blob: a27824a0455653e6650396d2b53b7623b3fcdbab [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>
20
21#include "kgsl.h"
22#include "kgsl_device.h"
23#include "kgsl_mmu.h"
24#include "kgsl_sharedmem.h"
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -060025#include "kgsl_iommu.h"
Shubhraprakash Das767fdda2011-08-15 15:49:45 -060026
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -060027/*
28 * kgsl_iommu_disable_clk - Disable iommu clocks
29 * @mmu - Pointer to mmu structure
30 *
31 * Disables iommu clocks
32 * Return - void
33 */
34static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu)
35{
36 struct kgsl_iommu *iommu = mmu->priv;
37 struct msm_iommu_drvdata *iommu_drvdata;
38 int i, j;
39
40 for (i = 0; i < iommu->unit_count; i++) {
41 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
42 for (j = 0; j < iommu_unit->dev_count; j++) {
43 if (!iommu_unit->dev[j].clk_enabled)
44 continue;
45 iommu_drvdata = dev_get_drvdata(
46 iommu_unit->dev[j].dev->parent);
47 if (iommu_drvdata->clk)
48 clk_disable_unprepare(iommu_drvdata->clk);
49 clk_disable_unprepare(iommu_drvdata->pclk);
50 iommu_unit->dev[j].clk_enabled = false;
51 }
52 }
53}
54
55/*
56 * kgsl_iommu_enable_clk - Enable iommu clocks
57 * @mmu - Pointer to mmu structure
58 * @ctx_id - The context bank whose clocks are to be turned on
59 *
60 * Enables iommu clocks of a given context
61 * Return: 0 on success else error code
62 */
63static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu,
64 int ctx_id)
65{
66 int ret = 0;
67 int i, j;
68 struct kgsl_iommu *iommu = mmu->priv;
69 struct msm_iommu_drvdata *iommu_drvdata;
70
71 for (i = 0; i < iommu->unit_count; i++) {
72 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
73 for (j = 0; j < iommu_unit->dev_count; j++) {
74 if (iommu_unit->dev[j].clk_enabled ||
75 ctx_id != iommu_unit->dev[j].ctx_id)
76 continue;
77 iommu_drvdata =
78 dev_get_drvdata(iommu_unit->dev[j].dev->parent);
79 ret = clk_prepare_enable(iommu_drvdata->pclk);
80 if (ret)
81 goto done;
82 if (iommu_drvdata->clk) {
83 ret = clk_prepare_enable(iommu_drvdata->clk);
84 if (ret) {
85 clk_disable_unprepare(
86 iommu_drvdata->pclk);
87 goto done;
88 }
89 }
90 iommu_unit->dev[j].clk_enabled = true;
91 }
92 }
93done:
94 if (ret)
95 kgsl_iommu_disable_clk(mmu);
96 return ret;
97}
98
Shubhraprakash Das48d97302012-05-07 12:16:08 -060099/*
100 * kgsl_iommu_pt_equal - Check if pagetables are equal
101 * @pt - Pointer to pagetable
102 * @pt_base - Address of a pagetable that the IOMMU register is
103 * programmed with
104 *
105 * Checks whether the pt_base is equal to the base address of
106 * the pagetable which is contained in the pt structure
107 * Return - Non-zero if the pagetable addresses are equal else 0
108 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600109static int kgsl_iommu_pt_equal(struct kgsl_pagetable *pt,
110 unsigned int pt_base)
111{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600112 struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
113 unsigned int domain_ptbase = iommu_pt ?
114 iommu_get_pt_base_addr(iommu_pt->domain) : 0;
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600115 /* Only compare the valid address bits of the pt_base */
116 domain_ptbase &= (KGSL_IOMMU_TTBR0_PA_MASK <<
117 KGSL_IOMMU_TTBR0_PA_SHIFT);
118 pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK <<
119 KGSL_IOMMU_TTBR0_PA_SHIFT);
120 return domain_ptbase && pt_base &&
121 (domain_ptbase == pt_base);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600122}
123
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600124/*
125 * kgsl_iommu_destroy_pagetable - Free up reaources help by a pagetable
126 * @mmu_specific_pt - Pointer to pagetable which is to be freed
127 *
128 * Return - void
129 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600130static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
131{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600132 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
133 if (iommu_pt->domain)
134 iommu_domain_free(iommu_pt->domain);
135 if (iommu_pt->iommu) {
136 if ((KGSL_IOMMU_ASID_REUSE == iommu_pt->asid) &&
137 iommu_pt->iommu->asid_reuse)
138 iommu_pt->iommu->asid_reuse--;
139 if (!iommu_pt->iommu->asid_reuse ||
140 (KGSL_IOMMU_ASID_REUSE != iommu_pt->asid))
141 clear_bit(iommu_pt->asid, iommu_pt->iommu->asids);
142 }
143 kfree(iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600144}
145
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600146/*
147 * kgsl_iommu_create_pagetable - Create a IOMMU pagetable
148 *
149 * Allocate memory to hold a pagetable and allocate the IOMMU
150 * domain which is the actual IOMMU pagetable
151 * Return - void
152 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600153void *kgsl_iommu_create_pagetable(void)
154{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600155 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600156
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600157 iommu_pt = kzalloc(sizeof(struct kgsl_iommu_pt), GFP_KERNEL);
158 if (!iommu_pt) {
159 KGSL_CORE_ERR("kzalloc(%d) failed\n",
160 sizeof(struct kgsl_iommu_pt));
161 return NULL;
162 }
163 iommu_pt->domain = iommu_domain_alloc(0);
164 if (!iommu_pt->domain) {
165 KGSL_CORE_ERR("Failed to create iommu domain\n");
166 kfree(iommu_pt);
167 return NULL;
168 }
169 return iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600170}
171
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600172/*
173 * kgsl_detach_pagetable_iommu_domain - Detach the IOMMU unit from a
174 * pagetable
175 * @mmu - Pointer to the device mmu structure
176 * @priv - Flag indicating whether the private or user context is to be
177 * detached
178 *
179 * Detach the IOMMU unit with the domain that is contained in the
180 * hwpagetable of the given mmu. After detaching the IOMMU unit is not
181 * in use because the PTBR will not be set after a detach
182 * Return - void
183 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600184static void kgsl_detach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
185{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600186 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600187 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600188 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600189
190 BUG_ON(mmu->hwpagetable == NULL);
191 BUG_ON(mmu->hwpagetable->priv == NULL);
192
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600193 iommu_pt = mmu->hwpagetable->priv;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600194
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600195 for (i = 0; i < iommu->unit_count; i++) {
196 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
197 for (j = 0; j < iommu_unit->dev_count; j++) {
198 if (iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600199 iommu_detach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600200 iommu_unit->dev[j].dev);
201 iommu_unit->dev[j].attached = false;
202 KGSL_MEM_INFO(mmu->device, "iommu %p detached "
203 "from user dev of MMU: %p\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600204 iommu_pt->domain, mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600205 }
206 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600207 }
208}
209
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600210/*
211 * kgsl_attach_pagetable_iommu_domain - Attach the IOMMU unit to a
212 * pagetable, i.e set the IOMMU's PTBR to the pagetable address and
213 * setup other IOMMU registers for the device so that it becomes
214 * active
215 * @mmu - Pointer to the device mmu structure
216 * @priv - Flag indicating whether the private or user context is to be
217 * attached
218 *
219 * Attach the IOMMU unit with the domain that is contained in the
220 * hwpagetable of the given mmu.
221 * Return - 0 on success else error code
222 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600223static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
224{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600225 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600226 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600227 int i, j, ret = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600228
229 BUG_ON(mmu->hwpagetable == NULL);
230 BUG_ON(mmu->hwpagetable->priv == NULL);
231
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600232 iommu_pt = mmu->hwpagetable->priv;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600233
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600234 /*
235 * Loop through all the iommu devcies under all iommu units and
236 * attach the domain
237 */
238 for (i = 0; i < iommu->unit_count; i++) {
239 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
240 for (j = 0; j < iommu_unit->dev_count; j++) {
241 if (!iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600242 ret = iommu_attach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600243 iommu_unit->dev[j].dev);
244 if (ret) {
245 KGSL_MEM_ERR(mmu->device,
246 "Failed to attach device, err %d\n",
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700247 ret);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600248 goto done;
249 }
250 iommu_unit->dev[j].attached = true;
251 KGSL_MEM_INFO(mmu->device,
252 "iommu pt %p attached to dev %p, ctx_id %d\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600253 iommu_pt->domain, iommu_unit->dev[j].dev,
254 iommu_unit->dev[j].ctx_id);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700255 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600256 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600257 }
258done:
259 return ret;
260}
261
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600262/*
263 * _get_iommu_ctxs - Get device pointer to IOMMU contexts
264 * @mmu - Pointer to mmu device
265 * data - Pointer to the platform data containing information about
266 * iommu devices for one iommu unit
267 * unit_id - The IOMMU unit number. This is not a specific ID but just
268 * a serial number. The serial numbers are treated as ID's of the
269 * IOMMU units
270 *
271 * Return - 0 on success else error code
272 */
273static int _get_iommu_ctxs(struct kgsl_mmu *mmu,
274 struct kgsl_device_iommu_data *data, unsigned int unit_id)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700275{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600276 struct kgsl_iommu *iommu = mmu->priv;
277 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id];
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700278 int i;
279
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600280 if (data->iommu_ctx_count > KGSL_IOMMU_MAX_DEVS_PER_UNIT) {
281 KGSL_CORE_ERR("Too many iommu devices defined for an "
282 "IOMMU unit\n");
283 return -EINVAL;
284 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700285
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600286 for (i = 0; i < data->iommu_ctx_count; i++) {
287 if (!data->iommu_ctxs[i].iommu_ctx_name)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700288 continue;
289
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600290 iommu_unit->dev[iommu_unit->dev_count].dev =
291 msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
292 if (iommu_unit->dev[iommu_unit->dev_count].dev == NULL) {
293 KGSL_CORE_ERR("Failed to get iommu dev handle for "
294 "device %s\n", data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700295 return -EINVAL;
296 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600297 if (KGSL_IOMMU_CONTEXT_USER != data->iommu_ctxs[i].ctx_id &&
298 KGSL_IOMMU_CONTEXT_PRIV != data->iommu_ctxs[i].ctx_id) {
299 KGSL_CORE_ERR("Invalid context ID defined: %d\n",
300 data->iommu_ctxs[i].ctx_id);
301 return -EINVAL;
302 }
303 iommu_unit->dev[iommu_unit->dev_count].ctx_id =
304 data->iommu_ctxs[i].ctx_id;
305 KGSL_DRV_INFO(mmu->device,
306 "Obtained dev handle %p for iommu context %s\n",
307 iommu_unit->dev[iommu_unit->dev_count].dev,
308 data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700309
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600310 iommu_unit->dev_count++;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700311 }
312
313 return 0;
314}
315
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600316/*
317 * kgsl_get_iommu_ctxt - Get device pointer to IOMMU contexts
318 * @mmu - Pointer to mmu device
319 *
320 * Get the device pointers for the IOMMU user and priv contexts of the
321 * kgsl device
322 * Return - 0 on success else error code
323 */
324static int kgsl_get_iommu_ctxt(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600325{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600326 struct platform_device *pdev =
327 container_of(mmu->device->parentdev, struct platform_device,
328 dev);
329 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
330 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700331 int i, ret = 0;
332
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600333 /* Go through the IOMMU data and get all the context devices */
334 if (KGSL_IOMMU_MAX_UNITS < pdata_dev->iommu_count) {
335 KGSL_CORE_ERR("Too many IOMMU units defined\n");
336 ret = -EINVAL;
337 goto done;
338 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700339
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600340 for (i = 0; i < pdata_dev->iommu_count; i++) {
341 ret = _get_iommu_ctxs(mmu, &pdata_dev->iommu_data[i], i);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700342 if (ret)
343 break;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600344 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600345 iommu->unit_count = pdata_dev->iommu_count;
346done:
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700347 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600348}
349
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600350/*
351 * kgsl_set_register_map - Map the IOMMU regsiters in the memory descriptors
352 * of the respective iommu units
353 * @mmu - Pointer to mmu structure
354 *
355 * Return - 0 on success else error code
356 */
357static int kgsl_set_register_map(struct kgsl_mmu *mmu)
358{
359 struct platform_device *pdev =
360 container_of(mmu->device->parentdev, struct platform_device,
361 dev);
362 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
363 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
364 struct kgsl_iommu_unit *iommu_unit;
365 int i = 0, ret = 0;
366
367 for (; i < pdata_dev->iommu_count; i++) {
368 struct kgsl_device_iommu_data data = pdata_dev->iommu_data[i];
369 iommu_unit = &iommu->iommu_units[i];
370 /* set up the IOMMU register map for the given IOMMU unit */
371 if (!data.physstart || !data.physend) {
372 KGSL_CORE_ERR("The register range for IOMMU unit not"
373 " specified\n");
374 ret = -EINVAL;
375 goto err;
376 }
377 iommu_unit->reg_map.hostptr = ioremap(data.physstart,
378 data.physend - data.physstart + 1);
379 if (!iommu_unit->reg_map.hostptr) {
380 KGSL_CORE_ERR("Failed to map SMMU register address "
381 "space from %x to %x\n", data.physstart,
382 data.physend - data.physstart + 1);
383 ret = -ENOMEM;
384 i--;
385 goto err;
386 }
387 iommu_unit->reg_map.size = data.physend - data.physstart + 1;
388 iommu_unit->reg_map.physaddr = data.physstart;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600389 memdesc_sg_phys(&iommu_unit->reg_map, data.physstart,
390 iommu_unit->reg_map.size);
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600391 }
392 iommu->unit_count = pdata_dev->iommu_count;
393 return ret;
394err:
395 /* Unmap any mapped IOMMU regions */
396 for (; i >= 0; i--) {
397 iommu_unit = &iommu->iommu_units[i];
398 iounmap(iommu_unit->reg_map.hostptr);
399 iommu_unit->reg_map.size = 0;
400 iommu_unit->reg_map.physaddr = 0;
401 }
402 return ret;
403}
404
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600405/*
406 * kgsl_iommu_pt_get_base_addr - Get the address of the pagetable that the
407 * IOMMU ttbr0 register is programmed with
408 * @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
409 *
410 * Return - actual pagetable address that the ttbr0 register is programmed
411 * with
412 */
413static unsigned int kgsl_iommu_pt_get_base_addr(struct kgsl_pagetable *pt)
414{
415 struct kgsl_iommu_pt *iommu_pt = pt->priv;
416 return iommu_get_pt_base_addr(iommu_pt->domain);
417}
418
419/*
420 * kgsl_iommu_get_pt_lsb - Return the lsb of the ttbr0 IOMMU register
421 * @mmu - Pointer to mmu structure
422 * @hostptr - Pointer to the IOMMU register map. This is used to match
423 * the iommu device whose lsb value is to be returned
424 * @ctx_id - The context bank whose lsb valus is to be returned
425 * Return - returns the lsb which is the last 14 bits of the ttbr0 IOMMU
426 * register. ttbr0 is the actual PTBR for of the IOMMU. The last 14 bits
427 * are only programmed once in the beginning when a domain is attached
428 * does not change.
429 */
430static int kgsl_iommu_get_pt_lsb(struct kgsl_mmu *mmu,
431 unsigned int unit_id,
432 enum kgsl_iommu_context_id ctx_id)
433{
434 struct kgsl_iommu *iommu = mmu->priv;
435 int i, j;
436 for (i = 0; i < iommu->unit_count; i++) {
437 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
438 for (j = 0; j < iommu_unit->dev_count; j++)
439 if (unit_id == i &&
440 ctx_id == iommu_unit->dev[j].ctx_id)
441 return iommu_unit->dev[j].pt_lsb;
442 }
443 return 0;
444}
445
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600446static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600447 struct kgsl_pagetable *pagetable)
448{
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600449 if (mmu->flags & KGSL_FLAGS_STARTED) {
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600450 struct kgsl_iommu *iommu = mmu->priv;
451 struct kgsl_iommu_pt *iommu_pt = pagetable->priv;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600452 /* page table not current, then setup mmu to use new
453 * specified page table
454 */
455 if (mmu->hwpagetable != pagetable) {
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600456 unsigned int flags = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600457 mmu->hwpagetable = pagetable;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600458 /* force tlb flush if asid is reused */
459 if (iommu->asid_reuse &&
460 (KGSL_IOMMU_ASID_REUSE == iommu_pt->asid))
461 flags |= KGSL_MMUFLAGS_TLBFLUSH;
462 flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
463 mmu->device->id);
464 kgsl_setstate(mmu, KGSL_MMUFLAGS_PTUPDATE | flags);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600465 }
466 }
467}
468
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600469static int kgsl_iommu_init(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600470{
471 /*
472 * intialize device mmu
473 *
474 * call this with the global lock held
475 */
476 int status = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600477 struct kgsl_iommu *iommu;
478
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600479 iommu = kzalloc(sizeof(struct kgsl_iommu), GFP_KERNEL);
480 if (!iommu) {
481 KGSL_CORE_ERR("kzalloc(%d) failed\n",
482 sizeof(struct kgsl_iommu));
483 return -ENOMEM;
484 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600485 iommu->asids = kzalloc(BITS_TO_LONGS(KGSL_IOMMU_MAX_ASIDS) *
486 sizeof(unsigned long), GFP_KERNEL);
487 if (!iommu->asids) {
488 KGSL_CORE_ERR("kzalloc(%d) failed\n",
489 sizeof(struct kgsl_iommu));
490 status = -ENOMEM;
491 goto done;
492 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600493
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600494 mmu->priv = iommu;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600495 status = kgsl_get_iommu_ctxt(mmu);
496 if (status)
497 goto done;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600498 status = kgsl_set_register_map(mmu);
499 if (status)
500 goto done;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600501
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600502 dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600503 __func__);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600504done:
505 if (status) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600506 kfree(iommu->asids);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600507 kfree(iommu);
508 mmu->priv = NULL;
509 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600510 return status;
511}
512
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600513/*
514 * kgsl_iommu_setup_defaultpagetable - Setup the initial defualtpagetable
515 * for iommu. This function is only called once during first start, successive
516 * start do not call this funciton.
517 * @mmu - Pointer to mmu structure
518 *
519 * Create the initial defaultpagetable and setup the iommu mappings to it
520 * Return - 0 on success else error code
521 */
522static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu)
523{
524 int status = 0;
525 int i = 0;
526 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600527 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600528
529 mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
530 /* Return error if the default pagetable doesn't exist */
531 if (mmu->defaultpagetable == NULL) {
532 status = -ENOMEM;
533 goto err;
534 }
535 /* Map the IOMMU regsiters to only defaultpagetable */
536 for (i = 0; i < iommu->unit_count; i++) {
537 iommu->iommu_units[i].reg_map.priv |= KGSL_MEMFLAGS_GLOBAL;
538 status = kgsl_mmu_map(mmu->defaultpagetable,
539 &(iommu->iommu_units[i].reg_map),
540 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
541 if (status) {
542 iommu->iommu_units[i].reg_map.priv &=
543 ~KGSL_MEMFLAGS_GLOBAL;
544 goto err;
545 }
546 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600547 /*
548 * The dafault pagetable always has asid 0 assigned by the iommu driver
549 * and asid 1 is assigned to the private context.
550 */
551 iommu_pt = mmu->defaultpagetable->priv;
552 iommu_pt->asid = 0;
553 set_bit(0, iommu->asids);
554 set_bit(1, iommu->asids);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600555 return status;
556err:
557 for (i--; i >= 0; i--) {
558 kgsl_mmu_unmap(mmu->defaultpagetable,
559 &(iommu->iommu_units[i].reg_map));
560 iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMFLAGS_GLOBAL;
561 }
562 if (mmu->defaultpagetable) {
563 kgsl_mmu_putpagetable(mmu->defaultpagetable);
564 mmu->defaultpagetable = NULL;
565 }
566 return status;
567}
568
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600569static int kgsl_iommu_start(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600570{
571 int status;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600572 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600573 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600574
575 if (mmu->flags & KGSL_FLAGS_STARTED)
576 return 0;
577
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600578 if (mmu->defaultpagetable == NULL) {
579 status = kgsl_iommu_setup_defaultpagetable(mmu);
580 if (status)
581 return -ENOMEM;
582 }
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600583 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600584
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600585 mmu->hwpagetable = mmu->defaultpagetable;
586
587 status = kgsl_attach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600588 if (!status) {
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600589 mmu->flags |= KGSL_FLAGS_STARTED;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600590 } else {
591 kgsl_detach_pagetable_iommu_domain(mmu);
592 mmu->hwpagetable = NULL;
593 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600594 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600595 if (status) {
596 KGSL_CORE_ERR("clk enable failed\n");
597 goto done;
598 }
599 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
600 if (status) {
601 KGSL_CORE_ERR("clk enable failed\n");
602 goto done;
603 }
604 /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as
605 * that value should not change when we change pagetables, so while
606 * changing pagetables we can use this lsb value of the pagetable w/o
607 * having to read it again
608 */
609 for (i = 0; i < iommu->unit_count; i++) {
610 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
611 for (j = 0; j < iommu_unit->dev_count; j++)
612 iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(
613 KGSL_IOMMU_GET_IOMMU_REG(
614 iommu_unit->reg_map.hostptr,
615 iommu_unit->dev[j].ctx_id,
616 TTBR0));
617 }
618 iommu->asid = KGSL_IOMMU_GET_IOMMU_REG(
619 iommu->iommu_units[0].reg_map.hostptr,
620 KGSL_IOMMU_CONTEXT_USER,
621 CONTEXTIDR);
622
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600623 kgsl_iommu_disable_clk(mmu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600624
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600625done:
626 if (status) {
627 kgsl_iommu_disable_clk(mmu);
628 kgsl_detach_pagetable_iommu_domain(mmu);
629 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600630 return status;
631}
632
633static int
634kgsl_iommu_unmap(void *mmu_specific_pt,
635 struct kgsl_memdesc *memdesc)
636{
637 int ret;
638 unsigned int range = memdesc->size;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600639 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600640
641 /* All GPU addresses as assigned are page aligned, but some
642 functions purturb the gpuaddr with an offset, so apply the
643 mask here to make sure we have the right address */
644
645 unsigned int gpuaddr = memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK;
646
647 if (range == 0 || gpuaddr == 0)
648 return 0;
649
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600650 ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600651 if (ret)
652 KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600653 "with err: %d\n", iommu_pt->domain, gpuaddr,
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600654 range, ret);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600655
656 return 0;
657}
658
659static int
660kgsl_iommu_map(void *mmu_specific_pt,
661 struct kgsl_memdesc *memdesc,
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600662 unsigned int protflags,
663 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600664{
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600665 int ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600666 unsigned int iommu_virt_addr;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600667 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600668
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600669 BUG_ON(NULL == iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600670
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600671
Jordan Croused17e9aa2011-10-12 16:57:48 -0600672 iommu_virt_addr = memdesc->gpuaddr;
673
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600674 ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
Olav Hauganf310cf22012-05-08 08:42:49 -0700675 memdesc->size, (IOMMU_READ | IOMMU_WRITE));
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600676 if (ret) {
677 KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600678 "failed with err: %d\n", iommu_pt->domain,
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600679 iommu_virt_addr, memdesc->sg, memdesc->size,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600680 (IOMMU_READ | IOMMU_WRITE), ret);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600681 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600682 }
683
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600684#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
685 /*
686 * Flushing only required if per process pagetables are used. With
687 * global case, flushing will happen inside iommu_map function
688 */
689 if (!ret)
690 *tlb_flags = UINT_MAX;
691#endif
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600692 return ret;
693}
694
Shubhraprakash Das79447952012-04-26 18:12:23 -0600695static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600696{
697 /*
698 * stop device mmu
699 *
700 * call this with the global lock held
701 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600702
703 if (mmu->flags & KGSL_FLAGS_STARTED) {
704 /* detach iommu attachment */
705 kgsl_detach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600706 mmu->hwpagetable = NULL;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600707
708 mmu->flags &= ~KGSL_FLAGS_STARTED;
709 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600710}
711
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600712static int kgsl_iommu_close(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600713{
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600714 struct kgsl_iommu *iommu = mmu->priv;
715 int i;
716 for (i = 0; i < iommu->unit_count; i++) {
717 if (iommu->iommu_units[i].reg_map.gpuaddr)
718 kgsl_mmu_unmap(mmu->defaultpagetable,
719 &(iommu->iommu_units[i].reg_map));
720 if (iommu->iommu_units[i].reg_map.hostptr)
721 iounmap(iommu->iommu_units[i].reg_map.hostptr);
722 kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
723 iommu->iommu_units[i].reg_map.sglen);
724 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600725 if (mmu->defaultpagetable)
726 kgsl_mmu_putpagetable(mmu->defaultpagetable);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600727 kfree(iommu->asids);
728 kfree(iommu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600729
730 return 0;
731}
732
733static unsigned int
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600734kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600735{
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600736 unsigned int pt_base;
737 struct kgsl_iommu *iommu = mmu->priv;
738 /* Return the current pt base by reading IOMMU pt_base register */
739 kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
740 pt_base = readl_relaxed(iommu->iommu_units[0].reg_map.hostptr +
741 (KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
742 KGSL_IOMMU_TTBR0);
743 kgsl_iommu_disable_clk(mmu);
744 return pt_base & (KGSL_IOMMU_TTBR0_PA_MASK <<
745 KGSL_IOMMU_TTBR0_PA_SHIFT);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600746}
747
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600748/*
749 * kgsl_iommu_get_hwpagetable_asid - Returns asid(application space ID) for a
750 * pagetable
751 * @mmu - Pointer to mmu structure
752 *
753 * Allocates an asid to a IOMMU domain if it does not already have one. asid's
754 * are unique identifiers for pagetable that can be used to selectively flush
755 * tlb entries of the IOMMU unit.
756 * Return - asid to be used with the IOMMU domain
757 */
758static int kgsl_iommu_get_hwpagetable_asid(struct kgsl_mmu *mmu)
759{
760 struct kgsl_iommu *iommu = mmu->priv;
761 struct kgsl_iommu_pt *iommu_pt = mmu->hwpagetable->priv;
762
763 /*
764 * If the iommu pagetable does not have any asid assigned and is not the
765 * default pagetable then assign asid.
766 */
767 if (!iommu_pt->asid && iommu_pt != mmu->defaultpagetable->priv) {
768 iommu_pt->asid = find_first_zero_bit(iommu->asids,
769 KGSL_IOMMU_MAX_ASIDS);
770 /* No free bits means reuse asid */
771 if (iommu_pt->asid >= KGSL_IOMMU_MAX_ASIDS) {
772 iommu_pt->asid = KGSL_IOMMU_ASID_REUSE;
773 iommu->asid_reuse++;
774 }
775 set_bit(iommu_pt->asid, iommu->asids);
776 /*
777 * Store pointer to asids list so that during pagetable destroy
778 * the asid assigned to this pagetable may be cleared
779 */
780 iommu_pt->iommu = iommu;
781 }
782 /* Return the asid + the constant part of asid that never changes */
783 return (iommu_pt->asid & (KGSL_IOMMU_CONTEXTIDR_ASID_MASK <<
784 KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT)) +
785 (iommu->asid & ~(KGSL_IOMMU_CONTEXTIDR_ASID_MASK <<
786 KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT));
787}
788
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600789/*
790 * kgsl_iommu_default_setstate - Change the IOMMU pagetable or flush IOMMU tlb
791 * of the primary context bank
792 * @mmu - Pointer to mmu structure
793 * @flags - Flags indicating whether pagetable has to chnage or tlb is to be
794 * flushed or both
795 *
796 * Based on flags set the new pagetable fo the IOMMU unit or flush it's tlb or
797 * do both by doing direct register writes to the IOMMu registers through the
798 * cpu
799 * Return - void
800 */
801static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
802 uint32_t flags)
803{
804 struct kgsl_iommu *iommu = mmu->priv;
805 int temp;
806 int i;
807 unsigned int pt_base = kgsl_iommu_pt_get_base_addr(
808 mmu->hwpagetable);
809 unsigned int pt_val;
810
811 if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
812 KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
813 return;
814 }
815 /* Mask off the lsb of the pt base address since lsb will not change */
816 pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK << KGSL_IOMMU_TTBR0_PA_SHIFT);
817 if (flags & KGSL_MMUFLAGS_PTUPDATE) {
818 kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
819 for (i = 0; i < iommu->unit_count; i++) {
820 /* get the lsb value which should not change when
821 * changing ttbr0 */
822 pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
823 KGSL_IOMMU_CONTEXT_USER);
824 pt_val += pt_base;
825
826 KGSL_IOMMU_SET_IOMMU_REG(
827 iommu->iommu_units[i].reg_map.hostptr,
828 KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
829
830 mb();
831 temp = KGSL_IOMMU_GET_IOMMU_REG(
832 iommu->iommu_units[i].reg_map.hostptr,
833 KGSL_IOMMU_CONTEXT_USER, TTBR0);
834 /* Set asid */
835 KGSL_IOMMU_SET_IOMMU_REG(
836 iommu->iommu_units[i].reg_map.hostptr,
837 KGSL_IOMMU_CONTEXT_USER, CONTEXTIDR,
838 kgsl_iommu_get_hwpagetable_asid(mmu));
839 mb();
840 temp = KGSL_IOMMU_GET_IOMMU_REG(
841 iommu->iommu_units[i].reg_map.hostptr,
842 KGSL_IOMMU_CONTEXT_USER, CONTEXTIDR);
843 }
844 }
845 /* Flush tlb */
846 if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
847 for (i = 0; i < iommu->unit_count; i++) {
848 KGSL_IOMMU_SET_IOMMU_REG(
849 iommu->iommu_units[i].reg_map.hostptr,
850 KGSL_IOMMU_CONTEXT_USER, CTX_TLBIASID,
851 kgsl_iommu_get_hwpagetable_asid(mmu));
852 mb();
853 }
854 }
855 /* Disable smmu clock */
856 kgsl_iommu_disable_clk(mmu);
857}
858
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600859struct kgsl_mmu_ops iommu_ops = {
860 .mmu_init = kgsl_iommu_init,
861 .mmu_close = kgsl_iommu_close,
862 .mmu_start = kgsl_iommu_start,
863 .mmu_stop = kgsl_iommu_stop,
864 .mmu_setstate = kgsl_iommu_setstate,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600865 .mmu_device_setstate = kgsl_iommu_default_setstate,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600866 .mmu_pagefault = NULL,
867 .mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600868 .mmu_enable_clk = kgsl_iommu_enable_clk,
869 .mmu_disable_clk = kgsl_iommu_disable_clk,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600870 .mmu_get_hwpagetable_asid = kgsl_iommu_get_hwpagetable_asid,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600871};
872
873struct kgsl_mmu_pt_ops iommu_pt_ops = {
874 .mmu_map = kgsl_iommu_map,
875 .mmu_unmap = kgsl_iommu_unmap,
876 .mmu_create_pagetable = kgsl_iommu_create_pagetable,
877 .mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
878 .mmu_pt_equal = kgsl_iommu_pt_equal,
Shubhraprakash Das5a610b52012-05-09 17:31:54 -0600879 .mmu_pt_get_base_addr = kgsl_iommu_pt_get_base_addr,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600880};