blob: fb655653a95e420a80821f634384d55feeba4f75 [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 +
Shubhraprakash Dasc6e21012012-05-11 17:24:51 -0600598 iommu->iommu_units
599 [iommu->unit_count - 1].reg_map.gpuaddr -
600 PAGE_SIZE);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600601 } else {
602 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
603 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600604
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600605 mmu->hwpagetable = mmu->defaultpagetable;
606
607 status = kgsl_attach_pagetable_iommu_domain(mmu);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600608 if (status) {
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600609 mmu->hwpagetable = NULL;
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600610 goto done;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600611 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600612 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600613 if (status) {
614 KGSL_CORE_ERR("clk enable failed\n");
615 goto done;
616 }
617 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
618 if (status) {
619 KGSL_CORE_ERR("clk enable failed\n");
620 goto done;
621 }
622 /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as
623 * that value should not change when we change pagetables, so while
624 * changing pagetables we can use this lsb value of the pagetable w/o
625 * having to read it again
626 */
627 for (i = 0; i < iommu->unit_count; i++) {
628 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
629 for (j = 0; j < iommu_unit->dev_count; j++)
630 iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(
631 KGSL_IOMMU_GET_IOMMU_REG(
632 iommu_unit->reg_map.hostptr,
633 iommu_unit->dev[j].ctx_id,
634 TTBR0));
635 }
636 iommu->asid = KGSL_IOMMU_GET_IOMMU_REG(
637 iommu->iommu_units[0].reg_map.hostptr,
638 KGSL_IOMMU_CONTEXT_USER,
639 CONTEXTIDR);
640
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600641 kgsl_iommu_disable_clk(mmu);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600642 mmu->flags |= KGSL_FLAGS_STARTED;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600643
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600644done:
645 if (status) {
646 kgsl_iommu_disable_clk(mmu);
647 kgsl_detach_pagetable_iommu_domain(mmu);
648 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600649 return status;
650}
651
652static int
653kgsl_iommu_unmap(void *mmu_specific_pt,
654 struct kgsl_memdesc *memdesc)
655{
656 int ret;
657 unsigned int range = memdesc->size;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600658 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600659
660 /* All GPU addresses as assigned are page aligned, but some
661 functions purturb the gpuaddr with an offset, so apply the
662 mask here to make sure we have the right address */
663
664 unsigned int gpuaddr = memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK;
665
666 if (range == 0 || gpuaddr == 0)
667 return 0;
668
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600669 ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600670 if (ret)
671 KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600672 "with err: %d\n", iommu_pt->domain, gpuaddr,
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600673 range, ret);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600674
675 return 0;
676}
677
678static int
679kgsl_iommu_map(void *mmu_specific_pt,
680 struct kgsl_memdesc *memdesc,
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600681 unsigned int protflags,
682 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600683{
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600684 int ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600685 unsigned int iommu_virt_addr;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600686 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600687
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600688 BUG_ON(NULL == iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600689
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600690
Jordan Croused17e9aa2011-10-12 16:57:48 -0600691 iommu_virt_addr = memdesc->gpuaddr;
692
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600693 ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
Olav Hauganf310cf22012-05-08 08:42:49 -0700694 memdesc->size, (IOMMU_READ | IOMMU_WRITE));
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600695 if (ret) {
696 KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600697 "failed with err: %d\n", iommu_pt->domain,
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600698 iommu_virt_addr, memdesc->sg, memdesc->size,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600699 (IOMMU_READ | IOMMU_WRITE), ret);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600700 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600701 }
702
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600703#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
704 /*
705 * Flushing only required if per process pagetables are used. With
706 * global case, flushing will happen inside iommu_map function
707 */
708 if (!ret)
709 *tlb_flags = UINT_MAX;
710#endif
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600711 return ret;
712}
713
Shubhraprakash Das79447952012-04-26 18:12:23 -0600714static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600715{
716 /*
717 * stop device mmu
718 *
719 * call this with the global lock held
720 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600721
722 if (mmu->flags & KGSL_FLAGS_STARTED) {
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600723 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600724 /* detach iommu attachment */
725 kgsl_detach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600726 mmu->hwpagetable = NULL;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600727
728 mmu->flags &= ~KGSL_FLAGS_STARTED;
729 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600730}
731
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600732static int kgsl_iommu_close(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600733{
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600734 struct kgsl_iommu *iommu = mmu->priv;
735 int i;
736 for (i = 0; i < iommu->unit_count; i++) {
737 if (iommu->iommu_units[i].reg_map.gpuaddr)
738 kgsl_mmu_unmap(mmu->defaultpagetable,
739 &(iommu->iommu_units[i].reg_map));
740 if (iommu->iommu_units[i].reg_map.hostptr)
741 iounmap(iommu->iommu_units[i].reg_map.hostptr);
742 kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
743 iommu->iommu_units[i].reg_map.sglen);
744 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600745 if (mmu->defaultpagetable)
746 kgsl_mmu_putpagetable(mmu->defaultpagetable);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600747 kfree(iommu->asids);
748 kfree(iommu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600749
750 return 0;
751}
752
753static unsigned int
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600754kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600755{
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600756 unsigned int pt_base;
757 struct kgsl_iommu *iommu = mmu->priv;
758 /* Return the current pt base by reading IOMMU pt_base register */
759 kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
760 pt_base = readl_relaxed(iommu->iommu_units[0].reg_map.hostptr +
761 (KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
762 KGSL_IOMMU_TTBR0);
763 kgsl_iommu_disable_clk(mmu);
764 return pt_base & (KGSL_IOMMU_TTBR0_PA_MASK <<
765 KGSL_IOMMU_TTBR0_PA_SHIFT);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600766}
767
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600768/*
769 * kgsl_iommu_get_hwpagetable_asid - Returns asid(application space ID) for a
770 * pagetable
771 * @mmu - Pointer to mmu structure
772 *
773 * Allocates an asid to a IOMMU domain if it does not already have one. asid's
774 * are unique identifiers for pagetable that can be used to selectively flush
775 * tlb entries of the IOMMU unit.
776 * Return - asid to be used with the IOMMU domain
777 */
778static int kgsl_iommu_get_hwpagetable_asid(struct kgsl_mmu *mmu)
779{
780 struct kgsl_iommu *iommu = mmu->priv;
781 struct kgsl_iommu_pt *iommu_pt = mmu->hwpagetable->priv;
782
783 /*
784 * If the iommu pagetable does not have any asid assigned and is not the
785 * default pagetable then assign asid.
786 */
787 if (!iommu_pt->asid && iommu_pt != mmu->defaultpagetable->priv) {
788 iommu_pt->asid = find_first_zero_bit(iommu->asids,
789 KGSL_IOMMU_MAX_ASIDS);
790 /* No free bits means reuse asid */
791 if (iommu_pt->asid >= KGSL_IOMMU_MAX_ASIDS) {
792 iommu_pt->asid = KGSL_IOMMU_ASID_REUSE;
793 iommu->asid_reuse++;
794 }
795 set_bit(iommu_pt->asid, iommu->asids);
796 /*
797 * Store pointer to asids list so that during pagetable destroy
798 * the asid assigned to this pagetable may be cleared
799 */
800 iommu_pt->iommu = iommu;
801 }
802 /* Return the asid + the constant part of asid that never changes */
803 return (iommu_pt->asid & (KGSL_IOMMU_CONTEXTIDR_ASID_MASK <<
804 KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT)) +
805 (iommu->asid & ~(KGSL_IOMMU_CONTEXTIDR_ASID_MASK <<
806 KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT));
807}
808
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600809/*
810 * kgsl_iommu_default_setstate - Change the IOMMU pagetable or flush IOMMU tlb
811 * of the primary context bank
812 * @mmu - Pointer to mmu structure
813 * @flags - Flags indicating whether pagetable has to chnage or tlb is to be
814 * flushed or both
815 *
816 * Based on flags set the new pagetable fo the IOMMU unit or flush it's tlb or
817 * do both by doing direct register writes to the IOMMu registers through the
818 * cpu
819 * Return - void
820 */
821static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
822 uint32_t flags)
823{
824 struct kgsl_iommu *iommu = mmu->priv;
825 int temp;
826 int i;
827 unsigned int pt_base = kgsl_iommu_pt_get_base_addr(
828 mmu->hwpagetable);
829 unsigned int pt_val;
830
831 if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
832 KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
833 return;
834 }
835 /* Mask off the lsb of the pt base address since lsb will not change */
836 pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK << KGSL_IOMMU_TTBR0_PA_SHIFT);
837 if (flags & KGSL_MMUFLAGS_PTUPDATE) {
838 kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
839 for (i = 0; i < iommu->unit_count; i++) {
840 /* get the lsb value which should not change when
841 * changing ttbr0 */
842 pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
843 KGSL_IOMMU_CONTEXT_USER);
844 pt_val += pt_base;
845
846 KGSL_IOMMU_SET_IOMMU_REG(
847 iommu->iommu_units[i].reg_map.hostptr,
848 KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
849
850 mb();
851 temp = KGSL_IOMMU_GET_IOMMU_REG(
852 iommu->iommu_units[i].reg_map.hostptr,
853 KGSL_IOMMU_CONTEXT_USER, TTBR0);
854 /* Set asid */
855 KGSL_IOMMU_SET_IOMMU_REG(
856 iommu->iommu_units[i].reg_map.hostptr,
857 KGSL_IOMMU_CONTEXT_USER, CONTEXTIDR,
858 kgsl_iommu_get_hwpagetable_asid(mmu));
859 mb();
860 temp = KGSL_IOMMU_GET_IOMMU_REG(
861 iommu->iommu_units[i].reg_map.hostptr,
862 KGSL_IOMMU_CONTEXT_USER, CONTEXTIDR);
863 }
864 }
865 /* Flush tlb */
866 if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
867 for (i = 0; i < iommu->unit_count; i++) {
868 KGSL_IOMMU_SET_IOMMU_REG(
869 iommu->iommu_units[i].reg_map.hostptr,
870 KGSL_IOMMU_CONTEXT_USER, CTX_TLBIASID,
871 kgsl_iommu_get_hwpagetable_asid(mmu));
872 mb();
873 }
874 }
875 /* Disable smmu clock */
876 kgsl_iommu_disable_clk(mmu);
877}
878
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -0600879/*
880 * kgsl_iommu_get_reg_map_desc - Returns an array of pointers that contain
881 * the address of memory descriptors which map the IOMMU registers
882 * @mmu - Pointer to mmu structure
883 * @reg_map_desc - Out parameter in which the address of the array containing
884 * pointers to register map descriptors is returned. The caller is supposed
885 * to free this array
886 *
887 * Return - The number of iommu units which is also the number of register
888 * mapped descriptor arrays which the out parameter will have
889 */
890static int kgsl_iommu_get_reg_map_desc(struct kgsl_mmu *mmu,
891 void **reg_map_desc)
892{
893 struct kgsl_iommu *iommu = mmu->priv;
894 void **reg_desc_ptr;
895 int i;
896
897 /*
898 * Alocate array of pointers that will hold address of the register map
899 * descriptors
900 */
901 reg_desc_ptr = kmalloc(iommu->unit_count *
902 sizeof(struct kgsl_memdesc *), GFP_KERNEL);
903 if (!reg_desc_ptr) {
904 KGSL_CORE_ERR("Failed to kmalloc(%d)\n",
905 iommu->unit_count * sizeof(struct kgsl_memdesc *));
906 return -ENOMEM;
907 }
908
909 for (i = 0; i < iommu->unit_count; i++)
910 reg_desc_ptr[i] = &(iommu->iommu_units[i].reg_map);
911
912 *reg_map_desc = reg_desc_ptr;
913 return i;
914}
915
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600916struct kgsl_mmu_ops iommu_ops = {
917 .mmu_init = kgsl_iommu_init,
918 .mmu_close = kgsl_iommu_close,
919 .mmu_start = kgsl_iommu_start,
920 .mmu_stop = kgsl_iommu_stop,
921 .mmu_setstate = kgsl_iommu_setstate,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600922 .mmu_device_setstate = kgsl_iommu_default_setstate,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600923 .mmu_pagefault = NULL,
924 .mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600925 .mmu_enable_clk = kgsl_iommu_enable_clk,
926 .mmu_disable_clk = kgsl_iommu_disable_clk,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600927 .mmu_get_hwpagetable_asid = kgsl_iommu_get_hwpagetable_asid,
Shubhraprakash Dasfce27362012-05-09 17:44:14 -0600928 .mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -0600929 .mmu_get_reg_map_desc = kgsl_iommu_get_reg_map_desc,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600930};
931
932struct kgsl_mmu_pt_ops iommu_pt_ops = {
933 .mmu_map = kgsl_iommu_map,
934 .mmu_unmap = kgsl_iommu_unmap,
935 .mmu_create_pagetable = kgsl_iommu_create_pagetable,
936 .mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
937 .mmu_pt_equal = kgsl_iommu_pt_equal,
Shubhraprakash Das5a610b52012-05-09 17:31:54 -0600938 .mmu_pt_get_base_addr = kgsl_iommu_pt_get_base_addr,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600939};