1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
/*
* IOMMU backend support for NVMAP
*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/slab.h>
#include <mach/iomap.h>
#include <mach/iovmm.h>
#include "nvmap.h"
struct tegra_iovmm_area *tegra_iommu_create_vm(struct device *dev,
dma_addr_t req, size_t size, pgprot_t prot)
{
struct tegra_iovmm_area *area;
dma_addr_t iova;
area = kmalloc(sizeof(*area), GFP_KERNEL);
if (!area)
return NULL;
if (!req)
req = DMA_ANON_ADDR;
iova = arm_iommu_alloc_iova_at(dev, req, size);
if (iova == DMA_ERROR_CODE)
goto err_out;
area->iovm_start = iova;
area->iovm_length = size;
area->pgprot = prot;
area->dev = dev;
return area;
err_out:
kfree(area);
return NULL;
}
void tegra_iommu_free_vm(struct tegra_iovmm_area *area)
{
int i;
size_t count = area->iovm_length >> PAGE_SHIFT;
for (i = 0; i < count; i++) {
dma_addr_t iova;
iova = area->iovm_start + i * PAGE_SIZE;
dma_unmap_page(area->dev, iova, PAGE_SIZE, DMA_NONE);
}
kfree(area);
}
struct tegra_iovmm_client *tegra_iommu_alloc_client(struct device *dev)
{
struct dma_iommu_mapping *map;
struct tegra_iovmm_client *client;
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client)
return NULL;
map = arm_iommu_create_mapping(&platform_bus_type,
TEGRA_IOMMU_BASE, TEGRA_IOMMU_SIZE, 0);
if (IS_ERR(map))
goto err_map;
if (arm_iommu_attach_device(dev, map))
goto err_attach;
client->dev = dev;
return client;
err_attach:
arm_iommu_release_mapping(map);
err_map:
kfree(client);
return NULL;
}
void tegra_iommu_free_client(struct tegra_iovmm_client *client)
{
arm_iommu_release_mapping(client->dev->archdata.mapping);
kfree(client);
}
|