blob: 8f4af3b367d4a3c48e7b75c1cdaf18b8e8987104 [file] [log] [blame]
Olav Hauganab77b1b2012-02-28 09:19:22 -08001/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
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 <mach/msm_subsystem_map.h>
14#include <linux/memory_alloc.h>
15#include <linux/iommu.h>
Laura Abbott0577d7b2012-04-17 11:14:30 -070016#include <linux/platform_device.h>
Olav Haugan16cdb412012-03-27 13:02:17 -070017#include <linux/vmalloc.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070018#include <asm/sizes.h>
19#include <asm/page.h>
20#include <linux/init.h>
21#include <mach/iommu.h>
22#include <mach/iommu_domains.h>
Laura Abbott9f4a8e62011-08-29 19:08:07 -070023#include <mach/socinfo.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070024
Laura Abbotte956cce2011-10-25 13:33:20 -070025/* dummy 4k for overmapping */
26char iommu_dummy[2*PAGE_SIZE-4];
27
Laura Abbott0577d7b2012-04-17 11:14:30 -070028struct msm_iommu_domain_state {
29 struct msm_iommu_domain *domains;
30 int ndomains;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070031};
32
Laura Abbott0577d7b2012-04-17 11:14:30 -070033static struct msm_iommu_domain_state domain_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070034
Laura Abbotte956cce2011-10-25 13:33:20 -070035int msm_iommu_map_extra(struct iommu_domain *domain,
36 unsigned long start_iova,
37 unsigned long size,
38 int cached)
39{
Olav Haugan16cdb412012-03-27 13:02:17 -070040 int i, ret = 0;
41 struct scatterlist *sglist;
42 unsigned int nrpages = PFN_ALIGN(size) >> PAGE_SHIFT;
43 struct page *dummy_page = phys_to_page(
44 PFN_ALIGN(virt_to_phys(iommu_dummy)));
Laura Abbotte956cce2011-10-25 13:33:20 -070045
Olav Haugan16cdb412012-03-27 13:02:17 -070046 sglist = vmalloc(sizeof(*sglist) * nrpages);
47 if (!sglist) {
48 ret = -ENOMEM;
49 goto err1;
Laura Abbotte956cce2011-10-25 13:33:20 -070050 }
51
Olav Haugan16cdb412012-03-27 13:02:17 -070052 sg_init_table(sglist, nrpages);
Laura Abbotte956cce2011-10-25 13:33:20 -070053
Olav Haugan16cdb412012-03-27 13:02:17 -070054 for (i = 0; i < nrpages; i++)
55 sg_set_page(&sglist[i], dummy_page, PAGE_SIZE, 0);
Laura Abbotte956cce2011-10-25 13:33:20 -070056
Olav Haugan16cdb412012-03-27 13:02:17 -070057 ret = iommu_map_range(domain, start_iova, sglist, size, cached);
58 if (ret) {
59 pr_err("%s: could not map extra %lx in domain %p\n",
60 __func__, start_iova, domain);
61 }
Laura Abbotte956cce2011-10-25 13:33:20 -070062
Olav Haugan16cdb412012-03-27 13:02:17 -070063 vfree(sglist);
64err1:
65 return ret;
Laura Abbotte956cce2011-10-25 13:33:20 -070066}
67
68
Laura Abbott9f4a8e62011-08-29 19:08:07 -070069struct iommu_domain *msm_get_iommu_domain(int domain_num)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070070{
Laura Abbott0577d7b2012-04-17 11:14:30 -070071 if (domain_num >= 0 && domain_num < domain_state.ndomains)
72 return domain_state.domains[domain_num].domain;
Laura Abbott9f4a8e62011-08-29 19:08:07 -070073 else
74 return NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070075}
76
Laura Abbott9f4a8e62011-08-29 19:08:07 -070077unsigned long msm_allocate_iova_address(unsigned int iommu_domain,
78 unsigned int partition_no,
79 unsigned long size,
80 unsigned long align)
81{
82 struct mem_pool *pool;
83 unsigned long iova;
84
Laura Abbott0577d7b2012-04-17 11:14:30 -070085 if (iommu_domain >= domain_state.ndomains)
Laura Abbott9f4a8e62011-08-29 19:08:07 -070086 return 0;
87
Laura Abbott0577d7b2012-04-17 11:14:30 -070088 if (partition_no >= domain_state.domains[iommu_domain].npools)
Laura Abbott9f4a8e62011-08-29 19:08:07 -070089 return 0;
90
Laura Abbott0577d7b2012-04-17 11:14:30 -070091 pool = &domain_state.domains[iommu_domain].iova_pools[partition_no];
Laura Abbott9f4a8e62011-08-29 19:08:07 -070092
93 if (!pool->gpool)
94 return 0;
95
96 iova = gen_pool_alloc_aligned(pool->gpool, size, ilog2(align));
97 if (iova)
98 pool->free -= size;
99
100 return iova;
101}
102
103void msm_free_iova_address(unsigned long iova,
104 unsigned int iommu_domain,
105 unsigned int partition_no,
106 unsigned long size)
107{
108 struct mem_pool *pool;
109
Laura Abbott0577d7b2012-04-17 11:14:30 -0700110 if (iommu_domain >= domain_state.ndomains) {
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700111 WARN(1, "Invalid domain %d\n", iommu_domain);
112 return;
113 }
114
Laura Abbott0577d7b2012-04-17 11:14:30 -0700115 if (partition_no >= domain_state.domains[iommu_domain].npools) {
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700116 WARN(1, "Invalid partition %d for domain %d\n",
117 partition_no, iommu_domain);
118 return;
119 }
120
Laura Abbott0577d7b2012-04-17 11:14:30 -0700121 pool = &domain_state.domains[iommu_domain].iova_pools[partition_no];
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700122
123 if (!pool)
124 return;
125
126 pool->free += size;
127 gen_pool_free(pool->gpool, iova, size);
128}
129
130int msm_use_iommu()
131{
Laura Abbott0577d7b2012-04-17 11:14:30 -0700132 /*
133 * If there are no domains, don't bother trying to use the iommu
134 */
135 return domain_state.ndomains && iommu_found();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136}
137
Laura Abbott0577d7b2012-04-17 11:14:30 -0700138static int __init iommu_domain_probe(struct platform_device *pdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139{
Laura Abbott0577d7b2012-04-17 11:14:30 -0700140 struct iommu_domains_pdata *p = pdev->dev.platform_data;
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700141 int i, j;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142
Laura Abbott0577d7b2012-04-17 11:14:30 -0700143 if (!p)
144 return -ENODEV;
145
146 domain_state.domains = p->domains;
147 domain_state.ndomains = p->ndomains;
148
149 for (i = 0; i < domain_state.ndomains; i++) {
150 domain_state.domains[i].domain = iommu_domain_alloc(
151 p->domain_alloc_flags);
152 if (!domain_state.domains[i].domain)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700153 continue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700154
Laura Abbott0577d7b2012-04-17 11:14:30 -0700155 for (j = 0; j < domain_state.domains[i].npools; j++) {
156 struct mem_pool *pool = &domain_state.domains[i].
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700157 iova_pools[j];
158 mutex_init(&pool->pool_mutex);
Olav Haugan2d191032012-02-28 09:46:31 -0800159 if (pool->size) {
160 pool->gpool = gen_pool_create(PAGE_SHIFT, -1);
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700161
Olav Haugan2d191032012-02-28 09:46:31 -0800162 if (!pool->gpool) {
163 pr_err("%s: could not allocate pool\n",
164 __func__);
165 pr_err("%s: domain %d iova space %d\n",
166 __func__, i, j);
167 continue;
168 }
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700169
Olav Haugan2d191032012-02-28 09:46:31 -0800170 if (gen_pool_add(pool->gpool, pool->paddr,
171 pool->size, -1)) {
172 pr_err("%s: could not add memory\n",
173 __func__);
174 pr_err("%s: domain %d pool %d\n",
175 __func__, i, j);
176 gen_pool_destroy(pool->gpool);
177 pool->gpool = NULL;
178 continue;
179 }
180 } else {
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700181 pool->gpool = NULL;
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700182 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700183 }
184 }
185
Laura Abbott0577d7b2012-04-17 11:14:30 -0700186 for (i = 0; i < p->nnames; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700187 int domain_idx;
188 struct device *ctx = msm_iommu_get_ctx(
Laura Abbott0577d7b2012-04-17 11:14:30 -0700189 p->domain_names[i].name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190
191 if (!ctx)
192 continue;
193
Laura Abbott0577d7b2012-04-17 11:14:30 -0700194 domain_idx = p->domain_names[i].domain;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700195
Laura Abbott0577d7b2012-04-17 11:14:30 -0700196 if (!domain_state.domains[domain_idx].domain)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197 continue;
198
Laura Abbott0577d7b2012-04-17 11:14:30 -0700199 if (iommu_attach_device(domain_state.domains[domain_idx].domain,
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700200 ctx)) {
201 WARN(1, "%s: could not attach domain %d to context %s."
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700202 " iommu programming will not occur.\n",
203 __func__, domain_idx,
Laura Abbott0577d7b2012-04-17 11:14:30 -0700204 p->domain_names[i].name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700205 continue;
206 }
207 }
208
209 return 0;
210}
Laura Abbott0577d7b2012-04-17 11:14:30 -0700211
212static struct platform_driver iommu_domain_driver = {
213 .driver = {
214 .name = "iommu_domains",
215 .owner = THIS_MODULE
216 },
217};
218
219static int __init msm_subsystem_iommu_init(void)
220{
221 return platform_driver_probe(&iommu_domain_driver, iommu_domain_probe);
222}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700223device_initcall(msm_subsystem_iommu_init);