Re: [PATCH/RFC] iommu/ipmmu-vmsa: IPMMU SYS-DMAC iova mapping workaround
Hi Magnus, On 2016-09-27 15:43:30 +0900, Magnus Damm wrote: > Hi Niklas, > > On Tue, Sep 27, 2016 at 3:20 PM, Niklas Söderlund >wrote: > > Hi Magnus, > > > > On 2016-09-20 20:54:33 +0900, Magnus Damm wrote: > >> From: Magnus Damm > >> > >> Here's some prototype code that works around the lack of software > >> support for mapping I/O devices to the SYS-DMAC hardware via the > >> DMA Engine framework when using IOMMU. > >> > >> The code itself is one big layering violation that goes through > >> the DT and unconditionally maps I/O devices using DMACs via the > >> IPMMU device instance into iova space with a 1:1 mapping. > >> > >> This very short term prototype will for instance automatically make > >> the SCIF serial port function with the IPMMU hardware in case the > >> SYS-DMAC is hooked up to the IPMMU device. > >> > >> Not to be confused with the more long term solution to allow the > >> DMA Engine framework to map I/O device memory dynamically. > > > > Good news, Vinod queued the dma_{map,unmap}_resource API and rcar-dmac > > usage of it yesterday \o/. > > Excellent. Are the DMA Engine slave devices supposed to work out of > the box with the IPMMU then, or is some other component missing? The DT and shmobile_defconfig patches are missing. If you enable CONFIG_IPMMU_VMSA and wire up DT (see bellow for Koelsch example) then all devices I have tried works (MMC, I2C and serial consoles). diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index 8f0086b..d19bffd 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -325,6 +325,21 @@ power-domains = < R8A7791_PD_ALWAYS_ON>; #dma-cells = <1>; dma-channels = <15>; + iommus = <_ds 0>, +<_ds 1>, +<_ds 2>, +<_ds 3>, +<_ds 4>, +<_ds 5>, +<_ds 6>, +<_ds 7>, +<_ds 8>, +<_ds 9>, +<_ds 10>, +<_ds 11>, +<_ds 12>, +<_ds 13>, +<_ds 14>; }; dmac1: dma-controller@e672 { @@ -356,6 +371,21 @@ power-domains = < R8A7791_PD_ALWAYS_ON>; #dma-cells = <1>; dma-channels = <15>; + iommus = <_ds 15>, +<_ds 16>, +<_ds 17>, +<_ds 18>, +<_ds 19>, +<_ds 20>, +<_ds 21>, +<_ds 22>, +<_ds 23>, +<_ds 24>, +<_ds 25>, +<_ds 26>, +<_ds 27>, +<_ds 28>, +<_ds 29>; }; audma0: dma-controller@ec70 { @@ -1693,7 +1723,7 @@ interrupts = , ; #iommu-cells = <1>; - status = "disabled"; + status = "okay"; }; ipmmu_mp: mmu@ec68 { Also please note that I'm having problems with the next branch of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/slave-dma.git and the commit 761ed4a (tty: serial_core: convert uart_close to use tty_port_close) together with a systemd init system. I have to revert to commit in order for the system to boot, but I will comment on that in a separate e-mail. -- Regards, Niklas Söderlund
Re: [PATCH/RFC] iommu/ipmmu-vmsa: IPMMU SYS-DMAC iova mapping workaround
Hi Niklas, On Tue, Sep 27, 2016 at 3:20 PM, Niklas Söderlundwrote: > Hi Magnus, > > On 2016-09-20 20:54:33 +0900, Magnus Damm wrote: >> From: Magnus Damm >> >> Here's some prototype code that works around the lack of software >> support for mapping I/O devices to the SYS-DMAC hardware via the >> DMA Engine framework when using IOMMU. >> >> The code itself is one big layering violation that goes through >> the DT and unconditionally maps I/O devices using DMACs via the >> IPMMU device instance into iova space with a 1:1 mapping. >> >> This very short term prototype will for instance automatically make >> the SCIF serial port function with the IPMMU hardware in case the >> SYS-DMAC is hooked up to the IPMMU device. >> >> Not to be confused with the more long term solution to allow the >> DMA Engine framework to map I/O device memory dynamically. > > Good news, Vinod queued the dma_{map,unmap}_resource API and rcar-dmac > usage of it yesterday \o/. Excellent. Are the DMA Engine slave devices supposed to work out of the box with the IPMMU then, or is some other component missing? Cheers, / magnus
Re: [PATCH/RFC] iommu/ipmmu-vmsa: IPMMU SYS-DMAC iova mapping workaround
Hi Magnus, On 2016-09-20 20:54:33 +0900, Magnus Damm wrote: > From: Magnus Damm> > Here's some prototype code that works around the lack of software > support for mapping I/O devices to the SYS-DMAC hardware via the > DMA Engine framework when using IOMMU. > > The code itself is one big layering violation that goes through > the DT and unconditionally maps I/O devices using DMACs via the > IPMMU device instance into iova space with a 1:1 mapping. > > This very short term prototype will for instance automatically make > the SCIF serial port function with the IPMMU hardware in case the > SYS-DMAC is hooked up to the IPMMU device. > > Not to be confused with the more long term solution to allow the > DMA Engine framework to map I/O device memory dynamically. Good news, Vinod queued the dma_{map,unmap}_resource API and rcar-dmac usage of it yesterday \o/. > > Not-Yet-Signed-off-by: Magnus Damm > --- > > Applies on top of: renesas-drivers-2016-09-13-v4.8-rc6 > > drivers/iommu/ipmmu-vmsa.c | 75 > > 1 file changed, 75 insertions(+) > > --- 0001/drivers/iommu/ipmmu-vmsa.c > +++ work/drivers/iommu/ipmmu-vmsa.c 2016-09-20 20:03:37.620607110 +0900 > @@ -19,6 +19,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -625,6 +626,78 @@ static void ipmmu_domain_free(struct iom > kfree(domain); > } > > +static void ipmmu_workaround_map(struct iommu_domain *io_domain, > + struct device *dma_dev, struct resource *res) > +{ > + phys_addr_t phys_addr; > + > + dev_info(dma_dev, "map %pr\n", res); > + > + phys_addr = iommu_iova_to_phys(io_domain, res->start); > + if (phys_addr) > + return; > + > + iommu_map(io_domain, res->start, res->start, > + ALIGN(resource_size(res), SZ_4K), > + IOMMU_READ | IOMMU_WRITE); > +} > + > +static void ipmmu_workaround_dt(struct iommu_domain *io_domain, > + struct device *dev, > + void (*match)(struct iommu_domain *io_domain, > + struct device *dma_dev, > + struct resource *res)) > +{ > + struct device_node *np = NULL; > + struct of_phandle_args dma_spec; > + struct resource r; > + int i, cnt; > + bool found; > + > + /* Locate I/O devices using the DMAC and map their registers */ > + while ((np = of_find_all_nodes(np))) { > + if (!of_find_property(np, "dmas", NULL)) > + continue; > + > + cnt = of_property_count_strings(np, "dma-names"); > + if (cnt < 0) > + continue; > + > + found = false; > + for (i = 0; i < cnt; i++) { > + if (of_parse_phandle_with_args(np, "dmas", > +"#dma-cells", i, > +_spec)) > + continue; > + > + if (dma_spec.np == dev->of_node) > + found = true; > + > + of_node_put(dma_spec.np); > + } > + > + if (!found) > + continue; > + > + i = 0; > + while (!of_address_to_resource(np, i, )) { > + match(io_domain, dev, ); > + i++; > + } > + } > +} > + > +static void ipmmu_workaround(struct iommu_domain *io_domain, > + struct device *dev) > +{ > + /* only apply workaround for DMA controllers */ > + if (!strstr(dev_name(dev), "dma-controller")) > + return; > + > + dev_info(dev, "Adding iommu workaround to map I/O devices for DMACs\n"); > + ipmmu_workaround_dt(io_domain, dev, ipmmu_workaround_map); > +} > + > static int ipmmu_attach_device(struct iommu_domain *io_domain, > struct device *dev) > { > @@ -678,6 +751,8 @@ static int ipmmu_attach_device(struct io > if (ret < 0) > return ret; > > + ipmmu_workaround(io_domain, dev); > + > for (i = 0; i < archdata->num_utlbs; ++i) > ipmmu_utlb_enable(domain, archdata->utlbs[i]); > -- Regards, Niklas Söderlund
[PATCH/RFC] iommu/ipmmu-vmsa: IPMMU SYS-DMAC iova mapping workaround
From: Magnus DammHere's some prototype code that works around the lack of software support for mapping I/O devices to the SYS-DMAC hardware via the DMA Engine framework when using IOMMU. The code itself is one big layering violation that goes through the DT and unconditionally maps I/O devices using DMACs via the IPMMU device instance into iova space with a 1:1 mapping. This very short term prototype will for instance automatically make the SCIF serial port function with the IPMMU hardware in case the SYS-DMAC is hooked up to the IPMMU device. Not to be confused with the more long term solution to allow the DMA Engine framework to map I/O device memory dynamically. Not-Yet-Signed-off-by: Magnus Damm --- Applies on top of: renesas-drivers-2016-09-13-v4.8-rc6 drivers/iommu/ipmmu-vmsa.c | 75 1 file changed, 75 insertions(+) --- 0001/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2016-09-20 20:03:37.620607110 +0900 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -625,6 +626,78 @@ static void ipmmu_domain_free(struct iom kfree(domain); } +static void ipmmu_workaround_map(struct iommu_domain *io_domain, +struct device *dma_dev, struct resource *res) +{ + phys_addr_t phys_addr; + + dev_info(dma_dev, "map %pr\n", res); + + phys_addr = iommu_iova_to_phys(io_domain, res->start); + if (phys_addr) + return; + + iommu_map(io_domain, res->start, res->start, + ALIGN(resource_size(res), SZ_4K), + IOMMU_READ | IOMMU_WRITE); +} + +static void ipmmu_workaround_dt(struct iommu_domain *io_domain, + struct device *dev, + void (*match)(struct iommu_domain *io_domain, + struct device *dma_dev, + struct resource *res)) +{ + struct device_node *np = NULL; + struct of_phandle_args dma_spec; + struct resource r; + int i, cnt; + bool found; + + /* Locate I/O devices using the DMAC and map their registers */ + while ((np = of_find_all_nodes(np))) { + if (!of_find_property(np, "dmas", NULL)) + continue; + + cnt = of_property_count_strings(np, "dma-names"); + if (cnt < 0) + continue; + + found = false; + for (i = 0; i < cnt; i++) { + if (of_parse_phandle_with_args(np, "dmas", + "#dma-cells", i, + _spec)) + continue; + + if (dma_spec.np == dev->of_node) + found = true; + + of_node_put(dma_spec.np); + } + + if (!found) + continue; + + i = 0; + while (!of_address_to_resource(np, i, )) { + match(io_domain, dev, ); + i++; + } + } +} + +static void ipmmu_workaround(struct iommu_domain *io_domain, +struct device *dev) +{ + /* only apply workaround for DMA controllers */ + if (!strstr(dev_name(dev), "dma-controller")) + return; + + dev_info(dev, "Adding iommu workaround to map I/O devices for DMACs\n"); + ipmmu_workaround_dt(io_domain, dev, ipmmu_workaround_map); +} + static int ipmmu_attach_device(struct iommu_domain *io_domain, struct device *dev) { @@ -678,6 +751,8 @@ static int ipmmu_attach_device(struct io if (ret < 0) return ret; + ipmmu_workaround(io_domain, dev); + for (i = 0; i < archdata->num_utlbs; ++i) ipmmu_utlb_enable(domain, archdata->utlbs[i]);