blob: fdd4aa5d57ddf4255df8ea9e3ae95c539e3e4b39 [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 Dasbb5ad2a2012-05-09 22:58:52 -060027#include "adreno.h"
Shubhraprakash Das767fdda2011-08-15 15:49:45 -060028
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -060029/*
30 * kgsl_iommu_disable_clk - Disable iommu clocks
31 * @mmu - Pointer to mmu structure
32 *
33 * Disables iommu clocks
34 * Return - void
35 */
36static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu)
37{
38 struct kgsl_iommu *iommu = mmu->priv;
39 struct msm_iommu_drvdata *iommu_drvdata;
40 int i, j;
41
42 for (i = 0; i < iommu->unit_count; i++) {
43 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
44 for (j = 0; j < iommu_unit->dev_count; j++) {
45 if (!iommu_unit->dev[j].clk_enabled)
46 continue;
47 iommu_drvdata = dev_get_drvdata(
48 iommu_unit->dev[j].dev->parent);
49 if (iommu_drvdata->clk)
50 clk_disable_unprepare(iommu_drvdata->clk);
51 clk_disable_unprepare(iommu_drvdata->pclk);
52 iommu_unit->dev[j].clk_enabled = false;
53 }
54 }
55}
56
57/*
58 * kgsl_iommu_enable_clk - Enable iommu clocks
59 * @mmu - Pointer to mmu structure
60 * @ctx_id - The context bank whose clocks are to be turned on
61 *
62 * Enables iommu clocks of a given context
63 * Return: 0 on success else error code
64 */
65static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu,
66 int ctx_id)
67{
68 int ret = 0;
69 int i, j;
70 struct kgsl_iommu *iommu = mmu->priv;
71 struct msm_iommu_drvdata *iommu_drvdata;
72
73 for (i = 0; i < iommu->unit_count; i++) {
74 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
75 for (j = 0; j < iommu_unit->dev_count; j++) {
76 if (iommu_unit->dev[j].clk_enabled ||
77 ctx_id != iommu_unit->dev[j].ctx_id)
78 continue;
79 iommu_drvdata =
80 dev_get_drvdata(iommu_unit->dev[j].dev->parent);
81 ret = clk_prepare_enable(iommu_drvdata->pclk);
82 if (ret)
83 goto done;
84 if (iommu_drvdata->clk) {
85 ret = clk_prepare_enable(iommu_drvdata->clk);
86 if (ret) {
87 clk_disable_unprepare(
88 iommu_drvdata->pclk);
89 goto done;
90 }
91 }
92 iommu_unit->dev[j].clk_enabled = true;
93 }
94 }
95done:
96 if (ret)
97 kgsl_iommu_disable_clk(mmu);
98 return ret;
99}
100
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600101/*
102 * kgsl_iommu_pt_equal - Check if pagetables are equal
103 * @pt - Pointer to pagetable
104 * @pt_base - Address of a pagetable that the IOMMU register is
105 * programmed with
106 *
107 * Checks whether the pt_base is equal to the base address of
108 * the pagetable which is contained in the pt structure
109 * Return - Non-zero if the pagetable addresses are equal else 0
110 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600111static int kgsl_iommu_pt_equal(struct kgsl_pagetable *pt,
112 unsigned int pt_base)
113{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600114 struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
115 unsigned int domain_ptbase = iommu_pt ?
116 iommu_get_pt_base_addr(iommu_pt->domain) : 0;
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600117 /* Only compare the valid address bits of the pt_base */
118 domain_ptbase &= (KGSL_IOMMU_TTBR0_PA_MASK <<
119 KGSL_IOMMU_TTBR0_PA_SHIFT);
120 pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK <<
121 KGSL_IOMMU_TTBR0_PA_SHIFT);
122 return domain_ptbase && pt_base &&
123 (domain_ptbase == pt_base);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600124}
125
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600126/*
127 * kgsl_iommu_destroy_pagetable - Free up reaources help by a pagetable
128 * @mmu_specific_pt - Pointer to pagetable which is to be freed
129 *
130 * Return - void
131 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600132static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
133{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600134 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
135 if (iommu_pt->domain)
136 iommu_domain_free(iommu_pt->domain);
137 if (iommu_pt->iommu) {
138 if ((KGSL_IOMMU_ASID_REUSE == iommu_pt->asid) &&
139 iommu_pt->iommu->asid_reuse)
140 iommu_pt->iommu->asid_reuse--;
141 if (!iommu_pt->iommu->asid_reuse ||
142 (KGSL_IOMMU_ASID_REUSE != iommu_pt->asid))
143 clear_bit(iommu_pt->asid, iommu_pt->iommu->asids);
144 }
145 kfree(iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600146}
147
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600148/*
149 * kgsl_iommu_create_pagetable - Create a IOMMU pagetable
150 *
151 * Allocate memory to hold a pagetable and allocate the IOMMU
152 * domain which is the actual IOMMU pagetable
153 * Return - void
154 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600155void *kgsl_iommu_create_pagetable(void)
156{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600157 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600158
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600159 iommu_pt = kzalloc(sizeof(struct kgsl_iommu_pt), GFP_KERNEL);
160 if (!iommu_pt) {
161 KGSL_CORE_ERR("kzalloc(%d) failed\n",
162 sizeof(struct kgsl_iommu_pt));
163 return NULL;
164 }
Jordan Crouse523800f2012-04-16 14:14:45 -0600165 iommu_pt->domain = iommu_domain_alloc(MSM_IOMMU_DOMAIN_PT_CACHEABLE);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600166 if (!iommu_pt->domain) {
167 KGSL_CORE_ERR("Failed to create iommu domain\n");
168 kfree(iommu_pt);
169 return NULL;
170 }
171 return iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600172}
173
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600174/*
175 * kgsl_detach_pagetable_iommu_domain - Detach the IOMMU unit from a
176 * pagetable
177 * @mmu - Pointer to the device mmu structure
178 * @priv - Flag indicating whether the private or user context is to be
179 * detached
180 *
181 * Detach the IOMMU unit with the domain that is contained in the
182 * hwpagetable of the given mmu. After detaching the IOMMU unit is not
183 * in use because the PTBR will not be set after a detach
184 * Return - void
185 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600186static void kgsl_detach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
187{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600188 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600189 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600190 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600191
192 BUG_ON(mmu->hwpagetable == NULL);
193 BUG_ON(mmu->hwpagetable->priv == NULL);
194
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600195 iommu_pt = mmu->hwpagetable->priv;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600196
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600197 for (i = 0; i < iommu->unit_count; i++) {
198 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
199 for (j = 0; j < iommu_unit->dev_count; j++) {
200 if (iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600201 iommu_detach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600202 iommu_unit->dev[j].dev);
203 iommu_unit->dev[j].attached = false;
204 KGSL_MEM_INFO(mmu->device, "iommu %p detached "
205 "from user dev of MMU: %p\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600206 iommu_pt->domain, mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600207 }
208 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600209 }
210}
211
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600212/*
213 * kgsl_attach_pagetable_iommu_domain - Attach the IOMMU unit to a
214 * pagetable, i.e set the IOMMU's PTBR to the pagetable address and
215 * setup other IOMMU registers for the device so that it becomes
216 * active
217 * @mmu - Pointer to the device mmu structure
218 * @priv - Flag indicating whether the private or user context is to be
219 * attached
220 *
221 * Attach the IOMMU unit with the domain that is contained in the
222 * hwpagetable of the given mmu.
223 * Return - 0 on success else error code
224 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600225static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
226{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600227 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600228 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600229 int i, j, ret = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600230
231 BUG_ON(mmu->hwpagetable == NULL);
232 BUG_ON(mmu->hwpagetable->priv == NULL);
233
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600234 iommu_pt = mmu->hwpagetable->priv;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600235
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600236 /*
237 * Loop through all the iommu devcies under all iommu units and
238 * attach the domain
239 */
240 for (i = 0; i < iommu->unit_count; i++) {
241 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
242 for (j = 0; j < iommu_unit->dev_count; j++) {
243 if (!iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600244 ret = iommu_attach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600245 iommu_unit->dev[j].dev);
246 if (ret) {
247 KGSL_MEM_ERR(mmu->device,
248 "Failed to attach device, err %d\n",
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700249 ret);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600250 goto done;
251 }
252 iommu_unit->dev[j].attached = true;
253 KGSL_MEM_INFO(mmu->device,
254 "iommu pt %p attached to dev %p, ctx_id %d\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600255 iommu_pt->domain, iommu_unit->dev[j].dev,
256 iommu_unit->dev[j].ctx_id);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700257 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600258 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600259 }
260done:
261 return ret;
262}
263
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600264/*
265 * _get_iommu_ctxs - Get device pointer to IOMMU contexts
266 * @mmu - Pointer to mmu device
267 * data - Pointer to the platform data containing information about
268 * iommu devices for one iommu unit
269 * unit_id - The IOMMU unit number. This is not a specific ID but just
270 * a serial number. The serial numbers are treated as ID's of the
271 * IOMMU units
272 *
273 * Return - 0 on success else error code
274 */
275static int _get_iommu_ctxs(struct kgsl_mmu *mmu,
276 struct kgsl_device_iommu_data *data, unsigned int unit_id)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700277{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600278 struct kgsl_iommu *iommu = mmu->priv;
279 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id];
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700280 int i;
281
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600282 if (data->iommu_ctx_count > KGSL_IOMMU_MAX_DEVS_PER_UNIT) {
283 KGSL_CORE_ERR("Too many iommu devices defined for an "
284 "IOMMU unit\n");
285 return -EINVAL;
286 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700287
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600288 for (i = 0; i < data->iommu_ctx_count; i++) {
289 if (!data->iommu_ctxs[i].iommu_ctx_name)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700290 continue;
291
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600292 iommu_unit->dev[iommu_unit->dev_count].dev =
293 msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
294 if (iommu_unit->dev[iommu_unit->dev_count].dev == NULL) {
295 KGSL_CORE_ERR("Failed to get iommu dev handle for "
296 "device %s\n", data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700297 return -EINVAL;
298 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600299 if (KGSL_IOMMU_CONTEXT_USER != data->iommu_ctxs[i].ctx_id &&
300 KGSL_IOMMU_CONTEXT_PRIV != data->iommu_ctxs[i].ctx_id) {
301 KGSL_CORE_ERR("Invalid context ID defined: %d\n",
302 data->iommu_ctxs[i].ctx_id);
303 return -EINVAL;
304 }
305 iommu_unit->dev[iommu_unit->dev_count].ctx_id =
306 data->iommu_ctxs[i].ctx_id;
307 KGSL_DRV_INFO(mmu->device,
308 "Obtained dev handle %p for iommu context %s\n",
309 iommu_unit->dev[iommu_unit->dev_count].dev,
310 data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700311
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600312 iommu_unit->dev_count++;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700313 }
314
315 return 0;
316}
317
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600318/*
319 * kgsl_get_iommu_ctxt - Get device pointer to IOMMU contexts
320 * @mmu - Pointer to mmu device
321 *
322 * Get the device pointers for the IOMMU user and priv contexts of the
323 * kgsl device
324 * Return - 0 on success else error code
325 */
326static int kgsl_get_iommu_ctxt(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600327{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600328 struct platform_device *pdev =
329 container_of(mmu->device->parentdev, struct platform_device,
330 dev);
331 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
332 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700333 int i, ret = 0;
334
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600335 /* Go through the IOMMU data and get all the context devices */
336 if (KGSL_IOMMU_MAX_UNITS < pdata_dev->iommu_count) {
337 KGSL_CORE_ERR("Too many IOMMU units defined\n");
338 ret = -EINVAL;
339 goto done;
340 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700341
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600342 for (i = 0; i < pdata_dev->iommu_count; i++) {
343 ret = _get_iommu_ctxs(mmu, &pdata_dev->iommu_data[i], i);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700344 if (ret)
345 break;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600346 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600347 iommu->unit_count = pdata_dev->iommu_count;
348done:
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700349 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600350}
351
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600352/*
353 * kgsl_set_register_map - Map the IOMMU regsiters in the memory descriptors
354 * of the respective iommu units
355 * @mmu - Pointer to mmu structure
356 *
357 * Return - 0 on success else error code
358 */
359static int kgsl_set_register_map(struct kgsl_mmu *mmu)
360{
361 struct platform_device *pdev =
362 container_of(mmu->device->parentdev, struct platform_device,
363 dev);
364 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
365 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
366 struct kgsl_iommu_unit *iommu_unit;
367 int i = 0, ret = 0;
368
369 for (; i < pdata_dev->iommu_count; i++) {
370 struct kgsl_device_iommu_data data = pdata_dev->iommu_data[i];
371 iommu_unit = &iommu->iommu_units[i];
372 /* set up the IOMMU register map for the given IOMMU unit */
373 if (!data.physstart || !data.physend) {
374 KGSL_CORE_ERR("The register range for IOMMU unit not"
375 " specified\n");
376 ret = -EINVAL;
377 goto err;
378 }
379 iommu_unit->reg_map.hostptr = ioremap(data.physstart,
380 data.physend - data.physstart + 1);
381 if (!iommu_unit->reg_map.hostptr) {
382 KGSL_CORE_ERR("Failed to map SMMU register address "
383 "space from %x to %x\n", data.physstart,
384 data.physend - data.physstart + 1);
385 ret = -ENOMEM;
386 i--;
387 goto err;
388 }
389 iommu_unit->reg_map.size = data.physend - data.physstart + 1;
390 iommu_unit->reg_map.physaddr = data.physstart;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600391 memdesc_sg_phys(&iommu_unit->reg_map, data.physstart,
392 iommu_unit->reg_map.size);
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600393 }
394 iommu->unit_count = pdata_dev->iommu_count;
395 return ret;
396err:
397 /* Unmap any mapped IOMMU regions */
398 for (; i >= 0; i--) {
399 iommu_unit = &iommu->iommu_units[i];
400 iounmap(iommu_unit->reg_map.hostptr);
401 iommu_unit->reg_map.size = 0;
402 iommu_unit->reg_map.physaddr = 0;
403 }
404 return ret;
405}
406
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600407/*
408 * kgsl_iommu_pt_get_base_addr - Get the address of the pagetable that the
409 * IOMMU ttbr0 register is programmed with
410 * @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
411 *
412 * Return - actual pagetable address that the ttbr0 register is programmed
413 * with
414 */
415static unsigned int kgsl_iommu_pt_get_base_addr(struct kgsl_pagetable *pt)
416{
417 struct kgsl_iommu_pt *iommu_pt = pt->priv;
418 return iommu_get_pt_base_addr(iommu_pt->domain);
419}
420
421/*
422 * kgsl_iommu_get_pt_lsb - Return the lsb of the ttbr0 IOMMU register
423 * @mmu - Pointer to mmu structure
424 * @hostptr - Pointer to the IOMMU register map. This is used to match
425 * the iommu device whose lsb value is to be returned
426 * @ctx_id - The context bank whose lsb valus is to be returned
427 * Return - returns the lsb which is the last 14 bits of the ttbr0 IOMMU
428 * register. ttbr0 is the actual PTBR for of the IOMMU. The last 14 bits
429 * are only programmed once in the beginning when a domain is attached
430 * does not change.
431 */
432static int kgsl_iommu_get_pt_lsb(struct kgsl_mmu *mmu,
433 unsigned int unit_id,
434 enum kgsl_iommu_context_id ctx_id)
435{
436 struct kgsl_iommu *iommu = mmu->priv;
437 int i, j;
438 for (i = 0; i < iommu->unit_count; i++) {
439 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
440 for (j = 0; j < iommu_unit->dev_count; j++)
441 if (unit_id == i &&
442 ctx_id == iommu_unit->dev[j].ctx_id)
443 return iommu_unit->dev[j].pt_lsb;
444 }
445 return 0;
446}
447
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600448static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600449 struct kgsl_pagetable *pagetable)
450{
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600451 if (mmu->flags & KGSL_FLAGS_STARTED) {
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600452 struct kgsl_iommu *iommu = mmu->priv;
453 struct kgsl_iommu_pt *iommu_pt = pagetable->priv;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600454 /* page table not current, then setup mmu to use new
455 * specified page table
456 */
457 if (mmu->hwpagetable != pagetable) {
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600458 unsigned int flags = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600459 mmu->hwpagetable = pagetable;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600460 /* force tlb flush if asid is reused */
461 if (iommu->asid_reuse &&
462 (KGSL_IOMMU_ASID_REUSE == iommu_pt->asid))
463 flags |= KGSL_MMUFLAGS_TLBFLUSH;
464 flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
465 mmu->device->id);
466 kgsl_setstate(mmu, KGSL_MMUFLAGS_PTUPDATE | flags);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600467 }
468 }
469}
470
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600471static int kgsl_iommu_init(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600472{
473 /*
474 * intialize device mmu
475 *
476 * call this with the global lock held
477 */
478 int status = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600479 struct kgsl_iommu *iommu;
480
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600481 iommu = kzalloc(sizeof(struct kgsl_iommu), GFP_KERNEL);
482 if (!iommu) {
483 KGSL_CORE_ERR("kzalloc(%d) failed\n",
484 sizeof(struct kgsl_iommu));
485 return -ENOMEM;
486 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600487 iommu->asids = kzalloc(BITS_TO_LONGS(KGSL_IOMMU_MAX_ASIDS) *
488 sizeof(unsigned long), GFP_KERNEL);
489 if (!iommu->asids) {
490 KGSL_CORE_ERR("kzalloc(%d) failed\n",
491 sizeof(struct kgsl_iommu));
492 status = -ENOMEM;
493 goto done;
494 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600495
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600496 mmu->priv = iommu;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600497 status = kgsl_get_iommu_ctxt(mmu);
498 if (status)
499 goto done;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600500 status = kgsl_set_register_map(mmu);
501 if (status)
502 goto done;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600503
Shubhraprakash Dase9541a32012-05-09 22:25:55 -0600504 /* A nop is required in an indirect buffer when switching
505 * pagetables in-stream */
506 kgsl_sharedmem_writel(&mmu->setstate_memory,
507 KGSL_IOMMU_SETSTATE_NOP_OFFSET,
508 cp_nop_packet(1));
509
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600510 dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600511 __func__);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600512done:
513 if (status) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600514 kfree(iommu->asids);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600515 kfree(iommu);
516 mmu->priv = NULL;
517 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600518 return status;
519}
520
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600521/*
522 * kgsl_iommu_setup_defaultpagetable - Setup the initial defualtpagetable
523 * for iommu. This function is only called once during first start, successive
524 * start do not call this funciton.
525 * @mmu - Pointer to mmu structure
526 *
527 * Create the initial defaultpagetable and setup the iommu mappings to it
528 * Return - 0 on success else error code
529 */
530static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu)
531{
532 int status = 0;
533 int i = 0;
534 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600535 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600536
537 mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
538 /* Return error if the default pagetable doesn't exist */
539 if (mmu->defaultpagetable == NULL) {
540 status = -ENOMEM;
541 goto err;
542 }
543 /* Map the IOMMU regsiters to only defaultpagetable */
544 for (i = 0; i < iommu->unit_count; i++) {
545 iommu->iommu_units[i].reg_map.priv |= KGSL_MEMFLAGS_GLOBAL;
546 status = kgsl_mmu_map(mmu->defaultpagetable,
547 &(iommu->iommu_units[i].reg_map),
548 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
549 if (status) {
550 iommu->iommu_units[i].reg_map.priv &=
551 ~KGSL_MEMFLAGS_GLOBAL;
552 goto err;
553 }
554 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600555 /*
556 * The dafault pagetable always has asid 0 assigned by the iommu driver
557 * and asid 1 is assigned to the private context.
558 */
559 iommu_pt = mmu->defaultpagetable->priv;
560 iommu_pt->asid = 0;
561 set_bit(0, iommu->asids);
562 set_bit(1, iommu->asids);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600563 return status;
564err:
565 for (i--; i >= 0; i--) {
566 kgsl_mmu_unmap(mmu->defaultpagetable,
567 &(iommu->iommu_units[i].reg_map));
568 iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMFLAGS_GLOBAL;
569 }
570 if (mmu->defaultpagetable) {
571 kgsl_mmu_putpagetable(mmu->defaultpagetable);
572 mmu->defaultpagetable = NULL;
573 }
574 return status;
575}
576
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600577static int kgsl_iommu_start(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600578{
579 int status;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600580 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600581 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600582
583 if (mmu->flags & KGSL_FLAGS_STARTED)
584 return 0;
585
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600586 if (mmu->defaultpagetable == NULL) {
587 status = kgsl_iommu_setup_defaultpagetable(mmu);
588 if (status)
589 return -ENOMEM;
590 }
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600591 /* We use the GPU MMU to control access to IOMMU registers on a225,
592 * hence we still keep the MMU active on a225 */
593 if (adreno_is_a225(ADRENO_DEVICE(mmu->device))) {
594 struct kgsl_mh *mh = &(mmu->device->mh);
595 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001);
596 kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
597 mh->mpu_base +
598 iommu->iommu_units[0].reg_map.gpuaddr - PAGE_SIZE);
599 } else {
600 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
601 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600602
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600603 mmu->hwpagetable = mmu->defaultpagetable;
604
605 status = kgsl_attach_pagetable_iommu_domain(mmu);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600606 if (status) {
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600607 mmu->hwpagetable = NULL;
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600608 goto done;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600609 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600610 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600611 if (status) {
612 KGSL_CORE_ERR("clk enable failed\n");
613 goto done;
614 }
615 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
616 if (status) {
617 KGSL_CORE_ERR("clk enable failed\n");
618 goto done;
619 }
620 /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as
621 * that value should not change when we change pagetables, so while
622 * changing pagetables we can use this lsb value of the pagetable w/o
623 * having to read it again
624 */
625 for (i = 0; i < iommu->unit_count; i++) {
626 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
627 for (j = 0; j < iommu_unit->dev_count; j++)
628 iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(
629 KGSL_IOMMU_GET_IOMMU_REG(
630 iommu_unit->reg_map.hostptr,
631 iommu_unit->dev[j].ctx_id,
632 TTBR0));
633 }
634 iommu->asid = KGSL_IOMMU_GET_IOMMU_REG(
635 iommu->iommu_units[0].reg_map.hostptr,
636 KGSL_IOMMU_CONTEXT_USER,
637 CONTEXTIDR);
638
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600639 kgsl_iommu_disable_clk(mmu);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600640 mmu->flags |= KGSL_FLAGS_STARTED;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600641
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600642done:
643 if (status) {
644 kgsl_iommu_disable_clk(mmu);
645 kgsl_detach_pagetable_iommu_domain(mmu);
646 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600647 return status;
648}
649
650static int
651kgsl_iommu_unmap(void *mmu_specific_pt,
652 struct kgsl_memdesc *memdesc)
653{
654 int ret;
655 unsigned int range = memdesc->size;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600656 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600657
658 /* All GPU addresses as assigned are page aligned, but some
659 functions purturb the gpuaddr with an offset, so apply the
660 mask here to make sure we have the right address */
661
662 unsigned int gpuaddr = memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK;
663
664 if (range == 0 || gpuaddr == 0)
665 return 0;
666
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600667 ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600668 if (ret)
669 KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600670 "with err: %d\n", iommu_pt->domain, gpuaddr,
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600671 range, ret);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600672
673 return 0;
674}
675
676static int
677kgsl_iommu_map(void *mmu_specific_pt,
678 struct kgsl_memdesc *memdesc,
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600679 unsigned int protflags,
680 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600681{
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600682 int ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600683 unsigned int iommu_virt_addr;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600684 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600685
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600686 BUG_ON(NULL == iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600687
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600688
Jordan Croused17e9aa2011-10-12 16:57:48 -0600689 iommu_virt_addr = memdesc->gpuaddr;
690
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600691 ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
Olav Hauganf310cf22012-05-08 08:42:49 -0700692 memdesc->size, (IOMMU_READ | IOMMU_WRITE));
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600693 if (ret) {
694 KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600695 "failed with err: %d\n", iommu_pt->domain,
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600696 iommu_virt_addr, memdesc->sg, memdesc->size,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600697 (IOMMU_READ | IOMMU_WRITE), ret);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600698 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600699 }
700
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600701#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
702 /*
703 * Flushing only required if per process pagetables are used. With
704 * global case, flushing will happen inside iommu_map function
705 */
706 if (!ret)
707 *tlb_flags = UINT_MAX;
708#endif
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600709 return ret;
710}
711
Shubhraprakash Das79447952012-04-26 18:12:23 -0600712static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600713{
714 /*
715 * stop device mmu
716 *
717 * call this with the global lock held
718 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600719
720 if (mmu->flags & KGSL_FLAGS_STARTED) {
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600721 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600722 /* detach iommu attachment */
723 kgsl_detach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600724 mmu->hwpagetable = NULL;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600725
726 mmu->flags &= ~KGSL_FLAGS_STARTED;
727 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600728}
729
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600730static int kgsl_iommu_close(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600731{
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600732 struct kgsl_iommu *iommu = mmu->priv;
733 int i;
734 for (i = 0; i < iommu->unit_count; i++) {
735 if (iommu->iommu_units[i].reg_map.gpuaddr)
736 kgsl_mmu_unmap(mmu->defaultpagetable,
737 &(iommu->iommu_units[i].reg_map));
738 if (iommu->iommu_units[i].reg_map.hostptr)
739 iounmap(iommu->iommu_units[i].reg_map.hostptr);
740 kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
741 iommu->iommu_units[i].reg_map.sglen);
742 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600743 if (mmu->defaultpagetable)
744 kgsl_mmu_putpagetable(mmu->defaultpagetable);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600745 kfree(iommu->asids);
746 kfree(iommu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600747
748 return 0;
749}
750
751static unsigned int
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600752kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600753{
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600754 unsigned int pt_base;
755 struct kgsl_iommu *iommu = mmu->priv;
756 /* Return the current pt base by reading IOMMU pt_base register */
757 kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
758 pt_base = readl_relaxed(iommu->iommu_units[0].reg_map.hostptr +
759 (KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
760 KGSL_IOMMU_TTBR0);
761 kgsl_iommu_disable_clk(mmu);
762 return pt_base & (KGSL_IOMMU_TTBR0_PA_MASK <<
763 KGSL_IOMMU_TTBR0_PA_SHIFT);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600764}
765
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600766/*
767 * kgsl_iommu_get_hwpagetable_asid - Returns asid(application space ID) for a
768 * pagetable
769 * @mmu - Pointer to mmu structure
770 *
771 * Allocates an asid to a IOMMU domain if it does not already have one. asid's
772 * are unique identifiers for pagetable that can be used to selectively flush
773 * tlb entries of the IOMMU unit.
774 * Return - asid to be used with the IOMMU domain
775 */
776static int kgsl_iommu_get_hwpagetable_asid(struct kgsl_mmu *mmu)
777{
778 struct kgsl_iommu *iommu = mmu->priv;
779 struct kgsl_iommu_pt *iommu_pt = mmu->hwpagetable->priv;
780
781 /*
782 * If the iommu pagetable does not have any asid assigned and is not the
783 * default pagetable then assign asid.
784 */
785 if (!iommu_pt->asid && iommu_pt != mmu->defaultpagetable->priv) {
786 iommu_pt->asid = find_first_zero_bit(iommu->asids,
787 KGSL_IOMMU_MAX_ASIDS);
788 /* No free bits means reuse asid */
789 if (iommu_pt->asid >= KGSL_IOMMU_MAX_ASIDS) {
790 iommu_pt->asid = KGSL_IOMMU_ASID_REUSE;
791 iommu->asid_reuse++;
792 }
793 set_bit(iommu_pt->asid, iommu->asids);
794 /*
795 * Store pointer to asids list so that during pagetable destroy
796 * the asid assigned to this pagetable may be cleared
797 */
798 iommu_pt->iommu = iommu;
799 }
800 /* Return the asid + the constant part of asid that never changes */
801 return (iommu_pt->asid & (KGSL_IOMMU_CONTEXTIDR_ASID_MASK <<
802 KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT)) +
803 (iommu->asid & ~(KGSL_IOMMU_CONTEXTIDR_ASID_MASK <<
804 KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT));
805}
806
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600807/*
808 * kgsl_iommu_default_setstate - Change the IOMMU pagetable or flush IOMMU tlb
809 * of the primary context bank
810 * @mmu - Pointer to mmu structure
811 * @flags - Flags indicating whether pagetable has to chnage or tlb is to be
812 * flushed or both
813 *
814 * Based on flags set the new pagetable fo the IOMMU unit or flush it's tlb or
815 * do both by doing direct register writes to the IOMMu registers through the
816 * cpu
817 * Return - void
818 */
819static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
820 uint32_t flags)
821{
822 struct kgsl_iommu *iommu = mmu->priv;
823 int temp;
824 int i;
825 unsigned int pt_base = kgsl_iommu_pt_get_base_addr(
826 mmu->hwpagetable);
827 unsigned int pt_val;
828
829 if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
830 KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
831 return;
832 }
833 /* Mask off the lsb of the pt base address since lsb will not change */
834 pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK << KGSL_IOMMU_TTBR0_PA_SHIFT);
835 if (flags & KGSL_MMUFLAGS_PTUPDATE) {
836 kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
837 for (i = 0; i < iommu->unit_count; i++) {
838 /* get the lsb value which should not change when
839 * changing ttbr0 */
840 pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
841 KGSL_IOMMU_CONTEXT_USER);
842 pt_val += pt_base;
843
844 KGSL_IOMMU_SET_IOMMU_REG(
845 iommu->iommu_units[i].reg_map.hostptr,
846 KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
847
848 mb();
849 temp = KGSL_IOMMU_GET_IOMMU_REG(
850 iommu->iommu_units[i].reg_map.hostptr,
851 KGSL_IOMMU_CONTEXT_USER, TTBR0);
852 /* Set asid */
853 KGSL_IOMMU_SET_IOMMU_REG(
854 iommu->iommu_units[i].reg_map.hostptr,
855 KGSL_IOMMU_CONTEXT_USER, CONTEXTIDR,
856 kgsl_iommu_get_hwpagetable_asid(mmu));
857 mb();
858 temp = KGSL_IOMMU_GET_IOMMU_REG(
859 iommu->iommu_units[i].reg_map.hostptr,
860 KGSL_IOMMU_CONTEXT_USER, CONTEXTIDR);
861 }
862 }
863 /* Flush tlb */
864 if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
865 for (i = 0; i < iommu->unit_count; i++) {
866 KGSL_IOMMU_SET_IOMMU_REG(
867 iommu->iommu_units[i].reg_map.hostptr,
868 KGSL_IOMMU_CONTEXT_USER, CTX_TLBIASID,
869 kgsl_iommu_get_hwpagetable_asid(mmu));
870 mb();
871 }
872 }
873 /* Disable smmu clock */
874 kgsl_iommu_disable_clk(mmu);
875}
876
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -0600877/*
878 * kgsl_iommu_get_reg_map_desc - Returns an array of pointers that contain
879 * the address of memory descriptors which map the IOMMU registers
880 * @mmu - Pointer to mmu structure
881 * @reg_map_desc - Out parameter in which the address of the array containing
882 * pointers to register map descriptors is returned. The caller is supposed
883 * to free this array
884 *
885 * Return - The number of iommu units which is also the number of register
886 * mapped descriptor arrays which the out parameter will have
887 */
888static int kgsl_iommu_get_reg_map_desc(struct kgsl_mmu *mmu,
889 void **reg_map_desc)
890{
891 struct kgsl_iommu *iommu = mmu->priv;
892 void **reg_desc_ptr;
893 int i;
894
895 /*
896 * Alocate array of pointers that will hold address of the register map
897 * descriptors
898 */
899 reg_desc_ptr = kmalloc(iommu->unit_count *
900 sizeof(struct kgsl_memdesc *), GFP_KERNEL);
901 if (!reg_desc_ptr) {
902 KGSL_CORE_ERR("Failed to kmalloc(%d)\n",
903 iommu->unit_count * sizeof(struct kgsl_memdesc *));
904 return -ENOMEM;
905 }
906
907 for (i = 0; i < iommu->unit_count; i++)
908 reg_desc_ptr[i] = &(iommu->iommu_units[i].reg_map);
909
910 *reg_map_desc = reg_desc_ptr;
911 return i;
912}
913
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600914struct kgsl_mmu_ops iommu_ops = {
915 .mmu_init = kgsl_iommu_init,
916 .mmu_close = kgsl_iommu_close,
917 .mmu_start = kgsl_iommu_start,
918 .mmu_stop = kgsl_iommu_stop,
919 .mmu_setstate = kgsl_iommu_setstate,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600920 .mmu_device_setstate = kgsl_iommu_default_setstate,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600921 .mmu_pagefault = NULL,
922 .mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600923 .mmu_enable_clk = kgsl_iommu_enable_clk,
924 .mmu_disable_clk = kgsl_iommu_disable_clk,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600925 .mmu_get_hwpagetable_asid = kgsl_iommu_get_hwpagetable_asid,
Shubhraprakash Dasfce27362012-05-09 17:44:14 -0600926 .mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -0600927 .mmu_get_reg_map_desc = kgsl_iommu_get_reg_map_desc,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600928};
929
930struct kgsl_mmu_pt_ops iommu_pt_ops = {
931 .mmu_map = kgsl_iommu_map,
932 .mmu_unmap = kgsl_iommu_unmap,
933 .mmu_create_pagetable = kgsl_iommu_create_pagetable,
934 .mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
935 .mmu_pt_equal = kgsl_iommu_pt_equal,
Shubhraprakash Das5a610b52012-05-09 17:31:54 -0600936 .mmu_pt_get_base_addr = kgsl_iommu_pt_get_base_addr,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600937};