blob: 6a86ea370fca5457d15efe86edd2a55cd0b2b257 [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 Dase9541a32012-05-09 22:25:55 -060026#include "adreno_pm4types.h"
Shubhraprakash Das767fdda2011-08-15 15:49:45 -060027
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -060028/*
29 * kgsl_iommu_disable_clk - Disable iommu clocks
30 * @mmu - Pointer to mmu structure
31 *
32 * Disables iommu clocks
33 * Return - void
34 */
35static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu)
36{
37 struct kgsl_iommu *iommu = mmu->priv;
38 struct msm_iommu_drvdata *iommu_drvdata;
39 int i, j;
40
41 for (i = 0; i < iommu->unit_count; i++) {
42 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
43 for (j = 0; j < iommu_unit->dev_count; j++) {
44 if (!iommu_unit->dev[j].clk_enabled)
45 continue;
46 iommu_drvdata = dev_get_drvdata(
47 iommu_unit->dev[j].dev->parent);
48 if (iommu_drvdata->clk)
49 clk_disable_unprepare(iommu_drvdata->clk);
50 clk_disable_unprepare(iommu_drvdata->pclk);
51 iommu_unit->dev[j].clk_enabled = false;
52 }
53 }
54}
55
56/*
57 * kgsl_iommu_enable_clk - Enable iommu clocks
58 * @mmu - Pointer to mmu structure
59 * @ctx_id - The context bank whose clocks are to be turned on
60 *
61 * Enables iommu clocks of a given context
62 * Return: 0 on success else error code
63 */
64static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu,
65 int ctx_id)
66{
67 int ret = 0;
68 int i, j;
69 struct kgsl_iommu *iommu = mmu->priv;
70 struct msm_iommu_drvdata *iommu_drvdata;
71
72 for (i = 0; i < iommu->unit_count; i++) {
73 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
74 for (j = 0; j < iommu_unit->dev_count; j++) {
75 if (iommu_unit->dev[j].clk_enabled ||
76 ctx_id != iommu_unit->dev[j].ctx_id)
77 continue;
78 iommu_drvdata =
79 dev_get_drvdata(iommu_unit->dev[j].dev->parent);
80 ret = clk_prepare_enable(iommu_drvdata->pclk);
81 if (ret)
82 goto done;
83 if (iommu_drvdata->clk) {
84 ret = clk_prepare_enable(iommu_drvdata->clk);
85 if (ret) {
86 clk_disable_unprepare(
87 iommu_drvdata->pclk);
88 goto done;
89 }
90 }
91 iommu_unit->dev[j].clk_enabled = true;
92 }
93 }
94done:
95 if (ret)
96 kgsl_iommu_disable_clk(mmu);
97 return ret;
98}
99
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600100/*
101 * kgsl_iommu_pt_equal - Check if pagetables are equal
102 * @pt - Pointer to pagetable
103 * @pt_base - Address of a pagetable that the IOMMU register is
104 * programmed with
105 *
106 * Checks whether the pt_base is equal to the base address of
107 * the pagetable which is contained in the pt structure
108 * Return - Non-zero if the pagetable addresses are equal else 0
109 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600110static int kgsl_iommu_pt_equal(struct kgsl_pagetable *pt,
111 unsigned int pt_base)
112{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600113 struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
114 unsigned int domain_ptbase = iommu_pt ?
115 iommu_get_pt_base_addr(iommu_pt->domain) : 0;
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600116 /* Only compare the valid address bits of the pt_base */
117 domain_ptbase &= (KGSL_IOMMU_TTBR0_PA_MASK <<
118 KGSL_IOMMU_TTBR0_PA_SHIFT);
119 pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK <<
120 KGSL_IOMMU_TTBR0_PA_SHIFT);
121 return domain_ptbase && pt_base &&
122 (domain_ptbase == pt_base);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600123}
124
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600125/*
126 * kgsl_iommu_destroy_pagetable - Free up reaources help by a pagetable
127 * @mmu_specific_pt - Pointer to pagetable which is to be freed
128 *
129 * Return - void
130 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600131static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
132{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600133 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
134 if (iommu_pt->domain)
135 iommu_domain_free(iommu_pt->domain);
136 if (iommu_pt->iommu) {
137 if ((KGSL_IOMMU_ASID_REUSE == iommu_pt->asid) &&
138 iommu_pt->iommu->asid_reuse)
139 iommu_pt->iommu->asid_reuse--;
140 if (!iommu_pt->iommu->asid_reuse ||
141 (KGSL_IOMMU_ASID_REUSE != iommu_pt->asid))
142 clear_bit(iommu_pt->asid, iommu_pt->iommu->asids);
143 }
144 kfree(iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600145}
146
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600147/*
148 * kgsl_iommu_create_pagetable - Create a IOMMU pagetable
149 *
150 * Allocate memory to hold a pagetable and allocate the IOMMU
151 * domain which is the actual IOMMU pagetable
152 * Return - void
153 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600154void *kgsl_iommu_create_pagetable(void)
155{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600156 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600157
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600158 iommu_pt = kzalloc(sizeof(struct kgsl_iommu_pt), GFP_KERNEL);
159 if (!iommu_pt) {
160 KGSL_CORE_ERR("kzalloc(%d) failed\n",
161 sizeof(struct kgsl_iommu_pt));
162 return NULL;
163 }
Jordan Crouse523800f2012-04-16 14:14:45 -0600164 iommu_pt->domain = iommu_domain_alloc(MSM_IOMMU_DOMAIN_PT_CACHEABLE);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600165 if (!iommu_pt->domain) {
166 KGSL_CORE_ERR("Failed to create iommu domain\n");
167 kfree(iommu_pt);
168 return NULL;
169 }
170 return iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600171}
172
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600173/*
174 * kgsl_detach_pagetable_iommu_domain - Detach the IOMMU unit from a
175 * pagetable
176 * @mmu - Pointer to the device mmu structure
177 * @priv - Flag indicating whether the private or user context is to be
178 * detached
179 *
180 * Detach the IOMMU unit with the domain that is contained in the
181 * hwpagetable of the given mmu. After detaching the IOMMU unit is not
182 * in use because the PTBR will not be set after a detach
183 * Return - void
184 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600185static void kgsl_detach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
186{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600187 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600188 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600189 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600190
191 BUG_ON(mmu->hwpagetable == NULL);
192 BUG_ON(mmu->hwpagetable->priv == NULL);
193
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600194 iommu_pt = mmu->hwpagetable->priv;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600195
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600196 for (i = 0; i < iommu->unit_count; i++) {
197 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
198 for (j = 0; j < iommu_unit->dev_count; j++) {
199 if (iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600200 iommu_detach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600201 iommu_unit->dev[j].dev);
202 iommu_unit->dev[j].attached = false;
203 KGSL_MEM_INFO(mmu->device, "iommu %p detached "
204 "from user dev of MMU: %p\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600205 iommu_pt->domain, mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600206 }
207 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600208 }
209}
210
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600211/*
212 * kgsl_attach_pagetable_iommu_domain - Attach the IOMMU unit to a
213 * pagetable, i.e set the IOMMU's PTBR to the pagetable address and
214 * setup other IOMMU registers for the device so that it becomes
215 * active
216 * @mmu - Pointer to the device mmu structure
217 * @priv - Flag indicating whether the private or user context is to be
218 * attached
219 *
220 * Attach the IOMMU unit with the domain that is contained in the
221 * hwpagetable of the given mmu.
222 * Return - 0 on success else error code
223 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600224static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
225{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600226 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600227 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600228 int i, j, ret = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600229
230 BUG_ON(mmu->hwpagetable == NULL);
231 BUG_ON(mmu->hwpagetable->priv == NULL);
232
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600233 iommu_pt = mmu->hwpagetable->priv;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600234
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600235 /*
236 * Loop through all the iommu devcies under all iommu units and
237 * attach the domain
238 */
239 for (i = 0; i < iommu->unit_count; i++) {
240 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
241 for (j = 0; j < iommu_unit->dev_count; j++) {
242 if (!iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600243 ret = iommu_attach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600244 iommu_unit->dev[j].dev);
245 if (ret) {
246 KGSL_MEM_ERR(mmu->device,
247 "Failed to attach device, err %d\n",
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700248 ret);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600249 goto done;
250 }
251 iommu_unit->dev[j].attached = true;
252 KGSL_MEM_INFO(mmu->device,
253 "iommu pt %p attached to dev %p, ctx_id %d\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600254 iommu_pt->domain, iommu_unit->dev[j].dev,
255 iommu_unit->dev[j].ctx_id);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700256 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600257 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600258 }
259done:
260 return ret;
261}
262
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600263/*
264 * _get_iommu_ctxs - Get device pointer to IOMMU contexts
265 * @mmu - Pointer to mmu device
266 * data - Pointer to the platform data containing information about
267 * iommu devices for one iommu unit
268 * unit_id - The IOMMU unit number. This is not a specific ID but just
269 * a serial number. The serial numbers are treated as ID's of the
270 * IOMMU units
271 *
272 * Return - 0 on success else error code
273 */
274static int _get_iommu_ctxs(struct kgsl_mmu *mmu,
275 struct kgsl_device_iommu_data *data, unsigned int unit_id)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700276{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600277 struct kgsl_iommu *iommu = mmu->priv;
278 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id];
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700279 int i;
280
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600281 if (data->iommu_ctx_count > KGSL_IOMMU_MAX_DEVS_PER_UNIT) {
282 KGSL_CORE_ERR("Too many iommu devices defined for an "
283 "IOMMU unit\n");
284 return -EINVAL;
285 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700286
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600287 for (i = 0; i < data->iommu_ctx_count; i++) {
288 if (!data->iommu_ctxs[i].iommu_ctx_name)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700289 continue;
290
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600291 iommu_unit->dev[iommu_unit->dev_count].dev =
292 msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
293 if (iommu_unit->dev[iommu_unit->dev_count].dev == NULL) {
294 KGSL_CORE_ERR("Failed to get iommu dev handle for "
295 "device %s\n", data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700296 return -EINVAL;
297 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600298 if (KGSL_IOMMU_CONTEXT_USER != data->iommu_ctxs[i].ctx_id &&
299 KGSL_IOMMU_CONTEXT_PRIV != data->iommu_ctxs[i].ctx_id) {
300 KGSL_CORE_ERR("Invalid context ID defined: %d\n",
301 data->iommu_ctxs[i].ctx_id);
302 return -EINVAL;
303 }
304 iommu_unit->dev[iommu_unit->dev_count].ctx_id =
305 data->iommu_ctxs[i].ctx_id;
306 KGSL_DRV_INFO(mmu->device,
307 "Obtained dev handle %p for iommu context %s\n",
308 iommu_unit->dev[iommu_unit->dev_count].dev,
309 data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700310
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600311 iommu_unit->dev_count++;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700312 }
313
314 return 0;
315}
316
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600317/*
318 * kgsl_get_iommu_ctxt - Get device pointer to IOMMU contexts
319 * @mmu - Pointer to mmu device
320 *
321 * Get the device pointers for the IOMMU user and priv contexts of the
322 * kgsl device
323 * Return - 0 on success else error code
324 */
325static int kgsl_get_iommu_ctxt(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600326{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600327 struct platform_device *pdev =
328 container_of(mmu->device->parentdev, struct platform_device,
329 dev);
330 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
331 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700332 int i, ret = 0;
333
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600334 /* Go through the IOMMU data and get all the context devices */
335 if (KGSL_IOMMU_MAX_UNITS < pdata_dev->iommu_count) {
336 KGSL_CORE_ERR("Too many IOMMU units defined\n");
337 ret = -EINVAL;
338 goto done;
339 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700340
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600341 for (i = 0; i < pdata_dev->iommu_count; i++) {
342 ret = _get_iommu_ctxs(mmu, &pdata_dev->iommu_data[i], i);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700343 if (ret)
344 break;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600345 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600346 iommu->unit_count = pdata_dev->iommu_count;
347done:
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700348 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600349}
350
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600351/*
352 * kgsl_set_register_map - Map the IOMMU regsiters in the memory descriptors
353 * of the respective iommu units
354 * @mmu - Pointer to mmu structure
355 *
356 * Return - 0 on success else error code
357 */
358static int kgsl_set_register_map(struct kgsl_mmu *mmu)
359{
360 struct platform_device *pdev =
361 container_of(mmu->device->parentdev, struct platform_device,
362 dev);
363 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
364 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
365 struct kgsl_iommu_unit *iommu_unit;
366 int i = 0, ret = 0;
367
368 for (; i < pdata_dev->iommu_count; i++) {
369 struct kgsl_device_iommu_data data = pdata_dev->iommu_data[i];
370 iommu_unit = &iommu->iommu_units[i];
371 /* set up the IOMMU register map for the given IOMMU unit */
372 if (!data.physstart || !data.physend) {
373 KGSL_CORE_ERR("The register range for IOMMU unit not"
374 " specified\n");
375 ret = -EINVAL;
376 goto err;
377 }
378 iommu_unit->reg_map.hostptr = ioremap(data.physstart,
379 data.physend - data.physstart + 1);
380 if (!iommu_unit->reg_map.hostptr) {
381 KGSL_CORE_ERR("Failed to map SMMU register address "
382 "space from %x to %x\n", data.physstart,
383 data.physend - data.physstart + 1);
384 ret = -ENOMEM;
385 i--;
386 goto err;
387 }
388 iommu_unit->reg_map.size = data.physend - data.physstart + 1;
389 iommu_unit->reg_map.physaddr = data.physstart;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600390 memdesc_sg_phys(&iommu_unit->reg_map, data.physstart,
391 iommu_unit->reg_map.size);
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600392 }
393 iommu->unit_count = pdata_dev->iommu_count;
394 return ret;
395err:
396 /* Unmap any mapped IOMMU regions */
397 for (; i >= 0; i--) {
398 iommu_unit = &iommu->iommu_units[i];
399 iounmap(iommu_unit->reg_map.hostptr);
400 iommu_unit->reg_map.size = 0;
401 iommu_unit->reg_map.physaddr = 0;
402 }
403 return ret;
404}
405
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600406/*
407 * kgsl_iommu_pt_get_base_addr - Get the address of the pagetable that the
408 * IOMMU ttbr0 register is programmed with
409 * @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
410 *
411 * Return - actual pagetable address that the ttbr0 register is programmed
412 * with
413 */
414static unsigned int kgsl_iommu_pt_get_base_addr(struct kgsl_pagetable *pt)
415{
416 struct kgsl_iommu_pt *iommu_pt = pt->priv;
417 return iommu_get_pt_base_addr(iommu_pt->domain);
418}
419
420/*
421 * kgsl_iommu_get_pt_lsb - Return the lsb of the ttbr0 IOMMU register
422 * @mmu - Pointer to mmu structure
423 * @hostptr - Pointer to the IOMMU register map. This is used to match
424 * the iommu device whose lsb value is to be returned
425 * @ctx_id - The context bank whose lsb valus is to be returned
426 * Return - returns the lsb which is the last 14 bits of the ttbr0 IOMMU
427 * register. ttbr0 is the actual PTBR for of the IOMMU. The last 14 bits
428 * are only programmed once in the beginning when a domain is attached
429 * does not change.
430 */
431static int kgsl_iommu_get_pt_lsb(struct kgsl_mmu *mmu,
432 unsigned int unit_id,
433 enum kgsl_iommu_context_id ctx_id)
434{
435 struct kgsl_iommu *iommu = mmu->priv;
436 int i, j;
437 for (i = 0; i < iommu->unit_count; i++) {
438 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
439 for (j = 0; j < iommu_unit->dev_count; j++)
440 if (unit_id == i &&
441 ctx_id == iommu_unit->dev[j].ctx_id)
442 return iommu_unit->dev[j].pt_lsb;
443 }
444 return 0;
445}
446
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600447static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600448 struct kgsl_pagetable *pagetable)
449{
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600450 if (mmu->flags & KGSL_FLAGS_STARTED) {
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600451 struct kgsl_iommu *iommu = mmu->priv;
452 struct kgsl_iommu_pt *iommu_pt = pagetable->priv;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600453 /* page table not current, then setup mmu to use new
454 * specified page table
455 */
456 if (mmu->hwpagetable != pagetable) {
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600457 unsigned int flags = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600458 mmu->hwpagetable = pagetable;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600459 /* force tlb flush if asid is reused */
460 if (iommu->asid_reuse &&
461 (KGSL_IOMMU_ASID_REUSE == iommu_pt->asid))
462 flags |= KGSL_MMUFLAGS_TLBFLUSH;
463 flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
464 mmu->device->id);
465 kgsl_setstate(mmu, KGSL_MMUFLAGS_PTUPDATE | flags);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600466 }
467 }
468}
469
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600470static int kgsl_iommu_init(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600471{
472 /*
473 * intialize device mmu
474 *
475 * call this with the global lock held
476 */
477 int status = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600478 struct kgsl_iommu *iommu;
479
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600480 iommu = kzalloc(sizeof(struct kgsl_iommu), GFP_KERNEL);
481 if (!iommu) {
482 KGSL_CORE_ERR("kzalloc(%d) failed\n",
483 sizeof(struct kgsl_iommu));
484 return -ENOMEM;
485 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600486 iommu->asids = kzalloc(BITS_TO_LONGS(KGSL_IOMMU_MAX_ASIDS) *
487 sizeof(unsigned long), GFP_KERNEL);
488 if (!iommu->asids) {
489 KGSL_CORE_ERR("kzalloc(%d) failed\n",
490 sizeof(struct kgsl_iommu));
491 status = -ENOMEM;
492 goto done;
493 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600494
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600495 mmu->priv = iommu;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600496 status = kgsl_get_iommu_ctxt(mmu);
497 if (status)
498 goto done;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600499 status = kgsl_set_register_map(mmu);
500 if (status)
501 goto done;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600502
Shubhraprakash Dase9541a32012-05-09 22:25:55 -0600503 /* A nop is required in an indirect buffer when switching
504 * pagetables in-stream */
505 kgsl_sharedmem_writel(&mmu->setstate_memory,
506 KGSL_IOMMU_SETSTATE_NOP_OFFSET,
507 cp_nop_packet(1));
508
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600509 dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600510 __func__);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600511done:
512 if (status) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600513 kfree(iommu->asids);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600514 kfree(iommu);
515 mmu->priv = NULL;
516 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600517 return status;
518}
519
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600520/*
521 * kgsl_iommu_setup_defaultpagetable - Setup the initial defualtpagetable
522 * for iommu. This function is only called once during first start, successive
523 * start do not call this funciton.
524 * @mmu - Pointer to mmu structure
525 *
526 * Create the initial defaultpagetable and setup the iommu mappings to it
527 * Return - 0 on success else error code
528 */
529static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu)
530{
531 int status = 0;
532 int i = 0;
533 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600534 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600535
536 mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
537 /* Return error if the default pagetable doesn't exist */
538 if (mmu->defaultpagetable == NULL) {
539 status = -ENOMEM;
540 goto err;
541 }
542 /* Map the IOMMU regsiters to only defaultpagetable */
543 for (i = 0; i < iommu->unit_count; i++) {
544 iommu->iommu_units[i].reg_map.priv |= KGSL_MEMFLAGS_GLOBAL;
545 status = kgsl_mmu_map(mmu->defaultpagetable,
546 &(iommu->iommu_units[i].reg_map),
547 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
548 if (status) {
549 iommu->iommu_units[i].reg_map.priv &=
550 ~KGSL_MEMFLAGS_GLOBAL;
551 goto err;
552 }
553 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600554 /*
555 * The dafault pagetable always has asid 0 assigned by the iommu driver
556 * and asid 1 is assigned to the private context.
557 */
558 iommu_pt = mmu->defaultpagetable->priv;
559 iommu_pt->asid = 0;
560 set_bit(0, iommu->asids);
561 set_bit(1, iommu->asids);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600562 return status;
563err:
564 for (i--; i >= 0; i--) {
565 kgsl_mmu_unmap(mmu->defaultpagetable,
566 &(iommu->iommu_units[i].reg_map));
567 iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMFLAGS_GLOBAL;
568 }
569 if (mmu->defaultpagetable) {
570 kgsl_mmu_putpagetable(mmu->defaultpagetable);
571 mmu->defaultpagetable = NULL;
572 }
573 return status;
574}
575
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600576static int kgsl_iommu_start(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600577{
578 int status;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600579 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600580 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600581
582 if (mmu->flags & KGSL_FLAGS_STARTED)
583 return 0;
584
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600585 if (mmu->defaultpagetable == NULL) {
586 status = kgsl_iommu_setup_defaultpagetable(mmu);
587 if (status)
588 return -ENOMEM;
589 }
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600590 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600591
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600592 mmu->hwpagetable = mmu->defaultpagetable;
593
594 status = kgsl_attach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600595 if (!status) {
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600596 mmu->flags |= KGSL_FLAGS_STARTED;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600597 } else {
598 kgsl_detach_pagetable_iommu_domain(mmu);
599 mmu->hwpagetable = NULL;
600 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600601 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600602 if (status) {
603 KGSL_CORE_ERR("clk enable failed\n");
604 goto done;
605 }
606 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
607 if (status) {
608 KGSL_CORE_ERR("clk enable failed\n");
609 goto done;
610 }
611 /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as
612 * that value should not change when we change pagetables, so while
613 * changing pagetables we can use this lsb value of the pagetable w/o
614 * having to read it again
615 */
616 for (i = 0; i < iommu->unit_count; i++) {
617 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
618 for (j = 0; j < iommu_unit->dev_count; j++)
619 iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(
620 KGSL_IOMMU_GET_IOMMU_REG(
621 iommu_unit->reg_map.hostptr,
622 iommu_unit->dev[j].ctx_id,
623 TTBR0));
624 }
625 iommu->asid = KGSL_IOMMU_GET_IOMMU_REG(
626 iommu->iommu_units[0].reg_map.hostptr,
627 KGSL_IOMMU_CONTEXT_USER,
628 CONTEXTIDR);
629
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600630 kgsl_iommu_disable_clk(mmu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600631
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600632done:
633 if (status) {
634 kgsl_iommu_disable_clk(mmu);
635 kgsl_detach_pagetable_iommu_domain(mmu);
636 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600637 return status;
638}
639
640static int
641kgsl_iommu_unmap(void *mmu_specific_pt,
642 struct kgsl_memdesc *memdesc)
643{
644 int ret;
645 unsigned int range = memdesc->size;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600646 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600647
648 /* All GPU addresses as assigned are page aligned, but some
649 functions purturb the gpuaddr with an offset, so apply the
650 mask here to make sure we have the right address */
651
652 unsigned int gpuaddr = memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK;
653
654 if (range == 0 || gpuaddr == 0)
655 return 0;
656
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600657 ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600658 if (ret)
659 KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600660 "with err: %d\n", iommu_pt->domain, gpuaddr,
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600661 range, ret);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600662
663 return 0;
664}
665
666static int
667kgsl_iommu_map(void *mmu_specific_pt,
668 struct kgsl_memdesc *memdesc,
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600669 unsigned int protflags,
670 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600671{
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600672 int ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600673 unsigned int iommu_virt_addr;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600674 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600675
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600676 BUG_ON(NULL == iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600677
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600678
Jordan Croused17e9aa2011-10-12 16:57:48 -0600679 iommu_virt_addr = memdesc->gpuaddr;
680
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600681 ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
Olav Hauganf310cf22012-05-08 08:42:49 -0700682 memdesc->size, (IOMMU_READ | IOMMU_WRITE));
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600683 if (ret) {
684 KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600685 "failed with err: %d\n", iommu_pt->domain,
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600686 iommu_virt_addr, memdesc->sg, memdesc->size,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600687 (IOMMU_READ | IOMMU_WRITE), ret);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600688 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600689 }
690
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600691#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
692 /*
693 * Flushing only required if per process pagetables are used. With
694 * global case, flushing will happen inside iommu_map function
695 */
696 if (!ret)
697 *tlb_flags = UINT_MAX;
698#endif
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600699 return ret;
700}
701
Shubhraprakash Das79447952012-04-26 18:12:23 -0600702static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600703{
704 /*
705 * stop device mmu
706 *
707 * call this with the global lock held
708 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600709
710 if (mmu->flags & KGSL_FLAGS_STARTED) {
711 /* detach iommu attachment */
712 kgsl_detach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600713 mmu->hwpagetable = NULL;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600714
715 mmu->flags &= ~KGSL_FLAGS_STARTED;
716 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600717}
718
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600719static int kgsl_iommu_close(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600720{
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600721 struct kgsl_iommu *iommu = mmu->priv;
722 int i;
723 for (i = 0; i < iommu->unit_count; i++) {
724 if (iommu->iommu_units[i].reg_map.gpuaddr)
725 kgsl_mmu_unmap(mmu->defaultpagetable,
726 &(iommu->iommu_units[i].reg_map));
727 if (iommu->iommu_units[i].reg_map.hostptr)
728 iounmap(iommu->iommu_units[i].reg_map.hostptr);
729 kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
730 iommu->iommu_units[i].reg_map.sglen);
731 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600732 if (mmu->defaultpagetable)
733 kgsl_mmu_putpagetable(mmu->defaultpagetable);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600734 kfree(iommu->asids);
735 kfree(iommu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600736
737 return 0;
738}
739
740static unsigned int
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600741kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600742{
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600743 unsigned int pt_base;
744 struct kgsl_iommu *iommu = mmu->priv;
745 /* Return the current pt base by reading IOMMU pt_base register */
746 kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
747 pt_base = readl_relaxed(iommu->iommu_units[0].reg_map.hostptr +
748 (KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
749 KGSL_IOMMU_TTBR0);
750 kgsl_iommu_disable_clk(mmu);
751 return pt_base & (KGSL_IOMMU_TTBR0_PA_MASK <<
752 KGSL_IOMMU_TTBR0_PA_SHIFT);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600753}
754
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600755/*
756 * kgsl_iommu_get_hwpagetable_asid - Returns asid(application space ID) for a
757 * pagetable
758 * @mmu - Pointer to mmu structure
759 *
760 * Allocates an asid to a IOMMU domain if it does not already have one. asid's
761 * are unique identifiers for pagetable that can be used to selectively flush
762 * tlb entries of the IOMMU unit.
763 * Return - asid to be used with the IOMMU domain
764 */
765static int kgsl_iommu_get_hwpagetable_asid(struct kgsl_mmu *mmu)
766{
767 struct kgsl_iommu *iommu = mmu->priv;
768 struct kgsl_iommu_pt *iommu_pt = mmu->hwpagetable->priv;
769
770 /*
771 * If the iommu pagetable does not have any asid assigned and is not the
772 * default pagetable then assign asid.
773 */
774 if (!iommu_pt->asid && iommu_pt != mmu->defaultpagetable->priv) {
775 iommu_pt->asid = find_first_zero_bit(iommu->asids,
776 KGSL_IOMMU_MAX_ASIDS);
777 /* No free bits means reuse asid */
778 if (iommu_pt->asid >= KGSL_IOMMU_MAX_ASIDS) {
779 iommu_pt->asid = KGSL_IOMMU_ASID_REUSE;
780 iommu->asid_reuse++;
781 }
782 set_bit(iommu_pt->asid, iommu->asids);
783 /*
784 * Store pointer to asids list so that during pagetable destroy
785 * the asid assigned to this pagetable may be cleared
786 */
787 iommu_pt->iommu = iommu;
788 }
789 /* Return the asid + the constant part of asid that never changes */
790 return (iommu_pt->asid & (KGSL_IOMMU_CONTEXTIDR_ASID_MASK <<
791 KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT)) +
792 (iommu->asid & ~(KGSL_IOMMU_CONTEXTIDR_ASID_MASK <<
793 KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT));
794}
795
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600796/*
797 * kgsl_iommu_default_setstate - Change the IOMMU pagetable or flush IOMMU tlb
798 * of the primary context bank
799 * @mmu - Pointer to mmu structure
800 * @flags - Flags indicating whether pagetable has to chnage or tlb is to be
801 * flushed or both
802 *
803 * Based on flags set the new pagetable fo the IOMMU unit or flush it's tlb or
804 * do both by doing direct register writes to the IOMMu registers through the
805 * cpu
806 * Return - void
807 */
808static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
809 uint32_t flags)
810{
811 struct kgsl_iommu *iommu = mmu->priv;
812 int temp;
813 int i;
814 unsigned int pt_base = kgsl_iommu_pt_get_base_addr(
815 mmu->hwpagetable);
816 unsigned int pt_val;
817
818 if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
819 KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
820 return;
821 }
822 /* Mask off the lsb of the pt base address since lsb will not change */
823 pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK << KGSL_IOMMU_TTBR0_PA_SHIFT);
824 if (flags & KGSL_MMUFLAGS_PTUPDATE) {
825 kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
826 for (i = 0; i < iommu->unit_count; i++) {
827 /* get the lsb value which should not change when
828 * changing ttbr0 */
829 pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
830 KGSL_IOMMU_CONTEXT_USER);
831 pt_val += pt_base;
832
833 KGSL_IOMMU_SET_IOMMU_REG(
834 iommu->iommu_units[i].reg_map.hostptr,
835 KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
836
837 mb();
838 temp = KGSL_IOMMU_GET_IOMMU_REG(
839 iommu->iommu_units[i].reg_map.hostptr,
840 KGSL_IOMMU_CONTEXT_USER, TTBR0);
841 /* Set asid */
842 KGSL_IOMMU_SET_IOMMU_REG(
843 iommu->iommu_units[i].reg_map.hostptr,
844 KGSL_IOMMU_CONTEXT_USER, CONTEXTIDR,
845 kgsl_iommu_get_hwpagetable_asid(mmu));
846 mb();
847 temp = KGSL_IOMMU_GET_IOMMU_REG(
848 iommu->iommu_units[i].reg_map.hostptr,
849 KGSL_IOMMU_CONTEXT_USER, CONTEXTIDR);
850 }
851 }
852 /* Flush tlb */
853 if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
854 for (i = 0; i < iommu->unit_count; i++) {
855 KGSL_IOMMU_SET_IOMMU_REG(
856 iommu->iommu_units[i].reg_map.hostptr,
857 KGSL_IOMMU_CONTEXT_USER, CTX_TLBIASID,
858 kgsl_iommu_get_hwpagetable_asid(mmu));
859 mb();
860 }
861 }
862 /* Disable smmu clock */
863 kgsl_iommu_disable_clk(mmu);
864}
865
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -0600866/*
867 * kgsl_iommu_get_reg_map_desc - Returns an array of pointers that contain
868 * the address of memory descriptors which map the IOMMU registers
869 * @mmu - Pointer to mmu structure
870 * @reg_map_desc - Out parameter in which the address of the array containing
871 * pointers to register map descriptors is returned. The caller is supposed
872 * to free this array
873 *
874 * Return - The number of iommu units which is also the number of register
875 * mapped descriptor arrays which the out parameter will have
876 */
877static int kgsl_iommu_get_reg_map_desc(struct kgsl_mmu *mmu,
878 void **reg_map_desc)
879{
880 struct kgsl_iommu *iommu = mmu->priv;
881 void **reg_desc_ptr;
882 int i;
883
884 /*
885 * Alocate array of pointers that will hold address of the register map
886 * descriptors
887 */
888 reg_desc_ptr = kmalloc(iommu->unit_count *
889 sizeof(struct kgsl_memdesc *), GFP_KERNEL);
890 if (!reg_desc_ptr) {
891 KGSL_CORE_ERR("Failed to kmalloc(%d)\n",
892 iommu->unit_count * sizeof(struct kgsl_memdesc *));
893 return -ENOMEM;
894 }
895
896 for (i = 0; i < iommu->unit_count; i++)
897 reg_desc_ptr[i] = &(iommu->iommu_units[i].reg_map);
898
899 *reg_map_desc = reg_desc_ptr;
900 return i;
901}
902
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600903struct kgsl_mmu_ops iommu_ops = {
904 .mmu_init = kgsl_iommu_init,
905 .mmu_close = kgsl_iommu_close,
906 .mmu_start = kgsl_iommu_start,
907 .mmu_stop = kgsl_iommu_stop,
908 .mmu_setstate = kgsl_iommu_setstate,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600909 .mmu_device_setstate = kgsl_iommu_default_setstate,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600910 .mmu_pagefault = NULL,
911 .mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600912 .mmu_enable_clk = kgsl_iommu_enable_clk,
913 .mmu_disable_clk = kgsl_iommu_disable_clk,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600914 .mmu_get_hwpagetable_asid = kgsl_iommu_get_hwpagetable_asid,
Shubhraprakash Dasfce27362012-05-09 17:44:14 -0600915 .mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -0600916 .mmu_get_reg_map_desc = kgsl_iommu_get_reg_map_desc,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600917};
918
919struct kgsl_mmu_pt_ops iommu_pt_ops = {
920 .mmu_map = kgsl_iommu_map,
921 .mmu_unmap = kgsl_iommu_unmap,
922 .mmu_create_pagetable = kgsl_iommu_create_pagetable,
923 .mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
924 .mmu_pt_equal = kgsl_iommu_pt_equal,
Shubhraprakash Das5a610b52012-05-09 17:31:54 -0600925 .mmu_pt_get_base_addr = kgsl_iommu_pt_get_base_addr,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600926};