blob: 6dc7dc5779c3b06e59e169b0c6e054e4d78c5c0f [file] [log] [blame]
Shubhraprakash Das79447952012-04-26 18:12:23 -06001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#include <linux/types.h>
14#include <linux/device.h>
15#include <linux/spinlock.h>
16#include <linux/genalloc.h>
17#include <linux/slab.h>
18#include <linux/iommu.h>
Shubhraprakash Das767fdda2011-08-15 15:49:45 -060019#include <linux/msm_kgsl.h>
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -060020#include <mach/socinfo.h>
Shubhraprakash Das767fdda2011-08-15 15:49:45 -060021
22#include "kgsl.h"
23#include "kgsl_device.h"
24#include "kgsl_mmu.h"
25#include "kgsl_sharedmem.h"
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -060026#include "kgsl_iommu.h"
Shubhraprakash Dase9541a32012-05-09 22:25:55 -060027#include "adreno_pm4types.h"
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -060028#include "adreno.h"
Jordan Crouse95b68472012-05-25 10:25:01 -060029#include "kgsl_trace.h"
30
31static struct kgsl_iommu_unit *get_iommu_unit(struct device *dev)
32{
33 int i, j, k;
34
35 for (i = 0; i < KGSL_DEVICE_MAX; i++) {
36 struct kgsl_mmu *mmu;
37 struct kgsl_iommu *iommu;
38
39 if (kgsl_driver.devp[i] == NULL)
40 continue;
41
42 mmu = kgsl_get_mmu(kgsl_driver.devp[i]);
43 if (mmu == NULL || mmu->priv == NULL)
44 continue;
45
46 iommu = mmu->priv;
47
48 for (j = 0; j < iommu->unit_count; j++) {
49 struct kgsl_iommu_unit *iommu_unit =
50 &iommu->iommu_units[j];
51 for (k = 0; k < iommu_unit->dev_count; k++) {
52 if (iommu_unit->dev[k].dev == dev)
53 return iommu_unit;
54 }
55 }
56 }
57
58 return NULL;
59}
60
61static struct kgsl_iommu_device *get_iommu_device(struct kgsl_iommu_unit *unit,
62 struct device *dev)
63{
64 int k;
65
66 for (k = 0; unit && k < unit->dev_count; k++) {
67 if (unit->dev[k].dev == dev)
68 return &(unit->dev[k]);
69 }
70
71 return NULL;
72}
73
74static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
75 struct device *dev, unsigned long addr, int flags)
76{
77 struct kgsl_iommu_unit *iommu_unit = get_iommu_unit(dev);
78 struct kgsl_iommu_device *iommu_dev = get_iommu_device(iommu_unit, dev);
79 unsigned int ptbase, fsr;
80
81 if (!iommu_dev) {
82 KGSL_CORE_ERR("Invalid IOMMU device %p\n", dev);
83 return -ENOSYS;
84 }
85
Shubhraprakash Das190553a2012-06-11 15:17:59 -060086 ptbase = KGSL_IOMMU_GET_IOMMU_REG(iommu_unit->reg_map.hostptr,
87 iommu_dev->ctx_id, TTBR0);
Jordan Crouse95b68472012-05-25 10:25:01 -060088
89 fsr = KGSL_IOMMU_GET_IOMMU_REG(iommu_unit->reg_map.hostptr,
90 iommu_dev->ctx_id, FSR);
91
92 KGSL_MEM_CRIT(iommu_dev->kgsldev,
93 "GPU PAGE FAULT: addr = %lX pid = %d\n",
94 addr, kgsl_mmu_get_ptname_from_ptbase(ptbase));
95 KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
96 iommu_dev->ctx_id, fsr);
97
98 trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
99 kgsl_mmu_get_ptname_from_ptbase(ptbase), 0);
100
101 return 0;
102}
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600103
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600104/*
105 * kgsl_iommu_disable_clk - Disable iommu clocks
106 * @mmu - Pointer to mmu structure
107 *
108 * Disables iommu clocks
109 * Return - void
110 */
111static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu)
112{
113 struct kgsl_iommu *iommu = mmu->priv;
114 struct msm_iommu_drvdata *iommu_drvdata;
115 int i, j;
116
117 for (i = 0; i < iommu->unit_count; i++) {
118 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
119 for (j = 0; j < iommu_unit->dev_count; j++) {
120 if (!iommu_unit->dev[j].clk_enabled)
121 continue;
122 iommu_drvdata = dev_get_drvdata(
123 iommu_unit->dev[j].dev->parent);
Shubhraprakash Das102aac52012-08-16 22:12:27 -0700124 if (iommu_drvdata->aclk)
125 clk_disable_unprepare(iommu_drvdata->aclk);
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600126 if (iommu_drvdata->clk)
127 clk_disable_unprepare(iommu_drvdata->clk);
128 clk_disable_unprepare(iommu_drvdata->pclk);
129 iommu_unit->dev[j].clk_enabled = false;
130 }
131 }
132}
133
134/*
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600135 * kgsl_iommu_disable_clk_event - An event function that is executed when
136 * the required timestamp is reached. It disables the IOMMU clocks if
137 * the timestamp on which the clocks can be disabled has expired.
138 * @device - The kgsl device pointer
139 * @data - The data passed during event creation, it is the MMU pointer
140 * @id - Context ID, should always be KGSL_MEMSTORE_GLOBAL
141 * @ts - The current timestamp that has expired for the device
142 *
143 * Disables IOMMU clocks if timestamp has expired
144 * Return - void
145 */
146static void kgsl_iommu_clk_disable_event(struct kgsl_device *device, void *data,
147 unsigned int id, unsigned int ts)
148{
149 struct kgsl_mmu *mmu = data;
150 struct kgsl_iommu *iommu = mmu->priv;
151
152 if (!iommu->clk_event_queued) {
153 if (0 > timestamp_cmp(ts, iommu->iommu_last_cmd_ts))
154 KGSL_DRV_ERR(device,
155 "IOMMU disable clock event being cancelled, "
156 "iommu_last_cmd_ts: %x, retired ts: %x\n",
157 iommu->iommu_last_cmd_ts, ts);
158 return;
159 }
160
161 if (0 <= timestamp_cmp(ts, iommu->iommu_last_cmd_ts)) {
162 kgsl_iommu_disable_clk(mmu);
163 iommu->clk_event_queued = false;
164 } else {
165 /* add new event to fire when ts is reached, this can happen
166 * if we queued an event and someone requested the clocks to
167 * be disbaled on a later timestamp */
168 if (kgsl_add_event(device, id, iommu->iommu_last_cmd_ts,
169 kgsl_iommu_clk_disable_event, mmu, mmu)) {
170 KGSL_DRV_ERR(device,
171 "Failed to add IOMMU disable clk event\n");
172 iommu->clk_event_queued = false;
173 }
174 }
175}
176
177/*
178 * kgsl_iommu_disable_clk_on_ts - Sets up event to disable IOMMU clocks
179 * @mmu - The kgsl MMU pointer
180 * @ts - Timestamp on which the clocks should be disabled
181 * @ts_valid - Indicates whether ts parameter is valid, if this parameter
182 * is false then it means that the calling function wants to disable the
183 * IOMMU clocks immediately without waiting for any timestamp
184 *
185 * Creates an event to disable the IOMMU clocks on timestamp and if event
186 * already exists then updates the timestamp of disabling the IOMMU clocks
187 * with the passed in ts if it is greater than the current value at which
188 * the clocks will be disabled
189 * Return - void
190 */
191static void
192kgsl_iommu_disable_clk_on_ts(struct kgsl_mmu *mmu, unsigned int ts,
193 bool ts_valid)
194{
195 struct kgsl_iommu *iommu = mmu->priv;
196
197 if (iommu->clk_event_queued) {
198 if (ts_valid && (0 <
199 timestamp_cmp(ts, iommu->iommu_last_cmd_ts)))
200 iommu->iommu_last_cmd_ts = ts;
201 } else {
202 if (ts_valid) {
203 iommu->iommu_last_cmd_ts = ts;
204 iommu->clk_event_queued = true;
205 if (kgsl_add_event(mmu->device, KGSL_MEMSTORE_GLOBAL,
206 ts, kgsl_iommu_clk_disable_event, mmu, mmu)) {
207 KGSL_DRV_ERR(mmu->device,
208 "Failed to add IOMMU disable clk event\n");
209 iommu->clk_event_queued = false;
210 }
211 } else {
212 kgsl_iommu_disable_clk(mmu);
213 }
214 }
215}
216
217/*
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600218 * kgsl_iommu_enable_clk - Enable iommu clocks
219 * @mmu - Pointer to mmu structure
220 * @ctx_id - The context bank whose clocks are to be turned on
221 *
222 * Enables iommu clocks of a given context
223 * Return: 0 on success else error code
224 */
225static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu,
226 int ctx_id)
227{
228 int ret = 0;
229 int i, j;
230 struct kgsl_iommu *iommu = mmu->priv;
231 struct msm_iommu_drvdata *iommu_drvdata;
232
233 for (i = 0; i < iommu->unit_count; i++) {
234 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
235 for (j = 0; j < iommu_unit->dev_count; j++) {
236 if (iommu_unit->dev[j].clk_enabled ||
237 ctx_id != iommu_unit->dev[j].ctx_id)
238 continue;
239 iommu_drvdata =
240 dev_get_drvdata(iommu_unit->dev[j].dev->parent);
241 ret = clk_prepare_enable(iommu_drvdata->pclk);
242 if (ret)
243 goto done;
244 if (iommu_drvdata->clk) {
245 ret = clk_prepare_enable(iommu_drvdata->clk);
246 if (ret) {
247 clk_disable_unprepare(
248 iommu_drvdata->pclk);
249 goto done;
250 }
251 }
Shubhraprakash Das102aac52012-08-16 22:12:27 -0700252 if (iommu_drvdata->aclk) {
253 ret = clk_prepare_enable(iommu_drvdata->aclk);
254 if (ret) {
255 if (iommu_drvdata->clk)
256 clk_disable_unprepare(
257 iommu_drvdata->clk);
258 clk_disable_unprepare(
259 iommu_drvdata->pclk);
260 goto done;
261 }
262 }
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600263 iommu_unit->dev[j].clk_enabled = true;
264 }
265 }
266done:
267 if (ret)
268 kgsl_iommu_disable_clk(mmu);
269 return ret;
270}
271
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600272/*
273 * kgsl_iommu_pt_equal - Check if pagetables are equal
274 * @pt - Pointer to pagetable
275 * @pt_base - Address of a pagetable that the IOMMU register is
276 * programmed with
277 *
278 * Checks whether the pt_base is equal to the base address of
279 * the pagetable which is contained in the pt structure
280 * Return - Non-zero if the pagetable addresses are equal else 0
281 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600282static int kgsl_iommu_pt_equal(struct kgsl_pagetable *pt,
283 unsigned int pt_base)
284{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600285 struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
286 unsigned int domain_ptbase = iommu_pt ?
287 iommu_get_pt_base_addr(iommu_pt->domain) : 0;
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600288 /* Only compare the valid address bits of the pt_base */
289 domain_ptbase &= (KGSL_IOMMU_TTBR0_PA_MASK <<
290 KGSL_IOMMU_TTBR0_PA_SHIFT);
291 pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK <<
292 KGSL_IOMMU_TTBR0_PA_SHIFT);
293 return domain_ptbase && pt_base &&
294 (domain_ptbase == pt_base);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600295}
296
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600297/*
298 * kgsl_iommu_destroy_pagetable - Free up reaources help by a pagetable
299 * @mmu_specific_pt - Pointer to pagetable which is to be freed
300 *
301 * Return - void
302 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600303static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
304{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600305 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
306 if (iommu_pt->domain)
307 iommu_domain_free(iommu_pt->domain);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600308 kfree(iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600309}
310
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600311/*
312 * kgsl_iommu_create_pagetable - Create a IOMMU pagetable
313 *
314 * Allocate memory to hold a pagetable and allocate the IOMMU
315 * domain which is the actual IOMMU pagetable
316 * Return - void
317 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600318void *kgsl_iommu_create_pagetable(void)
319{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600320 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600321
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600322 iommu_pt = kzalloc(sizeof(struct kgsl_iommu_pt), GFP_KERNEL);
323 if (!iommu_pt) {
324 KGSL_CORE_ERR("kzalloc(%d) failed\n",
325 sizeof(struct kgsl_iommu_pt));
326 return NULL;
327 }
Steve Mucklef132c6c2012-06-06 18:30:57 -0700328 iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
329 MSM_IOMMU_DOMAIN_PT_CACHEABLE);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600330 if (!iommu_pt->domain) {
331 KGSL_CORE_ERR("Failed to create iommu domain\n");
332 kfree(iommu_pt);
333 return NULL;
Jordan Crouse95b68472012-05-25 10:25:01 -0600334 } else {
335 iommu_set_fault_handler(iommu_pt->domain,
336 kgsl_iommu_fault_handler);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600337 }
Jordan Crouse95b68472012-05-25 10:25:01 -0600338
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600339 return iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600340}
341
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600342/*
343 * kgsl_detach_pagetable_iommu_domain - Detach the IOMMU unit from a
344 * pagetable
345 * @mmu - Pointer to the device mmu structure
346 * @priv - Flag indicating whether the private or user context is to be
347 * detached
348 *
349 * Detach the IOMMU unit with the domain that is contained in the
350 * hwpagetable of the given mmu. After detaching the IOMMU unit is not
351 * in use because the PTBR will not be set after a detach
352 * Return - void
353 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600354static void kgsl_detach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
355{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600356 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600357 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600358 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600359
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600360 for (i = 0; i < iommu->unit_count; i++) {
361 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600362 iommu_pt = mmu->defaultpagetable->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600363 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600364 /*
365 * If there is a 2nd default pagetable then priv domain
366 * is attached with this pagetable
367 */
368 if (mmu->priv_bank_table &&
369 (KGSL_IOMMU_CONTEXT_PRIV == j))
370 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600371 if (iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600372 iommu_detach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600373 iommu_unit->dev[j].dev);
374 iommu_unit->dev[j].attached = false;
375 KGSL_MEM_INFO(mmu->device, "iommu %p detached "
376 "from user dev of MMU: %p\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600377 iommu_pt->domain, mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600378 }
379 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600380 }
381}
382
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600383/*
384 * kgsl_attach_pagetable_iommu_domain - Attach the IOMMU unit to a
385 * pagetable, i.e set the IOMMU's PTBR to the pagetable address and
386 * setup other IOMMU registers for the device so that it becomes
387 * active
388 * @mmu - Pointer to the device mmu structure
389 * @priv - Flag indicating whether the private or user context is to be
390 * attached
391 *
392 * Attach the IOMMU unit with the domain that is contained in the
393 * hwpagetable of the given mmu.
394 * Return - 0 on success else error code
395 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600396static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
397{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600398 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600399 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600400 int i, j, ret = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600401
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600402 /*
403 * Loop through all the iommu devcies under all iommu units and
404 * attach the domain
405 */
406 for (i = 0; i < iommu->unit_count; i++) {
407 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600408 iommu_pt = mmu->defaultpagetable->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600409 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600410 /*
411 * If there is a 2nd default pagetable then priv domain
412 * is attached to this pagetable
413 */
414 if (mmu->priv_bank_table &&
415 (KGSL_IOMMU_CONTEXT_PRIV == j))
416 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600417 if (!iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600418 ret = iommu_attach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600419 iommu_unit->dev[j].dev);
420 if (ret) {
421 KGSL_MEM_ERR(mmu->device,
422 "Failed to attach device, err %d\n",
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700423 ret);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600424 goto done;
425 }
426 iommu_unit->dev[j].attached = true;
427 KGSL_MEM_INFO(mmu->device,
428 "iommu pt %p attached to dev %p, ctx_id %d\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600429 iommu_pt->domain, iommu_unit->dev[j].dev,
430 iommu_unit->dev[j].ctx_id);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700431 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600432 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600433 }
434done:
435 return ret;
436}
437
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600438/*
439 * _get_iommu_ctxs - Get device pointer to IOMMU contexts
440 * @mmu - Pointer to mmu device
441 * data - Pointer to the platform data containing information about
442 * iommu devices for one iommu unit
443 * unit_id - The IOMMU unit number. This is not a specific ID but just
444 * a serial number. The serial numbers are treated as ID's of the
445 * IOMMU units
446 *
447 * Return - 0 on success else error code
448 */
449static int _get_iommu_ctxs(struct kgsl_mmu *mmu,
450 struct kgsl_device_iommu_data *data, unsigned int unit_id)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700451{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600452 struct kgsl_iommu *iommu = mmu->priv;
453 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id];
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700454 int i;
455
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600456 if (data->iommu_ctx_count > KGSL_IOMMU_MAX_DEVS_PER_UNIT) {
457 KGSL_CORE_ERR("Too many iommu devices defined for an "
458 "IOMMU unit\n");
459 return -EINVAL;
460 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700461
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600462 for (i = 0; i < data->iommu_ctx_count; i++) {
463 if (!data->iommu_ctxs[i].iommu_ctx_name)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700464 continue;
465
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600466 iommu_unit->dev[iommu_unit->dev_count].dev =
467 msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
468 if (iommu_unit->dev[iommu_unit->dev_count].dev == NULL) {
469 KGSL_CORE_ERR("Failed to get iommu dev handle for "
470 "device %s\n", data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700471 return -EINVAL;
472 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600473 if (KGSL_IOMMU_CONTEXT_USER != data->iommu_ctxs[i].ctx_id &&
474 KGSL_IOMMU_CONTEXT_PRIV != data->iommu_ctxs[i].ctx_id) {
475 KGSL_CORE_ERR("Invalid context ID defined: %d\n",
476 data->iommu_ctxs[i].ctx_id);
477 return -EINVAL;
478 }
479 iommu_unit->dev[iommu_unit->dev_count].ctx_id =
480 data->iommu_ctxs[i].ctx_id;
Jordan Crouse95b68472012-05-25 10:25:01 -0600481 iommu_unit->dev[iommu_unit->dev_count].kgsldev = mmu->device;
482
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600483 KGSL_DRV_INFO(mmu->device,
484 "Obtained dev handle %p for iommu context %s\n",
485 iommu_unit->dev[iommu_unit->dev_count].dev,
486 data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700487
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600488 iommu_unit->dev_count++;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700489 }
490
491 return 0;
492}
493
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600494/*
495 * kgsl_get_iommu_ctxt - Get device pointer to IOMMU contexts
496 * @mmu - Pointer to mmu device
497 *
498 * Get the device pointers for the IOMMU user and priv contexts of the
499 * kgsl device
500 * Return - 0 on success else error code
501 */
502static int kgsl_get_iommu_ctxt(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600503{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600504 struct platform_device *pdev =
505 container_of(mmu->device->parentdev, struct platform_device,
506 dev);
507 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
508 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700509 int i, ret = 0;
510
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600511 /* Go through the IOMMU data and get all the context devices */
512 if (KGSL_IOMMU_MAX_UNITS < pdata_dev->iommu_count) {
513 KGSL_CORE_ERR("Too many IOMMU units defined\n");
514 ret = -EINVAL;
515 goto done;
516 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700517
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600518 for (i = 0; i < pdata_dev->iommu_count; i++) {
519 ret = _get_iommu_ctxs(mmu, &pdata_dev->iommu_data[i], i);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700520 if (ret)
521 break;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600522 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600523 iommu->unit_count = pdata_dev->iommu_count;
524done:
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700525 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600526}
527
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600528/*
529 * kgsl_set_register_map - Map the IOMMU regsiters in the memory descriptors
530 * of the respective iommu units
531 * @mmu - Pointer to mmu structure
532 *
533 * Return - 0 on success else error code
534 */
535static int kgsl_set_register_map(struct kgsl_mmu *mmu)
536{
537 struct platform_device *pdev =
538 container_of(mmu->device->parentdev, struct platform_device,
539 dev);
540 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
541 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
542 struct kgsl_iommu_unit *iommu_unit;
543 int i = 0, ret = 0;
544
545 for (; i < pdata_dev->iommu_count; i++) {
546 struct kgsl_device_iommu_data data = pdata_dev->iommu_data[i];
547 iommu_unit = &iommu->iommu_units[i];
548 /* set up the IOMMU register map for the given IOMMU unit */
549 if (!data.physstart || !data.physend) {
550 KGSL_CORE_ERR("The register range for IOMMU unit not"
551 " specified\n");
552 ret = -EINVAL;
553 goto err;
554 }
555 iommu_unit->reg_map.hostptr = ioremap(data.physstart,
556 data.physend - data.physstart + 1);
557 if (!iommu_unit->reg_map.hostptr) {
558 KGSL_CORE_ERR("Failed to map SMMU register address "
559 "space from %x to %x\n", data.physstart,
560 data.physend - data.physstart + 1);
561 ret = -ENOMEM;
562 i--;
563 goto err;
564 }
565 iommu_unit->reg_map.size = data.physend - data.physstart + 1;
566 iommu_unit->reg_map.physaddr = data.physstart;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600567 memdesc_sg_phys(&iommu_unit->reg_map, data.physstart,
568 iommu_unit->reg_map.size);
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600569 }
570 iommu->unit_count = pdata_dev->iommu_count;
571 return ret;
572err:
573 /* Unmap any mapped IOMMU regions */
574 for (; i >= 0; i--) {
575 iommu_unit = &iommu->iommu_units[i];
576 iounmap(iommu_unit->reg_map.hostptr);
577 iommu_unit->reg_map.size = 0;
578 iommu_unit->reg_map.physaddr = 0;
579 }
580 return ret;
581}
582
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600583/*
584 * kgsl_iommu_pt_get_base_addr - Get the address of the pagetable that the
585 * IOMMU ttbr0 register is programmed with
586 * @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
587 *
588 * Return - actual pagetable address that the ttbr0 register is programmed
589 * with
590 */
591static unsigned int kgsl_iommu_pt_get_base_addr(struct kgsl_pagetable *pt)
592{
593 struct kgsl_iommu_pt *iommu_pt = pt->priv;
594 return iommu_get_pt_base_addr(iommu_pt->domain);
595}
596
597/*
598 * kgsl_iommu_get_pt_lsb - Return the lsb of the ttbr0 IOMMU register
599 * @mmu - Pointer to mmu structure
600 * @hostptr - Pointer to the IOMMU register map. This is used to match
601 * the iommu device whose lsb value is to be returned
602 * @ctx_id - The context bank whose lsb valus is to be returned
603 * Return - returns the lsb which is the last 14 bits of the ttbr0 IOMMU
604 * register. ttbr0 is the actual PTBR for of the IOMMU. The last 14 bits
605 * are only programmed once in the beginning when a domain is attached
606 * does not change.
607 */
608static int kgsl_iommu_get_pt_lsb(struct kgsl_mmu *mmu,
609 unsigned int unit_id,
610 enum kgsl_iommu_context_id ctx_id)
611{
612 struct kgsl_iommu *iommu = mmu->priv;
613 int i, j;
614 for (i = 0; i < iommu->unit_count; i++) {
615 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
616 for (j = 0; j < iommu_unit->dev_count; j++)
617 if (unit_id == i &&
618 ctx_id == iommu_unit->dev[j].ctx_id)
619 return iommu_unit->dev[j].pt_lsb;
620 }
621 return 0;
622}
623
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600624static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600625 struct kgsl_pagetable *pagetable,
626 unsigned int context_id)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600627{
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600628 if (mmu->flags & KGSL_FLAGS_STARTED) {
629 /* page table not current, then setup mmu to use new
630 * specified page table
631 */
632 if (mmu->hwpagetable != pagetable) {
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600633 unsigned int flags = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600634 mmu->hwpagetable = pagetable;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600635 flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
Shubhraprakash Das8649fa52012-07-26 15:49:46 -0700636 mmu->device->id) |
637 KGSL_MMUFLAGS_TLBFLUSH;
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600638 kgsl_setstate(mmu, context_id,
639 KGSL_MMUFLAGS_PTUPDATE | flags);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600640 }
641 }
642}
643
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600644static int kgsl_iommu_init(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600645{
646 /*
647 * intialize device mmu
648 *
649 * call this with the global lock held
650 */
651 int status = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600652 struct kgsl_iommu *iommu;
653
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600654 iommu = kzalloc(sizeof(struct kgsl_iommu), GFP_KERNEL);
655 if (!iommu) {
656 KGSL_CORE_ERR("kzalloc(%d) failed\n",
657 sizeof(struct kgsl_iommu));
658 return -ENOMEM;
659 }
660
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600661 mmu->priv = iommu;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600662 status = kgsl_get_iommu_ctxt(mmu);
663 if (status)
664 goto done;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600665 status = kgsl_set_register_map(mmu);
666 if (status)
667 goto done;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600668
Shubhraprakash Dase9541a32012-05-09 22:25:55 -0600669 /* A nop is required in an indirect buffer when switching
670 * pagetables in-stream */
671 kgsl_sharedmem_writel(&mmu->setstate_memory,
672 KGSL_IOMMU_SETSTATE_NOP_OFFSET,
673 cp_nop_packet(1));
674
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600675 dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600676 __func__);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600677done:
678 if (status) {
679 kfree(iommu);
680 mmu->priv = NULL;
681 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600682 return status;
683}
684
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600685/*
686 * kgsl_iommu_setup_defaultpagetable - Setup the initial defualtpagetable
687 * for iommu. This function is only called once during first start, successive
688 * start do not call this funciton.
689 * @mmu - Pointer to mmu structure
690 *
691 * Create the initial defaultpagetable and setup the iommu mappings to it
692 * Return - 0 on success else error code
693 */
694static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu)
695{
696 int status = 0;
697 int i = 0;
698 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600699 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600700 struct kgsl_pagetable *pagetable = NULL;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600701
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600702 /* If chip is not 8960 then we use the 2nd context bank for pagetable
703 * switching on the 3D side for which a separate table is allocated */
704 if (!cpu_is_msm8960()) {
705 mmu->priv_bank_table =
706 kgsl_mmu_getpagetable(KGSL_MMU_PRIV_BANK_TABLE_NAME);
707 if (mmu->priv_bank_table == NULL) {
708 status = -ENOMEM;
709 goto err;
710 }
711 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600712 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600713 mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
714 /* Return error if the default pagetable doesn't exist */
715 if (mmu->defaultpagetable == NULL) {
716 status = -ENOMEM;
717 goto err;
718 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600719 pagetable = mmu->priv_bank_table ? mmu->priv_bank_table :
720 mmu->defaultpagetable;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600721 /* Map the IOMMU regsiters to only defaultpagetable */
722 for (i = 0; i < iommu->unit_count; i++) {
723 iommu->iommu_units[i].reg_map.priv |= KGSL_MEMFLAGS_GLOBAL;
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600724 status = kgsl_mmu_map(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600725 &(iommu->iommu_units[i].reg_map),
726 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
727 if (status) {
728 iommu->iommu_units[i].reg_map.priv &=
729 ~KGSL_MEMFLAGS_GLOBAL;
730 goto err;
731 }
732 }
733 return status;
734err:
735 for (i--; i >= 0; i--) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600736 kgsl_mmu_unmap(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600737 &(iommu->iommu_units[i].reg_map));
738 iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMFLAGS_GLOBAL;
739 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600740 if (mmu->priv_bank_table) {
741 kgsl_mmu_putpagetable(mmu->priv_bank_table);
742 mmu->priv_bank_table = NULL;
743 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600744 if (mmu->defaultpagetable) {
745 kgsl_mmu_putpagetable(mmu->defaultpagetable);
746 mmu->defaultpagetable = NULL;
747 }
748 return status;
749}
750
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600751static int kgsl_iommu_start(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600752{
753 int status;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600754 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600755 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600756
757 if (mmu->flags & KGSL_FLAGS_STARTED)
758 return 0;
759
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600760 if (mmu->defaultpagetable == NULL) {
761 status = kgsl_iommu_setup_defaultpagetable(mmu);
762 if (status)
763 return -ENOMEM;
764 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600765 /* We use the GPU MMU to control access to IOMMU registers on 8960 with
766 * a225, hence we still keep the MMU active on 8960 */
767 if (cpu_is_msm8960()) {
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600768 struct kgsl_mh *mh = &(mmu->device->mh);
769 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001);
770 kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
771 mh->mpu_base +
Shubhraprakash Das2b54b5f2012-08-08 18:21:36 -0700772 iommu->iommu_units[0].reg_map.gpuaddr);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600773 } else {
774 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
775 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600776
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600777 mmu->hwpagetable = mmu->defaultpagetable;
778
779 status = kgsl_attach_pagetable_iommu_domain(mmu);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600780 if (status) {
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600781 mmu->hwpagetable = NULL;
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600782 goto done;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600783 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600784 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600785 if (status) {
786 KGSL_CORE_ERR("clk enable failed\n");
787 goto done;
788 }
789 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
790 if (status) {
791 KGSL_CORE_ERR("clk enable failed\n");
792 goto done;
793 }
794 /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as
795 * that value should not change when we change pagetables, so while
796 * changing pagetables we can use this lsb value of the pagetable w/o
797 * having to read it again
798 */
799 for (i = 0; i < iommu->unit_count; i++) {
800 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
801 for (j = 0; j < iommu_unit->dev_count; j++)
802 iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(
803 KGSL_IOMMU_GET_IOMMU_REG(
804 iommu_unit->reg_map.hostptr,
805 iommu_unit->dev[j].ctx_id,
806 TTBR0));
807 }
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600808
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600809 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600810 mmu->flags |= KGSL_FLAGS_STARTED;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600811
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600812done:
813 if (status) {
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600814 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600815 kgsl_detach_pagetable_iommu_domain(mmu);
816 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600817 return status;
818}
819
820static int
821kgsl_iommu_unmap(void *mmu_specific_pt,
Shubhraprakash Das0c811262012-06-06 23:22:19 -0600822 struct kgsl_memdesc *memdesc,
823 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600824{
825 int ret;
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600826 unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600827 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600828
829 /* All GPU addresses as assigned are page aligned, but some
830 functions purturb the gpuaddr with an offset, so apply the
831 mask here to make sure we have the right address */
832
833 unsigned int gpuaddr = memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK;
834
835 if (range == 0 || gpuaddr == 0)
836 return 0;
837
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600838 ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600839 if (ret)
840 KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600841 "with err: %d\n", iommu_pt->domain, gpuaddr,
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600842 range, ret);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600843
Shubhraprakash Das0c811262012-06-06 23:22:19 -0600844#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
845 /*
846 * Flushing only required if per process pagetables are used. With
847 * global case, flushing will happen inside iommu_map function
848 */
849 if (!ret)
850 *tlb_flags = UINT_MAX;
851#endif
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600852 return 0;
853}
854
855static int
856kgsl_iommu_map(void *mmu_specific_pt,
857 struct kgsl_memdesc *memdesc,
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600858 unsigned int protflags,
859 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600860{
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600861 int ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600862 unsigned int iommu_virt_addr;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600863 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600864 int size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600865
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600866 BUG_ON(NULL == iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600867
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600868
Jordan Croused17e9aa2011-10-12 16:57:48 -0600869 iommu_virt_addr = memdesc->gpuaddr;
870
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600871 ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600872 size, (IOMMU_READ | IOMMU_WRITE));
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600873 if (ret) {
874 KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600875 "failed with err: %d\n", iommu_pt->domain,
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600876 iommu_virt_addr, memdesc->sg, size,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600877 (IOMMU_READ | IOMMU_WRITE), ret);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600878 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600879 }
880
881 return ret;
882}
883
Shubhraprakash Das79447952012-04-26 18:12:23 -0600884static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600885{
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600886 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600887 /*
888 * stop device mmu
889 *
890 * call this with the global lock held
891 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600892
893 if (mmu->flags & KGSL_FLAGS_STARTED) {
894 /* detach iommu attachment */
895 kgsl_detach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600896 mmu->hwpagetable = NULL;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600897
898 mmu->flags &= ~KGSL_FLAGS_STARTED;
899 }
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600900
901 /* switch off MMU clocks and cancel any events it has queued */
902 iommu->clk_event_queued = false;
903 kgsl_cancel_events(mmu->device, mmu);
904 kgsl_iommu_disable_clk(mmu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600905}
906
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600907static int kgsl_iommu_close(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600908{
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600909 struct kgsl_iommu *iommu = mmu->priv;
910 int i;
911 for (i = 0; i < iommu->unit_count; i++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600912 struct kgsl_pagetable *pagetable = (mmu->priv_bank_table ?
913 mmu->priv_bank_table : mmu->defaultpagetable);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600914 if (iommu->iommu_units[i].reg_map.gpuaddr)
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600915 kgsl_mmu_unmap(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600916 &(iommu->iommu_units[i].reg_map));
917 if (iommu->iommu_units[i].reg_map.hostptr)
918 iounmap(iommu->iommu_units[i].reg_map.hostptr);
919 kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
920 iommu->iommu_units[i].reg_map.sglen);
921 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600922
923 if (mmu->priv_bank_table)
924 kgsl_mmu_putpagetable(mmu->priv_bank_table);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600925 if (mmu->defaultpagetable)
926 kgsl_mmu_putpagetable(mmu->defaultpagetable);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600927 kfree(iommu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600928
929 return 0;
930}
931
932static unsigned int
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600933kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600934{
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600935 unsigned int pt_base;
936 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das64a745c2012-06-11 16:44:16 -0600937 /* We cannot enable or disable the clocks in interrupt context, this
938 function is called from interrupt context if there is an axi error */
939 if (in_interrupt())
940 return 0;
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600941 /* Return the current pt base by reading IOMMU pt_base register */
942 kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
943 pt_base = readl_relaxed(iommu->iommu_units[0].reg_map.hostptr +
944 (KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
945 KGSL_IOMMU_TTBR0);
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600946 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600947 return pt_base & (KGSL_IOMMU_TTBR0_PA_MASK <<
948 KGSL_IOMMU_TTBR0_PA_SHIFT);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600949}
950
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600951/*
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600952 * kgsl_iommu_default_setstate - Change the IOMMU pagetable or flush IOMMU tlb
953 * of the primary context bank
954 * @mmu - Pointer to mmu structure
955 * @flags - Flags indicating whether pagetable has to chnage or tlb is to be
956 * flushed or both
957 *
958 * Based on flags set the new pagetable fo the IOMMU unit or flush it's tlb or
959 * do both by doing direct register writes to the IOMMu registers through the
960 * cpu
961 * Return - void
962 */
963static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
964 uint32_t flags)
965{
966 struct kgsl_iommu *iommu = mmu->priv;
967 int temp;
968 int i;
969 unsigned int pt_base = kgsl_iommu_pt_get_base_addr(
970 mmu->hwpagetable);
971 unsigned int pt_val;
972
973 if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
974 KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
975 return;
976 }
977 /* Mask off the lsb of the pt base address since lsb will not change */
978 pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK << KGSL_IOMMU_TTBR0_PA_SHIFT);
979 if (flags & KGSL_MMUFLAGS_PTUPDATE) {
Jordan Crousea29a2e02012-08-14 09:09:23 -0600980 kgsl_idle(mmu->device);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600981 for (i = 0; i < iommu->unit_count; i++) {
982 /* get the lsb value which should not change when
983 * changing ttbr0 */
984 pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
985 KGSL_IOMMU_CONTEXT_USER);
986 pt_val += pt_base;
987
988 KGSL_IOMMU_SET_IOMMU_REG(
989 iommu->iommu_units[i].reg_map.hostptr,
990 KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
991
992 mb();
993 temp = KGSL_IOMMU_GET_IOMMU_REG(
994 iommu->iommu_units[i].reg_map.hostptr,
995 KGSL_IOMMU_CONTEXT_USER, TTBR0);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600996 }
997 }
998 /* Flush tlb */
999 if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
1000 for (i = 0; i < iommu->unit_count; i++) {
1001 KGSL_IOMMU_SET_IOMMU_REG(
1002 iommu->iommu_units[i].reg_map.hostptr,
Shubhraprakash Das8649fa52012-07-26 15:49:46 -07001003 KGSL_IOMMU_CONTEXT_USER, CTX_TLBIALL,
1004 1);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001005 mb();
1006 }
1007 }
1008 /* Disable smmu clock */
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001009 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001010}
1011
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001012/*
1013 * kgsl_iommu_get_reg_map_desc - Returns an array of pointers that contain
1014 * the address of memory descriptors which map the IOMMU registers
1015 * @mmu - Pointer to mmu structure
1016 * @reg_map_desc - Out parameter in which the address of the array containing
1017 * pointers to register map descriptors is returned. The caller is supposed
1018 * to free this array
1019 *
1020 * Return - The number of iommu units which is also the number of register
1021 * mapped descriptor arrays which the out parameter will have
1022 */
1023static int kgsl_iommu_get_reg_map_desc(struct kgsl_mmu *mmu,
1024 void **reg_map_desc)
1025{
1026 struct kgsl_iommu *iommu = mmu->priv;
1027 void **reg_desc_ptr;
1028 int i;
1029
1030 /*
1031 * Alocate array of pointers that will hold address of the register map
1032 * descriptors
1033 */
1034 reg_desc_ptr = kmalloc(iommu->unit_count *
1035 sizeof(struct kgsl_memdesc *), GFP_KERNEL);
1036 if (!reg_desc_ptr) {
1037 KGSL_CORE_ERR("Failed to kmalloc(%d)\n",
1038 iommu->unit_count * sizeof(struct kgsl_memdesc *));
1039 return -ENOMEM;
1040 }
1041
1042 for (i = 0; i < iommu->unit_count; i++)
1043 reg_desc_ptr[i] = &(iommu->iommu_units[i].reg_map);
1044
1045 *reg_map_desc = reg_desc_ptr;
1046 return i;
1047}
1048
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001049struct kgsl_mmu_ops iommu_ops = {
1050 .mmu_init = kgsl_iommu_init,
1051 .mmu_close = kgsl_iommu_close,
1052 .mmu_start = kgsl_iommu_start,
1053 .mmu_stop = kgsl_iommu_stop,
1054 .mmu_setstate = kgsl_iommu_setstate,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001055 .mmu_device_setstate = kgsl_iommu_default_setstate,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001056 .mmu_pagefault = NULL,
1057 .mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -06001058 .mmu_enable_clk = kgsl_iommu_enable_clk,
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001059 .mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
Shubhraprakash Dasfce27362012-05-09 17:44:14 -06001060 .mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001061 .mmu_get_reg_map_desc = kgsl_iommu_get_reg_map_desc,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001062};
1063
1064struct kgsl_mmu_pt_ops iommu_pt_ops = {
1065 .mmu_map = kgsl_iommu_map,
1066 .mmu_unmap = kgsl_iommu_unmap,
1067 .mmu_create_pagetable = kgsl_iommu_create_pagetable,
1068 .mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
1069 .mmu_pt_equal = kgsl_iommu_pt_equal,
Shubhraprakash Das5a610b52012-05-09 17:31:54 -06001070 .mmu_pt_get_base_addr = kgsl_iommu_pt_get_base_addr,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001071};