Re: [PATCH 1/2] iommu: call detach also for default_domain before attaching to new one
Hello, On 2016-02-16 16:59, Joerg Roedel wrote: On Tue, Feb 16, 2016 at 03:40:31PM +0100, Marek Szyprowski wrote: This patch ensures that devices attached to the default_domain will be first detached from it before attaching to new domain. To avoid forward declaration, __iommu_attach_group() function has been moved to new place in the source code. Actually it was intentional to not invoke the detach_device call-back in the attach_device path. The reason is that detaching first and than attaching again leaves the device without a domain for a short period of time, until it is attached to the new domain. The attach_device call-back is supposed to handle this situation and just silently overwrite any other domain->device binding it finds for the device. This allows to do re-attachment with less iommu flushes and to get rid of the detach_device call-back at some point. Huh, I wasn't aware of this change in the iommu drivers api. For some drivers attach/detach callbacks does something more than just programming page table base register, like for example in case of exynos iommu it is enabling runtime power management and clocks. The code is really much simpler if those calls are balanced, but if the goal is to allow multiple unballanced attach calls, I will try to fix this in our driver. Maybe it should be documented somewhere, that attach calls can be unbalanced? Best regards -- Marek Szyprowski, PhD Samsung R Institute Poland ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 11/11] iommu: exynos: add Maintainers entry for Exynos SYSMMU driver
On 16.02.2016 23:57, Marek Szyprowski wrote: > Add Marek Szyprowski as maintainer for Exynos IOMMU driver. > > Signed-off-by: Marek Szyprowski> --- > MAINTAINERS | 6 ++ > 1 file changed, 6 insertions(+) > Acked-by: Krzysztof Kozlowski Best regards, Krzysztof > diff --git a/MAINTAINERS b/MAINTAINERS > index 7bd927e..1e9c4df 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -4336,6 +4336,12 @@ L: dri-de...@lists.freedesktop.org > S: Maintained > F: drivers/gpu/drm/exynos/exynos_dp* > > +EXYNOS SYSMMU (IOMMU) driver > +M: Marek Szyprowski > +L: iommu@lists.linux-foundation.org > +S: Maintained > +F: drivers/iommu/exynos-iommu.c > + > EXYNOS MIPI DISPLAY DRIVERS > M: Inki Dae > M: Donghwa Lee > ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [RFC PATCH 1/2] PCI: Add PCI device flag PCI_DEV_FLAGS_BRIDGE_SKIP_ALIAS
On Wed, 17 Feb 2016 02:38:24 +0530 Jayachandran Chandrashekaran Nairwrote: > On Tue, Feb 16, 2016 at 1:09 AM, Alex Williamson > wrote: > > On Mon, 15 Feb 2016 12:20:23 -0600 > > Bjorn Helgaas wrote: > > > >> [+cc Alex, iommu list] > >> > >> On Mon, Feb 15, 2016 at 03:35:00AM +0530, Jayachandran C wrote: > >> > Add a new flag PCI_DEV_FLAGS_BRIDGE_SKIP_ALIAS to indicate bridges > >> > that should not be considered during DMA alias search. This is > >> > to support hardware (in this case Broadcom Vulcan PCIe subsystem) > >> > that has internal bridges which have either missing or wrong PCIe > >> > capabilities. > > > > I figured this would come at some point, the right answer is of course > > to follow the PCIe spec and implement the required PCIe capability in > > the hardware. > > There are PCIe controllers on the chip that follows the spec, the issue is > how it is integrated to the northbridge (equivalent) on the chip, I have > tried to explain it below. > > >> This needs more explanation, like what exactly is wrong with this > >> device? A missing PCIe capability might cause other problems. > >> > >> What problem does this fix? Without these patches, do we merely add > >> aliases that are unnecessary? Do we crash because something goes > >> wrong in the pci_pcie_type() switch because of the incorrect > >> capability? > > Here's how (for example) how the PCI enumeration of a 2 node Vulcan > processor will look like: > > > [0] +-0.0.0--[1]---+--1.a.0[2]-2.0.0---[3]3.0.0 > | +--1.a.1[4]-4.0.0---[5]5.0.0 > | . > | ... etc... > | > +-0.0.1--[10]--+-10.a.0[11]---11.0.0---[12]---12.0.0 >+-10.a.1[13]---13.0.0---[14]---14.0.0 >. >... etc... So we have: "Glue Bridge"---"Glue Bridges"---Root Ports---Endpoints (no pcie) (pci/x-pcie) > > The devices 0.0.x and x.a.x are glue bridges that are there to > bring the real PCIe controllers (pcie cap type 4) 2.0.0, 4.0.0, > 11.0.0, 13.0.0 under a single PCI hierarchy. The x.a.x bridges > have a PCIe capability (type 8) and 0.0.x does not have any pcie > capability. > > In case of Vulcan, both the GICv3 ITS driver code and the SMMUv3 > driver code does dma alias walk to find the device id to use > in ITS and SMMU. In both cases it will ignore the x.0.0 bridges > since they are type root port, but will continue on up and end > up with incorrect device id. > > The flag I have added is to make the pci_for_each_dma_alias() > ignore the last 2 levels of glue/internal bridges. Per the PCIe spec, I'm not even sure what you have is a valid hierarchy, root ports sit on root complexes, not behind a PCI-to-PCIe bridge. So really you're pretending that the downstream "glue bridge" is your host bridge and therefore root complex, but the PCI topology would clearly dictate that the top-most bus is conventional PCI and therefore everything is an alias of everything else and the DMA alias code is doing exactly what it should. Also note that the caller of pci_for_each_dma_alias() owns the callback function triggered for each alias, that function could choose to prune out these "glue bridges" itself if that's the appropriate thing to do. Where do the SMMU and ITS actually reside in the above diagram? You can use the callout function to stop the traversal anywhere you wish, it's free to return a -errno to stop or positive number, which the caller can interpret as error or non-failure stop condition. You could even think about changing what Linux considers to be the host bridge. Maybe these glue bridges shouldn't even be visible to Linux, would that also solve the issue with the broken BAR? > > The change takes the same code path as it would for a real PCIe bridge > > port (downstream/upstream/root), which means they want to skip adding > > this bridge as an alias of the device. So we're adding in aliases that > > don't exist, the bridge itself. > > > > If anything I'd suggest a flag that actually tries to address the > > problem rather than a symptom of the problem. For example, maybe the > > flag should be PCI_DEV_FLAGS_IS_PCIE. Maybe pci_is_pcie() should even > > take that into account. That has some trickle through for > > pci_pcie_type() and all the accessor functions, but maybe it's a > > cleaner solution overall (or maybe it explodes further). Thanks, > > I didn't really want to mark the glue bridges as PCIe or have fake > PCIe capability there, the obvious simple solution was to add > the flag PCI_DEV_FLAGS_BRIDGE_SKIP_ALIAS > > Any suggestions/comments on how to do this better would be welcome. I definitely don't think either flag idea is the right solution, I think you've actually already got the tools you need to solve it by putting the intelligence in the callback function or by going
Re: [RFC PATCH 1/2] PCI: Add PCI device flag PCI_DEV_FLAGS_BRIDGE_SKIP_ALIAS
On Tue, Feb 16, 2016 at 1:09 AM, Alex Williamsonwrote: > On Mon, 15 Feb 2016 12:20:23 -0600 > Bjorn Helgaas wrote: > >> [+cc Alex, iommu list] >> >> On Mon, Feb 15, 2016 at 03:35:00AM +0530, Jayachandran C wrote: >> > Add a new flag PCI_DEV_FLAGS_BRIDGE_SKIP_ALIAS to indicate bridges >> > that should not be considered during DMA alias search. This is >> > to support hardware (in this case Broadcom Vulcan PCIe subsystem) >> > that has internal bridges which have either missing or wrong PCIe >> > capabilities. > > I figured this would come at some point, the right answer is of course > to follow the PCIe spec and implement the required PCIe capability in > the hardware. There are PCIe controllers on the chip that follows the spec, the issue is how it is integrated to the northbridge (equivalent) on the chip, I have tried to explain it below. >> This needs more explanation, like what exactly is wrong with this >> device? A missing PCIe capability might cause other problems. >> >> What problem does this fix? Without these patches, do we merely add >> aliases that are unnecessary? Do we crash because something goes >> wrong in the pci_pcie_type() switch because of the incorrect >> capability? Here's how (for example) how the PCI enumeration of a 2 node Vulcan processor will look like: [0] +-0.0.0--[1]---+--1.a.0[2]-2.0.0---[3]3.0.0 | +--1.a.1[4]-4.0.0---[5]5.0.0 | . | ... etc... | +-0.0.1--[10]--+-10.a.0[11]---11.0.0---[12]---12.0.0 +-10.a.1[13]---13.0.0---[14]---14.0.0 . ... etc... The devices 0.0.x and x.a.x are glue bridges that are there to bring the real PCIe controllers (pcie cap type 4) 2.0.0, 4.0.0, 11.0.0, 13.0.0 under a single PCI hierarchy. The x.a.x bridges have a PCIe capability (type 8) and 0.0.x does not have any pcie capability. In case of Vulcan, both the GICv3 ITS driver code and the SMMUv3 driver code does dma alias walk to find the device id to use in ITS and SMMU. In both cases it will ignore the x.0.0 bridges since they are type root port, but will continue on up and end up with incorrect device id. The flag I have added is to make the pci_for_each_dma_alias() ignore the last 2 levels of glue/internal bridges. > The change takes the same code path as it would for a real PCIe bridge > port (downstream/upstream/root), which means they want to skip adding > this bridge as an alias of the device. So we're adding in aliases that > don't exist, the bridge itself. > > If anything I'd suggest a flag that actually tries to address the > problem rather than a symptom of the problem. For example, maybe the > flag should be PCI_DEV_FLAGS_IS_PCIE. Maybe pci_is_pcie() should even > take that into account. That has some trickle through for > pci_pcie_type() and all the accessor functions, but maybe it's a > cleaner solution overall (or maybe it explodes further). Thanks, I didn't really want to mark the glue bridges as PCIe or have fake PCIe capability there, the obvious simple solution was to add the flag PCI_DEV_FLAGS_BRIDGE_SKIP_ALIAS Any suggestions/comments on how to do this better would be welcome. Thanks, JC. [Using gmail due to IT transition, hope the ascii art makes it thru] ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v4 3/8] dma-mapping: add dma_{map,unmap}_resource
Map/Unmap a device resource from a physical address. If no dma_map_ops method is available the operation is a no-op. Signed-off-by: Niklas Söderlund--- include/linux/dma-mapping.h | 32 1 file changed, 32 insertions(+) diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index e3aba4e..cc305d1 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -216,6 +216,38 @@ static inline void dma_unmap_page(struct device *dev, dma_addr_t addr, debug_dma_unmap_page(dev, addr, size, dir, false); } +static inline dma_addr_t dma_map_resource(struct device *dev, + phys_addr_t phys_addr, + size_t size, + enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + struct dma_map_ops *ops = get_dma_ops(dev); + unsigned long pfn = __phys_to_pfn(phys_addr); + + BUG_ON(!valid_dma_direction(dir)); + + /* Don't allow RAM to be mapped */ + BUG_ON(pfn_valid(pfn)); + + if (ops->map_resource) + return ops->map_resource(dev, phys_addr, size, dir, attrs); + + return phys_addr; +} + +static inline void dma_unmap_resource(struct device *dev, dma_addr_t addr, + size_t size, enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + struct dma_map_ops *ops = get_dma_ops(dev); + + BUG_ON(!valid_dma_direction(dir)); + if (ops->unmap_resource) + ops->unmap_resource(dev, addr, size, dir, attrs); + +} + static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr, size_t size, enum dma_data_direction dir) -- 2.7.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v4 2/8] dma-mapping: add {map,unmap}_resource to dma_map_ops
Add methods to handle mapping of device resources from a physical address. This is needed for example to be able to map MMIO FIFO registers to a IOMMU. Signed-off-by: Niklas SöderlundReviewed-by: Laurent Pinchart --- include/linux/dma-mapping.h | 6 ++ 1 file changed, 6 insertions(+) diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index 75857cd..e3aba4e 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -49,6 +49,12 @@ struct dma_map_ops { struct scatterlist *sg, int nents, enum dma_data_direction dir, struct dma_attrs *attrs); + dma_addr_t (*map_resource)(struct device *dev, phys_addr_t phys_addr, + size_t size, enum dma_data_direction dir, + struct dma_attrs *attrs); + void (*unmap_resource)(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction dir, + struct dma_attrs *attrs); void (*sync_single_for_cpu)(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction dir); -- 2.7.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v4 0/8] dmaengine: rcar-dmac: add iommu support for slave transfers
Hi, This series add iommu support to rcar-dmac. It's tested on Koelsch with CONFIG_IPMMU_VMSA and by enabling the ipmmu_ds node in r8a7791.dtsi. I verified operation by interacting with /dev/mmcblk1 which is a device behind the iommu. The series depends on out of tree patch '[PATCH] dmaengine: use phys_addr_t for slave configuration' which Vinod now have moved forward whit, thanks! * Changes since v3 - Folded in a fix from Robin to his patch. - Added a check to make sure dma_map_resource can not be used to map RAM as pointed out by Robin. I use BUG_ON to enforce this. It might not be the best method but I saw no other good way since DMA_ERROR_CODE might not be defined on all platforms. - Added comment about that DTS changes will disable 2 DMA channels due to a HW (?) but in the DMAC. - Dropped the use of dma_attrs, no longer needed. - Collected Acked-by and Reviewed-by from Laurent. - Various indentation fix ups. * Changes since v2 - Drop patch to add dma_{map,unmap}_page_attrs. - Add dma_{map,unmap}_resource to handle the mapping without involving a 'struct page'. Thanks Laurent and Robin for pointing this out. - Use size instead of address to keep track of if a mapping exist or not since addr == 0 is valid. Thanks Laurent. - Pick up patch from Robin with Laurents ack (hope it's OK for me to attach the ack?) to add IOMMU_MMIO. - Fix bug in rcar_dmac_device_config where the error check where inverted. - Use DMA_BIDIRECTIONAL in rcar_dmac_device_config since we at that point can't be sure what direction the mapping is going to be used. * Changes since v1 - Add and use a dma_{map,unmap}_page_attrs to be able to map the page using attributes DMA_ATTR_NO_KERNEL_MAPPING and DMA_ATTR_SKIP_CPU_SYNC. Thanks Laurent. - Drop check if dmac is part of a iommu group or not, let the DMA mapping api handle it. - Move slave configuration data around in rcar-dmac to avoid code duplication. - Fix build issue reported by 'kbuild test robot' regarding phys_to_page not availability on some configurations. - Add DT information for r8a7791. * Changes since RFC - Switch to use the dma-mapping api instead of using the iommu_map() directly. Turns out the dma-mapper is much smarter then me... - Dropped the patch to expose domain->ops->pgsize_bitmap from within the iommu api. - Dropped the patch showing how I tested the RFC. Niklas Söderlund (7): dma-mapping: add {map,unmap}_resource to dma_map_ops dma-mapping: add dma_{map,unmap}_resource arm: dma-mapping: add {map,unmap}_resource for iommu ops dmaengine: rcar-dmac: group slave configuration dmaengine: rcar-dmac: add iommu support for slave transfers ARM: dts: r8a7790: add iommus to dmac0 and dmac1 ARM: dts: r8a7791: add iommus to dmac0 and dmac1 Robin Murphy (1): iommu: Add MMIO mapping type arch/arm/boot/dts/r8a7790.dtsi | 30 arch/arm/boot/dts/r8a7791.dtsi | 30 arch/arm/mm/dma-mapping.c | 63 drivers/dma/sh/rcar-dmac.c | 81 +- drivers/iommu/io-pgtable-arm.c | 9 +++-- include/linux/dma-mapping.h| 38 include/linux/iommu.h | 1 + 7 files changed, 233 insertions(+), 19 deletions(-) -- 2.7.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v4 4/8] arm: dma-mapping: add {map, unmap}_resource for iommu ops
Add methods to map/unmap device resources addresses for dma_map_ops that are IOMMU aware. This is needed to map a device MMIO register from a physical address. Signed-off-by: Niklas SöderlundReviewed-by: Laurent Pinchart --- arch/arm/mm/dma-mapping.c | 63 +++ 1 file changed, 63 insertions(+) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 0eca381..ae2b175 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1814,6 +1814,63 @@ static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle, __free_iova(mapping, iova, len); } +/** + * arm_iommu_map_resource - map a device resource for DMA + * @dev: valid struct device pointer + * @phys_addr: physical address of resource + * @size: size of resource to map + * @dir: DMA transfer direction + */ +static dma_addr_t arm_iommu_map_resource(struct device *dev, + phys_addr_t phys_addr, size_t size, + enum dma_data_direction dir, struct dma_attrs *attrs) +{ + struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); + dma_addr_t dma_addr; + int ret, prot; + phys_addr_t addr = phys_addr & PAGE_MASK; + int offset = phys_addr & ~PAGE_MASK; + int len = PAGE_ALIGN(size + offset); + + dma_addr = __alloc_iova(mapping, size); + if (dma_addr == DMA_ERROR_CODE) + return dma_addr; + + prot = __dma_direction_to_prot(dir) | IOMMU_MMIO; + + ret = iommu_map(mapping->domain, dma_addr, addr, len, prot); + if (ret < 0) + goto fail; + + return dma_addr + offset; +fail: + __free_iova(mapping, dma_addr, size); + return DMA_ERROR_CODE; +} + +/** + * arm_iommu_unmap_resource - unmap a device DMA resource + * @dev: valid struct device pointer + * @dma_handle: DMA address to resource + * @size: size of resource to map + * @dir: DMA transfer direction + */ +static void arm_iommu_unmap_resource(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); + dma_addr_t iova = dma_handle & PAGE_MASK; + int offset = dma_handle & ~PAGE_MASK; + int len = PAGE_ALIGN(size + offset); + + if (!iova) + return; + + iommu_unmap(mapping->domain, iova, len); + __free_iova(mapping, iova, len); +} + static void arm_iommu_sync_single_for_cpu(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { @@ -1858,6 +1915,9 @@ struct dma_map_ops iommu_ops = { .sync_sg_for_cpu= arm_iommu_sync_sg_for_cpu, .sync_sg_for_device = arm_iommu_sync_sg_for_device, + .map_resource = arm_iommu_map_resource, + .unmap_resource = arm_iommu_unmap_resource, + .set_dma_mask = arm_dma_set_mask, }; @@ -1873,6 +1933,9 @@ struct dma_map_ops iommu_coherent_ops = { .map_sg = arm_coherent_iommu_map_sg, .unmap_sg = arm_coherent_iommu_unmap_sg, + .map_resource = arm_iommu_map_resource, + .unmap_resource = arm_iommu_unmap_resource, + .set_dma_mask = arm_dma_set_mask, }; -- 2.7.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v4 7/8] ARM: dts: r8a7790: add iommus to dmac0 and dmac1
A unconfirmed hardware bug prevents channel 0 and 15 to be used by the DMAC together with the IPMMU. The DMAC driver will disable the channels reducing the effective number of channels to 14 per DMAC. Signed-off-by: Niklas SöderlundAcked-by: Laurent Pinchart --- arch/arm/boot/dts/r8a7790.dtsi | 30 ++ 1 file changed, 30 insertions(+) diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index 7dfd393..048bbf8 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -294,6 +294,21 @@ power-domains = <_clocks>; #dma-cells = <1>; dma-channels = <15>; + iommus = <_ds 0>, +<_ds 1>, +<_ds 2>, +<_ds 3>, +<_ds 4>, +<_ds 5>, +<_ds 6>, +<_ds 7>, +<_ds 8>, +<_ds 9>, +<_ds 10>, +<_ds 11>, +<_ds 12>, +<_ds 13>, +<_ds 14>; }; dmac1: dma-controller@e672 { @@ -325,6 +340,21 @@ power-domains = <_clocks>; #dma-cells = <1>; dma-channels = <15>; + iommus = <_ds 15>, +<_ds 16>, +<_ds 17>, +<_ds 18>, +<_ds 19>, +<_ds 20>, +<_ds 21>, +<_ds 22>, +<_ds 23>, +<_ds 24>, +<_ds 25>, +<_ds 26>, +<_ds 27>, +<_ds 28>, +<_ds 29>; }; audma0: dma-controller@ec70 { -- 2.7.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v4 6/8] dmaengine: rcar-dmac: add iommu support for slave transfers
Enable slave transfers to devices behind IPMMU:s by mapping the slave addresses using the dma-mapping API. Signed-off-by: Niklas SöderlundReviewed-by: Laurent Pinchart --- drivers/dma/sh/rcar-dmac.c | 52 +- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index 743873c..6a24847 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c @@ -1106,21 +1106,63 @@ rcar_dmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, return desc; } +static int rcar_dmac_set_slave_addr(struct dma_chan *chan, +struct rcar_dmac_chan_slave *slave, +phys_addr_t addr, size_t size) +{ + enum dma_data_direction dir; + + /* +* We can't know the direction at this time, see documentation for +* 'direction' in struct dma_slave_config. +*/ + dir = DMA_BIDIRECTIONAL; + + if (slave->xfer_size) { + dma_unmap_resource(chan->device->dev, slave->slave_addr, + slave->xfer_size, dir, NULL); + slave->slave_addr = 0; + slave->xfer_size = 0; + } + + if (size) { + slave->slave_addr = dma_map_resource(chan->device->dev, addr, + size, dir, NULL); + + if (dma_mapping_error(chan->device->dev, slave->slave_addr)) { + struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan); + + dev_err(chan->device->dev, + "chan%u: failed to map %zx@%pap", rchan->index, + size, ); + return -EIO; + } + + slave->xfer_size = size; + } + + return 0; +} + static int rcar_dmac_device_config(struct dma_chan *chan, struct dma_slave_config *cfg) { struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan); + int ret; /* * We could lock this, but you shouldn't be configuring the * channel, while using it... */ - rchan->src.slave_addr = cfg->src_addr; - rchan->dst.slave_addr = cfg->dst_addr; - rchan->src.xfer_size = cfg->src_addr_width; - rchan->dst.xfer_size = cfg->dst_addr_width; - return 0; + ret = rcar_dmac_set_slave_addr(chan, >src, cfg->src_addr, + cfg->src_addr_width); + if (ret) + return ret; + + ret = rcar_dmac_set_slave_addr(chan, >dst, cfg->dst_addr, + cfg->dst_addr_width); + return ret; } static int rcar_dmac_chan_terminate_all(struct dma_chan *chan) -- 2.7.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v4 5/8] dmaengine: rcar-dmac: group slave configuration
Group slave address and transfer size in own structs for source and destination. This is in preparation for hooking up the dma-mapping API to the slave addresses. Signed-off-by: Niklas SöderlundReviewed-by: Laurent Pinchart --- drivers/dma/sh/rcar-dmac.c | 37 + 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index 7820d07..743873c 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c @@ -118,14 +118,21 @@ struct rcar_dmac_desc_page { sizeof(struct rcar_dmac_xfer_chunk)) /* + * @slave_addr: slave memory address + * @xfer_size: size (in bytes) of hardware transfers + */ +struct rcar_dmac_chan_slave { + dma_addr_t slave_addr; + unsigned int xfer_size; +}; + +/* * struct rcar_dmac_chan - R-Car Gen2 DMA Controller Channel * @chan: base DMA channel object * @iomem: channel I/O memory base * @index: index of this channel in the controller - * @src_xfer_size: size (in bytes) of hardware transfers on the source side - * @dst_xfer_size: size (in bytes) of hardware transfers on the destination side - * @src_slave_addr: slave source memory address - * @dst_slave_addr: slave destination memory address + * @src: slave memory address and size on the source side + * @dst: slave memory address and size on the destination side * @mid_rid: hardware MID/RID for the DMA client using this channel * @lock: protects the channel CHCR register and the desc members * @desc.free: list of free descriptors @@ -142,10 +149,8 @@ struct rcar_dmac_chan { void __iomem *iomem; unsigned int index; - unsigned int src_xfer_size; - unsigned int dst_xfer_size; - dma_addr_t src_slave_addr; - dma_addr_t dst_slave_addr; + struct rcar_dmac_chan_slave src; + struct rcar_dmac_chan_slave dst; int mid_rid; spinlock_t lock; @@ -793,13 +798,13 @@ static void rcar_dmac_chan_configure_desc(struct rcar_dmac_chan *chan, case DMA_DEV_TO_MEM: chcr = RCAR_DMACHCR_DM_INC | RCAR_DMACHCR_SM_FIXED | RCAR_DMACHCR_RS_DMARS; - xfer_size = chan->src_xfer_size; + xfer_size = chan->src.xfer_size; break; case DMA_MEM_TO_DEV: chcr = RCAR_DMACHCR_DM_FIXED | RCAR_DMACHCR_SM_INC | RCAR_DMACHCR_RS_DMARS; - xfer_size = chan->dst_xfer_size; + xfer_size = chan->dst.xfer_size; break; case DMA_MEM_TO_MEM: @@ -1038,7 +1043,7 @@ rcar_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, } dev_addr = dir == DMA_DEV_TO_MEM -? rchan->src_slave_addr : rchan->dst_slave_addr; +? rchan->src.slave_addr : rchan->dst.slave_addr; return rcar_dmac_chan_prep_sg(rchan, sgl, sg_len, dev_addr, dir, flags, false); } @@ -1093,7 +1098,7 @@ rcar_dmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, } dev_addr = dir == DMA_DEV_TO_MEM -? rchan->src_slave_addr : rchan->dst_slave_addr; +? rchan->src.slave_addr : rchan->dst.slave_addr; desc = rcar_dmac_chan_prep_sg(rchan, sgl, sg_len, dev_addr, dir, flags, true); @@ -1110,10 +1115,10 @@ static int rcar_dmac_device_config(struct dma_chan *chan, * We could lock this, but you shouldn't be configuring the * channel, while using it... */ - rchan->src_slave_addr = cfg->src_addr; - rchan->dst_slave_addr = cfg->dst_addr; - rchan->src_xfer_size = cfg->src_addr_width; - rchan->dst_xfer_size = cfg->dst_addr_width; + rchan->src.slave_addr = cfg->src_addr; + rchan->dst.slave_addr = cfg->dst_addr; + rchan->src.xfer_size = cfg->src_addr_width; + rchan->dst.xfer_size = cfg->dst_addr_width; return 0; } -- 2.7.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: Can't boot new 4.4 kernel with IOMMU enabled
On 02/16/2016 11:24 AM, Joerg Roedel wrote: On Tue, Feb 02, 2016 at 10:49:11AM -0500, Mark Hounschell wrote: Just wondering if this issue is still being considered? Yes it is, I just went through a move and have a few other issues on the plate. But I this is still on the list. Thanks, I'll be standing by. Mark ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: DMAR error messages after 'shutdown -r'.
On Tue, Feb 09, 2016 at 02:59:00PM -0500, Valdis Kletnieks wrote: > [0.027629] Freeing SMP alternatives memory: 28K (8e111000 - > 8e118000) > [0.048199] ftrace: allocating 31090 entries in 122 pages > [0.061837] DMAR: Host address width 36 > [0.061841] DMAR: DRHD base: 0x00fed9 flags: 0x1 > [0.061894] DMAR: dmar0: reg_base_addr fed9 ver 1:0 cap c9008020660262 > ecap f0105a > [0.061896] DMAR: RMRR base: 0x00cdb11000 end: 0x00cdb30fff > [0.061899] DMAR-IR: IOAPIC id 2 under DRHD base 0xfed9 IOMMU 0 > [0.061901] DMAR-IR: HPET id 0 under DRHD base 0xfed9 > [0.061903] DMAR-IR: Queued invalidation will be enabled to support x2apic > and Intr-remapping. > Error here > [0.062027] DMAR: DRHD: handling fault status reg 2 > [0.062034] DMAR: DMAR:[DMA Read] Request device [00:1f.2] fault addr > cdacd000 >DMAR:[fault reason 06] PTE Read access is not set > This is probably from a missing RMRR entry for device 00:1f.2. Can you please post full dmesg after boot? Thanks, Joerg ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v8 3/5] memory: mediatek: Add SMI driver
On Tue, Feb 16, 2016 at 05:26:41PM +0100, Joerg Roedel wrote: > On Tue, Feb 16, 2016 at 04:20:00PM +, Will Deacon wrote: > > I'm more than happy to bake a branch containing all the page table stuff, > > but Yong's stuff depends on it so I'll work with whatever is easiest for > > you. > > Okay, to the best is if you would collect all the page table patches and > send me a pull-request. I pull that into my tree then and put Yong's > stuff on-top. Okey doke, I'll put something together this week. Cheers, Will ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v8 3/5] memory: mediatek: Add SMI driver
On Tue, Feb 16, 2016 at 04:20:00PM +, Will Deacon wrote: > I'm more than happy to bake a branch containing all the page table stuff, > but Yong's stuff depends on it so I'll work with whatever is easiest for > you. Okay, to the best is if you would collect all the page table patches and send me a pull-request. I pull that into my tree then and put Yong's stuff on-top. Joerg ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: Can't boot new 4.4 kernel with IOMMU enabled
On Tue, Feb 02, 2016 at 10:49:11AM -0500, Mark Hounschell wrote: > Just wondering if this issue is still being considered? Yes it is, I just went through a move and have a few other issues on the plate. But I this is still on the list. Joerg ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v8 3/5] memory: mediatek: Add SMI driver
On Tue, Feb 16, 2016 at 05:10:09PM +0100, Joerg Roedel wrote: > On Tue, Feb 16, 2016 at 03:32:11PM +, Robin Murphy wrote: > > On 16/02/16 14:11, Joerg Roedel wrote: > > >On Sun, Jan 31, 2016 at 12:00:41PM +0100, Matthias Brugger wrote: > > >>On 26/01/16 05:12, Yong Wu wrote: > > >>>This patch add SMI(Smart Multimedia Interface) driver. This driver > > >>>is responsible to enable/disable iommu and control the power domain > > >>>and clocks of each local arbiter. > > >>> > > >>>Signed-off-by: Yong Wu> > >>>Tested-by: Philipp Zabel > > >>>--- > > >> > > >>Signed-off-by: Matthias Brugger > > >> > > >>Joerg would you mind to take this through your branch? > > > > > >Hmm, I somehow missed the patch-set, at least I can't find the v8 > > >patches in my inbox. > > > > > >Yong, can you please re-send with all Acks and other tags added? > > > > Just to note patch 4 of this series also depends on the v3 > > io-pgtable short-descriptor series posted separately[1] - is that on > > your radar already or would you like that resent as well? > > No, that was not on my radar, I somehow expected Will to handle this > series :) I'm more than happy to bake a branch containing all the page table stuff, but Yong's stuff depends on it so I'll work with whatever is easiest for you. Will ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v8 3/5] memory: mediatek: Add SMI driver
On Tue, Feb 16, 2016 at 03:32:11PM +, Robin Murphy wrote: > Hi Joerg, > > On 16/02/16 14:11, Joerg Roedel wrote: > >On Sun, Jan 31, 2016 at 12:00:41PM +0100, Matthias Brugger wrote: > >> > >> > >>On 26/01/16 05:12, Yong Wu wrote: > >>>This patch add SMI(Smart Multimedia Interface) driver. This driver > >>>is responsible to enable/disable iommu and control the power domain > >>>and clocks of each local arbiter. > >>> > >>>Signed-off-by: Yong Wu> >>>Tested-by: Philipp Zabel > >>>--- > >> > >>Signed-off-by: Matthias Brugger > >> > >>Joerg would you mind to take this through your branch? > > > >Hmm, I somehow missed the patch-set, at least I can't find the v8 > >patches in my inbox. > > > >Yong, can you please re-send with all Acks and other tags added? > > Just to note patch 4 of this series also depends on the v3 > io-pgtable short-descriptor series posted separately[1] - is that on > your radar already or would you like that resent as well? No, that was not on my radar, I somehow expected Will to handle this series :) So please resend that as well. Thanks, Joerg ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 1/2] iommu: call detach also for default_domain before attaching to new one
On Tue, Feb 16, 2016 at 03:40:31PM +0100, Marek Szyprowski wrote: > This patch ensures that devices attached to the default_domain will be > first detached from it before attaching to new domain. To avoid forward > declaration, __iommu_attach_group() function has been moved to new place > in the source code. Actually it was intentional to not invoke the detach_device call-back in the attach_device path. The reason is that detaching first and than attaching again leaves the device without a domain for a short period of time, until it is attached to the new domain. The attach_device call-back is supposed to handle this situation and just silently overwrite any other domain->device binding it finds for the device. This allows to do re-attachment with less iommu flushes and to get rid of the detach_device call-back at some point. Joerg ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v8 3/5] memory: mediatek: Add SMI driver
Hi Joerg, On 16/02/16 14:11, Joerg Roedel wrote: On Sun, Jan 31, 2016 at 12:00:41PM +0100, Matthias Brugger wrote: On 26/01/16 05:12, Yong Wu wrote: This patch add SMI(Smart Multimedia Interface) driver. This driver is responsible to enable/disable iommu and control the power domain and clocks of each local arbiter. Signed-off-by: Yong WuTested-by: Philipp Zabel --- Signed-off-by: Matthias Brugger Joerg would you mind to take this through your branch? Hmm, I somehow missed the patch-set, at least I can't find the v8 patches in my inbox. Yong, can you please re-send with all Acks and other tags added? Just to note patch 4 of this series also depends on the v3 io-pgtable short-descriptor series posted separately[1] - is that on your radar already or would you like that resent as well? Robin. [1]:http://thread.gmane.org/gmane.linux.kernel.iommu/12007 Thanks, Joerg ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 06/11] iommu: exynos: refactor fault handling code
This patch provides a new implementation for page fault handing code. The new implementation is ready for future extensions. No functional changes have been made. Signed-off-by: Marek Szyprowski--- drivers/iommu/exynos-iommu.c | 109 --- 1 file changed, 41 insertions(+), 68 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 4275222..3a577a4 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -148,40 +148,25 @@ static sysmmu_pte_t *page_entry(sysmmu_pte_t *sent, sysmmu_iova_t iova) lv2table_base(sent)) + lv2ent_offset(iova); } -enum exynos_sysmmu_inttype { - SYSMMU_PAGEFAULT, - SYSMMU_AR_MULTIHIT, - SYSMMU_AW_MULTIHIT, - SYSMMU_BUSERROR, - SYSMMU_AR_SECURITY, - SYSMMU_AR_ACCESS, - SYSMMU_AW_SECURITY, - SYSMMU_AW_PROTECTION, /* 7 */ - SYSMMU_FAULT_UNKNOWN, - SYSMMU_FAULTS_NUM -}; - -static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = { - REG_PAGE_FAULT_ADDR, - REG_AR_FAULT_ADDR, - REG_AW_FAULT_ADDR, - REG_DEFAULT_SLAVE_ADDR, - REG_AR_FAULT_ADDR, - REG_AR_FAULT_ADDR, - REG_AW_FAULT_ADDR, - REG_AW_FAULT_ADDR +/* + * IOMMU fault information register + */ +struct sysmmu_fault_info { + unsigned int bit; /* bit number in STATUS register */ + unsigned short addr_reg; /* register to read VA fault address */ + const char *name; /* human readable fault name */ + unsigned int type; /* fault type for report_iommu_fault */ }; -static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = { - "PAGE FAULT", - "AR MULTI-HIT FAULT", - "AW MULTI-HIT FAULT", - "BUS ERROR", - "AR SECURITY PROTECTION FAULT", - "AR ACCESS PROTECTION FAULT", - "AW SECURITY PROTECTION FAULT", - "AW ACCESS PROTECTION FAULT", - "UNKNOWN FAULT" +static const struct sysmmu_fault_info sysmmu_faults[] = { + { 0, REG_PAGE_FAULT_ADDR, "PAGE", IOMMU_FAULT_READ }, + { 1, REG_AR_FAULT_ADDR, "AR MULTI-HIT", IOMMU_FAULT_READ }, + { 2, REG_AW_FAULT_ADDR, "AW MULTI-HIT", IOMMU_FAULT_WRITE }, + { 3, REG_DEFAULT_SLAVE_ADDR, "BUS ERROR", IOMMU_FAULT_READ }, + { 4, REG_AR_FAULT_ADDR, "AR SECURITY PROTECTION", IOMMU_FAULT_READ }, + { 5, REG_AR_FAULT_ADDR, "AR ACCESS PROTECTION", IOMMU_FAULT_READ }, + { 6, REG_AW_FAULT_ADDR, "AW SECURITY PROTECTION", IOMMU_FAULT_WRITE }, + { 7, REG_AW_FAULT_ADDR, "AW ACCESS PROTECTION", IOMMU_FAULT_WRITE }, }; /* @@ -299,24 +284,19 @@ static void __sysmmu_set_ptbase(struct sysmmu_drvdata *data, phys_addr_t pgd) __sysmmu_tlb_invalidate(data); } -static void show_fault_information(const char *name, - enum exynos_sysmmu_inttype itype, - phys_addr_t pgtable_base, sysmmu_iova_t fault_addr) +static void show_fault_information(struct sysmmu_drvdata *data, + const struct sysmmu_fault_info *finfo, + sysmmu_iova_t fault_addr) { sysmmu_pte_t *ent; - if ((itype >= SYSMMU_FAULTS_NUM) || (itype < SYSMMU_PAGEFAULT)) - itype = SYSMMU_FAULT_UNKNOWN; - - pr_err("%s occurred at %#x by %s(Page table base: %pa)\n", - sysmmu_fault_name[itype], fault_addr, name, _base); - - ent = section_entry(phys_to_virt(pgtable_base), fault_addr); - pr_err("\tLv1 entry: %#x\n", *ent); - + dev_err(data->sysmmu, "%s FAULT occurred at %#x (page table base: %pa)\n", + finfo->name, fault_addr, >pgtable); + ent = section_entry(phys_to_virt(data->pgtable), fault_addr); + dev_err(data->sysmmu, "\tLv1 entry: %#x\n", *ent); if (lv1ent_page(ent)) { ent = page_entry(ent, fault_addr); - pr_err("\t Lv2 entry: %#x\n", *ent); + dev_err(data->sysmmu, "\t Lv2 entry: %#x\n", *ent); } } @@ -324,8 +304,10 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id) { /* SYSMMU is in blocked state when interrupt occurred. */ struct sysmmu_drvdata *data = dev_id; - enum exynos_sysmmu_inttype itype; - sysmmu_iova_t addr = -1; + const struct sysmmu_fault_info *finfo = sysmmu_faults; + int i, n = ARRAY_SIZE(sysmmu_faults); + unsigned int itype; + sysmmu_iova_t fault_addr = -1; int ret = -ENOSYS; WARN_ON(!is_sysmmu_active(data)); @@ -334,29 +316,20 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id) clk_enable(data->clk_master); - itype = (enum exynos_sysmmu_inttype) - __ffs(__raw_readl(data->sfrbase + REG_INT_STATUS)); - if (WARN_ON(!((itype >= 0) && (itype < SYSMMU_FAULT_UNKNOWN - itype = SYSMMU_FAULT_UNKNOWN; - else - addr = __raw_readl(data->sfrbase +
[PATCH 10/11] iommu: exynos: add support for v5 SYSMMU
This patch adds support for v5 of SYSMMU controller, found in Samsung Exynos 5433 SoCs. The main difference of v5 is support for 36-bit physical address space and some changes in register layout and core clocks hanging. This patch also adds support for ARM64 architecture, which is used by Exynos 5433 SoCs. Signed-off-by: Marek Szyprowski--- .../devicetree/bindings/iommu/samsung,sysmmu.txt | 5 +- drivers/iommu/Kconfig | 2 +- drivers/iommu/exynos-iommu.c | 195 +++-- 3 files changed, 150 insertions(+), 52 deletions(-) diff --git a/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt b/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt index f61ca25..85f0688 100644 --- a/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt +++ b/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt @@ -35,9 +35,10 @@ Required properties: - interrupts: An interrupt specifier for interrupt signal of System MMU, according to the format defined by a particular interrupt controller. -- clock-names: Should be "sysmmu" if the System MMU is needed to gate its clock. +- clock-names: Should be "sysmmu" or a pair of "aclk" and "pclk" to gate + SYSMMU core clocks. Optional "master" if the clock to the System MMU is gated by - another gate clock other than "sysmmu" (usually main gate clock + another gate clock other core (usually main gate clock of peripheral device this SYSMMU belongs to). - clocks: Phandles for respective clocks described by clock-names. - power-domains: Required if the System MMU is needed to gate its power. diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index a1e75cb..1674de1 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -243,7 +243,7 @@ config TEGRA_IOMMU_SMMU config EXYNOS_IOMMU bool "Exynos IOMMU Support" - depends on ARCH_EXYNOS && ARM && MMU + depends on ARCH_EXYNOS && MMU select IOMMU_API select ARM_DMA_USE_IOMMU help diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index e42a76c..f00378a 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -1,6 +1,5 @@ -/* linux/drivers/iommu/exynos_iommu.c - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. +/* + * Copyright (c) 2011,2016 Samsung Electronics Co., Ltd. * http://www.samsung.com * * This program is free software; you can redistribute it and/or modify @@ -55,17 +54,25 @@ typedef u32 sysmmu_pte_t; #define lv2ent_small(pent) ((*(pent) & 2) == 2) #define lv2ent_large(pent) ((*(pent) & 3) == 1) -static u32 sysmmu_page_offset(sysmmu_iova_t iova, u32 size) -{ - return iova & (size - 1); -} - -#define section_phys(sent) (*(sent) & SECT_MASK) -#define section_offs(iova) sysmmu_page_offset((iova), SECT_SIZE) -#define lpage_phys(pent) (*(pent) & LPAGE_MASK) -#define lpage_offs(iova) sysmmu_page_offset((iova), LPAGE_SIZE) -#define spage_phys(pent) (*(pent) & SPAGE_MASK) -#define spage_offs(iova) sysmmu_page_offset((iova), SPAGE_SIZE) +/* + * v1.x - v3.x SYSMMU supports 32bit physical and 32bit virtual address spaces + * v5.0 introduced support for 36bit physical address space by shifting + * all page entry values by 4 bits. + * All SYSMMU controllers in the system support the address spaces of the same + * size, so PG_ENT_SHIFT can be initialized on first SYSMMU probe to proper + * value (0 or 4). + */ +static short PG_ENT_SHIFT = -1; +#define SYSMMU_PG_ENT_SHIFT 0 +#define SYSMMU_V5_PG_ENT_SHIFT 4 + +#define sect_to_phys(ent) (((phys_addr_t) ent) << PG_ENT_SHIFT) +#define section_phys(sent) (sect_to_phys(*(sent)) & SECT_MASK) +#define section_offs(iova) (iova & (SECT_SIZE - 1)) +#define lpage_phys(pent) (sect_to_phys(*(pent)) & LPAGE_MASK) +#define lpage_offs(iova) (iova & (LPAGE_SIZE - 1)) +#define spage_phys(pent) (sect_to_phys(*(pent)) & SPAGE_MASK) +#define spage_offs(iova) (iova & (SPAGE_SIZE - 1)) #define NUM_LV1ENTRIES 4096 #define NUM_LV2ENTRIES (SECT_SIZE / SPAGE_SIZE) @@ -84,13 +91,12 @@ static u32 lv2ent_offset(sysmmu_iova_t iova) #define LV2TABLE_SIZE (NUM_LV2ENTRIES * sizeof(sysmmu_pte_t)) #define SPAGES_PER_LPAGE (LPAGE_SIZE / SPAGE_SIZE) +#define lv2table_base(sent) (sect_to_phys(*(sent) & 0xFFC0)) -#define lv2table_base(sent) (*(sent) & 0xFC00) - -#define mk_lv1ent_sect(pa) ((pa) | 2) -#define mk_lv1ent_page(pa) ((pa) | 1) -#define mk_lv2ent_lpage(pa) ((pa) | 1) -#define mk_lv2ent_spage(pa) ((pa) | 2) +#define mk_lv1ent_sect(pa) ((pa >> PG_ENT_SHIFT) | 2) +#define mk_lv1ent_page(pa) ((pa >> PG_ENT_SHIFT) | 1) +#define mk_lv2ent_lpage(pa) ((pa >> PG_ENT_SHIFT) | 1) +#define mk_lv2ent_spage(pa) ((pa >> PG_ENT_SHIFT) | 2) #define CTRL_ENABLE0x5 #define CTRL_BLOCK 0x7 @@ -98,14 +104,23 @@ static u32 lv2ent_offset(sysmmu_iova_t iova)
[PATCH 05/11] iommu: exynos: refactor code (no direct register access)
This patch changes some internal functions to have access to the state of sysmmu device instead of having only it's registers. This will make the code ready for future extensions. Signed-off-by: Marek Szyprowski--- drivers/iommu/exynos-iommu.c | 40 +++- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index bf6b826..4275222 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -254,50 +254,49 @@ static bool is_sysmmu_active(struct sysmmu_drvdata *data) return data->activations > 0; } -static void sysmmu_unblock(void __iomem *sfrbase) +static void sysmmu_unblock(struct sysmmu_drvdata *data) { - __raw_writel(CTRL_ENABLE, sfrbase + REG_MMU_CTRL); + __raw_writel(CTRL_ENABLE, data->sfrbase + REG_MMU_CTRL); } -static bool sysmmu_block(void __iomem *sfrbase) +static bool sysmmu_block(struct sysmmu_drvdata *data) { int i = 120; - __raw_writel(CTRL_BLOCK, sfrbase + REG_MMU_CTRL); - while ((i > 0) && !(__raw_readl(sfrbase + REG_MMU_STATUS) & 1)) + __raw_writel(CTRL_BLOCK, data->sfrbase + REG_MMU_CTRL); + while ((i > 0) && !(__raw_readl(data->sfrbase + REG_MMU_STATUS) & 1)) --i; - if (!(__raw_readl(sfrbase + REG_MMU_STATUS) & 1)) { - sysmmu_unblock(sfrbase); + if (!(__raw_readl(data->sfrbase + REG_MMU_STATUS) & 1)) { + sysmmu_unblock(data); return false; } return true; } -static void __sysmmu_tlb_invalidate(void __iomem *sfrbase) +static void __sysmmu_tlb_invalidate(struct sysmmu_drvdata *data) { - __raw_writel(0x1, sfrbase + REG_MMU_FLUSH); + __raw_writel(0x1, data->sfrbase + REG_MMU_FLUSH); } -static void __sysmmu_tlb_invalidate_entry(void __iomem *sfrbase, +static void __sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data, sysmmu_iova_t iova, unsigned int num_inv) { unsigned int i; for (i = 0; i < num_inv; i++) { __raw_writel((iova & SPAGE_MASK) | 1, - sfrbase + REG_MMU_FLUSH_ENTRY); + data->sfrbase + REG_MMU_FLUSH_ENTRY); iova += SPAGE_SIZE; } } -static void __sysmmu_set_ptbase(void __iomem *sfrbase, - phys_addr_t pgd) +static void __sysmmu_set_ptbase(struct sysmmu_drvdata *data, phys_addr_t pgd) { - __raw_writel(pgd, sfrbase + REG_PT_BASE_ADDR); + __raw_writel(pgd, data->sfrbase + REG_PT_BASE_ADDR); - __sysmmu_tlb_invalidate(sfrbase); + __sysmmu_tlb_invalidate(data); } static void show_fault_information(const char *name, @@ -363,7 +362,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id) __raw_writel(1 << itype, data->sfrbase + REG_INT_CLEAR); - sysmmu_unblock(data->sfrbase); + sysmmu_unblock(data); clk_disable(data->clk_master); @@ -440,7 +439,7 @@ static void __sysmmu_enable_nocount(struct sysmmu_drvdata *data) __sysmmu_init_config(data); - __sysmmu_set_ptbase(data->sfrbase, data->pgtable); + __sysmmu_set_ptbase(data, data->pgtable); __raw_writel(CTRL_ENABLE, data->sfrbase + REG_MMU_CTRL); @@ -521,10 +520,9 @@ static void sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data, if (MMU_MAJ_VER(data->version) == 2) num_inv = min_t(unsigned int, size / PAGE_SIZE, 64); - if (sysmmu_block(data->sfrbase)) { - __sysmmu_tlb_invalidate_entry( - data->sfrbase, iova, num_inv); - sysmmu_unblock(data->sfrbase); + if (sysmmu_block(data)) { + __sysmmu_tlb_invalidate_entry(data, iova, num_inv); + sysmmu_unblock(data); } clk_disable(data->clk_master); } else { -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 01/11] iommu: exynos: rework iommu group initialization
This patch replaces custom code in add_device implementation with iommu_group_get_for_dev() call and provides the needed callback. Signed-off-by: Marek Szyprowski--- drivers/iommu/exynos-iommu.c | 27 --- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 97c41b8..4fc0790 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -1114,28 +1114,32 @@ static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *iommu_domain, return phys; } +static struct iommu_group *get_device_iommu_group(struct device *dev) +{ + struct iommu_group *group; + + group = iommu_group_get(dev); + if (!group) + group = iommu_group_alloc(); + + return group; +} + static int exynos_iommu_add_device(struct device *dev) { struct iommu_group *group; - int ret; if (!has_sysmmu(dev)) return -ENODEV; - group = iommu_group_get(dev); + group = iommu_group_get_for_dev(dev); - if (!group) { - group = iommu_group_alloc(); - if (IS_ERR(group)) { - dev_err(dev, "Failed to allocate IOMMU group\n"); - return PTR_ERR(group); - } - } + if (IS_ERR(group)) + return PTR_ERR(group); - ret = iommu_group_add_device(group, dev); iommu_group_put(group); - return ret; + return 0; } static void exynos_iommu_remove_device(struct device *dev) @@ -1182,6 +1186,7 @@ static struct iommu_ops exynos_iommu_ops = { .unmap = exynos_iommu_unmap, .map_sg = default_iommu_map_sg, .iova_to_phys = exynos_iommu_iova_to_phys, + .device_group = get_device_iommu_group, .add_device = exynos_iommu_add_device, .remove_device = exynos_iommu_remove_device, .pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE, -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 02/11] iommu: exynos: add support for IOMMU_DOMAIN_DMA domain type
This patch adds support for DMA domain type. Such domain have DMA cookie prepared and can be used by generic DMA-IOMMU glue layer. Signed-off-by: Marek Szyprowski--- drivers/iommu/exynos-iommu.c | 19 +++ 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 4fc0790..595e0da 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -25,9 +25,9 @@ #include #include #include +#include #include -#include #include typedef u32 sysmmu_iova_t; @@ -662,16 +662,21 @@ static struct iommu_domain *exynos_iommu_domain_alloc(unsigned type) struct exynos_iommu_domain *domain; int i; - if (type != IOMMU_DOMAIN_UNMANAGED) - return NULL; domain = kzalloc(sizeof(*domain), GFP_KERNEL); if (!domain) return NULL; + if (type == IOMMU_DOMAIN_DMA) { + if (iommu_get_dma_cookie(>domain) != 0) + goto err_pgtable; + } else if (type != IOMMU_DOMAIN_UNMANAGED) { + goto err_pgtable; + } + domain->pgtable = (sysmmu_pte_t *)__get_free_pages(GFP_KERNEL, 2); if (!domain->pgtable) - goto err_pgtable; + goto err_dma_cookie; domain->lv2entcnt = (short *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1); if (!domain->lv2entcnt) @@ -703,6 +708,9 @@ static struct iommu_domain *exynos_iommu_domain_alloc(unsigned type) err_counter: free_pages((unsigned long)domain->pgtable, 2); +err_dma_cookie: + if (type == IOMMU_DOMAIN_DMA) + iommu_put_dma_cookie(>domain); err_pgtable: kfree(domain); return NULL; @@ -727,6 +735,9 @@ static void exynos_iommu_domain_free(struct iommu_domain *iommu_domain) spin_unlock_irqrestore(>lock, flags); + if (iommu_domain->type == IOMMU_DOMAIN_DMA) + iommu_put_dma_cookie(iommu_domain); + for (i = 0; i < NUM_LV1ENTRIES; i++) if (lv1ent_page(domain->pgtable + i)) kmem_cache_free(lv2table_kmem_cache, -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 11/11] iommu: exynos: add Maintainers entry for Exynos SYSMMU driver
Add Marek Szyprowski as maintainer for Exynos IOMMU driver. Signed-off-by: Marek Szyprowski--- MAINTAINERS | 6 ++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7bd927e..1e9c4df 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4336,6 +4336,12 @@ L: dri-de...@lists.freedesktop.org S: Maintained F: drivers/gpu/drm/exynos/exynos_dp* +EXYNOS SYSMMU (IOMMU) driver +M: Marek Szyprowski +L: iommu@lists.linux-foundation.org +S: Maintained +F: drivers/iommu/exynos-iommu.c + EXYNOS MIPI DISPLAY DRIVERS M: Inki Dae M: Donghwa Lee -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 07/11] iommu: exynos: refactor init config code
This patch rewrites sysmmu_init_config function to make it easier to read and understand. Signed-off-by: Marek Szyprowski--- drivers/iommu/exynos-iommu.c | 25 + 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 3a577a4..15787a1 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -383,24 +383,17 @@ static bool __sysmmu_disable(struct sysmmu_drvdata *data) static void __sysmmu_init_config(struct sysmmu_drvdata *data) { - unsigned int cfg = CFG_LRU | CFG_QOS(15); - unsigned int ver; - - ver = MMU_RAW_VER(__raw_readl(data->sfrbase + REG_MMU_VERSION)); - if (MMU_MAJ_VER(ver) == 3) { - if (MMU_MIN_VER(ver) >= 2) { - cfg |= CFG_FLPDCACHE; - if (MMU_MIN_VER(ver) == 3) { - cfg |= CFG_ACGEN; - cfg &= ~CFG_LRU; - } else { - cfg |= CFG_SYSSEL; - } - } - } + unsigned int cfg; + + data->version = MMU_RAW_VER(__raw_readl(data->sfrbase + REG_MMU_VERSION)); + if (data->version <= MAKE_MMU_VER(3, 1)) + cfg = CFG_LRU | CFG_QOS(15); + else if (data->version <= MAKE_MMU_VER(3, 2)) + cfg = CFG_LRU | CFG_QOS(15) | CFG_FLPDCACHE | CFG_SYSSEL; + else + cfg = CFG_QOS(15) | CFG_FLPDCACHE | CFG_ACGEN; __raw_writel(cfg, data->sfrbase + REG_MMU_CFG); - data->version = ver; } static void __sysmmu_enable_nocount(struct sysmmu_drvdata *data) -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 03/11] iommu: exynos: remove ARM-specific cache flush interface
This patch replaces custom ARM-specific code for performing CPU cache flush operations with generic code based on DMA-mapping. Domain managing code is independent of particular SYSMMU device, so the first registered SYSMMU device is used for DMA-mapping calls. This simplification works fine because all SYSMMU controllers are in the same address space (where DMA address equals physical address) and the DMA-mapping calls are done mainly to flush CPU cache to make changes visible to SYSMMU controllers. Signed-off-by: Marek Szyprowski--- drivers/iommu/exynos-iommu.c | 74 +--- 1 file changed, 49 insertions(+), 25 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 595e0da..8c8a7f7 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -27,9 +27,6 @@ #include #include -#include -#include - typedef u32 sysmmu_iova_t; typedef u32 sysmmu_pte_t; @@ -83,6 +80,7 @@ static u32 lv2ent_offset(sysmmu_iova_t iova) return (iova >> SPAGE_ORDER) & (NUM_LV2ENTRIES - 1); } +#define LV1TABLE_SIZE (NUM_LV1ENTRIES * sizeof(sysmmu_pte_t)) #define LV2TABLE_SIZE (NUM_LV2ENTRIES * sizeof(sysmmu_pte_t)) #define SPAGES_PER_LPAGE (LPAGE_SIZE / SPAGE_SIZE) @@ -134,6 +132,7 @@ static u32 lv2ent_offset(sysmmu_iova_t iova) #define has_sysmmu(dev)(dev->archdata.iommu != NULL) +static struct device *dma_dev; static struct kmem_cache *lv2table_kmem_cache; static sysmmu_pte_t *zero_lv2_table; #define ZERO_LV2LINK mk_lv1ent_page(virt_to_phys(zero_lv2_table)) @@ -650,16 +649,19 @@ static struct platform_driver exynos_sysmmu_driver __refdata = { } }; -static inline void pgtable_flush(void *vastart, void *vaend) +static inline void update_pte(sysmmu_pte_t *ent, sysmmu_pte_t val) { - dmac_flush_range(vastart, vaend); - outer_flush_range(virt_to_phys(vastart), - virt_to_phys(vaend)); + dma_sync_single_for_cpu(dma_dev, virt_to_phys(ent), sizeof(*ent), + DMA_TO_DEVICE); + *ent = val; + dma_sync_single_for_device(dma_dev, virt_to_phys(ent), sizeof(*ent), + DMA_TO_DEVICE); } static struct iommu_domain *exynos_iommu_domain_alloc(unsigned type) { struct exynos_iommu_domain *domain; + dma_addr_t handle; int i; @@ -694,7 +696,10 @@ static struct iommu_domain *exynos_iommu_domain_alloc(unsigned type) domain->pgtable[i + 7] = ZERO_LV2LINK; } - pgtable_flush(domain->pgtable, domain->pgtable + NUM_LV1ENTRIES); + handle = dma_map_single(dma_dev, domain->pgtable, LV1TABLE_SIZE, + DMA_TO_DEVICE); + /* For mapping page table entries we rely on dma == phys */ + BUG_ON(handle != virt_to_phys(domain->pgtable)); spin_lock_init(>lock); spin_lock_init(>pgtablelock); @@ -738,10 +743,18 @@ static void exynos_iommu_domain_free(struct iommu_domain *iommu_domain) if (iommu_domain->type == IOMMU_DOMAIN_DMA) iommu_put_dma_cookie(iommu_domain); + dma_unmap_single(dma_dev, virt_to_phys(domain->pgtable), LV1TABLE_SIZE, +DMA_TO_DEVICE); + for (i = 0; i < NUM_LV1ENTRIES; i++) - if (lv1ent_page(domain->pgtable + i)) + if (lv1ent_page(domain->pgtable + i)) { + phys_addr_t base = lv2table_base(domain->pgtable + i); + + dma_unmap_single(dma_dev, base, LV2TABLE_SIZE, +DMA_TO_DEVICE); kmem_cache_free(lv2table_kmem_cache, - phys_to_virt(lv2table_base(domain->pgtable + i))); + phys_to_virt(base)); + } free_pages((unsigned long)domain->pgtable, 2); free_pages((unsigned long)domain->lv2entcnt, 1); @@ -834,11 +847,10 @@ static sysmmu_pte_t *alloc_lv2entry(struct exynos_iommu_domain *domain, if (!pent) return ERR_PTR(-ENOMEM); - *sent = mk_lv1ent_page(virt_to_phys(pent)); + update_pte(sent, mk_lv1ent_page(virt_to_phys(pent))); kmemleak_ignore(pent); *pgcounter = NUM_LV2ENTRIES; - pgtable_flush(pent, pent + NUM_LV2ENTRIES); - pgtable_flush(sent, sent + 1); + dma_map_single(dma_dev, pent, LV2TABLE_SIZE, DMA_TO_DEVICE); /* * If pre-fetched SLPD is a faulty SLPD in zero_l2_table, @@ -891,9 +903,7 @@ static int lv1set_section(struct exynos_iommu_domain *domain, *pgcnt = 0; } - *sent = mk_lv1ent_sect(paddr); - - pgtable_flush(sent, sent + 1); + update_pte(sent, mk_lv1ent_sect(paddr)); spin_lock(>lock); if
[PATCH 08/11] iommu: exynos: unify code for fldp cache invalidation
This patch simplifies the code for handling of flpdcache invalidation. Signed-off-by: Marek Szyprowski--- drivers/iommu/exynos-iommu.c | 13 - 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 15787a1..e42a76c 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -440,13 +440,6 @@ static int __sysmmu_enable(struct sysmmu_drvdata *data, phys_addr_t pgtable, return ret; } -static void __sysmmu_tlb_invalidate_flpdcache(struct sysmmu_drvdata *data, - sysmmu_iova_t iova) -{ - if (data->version == MAKE_MMU_VER(3, 3)) - __raw_writel(iova | 0x1, data->sfrbase + REG_MMU_FLUSH_ENTRY); -} - static void sysmmu_tlb_invalidate_flpdcache(struct sysmmu_drvdata *data, sysmmu_iova_t iova) { @@ -455,8 +448,10 @@ static void sysmmu_tlb_invalidate_flpdcache(struct sysmmu_drvdata *data, clk_enable(data->clk_master); spin_lock_irqsave(>lock, flags); - if (is_sysmmu_active(data)) - __sysmmu_tlb_invalidate_flpdcache(data, iova); + if (is_sysmmu_active(data)) { + if (data->version >= MAKE_MMU_VER(3, 3)) + __sysmmu_tlb_invalidate_entry(data, iova, 1); + } spin_unlock_irqrestore(>lock, flags); clk_disable(data->clk_master); -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 04/11] iommu: exynos: simplify master clock operations
All clock API function can be called on NULL clock, so simplify code avoid checking of master clock presence. Signed-off-by: Marek Szyprowski--- drivers/iommu/exynos-iommu.c | 32 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 8c8a7f7..bf6b826 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -333,8 +333,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id) spin_lock(>lock); - if (!IS_ERR(data->clk_master)) - clk_enable(data->clk_master); + clk_enable(data->clk_master); itype = (enum exynos_sysmmu_inttype) __ffs(__raw_readl(data->sfrbase + REG_INT_STATUS)); @@ -366,8 +365,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id) sysmmu_unblock(data->sfrbase); - if (!IS_ERR(data->clk_master)) - clk_disable(data->clk_master); + clk_disable(data->clk_master); spin_unlock(>lock); @@ -376,15 +374,13 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id) static void __sysmmu_disable_nocount(struct sysmmu_drvdata *data) { - if (!IS_ERR(data->clk_master)) - clk_enable(data->clk_master); + clk_enable(data->clk_master); __raw_writel(CTRL_DISABLE, data->sfrbase + REG_MMU_CTRL); __raw_writel(0, data->sfrbase + REG_MMU_CFG); clk_disable(data->clk); - if (!IS_ERR(data->clk_master)) - clk_disable(data->clk_master); + clk_disable(data->clk_master); } static bool __sysmmu_disable(struct sysmmu_drvdata *data) @@ -437,8 +433,7 @@ static void __sysmmu_init_config(struct sysmmu_drvdata *data) static void __sysmmu_enable_nocount(struct sysmmu_drvdata *data) { - if (!IS_ERR(data->clk_master)) - clk_enable(data->clk_master); + clk_enable(data->clk_master); clk_enable(data->clk); __raw_writel(CTRL_BLOCK, data->sfrbase + REG_MMU_CTRL); @@ -449,8 +444,7 @@ static void __sysmmu_enable_nocount(struct sysmmu_drvdata *data) __raw_writel(CTRL_ENABLE, data->sfrbase + REG_MMU_CTRL); - if (!IS_ERR(data->clk_master)) - clk_disable(data->clk_master); + clk_disable(data->clk_master); } static int __sysmmu_enable(struct sysmmu_drvdata *data, phys_addr_t pgtable, @@ -493,16 +487,14 @@ static void sysmmu_tlb_invalidate_flpdcache(struct sysmmu_drvdata *data, { unsigned long flags; - if (!IS_ERR(data->clk_master)) - clk_enable(data->clk_master); + clk_enable(data->clk_master); spin_lock_irqsave(>lock, flags); if (is_sysmmu_active(data)) __sysmmu_tlb_invalidate_flpdcache(data, iova); spin_unlock_irqrestore(>lock, flags); - if (!IS_ERR(data->clk_master)) - clk_disable(data->clk_master); + clk_disable(data->clk_master); } static void sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data, @@ -514,8 +506,7 @@ static void sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data, if (is_sysmmu_active(data)) { unsigned int num_inv = 1; - if (!IS_ERR(data->clk_master)) - clk_enable(data->clk_master); + clk_enable(data->clk_master); /* * L2TLB invalidation required @@ -535,8 +526,7 @@ static void sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data, data->sfrbase, iova, num_inv); sysmmu_unblock(data->sfrbase); } - if (!IS_ERR(data->clk_master)) - clk_disable(data->clk_master); + clk_disable(data->clk_master); } else { dev_dbg(data->master, "disabled. Skipping TLB invalidation @ %#x\n", iova); @@ -593,6 +583,8 @@ static int __init exynos_sysmmu_probe(struct platform_device *pdev) dev_err(dev, "Failed to prepare master's clk\n"); return ret; } + } else { + data->clk_master = NULL; } data->sysmmu = dev; -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 09/11] iommu: exynos: update device tree documentation
Exynos SYSMMU bindings documentation was merged before generic IOMMU binding have been introduced. This patch updates documentation to match current state. Signed-off-by: Marek Szyprowski--- .../devicetree/bindings/iommu/samsung,sysmmu.txt | 19 --- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt b/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt index bc620fe..f61ca25 100644 --- a/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt +++ b/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt @@ -23,28 +23,23 @@ MMUs. for window 1, 2 and 3. * M2M Scalers and G2D in Exynos5420 has one System MMU on the read channel and the other System MMU on the write channel. -The drivers must consider how to handle those System MMUs. One of the idea is -to implement child devices or sub-devices which are the client devices of the -System MMU. -Note: -The current DT binding for the Exynos System MMU is incomplete. -The following properties can be removed or changed, if found incompatible with -the "Generic IOMMU Binding" support for attaching devices to the IOMMU. +For information on assigning System MMU controller to its peripheral devices, +see generic IOMMU bindings. Required properties: - compatible: Should be "samsung,exynos-sysmmu" - reg: A tuple of base address and size of System MMU registers. +- #iommu-cells: Should be <0>. - interrupt-parent: The phandle of the interrupt controller of System MMU - interrupts: An interrupt specifier for interrupt signal of System MMU, according to the format defined by a particular interrupt controller. - clock-names: Should be "sysmmu" if the System MMU is needed to gate its clock. Optional "master" if the clock to the System MMU is gated by - another gate clock other than "sysmmu". - Exynos4 SoCs, there needs no "master" clock. - Exynos5 SoCs, some System MMUs must have "master" clocks. -- clocks: Required if the System MMU is needed to gate its clock. + another gate clock other than "sysmmu" (usually main gate clock + of peripheral device this SYSMMU belongs to). +- clocks: Phandles for respective clocks described by clock-names. - power-domains: Required if the System MMU is needed to gate its power. Please refer to the following document: Documentation/devicetree/bindings/power/pd-samsung.txt @@ -57,6 +52,7 @@ Examples: power-domains = <_gsc>; clocks = < CLK_GSCL0>; clock-names = "gscl"; + iommus = <_gsc0>; }; sysmmu_gsc0: sysmmu@13E8 { @@ -67,4 +63,5 @@ Examples: clock-names = "sysmmu", "master"; clocks = < CLK_SMMU_GSCL0>, < CLK_GSCL0>; power-domains = <_gsc>; + #iommu-cells = <0>; }; -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 00/11] SYSMMU driver update and support for Exynos 5433
Hello, This patchset updates Exynos SYSMMU (IOMMU) driver to make use of the new features in the IOMMU core (support for IOMMU_DOMAIN_DMA) and adds support for SYSMMU v5 controllers, which are available in Samsung Exynos 5433 SoCs. The driver has been also updated to compile and work on ARM64 architecture. Best regards Marek Szyprowski Samsung R Institute Poland Patch summary: Marek Szyprowski (11): iommu: exynos: rework iommu group initialization iommu: exynos: add support for IOMMU_DOMAIN_DMA domain type iommu: exynos: remove ARM-specific cache flush interface iommu: exynos: simplify master clock operations iommu: exynos: refactor code (no direct register access) iommu: exynos: refactor fault handling code iommu: exynos: refactor init config code iommu: exynos: unify code for fldp cache invalidation iommu: exynos: update device tree documentation iommu: exynos: add support for v5 SYSMMU iommu: exynos: add Maintainers entry for Exynos SYSMMU driver .../devicetree/bindings/iommu/samsung,sysmmu.txt | 22 +- MAINTAINERS| 6 + drivers/iommu/Kconfig | 2 +- drivers/iommu/exynos-iommu.c | 514 - 4 files changed, 318 insertions(+), 226 deletions(-) -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 0/2] iommu: fix handling of attach/detach for default domains
Hello, This patchset fixes attaching and detaching devices to a group, which has default domain configured. With both patches applied all calls to iommu's attach/detach functions will be balanced, whenever caller attaches device to the default domain or the custom one. Best regards Marek Szyprowski Samsung R Institute Poland Patch summary: Marek Szyprowski (2): iommu: call detach also for default_domain before attaching to new one iommu: fix default domain handling in __iommu_detach_group() drivers/iommu/iommu.c | 48 +++- 1 file changed, 27 insertions(+), 21 deletions(-) -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 1/2] iommu: call detach also for default_domain before attaching to new one
This patch ensures that devices attached to the default_domain will be first detached from it before attaching to new domain. To avoid forward declaration, __iommu_attach_group() function has been moved to new place in the source code. Signed-off-by: Marek Szyprowski--- drivers/iommu/iommu.c | 38 ++ 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 0e3b009..db231ad 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1198,22 +1198,6 @@ static int iommu_group_do_attach_device(struct device *dev, void *data) return __iommu_attach_device(domain, dev); } -static int __iommu_attach_group(struct iommu_domain *domain, - struct iommu_group *group) -{ - int ret; - - if (group->default_domain && group->domain != group->default_domain) - return -EBUSY; - - ret = __iommu_group_for_each_dev(group, domain, -iommu_group_do_attach_device); - if (ret == 0) - group->domain = domain; - - return ret; -} - int iommu_attach_group(struct iommu_domain *domain, struct iommu_group *group) { int ret; @@ -1235,6 +1219,28 @@ static int iommu_group_do_detach_device(struct device *dev, void *data) return 0; } +static int __iommu_attach_group(struct iommu_domain *domain, + struct iommu_group *group) +{ + int ret; + + if (group->default_domain && group->domain != group->default_domain) + return -EBUSY; + + if (group->default_domain && group->default_domain == group->domain) { + __iommu_group_for_each_dev(group, group->domain, + iommu_group_do_detach_device); + group->domain = NULL; + } + + ret = __iommu_group_for_each_dev(group, domain, +iommu_group_do_attach_device); + if (ret == 0) + group->domain = domain; + + return ret; +} + static void __iommu_detach_group(struct iommu_domain *domain, struct iommu_group *group) { -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 2/2] iommu: fix default domain handling in __iommu_detach_group()
This patch ensures that all devices will be first detached from the provided domain and then attached to the default_domain if such has been provided. Signed-off-by: Marek Szyprowski--- drivers/iommu/iommu.c | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index db231ad..045efb0 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1246,14 +1246,14 @@ static void __iommu_detach_group(struct iommu_domain *domain, { int ret; - if (!group->default_domain) { - __iommu_group_for_each_dev(group, domain, - iommu_group_do_detach_device); - group->domain = NULL; + if (group->domain == group->default_domain) return; - } - if (group->domain == group->default_domain) + __iommu_group_for_each_dev(group, domain, + iommu_group_do_detach_device); + group->domain = NULL; + + if (!group->default_domain) return; /* Detach by re-attaching to the default domain */ -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v3 1/8] iommu: Add MMIO mapping type
* Robin Murphy[2016-02-16 12:43:40 +]: > On 16/02/16 12:06, Niklas Söderlund wrote: > >Hi Robin, > > > >Thanks for your update patch I will include it in my next version. But > >I'm sorry I do not understand, is your modification an addition or a > >substitution to your original patch? > > Apologies for being confusing - that was a diff on top of the existing > patch, to be folded in. My original patch was only handling IOMMU_MMIO for > stage 2 PTEs, so we also need the extra code to handle the different way of > setting the appropriate memory type in stage 1 PTEs. That's what I though but wanted to be clear, thanks for clarifying. I will fold the diff into your patch and keep your SoB line and send it out with my series, hope that's a OK way for me to handle it. Once more thanks for your patch and feedback. > > Robin. > > >* Robin Murphy [2016-02-11 15:57:26 +]: > > > >>On 11/02/16 00:02, Laurent Pinchart wrote: > >>>Hi Niklas, > >>> > >>>Thank you for the patch. > >>> > >>>On Wednesday 10 February 2016 01:57:51 Niklas Söderlund wrote: > From: Robin Murphy > > On some platforms, MMIO regions might need slightly different treatment > compared to mapping regular memory; add the notion of MMIO mappings to > the IOMMU API's memory type flags, so that callers can let the IOMMU > drivers know to do the right thing. > > Signed-off-by: Robin Murphy > Acked-by: Laurent Pinchart > >>> > >>>Answering the question from the cover letter, yes, it's totally fine to > >>>pick > >>>the ack, that's actually expected. > >>> > --- > drivers/iommu/io-pgtable-arm.c | 4 +++- > include/linux/iommu.h | 1 + > >>> > >>>You might be asked to split this patch in two. > >> > >>Worse than that, you might also be asked to fix it up when the silly author > >>remembers that he did this on a stage-2-only ARM SMMU, and the attributes > >>for the stage 1 tables that the IPMMU uses are in a different code path: > >> > >>--->8--- > >>diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c > >>index 5b5c299..7622c6e 100644 > >>--- a/drivers/iommu/io-pgtable-arm.c > >>+++ b/drivers/iommu/io-pgtable-arm.c > >>@@ -354,7 +354,10 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct > >>arm_lpae_io_pgtable *data, > >> if (!(prot & IOMMU_WRITE) && (prot & IOMMU_READ)) > >> pte |= ARM_LPAE_PTE_AP_RDONLY; > >> > >>- if (prot & IOMMU_CACHE) > >>+ if (prot & IOMMU_MMIO) > >>+ pte |= (ARM_LPAE_MAIR_ATTR_IDX_DEV > >>+ << ARM_LPAE_PTE_ATTRINDX_SHIFT); > >>+ else if (prot & IOMMU_CACHE) > >> pte |= (ARM_LPAE_MAIR_ATTR_IDX_CACHE > >> << ARM_LPAE_PTE_ATTRINDX_SHIFT); > >> } else { > >>--->8--- > >> > >>Sorry for the bother, > >>Robin. > >> > 2 files changed, 4 insertions(+), 1 deletion(-) > > diff --git a/drivers/iommu/io-pgtable-arm.c > b/drivers/iommu/io-pgtable-arm.c > index 381ca5a..3ff4f87 100644 > --- a/drivers/iommu/io-pgtable-arm.c > +++ b/drivers/iommu/io-pgtable-arm.c > @@ -364,7 +364,9 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct > arm_lpae_io_pgtable *data, pte |= ARM_LPAE_PTE_HAP_READ; > if (prot & IOMMU_WRITE) > pte |= ARM_LPAE_PTE_HAP_WRITE; > - if (prot & IOMMU_CACHE) > + if (prot & IOMMU_MMIO) > + pte |= ARM_LPAE_PTE_MEMATTR_DEV; > + else if (prot & IOMMU_CACHE) > pte |= ARM_LPAE_PTE_MEMATTR_OIWB; > else > pte |= ARM_LPAE_PTE_MEMATTR_NC; > diff --git a/include/linux/iommu.h b/include/linux/iommu.h > index a5c539f..34b6432 100644 > --- a/include/linux/iommu.h > +++ b/include/linux/iommu.h > @@ -30,6 +30,7 @@ > #define IOMMU_WRITE (1 << 1) > #define IOMMU_CACHE (1 << 2) /* DMA cache coherency */ > #define IOMMU_NOEXEC(1 << 3) > +#define IOMMU_MMIO (1 << 4) /* e.g. things like MSI doorbells */ > > struct iommu_ops; > struct iommu_group; > >>> > >> > > > ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v3 1/8] iommu: Add MMIO mapping type
On 16/02/16 12:06, Niklas Söderlund wrote: Hi Robin, Thanks for your update patch I will include it in my next version. But I'm sorry I do not understand, is your modification an addition or a substitution to your original patch? Apologies for being confusing - that was a diff on top of the existing patch, to be folded in. My original patch was only handling IOMMU_MMIO for stage 2 PTEs, so we also need the extra code to handle the different way of setting the appropriate memory type in stage 1 PTEs. Robin. * Robin Murphy[2016-02-11 15:57:26 +]: On 11/02/16 00:02, Laurent Pinchart wrote: Hi Niklas, Thank you for the patch. On Wednesday 10 February 2016 01:57:51 Niklas Söderlund wrote: From: Robin Murphy On some platforms, MMIO regions might need slightly different treatment compared to mapping regular memory; add the notion of MMIO mappings to the IOMMU API's memory type flags, so that callers can let the IOMMU drivers know to do the right thing. Signed-off-by: Robin Murphy Acked-by: Laurent Pinchart Answering the question from the cover letter, yes, it's totally fine to pick the ack, that's actually expected. --- drivers/iommu/io-pgtable-arm.c | 4 +++- include/linux/iommu.h | 1 + You might be asked to split this patch in two. Worse than that, you might also be asked to fix it up when the silly author remembers that he did this on a stage-2-only ARM SMMU, and the attributes for the stage 1 tables that the IPMMU uses are in a different code path: --->8--- diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 5b5c299..7622c6e 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -354,7 +354,10 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data, if (!(prot & IOMMU_WRITE) && (prot & IOMMU_READ)) pte |= ARM_LPAE_PTE_AP_RDONLY; - if (prot & IOMMU_CACHE) + if (prot & IOMMU_MMIO) + pte |= (ARM_LPAE_MAIR_ATTR_IDX_DEV + << ARM_LPAE_PTE_ATTRINDX_SHIFT); + else if (prot & IOMMU_CACHE) pte |= (ARM_LPAE_MAIR_ATTR_IDX_CACHE << ARM_LPAE_PTE_ATTRINDX_SHIFT); } else { --->8--- Sorry for the bother, Robin. 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 381ca5a..3ff4f87 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -364,7 +364,9 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data, pte |= ARM_LPAE_PTE_HAP_READ; if (prot & IOMMU_WRITE) pte |= ARM_LPAE_PTE_HAP_WRITE; - if (prot & IOMMU_CACHE) + if (prot & IOMMU_MMIO) + pte |= ARM_LPAE_PTE_MEMATTR_DEV; + else if (prot & IOMMU_CACHE) pte |= ARM_LPAE_PTE_MEMATTR_OIWB; else pte |= ARM_LPAE_PTE_MEMATTR_NC; diff --git a/include/linux/iommu.h b/include/linux/iommu.h index a5c539f..34b6432 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -30,6 +30,7 @@ #define IOMMU_WRITE (1 << 1) #define IOMMU_CACHE (1 << 2) /* DMA cache coherency */ #define IOMMU_NOEXEC (1 << 3) +#define IOMMU_MMIO (1 << 4) /* e.g. things like MSI doorbells */ struct iommu_ops; struct iommu_group; ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v3 1/8] iommu: Add MMIO mapping type
Hi Robin, Thanks for your update patch I will include it in my next version. But I'm sorry I do not understand, is your modification an addition or a substitution to your original patch? * Robin Murphy[2016-02-11 15:57:26 +]: > On 11/02/16 00:02, Laurent Pinchart wrote: > >Hi Niklas, > > > >Thank you for the patch. > > > >On Wednesday 10 February 2016 01:57:51 Niklas Söderlund wrote: > >>From: Robin Murphy > >> > >>On some platforms, MMIO regions might need slightly different treatment > >>compared to mapping regular memory; add the notion of MMIO mappings to > >>the IOMMU API's memory type flags, so that callers can let the IOMMU > >>drivers know to do the right thing. > >> > >>Signed-off-by: Robin Murphy > >>Acked-by: Laurent Pinchart > > > >Answering the question from the cover letter, yes, it's totally fine to pick > >the ack, that's actually expected. > > > >>--- > >> drivers/iommu/io-pgtable-arm.c | 4 +++- > >> include/linux/iommu.h | 1 + > > > >You might be asked to split this patch in two. > > Worse than that, you might also be asked to fix it up when the silly author > remembers that he did this on a stage-2-only ARM SMMU, and the attributes > for the stage 1 tables that the IPMMU uses are in a different code path: > > --->8--- > diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c > index 5b5c299..7622c6e 100644 > --- a/drivers/iommu/io-pgtable-arm.c > +++ b/drivers/iommu/io-pgtable-arm.c > @@ -354,7 +354,10 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct > arm_lpae_io_pgtable *data, > if (!(prot & IOMMU_WRITE) && (prot & IOMMU_READ)) > pte |= ARM_LPAE_PTE_AP_RDONLY; > > - if (prot & IOMMU_CACHE) > + if (prot & IOMMU_MMIO) > + pte |= (ARM_LPAE_MAIR_ATTR_IDX_DEV > + << ARM_LPAE_PTE_ATTRINDX_SHIFT); > + else if (prot & IOMMU_CACHE) > pte |= (ARM_LPAE_MAIR_ATTR_IDX_CACHE > << ARM_LPAE_PTE_ATTRINDX_SHIFT); > } else { > --->8--- > > Sorry for the bother, > Robin. > > >> 2 files changed, 4 insertions(+), 1 deletion(-) > >> > >>diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c > >>index 381ca5a..3ff4f87 100644 > >>--- a/drivers/iommu/io-pgtable-arm.c > >>+++ b/drivers/iommu/io-pgtable-arm.c > >>@@ -364,7 +364,9 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct > >>arm_lpae_io_pgtable *data, pte |= ARM_LPAE_PTE_HAP_READ; > >>if (prot & IOMMU_WRITE) > >>pte |= ARM_LPAE_PTE_HAP_WRITE; > >>- if (prot & IOMMU_CACHE) > >>+ if (prot & IOMMU_MMIO) > >>+ pte |= ARM_LPAE_PTE_MEMATTR_DEV; > >>+ else if (prot & IOMMU_CACHE) > >>pte |= ARM_LPAE_PTE_MEMATTR_OIWB; > >>else > >>pte |= ARM_LPAE_PTE_MEMATTR_NC; > >>diff --git a/include/linux/iommu.h b/include/linux/iommu.h > >>index a5c539f..34b6432 100644 > >>--- a/include/linux/iommu.h > >>+++ b/include/linux/iommu.h > >>@@ -30,6 +30,7 @@ > >> #define IOMMU_WRITE (1 << 1) > >> #define IOMMU_CACHE (1 << 2) /* DMA cache coherency */ > >> #define IOMMU_NOEXEC (1 << 3) > >>+#define IOMMU_MMIO (1 << 4) /* e.g. things like MSI doorbells */ > >> > >> struct iommu_ops; > >> struct iommu_group; > > > ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu