blob: 72546476b104393b4f13870b1688142e0f03ea30 [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
39static int get_iommu_unit(struct device *dev, struct kgsl_mmu **mmu_out,
40 struct kgsl_iommu_unit **iommu_unit_out)
Jordan Crouse95b68472012-05-25 10:25:01 -060041{
42 int i, j, k;
43
44 for (i = 0; i < KGSL_DEVICE_MAX; i++) {
45 struct kgsl_mmu *mmu;
46 struct kgsl_iommu *iommu;
47
48 if (kgsl_driver.devp[i] == NULL)
49 continue;
50
51 mmu = kgsl_get_mmu(kgsl_driver.devp[i]);
52 if (mmu == NULL || mmu->priv == NULL)
53 continue;
54
55 iommu = mmu->priv;
56
57 for (j = 0; j < iommu->unit_count; j++) {
58 struct kgsl_iommu_unit *iommu_unit =
59 &iommu->iommu_units[j];
60 for (k = 0; k < iommu_unit->dev_count; k++) {
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070061 if (iommu_unit->dev[k].dev == dev) {
62 *mmu_out = mmu;
63 *iommu_unit_out = iommu_unit;
64 return 0;
65 }
Jordan Crouse95b68472012-05-25 10:25:01 -060066 }
67 }
68 }
69
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070070 return -EINVAL;
Jordan Crouse95b68472012-05-25 10:25:01 -060071}
72
73static struct kgsl_iommu_device *get_iommu_device(struct kgsl_iommu_unit *unit,
74 struct device *dev)
75{
76 int k;
77
78 for (k = 0; unit && k < unit->dev_count; k++) {
79 if (unit->dev[k].dev == dev)
80 return &(unit->dev[k]);
81 }
82
83 return NULL;
84}
85
86static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
87 struct device *dev, unsigned long addr, int flags)
88{
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070089 int ret = 0;
90 struct kgsl_mmu *mmu;
91 struct kgsl_iommu *iommu;
92 struct kgsl_iommu_unit *iommu_unit;
93 struct kgsl_iommu_device *iommu_dev;
Jordan Crouse95b68472012-05-25 10:25:01 -060094 unsigned int ptbase, fsr;
95
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -070096 ret = get_iommu_unit(dev, &mmu, &iommu_unit);
97 if (ret)
98 goto done;
99 iommu_dev = get_iommu_device(iommu_unit, dev);
Jordan Crouse95b68472012-05-25 10:25:01 -0600100 if (!iommu_dev) {
101 KGSL_CORE_ERR("Invalid IOMMU device %p\n", dev);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700102 ret = -ENOSYS;
103 goto done;
Jordan Crouse95b68472012-05-25 10:25:01 -0600104 }
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700105 iommu = mmu->priv;
Jordan Crouse95b68472012-05-25 10:25:01 -0600106
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700107 ptbase = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
Shubhraprakash Das190553a2012-06-11 15:17:59 -0600108 iommu_dev->ctx_id, TTBR0);
Jordan Crouse95b68472012-05-25 10:25:01 -0600109
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700110 fsr = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
Jordan Crouse95b68472012-05-25 10:25:01 -0600111 iommu_dev->ctx_id, FSR);
112
113 KGSL_MEM_CRIT(iommu_dev->kgsldev,
114 "GPU PAGE FAULT: addr = %lX pid = %d\n",
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700115 addr, kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase));
Jordan Crouse95b68472012-05-25 10:25:01 -0600116 KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
117 iommu_dev->ctx_id, fsr);
118
119 trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700120 kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase), 0);
Jordan Crouse95b68472012-05-25 10:25:01 -0600121
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700122done:
123 return ret;
Jordan Crouse95b68472012-05-25 10:25:01 -0600124}
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600125
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600126/*
127 * kgsl_iommu_disable_clk - Disable iommu clocks
128 * @mmu - Pointer to mmu structure
129 *
130 * Disables iommu clocks
131 * Return - void
132 */
133static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu)
134{
135 struct kgsl_iommu *iommu = mmu->priv;
136 struct msm_iommu_drvdata *iommu_drvdata;
137 int i, j;
138
139 for (i = 0; i < iommu->unit_count; i++) {
140 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
141 for (j = 0; j < iommu_unit->dev_count; j++) {
142 if (!iommu_unit->dev[j].clk_enabled)
143 continue;
144 iommu_drvdata = dev_get_drvdata(
145 iommu_unit->dev[j].dev->parent);
Shubhraprakash Das102aac52012-08-16 22:12:27 -0700146 if (iommu_drvdata->aclk)
147 clk_disable_unprepare(iommu_drvdata->aclk);
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600148 if (iommu_drvdata->clk)
149 clk_disable_unprepare(iommu_drvdata->clk);
150 clk_disable_unprepare(iommu_drvdata->pclk);
151 iommu_unit->dev[j].clk_enabled = false;
152 }
153 }
154}
155
156/*
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600157 * kgsl_iommu_disable_clk_event - An event function that is executed when
158 * the required timestamp is reached. It disables the IOMMU clocks if
159 * the timestamp on which the clocks can be disabled has expired.
160 * @device - The kgsl device pointer
161 * @data - The data passed during event creation, it is the MMU pointer
162 * @id - Context ID, should always be KGSL_MEMSTORE_GLOBAL
163 * @ts - The current timestamp that has expired for the device
164 *
165 * Disables IOMMU clocks if timestamp has expired
166 * Return - void
167 */
168static void kgsl_iommu_clk_disable_event(struct kgsl_device *device, void *data,
169 unsigned int id, unsigned int ts)
170{
171 struct kgsl_mmu *mmu = data;
172 struct kgsl_iommu *iommu = mmu->priv;
173
174 if (!iommu->clk_event_queued) {
175 if (0 > timestamp_cmp(ts, iommu->iommu_last_cmd_ts))
176 KGSL_DRV_ERR(device,
177 "IOMMU disable clock event being cancelled, "
178 "iommu_last_cmd_ts: %x, retired ts: %x\n",
179 iommu->iommu_last_cmd_ts, ts);
180 return;
181 }
182
183 if (0 <= timestamp_cmp(ts, iommu->iommu_last_cmd_ts)) {
184 kgsl_iommu_disable_clk(mmu);
185 iommu->clk_event_queued = false;
186 } else {
187 /* add new event to fire when ts is reached, this can happen
188 * if we queued an event and someone requested the clocks to
189 * be disbaled on a later timestamp */
190 if (kgsl_add_event(device, id, iommu->iommu_last_cmd_ts,
191 kgsl_iommu_clk_disable_event, mmu, mmu)) {
192 KGSL_DRV_ERR(device,
193 "Failed to add IOMMU disable clk event\n");
194 iommu->clk_event_queued = false;
195 }
196 }
197}
198
199/*
200 * kgsl_iommu_disable_clk_on_ts - Sets up event to disable IOMMU clocks
201 * @mmu - The kgsl MMU pointer
202 * @ts - Timestamp on which the clocks should be disabled
203 * @ts_valid - Indicates whether ts parameter is valid, if this parameter
204 * is false then it means that the calling function wants to disable the
205 * IOMMU clocks immediately without waiting for any timestamp
206 *
207 * Creates an event to disable the IOMMU clocks on timestamp and if event
208 * already exists then updates the timestamp of disabling the IOMMU clocks
209 * with the passed in ts if it is greater than the current value at which
210 * the clocks will be disabled
211 * Return - void
212 */
213static void
214kgsl_iommu_disable_clk_on_ts(struct kgsl_mmu *mmu, unsigned int ts,
215 bool ts_valid)
216{
217 struct kgsl_iommu *iommu = mmu->priv;
218
219 if (iommu->clk_event_queued) {
220 if (ts_valid && (0 <
221 timestamp_cmp(ts, iommu->iommu_last_cmd_ts)))
222 iommu->iommu_last_cmd_ts = ts;
223 } else {
224 if (ts_valid) {
225 iommu->iommu_last_cmd_ts = ts;
226 iommu->clk_event_queued = true;
227 if (kgsl_add_event(mmu->device, KGSL_MEMSTORE_GLOBAL,
228 ts, kgsl_iommu_clk_disable_event, mmu, mmu)) {
229 KGSL_DRV_ERR(mmu->device,
230 "Failed to add IOMMU disable clk event\n");
231 iommu->clk_event_queued = false;
232 }
233 } else {
234 kgsl_iommu_disable_clk(mmu);
235 }
236 }
237}
238
239/*
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600240 * kgsl_iommu_enable_clk - Enable iommu clocks
241 * @mmu - Pointer to mmu structure
242 * @ctx_id - The context bank whose clocks are to be turned on
243 *
244 * Enables iommu clocks of a given context
245 * Return: 0 on success else error code
246 */
247static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu,
248 int ctx_id)
249{
250 int ret = 0;
251 int i, j;
252 struct kgsl_iommu *iommu = mmu->priv;
253 struct msm_iommu_drvdata *iommu_drvdata;
254
255 for (i = 0; i < iommu->unit_count; i++) {
256 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
257 for (j = 0; j < iommu_unit->dev_count; j++) {
258 if (iommu_unit->dev[j].clk_enabled ||
259 ctx_id != iommu_unit->dev[j].ctx_id)
260 continue;
261 iommu_drvdata =
262 dev_get_drvdata(iommu_unit->dev[j].dev->parent);
263 ret = clk_prepare_enable(iommu_drvdata->pclk);
264 if (ret)
265 goto done;
266 if (iommu_drvdata->clk) {
267 ret = clk_prepare_enable(iommu_drvdata->clk);
268 if (ret) {
269 clk_disable_unprepare(
270 iommu_drvdata->pclk);
271 goto done;
272 }
273 }
Shubhraprakash Das102aac52012-08-16 22:12:27 -0700274 if (iommu_drvdata->aclk) {
275 ret = clk_prepare_enable(iommu_drvdata->aclk);
276 if (ret) {
277 if (iommu_drvdata->clk)
278 clk_disable_unprepare(
279 iommu_drvdata->clk);
280 clk_disable_unprepare(
281 iommu_drvdata->pclk);
282 goto done;
283 }
284 }
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600285 iommu_unit->dev[j].clk_enabled = true;
286 }
287 }
288done:
289 if (ret)
290 kgsl_iommu_disable_clk(mmu);
291 return ret;
292}
293
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600294/*
295 * kgsl_iommu_pt_equal - Check if pagetables are equal
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700296 * @mmu - Pointer to mmu structure
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600297 * @pt - Pointer to pagetable
298 * @pt_base - Address of a pagetable that the IOMMU register is
299 * programmed with
300 *
301 * Checks whether the pt_base is equal to the base address of
302 * the pagetable which is contained in the pt structure
303 * Return - Non-zero if the pagetable addresses are equal else 0
304 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700305static int kgsl_iommu_pt_equal(struct kgsl_mmu *mmu,
306 struct kgsl_pagetable *pt,
307 unsigned int pt_base)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600308{
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700309 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600310 struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
311 unsigned int domain_ptbase = iommu_pt ?
312 iommu_get_pt_base_addr(iommu_pt->domain) : 0;
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600313 /* Only compare the valid address bits of the pt_base */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700314 domain_ptbase &=
315 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
316 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
317
318 pt_base &=
319 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
320 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
321
Shubhraprakash Das48d97302012-05-07 12:16:08 -0600322 return domain_ptbase && pt_base &&
323 (domain_ptbase == pt_base);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600324}
325
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600326/*
327 * kgsl_iommu_destroy_pagetable - Free up reaources help by a pagetable
328 * @mmu_specific_pt - Pointer to pagetable which is to be freed
329 *
330 * Return - void
331 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600332static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
333{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600334 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
335 if (iommu_pt->domain)
336 iommu_domain_free(iommu_pt->domain);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600337 kfree(iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600338}
339
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600340/*
341 * kgsl_iommu_create_pagetable - Create a IOMMU pagetable
342 *
343 * Allocate memory to hold a pagetable and allocate the IOMMU
344 * domain which is the actual IOMMU pagetable
345 * Return - void
346 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600347void *kgsl_iommu_create_pagetable(void)
348{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600349 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600350
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600351 iommu_pt = kzalloc(sizeof(struct kgsl_iommu_pt), GFP_KERNEL);
352 if (!iommu_pt) {
353 KGSL_CORE_ERR("kzalloc(%d) failed\n",
354 sizeof(struct kgsl_iommu_pt));
355 return NULL;
356 }
Steve Mucklef132c6c2012-06-06 18:30:57 -0700357 iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700358 MSM_IOMMU_DOMAIN_PT_CACHEABLE);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600359 if (!iommu_pt->domain) {
360 KGSL_CORE_ERR("Failed to create iommu domain\n");
361 kfree(iommu_pt);
362 return NULL;
Jordan Crouse95b68472012-05-25 10:25:01 -0600363 } else {
364 iommu_set_fault_handler(iommu_pt->domain,
365 kgsl_iommu_fault_handler);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600366 }
Jordan Crouse95b68472012-05-25 10:25:01 -0600367
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600368 return iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600369}
370
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600371/*
372 * kgsl_detach_pagetable_iommu_domain - Detach the IOMMU unit from a
373 * pagetable
374 * @mmu - Pointer to the device mmu structure
375 * @priv - Flag indicating whether the private or user context is to be
376 * detached
377 *
378 * Detach the IOMMU unit with the domain that is contained in the
379 * hwpagetable of the given mmu. After detaching the IOMMU unit is not
380 * in use because the PTBR will not be set after a detach
381 * Return - void
382 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600383static void kgsl_detach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
384{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600385 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600386 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600387 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600388
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600389 for (i = 0; i < iommu->unit_count; i++) {
390 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600391 iommu_pt = mmu->defaultpagetable->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600392 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600393 /*
394 * If there is a 2nd default pagetable then priv domain
395 * is attached with this pagetable
396 */
397 if (mmu->priv_bank_table &&
398 (KGSL_IOMMU_CONTEXT_PRIV == j))
399 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600400 if (iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600401 iommu_detach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600402 iommu_unit->dev[j].dev);
403 iommu_unit->dev[j].attached = false;
404 KGSL_MEM_INFO(mmu->device, "iommu %p detached "
405 "from user dev of MMU: %p\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600406 iommu_pt->domain, mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600407 }
408 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600409 }
410}
411
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600412/*
413 * kgsl_attach_pagetable_iommu_domain - Attach the IOMMU unit to a
414 * pagetable, i.e set the IOMMU's PTBR to the pagetable address and
415 * setup other IOMMU registers for the device so that it becomes
416 * active
417 * @mmu - Pointer to the device mmu structure
418 * @priv - Flag indicating whether the private or user context is to be
419 * attached
420 *
421 * Attach the IOMMU unit with the domain that is contained in the
422 * hwpagetable of the given mmu.
423 * Return - 0 on success else error code
424 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600425static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
426{
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600427 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600428 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600429 int i, j, ret = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600430
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600431 /*
432 * Loop through all the iommu devcies under all iommu units and
433 * attach the domain
434 */
435 for (i = 0; i < iommu->unit_count; i++) {
436 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600437 iommu_pt = mmu->defaultpagetable->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600438 for (j = 0; j < iommu_unit->dev_count; j++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600439 /*
440 * If there is a 2nd default pagetable then priv domain
441 * is attached to this pagetable
442 */
443 if (mmu->priv_bank_table &&
444 (KGSL_IOMMU_CONTEXT_PRIV == j))
445 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600446 if (!iommu_unit->dev[j].attached) {
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600447 ret = iommu_attach_device(iommu_pt->domain,
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600448 iommu_unit->dev[j].dev);
449 if (ret) {
450 KGSL_MEM_ERR(mmu->device,
451 "Failed to attach device, err %d\n",
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700452 ret);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600453 goto done;
454 }
455 iommu_unit->dev[j].attached = true;
456 KGSL_MEM_INFO(mmu->device,
457 "iommu pt %p attached to dev %p, ctx_id %d\n",
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600458 iommu_pt->domain, iommu_unit->dev[j].dev,
459 iommu_unit->dev[j].ctx_id);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700460 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600461 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600462 }
463done:
464 return ret;
465}
466
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600467/*
468 * _get_iommu_ctxs - Get device pointer to IOMMU contexts
469 * @mmu - Pointer to mmu device
470 * data - Pointer to the platform data containing information about
471 * iommu devices for one iommu unit
472 * unit_id - The IOMMU unit number. This is not a specific ID but just
473 * a serial number. The serial numbers are treated as ID's of the
474 * IOMMU units
475 *
476 * Return - 0 on success else error code
477 */
478static int _get_iommu_ctxs(struct kgsl_mmu *mmu,
479 struct kgsl_device_iommu_data *data, unsigned int unit_id)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700480{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600481 struct kgsl_iommu *iommu = mmu->priv;
482 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id];
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700483 int i;
484
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600485 if (data->iommu_ctx_count > KGSL_IOMMU_MAX_DEVS_PER_UNIT) {
486 KGSL_CORE_ERR("Too many iommu devices defined for an "
487 "IOMMU unit\n");
488 return -EINVAL;
489 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700490
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600491 for (i = 0; i < data->iommu_ctx_count; i++) {
492 if (!data->iommu_ctxs[i].iommu_ctx_name)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700493 continue;
494
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600495 iommu_unit->dev[iommu_unit->dev_count].dev =
496 msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
497 if (iommu_unit->dev[iommu_unit->dev_count].dev == NULL) {
498 KGSL_CORE_ERR("Failed to get iommu dev handle for "
499 "device %s\n", data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700500 return -EINVAL;
501 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600502 if (KGSL_IOMMU_CONTEXT_USER != data->iommu_ctxs[i].ctx_id &&
503 KGSL_IOMMU_CONTEXT_PRIV != data->iommu_ctxs[i].ctx_id) {
504 KGSL_CORE_ERR("Invalid context ID defined: %d\n",
505 data->iommu_ctxs[i].ctx_id);
506 return -EINVAL;
507 }
508 iommu_unit->dev[iommu_unit->dev_count].ctx_id =
509 data->iommu_ctxs[i].ctx_id;
Jordan Crouse95b68472012-05-25 10:25:01 -0600510 iommu_unit->dev[iommu_unit->dev_count].kgsldev = mmu->device;
511
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600512 KGSL_DRV_INFO(mmu->device,
513 "Obtained dev handle %p for iommu context %s\n",
514 iommu_unit->dev[iommu_unit->dev_count].dev,
515 data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700516
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600517 iommu_unit->dev_count++;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700518 }
519
520 return 0;
521}
522
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600523/*
524 * kgsl_get_iommu_ctxt - Get device pointer to IOMMU contexts
525 * @mmu - Pointer to mmu device
526 *
527 * Get the device pointers for the IOMMU user and priv contexts of the
528 * kgsl device
529 * Return - 0 on success else error code
530 */
531static int kgsl_get_iommu_ctxt(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600532{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600533 struct platform_device *pdev =
534 container_of(mmu->device->parentdev, struct platform_device,
535 dev);
536 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
537 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700538 int i, ret = 0;
539
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600540 /* Go through the IOMMU data and get all the context devices */
541 if (KGSL_IOMMU_MAX_UNITS < pdata_dev->iommu_count) {
542 KGSL_CORE_ERR("Too many IOMMU units defined\n");
543 ret = -EINVAL;
544 goto done;
545 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700546
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600547 for (i = 0; i < pdata_dev->iommu_count; i++) {
548 ret = _get_iommu_ctxs(mmu, &pdata_dev->iommu_data[i], i);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700549 if (ret)
550 break;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600551 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600552 iommu->unit_count = pdata_dev->iommu_count;
553done:
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700554 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600555}
556
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600557/*
558 * kgsl_set_register_map - Map the IOMMU regsiters in the memory descriptors
559 * of the respective iommu units
560 * @mmu - Pointer to mmu structure
561 *
562 * Return - 0 on success else error code
563 */
564static int kgsl_set_register_map(struct kgsl_mmu *mmu)
565{
566 struct platform_device *pdev =
567 container_of(mmu->device->parentdev, struct platform_device,
568 dev);
569 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
570 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
571 struct kgsl_iommu_unit *iommu_unit;
572 int i = 0, ret = 0;
573
574 for (; i < pdata_dev->iommu_count; i++) {
575 struct kgsl_device_iommu_data data = pdata_dev->iommu_data[i];
576 iommu_unit = &iommu->iommu_units[i];
577 /* set up the IOMMU register map for the given IOMMU unit */
578 if (!data.physstart || !data.physend) {
579 KGSL_CORE_ERR("The register range for IOMMU unit not"
580 " specified\n");
581 ret = -EINVAL;
582 goto err;
583 }
584 iommu_unit->reg_map.hostptr = ioremap(data.physstart,
585 data.physend - data.physstart + 1);
586 if (!iommu_unit->reg_map.hostptr) {
587 KGSL_CORE_ERR("Failed to map SMMU register address "
588 "space from %x to %x\n", data.physstart,
589 data.physend - data.physstart + 1);
590 ret = -ENOMEM;
591 i--;
592 goto err;
593 }
594 iommu_unit->reg_map.size = data.physend - data.physstart + 1;
595 iommu_unit->reg_map.physaddr = data.physstart;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600596 memdesc_sg_phys(&iommu_unit->reg_map, data.physstart,
597 iommu_unit->reg_map.size);
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600598 }
599 iommu->unit_count = pdata_dev->iommu_count;
600 return ret;
601err:
602 /* Unmap any mapped IOMMU regions */
603 for (; i >= 0; i--) {
604 iommu_unit = &iommu->iommu_units[i];
605 iounmap(iommu_unit->reg_map.hostptr);
606 iommu_unit->reg_map.size = 0;
607 iommu_unit->reg_map.physaddr = 0;
608 }
609 return ret;
610}
611
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600612/*
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700613 * kgsl_iommu_get_pt_base_addr - Get the address of the pagetable that the
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600614 * IOMMU ttbr0 register is programmed with
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700615 * @mmu - Pointer to mmu
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600616 * @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
617 *
618 * Return - actual pagetable address that the ttbr0 register is programmed
619 * with
620 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700621static unsigned int kgsl_iommu_get_pt_base_addr(struct kgsl_mmu *mmu,
622 struct kgsl_pagetable *pt)
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600623{
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700624 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600625 struct kgsl_iommu_pt *iommu_pt = pt->priv;
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700626 return iommu_get_pt_base_addr(iommu_pt->domain) &
627 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
628 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600629}
630
631/*
632 * kgsl_iommu_get_pt_lsb - Return the lsb of the ttbr0 IOMMU register
633 * @mmu - Pointer to mmu structure
634 * @hostptr - Pointer to the IOMMU register map. This is used to match
635 * the iommu device whose lsb value is to be returned
636 * @ctx_id - The context bank whose lsb valus is to be returned
637 * Return - returns the lsb which is the last 14 bits of the ttbr0 IOMMU
638 * register. ttbr0 is the actual PTBR for of the IOMMU. The last 14 bits
639 * are only programmed once in the beginning when a domain is attached
640 * does not change.
641 */
642static int kgsl_iommu_get_pt_lsb(struct kgsl_mmu *mmu,
643 unsigned int unit_id,
644 enum kgsl_iommu_context_id ctx_id)
645{
646 struct kgsl_iommu *iommu = mmu->priv;
647 int i, j;
648 for (i = 0; i < iommu->unit_count; i++) {
649 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
650 for (j = 0; j < iommu_unit->dev_count; j++)
651 if (unit_id == i &&
652 ctx_id == iommu_unit->dev[j].ctx_id)
653 return iommu_unit->dev[j].pt_lsb;
654 }
655 return 0;
656}
657
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600658static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600659 struct kgsl_pagetable *pagetable,
660 unsigned int context_id)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600661{
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600662 if (mmu->flags & KGSL_FLAGS_STARTED) {
663 /* page table not current, then setup mmu to use new
664 * specified page table
665 */
666 if (mmu->hwpagetable != pagetable) {
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600667 unsigned int flags = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600668 mmu->hwpagetable = pagetable;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600669 flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
Shubhraprakash Das8649fa52012-07-26 15:49:46 -0700670 mmu->device->id) |
671 KGSL_MMUFLAGS_TLBFLUSH;
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600672 kgsl_setstate(mmu, context_id,
673 KGSL_MMUFLAGS_PTUPDATE | flags);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600674 }
675 }
676}
677
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600678static int kgsl_iommu_init(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600679{
680 /*
681 * intialize device mmu
682 *
683 * call this with the global lock held
684 */
685 int status = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600686 struct kgsl_iommu *iommu;
687
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600688 iommu = kzalloc(sizeof(struct kgsl_iommu), GFP_KERNEL);
689 if (!iommu) {
690 KGSL_CORE_ERR("kzalloc(%d) failed\n",
691 sizeof(struct kgsl_iommu));
692 return -ENOMEM;
693 }
694
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600695 mmu->priv = iommu;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600696 status = kgsl_get_iommu_ctxt(mmu);
697 if (status)
698 goto done;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600699 status = kgsl_set_register_map(mmu);
700 if (status)
701 goto done;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600702
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700703 iommu->iommu_reg_list = kgsl_iommuv1_reg;
704 iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
705
Shubhraprakash Dase9541a32012-05-09 22:25:55 -0600706 /* A nop is required in an indirect buffer when switching
707 * pagetables in-stream */
708 kgsl_sharedmem_writel(&mmu->setstate_memory,
709 KGSL_IOMMU_SETSTATE_NOP_OFFSET,
710 cp_nop_packet(1));
711
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600712 dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600713 __func__);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600714done:
715 if (status) {
716 kfree(iommu);
717 mmu->priv = NULL;
718 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600719 return status;
720}
721
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600722/*
723 * kgsl_iommu_setup_defaultpagetable - Setup the initial defualtpagetable
724 * for iommu. This function is only called once during first start, successive
725 * start do not call this funciton.
726 * @mmu - Pointer to mmu structure
727 *
728 * Create the initial defaultpagetable and setup the iommu mappings to it
729 * Return - 0 on success else error code
730 */
731static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu)
732{
733 int status = 0;
734 int i = 0;
735 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600736 struct kgsl_iommu_pt *iommu_pt;
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600737 struct kgsl_pagetable *pagetable = NULL;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600738
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600739 /* If chip is not 8960 then we use the 2nd context bank for pagetable
740 * switching on the 3D side for which a separate table is allocated */
741 if (!cpu_is_msm8960()) {
742 mmu->priv_bank_table =
743 kgsl_mmu_getpagetable(KGSL_MMU_PRIV_BANK_TABLE_NAME);
744 if (mmu->priv_bank_table == NULL) {
745 status = -ENOMEM;
746 goto err;
747 }
748 iommu_pt = mmu->priv_bank_table->priv;
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600749 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600750 mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
751 /* Return error if the default pagetable doesn't exist */
752 if (mmu->defaultpagetable == NULL) {
753 status = -ENOMEM;
754 goto err;
755 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600756 pagetable = mmu->priv_bank_table ? mmu->priv_bank_table :
757 mmu->defaultpagetable;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600758 /* Map the IOMMU regsiters to only defaultpagetable */
759 for (i = 0; i < iommu->unit_count; i++) {
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700760 iommu->iommu_units[i].reg_map.priv |=
761 KGSL_MEMFLAGS_GLOBAL;
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600762 status = kgsl_mmu_map(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600763 &(iommu->iommu_units[i].reg_map),
764 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
765 if (status) {
766 iommu->iommu_units[i].reg_map.priv &=
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700767 ~KGSL_MEMFLAGS_GLOBAL;
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600768 goto err;
769 }
770 }
771 return status;
772err:
773 for (i--; i >= 0; i--) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600774 kgsl_mmu_unmap(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600775 &(iommu->iommu_units[i].reg_map));
776 iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMFLAGS_GLOBAL;
777 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600778 if (mmu->priv_bank_table) {
779 kgsl_mmu_putpagetable(mmu->priv_bank_table);
780 mmu->priv_bank_table = NULL;
781 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600782 if (mmu->defaultpagetable) {
783 kgsl_mmu_putpagetable(mmu->defaultpagetable);
784 mmu->defaultpagetable = NULL;
785 }
786 return status;
787}
788
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600789static int kgsl_iommu_start(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600790{
791 int status;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600792 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600793 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600794
795 if (mmu->flags & KGSL_FLAGS_STARTED)
796 return 0;
797
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600798 if (mmu->defaultpagetable == NULL) {
799 status = kgsl_iommu_setup_defaultpagetable(mmu);
800 if (status)
801 return -ENOMEM;
802 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600803 /* We use the GPU MMU to control access to IOMMU registers on 8960 with
804 * a225, hence we still keep the MMU active on 8960 */
805 if (cpu_is_msm8960()) {
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600806 struct kgsl_mh *mh = &(mmu->device->mh);
807 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001);
808 kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
809 mh->mpu_base +
Shubhraprakash Das2b54b5f2012-08-08 18:21:36 -0700810 iommu->iommu_units[0].reg_map.gpuaddr);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600811 } else {
812 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
813 }
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600814
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600815 mmu->hwpagetable = mmu->defaultpagetable;
816
817 status = kgsl_attach_pagetable_iommu_domain(mmu);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600818 if (status) {
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600819 mmu->hwpagetable = NULL;
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600820 goto done;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600821 }
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600822 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600823 if (status) {
824 KGSL_CORE_ERR("clk enable failed\n");
825 goto done;
826 }
827 status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
828 if (status) {
829 KGSL_CORE_ERR("clk enable failed\n");
830 goto done;
831 }
832 /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as
833 * that value should not change when we change pagetables, so while
834 * changing pagetables we can use this lsb value of the pagetable w/o
835 * having to read it again
836 */
837 for (i = 0; i < iommu->unit_count; i++) {
838 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
839 for (j = 0; j < iommu_unit->dev_count; j++)
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700840 iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(iommu,
841 KGSL_IOMMU_GET_CTX_REG(iommu,
842 iommu_unit,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600843 iommu_unit->dev[j].ctx_id,
844 TTBR0));
845 }
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600846
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600847 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasbb5ad2a2012-05-09 22:58:52 -0600848 mmu->flags |= KGSL_FLAGS_STARTED;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600849
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600850done:
851 if (status) {
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600852 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600853 kgsl_detach_pagetable_iommu_domain(mmu);
854 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600855 return status;
856}
857
858static int
859kgsl_iommu_unmap(void *mmu_specific_pt,
Shubhraprakash Das0c811262012-06-06 23:22:19 -0600860 struct kgsl_memdesc *memdesc,
861 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600862{
863 int ret;
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600864 unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600865 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600866
867 /* All GPU addresses as assigned are page aligned, but some
868 functions purturb the gpuaddr with an offset, so apply the
869 mask here to make sure we have the right address */
870
871 unsigned int gpuaddr = memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK;
872
873 if (range == 0 || gpuaddr == 0)
874 return 0;
875
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600876 ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600877 if (ret)
878 KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600879 "with err: %d\n", iommu_pt->domain, gpuaddr,
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600880 range, ret);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600881
Shubhraprakash Das0c811262012-06-06 23:22:19 -0600882#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
883 /*
884 * Flushing only required if per process pagetables are used. With
885 * global case, flushing will happen inside iommu_map function
886 */
887 if (!ret)
888 *tlb_flags = UINT_MAX;
889#endif
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600890 return 0;
891}
892
893static int
894kgsl_iommu_map(void *mmu_specific_pt,
895 struct kgsl_memdesc *memdesc,
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600896 unsigned int protflags,
897 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600898{
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600899 int ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600900 unsigned int iommu_virt_addr;
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600901 struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600902 int size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600903
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600904 BUG_ON(NULL == iommu_pt);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600905
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600906
Jordan Croused17e9aa2011-10-12 16:57:48 -0600907 iommu_virt_addr = memdesc->gpuaddr;
908
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600909 ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600910 size, (IOMMU_READ | IOMMU_WRITE));
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600911 if (ret) {
912 KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600913 "failed with err: %d\n", iommu_pt->domain,
Jordan Crouse3c86ca82012-05-21 08:41:52 -0600914 iommu_virt_addr, memdesc->sg, size,
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600915 (IOMMU_READ | IOMMU_WRITE), ret);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600916 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600917 }
918
919 return ret;
920}
921
Shubhraprakash Das79447952012-04-26 18:12:23 -0600922static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600923{
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600924 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600925 /*
926 * stop device mmu
927 *
928 * call this with the global lock held
929 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600930
931 if (mmu->flags & KGSL_FLAGS_STARTED) {
932 /* detach iommu attachment */
933 kgsl_detach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600934 mmu->hwpagetable = NULL;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600935
936 mmu->flags &= ~KGSL_FLAGS_STARTED;
937 }
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600938
939 /* switch off MMU clocks and cancel any events it has queued */
940 iommu->clk_event_queued = false;
941 kgsl_cancel_events(mmu->device, mmu);
942 kgsl_iommu_disable_clk(mmu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600943}
944
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600945static int kgsl_iommu_close(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600946{
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600947 struct kgsl_iommu *iommu = mmu->priv;
948 int i;
949 for (i = 0; i < iommu->unit_count; i++) {
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600950 struct kgsl_pagetable *pagetable = (mmu->priv_bank_table ?
951 mmu->priv_bank_table : mmu->defaultpagetable);
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600952 if (iommu->iommu_units[i].reg_map.gpuaddr)
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600953 kgsl_mmu_unmap(pagetable,
Shubhraprakash Das589c7fe2012-05-04 17:30:20 -0600954 &(iommu->iommu_units[i].reg_map));
955 if (iommu->iommu_units[i].reg_map.hostptr)
956 iounmap(iommu->iommu_units[i].reg_map.hostptr);
957 kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
958 iommu->iommu_units[i].reg_map.sglen);
959 }
Shubhraprakash Das19ca4a62012-05-18 12:11:20 -0600960
961 if (mmu->priv_bank_table)
962 kgsl_mmu_putpagetable(mmu->priv_bank_table);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600963 if (mmu->defaultpagetable)
964 kgsl_mmu_putpagetable(mmu->defaultpagetable);
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600965 kfree(iommu);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600966
967 return 0;
968}
969
970static unsigned int
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600971kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600972{
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600973 unsigned int pt_base;
974 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Das64a745c2012-06-11 16:44:16 -0600975 /* We cannot enable or disable the clocks in interrupt context, this
976 function is called from interrupt context if there is an axi error */
977 if (in_interrupt())
978 return 0;
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600979 /* Return the current pt base by reading IOMMU pt_base register */
980 kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700981 pt_base = KGSL_IOMMU_GET_CTX_REG(iommu, (&iommu->iommu_units[0]),
982 KGSL_IOMMU_CONTEXT_USER,
983 TTBR0);
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600984 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700985 return pt_base &
986 (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
987 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600988}
989
Shubhraprakash Dasd3f937c2012-05-07 12:44:40 -0600990/*
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -0600991 * kgsl_iommu_default_setstate - Change the IOMMU pagetable or flush IOMMU tlb
992 * of the primary context bank
993 * @mmu - Pointer to mmu structure
994 * @flags - Flags indicating whether pagetable has to chnage or tlb is to be
995 * flushed or both
996 *
997 * Based on flags set the new pagetable fo the IOMMU unit or flush it's tlb or
998 * do both by doing direct register writes to the IOMMu registers through the
999 * cpu
1000 * Return - void
1001 */
1002static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
1003 uint32_t flags)
1004{
1005 struct kgsl_iommu *iommu = mmu->priv;
1006 int temp;
1007 int i;
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001008 unsigned int pt_base = kgsl_iommu_get_pt_base_addr(mmu,
1009 mmu->hwpagetable);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001010 unsigned int pt_val;
1011
1012 if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
1013 KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
1014 return;
1015 }
1016 /* Mask off the lsb of the pt base address since lsb will not change */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001017 pt_base &= (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
1018 iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
1019
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001020 if (flags & KGSL_MMUFLAGS_PTUPDATE) {
Jordan Crousea29a2e02012-08-14 09:09:23 -06001021 kgsl_idle(mmu->device);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001022 for (i = 0; i < iommu->unit_count; i++) {
1023 /* get the lsb value which should not change when
1024 * changing ttbr0 */
1025 pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
1026 KGSL_IOMMU_CONTEXT_USER);
1027 pt_val += pt_base;
1028
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001029 KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001030 KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
1031
1032 mb();
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001033 temp = KGSL_IOMMU_GET_CTX_REG(iommu,
1034 (&iommu->iommu_units[i]),
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001035 KGSL_IOMMU_CONTEXT_USER, TTBR0);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001036 }
1037 }
1038 /* Flush tlb */
1039 if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
1040 for (i = 0; i < iommu->unit_count; i++) {
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001041 KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
1042 KGSL_IOMMU_CONTEXT_USER, TLBIALL, 1);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001043 mb();
1044 }
1045 }
1046 /* Disable smmu clock */
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001047 kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001048}
1049
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001050/*
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001051 * kgsl_iommu_get_reg_gpuaddr - Returns the gpu address of IOMMU regsiter
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001052 * @mmu - Pointer to mmu structure
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001053 * @iommu_unit - The iommu unit for which base address is requested
1054 * @ctx_id - The context ID of the IOMMU ctx
1055 * @reg - The register for which address is required
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001056 *
1057 * Return - The number of iommu units which is also the number of register
1058 * mapped descriptor arrays which the out parameter will have
1059 */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001060static unsigned int kgsl_iommu_get_reg_gpuaddr(struct kgsl_mmu *mmu,
1061 int iommu_unit, int ctx_id, int reg)
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001062{
1063 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001064
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001065 if (KGSL_IOMMU_GLOBAL_BASE == reg)
1066 return iommu->iommu_units[iommu_unit].reg_map.gpuaddr;
1067 else
1068 return iommu->iommu_units[iommu_unit].reg_map.gpuaddr +
1069 iommu->iommu_reg_list[reg].reg_offset +
1070 (ctx_id << KGSL_IOMMU_CTX_SHIFT) + iommu->ctx_offset;
1071}
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001072
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001073static int kgsl_iommu_get_num_iommu_units(struct kgsl_mmu *mmu)
1074{
1075 struct kgsl_iommu *iommu = mmu->priv;
1076 return iommu->unit_count;
Shubhraprakash Dasa5b1db42012-05-09 18:02:34 -06001077}
1078
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001079struct kgsl_mmu_ops iommu_ops = {
1080 .mmu_init = kgsl_iommu_init,
1081 .mmu_close = kgsl_iommu_close,
1082 .mmu_start = kgsl_iommu_start,
1083 .mmu_stop = kgsl_iommu_stop,
1084 .mmu_setstate = kgsl_iommu_setstate,
Shubhraprakash Dasd8cbcd12012-05-07 16:11:32 -06001085 .mmu_device_setstate = kgsl_iommu_default_setstate,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001086 .mmu_pagefault = NULL,
1087 .mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -06001088 .mmu_enable_clk = kgsl_iommu_enable_clk,
Shubhraprakash Dascb068072012-06-07 17:52:41 -06001089 .mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
Shubhraprakash Dasfce27362012-05-09 17:44:14 -06001090 .mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -07001091 .mmu_get_reg_gpuaddr = kgsl_iommu_get_reg_gpuaddr,
1092 .mmu_get_num_iommu_units = kgsl_iommu_get_num_iommu_units,
1093 .mmu_pt_equal = kgsl_iommu_pt_equal,
1094 .mmu_get_pt_base_addr = kgsl_iommu_get_pt_base_addr,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001095};
1096
1097struct kgsl_mmu_pt_ops iommu_pt_ops = {
1098 .mmu_map = kgsl_iommu_map,
1099 .mmu_unmap = kgsl_iommu_unmap,
1100 .mmu_create_pagetable = kgsl_iommu_create_pagetable,
1101 .mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06001102};