Messages in this thread Patch in this message | | | From | Nobuhiro Iwamatsu <> | Date | Wed, 12 Sep 2012 17:07:00 +0900 | Subject | Re: [PATCH v3 1/2] iommu/shmobile: Add iommu driver for Renesas IPMMU modules |
| |
Hi,
On Tue, Sep 11, 2012 at 3:10 PM, Hideki EIRAKU <hdk@igel.co.jp> wrote: > This is the Renesas IPMMU driver and IOMMU API implementation. > > The IPMMU module supports the MMU function and the PMB function. The > MMU function provides address translation by pagetable compatible with > ARMv6. The PMB function provides address translation including > tile-linear translation. This patch implements the MMU function. > > The iommu driver does not register a platform driver directly because: > - the register space of the MMU function and the PMB function > have a common register (used for settings flush), so they should ideally > have a way to appropriately share this register. > - the MMU function uses the IOMMU API while the PMB function does not. > - the two functions may be used independently. > > Signed-off-by: Hideki EIRAKU <hdk@igel.co.jp> > Tested-by: Damian Hobson-Garcia <dhobsong@igel.co.jp> > --- > arch/arm/mach-shmobile/Kconfig | 6 + > arch/arm/mach-shmobile/Makefile | 3 + > arch/arm/mach-shmobile/include/mach/ipmmu.h | 16 ++ > arch/arm/mach-shmobile/ipmmu.c | 150 +++++++++++ > drivers/iommu/Kconfig | 36 +++ > drivers/iommu/Makefile | 1 + > drivers/iommu/shmobile-iommu.c | 372 +++++++++++++++++++++++++++ > 7 files changed, 584 insertions(+), 0 deletions(-) > create mode 100644 arch/arm/mach-shmobile/include/mach/ipmmu.h > create mode 100644 arch/arm/mach-shmobile/ipmmu.c > create mode 100644 drivers/iommu/shmobile-iommu.c > > diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig > index 4cacc2d..86adcf0 100644 > --- a/arch/arm/mach-shmobile/Kconfig > +++ b/arch/arm/mach-shmobile/Kconfig > @@ -210,6 +210,12 @@ endmenu > config SH_CLK_CPG > bool > > +config SHMOBILE_IPMMU > + bool > + > +config SHMOBILE_IPMMU_TLB > + bool > + > source "drivers/sh/Kconfig" > > endif > diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile > index 0df5ae6..1e72199 100644 > --- a/arch/arm/mach-shmobile/Makefile > +++ b/arch/arm/mach-shmobile/Makefile > @@ -60,3 +60,6 @@ obj-$(CONFIG_MACH_KZM9G) += board-kzm9g.o > # Framework support > obj-$(CONFIG_SMP) += $(smp-y) > obj-$(CONFIG_GENERIC_GPIO) += $(pfc-y) > + > +# IPMMU/IPMMUI > +obj-$(CONFIG_SHMOBILE_IPMMU) += ipmmu.o > diff --git a/arch/arm/mach-shmobile/include/mach/ipmmu.h b/arch/arm/mach-shmobile/include/mach/ipmmu.h > new file mode 100644 > index 0000000..ede2f0b > --- /dev/null > +++ b/arch/arm/mach-shmobile/include/mach/ipmmu.h > @@ -0,0 +1,16 @@ > +#ifdef CONFIG_SHMOBILE_IPMMU_TLB > +void ipmmu_tlb_flush(struct device *ipmmu_dev); > +void ipmmu_tlb_set(struct device *ipmmu_dev, unsigned long phys, int size, > + int asid); > +void ipmmu_add_device(struct device *dev); > +int ipmmu_iommu_init(struct device *dev); > +#else > +static inline void ipmmu_add_device(struct device *dev) > +{ > +}
Please use 'do { } while (0)'.
> + > +static int ipmmu_iommu_init(struct device *dev) > +{ > + return -EINVAL; > +} > +#endif > diff --git a/arch/arm/mach-shmobile/ipmmu.c b/arch/arm/mach-shmobile/ipmmu.c > new file mode 100644 > index 0000000..72cacb9 > --- /dev/null > +++ b/arch/arm/mach-shmobile/ipmmu.c > @@ -0,0 +1,150 @@ > +/* > + * IPMMU/IPMMUI > + * Copyright (C) 2012 Hideki EIRAKU > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; version 2 of the License. > + * > + * This program is distributed in the hope that 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/platform_device.h> > +#include <linux/io.h> > +#include <linux/err.h> > +#include <linux/export.h> > +#include <linux/slab.h> > +#include <mach/ipmmu.h> > + > +#define IMCTR1 0x000 > +#define IMCTR2 0x004 > +#define IMASID 0x010 > +#define IMTTBR 0x014 > +#define IMTTBCR 0x018 > + > +#define IMCTR1_TLBEN (1 << 0) > +#define IMCTR1_FLUSH (1 << 1) > + > +struct ipmmu_priv { > + void __iomem *ipmmu_base; > + int tlb_enabled; > + struct mutex flush_lock; > +}; > + > +static void ipmmu_reg_write(struct ipmmu_priv *priv, unsigned long reg_off, > + unsigned long data) > +{ > + iowrite32(data, priv->ipmmu_base + reg_off); > +} > + > +void ipmmu_tlb_flush(struct device *dev) > +{ > + struct ipmmu_priv *priv; > + > + if (!dev) > + return; > + priv = dev_get_drvdata(dev); > + mutex_lock(&priv->flush_lock); > + if (priv->tlb_enabled) > + ipmmu_reg_write(priv, IMCTR1, IMCTR1_FLUSH | IMCTR1_TLBEN); > + else > + ipmmu_reg_write(priv, IMCTR1, IMCTR1_FLUSH); > + mutex_unlock(&priv->flush_lock); > +} > + > +void ipmmu_tlb_set(struct device *dev, unsigned long phys, int size, int asid) > +{ > + struct ipmmu_priv *priv; > + > + if (!dev) > + return; > + priv = dev_get_drvdata(dev); > + mutex_lock(&priv->flush_lock); > + switch (size) { > + default: > + priv->tlb_enabled = 0; > + break; > + case 0x2000: > + ipmmu_reg_write(priv, IMTTBCR, 1); > + priv->tlb_enabled = 1; > + break; > + case 0x1000: > + ipmmu_reg_write(priv, IMTTBCR, 2); > + priv->tlb_enabled = 1; > + break; > + case 0x800: > + ipmmu_reg_write(priv, IMTTBCR, 3); > + priv->tlb_enabled = 1; > + break; > + case 0x400: > + ipmmu_reg_write(priv, IMTTBCR, 4); > + priv->tlb_enabled = 1; > + break; > + case 0x200: > + ipmmu_reg_write(priv, IMTTBCR, 5); > + priv->tlb_enabled = 1; > + break; > + case 0x100: > + ipmmu_reg_write(priv, IMTTBCR, 6); > + priv->tlb_enabled = 1; > + break; > + case 0x80: > + ipmmu_reg_write(priv, IMTTBCR, 7); > + priv->tlb_enabled = 1; > + break; > + } I thought that you could describe more briefly if ffs() is used.
> + ipmmu_reg_write(priv, IMTTBR, phys); > + ipmmu_reg_write(priv, IMASID, asid); > + mutex_unlock(&priv->flush_lock); > +} > + > +static int __devinit ipmmu_probe(struct platform_device *pdev) > +{ > + struct resource *res; > + struct ipmmu_priv *priv; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!res) { > + dev_err(&pdev->dev, "cannot get platform resources\n"); > + return -ENOENT; > + } > + priv = kzalloc(sizeof(*priv), GFP_KERNEL); > + if (!priv) { > + dev_err(&pdev->dev, "cannot allocate device data\n"); > + return -ENOMEM; > + } > + mutex_init(&priv->flush_lock); > + priv->ipmmu_base = ioremap_nocache(res->start, resource_size(res)); > + if (!priv->ipmmu_base) { > + dev_err(&pdev->dev, "ioremap_nocache failed\n"); > + kfree(priv); > + return -ENOMEM; > + } > + platform_set_drvdata(pdev, priv); > + ipmmu_reg_write(priv, IMCTR1, 0x0); /* disable TLB */ > + ipmmu_reg_write(priv, IMCTR2, 0x0); /* disable PMB */ > + ipmmu_iommu_init(&pdev->dev); > + return 0; > +} > + > +static struct platform_driver ipmmu_driver = { > + .probe = ipmmu_probe, > + .driver = { > + .owner = THIS_MODULE, > + .name = "ipmmu", > + }, > +}; > + > +static int __init ipmmu_init(void) > +{ > + return platform_driver_register(&ipmmu_driver); > +} > +subsys_initcall(ipmmu_init); > diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig > index 9f69b56..0ed44d0 100644 > --- a/drivers/iommu/Kconfig > +++ b/drivers/iommu/Kconfig > @@ -187,4 +187,40 @@ config EXYNOS_IOMMU_DEBUG > > Say N unless you need kernel log message for IOMMU debugging > > +config SHMOBILE_IOMMU > + bool "IOMMU for Renesas IPMMU/IPMMUI" > + default n > + select IOMMU_API > + select ARM_DMA_USE_IOMMU > + select SHMOBILE_IPMMU > + select SHMOBILE_IPMMU_TLB > + > +choice > + prompt "IPMMU/IPMMUI 1st level page table size" > + default SHMOBILE_IOMMU_L1SIZE_8192 > + depends on SHMOBILE_IOMMU > + > + config SHMOBILE_IOMMU_L1SIZE_8192 > + bool "8192 bytes (2 GiB address space)" > + > + config SHMOBILE_IOMMU_L1SIZE_4096 > + bool "4096 bytes (1 GiB address space)" > + > + config SHMOBILE_IOMMU_L1SIZE_2048 > + bool "2048 bytes (512 MiB address space)" > + > + config SHMOBILE_IOMMU_L1SIZE_1024 > + bool "1024 bytes (256 MiB address space)" > + > + config SHMOBILE_IOMMU_L1SIZE_512 > + bool "512 bytes (128 MiB address space)" > + > + config SHMOBILE_IOMMU_L1SIZE_256 > + bool "256 bytes (64 MiB address space)" > + > + config SHMOBILE_IOMMU_L1SIZE_128 > + bool "128 bytes (32 MiB address space)" > + > +endchoice > + > endif # IOMMU_SUPPORT > diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile > index 14a4d5f..62cf917 100644 > --- a/drivers/iommu/Makefile > +++ b/drivers/iommu/Makefile > @@ -12,3 +12,4 @@ obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o > obj-$(CONFIG_TEGRA_IOMMU_GART) += tegra-gart.o > obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o > obj-$(CONFIG_EXYNOS_IOMMU) += exynos-iommu.o > +obj-$(CONFIG_SHMOBILE_IOMMU) += shmobile-iommu.o > diff --git a/drivers/iommu/shmobile-iommu.c b/drivers/iommu/shmobile-iommu.c > new file mode 100644 > index 0000000..3285b3b > --- /dev/null > +++ b/drivers/iommu/shmobile-iommu.c > @@ -0,0 +1,372 @@ > +/* > + * IOMMU for IPMMU/IPMMUI > + * Copyright (C) 2012 Hideki EIRAKU > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; version 2 of the License. > + * > + * This program is distributed in the hope that 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/io.h> > +#include <linux/dmapool.h> > +#include <linux/slab.h> > +#include <linux/platform_device.h> > +#include <linux/iommu.h> > +#include <linux/dma-mapping.h> > +#include <mach/ipmmu.h> > +#include <asm/dma-iommu.h> > + > +#ifdef CONFIG_SHMOBILE_IOMMU_L1SIZE_8192 > +#define L1_SIZE 8192 > +#endif > +#ifdef CONFIG_SHMOBILE_IOMMU_L1SIZE_4096 > +#define L1_SIZE 4096 > +#endif > +#ifdef CONFIG_SHMOBILE_IOMMU_L1SIZE_2048 > +#define L1_SIZE 2048 > +#endif > +#ifdef CONFIG_SHMOBILE_IOMMU_L1SIZE_1024 > +#define L1_SIZE 1024 > +#endif > +#ifdef CONFIG_SHMOBILE_IOMMU_L1SIZE_512 > +#define L1_SIZE 512 > +#endif > +#ifdef CONFIG_SHMOBILE_IOMMU_L1SIZE_256 > +#define L1_SIZE 256 > +#endif > +#ifdef CONFIG_SHMOBILE_IOMMU_L1SIZE_128 > +#define L1_SIZE 128 > +#endif
I think that it was better to define by kconfig. For example, following codes.
+config SHMOBILE_IOMMU_L1SIZE + hex + default "0x00002000" if SHMOBILE_IOMMU_L1SIZE_8192 + default "0x00001000" if SHMOBILE_IOMMU_L1SIZE_4096 + default "0x00000800" if SHMOBILE_IOMMU_L1SIZE_2048 + default "0x00000400" if SHMOBILE_IOMMU_L1SIZE_1024 + default "0x00000200" if SHMOBILE_IOMMU_L1SIZE_512 + default "0x00000100" if SHMOBILE_IOMMU_L1SIZE_256 + default "0x00000080" if SHMOBILE_IOMMU_L1SIZE_128 > +#define L1_LEN (L1_SIZE / 4) > +#define L1_ALIGN L1_SIZE > +#define L2_SIZE 0x400 > +#define L2_LEN (L2_SIZE / 4) > +#define L2_ALIGN L2_SIZE > + > +struct shmobile_iommu_priv_pgtable { > + uint32_t *pgtable; > + dma_addr_t handle; > +}; > + > +struct shmobile_iommu_priv { > + struct shmobile_iommu_priv_pgtable l1, l2[L1_LEN]; > + spinlock_t map_lock; > + atomic_t active; > +}; > + > +static struct dma_iommu_mapping *iommu_mapping; > +static struct device *ipmmu_devices; > +static struct dma_pool *l1pool, *l2pool; > +static spinlock_t lock; > +static DEFINE_SPINLOCK(lock_add); > +static struct shmobile_iommu_priv *attached; > +static int num_attached_devices; > +static struct device *ipmmu_access_device; > + > +static int shmobile_iommu_domain_init(struct iommu_domain *domain) > +{ > + struct shmobile_iommu_priv *priv; > + int i; > + > + priv = kmalloc(sizeof(*priv), GFP_KERNEL); > + if (!priv) > + return -ENOMEM; > + priv->l1.pgtable = dma_pool_alloc(l1pool, GFP_KERNEL, > + &priv->l1.handle); > + if (!priv->l1.pgtable) { > + kfree(priv); > + return -ENOMEM; > + } > + for (i = 0; i < L1_LEN; i++) > + priv->l2[i].pgtable = NULL; > + memset(priv->l1.pgtable, 0, L1_SIZE); > + spin_lock_init(&priv->map_lock); > + atomic_set(&priv->active, 0); > + domain->priv = priv; > + return 0; > +} > + > +static void shmobile_iommu_domain_destroy(struct iommu_domain *domain) > +{ > + struct shmobile_iommu_priv *priv = domain->priv; > + int i; > + > + for (i = 0; i < L1_LEN; i++) { > + if (priv->l2[i].pgtable) > + dma_pool_free(l2pool, priv->l2[i].pgtable, > + priv->l2[i].handle); > + } > + dma_pool_free(l1pool, priv->l1.pgtable, priv->l1.handle); > + kfree(priv); > + domain->priv = NULL; > +} > + > +static int shmobile_iommu_attach_device(struct iommu_domain *domain, > + struct device *dev) > +{ > + struct shmobile_iommu_priv *priv = domain->priv; > + int ret = -EBUSY; > + > + spin_lock(&lock); > + if (attached != priv) { > + if (attached) > + goto err; > + atomic_set(&priv->active, 1); > + ipmmu_tlb_set(ipmmu_access_device, priv->l1.handle, L1_SIZE, > + 0); > + wmb(); > + ipmmu_tlb_flush(ipmmu_access_device); > + attached = priv; > + num_attached_devices = 0; > + } > + num_attached_devices++; > + ret = 0; > +err: > + spin_unlock(&lock); > + return ret; > +} > + > +static void shmobile_iommu_detach_device(struct iommu_domain *domain, > + struct device *dev) > +{ > + struct shmobile_iommu_priv *priv = domain->priv; > + > + spin_lock(&lock); > + atomic_set(&priv->active, 0); > + num_attached_devices--; > + if (!num_attached_devices) { > + ipmmu_tlb_set(ipmmu_access_device, 0, 0, 0); > + ipmmu_tlb_flush(ipmmu_access_device); > + attached = NULL; > + } > + spin_unlock(&lock); > +} > + > +static int > +l2alloc(struct shmobile_iommu_priv *priv, unsigned int l1index) > +{ > + if (!priv->l2[l1index].pgtable) { > + priv->l2[l1index].pgtable = dma_pool_alloc(l2pool, GFP_KERNEL, > + &priv->l2[l1index].handle); > + if (!priv->l2[l1index].pgtable) > + return -ENOMEM; > + memset(priv->l2[l1index].pgtable, 0, L2_SIZE); > + } > + priv->l1.pgtable[l1index] = priv->l2[l1index].handle | 0x1; > + return 0; > +} > + > +static void > +l2realfree(struct shmobile_iommu_priv_pgtable *l2) > +{ > + if (l2->pgtable) > + dma_pool_free(l2pool, l2->pgtable, l2->handle); > +} > + > +static int > +l2free(struct shmobile_iommu_priv *priv, unsigned int l1index, > + struct shmobile_iommu_priv_pgtable *l2) > +{ > + priv->l1.pgtable[l1index] = 0; > + if (priv->l2[l1index].pgtable) { > + *l2 = priv->l2[l1index]; > + priv->l2[l1index].pgtable = NULL; > + } > + return 0; > +} > + > +static int shmobile_iommu_map(struct iommu_domain *domain, unsigned long iova, > + phys_addr_t paddr, size_t size, int prot) > +{ > + struct shmobile_iommu_priv_pgtable l2 = { .pgtable = NULL }; > + struct shmobile_iommu_priv *priv = domain->priv; > + unsigned int l1index, l2index, i; > + int ret; > + > + l1index = iova >> 20; > + switch (size) { > + case 0x1000: > + l2index = (iova >> 12) & 0xff; > + spin_lock(&priv->map_lock); > + ret = l2alloc(priv, l1index); > + if (!ret) > + priv->l2[l1index].pgtable[l2index] = paddr | 0xff2; > + spin_unlock(&priv->map_lock); > + break; > + case 0x10000: > + l2index = (iova >> 12) & 0xf0; > + spin_lock(&priv->map_lock); > + ret = l2alloc(priv, l1index); > + if (!ret) { > + for (i = 0; i < 0x10; i++) > + priv->l2[l1index].pgtable[l2index + i] = > + paddr | 0xff1; > + } > + spin_unlock(&priv->map_lock); > + break; > + case 0x100000: > + spin_lock(&priv->map_lock); > + l2free(priv, l1index, &l2); > + priv->l1.pgtable[l1index] = paddr | 0xc02; > + spin_unlock(&priv->map_lock); > + ret = 0; > + break; > + default: > + ret = -EINVAL; > + } > + if (!ret && atomic_read(&priv->active)) { > + wmb(); > + ipmmu_tlb_flush(ipmmu_access_device); > + l2realfree(&l2); > + } > + return ret; > +} > + > +static size_t shmobile_iommu_unmap(struct iommu_domain *domain, > + unsigned long iova, size_t size) > +{ > + struct shmobile_iommu_priv_pgtable l2 = { .pgtable = NULL }; > + struct shmobile_iommu_priv *priv = domain->priv; > + unsigned int l1index, l2index, i; > + uint32_t l2entry = 0; > + size_t ret = 0; > + > + l1index = iova >> 20; > + if (!(iova & 0xFFFFF) && size >= 0x100000) { > + spin_lock(&priv->map_lock); > + l2free(priv, l1index, &l2); > + spin_unlock(&priv->map_lock); > + ret = 0x100000; > + goto done; > + } > + l2index = (iova >> 12) & 0xff; > + spin_lock(&priv->map_lock); > + if (priv->l2[l1index].pgtable) > + l2entry = priv->l2[l1index].pgtable[l2index]; > + switch (l2entry & 3) { > + case 1: > + if (l2index & 0xf) > + break; > + for (i = 0; i < 0x10; i++) > + priv->l2[l1index].pgtable[l2index + i] = 0; > + ret = 0x10000; > + break; > + case 2: > + priv->l2[l1index].pgtable[l2index] = 0; > + ret = 0x1000; > + break; > + } > + spin_unlock(&priv->map_lock); > +done: > + if (ret && atomic_read(&priv->active)) { > + wmb(); > + ipmmu_tlb_flush(ipmmu_access_device); > + l2realfree(&l2); > + } > + return ret; > +} > + > +static phys_addr_t shmobile_iommu_iova_to_phys(struct iommu_domain *domain, > + unsigned long iova) > +{ > + struct shmobile_iommu_priv *priv = domain->priv; > + uint32_t l1entry = 0, l2entry = 0; > + unsigned int l1index, l2index; > + > + l1index = iova >> 20; > + l2index = (iova >> 12) & 0xff; > + spin_lock(&priv->map_lock); > + if (priv->l2[l1index].pgtable) > + l2entry = priv->l2[l1index].pgtable[l2index]; > + else > + l1entry = priv->l1.pgtable[l1index]; > + spin_unlock(&priv->map_lock); > + switch (l2entry & 3) { > + case 1: > + return (l2entry & ~0xffff) | (iova & 0xffff); > + case 2: > + return (l2entry & ~0xfff) | (iova & 0xfff); > + default: > + if ((l1entry & 3) == 2) > + return (l1entry & ~0xfffff) | (iova & 0xfffff); > + return 0; > + } > +} > + > +static struct iommu_ops shmobile_iommu_ops = { > + .domain_init = shmobile_iommu_domain_init, > + .domain_destroy = shmobile_iommu_domain_destroy, > + .attach_dev = shmobile_iommu_attach_device, > + .detach_dev = shmobile_iommu_detach_device, > + .map = shmobile_iommu_map, > + .unmap = shmobile_iommu_unmap, > + .iova_to_phys = shmobile_iommu_iova_to_phys, > + .pgsize_bitmap = 0x111000, > +}; > + > +static int shmobile_iommu_attach_all_devices(void) > +{ > + struct device *dev; > + int ret = 0; > + > + spin_lock(&lock_add); > + iommu_mapping = arm_iommu_create_mapping(&platform_bus_type, 0x0, > + L1_LEN << 20, 0); > + if (IS_ERR_OR_NULL(iommu_mapping)) { > + ret = PTR_ERR(iommu_mapping); > + goto err; > + } > + for (dev = ipmmu_devices; dev; dev = dev->archdata.iommu) { > + if (arm_iommu_attach_device(dev, iommu_mapping)) > + pr_err("arm_iommu_attach_device failed\n"); > + } > +err: > + spin_unlock(&lock_add); > + return 0; > +} > + > +void ipmmu_add_device(struct device *dev) > +{ > + spin_lock(&lock_add); > + dev->archdata.iommu = ipmmu_devices; > + ipmmu_devices = dev; > + if (!IS_ERR_OR_NULL(iommu_mapping)) { > + if (arm_iommu_attach_device(dev, iommu_mapping)) > + pr_err("arm_iommu_attach_device failed\n"); > + } > + spin_unlock(&lock_add); > +} > + > +int ipmmu_iommu_init(struct device *dev) > +{ > + dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); > + l1pool = dma_pool_create("shmobile-iommu-pgtable1", dev, > + L1_SIZE, L1_ALIGN, 0); > + if (!l1pool) > + goto nomem_pool1; > + l2pool = dma_pool_create("shmobile-iommu-pgtable2", dev, > + L2_SIZE, L2_ALIGN, 0); > + if (!l2pool) > + goto nomem_pool2; > + spin_lock_init(&lock); > + attached = NULL; > + ipmmu_access_device = dev; > + bus_set_iommu(&platform_bus_type, &shmobile_iommu_ops); > + if (shmobile_iommu_attach_all_devices()) > + pr_err("shmobile_iommu_attach_all_devices failed\n"); > + return 0; > +nomem_pool2: > + dma_pool_destroy(l1pool); > +nomem_pool1: > + return -ENOMEM; > +} > -- > 1.7.0.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-sh" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html
Best regards, Nobuhiro
-- Nobuhiro Iwamatsu
| |