blob: a14397143a3c169a0d5408dd00742566fe516230 [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;
113 unsigned int no_page_fault_log;
Jordan Crouse95b68472012-05-25 10:25:01 -0600114
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700115 ret = get_iommu_unit(dev, &mmu, &iommu_unit);
116 if (ret)
117 goto done;
118 iommu_dev = get_iommu_device(iommu_unit, dev);
Jordan Crouse95b68472012-05-25 10:25:01 -0600119 if (!iommu_dev) {
120 KGSL_CORE_ERR("Invalid IOMMU device %p\n", dev);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700121 ret = -ENOSYS;
122 goto done;
Jordan Crouse95b68472012-05-25 10:25:01 -0600123 }
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700124 iommu = mmu->priv;
Tarun Karrab8107322013-02-07 13:46:02 -0800125 device = mmu->device;
Jordan Crouse95b68472012-05-25 10:25:01 -0600126
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700127 ptbase = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
Shubhraprakash Das190553a2012-06-11 15:17:59 -0600128 iommu_dev->ctx_id, TTBR0);
Jordan Crouse95b68472012-05-25 10:25:01 -0600129
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700130 fsr = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
Jordan Crouse95b68472012-05-25 10:25:01 -0600131 iommu_dev->ctx_id, FSR);
132
Tarun Karrab8107322013-02-07 13:46:02 -0800133 no_page_fault_log = kgsl_mmu_log_fault_addr(mmu, ptbase, addr);
134
135 if (!no_page_fault_log) {
136 KGSL_MEM_CRIT(iommu_dev->kgsldev,
137 "GPU PAGE FAULT: addr = %lX pid = %d\n",
138 addr, kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase));
139 KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
140 iommu_dev->ctx_id, fsr);
141 }
Jordan Crouse95b68472012-05-25 10:25:01 -0600142
Shubhraprakash Das2747cf62012-09-27 23:05:43 -0700143 mmu->fault = 1;
144 iommu_dev->fault = 1;
145
Jordan Crouse95b68472012-05-25 10:25:01 -0600146 trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700147 kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase), 0);
Jordan Crouse95b68472012-05-25 10:25:01 -0600148
Shubhraprakash Das2747cf62012-09-27 23:05:43 -0700149 /*
150 * We do not want the h/w to resume fetching data from an iommu unit
151 * that has faulted, this is better for debugging as it will stall
152 * the GPU and trigger a snapshot. To stall the transaction return
153 * EBUSY error.
154 */
155 ret = -EBUSY;
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700156done:
157 return ret;
Jordan Crouse95b68472012-05-25 10:25:01 -0600158}
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600159
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600160/*
161 * kgsl_iommu_disable_clk - Disable iommu clocks
162 * @mmu - Pointer to mmu structure
163 *
164 * Disables iommu clocks
165 * Return - void
166 */
167static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu)
168{
169 struct kgsl_iommu *iommu = mmu->priv;
170 struct msm_iommu_drvdata *iommu_drvdata;
171 int i, j;
172
173 for (i = 0; i < iommu->unit_count; i++) {
174 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
175 for (j = 0; j < iommu_unit->dev_count; j++) {
176 if (!iommu_unit->dev[j].clk_enabled)
177 continue;
178 iommu_drvdata = dev_get_drvdata(
179 iommu_unit->dev[j].dev->parent);
Shubhraprakash Das102aac52012-08-16 22:12:27 -0700180 if (iommu_drvdata->aclk)
181 clk_disable_unprepare(iommu_drvdata->aclk);
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600182 if (iommu_drvdata->clk)
183 clk_disable_unprepare(iommu_drvdata->clk);
184 clk_disable_unprepare(iommu_drvdata->pclk);
185 iommu_unit->dev[j].clk_enabled = false;
186 }
187 }
188}
189
190/*
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600191 * kgsl_iommu_disable_clk_event - An event function that is executed when
192 * the required timestamp is reached. It disables the IOMMU clocks if
193 * the timestamp on which the clocks can be disabled has expired.
194 * @device - The kgsl device pointer
195 * @data - The data passed during event creation, it is the MMU pointer
196 * @id - Context ID, should always be KGSL_MEMSTORE_GLOBAL
197 * @ts - The current timestamp that has expired for the device
198 *
199 * Disables IOMMU clocks if timestamp has expired
200 * Return - void
201 */
202static void kgsl_iommu_clk_disable_event(struct kgsl_device *device, void *data,
203 unsigned int id, unsigned int ts)
204{
205 struct kgsl_mmu *mmu = data;
206 struct kgsl_iommu *iommu = mmu->priv;
207
208 if (!iommu->clk_event_queued) {
209 if (0 > timestamp_cmp(ts, iommu->iommu_last_cmd_ts))
210 KGSL_DRV_ERR(device,
211 "IOMMU disable clock event being cancelled, "
212 "iommu_last_cmd_ts: %x, retired ts: %x\n",
213 iommu->iommu_last_cmd_ts, ts);
214 return;
215 }
216
217 if (0 <= timestamp_cmp(ts, iommu->iommu_last_cmd_ts)) {
218 kgsl_iommu_disable_clk(mmu);
219 iommu->clk_event_queued = false;
220 } else {
221 /* add new event to fire when ts is reached, this can happen
222 * if we queued an event and someone requested the clocks to
223 * be disbaled on a later timestamp */
224 if (kgsl_add_event(device, id, iommu->iommu_last_cmd_ts,
225 kgsl_iommu_clk_disable_event, mmu, mmu)) {
226 KGSL_DRV_ERR(device,
227 "Failed to add IOMMU disable clk event\n");
228 iommu->clk_event_queued = false;
229 }
230 }
231}
232
233/*
234 * kgsl_iommu_disable_clk_on_ts - Sets up event to disable IOMMU clocks
235 * @mmu - The kgsl MMU pointer
236 * @ts - Timestamp on which the clocks should be disabled
237 * @ts_valid - Indicates whether ts parameter is valid, if this parameter
238 * is false then it means that the calling function wants to disable the
239 * IOMMU clocks immediately without waiting for any timestamp
240 *
241 * Creates an event to disable the IOMMU clocks on timestamp and if event
242 * already exists then updates the timestamp of disabling the IOMMU clocks
243 * with the passed in ts if it is greater than the current value at which
244 * the clocks will be disabled
245 * Return - void
246 */
247static void
248kgsl_iommu_disable_clk_on_ts(struct kgsl_mmu *mmu, unsigned int ts,
249 bool ts_valid)
250{
251 struct kgsl_iommu *iommu = mmu->priv;
252
253 if (iommu->clk_event_queued) {
254 if (ts_valid && (0 <
255 timestamp_cmp(ts, iommu->iommu_last_cmd_ts)))
256 iommu->iommu_last_cmd_ts = ts;
257 } else {
258 if (ts_valid) {
259 iommu->iommu_last_cmd_ts = ts;
260 iommu->clk_event_queued = true;
261 if (kgsl_add_event(mmu->device, KGSL_MEMSTORE_GLOBAL,
262 ts, kgsl_iommu_clk_disable_event, mmu, mmu)) {
263 KGSL_DRV_ERR(mmu->device,
264 "Failed to add IOMMU disable clk event\n");
265 iommu->clk_event_queued = false;
266 }
267 } else {
268 kgsl_iommu_disable_clk(mmu);
269 }
270 }
271}
272
273/*
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600274 * kgsl_iommu_enable_clk - Enable iommu clocks
275 * @mmu - Pointer to mmu structure
276 * @ctx_id - The context bank whose clocks are to be turned on
277 *
278 * Enables iommu clocks of a given context
279 * Return: 0 on success else error code
280 */
281static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu,
282 int ctx_id)
283{
284 int ret = 0;
285 int i, j;
286 struct kgsl_iommu *iommu = mmu->priv;
287 struct msm_iommu_drvdata *iommu_drvdata;
288
289 for (i = 0; i < iommu->unit_count; i++) {
290 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
291 for (j = 0; j < iommu_unit->dev_count; j++) {
292 if (iommu_unit->dev[j].clk_enabled ||
293 ctx_id != iommu_unit->dev[j].ctx_id)
294 continue;
295 iommu_drvdata =
296 dev_get_drvdata(iommu_unit->dev[j].dev->parent);
297 ret = clk_prepare_enable(iommu_drvdata->pclk);
298 if (ret)
299 goto done;
300 if (iommu_drvdata->clk) {
301 ret = clk_prepare_enable(iommu_drvdata->clk);
302 if (ret) {
303 clk_disable_unprepare(
304 iommu_drvdata->pclk);
305 goto done;
306 }
307 }
Shubhraprakash Das102aac52012-08-16 22:12:27 -0700308 if (iommu_drvdata->aclk) {
309 ret = clk_prepare_enable(iommu_drvdata->aclk);
310 if (ret) {
311 if (iommu_drvdata->clk)
312 clk_disable_unprepare(
313 iommu_drvdata->clk);
314 clk_disable_unprepare(
315 iommu_drvdata->pclk);
316 goto done;
317 }
318 }
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600319 iommu_unit->dev[j].clk_enabled = true;
320 }
321 }
322done:
323 if (ret)
324 kgsl_iommu_disable_clk(mmu);
325 return ret;
326}
327
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600328/*
329 * kgsl_iommu_pt_equal - Check if pagetables are equal
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700330 * @mmu - Pointer to mmu structure
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600331 * @pt - Pointer to pagetable
332 * @pt_base - Address of a pagetable that the IOMMU register is
333 * programmed with
334 *
335 * Checks whether the pt_base is equal to the base address of
336 * the pagetable which is contained in the pt structure
337 * Return - Non-zero if the pagetable addresses are equal else 0
338 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700339static int kgsl_iommu_pt_equal(struct kgsl_mmu *mmu,
340 struct kgsl_pagetable *pt,
341 unsigned int pt_base)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600342{
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700343 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600344 struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
345 unsigned int domain_ptbase = iommu_pt ?
346 iommu_get_pt_base_addr(iommu_pt->domain) : 0;
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600347 /* Only compare the valid address bits of the pt_base */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700348 domain_ptbase &=
349 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
350 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
351
352 pt_base &=
353 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
354 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
355
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600356 return domain_ptbase && pt_base &&
357 (domain_ptbase == pt_base);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600358}
359
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600360/*
361 * kgsl_iommu_destroy_pagetable - Free up reaources help by a pagetable
362 * @mmu_specific_pt - Pointer to pagetable which is to be freed
363 *
364 * Return - void
365 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600366static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
367{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600368 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
369 if (iommu_pt->domain)
370 iommu_domain_free(iommu_pt->domain);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600371 kfree(iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600372}
373
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600374/*
375 * kgsl_iommu_create_pagetable - Create a IOMMU pagetable
376 *
377 * Allocate memory to hold a pagetable and allocate the IOMMU
378 * domain which is the actual IOMMU pagetable
379 * Return - void
380 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600381void *kgsl_iommu_create_pagetable(void)
382{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600383 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600384
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600385 iommu_pt = kzalloc(sizeof(struct kgsl_iommu_pt), GFP_KERNEL);
386 if (!iommu_pt) {
387 KGSL_CORE_ERR("kzalloc(%d) failed\n",
388 sizeof(struct kgsl_iommu_pt));
389 return NULL;
390 }
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700391 /* L2 redirect is not stable on IOMMU v2 */
392 if (msm_soc_version_supports_iommu_v1())
393 iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700394 MSM_IOMMU_DOMAIN_PT_CACHEABLE);
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700395 else
396 iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
397 0);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600398 if (!iommu_pt->domain) {
399 KGSL_CORE_ERR("Failed to create iommu domain\n");
400 kfree(iommu_pt);
401 return NULL;
Jordan Crouse95b68472012-05-25 10:25:01 -0600402 } else {
403 iommu_set_fault_handler(iommu_pt->domain,
404 kgsl_iommu_fault_handler);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600405 }
Jordan Crouse95b68472012-05-25 10:25:01 -0600406
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600407 return iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600408}
409
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600410/*
411 * kgsl_detach_pagetable_iommu_domain - Detach the IOMMU unit from a
412 * pagetable
413 * @mmu - Pointer to the device mmu structure
414 * @priv - Flag indicating whether the private or user context is to be
415 * detached
416 *
417 * Detach the IOMMU unit with the domain that is contained in the
418 * hwpagetable of the given mmu. After detaching the IOMMU unit is not
419 * in use because the PTBR will not be set after a detach
420 * Return - void
421 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600422static void kgsl_detach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
423{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600424 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600425 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600426 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600427
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600428 for (i = 0; i < iommu->unit_count; i++) {
429 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600430 iommu_pt = mmu->defaultpagetable->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600431 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600432 /*
433 * If there is a 2nd default pagetable then priv domain
434 * is attached with this pagetable
435 */
436 if (mmu->priv_bank_table &&
437 (KGSL_IOMMU_CONTEXT_PRIV == j))
438 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600439 if (iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600440 iommu_detach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600441 iommu_unit->dev[j].dev);
442 iommu_unit->dev[j].attached = false;
443 KGSL_MEM_INFO(mmu->device, "iommu %p detached "
444 "from user dev of MMU: %p\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600445 iommu_pt->domain, mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600446 }
447 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600448 }
449}
450
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600451/*
452 * kgsl_attach_pagetable_iommu_domain - Attach the IOMMU unit to a
453 * pagetable, i.e set the IOMMU's PTBR to the pagetable address and
454 * setup other IOMMU registers for the device so that it becomes
455 * active
456 * @mmu - Pointer to the device mmu structure
457 * @priv - Flag indicating whether the private or user context is to be
458 * attached
459 *
460 * Attach the IOMMU unit with the domain that is contained in the
461 * hwpagetable of the given mmu.
462 * Return - 0 on success else error code
463 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600464static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
465{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600466 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600467 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600468 int i, j, ret = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600469
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600470 /*
471 * Loop through all the iommu devcies under all iommu units and
472 * attach the domain
473 */
474 for (i = 0; i < iommu->unit_count; i++) {
475 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600476 iommu_pt = mmu->defaultpagetable->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600477 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600478 /*
479 * If there is a 2nd default pagetable then priv domain
480 * is attached to this pagetable
481 */
482 if (mmu->priv_bank_table &&
483 (KGSL_IOMMU_CONTEXT_PRIV == j))
484 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600485 if (!iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600486 ret = iommu_attach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600487 iommu_unit->dev[j].dev);
488 if (ret) {
489 KGSL_MEM_ERR(mmu->device,
490 "Failed to attach device, err %d\n",
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700491 ret);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600492 goto done;
493 }
494 iommu_unit->dev[j].attached = true;
495 KGSL_MEM_INFO(mmu->device,
496 "iommu pt %p attached to dev %p, ctx_id %d\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600497 iommu_pt->domain, iommu_unit->dev[j].dev,
498 iommu_unit->dev[j].ctx_id);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700499 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600500 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600501 }
502done:
503 return ret;
504}
505
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600506/*
507 * _get_iommu_ctxs - Get device pointer to IOMMU contexts
508 * @mmu - Pointer to mmu device
509 * data - Pointer to the platform data containing information about
510 * iommu devices for one iommu unit
511 * unit_id - The IOMMU unit number. This is not a specific ID but just
512 * a serial number. The serial numbers are treated as ID's of the
513 * IOMMU units
514 *
515 * Return - 0 on success else error code
516 */
517static int _get_iommu_ctxs(struct kgsl_mmu *mmu,
518 struct kgsl_device_iommu_data *data, unsigned int unit_id)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700519{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600520 struct kgsl_iommu *iommu = mmu->priv;
521 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id];
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700522 int i;
523
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600524 if (data->iommu_ctx_count > KGSL_IOMMU_MAX_DEVS_PER_UNIT) {
525 KGSL_CORE_ERR("Too many iommu devices defined for an "
526 "IOMMU unit\n");
527 return -EINVAL;
528 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700529
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600530 for (i = 0; i < data->iommu_ctx_count; i++) {
531 if (!data->iommu_ctxs[i].iommu_ctx_name)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700532 continue;
533
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600534 iommu_unit->dev[iommu_unit->dev_count].dev =
535 msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
536 if (iommu_unit->dev[iommu_unit->dev_count].dev == NULL) {
537 KGSL_CORE_ERR("Failed to get iommu dev handle for "
538 "device %s\n", data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700539 return -EINVAL;
540 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600541 if (KGSL_IOMMU_CONTEXT_USER != data->iommu_ctxs[i].ctx_id &&
542 KGSL_IOMMU_CONTEXT_PRIV != data->iommu_ctxs[i].ctx_id) {
543 KGSL_CORE_ERR("Invalid context ID defined: %d\n",
544 data->iommu_ctxs[i].ctx_id);
545 return -EINVAL;
546 }
547 iommu_unit->dev[iommu_unit->dev_count].ctx_id =
548 data->iommu_ctxs[i].ctx_id;
Jordan Crouse95b68472012-05-25 10:25:01 -0600549 iommu_unit->dev[iommu_unit->dev_count].kgsldev = mmu->device;
550
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600551 KGSL_DRV_INFO(mmu->device,
552 "Obtained dev handle %p for iommu context %s\n",
553 iommu_unit->dev[iommu_unit->dev_count].dev,
554 data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700555
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600556 iommu_unit->dev_count++;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700557 }
558
559 return 0;
560}
561
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600562/*
Tarun Karra9c070822012-11-27 16:43:51 -0700563 * kgsl_get_sync_lock - Init Sync Lock between GPU and CPU
564 * @mmu - Pointer to mmu device
565 *
566 * Return - 0 on success else error code
567 */
568static int kgsl_iommu_init_sync_lock(struct kgsl_mmu *mmu)
569{
570 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
571 int status = 0;
572 struct kgsl_pagetable *pagetable = NULL;
573 uint32_t lock_gpu_addr = 0;
574 uint32_t lock_phy_addr = 0;
575 uint32_t page_offset = 0;
576
577 iommu->sync_lock_initialized = 0;
578
579 if (!(mmu->flags & KGSL_MMU_FLAGS_IOMMU_SYNC)) {
580 KGSL_DRV_ERR(mmu->device,
581 "The GPU microcode does not support IOMMUv1 sync opcodes\n");
582 return -ENXIO;
583 }
584
585 /* Get the physical address of the Lock variables */
586 lock_phy_addr = (msm_iommu_lock_initialize()
587 - MSM_SHARED_RAM_BASE + msm_shared_ram_phys);
588
589 if (!lock_phy_addr) {
590 KGSL_DRV_ERR(mmu->device,
591 "GPU CPU sync lock is not supported by kernel\n");
592 return -ENXIO;
593 }
594
595 /* Align the physical address to PAGE boundary and store the offset */
596 page_offset = (lock_phy_addr & (PAGE_SIZE - 1));
597 lock_phy_addr = (lock_phy_addr & ~(PAGE_SIZE - 1));
598 iommu->sync_lock_desc.physaddr = (unsigned int)lock_phy_addr;
599
600 iommu->sync_lock_desc.size =
601 PAGE_ALIGN(sizeof(kgsl_iommu_sync_lock_vars));
602 status = memdesc_sg_phys(&iommu->sync_lock_desc,
603 iommu->sync_lock_desc.physaddr,
604 iommu->sync_lock_desc.size);
605
606 if (status)
607 return status;
608
609 /* Map Lock variables to GPU pagetable */
Jordan Crousedc67dfb2012-10-25 09:41:46 -0600610 iommu->sync_lock_desc.priv |= KGSL_MEMDESC_GLOBAL;
Tarun Karra9c070822012-11-27 16:43:51 -0700611
612 pagetable = mmu->priv_bank_table ? mmu->priv_bank_table :
613 mmu->defaultpagetable;
614
615 status = kgsl_mmu_map(pagetable, &iommu->sync_lock_desc,
616 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
617
618 if (status) {
619 kgsl_mmu_unmap(pagetable, &iommu->sync_lock_desc);
Jordan Crousedc67dfb2012-10-25 09:41:46 -0600620 iommu->sync_lock_desc.priv &= ~KGSL_MEMDESC_GLOBAL;
Tarun Karra9c070822012-11-27 16:43:51 -0700621 return status;
622 }
623
624 /* Store Lock variables GPU address */
625 lock_gpu_addr = (iommu->sync_lock_desc.gpuaddr + page_offset);
626
627 kgsl_iommu_sync_lock_vars.flag[PROC_APPS] = (lock_gpu_addr +
628 (offsetof(struct remote_iommu_petersons_spinlock,
629 flag[PROC_APPS])));
630 kgsl_iommu_sync_lock_vars.flag[PROC_GPU] = (lock_gpu_addr +
631 (offsetof(struct remote_iommu_petersons_spinlock,
632 flag[PROC_GPU])));
633 kgsl_iommu_sync_lock_vars.turn = (lock_gpu_addr +
634 (offsetof(struct remote_iommu_petersons_spinlock, turn)));
635
636 iommu->sync_lock_vars = &kgsl_iommu_sync_lock_vars;
637
638 /* Flag Sync Lock is Initialized */
639 iommu->sync_lock_initialized = 1;
640
641 return status;
642}
643
644/*
645 * kgsl_iommu_sync_lock - Acquire Sync Lock between GPU and CPU
646 * @mmu - Pointer to mmu device
647 * @cmds - Pointer to array of commands
648 *
649 * Return - int - number of commands.
650 */
651inline unsigned int kgsl_iommu_sync_lock(struct kgsl_mmu *mmu,
652 unsigned int *cmds)
653{
654 struct kgsl_device *device = mmu->device;
655 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
656 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
657 struct remote_iommu_petersons_spinlock *lock_vars =
658 iommu->sync_lock_vars;
659 unsigned int *start = cmds;
660
661 if (!iommu->sync_lock_initialized)
662 return 0;
663
664 *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
665 *cmds++ = lock_vars->flag[PROC_GPU];
666 *cmds++ = 1;
667
668 cmds += adreno_add_idle_cmds(adreno_dev, cmds);
669
670 *cmds++ = cp_type3_packet(CP_WAIT_REG_MEM, 5);
671 /* MEM SPACE = memory, FUNCTION = equals */
672 *cmds++ = 0x13;
673 *cmds++ = lock_vars->flag[PROC_GPU];
674 *cmds++ = 0x1;
675 *cmds++ = 0x1;
676 *cmds++ = 0x1;
677
678 *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
679 *cmds++ = lock_vars->turn;
680 *cmds++ = 0;
681
682 cmds += adreno_add_idle_cmds(adreno_dev, cmds);
683
684 *cmds++ = cp_type3_packet(CP_WAIT_REG_MEM, 5);
685 /* MEM SPACE = memory, FUNCTION = equals */
686 *cmds++ = 0x13;
687 *cmds++ = lock_vars->flag[PROC_GPU];
688 *cmds++ = 0x1;
689 *cmds++ = 0x1;
690 *cmds++ = 0x1;
691
692 *cmds++ = cp_type3_packet(CP_TEST_TWO_MEMS, 3);
693 *cmds++ = lock_vars->flag[PROC_APPS];
694 *cmds++ = lock_vars->turn;
695 *cmds++ = 0;
696
697 cmds += adreno_add_idle_cmds(adreno_dev, cmds);
698
699 return cmds - start;
700}
701
702/*
703 * kgsl_iommu_sync_lock - Release Sync Lock between GPU and CPU
704 * @mmu - Pointer to mmu device
705 * @cmds - Pointer to array of commands
706 *
707 * Return - int - number of commands.
708 */
709inline unsigned int kgsl_iommu_sync_unlock(struct kgsl_mmu *mmu,
710 unsigned int *cmds)
711{
712 struct kgsl_device *device = mmu->device;
713 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
714 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
715 struct remote_iommu_petersons_spinlock *lock_vars =
716 iommu->sync_lock_vars;
717 unsigned int *start = cmds;
718
719 if (!iommu->sync_lock_initialized)
720 return 0;
721
722 *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
723 *cmds++ = lock_vars->flag[PROC_GPU];
724 *cmds++ = 0;
725
726 *cmds++ = cp_type3_packet(CP_WAIT_REG_MEM, 5);
727 /* MEM SPACE = memory, FUNCTION = equals */
728 *cmds++ = 0x13;
729 *cmds++ = lock_vars->flag[PROC_GPU];
730 *cmds++ = 0x0;
731 *cmds++ = 0x1;
732 *cmds++ = 0x1;
733
734 cmds += adreno_add_idle_cmds(adreno_dev, cmds);
735
736 return cmds - start;
737}
738
739/*
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600740 * kgsl_get_iommu_ctxt - Get device pointer to IOMMU contexts
741 * @mmu - Pointer to mmu device
742 *
743 * Get the device pointers for the IOMMU user and priv contexts of the
744 * kgsl device
745 * Return - 0 on success else error code
746 */
747static int kgsl_get_iommu_ctxt(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600748{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600749 struct platform_device *pdev =
750 container_of(mmu->device->parentdev, struct platform_device,
751 dev);
752 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
753 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700754 int i, ret = 0;
755
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600756 /* Go through the IOMMU data and get all the context devices */
757 if (KGSL_IOMMU_MAX_UNITS < pdata_dev->iommu_count) {
758 KGSL_CORE_ERR("Too many IOMMU units defined\n");
759 ret = -EINVAL;
760 goto done;
761 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700762
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600763 for (i = 0; i < pdata_dev->iommu_count; i++) {
764 ret = _get_iommu_ctxs(mmu, &pdata_dev->iommu_data[i], i);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700765 if (ret)
766 break;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600767 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600768 iommu->unit_count = pdata_dev->iommu_count;
769done:
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700770 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600771}
772
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600773/*
774 * kgsl_set_register_map - Map the IOMMU regsiters in the memory descriptors
775 * of the respective iommu units
776 * @mmu - Pointer to mmu structure
777 *
778 * Return - 0 on success else error code
779 */
780static int kgsl_set_register_map(struct kgsl_mmu *mmu)
781{
782 struct platform_device *pdev =
783 container_of(mmu->device->parentdev, struct platform_device,
784 dev);
785 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
786 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
787 struct kgsl_iommu_unit *iommu_unit;
788 int i = 0, ret = 0;
789
790 for (; i < pdata_dev->iommu_count; i++) {
791 struct kgsl_device_iommu_data data = pdata_dev->iommu_data[i];
792 iommu_unit = &iommu->iommu_units[i];
793 /* set up the IOMMU register map for the given IOMMU unit */
794 if (!data.physstart || !data.physend) {
795 KGSL_CORE_ERR("The register range for IOMMU unit not"
796 " specified\n");
797 ret = -EINVAL;
798 goto err;
799 }
800 iommu_unit->reg_map.hostptr = ioremap(data.physstart,
801 data.physend - data.physstart + 1);
802 if (!iommu_unit->reg_map.hostptr) {
803 KGSL_CORE_ERR("Failed to map SMMU register address "
804 "space from %x to %x\n", data.physstart,
805 data.physend - data.physstart + 1);
806 ret = -ENOMEM;
807 i--;
808 goto err;
809 }
810 iommu_unit->reg_map.size = data.physend - data.physstart + 1;
811 iommu_unit->reg_map.physaddr = data.physstart;
Rajeev Kulkarni55863722012-11-21 23:40:05 -0800812 ret = memdesc_sg_phys(&iommu_unit->reg_map, data.physstart,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600813 iommu_unit->reg_map.size);
Rajeev Kulkarni55863722012-11-21 23:40:05 -0800814 if (ret)
815 goto err;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600816 }
817 iommu->unit_count = pdata_dev->iommu_count;
818 return ret;
819err:
820 /* Unmap any mapped IOMMU regions */
821 for (; i >= 0; i--) {
822 iommu_unit = &iommu->iommu_units[i];
823 iounmap(iommu_unit->reg_map.hostptr);
824 iommu_unit->reg_map.size = 0;
825 iommu_unit->reg_map.physaddr = 0;
826 }
827 return ret;
828}
829
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600830/*
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700831 * kgsl_iommu_get_pt_base_addr - Get the address of the pagetable that the
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600832 * IOMMU ttbr0 register is programmed with
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700833 * @mmu - Pointer to mmu
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600834 * @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
835 *
836 * Return - actual pagetable address that the ttbr0 register is programmed
837 * with
838 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700839static unsigned int kgsl_iommu_get_pt_base_addr(struct kgsl_mmu *mmu,
840 struct kgsl_pagetable *pt)
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600841{
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700842 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600843 struct kgsl_iommu_pt *iommu_pt = pt->priv;
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700844 return iommu_get_pt_base_addr(iommu_pt->domain) &
845 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
846 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600847}
848
849/*
850 * kgsl_iommu_get_pt_lsb - Return the lsb of the ttbr0 IOMMU register
851 * @mmu - Pointer to mmu structure
852 * @hostptr - Pointer to the IOMMU register map. This is used to match
853 * the iommu device whose lsb value is to be returned
854 * @ctx_id - The context bank whose lsb valus is to be returned
855 * Return - returns the lsb which is the last 14 bits of the ttbr0 IOMMU
856 * register. ttbr0 is the actual PTBR for of the IOMMU. The last 14 bits
857 * are only programmed once in the beginning when a domain is attached
858 * does not change.
859 */
860static int kgsl_iommu_get_pt_lsb(struct kgsl_mmu *mmu,
861 unsigned int unit_id,
862 enum kgsl_iommu_context_id ctx_id)
863{
864 struct kgsl_iommu *iommu = mmu->priv;
865 int i, j;
866 for (i = 0; i < iommu->unit_count; i++) {
867 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
868 for (j = 0; j < iommu_unit->dev_count; j++)
869 if (unit_id == i &&
870 ctx_id == iommu_unit->dev[j].ctx_id)
871 return iommu_unit->dev[j].pt_lsb;
872 }
873 return 0;
874}
875
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600876static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600877 struct kgsl_pagetable *pagetable,
878 unsigned int context_id)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600879{
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600880 if (mmu->flags & KGSL_FLAGS_STARTED) {
881 /* page table not current, then setup mmu to use new
882 * specified page table
883 */
884 if (mmu->hwpagetable != pagetable) {
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600885 unsigned int flags = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600886 mmu->hwpagetable = pagetable;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600887 flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
Shubhraprakash Das8649fa52012-07-26 15:49:46 -0700888 mmu->device->id) |
889 KGSL_MMUFLAGS_TLBFLUSH;
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600890 kgsl_setstate(mmu, context_id,
891 KGSL_MMUFLAGS_PTUPDATE | flags);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600892 }
893 }
894}
895
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600896static int kgsl_iommu_init(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600897{
898 /*
899 * intialize device mmu
900 *
901 * call this with the global lock held
902 */
903 int status = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600904 struct kgsl_iommu *iommu;
905
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600906 iommu = kzalloc(sizeof(struct kgsl_iommu), GFP_KERNEL);
907 if (!iommu) {
908 KGSL_CORE_ERR("kzalloc(%d) failed\n",
909 sizeof(struct kgsl_iommu));
910 return -ENOMEM;
911 }
912
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600913 mmu->priv = iommu;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600914 status = kgsl_get_iommu_ctxt(mmu);
915 if (status)
916 goto done;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600917 status = kgsl_set_register_map(mmu);
918 if (status)
919 goto done;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600920
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700921 iommu->iommu_reg_list = kgsl_iommuv1_reg;
922 iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
923
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700924 if (msm_soc_version_supports_iommu_v1()) {
925 iommu->iommu_reg_list = kgsl_iommuv1_reg;
926 iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
927 } else {
928 iommu->iommu_reg_list = kgsl_iommuv2_reg;
929 iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V2;
930 }
931
Shubhraprakash Dase9541a32012-05-09 22:25:55 -0600932 /* A nop is required in an indirect buffer when switching
933 * pagetables in-stream */
934 kgsl_sharedmem_writel(&mmu->setstate_memory,
935 KGSL_IOMMU_SETSTATE_NOP_OFFSET,
936 cp_nop_packet(1));
937
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600938 dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600939 __func__);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600940done:
941 if (status) {
942 kfree(iommu);
943 mmu->priv = NULL;
944 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600945 return status;
946}
947
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600948/*
949 * kgsl_iommu_setup_defaultpagetable - Setup the initial defualtpagetable
950 * for iommu. This function is only called once during first start, successive
951 * start do not call this funciton.
952 * @mmu - Pointer to mmu structure
953 *
954 * Create the initial defaultpagetable and setup the iommu mappings to it
955 * Return - 0 on success else error code
956 */
957static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu)
958{
959 int status = 0;
960 int i = 0;
961 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600962 struct kgsl_pagetable *pagetable = NULL;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600963
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600964 /* If chip is not 8960 then we use the 2nd context bank for pagetable
965 * switching on the 3D side for which a separate table is allocated */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700966 if (!cpu_is_msm8960() && msm_soc_version_supports_iommu_v1()) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600967 mmu->priv_bank_table =
968 kgsl_mmu_getpagetable(KGSL_MMU_PRIV_BANK_TABLE_NAME);
969 if (mmu->priv_bank_table == NULL) {
970 status = -ENOMEM;
971 goto err;
972 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600973 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600974 mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
975 /* Return error if the default pagetable doesn't exist */
976 if (mmu->defaultpagetable == NULL) {
977 status = -ENOMEM;
978 goto err;
979 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600980 pagetable = mmu->priv_bank_table ? mmu->priv_bank_table :
981 mmu->defaultpagetable;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600982 /* Map the IOMMU regsiters to only defaultpagetable */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700983 if (msm_soc_version_supports_iommu_v1()) {
984 for (i = 0; i < iommu->unit_count; i++) {
985 iommu->iommu_units[i].reg_map.priv |=
Jordan Crousedc67dfb2012-10-25 09:41:46 -0600986 KGSL_MEMDESC_GLOBAL;
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700987 status = kgsl_mmu_map(pagetable,
988 &(iommu->iommu_units[i].reg_map),
989 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
990 if (status) {
991 iommu->iommu_units[i].reg_map.priv &=
Jordan Crousedc67dfb2012-10-25 09:41:46 -0600992 ~KGSL_MEMDESC_GLOBAL;
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700993 goto err;
994 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600995 }
996 }
997 return status;
998err:
999 for (i--; i >= 0; i--) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001000 kgsl_mmu_unmap(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001001 &(iommu->iommu_units[i].reg_map));
Jordan Crousedc67dfb2012-10-25 09:41:46 -06001002 iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMDESC_GLOBAL;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001003 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001004 if (mmu->priv_bank_table) {
1005 kgsl_mmu_putpagetable(mmu->priv_bank_table);
1006 mmu->priv_bank_table = NULL;
1007 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001008 if (mmu->defaultpagetable) {
1009 kgsl_mmu_putpagetable(mmu->defaultpagetable);
1010 mmu->defaultpagetable = NULL;
1011 }
1012 return status;
1013}
1014
Shubhraprakash Das1c528262012-04-26 17:38:13 -06001015static int kgsl_iommu_start(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001016{
Tarun Karra9c070822012-11-27 16:43:51 -07001017 struct kgsl_device *device = mmu->device;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001018 int status;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001019 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001020 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001021
1022 if (mmu->flags & KGSL_FLAGS_STARTED)
1023 return 0;
1024
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001025 if (mmu->defaultpagetable == NULL) {
1026 status = kgsl_iommu_setup_defaultpagetable(mmu);
1027 if (status)
1028 return -ENOMEM;
Tarun Karra9c070822012-11-27 16:43:51 -07001029
1030 /* Initialize the sync lock between GPU and CPU */
1031 if (msm_soc_version_supports_iommu_v1() &&
1032 (device->id == KGSL_DEVICE_3D0))
1033 kgsl_iommu_init_sync_lock(mmu);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001034 }
Tarun Karra9c070822012-11-27 16:43:51 -07001035
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001036 /* We use the GPU MMU to control access to IOMMU registers on 8960 with
1037 * a225, hence we still keep the MMU active on 8960 */
1038 if (cpu_is_msm8960()) {
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001039 struct kgsl_mh *mh = &(mmu->device->mh);
1040 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001);
1041 kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
1042 mh->mpu_base +
Shubhraprakash Das2b54b5f2012-08-08 18:21:36 -07001043 iommu->iommu_units[0].reg_map.gpuaddr);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001044 } else {
1045 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
1046 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001047
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001048 mmu->hwpagetable = mmu->defaultpagetable;
1049
1050 status = kgsl_attach_pagetable_iommu_domain(mmu);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001051 if (status) {
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -06001052 mmu->hwpagetable = NULL;
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001053 goto done;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -06001054 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001055 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001056 if (status) {
1057 KGSL_CORE_ERR("clk enable failed\n");
1058 goto done;
1059 }
1060 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
1061 if (status) {
1062 KGSL_CORE_ERR("clk enable failed\n");
1063 goto done;
1064 }
1065 /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as
1066 * that value should not change when we change pagetables, so while
1067 * changing pagetables we can use this lsb value of the pagetable w/o
1068 * having to read it again
1069 */
1070 for (i = 0; i < iommu->unit_count; i++) {
1071 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das2747cf62012-09-27 23:05:43 -07001072 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001073 iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(iommu,
1074 KGSL_IOMMU_GET_CTX_REG(iommu,
1075 iommu_unit,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001076 iommu_unit->dev[j].ctx_id,
1077 TTBR0));
Shubhraprakash Das2747cf62012-09-27 23:05:43 -07001078 }
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001079 }
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001080
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001081 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -06001082 mmu->flags |= KGSL_FLAGS_STARTED;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001083
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001084done:
1085 if (status) {
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001086 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001087 kgsl_detach_pagetable_iommu_domain(mmu);
1088 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001089 return status;
1090}
1091
1092static int
1093kgsl_iommu_unmap(void *mmu_specific_pt,
Shubhraprakash Das0c811262012-06-06 23:22:19 -06001094 struct kgsl_memdesc *memdesc,
1095 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001096{
1097 int ret;
Jordan Crouse3c86ca82012-05-21 08:41:52 -06001098 unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001099 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001100
1101 /* All GPU addresses as assigned are page aligned, but some
1102 functions purturb the gpuaddr with an offset, so apply the
1103 mask here to make sure we have the right address */
1104
1105 unsigned int gpuaddr = memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK;
1106
1107 if (range == 0 || gpuaddr == 0)
1108 return 0;
1109
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001110 ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001111 if (ret)
1112 KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001113 "with err: %d\n", iommu_pt->domain, gpuaddr,
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001114 range, ret);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001115
Shubhraprakash Das0c811262012-06-06 23:22:19 -06001116#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
1117 /*
1118 * Flushing only required if per process pagetables are used. With
1119 * global case, flushing will happen inside iommu_map function
1120 */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -07001121 if (!ret && msm_soc_version_supports_iommu_v1())
Shubhraprakash Das0c811262012-06-06 23:22:19 -06001122 *tlb_flags = UINT_MAX;
1123#endif
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001124 return 0;
1125}
1126
1127static int
1128kgsl_iommu_map(void *mmu_specific_pt,
1129 struct kgsl_memdesc *memdesc,
Shubhraprakash Dasf764e462012-04-26 15:38:09 -06001130 unsigned int protflags,
1131 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001132{
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001133 int ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001134 unsigned int iommu_virt_addr;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001135 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Jordan Crouse3c86ca82012-05-21 08:41:52 -06001136 int size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001137
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001138 BUG_ON(NULL == iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001139
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001140
Jordan Croused17e9aa2011-10-12 16:57:48 -06001141 iommu_virt_addr = memdesc->gpuaddr;
1142
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001143 ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
Jordan Crouse3c86ca82012-05-21 08:41:52 -06001144 size, (IOMMU_READ | IOMMU_WRITE));
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001145 if (ret) {
1146 KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001147 "failed with err: %d\n", iommu_pt->domain,
Jordan Crouse3c86ca82012-05-21 08:41:52 -06001148 iommu_virt_addr, memdesc->sg, size,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001149 (IOMMU_READ | IOMMU_WRITE), ret);
Shubhraprakash Das08894b92011-10-14 11:42:25 -06001150 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001151 }
1152
1153 return ret;
1154}
1155
Shubhraprakash Das79447952012-04-26 18:12:23 -06001156static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001157{
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001158 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das2747cf62012-09-27 23:05:43 -07001159 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001160 /*
1161 * stop device mmu
1162 *
1163 * call this with the global lock held
1164 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001165
1166 if (mmu->flags & KGSL_FLAGS_STARTED) {
1167 /* detach iommu attachment */
1168 kgsl_detach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -06001169 mmu->hwpagetable = NULL;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001170
1171 mmu->flags &= ~KGSL_FLAGS_STARTED;
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001172
Shubhraprakash Das2747cf62012-09-27 23:05:43 -07001173 if (mmu->fault) {
1174 for (i = 0; i < iommu->unit_count; i++) {
1175 struct kgsl_iommu_unit *iommu_unit =
1176 &iommu->iommu_units[i];
1177 for (j = 0; j < iommu_unit->dev_count; j++) {
1178 if (iommu_unit->dev[j].fault) {
1179 kgsl_iommu_enable_clk(mmu, j);
1180 KGSL_IOMMU_SET_CTX_REG(iommu,
1181 iommu_unit,
1182 iommu_unit->dev[j].ctx_id,
1183 RESUME, 1);
1184 iommu_unit->dev[j].fault = 0;
1185 }
1186 }
1187 }
1188 mmu->fault = 0;
1189 }
1190 }
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001191 /* switch off MMU clocks and cancel any events it has queued */
1192 iommu->clk_event_queued = false;
1193 kgsl_cancel_events(mmu->device, mmu);
1194 kgsl_iommu_disable_clk(mmu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001195}
1196
Shubhraprakash Das1c528262012-04-26 17:38:13 -06001197static int kgsl_iommu_close(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001198{
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001199 struct kgsl_iommu *iommu = mmu->priv;
1200 int i;
1201 for (i = 0; i < iommu->unit_count; i++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001202 struct kgsl_pagetable *pagetable = (mmu->priv_bank_table ?
1203 mmu->priv_bank_table : mmu->defaultpagetable);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001204 if (iommu->iommu_units[i].reg_map.gpuaddr)
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001205 kgsl_mmu_unmap(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -06001206 &(iommu->iommu_units[i].reg_map));
1207 if (iommu->iommu_units[i].reg_map.hostptr)
1208 iounmap(iommu->iommu_units[i].reg_map.hostptr);
1209 kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
1210 iommu->iommu_units[i].reg_map.sglen);
1211 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -06001212
1213 if (mmu->priv_bank_table)
1214 kgsl_mmu_putpagetable(mmu->priv_bank_table);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001215 if (mmu->defaultpagetable)
1216 kgsl_mmu_putpagetable(mmu->defaultpagetable);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001217 kfree(iommu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001218
1219 return 0;
1220}
1221
1222static unsigned int
Shubhraprakash Das1c528262012-04-26 17:38:13 -06001223kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001224{
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -06001225 unsigned int pt_base;
1226 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das64a745c2012-06-11 16:44:16 -06001227 /* We cannot enable or disable the clocks in interrupt context, this
1228 function is called from interrupt context if there is an axi error */
1229 if (in_interrupt())
1230 return 0;
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -06001231 /* Return the current pt base by reading IOMMU pt_base register */
1232 kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001233 pt_base = KGSL_IOMMU_GET_CTX_REG(iommu, (&iommu->iommu_units[0]),
1234 KGSL_IOMMU_CONTEXT_USER,
1235 TTBR0);
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001236 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001237 return pt_base &
1238 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
1239 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001240}
1241
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001242/*
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001243 * kgsl_iommu_default_setstate - Change the IOMMU pagetable or flush IOMMU tlb
1244 * of the primary context bank
1245 * @mmu - Pointer to mmu structure
1246 * @flags - Flags indicating whether pagetable has to chnage or tlb is to be
1247 * flushed or both
1248 *
1249 * Based on flags set the new pagetable fo the IOMMU unit or flush it's tlb or
1250 * do both by doing direct register writes to the IOMMu registers through the
1251 * cpu
1252 * Return - void
1253 */
1254static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
1255 uint32_t flags)
1256{
1257 struct kgsl_iommu *iommu = mmu->priv;
1258 int temp;
1259 int i;
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001260 unsigned int pt_base = kgsl_iommu_get_pt_base_addr(mmu,
1261 mmu->hwpagetable);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001262 unsigned int pt_val;
1263
1264 if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
1265 KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
1266 return;
1267 }
1268 /* Mask off the lsb of the pt base address since lsb will not change */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001269 pt_base &= (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
1270 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
1271
Tarun Karra9c070822012-11-27 16:43:51 -07001272 //if (msm_soc_version_supports_iommu_v1())
Shubhraprakash Dasee61e4d2012-11-27 17:07:44 -07001273 /* Acquire GPU-CPU sync Lock here */
1274 msm_iommu_lock();
1275
1276 if (flags & KGSL_MMUFLAGS_PTUPDATE) {
1277 if (!msm_soc_version_supports_iommu_v1())
1278 kgsl_idle(mmu->device);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001279 for (i = 0; i < iommu->unit_count; i++) {
1280 /* get the lsb value which should not change when
1281 * changing ttbr0 */
1282 pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
1283 KGSL_IOMMU_CONTEXT_USER);
1284 pt_val += pt_base;
1285
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001286 KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001287 KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
1288
1289 mb();
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001290 temp = KGSL_IOMMU_GET_CTX_REG(iommu,
1291 (&iommu->iommu_units[i]),
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001292 KGSL_IOMMU_CONTEXT_USER, TTBR0);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001293 }
1294 }
1295 /* Flush tlb */
1296 if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
1297 for (i = 0; i < iommu->unit_count; i++) {
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001298 KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
1299 KGSL_IOMMU_CONTEXT_USER, TLBIALL, 1);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001300 mb();
1301 }
1302 }
Tarun Karra9c070822012-11-27 16:43:51 -07001303
1304 /* Release GPU-CPU sync Lock here */
1305 msm_iommu_unlock();
1306
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001307 /* Disable smmu clock */
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001308 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001309}
1310
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001311/*
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001312 * kgsl_iommu_get_reg_gpuaddr - Returns the gpu address of IOMMU regsiter
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001313 * @mmu - Pointer to mmu structure
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001314 * @iommu_unit - The iommu unit for which base address is requested
1315 * @ctx_id - The context ID of the IOMMU ctx
1316 * @reg - The register for which address is required
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001317 *
1318 * Return - The number of iommu units which is also the number of register
1319 * mapped descriptor arrays which the out parameter will have
1320 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001321static unsigned int kgsl_iommu_get_reg_gpuaddr(struct kgsl_mmu *mmu,
1322 int iommu_unit, int ctx_id, int reg)
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001323{
1324 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001325
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001326 if (KGSL_IOMMU_GLOBAL_BASE == reg)
1327 return iommu->iommu_units[iommu_unit].reg_map.gpuaddr;
1328 else
1329 return iommu->iommu_units[iommu_unit].reg_map.gpuaddr +
1330 iommu->iommu_reg_list[reg].reg_offset +
1331 (ctx_id << KGSL_IOMMU_CTX_SHIFT) + iommu->ctx_offset;
1332}
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001333
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001334static int kgsl_iommu_get_num_iommu_units(struct kgsl_mmu *mmu)
1335{
1336 struct kgsl_iommu *iommu = mmu->priv;
1337 return iommu->unit_count;
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001338}
1339
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001340struct kgsl_mmu_ops iommu_ops = {
1341 .mmu_init = kgsl_iommu_init,
1342 .mmu_close = kgsl_iommu_close,
1343 .mmu_start = kgsl_iommu_start,
1344 .mmu_stop = kgsl_iommu_stop,
1345 .mmu_setstate = kgsl_iommu_setstate,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001346 .mmu_device_setstate = kgsl_iommu_default_setstate,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001347 .mmu_pagefault = NULL,
1348 .mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -06001349 .mmu_enable_clk = kgsl_iommu_enable_clk,
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001350 .mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
Shubhraprakash Dasfce27362012-05-09 17:44:14 -06001351 .mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001352 .mmu_get_reg_gpuaddr = kgsl_iommu_get_reg_gpuaddr,
1353 .mmu_get_num_iommu_units = kgsl_iommu_get_num_iommu_units,
1354 .mmu_pt_equal = kgsl_iommu_pt_equal,
1355 .mmu_get_pt_base_addr = kgsl_iommu_get_pt_base_addr,
Tarun Karra9c070822012-11-27 16:43:51 -07001356 .mmu_sync_lock = kgsl_iommu_sync_lock,
1357 .mmu_sync_unlock = kgsl_iommu_sync_unlock,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001358};
1359
1360struct kgsl_mmu_pt_ops iommu_pt_ops = {
1361 .mmu_map = kgsl_iommu_map,
1362 .mmu_unmap = kgsl_iommu_unmap,
1363 .mmu_create_pagetable = kgsl_iommu_create_pagetable,
1364 .mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001365};