blob: 0005e08ea10554210fabeda67e54d9c93749a8a4 [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);
124 if (iommu_drvdata->clk)
125 clk_disable_unprepare(iommu_drvdata->clk);
126 clk_disable_unprepare(iommu_drvdata->pclk);
127 iommu_unit->dev[j].clk_enabled = false;
128 }
129 }
130}
131
132/*
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600133 * kgsl_iommu_disable_clk_event - An event function that is executed when
134 * the required timestamp is reached. It disables the IOMMU clocks if
135 * the timestamp on which the clocks can be disabled has expired.
136 * @device - The kgsl device pointer
137 * @data - The data passed during event creation, it is the MMU pointer
138 * @id - Context ID, should always be KGSL_MEMSTORE_GLOBAL
139 * @ts - The current timestamp that has expired for the device
140 *
141 * Disables IOMMU clocks if timestamp has expired
142 * Return - void
143 */
144static void kgsl_iommu_clk_disable_event(struct kgsl_device *device, void *data,
145 unsigned int id, unsigned int ts)
146{
147 struct kgsl_mmu *mmu = data;
148 struct kgsl_iommu *iommu = mmu->priv;
149
150 if (!iommu->clk_event_queued) {
151 if (0 > timestamp_cmp(ts, iommu->iommu_last_cmd_ts))
152 KGSL_DRV_ERR(device,
153 "IOMMU disable clock event being cancelled, "
154 "iommu_last_cmd_ts: %x, retired ts: %x\n",
155 iommu->iommu_last_cmd_ts, ts);
156 return;
157 }
158
159 if (0 <= timestamp_cmp(ts, iommu->iommu_last_cmd_ts)) {
160 kgsl_iommu_disable_clk(mmu);
161 iommu->clk_event_queued = false;
162 } else {
163 /* add new event to fire when ts is reached, this can happen
164 * if we queued an event and someone requested the clocks to
165 * be disbaled on a later timestamp */
166 if (kgsl_add_event(device, id, iommu->iommu_last_cmd_ts,
167 kgsl_iommu_clk_disable_event, mmu, mmu)) {
168 KGSL_DRV_ERR(device,
169 "Failed to add IOMMU disable clk event\n");
170 iommu->clk_event_queued = false;
171 }
172 }
173}
174
175/*
176 * kgsl_iommu_disable_clk_on_ts - Sets up event to disable IOMMU clocks
177 * @mmu - The kgsl MMU pointer
178 * @ts - Timestamp on which the clocks should be disabled
179 * @ts_valid - Indicates whether ts parameter is valid, if this parameter
180 * is false then it means that the calling function wants to disable the
181 * IOMMU clocks immediately without waiting for any timestamp
182 *
183 * Creates an event to disable the IOMMU clocks on timestamp and if event
184 * already exists then updates the timestamp of disabling the IOMMU clocks
185 * with the passed in ts if it is greater than the current value at which
186 * the clocks will be disabled
187 * Return - void
188 */
189static void
190kgsl_iommu_disable_clk_on_ts(struct kgsl_mmu *mmu, unsigned int ts,
191 bool ts_valid)
192{
193 struct kgsl_iommu *iommu = mmu->priv;
194
195 if (iommu->clk_event_queued) {
196 if (ts_valid && (0 <
197 timestamp_cmp(ts, iommu->iommu_last_cmd_ts)))
198 iommu->iommu_last_cmd_ts = ts;
199 } else {
200 if (ts_valid) {
201 iommu->iommu_last_cmd_ts = ts;
202 iommu->clk_event_queued = true;
203 if (kgsl_add_event(mmu->device, KGSL_MEMSTORE_GLOBAL,
204 ts, kgsl_iommu_clk_disable_event, mmu, mmu)) {
205 KGSL_DRV_ERR(mmu->device,
206 "Failed to add IOMMU disable clk event\n");
207 iommu->clk_event_queued = false;
208 }
209 } else {
210 kgsl_iommu_disable_clk(mmu);
211 }
212 }
213}
214
215/*
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600216 * kgsl_iommu_enable_clk - Enable iommu clocks
217 * @mmu - Pointer to mmu structure
218 * @ctx_id - The context bank whose clocks are to be turned on
219 *
220 * Enables iommu clocks of a given context
221 * Return: 0 on success else error code
222 */
223static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu,
224 int ctx_id)
225{
226 int ret = 0;
227 int i, j;
228 struct kgsl_iommu *iommu = mmu->priv;
229 struct msm_iommu_drvdata *iommu_drvdata;
230
231 for (i = 0; i < iommu->unit_count; i++) {
232 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
233 for (j = 0; j < iommu_unit->dev_count; j++) {
234 if (iommu_unit->dev[j].clk_enabled ||
235 ctx_id != iommu_unit->dev[j].ctx_id)
236 continue;
237 iommu_drvdata =
238 dev_get_drvdata(iommu_unit->dev[j].dev->parent);
239 ret = clk_prepare_enable(iommu_drvdata->pclk);
240 if (ret)
241 goto done;
242 if (iommu_drvdata->clk) {
243 ret = clk_prepare_enable(iommu_drvdata->clk);
244 if (ret) {
245 clk_disable_unprepare(
246 iommu_drvdata->pclk);
247 goto done;
248 }
249 }
250 iommu_unit->dev[j].clk_enabled = true;
251 }
252 }
253done:
254 if (ret)
255 kgsl_iommu_disable_clk(mmu);
256 return ret;
257}
258
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600259/*
260 * kgsl_iommu_pt_equal - Check if pagetables are equal
261 * @pt - Pointer to pagetable
262 * @pt_base - Address of a pagetable that the IOMMU register is
263 * programmed with
264 *
265 * Checks whether the pt_base is equal to the base address of
266 * the pagetable which is contained in the pt structure
267 * Return - Non-zero if the pagetable addresses are equal else 0
268 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600269static int kgsl_iommu_pt_equal(struct kgsl_pagetable *pt,
270 unsigned int pt_base)
271{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600272 struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
273 unsigned int domain_ptbase = iommu_pt ?
274 iommu_get_pt_base_addr(iommu_pt->domain) : 0;
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600275 /* Only compare the valid address bits of the pt_base */
276 domain_ptbase &= (KGSL_IOMMU_TTBR0_PA_MASK <<
277 KGSL_IOMMU_TTBR0_PA_SHIFT);
278 pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK <<
279 KGSL_IOMMU_TTBR0_PA_SHIFT);
280 return domain_ptbase && pt_base &&
281 (domain_ptbase == pt_base);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600282}
283
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600284/*
285 * kgsl_iommu_destroy_pagetable - Free up reaources help by a pagetable
286 * @mmu_specific_pt - Pointer to pagetable which is to be freed
287 *
288 * Return - void
289 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600290static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
291{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600292 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
293 if (iommu_pt->domain)
294 iommu_domain_free(iommu_pt->domain);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600295 kfree(iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600296}
297
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600298/*
299 * kgsl_iommu_create_pagetable - Create a IOMMU pagetable
300 *
301 * Allocate memory to hold a pagetable and allocate the IOMMU
302 * domain which is the actual IOMMU pagetable
303 * Return - void
304 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600305void *kgsl_iommu_create_pagetable(void)
306{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600307 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600308
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600309 iommu_pt = kzalloc(sizeof(struct kgsl_iommu_pt), GFP_KERNEL);
310 if (!iommu_pt) {
311 KGSL_CORE_ERR("kzalloc(%d) failed\n",
312 sizeof(struct kgsl_iommu_pt));
313 return NULL;
314 }
Steve Mucklef132c6c2012-06-06 18:30:57 -0700315 iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
316 MSM_IOMMU_DOMAIN_PT_CACHEABLE);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600317 if (!iommu_pt->domain) {
318 KGSL_CORE_ERR("Failed to create iommu domain\n");
319 kfree(iommu_pt);
320 return NULL;
Jordan Crouse95b68472012-05-25 10:25:01 -0600321 } else {
322 iommu_set_fault_handler(iommu_pt->domain,
323 kgsl_iommu_fault_handler);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600324 }
Jordan Crouse95b68472012-05-25 10:25:01 -0600325
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600326 return iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600327}
328
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600329/*
330 * kgsl_detach_pagetable_iommu_domain - Detach the IOMMU unit from a
331 * pagetable
332 * @mmu - Pointer to the device mmu structure
333 * @priv - Flag indicating whether the private or user context is to be
334 * detached
335 *
336 * Detach the IOMMU unit with the domain that is contained in the
337 * hwpagetable of the given mmu. After detaching the IOMMU unit is not
338 * in use because the PTBR will not be set after a detach
339 * Return - void
340 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600341static void kgsl_detach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
342{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600343 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600344 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600345 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600346
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600347 for (i = 0; i < iommu->unit_count; i++) {
348 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600349 iommu_pt = mmu->defaultpagetable->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600350 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600351 /*
352 * If there is a 2nd default pagetable then priv domain
353 * is attached with this pagetable
354 */
355 if (mmu->priv_bank_table &&
356 (KGSL_IOMMU_CONTEXT_PRIV == j))
357 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600358 if (iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600359 iommu_detach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600360 iommu_unit->dev[j].dev);
361 iommu_unit->dev[j].attached = false;
362 KGSL_MEM_INFO(mmu->device, "iommu %p detached "
363 "from user dev of MMU: %p\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600364 iommu_pt->domain, mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600365 }
366 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600367 }
368}
369
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600370/*
371 * kgsl_attach_pagetable_iommu_domain - Attach the IOMMU unit to a
372 * pagetable, i.e set the IOMMU's PTBR to the pagetable address and
373 * setup other IOMMU registers for the device so that it becomes
374 * active
375 * @mmu - Pointer to the device mmu structure
376 * @priv - Flag indicating whether the private or user context is to be
377 * attached
378 *
379 * Attach the IOMMU unit with the domain that is contained in the
380 * hwpagetable of the given mmu.
381 * Return - 0 on success else error code
382 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600383static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
384{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600385 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600386 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600387 int i, j, ret = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600388
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600389 /*
390 * Loop through all the iommu devcies under all iommu units and
391 * attach the domain
392 */
393 for (i = 0; i < iommu->unit_count; i++) {
394 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600395 iommu_pt = mmu->defaultpagetable->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600396 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600397 /*
398 * If there is a 2nd default pagetable then priv domain
399 * is attached to this pagetable
400 */
401 if (mmu->priv_bank_table &&
402 (KGSL_IOMMU_CONTEXT_PRIV == j))
403 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600404 if (!iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600405 ret = iommu_attach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600406 iommu_unit->dev[j].dev);
407 if (ret) {
408 KGSL_MEM_ERR(mmu->device,
409 "Failed to attach device, err %d\n",
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700410 ret);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600411 goto done;
412 }
413 iommu_unit->dev[j].attached = true;
414 KGSL_MEM_INFO(mmu->device,
415 "iommu pt %p attached to dev %p, ctx_id %d\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600416 iommu_pt->domain, iommu_unit->dev[j].dev,
417 iommu_unit->dev[j].ctx_id);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700418 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600419 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600420 }
421done:
422 return ret;
423}
424
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600425/*
426 * _get_iommu_ctxs - Get device pointer to IOMMU contexts
427 * @mmu - Pointer to mmu device
428 * data - Pointer to the platform data containing information about
429 * iommu devices for one iommu unit
430 * unit_id - The IOMMU unit number. This is not a specific ID but just
431 * a serial number. The serial numbers are treated as ID's of the
432 * IOMMU units
433 *
434 * Return - 0 on success else error code
435 */
436static int _get_iommu_ctxs(struct kgsl_mmu *mmu,
437 struct kgsl_device_iommu_data *data, unsigned int unit_id)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700438{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600439 struct kgsl_iommu *iommu = mmu->priv;
440 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id];
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700441 int i;
442
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600443 if (data->iommu_ctx_count > KGSL_IOMMU_MAX_DEVS_PER_UNIT) {
444 KGSL_CORE_ERR("Too many iommu devices defined for an "
445 "IOMMU unit\n");
446 return -EINVAL;
447 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700448
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600449 for (i = 0; i < data->iommu_ctx_count; i++) {
450 if (!data->iommu_ctxs[i].iommu_ctx_name)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700451 continue;
452
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600453 iommu_unit->dev[iommu_unit->dev_count].dev =
454 msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
455 if (iommu_unit->dev[iommu_unit->dev_count].dev == NULL) {
456 KGSL_CORE_ERR("Failed to get iommu dev handle for "
457 "device %s\n", data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700458 return -EINVAL;
459 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600460 if (KGSL_IOMMU_CONTEXT_USER != data->iommu_ctxs[i].ctx_id &&
461 KGSL_IOMMU_CONTEXT_PRIV != data->iommu_ctxs[i].ctx_id) {
462 KGSL_CORE_ERR("Invalid context ID defined: %d\n",
463 data->iommu_ctxs[i].ctx_id);
464 return -EINVAL;
465 }
466 iommu_unit->dev[iommu_unit->dev_count].ctx_id =
467 data->iommu_ctxs[i].ctx_id;
Jordan Crouse95b68472012-05-25 10:25:01 -0600468 iommu_unit->dev[iommu_unit->dev_count].kgsldev = mmu->device;
469
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600470 KGSL_DRV_INFO(mmu->device,
471 "Obtained dev handle %p for iommu context %s\n",
472 iommu_unit->dev[iommu_unit->dev_count].dev,
473 data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700474
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600475 iommu_unit->dev_count++;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700476 }
477
478 return 0;
479}
480
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600481/*
482 * kgsl_get_iommu_ctxt - Get device pointer to IOMMU contexts
483 * @mmu - Pointer to mmu device
484 *
485 * Get the device pointers for the IOMMU user and priv contexts of the
486 * kgsl device
487 * Return - 0 on success else error code
488 */
489static int kgsl_get_iommu_ctxt(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600490{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600491 struct platform_device *pdev =
492 container_of(mmu->device->parentdev, struct platform_device,
493 dev);
494 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
495 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700496 int i, ret = 0;
497
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600498 /* Go through the IOMMU data and get all the context devices */
499 if (KGSL_IOMMU_MAX_UNITS < pdata_dev->iommu_count) {
500 KGSL_CORE_ERR("Too many IOMMU units defined\n");
501 ret = -EINVAL;
502 goto done;
503 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700504
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600505 for (i = 0; i < pdata_dev->iommu_count; i++) {
506 ret = _get_iommu_ctxs(mmu, &pdata_dev->iommu_data[i], i);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700507 if (ret)
508 break;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600509 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600510 iommu->unit_count = pdata_dev->iommu_count;
511done:
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700512 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600513}
514
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600515/*
516 * kgsl_set_register_map - Map the IOMMU regsiters in the memory descriptors
517 * of the respective iommu units
518 * @mmu - Pointer to mmu structure
519 *
520 * Return - 0 on success else error code
521 */
522static int kgsl_set_register_map(struct kgsl_mmu *mmu)
523{
524 struct platform_device *pdev =
525 container_of(mmu->device->parentdev, struct platform_device,
526 dev);
527 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
528 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
529 struct kgsl_iommu_unit *iommu_unit;
530 int i = 0, ret = 0;
531
532 for (; i < pdata_dev->iommu_count; i++) {
533 struct kgsl_device_iommu_data data = pdata_dev->iommu_data[i];
534 iommu_unit = &iommu->iommu_units[i];
535 /* set up the IOMMU register map for the given IOMMU unit */
536 if (!data.physstart || !data.physend) {
537 KGSL_CORE_ERR("The register range for IOMMU unit not"
538 " specified\n");
539 ret = -EINVAL;
540 goto err;
541 }
542 iommu_unit->reg_map.hostptr = ioremap(data.physstart,
543 data.physend - data.physstart + 1);
544 if (!iommu_unit->reg_map.hostptr) {
545 KGSL_CORE_ERR("Failed to map SMMU register address "
546 "space from %x to %x\n", data.physstart,
547 data.physend - data.physstart + 1);
548 ret = -ENOMEM;
549 i--;
550 goto err;
551 }
552 iommu_unit->reg_map.size = data.physend - data.physstart + 1;
553 iommu_unit->reg_map.physaddr = data.physstart;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600554 memdesc_sg_phys(&iommu_unit->reg_map, data.physstart,
555 iommu_unit->reg_map.size);
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600556 }
557 iommu->unit_count = pdata_dev->iommu_count;
558 return ret;
559err:
560 /* Unmap any mapped IOMMU regions */
561 for (; i >= 0; i--) {
562 iommu_unit = &iommu->iommu_units[i];
563 iounmap(iommu_unit->reg_map.hostptr);
564 iommu_unit->reg_map.size = 0;
565 iommu_unit->reg_map.physaddr = 0;
566 }
567 return ret;
568}
569
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600570/*
571 * kgsl_iommu_pt_get_base_addr - Get the address of the pagetable that the
572 * IOMMU ttbr0 register is programmed with
573 * @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
574 *
575 * Return - actual pagetable address that the ttbr0 register is programmed
576 * with
577 */
578static unsigned int kgsl_iommu_pt_get_base_addr(struct kgsl_pagetable *pt)
579{
580 struct kgsl_iommu_pt *iommu_pt = pt->priv;
581 return iommu_get_pt_base_addr(iommu_pt->domain);
582}
583
584/*
585 * kgsl_iommu_get_pt_lsb - Return the lsb of the ttbr0 IOMMU register
586 * @mmu - Pointer to mmu structure
587 * @hostptr - Pointer to the IOMMU register map. This is used to match
588 * the iommu device whose lsb value is to be returned
589 * @ctx_id - The context bank whose lsb valus is to be returned
590 * Return - returns the lsb which is the last 14 bits of the ttbr0 IOMMU
591 * register. ttbr0 is the actual PTBR for of the IOMMU. The last 14 bits
592 * are only programmed once in the beginning when a domain is attached
593 * does not change.
594 */
595static int kgsl_iommu_get_pt_lsb(struct kgsl_mmu *mmu,
596 unsigned int unit_id,
597 enum kgsl_iommu_context_id ctx_id)
598{
599 struct kgsl_iommu *iommu = mmu->priv;
600 int i, j;
601 for (i = 0; i < iommu->unit_count; i++) {
602 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
603 for (j = 0; j < iommu_unit->dev_count; j++)
604 if (unit_id == i &&
605 ctx_id == iommu_unit->dev[j].ctx_id)
606 return iommu_unit->dev[j].pt_lsb;
607 }
608 return 0;
609}
610
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600611static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600612 struct kgsl_pagetable *pagetable,
613 unsigned int context_id)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600614{
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600615 if (mmu->flags & KGSL_FLAGS_STARTED) {
616 /* page table not current, then setup mmu to use new
617 * specified page table
618 */
619 if (mmu->hwpagetable != pagetable) {
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600620 unsigned int flags = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600621 mmu->hwpagetable = pagetable;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600622 flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
Shubhraprakash Das8649fa52012-07-26 15:49:46 -0700623 mmu->device->id) |
624 KGSL_MMUFLAGS_TLBFLUSH;
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600625 kgsl_setstate(mmu, context_id,
626 KGSL_MMUFLAGS_PTUPDATE | flags);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600627 }
628 }
629}
630
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600631static int kgsl_iommu_init(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600632{
633 /*
634 * intialize device mmu
635 *
636 * call this with the global lock held
637 */
638 int status = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600639 struct kgsl_iommu *iommu;
640
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600641 iommu = kzalloc(sizeof(struct kgsl_iommu), GFP_KERNEL);
642 if (!iommu) {
643 KGSL_CORE_ERR("kzalloc(%d) failed\n",
644 sizeof(struct kgsl_iommu));
645 return -ENOMEM;
646 }
647
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600648 mmu->priv = iommu;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600649 status = kgsl_get_iommu_ctxt(mmu);
650 if (status)
651 goto done;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600652 status = kgsl_set_register_map(mmu);
653 if (status)
654 goto done;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600655
Shubhraprakash Dase9541a32012-05-09 22:25:55 -0600656 /* A nop is required in an indirect buffer when switching
657 * pagetables in-stream */
658 kgsl_sharedmem_writel(&mmu->setstate_memory,
659 KGSL_IOMMU_SETSTATE_NOP_OFFSET,
660 cp_nop_packet(1));
661
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600662 dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600663 __func__);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600664done:
665 if (status) {
666 kfree(iommu);
667 mmu->priv = NULL;
668 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600669 return status;
670}
671
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600672/*
673 * kgsl_iommu_setup_defaultpagetable - Setup the initial defualtpagetable
674 * for iommu. This function is only called once during first start, successive
675 * start do not call this funciton.
676 * @mmu - Pointer to mmu structure
677 *
678 * Create the initial defaultpagetable and setup the iommu mappings to it
679 * Return - 0 on success else error code
680 */
681static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu)
682{
683 int status = 0;
684 int i = 0;
685 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600686 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600687 struct kgsl_pagetable *pagetable = NULL;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600688
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600689 /* If chip is not 8960 then we use the 2nd context bank for pagetable
690 * switching on the 3D side for which a separate table is allocated */
691 if (!cpu_is_msm8960()) {
692 mmu->priv_bank_table =
693 kgsl_mmu_getpagetable(KGSL_MMU_PRIV_BANK_TABLE_NAME);
694 if (mmu->priv_bank_table == NULL) {
695 status = -ENOMEM;
696 goto err;
697 }
698 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600699 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600700 mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
701 /* Return error if the default pagetable doesn't exist */
702 if (mmu->defaultpagetable == NULL) {
703 status = -ENOMEM;
704 goto err;
705 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600706 pagetable = mmu->priv_bank_table ? mmu->priv_bank_table :
707 mmu->defaultpagetable;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600708 /* Map the IOMMU regsiters to only defaultpagetable */
709 for (i = 0; i < iommu->unit_count; i++) {
710 iommu->iommu_units[i].reg_map.priv |= KGSL_MEMFLAGS_GLOBAL;
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600711 status = kgsl_mmu_map(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600712 &(iommu->iommu_units[i].reg_map),
713 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
714 if (status) {
715 iommu->iommu_units[i].reg_map.priv &=
716 ~KGSL_MEMFLAGS_GLOBAL;
717 goto err;
718 }
719 }
720 return status;
721err:
722 for (i--; i >= 0; i--) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600723 kgsl_mmu_unmap(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600724 &(iommu->iommu_units[i].reg_map));
725 iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMFLAGS_GLOBAL;
726 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600727 if (mmu->priv_bank_table) {
728 kgsl_mmu_putpagetable(mmu->priv_bank_table);
729 mmu->priv_bank_table = NULL;
730 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600731 if (mmu->defaultpagetable) {
732 kgsl_mmu_putpagetable(mmu->defaultpagetable);
733 mmu->defaultpagetable = NULL;
734 }
735 return status;
736}
737
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600738static int kgsl_iommu_start(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600739{
740 int status;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600741 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600742 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600743
744 if (mmu->flags & KGSL_FLAGS_STARTED)
745 return 0;
746
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600747 if (mmu->defaultpagetable == NULL) {
748 status = kgsl_iommu_setup_defaultpagetable(mmu);
749 if (status)
750 return -ENOMEM;
751 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600752 /* We use the GPU MMU to control access to IOMMU registers on 8960 with
753 * a225, hence we still keep the MMU active on 8960 */
754 if (cpu_is_msm8960()) {
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600755 struct kgsl_mh *mh = &(mmu->device->mh);
756 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001);
757 kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
758 mh->mpu_base +
Shubhraprakash Das2b54b5f2012-08-08 18:21:36 -0700759 iommu->iommu_units[0].reg_map.gpuaddr);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600760 } else {
761 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
762 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600763
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600764 mmu->hwpagetable = mmu->defaultpagetable;
765
766 status = kgsl_attach_pagetable_iommu_domain(mmu);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600767 if (status) {
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600768 mmu->hwpagetable = NULL;
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600769 goto done;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600770 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600771 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600772 if (status) {
773 KGSL_CORE_ERR("clk enable failed\n");
774 goto done;
775 }
776 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
777 if (status) {
778 KGSL_CORE_ERR("clk enable failed\n");
779 goto done;
780 }
781 /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as
782 * that value should not change when we change pagetables, so while
783 * changing pagetables we can use this lsb value of the pagetable w/o
784 * having to read it again
785 */
786 for (i = 0; i < iommu->unit_count; i++) {
787 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
788 for (j = 0; j < iommu_unit->dev_count; j++)
789 iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(
790 KGSL_IOMMU_GET_IOMMU_REG(
791 iommu_unit->reg_map.hostptr,
792 iommu_unit->dev[j].ctx_id,
793 TTBR0));
794 }
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600795
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600796 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600797 mmu->flags |= KGSL_FLAGS_STARTED;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600798
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600799done:
800 if (status) {
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600801 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600802 kgsl_detach_pagetable_iommu_domain(mmu);
803 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600804 return status;
805}
806
807static int
808kgsl_iommu_unmap(void *mmu_specific_pt,
Shubhraprakash Das0c811262012-06-06 23:22:19 -0600809 struct kgsl_memdesc *memdesc,
810 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600811{
812 int ret;
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600813 unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600814 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600815
816 /* All GPU addresses as assigned are page aligned, but some
817 functions purturb the gpuaddr with an offset, so apply the
818 mask here to make sure we have the right address */
819
820 unsigned int gpuaddr = memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK;
821
822 if (range == 0 || gpuaddr == 0)
823 return 0;
824
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600825 ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600826 if (ret)
827 KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600828 "with err: %d\n", iommu_pt->domain, gpuaddr,
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600829 range, ret);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600830
Shubhraprakash Das0c811262012-06-06 23:22:19 -0600831#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
832 /*
833 * Flushing only required if per process pagetables are used. With
834 * global case, flushing will happen inside iommu_map function
835 */
836 if (!ret)
837 *tlb_flags = UINT_MAX;
838#endif
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600839 return 0;
840}
841
842static int
843kgsl_iommu_map(void *mmu_specific_pt,
844 struct kgsl_memdesc *memdesc,
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600845 unsigned int protflags,
846 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600847{
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600848 int ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600849 unsigned int iommu_virt_addr;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600850 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600851 int size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600852
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600853 BUG_ON(NULL == iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600854
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600855
Jordan Croused17e9aa2011-10-12 16:57:48 -0600856 iommu_virt_addr = memdesc->gpuaddr;
857
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600858 ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600859 size, (IOMMU_READ | IOMMU_WRITE));
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600860 if (ret) {
861 KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600862 "failed with err: %d\n", iommu_pt->domain,
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600863 iommu_virt_addr, memdesc->sg, size,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600864 (IOMMU_READ | IOMMU_WRITE), ret);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600865 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600866 }
867
868 return ret;
869}
870
Shubhraprakash Das79447952012-04-26 18:12:23 -0600871static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600872{
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600873 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600874 /*
875 * stop device mmu
876 *
877 * call this with the global lock held
878 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600879
880 if (mmu->flags & KGSL_FLAGS_STARTED) {
881 /* detach iommu attachment */
882 kgsl_detach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600883 mmu->hwpagetable = NULL;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600884
885 mmu->flags &= ~KGSL_FLAGS_STARTED;
886 }
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600887
888 /* switch off MMU clocks and cancel any events it has queued */
889 iommu->clk_event_queued = false;
890 kgsl_cancel_events(mmu->device, mmu);
891 kgsl_iommu_disable_clk(mmu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600892}
893
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600894static int kgsl_iommu_close(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600895{
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600896 struct kgsl_iommu *iommu = mmu->priv;
897 int i;
898 for (i = 0; i < iommu->unit_count; i++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600899 struct kgsl_pagetable *pagetable = (mmu->priv_bank_table ?
900 mmu->priv_bank_table : mmu->defaultpagetable);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600901 if (iommu->iommu_units[i].reg_map.gpuaddr)
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600902 kgsl_mmu_unmap(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600903 &(iommu->iommu_units[i].reg_map));
904 if (iommu->iommu_units[i].reg_map.hostptr)
905 iounmap(iommu->iommu_units[i].reg_map.hostptr);
906 kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
907 iommu->iommu_units[i].reg_map.sglen);
908 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600909
910 if (mmu->priv_bank_table)
911 kgsl_mmu_putpagetable(mmu->priv_bank_table);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600912 if (mmu->defaultpagetable)
913 kgsl_mmu_putpagetable(mmu->defaultpagetable);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600914 kfree(iommu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600915
916 return 0;
917}
918
919static unsigned int
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600920kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600921{
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600922 unsigned int pt_base;
923 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das64a745c2012-06-11 16:44:16 -0600924 /* We cannot enable or disable the clocks in interrupt context, this
925 function is called from interrupt context if there is an axi error */
926 if (in_interrupt())
927 return 0;
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600928 /* Return the current pt base by reading IOMMU pt_base register */
929 kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
930 pt_base = readl_relaxed(iommu->iommu_units[0].reg_map.hostptr +
931 (KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
932 KGSL_IOMMU_TTBR0);
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600933 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600934 return pt_base & (KGSL_IOMMU_TTBR0_PA_MASK <<
935 KGSL_IOMMU_TTBR0_PA_SHIFT);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600936}
937
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600938/*
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600939 * kgsl_iommu_default_setstate - Change the IOMMU pagetable or flush IOMMU tlb
940 * of the primary context bank
941 * @mmu - Pointer to mmu structure
942 * @flags - Flags indicating whether pagetable has to chnage or tlb is to be
943 * flushed or both
944 *
945 * Based on flags set the new pagetable fo the IOMMU unit or flush it's tlb or
946 * do both by doing direct register writes to the IOMMu registers through the
947 * cpu
948 * Return - void
949 */
950static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
951 uint32_t flags)
952{
953 struct kgsl_iommu *iommu = mmu->priv;
954 int temp;
955 int i;
956 unsigned int pt_base = kgsl_iommu_pt_get_base_addr(
957 mmu->hwpagetable);
958 unsigned int pt_val;
959
960 if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
961 KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
962 return;
963 }
964 /* Mask off the lsb of the pt base address since lsb will not change */
965 pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK << KGSL_IOMMU_TTBR0_PA_SHIFT);
966 if (flags & KGSL_MMUFLAGS_PTUPDATE) {
Jordan Crousea29a2e02012-08-14 09:09:23 -0600967 kgsl_idle(mmu->device);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600968 for (i = 0; i < iommu->unit_count; i++) {
969 /* get the lsb value which should not change when
970 * changing ttbr0 */
971 pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
972 KGSL_IOMMU_CONTEXT_USER);
973 pt_val += pt_base;
974
975 KGSL_IOMMU_SET_IOMMU_REG(
976 iommu->iommu_units[i].reg_map.hostptr,
977 KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
978
979 mb();
980 temp = KGSL_IOMMU_GET_IOMMU_REG(
981 iommu->iommu_units[i].reg_map.hostptr,
982 KGSL_IOMMU_CONTEXT_USER, TTBR0);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600983 }
984 }
985 /* Flush tlb */
986 if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
987 for (i = 0; i < iommu->unit_count; i++) {
988 KGSL_IOMMU_SET_IOMMU_REG(
989 iommu->iommu_units[i].reg_map.hostptr,
Shubhraprakash Das8649fa52012-07-26 15:49:46 -0700990 KGSL_IOMMU_CONTEXT_USER, CTX_TLBIALL,
991 1);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600992 mb();
993 }
994 }
995 /* Disable smmu clock */
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600996 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600997}
998
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -0600999/*
1000 * kgsl_iommu_get_reg_map_desc - Returns an array of pointers that contain
1001 * the address of memory descriptors which map the IOMMU registers
1002 * @mmu - Pointer to mmu structure
1003 * @reg_map_desc - Out parameter in which the address of the array containing
1004 * pointers to register map descriptors is returned. The caller is supposed
1005 * to free this array
1006 *
1007 * Return - The number of iommu units which is also the number of register
1008 * mapped descriptor arrays which the out parameter will have
1009 */
1010static int kgsl_iommu_get_reg_map_desc(struct kgsl_mmu *mmu,
1011 void **reg_map_desc)
1012{
1013 struct kgsl_iommu *iommu = mmu->priv;
1014 void **reg_desc_ptr;
1015 int i;
1016
1017 /*
1018 * Alocate array of pointers that will hold address of the register map
1019 * descriptors
1020 */
1021 reg_desc_ptr = kmalloc(iommu->unit_count *
1022 sizeof(struct kgsl_memdesc *), GFP_KERNEL);
1023 if (!reg_desc_ptr) {
1024 KGSL_CORE_ERR("Failed to kmalloc(%d)\n",
1025 iommu->unit_count * sizeof(struct kgsl_memdesc *));
1026 return -ENOMEM;
1027 }
1028
1029 for (i = 0; i < iommu->unit_count; i++)
1030 reg_desc_ptr[i] = &(iommu->iommu_units[i].reg_map);
1031
1032 *reg_map_desc = reg_desc_ptr;
1033 return i;
1034}
1035
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001036struct kgsl_mmu_ops iommu_ops = {
1037 .mmu_init = kgsl_iommu_init,
1038 .mmu_close = kgsl_iommu_close,
1039 .mmu_start = kgsl_iommu_start,
1040 .mmu_stop = kgsl_iommu_stop,
1041 .mmu_setstate = kgsl_iommu_setstate,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001042 .mmu_device_setstate = kgsl_iommu_default_setstate,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001043 .mmu_pagefault = NULL,
1044 .mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -06001045 .mmu_enable_clk = kgsl_iommu_enable_clk,
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001046 .mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
Shubhraprakash Dasfce27362012-05-09 17:44:14 -06001047 .mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001048 .mmu_get_reg_map_desc = kgsl_iommu_get_reg_map_desc,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001049};
1050
1051struct kgsl_mmu_pt_ops iommu_pt_ops = {
1052 .mmu_map = kgsl_iommu_map,
1053 .mmu_unmap = kgsl_iommu_unmap,
1054 .mmu_create_pagetable = kgsl_iommu_create_pagetable,
1055 .mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
1056 .mmu_pt_equal = kgsl_iommu_pt_equal,
Shubhraprakash Das5a610b52012-05-09 17:31:54 -06001057 .mmu_pt_get_base_addr = kgsl_iommu_pt_get_base_addr,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001058};