blob: 4f27e6c8481953a01decb140b935990f1b4b80c4 [file] [log] [blame]
Shubhraprakash Das79447952012-04-26 18:12:23 -06001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#include <linux/types.h>
14#include <linux/device.h>
15#include <linux/spinlock.h>
16#include <linux/genalloc.h>
17#include <linux/slab.h>
18#include <linux/iommu.h>
Shubhraprakash Das767fdda2011-08-15 15:49:45 -060019#include <linux/msm_kgsl.h>
20
21#include "kgsl.h"
22#include "kgsl_device.h"
23#include "kgsl_mmu.h"
24#include "kgsl_sharedmem.h"
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -060025#include "kgsl_iommu.h"
Shubhraprakash Das767fdda2011-08-15 15:49:45 -060026
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -060027/*
28 * kgsl_iommu_disable_clk - Disable iommu clocks
29 * @mmu - Pointer to mmu structure
30 *
31 * Disables iommu clocks
32 * Return - void
33 */
34static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu)
35{
36 struct kgsl_iommu *iommu = mmu->priv;
37 struct msm_iommu_drvdata *iommu_drvdata;
38 int i, j;
39
40 for (i = 0; i < iommu->unit_count; i++) {
41 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
42 for (j = 0; j < iommu_unit->dev_count; j++) {
43 if (!iommu_unit->dev[j].clk_enabled)
44 continue;
45 iommu_drvdata = dev_get_drvdata(
46 iommu_unit->dev[j].dev->parent);
47 if (iommu_drvdata->clk)
48 clk_disable_unprepare(iommu_drvdata->clk);
49 clk_disable_unprepare(iommu_drvdata->pclk);
50 iommu_unit->dev[j].clk_enabled = false;
51 }
52 }
53}
54
55/*
56 * kgsl_iommu_enable_clk - Enable iommu clocks
57 * @mmu - Pointer to mmu structure
58 * @ctx_id - The context bank whose clocks are to be turned on
59 *
60 * Enables iommu clocks of a given context
61 * Return: 0 on success else error code
62 */
63static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu,
64 int ctx_id)
65{
66 int ret = 0;
67 int i, j;
68 struct kgsl_iommu *iommu = mmu->priv;
69 struct msm_iommu_drvdata *iommu_drvdata;
70
71 for (i = 0; i < iommu->unit_count; i++) {
72 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
73 for (j = 0; j < iommu_unit->dev_count; j++) {
74 if (iommu_unit->dev[j].clk_enabled ||
75 ctx_id != iommu_unit->dev[j].ctx_id)
76 continue;
77 iommu_drvdata =
78 dev_get_drvdata(iommu_unit->dev[j].dev->parent);
79 ret = clk_prepare_enable(iommu_drvdata->pclk);
80 if (ret)
81 goto done;
82 if (iommu_drvdata->clk) {
83 ret = clk_prepare_enable(iommu_drvdata->clk);
84 if (ret) {
85 clk_disable_unprepare(
86 iommu_drvdata->pclk);
87 goto done;
88 }
89 }
90 iommu_unit->dev[j].clk_enabled = true;
91 }
92 }
93done:
94 if (ret)
95 kgsl_iommu_disable_clk(mmu);
96 return ret;
97}
98
Shubhraprakash Das767fdda2011-08-15 15:49:45 -060099static int kgsl_iommu_pt_equal(struct kgsl_pagetable *pt,
100 unsigned int pt_base)
101{
Shubhraprakash Das528aa462012-03-01 14:56:28 -0700102 struct iommu_domain *domain = pt ? pt->priv : NULL;
103 return domain && pt_base && ((unsigned int)domain == pt_base);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600104}
105
106static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
107{
108 struct iommu_domain *domain = mmu_specific_pt;
109 if (domain)
110 iommu_domain_free(domain);
111}
112
113void *kgsl_iommu_create_pagetable(void)
114{
115 struct iommu_domain *domain = iommu_domain_alloc(0);
116 if (!domain)
117 KGSL_CORE_ERR("Failed to create iommu domain\n");
118
119 return domain;
120}
121
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600122/*
123 * kgsl_detach_pagetable_iommu_domain - Detach the IOMMU unit from a
124 * pagetable
125 * @mmu - Pointer to the device mmu structure
126 * @priv - Flag indicating whether the private or user context is to be
127 * detached
128 *
129 * Detach the IOMMU unit with the domain that is contained in the
130 * hwpagetable of the given mmu. After detaching the IOMMU unit is not
131 * in use because the PTBR will not be set after a detach
132 * Return - void
133 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600134static void kgsl_detach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
135{
136 struct iommu_domain *domain;
137 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600138 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600139
140 BUG_ON(mmu->hwpagetable == NULL);
141 BUG_ON(mmu->hwpagetable->priv == NULL);
142
143 domain = mmu->hwpagetable->priv;
144
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600145 for (i = 0; i < iommu->unit_count; i++) {
146 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
147 for (j = 0; j < iommu_unit->dev_count; j++) {
148 if (iommu_unit->dev[j].attached) {
149 iommu_detach_device(domain,
150 iommu_unit->dev[j].dev);
151 iommu_unit->dev[j].attached = false;
152 KGSL_MEM_INFO(mmu->device, "iommu %p detached "
153 "from user dev of MMU: %p\n",
154 domain, mmu);
155 }
156 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600157 }
158}
159
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600160/*
161 * kgsl_attach_pagetable_iommu_domain - Attach the IOMMU unit to a
162 * pagetable, i.e set the IOMMU's PTBR to the pagetable address and
163 * setup other IOMMU registers for the device so that it becomes
164 * active
165 * @mmu - Pointer to the device mmu structure
166 * @priv - Flag indicating whether the private or user context is to be
167 * attached
168 *
169 * Attach the IOMMU unit with the domain that is contained in the
170 * hwpagetable of the given mmu.
171 * Return - 0 on success else error code
172 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600173static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
174{
175 struct iommu_domain *domain;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600176 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600177 int i, j, ret = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600178
179 BUG_ON(mmu->hwpagetable == NULL);
180 BUG_ON(mmu->hwpagetable->priv == NULL);
181
182 domain = mmu->hwpagetable->priv;
183
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600184 /*
185 * Loop through all the iommu devcies under all iommu units and
186 * attach the domain
187 */
188 for (i = 0; i < iommu->unit_count; i++) {
189 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
190 for (j = 0; j < iommu_unit->dev_count; j++) {
191 if (!iommu_unit->dev[j].attached) {
192 ret = iommu_attach_device(domain,
193 iommu_unit->dev[j].dev);
194 if (ret) {
195 KGSL_MEM_ERR(mmu->device,
196 "Failed to attach device, err %d\n",
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700197 ret);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600198 goto done;
199 }
200 iommu_unit->dev[j].attached = true;
201 KGSL_MEM_INFO(mmu->device,
202 "iommu pt %p attached to dev %p, ctx_id %d\n",
203 domain, iommu_unit->dev[j].dev,
204 iommu_unit->dev[j].ctx_id);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700205 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600206 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600207 }
208done:
209 return ret;
210}
211
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600212/*
213 * _get_iommu_ctxs - Get device pointer to IOMMU contexts
214 * @mmu - Pointer to mmu device
215 * data - Pointer to the platform data containing information about
216 * iommu devices for one iommu unit
217 * unit_id - The IOMMU unit number. This is not a specific ID but just
218 * a serial number. The serial numbers are treated as ID's of the
219 * IOMMU units
220 *
221 * Return - 0 on success else error code
222 */
223static int _get_iommu_ctxs(struct kgsl_mmu *mmu,
224 struct kgsl_device_iommu_data *data, unsigned int unit_id)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700225{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600226 struct kgsl_iommu *iommu = mmu->priv;
227 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id];
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700228 int i;
229
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600230 if (data->iommu_ctx_count > KGSL_IOMMU_MAX_DEVS_PER_UNIT) {
231 KGSL_CORE_ERR("Too many iommu devices defined for an "
232 "IOMMU unit\n");
233 return -EINVAL;
234 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700235
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600236 for (i = 0; i < data->iommu_ctx_count; i++) {
237 if (!data->iommu_ctxs[i].iommu_ctx_name)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700238 continue;
239
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600240 iommu_unit->dev[iommu_unit->dev_count].dev =
241 msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
242 if (iommu_unit->dev[iommu_unit->dev_count].dev == NULL) {
243 KGSL_CORE_ERR("Failed to get iommu dev handle for "
244 "device %s\n", data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700245 return -EINVAL;
246 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600247 if (KGSL_IOMMU_CONTEXT_USER != data->iommu_ctxs[i].ctx_id &&
248 KGSL_IOMMU_CONTEXT_PRIV != data->iommu_ctxs[i].ctx_id) {
249 KGSL_CORE_ERR("Invalid context ID defined: %d\n",
250 data->iommu_ctxs[i].ctx_id);
251 return -EINVAL;
252 }
253 iommu_unit->dev[iommu_unit->dev_count].ctx_id =
254 data->iommu_ctxs[i].ctx_id;
255 KGSL_DRV_INFO(mmu->device,
256 "Obtained dev handle %p for iommu context %s\n",
257 iommu_unit->dev[iommu_unit->dev_count].dev,
258 data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700259
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600260 iommu_unit->dev_count++;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700261 }
262
263 return 0;
264}
265
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600266/*
267 * kgsl_get_iommu_ctxt - Get device pointer to IOMMU contexts
268 * @mmu - Pointer to mmu device
269 *
270 * Get the device pointers for the IOMMU user and priv contexts of the
271 * kgsl device
272 * Return - 0 on success else error code
273 */
274static int kgsl_get_iommu_ctxt(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600275{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600276 struct platform_device *pdev =
277 container_of(mmu->device->parentdev, struct platform_device,
278 dev);
279 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
280 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700281 int i, ret = 0;
282
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600283 /* Go through the IOMMU data and get all the context devices */
284 if (KGSL_IOMMU_MAX_UNITS < pdata_dev->iommu_count) {
285 KGSL_CORE_ERR("Too many IOMMU units defined\n");
286 ret = -EINVAL;
287 goto done;
288 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700289
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600290 for (i = 0; i < pdata_dev->iommu_count; i++) {
291 ret = _get_iommu_ctxs(mmu, &pdata_dev->iommu_data[i], i);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700292 if (ret)
293 break;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600294 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600295 iommu->unit_count = pdata_dev->iommu_count;
296done:
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700297 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600298}
299
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600300/*
301 * kgsl_set_register_map - Map the IOMMU regsiters in the memory descriptors
302 * of the respective iommu units
303 * @mmu - Pointer to mmu structure
304 *
305 * Return - 0 on success else error code
306 */
307static int kgsl_set_register_map(struct kgsl_mmu *mmu)
308{
309 struct platform_device *pdev =
310 container_of(mmu->device->parentdev, struct platform_device,
311 dev);
312 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
313 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
314 struct kgsl_iommu_unit *iommu_unit;
315 int i = 0, ret = 0;
316
317 for (; i < pdata_dev->iommu_count; i++) {
318 struct kgsl_device_iommu_data data = pdata_dev->iommu_data[i];
319 iommu_unit = &iommu->iommu_units[i];
320 /* set up the IOMMU register map for the given IOMMU unit */
321 if (!data.physstart || !data.physend) {
322 KGSL_CORE_ERR("The register range for IOMMU unit not"
323 " specified\n");
324 ret = -EINVAL;
325 goto err;
326 }
327 iommu_unit->reg_map.hostptr = ioremap(data.physstart,
328 data.physend - data.physstart + 1);
329 if (!iommu_unit->reg_map.hostptr) {
330 KGSL_CORE_ERR("Failed to map SMMU register address "
331 "space from %x to %x\n", data.physstart,
332 data.physend - data.physstart + 1);
333 ret = -ENOMEM;
334 i--;
335 goto err;
336 }
337 iommu_unit->reg_map.size = data.physend - data.physstart + 1;
338 iommu_unit->reg_map.physaddr = data.physstart;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600339 memdesc_sg_phys(&iommu_unit->reg_map, data.physstart,
340 iommu_unit->reg_map.size);
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600341 }
342 iommu->unit_count = pdata_dev->iommu_count;
343 return ret;
344err:
345 /* Unmap any mapped IOMMU regions */
346 for (; i >= 0; i--) {
347 iommu_unit = &iommu->iommu_units[i];
348 iounmap(iommu_unit->reg_map.hostptr);
349 iommu_unit->reg_map.size = 0;
350 iommu_unit->reg_map.physaddr = 0;
351 }
352 return ret;
353}
354
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600355static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600356 struct kgsl_pagetable *pagetable)
357{
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600358 if (mmu->flags & KGSL_FLAGS_STARTED) {
359 /* page table not current, then setup mmu to use new
360 * specified page table
361 */
362 if (mmu->hwpagetable != pagetable) {
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600363 kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600364 kgsl_detach_pagetable_iommu_domain(mmu);
365 mmu->hwpagetable = pagetable;
366 if (mmu->hwpagetable)
367 kgsl_attach_pagetable_iommu_domain(mmu);
368 }
369 }
370}
371
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600372static int kgsl_iommu_init(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600373{
374 /*
375 * intialize device mmu
376 *
377 * call this with the global lock held
378 */
379 int status = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600380 struct kgsl_iommu *iommu;
381
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600382 iommu = kzalloc(sizeof(struct kgsl_iommu), GFP_KERNEL);
383 if (!iommu) {
384 KGSL_CORE_ERR("kzalloc(%d) failed\n",
385 sizeof(struct kgsl_iommu));
386 return -ENOMEM;
387 }
388
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600389 mmu->priv = iommu;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600390 status = kgsl_get_iommu_ctxt(mmu);
391 if (status)
392 goto done;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600393 status = kgsl_set_register_map(mmu);
394 if (status)
395 goto done;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600396
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600397 dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600398 __func__);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600399done:
400 if (status) {
401 kfree(iommu);
402 mmu->priv = NULL;
403 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600404 return status;
405}
406
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600407/*
408 * kgsl_iommu_setup_defaultpagetable - Setup the initial defualtpagetable
409 * for iommu. This function is only called once during first start, successive
410 * start do not call this funciton.
411 * @mmu - Pointer to mmu structure
412 *
413 * Create the initial defaultpagetable and setup the iommu mappings to it
414 * Return - 0 on success else error code
415 */
416static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu)
417{
418 int status = 0;
419 int i = 0;
420 struct kgsl_iommu *iommu = mmu->priv;
421
422 mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
423 /* Return error if the default pagetable doesn't exist */
424 if (mmu->defaultpagetable == NULL) {
425 status = -ENOMEM;
426 goto err;
427 }
428 /* Map the IOMMU regsiters to only defaultpagetable */
429 for (i = 0; i < iommu->unit_count; i++) {
430 iommu->iommu_units[i].reg_map.priv |= KGSL_MEMFLAGS_GLOBAL;
431 status = kgsl_mmu_map(mmu->defaultpagetable,
432 &(iommu->iommu_units[i].reg_map),
433 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
434 if (status) {
435 iommu->iommu_units[i].reg_map.priv &=
436 ~KGSL_MEMFLAGS_GLOBAL;
437 goto err;
438 }
439 }
440 return status;
441err:
442 for (i--; i >= 0; i--) {
443 kgsl_mmu_unmap(mmu->defaultpagetable,
444 &(iommu->iommu_units[i].reg_map));
445 iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMFLAGS_GLOBAL;
446 }
447 if (mmu->defaultpagetable) {
448 kgsl_mmu_putpagetable(mmu->defaultpagetable);
449 mmu->defaultpagetable = NULL;
450 }
451 return status;
452}
453
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600454static int kgsl_iommu_start(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600455{
456 int status;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600457
458 if (mmu->flags & KGSL_FLAGS_STARTED)
459 return 0;
460
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600461 if (mmu->defaultpagetable == NULL) {
462 status = kgsl_iommu_setup_defaultpagetable(mmu);
463 if (status)
464 return -ENOMEM;
465 }
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600466 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600467
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600468 mmu->hwpagetable = mmu->defaultpagetable;
469
470 status = kgsl_attach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600471 if (!status) {
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600472 mmu->flags |= KGSL_FLAGS_STARTED;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600473 } else {
474 kgsl_detach_pagetable_iommu_domain(mmu);
475 mmu->hwpagetable = NULL;
476 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600477
478 return status;
479}
480
481static int
482kgsl_iommu_unmap(void *mmu_specific_pt,
483 struct kgsl_memdesc *memdesc)
484{
485 int ret;
486 unsigned int range = memdesc->size;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600487 struct iommu_domain *domain = (struct iommu_domain *)
488 mmu_specific_pt;
489
490 /* All GPU addresses as assigned are page aligned, but some
491 functions purturb the gpuaddr with an offset, so apply the
492 mask here to make sure we have the right address */
493
494 unsigned int gpuaddr = memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK;
495
496 if (range == 0 || gpuaddr == 0)
497 return 0;
498
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600499 ret = iommu_unmap_range(domain, gpuaddr, range);
500 if (ret)
501 KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
502 "with err: %d\n", domain, gpuaddr,
503 range, ret);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600504
505 return 0;
506}
507
508static int
509kgsl_iommu_map(void *mmu_specific_pt,
510 struct kgsl_memdesc *memdesc,
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600511 unsigned int protflags,
512 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600513{
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600514 int ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600515 unsigned int iommu_virt_addr;
Jordan Croused17e9aa2011-10-12 16:57:48 -0600516 struct iommu_domain *domain = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600517
518 BUG_ON(NULL == domain);
519
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600520
Jordan Croused17e9aa2011-10-12 16:57:48 -0600521 iommu_virt_addr = memdesc->gpuaddr;
522
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600523 ret = iommu_map_range(domain, iommu_virt_addr, memdesc->sg,
Olav Hauganf310cf22012-05-08 08:42:49 -0700524 memdesc->size, (IOMMU_READ | IOMMU_WRITE));
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600525 if (ret) {
526 KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
527 "failed with err: %d\n", domain,
528 iommu_virt_addr, memdesc->sg, memdesc->size,
Stepan Moskovchenko6ee3be82011-11-08 15:24:53 -0800529 0, ret);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600530 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600531 }
532
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600533#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
534 /*
535 * Flushing only required if per process pagetables are used. With
536 * global case, flushing will happen inside iommu_map function
537 */
538 if (!ret)
539 *tlb_flags = UINT_MAX;
540#endif
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600541 return ret;
542}
543
Shubhraprakash Das79447952012-04-26 18:12:23 -0600544static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600545{
546 /*
547 * stop device mmu
548 *
549 * call this with the global lock held
550 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600551
552 if (mmu->flags & KGSL_FLAGS_STARTED) {
553 /* detach iommu attachment */
554 kgsl_detach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600555 mmu->hwpagetable = NULL;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600556
557 mmu->flags &= ~KGSL_FLAGS_STARTED;
558 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600559}
560
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600561static int kgsl_iommu_close(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600562{
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600563 struct kgsl_iommu *iommu = mmu->priv;
564 int i;
565 for (i = 0; i < iommu->unit_count; i++) {
566 if (iommu->iommu_units[i].reg_map.gpuaddr)
567 kgsl_mmu_unmap(mmu->defaultpagetable,
568 &(iommu->iommu_units[i].reg_map));
569 if (iommu->iommu_units[i].reg_map.hostptr)
570 iounmap(iommu->iommu_units[i].reg_map.hostptr);
571 kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
572 iommu->iommu_units[i].reg_map.sglen);
573 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600574 if (mmu->defaultpagetable)
575 kgsl_mmu_putpagetable(mmu->defaultpagetable);
576
577 return 0;
578}
579
580static unsigned int
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600581kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600582{
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600583 unsigned int pt_base;
584 struct kgsl_iommu *iommu = mmu->priv;
585 /* Return the current pt base by reading IOMMU pt_base register */
586 kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
587 pt_base = readl_relaxed(iommu->iommu_units[0].reg_map.hostptr +
588 (KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
589 KGSL_IOMMU_TTBR0);
590 kgsl_iommu_disable_clk(mmu);
591 return pt_base & (KGSL_IOMMU_TTBR0_PA_MASK <<
592 KGSL_IOMMU_TTBR0_PA_SHIFT);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600593}
594
595struct kgsl_mmu_ops iommu_ops = {
596 .mmu_init = kgsl_iommu_init,
597 .mmu_close = kgsl_iommu_close,
598 .mmu_start = kgsl_iommu_start,
599 .mmu_stop = kgsl_iommu_stop,
600 .mmu_setstate = kgsl_iommu_setstate,
601 .mmu_device_setstate = NULL,
602 .mmu_pagefault = NULL,
603 .mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600604 .mmu_enable_clk = kgsl_iommu_enable_clk,
605 .mmu_disable_clk = kgsl_iommu_disable_clk,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600606};
607
608struct kgsl_mmu_pt_ops iommu_pt_ops = {
609 .mmu_map = kgsl_iommu_map,
610 .mmu_unmap = kgsl_iommu_unmap,
611 .mmu_create_pagetable = kgsl_iommu_create_pagetable,
612 .mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
613 .mmu_pt_equal = kgsl_iommu_pt_equal,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600614};