RE: [PATCH 5/6] dma-mapping: support fsl-mc bus
> From: Robin Murphy [mailto:robin.mur...@arm.com] > Sent: Tuesday, March 06, 2018 0:22 > > On 05/03/18 18:39, Christoph Hellwig wrote: > > On Mon, Mar 05, 2018 at 03:48:32PM +, Robin Murphy wrote: > >> Unfortunately for us, fsl-mc is conceptually rather like PCI in that it's > >> software-discoverable and the only thing described in DT is the bus "host", > >> thus we need the same sort of thing as for PCI to map from the child > >> devices back to the bus root in order to find the appropriate firmware > >> node. Worse than PCI, though, we wouldn't even have the option of > >> describing child devices statically in firmware at all, since it's actually > >> one of these runtime-configurable "build your own network accelerator" > >> hardware pools where userspace gets to create and destroy "devices" as it > >> likes. > > > > I really hate the PCI special case just as much. Maybe we just > > need a dma_configure method on the bus, and move PCI as well as fsl-mc > > to it. > > Hmm, on reflection, 100% ack to that idea. It would neatly supersede > bus->force_dma *and* mean that we don't have to effectively pull pci.h > into everything, which I've never liked. In hindsight dma_configure() > does feel like it's grown into this odd choke point where we munge > everything in just for it to awkwardly unpick things again. > > Robin. +1 to the idea. Sorry for asking a trivial question - looking into dma_configure() I see that PCI is used in the start and the end of the API. In the end part pci_put_host_bridge_device() is called. So are two bus callbacks something like 'dma_config_start' & 'dma_config_end' will be required where the former one will return "dma_dev"? Regards, Nipun ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v7 13/14] iommu/rockchip: Add runtime PM support
When the power domain is powered off, the IOMMU cannot be accessed and register programming must be deferred until the power domain becomes enabled. Add runtime PM support, and use runtime PM device link from IOMMU to master to startup and shutdown IOMMU. Signed-off-by: Jeffy Chen--- Changes in v7: Add WARN_ON in irq isr, and modify iommu archdata comment. Changes in v6: None Changes in v5: Avoid race about pm_runtime_get_if_in_use() and pm_runtime_enabled(). Changes in v4: None Changes in v3: Only call startup() and shutdown() when iommu attached. Remove pm_mutex. Check runtime PM disabled. Check pm_runtime in rk_iommu_irq(). Changes in v2: None drivers/iommu/rockchip-iommu.c | 189 - 1 file changed, 148 insertions(+), 41 deletions(-) diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index 2448a0528e39..db08978203f7 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -105,7 +106,14 @@ struct rk_iommu { struct iommu_domain *domain; /* domain to which iommu is attached */ }; +/** + * struct rk_iommudata - iommu archdata of master device. + * @link: device link with runtime PM integration from the master + * (consumer) to the IOMMU (supplier). + * @iommu: IOMMU of the master device. + */ struct rk_iommudata { + struct device_link *link; struct rk_iommu *iommu; }; @@ -518,7 +526,13 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id) u32 int_status; dma_addr_t iova; irqreturn_t ret = IRQ_NONE; - int i; + bool need_runtime_put; + int i, err; + + err = pm_runtime_get_if_in_use(iommu->dev); + if (WARN_ON(err <= 0 && err != -EINVAL)) + return ret; + need_runtime_put = err > 0; WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)); @@ -570,6 +584,9 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id) clk_bulk_disable(iommu->num_clocks, iommu->clocks); + if (need_runtime_put) + pm_runtime_put(iommu->dev); + return ret; } @@ -611,10 +628,20 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain, spin_lock_irqsave(_domain->iommus_lock, flags); list_for_each(pos, _domain->iommus) { struct rk_iommu *iommu; + int ret; + iommu = list_entry(pos, struct rk_iommu, node); - WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)); - rk_iommu_zap_lines(iommu, iova, size); - clk_bulk_disable(iommu->num_clocks, iommu->clocks); + + /* Only zap TLBs of IOMMUs that are powered on. */ + ret = pm_runtime_get_if_in_use(iommu->dev); + if (ret > 0 || ret == -EINVAL) { + WARN_ON(clk_bulk_enable(iommu->num_clocks, + iommu->clocks)); + rk_iommu_zap_lines(iommu, iova, size); + clk_bulk_disable(iommu->num_clocks, iommu->clocks); + } + if (ret > 0) + pm_runtime_put(iommu->dev); } spin_unlock_irqrestore(_domain->iommus_lock, flags); } @@ -817,22 +844,30 @@ static struct rk_iommu *rk_iommu_from_dev(struct device *dev) return data ? data->iommu : NULL; } -static int rk_iommu_attach_device(struct iommu_domain *domain, - struct device *dev) +/* Must be called with iommu powered on and attached */ +static void rk_iommu_shutdown(struct rk_iommu *iommu) { - struct rk_iommu *iommu; + int i; + + /* Ignore error while disabling, just keep going */ + WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)); + rk_iommu_enable_stall(iommu); + rk_iommu_disable_paging(iommu); + for (i = 0; i < iommu->num_mmu; i++) { + rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, 0); + rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, 0); + } + rk_iommu_disable_stall(iommu); + clk_bulk_disable(iommu->num_clocks, iommu->clocks); +} + +/* Must be called with iommu powered on and attached */ +static int rk_iommu_startup(struct rk_iommu *iommu) +{ + struct iommu_domain *domain = iommu->domain; struct rk_iommu_domain *rk_domain = to_rk_domain(domain); - unsigned long flags; int ret, i; - /* -* Allow 'virtual devices' (e.g., drm) to attach to domain. -* Such a device does not belong to an iommu group. -*/ - iommu = rk_iommu_from_dev(dev); - if (!iommu) - return 0; - ret = clk_bulk_enable(iommu->num_clocks, iommu->clocks); if (ret) return ret; @@ -845,8 +880,6 @@ static int
[PATCH v7 12/14] iommu/rockchip: Fix error handling in init
It's hard to undo bus_set_iommu() in the error path, so move it to the end of rk_iommu_probe(). Signed-off-by: Jeffy ChenReviewed-by: Tomasz Figa Reviewed-by: Robin Murphy --- Changes in v7: None Changes in v6: None Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: Move bus_set_iommu() to rk_iommu_probe(). drivers/iommu/rockchip-iommu.c | 15 ++- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index 1346bbb8a3e7..2448a0528e39 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -1133,6 +1133,8 @@ static int rk_iommu_probe(struct platform_device *pdev) if (!dma_dev) dma_dev = >dev; + bus_set_iommu(_bus_type, _iommu_ops); + return 0; err_remove_sysfs: iommu_device_sysfs_remove(>iommu); @@ -1158,19 +1160,6 @@ static struct platform_driver rk_iommu_driver = { static int __init rk_iommu_init(void) { - struct device_node *np; - int ret; - - np = of_find_matching_node(NULL, rk_iommu_dt_ids); - if (!np) - return 0; - - of_node_put(np); - - ret = bus_set_iommu(_bus_type, _iommu_ops); - if (ret) - return ret; - return platform_driver_register(_iommu_driver); } subsys_initcall(rk_iommu_init); -- 2.11.0 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v7 11/14] iommu/rockchip: Use OF_IOMMU to attach devices automatically
Converts the rockchip-iommu driver to use the OF_IOMMU infrastructure, which allows attaching master devices to their IOMMUs automatically according to DT properties. Signed-off-by: Jeffy ChenReviewed-by: Robin Murphy --- Changes in v7: None Changes in v6: None Changes in v5: None Changes in v4: None Changes in v3: Add struct rk_iommudata. Squash iommu/rockchip: Use iommu_group_get_for_dev() for add_device Changes in v2: None drivers/iommu/rockchip-iommu.c | 135 - 1 file changed, 40 insertions(+), 95 deletions(-) diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index 6789e11b7087..1346bbb8a3e7 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -104,6 +105,10 @@ struct rk_iommu { struct iommu_domain *domain; /* domain to which iommu is attached */ }; +struct rk_iommudata { + struct rk_iommu *iommu; +}; + static struct device *dma_dev; static inline void rk_table_flush(struct rk_iommu_domain *dom, dma_addr_t dma, @@ -807,18 +812,9 @@ static size_t rk_iommu_unmap(struct iommu_domain *domain, unsigned long _iova, static struct rk_iommu *rk_iommu_from_dev(struct device *dev) { - struct iommu_group *group; - struct device *iommu_dev; - struct rk_iommu *rk_iommu; + struct rk_iommudata *data = dev->archdata.iommu; - group = iommu_group_get(dev); - if (!group) - return NULL; - iommu_dev = iommu_group_get_iommudata(group); - rk_iommu = dev_get_drvdata(iommu_dev); - iommu_group_put(group); - - return rk_iommu; + return data ? data->iommu : NULL; } static int rk_iommu_attach_device(struct iommu_domain *domain, @@ -989,110 +985,53 @@ static void rk_iommu_domain_free(struct iommu_domain *domain) iommu_put_dma_cookie(_domain->domain); } -static bool rk_iommu_is_dev_iommu_master(struct device *dev) -{ - struct device_node *np = dev->of_node; - int ret; - - /* -* An iommu master has an iommus property containing a list of phandles -* to iommu nodes, each with an #iommu-cells property with value 0. -*/ - ret = of_count_phandle_with_args(np, "iommus", "#iommu-cells"); - return (ret > 0); -} - -static int rk_iommu_group_set_iommudata(struct iommu_group *group, - struct device *dev) +static int rk_iommu_add_device(struct device *dev) { - struct device_node *np = dev->of_node; - struct platform_device *pd; - int ret; - struct of_phandle_args args; + struct iommu_group *group; + struct rk_iommu *iommu; - /* -* An iommu master has an iommus property containing a list of phandles -* to iommu nodes, each with an #iommu-cells property with value 0. -*/ - ret = of_parse_phandle_with_args(np, "iommus", "#iommu-cells", 0, -); - if (ret) { - dev_err(dev, "of_parse_phandle_with_args(%pOF) => %d\n", - np, ret); - return ret; - } - if (args.args_count != 0) { - dev_err(dev, "incorrect number of iommu params found for %pOF (found %d, expected 0)\n", - args.np, args.args_count); - return -EINVAL; - } + iommu = rk_iommu_from_dev(dev); + if (!iommu) + return -ENODEV; - pd = of_find_device_by_node(args.np); - of_node_put(args.np); - if (!pd) { - dev_err(dev, "iommu %pOF not found\n", args.np); - return -EPROBE_DEFER; - } + group = iommu_group_get_for_dev(dev); + if (IS_ERR(group)) + return PTR_ERR(group); + iommu_group_put(group); - /* TODO(djkurtz): handle multiple slave iommus for a single master */ - iommu_group_set_iommudata(group, >dev, NULL); + iommu_device_link(>iommu, dev); return 0; } -static int rk_iommu_add_device(struct device *dev) +static void rk_iommu_remove_device(struct device *dev) { - struct iommu_group *group; struct rk_iommu *iommu; - int ret; - - if (!rk_iommu_is_dev_iommu_master(dev)) - return -ENODEV; - - group = iommu_group_get(dev); - if (!group) { - group = iommu_group_alloc(); - if (IS_ERR(group)) { - dev_err(dev, "Failed to allocate IOMMU group\n"); - return PTR_ERR(group); - } - } - - ret = iommu_group_add_device(group, dev); - if (ret) - goto err_put_group; - - ret = rk_iommu_group_set_iommudata(group, dev); - if (ret) - goto err_remove_device; iommu =
[PATCH v7 14/14] iommu/rockchip: Support sharing IOMMU between masters
There would be some masters sharing the same IOMMU device. Put them in the same iommu group and share the same iommu domain. Signed-off-by: Jeffy ChenReviewed-by: Robin Murphy --- Changes in v7: Use iommu_group_ref_get to avoid ref leak Changes in v6: None Changes in v5: None Changes in v4: None Changes in v3: Remove rk_iommudata->domain. Changes in v2: None drivers/iommu/rockchip-iommu.c | 22 -- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index db08978203f7..6a1c7efa7c17 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -104,6 +104,7 @@ struct rk_iommu { struct iommu_device iommu; struct list_head node; /* entry in rk_iommu_domain.iommus */ struct iommu_domain *domain; /* domain to which iommu is attached */ + struct iommu_group *group; }; /** @@ -1091,6 +1092,15 @@ static void rk_iommu_remove_device(struct device *dev) iommu_group_remove_device(dev); } +static struct iommu_group *rk_iommu_device_group(struct device *dev) +{ + struct rk_iommu *iommu; + + iommu = rk_iommu_from_dev(dev); + + return iommu_group_ref_get(iommu->group); +} + static int rk_iommu_of_xlate(struct device *dev, struct of_phandle_args *args) { @@ -1122,7 +1132,7 @@ static const struct iommu_ops rk_iommu_ops = { .add_device = rk_iommu_add_device, .remove_device = rk_iommu_remove_device, .iova_to_phys = rk_iommu_iova_to_phys, - .device_group = generic_device_group, + .device_group = rk_iommu_device_group, .pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP, .of_xlate = rk_iommu_of_xlate, }; @@ -1191,9 +1201,15 @@ static int rk_iommu_probe(struct platform_device *pdev) if (err) return err; + iommu->group = iommu_group_alloc(); + if (IS_ERR(iommu->group)) { + err = PTR_ERR(iommu->group); + goto err_unprepare_clocks; + } + err = iommu_device_sysfs_add(>iommu, dev, NULL, dev_name(dev)); if (err) - goto err_unprepare_clocks; + goto err_put_group; iommu_device_set_ops(>iommu, _iommu_ops); iommu_device_set_fwnode(>iommu, >of_node->fwnode); @@ -1217,6 +1233,8 @@ static int rk_iommu_probe(struct platform_device *pdev) return 0; err_remove_sysfs: iommu_device_sysfs_remove(>iommu); +err_put_group: + iommu_group_put(iommu->group); err_unprepare_clocks: clk_bulk_unprepare(iommu->num_clocks, iommu->clocks); return err; -- 2.11.0 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v7 10/14] iommu/rockchip: Use IOMMU device for dma mapping operations
Use the first registered IOMMU device for dma mapping operations, and drop the domain platform device. This is similar to exynos iommu driver. Signed-off-by: Jeffy ChenReviewed-by: Tomasz Figa Reviewed-by: Robin Murphy --- Changes in v7: None Changes in v6: None Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None drivers/iommu/rockchip-iommu.c | 85 -- 1 file changed, 24 insertions(+), 61 deletions(-) diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index 6c6275589bd5..6789e11b7087 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -79,7 +79,6 @@ struct rk_iommu_domain { struct list_head iommus; - struct platform_device *pdev; u32 *dt; /* page directory table */ dma_addr_t dt_dma; spinlock_t iommus_lock; /* lock for iommus list */ @@ -105,12 +104,14 @@ struct rk_iommu { struct iommu_domain *domain; /* domain to which iommu is attached */ }; +static struct device *dma_dev; + static inline void rk_table_flush(struct rk_iommu_domain *dom, dma_addr_t dma, unsigned int count) { size_t size = count * sizeof(u32); /* count of u32 entry */ - dma_sync_single_for_device(>pdev->dev, dma, size, DMA_TO_DEVICE); + dma_sync_single_for_device(dma_dev, dma, size, DMA_TO_DEVICE); } static struct rk_iommu_domain *to_rk_domain(struct iommu_domain *dom) @@ -625,7 +626,6 @@ static void rk_iommu_zap_iova_first_last(struct rk_iommu_domain *rk_domain, static u32 *rk_dte_get_page_table(struct rk_iommu_domain *rk_domain, dma_addr_t iova) { - struct device *dev = _domain->pdev->dev; u32 *page_table, *dte_addr; u32 dte_index, dte; phys_addr_t pt_phys; @@ -643,9 +643,9 @@ static u32 *rk_dte_get_page_table(struct rk_iommu_domain *rk_domain, if (!page_table) return ERR_PTR(-ENOMEM); - pt_dma = dma_map_single(dev, page_table, SPAGE_SIZE, DMA_TO_DEVICE); - if (dma_mapping_error(dev, pt_dma)) { - dev_err(dev, "DMA mapping error while allocating page table\n"); + pt_dma = dma_map_single(dma_dev, page_table, SPAGE_SIZE, DMA_TO_DEVICE); + if (dma_mapping_error(dma_dev, pt_dma)) { + dev_err(dma_dev, "DMA mapping error while allocating page table\n"); free_page((unsigned long)page_table); return ERR_PTR(-ENOMEM); } @@ -911,29 +911,20 @@ static void rk_iommu_detach_device(struct iommu_domain *domain, static struct iommu_domain *rk_iommu_domain_alloc(unsigned type) { struct rk_iommu_domain *rk_domain; - struct platform_device *pdev; - struct device *iommu_dev; if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA) return NULL; - /* Register a pdev per domain, so DMA API can base on this *dev -* even some virtual master doesn't have an iommu slave -*/ - pdev = platform_device_register_simple("rk_iommu_domain", - PLATFORM_DEVID_AUTO, NULL, 0); - if (IS_ERR(pdev)) + if (!dma_dev) return NULL; - rk_domain = devm_kzalloc(>dev, sizeof(*rk_domain), GFP_KERNEL); + rk_domain = devm_kzalloc(dma_dev, sizeof(*rk_domain), GFP_KERNEL); if (!rk_domain) - goto err_unreg_pdev; - - rk_domain->pdev = pdev; + return NULL; if (type == IOMMU_DOMAIN_DMA && iommu_get_dma_cookie(_domain->domain)) - goto err_unreg_pdev; + return NULL; /* * rk32xx iommus use a 2 level pagetable. @@ -944,11 +935,10 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type) if (!rk_domain->dt) goto err_put_cookie; - iommu_dev = >dev; - rk_domain->dt_dma = dma_map_single(iommu_dev, rk_domain->dt, + rk_domain->dt_dma = dma_map_single(dma_dev, rk_domain->dt, SPAGE_SIZE, DMA_TO_DEVICE); - if (dma_mapping_error(iommu_dev, rk_domain->dt_dma)) { - dev_err(iommu_dev, "DMA map error for DT\n"); + if (dma_mapping_error(dma_dev, rk_domain->dt_dma)) { + dev_err(dma_dev, "DMA map error for DT\n"); goto err_free_dt; } @@ -969,8 +959,6 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type) err_put_cookie: if (type == IOMMU_DOMAIN_DMA) iommu_put_dma_cookie(_domain->domain); -err_unreg_pdev: - platform_device_unregister(pdev); return NULL; } @@ -987,20 +975,18 @@ static void rk_iommu_domain_free(struct iommu_domain *domain) if (rk_dte_is_pt_valid(dte)) { phys_addr_t pt_phys
[PATCH v7 09/14] dt-bindings: iommu/rockchip: Add clock property
Add clock property, since we are going to control clocks in rockchip iommu driver. Signed-off-by: Jeffy ChenReviewed-by: Rob Herring --- Changes in v7: None Changes in v6: Fix dt-binding as Robin suggested. Use aclk and iface clk as Rob and Robin suggested, and split binding patch. Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None Documentation/devicetree/bindings/iommu/rockchip,iommu.txt | 7 +++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt b/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt index 2098f7732264..6ecefea1c6f9 100644 --- a/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt +++ b/Documentation/devicetree/bindings/iommu/rockchip,iommu.txt @@ -14,6 +14,11 @@ Required properties: "single-master" device, and needs no additional information to associate with its master device. See: Documentation/devicetree/bindings/iommu/iommu.txt +- clocks : A list of clocks required for the IOMMU to be accessible by +the host CPU. +- clock-names : Should contain the following: + "iface" - Main peripheral bus clock (PCLK/HCL) (required) + "aclk" - AXI bus clock (required) Optional properties: - rockchip,disable-mmu-reset : Don't use the mmu reset operation. @@ -27,5 +32,7 @@ Example: reg = <0xff940300 0x100>; interrupts = ; interrupt-names = "vopl_mmu"; + clocks = < ACLK_VOP1>, < HCLK_VOP1>; + clock-names = "aclk", "iface"; #iommu-cells = <0>; }; -- 2.11.0 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v7 08/14] iommu/rockchip: Control clocks needed to access the IOMMU
From: Tomasz FigaCurrent code relies on master driver enabling necessary clocks before IOMMU is accessed, however there are cases when the IOMMU should be accessed while the master is not running yet, for example allocating V4L2 videobuf2 buffers, which is done by the VB2 framework using DMA mapping API and doesn't engage the master driver at all. This patch fixes the problem by letting clocks needed for IOMMU operation to be listed in Device Tree and making the driver enable them for the time of accessing the hardware. Signed-off-by: Jeffy Chen Signed-off-by: Tomasz Figa Acked-by: Robin Murphy --- Changes in v7: None Changes in v6: Fix dt-binding as Robin suggested. Use aclk and iface clk as Rob and Robin suggested, and split binding patch. Changes in v5: Use clk_bulk APIs. Changes in v4: None Changes in v3: None Changes in v2: None drivers/iommu/rockchip-iommu.c | 54 +- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index c4131ca792e0..6c6275589bd5 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -4,6 +4,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -87,10 +88,17 @@ struct rk_iommu_domain { struct iommu_domain domain; }; +/* list of clocks required by IOMMU */ +static const char * const rk_iommu_clocks[] = { + "aclk", "iface", +}; + struct rk_iommu { struct device *dev; void __iomem **bases; int num_mmu; + struct clk_bulk_data *clocks; + int num_clocks; bool reset_disabled; struct iommu_device iommu; struct list_head node; /* entry in rk_iommu_domain.iommus */ @@ -506,6 +514,8 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id) irqreturn_t ret = IRQ_NONE; int i; + WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)); + for (i = 0; i < iommu->num_mmu; i++) { int_status = rk_iommu_read(iommu->bases[i], RK_MMU_INT_STATUS); if (int_status == 0) @@ -552,6 +562,8 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id) rk_iommu_write(iommu->bases[i], RK_MMU_INT_CLEAR, int_status); } + clk_bulk_disable(iommu->num_clocks, iommu->clocks); + return ret; } @@ -594,7 +606,9 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain, list_for_each(pos, _domain->iommus) { struct rk_iommu *iommu; iommu = list_entry(pos, struct rk_iommu, node); + WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)); rk_iommu_zap_lines(iommu, iova, size); + clk_bulk_disable(iommu->num_clocks, iommu->clocks); } spin_unlock_irqrestore(_domain->iommus_lock, flags); } @@ -823,10 +837,14 @@ static int rk_iommu_attach_device(struct iommu_domain *domain, if (!iommu) return 0; - ret = rk_iommu_enable_stall(iommu); + ret = clk_bulk_enable(iommu->num_clocks, iommu->clocks); if (ret) return ret; + ret = rk_iommu_enable_stall(iommu); + if (ret) + goto out_disable_clocks; + ret = rk_iommu_force_reset(iommu); if (ret) goto out_disable_stall; @@ -852,6 +870,8 @@ static int rk_iommu_attach_device(struct iommu_domain *domain, out_disable_stall: rk_iommu_disable_stall(iommu); +out_disable_clocks: + clk_bulk_disable(iommu->num_clocks, iommu->clocks); return ret; } @@ -873,6 +893,7 @@ static void rk_iommu_detach_device(struct iommu_domain *domain, spin_unlock_irqrestore(_domain->iommus_lock, flags); /* Ignore error while disabling, just keep going */ + WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)); rk_iommu_enable_stall(iommu); rk_iommu_disable_paging(iommu); for (i = 0; i < iommu->num_mmu; i++) { @@ -880,6 +901,7 @@ static void rk_iommu_detach_device(struct iommu_domain *domain, rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, 0); } rk_iommu_disable_stall(iommu); + clk_bulk_disable(iommu->num_clocks, iommu->clocks); iommu->domain = NULL; @@ -1172,18 +1194,38 @@ static int rk_iommu_probe(struct platform_device *pdev) iommu->reset_disabled = device_property_read_bool(dev, "rockchip,disable-mmu-reset"); - err = iommu_device_sysfs_add(>iommu, dev, NULL, dev_name(dev)); + iommu->num_clocks = ARRAY_SIZE(rk_iommu_clocks); + iommu->clocks = devm_kcalloc(iommu->dev, iommu->num_clocks, +sizeof(*iommu->clocks), GFP_KERNEL); + if (!iommu->clocks) + return -ENOMEM; +
[PATCH v7 05/14] iommu/rockchip: Use iopoll helpers to wait for hardware
From: Tomasz FigaThis patch converts the rockchip-iommu driver to use the in-kernel iopoll helpers to wait for certain status bits to change in registers instead of an open-coded custom macro. Signed-off-by: Tomasz Figa Signed-off-by: Jeffy Chen Reviewed-by: Robin Murphy --- Changes in v7: None Changes in v6: None Changes in v5: Use RK_MMU_POLL_PERIOD_US instead of 100. Changes in v4: None Changes in v3: None Changes in v2: None drivers/iommu/rockchip-iommu.c | 75 ++ 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index f7ff3a3645ea..baba283ccdf9 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -36,7 +36,10 @@ #define RK_MMU_AUTO_GATING 0x24 #define DTE_ADDR_DUMMY 0xCAFEBABE -#define FORCE_RESET_TIMEOUT100 /* ms */ + +#define RK_MMU_POLL_PERIOD_US 100 +#define RK_MMU_FORCE_RESET_TIMEOUT_US 10 +#define RK_MMU_POLL_TIMEOUT_US 1000 /* RK_MMU_STATUS fields */ #define RK_MMU_STATUS_PAGING_ENABLED BIT(0) @@ -73,8 +76,6 @@ */ #define RK_IOMMU_PGSIZE_BITMAP 0x007ff000 -#define IOMMU_REG_POLL_COUNT_FAST 1000 - struct rk_iommu_domain { struct list_head iommus; struct platform_device *pdev; @@ -109,27 +110,6 @@ static struct rk_iommu_domain *to_rk_domain(struct iommu_domain *dom) return container_of(dom, struct rk_iommu_domain, domain); } -/** - * Inspired by _wait_for in intel_drv.h - * This is NOT safe for use in interrupt context. - * - * Note that it's important that we check the condition again after having - * timed out, since the timeout could be due to preemption or similar and - * we've never had a chance to check the condition before the timeout. - */ -#define rk_wait_for(COND, MS) ({ \ - unsigned long timeout__ = jiffies + msecs_to_jiffies(MS) + 1; \ - int ret__ = 0; \ - while (!(COND)) { \ - if (time_after(jiffies, timeout__)) { \ - ret__ = (COND) ? 0 : -ETIMEDOUT;\ - break; \ - } \ - usleep_range(50, 100); \ - } \ - ret__; \ -}) - /* * The Rockchip rk3288 iommu uses a 2-level page table. * The first level is the "Directory Table" (DT). @@ -333,9 +313,21 @@ static bool rk_iommu_is_paging_enabled(struct rk_iommu *iommu) return enable; } +static bool rk_iommu_is_reset_done(struct rk_iommu *iommu) +{ + bool done = true; + int i; + + for (i = 0; i < iommu->num_mmu; i++) + done &= rk_iommu_read(iommu->bases[i], RK_MMU_DTE_ADDR) == 0; + + return done; +} + static int rk_iommu_enable_stall(struct rk_iommu *iommu) { int ret, i; + bool val; if (rk_iommu_is_stall_active(iommu)) return 0; @@ -346,7 +338,9 @@ static int rk_iommu_enable_stall(struct rk_iommu *iommu) rk_iommu_command(iommu, RK_MMU_CMD_ENABLE_STALL); - ret = rk_wait_for(rk_iommu_is_stall_active(iommu), 1); + ret = readx_poll_timeout(rk_iommu_is_stall_active, iommu, val, +val, RK_MMU_POLL_PERIOD_US, +RK_MMU_POLL_TIMEOUT_US); if (ret) for (i = 0; i < iommu->num_mmu; i++) dev_err(iommu->dev, "Enable stall request timed out, status: %#08x\n", @@ -358,13 +352,16 @@ static int rk_iommu_enable_stall(struct rk_iommu *iommu) static int rk_iommu_disable_stall(struct rk_iommu *iommu) { int ret, i; + bool val; if (!rk_iommu_is_stall_active(iommu)) return 0; rk_iommu_command(iommu, RK_MMU_CMD_DISABLE_STALL); - ret = rk_wait_for(!rk_iommu_is_stall_active(iommu), 1); + ret = readx_poll_timeout(rk_iommu_is_stall_active, iommu, val, +!val, RK_MMU_POLL_PERIOD_US, +RK_MMU_POLL_TIMEOUT_US); if (ret) for (i = 0; i < iommu->num_mmu; i++) dev_err(iommu->dev, "Disable stall request timed out, status: %#08x\n", @@ -376,13 +373,16 @@ static int rk_iommu_disable_stall(struct rk_iommu *iommu) static int rk_iommu_enable_paging(struct rk_iommu *iommu) { int ret, i; + bool val; if (rk_iommu_is_paging_enabled(iommu))
[PATCH v7 06/14] iommu/rockchip: Fix TLB flush of secondary IOMMUs
From: Tomasz FigaDue to the bug in current code, only first IOMMU has the TLB lines flushed in rk_iommu_zap_lines. This patch fixes the inner loop to execute for all IOMMUs and properly flush the TLB. Signed-off-by: Tomasz Figa Signed-off-by: Jeffy Chen --- Changes in v7: None Changes in v6: None Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None drivers/iommu/rockchip-iommu.c | 12 +++- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index baba283ccdf9..c4131ca792e0 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -274,19 +274,21 @@ static void rk_iommu_base_command(void __iomem *base, u32 command) { writel(command, base + RK_MMU_COMMAND); } -static void rk_iommu_zap_lines(struct rk_iommu *iommu, dma_addr_t iova, +static void rk_iommu_zap_lines(struct rk_iommu *iommu, dma_addr_t iova_start, size_t size) { int i; - - dma_addr_t iova_end = iova + size; + dma_addr_t iova_end = iova_start + size; /* * TODO(djkurtz): Figure out when it is more efficient to shootdown the * entire iotlb rather than iterate over individual iovas. */ - for (i = 0; i < iommu->num_mmu; i++) - for (; iova < iova_end; iova += SPAGE_SIZE) + for (i = 0; i < iommu->num_mmu; i++) { + dma_addr_t iova; + + for (iova = iova_start; iova < iova_end; iova += SPAGE_SIZE) rk_iommu_write(iommu->bases[i], RK_MMU_ZAP_ONE_LINE, iova); + } } static bool rk_iommu_is_stall_active(struct rk_iommu *iommu) -- 2.11.0 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v7 04/14] iommu/rockchip: Fix error handling in attach
From: Tomasz FigaCurrently if the driver encounters an error while attaching device, it will leave the IOMMU in an inconsistent state. Even though it shouldn't really happen in reality, let's just add proper error path to keep things consistent. Signed-off-by: Tomasz Figa Signed-off-by: Jeffy Chen Reviewed-by: Robin Murphy --- Changes in v7: None Changes in v6: None Changes in v5: Use out labels to save the duplication between the error and success paths. Changes in v4: None Changes in v3: None Changes in v2: Move irq request to probe(in patch[0]) drivers/iommu/rockchip-iommu.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index b743d82e6fe1..f7ff3a3645ea 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -824,7 +824,7 @@ static int rk_iommu_attach_device(struct iommu_domain *domain, ret = rk_iommu_force_reset(iommu); if (ret) - return ret; + goto out_disable_stall; iommu->domain = domain; @@ -837,7 +837,7 @@ static int rk_iommu_attach_device(struct iommu_domain *domain, ret = rk_iommu_enable_paging(iommu); if (ret) - return ret; + goto out_disable_stall; spin_lock_irqsave(_domain->iommus_lock, flags); list_add_tail(>node, _domain->iommus); @@ -845,9 +845,9 @@ static int rk_iommu_attach_device(struct iommu_domain *domain, dev_dbg(dev, "Attached to iommu domain\n"); +out_disable_stall: rk_iommu_disable_stall(iommu); - - return 0; + return ret; } static void rk_iommu_detach_device(struct iommu_domain *domain, -- 2.11.0 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v7 03/14] iommu/rockchip: Request irqs in rk_iommu_probe()
Move request_irq to the end of rk_iommu_probe(). Suggested-by: Robin MurphySigned-off-by: Jeffy Chen Reviewed-by: Tomasz Figa --- Changes in v7: None Changes in v6: None Changes in v5: None Changes in v4: None Changes in v3: Loop platform_get_irq() as Robin suggested. Changes in v2: None drivers/iommu/rockchip-iommu.c | 38 +- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index c2ef3cbd4401..b743d82e6fe1 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -90,8 +90,6 @@ struct rk_iommu { struct device *dev; void __iomem **bases; int num_mmu; - int *irq; - int num_irq; bool reset_disabled; struct iommu_device iommu; struct list_head node; /* entry in rk_iommu_domain.iommus */ @@ -830,13 +828,6 @@ static int rk_iommu_attach_device(struct iommu_domain *domain, iommu->domain = domain; - for (i = 0; i < iommu->num_irq; i++) { - ret = devm_request_irq(iommu->dev, iommu->irq[i], rk_iommu_irq, - IRQF_SHARED, dev_name(dev), iommu); - if (ret) - return ret; - } - for (i = 0; i < iommu->num_mmu; i++) { rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, rk_domain->dt_dma); @@ -885,9 +876,6 @@ static void rk_iommu_detach_device(struct iommu_domain *domain, } rk_iommu_disable_stall(iommu); - for (i = 0; i < iommu->num_irq; i++) - devm_free_irq(iommu->dev, iommu->irq[i], iommu); - iommu->domain = NULL; dev_dbg(dev, "Detached from iommu domain\n"); @@ -1138,7 +1126,7 @@ static int rk_iommu_probe(struct platform_device *pdev) struct rk_iommu *iommu; struct resource *res; int num_res = pdev->num_resources; - int err, i; + int err, i, irq; iommu = devm_kzalloc(dev, sizeof(*iommu), GFP_KERNEL); if (!iommu) @@ -1165,23 +1153,15 @@ static int rk_iommu_probe(struct platform_device *pdev) if (iommu->num_mmu == 0) return PTR_ERR(iommu->bases[0]); - iommu->num_irq = platform_irq_count(pdev); - if (iommu->num_irq < 0) - return iommu->num_irq; - if (iommu->num_irq == 0) - return -ENXIO; + i = 0; + while ((irq = platform_get_irq(pdev, i++)) != -ENXIO) { + if (irq < 0) + return irq; - iommu->irq = devm_kcalloc(dev, iommu->num_irq, sizeof(*iommu->irq), - GFP_KERNEL); - if (!iommu->irq) - return -ENOMEM; - - for (i = 0; i < iommu->num_irq; i++) { - iommu->irq[i] = platform_get_irq(pdev, i); - if (iommu->irq[i] < 0) { - dev_err(dev, "Failed to get IRQ, %d\n", iommu->irq[i]); - return -ENXIO; - } + err = devm_request_irq(iommu->dev, irq, rk_iommu_irq, + IRQF_SHARED, dev_name(dev), iommu); + if (err) + return err; } iommu->reset_disabled = device_property_read_bool(dev, -- 2.11.0 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v7 01/14] iommu/rockchip: Prohibit unbind and remove
Removal of IOMMUs cannot be done reliably. This is similar to exynos iommu driver. Signed-off-by: Jeffy ChenReviewed-by: Tomasz Figa --- Changes in v7: None Changes in v6: None Changes in v5: None Changes in v4: Rewrite commit message. Changes in v3: Also remove remove() and module_exit() as Tomasz suggested. Changes in v2: None drivers/iommu/rockchip-iommu.c | 21 + 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index 9d991c2d8767..16cd8780c289 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -1197,18 +1197,6 @@ static int rk_iommu_probe(struct platform_device *pdev) return err; } -static int rk_iommu_remove(struct platform_device *pdev) -{ - struct rk_iommu *iommu = platform_get_drvdata(pdev); - - if (iommu) { - iommu_device_sysfs_remove(>iommu); - iommu_device_unregister(>iommu); - } - - return 0; -} - static const struct of_device_id rk_iommu_dt_ids[] = { { .compatible = "rockchip,iommu" }, { /* sentinel */ } @@ -1217,10 +1205,10 @@ MODULE_DEVICE_TABLE(of, rk_iommu_dt_ids); static struct platform_driver rk_iommu_driver = { .probe = rk_iommu_probe, - .remove = rk_iommu_remove, .driver = { .name = "rk_iommu", .of_match_table = rk_iommu_dt_ids, + .suppress_bind_attrs = true, }, }; @@ -1248,14 +1236,7 @@ static int __init rk_iommu_init(void) platform_driver_unregister(_iommu_domain_driver); return ret; } -static void __exit rk_iommu_exit(void) -{ - platform_driver_unregister(_iommu_driver); - platform_driver_unregister(_iommu_domain_driver); -} - subsys_initcall(rk_iommu_init); -module_exit(rk_iommu_exit); MODULE_DESCRIPTION("IOMMU API for Rockchip"); MODULE_AUTHOR("Simon Xue and Daniel Kurtz "); -- 2.11.0 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v7 00/14] iommu/rockchip: Use OF_IOMMU
This series fixes some issues in rockchip iommu driver, and add of_iommu support in it. Changes in v7: Add WARN_ON in irq isr, and modify iommu archdata comment. Use iommu_group_ref_get to avoid ref leak Changes in v6: Add clk names, and modify all iommu nodes in all existing rockchip dts Fix dt-binding as Robin suggested. Use aclk and iface clk as Rob and Robin suggested, and split binding patch. Fix dt-binding as Robin suggested. Use aclk and iface clk as Rob and Robin suggested, and split binding patch. Changes in v5: Use out labels to save the duplication between the error and success paths. Use RK_MMU_POLL_PERIOD_US instead of 100. Remove clk names. Use clk_bulk APIs. Avoid race about pm_runtime_get_if_in_use() and pm_runtime_enabled(). Changes in v4: Rewrite commit message. Changes in v3: Also remove remove() and module_exit() as Tomasz suggested. Loop platform_get_irq() as Robin suggested. Add struct rk_iommudata. Squash iommu/rockchip: Use iommu_group_get_for_dev() for add_device Only call startup() and shutdown() when iommu attached. Remove pm_mutex. Check runtime PM disabled. Check pm_runtime in rk_iommu_irq(). Remove rk_iommudata->domain. Changes in v2: Move irq request to probe(in patch[0]) Move bus_set_iommu() to rk_iommu_probe(). Jeffy Chen (10): iommu/rockchip: Prohibit unbind and remove iommu/rockchip: Fix error handling in probe iommu/rockchip: Request irqs in rk_iommu_probe() ARM: dts: rockchip: add clocks in iommu nodes dt-bindings: iommu/rockchip: Add clock property iommu/rockchip: Use IOMMU device for dma mapping operations iommu/rockchip: Use OF_IOMMU to attach devices automatically iommu/rockchip: Fix error handling in init iommu/rockchip: Add runtime PM support iommu/rockchip: Support sharing IOMMU between masters Tomasz Figa (4): iommu/rockchip: Fix error handling in attach iommu/rockchip: Use iopoll helpers to wait for hardware iommu/rockchip: Fix TLB flush of secondary IOMMUs iommu/rockchip: Control clocks needed to access the IOMMU .../devicetree/bindings/iommu/rockchip,iommu.txt | 7 + arch/arm/boot/dts/rk3036.dtsi | 2 + arch/arm/boot/dts/rk322x.dtsi | 8 + arch/arm/boot/dts/rk3288.dtsi | 12 + arch/arm64/boot/dts/rockchip/rk3328.dtsi | 10 + arch/arm64/boot/dts/rockchip/rk3368.dtsi | 10 + arch/arm64/boot/dts/rockchip/rk3399.dtsi | 14 +- drivers/iommu/rockchip-iommu.c | 608 +++-- 8 files changed, 382 insertions(+), 289 deletions(-) -- 2.11.0 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v7 02/14] iommu/rockchip: Fix error handling in probe
Add missing iommu_device_sysfs_remove in error path. Signed-off-by: Jeffy ChenReviewed-by: Tomasz Figa --- Changes in v7: None Changes in v6: None Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None drivers/iommu/rockchip-iommu.c | 6 +- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index 16cd8780c289..c2ef3cbd4401 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -1193,8 +1193,12 @@ static int rk_iommu_probe(struct platform_device *pdev) iommu_device_set_ops(>iommu, _iommu_ops); err = iommu_device_register(>iommu); + if (err) { + iommu_device_sysfs_remove(>iommu); + return err; + } - return err; + return 0; } static const struct of_device_id rk_iommu_dt_ids[] = { -- 2.11.0 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [RESEND PATCH v6 09/14] dt-bindings: iommu/rockchip: Add clock property
Hi Rob, Thanks for your reply. On 03/06/2018 10:27 AM, Rob Herring wrote: On Thu, Mar 01, 2018 at 06:18:32PM +0800, Jeffy Chen wrote: Add clock property, since we are going to control clocks in rockchip iommu driver. Signed-off-by: Jeffy Chen--- Changes in v6: None Really? There was a different number of clocks before. hmm, right, forgot to modify the change log, sorry... Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None Documentation/devicetree/bindings/iommu/rockchip,iommu.txt | 7 +++ 1 file changed, 7 insertions(+) Reviewed-by: Rob Herring ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [RESEND PATCH v6 09/14] dt-bindings: iommu/rockchip: Add clock property
On Thu, Mar 01, 2018 at 06:18:32PM +0800, Jeffy Chen wrote: > Add clock property, since we are going to control clocks in rockchip > iommu driver. > > Signed-off-by: Jeffy Chen> --- > > Changes in v6: None Really? There was a different number of clocks before. > Changes in v5: None > Changes in v4: None > Changes in v3: None > Changes in v2: None > > Documentation/devicetree/bindings/iommu/rockchip,iommu.txt | 7 +++ > 1 file changed, 7 insertions(+) Reviewed-by: Rob Herring ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [RESEND PATCH v6 13/14] iommu/rockchip: Add runtime PM support
Hi Tomasz, Thanks for your reply. On 03/05/2018 09:49 PM, Tomasz Figa wrote: > struct rk_iommudata { >+ struct device_link *link; /* runtime PM link from IOMMU to master */ Kerneldoc comment for the struct could be added instead. i saw this in the kerneldoc: * An MMU device exists alongside a busmaster device, both are in the same power domain. The MMU implements DMA address translation for the busmaster device and shall be runtime resumed and kept active whenever and as long as the busmaster device is active. The busmaster device's driver shall not bind before the MMU is bound. To achieve this, a device link with runtime PM integration is added from the busmaster device (consumer) to the MMU device (supplier). The effect with regards to runtime PM is the same as if the MMU was the parent of the master device. maybe we can use something like: device link with runtime PM integration from the master (consumer) to the IOMMU (supplier). > struct rk_iommu *iommu; > }; > >@@ -518,7 +520,12 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id) > u32 int_status; > dma_addr_t iova; > irqreturn_t ret = IRQ_NONE; >- int i; >+ int i, err, need_runtime_put; nit: need_runtime_put could be a bool. ok >+ >+ err = pm_runtime_get_if_in_use(iommu->dev); >+ if (err <= 0 && err != -EINVAL) >+ return ret; >+ need_runtime_put = err > 0; Generally something must be really wrong if we end up with err == 0 here, because the IOMMU must be powered on to signal an interrupt. The only case this could happen would be if the IRQ signal was shared with some device from another power domain. Is it possible on Rockchip SoCs? If not, perhaps we should have a WARN_ON() here for such case. the irq could be shared between master and IOMMU, but always from the same power domain i think. will add a WARN_ON() > > WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)); > >@@ -570,6 +577,9 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id) > > clk_bulk_disable(iommu->num_clocks, iommu->clocks); > >+ if (need_runtime_put) >+ pm_runtime_put(iommu->dev); >+ > return ret; > } > >@@ -611,10 +621,20 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain, > spin_lock_irqsave(_domain->iommus_lock, flags); > list_for_each(pos, _domain->iommus) { > struct rk_iommu *iommu; >+ int ret; >+ > iommu = list_entry(pos, struct rk_iommu, node); >- WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)); >- rk_iommu_zap_lines(iommu, iova, size); >- clk_bulk_disable(iommu->num_clocks, iommu->clocks); >+ >+ /* Only zap TLBs of IOMMUs that are powered on. */ >+ ret = pm_runtime_get_if_in_use(iommu->dev); >+ if (ret > 0 || ret == -EINVAL) { >+ WARN_ON(clk_bulk_enable(iommu->num_clocks, >+ iommu->clocks)); >+ rk_iommu_zap_lines(iommu, iova, size); >+ clk_bulk_disable(iommu->num_clocks, iommu->clocks); >+ } >+ if (ret > 0) >+ pm_runtime_put(iommu->dev); > } > spin_unlock_irqrestore(_domain->iommus_lock, flags); > } >@@ -817,22 +837,30 @@ static struct rk_iommu *rk_iommu_from_dev(struct device *dev) > return data ? data->iommu : NULL; > } > >-static int rk_iommu_attach_device(struct iommu_domain *domain, >- struct device *dev) >+/* Must be called with iommu powered on and attached */ >+static void rk_iommu_shutdown(struct rk_iommu *iommu) > { >- struct rk_iommu *iommu; >+ int i; >+ >+ /* Ignore error while disabling, just keep going */ >+ WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)); >+ rk_iommu_enable_stall(iommu); >+ rk_iommu_disable_paging(iommu); >+ for (i = 0; i < iommu->num_mmu; i++) { >+ rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, 0); >+ rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, 0); >+ } >+ rk_iommu_disable_stall(iommu); >+ clk_bulk_disable(iommu->num_clocks, iommu->clocks); >+} >+ >+/* Must be called with iommu powered on and attached */ >+static int rk_iommu_startup(struct rk_iommu *iommu) >+{ >+ struct iommu_domain *domain = iommu->domain; > struct rk_iommu_domain *rk_domain = to_rk_domain(domain); >- unsigned long flags; > int ret, i; > >- /* >-* Allow 'virtual devices' (e.g., drm) to attach to domain. >-* Such a device does not belong to an iommu group. >-*/ >- iommu = rk_iommu_from_dev(dev); >- if (!iommu) >- return 0; >- > ret = clk_bulk_enable(iommu->num_clocks, iommu->clocks); > if
Re: [PATCH 07/37] iommu: Add a page fault handler
On 2/12/2018 1:33 PM, Jean-Philippe Brucker wrote: > +static struct workqueue_struct *iommu_fault_queue; Is there anyway we can make this fault queue per struct device? Since this is common code, I think it needs some care. -- Sinan Kaya Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 07/37] iommu: Add a page fault handler
On 2/12/2018 1:33 PM, Jean-Philippe Brucker wrote: > +static int iommu_queue_fault(struct iommu_domain *domain, struct device *dev, > + struct iommu_fault_event *evt) > +{ > + struct iommu_fault_group *group; > + struct iommu_fault_context *fault, *next; > + > + if (!iommu_fault_queue) > + return -ENOSYS; > + > + if (!evt->last_req) { > + fault = kzalloc(sizeof(*fault), GFP_KERNEL); > + if (!fault) > + return -ENOMEM; > + > + fault->evt = *evt; > + fault->dev = dev; > + > + /* Non-last request of a group. Postpone until the last one */ > + spin_lock(_partial_faults_lock); > + list_add_tail(>head, _partial_faults); > + spin_unlock(_partial_faults_lock); > + > + return IOMMU_PAGE_RESP_HANDLED; > + } > + > + group = kzalloc(sizeof(*group), GFP_KERNEL); > + if (!group) > + return -ENOMEM; Release the requests in iommu_partial_faults here. -- Sinan Kaya Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 5/8] dt-bindings: iommu/ipmmu-vmsa: Add R-Car M3-N (R8A77965)
On Mon, Feb 26, 2018 at 06:57:13PM +0100, Jacopo Mondi wrote: > Add Renesas R-Car M3-N (R8A77965) compat string to IPMMU DT bindings > documentation. > > Signed-off-by: Jacopo Mondi> --- > Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt | 1 + > 1 file changed, 1 insertion(+) Reviewed-by: Rob Herring ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 5/6] dma-mapping: support fsl-mc bus
On 05/03/18 18:39, Christoph Hellwig wrote: On Mon, Mar 05, 2018 at 03:48:32PM +, Robin Murphy wrote: Unfortunately for us, fsl-mc is conceptually rather like PCI in that it's software-discoverable and the only thing described in DT is the bus "host", thus we need the same sort of thing as for PCI to map from the child devices back to the bus root in order to find the appropriate firmware node. Worse than PCI, though, we wouldn't even have the option of describing child devices statically in firmware at all, since it's actually one of these runtime-configurable "build your own network accelerator" hardware pools where userspace gets to create and destroy "devices" as it likes. I really hate the PCI special case just as much. Maybe we just need a dma_configure method on the bus, and move PCI as well as fsl-mc to it. Hmm, on reflection, 100% ack to that idea. It would neatly supersede bus->force_dma *and* mean that we don't have to effectively pull pci.h into everything, which I've never liked. In hindsight dma_configure() does feel like it's grown into this odd choke point where we munge everything in just for it to awkwardly unpick things again. Robin. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 5/6] dma-mapping: support fsl-mc bus
On Mon, Mar 05, 2018 at 03:48:32PM +, Robin Murphy wrote: > Unfortunately for us, fsl-mc is conceptually rather like PCI in that it's > software-discoverable and the only thing described in DT is the bus "host", > thus we need the same sort of thing as for PCI to map from the child > devices back to the bus root in order to find the appropriate firmware > node. Worse than PCI, though, we wouldn't even have the option of > describing child devices statically in firmware at all, since it's actually > one of these runtime-configurable "build your own network accelerator" > hardware pools where userspace gets to create and destroy "devices" as it > likes. I really hate the PCI special case just as much. Maybe we just need a dma_configure method on the bus, and move PCI as well as fsl-mc to it. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: Using dma-ranges with iommu to limit range of iova
Hi Robin, On 3/5/2018 5:46 PM, Robin Murphy wrote: Hi Vivek, On 05/03/18 09:06, Vivek Gautam wrote: Hi all, I have a question regarding usage of 'dma-ranges', can someone point me in the right direction? On qcom soc, few of the master devices with iommu attached to them, have limitations in using the iova address range. They can allow the iova to be only in a certain range, e.g. video codec firmware can only access iova only in a first few MBs as the video's arm core reset starts at 0x0. To do that, I earlier, had the understanding that we can modify the iommu_domain's geometry aperture. But that looks kind of a hacky way to get the domain for the device and modify the aperture. I was trying to explore if we can use the dma-ranges property. But the iommu bindings documentation doesn't really talks much about usage of dma-ranges. Can someone help me with with the answer to - can we use 'dma-ranges' to limit a device's iova address access? If yes, then how? Yes, if the device has physical restrictions on what it can address, then "dma-ranges" is the correct way to describe that. That should be pretty much orthogonal to the IOMMU binding and combine in the obvious way, e.g.: ... soc { Â Â Â #address-cells = <1>; Â Â Â #size-cells = <1>; Â Â Â compatible = "simple-bus"; Â Â Â ranges; Â Â Â ... Â Â Â iommu@f000 { Â Â Â compatible = "iommu"; Â Â Â reg = <0xf000 0x1000>; Â Â Â #iommu-cells = <0>; Â Â Â }; Â Â Â ... Â Â Â subsystem { Usually, the multimedia devices are just the device nodes without any subsystem. Can dma-ranges, and iommus exist together for the device? #address-cells = <1>; Â Â Â #size-cells = <1>; Â Â Â compatible = "simple-bus"; Â Â Â ranges; Â Â Â /* Devices can only drive address bits 0:23 */ Â Â Â dma-ranges = <0 0 0x100>; Â Â Â device { Â Â Â iommus = <>; Â Â Â }; Â Â Â }; }; ... In terms of Linux, for the straightforward platform device case of_dma_configure() initialises the subsystem devices' DMA masks based on the size covered by "dma-ranges", and the DMA API code respects the device's DMA mask when allocating IOVAs. The only problem is the bit in the middle where the device driver's dma_set_mask() call can just trash of_dma_configure()'s initial mask, because there's no way to differentiate an explicitly-specified mask from a default one. But the drivers should ideally check for any existing dma_mask set for the device before calling dma_set_mask_and_coherent(). I see few of the drivers do check that, so we don't overwrite the dma mask. It's also even uglier for PCI devices since the existing "pass the host bridge's node as the device's" bodge happens to work for the "dma-coherent" property but is a bit broken in general and doesn't work at all for "dma-ranges". Fixing all of this (not to mention the DT/ACPI interaction aspect) has been hovering around #3 on my to-do list for the past couple of years now, but things keep sneaking in above it :( Anything that I can take a look at, and add? regards Vivek Robin. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 12/13] swiotlb: remove swiotlb_set_mem_attributes
Now that set_memory_decrypted is always available we can just call it directly. Signed-off-by: Christoph Hellwig--- arch/x86/include/asm/mem_encrypt.h | 2 -- arch/x86/mm/mem_encrypt.c | 9 - lib/swiotlb.c | 12 ++-- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/arch/x86/include/asm/mem_encrypt.h b/arch/x86/include/asm/mem_encrypt.h index 22c5f3e6f820..9da0b63c8fc7 100644 --- a/arch/x86/include/asm/mem_encrypt.h +++ b/arch/x86/include/asm/mem_encrypt.h @@ -48,8 +48,6 @@ int __init early_set_memory_encrypted(unsigned long vaddr, unsigned long size); /* Architecture __weak replacement functions */ void __init mem_encrypt_init(void); -void swiotlb_set_mem_attributes(void *vaddr, unsigned long size); - bool sme_active(void); bool sev_active(void); diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c index 8bfc735bbdd7..65f45e0ef496 100644 --- a/arch/x86/mm/mem_encrypt.c +++ b/arch/x86/mm/mem_encrypt.c @@ -379,15 +379,6 @@ void __init mem_encrypt_init(void) : "Secure Memory Encryption (SME)"); } -void swiotlb_set_mem_attributes(void *vaddr, unsigned long size) -{ - WARN(PAGE_ALIGN(size) != size, -"size is not page-aligned (%#lx)\n", size); - - /* Make the SWIOTLB buffer area decrypted */ - set_memory_decrypted((unsigned long)vaddr, size >> PAGE_SHIFT); -} - struct sme_populate_pgd_data { void*pgtable_area; pgd_t *pgd; diff --git a/lib/swiotlb.c b/lib/swiotlb.c index ca8eeaead925..8b06b4485e65 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -156,8 +157,6 @@ unsigned long swiotlb_size_or_default(void) return size ? size : (IO_TLB_DEFAULT_SIZE); } -void __weak swiotlb_set_mem_attributes(void *vaddr, unsigned long size) { } - /* Note that this doesn't work with highmem page */ static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev, volatile void *address) @@ -202,12 +201,12 @@ void __init swiotlb_update_mem_attributes(void) vaddr = phys_to_virt(io_tlb_start); bytes = PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT); - swiotlb_set_mem_attributes(vaddr, bytes); + set_memory_decrypted((unsigned long)vaddr, bytes >> PAGE_SHIFT); memset(vaddr, 0, bytes); vaddr = phys_to_virt(io_tlb_overflow_buffer); bytes = PAGE_ALIGN(io_tlb_overflow); - swiotlb_set_mem_attributes(vaddr, bytes); + set_memory_decrypted((unsigned long)vaddr, bytes >> PAGE_SHIFT); memset(vaddr, 0, bytes); } @@ -348,7 +347,7 @@ swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs) io_tlb_start = virt_to_phys(tlb); io_tlb_end = io_tlb_start + bytes; - swiotlb_set_mem_attributes(tlb, bytes); + set_memory_decrypted((unsigned long)tlb, bytes >> PAGE_SHIFT); memset(tlb, 0, bytes); /* @@ -359,7 +358,8 @@ swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs) if (!v_overflow_buffer) goto cleanup2; - swiotlb_set_mem_attributes(v_overflow_buffer, io_tlb_overflow); + set_memory_decrypted((unsigned long)v_overflow_buffer, + io_tlb_overflow >> PAGE_SHIFT); memset(v_overflow_buffer, 0, io_tlb_overflow); io_tlb_overflow_buffer = virt_to_phys(v_overflow_buffer); -- 2.14.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 13/13] swiotlb: remove swiotlb_{alloc,free}_coherent
Unused now that everyone uses swiotlb_{alloc,free}. Signed-off-by: Christoph Hellwig--- include/linux/swiotlb.h | 8 lib/swiotlb.c | 38 -- 2 files changed, 46 deletions(-) diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index 5b1f2a00491c..965be92c33b5 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -72,14 +72,6 @@ void *swiotlb_alloc(struct device *hwdev, size_t size, dma_addr_t *dma_handle, void swiotlb_free(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_addr, unsigned long attrs); -extern void -*swiotlb_alloc_coherent(struct device *hwdev, size_t size, - dma_addr_t *dma_handle, gfp_t flags); - -extern void -swiotlb_free_coherent(struct device *hwdev, size_t size, - void *vaddr, dma_addr_t dma_handle); - extern dma_addr_t swiotlb_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir, diff --git a/lib/swiotlb.c b/lib/swiotlb.c index 8b06b4485e65..15954b86f09e 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -157,13 +157,6 @@ unsigned long swiotlb_size_or_default(void) return size ? size : (IO_TLB_DEFAULT_SIZE); } -/* Note that this doesn't work with highmem page */ -static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev, - volatile void *address) -{ - return phys_to_dma(hwdev, virt_to_phys(address)); -} - static bool no_iotlb_memory; void swiotlb_print_info(void) @@ -752,28 +745,6 @@ swiotlb_alloc_buffer(struct device *dev, size_t size, dma_addr_t *dma_handle, return NULL; } -void * -swiotlb_alloc_coherent(struct device *hwdev, size_t size, - dma_addr_t *dma_handle, gfp_t flags) -{ - int order = get_order(size); - unsigned long attrs = (flags & __GFP_NOWARN) ? DMA_ATTR_NO_WARN : 0; - void *ret; - - ret = (void *)__get_free_pages(flags, order); - if (ret) { - *dma_handle = swiotlb_virt_to_bus(hwdev, ret); - if (dma_coherent_ok(hwdev, *dma_handle, size)) { - memset(ret, 0, size); - return ret; - } - free_pages((unsigned long)ret, order); - } - - return swiotlb_alloc_buffer(hwdev, size, dma_handle, attrs); -} -EXPORT_SYMBOL(swiotlb_alloc_coherent); - static bool swiotlb_free_buffer(struct device *dev, size_t size, dma_addr_t dma_addr) { @@ -793,15 +764,6 @@ static bool swiotlb_free_buffer(struct device *dev, size_t size, return true; } -void -swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr, - dma_addr_t dev_addr) -{ - if (!swiotlb_free_buffer(hwdev, size, dev_addr)) - free_pages((unsigned long)vaddr, get_order(size)); -} -EXPORT_SYMBOL(swiotlb_free_coherent); - static void swiotlb_full(struct device *dev, size_t size, enum dma_data_direction dir, int do_panic) -- 2.14.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 11/13] dma-direct: handle the memory encryption bit in common code
Give the basic phys_to_dma and dma_to_phys helpers a __-prefix and add the memory encryption mask to the non-prefixed versions. Use the __-prefixed versions directly instead of clearing the mask again in various places. With that in place the generic dma-direct routines can be used to allocate non-encrypted bounce buffers, and the x86 SEV case can use the generic swiotlb ops. Signed-off-by: Christoph Hellwig--- arch/arm/include/asm/dma-direct.h | 4 +- arch/mips/cavium-octeon/dma-octeon.c | 10 +-- .../include/asm/mach-cavium-octeon/dma-coherence.h | 4 +- .../include/asm/mach-loongson64/dma-coherence.h| 10 +-- arch/mips/loongson64/common/dma-swiotlb.c | 4 +- arch/powerpc/include/asm/dma-direct.h | 4 +- arch/x86/Kconfig | 2 +- arch/x86/include/asm/dma-direct.h | 25 +--- arch/x86/mm/mem_encrypt.c | 73 +- arch/x86/pci/sta2x11-fixup.c | 6 +- include/linux/dma-direct.h | 21 ++- lib/dma-direct.c | 21 +-- lib/swiotlb.c | 25 +++- 13 files changed, 70 insertions(+), 139 deletions(-) diff --git a/arch/arm/include/asm/dma-direct.h b/arch/arm/include/asm/dma-direct.h index 5b0a8a421894..b67e5fc1fe43 100644 --- a/arch/arm/include/asm/dma-direct.h +++ b/arch/arm/include/asm/dma-direct.h @@ -2,13 +2,13 @@ #ifndef ASM_ARM_DMA_DIRECT_H #define ASM_ARM_DMA_DIRECT_H 1 -static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) +static inline dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr) { unsigned int offset = paddr & ~PAGE_MASK; return pfn_to_dma(dev, __phys_to_pfn(paddr)) + offset; } -static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr) +static inline phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t dev_addr) { unsigned int offset = dev_addr & ~PAGE_MASK; return __pfn_to_phys(dma_to_pfn(dev, dev_addr)) + offset; diff --git a/arch/mips/cavium-octeon/dma-octeon.c b/arch/mips/cavium-octeon/dma-octeon.c index c7bb8a407041..7b335ab21697 100644 --- a/arch/mips/cavium-octeon/dma-octeon.c +++ b/arch/mips/cavium-octeon/dma-octeon.c @@ -10,7 +10,7 @@ * IP32 changes by Ilya. * Copyright (C) 2010 Cavium Networks, Inc. */ -#include +#include #include #include #include @@ -182,7 +182,7 @@ struct octeon_dma_map_ops { phys_addr_t (*dma_to_phys)(struct device *dev, dma_addr_t daddr); }; -dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) +dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr) { struct octeon_dma_map_ops *ops = container_of(get_dma_ops(dev), struct octeon_dma_map_ops, @@ -190,9 +190,9 @@ dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) return ops->phys_to_dma(dev, paddr); } -EXPORT_SYMBOL(phys_to_dma); +EXPORT_SYMBOL(__phys_to_dma); -phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) +phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr) { struct octeon_dma_map_ops *ops = container_of(get_dma_ops(dev), struct octeon_dma_map_ops, @@ -200,7 +200,7 @@ phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) return ops->dma_to_phys(dev, daddr); } -EXPORT_SYMBOL(dma_to_phys); +EXPORT_SYMBOL(__dma_to_phys); static struct octeon_dma_map_ops octeon_linear_dma_map_ops = { .dma_map_ops = { diff --git a/arch/mips/include/asm/mach-cavium-octeon/dma-coherence.h b/arch/mips/include/asm/mach-cavium-octeon/dma-coherence.h index 138edf6b5b48..6eb1ee548b11 100644 --- a/arch/mips/include/asm/mach-cavium-octeon/dma-coherence.h +++ b/arch/mips/include/asm/mach-cavium-octeon/dma-coherence.h @@ -69,8 +69,8 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) return addr + size - 1 <= *dev->dma_mask; } -dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr); -phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr); +dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr); +phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr); struct dma_map_ops; extern const struct dma_map_ops *octeon_pci_dma_map_ops; diff --git a/arch/mips/include/asm/mach-loongson64/dma-coherence.h b/arch/mips/include/asm/mach-loongson64/dma-coherence.h index b1b575f5c6c1..64fc44dec0a8 100644 --- a/arch/mips/include/asm/mach-loongson64/dma-coherence.h +++ b/arch/mips/include/asm/mach-loongson64/dma-coherence.h @@ -25,13 +25,13 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) return addr + size - 1 <= *dev->dma_mask; } -extern dma_addr_t phys_to_dma(struct device *dev, phys_addr_t
use generic dma-direct and swiotlb code for x86
Hi all, this series switches the x86 code the the dma-direct implementation for direct (non-iommu) dma and the generic swiotlb ops. This includes getting rid of the special ops for the AMD memory encryption case and the STA2x11 SOC. The generic implementations are based on the x86 code, so they provide the same functionality. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 10/13] set_memory.h: provide set_memory_{en,de}crypted stubs
Signed-off-by: Christoph Hellwig--- include/linux/set_memory.h | 12 1 file changed, 12 insertions(+) diff --git a/include/linux/set_memory.h b/include/linux/set_memory.h index e5140648f638..da5178216da5 100644 --- a/include/linux/set_memory.h +++ b/include/linux/set_memory.h @@ -17,4 +17,16 @@ static inline int set_memory_x(unsigned long addr, int numpages) { return 0; } static inline int set_memory_nx(unsigned long addr, int numpages) { return 0; } #endif +#ifndef CONFIG_ARCH_HAS_MEM_ENCRYPT +static inline int set_memory_encrypted(unsigned long addr, int numpages) +{ + return 0; +} + +static inline int set_memory_decrypted(unsigned long addr, int numpages) +{ + return 0; +} +#endif /* CONFIG_ARCH_HAS_MEM_ENCRYPT */ + #endif /* _LINUX_SET_MEMORY_H_ */ -- 2.14.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 07/13] iommu/amd_iommu: use dma_direct_{alloc,free}
This cleans up the code a lot by removing duplicate logic. Signed-off-by: Christoph Hellwig--- drivers/iommu/Kconfig | 1 + drivers/iommu/amd_iommu.c | 68 +++ 2 files changed, 22 insertions(+), 47 deletions(-) diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index f3a21343e636..dc7c1914645d 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -107,6 +107,7 @@ config IOMMU_PGTABLES_L2 # AMD IOMMU support config AMD_IOMMU bool "AMD IOMMU support" + select DMA_DIRECT_OPS select SWIOTLB select PCI_MSI select PCI_ATS diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 0bf19423b588..83819d0cbf90 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -2600,51 +2600,32 @@ static void *alloc_coherent(struct device *dev, size_t size, unsigned long attrs) { u64 dma_mask = dev->coherent_dma_mask; - struct protection_domain *domain; - struct dma_ops_domain *dma_dom; - struct page *page; - - domain = get_domain(dev); - if (PTR_ERR(domain) == -EINVAL) { - page = alloc_pages(flag, get_order(size)); - *dma_addr = page_to_phys(page); - return page_address(page); - } else if (IS_ERR(domain)) - return NULL; + struct protection_domain *domain = get_domain(dev); + bool is_direct = false; + void *virt_addr; - dma_dom = to_dma_ops_domain(domain); - size = PAGE_ALIGN(size); - dma_mask = dev->coherent_dma_mask; - flag &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); - flag |= __GFP_ZERO; - - page = alloc_pages(flag | __GFP_NOWARN, get_order(size)); - if (!page) { - if (!gfpflags_allow_blocking(flag)) - return NULL; - - page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT, -get_order(size), flag); - if (!page) + if (IS_ERR(domain)) { + if (PTR_ERR(domain) != -EINVAL) return NULL; + is_direct = true; } + virt_addr = dma_direct_alloc(dev, size, dma_addr, flag, attrs); + if (!virt_addr || is_direct) + return virt_addr; + if (!dma_mask) dma_mask = *dev->dma_mask; - *dma_addr = __map_single(dev, dma_dom, page_to_phys(page), -size, DMA_BIDIRECTIONAL, dma_mask); - + *dma_addr = __map_single(dev, to_dma_ops_domain(domain), + virt_to_phys(virt_addr), PAGE_ALIGN(size), + DMA_BIDIRECTIONAL, dma_mask); if (*dma_addr == AMD_IOMMU_MAPPING_ERROR) goto out_free; - - return page_address(page); + return virt_addr; out_free: - - if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT)) - __free_pages(page, get_order(size)); - + dma_direct_free(dev, size, virt_addr, *dma_addr, attrs); return NULL; } @@ -2655,24 +2636,17 @@ static void free_coherent(struct device *dev, size_t size, void *virt_addr, dma_addr_t dma_addr, unsigned long attrs) { - struct protection_domain *domain; - struct dma_ops_domain *dma_dom; - struct page *page; + struct protection_domain *domain = get_domain(dev); - page = virt_to_page(virt_addr); size = PAGE_ALIGN(size); - domain = get_domain(dev); - if (IS_ERR(domain)) - goto free_mem; + if (!IS_ERR(domain)) { + struct dma_ops_domain *dma_dom = to_dma_ops_domain(domain); - dma_dom = to_dma_ops_domain(domain); - - __unmap_single(dma_dom, dma_addr, size, DMA_BIDIRECTIONAL); + __unmap_single(dma_dom, dma_addr, size, DMA_BIDIRECTIONAL); + } -free_mem: - if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT)) - __free_pages(page, get_order(size)); + dma_direct_free(dev, size, virt_addr, dma_addr, attrs); } /* -- 2.14.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 02/13] x86: remove dma_alloc_coherent_mask
These days all devices (including the ISA fallback device) have a coherent DMA mask set, so remove the workaround. Signed-off-by: Christoph Hellwig--- arch/x86/include/asm/dma-mapping.h | 18 ++ arch/x86/kernel/pci-dma.c | 10 -- arch/x86/mm/mem_encrypt.c | 4 +--- drivers/xen/swiotlb-xen.c | 16 +--- 4 files changed, 8 insertions(+), 40 deletions(-) diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index 6277c83c0eb1..545bf3721bc0 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -44,26 +44,12 @@ extern void dma_generic_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_addr, unsigned long attrs); -static inline unsigned long dma_alloc_coherent_mask(struct device *dev, - gfp_t gfp) -{ - unsigned long dma_mask = 0; - - dma_mask = dev->coherent_dma_mask; - if (!dma_mask) - dma_mask = (gfp & GFP_DMA) ? DMA_BIT_MASK(24) : DMA_BIT_MASK(32); - - return dma_mask; -} - static inline gfp_t dma_alloc_coherent_gfp_flags(struct device *dev, gfp_t gfp) { - unsigned long dma_mask = dma_alloc_coherent_mask(dev, gfp); - - if (dma_mask <= DMA_BIT_MASK(24)) + if (dev->coherent_dma_mask <= DMA_BIT_MASK(24)) gfp |= GFP_DMA; #ifdef CONFIG_X86_64 - if (dma_mask <= DMA_BIT_MASK(32) && !(gfp & GFP_DMA)) + if (dev->coherent_dma_mask <= DMA_BIT_MASK(32) && !(gfp & GFP_DMA)) gfp |= GFP_DMA32; #endif return gfp; diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index df7ab02f959f..b59820872ec7 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -80,13 +80,10 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr, gfp_t flag, unsigned long attrs) { - unsigned long dma_mask; struct page *page; unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; dma_addr_t addr; - dma_mask = dma_alloc_coherent_mask(dev, flag); - again: page = NULL; /* CMA can be used only in the context which permits sleeping */ @@ -95,7 +92,7 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size, flag); if (page) { addr = phys_to_dma(dev, page_to_phys(page)); - if (addr + size > dma_mask) { + if (addr + size > dev->coherent_dma_mask) { dma_release_from_contiguous(dev, page, count); page = NULL; } @@ -108,10 +105,11 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size, return NULL; addr = phys_to_dma(dev, page_to_phys(page)); - if (addr + size > dma_mask) { + if (addr + size > dev->coherent_dma_mask) { __free_pages(page, get_order(size)); - if (dma_mask < DMA_BIT_MASK(32) && !(flag & GFP_DMA)) { + if (dev->coherent_dma_mask < DMA_BIT_MASK(32) && + !(flag & GFP_DMA)) { flag = (flag & ~GFP_DMA32) | GFP_DMA; goto again; } diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c index 1a53071e2e17..75dc8b525c12 100644 --- a/arch/x86/mm/mem_encrypt.c +++ b/arch/x86/mm/mem_encrypt.c @@ -203,12 +203,10 @@ void __init sme_early_init(void) static void *sev_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs) { - unsigned long dma_mask; unsigned int order; struct page *page; void *vaddr = NULL; - dma_mask = dma_alloc_coherent_mask(dev, gfp); order = get_order(size); /* @@ -226,7 +224,7 @@ static void *sev_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, * mask with it already cleared. */ addr = __sme_clr(phys_to_dma(dev, page_to_phys(page))); - if ((addr + size) > dma_mask) { + if ((addr + size) > dev->coherent_dma_mask) { __free_pages(page, get_order(size)); } else { vaddr = page_address(page); diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 5bb72d3f8337..e1c60899fdbc 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -53,20 +53,6 @@ * API. */ -#ifndef CONFIG_X86 -static unsigned long dma_alloc_coherent_mask(struct device *dev, - gfp_t gfp) -{ - unsigned long dma_mask =
[PATCH 08/13] iommu/intel-iommu: cleanup intel_{alloc,free}_coherent
Use the dma_direct_* helpers and cleanup the code flow. Signed-off-by: Christoph Hellwig--- drivers/iommu/Kconfig | 1 + drivers/iommu/intel-iommu.c | 62 - 2 files changed, 17 insertions(+), 46 deletions(-) diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index dc7c1914645d..df171cb85822 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -143,6 +143,7 @@ config DMAR_TABLE config INTEL_IOMMU bool "Support for Intel IOMMU using DMA Remapping Devices" depends on PCI_MSI && ACPI && (X86 || IA64_GENERIC) + select DMA_DIRECT_OPS select IOMMU_API select IOMMU_IOVA select DMAR_TABLE diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index fd899b2a12bb..24d1b1b42013 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -3708,61 +3709,30 @@ static void *intel_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flags, unsigned long attrs) { - struct page *page = NULL; - int order; - - size = PAGE_ALIGN(size); - order = get_order(size); - - if (!iommu_no_mapping(dev)) - flags &= ~(GFP_DMA | GFP_DMA32); - else if (dev->coherent_dma_mask < dma_get_required_mask(dev)) { - if (dev->coherent_dma_mask < DMA_BIT_MASK(32)) - flags |= GFP_DMA; - else - flags |= GFP_DMA32; - } + void *vaddr; - if (gfpflags_allow_blocking(flags)) { - unsigned int count = size >> PAGE_SHIFT; + vaddr = dma_direct_alloc(dev, size, dma_handle, flags, attrs); + if (iommu_no_mapping(dev) || !vaddr) + return vaddr; - page = dma_alloc_from_contiguous(dev, count, order, flags); - if (page && iommu_no_mapping(dev) && - page_to_phys(page) + size > dev->coherent_dma_mask) { - dma_release_from_contiguous(dev, page, count); - page = NULL; - } - } - - if (!page) - page = alloc_pages(flags, order); - if (!page) - return NULL; - memset(page_address(page), 0, size); - - *dma_handle = __intel_map_single(dev, page_to_phys(page), size, -DMA_BIDIRECTIONAL, -dev->coherent_dma_mask); - if (*dma_handle) - return page_address(page); - if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT)) - __free_pages(page, order); + *dma_handle = __intel_map_single(dev, virt_to_phys(vaddr), + PAGE_ALIGN(size), DMA_BIDIRECTIONAL, + dev->coherent_dma_mask); + if (!*dma_handle) + goto out_free_pages; + return vaddr; +out_free_pages: + dma_direct_free(dev, size, vaddr, *dma_handle, attrs); return NULL; } static void intel_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle, unsigned long attrs) { - int order; - struct page *page = virt_to_page(vaddr); - - size = PAGE_ALIGN(size); - order = get_order(size); - - intel_unmap(dev, dma_handle, size); - if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT)) - __free_pages(page, order); + if (!iommu_no_mapping(dev)) + intel_unmap(dev, dma_handle, PAGE_ALIGN(size)); + dma_direct_free(dev, size, vaddr, dma_handle, attrs); } static void intel_unmap_sg(struct device *dev, struct scatterlist *sglist, -- 2.14.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 09/13] x86: remove dma_alloc_coherent_gfp_flags
All dma_ops implementations used on x86 now take care of setting their own required GFP_ masks for the allocation. And given that the common code now clears harmful flags itself that means we can stop the flags in all the iommu implementations as well. Signed-off-by: Christoph Hellwig--- arch/x86/include/asm/dma-mapping.h | 11 --- arch/x86/kernel/pci-calgary_64.c | 2 -- arch/x86/kernel/pci-dma.c | 2 -- arch/x86/mm/mem_encrypt.c | 7 --- 4 files changed, 22 deletions(-) diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index df9816b385eb..89ce4bfd241f 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -36,15 +36,4 @@ int arch_dma_supported(struct device *dev, u64 mask); bool arch_dma_alloc_attrs(struct device **dev, gfp_t *gfp); #define arch_dma_alloc_attrs arch_dma_alloc_attrs -static inline gfp_t dma_alloc_coherent_gfp_flags(struct device *dev, gfp_t gfp) -{ - if (dev->coherent_dma_mask <= DMA_BIT_MASK(24)) - gfp |= GFP_DMA; -#ifdef CONFIG_X86_64 - if (dev->coherent_dma_mask <= DMA_BIT_MASK(32) && !(gfp & GFP_DMA)) - gfp |= GFP_DMA32; -#endif - return gfp; -} - #endif diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index 5647853053bd..bbfc8b1e9104 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c @@ -446,8 +446,6 @@ static void* calgary_alloc_coherent(struct device *dev, size_t size, npages = size >> PAGE_SHIFT; order = get_order(size); - flag &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); - /* alloc enough pages (and possibly more) */ ret = (void *)__get_free_pages(flag, order); if (!ret) diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index db0b88ea8d1b..14437116ffea 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -82,8 +82,6 @@ bool arch_dma_alloc_attrs(struct device **dev, gfp_t *gfp) if (!*dev) *dev = _dma_fallback_dev; - *gfp = dma_alloc_coherent_gfp_flags(*dev, *gfp); - if (!is_device_dma_capable(*dev)) return false; return true; diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c index 75dc8b525c12..66beedc8fe3d 100644 --- a/arch/x86/mm/mem_encrypt.c +++ b/arch/x86/mm/mem_encrypt.c @@ -208,13 +208,6 @@ static void *sev_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, void *vaddr = NULL; order = get_order(size); - - /* -* Memory will be memset to zero after marking decrypted, so don't -* bother clearing it before. -*/ - gfp &= ~__GFP_ZERO; - page = alloc_pages_node(dev_to_node(dev), gfp, order); if (page) { dma_addr_t addr; -- 2.14.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 01/13] x86: remove X86_PPRO_FENCE
There were only a few Pentium Pro multiprocessors systems where this errata applied. They are more than 20 years old now, and we've slowly dropped places where put the workarounds in and discouraged anyone from enabling the workaround. Get rid of it for good. Signed-off-by: Christoph Hellwig--- arch/x86/Kconfig.cpu| 13 - arch/x86/entry/vdso/vdso32/vclock_gettime.c | 2 -- arch/x86/include/asm/barrier.h | 30 - arch/x86/include/asm/io.h | 15 --- arch/x86/kernel/pci-nommu.c | 19 -- arch/x86/um/asm/barrier.h | 4 6 files changed, 83 deletions(-) diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index 8b8d2297d486..638411f22267 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -315,19 +315,6 @@ config X86_L1_CACHE_SHIFT default "4" if MELAN || M486 || MGEODEGX1 default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX -config X86_PPRO_FENCE - bool "PentiumPro memory ordering errata workaround" - depends on M686 || M586MMX || M586TSC || M586 || M486 || MGEODEGX1 - ---help--- - Old PentiumPro multiprocessor systems had errata that could cause - memory operations to violate the x86 ordering standard in rare cases. - Enabling this option will attempt to work around some (but not all) - occurrences of this problem, at the cost of much heavier spinlock and - memory barrier operations. - - If unsure, say n here. Even distro kernels should think twice before - enabling this: there are few systems, and an unlikely bug. - config X86_F00F_BUG def_bool y depends on M586MMX || M586TSC || M586 || M486 diff --git a/arch/x86/entry/vdso/vdso32/vclock_gettime.c b/arch/x86/entry/vdso/vdso32/vclock_gettime.c index 7780bbfb06ef..9242b28418d5 100644 --- a/arch/x86/entry/vdso/vdso32/vclock_gettime.c +++ b/arch/x86/entry/vdso/vdso32/vclock_gettime.c @@ -5,8 +5,6 @@ #undef CONFIG_OPTIMIZE_INLINING #endif -#undef CONFIG_X86_PPRO_FENCE - #ifdef CONFIG_X86_64 /* diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h index e1259f043ae9..042b5e892ed1 100644 --- a/arch/x86/include/asm/barrier.h +++ b/arch/x86/include/asm/barrier.h @@ -52,11 +52,7 @@ static inline unsigned long array_index_mask_nospec(unsigned long index, #define barrier_nospec() alternative_2("", "mfence", X86_FEATURE_MFENCE_RDTSC, \ "lfence", X86_FEATURE_LFENCE_RDTSC) -#ifdef CONFIG_X86_PPRO_FENCE -#define dma_rmb() rmb() -#else #define dma_rmb() barrier() -#endif #define dma_wmb() barrier() #ifdef CONFIG_X86_32 @@ -68,30 +64,6 @@ static inline unsigned long array_index_mask_nospec(unsigned long index, #define __smp_wmb()barrier() #define __smp_store_mb(var, value) do { (void)xchg(, value); } while (0) -#if defined(CONFIG_X86_PPRO_FENCE) - -/* - * For this option x86 doesn't have a strong TSO memory - * model and we should fall back to full barriers. - */ - -#define __smp_store_release(p, v) \ -do { \ - compiletime_assert_atomic_type(*p); \ - __smp_mb(); \ - WRITE_ONCE(*p, v); \ -} while (0) - -#define __smp_load_acquire(p) \ -({ \ - typeof(*p) ___p1 = READ_ONCE(*p); \ - compiletime_assert_atomic_type(*p); \ - __smp_mb(); \ - ___p1; \ -}) - -#else /* regular x86 TSO memory ordering */ - #define __smp_store_release(p, v) \ do { \ compiletime_assert_atomic_type(*p); \ @@ -107,8 +79,6 @@ do { \ ___p1; \ }) -#endif - /* Atomic operations are already serializing on x86 */ #define __smp_mb__before_atomic() barrier() #define __smp_mb__after_atomic() barrier() diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h index 95e948627fd0..f6e5b9375d8c 100644 --- a/arch/x86/include/asm/io.h +++ b/arch/x86/include/asm/io.h @@ -232,21 +232,6 @@ extern void set_iounmap_nonlazy(void); */ #define __ISA_IO_base ((char __iomem
[PATCH 03/13] x86: use dma-direct
The generic dma-direct implementation is now functionally equivalent to the x86 nommu dma_map implementation, so switch over to using it. Note that the various iommu drivers are switched from x86_dma_supported to dma_direct_supported to provide identical functionality, although the checks looks fairly questionable for at least some of them. Signed-off-by: Christoph Hellwig--- arch/x86/Kconfig | 1 + arch/x86/include/asm/dma-mapping.h | 8 - arch/x86/include/asm/iommu.h | 3 -- arch/x86/kernel/Makefile | 2 +- arch/x86/kernel/amd_gart_64.c | 7 ++-- arch/x86/kernel/pci-calgary_64.c | 3 +- arch/x86/kernel/pci-dma.c | 66 +- arch/x86/kernel/pci-swiotlb.c | 5 ++- arch/x86/pci/sta2x11-fixup.c | 2 +- drivers/iommu/amd_iommu.c | 7 ++-- drivers/iommu/intel-iommu.c| 3 +- 11 files changed, 17 insertions(+), 90 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index c1236b187824..7272bb3768d7 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -83,6 +83,7 @@ config X86 select CLOCKSOURCE_VALIDATE_LAST_CYCLE select CLOCKSOURCE_WATCHDOG select DCACHE_WORD_ACCESS + select DMA_DIRECT_OPS select EDAC_ATOMIC_SCRUB select EDAC_SUPPORT select GENERIC_CLOCKEVENTS diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index 545bf3721bc0..df9816b385eb 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -36,14 +36,6 @@ int arch_dma_supported(struct device *dev, u64 mask); bool arch_dma_alloc_attrs(struct device **dev, gfp_t *gfp); #define arch_dma_alloc_attrs arch_dma_alloc_attrs -extern void *dma_generic_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_addr, gfp_t flag, - unsigned long attrs); - -extern void dma_generic_free_coherent(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma_addr, - unsigned long attrs); - static inline gfp_t dma_alloc_coherent_gfp_flags(struct device *dev, gfp_t gfp) { if (dev->coherent_dma_mask <= DMA_BIT_MASK(24)) diff --git a/arch/x86/include/asm/iommu.h b/arch/x86/include/asm/iommu.h index 1e5d5d92eb40..baedab8ac538 100644 --- a/arch/x86/include/asm/iommu.h +++ b/arch/x86/include/asm/iommu.h @@ -2,13 +2,10 @@ #ifndef _ASM_X86_IOMMU_H #define _ASM_X86_IOMMU_H -extern const struct dma_map_ops nommu_dma_ops; extern int force_iommu, no_iommu; extern int iommu_detected; extern int iommu_pass_through; -int x86_dma_supported(struct device *dev, u64 mask); - /* 10 seconds */ #define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 29786c87e864..2e8c8a09ecab 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -57,7 +57,7 @@ obj-$(CONFIG_X86_ESPFIX64)+= espfix_64.o obj-$(CONFIG_SYSFS)+= ksysfs.o obj-y += bootflag.o e820.o obj-y += pci-dma.o quirks.o topology.o kdebugfs.o -obj-y += alternative.o i8253.o pci-nommu.o hw_breakpoint.o +obj-y += alternative.o i8253.o hw_breakpoint.o obj-y += tsc.o tsc_msr.o io_delay.o rtc.o obj-y += pci-iommu_table.o obj-y += resource.o diff --git a/arch/x86/kernel/amd_gart_64.c b/arch/x86/kernel/amd_gart_64.c index ecd486cb06ab..52e3abcf3e70 100644 --- a/arch/x86/kernel/amd_gart_64.c +++ b/arch/x86/kernel/amd_gart_64.c @@ -501,8 +501,7 @@ gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr, } __free_pages(page, get_order(size)); } else - return dma_generic_alloc_coherent(dev, size, dma_addr, flag, - attrs); + return dma_direct_alloc(dev, size, dma_addr, flag, attrs); return NULL; } @@ -513,7 +512,7 @@ gart_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_addr, unsigned long attrs) { gart_unmap_page(dev, dma_addr, size, DMA_BIDIRECTIONAL, 0); - dma_generic_free_coherent(dev, size, vaddr, dma_addr, attrs); + dma_direct_free(dev, size, vaddr, dma_addr, attrs); } static int gart_mapping_error(struct device *dev, dma_addr_t dma_addr) @@ -705,7 +704,7 @@ static const struct dma_map_ops gart_dma_ops = { .alloc = gart_alloc_coherent, .free = gart_free_coherent, .mapping_error = gart_mapping_error, - .dma_supported = x86_dma_supported, + .dma_supported = dma_direct_supported, }; static void gart_iommu_shutdown(void) diff
[PATCH 06/13] x86/amd_gart: use dma_direct_{alloc,free}
This gains support for CMA allocations for the force_iommu case, and cleans up the code a bit. Signed-off-by: Christoph Hellwig--- arch/x86/kernel/amd_gart_64.c | 36 ++-- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/arch/x86/kernel/amd_gart_64.c b/arch/x86/kernel/amd_gart_64.c index 79ac6cbb..f299d8a479bb 100644 --- a/arch/x86/kernel/amd_gart_64.c +++ b/arch/x86/kernel/amd_gart_64.c @@ -480,29 +480,21 @@ static void * gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr, gfp_t flag, unsigned long attrs) { - dma_addr_t paddr; - unsigned long align_mask; - struct page *page; - - if (force_iommu && dev->coherent_dma_mask > DMA_BIT_MASK(24)) { - flag &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); - page = alloc_pages(flag | __GFP_ZERO, get_order(size)); - if (!page) - return NULL; - - align_mask = (1UL << get_order(size)) - 1; - paddr = dma_map_area(dev, page_to_phys(page), size, -DMA_BIDIRECTIONAL, align_mask); - - flush_gart(); - if (paddr != bad_dma_addr) { - *dma_addr = paddr; - return page_address(page); - } - __free_pages(page, get_order(size)); - } else - return dma_direct_alloc(dev, size, dma_addr, flag, attrs); + void *vaddr; + + vaddr = dma_direct_alloc(dev, size, dma_addr, flag, attrs); + if (!vaddr || + !force_iommu || dev->coherent_dma_mask <= DMA_BIT_MASK(24)) + return vaddr; + *dma_addr = dma_map_area(dev, virt_to_phys(vaddr), size, + DMA_BIDIRECTIONAL, (1UL << get_order(size)) - 1); + flush_gart(); + if (unlikely(*dma_addr == bad_dma_addr)) + goto out_free; + return vaddr; +out_free: + dma_direct_free(dev, size, vaddr, *dma_addr, attrs); return NULL; } -- 2.14.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v8 0/5] iommu/arm-smmu: Add runtime pm/sleep support
Hi Tomasz, On 3/5/2018 6:55 PM, Tomasz Figa wrote: Hi Vivek, On Fri, Mar 2, 2018 at 7:10 PM, Vivek Gautamwrote: This series provides the support for turning on the arm-smmu's clocks/power domains using runtime pm. This is done using the recently introduced device links patches, which lets the smmu's runtime to follow the master's runtime pm, so the smmu remains powered only when the masters use it. It also adds support for Qcom's arm-smmu-v2 variant that has different clocks and power requirements. Took some reference from the exynos runtime patches [1]. After another round of discussion [3], we now finally seem to be in agreement to add a flag based on compatible, a flag that would indicate if a particular implementation of arm-smmu supports runtime pm or not. This lets us to use the much-argued pm_runtime_get_sync/put_sync() calls in map/unmap callbacks so that the clients do not have to worry about handling any of the arm-smmu's power. The patch that exported couple of pm_runtime suppliers APIS, viz. pm_runtime_get_suppliers(), and pm_runtime_put_suppliers() can be dropped since we don't have a user now for these APIs. Thanks Rafael for reviewing the changes, but looks like we don't need to export those APIs for some more time. :) Previous version of this patch series is @ [5]. Thanks for addressing my comments. There is still a bit of space for improving the granularity of power management, as far as I understood how it works on SDM845 correctly, but as a first step, this should at least let things work. Sure. I will be sending a patch, based on this series, to add 'qcom,smmu-500' that enables *rpm_suported* flag for us. We can try to take care of some of the things with that. Reviewed-by: Tomasz Figa Thanks for the review. regards Vivek Best regards, Tomasz ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
RE: [PATCH 1/6] Docs: dt: add fsl-mc iommu-parent device-tree binding
> -Original Message- > From: Robin Murphy [mailto:robin.mur...@arm.com] > Sent: Monday, March 05, 2018 21:07 > To: Nipun Gupta; will.dea...@arm.com; > mark.rutl...@arm.com; catalin.mari...@arm.com > Cc: iommu@lists.linux-foundation.org; robh...@kernel.org; h...@lst.de; > m.szyprow...@samsung.com; gre...@linuxfoundation.org; j...@8bytes.org; > Leo Li ; shawn...@kernel.org; linux- > ker...@vger.kernel.org; devicet...@vger.kernel.org; linux-arm- > ker...@lists.infradead.org; linuxppc-...@lists.ozlabs.org; Bharat Bhushan > ; stuyo...@gmail.com; Laurentiu Tudor > > Subject: Re: [PATCH 1/6] Docs: dt: add fsl-mc iommu-parent device-tree binding > > On 05/03/18 15:00, Nipun Gupta wrote: > > > > > >> -Original Message- > >> From: Robin Murphy [mailto:robin.mur...@arm.com] > >> Sent: Monday, March 05, 2018 20:23 > >> To: Nipun Gupta ; will.dea...@arm.com; > >> mark.rutl...@arm.com; catalin.mari...@arm.com > >> Cc: iommu@lists.linux-foundation.org; robh...@kernel.org; h...@lst.de; > >> m.szyprow...@samsung.com; gre...@linuxfoundation.org; > j...@8bytes.org; > >> Leo Li ; shawn...@kernel.org; linux- > >> ker...@vger.kernel.org; devicet...@vger.kernel.org; linux-arm- > >> ker...@lists.infradead.org; linuxppc-...@lists.ozlabs.org; Bharat Bhushan > >> ; stuyo...@gmail.com; Laurentiu Tudor > >> > >> Subject: Re: [PATCH 1/6] Docs: dt: add fsl-mc iommu-parent device-tree > binding > >> > >> On 05/03/18 14:29, Nipun Gupta wrote: > >>> The existing IOMMU bindings cannot be used to specify the relationship > >>> between fsl-mc devices and IOMMUs. This patch adds a binding for > >>> mapping fsl-mc devices to IOMMUs, using a new iommu-parent property. > >> > >> Given that allowing "msi-parent" for #msi-cells > 1 is merely a > >> backward-compatibility bodge full of hard-coded assumptions, why would > >> we want to knowingly introduce a similarly unpleasant equivalent for > >> IOMMUs? What's wrong with "iommu-map"? > > > > Hi Robin, > > > > With 'msi-parent' the property is fixed up to have msi-map. In this case > > there is > > no fixup required and simple 'iommu-parent' property can be used, with MC > bus > > itself providing the stream-id's (in the code execution via FW). > > > > We can also use the iommu-map property similar to PCI, which will require u- > boot > > fixup. But then it leads to little bit complications of u-boot - kernel > compatibility. > > What needs fixing up? With a stream-map-mask in place to ignore the > upper Stream ID bits, you just need: > > iommu-map = <0 0 0x80>; > > to say that the lower bits of the ICID value map directly to the lower > bits of the Stream ID value - that's the same fixed property of the > hardware that you're wanting to assume in iommu-parent. Makes sense. I was going in a little bit wrong direction. Thanks for correcting. I will send v2 patchset with iommu-map property. Regards, Nipun > > > If you suggest we can re-use the iommu-map property. What is your opinion? > > I think it makes a lot more sense to directly use the property which > already exists, than to introduce a new one to merely assume one > hard-coded value of the existing one. Extending msi-parent to msi-map > was a case of "oops, it turns out we need more flexibility here"; for > the case of iommu-map I can't imagine any justification for saying > "oops, we need less flexibility here" (saving 9 whole bytes in the DT > really is irrelevant). > > Robin. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 5/6] dma-mapping: support fsl-mc bus
On 05/03/18 15:08, Christoph Hellwig wrote: We should not add any new hardocded busses here. Please mark them in OF/ACPI. Unfortunately for us, fsl-mc is conceptually rather like PCI in that it's software-discoverable and the only thing described in DT is the bus "host", thus we need the same sort of thing as for PCI to map from the child devices back to the bus root in order to find the appropriate firmware node. Worse than PCI, though, we wouldn't even have the option of describing child devices statically in firmware at all, since it's actually one of these runtime-configurable "build your own network accelerator" hardware pools where userspace gets to create and destroy "devices" as it likes. Robin. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: WARN_ON(irqs_disabled()) in dma_free_attrs?
On Sat, Mar 03, 2018 at 07:19:06PM +0100, Fredrik Noring wrote: > Christoph, Alan, > > > If it is allocating / freeing this memory all the time in the hot path > > it should really use a dma pool (see include/ilinux/dmapool.h). > > The dma coherent APIs aren't really built for being called in the > > hot path. > > hcd_buffer_free uses a combination of dma pools and dma coherent APIs: > > ... > for (i = 0; i < HCD_BUFFER_POOLS; i++) { > if (size <= pool_max[i]) { > dma_pool_free(hcd->pool[i], addr, dma); > return; > } > } > dma_free_coherent(hcd->self.sysdev, size, addr, dma); > > Alan, can dma_free_coherent be delayed to a point when IRQs are enabled? The point is that you should always use a pool, period. dma_alloc*/dma_free* are fundamentally expensive operations on my architectures, so if you call them from a fast path you are doing something wrong. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 5/6] dma-mapping: support fsl-mc bus
We should not add any new hardocded busses here. Please mark them in OF/ACPI. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
RE: [PATCH 1/6] Docs: dt: add fsl-mc iommu-parent device-tree binding
> -Original Message- > From: Robin Murphy [mailto:robin.mur...@arm.com] > Sent: Monday, March 05, 2018 20:23 > To: Nipun Gupta; will.dea...@arm.com; > mark.rutl...@arm.com; catalin.mari...@arm.com > Cc: iommu@lists.linux-foundation.org; robh...@kernel.org; h...@lst.de; > m.szyprow...@samsung.com; gre...@linuxfoundation.org; j...@8bytes.org; > Leo Li ; shawn...@kernel.org; linux- > ker...@vger.kernel.org; devicet...@vger.kernel.org; linux-arm- > ker...@lists.infradead.org; linuxppc-...@lists.ozlabs.org; Bharat Bhushan > ; stuyo...@gmail.com; Laurentiu Tudor > > Subject: Re: [PATCH 1/6] Docs: dt: add fsl-mc iommu-parent device-tree binding > > On 05/03/18 14:29, Nipun Gupta wrote: > > The existing IOMMU bindings cannot be used to specify the relationship > > between fsl-mc devices and IOMMUs. This patch adds a binding for > > mapping fsl-mc devices to IOMMUs, using a new iommu-parent property. > > Given that allowing "msi-parent" for #msi-cells > 1 is merely a > backward-compatibility bodge full of hard-coded assumptions, why would > we want to knowingly introduce a similarly unpleasant equivalent for > IOMMUs? What's wrong with "iommu-map"? Hi Robin, With 'msi-parent' the property is fixed up to have msi-map. In this case there is no fixup required and simple 'iommu-parent' property can be used, with MC bus itself providing the stream-id's (in the code execution via FW). We can also use the iommu-map property similar to PCI, which will require u-boot fixup. But then it leads to little bit complications of u-boot - kernel compatibility. If you suggest we can re-use the iommu-map property. What is your opinion? Thanks, Nipun > > > Signed-off-by: Nipun Gupta > > --- > > .../devicetree/bindings/misc/fsl,qoriq-mc.txt | 31 > ++ > > 1 file changed, 31 insertions(+) > > > > diff --git a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt > b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt > > index 6611a7c..011c7d6 100644 > > --- a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt > > +++ b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt > > @@ -9,6 +9,24 @@ blocks that can be used to create functional hardware > objects/devices > > such as network interfaces, crypto accelerator instances, L2 switches, > > etc. > > > > +For an overview of the DPAA2 architecture and fsl-mc bus see: > > +drivers/staging/fsl-mc/README.txt > > + > > +As described in the above overview, all DPAA2 objects in a DPRC share the > > +same hardware "isolation context" and a 10-bit value called an ICID > > +(isolation context id) is expressed by the hardware to identify > > +the requester. > > IOW, precisely the case for which "{msi,iommu}-map" exist. Yes, I know > they're currently documented under bindings/pci, but they're not really > intended to be absolutely PCI-specific. > > Robin. > > > +The generic 'iommus' property is cannot be used to describe the > > relationship > > +between fsl-mc and IOMMUs, so an iommu-parent property is used to define > > +the same. > > + > > +For generic IOMMU bindings, see > > +Documentation/devicetree/bindings/iommu/iommu.txt. > > + > > +For arm-smmu binding, see: > > +Documentation/devicetree/bindings/iommu/arm,smmu.txt. > > + > > Required properties: > > > > - compatible > > @@ -88,14 +106,27 @@ Sub-nodes: > > Value type: > > Definition: Specifies the phandle to the PHY device node > > associated > > with the this dpmac. > > +Optional properties: > > + > > +- iommu-parent: Maps the devices on fsl-mc bus to an IOMMU. > > + The property specifies the IOMMU behind which the devices on > > + fsl-mc bus are residing. > > > > Example: > > > > +smmu: iommu@500 { > > + compatible = "arm,mmu-500"; > > + #iommu-cells = <1>; > > + stream-match-mask = <0x7C00>; > > + ... > > +}; > > + > > fsl_mc: fsl-mc@80c00 { > > compatible = "fsl,qoriq-mc"; > > reg = <0x0008 0x0c00 0 0x40>,/* MC portal > > base */ > > <0x 0x0834 0 0x4>; /* MC control > > reg */ > > msi-parent = <>; > > +iommu-parent = <>; > > #address-cells = <3>; > > #size-cells = <1>; > > > > ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCHv3] iommu/intel: Ratelimit each dmar fault printing
Hi Joerg, What do you think about v3? It looks like, I can solve my softlookups with just a bit more proper ratelimiting.. On Thu, 2018-02-15 at 19:17 +, Dmitry Safonov wrote: > There is a ratelimit for printing, but it's incremented each time the > cpu recives dmar fault interrupt. While one interrupt may signal > about > *many* faults. > So, measuring the impact it turns out that reading/clearing one fault > takes < 1 usec, and printing info about the fault takes ~170 msec. > > Having in mind that maximum number of fault recording registers per > remapping hardware unit is 256.. IRQ handler may run for (170*256) > msec. > And as fault-serving loop runs without a time limit, during servicing > new faults may occur.. > > Ratelimit each fault printing rather than each irq printing. > > Fixes: commit c43fce4eebae ("iommu/vt-d: Ratelimit fault handler") > > BUG: spinlock lockup suspected on CPU#0, CliShell/9903 > lock: 0x81a47440, .magic: dead4ead, .owner: > kworker/u16:2/8915, .owner_cpu: 6 > CPU: 0 PID: 9903 Comm: CliShell > Call Trace:$\n' > [..] dump_stack+0x65/0x83$\n' > [..] spin_dump+0x8f/0x94$\n' > [..] do_raw_spin_lock+0x123/0x170$\n' > [..] _raw_spin_lock_irqsave+0x32/0x3a$\n' > [..] uart_chars_in_buffer+0x20/0x4d$\n' > [..] tty_chars_in_buffer+0x18/0x1d$\n' > [..] n_tty_poll+0x1cb/0x1f2$\n' > [..] tty_poll+0x5e/0x76$\n' > [..] do_select+0x363/0x629$\n' > [..] compat_core_sys_select+0x19e/0x239$\n' > [..] compat_SyS_select+0x98/0xc0$\n' > [..] sysenter_dispatch+0x7/0x25$\n' > [..] > NMI backtrace for cpu 6 > CPU: 6 PID: 8915 Comm: kworker/u16:2 > Workqueue: dmar_fault dmar_fault_work > Call Trace:$\n' > [..] wait_for_xmitr+0x26/0x8f$\n' > [..] serial8250_console_putchar+0x1c/0x2c$\n' > [..] uart_console_write+0x40/0x4b$\n' > [..] serial8250_console_write+0xe6/0x13f$\n' > [..] call_console_drivers.constprop.13+0xce/0x103$\n' > [..] console_unlock+0x1f8/0x39b$\n' > [..] vprintk_emit+0x39e/0x3e6$\n' > [..] printk+0x4d/0x4f$\n' > [..] dmar_fault+0x1a8/0x1fc$\n' > [..] dmar_fault_work+0x15/0x17$\n' > [..] process_one_work+0x1e8/0x3a9$\n' > [..] worker_thread+0x25d/0x345$\n' > [..] kthread+0xea/0xf2$\n' > [..] ret_from_fork+0x58/0x90$\n' > > Cc: Alex Williamson> Cc: David Woodhouse > Cc: Ingo Molnar > Cc: Joerg Roedel > Cc: Lu Baolu > Cc: iommu@lists.linux-foundation.org > Signed-off-by: Dmitry Safonov > --- > Maybe it's worth to limit while(1) cycle. > If IOMMU generates faults with equal speed as irq handler cleans > them, it may turn into long-irq-disabled region again. > Not sure if it can happen anyway. > > drivers/iommu/dmar.c | 8 +++- > 1 file changed, 3 insertions(+), 5 deletions(-) > > diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c > index accf58388bdb..6c4ea32ee6a9 100644 > --- a/drivers/iommu/dmar.c > +++ b/drivers/iommu/dmar.c > @@ -1618,17 +1618,13 @@ irqreturn_t dmar_fault(int irq, void *dev_id) > int reg, fault_index; > u32 fault_status; > unsigned long flag; > - bool ratelimited; > static DEFINE_RATELIMIT_STATE(rs, > DEFAULT_RATELIMIT_INTERVAL, > DEFAULT_RATELIMIT_BURST); > > - /* Disable printing, simply clear the fault when ratelimited > */ > - ratelimited = !__ratelimit(); > - > raw_spin_lock_irqsave(>register_lock, flag); > fault_status = readl(iommu->reg + DMAR_FSTS_REG); > - if (fault_status && !ratelimited) > + if (fault_status && __ratelimit()) > pr_err("DRHD: handling fault status reg %x\n", > fault_status); > > /* TBD: ignore advanced fault log currently */ > @@ -1638,6 +1634,8 @@ irqreturn_t dmar_fault(int irq, void *dev_id) > fault_index = dma_fsts_fault_record_index(fault_status); > reg = cap_fault_reg_offset(iommu->cap); > while (1) { > + /* Disable printing, simply clear the fault when > ratelimited */ > + bool ratelimited = !__ratelimit(); > u8 fault_reason; > u16 source_id; > u64 guest_addr; ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 1/6] Docs: dt: add fsl-mc iommu-parent device-tree binding
On 05/03/18 14:29, Nipun Gupta wrote: The existing IOMMU bindings cannot be used to specify the relationship between fsl-mc devices and IOMMUs. This patch adds a binding for mapping fsl-mc devices to IOMMUs, using a new iommu-parent property. Given that allowing "msi-parent" for #msi-cells > 1 is merely a backward-compatibility bodge full of hard-coded assumptions, why would we want to knowingly introduce a similarly unpleasant equivalent for IOMMUs? What's wrong with "iommu-map"? Signed-off-by: Nipun Gupta--- .../devicetree/bindings/misc/fsl,qoriq-mc.txt | 31 ++ 1 file changed, 31 insertions(+) diff --git a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt index 6611a7c..011c7d6 100644 --- a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt +++ b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt @@ -9,6 +9,24 @@ blocks that can be used to create functional hardware objects/devices such as network interfaces, crypto accelerator instances, L2 switches, etc. +For an overview of the DPAA2 architecture and fsl-mc bus see: +drivers/staging/fsl-mc/README.txt + +As described in the above overview, all DPAA2 objects in a DPRC share the +same hardware "isolation context" and a 10-bit value called an ICID +(isolation context id) is expressed by the hardware to identify +the requester. IOW, precisely the case for which "{msi,iommu}-map" exist. Yes, I know they're currently documented under bindings/pci, but they're not really intended to be absolutely PCI-specific. Robin. +The generic 'iommus' property is cannot be used to describe the relationship +between fsl-mc and IOMMUs, so an iommu-parent property is used to define +the same. + +For generic IOMMU bindings, see +Documentation/devicetree/bindings/iommu/iommu.txt. + +For arm-smmu binding, see: +Documentation/devicetree/bindings/iommu/arm,smmu.txt. + Required properties: - compatible @@ -88,14 +106,27 @@ Sub-nodes: Value type: Definition: Specifies the phandle to the PHY device node associated with the this dpmac. +Optional properties: + +- iommu-parent: Maps the devices on fsl-mc bus to an IOMMU. + The property specifies the IOMMU behind which the devices on + fsl-mc bus are residing. Example: +smmu: iommu@500 { + compatible = "arm,mmu-500"; + #iommu-cells = <1>; + stream-match-mask = <0x7C00>; + ... +}; + fsl_mc: fsl-mc@80c00 { compatible = "fsl,qoriq-mc"; reg = <0x0008 0x0c00 0 0x40>,/* MC portal base */ <0x 0x0834 0 0x4>; /* MC control reg */ msi-parent = <>; +iommu-parent = <>; #address-cells = <3>; #size-cells = <1>; ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[bug report] iommu/arm-smmu: Make use of the iommu_register interface
Hello Joerg Roedel, This is a semi-automatic email about new static checker warnings. The patch 9648cbc9625b: "iommu/arm-smmu: Make use of the iommu_register interface" from Feb 1, 2017, leads to the following Smatch complaint: ./drivers/iommu/arm-smmu-v3.c:1957 arm_smmu_remove_device() warn: variable dereferenced before check 'master' (see line 1956) ./drivers/iommu/arm-smmu-v3.c 1955 master = fwspec->iommu_priv; 1956 smmu = master->smmu; Pach adds unchecked dereference 1957 if (master && master->ste.assigned) ^^ The old code assumes "master" can be NULL. 1958 arm_smmu_detach_dev(dev); 1959 iommu_group_remove_device(dev); regards, dan carpenter ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [RESEND PATCH v6 13/14] iommu/rockchip: Add runtime PM support
On Mon, Mar 5, 2018 at 11:13 PM, Robin Murphywrote: > On 05/03/18 13:49, Tomasz Figa wrote: > [...] >>> >>> @@ -518,7 +520,12 @@ static irqreturn_t rk_iommu_irq(int irq, void >>> *dev_id) >>> u32 int_status; >>> dma_addr_t iova; >>> irqreturn_t ret = IRQ_NONE; >>> - int i; >>> + int i, err, need_runtime_put; >> >> >> nit: need_runtime_put could be a bool. >> >>> + >>> + err = pm_runtime_get_if_in_use(iommu->dev); >>> + if (err <= 0 && err != -EINVAL) >>> + return ret; >>> + need_runtime_put = err > 0; >> >> >> Generally something must be really wrong if we end up with err == 0 >> here, because the IOMMU must be powered on to signal an interrupt. The >> only case this could happen would be if the IRQ signal was shared with >> some device from another power domain. Is it possible on Rockchip >> SoCs? If not, perhaps we should have a WARN_ON() here for such case. > > > In general, there's almost certainly some time window between the interrupt > level being latched at the GIC and the IRQ actually being taken by its > target CPU, in which potentially the power could be removed and/or the > clocks gated - especially if there are higher-priority IRQs pending at the > same time and the racing PM call is on some other CPU. Sure, it's probably > unlikely, but I wouldn't necessarily consider it completely erroneous. Clocks are not a problem here, since the handler re-enables them and clk_enable() is IRQ-safe. However, runtime PM might need sleeping, so we can't just get_sync() from the handler. I guess, we should just bail out in such case, since the power off would probably clear any internal interrupt state anyway. Also, the interrupt would be basically a page fault, during which the master device would be stalled, so it's rather unlikely that we see its driver putting the runtime PM, which would only happen after the master device resumes and competes (or something times out). So probably WARN_ON() isn't such bad idea still. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 5/6] dma-mapping: support fsl-mc bus
Signed-off-by: Nipun Gupta--- drivers/base/dma-mapping.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c index 3b11835..2279c4d 100644 --- a/drivers/base/dma-mapping.c +++ b/drivers/base/dma-mapping.c @@ -334,6 +334,7 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags) * Common configuration to enable DMA API use for a device */ #include +#include int dma_configure(struct device *dev) { @@ -349,6 +350,12 @@ int dma_configure(struct device *dev) dma_dev = dma_dev->parent; } + if (dev_is_fsl_mc(dev)) { + dma_dev = dev; + while (dev_is_fsl_mc(dma_dev)) + dma_dev = dma_dev->parent; + } + if (dma_dev->of_node) { ret = of_dma_configure(dev, dma_dev->of_node); } else if (has_acpi_companion(dma_dev)) { -- 1.9.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 6/6] dts: fsl-ls208x: updated DT with SMMU support for fsl-mc
Signed-off-by: Nipun Gupta--- arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi | 6 +- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi index f3a40af..1f15492 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi @@ -135,6 +135,7 @@ #address-cells = <2>; #size-cells = <2>; ranges; + dma-ranges = <0x0 0x0 0x0 0x0 0x1 0x>; clockgen: clocking@130 { compatible = "fsl,ls2080a-clockgen"; @@ -357,6 +358,8 @@ reg = <0x0008 0x0c00 0 0x40>,/* MC portal base */ <0x 0x0834 0 0x4>; /* MC control reg */ msi-parent = <>; + iommu-parent = <>; + dma-coherent; #address-cells = <3>; #size-cells = <1>; @@ -460,6 +463,8 @@ compatible = "arm,mmu-500"; reg = <0 0x500 0 0x80>; #global-interrupts = <12>; + stream-match-mask = <0x7C00>; + dma-coherent; interrupts = <0 13 4>, /* global secure fault */ <0 14 4>, /* combined secure interrupt */ <0 15 4>, /* global non-secure fault */ @@ -502,7 +507,6 @@ <0 204 4>, <0 205 4>, <0 206 4>, <0 207 4>, <0 208 4>, <0 209 4>; - mmu-masters = <_mc 0x300 0>; }; dspi: dspi@210 { -- 1.9.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 4/6] bus: fsl-mc: remove dma ops setup from driver
The dma setup for fsl-mc devices is being done from device_add() function. So, no need to call in mc bus driver. Signed-off-by: Nipun Gupta--- drivers/bus/fsl-mc/fsl-mc-bus.c | 5 + 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 1b333c4..c9a239a 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -616,6 +616,7 @@ int fsl_mc_device_add(struct fsl_mc_obj_desc *obj_desc, mc_dev->icid = parent_mc_dev->icid; mc_dev->dma_mask = FSL_MC_DEFAULT_DMA_MASK; mc_dev->dev.dma_mask = _dev->dma_mask; + mc_dev->dev.coherent_dma_mask = mc_dev->dma_mask; dev_set_msi_domain(_dev->dev, dev_get_msi_domain(_mc_dev->dev)); } @@ -633,10 +634,6 @@ int fsl_mc_device_add(struct fsl_mc_obj_desc *obj_desc, goto error_cleanup_dev; } - /* Objects are coherent, unless 'no shareability' flag set. */ - if (!(obj_desc->flags & FSL_MC_OBJ_FLAG_NO_MEM_SHAREABILITY)) - arch_setup_dma_ops(_dev->dev, 0, 0, NULL, true); - /* * The device-specific probe callback will get invoked by device_add() */ -- 1.9.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 3/6] iommu: arm-smmu: Add support for the fsl-mc bus
Implement bus specific support for the fsl-mc bus including registering arm_smmu_ops and bus specific device add operations. Signed-off-by: Nipun Gupta--- drivers/iommu/arm-smmu.c | 7 +++ drivers/iommu/iommu.c| 21 + include/linux/fsl/mc.h | 8 include/linux/iommu.h| 2 ++ 4 files changed, 38 insertions(+) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 69e7c60..e1d5090 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -52,6 +52,7 @@ #include #include +#include #include "io-pgtable.h" #include "arm-smmu-regs.h" @@ -1459,6 +1460,8 @@ static struct iommu_group *arm_smmu_device_group(struct device *dev) if (dev_is_pci(dev)) group = pci_device_group(dev); + else if (dev_is_fsl_mc(dev)) + group = fsl_mc_device_group(dev); else group = generic_device_group(dev); @@ -2037,6 +2040,10 @@ static void arm_smmu_bus_init(void) bus_set_iommu(_bus_type, _smmu_ops); } #endif +#ifdef CONFIG_FSL_MC_BUS + if (!iommu_present(_mc_bus_type)) + bus_set_iommu(_mc_bus_type, _smmu_ops); +#endif } static int arm_smmu_device_probe(struct platform_device *pdev) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 69fef99..fbeebb2 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -32,6 +32,7 @@ #include #include #include +#include #include static struct kset *iommu_group_kset; @@ -987,6 +988,26 @@ struct iommu_group *pci_device_group(struct device *dev) return iommu_group_alloc(); } +/* Get the IOMMU group for device on fsl-mc bus */ +struct iommu_group *fsl_mc_device_group(struct device *dev) +{ + struct device *cont_dev = fsl_mc_cont_dev(dev); + struct iommu_group *group; + + /* Container device is responsible for creating the iommu group */ + if (fsl_mc_is_cont_dev(dev)) { + group = iommu_group_alloc(); + if (IS_ERR(group)) + return NULL; + } else { + get_device(cont_dev); + group = iommu_group_get(cont_dev); + put_device(cont_dev); + } + + return group; +} + /** * iommu_group_get_for_dev - Find or create the IOMMU group for a device * @dev: target device diff --git a/include/linux/fsl/mc.h b/include/linux/fsl/mc.h index 765ba41..ae9382b 100644 --- a/include/linux/fsl/mc.h +++ b/include/linux/fsl/mc.h @@ -351,6 +351,14 @@ struct fsl_mc_io { #define dev_is_fsl_mc(_dev) (0) #endif +/* Macro to check if a device is a container device */ +#define fsl_mc_is_cont_dev(_dev) (to_fsl_mc_device(_dev)->flags & \ + FSL_MC_IS_DPRC) + +/* Macro to get the container device of a MC device */ +#define fsl_mc_cont_dev(_dev) (fsl_mc_is_cont_dev(_dev) ? \ + (_dev) : (_dev)->parent) + /* * module_fsl_mc_driver() - Helper macro for drivers that don't do * anything special in module init/exit. This eliminates a lot of diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 41b8c57..00a460b 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -389,6 +389,8 @@ static inline size_t iommu_map_sg(struct iommu_domain *domain, extern struct iommu_group *pci_device_group(struct device *dev); /* Generic device grouping function */ extern struct iommu_group *generic_device_group(struct device *dev); +/* FSL-MC device grouping function */ +struct iommu_group *fsl_mc_device_group(struct device *dev); /** * struct iommu_fwspec - per-device IOMMU instance data -- 1.9.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 2/6] iommu: support iommu configuration for fsl-mc devices
Signed-off-by: Nipun Gupta--- drivers/iommu/of_iommu.c | 23 +++ 1 file changed, 23 insertions(+) diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c index 5c36a8b..cc2fb9c 100644 --- a/drivers/iommu/of_iommu.c +++ b/drivers/iommu/of_iommu.c @@ -24,6 +24,7 @@ #include #include #include +#include #define NO_IOMMU 1 @@ -160,6 +161,26 @@ static int of_pci_iommu_init(struct pci_dev *pdev, u16 alias, void *data) return err; } +static int +of_fsl_mc_iommu_init(struct fsl_mc_device *mc_dev, + struct device_node *master_np) +{ + struct of_phandle_args iommu_spec; + int err; + + iommu_spec.np = of_parse_phandle(master_np, "iommu-parent", 0); + if (!iommu_spec.np) + return NO_IOMMU; + + iommu_spec.args[0] = mc_dev->icid; + iommu_spec.args_count = 1; + + err = of_iommu_xlate(_dev->dev, _spec); + of_node_put(iommu_spec.np); + + return err; +} + const struct iommu_ops *of_iommu_configure(struct device *dev, struct device_node *master_np) { @@ -191,6 +212,8 @@ const struct iommu_ops *of_iommu_configure(struct device *dev, err = pci_for_each_dma_alias(to_pci_dev(dev), of_pci_iommu_init, ); + } else if (dev_is_fsl_mc(dev)) { + err = of_fsl_mc_iommu_init(to_fsl_mc_device(dev), master_np); } else { struct of_phandle_args iommu_spec; int idx = 0; -- 1.9.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 1/6] Docs: dt: add fsl-mc iommu-parent device-tree binding
The existing IOMMU bindings cannot be used to specify the relationship between fsl-mc devices and IOMMUs. This patch adds a binding for mapping fsl-mc devices to IOMMUs, using a new iommu-parent property. Signed-off-by: Nipun Gupta--- .../devicetree/bindings/misc/fsl,qoriq-mc.txt | 31 ++ 1 file changed, 31 insertions(+) diff --git a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt index 6611a7c..011c7d6 100644 --- a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt +++ b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt @@ -9,6 +9,24 @@ blocks that can be used to create functional hardware objects/devices such as network interfaces, crypto accelerator instances, L2 switches, etc. +For an overview of the DPAA2 architecture and fsl-mc bus see: +drivers/staging/fsl-mc/README.txt + +As described in the above overview, all DPAA2 objects in a DPRC share the +same hardware "isolation context" and a 10-bit value called an ICID +(isolation context id) is expressed by the hardware to identify +the requester. + +The generic 'iommus' property is cannot be used to describe the relationship +between fsl-mc and IOMMUs, so an iommu-parent property is used to define +the same. + +For generic IOMMU bindings, see +Documentation/devicetree/bindings/iommu/iommu.txt. + +For arm-smmu binding, see: +Documentation/devicetree/bindings/iommu/arm,smmu.txt. + Required properties: - compatible @@ -88,14 +106,27 @@ Sub-nodes: Value type: Definition: Specifies the phandle to the PHY device node associated with the this dpmac. +Optional properties: + +- iommu-parent: Maps the devices on fsl-mc bus to an IOMMU. + The property specifies the IOMMU behind which the devices on + fsl-mc bus are residing. Example: +smmu: iommu@500 { + compatible = "arm,mmu-500"; + #iommu-cells = <1>; + stream-match-mask = <0x7C00>; + ... +}; + fsl_mc: fsl-mc@80c00 { compatible = "fsl,qoriq-mc"; reg = <0x0008 0x0c00 0 0x40>,/* MC portal base */ <0x 0x0834 0 0x4>; /* MC control reg */ msi-parent = <>; +iommu-parent = <>; #address-cells = <3>; #size-cells = <1>; -- 1.9.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 0/6] Support for fsl-mc bus and its devices in SMMU
This patchset defines IOMMU DT binding for fsl-mc bus and adds support in SMMU for fsl-mc bus. These patches - Define the new property 'iommu-parent' for fsl-mc bus (patch 1) - Integrates the fsl-mc bus with the SMMU using this IOMMU binding (patch 2,3) - Adds the dma-mapping support for fsl-mc bus (patch 4,5) - Updates the fsl-mc device node with iommu/dma related changes This patchset is based on staging-testing tree where fsl-mc bus is out from staging This patchset is dependent on patch https://patchwork.kernel.org/patch/10207507/; otherwise DPAA2 Ethernet driver functionality will break. Nipun Gupta (6): Docs: dt: add fsl-mc iommu-parent device-tree binding iommu: support iommu configuration for fsl-mc devices iommu: arm-smmu: Add support for the fsl-mc bus bus: fsl-mc: remove dma ops setup from driver dma-mapping: support fsl-mc bus dts: fsl-ls208x: updated DT with SMMU support for fsl-mc .../devicetree/bindings/misc/fsl,qoriq-mc.txt | 31 ++ arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi | 6 - drivers/base/dma-mapping.c | 7 + drivers/bus/fsl-mc/fsl-mc-bus.c| 5 +--- drivers/iommu/arm-smmu.c | 7 + drivers/iommu/iommu.c | 21 +++ drivers/iommu/of_iommu.c | 23 include/linux/fsl/mc.h | 8 ++ include/linux/iommu.h | 2 ++ 9 files changed, 105 insertions(+), 5 deletions(-) -- 1.9.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [RESEND PATCH v6 13/14] iommu/rockchip: Add runtime PM support
On 05/03/18 13:49, Tomasz Figa wrote: [...] @@ -518,7 +520,12 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id) u32 int_status; dma_addr_t iova; irqreturn_t ret = IRQ_NONE; - int i; + int i, err, need_runtime_put; nit: need_runtime_put could be a bool. + + err = pm_runtime_get_if_in_use(iommu->dev); + if (err <= 0 && err != -EINVAL) + return ret; + need_runtime_put = err > 0; Generally something must be really wrong if we end up with err == 0 here, because the IOMMU must be powered on to signal an interrupt. The only case this could happen would be if the IRQ signal was shared with some device from another power domain. Is it possible on Rockchip SoCs? If not, perhaps we should have a WARN_ON() here for such case. In general, there's almost certainly some time window between the interrupt level being latched at the GIC and the IRQ actually being taken by its target CPU, in which potentially the power could be removed and/or the clocks gated - especially if there are higher-priority IRQs pending at the same time and the racing PM call is on some other CPU. Sure, it's probably unlikely, but I wouldn't necessarily consider it completely erroneous. Robin. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [RESEND PATCH v6 13/14] iommu/rockchip: Add runtime PM support
Hi Jeffy, On Thu, Mar 1, 2018 at 7:18 PM, Jeffy Chenwrote: > When the power domain is powered off, the IOMMU cannot be accessed and > register programming must be deferred until the power domain becomes > enabled. > > Add runtime PM support, and use runtime PM device link from IOMMU to > master to startup and shutdown IOMMU. > > Signed-off-by: Jeffy Chen > --- > > Changes in v6: None > Changes in v5: > Avoid race about pm_runtime_get_if_in_use() and pm_runtime_enabled(). > > Changes in v4: None > Changes in v3: > Only call startup() and shutdown() when iommu attached. > Remove pm_mutex. > Check runtime PM disabled. > Check pm_runtime in rk_iommu_irq(). > > Changes in v2: None > > drivers/iommu/rockchip-iommu.c | 181 > +++-- > 1 file changed, 140 insertions(+), 41 deletions(-) > > diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c > index 2448a0528e39..0e0a42f41818 100644 > --- a/drivers/iommu/rockchip-iommu.c > +++ b/drivers/iommu/rockchip-iommu.c > @@ -22,6 +22,7 @@ > #include > #include > #include > +#include > #include > #include > > @@ -106,6 +107,7 @@ struct rk_iommu { > }; > > struct rk_iommudata { > + struct device_link *link; /* runtime PM link from IOMMU to master */ Kerneldoc comment for the struct could be added instead. > struct rk_iommu *iommu; > }; > > @@ -518,7 +520,12 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id) > u32 int_status; > dma_addr_t iova; > irqreturn_t ret = IRQ_NONE; > - int i; > + int i, err, need_runtime_put; nit: need_runtime_put could be a bool. > + > + err = pm_runtime_get_if_in_use(iommu->dev); > + if (err <= 0 && err != -EINVAL) > + return ret; > + need_runtime_put = err > 0; Generally something must be really wrong if we end up with err == 0 here, because the IOMMU must be powered on to signal an interrupt. The only case this could happen would be if the IRQ signal was shared with some device from another power domain. Is it possible on Rockchip SoCs? If not, perhaps we should have a WARN_ON() here for such case. > > WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)); > > @@ -570,6 +577,9 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id) > > clk_bulk_disable(iommu->num_clocks, iommu->clocks); > > + if (need_runtime_put) > + pm_runtime_put(iommu->dev); > + > return ret; > } > > @@ -611,10 +621,20 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain > *rk_domain, > spin_lock_irqsave(_domain->iommus_lock, flags); > list_for_each(pos, _domain->iommus) { > struct rk_iommu *iommu; > + int ret; > + > iommu = list_entry(pos, struct rk_iommu, node); > - WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)); > - rk_iommu_zap_lines(iommu, iova, size); > - clk_bulk_disable(iommu->num_clocks, iommu->clocks); > + > + /* Only zap TLBs of IOMMUs that are powered on. */ > + ret = pm_runtime_get_if_in_use(iommu->dev); > + if (ret > 0 || ret == -EINVAL) { > + WARN_ON(clk_bulk_enable(iommu->num_clocks, > + iommu->clocks)); > + rk_iommu_zap_lines(iommu, iova, size); > + clk_bulk_disable(iommu->num_clocks, iommu->clocks); > + } > + if (ret > 0) > + pm_runtime_put(iommu->dev); > } > spin_unlock_irqrestore(_domain->iommus_lock, flags); > } > @@ -817,22 +837,30 @@ static struct rk_iommu *rk_iommu_from_dev(struct device > *dev) > return data ? data->iommu : NULL; > } > > -static int rk_iommu_attach_device(struct iommu_domain *domain, > - struct device *dev) > +/* Must be called with iommu powered on and attached */ > +static void rk_iommu_shutdown(struct rk_iommu *iommu) > { > - struct rk_iommu *iommu; > + int i; > + > + /* Ignore error while disabling, just keep going */ > + WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)); > + rk_iommu_enable_stall(iommu); > + rk_iommu_disable_paging(iommu); > + for (i = 0; i < iommu->num_mmu; i++) { > + rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, 0); > + rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, 0); > + } > + rk_iommu_disable_stall(iommu); > + clk_bulk_disable(iommu->num_clocks, iommu->clocks); > +} > + > +/* Must be called with iommu powered on and attached */ > +static int rk_iommu_startup(struct rk_iommu *iommu) > +{ > + struct iommu_domain *domain = iommu->domain; > struct rk_iommu_domain *rk_domain = to_rk_domain(domain); > - unsigned long flags; > int ret,
Re: [RESEND PATCH v6 03/14] iommu/rockchip: Request irqs in rk_iommu_probe()
Hi Jeffy, On Thu, Mar 1, 2018 at 7:18 PM, Jeffy Chenwrote: > Move request_irq to the end of rk_iommu_probe(). > > Suggested-by: Robin Murphy > Signed-off-by: Jeffy Chen > --- > > Changes in v6: None > Changes in v5: None > Changes in v4: None > Changes in v3: > Loop platform_get_irq() as Robin suggested. > > Changes in v2: None > > drivers/iommu/rockchip-iommu.c | 38 +- > 1 file changed, 9 insertions(+), 29 deletions(-) > Reviewed-by: Tomasz Figa Best regards, Tomasz ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v8 0/5] iommu/arm-smmu: Add runtime pm/sleep support
Hi Vivek, On Fri, Mar 2, 2018 at 7:10 PM, Vivek Gautamwrote: > This series provides the support for turning on the arm-smmu's > clocks/power domains using runtime pm. This is done using the > recently introduced device links patches, which lets the smmu's > runtime to follow the master's runtime pm, so the smmu remains > powered only when the masters use it. > > It also adds support for Qcom's arm-smmu-v2 variant that > has different clocks and power requirements. > > Took some reference from the exynos runtime patches [1]. > > After another round of discussion [3], we now finally seem to be > in agreement to add a flag based on compatible, a flag that would > indicate if a particular implementation of arm-smmu supports > runtime pm or not. > This lets us to use the much-argued pm_runtime_get_sync/put_sync() > calls in map/unmap callbacks so that the clients do not have to > worry about handling any of the arm-smmu's power. > The patch that exported couple of pm_runtime suppliers APIS, viz. > pm_runtime_get_suppliers(), and pm_runtime_put_suppliers() can be > dropped since we don't have a user now for these APIs. > Thanks Rafael for reviewing the changes, but looks like we don't > need to export those APIs for some more time. :) > > Previous version of this patch series is @ [5]. Thanks for addressing my comments. There is still a bit of space for improving the granularity of power management, as far as I understood how it works on SDM845 correctly, but as a first step, this should at least let things work. Reviewed-by: Tomasz Figa Best regards, Tomasz ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 35/37] iommu/arm-smmu-v3: Add support for PRI
On 05/03/18 12:29, Dongdong Liu wrote: >> >> +static int arm_smmu_enable_pri(struct arm_smmu_master_data *master) >> +{ >> +int ret, pos; >> +struct pci_dev *pdev; >> +/* >> + * TODO: find a good inflight PPR number. We should divide the PRI queue >> + * by the number of PRI-capable devices, but it's impossible to know >> + * about current and future (hotplugged) devices. So we're at risk of >> + * dropping PPRs (and leaking pending requests in the FQ). >> + */ >> +size_t max_inflight_pprs = 16; >> +struct arm_smmu_device *smmu = master->smmu; >> + >> +if (!(smmu->features & ARM_SMMU_FEAT_PRI) || !dev_is_pci(master->dev)) >> +return -ENOSYS; >> + >> +pdev = to_pci_dev(master->dev); >> + > From here >> +pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); >> +if (!pos) >> +return -ENOSYS; > to here, seems this code is not needed as it is already done in > pci_reset_pri(). Indeed, thanks. It would allow to differentiate a device that doesn't support PRI from a reset error, but since we ignore the return value at the moment I'll remove it. Thanks, Jean ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 35/37] iommu/arm-smmu-v3: Add support for PRI
+static int arm_smmu_enable_pri(struct arm_smmu_master_data *master) +{ + int ret, pos; + struct pci_dev *pdev; + /* +* TODO: find a good inflight PPR number. We should divide the PRI queue +* by the number of PRI-capable devices, but it's impossible to know +* about current and future (hotplugged) devices. So we're at risk of +* dropping PPRs (and leaking pending requests in the FQ). +*/ + size_t max_inflight_pprs = 16; + struct arm_smmu_device *smmu = master->smmu; + + if (!(smmu->features & ARM_SMMU_FEAT_PRI) || !dev_is_pci(master->dev)) + return -ENOSYS; + + pdev = to_pci_dev(master->dev); + From here + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); + if (!pos) + return -ENOSYS; to here, seems this code is not needed as it is already done in pci_reset_pri(). Thanks, Dongdong + + ret = pci_reset_pri(pdev); + if (ret) + return ret; + + ret = pci_enable_pri(pdev, max_inflight_pprs); + if (ret) { + dev_err(master->dev, "cannot enable PRI: %d\n", ret); + return ret; + } + + master->can_fault = true; + master->ste.prg_resp_needs_ssid = pci_prg_resp_requires_prefix(pdev); + + dev_dbg(master->dev, "enabled PRI"); + + return 0; +} + static void arm_smmu_disable_ats(struct arm_smmu_master_data *master) { struct pci_dev *pdev; @@ -2548,6 +2592,22 @@ static void arm_smmu_disable_ats(struct arm_smmu_master_data *master) pci_disable_ats(pdev); } +static void arm_smmu_disable_pri(struct arm_smmu_master_data *master) +{ + struct pci_dev *pdev; + + if (!dev_is_pci(master->dev)) + return; + + pdev = to_pci_dev(master->dev); + + if (!pdev->pri_enabled) + return; + + pci_disable_pri(pdev); + master->can_fault = false; +} + static int arm_smmu_insert_master(struct arm_smmu_device *smmu, struct arm_smmu_master_data *master) { @@ -2668,12 +2728,13 @@ static int arm_smmu_add_device(struct device *dev) master->ste.can_stall = true; } - arm_smmu_enable_ats(master); + if (!arm_smmu_enable_ats(master)) + arm_smmu_enable_pri(master); group = iommu_group_get_for_dev(dev); if (IS_ERR(group)) { ret = PTR_ERR(group); - goto err_disable_ats; + goto err_disable_pri; } iommu_group_put(group); @@ -2682,7 +2743,8 @@ static int arm_smmu_add_device(struct device *dev) return 0; -err_disable_ats: +err_disable_pri: + arm_smmu_disable_pri(master); arm_smmu_disable_ats(master); return ret; @@ -2702,6 +2764,8 @@ static void arm_smmu_remove_device(struct device *dev) if (master && master->ste.assigned) arm_smmu_detach_dev(dev); arm_smmu_remove_master(smmu, master); + + arm_smmu_disable_pri(master); arm_smmu_disable_ats(master); iommu_group_remove_device(dev); ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: Using dma-ranges with iommu to limit range of iova
Hi Vivek, On 05/03/18 09:06, Vivek Gautam wrote: Hi all, I have a question regarding usage of 'dma-ranges', can someone point me in the right direction? On qcom soc, few of the master devices with iommu attached to them, have limitations in using the iova address range. They can allow the iova to be only in a certain range, e.g. video codec firmware can only access iova only in a first few MBs as the video's arm core reset starts at 0x0. To do that, I earlier, had the understanding that we can modify the iommu_domain's geometry aperture. But that looks kind of a hacky way to get the domain for the device and modify the aperture. I was trying to explore if we can use the dma-ranges property. But the iommu bindings documentation doesn't really talks much about usage of dma-ranges. Can someone help me with with the answer to - can we use 'dma-ranges' to limit a device's iova address access? If yes, then how? Yes, if the device has physical restrictions on what it can address, then "dma-ranges" is the correct way to describe that. That should be pretty much orthogonal to the IOMMU binding and combine in the obvious way, e.g.: ... soc { #address-cells = <1>; #size-cells = <1>; compatible = "simple-bus"; ranges; ... iommu@f000 { compatible = "iommu"; reg = <0xf000 0x1000>; #iommu-cells = <0>; }; ... subsystem { #address-cells = <1>; #size-cells = <1>; compatible = "simple-bus"; ranges; /* Devices can only drive address bits 0:23 */ dma-ranges = <0 0 0x100>; device { iommus = <>; }; }; }; ... In terms of Linux, for the straightforward platform device case of_dma_configure() initialises the subsystem devices' DMA masks based on the size covered by "dma-ranges", and the DMA API code respects the device's DMA mask when allocating IOVAs. The only problem is the bit in the middle where the device driver's dma_set_mask() call can just trash of_dma_configure()'s initial mask, because there's no way to differentiate an explicitly-specified mask from a default one. It's also even uglier for PCI devices since the existing "pass the host bridge's node as the device's" bodge happens to work for the "dma-coherent" property but is a bit broken in general and doesn't work at all for "dma-ranges". Fixing all of this (not to mention the DT/ACPI interaction aspect) has been hovering around #3 on my to-do list for the past couple of years now, but things keep sneaking in above it :( Robin. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Using dma-ranges with iommu to limit range of iova
Hi all, I have a question regarding usage of 'dma-ranges', can someone point me in the right direction? On qcom soc, few of the master devices with iommu attached to them, have limitations in using the iova address range. They can allow the iova to be only in a certain range, e.g. video codec firmware can only access iova only in a first few MBs as the video's arm core reset starts at 0x0. To do that, I earlier, had the understanding that we can modify the iommu_domain's geometry aperture. But that looks kind of a hacky way to get the domain for the device and modify the aperture. I was trying to explore if we can use the dma-ranges property. But the iommu bindings documentation doesn't really talks much about usage of dma-ranges. Can someone help me with with the answer to - can we use 'dma-ranges' to limit a device's iova address access? If yes, then how? TIF Regards Vivek ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu