blob: 87e8746ed2e54da5af51ab23f773d221464ada16 [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>
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -060020#include <mach/socinfo.h>
Shubhraprakash Das767fdda2011-08-15 15:49:45 -060021
22#include "kgsl.h"
23#include "kgsl_device.h"
24#include "kgsl_mmu.h"
25#include "kgsl_sharedmem.h"
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -060026#include "kgsl_iommu.h"
Shubhraprakash Dase9541a32012-05-09 22:25:55 -060027#include "adreno_pm4types.h"
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -060028#include "adreno.h"
Jordan Crouse95b68472012-05-25 10:25:01 -060029#include "kgsl_trace.h"
30
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070031static struct kgsl_iommu_register_list kgsl_iommuv1_reg[KGSL_IOMMU_REG_MAX] = {
32 { 0, 0, 0 }, /* GLOBAL_BASE */
33 { 0x10, 0x0003FFFF, 14 }, /* TTBR0 */
34 { 0x14, 0x0003FFFF, 14 }, /* TTBR1 */
35 { 0x20, 0, 0 }, /* FSR */
36 { 0x800, 0, 0 }, /* TLBIALL */
37};
38
Shubhraprakash Das15a8b462012-08-16 23:24:28 -070039static struct kgsl_iommu_register_list kgsl_iommuv2_reg[KGSL_IOMMU_REG_MAX] = {
40 { 0, 0, 0 }, /* GLOBAL_BASE */
41 { 0x20, 0x00FFFFFF, 14 }, /* TTBR0 */
42 { 0x28, 0x00FFFFFF, 14 }, /* TTBR1 */
43 { 0x58, 0, 0 }, /* FSR */
44 { 0x618, 0, 0 } /* TLBIALL */
45};
46
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070047static int get_iommu_unit(struct device *dev, struct kgsl_mmu **mmu_out,
48 struct kgsl_iommu_unit **iommu_unit_out)
Jordan Crouse95b68472012-05-25 10:25:01 -060049{
50 int i, j, k;
51
52 for (i = 0; i < KGSL_DEVICE_MAX; i++) {
53 struct kgsl_mmu *mmu;
54 struct kgsl_iommu *iommu;
55
56 if (kgsl_driver.devp[i] == NULL)
57 continue;
58
59 mmu = kgsl_get_mmu(kgsl_driver.devp[i]);
60 if (mmu == NULL || mmu->priv == NULL)
61 continue;
62
63 iommu = mmu->priv;
64
65 for (j = 0; j < iommu->unit_count; j++) {
66 struct kgsl_iommu_unit *iommu_unit =
67 &iommu->iommu_units[j];
68 for (k = 0; k < iommu_unit->dev_count; k++) {
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070069 if (iommu_unit->dev[k].dev == dev) {
70 *mmu_out = mmu;
71 *iommu_unit_out = iommu_unit;
72 return 0;
73 }
Jordan Crouse95b68472012-05-25 10:25:01 -060074 }
75 }
76 }
77
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070078 return -EINVAL;
Jordan Crouse95b68472012-05-25 10:25:01 -060079}
80
81static struct kgsl_iommu_device *get_iommu_device(struct kgsl_iommu_unit *unit,
82 struct device *dev)
83{
84 int k;
85
86 for (k = 0; unit && k < unit->dev_count; k++) {
87 if (unit->dev[k].dev == dev)
88 return &(unit->dev[k]);
89 }
90
91 return NULL;
92}
93
94static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
95 struct device *dev, unsigned long addr, int flags)
96{
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070097 int ret = 0;
98 struct kgsl_mmu *mmu;
99 struct kgsl_iommu *iommu;
100 struct kgsl_iommu_unit *iommu_unit;
101 struct kgsl_iommu_device *iommu_dev;
Jordan Crouse95b68472012-05-25 10:25:01 -0600102 unsigned int ptbase, fsr;
103
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700104 ret = get_iommu_unit(dev, &mmu, &iommu_unit);
105 if (ret)
106 goto done;
107 iommu_dev = get_iommu_device(iommu_unit, dev);
Jordan Crouse95b68472012-05-25 10:25:01 -0600108 if (!iommu_dev) {
109 KGSL_CORE_ERR("Invalid IOMMU device %p\n", dev);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700110 ret = -ENOSYS;
111 goto done;
Jordan Crouse95b68472012-05-25 10:25:01 -0600112 }
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700113 iommu = mmu->priv;
Jordan Crouse95b68472012-05-25 10:25:01 -0600114
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700115 ptbase = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
Shubhraprakash Das190553a2012-06-11 15:17:59 -0600116 iommu_dev->ctx_id, TTBR0);
Jordan Crouse95b68472012-05-25 10:25:01 -0600117
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700118 fsr = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
Jordan Crouse95b68472012-05-25 10:25:01 -0600119 iommu_dev->ctx_id, FSR);
120
121 KGSL_MEM_CRIT(iommu_dev->kgsldev,
122 "GPU PAGE FAULT: addr = %lX pid = %d\n",
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700123 addr, kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase));
Jordan Crouse95b68472012-05-25 10:25:01 -0600124 KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
125 iommu_dev->ctx_id, fsr);
126
127 trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700128 kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase), 0);
Jordan Crouse95b68472012-05-25 10:25:01 -0600129
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700130done:
131 return ret;
Jordan Crouse95b68472012-05-25 10:25:01 -0600132}
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600133
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600134/*
135 * kgsl_iommu_disable_clk - Disable iommu clocks
136 * @mmu - Pointer to mmu structure
137 *
138 * Disables iommu clocks
139 * Return - void
140 */
141static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu)
142{
143 struct kgsl_iommu *iommu = mmu->priv;
144 struct msm_iommu_drvdata *iommu_drvdata;
145 int i, j;
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 continue;
152 iommu_drvdata = dev_get_drvdata(
153 iommu_unit->dev[j].dev->parent);
Shubhraprakash Das102aac52012-08-16 22:12:27 -0700154 if (iommu_drvdata->aclk)
155 clk_disable_unprepare(iommu_drvdata->aclk);
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600156 if (iommu_drvdata->clk)
157 clk_disable_unprepare(iommu_drvdata->clk);
158 clk_disable_unprepare(iommu_drvdata->pclk);
159 iommu_unit->dev[j].clk_enabled = false;
160 }
161 }
162}
163
164/*
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600165 * kgsl_iommu_disable_clk_event - An event function that is executed when
166 * the required timestamp is reached. It disables the IOMMU clocks if
167 * the timestamp on which the clocks can be disabled has expired.
168 * @device - The kgsl device pointer
169 * @data - The data passed during event creation, it is the MMU pointer
170 * @id - Context ID, should always be KGSL_MEMSTORE_GLOBAL
171 * @ts - The current timestamp that has expired for the device
172 *
173 * Disables IOMMU clocks if timestamp has expired
174 * Return - void
175 */
176static void kgsl_iommu_clk_disable_event(struct kgsl_device *device, void *data,
177 unsigned int id, unsigned int ts)
178{
179 struct kgsl_mmu *mmu = data;
180 struct kgsl_iommu *iommu = mmu->priv;
181
182 if (!iommu->clk_event_queued) {
183 if (0 > timestamp_cmp(ts, iommu->iommu_last_cmd_ts))
184 KGSL_DRV_ERR(device,
185 "IOMMU disable clock event being cancelled, "
186 "iommu_last_cmd_ts: %x, retired ts: %x\n",
187 iommu->iommu_last_cmd_ts, ts);
188 return;
189 }
190
191 if (0 <= timestamp_cmp(ts, iommu->iommu_last_cmd_ts)) {
192 kgsl_iommu_disable_clk(mmu);
193 iommu->clk_event_queued = false;
194 } else {
195 /* add new event to fire when ts is reached, this can happen
196 * if we queued an event and someone requested the clocks to
197 * be disbaled on a later timestamp */
198 if (kgsl_add_event(device, id, iommu->iommu_last_cmd_ts,
199 kgsl_iommu_clk_disable_event, mmu, mmu)) {
200 KGSL_DRV_ERR(device,
201 "Failed to add IOMMU disable clk event\n");
202 iommu->clk_event_queued = false;
203 }
204 }
205}
206
207/*
208 * kgsl_iommu_disable_clk_on_ts - Sets up event to disable IOMMU clocks
209 * @mmu - The kgsl MMU pointer
210 * @ts - Timestamp on which the clocks should be disabled
211 * @ts_valid - Indicates whether ts parameter is valid, if this parameter
212 * is false then it means that the calling function wants to disable the
213 * IOMMU clocks immediately without waiting for any timestamp
214 *
215 * Creates an event to disable the IOMMU clocks on timestamp and if event
216 * already exists then updates the timestamp of disabling the IOMMU clocks
217 * with the passed in ts if it is greater than the current value at which
218 * the clocks will be disabled
219 * Return - void
220 */
221static void
222kgsl_iommu_disable_clk_on_ts(struct kgsl_mmu *mmu, unsigned int ts,
223 bool ts_valid)
224{
225 struct kgsl_iommu *iommu = mmu->priv;
226
227 if (iommu->clk_event_queued) {
228 if (ts_valid && (0 <
229 timestamp_cmp(ts, iommu->iommu_last_cmd_ts)))
230 iommu->iommu_last_cmd_ts = ts;
231 } else {
232 if (ts_valid) {
233 iommu->iommu_last_cmd_ts = ts;
234 iommu->clk_event_queued = true;
235 if (kgsl_add_event(mmu->device, KGSL_MEMSTORE_GLOBAL,
236 ts, kgsl_iommu_clk_disable_event, mmu, mmu)) {
237 KGSL_DRV_ERR(mmu->device,
238 "Failed to add IOMMU disable clk event\n");
239 iommu->clk_event_queued = false;
240 }
241 } else {
242 kgsl_iommu_disable_clk(mmu);
243 }
244 }
245}
246
247/*
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600248 * kgsl_iommu_enable_clk - Enable iommu clocks
249 * @mmu - Pointer to mmu structure
250 * @ctx_id - The context bank whose clocks are to be turned on
251 *
252 * Enables iommu clocks of a given context
253 * Return: 0 on success else error code
254 */
255static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu,
256 int ctx_id)
257{
258 int ret = 0;
259 int i, j;
260 struct kgsl_iommu *iommu = mmu->priv;
261 struct msm_iommu_drvdata *iommu_drvdata;
262
263 for (i = 0; i < iommu->unit_count; i++) {
264 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
265 for (j = 0; j < iommu_unit->dev_count; j++) {
266 if (iommu_unit->dev[j].clk_enabled ||
267 ctx_id != iommu_unit->dev[j].ctx_id)
268 continue;
269 iommu_drvdata =
270 dev_get_drvdata(iommu_unit->dev[j].dev->parent);
271 ret = clk_prepare_enable(iommu_drvdata->pclk);
272 if (ret)
273 goto done;
274 if (iommu_drvdata->clk) {
275 ret = clk_prepare_enable(iommu_drvdata->clk);
276 if (ret) {
277 clk_disable_unprepare(
278 iommu_drvdata->pclk);
279 goto done;
280 }
281 }
Shubhraprakash Das102aac52012-08-16 22:12:27 -0700282 if (iommu_drvdata->aclk) {
283 ret = clk_prepare_enable(iommu_drvdata->aclk);
284 if (ret) {
285 if (iommu_drvdata->clk)
286 clk_disable_unprepare(
287 iommu_drvdata->clk);
288 clk_disable_unprepare(
289 iommu_drvdata->pclk);
290 goto done;
291 }
292 }
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600293 iommu_unit->dev[j].clk_enabled = true;
294 }
295 }
296done:
297 if (ret)
298 kgsl_iommu_disable_clk(mmu);
299 return ret;
300}
301
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600302/*
303 * kgsl_iommu_pt_equal - Check if pagetables are equal
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700304 * @mmu - Pointer to mmu structure
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600305 * @pt - Pointer to pagetable
306 * @pt_base - Address of a pagetable that the IOMMU register is
307 * programmed with
308 *
309 * Checks whether the pt_base is equal to the base address of
310 * the pagetable which is contained in the pt structure
311 * Return - Non-zero if the pagetable addresses are equal else 0
312 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700313static int kgsl_iommu_pt_equal(struct kgsl_mmu *mmu,
314 struct kgsl_pagetable *pt,
315 unsigned int pt_base)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600316{
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700317 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600318 struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
319 unsigned int domain_ptbase = iommu_pt ?
320 iommu_get_pt_base_addr(iommu_pt->domain) : 0;
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600321 /* Only compare the valid address bits of the pt_base */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700322 domain_ptbase &=
323 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
324 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
325
326 pt_base &=
327 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
328 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
329
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600330 return domain_ptbase && pt_base &&
331 (domain_ptbase == pt_base);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600332}
333
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600334/*
335 * kgsl_iommu_destroy_pagetable - Free up reaources help by a pagetable
336 * @mmu_specific_pt - Pointer to pagetable which is to be freed
337 *
338 * Return - void
339 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600340static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
341{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600342 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
343 if (iommu_pt->domain)
344 iommu_domain_free(iommu_pt->domain);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600345 kfree(iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600346}
347
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600348/*
349 * kgsl_iommu_create_pagetable - Create a IOMMU pagetable
350 *
351 * Allocate memory to hold a pagetable and allocate the IOMMU
352 * domain which is the actual IOMMU pagetable
353 * Return - void
354 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600355void *kgsl_iommu_create_pagetable(void)
356{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600357 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600358
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600359 iommu_pt = kzalloc(sizeof(struct kgsl_iommu_pt), GFP_KERNEL);
360 if (!iommu_pt) {
361 KGSL_CORE_ERR("kzalloc(%d) failed\n",
362 sizeof(struct kgsl_iommu_pt));
363 return NULL;
364 }
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700365 /* L2 redirect is not stable on IOMMU v2 */
366 if (msm_soc_version_supports_iommu_v1())
367 iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700368 MSM_IOMMU_DOMAIN_PT_CACHEABLE);
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700369 else
370 iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
371 0);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600372 if (!iommu_pt->domain) {
373 KGSL_CORE_ERR("Failed to create iommu domain\n");
374 kfree(iommu_pt);
375 return NULL;
Jordan Crouse95b68472012-05-25 10:25:01 -0600376 } else {
377 iommu_set_fault_handler(iommu_pt->domain,
378 kgsl_iommu_fault_handler);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600379 }
Jordan Crouse95b68472012-05-25 10:25:01 -0600380
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600381 return iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600382}
383
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600384/*
385 * kgsl_detach_pagetable_iommu_domain - Detach the IOMMU unit from a
386 * pagetable
387 * @mmu - Pointer to the device mmu structure
388 * @priv - Flag indicating whether the private or user context is to be
389 * detached
390 *
391 * Detach the IOMMU unit with the domain that is contained in the
392 * hwpagetable of the given mmu. After detaching the IOMMU unit is not
393 * in use because the PTBR will not be set after a detach
394 * Return - void
395 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600396static void kgsl_detach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
397{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600398 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600399 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600400 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600401
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600402 for (i = 0; i < iommu->unit_count; i++) {
403 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600404 iommu_pt = mmu->defaultpagetable->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600405 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600406 /*
407 * If there is a 2nd default pagetable then priv domain
408 * is attached with this pagetable
409 */
410 if (mmu->priv_bank_table &&
411 (KGSL_IOMMU_CONTEXT_PRIV == j))
412 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600413 if (iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600414 iommu_detach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600415 iommu_unit->dev[j].dev);
416 iommu_unit->dev[j].attached = false;
417 KGSL_MEM_INFO(mmu->device, "iommu %p detached "
418 "from user dev of MMU: %p\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600419 iommu_pt->domain, mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600420 }
421 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600422 }
423}
424
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600425/*
426 * kgsl_attach_pagetable_iommu_domain - Attach the IOMMU unit to a
427 * pagetable, i.e set the IOMMU's PTBR to the pagetable address and
428 * setup other IOMMU registers for the device so that it becomes
429 * active
430 * @mmu - Pointer to the device mmu structure
431 * @priv - Flag indicating whether the private or user context is to be
432 * attached
433 *
434 * Attach the IOMMU unit with the domain that is contained in the
435 * hwpagetable of the given mmu.
436 * Return - 0 on success else error code
437 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600438static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
439{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600440 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600441 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600442 int i, j, ret = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600443
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600444 /*
445 * Loop through all the iommu devcies under all iommu units and
446 * attach the domain
447 */
448 for (i = 0; i < iommu->unit_count; i++) {
449 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600450 iommu_pt = mmu->defaultpagetable->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600451 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600452 /*
453 * If there is a 2nd default pagetable then priv domain
454 * is attached to this pagetable
455 */
456 if (mmu->priv_bank_table &&
457 (KGSL_IOMMU_CONTEXT_PRIV == j))
458 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600459 if (!iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600460 ret = iommu_attach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600461 iommu_unit->dev[j].dev);
462 if (ret) {
463 KGSL_MEM_ERR(mmu->device,
464 "Failed to attach device, err %d\n",
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700465 ret);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600466 goto done;
467 }
468 iommu_unit->dev[j].attached = true;
469 KGSL_MEM_INFO(mmu->device,
470 "iommu pt %p attached to dev %p, ctx_id %d\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600471 iommu_pt->domain, iommu_unit->dev[j].dev,
472 iommu_unit->dev[j].ctx_id);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700473 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600474 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600475 }
476done:
477 return ret;
478}
479
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600480/*
481 * _get_iommu_ctxs - Get device pointer to IOMMU contexts
482 * @mmu - Pointer to mmu device
483 * data - Pointer to the platform data containing information about
484 * iommu devices for one iommu unit
485 * unit_id - The IOMMU unit number. This is not a specific ID but just
486 * a serial number. The serial numbers are treated as ID's of the
487 * IOMMU units
488 *
489 * Return - 0 on success else error code
490 */
491static int _get_iommu_ctxs(struct kgsl_mmu *mmu,
492 struct kgsl_device_iommu_data *data, unsigned int unit_id)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700493{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600494 struct kgsl_iommu *iommu = mmu->priv;
495 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id];
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700496 int i;
497
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600498 if (data->iommu_ctx_count > KGSL_IOMMU_MAX_DEVS_PER_UNIT) {
499 KGSL_CORE_ERR("Too many iommu devices defined for an "
500 "IOMMU unit\n");
501 return -EINVAL;
502 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700503
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600504 for (i = 0; i < data->iommu_ctx_count; i++) {
505 if (!data->iommu_ctxs[i].iommu_ctx_name)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700506 continue;
507
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600508 iommu_unit->dev[iommu_unit->dev_count].dev =
509 msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
510 if (iommu_unit->dev[iommu_unit->dev_count].dev == NULL) {
511 KGSL_CORE_ERR("Failed to get iommu dev handle for "
512 "device %s\n", data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700513 return -EINVAL;
514 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600515 if (KGSL_IOMMU_CONTEXT_USER != data->iommu_ctxs[i].ctx_id &&
516 KGSL_IOMMU_CONTEXT_PRIV != data->iommu_ctxs[i].ctx_id) {
517 KGSL_CORE_ERR("Invalid context ID defined: %d\n",
518 data->iommu_ctxs[i].ctx_id);
519 return -EINVAL;
520 }
521 iommu_unit->dev[iommu_unit->dev_count].ctx_id =
522 data->iommu_ctxs[i].ctx_id;
Jordan Crouse95b68472012-05-25 10:25:01 -0600523 iommu_unit->dev[iommu_unit->dev_count].kgsldev = mmu->device;
524
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600525 KGSL_DRV_INFO(mmu->device,
526 "Obtained dev handle %p for iommu context %s\n",
527 iommu_unit->dev[iommu_unit->dev_count].dev,
528 data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700529
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600530 iommu_unit->dev_count++;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700531 }
532
533 return 0;
534}
535
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600536/*
537 * kgsl_get_iommu_ctxt - Get device pointer to IOMMU contexts
538 * @mmu - Pointer to mmu device
539 *
540 * Get the device pointers for the IOMMU user and priv contexts of the
541 * kgsl device
542 * Return - 0 on success else error code
543 */
544static int kgsl_get_iommu_ctxt(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600545{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600546 struct platform_device *pdev =
547 container_of(mmu->device->parentdev, struct platform_device,
548 dev);
549 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
550 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700551 int i, ret = 0;
552
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600553 /* Go through the IOMMU data and get all the context devices */
554 if (KGSL_IOMMU_MAX_UNITS < pdata_dev->iommu_count) {
555 KGSL_CORE_ERR("Too many IOMMU units defined\n");
556 ret = -EINVAL;
557 goto done;
558 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700559
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600560 for (i = 0; i < pdata_dev->iommu_count; i++) {
561 ret = _get_iommu_ctxs(mmu, &pdata_dev->iommu_data[i], i);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700562 if (ret)
563 break;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600564 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600565 iommu->unit_count = pdata_dev->iommu_count;
566done:
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700567 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600568}
569
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600570/*
571 * kgsl_set_register_map - Map the IOMMU regsiters in the memory descriptors
572 * of the respective iommu units
573 * @mmu - Pointer to mmu structure
574 *
575 * Return - 0 on success else error code
576 */
577static int kgsl_set_register_map(struct kgsl_mmu *mmu)
578{
579 struct platform_device *pdev =
580 container_of(mmu->device->parentdev, struct platform_device,
581 dev);
582 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
583 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
584 struct kgsl_iommu_unit *iommu_unit;
585 int i = 0, ret = 0;
586
587 for (; i < pdata_dev->iommu_count; i++) {
588 struct kgsl_device_iommu_data data = pdata_dev->iommu_data[i];
589 iommu_unit = &iommu->iommu_units[i];
590 /* set up the IOMMU register map for the given IOMMU unit */
591 if (!data.physstart || !data.physend) {
592 KGSL_CORE_ERR("The register range for IOMMU unit not"
593 " specified\n");
594 ret = -EINVAL;
595 goto err;
596 }
597 iommu_unit->reg_map.hostptr = ioremap(data.physstart,
598 data.physend - data.physstart + 1);
599 if (!iommu_unit->reg_map.hostptr) {
600 KGSL_CORE_ERR("Failed to map SMMU register address "
601 "space from %x to %x\n", data.physstart,
602 data.physend - data.physstart + 1);
603 ret = -ENOMEM;
604 i--;
605 goto err;
606 }
607 iommu_unit->reg_map.size = data.physend - data.physstart + 1;
608 iommu_unit->reg_map.physaddr = data.physstart;
Rajeev Kulkarni55863722012-11-21 23:40:05 -0800609 ret = memdesc_sg_phys(&iommu_unit->reg_map, data.physstart,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600610 iommu_unit->reg_map.size);
Rajeev Kulkarni55863722012-11-21 23:40:05 -0800611 if (ret)
612 goto err;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600613 }
614 iommu->unit_count = pdata_dev->iommu_count;
615 return ret;
616err:
617 /* Unmap any mapped IOMMU regions */
618 for (; i >= 0; i--) {
619 iommu_unit = &iommu->iommu_units[i];
620 iounmap(iommu_unit->reg_map.hostptr);
621 iommu_unit->reg_map.size = 0;
622 iommu_unit->reg_map.physaddr = 0;
623 }
624 return ret;
625}
626
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600627/*
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700628 * kgsl_iommu_get_pt_base_addr - Get the address of the pagetable that the
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600629 * IOMMU ttbr0 register is programmed with
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700630 * @mmu - Pointer to mmu
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600631 * @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
632 *
633 * Return - actual pagetable address that the ttbr0 register is programmed
634 * with
635 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700636static unsigned int kgsl_iommu_get_pt_base_addr(struct kgsl_mmu *mmu,
637 struct kgsl_pagetable *pt)
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600638{
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700639 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600640 struct kgsl_iommu_pt *iommu_pt = pt->priv;
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700641 return iommu_get_pt_base_addr(iommu_pt->domain) &
642 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
643 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600644}
645
646/*
647 * kgsl_iommu_get_pt_lsb - Return the lsb of the ttbr0 IOMMU register
648 * @mmu - Pointer to mmu structure
649 * @hostptr - Pointer to the IOMMU register map. This is used to match
650 * the iommu device whose lsb value is to be returned
651 * @ctx_id - The context bank whose lsb valus is to be returned
652 * Return - returns the lsb which is the last 14 bits of the ttbr0 IOMMU
653 * register. ttbr0 is the actual PTBR for of the IOMMU. The last 14 bits
654 * are only programmed once in the beginning when a domain is attached
655 * does not change.
656 */
657static int kgsl_iommu_get_pt_lsb(struct kgsl_mmu *mmu,
658 unsigned int unit_id,
659 enum kgsl_iommu_context_id ctx_id)
660{
661 struct kgsl_iommu *iommu = mmu->priv;
662 int i, j;
663 for (i = 0; i < iommu->unit_count; i++) {
664 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
665 for (j = 0; j < iommu_unit->dev_count; j++)
666 if (unit_id == i &&
667 ctx_id == iommu_unit->dev[j].ctx_id)
668 return iommu_unit->dev[j].pt_lsb;
669 }
670 return 0;
671}
672
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600673static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600674 struct kgsl_pagetable *pagetable,
675 unsigned int context_id)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600676{
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600677 if (mmu->flags & KGSL_FLAGS_STARTED) {
678 /* page table not current, then setup mmu to use new
679 * specified page table
680 */
681 if (mmu->hwpagetable != pagetable) {
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600682 unsigned int flags = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600683 mmu->hwpagetable = pagetable;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600684 flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
Shubhraprakash Das8649fa52012-07-26 15:49:46 -0700685 mmu->device->id) |
686 KGSL_MMUFLAGS_TLBFLUSH;
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600687 kgsl_setstate(mmu, context_id,
688 KGSL_MMUFLAGS_PTUPDATE | flags);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600689 }
690 }
691}
692
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600693static int kgsl_iommu_init(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600694{
695 /*
696 * intialize device mmu
697 *
698 * call this with the global lock held
699 */
700 int status = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600701 struct kgsl_iommu *iommu;
702
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600703 iommu = kzalloc(sizeof(struct kgsl_iommu), GFP_KERNEL);
704 if (!iommu) {
705 KGSL_CORE_ERR("kzalloc(%d) failed\n",
706 sizeof(struct kgsl_iommu));
707 return -ENOMEM;
708 }
709
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600710 mmu->priv = iommu;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600711 status = kgsl_get_iommu_ctxt(mmu);
712 if (status)
713 goto done;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600714 status = kgsl_set_register_map(mmu);
715 if (status)
716 goto done;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600717
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700718 iommu->iommu_reg_list = kgsl_iommuv1_reg;
719 iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
720
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700721 if (msm_soc_version_supports_iommu_v1()) {
722 iommu->iommu_reg_list = kgsl_iommuv1_reg;
723 iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
724 } else {
725 iommu->iommu_reg_list = kgsl_iommuv2_reg;
726 iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V2;
727 }
728
Shubhraprakash Dase9541a32012-05-09 22:25:55 -0600729 /* A nop is required in an indirect buffer when switching
730 * pagetables in-stream */
731 kgsl_sharedmem_writel(&mmu->setstate_memory,
732 KGSL_IOMMU_SETSTATE_NOP_OFFSET,
733 cp_nop_packet(1));
734
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600735 dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600736 __func__);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600737done:
738 if (status) {
739 kfree(iommu);
740 mmu->priv = NULL;
741 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600742 return status;
743}
744
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600745/*
746 * kgsl_iommu_setup_defaultpagetable - Setup the initial defualtpagetable
747 * for iommu. This function is only called once during first start, successive
748 * start do not call this funciton.
749 * @mmu - Pointer to mmu structure
750 *
751 * Create the initial defaultpagetable and setup the iommu mappings to it
752 * Return - 0 on success else error code
753 */
754static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu)
755{
756 int status = 0;
757 int i = 0;
758 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600759 struct kgsl_pagetable *pagetable = NULL;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600760
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600761 /* If chip is not 8960 then we use the 2nd context bank for pagetable
762 * switching on the 3D side for which a separate table is allocated */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700763 if (!cpu_is_msm8960() && msm_soc_version_supports_iommu_v1()) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600764 mmu->priv_bank_table =
765 kgsl_mmu_getpagetable(KGSL_MMU_PRIV_BANK_TABLE_NAME);
766 if (mmu->priv_bank_table == NULL) {
767 status = -ENOMEM;
768 goto err;
769 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600770 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600771 mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
772 /* Return error if the default pagetable doesn't exist */
773 if (mmu->defaultpagetable == NULL) {
774 status = -ENOMEM;
775 goto err;
776 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600777 pagetable = mmu->priv_bank_table ? mmu->priv_bank_table :
778 mmu->defaultpagetable;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600779 /* Map the IOMMU regsiters to only defaultpagetable */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700780 if (msm_soc_version_supports_iommu_v1()) {
781 for (i = 0; i < iommu->unit_count; i++) {
782 iommu->iommu_units[i].reg_map.priv |=
783 KGSL_MEMFLAGS_GLOBAL;
784 status = kgsl_mmu_map(pagetable,
785 &(iommu->iommu_units[i].reg_map),
786 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
787 if (status) {
788 iommu->iommu_units[i].reg_map.priv &=
789 ~KGSL_MEMFLAGS_GLOBAL;
790 goto err;
791 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600792 }
793 }
794 return status;
795err:
796 for (i--; i >= 0; i--) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600797 kgsl_mmu_unmap(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600798 &(iommu->iommu_units[i].reg_map));
799 iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMFLAGS_GLOBAL;
800 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600801 if (mmu->priv_bank_table) {
802 kgsl_mmu_putpagetable(mmu->priv_bank_table);
803 mmu->priv_bank_table = NULL;
804 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600805 if (mmu->defaultpagetable) {
806 kgsl_mmu_putpagetable(mmu->defaultpagetable);
807 mmu->defaultpagetable = NULL;
808 }
809 return status;
810}
811
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600812static int kgsl_iommu_start(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600813{
814 int status;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600815 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600816 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600817
818 if (mmu->flags & KGSL_FLAGS_STARTED)
819 return 0;
820
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600821 if (mmu->defaultpagetable == NULL) {
822 status = kgsl_iommu_setup_defaultpagetable(mmu);
823 if (status)
824 return -ENOMEM;
825 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600826 /* We use the GPU MMU to control access to IOMMU registers on 8960 with
827 * a225, hence we still keep the MMU active on 8960 */
828 if (cpu_is_msm8960()) {
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600829 struct kgsl_mh *mh = &(mmu->device->mh);
830 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001);
831 kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
832 mh->mpu_base +
Shubhraprakash Das2b54b5f2012-08-08 18:21:36 -0700833 iommu->iommu_units[0].reg_map.gpuaddr);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600834 } else {
835 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
836 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600837
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600838 mmu->hwpagetable = mmu->defaultpagetable;
839
840 status = kgsl_attach_pagetable_iommu_domain(mmu);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600841 if (status) {
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600842 mmu->hwpagetable = NULL;
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600843 goto done;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600844 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600845 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600846 if (status) {
847 KGSL_CORE_ERR("clk enable failed\n");
848 goto done;
849 }
850 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
851 if (status) {
852 KGSL_CORE_ERR("clk enable failed\n");
853 goto done;
854 }
855 /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as
856 * that value should not change when we change pagetables, so while
857 * changing pagetables we can use this lsb value of the pagetable w/o
858 * having to read it again
859 */
860 for (i = 0; i < iommu->unit_count; i++) {
861 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
862 for (j = 0; j < iommu_unit->dev_count; j++)
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700863 iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(iommu,
864 KGSL_IOMMU_GET_CTX_REG(iommu,
865 iommu_unit,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600866 iommu_unit->dev[j].ctx_id,
867 TTBR0));
868 }
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600869
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600870 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600871 mmu->flags |= KGSL_FLAGS_STARTED;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600872
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600873done:
874 if (status) {
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600875 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600876 kgsl_detach_pagetable_iommu_domain(mmu);
877 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600878 return status;
879}
880
881static int
882kgsl_iommu_unmap(void *mmu_specific_pt,
Shubhraprakash Das0c811262012-06-06 23:22:19 -0600883 struct kgsl_memdesc *memdesc,
884 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600885{
886 int ret;
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600887 unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600888 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600889
890 /* All GPU addresses as assigned are page aligned, but some
891 functions purturb the gpuaddr with an offset, so apply the
892 mask here to make sure we have the right address */
893
894 unsigned int gpuaddr = memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK;
895
896 if (range == 0 || gpuaddr == 0)
897 return 0;
898
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600899 ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600900 if (ret)
901 KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600902 "with err: %d\n", iommu_pt->domain, gpuaddr,
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600903 range, ret);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600904
Shubhraprakash Das0c811262012-06-06 23:22:19 -0600905#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
906 /*
907 * Flushing only required if per process pagetables are used. With
908 * global case, flushing will happen inside iommu_map function
909 */
Shubhraprakash Das15a8b462012-08-16 23:24:28 -0700910 if (!ret && msm_soc_version_supports_iommu_v1())
Shubhraprakash Das0c811262012-06-06 23:22:19 -0600911 *tlb_flags = UINT_MAX;
912#endif
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600913 return 0;
914}
915
916static int
917kgsl_iommu_map(void *mmu_specific_pt,
918 struct kgsl_memdesc *memdesc,
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600919 unsigned int protflags,
920 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600921{
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600922 int ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600923 unsigned int iommu_virt_addr;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600924 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600925 int size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600926
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600927 BUG_ON(NULL == iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600928
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600929
Jordan Croused17e9aa2011-10-12 16:57:48 -0600930 iommu_virt_addr = memdesc->gpuaddr;
931
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600932 ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600933 size, (IOMMU_READ | IOMMU_WRITE));
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600934 if (ret) {
935 KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600936 "failed with err: %d\n", iommu_pt->domain,
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600937 iommu_virt_addr, memdesc->sg, size,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600938 (IOMMU_READ | IOMMU_WRITE), ret);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600939 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600940 }
941
942 return ret;
943}
944
Shubhraprakash Das79447952012-04-26 18:12:23 -0600945static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600946{
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600947 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600948 /*
949 * stop device mmu
950 *
951 * call this with the global lock held
952 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600953
954 if (mmu->flags & KGSL_FLAGS_STARTED) {
955 /* detach iommu attachment */
956 kgsl_detach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600957 mmu->hwpagetable = NULL;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600958
959 mmu->flags &= ~KGSL_FLAGS_STARTED;
960 }
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600961
962 /* switch off MMU clocks and cancel any events it has queued */
963 iommu->clk_event_queued = false;
964 kgsl_cancel_events(mmu->device, mmu);
965 kgsl_iommu_disable_clk(mmu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600966}
967
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600968static int kgsl_iommu_close(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600969{
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600970 struct kgsl_iommu *iommu = mmu->priv;
971 int i;
972 for (i = 0; i < iommu->unit_count; i++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600973 struct kgsl_pagetable *pagetable = (mmu->priv_bank_table ?
974 mmu->priv_bank_table : mmu->defaultpagetable);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600975 if (iommu->iommu_units[i].reg_map.gpuaddr)
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600976 kgsl_mmu_unmap(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600977 &(iommu->iommu_units[i].reg_map));
978 if (iommu->iommu_units[i].reg_map.hostptr)
979 iounmap(iommu->iommu_units[i].reg_map.hostptr);
980 kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
981 iommu->iommu_units[i].reg_map.sglen);
982 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600983
984 if (mmu->priv_bank_table)
985 kgsl_mmu_putpagetable(mmu->priv_bank_table);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600986 if (mmu->defaultpagetable)
987 kgsl_mmu_putpagetable(mmu->defaultpagetable);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600988 kfree(iommu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600989
990 return 0;
991}
992
993static unsigned int
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600994kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600995{
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600996 unsigned int pt_base;
997 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das64a745c2012-06-11 16:44:16 -0600998 /* We cannot enable or disable the clocks in interrupt context, this
999 function is called from interrupt context if there is an axi error */
1000 if (in_interrupt())
1001 return 0;
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -06001002 /* Return the current pt base by reading IOMMU pt_base register */
1003 kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001004 pt_base = KGSL_IOMMU_GET_CTX_REG(iommu, (&iommu->iommu_units[0]),
1005 KGSL_IOMMU_CONTEXT_USER,
1006 TTBR0);
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001007 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001008 return pt_base &
1009 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
1010 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001011}
1012
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -06001013/*
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001014 * kgsl_iommu_default_setstate - Change the IOMMU pagetable or flush IOMMU tlb
1015 * of the primary context bank
1016 * @mmu - Pointer to mmu structure
1017 * @flags - Flags indicating whether pagetable has to chnage or tlb is to be
1018 * flushed or both
1019 *
1020 * Based on flags set the new pagetable fo the IOMMU unit or flush it's tlb or
1021 * do both by doing direct register writes to the IOMMu registers through the
1022 * cpu
1023 * Return - void
1024 */
1025static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
1026 uint32_t flags)
1027{
1028 struct kgsl_iommu *iommu = mmu->priv;
1029 int temp;
1030 int i;
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001031 unsigned int pt_base = kgsl_iommu_get_pt_base_addr(mmu,
1032 mmu->hwpagetable);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001033 unsigned int pt_val;
1034
1035 if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
1036 KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
1037 return;
1038 }
1039 /* Mask off the lsb of the pt base address since lsb will not change */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001040 pt_base &= (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
1041 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
1042
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001043 if (flags & KGSL_MMUFLAGS_PTUPDATE) {
Jordan Crousea29a2e02012-08-14 09:09:23 -06001044 kgsl_idle(mmu->device);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001045 for (i = 0; i < iommu->unit_count; i++) {
1046 /* get the lsb value which should not change when
1047 * changing ttbr0 */
1048 pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
1049 KGSL_IOMMU_CONTEXT_USER);
1050 pt_val += pt_base;
1051
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001052 KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001053 KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
1054
1055 mb();
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001056 temp = KGSL_IOMMU_GET_CTX_REG(iommu,
1057 (&iommu->iommu_units[i]),
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001058 KGSL_IOMMU_CONTEXT_USER, TTBR0);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001059 }
1060 }
1061 /* Flush tlb */
1062 if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
1063 for (i = 0; i < iommu->unit_count; i++) {
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001064 KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
1065 KGSL_IOMMU_CONTEXT_USER, TLBIALL, 1);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001066 mb();
1067 }
1068 }
1069 /* Disable smmu clock */
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001070 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001071}
1072
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001073/*
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001074 * kgsl_iommu_get_reg_gpuaddr - Returns the gpu address of IOMMU regsiter
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001075 * @mmu - Pointer to mmu structure
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001076 * @iommu_unit - The iommu unit for which base address is requested
1077 * @ctx_id - The context ID of the IOMMU ctx
1078 * @reg - The register for which address is required
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001079 *
1080 * Return - The number of iommu units which is also the number of register
1081 * mapped descriptor arrays which the out parameter will have
1082 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001083static unsigned int kgsl_iommu_get_reg_gpuaddr(struct kgsl_mmu *mmu,
1084 int iommu_unit, int ctx_id, int reg)
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001085{
1086 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001087
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001088 if (KGSL_IOMMU_GLOBAL_BASE == reg)
1089 return iommu->iommu_units[iommu_unit].reg_map.gpuaddr;
1090 else
1091 return iommu->iommu_units[iommu_unit].reg_map.gpuaddr +
1092 iommu->iommu_reg_list[reg].reg_offset +
1093 (ctx_id << KGSL_IOMMU_CTX_SHIFT) + iommu->ctx_offset;
1094}
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001095
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001096static int kgsl_iommu_get_num_iommu_units(struct kgsl_mmu *mmu)
1097{
1098 struct kgsl_iommu *iommu = mmu->priv;
1099 return iommu->unit_count;
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001100}
1101
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001102struct kgsl_mmu_ops iommu_ops = {
1103 .mmu_init = kgsl_iommu_init,
1104 .mmu_close = kgsl_iommu_close,
1105 .mmu_start = kgsl_iommu_start,
1106 .mmu_stop = kgsl_iommu_stop,
1107 .mmu_setstate = kgsl_iommu_setstate,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001108 .mmu_device_setstate = kgsl_iommu_default_setstate,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001109 .mmu_pagefault = NULL,
1110 .mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -06001111 .mmu_enable_clk = kgsl_iommu_enable_clk,
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001112 .mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
Shubhraprakash Dasfce27362012-05-09 17:44:14 -06001113 .mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001114 .mmu_get_reg_gpuaddr = kgsl_iommu_get_reg_gpuaddr,
1115 .mmu_get_num_iommu_units = kgsl_iommu_get_num_iommu_units,
1116 .mmu_pt_equal = kgsl_iommu_pt_equal,
1117 .mmu_get_pt_base_addr = kgsl_iommu_get_pt_base_addr,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001118};
1119
1120struct kgsl_mmu_pt_ops iommu_pt_ops = {
1121 .mmu_map = kgsl_iommu_map,
1122 .mmu_unmap = kgsl_iommu_unmap,
1123 .mmu_create_pagetable = kgsl_iommu_create_pagetable,
1124 .mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001125};