blob: e42c7b64b59c4300c0a480ed2f5f40a64941fc25 [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"
Jordan Crouse95b68472012-05-25 10:25:01 -060028#include "kgsl_trace.h"
29
30static struct kgsl_iommu_unit *get_iommu_unit(struct device *dev)
31{
32 int i, j, k;
33
34 for (i = 0; i < KGSL_DEVICE_MAX; i++) {
35 struct kgsl_mmu *mmu;
36 struct kgsl_iommu *iommu;
37
38 if (kgsl_driver.devp[i] == NULL)
39 continue;
40
41 mmu = kgsl_get_mmu(kgsl_driver.devp[i]);
42 if (mmu == NULL || mmu->priv == NULL)
43 continue;
44
45 iommu = mmu->priv;
46
47 for (j = 0; j < iommu->unit_count; j++) {
48 struct kgsl_iommu_unit *iommu_unit =
49 &iommu->iommu_units[j];
50 for (k = 0; k < iommu_unit->dev_count; k++) {
51 if (iommu_unit->dev[k].dev == dev)
52 return iommu_unit;
53 }
54 }
55 }
56
57 return NULL;
58}
59
60static struct kgsl_iommu_device *get_iommu_device(struct kgsl_iommu_unit *unit,
61 struct device *dev)
62{
63 int k;
64
65 for (k = 0; unit && k < unit->dev_count; k++) {
66 if (unit->dev[k].dev == dev)
67 return &(unit->dev[k]);
68 }
69
70 return NULL;
71}
72
73static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
74 struct device *dev, unsigned long addr, int flags)
75{
76 struct kgsl_iommu_unit *iommu_unit = get_iommu_unit(dev);
77 struct kgsl_iommu_device *iommu_dev = get_iommu_device(iommu_unit, dev);
78 unsigned int ptbase, fsr;
79
80 if (!iommu_dev) {
81 KGSL_CORE_ERR("Invalid IOMMU device %p\n", dev);
82 return -ENOSYS;
83 }
84
Shubhraprakash Das190553a2012-06-11 15:17:59 -060085 ptbase = KGSL_IOMMU_GET_IOMMU_REG(iommu_unit->reg_map.hostptr,
86 iommu_dev->ctx_id, TTBR0);
Jordan Crouse95b68472012-05-25 10:25:01 -060087
88 fsr = KGSL_IOMMU_GET_IOMMU_REG(iommu_unit->reg_map.hostptr,
89 iommu_dev->ctx_id, FSR);
90
91 KGSL_MEM_CRIT(iommu_dev->kgsldev,
92 "GPU PAGE FAULT: addr = %lX pid = %d\n",
93 addr, kgsl_mmu_get_ptname_from_ptbase(ptbase));
94 KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
95 iommu_dev->ctx_id, fsr);
96
97 trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
98 kgsl_mmu_get_ptname_from_ptbase(ptbase), 0);
99
100 return 0;
101}
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600102
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600103/*
104 * kgsl_iommu_disable_clk - Disable iommu clocks
105 * @mmu - Pointer to mmu structure
106 *
107 * Disables iommu clocks
108 * Return - void
109 */
110static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu)
111{
112 struct kgsl_iommu *iommu = mmu->priv;
113 struct msm_iommu_drvdata *iommu_drvdata;
114 int i, j;
115
116 for (i = 0; i < iommu->unit_count; i++) {
117 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
118 for (j = 0; j < iommu_unit->dev_count; j++) {
119 if (!iommu_unit->dev[j].clk_enabled)
120 continue;
121 iommu_drvdata = dev_get_drvdata(
122 iommu_unit->dev[j].dev->parent);
123 if (iommu_drvdata->clk)
124 clk_disable_unprepare(iommu_drvdata->clk);
125 clk_disable_unprepare(iommu_drvdata->pclk);
126 iommu_unit->dev[j].clk_enabled = false;
127 }
128 }
129}
130
131/*
132 * kgsl_iommu_enable_clk - Enable iommu clocks
133 * @mmu - Pointer to mmu structure
134 * @ctx_id - The context bank whose clocks are to be turned on
135 *
136 * Enables iommu clocks of a given context
137 * Return: 0 on success else error code
138 */
139static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu,
140 int ctx_id)
141{
142 int ret = 0;
143 int i, j;
144 struct kgsl_iommu *iommu = mmu->priv;
145 struct msm_iommu_drvdata *iommu_drvdata;
146
147 for (i = 0; i < iommu->unit_count; i++) {
148 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
149 for (j = 0; j < iommu_unit->dev_count; j++) {
150 if (iommu_unit->dev[j].clk_enabled ||
151 ctx_id != iommu_unit->dev[j].ctx_id)
152 continue;
153 iommu_drvdata =
154 dev_get_drvdata(iommu_unit->dev[j].dev->parent);
155 ret = clk_prepare_enable(iommu_drvdata->pclk);
156 if (ret)
157 goto done;
158 if (iommu_drvdata->clk) {
159 ret = clk_prepare_enable(iommu_drvdata->clk);
160 if (ret) {
161 clk_disable_unprepare(
162 iommu_drvdata->pclk);
163 goto done;
164 }
165 }
166 iommu_unit->dev[j].clk_enabled = true;
167 }
168 }
169done:
170 if (ret)
171 kgsl_iommu_disable_clk(mmu);
172 return ret;
173}
174
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600175/*
176 * kgsl_iommu_pt_equal - Check if pagetables are equal
177 * @pt - Pointer to pagetable
178 * @pt_base - Address of a pagetable that the IOMMU register is
179 * programmed with
180 *
181 * Checks whether the pt_base is equal to the base address of
182 * the pagetable which is contained in the pt structure
183 * Return - Non-zero if the pagetable addresses are equal else 0
184 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600185static int kgsl_iommu_pt_equal(struct kgsl_pagetable *pt,
186 unsigned int pt_base)
187{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600188 struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
189 unsigned int domain_ptbase = iommu_pt ?
190 iommu_get_pt_base_addr(iommu_pt->domain) : 0;
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600191 /* Only compare the valid address bits of the pt_base */
192 domain_ptbase &= (KGSL_IOMMU_TTBR0_PA_MASK <<
193 KGSL_IOMMU_TTBR0_PA_SHIFT);
194 pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK <<
195 KGSL_IOMMU_TTBR0_PA_SHIFT);
196 return domain_ptbase && pt_base &&
197 (domain_ptbase == pt_base);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600198}
199
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600200/*
201 * kgsl_iommu_destroy_pagetable - Free up reaources help by a pagetable
202 * @mmu_specific_pt - Pointer to pagetable which is to be freed
203 *
204 * Return - void
205 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600206static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
207{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600208 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
209 if (iommu_pt->domain)
210 iommu_domain_free(iommu_pt->domain);
211 if (iommu_pt->iommu) {
212 if ((KGSL_IOMMU_ASID_REUSE == iommu_pt->asid) &&
213 iommu_pt->iommu->asid_reuse)
214 iommu_pt->iommu->asid_reuse--;
215 if (!iommu_pt->iommu->asid_reuse ||
216 (KGSL_IOMMU_ASID_REUSE != iommu_pt->asid))
217 clear_bit(iommu_pt->asid, iommu_pt->iommu->asids);
218 }
219 kfree(iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600220}
221
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600222/*
223 * kgsl_iommu_create_pagetable - Create a IOMMU pagetable
224 *
225 * Allocate memory to hold a pagetable and allocate the IOMMU
226 * domain which is the actual IOMMU pagetable
227 * Return - void
228 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600229void *kgsl_iommu_create_pagetable(void)
230{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600231 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600232
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600233 iommu_pt = kzalloc(sizeof(struct kgsl_iommu_pt), GFP_KERNEL);
234 if (!iommu_pt) {
235 KGSL_CORE_ERR("kzalloc(%d) failed\n",
236 sizeof(struct kgsl_iommu_pt));
237 return NULL;
238 }
Steve Mucklef132c6c2012-06-06 18:30:57 -0700239 iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
240 MSM_IOMMU_DOMAIN_PT_CACHEABLE);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600241 if (!iommu_pt->domain) {
242 KGSL_CORE_ERR("Failed to create iommu domain\n");
243 kfree(iommu_pt);
244 return NULL;
Jordan Crouse95b68472012-05-25 10:25:01 -0600245 } else {
246 iommu_set_fault_handler(iommu_pt->domain,
247 kgsl_iommu_fault_handler);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600248 }
Jordan Crouse95b68472012-05-25 10:25:01 -0600249
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600250 return iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600251}
252
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600253/*
254 * kgsl_detach_pagetable_iommu_domain - Detach the IOMMU unit from a
255 * pagetable
256 * @mmu - Pointer to the device mmu structure
257 * @priv - Flag indicating whether the private or user context is to be
258 * detached
259 *
260 * Detach the IOMMU unit with the domain that is contained in the
261 * hwpagetable of the given mmu. After detaching the IOMMU unit is not
262 * in use because the PTBR will not be set after a detach
263 * Return - void
264 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600265static void kgsl_detach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
266{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600267 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600268 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600269 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600270
271 BUG_ON(mmu->hwpagetable == NULL);
272 BUG_ON(mmu->hwpagetable->priv == NULL);
273
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600274 iommu_pt = mmu->hwpagetable->priv;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600275
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600276 for (i = 0; i < iommu->unit_count; i++) {
277 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
278 for (j = 0; j < iommu_unit->dev_count; j++) {
279 if (iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600280 iommu_detach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600281 iommu_unit->dev[j].dev);
282 iommu_unit->dev[j].attached = false;
283 KGSL_MEM_INFO(mmu->device, "iommu %p detached "
284 "from user dev of MMU: %p\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600285 iommu_pt->domain, mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600286 }
287 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600288 }
289}
290
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600291/*
292 * kgsl_attach_pagetable_iommu_domain - Attach the IOMMU unit to a
293 * pagetable, i.e set the IOMMU's PTBR to the pagetable address and
294 * setup other IOMMU registers for the device so that it becomes
295 * active
296 * @mmu - Pointer to the device mmu structure
297 * @priv - Flag indicating whether the private or user context is to be
298 * attached
299 *
300 * Attach the IOMMU unit with the domain that is contained in the
301 * hwpagetable of the given mmu.
302 * Return - 0 on success else error code
303 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600304static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
305{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600306 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600307 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600308 int i, j, ret = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600309
310 BUG_ON(mmu->hwpagetable == NULL);
311 BUG_ON(mmu->hwpagetable->priv == NULL);
312
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600313 iommu_pt = mmu->hwpagetable->priv;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600314
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600315 /*
316 * Loop through all the iommu devcies under all iommu units and
317 * attach the domain
318 */
319 for (i = 0; i < iommu->unit_count; i++) {
320 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
321 for (j = 0; j < iommu_unit->dev_count; j++) {
322 if (!iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600323 ret = iommu_attach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600324 iommu_unit->dev[j].dev);
325 if (ret) {
326 KGSL_MEM_ERR(mmu->device,
327 "Failed to attach device, err %d\n",
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700328 ret);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600329 goto done;
330 }
331 iommu_unit->dev[j].attached = true;
332 KGSL_MEM_INFO(mmu->device,
333 "iommu pt %p attached to dev %p, ctx_id %d\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600334 iommu_pt->domain, iommu_unit->dev[j].dev,
335 iommu_unit->dev[j].ctx_id);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700336 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600337 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600338 }
339done:
340 return ret;
341}
342
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600343/*
344 * _get_iommu_ctxs - Get device pointer to IOMMU contexts
345 * @mmu - Pointer to mmu device
346 * data - Pointer to the platform data containing information about
347 * iommu devices for one iommu unit
348 * unit_id - The IOMMU unit number. This is not a specific ID but just
349 * a serial number. The serial numbers are treated as ID's of the
350 * IOMMU units
351 *
352 * Return - 0 on success else error code
353 */
354static int _get_iommu_ctxs(struct kgsl_mmu *mmu,
355 struct kgsl_device_iommu_data *data, unsigned int unit_id)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700356{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600357 struct kgsl_iommu *iommu = mmu->priv;
358 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id];
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700359 int i;
360
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600361 if (data->iommu_ctx_count > KGSL_IOMMU_MAX_DEVS_PER_UNIT) {
362 KGSL_CORE_ERR("Too many iommu devices defined for an "
363 "IOMMU unit\n");
364 return -EINVAL;
365 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700366
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600367 for (i = 0; i < data->iommu_ctx_count; i++) {
368 if (!data->iommu_ctxs[i].iommu_ctx_name)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700369 continue;
370
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600371 iommu_unit->dev[iommu_unit->dev_count].dev =
372 msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
373 if (iommu_unit->dev[iommu_unit->dev_count].dev == NULL) {
374 KGSL_CORE_ERR("Failed to get iommu dev handle for "
375 "device %s\n", data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700376 return -EINVAL;
377 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600378 if (KGSL_IOMMU_CONTEXT_USER != data->iommu_ctxs[i].ctx_id &&
379 KGSL_IOMMU_CONTEXT_PRIV != data->iommu_ctxs[i].ctx_id) {
380 KGSL_CORE_ERR("Invalid context ID defined: %d\n",
381 data->iommu_ctxs[i].ctx_id);
382 return -EINVAL;
383 }
384 iommu_unit->dev[iommu_unit->dev_count].ctx_id =
385 data->iommu_ctxs[i].ctx_id;
Jordan Crouse95b68472012-05-25 10:25:01 -0600386 iommu_unit->dev[iommu_unit->dev_count].kgsldev = mmu->device;
387
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600388 KGSL_DRV_INFO(mmu->device,
389 "Obtained dev handle %p for iommu context %s\n",
390 iommu_unit->dev[iommu_unit->dev_count].dev,
391 data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700392
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600393 iommu_unit->dev_count++;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700394 }
395
396 return 0;
397}
398
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600399/*
400 * kgsl_get_iommu_ctxt - Get device pointer to IOMMU contexts
401 * @mmu - Pointer to mmu device
402 *
403 * Get the device pointers for the IOMMU user and priv contexts of the
404 * kgsl device
405 * Return - 0 on success else error code
406 */
407static int kgsl_get_iommu_ctxt(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600408{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600409 struct platform_device *pdev =
410 container_of(mmu->device->parentdev, struct platform_device,
411 dev);
412 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
413 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700414 int i, ret = 0;
415
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600416 /* Go through the IOMMU data and get all the context devices */
417 if (KGSL_IOMMU_MAX_UNITS < pdata_dev->iommu_count) {
418 KGSL_CORE_ERR("Too many IOMMU units defined\n");
419 ret = -EINVAL;
420 goto done;
421 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700422
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600423 for (i = 0; i < pdata_dev->iommu_count; i++) {
424 ret = _get_iommu_ctxs(mmu, &pdata_dev->iommu_data[i], i);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700425 if (ret)
426 break;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600427 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600428 iommu->unit_count = pdata_dev->iommu_count;
429done:
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700430 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600431}
432
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600433/*
434 * kgsl_set_register_map - Map the IOMMU regsiters in the memory descriptors
435 * of the respective iommu units
436 * @mmu - Pointer to mmu structure
437 *
438 * Return - 0 on success else error code
439 */
440static int kgsl_set_register_map(struct kgsl_mmu *mmu)
441{
442 struct platform_device *pdev =
443 container_of(mmu->device->parentdev, struct platform_device,
444 dev);
445 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
446 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
447 struct kgsl_iommu_unit *iommu_unit;
448 int i = 0, ret = 0;
449
450 for (; i < pdata_dev->iommu_count; i++) {
451 struct kgsl_device_iommu_data data = pdata_dev->iommu_data[i];
452 iommu_unit = &iommu->iommu_units[i];
453 /* set up the IOMMU register map for the given IOMMU unit */
454 if (!data.physstart || !data.physend) {
455 KGSL_CORE_ERR("The register range for IOMMU unit not"
456 " specified\n");
457 ret = -EINVAL;
458 goto err;
459 }
460 iommu_unit->reg_map.hostptr = ioremap(data.physstart,
461 data.physend - data.physstart + 1);
462 if (!iommu_unit->reg_map.hostptr) {
463 KGSL_CORE_ERR("Failed to map SMMU register address "
464 "space from %x to %x\n", data.physstart,
465 data.physend - data.physstart + 1);
466 ret = -ENOMEM;
467 i--;
468 goto err;
469 }
470 iommu_unit->reg_map.size = data.physend - data.physstart + 1;
471 iommu_unit->reg_map.physaddr = data.physstart;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600472 memdesc_sg_phys(&iommu_unit->reg_map, data.physstart,
473 iommu_unit->reg_map.size);
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600474 }
475 iommu->unit_count = pdata_dev->iommu_count;
476 return ret;
477err:
478 /* Unmap any mapped IOMMU regions */
479 for (; i >= 0; i--) {
480 iommu_unit = &iommu->iommu_units[i];
481 iounmap(iommu_unit->reg_map.hostptr);
482 iommu_unit->reg_map.size = 0;
483 iommu_unit->reg_map.physaddr = 0;
484 }
485 return ret;
486}
487
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600488/*
489 * kgsl_iommu_pt_get_base_addr - Get the address of the pagetable that the
490 * IOMMU ttbr0 register is programmed with
491 * @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
492 *
493 * Return - actual pagetable address that the ttbr0 register is programmed
494 * with
495 */
496static unsigned int kgsl_iommu_pt_get_base_addr(struct kgsl_pagetable *pt)
497{
498 struct kgsl_iommu_pt *iommu_pt = pt->priv;
499 return iommu_get_pt_base_addr(iommu_pt->domain);
500}
501
502/*
503 * kgsl_iommu_get_pt_lsb - Return the lsb of the ttbr0 IOMMU register
504 * @mmu - Pointer to mmu structure
505 * @hostptr - Pointer to the IOMMU register map. This is used to match
506 * the iommu device whose lsb value is to be returned
507 * @ctx_id - The context bank whose lsb valus is to be returned
508 * Return - returns the lsb which is the last 14 bits of the ttbr0 IOMMU
509 * register. ttbr0 is the actual PTBR for of the IOMMU. The last 14 bits
510 * are only programmed once in the beginning when a domain is attached
511 * does not change.
512 */
513static int kgsl_iommu_get_pt_lsb(struct kgsl_mmu *mmu,
514 unsigned int unit_id,
515 enum kgsl_iommu_context_id ctx_id)
516{
517 struct kgsl_iommu *iommu = mmu->priv;
518 int i, j;
519 for (i = 0; i < iommu->unit_count; i++) {
520 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
521 for (j = 0; j < iommu_unit->dev_count; j++)
522 if (unit_id == i &&
523 ctx_id == iommu_unit->dev[j].ctx_id)
524 return iommu_unit->dev[j].pt_lsb;
525 }
526 return 0;
527}
528
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600529static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600530 struct kgsl_pagetable *pagetable)
531{
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600532 if (mmu->flags & KGSL_FLAGS_STARTED) {
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600533 struct kgsl_iommu *iommu = mmu->priv;
534 struct kgsl_iommu_pt *iommu_pt = pagetable->priv;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600535 /* page table not current, then setup mmu to use new
536 * specified page table
537 */
538 if (mmu->hwpagetable != pagetable) {
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600539 unsigned int flags = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600540 mmu->hwpagetable = pagetable;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600541 /* force tlb flush if asid is reused */
542 if (iommu->asid_reuse &&
543 (KGSL_IOMMU_ASID_REUSE == iommu_pt->asid))
544 flags |= KGSL_MMUFLAGS_TLBFLUSH;
545 flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
546 mmu->device->id);
547 kgsl_setstate(mmu, KGSL_MMUFLAGS_PTUPDATE | flags);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600548 }
549 }
550}
551
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600552static int kgsl_iommu_init(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600553{
554 /*
555 * intialize device mmu
556 *
557 * call this with the global lock held
558 */
559 int status = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600560 struct kgsl_iommu *iommu;
561
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600562 iommu = kzalloc(sizeof(struct kgsl_iommu), GFP_KERNEL);
563 if (!iommu) {
564 KGSL_CORE_ERR("kzalloc(%d) failed\n",
565 sizeof(struct kgsl_iommu));
566 return -ENOMEM;
567 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600568 iommu->asids = kzalloc(BITS_TO_LONGS(KGSL_IOMMU_MAX_ASIDS) *
569 sizeof(unsigned long), GFP_KERNEL);
570 if (!iommu->asids) {
571 KGSL_CORE_ERR("kzalloc(%d) failed\n",
572 sizeof(struct kgsl_iommu));
573 status = -ENOMEM;
574 goto done;
575 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600576
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600577 mmu->priv = iommu;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600578 status = kgsl_get_iommu_ctxt(mmu);
579 if (status)
580 goto done;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600581 status = kgsl_set_register_map(mmu);
582 if (status)
583 goto done;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600584
Shubhraprakash Dase9541a32012-05-09 22:25:55 -0600585 /* A nop is required in an indirect buffer when switching
586 * pagetables in-stream */
587 kgsl_sharedmem_writel(&mmu->setstate_memory,
588 KGSL_IOMMU_SETSTATE_NOP_OFFSET,
589 cp_nop_packet(1));
590
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600591 dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600592 __func__);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600593done:
594 if (status) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600595 kfree(iommu->asids);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600596 kfree(iommu);
597 mmu->priv = NULL;
598 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600599 return status;
600}
601
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600602/*
603 * kgsl_iommu_setup_defaultpagetable - Setup the initial defualtpagetable
604 * for iommu. This function is only called once during first start, successive
605 * start do not call this funciton.
606 * @mmu - Pointer to mmu structure
607 *
608 * Create the initial defaultpagetable and setup the iommu mappings to it
609 * Return - 0 on success else error code
610 */
611static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu)
612{
613 int status = 0;
614 int i = 0;
615 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600616 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600617
618 mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
619 /* Return error if the default pagetable doesn't exist */
620 if (mmu->defaultpagetable == NULL) {
621 status = -ENOMEM;
622 goto err;
623 }
624 /* Map the IOMMU regsiters to only defaultpagetable */
625 for (i = 0; i < iommu->unit_count; i++) {
626 iommu->iommu_units[i].reg_map.priv |= KGSL_MEMFLAGS_GLOBAL;
627 status = kgsl_mmu_map(mmu->defaultpagetable,
628 &(iommu->iommu_units[i].reg_map),
629 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
630 if (status) {
631 iommu->iommu_units[i].reg_map.priv &=
632 ~KGSL_MEMFLAGS_GLOBAL;
633 goto err;
634 }
635 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600636 /*
637 * The dafault pagetable always has asid 0 assigned by the iommu driver
638 * and asid 1 is assigned to the private context.
639 */
640 iommu_pt = mmu->defaultpagetable->priv;
641 iommu_pt->asid = 0;
642 set_bit(0, iommu->asids);
643 set_bit(1, iommu->asids);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600644 return status;
645err:
646 for (i--; i >= 0; i--) {
647 kgsl_mmu_unmap(mmu->defaultpagetable,
648 &(iommu->iommu_units[i].reg_map));
649 iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMFLAGS_GLOBAL;
650 }
651 if (mmu->defaultpagetable) {
652 kgsl_mmu_putpagetable(mmu->defaultpagetable);
653 mmu->defaultpagetable = NULL;
654 }
655 return status;
656}
657
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600658static int kgsl_iommu_start(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600659{
660 int status;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600661 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600662 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600663
664 if (mmu->flags & KGSL_FLAGS_STARTED)
665 return 0;
666
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600667 if (mmu->defaultpagetable == NULL) {
668 status = kgsl_iommu_setup_defaultpagetable(mmu);
669 if (status)
670 return -ENOMEM;
671 }
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600672 /* We use the GPU MMU to control access to IOMMU registers on a225,
673 * hence we still keep the MMU active on a225 */
674 if (adreno_is_a225(ADRENO_DEVICE(mmu->device))) {
675 struct kgsl_mh *mh = &(mmu->device->mh);
676 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001);
677 kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
678 mh->mpu_base +
Shubhraprakash Dasc6e21012012-05-11 17:24:51 -0600679 iommu->iommu_units
680 [iommu->unit_count - 1].reg_map.gpuaddr -
681 PAGE_SIZE);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600682 } else {
683 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
684 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600685
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600686 mmu->hwpagetable = mmu->defaultpagetable;
687
688 status = kgsl_attach_pagetable_iommu_domain(mmu);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600689 if (status) {
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600690 mmu->hwpagetable = NULL;
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600691 goto done;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600692 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600693 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600694 if (status) {
695 KGSL_CORE_ERR("clk enable failed\n");
696 goto done;
697 }
698 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
699 if (status) {
700 KGSL_CORE_ERR("clk enable failed\n");
701 goto done;
702 }
703 /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as
704 * that value should not change when we change pagetables, so while
705 * changing pagetables we can use this lsb value of the pagetable w/o
706 * having to read it again
707 */
708 for (i = 0; i < iommu->unit_count; i++) {
709 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
710 for (j = 0; j < iommu_unit->dev_count; j++)
711 iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(
712 KGSL_IOMMU_GET_IOMMU_REG(
713 iommu_unit->reg_map.hostptr,
714 iommu_unit->dev[j].ctx_id,
715 TTBR0));
716 }
717 iommu->asid = KGSL_IOMMU_GET_IOMMU_REG(
718 iommu->iommu_units[0].reg_map.hostptr,
719 KGSL_IOMMU_CONTEXT_USER,
720 CONTEXTIDR);
721
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600722 kgsl_iommu_disable_clk(mmu);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600723 mmu->flags |= KGSL_FLAGS_STARTED;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600724
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600725done:
726 if (status) {
727 kgsl_iommu_disable_clk(mmu);
728 kgsl_detach_pagetable_iommu_domain(mmu);
729 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600730 return status;
731}
732
733static int
734kgsl_iommu_unmap(void *mmu_specific_pt,
735 struct kgsl_memdesc *memdesc)
736{
737 int ret;
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600738 unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600739 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600740
741 /* All GPU addresses as assigned are page aligned, but some
742 functions purturb the gpuaddr with an offset, so apply the
743 mask here to make sure we have the right address */
744
745 unsigned int gpuaddr = memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK;
746
747 if (range == 0 || gpuaddr == 0)
748 return 0;
749
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600750 ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600751 if (ret)
752 KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600753 "with err: %d\n", iommu_pt->domain, gpuaddr,
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600754 range, ret);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600755
756 return 0;
757}
758
759static int
760kgsl_iommu_map(void *mmu_specific_pt,
761 struct kgsl_memdesc *memdesc,
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600762 unsigned int protflags,
763 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600764{
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600765 int ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600766 unsigned int iommu_virt_addr;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600767 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600768 int size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600769
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600770 BUG_ON(NULL == iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600771
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600772
Jordan Croused17e9aa2011-10-12 16:57:48 -0600773 iommu_virt_addr = memdesc->gpuaddr;
774
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600775 ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600776 size, (IOMMU_READ | IOMMU_WRITE));
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600777 if (ret) {
778 KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600779 "failed with err: %d\n", iommu_pt->domain,
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600780 iommu_virt_addr, memdesc->sg, size,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600781 (IOMMU_READ | IOMMU_WRITE), ret);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600782 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600783 }
784
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600785#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
786 /*
787 * Flushing only required if per process pagetables are used. With
788 * global case, flushing will happen inside iommu_map function
789 */
790 if (!ret)
791 *tlb_flags = UINT_MAX;
792#endif
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600793 return ret;
794}
795
Shubhraprakash Das79447952012-04-26 18:12:23 -0600796static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600797{
798 /*
799 * stop device mmu
800 *
801 * call this with the global lock held
802 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600803
804 if (mmu->flags & KGSL_FLAGS_STARTED) {
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600805 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600806 /* detach iommu attachment */
807 kgsl_detach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600808 mmu->hwpagetable = NULL;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600809
810 mmu->flags &= ~KGSL_FLAGS_STARTED;
811 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600812}
813
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600814static int kgsl_iommu_close(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600815{
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600816 struct kgsl_iommu *iommu = mmu->priv;
817 int i;
818 for (i = 0; i < iommu->unit_count; i++) {
819 if (iommu->iommu_units[i].reg_map.gpuaddr)
820 kgsl_mmu_unmap(mmu->defaultpagetable,
821 &(iommu->iommu_units[i].reg_map));
822 if (iommu->iommu_units[i].reg_map.hostptr)
823 iounmap(iommu->iommu_units[i].reg_map.hostptr);
824 kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
825 iommu->iommu_units[i].reg_map.sglen);
826 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600827 if (mmu->defaultpagetable)
828 kgsl_mmu_putpagetable(mmu->defaultpagetable);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600829 kfree(iommu->asids);
830 kfree(iommu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600831
832 return 0;
833}
834
835static unsigned int
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600836kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600837{
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600838 unsigned int pt_base;
839 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das64a745c2012-06-11 16:44:16 -0600840 /* We cannot enable or disable the clocks in interrupt context, this
841 function is called from interrupt context if there is an axi error */
842 if (in_interrupt())
843 return 0;
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600844 /* Return the current pt base by reading IOMMU pt_base register */
845 kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
846 pt_base = readl_relaxed(iommu->iommu_units[0].reg_map.hostptr +
847 (KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
848 KGSL_IOMMU_TTBR0);
849 kgsl_iommu_disable_clk(mmu);
850 return pt_base & (KGSL_IOMMU_TTBR0_PA_MASK <<
851 KGSL_IOMMU_TTBR0_PA_SHIFT);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600852}
853
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600854/*
855 * kgsl_iommu_get_hwpagetable_asid - Returns asid(application space ID) for a
856 * pagetable
857 * @mmu - Pointer to mmu structure
858 *
859 * Allocates an asid to a IOMMU domain if it does not already have one. asid's
860 * are unique identifiers for pagetable that can be used to selectively flush
861 * tlb entries of the IOMMU unit.
862 * Return - asid to be used with the IOMMU domain
863 */
864static int kgsl_iommu_get_hwpagetable_asid(struct kgsl_mmu *mmu)
865{
866 struct kgsl_iommu *iommu = mmu->priv;
867 struct kgsl_iommu_pt *iommu_pt = mmu->hwpagetable->priv;
868
869 /*
870 * If the iommu pagetable does not have any asid assigned and is not the
871 * default pagetable then assign asid.
872 */
873 if (!iommu_pt->asid && iommu_pt != mmu->defaultpagetable->priv) {
874 iommu_pt->asid = find_first_zero_bit(iommu->asids,
875 KGSL_IOMMU_MAX_ASIDS);
876 /* No free bits means reuse asid */
877 if (iommu_pt->asid >= KGSL_IOMMU_MAX_ASIDS) {
878 iommu_pt->asid = KGSL_IOMMU_ASID_REUSE;
879 iommu->asid_reuse++;
880 }
881 set_bit(iommu_pt->asid, iommu->asids);
882 /*
883 * Store pointer to asids list so that during pagetable destroy
884 * the asid assigned to this pagetable may be cleared
885 */
886 iommu_pt->iommu = iommu;
887 }
888 /* Return the asid + the constant part of asid that never changes */
889 return (iommu_pt->asid & (KGSL_IOMMU_CONTEXTIDR_ASID_MASK <<
890 KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT)) +
891 (iommu->asid & ~(KGSL_IOMMU_CONTEXTIDR_ASID_MASK <<
892 KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT));
893}
894
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600895/*
896 * kgsl_iommu_default_setstate - Change the IOMMU pagetable or flush IOMMU tlb
897 * of the primary context bank
898 * @mmu - Pointer to mmu structure
899 * @flags - Flags indicating whether pagetable has to chnage or tlb is to be
900 * flushed or both
901 *
902 * Based on flags set the new pagetable fo the IOMMU unit or flush it's tlb or
903 * do both by doing direct register writes to the IOMMu registers through the
904 * cpu
905 * Return - void
906 */
907static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
908 uint32_t flags)
909{
910 struct kgsl_iommu *iommu = mmu->priv;
911 int temp;
912 int i;
913 unsigned int pt_base = kgsl_iommu_pt_get_base_addr(
914 mmu->hwpagetable);
915 unsigned int pt_val;
916
917 if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
918 KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
919 return;
920 }
921 /* Mask off the lsb of the pt base address since lsb will not change */
922 pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK << KGSL_IOMMU_TTBR0_PA_SHIFT);
923 if (flags & KGSL_MMUFLAGS_PTUPDATE) {
924 kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
925 for (i = 0; i < iommu->unit_count; i++) {
926 /* get the lsb value which should not change when
927 * changing ttbr0 */
928 pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
929 KGSL_IOMMU_CONTEXT_USER);
930 pt_val += pt_base;
931
932 KGSL_IOMMU_SET_IOMMU_REG(
933 iommu->iommu_units[i].reg_map.hostptr,
934 KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
935
936 mb();
937 temp = KGSL_IOMMU_GET_IOMMU_REG(
938 iommu->iommu_units[i].reg_map.hostptr,
939 KGSL_IOMMU_CONTEXT_USER, TTBR0);
940 /* Set asid */
941 KGSL_IOMMU_SET_IOMMU_REG(
942 iommu->iommu_units[i].reg_map.hostptr,
943 KGSL_IOMMU_CONTEXT_USER, CONTEXTIDR,
944 kgsl_iommu_get_hwpagetable_asid(mmu));
945 mb();
946 temp = KGSL_IOMMU_GET_IOMMU_REG(
947 iommu->iommu_units[i].reg_map.hostptr,
948 KGSL_IOMMU_CONTEXT_USER, CONTEXTIDR);
949 }
950 }
951 /* Flush tlb */
952 if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
953 for (i = 0; i < iommu->unit_count; i++) {
954 KGSL_IOMMU_SET_IOMMU_REG(
955 iommu->iommu_units[i].reg_map.hostptr,
956 KGSL_IOMMU_CONTEXT_USER, CTX_TLBIASID,
957 kgsl_iommu_get_hwpagetable_asid(mmu));
958 mb();
959 }
960 }
961 /* Disable smmu clock */
962 kgsl_iommu_disable_clk(mmu);
963}
964
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -0600965/*
966 * kgsl_iommu_get_reg_map_desc - Returns an array of pointers that contain
967 * the address of memory descriptors which map the IOMMU registers
968 * @mmu - Pointer to mmu structure
969 * @reg_map_desc - Out parameter in which the address of the array containing
970 * pointers to register map descriptors is returned. The caller is supposed
971 * to free this array
972 *
973 * Return - The number of iommu units which is also the number of register
974 * mapped descriptor arrays which the out parameter will have
975 */
976static int kgsl_iommu_get_reg_map_desc(struct kgsl_mmu *mmu,
977 void **reg_map_desc)
978{
979 struct kgsl_iommu *iommu = mmu->priv;
980 void **reg_desc_ptr;
981 int i;
982
983 /*
984 * Alocate array of pointers that will hold address of the register map
985 * descriptors
986 */
987 reg_desc_ptr = kmalloc(iommu->unit_count *
988 sizeof(struct kgsl_memdesc *), GFP_KERNEL);
989 if (!reg_desc_ptr) {
990 KGSL_CORE_ERR("Failed to kmalloc(%d)\n",
991 iommu->unit_count * sizeof(struct kgsl_memdesc *));
992 return -ENOMEM;
993 }
994
995 for (i = 0; i < iommu->unit_count; i++)
996 reg_desc_ptr[i] = &(iommu->iommu_units[i].reg_map);
997
998 *reg_map_desc = reg_desc_ptr;
999 return i;
1000}
1001
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001002struct kgsl_mmu_ops iommu_ops = {
1003 .mmu_init = kgsl_iommu_init,
1004 .mmu_close = kgsl_iommu_close,
1005 .mmu_start = kgsl_iommu_start,
1006 .mmu_stop = kgsl_iommu_stop,
1007 .mmu_setstate = kgsl_iommu_setstate,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001008 .mmu_device_setstate = kgsl_iommu_default_setstate,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001009 .mmu_pagefault = NULL,
1010 .mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -06001011 .mmu_enable_clk = kgsl_iommu_enable_clk,
1012 .mmu_disable_clk = kgsl_iommu_disable_clk,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001013 .mmu_get_hwpagetable_asid = kgsl_iommu_get_hwpagetable_asid,
Shubhraprakash Dasfce27362012-05-09 17:44:14 -06001014 .mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001015 .mmu_get_reg_map_desc = kgsl_iommu_get_reg_map_desc,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001016};
1017
1018struct kgsl_mmu_pt_ops iommu_pt_ops = {
1019 .mmu_map = kgsl_iommu_map,
1020 .mmu_unmap = kgsl_iommu_unmap,
1021 .mmu_create_pagetable = kgsl_iommu_create_pagetable,
1022 .mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
1023 .mmu_pt_equal = kgsl_iommu_pt_equal,
Shubhraprakash Das5a610b52012-05-09 17:31:54 -06001024 .mmu_pt_get_base_addr = kgsl_iommu_pt_get_base_addr,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001025};