blob: 28542af41efaef82b13ebe216675f7bcbc9f0972 [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;
Tarun Karra24e3dfa2013-02-25 21:58:05 -0800115 unsigned int curr_context_id = 0;
116 unsigned int curr_global_ts = 0;
117 static struct adreno_context *curr_context;
118 static struct kgsl_context *context;
Jordan Crouse95b68472012-05-25 10:25:01 -0600119
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700120 ret = get_iommu_unit(dev, &mmu, &iommu_unit);
121 if (ret)
122 goto done;
123 iommu_dev = get_iommu_device(iommu_unit, dev);
Jordan Crouse95b68472012-05-25 10:25:01 -0600124 if (!iommu_dev) {
125 KGSL_CORE_ERR("Invalid IOMMU device %p\n", dev);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700126 ret = -ENOSYS;
127 goto done;
Jordan Crouse95b68472012-05-25 10:25:01 -0600128 }
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700129 iommu = mmu->priv;
Tarun Karrab8107322013-02-07 13:46:02 -0800130 device = mmu->device;
Tarun Karra99678f82013-02-13 13:57:25 -0800131 adreno_dev = ADRENO_DEVICE(device);
Jordan Crouse95b68472012-05-25 10:25:01 -0600132
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700133 ptbase = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
Shubhraprakash Das190553a2012-06-11 15:17:59 -0600134 iommu_dev->ctx_id, TTBR0);
Jordan Crouse95b68472012-05-25 10:25:01 -0600135
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700136 fsr = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
Jordan Crouse95b68472012-05-25 10:25:01 -0600137 iommu_dev->ctx_id, FSR);
138
Tarun Karra99678f82013-02-13 13:57:25 -0800139 if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE)
140 no_page_fault_log = kgsl_mmu_log_fault_addr(mmu, ptbase, addr);
Tarun Karrab8107322013-02-07 13:46:02 -0800141
142 if (!no_page_fault_log) {
143 KGSL_MEM_CRIT(iommu_dev->kgsldev,
144 "GPU PAGE FAULT: addr = %lX pid = %d\n",
145 addr, kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase));
146 KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
147 iommu_dev->ctx_id, fsr);
148 }
Jordan Crouse95b68472012-05-25 10:25:01 -0600149
Shubhraprakash Das2747cf62012-09-27 23:05:43 -0700150 mmu->fault = 1;
151 iommu_dev->fault = 1;
152
Tarun Karra24e3dfa2013-02-25 21:58:05 -0800153 kgsl_sharedmem_readl(&device->memstore, &curr_context_id,
154 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context));
155 context = idr_find(&device->context_idr, curr_context_id);
156 if (context != NULL)
157 curr_context = context->devctxt;
158
159 kgsl_sharedmem_readl(&device->memstore, &curr_global_ts,
160 KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, eoptimestamp));
161
162 /*
163 * Store pagefault's timestamp and ib1 addr in context,
164 * this information is used in GFT
165 */
166 curr_context->pagefault = 1;
167 curr_context->pagefault_ts = curr_global_ts;
168
Jordan Crouse95b68472012-05-25 10:25:01 -0600169 trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700170 kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase), 0);
Jordan Crouse95b68472012-05-25 10:25:01 -0600171
Shubhraprakash Das2747cf62012-09-27 23:05:43 -0700172 /*
173 * We do not want the h/w to resume fetching data from an iommu unit
174 * that has faulted, this is better for debugging as it will stall
175 * the GPU and trigger a snapshot. To stall the transaction return
176 * EBUSY error.
177 */
Tarun Karra99678f82013-02-13 13:57:25 -0800178 if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE)
179 ret = -EBUSY;
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700180done:
181 return ret;
Jordan Crouse95b68472012-05-25 10:25:01 -0600182}
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600183
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600184/*
185 * kgsl_iommu_disable_clk - Disable iommu clocks
186 * @mmu - Pointer to mmu structure
187 *
188 * Disables iommu clocks
189 * Return - void
190 */
191static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu)
192{
193 struct kgsl_iommu *iommu = mmu->priv;
194 struct msm_iommu_drvdata *iommu_drvdata;
195 int i, j;
196
197 for (i = 0; i < iommu->unit_count; i++) {
198 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
199 for (j = 0; j < iommu_unit->dev_count; j++) {
200 if (!iommu_unit->dev[j].clk_enabled)
201 continue;
202 iommu_drvdata = dev_get_drvdata(
203 iommu_unit->dev[j].dev->parent);
Shubhraprakash Das102aac52012-08-16 22:12:27 -0700204 if (iommu_drvdata->aclk)
205 clk_disable_unprepare(iommu_drvdata->aclk);
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600206 if (iommu_drvdata->clk)
207 clk_disable_unprepare(iommu_drvdata->clk);
208 clk_disable_unprepare(iommu_drvdata->pclk);
209 iommu_unit->dev[j].clk_enabled = false;
210 }
211 }
212}
213
214/*
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600215 * kgsl_iommu_disable_clk_event - An event function that is executed when
216 * the required timestamp is reached. It disables the IOMMU clocks if
217 * the timestamp on which the clocks can be disabled has expired.
218 * @device - The kgsl device pointer
219 * @data - The data passed during event creation, it is the MMU pointer
220 * @id - Context ID, should always be KGSL_MEMSTORE_GLOBAL
221 * @ts - The current timestamp that has expired for the device
222 *
223 * Disables IOMMU clocks if timestamp has expired
224 * Return - void
225 */
226static void kgsl_iommu_clk_disable_event(struct kgsl_device *device, void *data,
227 unsigned int id, unsigned int ts)
228{
229 struct kgsl_mmu *mmu = data;
230 struct kgsl_iommu *iommu = mmu->priv;
231
232 if (!iommu->clk_event_queued) {
233 if (0 > timestamp_cmp(ts, iommu->iommu_last_cmd_ts))
234 KGSL_DRV_ERR(device,
235 "IOMMU disable clock event being cancelled, "
236 "iommu_last_cmd_ts: %x, retired ts: %x\n",
237 iommu->iommu_last_cmd_ts, ts);
238 return;
239 }
240
241 if (0 <= timestamp_cmp(ts, iommu->iommu_last_cmd_ts)) {
242 kgsl_iommu_disable_clk(mmu);
243 iommu->clk_event_queued = false;
244 } else {
245 /* add new event to fire when ts is reached, this can happen
246 * if we queued an event and someone requested the clocks to
247 * be disbaled on a later timestamp */
248 if (kgsl_add_event(device, id, iommu->iommu_last_cmd_ts,
249 kgsl_iommu_clk_disable_event, mmu, mmu)) {
250 KGSL_DRV_ERR(device,
251 "Failed to add IOMMU disable clk event\n");
252 iommu->clk_event_queued = false;
253 }
254 }
255}
256
257/*
258 * kgsl_iommu_disable_clk_on_ts - Sets up event to disable IOMMU clocks
259 * @mmu - The kgsl MMU pointer
260 * @ts - Timestamp on which the clocks should be disabled
261 * @ts_valid - Indicates whether ts parameter is valid, if this parameter
262 * is false then it means that the calling function wants to disable the
263 * IOMMU clocks immediately without waiting for any timestamp
264 *
265 * Creates an event to disable the IOMMU clocks on timestamp and if event
266 * already exists then updates the timestamp of disabling the IOMMU clocks
267 * with the passed in ts if it is greater than the current value at which
268 * the clocks will be disabled
269 * Return - void
270 */
271static void
272kgsl_iommu_disable_clk_on_ts(struct kgsl_mmu *mmu, unsigned int ts,
273 bool ts_valid)
274{
275 struct kgsl_iommu *iommu = mmu->priv;
276
277 if (iommu->clk_event_queued) {
278 if (ts_valid && (0 <
279 timestamp_cmp(ts, iommu->iommu_last_cmd_ts)))
280 iommu->iommu_last_cmd_ts = ts;
281 } else {
282 if (ts_valid) {
283 iommu->iommu_last_cmd_ts = ts;
284 iommu->clk_event_queued = true;
285 if (kgsl_add_event(mmu->device, KGSL_MEMSTORE_GLOBAL,
286 ts, kgsl_iommu_clk_disable_event, mmu, mmu)) {
287 KGSL_DRV_ERR(mmu->device,
288 "Failed to add IOMMU disable clk event\n");
289 iommu->clk_event_queued = false;
290 }
291 } else {
292 kgsl_iommu_disable_clk(mmu);
293 }
294 }
295}
296
297/*
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600298 * kgsl_iommu_enable_clk - Enable iommu clocks
299 * @mmu - Pointer to mmu structure
300 * @ctx_id - The context bank whose clocks are to be turned on
301 *
302 * Enables iommu clocks of a given context
303 * Return: 0 on success else error code
304 */
305static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu,
306 int ctx_id)
307{
308 int ret = 0;
309 int i, j;
310 struct kgsl_iommu *iommu = mmu->priv;
311 struct msm_iommu_drvdata *iommu_drvdata;
312
313 for (i = 0; i < iommu->unit_count; i++) {
314 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
315 for (j = 0; j < iommu_unit->dev_count; j++) {
316 if (iommu_unit->dev[j].clk_enabled ||
317 ctx_id != iommu_unit->dev[j].ctx_id)
318 continue;
319 iommu_drvdata =
320 dev_get_drvdata(iommu_unit->dev[j].dev->parent);
321 ret = clk_prepare_enable(iommu_drvdata->pclk);
322 if (ret)
323 goto done;
324 if (iommu_drvdata->clk) {
325 ret = clk_prepare_enable(iommu_drvdata->clk);
326 if (ret) {
327 clk_disable_unprepare(
328 iommu_drvdata->pclk);
329 goto done;
330 }
331 }
Shubhraprakash Das102aac52012-08-16 22:12:27 -0700332 if (iommu_drvdata->aclk) {
333 ret = clk_prepare_enable(iommu_drvdata->aclk);
334 if (ret) {
335 if (iommu_drvdata->clk)
336 clk_disable_unprepare(
337 iommu_drvdata->clk);
338 clk_disable_unprepare(
339 iommu_drvdata->pclk);
340 goto done;
341 }
342 }
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600343 iommu_unit->dev[j].clk_enabled = true;
344 }
345 }
346done:
347 if (ret)
348 kgsl_iommu_disable_clk(mmu);
349 return ret;
350}
351
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600352/*
353 * kgsl_iommu_pt_equal - Check if pagetables are equal
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700354 * @mmu - Pointer to mmu structure
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600355 * @pt - Pointer to pagetable
356 * @pt_base - Address of a pagetable that the IOMMU register is
357 * programmed with
358 *
359 * Checks whether the pt_base is equal to the base address of
360 * the pagetable which is contained in the pt structure
361 * Return - Non-zero if the pagetable addresses are equal else 0
362 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700363static int kgsl_iommu_pt_equal(struct kgsl_mmu *mmu,
364 struct kgsl_pagetable *pt,
365 unsigned int pt_base)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600366{
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700367 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600368 struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
369 unsigned int domain_ptbase = iommu_pt ?
370 iommu_get_pt_base_addr(iommu_pt->domain) : 0;
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600371 /* Only compare the valid address bits of the pt_base */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700372 domain_ptbase &=
373 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
374 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
375
376 pt_base &=
377 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
378 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
379
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600380 return domain_ptbase && pt_base &&
381 (domain_ptbase == pt_base);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600382}
383
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600384/*
385 * kgsl_iommu_destroy_pagetable - Free up reaources help by a pagetable
386 * @mmu_specific_pt - Pointer to pagetable which is to be freed
387 *
388 * Return - void
389 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600390static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
391{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600392 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
393 if (iommu_pt->domain)
394 iommu_domain_free(iommu_pt->domain);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600395 kfree(iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600396}
397
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600398/*
399 * kgsl_iommu_create_pagetable - Create a IOMMU pagetable
400 *
401 * Allocate memory to hold a pagetable and allocate the IOMMU
402 * domain which is the actual IOMMU pagetable
403 * Return - void
404 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600405void *kgsl_iommu_create_pagetable(void)
406{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600407 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600408
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600409 iommu_pt = kzalloc(sizeof(struct kgsl_iommu_pt), GFP_KERNEL);
410 if (!iommu_pt) {
411 KGSL_CORE_ERR("kzalloc(%d) failed\n",
412 sizeof(struct kgsl_iommu_pt));
413 return NULL;
414 }
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700415 /* L2 redirect is not stable on IOMMU v2 */
416 if (msm_soc_version_supports_iommu_v1())
417 iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700418 MSM_IOMMU_DOMAIN_PT_CACHEABLE);
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700419 else
420 iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
421 0);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600422 if (!iommu_pt->domain) {
423 KGSL_CORE_ERR("Failed to create iommu domain\n");
424 kfree(iommu_pt);
425 return NULL;
Jordan Crouse95b68472012-05-25 10:25:01 -0600426 } else {
427 iommu_set_fault_handler(iommu_pt->domain,
428 kgsl_iommu_fault_handler);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600429 }
Jordan Crouse95b68472012-05-25 10:25:01 -0600430
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600431 return iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600432}
433
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600434/*
435 * kgsl_detach_pagetable_iommu_domain - Detach the IOMMU unit from a
436 * pagetable
437 * @mmu - Pointer to the device mmu structure
438 * @priv - Flag indicating whether the private or user context is to be
439 * detached
440 *
441 * Detach the IOMMU unit with the domain that is contained in the
442 * hwpagetable of the given mmu. After detaching the IOMMU unit is not
443 * in use because the PTBR will not be set after a detach
444 * Return - void
445 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600446static void kgsl_detach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
447{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600448 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600449 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600450 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600451
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600452 for (i = 0; i < iommu->unit_count; i++) {
453 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600454 iommu_pt = mmu->defaultpagetable->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600455 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600456 /*
457 * If there is a 2nd default pagetable then priv domain
458 * is attached with this pagetable
459 */
460 if (mmu->priv_bank_table &&
461 (KGSL_IOMMU_CONTEXT_PRIV == j))
462 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600463 if (iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600464 iommu_detach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600465 iommu_unit->dev[j].dev);
466 iommu_unit->dev[j].attached = false;
467 KGSL_MEM_INFO(mmu->device, "iommu %p detached "
468 "from user dev of MMU: %p\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600469 iommu_pt->domain, mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600470 }
471 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600472 }
473}
474
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600475/*
476 * kgsl_attach_pagetable_iommu_domain - Attach the IOMMU unit to a
477 * pagetable, i.e set the IOMMU's PTBR to the pagetable address and
478 * setup other IOMMU registers for the device so that it becomes
479 * active
480 * @mmu - Pointer to the device mmu structure
481 * @priv - Flag indicating whether the private or user context is to be
482 * attached
483 *
484 * Attach the IOMMU unit with the domain that is contained in the
485 * hwpagetable of the given mmu.
486 * Return - 0 on success else error code
487 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600488static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
489{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600490 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600491 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600492 int i, j, ret = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600493
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600494 /*
495 * Loop through all the iommu devcies under all iommu units and
496 * attach the domain
497 */
498 for (i = 0; i < iommu->unit_count; i++) {
499 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600500 iommu_pt = mmu->defaultpagetable->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600501 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600502 /*
503 * If there is a 2nd default pagetable then priv domain
504 * is attached to this pagetable
505 */
506 if (mmu->priv_bank_table &&
507 (KGSL_IOMMU_CONTEXT_PRIV == j))
508 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600509 if (!iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600510 ret = iommu_attach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600511 iommu_unit->dev[j].dev);
512 if (ret) {
513 KGSL_MEM_ERR(mmu->device,
514 "Failed to attach device, err %d\n",
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700515 ret);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600516 goto done;
517 }
518 iommu_unit->dev[j].attached = true;
519 KGSL_MEM_INFO(mmu->device,
520 "iommu pt %p attached to dev %p, ctx_id %d\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600521 iommu_pt->domain, iommu_unit->dev[j].dev,
522 iommu_unit->dev[j].ctx_id);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700523 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600524 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600525 }
526done:
527 return ret;
528}
529
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600530/*
531 * _get_iommu_ctxs - Get device pointer to IOMMU contexts
532 * @mmu - Pointer to mmu device
533 * data - Pointer to the platform data containing information about
534 * iommu devices for one iommu unit
535 * unit_id - The IOMMU unit number. This is not a specific ID but just
536 * a serial number. The serial numbers are treated as ID's of the
537 * IOMMU units
538 *
539 * Return - 0 on success else error code
540 */
541static int _get_iommu_ctxs(struct kgsl_mmu *mmu,
542 struct kgsl_device_iommu_data *data, unsigned int unit_id)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700543{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600544 struct kgsl_iommu *iommu = mmu->priv;
545 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id];
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700546 int i;
547
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600548 if (data->iommu_ctx_count > KGSL_IOMMU_MAX_DEVS_PER_UNIT) {
549 KGSL_CORE_ERR("Too many iommu devices defined for an "
550 "IOMMU unit\n");
551 return -EINVAL;
552 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700553
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600554 for (i = 0; i < data->iommu_ctx_count; i++) {
555 if (!data->iommu_ctxs[i].iommu_ctx_name)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700556 continue;
557
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600558 iommu_unit->dev[iommu_unit->dev_count].dev =
559 msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
560 if (iommu_unit->dev[iommu_unit->dev_count].dev == NULL) {
561 KGSL_CORE_ERR("Failed to get iommu dev handle for "
562 "device %s\n", data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700563 return -EINVAL;
564 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600565 if (KGSL_IOMMU_CONTEXT_USER != data->iommu_ctxs[i].ctx_id &&
566 KGSL_IOMMU_CONTEXT_PRIV != data->iommu_ctxs[i].ctx_id) {
567 KGSL_CORE_ERR("Invalid context ID defined: %d\n",
568 data->iommu_ctxs[i].ctx_id);
569 return -EINVAL;
570 }
571 iommu_unit->dev[iommu_unit->dev_count].ctx_id =
572 data->iommu_ctxs[i].ctx_id;
Jordan Crouse95b68472012-05-25 10:25:01 -0600573 iommu_unit->dev[iommu_unit->dev_count].kgsldev = mmu->device;
574
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600575 KGSL_DRV_INFO(mmu->device,
576 "Obtained dev handle %p for iommu context %s\n",
577 iommu_unit->dev[iommu_unit->dev_count].dev,
578 data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700579
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600580 iommu_unit->dev_count++;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700581 }
582
583 return 0;
584}
585
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600586/*
Tarun Karra9c070822012-11-27 16:43:51 -0700587 * kgsl_get_sync_lock - Init Sync Lock between GPU and CPU
588 * @mmu - Pointer to mmu device
589 *
590 * Return - 0 on success else error code
591 */
592static int kgsl_iommu_init_sync_lock(struct kgsl_mmu *mmu)
593{
594 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
595 int status = 0;
596 struct kgsl_pagetable *pagetable = NULL;
597 uint32_t lock_gpu_addr = 0;
598 uint32_t lock_phy_addr = 0;
599 uint32_t page_offset = 0;
600
601 iommu->sync_lock_initialized = 0;
602
603 if (!(mmu->flags & KGSL_MMU_FLAGS_IOMMU_SYNC)) {
604 KGSL_DRV_ERR(mmu->device,
605 "The GPU microcode does not support IOMMUv1 sync opcodes\n");
606 return -ENXIO;
607 }
608
609 /* Get the physical address of the Lock variables */
610 lock_phy_addr = (msm_iommu_lock_initialize()
611 - MSM_SHARED_RAM_BASE + msm_shared_ram_phys);
612
613 if (!lock_phy_addr) {
614 KGSL_DRV_ERR(mmu->device,
615 "GPU CPU sync lock is not supported by kernel\n");
616 return -ENXIO;
617 }
618
619 /* Align the physical address to PAGE boundary and store the offset */
620 page_offset = (lock_phy_addr & (PAGE_SIZE - 1));
621 lock_phy_addr = (lock_phy_addr & ~(PAGE_SIZE - 1));
622 iommu->sync_lock_desc.physaddr = (unsigned int)lock_phy_addr;
623
624 iommu->sync_lock_desc.size =
625 PAGE_ALIGN(sizeof(kgsl_iommu_sync_lock_vars));
626 status = memdesc_sg_phys(&iommu->sync_lock_desc,
627 iommu->sync_lock_desc.physaddr,
628 iommu->sync_lock_desc.size);
629
630 if (status)
631 return status;
632
633 /* Map Lock variables to GPU pagetable */
Jordan Crousedc67dfb2012-10-25 09:41:46 -0600634 iommu->sync_lock_desc.priv |= KGSL_MEMDESC_GLOBAL;
Tarun Karra9c070822012-11-27 16:43:51 -0700635
636 pagetable = mmu->priv_bank_table ? mmu->priv_bank_table :
637 mmu->defaultpagetable;
638
639 status = kgsl_mmu_map(pagetable, &iommu->sync_lock_desc,
640 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
641
642 if (status) {
643 kgsl_mmu_unmap(pagetable, &iommu->sync_lock_desc);
Jordan Crousedc67dfb2012-10-25 09:41:46 -0600644 iommu->sync_lock_desc.priv &= ~KGSL_MEMDESC_GLOBAL;
Tarun Karra9c070822012-11-27 16:43:51 -0700645 return status;
646 }
647
648 /* Store Lock variables GPU address */
649 lock_gpu_addr = (iommu->sync_lock_desc.gpuaddr + page_offset);
650
651 kgsl_iommu_sync_lock_vars.flag[PROC_APPS] = (lock_gpu_addr +
652 (offsetof(struct remote_iommu_petersons_spinlock,
653 flag[PROC_APPS])));
654 kgsl_iommu_sync_lock_vars.flag[PROC_GPU] = (lock_gpu_addr +
655 (offsetof(struct remote_iommu_petersons_spinlock,
656 flag[PROC_GPU])));
657 kgsl_iommu_sync_lock_vars.turn = (lock_gpu_addr +
658 (offsetof(struct remote_iommu_petersons_spinlock, turn)));
659
660 iommu->sync_lock_vars = &kgsl_iommu_sync_lock_vars;
661
662 /* Flag Sync Lock is Initialized */
663 iommu->sync_lock_initialized = 1;
664
665 return status;
666}
667
668/*
669 * kgsl_iommu_sync_lock - Acquire Sync Lock between GPU and CPU
670 * @mmu - Pointer to mmu device
671 * @cmds - Pointer to array of commands
672 *
673 * Return - int - number of commands.
674 */
675inline unsigned int kgsl_iommu_sync_lock(struct kgsl_mmu *mmu,
676 unsigned int *cmds)
677{
678 struct kgsl_device *device = mmu->device;
679 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
680 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
681 struct remote_iommu_petersons_spinlock *lock_vars =
682 iommu->sync_lock_vars;
683 unsigned int *start = cmds;
684
685 if (!iommu->sync_lock_initialized)
686 return 0;
687
688 *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
689 *cmds++ = lock_vars->flag[PROC_GPU];
690 *cmds++ = 1;
691
692 cmds += adreno_add_idle_cmds(adreno_dev, cmds);
693
694 *cmds++ = cp_type3_packet(CP_WAIT_REG_MEM, 5);
695 /* MEM SPACE = memory, FUNCTION = equals */
696 *cmds++ = 0x13;
697 *cmds++ = lock_vars->flag[PROC_GPU];
698 *cmds++ = 0x1;
699 *cmds++ = 0x1;
700 *cmds++ = 0x1;
701
702 *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
703 *cmds++ = lock_vars->turn;
704 *cmds++ = 0;
705
706 cmds += adreno_add_idle_cmds(adreno_dev, cmds);
707
708 *cmds++ = cp_type3_packet(CP_WAIT_REG_MEM, 5);
709 /* MEM SPACE = memory, FUNCTION = equals */
710 *cmds++ = 0x13;
711 *cmds++ = lock_vars->flag[PROC_GPU];
712 *cmds++ = 0x1;
713 *cmds++ = 0x1;
714 *cmds++ = 0x1;
715
716 *cmds++ = cp_type3_packet(CP_TEST_TWO_MEMS, 3);
717 *cmds++ = lock_vars->flag[PROC_APPS];
718 *cmds++ = lock_vars->turn;
719 *cmds++ = 0;
720
721 cmds += adreno_add_idle_cmds(adreno_dev, cmds);
722
723 return cmds - start;
724}
725
726/*
727 * kgsl_iommu_sync_lock - Release Sync Lock between GPU and CPU
728 * @mmu - Pointer to mmu device
729 * @cmds - Pointer to array of commands
730 *
731 * Return - int - number of commands.
732 */
733inline unsigned int kgsl_iommu_sync_unlock(struct kgsl_mmu *mmu,
734 unsigned int *cmds)
735{
736 struct kgsl_device *device = mmu->device;
737 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
738 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
739 struct remote_iommu_petersons_spinlock *lock_vars =
740 iommu->sync_lock_vars;
741 unsigned int *start = cmds;
742
743 if (!iommu->sync_lock_initialized)
744 return 0;
745
746 *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
747 *cmds++ = lock_vars->flag[PROC_GPU];
748 *cmds++ = 0;
749
750 *cmds++ = cp_type3_packet(CP_WAIT_REG_MEM, 5);
751 /* MEM SPACE = memory, FUNCTION = equals */
752 *cmds++ = 0x13;
753 *cmds++ = lock_vars->flag[PROC_GPU];
754 *cmds++ = 0x0;
755 *cmds++ = 0x1;
756 *cmds++ = 0x1;
757
758 cmds += adreno_add_idle_cmds(adreno_dev, cmds);
759
760 return cmds - start;
761}
762
763/*
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600764 * kgsl_get_iommu_ctxt - Get device pointer to IOMMU contexts
765 * @mmu - Pointer to mmu device
766 *
767 * Get the device pointers for the IOMMU user and priv contexts of the
768 * kgsl device
769 * Return - 0 on success else error code
770 */
771static int kgsl_get_iommu_ctxt(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600772{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600773 struct platform_device *pdev =
774 container_of(mmu->device->parentdev, struct platform_device,
775 dev);
776 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
777 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700778 int i, ret = 0;
779
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600780 /* Go through the IOMMU data and get all the context devices */
781 if (KGSL_IOMMU_MAX_UNITS < pdata_dev->iommu_count) {
782 KGSL_CORE_ERR("Too many IOMMU units defined\n");
783 ret = -EINVAL;
784 goto done;
785 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700786
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600787 for (i = 0; i < pdata_dev->iommu_count; i++) {
788 ret = _get_iommu_ctxs(mmu, &pdata_dev->iommu_data[i], i);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700789 if (ret)
790 break;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600791 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600792 iommu->unit_count = pdata_dev->iommu_count;
793done:
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700794 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600795}
796
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600797/*
798 * kgsl_set_register_map - Map the IOMMU regsiters in the memory descriptors
799 * of the respective iommu units
800 * @mmu - Pointer to mmu structure
801 *
802 * Return - 0 on success else error code
803 */
804static int kgsl_set_register_map(struct kgsl_mmu *mmu)
805{
806 struct platform_device *pdev =
807 container_of(mmu->device->parentdev, struct platform_device,
808 dev);
809 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
810 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
811 struct kgsl_iommu_unit *iommu_unit;
812 int i = 0, ret = 0;
813
814 for (; i < pdata_dev->iommu_count; i++) {
815 struct kgsl_device_iommu_data data = pdata_dev->iommu_data[i];
816 iommu_unit = &iommu->iommu_units[i];
817 /* set up the IOMMU register map for the given IOMMU unit */
818 if (!data.physstart || !data.physend) {
819 KGSL_CORE_ERR("The register range for IOMMU unit not"
820 " specified\n");
821 ret = -EINVAL;
822 goto err;
823 }
824 iommu_unit->reg_map.hostptr = ioremap(data.physstart,
825 data.physend - data.physstart + 1);
826 if (!iommu_unit->reg_map.hostptr) {
827 KGSL_CORE_ERR("Failed to map SMMU register address "
828 "space from %x to %x\n", data.physstart,
829 data.physend - data.physstart + 1);
830 ret = -ENOMEM;
831 i--;
832 goto err;
833 }
834 iommu_unit->reg_map.size = data.physend - data.physstart + 1;
835 iommu_unit->reg_map.physaddr = data.physstart;
Rajeev Kulkarni55863722012-11-21 23:40:05 -0800836 ret = memdesc_sg_phys(&iommu_unit->reg_map, data.physstart,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600837 iommu_unit->reg_map.size);
Rajeev Kulkarni55863722012-11-21 23:40:05 -0800838 if (ret)
839 goto err;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600840 }
841 iommu->unit_count = pdata_dev->iommu_count;
842 return ret;
843err:
844 /* Unmap any mapped IOMMU regions */
845 for (; i >= 0; i--) {
846 iommu_unit = &iommu->iommu_units[i];
847 iounmap(iommu_unit->reg_map.hostptr);
848 iommu_unit->reg_map.size = 0;
849 iommu_unit->reg_map.physaddr = 0;
850 }
851 return ret;
852}
853
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600854/*
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700855 * kgsl_iommu_get_pt_base_addr - Get the address of the pagetable that the
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600856 * IOMMU ttbr0 register is programmed with
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700857 * @mmu - Pointer to mmu
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600858 * @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
859 *
860 * Return - actual pagetable address that the ttbr0 register is programmed
861 * with
862 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700863static unsigned int kgsl_iommu_get_pt_base_addr(struct kgsl_mmu *mmu,
864 struct kgsl_pagetable *pt)
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600865{
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700866 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600867 struct kgsl_iommu_pt *iommu_pt = pt->priv;
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700868 return iommu_get_pt_base_addr(iommu_pt->domain) &
869 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
870 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600871}
872
873/*
874 * kgsl_iommu_get_pt_lsb - Return the lsb of the ttbr0 IOMMU register
875 * @mmu - Pointer to mmu structure
876 * @hostptr - Pointer to the IOMMU register map. This is used to match
877 * the iommu device whose lsb value is to be returned
878 * @ctx_id - The context bank whose lsb valus is to be returned
879 * Return - returns the lsb which is the last 14 bits of the ttbr0 IOMMU
880 * register. ttbr0 is the actual PTBR for of the IOMMU. The last 14 bits
881 * are only programmed once in the beginning when a domain is attached
882 * does not change.
883 */
884static int kgsl_iommu_get_pt_lsb(struct kgsl_mmu *mmu,
885 unsigned int unit_id,
886 enum kgsl_iommu_context_id ctx_id)
887{
888 struct kgsl_iommu *iommu = mmu->priv;
889 int i, j;
890 for (i = 0; i < iommu->unit_count; i++) {
891 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
892 for (j = 0; j < iommu_unit->dev_count; j++)
893 if (unit_id == i &&
894 ctx_id == iommu_unit->dev[j].ctx_id)
895 return iommu_unit->dev[j].pt_lsb;
896 }
897 return 0;
898}
899
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600900static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600901 struct kgsl_pagetable *pagetable,
902 unsigned int context_id)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600903{
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600904 if (mmu->flags & KGSL_FLAGS_STARTED) {
905 /* page table not current, then setup mmu to use new
906 * specified page table
907 */
908 if (mmu->hwpagetable != pagetable) {
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600909 unsigned int flags = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600910 mmu->hwpagetable = pagetable;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600911 flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
Shubhraprakash Das8649fa52012-07-26 15:49:46 -0700912 mmu->device->id) |
913 KGSL_MMUFLAGS_TLBFLUSH;
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600914 kgsl_setstate(mmu, context_id,
915 KGSL_MMUFLAGS_PTUPDATE | flags);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600916 }
917 }
918}
919
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600920static int kgsl_iommu_init(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600921{
922 /*
923 * intialize device mmu
924 *
925 * call this with the global lock held
926 */
927 int status = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600928 struct kgsl_iommu *iommu;
929
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600930 iommu = kzalloc(sizeof(struct kgsl_iommu), GFP_KERNEL);
931 if (!iommu) {
932 KGSL_CORE_ERR("kzalloc(%d) failed\n",
933 sizeof(struct kgsl_iommu));
934 return -ENOMEM;
935 }
936
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600937 mmu->priv = iommu;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600938 status = kgsl_get_iommu_ctxt(mmu);
939 if (status)
940 goto done;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600941 status = kgsl_set_register_map(mmu);
942 if (status)
943 goto done;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600944
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700945 iommu->iommu_reg_list = kgsl_iommuv1_reg;
946 iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
947
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700948 if (msm_soc_version_supports_iommu_v1()) {
949 iommu->iommu_reg_list = kgsl_iommuv1_reg;
950 iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
951 } else {
952 iommu->iommu_reg_list = kgsl_iommuv2_reg;
953 iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V2;
954 }
955
Shubhraprakash Dase9541a32012-05-09 22:25:55 -0600956 /* A nop is required in an indirect buffer when switching
957 * pagetables in-stream */
958 kgsl_sharedmem_writel(&mmu->setstate_memory,
959 KGSL_IOMMU_SETSTATE_NOP_OFFSET,
960 cp_nop_packet(1));
961
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600962 dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600963 __func__);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600964done:
965 if (status) {
966 kfree(iommu);
967 mmu->priv = NULL;
968 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600969 return status;
970}
971
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600972/*
973 * kgsl_iommu_setup_defaultpagetable - Setup the initial defualtpagetable
974 * for iommu. This function is only called once during first start, successive
975 * start do not call this funciton.
976 * @mmu - Pointer to mmu structure
977 *
978 * Create the initial defaultpagetable and setup the iommu mappings to it
979 * Return - 0 on success else error code
980 */
981static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu)
982{
983 int status = 0;
984 int i = 0;
985 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600986 struct kgsl_pagetable *pagetable = NULL;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600987
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600988 /* If chip is not 8960 then we use the 2nd context bank for pagetable
989 * switching on the 3D side for which a separate table is allocated */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700990 if (!cpu_is_msm8960() && msm_soc_version_supports_iommu_v1()) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600991 mmu->priv_bank_table =
992 kgsl_mmu_getpagetable(KGSL_MMU_PRIV_BANK_TABLE_NAME);
993 if (mmu->priv_bank_table == NULL) {
994 status = -ENOMEM;
995 goto err;
996 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600997 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600998 mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
999 /* Return error if the default pagetable doesn't exist */
1000 if (mmu->defaultpagetable == NULL) {
1001 status = -ENOMEM;
1002 goto err;
1003 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001004 pagetable = mmu->priv_bank_table ? mmu->priv_bank_table :
1005 mmu->defaultpagetable;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001006 /* Map the IOMMU regsiters to only defaultpagetable */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -07001007 if (msm_soc_version_supports_iommu_v1()) {
1008 for (i = 0; i < iommu->unit_count; i++) {
1009 iommu->iommu_units[i].reg_map.priv |=
Jordan Crousedc67dfb2012-10-25 09:41:46 -06001010 KGSL_MEMDESC_GLOBAL;
Shubhraprakash Das15a8b462012-08-16 23:24:28 -07001011 status = kgsl_mmu_map(pagetable,
1012 &(iommu->iommu_units[i].reg_map),
1013 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
1014 if (status) {
1015 iommu->iommu_units[i].reg_map.priv &=
Jordan Crousedc67dfb2012-10-25 09:41:46 -06001016 ~KGSL_MEMDESC_GLOBAL;
Shubhraprakash Das15a8b462012-08-16 23:24:28 -07001017 goto err;
1018 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001019 }
1020 }
1021 return status;
1022err:
1023 for (i--; i >= 0; i--) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001024 kgsl_mmu_unmap(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001025 &(iommu->iommu_units[i].reg_map));
Jordan Crousedc67dfb2012-10-25 09:41:46 -06001026 iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMDESC_GLOBAL;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001027 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001028 if (mmu->priv_bank_table) {
1029 kgsl_mmu_putpagetable(mmu->priv_bank_table);
1030 mmu->priv_bank_table = NULL;
1031 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001032 if (mmu->defaultpagetable) {
1033 kgsl_mmu_putpagetable(mmu->defaultpagetable);
1034 mmu->defaultpagetable = NULL;
1035 }
1036 return status;
1037}
1038
Shubhraprakash Das1c528262012-04-26 17:38:13 -06001039static int kgsl_iommu_start(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001040{
Tarun Karra9c070822012-11-27 16:43:51 -07001041 struct kgsl_device *device = mmu->device;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001042 int status;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001043 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001044 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001045
1046 if (mmu->flags & KGSL_FLAGS_STARTED)
1047 return 0;
1048
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001049 if (mmu->defaultpagetable == NULL) {
1050 status = kgsl_iommu_setup_defaultpagetable(mmu);
1051 if (status)
1052 return -ENOMEM;
Tarun Karra9c070822012-11-27 16:43:51 -07001053
1054 /* Initialize the sync lock between GPU and CPU */
1055 if (msm_soc_version_supports_iommu_v1() &&
1056 (device->id == KGSL_DEVICE_3D0))
1057 kgsl_iommu_init_sync_lock(mmu);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001058 }
Tarun Karra9c070822012-11-27 16:43:51 -07001059
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001060 /* We use the GPU MMU to control access to IOMMU registers on 8960 with
1061 * a225, hence we still keep the MMU active on 8960 */
1062 if (cpu_is_msm8960()) {
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001063 struct kgsl_mh *mh = &(mmu->device->mh);
1064 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001);
1065 kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
1066 mh->mpu_base +
Shubhraprakash Das2b54b5f2012-08-08 18:21:36 -07001067 iommu->iommu_units[0].reg_map.gpuaddr);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001068 } else {
1069 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
1070 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001071
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001072 mmu->hwpagetable = mmu->defaultpagetable;
1073
1074 status = kgsl_attach_pagetable_iommu_domain(mmu);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001075 if (status) {
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -06001076 mmu->hwpagetable = NULL;
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001077 goto done;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -06001078 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001079 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001080 if (status) {
1081 KGSL_CORE_ERR("clk enable failed\n");
1082 goto done;
1083 }
1084 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
1085 if (status) {
1086 KGSL_CORE_ERR("clk enable failed\n");
1087 goto done;
1088 }
1089 /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as
1090 * that value should not change when we change pagetables, so while
1091 * changing pagetables we can use this lsb value of the pagetable w/o
1092 * having to read it again
1093 */
1094 for (i = 0; i < iommu->unit_count; i++) {
1095 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das2747cf62012-09-27 23:05:43 -07001096 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001097 iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(iommu,
1098 KGSL_IOMMU_GET_CTX_REG(iommu,
1099 iommu_unit,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001100 iommu_unit->dev[j].ctx_id,
1101 TTBR0));
Shubhraprakash Das2747cf62012-09-27 23:05:43 -07001102 }
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001103 }
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001104
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001105 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001106 mmu->flags |= KGSL_FLAGS_STARTED;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001107
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001108done:
1109 if (status) {
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001110 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001111 kgsl_detach_pagetable_iommu_domain(mmu);
1112 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001113 return status;
1114}
1115
1116static int
1117kgsl_iommu_unmap(void *mmu_specific_pt,
Shubhraprakash Das0c811262012-06-06 23:22:19 -06001118 struct kgsl_memdesc *memdesc,
1119 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001120{
1121 int ret;
Jordan Crouse3c86ca82012-05-21 08:41:52 -06001122 unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001123 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001124
1125 /* All GPU addresses as assigned are page aligned, but some
1126 functions purturb the gpuaddr with an offset, so apply the
1127 mask here to make sure we have the right address */
1128
1129 unsigned int gpuaddr = memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK;
1130
1131 if (range == 0 || gpuaddr == 0)
1132 return 0;
1133
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001134 ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001135 if (ret)
1136 KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001137 "with err: %d\n", iommu_pt->domain, gpuaddr,
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001138 range, ret);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001139
Shubhraprakash Das0c811262012-06-06 23:22:19 -06001140#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
1141 /*
1142 * Flushing only required if per process pagetables are used. With
1143 * global case, flushing will happen inside iommu_map function
1144 */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -07001145 if (!ret && msm_soc_version_supports_iommu_v1())
Shubhraprakash Das0c811262012-06-06 23:22:19 -06001146 *tlb_flags = UINT_MAX;
1147#endif
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001148 return 0;
1149}
1150
1151static int
1152kgsl_iommu_map(void *mmu_specific_pt,
1153 struct kgsl_memdesc *memdesc,
Shubhraprakash Dasf764e462012-04-26 15:38:09 -06001154 unsigned int protflags,
1155 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001156{
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001157 int ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001158 unsigned int iommu_virt_addr;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001159 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Jordan Crouse3c86ca82012-05-21 08:41:52 -06001160 int size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001161
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001162 BUG_ON(NULL == iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001163
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001164
Jordan Croused17e9aa2011-10-12 16:57:48 -06001165 iommu_virt_addr = memdesc->gpuaddr;
1166
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001167 ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
Jordan Crouse3c86ca82012-05-21 08:41:52 -06001168 size, (IOMMU_READ | IOMMU_WRITE));
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001169 if (ret) {
1170 KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001171 "failed with err: %d\n", iommu_pt->domain,
Jordan Crouse3c86ca82012-05-21 08:41:52 -06001172 iommu_virt_addr, memdesc->sg, size,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001173 (IOMMU_READ | IOMMU_WRITE), ret);
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001174 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001175 }
1176
1177 return ret;
1178}
1179
Shubhraprakash Das79447952012-04-26 18:12:23 -06001180static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001181{
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001182 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das2747cf62012-09-27 23:05:43 -07001183 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001184 /*
1185 * stop device mmu
1186 *
1187 * call this with the global lock held
1188 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001189
1190 if (mmu->flags & KGSL_FLAGS_STARTED) {
1191 /* detach iommu attachment */
1192 kgsl_detach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -06001193 mmu->hwpagetable = NULL;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001194
1195 mmu->flags &= ~KGSL_FLAGS_STARTED;
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001196
Shubhraprakash Das2747cf62012-09-27 23:05:43 -07001197 if (mmu->fault) {
1198 for (i = 0; i < iommu->unit_count; i++) {
1199 struct kgsl_iommu_unit *iommu_unit =
1200 &iommu->iommu_units[i];
1201 for (j = 0; j < iommu_unit->dev_count; j++) {
1202 if (iommu_unit->dev[j].fault) {
1203 kgsl_iommu_enable_clk(mmu, j);
1204 KGSL_IOMMU_SET_CTX_REG(iommu,
1205 iommu_unit,
1206 iommu_unit->dev[j].ctx_id,
1207 RESUME, 1);
1208 iommu_unit->dev[j].fault = 0;
1209 }
1210 }
1211 }
1212 mmu->fault = 0;
1213 }
1214 }
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001215 /* switch off MMU clocks and cancel any events it has queued */
1216 iommu->clk_event_queued = false;
1217 kgsl_cancel_events(mmu->device, mmu);
1218 kgsl_iommu_disable_clk(mmu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001219}
1220
Shubhraprakash Das1c528262012-04-26 17:38:13 -06001221static int kgsl_iommu_close(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001222{
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001223 struct kgsl_iommu *iommu = mmu->priv;
1224 int i;
1225 for (i = 0; i < iommu->unit_count; i++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001226 struct kgsl_pagetable *pagetable = (mmu->priv_bank_table ?
1227 mmu->priv_bank_table : mmu->defaultpagetable);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001228 if (iommu->iommu_units[i].reg_map.gpuaddr)
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001229 kgsl_mmu_unmap(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001230 &(iommu->iommu_units[i].reg_map));
1231 if (iommu->iommu_units[i].reg_map.hostptr)
1232 iounmap(iommu->iommu_units[i].reg_map.hostptr);
1233 kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
1234 iommu->iommu_units[i].reg_map.sglen);
1235 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001236
1237 if (mmu->priv_bank_table)
1238 kgsl_mmu_putpagetable(mmu->priv_bank_table);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001239 if (mmu->defaultpagetable)
1240 kgsl_mmu_putpagetable(mmu->defaultpagetable);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001241 kfree(iommu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001242
1243 return 0;
1244}
1245
1246static unsigned int
Shubhraprakash Das1c528262012-04-26 17:38:13 -06001247kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001248{
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -06001249 unsigned int pt_base;
1250 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das64a745c2012-06-11 16:44:16 -06001251 /* We cannot enable or disable the clocks in interrupt context, this
1252 function is called from interrupt context if there is an axi error */
1253 if (in_interrupt())
1254 return 0;
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -06001255 /* Return the current pt base by reading IOMMU pt_base register */
1256 kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001257 pt_base = KGSL_IOMMU_GET_CTX_REG(iommu, (&iommu->iommu_units[0]),
1258 KGSL_IOMMU_CONTEXT_USER,
1259 TTBR0);
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001260 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001261 return pt_base &
1262 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
1263 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001264}
1265
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001266/*
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001267 * kgsl_iommu_default_setstate - Change the IOMMU pagetable or flush IOMMU tlb
1268 * of the primary context bank
1269 * @mmu - Pointer to mmu structure
1270 * @flags - Flags indicating whether pagetable has to chnage or tlb is to be
1271 * flushed or both
1272 *
1273 * Based on flags set the new pagetable fo the IOMMU unit or flush it's tlb or
1274 * do both by doing direct register writes to the IOMMu registers through the
1275 * cpu
1276 * Return - void
1277 */
1278static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
1279 uint32_t flags)
1280{
1281 struct kgsl_iommu *iommu = mmu->priv;
1282 int temp;
1283 int i;
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001284 unsigned int pt_base = kgsl_iommu_get_pt_base_addr(mmu,
1285 mmu->hwpagetable);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001286 unsigned int pt_val;
1287
1288 if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
1289 KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
1290 return;
1291 }
1292 /* Mask off the lsb of the pt base address since lsb will not change */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001293 pt_base &= (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
1294 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
1295
Hareesh Gunduf44df5b2013-05-07 14:52:17 +05301296 /* For v1 SMMU GPU needs to be idle for tlb invalidate as well */
1297 if (msm_soc_version_supports_iommu_v1())
1298 kgsl_idle(mmu->device);
1299
Shubhraprakash Dasee61e4d2012-11-27 17:07:44 -07001300 /* Acquire GPU-CPU sync Lock here */
1301 msm_iommu_lock();
1302
1303 if (flags & KGSL_MMUFLAGS_PTUPDATE) {
1304 if (!msm_soc_version_supports_iommu_v1())
1305 kgsl_idle(mmu->device);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001306 for (i = 0; i < iommu->unit_count; i++) {
1307 /* get the lsb value which should not change when
1308 * changing ttbr0 */
1309 pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
1310 KGSL_IOMMU_CONTEXT_USER);
1311 pt_val += pt_base;
1312
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001313 KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001314 KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
1315
1316 mb();
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001317 temp = KGSL_IOMMU_GET_CTX_REG(iommu,
1318 (&iommu->iommu_units[i]),
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001319 KGSL_IOMMU_CONTEXT_USER, TTBR0);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001320 }
1321 }
1322 /* Flush tlb */
1323 if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
1324 for (i = 0; i < iommu->unit_count; i++) {
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001325 KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
1326 KGSL_IOMMU_CONTEXT_USER, TLBIALL, 1);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001327 mb();
1328 }
1329 }
Tarun Karra9c070822012-11-27 16:43:51 -07001330
1331 /* Release GPU-CPU sync Lock here */
1332 msm_iommu_unlock();
1333
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001334 /* Disable smmu clock */
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001335 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001336}
1337
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001338/*
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001339 * kgsl_iommu_get_reg_gpuaddr - Returns the gpu address of IOMMU regsiter
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001340 * @mmu - Pointer to mmu structure
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001341 * @iommu_unit - The iommu unit for which base address is requested
1342 * @ctx_id - The context ID of the IOMMU ctx
1343 * @reg - The register for which address is required
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001344 *
1345 * Return - The number of iommu units which is also the number of register
1346 * mapped descriptor arrays which the out parameter will have
1347 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001348static unsigned int kgsl_iommu_get_reg_gpuaddr(struct kgsl_mmu *mmu,
1349 int iommu_unit, int ctx_id, int reg)
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001350{
1351 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001352
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001353 if (KGSL_IOMMU_GLOBAL_BASE == reg)
1354 return iommu->iommu_units[iommu_unit].reg_map.gpuaddr;
1355 else
1356 return iommu->iommu_units[iommu_unit].reg_map.gpuaddr +
1357 iommu->iommu_reg_list[reg].reg_offset +
1358 (ctx_id << KGSL_IOMMU_CTX_SHIFT) + iommu->ctx_offset;
1359}
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001360
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001361static int kgsl_iommu_get_num_iommu_units(struct kgsl_mmu *mmu)
1362{
1363 struct kgsl_iommu *iommu = mmu->priv;
1364 return iommu->unit_count;
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001365}
1366
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001367struct kgsl_mmu_ops iommu_ops = {
1368 .mmu_init = kgsl_iommu_init,
1369 .mmu_close = kgsl_iommu_close,
1370 .mmu_start = kgsl_iommu_start,
1371 .mmu_stop = kgsl_iommu_stop,
1372 .mmu_setstate = kgsl_iommu_setstate,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001373 .mmu_device_setstate = kgsl_iommu_default_setstate,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001374 .mmu_pagefault = NULL,
1375 .mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -06001376 .mmu_enable_clk = kgsl_iommu_enable_clk,
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001377 .mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
Shubhraprakash Dasfce27362012-05-09 17:44:14 -06001378 .mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001379 .mmu_get_reg_gpuaddr = kgsl_iommu_get_reg_gpuaddr,
1380 .mmu_get_num_iommu_units = kgsl_iommu_get_num_iommu_units,
1381 .mmu_pt_equal = kgsl_iommu_pt_equal,
1382 .mmu_get_pt_base_addr = kgsl_iommu_get_pt_base_addr,
Tarun Karra9c070822012-11-27 16:43:51 -07001383 .mmu_sync_lock = kgsl_iommu_sync_lock,
1384 .mmu_sync_unlock = kgsl_iommu_sync_unlock,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001385};
1386
1387struct kgsl_mmu_pt_ops iommu_pt_ops = {
1388 .mmu_map = kgsl_iommu_map,
1389 .mmu_unmap = kgsl_iommu_unmap,
1390 .mmu_create_pagetable = kgsl_iommu_create_pagetable,
1391 .mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001392};