Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Copyright (C) 2013 Red Hat
  3 * Author: Rob Clark <robdclark@gmail.com>
  4 *
  5 * This program is free software; you can redistribute it and/or modify it
  6 * under the terms of the GNU General Public License version 2 as published by
  7 * the Free Software Foundation.
  8 *
  9 * This program is distributed in the hope that it will be useful, but WITHOUT
 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 12 * more details.
 13 *
 14 * You should have received a copy of the GNU General Public License along with
 15 * this program.  If not, see <http://www.gnu.org/licenses/>.
 16 */
 17
 18#include "msm_drv.h"
 19#include "msm_mmu.h"
 20
 21struct msm_iommu {
 22	struct msm_mmu base;
 23	struct iommu_domain *domain;
 24};
 25#define to_msm_iommu(x) container_of(x, struct msm_iommu, base)
 26
 27static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev,
 28		unsigned long iova, int flags, void *arg)
 29{
 30	pr_warn_ratelimited("*** fault: iova=%08lx, flags=%d\n", iova, flags);
 31	return 0;
 32}
 33
 34static int msm_iommu_attach(struct msm_mmu *mmu, const char * const *names,
 35			    int cnt)
 36{
 37	struct msm_iommu *iommu = to_msm_iommu(mmu);
 38	return iommu_attach_device(iommu->domain, mmu->dev);
 39}
 40
 41static void msm_iommu_detach(struct msm_mmu *mmu, const char * const *names,
 42			     int cnt)
 43{
 44	struct msm_iommu *iommu = to_msm_iommu(mmu);
 45	iommu_detach_device(iommu->domain, mmu->dev);
 46}
 47
 48static int msm_iommu_map(struct msm_mmu *mmu, uint32_t iova,
 49		struct sg_table *sgt, unsigned len, int prot)
 50{
 51	struct msm_iommu *iommu = to_msm_iommu(mmu);
 52	struct iommu_domain *domain = iommu->domain;
 53	struct scatterlist *sg;
 54	unsigned int da = iova;
 55	unsigned int i, j;
 56	int ret;
 57
 58	if (!domain || !sgt)
 59		return -EINVAL;
 60
 61	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
 62		u32 pa = sg_phys(sg) - sg->offset;
 63		size_t bytes = sg->length + sg->offset;
 64
 65		VERB("map[%d]: %08x %08x(%zx)", i, iova, pa, bytes);
 66
 67		ret = iommu_map(domain, da, pa, bytes, prot);
 68		if (ret)
 69			goto fail;
 70
 71		da += bytes;
 72	}
 73
 74	return 0;
 75
 76fail:
 77	da = iova;
 78
 79	for_each_sg(sgt->sgl, sg, i, j) {
 80		size_t bytes = sg->length + sg->offset;
 81		iommu_unmap(domain, da, bytes);
 82		da += bytes;
 83	}
 84	return ret;
 85}
 86
 87static int msm_iommu_unmap(struct msm_mmu *mmu, uint32_t iova,
 88		struct sg_table *sgt, unsigned len)
 89{
 90	struct msm_iommu *iommu = to_msm_iommu(mmu);
 91	struct iommu_domain *domain = iommu->domain;
 92	struct scatterlist *sg;
 93	unsigned int da = iova;
 94	int i;
 95
 96	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
 97		size_t bytes = sg->length + sg->offset;
 98		size_t unmapped;
 99
100		unmapped = iommu_unmap(domain, da, bytes);
101		if (unmapped < bytes)
102			return unmapped;
103
104		VERB("unmap[%d]: %08x(%zx)", i, iova, bytes);
105
106		BUG_ON(!PAGE_ALIGNED(bytes));
107
108		da += bytes;
109	}
110
111	return 0;
112}
113
114static void msm_iommu_destroy(struct msm_mmu *mmu)
115{
116	struct msm_iommu *iommu = to_msm_iommu(mmu);
117	iommu_domain_free(iommu->domain);
118	kfree(iommu);
119}
120
121static const struct msm_mmu_funcs funcs = {
122		.attach = msm_iommu_attach,
123		.detach = msm_iommu_detach,
124		.map = msm_iommu_map,
125		.unmap = msm_iommu_unmap,
126		.destroy = msm_iommu_destroy,
127};
128
129struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain)
130{
131	struct msm_iommu *iommu;
132
133	iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
134	if (!iommu)
135		return ERR_PTR(-ENOMEM);
136
137	iommu->domain = domain;
138	msm_mmu_init(&iommu->base, dev, &funcs);
139	iommu_set_fault_handler(domain, msm_fault_handler, dev);
140
141	return &iommu->base;
142}