blob: 016771bf8114d560c5860065b89dc09c0fedac45 [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 Dasc6e21012012-05-11 17:24:51 -0600759 iommu->iommu_units
760 [iommu->unit_count - 1].reg_map.gpuaddr -
761 PAGE_SIZE);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600762 } else {
763 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
764 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600765
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600766 mmu->hwpagetable = mmu->defaultpagetable;
767
768 status = kgsl_attach_pagetable_iommu_domain(mmu);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600769 if (status) {
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600770 mmu->hwpagetable = NULL;
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600771 goto done;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600772 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600773 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600774 if (status) {
775 KGSL_CORE_ERR("clk enable failed\n");
776 goto done;
777 }
778 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
779 if (status) {
780 KGSL_CORE_ERR("clk enable failed\n");
781 goto done;
782 }
783 /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as
784 * that value should not change when we change pagetables, so while
785 * changing pagetables we can use this lsb value of the pagetable w/o
786 * having to read it again
787 */
788 for (i = 0; i < iommu->unit_count; i++) {
789 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
790 for (j = 0; j < iommu_unit->dev_count; j++)
791 iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(
792 KGSL_IOMMU_GET_IOMMU_REG(
793 iommu_unit->reg_map.hostptr,
794 iommu_unit->dev[j].ctx_id,
795 TTBR0));
796 }
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600797
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600798 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600799 mmu->flags |= KGSL_FLAGS_STARTED;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600800
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600801done:
802 if (status) {
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600803 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600804 kgsl_detach_pagetable_iommu_domain(mmu);
805 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600806 return status;
807}
808
809static int
810kgsl_iommu_unmap(void *mmu_specific_pt,
Shubhraprakash Das0c811262012-06-06 23:22:19 -0600811 struct kgsl_memdesc *memdesc,
812 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600813{
814 int ret;
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600815 unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600816 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600817
818 /* All GPU addresses as assigned are page aligned, but some
819 functions purturb the gpuaddr with an offset, so apply the
820 mask here to make sure we have the right address */
821
822 unsigned int gpuaddr = memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK;
823
824 if (range == 0 || gpuaddr == 0)
825 return 0;
826
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600827 ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600828 if (ret)
829 KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600830 "with err: %d\n", iommu_pt->domain, gpuaddr,
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600831 range, ret);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600832
Shubhraprakash Das0c811262012-06-06 23:22:19 -0600833#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
834 /*
835 * Flushing only required if per process pagetables are used. With
836 * global case, flushing will happen inside iommu_map function
837 */
838 if (!ret)
839 *tlb_flags = UINT_MAX;
840#endif
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600841 return 0;
842}
843
844static int
845kgsl_iommu_map(void *mmu_specific_pt,
846 struct kgsl_memdesc *memdesc,
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600847 unsigned int protflags,
848 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600849{
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600850 int ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600851 unsigned int iommu_virt_addr;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600852 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600853 int size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600854
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600855 BUG_ON(NULL == iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600856
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600857
Jordan Croused17e9aa2011-10-12 16:57:48 -0600858 iommu_virt_addr = memdesc->gpuaddr;
859
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600860 ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600861 size, (IOMMU_READ | IOMMU_WRITE));
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600862 if (ret) {
863 KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600864 "failed with err: %d\n", iommu_pt->domain,
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600865 iommu_virt_addr, memdesc->sg, size,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600866 (IOMMU_READ | IOMMU_WRITE), ret);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600867 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600868 }
869
870 return ret;
871}
872
Shubhraprakash Das79447952012-04-26 18:12:23 -0600873static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600874{
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600875 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600876 /*
877 * stop device mmu
878 *
879 * call this with the global lock held
880 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600881
882 if (mmu->flags & KGSL_FLAGS_STARTED) {
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600883 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600884 /* detach iommu attachment */
885 kgsl_detach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600886 mmu->hwpagetable = NULL;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600887
888 mmu->flags &= ~KGSL_FLAGS_STARTED;
889 }
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600890
891 /* switch off MMU clocks and cancel any events it has queued */
892 iommu->clk_event_queued = false;
893 kgsl_cancel_events(mmu->device, mmu);
894 kgsl_iommu_disable_clk(mmu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600895}
896
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600897static int kgsl_iommu_close(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600898{
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600899 struct kgsl_iommu *iommu = mmu->priv;
900 int i;
901 for (i = 0; i < iommu->unit_count; i++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600902 struct kgsl_pagetable *pagetable = (mmu->priv_bank_table ?
903 mmu->priv_bank_table : mmu->defaultpagetable);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600904 if (iommu->iommu_units[i].reg_map.gpuaddr)
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600905 kgsl_mmu_unmap(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600906 &(iommu->iommu_units[i].reg_map));
907 if (iommu->iommu_units[i].reg_map.hostptr)
908 iounmap(iommu->iommu_units[i].reg_map.hostptr);
909 kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
910 iommu->iommu_units[i].reg_map.sglen);
911 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600912
913 if (mmu->priv_bank_table)
914 kgsl_mmu_putpagetable(mmu->priv_bank_table);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600915 if (mmu->defaultpagetable)
916 kgsl_mmu_putpagetable(mmu->defaultpagetable);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600917 kfree(iommu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600918
919 return 0;
920}
921
922static unsigned int
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600923kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600924{
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600925 unsigned int pt_base;
926 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das64a745c2012-06-11 16:44:16 -0600927 /* We cannot enable or disable the clocks in interrupt context, this
928 function is called from interrupt context if there is an axi error */
929 if (in_interrupt())
930 return 0;
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600931 /* Return the current pt base by reading IOMMU pt_base register */
932 kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
933 pt_base = readl_relaxed(iommu->iommu_units[0].reg_map.hostptr +
934 (KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
935 KGSL_IOMMU_TTBR0);
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600936 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600937 return pt_base & (KGSL_IOMMU_TTBR0_PA_MASK <<
938 KGSL_IOMMU_TTBR0_PA_SHIFT);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600939}
940
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600941/*
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600942 * kgsl_iommu_default_setstate - Change the IOMMU pagetable or flush IOMMU tlb
943 * of the primary context bank
944 * @mmu - Pointer to mmu structure
945 * @flags - Flags indicating whether pagetable has to chnage or tlb is to be
946 * flushed or both
947 *
948 * Based on flags set the new pagetable fo the IOMMU unit or flush it's tlb or
949 * do both by doing direct register writes to the IOMMu registers through the
950 * cpu
951 * Return - void
952 */
953static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
954 uint32_t flags)
955{
956 struct kgsl_iommu *iommu = mmu->priv;
957 int temp;
958 int i;
959 unsigned int pt_base = kgsl_iommu_pt_get_base_addr(
960 mmu->hwpagetable);
961 unsigned int pt_val;
962
963 if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
964 KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
965 return;
966 }
967 /* Mask off the lsb of the pt base address since lsb will not change */
968 pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK << KGSL_IOMMU_TTBR0_PA_SHIFT);
969 if (flags & KGSL_MMUFLAGS_PTUPDATE) {
970 kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
971 for (i = 0; i < iommu->unit_count; i++) {
972 /* get the lsb value which should not change when
973 * changing ttbr0 */
974 pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
975 KGSL_IOMMU_CONTEXT_USER);
976 pt_val += pt_base;
977
978 KGSL_IOMMU_SET_IOMMU_REG(
979 iommu->iommu_units[i].reg_map.hostptr,
980 KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
981
982 mb();
983 temp = KGSL_IOMMU_GET_IOMMU_REG(
984 iommu->iommu_units[i].reg_map.hostptr,
985 KGSL_IOMMU_CONTEXT_USER, TTBR0);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600986 }
987 }
988 /* Flush tlb */
989 if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
990 for (i = 0; i < iommu->unit_count; i++) {
991 KGSL_IOMMU_SET_IOMMU_REG(
992 iommu->iommu_units[i].reg_map.hostptr,
Shubhraprakash Das8649fa52012-07-26 15:49:46 -0700993 KGSL_IOMMU_CONTEXT_USER, CTX_TLBIALL,
994 1);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600995 mb();
996 }
997 }
998 /* Disable smmu clock */
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600999 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001000}
1001
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001002/*
1003 * kgsl_iommu_get_reg_map_desc - Returns an array of pointers that contain
1004 * the address of memory descriptors which map the IOMMU registers
1005 * @mmu - Pointer to mmu structure
1006 * @reg_map_desc - Out parameter in which the address of the array containing
1007 * pointers to register map descriptors is returned. The caller is supposed
1008 * to free this array
1009 *
1010 * Return - The number of iommu units which is also the number of register
1011 * mapped descriptor arrays which the out parameter will have
1012 */
1013static int kgsl_iommu_get_reg_map_desc(struct kgsl_mmu *mmu,
1014 void **reg_map_desc)
1015{
1016 struct kgsl_iommu *iommu = mmu->priv;
1017 void **reg_desc_ptr;
1018 int i;
1019
1020 /*
1021 * Alocate array of pointers that will hold address of the register map
1022 * descriptors
1023 */
1024 reg_desc_ptr = kmalloc(iommu->unit_count *
1025 sizeof(struct kgsl_memdesc *), GFP_KERNEL);
1026 if (!reg_desc_ptr) {
1027 KGSL_CORE_ERR("Failed to kmalloc(%d)\n",
1028 iommu->unit_count * sizeof(struct kgsl_memdesc *));
1029 return -ENOMEM;
1030 }
1031
1032 for (i = 0; i < iommu->unit_count; i++)
1033 reg_desc_ptr[i] = &(iommu->iommu_units[i].reg_map);
1034
1035 *reg_map_desc = reg_desc_ptr;
1036 return i;
1037}
1038
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001039struct kgsl_mmu_ops iommu_ops = {
1040 .mmu_init = kgsl_iommu_init,
1041 .mmu_close = kgsl_iommu_close,
1042 .mmu_start = kgsl_iommu_start,
1043 .mmu_stop = kgsl_iommu_stop,
1044 .mmu_setstate = kgsl_iommu_setstate,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001045 .mmu_device_setstate = kgsl_iommu_default_setstate,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001046 .mmu_pagefault = NULL,
1047 .mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -06001048 .mmu_enable_clk = kgsl_iommu_enable_clk,
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001049 .mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
Shubhraprakash Dasfce27362012-05-09 17:44:14 -06001050 .mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001051 .mmu_get_reg_map_desc = kgsl_iommu_get_reg_map_desc,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001052};
1053
1054struct kgsl_mmu_pt_ops iommu_pt_ops = {
1055 .mmu_map = kgsl_iommu_map,
1056 .mmu_unmap = kgsl_iommu_unmap,
1057 .mmu_create_pagetable = kgsl_iommu_create_pagetable,
1058 .mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
1059 .mmu_pt_equal = kgsl_iommu_pt_equal,
Shubhraprakash Das5a610b52012-05-09 17:31:54 -06001060 .mmu_pt_get_base_addr = kgsl_iommu_pt_get_base_addr,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001061};