Re: [PATCH v10 0/10] iommu/vt-d: Fix intel vt-d faults in kdump kernel
On 05/04/15 at 06:23pm, Joerg Roedel wrote: > On Fri, Apr 24, 2015 at 04:49:57PM +0800, Dave Young wrote: > > I'm more than happy to see this issue can be fixed in the patchset, I > > do not agree to add the code there with such problems. OTOH, for now > > seems there's no way to fix it. > > And that's the point. We discuss this issue and possible solutions for > years by now, and what ZhenHua implemented is what we agreed to be the > best-effort on what we can do in the kdump case with IOMMU enabled. > > Of course there are still failure scenarios left, but that is not > different from systems without any IOMMU. The failure is nothing different, but as I said in another reply the difference is we could use corrupted data to possiblly cause more failure. Thanks Dave ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v9 0/10] iommu/vt-d: Fix intel vt-d faults in kdump kernel
On 05/04/15 at 01:05pm, Joerg Roedel wrote: > On Fri, Apr 03, 2015 at 04:40:31PM +0800, Dave Young wrote: > > Have not read all the patches, but I have a question, not sure this > > has been answered before. Old memory is not reliable, what if the old > > memory get corrupted before panic? Is it safe to continue using it in > > 2nd kernel, I worry that it will cause problems. > > Yes, the old memory could be corrupted, and there are more failure cases > left which we have no way of handling yet (if iommu data structures are > in kdump backup areas). > > The question is what to do if we find some of the old data structures > corrupted, hand how far should the tests go. Should we also check the > page-tables, for example? I think if some of the data structures for a > device are corrupted it probably already failed in the old kernel and > things won't get worse in the new one. I agree that we can do nothing with the old corrupted data, but I worry about the future corruption after using the old corrupted data. I wonder if we can mark all the oldmem as readonly so that we can lower the risk. Is it resonable? Thanks Dave ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v6 25/25] ARM: dts: exynos: add iommu reserved regions for bootloader's splash screen
2015-05-04 17:16 GMT+09:00 Marek Szyprowski : > Some bootloaders enable FIMD module and configure it as a simple > framebuffer to display boot logo or splash screen before booting the > kernel. Such framebuffer stays enabled until proper kernel driver gets > probbed. Usually it is configured in such a way, that it performs DMA > from the buffer located in system memory. To avoid IOMMU access fault > during system boot, additional identity mapping between system memory > and IO virtual address space must be created when IOMMU driver gets > enabled. > > Signed-off-by: Marek Szyprowski Acked-by: Krzysztof Kozlowski Best regards, Krzysztof ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v6 21/25] ARM: dts: exynos3250: add sysmmu nodes
2015-05-04 17:16 GMT+09:00 Marek Szyprowski : > This patch adds System MMU nodes to the devices that are specific to > Exynos3250 series. > > Signed-off-by: Marek Szyprowski Acked-by: Krzysztof Kozlowski Best regards, Krzysztof ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v6 20/25] ARM: dts: exynos4: add sysmmu nodes
2015-05-04 17:16 GMT+09:00 Marek Szyprowski : > This patch adds System MMU nodes that are specific to Exynos4210/4x12 series. > > Signed-off-by: Marek Szyprowski Acked-by: Krzysztof Kozlowski Best regards, Krzysztof ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v6 24/25] ARM: dts: exynos5420: add sysmmu nodes
2015-05-04 17:16 GMT+09:00 Marek Szyprowski : > This patch adds System MMU nodes to all defined devices that are specific > to Exynos5420/5800/5422 series. > > Signed-off-by: Marek Szyprowski Acked-by: Krzysztof Kozlowski Best regards, Krzysztof ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v6 01/25] arm: dma-mapping: add support for creating reserved mappings in iova space
On Mon, May 4, 2015 at 3:15 AM, Marek Szyprowski wrote: > Some devices (like frame buffers) are enabled by bootloader and configured > to perform DMA operations automatically (like displaying boot logo or splash > screen). Such devices operate and perform DMA operation usually until the > proper driver for them is loaded and probed. However before that happens, > system usually loads IOMMU drivers and configures dma parameters for each > device. When such initial configuration is created and enabled, it usually > contains empty translation rules betweem IO address space and physical > memory, because no buffers nor memory regions have been requested by the > respective driver. > > This patch adds support for "iommu-reserved-mapping", which can be used > to provide definitions for mappings that need to be created on system > boot to let such devices (enabled by bootloader) to operate properly > until respective driver is probed. > > Signed-off-by: Marek Szyprowski > --- > Documentation/devicetree/bindings/iommu/iommu.txt | 44 + > arch/arm/mm/dma-mapping.c | 112 > ++ > 2 files changed, 156 insertions(+) > > diff --git a/Documentation/devicetree/bindings/iommu/iommu.txt > b/Documentation/devicetree/bindings/iommu/iommu.txt > index 5a8b4624defc..fd54e6b597f0 100644 > --- a/Documentation/devicetree/bindings/iommu/iommu.txt > +++ b/Documentation/devicetree/bindings/iommu/iommu.txt > @@ -86,6 +86,35 @@ have a means to turn off translation. But it is invalid in > such cases to > disable the IOMMU's device tree node in the first place because it would > prevent any driver from properly setting up the translations. > > +Optional properties: > + > +- iommu-reserved-mapping: A list of entries describing additional > + reserved mapping, that will be inserted to the default IO address space > + created for given master device. Each entry consist of IO address, > + physical memory address and size of the region. > + > +Some devices (like frame buffers) are enabled by bootloader and configured > +to perform DMA operations automatically (like displaying boot logo or splash > +screen). Such devices operate and perform DMA operation usually until the > +proper driver for them is loaded and probed. However before that happens, > +system usually loads IOMMU drivers and configures dma parameters for each s/dma/DMA/ > +device. When such initial configuration is created and enabled, it usually > +contains empty translation rules betweem IO address space and physical s/betweem/between/ > +memory, because no buffers nor memory regions have been requested by the > +respective driver. > + > +To avoid IOMMU page fault, one can provide "iommu-reserved-mapping" > +property, which defines all memory regions which must be mapped to IO > +address space to boot properly when device has been enabled by the > +bootloader. More than one region can be defined for given master device. > +Each region is defined by the following triplet: first entry is IO > +address (encoded in "address" cells), second is base physical memory > +address for this regions (also encoded in "address" cells) and the last > +is size of the region (encoded in "size" cells). To ensure that that > +given master device will not trigger page fault after enabling IOMMU, > +one should define identity mapping between physical memory and IO > +address space for the range of addresses accessed by the device. > + > > Notes: > == > @@ -113,6 +142,21 @@ Single-master IOMMU: > iommus = <&{/iommu}>; > }; > > + > +Single-master IOMMU, which has been left enabled by bootloader: > +--- > + > + iommu { > + #iommu-cells = <0>; > + }; > + > + master { > + iommus = <&{/iommu}>; > + /* bootloader configures framebuffer at 0x4000 (32MiB) > + iommu-reserved-mapping = <0x4000 0x4000 0x200>; Is there not an ordering problem if kernel initializes the IOMMU before parsing this for each master? I would think the IOMMU driver needs to find all of these mappings and cleanly switch the page tables with the new reserved mapping. Rob ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v6 22/25] ARM: dts: exynos4415: add sysmmu nodes
2015-05-04 17:16 GMT+09:00 Marek Szyprowski : > This patch adds System MMU nodes to all defined devices that are specific > to Exynos4415 series. > > Signed-off-by: Marek Szyprowski Acked-by: Krzysztof Kozlowski Best regards, Krzysztof ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v6 23/25] ARM: dts: exynos5250: add sysmmu nodes
2015-05-04 17:16 GMT+09:00 Marek Szyprowski : > This patch adds System MMU nodes to all defined devices that are specific > to Exynos5250 series. > > Signed-off-by: Marek Szyprowski Acked-by: Krzysztof Kozlowski Best regards, Krzysztof ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v10 0/10] iommu/vt-d: Fix intel vt-d faults in kdump kernel
On Fri, Apr 24, 2015 at 04:49:57PM +0800, Dave Young wrote: > I'm more than happy to see this issue can be fixed in the patchset, I > do not agree to add the code there with such problems. OTOH, for now > seems there's no way to fix it. And that's the point. We discuss this issue and possible solutions for years by now, and what ZhenHua implemented is what we agreed to be the best-effort on what we can do in the kdump case with IOMMU enabled. Of course there are still failure scenarios left, but that is not different from systems without any IOMMU. Joerg ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v9 0/10] iommu/vt-d: Fix intel vt-d faults in kdump kernel
On 05/04/2015 07:05 AM, Joerg Roedel wrote: On Fri, Apr 03, 2015 at 04:40:31PM +0800, Dave Young wrote: Have not read all the patches, but I have a question, not sure this has been answered before. Old memory is not reliable, what if the old memory get corrupted before panic? Is it safe to continue using it in 2nd kernel, I worry that it will cause problems. Yes, the old memory could be corrupted, and there are more failure cases left which we have no way of handling yet (if iommu data structures are in kdump backup areas). The question is what to do if we find some of the old data structures corrupted, hand how far should the tests go. Should we also check the page-tables, for example? I think if some of the data structures for a device are corrupted it probably already failed in the old kernel and things won't get worse in the new one. So checking is not strictly necessary in the first version of these patches (unless we find a valid failure scenario). Once we have some good plan on what to do if we find corruption, we can add checking of course. Regards, Joerg Agreed. This is a significant improvement over what we (don') have. Corruption related to IOMMU must occur within the host, and it must be a software corruption, b/c the IOMMU inherently protects itself by protecting all of memory from errant DMAs. Therefore, if the only IOMMU corruptor is in the host, it's likely the entire host kernel crash dump will either be useless, or corrupted by the security breach, at which point, this is just another scenario of a failed crash dump that will never be taken. The kernel can't protect the mapping tables, which are the most likely area to be corrupted, b/c it'd (minimally) have to be per-device (to avoid locking & coherency issues), and would require significant overhead to keep/update a checksum-like scheme on (potentially) 4 levels of page tables. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH] iommu/amd: Fix bug in put_pasid_state_wait
On Thu, Apr 16, 2015 at 05:08:44PM +0300, Oded Gabbay wrote: > This patch fixes a bug in put_pasid_state_wait that appeared in kernel 4.0 > The bug is that pasid_state->count wasn't decremented before entering the > wait_event. Thus, the condition in wait_event will never be true. > > The fix is to decrement (atomically) the pasid_state->count before the > wait_event. Gah! This issue was already pointed out in the original review of the patch, looks like I applied the wrong version. Thanks for the fix, I applied it to iommu/fixes. Joerg ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: Any side effect if turn off amd_iommu
Hi Acelan, On Thu, Apr 23, 2015 at 10:15:33AM +0800, AceLan Kao wrote: > We can confirm that the issue comes from the resources conflict, > adding this boot option can solve the issue. >ivrs_ioapic[5]=00:00.1 > We've tried to negotiate with the OEM BIOS team, but they refused to > modify the BIOS code, since there is no issue on MS Windows and it'll > require to re-start a full test if the BIOS code is changed, so they > don't want to do that. > > I'm wondering if we can add a quirk to list those machine and assign > them the correct ivrs_ioapic value in amd_iommu driver? It is probably hard to match a specific machine which has the bug. What do you think would be a good indicator to check whether this BIOS bug is present? Joerg ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v9 0/10] iommu/vt-d: Fix intel vt-d faults in kdump kernel
On Fri, Apr 03, 2015 at 04:40:31PM +0800, Dave Young wrote: > Have not read all the patches, but I have a question, not sure this > has been answered before. Old memory is not reliable, what if the old > memory get corrupted before panic? Is it safe to continue using it in > 2nd kernel, I worry that it will cause problems. Yes, the old memory could be corrupted, and there are more failure cases left which we have no way of handling yet (if iommu data structures are in kdump backup areas). The question is what to do if we find some of the old data structures corrupted, hand how far should the tests go. Should we also check the page-tables, for example? I think if some of the data structures for a device are corrupted it probably already failed in the old kernel and things won't get worse in the new one. So checking is not strictly necessary in the first version of these patches (unless we find a valid failure scenario). Once we have some good plan on what to do if we find corruption, we can add checking of course. Regards, Joerg ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 27/26] iommu: exynos: add system suspend/resume support
When system goes into suspend state, iommu should save it's state and restore after system resume. This is handled by 'late' pm ops to ensure that sysmmu will be suspended after its master devices and restored before them. Signed-off-by: Marek Szyprowski --- Hello, This patch got lost in the rebase, I'm really sorry. Please process it together with other iommu patches from "[PATCH v6 00/25] Exynos SYSMMU (IOMMU) integration with DT and DMA-mapping subsystem" patchset. Best regards Marek Szyprowski Samsung R&D Institute Poland --- drivers/iommu/exynos-iommu.c | 31 +++ 1 file changed, 31 insertions(+) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 821797328c52..074e6cb05cc8 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -606,6 +606,36 @@ static int __init exynos_sysmmu_probe(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int exynos_sysmmu_suspend(struct device *dev) +{ + struct sysmmu_drvdata *data = dev_get_drvdata(dev); + + dev_dbg(dev, "suspend\n"); + if (is_sysmmu_active(data)) { + __sysmmu_disable_nocount(data); + pm_runtime_put(dev); + } + return 0; +} + +static int exynos_sysmmu_resume(struct device *dev) +{ + struct sysmmu_drvdata *data = dev_get_drvdata(dev); + + dev_dbg(dev, "resume\n"); + if (is_sysmmu_active(data)) { + pm_runtime_get_sync(dev); + __sysmmu_enable_nocount(data); + } + return 0; +} +#endif + +static const struct dev_pm_ops sysmmu_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(exynos_sysmmu_suspend, exynos_sysmmu_resume) +}; + static const struct of_device_id sysmmu_of_match[] __initconst = { { .compatible = "samsung,exynos-sysmmu", }, { }, @@ -616,6 +646,7 @@ static struct platform_driver exynos_sysmmu_driver __refdata = { .driver = { .name = "exynos-sysmmu", .of_match_table = sysmmu_of_match, + .pm = &sysmmu_pm_ops, } }; -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 21/25] ARM: dts: exynos3250: add sysmmu nodes
This patch adds System MMU nodes to the devices that are specific to Exynos3250 series. Signed-off-by: Marek Szyprowski --- arch/arm/boot/dts/exynos3250.dtsi | 22 ++ 1 file changed, 22 insertions(+) diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi index e3bfb11c6ef8..36361e0cb802 100644 --- a/arch/arm/boot/dts/exynos3250.dtsi +++ b/arch/arm/boot/dts/exynos3250.dtsi @@ -251,6 +251,7 @@ clocks = <&cmu CLK_SCLK_FIMD0>, <&cmu CLK_FIMD0>; clock-names = "sclk_fimd", "fimd"; power-domains = <&pd_lcd0>; + iommus = <&sysmmu_fimd0>; samsung,sysreg = <&sys_reg>; status = "disabled"; }; @@ -270,6 +271,16 @@ status = "disabled"; }; + sysmmu_fimd0: sysmmu@11E2 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x11e2 0x1000>; + interrupts = <0 80 0>, <0 81 0>; + clock-names = "sysmmu", "master"; + clocks = <&cmu CLK_SMMUFIMD0>, <&cmu CLK_FIMD0>; + samsung,power-domain = <&pd_lcd0>; + #iommu-cells = <0>; + }; + hsotg: hsotg@1248 { compatible = "snps,dwc2"; reg = <0x1248 0x2>; @@ -364,9 +375,20 @@ clock-names = "mfc", "sclk_mfc"; clocks = <&cmu CLK_MFC>, <&cmu CLK_SCLK_MFC>; power-domains = <&pd_mfc>; + iommus = <&sysmmu_mfc>; status = "disabled"; }; + sysmmu_mfc: sysmmu@1362 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x1362 0x1000>; + interrupts = <0 96 0>, <0 98 0>; + clock-names = "sysmmu", "master"; + clocks = <&cmu CLK_SMMUMFC_L>, <&cmu CLK_MFC>; + samsung,power-domain = <&pd_mfc>; + #iommu-cells = <0>; + }; + serial_0: serial@1380 { compatible = "samsung,exynos4210-uart"; reg = <0x1380 0x100>; -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 25/25] ARM: dts: exynos: add iommu reserved regions for bootloader's splash screen
Some bootloaders enable FIMD module and configure it as a simple framebuffer to display boot logo or splash screen before booting the kernel. Such framebuffer stays enabled until proper kernel driver gets probbed. Usually it is configured in such a way, that it performs DMA from the buffer located in system memory. To avoid IOMMU access fault during system boot, additional identity mapping between system memory and IO virtual address space must be created when IOMMU driver gets enabled. Signed-off-by: Marek Szyprowski --- arch/arm/boot/dts/exynos3250-rinato.dts | 1 + arch/arm/boot/dts/exynos4210-trats.dts | 1 + arch/arm/boot/dts/exynos4210-universal_c210.dts | 1 + arch/arm/boot/dts/exynos4412-trats2.dts | 1 + arch/arm/boot/dts/exynos5250-snow.dts | 1 + arch/arm/boot/dts/exynos5250-spring.dts | 1 + arch/arm/boot/dts/exynos5420-peach-pit.dts | 1 + arch/arm/boot/dts/exynos5800-peach-pi.dts | 1 + 8 files changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/exynos3250-rinato.dts b/arch/arm/boot/dts/exynos3250-rinato.dts index 0b9906880c0c..71641f47f6bb 100644 --- a/arch/arm/boot/dts/exynos3250-rinato.dts +++ b/arch/arm/boot/dts/exynos3250-rinato.dts @@ -203,6 +203,7 @@ &fimd { status = "okay"; + iommu-reserved-mapping = <0x4000 0x4000 0x1ff0>; i80-if-timings { cs-setup = <0>; diff --git a/arch/arm/boot/dts/exynos4210-trats.dts b/arch/arm/boot/dts/exynos4210-trats.dts index 32c5fd8f6269..becc84b881a6 100644 --- a/arch/arm/boot/dts/exynos4210-trats.dts +++ b/arch/arm/boot/dts/exynos4210-trats.dts @@ -424,6 +424,7 @@ fimd@11c0 { status = "okay"; + iommu-reserved-mapping = <0x4000 0x4000 0x4000>; }; tmu@100C { diff --git a/arch/arm/boot/dts/exynos4210-universal_c210.dts b/arch/arm/boot/dts/exynos4210-universal_c210.dts index d4f2b11319dd..ecc95263ff4c 100644 --- a/arch/arm/boot/dts/exynos4210-universal_c210.dts +++ b/arch/arm/boot/dts/exynos4210-universal_c210.dts @@ -450,6 +450,7 @@ pinctrl-0 = <&lcd_clk>, <&lcd_data24>; pinctrl-names = "default"; status = "okay"; + iommu-reserved-mapping = <0x4000 0x4000 0x2000>; samsung,invert-vden; samsung,invert-vclk; #address-cells = <1>; diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts index 173ffa479ad3..78532629f396 100644 --- a/arch/arm/boot/dts/exynos4412-trats2.dts +++ b/arch/arm/boot/dts/exynos4412-trats2.dts @@ -758,6 +758,7 @@ fimd@11c0 { status = "okay"; + iommu-reserved-mapping = <0x4000 0x4000 0x4000>; }; camera: camera { diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts index 2657e842e5a5..9f2e992cb396 100644 --- a/arch/arm/boot/dts/exynos5250-snow.dts +++ b/arch/arm/boot/dts/exynos5250-snow.dts @@ -286,6 +286,7 @@ &fimd { status = "okay"; + iommu-reserved-mapping = <0x4000 0x4000 0x8000>; samsung,invert-vclk; }; diff --git a/arch/arm/boot/dts/exynos5250-spring.dts b/arch/arm/boot/dts/exynos5250-spring.dts index d03f9b8d376d..334d98925d4b 100644 --- a/arch/arm/boot/dts/exynos5250-spring.dts +++ b/arch/arm/boot/dts/exynos5250-spring.dts @@ -84,6 +84,7 @@ &fimd { status = "okay"; + iommu-reserved-mapping = <0x4000 0x4000 0x8000>; samsung,invert-vclk; }; diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts index 0788d08fb43e..edc3976665d0 100644 --- a/arch/arm/boot/dts/exynos5420-peach-pit.dts +++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts @@ -166,6 +166,7 @@ &fimd { status = "okay"; + iommu-reserved-mapping = <0x2000 0x2000 0x8000>; samsung,invert-vclk; }; diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts index 412f41d62686..ac5a67a3ce48 100644 --- a/arch/arm/boot/dts/exynos5800-peach-pi.dts +++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts @@ -153,6 +153,7 @@ &fimd { status = "okay"; + iommu-reserved-mapping = <0x2000 0x2000 0x8000>; samsung,invert-vclk; }; -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 23/25] ARM: dts: exynos5250: add sysmmu nodes
This patch adds System MMU nodes to all defined devices that are specific to Exynos5250 series. Signed-off-by: Marek Szyprowski --- arch/arm/boot/dts/exynos5250.dtsi | 250 ++ 1 file changed, 250 insertions(+) diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index 257e2f10525d..96471eabeb24 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -230,6 +230,7 @@ interrupts = <0 91 0>; clocks = <&clock CLK_G2D>; clock-names = "fimg2d"; + iommus = <&sysmmu_g2d>; }; mfc: codec@1100 { @@ -239,6 +240,8 @@ power-domains = <&pd_mfc>; clocks = <&clock CLK_MFC>; clock-names = "mfc"; + iommus = <&sysmmu_mfc_l>, <&sysmmu_mfc_r>; + iommu-names = "left", "right"; }; rtc: rtc@101E { @@ -720,6 +723,7 @@ power-domains = <&pd_gsc>; clocks = <&clock CLK_GSCL0>; clock-names = "gscl"; + iommu = <&sysmmu_gsc1>; }; gsc_1: gsc@13e1 { @@ -729,6 +733,7 @@ power-domains = <&pd_gsc>; clocks = <&clock CLK_GSCL1>; clock-names = "gscl"; + iommu = <&sysmmu_gsc1>; }; gsc_2: gsc@13e2 { @@ -738,6 +743,7 @@ power-domains = <&pd_gsc>; clocks = <&clock CLK_GSCL2>; clock-names = "gscl"; + iommu = <&sysmmu_gsc2>; }; gsc_3: gsc@13e3 { @@ -747,6 +753,7 @@ power-domains = <&pd_gsc>; clocks = <&clock CLK_GSCL3>; clock-names = "gscl"; + iommu = <&sysmmu_gsc3>; }; hdmi: hdmi { @@ -770,6 +777,7 @@ clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>, <&clock CLK_SCLK_HDMI>; clock-names = "mixer", "hdmi", "sclk_hdmi"; + iommus = <&sysmmu_tv>; }; dp_phy: video-phy@10040720 { @@ -790,6 +798,7 @@ power-domains = <&pd_disp1>; clocks = <&clock CLK_SCLK_FIMD1>, <&clock CLK_FIMD1>; clock-names = "sclk_fimd", "fimd"; + iommus = <&sysmmu_fimd1>; }; adc: adc@12D1 { @@ -811,4 +820,245 @@ clocks = <&clock CLK_SSS>; clock-names = "secss"; }; + + sysmmu_gsc0: sysmmu@13E8 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x13E8 0x1000>; + interrupt-parent = <&combiner>; + interrupts = <2 0>; + power-domains = <&pd_gsc>; + clock-names = "sysmmu", "master"; + clocks = <&clock CLK_SMMU_GSCL0>, <&clock CLK_GSCL0>; + #iommu-cells = <0>; + }; + + sysmmu_gsc1: sysmmu@13E9 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x13E9 0x1000>; + interrupt-parent = <&combiner>; + interrupts = <2 2>; + power-domains = <&pd_gsc>; + clock-names = "sysmmu", "master"; + clocks = <&clock CLK_SMMU_GSCL1>, <&clock CLK_GSCL1>; + #iommu-cells = <0>; + }; + + sysmmu_gsc2: sysmmu@13EA { + compatible = "samsung,exynos-sysmmu"; + reg = <0x13EA 0x1000>; + interrupt-parent = <&combiner>; + interrupts = <2 4>; + power-domains = <&pd_gsc>; + clock-names = "sysmmu", "master"; + clocks = <&clock CLK_SMMU_GSCL2>, <&clock CLK_GSCL2>; + #iommu-cells = <0>; + }; + + sysmmu_gsc3: sysmmu@13EB { + compatible = "samsung,exynos-sysmmu"; + reg = <0x13EB 0x1000>; + interrupt-parent = <&combiner>; + interrupts = <2 6>; + power-domains = <&pd_gsc>; + clock-names = "sysmmu", "master"; + clocks = <&clock CLK_SMMU_GSCL3>, <&clock CLK_GSCL3>; + #iommu-cells = <0>; + }; + + sysmmu_mfc_r: sysmmu@1120 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x1120 0x1000>; + interrupt-parent = <&combiner>; + interrupts = <6 2>; + power-domains = <&pd_mfc>; + clock-names = "sysmmu", "master"; + clocks = <&clock CLK_SMMU_MFCR>, <&clock CLK_MFC>; + #iommu-cells = <0>; + }; + + sysmmu_mfc_l: sysmmu@1121 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x1121 0x1000>; + interrupt-parent = <&combiner>; + interrupts = <8 5>; + power-domains = <&pd_mfc>; + clock-names =
[PATCH v6 24/25] ARM: dts: exynos5420: add sysmmu nodes
This patch adds System MMU nodes to all defined devices that are specific to Exynos5420/5800/5422 series. Signed-off-by: Marek Szyprowski --- arch/arm/boot/dts/exynos5420.dtsi | 181 ++ 1 file changed, 181 insertions(+) diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi index f67b23f303c3..7fdab914703f 100644 --- a/arch/arm/boot/dts/exynos5420.dtsi +++ b/arch/arm/boot/dts/exynos5420.dtsi @@ -179,6 +179,8 @@ clocks = <&clock CLK_MFC>; clock-names = "mfc"; power-domains = <&mfc_pd>; + iommus = <&sysmmu_mfc_l>, <&sysmmu_mfc_r>; + iommu-names = "left", "right"; }; mmc_0: mmc@1220 { @@ -561,6 +563,8 @@ clocks = <&clock CLK_SCLK_FIMD1>, <&clock CLK_FIMD1>; clock-names = "sclk_fimd", "fimd"; power-domains = <&disp_pd>; + iommus = <&sysmmu_fimd1_0>, <&sysmmu_fimd1_1>; + iommu-names = "m0", "m1"; }; adc: adc@12D1 { @@ -748,6 +752,7 @@ clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>, <&clock CLK_SCLK_HDMI>; clock-names = "mixer", "hdmi", "sclk_hdmi"; + iommus = <&sysmmu_tv>; power-domains = <&disp_pd>; }; @@ -758,6 +763,7 @@ clocks = <&clock CLK_GSCL0>; clock-names = "gscl"; power-domains = <&gsc_pd>; + iommus = <&sysmmu_gscl0>; }; gsc_1: video-scaler@13e1 { @@ -767,6 +773,7 @@ clocks = <&clock CLK_GSCL1>; clock-names = "gscl"; power-domains = <&gsc_pd>; + iommus = <&sysmmu_gscl1>; }; pmu_system_controller: system-controller@1004 { @@ -961,4 +968,178 @@ samsung,sysreg-phandle = <&sysreg_system_controller>; samsung,pmureg-phandle = <&pmu_system_controller>; }; + + sysmmu_g2dr: sysmmu@0x10A6 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x10A6 0x1000>; + interrupt-parent = <&combiner>; + interrupts = <24 5>; + clock-names = "sysmmu", "master"; + clocks = <&clock CLK_SMMU_G2D>, <&clock CLK_G2D>; + #iommu-cells = <0>; + }; + + sysmmu_g2dw: sysmmu@0x10A7 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x10A7 0x1000>; + interrupt-parent = <&combiner>; + interrupts = <22 2>; + clock-names = "sysmmu", "master"; + clocks = <&clock CLK_SMMU_G2D>, <&clock CLK_G2D>; + #iommu-cells = <0>; + }; + + sysmmu_tv: sysmmu@0x1465 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x1465 0x1000>; + interrupt-parent = <&combiner>; + interrupts = <7 4>; + clock-names = "sysmmu", "master"; + clocks = <&clock CLK_SMMU_MIXER>, <&clock CLK_MIXER>; + samsung,power-domain = <&disp_pd>; + #iommu-cells = <0>; + }; + + sysmmu_gscl0: sysmmu@0x13E8 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x13E8 0x1000>; + interrupt-parent = <&combiner>; + interrupts = <2 0>; + clock-names = "sysmmu", "master"; + clocks = <&clock CLK_SMMU_GSCL0>, <&clock CLK_GSCL0>; + power-domains = <&gsc_pd>; + #iommu-cells = <0>; + }; + + sysmmu_gscl1: sysmmu@0x13E9 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x13E9 0x1000>; + interrupt-parent = <&combiner>; + interrupts = <2 2>; + clock-names = "sysmmu", "master"; + clocks = <&clock CLK_SMMU_GSCL1>, <&clock CLK_GSCL1>; + power-domains = <&gsc_pd>; + #iommu-cells = <0>; + }; + + sysmmu_scaler0r: sysmmu@0x1288 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x1288 0x1000>; + interrupt-parent = <&combiner>; + interrupts = <22 4>; + clock-names = "sysmmu", "master"; + clocks = <&clock CLK_SMMU_MSCL0>, <&clock CLK_MSCL0>; + #iommu-cells = <0>; + }; + + sysmmu_scaler1r: sysmmu@0x1289 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x1289 0x1000>; + interrupts = <0 186 0>; + clock-names = "sysmmu", "master"; + clocks = <&clock CLK_SMMU_MSCL1>, <&clock CLK_MSCL1>; + #iommu-cells = <0>; + }; + + sysmmu_scaler2r: sysmmu@0x128A { + compatible = "samsung,exynos-sysmmu"; + re
[PATCH v6 22/25] ARM: dts: exynos4415: add sysmmu nodes
This patch adds System MMU nodes to all defined devices that are specific to Exynos4415 series. Signed-off-by: Marek Szyprowski --- arch/arm/boot/dts/exynos4415.dtsi | 11 +++ 1 file changed, 11 insertions(+) diff --git a/arch/arm/boot/dts/exynos4415.dtsi b/arch/arm/boot/dts/exynos4415.dtsi index 5caea996e090..7c4e44cfe75d 100644 --- a/arch/arm/boot/dts/exynos4415.dtsi +++ b/arch/arm/boot/dts/exynos4415.dtsi @@ -249,6 +249,7 @@ clocks = <&cmu CLK_SCLK_FIMD0>, <&cmu CLK_FIMD0>; clock-names = "sclk_fimd", "fimd"; samsung,power-domain = <&pd_lcd0>; + iommus = <&sysmmu_fimd0>; samsung,sysreg = <&sysreg_system_controller>; status = "disabled"; }; @@ -268,6 +269,16 @@ status = "disabled"; }; + sysmmu_fimd0: sysmmu@11E2 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x11e2 0x1000>; + interrupts = <0 80 0>, <0 81 0>; + clock-names = "sysmmu", "master"; + clocks = <&cmu CLK_SMMUFIMD0>, <&cmu CLK_FIMD0>; + samsung,power-domain = <&pd_lcd0>; + #iommu-cells = <0>; + }; + hsotg: hsotg@1248 { compatible = "samsung,s3c6400-hsotg"; reg = <0x1248 0x2>; -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 20/25] ARM: dts: exynos4: add sysmmu nodes
This patch adds System MMU nodes that are specific to Exynos4210/4x12 series. Signed-off-by: Marek Szyprowski --- arch/arm/boot/dts/exynos4.dtsi| 118 ++ arch/arm/boot/dts/exynos4210.dtsi | 23 arch/arm/boot/dts/exynos4x12.dtsi | 82 ++ 3 files changed, 223 insertions(+) diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi index e20cdc24c3bb..32593a8ac7c2 100644 --- a/arch/arm/boot/dts/exynos4.dtsi +++ b/arch/arm/boot/dts/exynos4.dtsi @@ -190,6 +190,7 @@ clock-names = "fimc", "sclk_fimc"; power-domains = <&pd_cam>; samsung,sysreg = <&sys_reg>; + iommus = <&sysmmu_fimc0>; status = "disabled"; }; @@ -201,6 +202,7 @@ clock-names = "fimc", "sclk_fimc"; power-domains = <&pd_cam>; samsung,sysreg = <&sys_reg>; + iommus = <&sysmmu_fimc1>; status = "disabled"; }; @@ -212,6 +214,7 @@ clock-names = "fimc", "sclk_fimc"; power-domains = <&pd_cam>; samsung,sysreg = <&sys_reg>; + iommus = <&sysmmu_fimc2>; status = "disabled"; }; @@ -223,6 +226,7 @@ clock-names = "fimc", "sclk_fimc"; power-domains = <&pd_cam>; samsung,sysreg = <&sys_reg>; + iommus = <&sysmmu_fimc3>; status = "disabled"; }; @@ -418,6 +422,8 @@ clocks = <&clock CLK_MFC>, <&clock CLK_SCLK_MFC>; clock-names = "mfc", "sclk_mfc"; status = "disabled"; + iommus = <&sysmmu_mfc_l>, <&sysmmu_mfc_r>; + iommu-names = "left", "right"; }; serial_0: serial@1380 { @@ -683,6 +689,7 @@ power-domains = <&pd_lcd0>; samsung,sysreg = <&sys_reg>; status = "disabled"; + iommus = <&sysmmu_fimd0>; }; tmu: tmu@100C { @@ -709,6 +716,7 @@ interrupts = <0 91 0>; reg = <0x12C1 0x2100>, <0x12c0 0x300>; power-domains = <&pd_tv>; + iommus = <&sysmmu_tv>; status = "disabled"; }; @@ -819,4 +827,114 @@ clock-names = "ppmu"; status = "disabled"; }; + + sysmmu_mfc_l: sysmmu@1362 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x1362 0x1000>; + interrupt-parent = <&combiner>; + interrupts = <5 5>; + clock-names = "sysmmu", "master"; + clocks = <&clock CLK_SMMU_MFCL>, <&clock CLK_MFC>; + power-domains = <&pd_mfc>; + #iommu-cells = <0>; + }; + + sysmmu_mfc_r: sysmmu@1363 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x1363 0x1000>; + interrupt-parent = <&combiner>; + interrupts = <5 6>; + clock-names = "sysmmu", "master"; + clocks = <&clock CLK_SMMU_MFCR>, <&clock CLK_MFC>; + power-domains = <&pd_mfc>; + #iommu-cells = <0>; + }; + + sysmmu_tv: sysmmu@12E2 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x12E2 0x1000>; + interrupt-parent = <&combiner>; + interrupts = <5 4>; + clock-names = "sysmmu", "master"; + clocks = <&clock CLK_SMMU_TV>, <&clock CLK_MIXER>; + power-domains = <&pd_tv>; + #iommu-cells = <0>; + }; + + sysmmu_fimc0: sysmmu@11A2 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x11A2 0x1000>; + interrupt-parent = <&combiner>; + interrupts = <4 2>; + clock-names = "sysmmu", "master"; + clocks = <&clock CLK_SMMU_FIMC0>, <&clock CLK_FIMC0>; + power-domains = <&pd_cam>; + #iommu-cells = <0>; + }; + + sysmmu_fimc1: sysmmu@11A3 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x11A3 0x1000>; + interrupt-parent = <&combiner>; + interrupts = <4 3>; + clock-names = "sysmmu", "master"; + clocks = <&clock CLK_SMMU_FIMC1>, <&clock CLK_FIMC1>; + power-domains = <&pd_cam>; + #iommu-cells = <0>; + }; + + sysmmu_fimc2: sysmmu@11A4 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x11A4 0x1000>; + interrupt-parent = <&combiner>; +
[PATCH v6 17/25] iommu: exynos: init from dt-specific callback instead of initcall
This patch introduces IOMMU_OF_DECLARE-based initialization to the driver, which replaces subsys_initcall-based procedure. exynos_iommu_of_setup ensures that each sysmmu controller is probed before its master device. Signed-off-by: Marek Szyprowski --- drivers/iommu/exynos-iommu.c | 30 -- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 5429e75b120c..94fbd870ede6 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -13,16 +13,21 @@ #endif #include +#include #include #include #include #include #include +#include +#include +#include #include #include #include #include +#include #include typedef u32 sysmmu_iova_t; @@ -1077,7 +1082,7 @@ static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *iommu_domain, return phys; } -static const struct iommu_ops exynos_iommu_ops = { +static struct iommu_ops exynos_iommu_ops = { .domain_alloc = exynos_iommu_domain_alloc, .domain_free = exynos_iommu_domain_free, .attach_dev = exynos_iommu_attach_device, @@ -1089,6 +1094,8 @@ static const struct iommu_ops exynos_iommu_ops = { .pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE, }; +static bool init_done; + static int __init exynos_iommu_init(void) { struct device_node *np; @@ -1128,6 +1135,8 @@ static int __init exynos_iommu_init(void) goto err_set_iommu; } + init_done = true; + return 0; err_set_iommu: kmem_cache_free(lv2table_kmem_cache, zero_lv2_table); @@ -1137,4 +1146,21 @@ err_reg_driver: kmem_cache_destroy(lv2table_kmem_cache); return ret; } -subsys_initcall(exynos_iommu_init); + +static int __init exynos_iommu_of_setup(struct device_node *np) +{ + struct platform_device *pdev; + + if (!init_done) + exynos_iommu_init(); + + pdev = of_platform_device_create(np, NULL, platform_bus_type.dev_root); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + of_iommu_set_ops(np, &exynos_iommu_ops); + return 0; +} + +IOMMU_OF_DECLARE(exynos_iommu_of, "samsung,exynos-sysmmu", +exynos_iommu_of_setup); -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 18/25] iommu: exynos: add callback for initializing devices from device tree
This patch adds implementation of of_xlate callback, which prepares masters device for attaching to IOMMU. This callback is called during creating devices from device tree. Signed-off-by: Marek Szyprowski --- drivers/iommu/exynos-iommu.c | 28 1 file changed, 28 insertions(+) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 94fbd870ede6..6e6b502ee2c9 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -1082,6 +1082,33 @@ static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *iommu_domain, return phys; } +static int exynos_iommu_of_xlate(struct device *dev, +struct of_phandle_args *spec) +{ + struct exynos_iommu_owner *owner = dev->archdata.iommu; + struct platform_device *sysmmu = of_find_device_by_node(spec->np); + struct sysmmu_drvdata *data; + + if (!sysmmu) + return -ENODEV; + + data = platform_get_drvdata(sysmmu); + if (!data) + return -ENODEV; + + if (!owner) { + owner = kzalloc(sizeof(*owner), GFP_KERNEL); + if (!owner) + return -ENOMEM; + + INIT_LIST_HEAD(&owner->clients); + dev->archdata.iommu = owner; + } + + list_add_tail(&data->owner_node, &owner->clients); + return 0; +} + static struct iommu_ops exynos_iommu_ops = { .domain_alloc = exynos_iommu_domain_alloc, .domain_free = exynos_iommu_domain_free, @@ -1092,6 +1119,7 @@ static struct iommu_ops exynos_iommu_ops = { .map_sg = default_iommu_map_sg, .iova_to_phys = exynos_iommu_iova_to_phys, .pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE, + .of_xlate = exynos_iommu_of_xlate, }; static bool init_done; -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 19/25] iommu: exynos: remove unneeded code
Once driver initialization has been moved from initcall to of_xlate() callback, this patch is no longer needed. Signed-off-by: Marek Szyprowski --- drivers/iommu/exynos-iommu.c | 7 --- 1 file changed, 7 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 6e6b502ee2c9..821797328c52 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -1126,15 +1126,8 @@ static bool init_done; static int __init exynos_iommu_init(void) { - struct device_node *np; int ret; - np = of_find_matching_node(NULL, sysmmu_of_match); - if (!np) - return 0; - - of_node_put(np); - lv2table_kmem_cache = kmem_cache_create("exynos-iommu-lv2table", LV2TABLE_SIZE, LV2TABLE_SIZE, 0, NULL); if (!lv2table_kmem_cache) { -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 13/25] iommu: exynos: rename variables to reflect their purpose
This patch renames some variables to make the code easier to understand. 'domain' is replaced by 'iommu_domain' (more generic entity) and really meaningless 'priv' by 'domain' to reflect its purpose. Signed-off-by: Marek Szyprowski --- drivers/iommu/exynos-iommu.c | 187 ++- 1 file changed, 94 insertions(+), 93 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 734107ec78fa..a58f4a4c91d0 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -436,8 +436,8 @@ static void __sysmmu_enable_nocount(struct sysmmu_drvdata *data) clk_disable(data->clk_master); } -static int __sysmmu_enable(struct sysmmu_drvdata *data, - phys_addr_t pgtable, struct iommu_domain *domain) +static int __sysmmu_enable(struct sysmmu_drvdata *data, phys_addr_t pgtable, + struct iommu_domain *iommu_domain) { int ret = 0; unsigned long flags; @@ -445,7 +445,7 @@ static int __sysmmu_enable(struct sysmmu_drvdata *data, spin_lock_irqsave(&data->lock, flags); if (set_sysmmu_active(data)) { data->pgtable = pgtable; - data->domain = domain; + data->domain = iommu_domain; __sysmmu_enable_nocount(data); @@ -610,91 +610,91 @@ static inline void pgtable_flush(void *vastart, void *vaend) static struct iommu_domain *exynos_iommu_domain_alloc(unsigned type) { - struct exynos_iommu_domain *exynos_domain; + struct exynos_iommu_domain *domain; int i; if (type != IOMMU_DOMAIN_UNMANAGED) return NULL; - exynos_domain = kzalloc(sizeof(*exynos_domain), GFP_KERNEL); - if (!exynos_domain) + domain = kzalloc(sizeof(*domain), GFP_KERNEL); + if (!domain) return NULL; - exynos_domain->pgtable = (sysmmu_pte_t *)__get_free_pages(GFP_KERNEL, 2); - if (!exynos_domain->pgtable) + domain->pgtable = (sysmmu_pte_t *)__get_free_pages(GFP_KERNEL, 2); + if (!domain->pgtable) goto err_pgtable; - exynos_domain->lv2entcnt = (short *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1); - if (!exynos_domain->lv2entcnt) + domain->lv2entcnt = (short *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1); + if (!domain->lv2entcnt) goto err_counter; /* Workaround for System MMU v3.3 to prevent caching 1MiB mapping */ for (i = 0; i < NUM_LV1ENTRIES; i += 8) { - exynos_domain->pgtable[i + 0] = ZERO_LV2LINK; - exynos_domain->pgtable[i + 1] = ZERO_LV2LINK; - exynos_domain->pgtable[i + 2] = ZERO_LV2LINK; - exynos_domain->pgtable[i + 3] = ZERO_LV2LINK; - exynos_domain->pgtable[i + 4] = ZERO_LV2LINK; - exynos_domain->pgtable[i + 5] = ZERO_LV2LINK; - exynos_domain->pgtable[i + 6] = ZERO_LV2LINK; - exynos_domain->pgtable[i + 7] = ZERO_LV2LINK; + domain->pgtable[i + 0] = ZERO_LV2LINK; + domain->pgtable[i + 1] = ZERO_LV2LINK; + domain->pgtable[i + 2] = ZERO_LV2LINK; + domain->pgtable[i + 3] = ZERO_LV2LINK; + domain->pgtable[i + 4] = ZERO_LV2LINK; + domain->pgtable[i + 5] = ZERO_LV2LINK; + domain->pgtable[i + 6] = ZERO_LV2LINK; + domain->pgtable[i + 7] = ZERO_LV2LINK; } - pgtable_flush(exynos_domain->pgtable, exynos_domain->pgtable + NUM_LV1ENTRIES); + pgtable_flush(domain->pgtable, domain->pgtable + NUM_LV1ENTRIES); - spin_lock_init(&exynos_domain->lock); - spin_lock_init(&exynos_domain->pgtablelock); - INIT_LIST_HEAD(&exynos_domain->clients); + spin_lock_init(&domain->lock); + spin_lock_init(&domain->pgtablelock); + INIT_LIST_HEAD(&domain->clients); - exynos_domain->domain.geometry.aperture_start = 0; - exynos_domain->domain.geometry.aperture_end = ~0UL; - exynos_domain->domain.geometry.force_aperture = true; + domain->domain.geometry.aperture_start = 0; + domain->domain.geometry.aperture_end = ~0UL; + domain->domain.geometry.force_aperture = true; - return &exynos_domain->domain; + return &domain->domain; err_counter: - free_pages((unsigned long)exynos_domain->pgtable, 2); + free_pages((unsigned long)domain->pgtable, 2); err_pgtable: - kfree(exynos_domain); + kfree(domain); return NULL; } -static void exynos_iommu_domain_free(struct iommu_domain *domain) +static void exynos_iommu_domain_free(struct iommu_domain *iommu_domain) { - struct exynos_iommu_domain *priv = to_exynos_domain(domain); + struct exynos_iommu_domain *domain = to_exynos_domain(iommu_domain); struct sysmmu_drvdata *data; unsigned long flags; int i; - WARN_ON(!lis
[PATCH v6 07/25] iommu: exynos: remove useless spinlock
This patch removes useless spinlocks and other unused members from struct exynos_iommu_owner. There is no point is protecting this structure by spinlock because content of this structure doesn't change and other structures have their own spinlocks. Signed-off-by: Marek Szyprowski --- drivers/iommu/exynos-iommu.c | 11 --- 1 file changed, 11 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 98aa7e9c2507..c307c400613c 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -189,9 +189,6 @@ struct exynos_iommu_owner { struct list_head client; /* entry of exynos_iommu_domain.clients */ struct device *dev; struct device *sysmmu; - struct iommu_domain *domain; - void *vmm_data; /* IO virtual memory manager's data */ - spinlock_t lock;/* Lock to preserve consistency of System MMU */ }; struct exynos_iommu_domain { @@ -483,16 +480,12 @@ static int __exynos_sysmmu_enable(struct device *dev, phys_addr_t pgtable, BUG_ON(!has_sysmmu(dev)); - spin_lock_irqsave(&owner->lock, flags); - data = dev_get_drvdata(owner->sysmmu); ret = __sysmmu_enable(data, pgtable, domain); if (ret >= 0) data->master = dev; - spin_unlock_irqrestore(&owner->lock, flags); - return ret; } @@ -505,16 +498,12 @@ static bool exynos_sysmmu_disable(struct device *dev) BUG_ON(!has_sysmmu(dev)); - spin_lock_irqsave(&owner->lock, flags); - data = dev_get_drvdata(owner->sysmmu); disabled = __sysmmu_disable(data); if (disabled) data->master = NULL; - spin_unlock_irqrestore(&owner->lock, flags); - return disabled; } -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 10/25] iommu: exynos: remove useless device_add/remove callbacks
The driver doesn't need to do anything important in device add/remove callbacks, because initialization will be done from device-tree specific callbacks added later. IOMMU groups created by current code were never used. Signed-off-by: Marek Szyprowski --- drivers/iommu/exynos-iommu.c | 28 1 file changed, 28 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 7d62715ab51e..f2eceb6605c5 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -1062,32 +1062,6 @@ static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *domain, return phys; } -static int exynos_iommu_add_device(struct device *dev) -{ - struct iommu_group *group; - int ret; - - 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); - iommu_group_put(group); - - return ret; -} - -static void exynos_iommu_remove_device(struct device *dev) -{ - iommu_group_remove_device(dev); -} - static const struct iommu_ops exynos_iommu_ops = { .domain_alloc = exynos_iommu_domain_alloc, .domain_free = exynos_iommu_domain_free, @@ -1097,8 +1071,6 @@ static const struct iommu_ops exynos_iommu_ops = { .unmap = exynos_iommu_unmap, .map_sg = default_iommu_map_sg, .iova_to_phys = exynos_iommu_iova_to_phys, - .add_device = exynos_iommu_add_device, - .remove_device = exynos_iommu_remove_device, .pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE, }; -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 08/25] iommu: exynos: refactor function parameters to simplify code
This patch simplifies the code by: - refactoring function parameters from struct device pointer to direct pointer to struct sysmmu drvdata - moving list_head enteries from struct exynos_iommu_owner directly to struct sysmmu_drvdata Signed-off-by: Marek Szyprowski --- drivers/iommu/exynos-iommu.c | 93 ++-- 1 file changed, 46 insertions(+), 47 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index c307c400613c..0c23b69022cd 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -186,8 +186,6 @@ static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = { /* attached to dev.archdata.iommu of the master device */ struct exynos_iommu_owner { - struct list_head client; /* entry of exynos_iommu_domain.clients */ - struct device *dev; struct device *sysmmu; }; @@ -209,6 +207,7 @@ struct sysmmu_drvdata { int activations; spinlock_t lock; struct iommu_domain *domain; + struct list_head domain_node; phys_addr_t pgtable; int version; }; @@ -514,12 +513,10 @@ static void __sysmmu_tlb_invalidate_flpdcache(struct sysmmu_drvdata *data, __raw_writel(iova | 0x1, data->sfrbase + REG_MMU_FLUSH_ENTRY); } -static void sysmmu_tlb_invalidate_flpdcache(struct device *dev, +static void sysmmu_tlb_invalidate_flpdcache(struct sysmmu_drvdata *data, sysmmu_iova_t iova) { unsigned long flags; - struct exynos_iommu_owner *owner = dev->archdata.iommu; - struct sysmmu_drvdata *data = dev_get_drvdata(owner->sysmmu); if (!IS_ERR(data->clk_master)) clk_enable(data->clk_master); @@ -533,14 +530,10 @@ static void sysmmu_tlb_invalidate_flpdcache(struct device *dev, clk_disable(data->clk_master); } -static void sysmmu_tlb_invalidate_entry(struct device *dev, sysmmu_iova_t iova, - size_t size) +static void sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data, + sysmmu_iova_t iova, size_t size) { - struct exynos_iommu_owner *owner = dev->archdata.iommu; unsigned long flags; - struct sysmmu_drvdata *data; - - data = dev_get_drvdata(owner->sysmmu); spin_lock_irqsave(&data->lock, flags); if (is_sysmmu_active(data)) { @@ -570,8 +563,8 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, sysmmu_iova_t iova, if (!IS_ERR(data->clk_master)) clk_disable(data->clk_master); } else { - dev_dbg(dev, "disabled. Skipping TLB invalidation @ %#x\n", - iova); + dev_dbg(data->master, + "disabled. Skipping TLB invalidation @ %#x\n", iova); } spin_unlock_irqrestore(&data->lock, flags); } @@ -711,7 +704,7 @@ err_pgtable: static void exynos_iommu_domain_free(struct iommu_domain *domain) { struct exynos_iommu_domain *priv = to_exynos_domain(domain); - struct exynos_iommu_owner *owner; + struct sysmmu_drvdata *data; unsigned long flags; int i; @@ -719,14 +712,12 @@ static void exynos_iommu_domain_free(struct iommu_domain *domain) spin_lock_irqsave(&priv->lock, flags); - list_for_each_entry(owner, &priv->clients, client) { - while (!exynos_sysmmu_disable(owner->dev)) - ; /* until System MMU is actually disabled */ + list_for_each_entry(data, &priv->clients, domain_node) { + if (__sysmmu_disable(data)) + data->master = NULL; + list_del_init(&data->domain_node); } - while (!list_empty(&priv->clients)) - list_del_init(priv->clients.next); - spin_unlock_irqrestore(&priv->lock, flags); for (i = 0; i < NUM_LV1ENTRIES; i++) @@ -744,20 +735,26 @@ static int exynos_iommu_attach_device(struct iommu_domain *domain, { struct exynos_iommu_owner *owner = dev->archdata.iommu; struct exynos_iommu_domain *priv = to_exynos_domain(domain); + struct sysmmu_drvdata *data; phys_addr_t pagetable = virt_to_phys(priv->pgtable); unsigned long flags; - int ret; + int ret = -ENODEV; - spin_lock_irqsave(&priv->lock, flags); + if (!has_sysmmu(dev)) + return -ENODEV; - ret = __exynos_sysmmu_enable(dev, pagetable, domain); - if (ret == 0) { - list_add_tail(&owner->client, &priv->clients); - owner->domain = domain; + data = dev_get_drvdata(owner->sysmmu); + if (data) { + ret = __sysmmu_enable(data, pagetable, domain); + if (ret >= 0) { + data->master = dev; + + spin_lock_irqsave(&priv->lock, flags); + list_add_tail(&d
[PATCH v6 12/25] iommu: exynos: add support for runtime_pm
This patch fixes support for runtime power management for SYSMMU controllers, so they are enabled when master device is attached. Signed-off-by: Marek Szyprowski --- drivers/iommu/exynos-iommu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 598660c87410..734107ec78fa 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -702,6 +702,7 @@ static int exynos_iommu_attach_device(struct iommu_domain *domain, return -ENODEV; list_for_each_entry(data, &owner->clients, owner_node) { + pm_runtime_get_sync(data->sysmmu); ret = __sysmmu_enable(data, pagetable, domain); if (ret >= 0) { data->master = dev; @@ -743,6 +744,7 @@ static void exynos_iommu_detach_device(struct iommu_domain *domain, data->master = NULL; list_del_init(&data->domain_node); } + pm_runtime_put(data->sysmmu); found = true; } } -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 03/25] drm/exynos: iommu: detach from default dma-mapping domain on init
This patch adds code, which detach sub-device nodes from default iommu domain if such has been configured. Signed-off-by: Marek Szyprowski --- drivers/gpu/drm/exynos/exynos_drm_iommu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.c b/drivers/gpu/drm/exynos/exynos_drm_iommu.c index b32b291f88ff..323601a52a25 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_iommu.c +++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.c @@ -100,6 +100,9 @@ int drm_iommu_attach_device(struct drm_device *drm_dev, dma_set_max_seg_size(subdrv_dev, 0xu); + if (subdrv_dev->archdata.mapping) + arm_iommu_detach_device(subdrv_dev); + ret = arm_iommu_attach_device(subdrv_dev, dev->archdata.mapping); if (ret < 0) { DRM_DEBUG_KMS("failed iommu attach.\n"); -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 09/25] iommu: exynos: remove unused functions, part 2
After refactoring functions to use pointer to struct sysmmu_drvdata directly, some functions became useless and thus never used, so remove them completely. Signed-off-by: Marek Szyprowski --- drivers/iommu/exynos-iommu.c | 43 --- 1 file changed, 43 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 0c23b69022cd..7d62715ab51e 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -463,49 +463,6 @@ static int __sysmmu_enable(struct sysmmu_drvdata *data, return ret; } -/* __exynos_sysmmu_enable: Enables System MMU - * - * returns -error if an error occurred and System MMU is not enabled, - * 0 if the System MMU has been just enabled and 1 if System MMU was already - * enabled before. - */ -static int __exynos_sysmmu_enable(struct device *dev, phys_addr_t pgtable, - struct iommu_domain *domain) -{ - int ret = 0; - unsigned long flags; - struct exynos_iommu_owner *owner = dev->archdata.iommu; - struct sysmmu_drvdata *data; - - BUG_ON(!has_sysmmu(dev)); - - data = dev_get_drvdata(owner->sysmmu); - - ret = __sysmmu_enable(data, pgtable, domain); - if (ret >= 0) - data->master = dev; - - return ret; -} - -static bool exynos_sysmmu_disable(struct device *dev) -{ - unsigned long flags; - bool disabled = true; - struct exynos_iommu_owner *owner = dev->archdata.iommu; - struct sysmmu_drvdata *data; - - BUG_ON(!has_sysmmu(dev)); - - data = dev_get_drvdata(owner->sysmmu); - - disabled = __sysmmu_disable(data); - if (disabled) - data->master = NULL; - - return disabled; -} - static void __sysmmu_tlb_invalidate_flpdcache(struct sysmmu_drvdata *data, sysmmu_iova_t iova) { -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 02/25] arm: exynos: pm_domains: register power domain driver from core_initcall
SYSMMU devices are registered very early in arch_initcall, so ensure that they can get access to power domains by registering power domain driver from earlier initcall. This change requires dropping usage of the platform device associated with each power domain and replacing clock calls with respective of_clk_* equivalents. Signed-off-by: Marek Szyprowski --- arch/arm/mach-exynos/pm_domains.c | 18 +++--- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c index cbe56b35aea0..708eb88aa677 100644 --- a/arch/arm/mach-exynos/pm_domains.c +++ b/arch/arm/mach-exynos/pm_domains.c @@ -117,16 +117,11 @@ static int exynos_pd_power_off(struct generic_pm_domain *domain) static __init int exynos4_pm_init_power_domain(void) { - struct platform_device *pdev; struct device_node *np; for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") { struct exynos_pm_domain *pd; int on, i; - struct device *dev; - - pdev = of_find_device_by_node(np); - dev = &pdev->dev; pd = kzalloc(sizeof(*pd), GFP_KERNEL); if (!pd) { @@ -135,7 +130,8 @@ static __init int exynos4_pm_init_power_domain(void) return -ENOMEM; } - pd->pd.name = kstrdup(dev_name(dev), GFP_KERNEL); + pd->pd.name = kstrdup_const(strrchr(np->full_name, '/') + 1, + GFP_KERNEL); pd->name = pd->pd.name; pd->base = of_iomap(np, 0); pd->pd.power_off = exynos_pd_power_off; @@ -145,12 +141,12 @@ static __init int exynos4_pm_init_power_domain(void) char clk_name[8]; snprintf(clk_name, sizeof(clk_name), "asb%d", i); - pd->asb_clk[i] = clk_get(dev, clk_name); + pd->asb_clk[i] = of_clk_get_by_name(np, clk_name); if (IS_ERR(pd->asb_clk[i])) break; } - pd->oscclk = clk_get(dev, "oscclk"); + pd->oscclk = of_clk_get_by_name(np, "oscclk"); if (IS_ERR(pd->oscclk)) goto no_clk; @@ -158,11 +154,11 @@ static __init int exynos4_pm_init_power_domain(void) char clk_name[8]; snprintf(clk_name, sizeof(clk_name), "clk%d", i); - pd->clk[i] = clk_get(dev, clk_name); + pd->clk[i] = of_clk_get_by_name(np, clk_name); if (IS_ERR(pd->clk[i])) break; snprintf(clk_name, sizeof(clk_name), "pclk%d", i); - pd->pclk[i] = clk_get(dev, clk_name); + pd->pclk[i] = of_clk_get_by_name(np, clk_name); if (IS_ERR(pd->pclk[i])) { clk_put(pd->clk[i]); pd->clk[i] = ERR_PTR(-EINVAL); @@ -210,4 +206,4 @@ no_clk: return 0; } -arch_initcall(exynos4_pm_init_power_domain); +core_initcall(exynos4_pm_init_power_domain); -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 05/25] iommu: exynos: don't read version register on every tlb operation
This patch removes reading of REG_MMU_VERSION register on every tlb operation and caches SYSMMU version in driver's internal data. Signed-off-by: Marek Szyprowski --- drivers/iommu/exynos-iommu.c | 13 + 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 3e898504a7c4..3861485f0689 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -213,6 +213,7 @@ struct sysmmu_drvdata { spinlock_t lock; struct iommu_domain *domain; phys_addr_t pgtable; + int version; }; static struct exynos_iommu_domain *to_exynos_domain(struct iommu_domain *dom) @@ -244,11 +245,6 @@ static void sysmmu_unblock(void __iomem *sfrbase) __raw_writel(CTRL_ENABLE, sfrbase + REG_MMU_CTRL); } -static unsigned int __raw_sysmmu_version(struct sysmmu_drvdata *data) -{ - return MMU_RAW_VER(__raw_readl(data->sfrbase + REG_MMU_VERSION)); -} - static bool sysmmu_block(void __iomem *sfrbase) { int i = 120; @@ -408,7 +404,7 @@ static void __sysmmu_init_config(struct sysmmu_drvdata *data) unsigned int cfg = CFG_LRU | CFG_QOS(15); unsigned int ver; - ver = __raw_sysmmu_version(data); + ver = MMU_RAW_VER(__raw_readl(data->sfrbase + REG_MMU_VERSION)); if (MMU_MAJ_VER(ver) == 3) { if (MMU_MIN_VER(ver) >= 2) { cfg |= CFG_FLPDCACHE; @@ -422,6 +418,7 @@ static void __sysmmu_init_config(struct sysmmu_drvdata *data) } __raw_writel(cfg, data->sfrbase + REG_MMU_CFG); + data->version = ver; } static void __sysmmu_enable_nocount(struct sysmmu_drvdata *data) @@ -531,7 +528,7 @@ static bool exynos_sysmmu_disable(struct device *dev) static void __sysmmu_tlb_invalidate_flpdcache(struct sysmmu_drvdata *data, sysmmu_iova_t iova) { - if (__raw_sysmmu_version(data) == MAKE_MMU_VER(3, 3)) + if (data->version == MAKE_MMU_VER(3, 3)) __raw_writel(iova | 0x1, data->sfrbase + REG_MMU_FLUSH_ENTRY); } @@ -580,7 +577,7 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, sysmmu_iova_t iova, * 1MB page can be cached in one of all sets. * 64KB page can be one of 16 consecutive sets. */ - if (MMU_MAJ_VER(__raw_sysmmu_version(data)) == 2) + if (MMU_MAJ_VER(data->version) == 2) num_inv = min_t(unsigned int, size / PAGE_SIZE, 64); if (sysmmu_block(data->sfrbase)) { -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 16/25] iommu: exynos: remove excessive includes and sort others alphabetically
Removed following unused includes: , , and . Signed-off-by: Marek Szyprowski --- drivers/iommu/exynos-iommu.c | 14 +- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 6a0199570b00..5429e75b120c 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -12,19 +12,15 @@ #define DEBUG #endif -#include -#include -#include -#include -#include #include #include -#include +#include #include -#include +#include #include -#include -#include +#include +#include +#include #include #include -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 14/25] iommu: exynos: use struct exynos_iommu_domain in internal structures
Replace all remaining usage of struct iommu_domain with struct exynos_iommu_domain in all internal structures and functions. Signed-off-by: Marek Szyprowski --- drivers/iommu/exynos-iommu.c | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index a58f4a4c91d0..67e0633b8080 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -206,7 +206,7 @@ struct sysmmu_drvdata { struct clk *clk_master; int activations; spinlock_t lock; - struct iommu_domain *domain; + struct exynos_iommu_domain *domain; struct list_head domain_node; struct list_head owner_node; phys_addr_t pgtable; @@ -338,7 +338,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id) show_fault_information(dev_name(data->sysmmu), itype, base, addr); if (data->domain) - ret = report_iommu_fault(data->domain, + ret = report_iommu_fault(&data->domain->domain, data->master, addr, itype); } @@ -437,7 +437,7 @@ static void __sysmmu_enable_nocount(struct sysmmu_drvdata *data) } static int __sysmmu_enable(struct sysmmu_drvdata *data, phys_addr_t pgtable, - struct iommu_domain *iommu_domain) + struct exynos_iommu_domain *domain) { int ret = 0; unsigned long flags; @@ -445,7 +445,7 @@ static int __sysmmu_enable(struct sysmmu_drvdata *data, phys_addr_t pgtable, spin_lock_irqsave(&data->lock, flags); if (set_sysmmu_active(data)) { data->pgtable = pgtable; - data->domain = iommu_domain; + data->domain = domain; __sysmmu_enable_nocount(data); @@ -703,7 +703,7 @@ static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain, list_for_each_entry(data, &owner->clients, owner_node) { pm_runtime_get_sync(data->sysmmu); - ret = __sysmmu_enable(data, pagetable, iommu_domain); + ret = __sysmmu_enable(data, pagetable, domain); if (ret >= 0) { data->master = dev; -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 06/25] iommu: exynos: remove unused functions
This patch removes two unneeded functions, which are not a part of generic IOMMU API and were never used by any other driver. Signed-off-by: Marek Szyprowski --- drivers/iommu/exynos-iommu.c | 31 --- 1 file changed, 31 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 3861485f0689..98aa7e9c2507 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -496,13 +496,6 @@ static int __exynos_sysmmu_enable(struct device *dev, phys_addr_t pgtable, return ret; } -int exynos_sysmmu_enable(struct device *dev, phys_addr_t pgtable) -{ - BUG_ON(!memblock_is_memory(pgtable)); - - return __exynos_sysmmu_enable(dev, pgtable, NULL); -} - static bool exynos_sysmmu_disable(struct device *dev) { unsigned long flags; @@ -594,30 +587,6 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, sysmmu_iova_t iova, spin_unlock_irqrestore(&data->lock, flags); } -void exynos_sysmmu_tlb_invalidate(struct device *dev) -{ - struct exynos_iommu_owner *owner = dev->archdata.iommu; - unsigned long flags; - struct sysmmu_drvdata *data; - - data = dev_get_drvdata(owner->sysmmu); - - spin_lock_irqsave(&data->lock, flags); - if (is_sysmmu_active(data)) { - if (!IS_ERR(data->clk_master)) - clk_enable(data->clk_master); - if (sysmmu_block(data->sfrbase)) { - __sysmmu_tlb_invalidate(data->sfrbase); - sysmmu_unblock(data->sfrbase); - } - if (!IS_ERR(data->clk_master)) - clk_disable(data->clk_master); - } else { - dev_dbg(dev, "disabled. Skipping TLB invalidation\n"); - } - spin_unlock_irqrestore(&data->lock, flags); -} - static int __init exynos_sysmmu_probe(struct platform_device *pdev) { int irq, ret; -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 15/25] iommu: exynos: document internal structures
Add a few words of comment to all internal structures used by the driver. Signed-off-by: Marek Szyprowski --- drivers/iommu/exynos-iommu.c | 49 +--- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 67e0633b8080..6a0199570b00 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -184,33 +184,50 @@ static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = { "UNKNOWN FAULT" }; -/* attached to dev.archdata.iommu of the master device */ +/* + * This structure is attached to dev.archdata.iommu of the master device + * on device add, contains a list of SYSMMU controllers defined by device tree, + * which are bound to given master device. It is usually referenced by 'owner' + * pointer. +*/ struct exynos_iommu_owner { - struct list_head clients; + struct list_head clients; /* list of sysmmu_drvdata.owner_node */ }; +/* + * This structure exynos specific generalization of struct iommu_domain. + * It contains list of SYSMMU controllers from all master devices, which has + * been attached to this domain and page tables of IO address space defined by + * it. It is usually referenced by 'domain' pointer. + */ struct exynos_iommu_domain { - struct list_head clients; /* list of sysmmu_drvdata.node */ + struct list_head clients; /* list of sysmmu_drvdata.domain_node */ sysmmu_pte_t *pgtable; /* lv1 page table, 16KB */ short *lv2entcnt; /* free lv2 entry counter for each section */ - spinlock_t lock; /* lock for this structure */ + spinlock_t lock; /* lock for modyfying list of clients */ spinlock_t pgtablelock; /* lock for modifying page table @ pgtable */ struct iommu_domain domain; /* generic domain data structure */ }; +/* + * This structure hold all data of a single SYSMMU controller, this includes + * hw resources like registers and clocks, pointers and list nodes to connect + * it to all other structures, internal state and parameters read from device + * tree. It is usually referenced by 'data' pointer. + */ struct sysmmu_drvdata { - struct device *sysmmu; /* System MMU's device descriptor */ - struct device *master; /* Owner of system MMU */ - void __iomem *sfrbase; - struct clk *clk; - struct clk *clk_master; - int activations; - spinlock_t lock; - struct exynos_iommu_domain *domain; - struct list_head domain_node; - struct list_head owner_node; - phys_addr_t pgtable; - int version; + struct device *sysmmu; /* SYSMMU controller device */ + struct device *master; /* master device (owner of given SYSMMU) */ + void __iomem *sfrbase; /* our registers */ + struct clk *clk; /* SYSMMU's clock */ + struct clk *clk_master; /* master's device clock */ + int activations; /* number of calls to sysmmu_enable */ + spinlock_t lock; /* lock for modyfying enable/disable state */ + struct exynos_iommu_domain *domain; /* domain we belong to */ + struct list_head domain_node; /* node for domain clients list */ + struct list_head owner_node; /* node for owner clients list */ + phys_addr_t pgtable; /* assigned page table structure */ + int version; /* our version */ }; static struct exynos_iommu_domain *to_exynos_domain(struct iommu_domain *dom) -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 11/25] iommu: exynos: add support for binding more than one sysmmu to master device
This patch adds support for assigning more than one SYSMMU controller to the master device. This has been achieved simply by chaning the struct device pointer in struct exynos_iommu_owner into the list of struct sysmmu_drvdata of all controllers assigned to the given master device. Signed-off-by: Marek Szyprowski --- drivers/iommu/exynos-iommu.c | 11 +-- 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index f2eceb6605c5..598660c87410 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -186,7 +186,7 @@ static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = { /* attached to dev.archdata.iommu of the master device */ struct exynos_iommu_owner { - struct device *sysmmu; + struct list_head clients; }; struct exynos_iommu_domain { @@ -208,6 +208,7 @@ struct sysmmu_drvdata { spinlock_t lock; struct iommu_domain *domain; struct list_head domain_node; + struct list_head owner_node; phys_addr_t pgtable; int version; }; @@ -700,8 +701,7 @@ static int exynos_iommu_attach_device(struct iommu_domain *domain, if (!has_sysmmu(dev)) return -ENODEV; - data = dev_get_drvdata(owner->sysmmu); - if (data) { + list_for_each_entry(data, &owner->clients, owner_node) { ret = __sysmmu_enable(data, pagetable, domain); if (ret >= 0) { data->master = dev; @@ -729,7 +729,7 @@ static void exynos_iommu_detach_device(struct iommu_domain *domain, { struct exynos_iommu_domain *priv = to_exynos_domain(domain); phys_addr_t pagetable = virt_to_phys(priv->pgtable); - struct sysmmu_drvdata *data; + struct sysmmu_drvdata *data, *next; unsigned long flags; bool found = false; @@ -737,14 +737,13 @@ static void exynos_iommu_detach_device(struct iommu_domain *domain, return; spin_lock_irqsave(&priv->lock, flags); - list_for_each_entry(data, &priv->clients, domain_node) { + list_for_each_entry_safe(data, next, &priv->clients, domain_node) { if (data->master == dev) { if (__sysmmu_disable(data)) { data->master = NULL; list_del_init(&data->domain_node); } found = true; - break; } } spin_unlock_irqrestore(&priv->lock, flags); -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v6 01/25] arm: dma-mapping: add support for creating reserved mappings in iova space
Some devices (like frame buffers) are enabled by bootloader and configured to perform DMA operations automatically (like displaying boot logo or splash screen). Such devices operate and perform DMA operation usually until the proper driver for them is loaded and probed. However before that happens, system usually loads IOMMU drivers and configures dma parameters for each device. When such initial configuration is created and enabled, it usually contains empty translation rules betweem IO address space and physical memory, because no buffers nor memory regions have been requested by the respective driver. This patch adds support for "iommu-reserved-mapping", which can be used to provide definitions for mappings that need to be created on system boot to let such devices (enabled by bootloader) to operate properly until respective driver is probed. Signed-off-by: Marek Szyprowski --- Documentation/devicetree/bindings/iommu/iommu.txt | 44 + arch/arm/mm/dma-mapping.c | 112 ++ 2 files changed, 156 insertions(+) diff --git a/Documentation/devicetree/bindings/iommu/iommu.txt b/Documentation/devicetree/bindings/iommu/iommu.txt index 5a8b4624defc..fd54e6b597f0 100644 --- a/Documentation/devicetree/bindings/iommu/iommu.txt +++ b/Documentation/devicetree/bindings/iommu/iommu.txt @@ -86,6 +86,35 @@ have a means to turn off translation. But it is invalid in such cases to disable the IOMMU's device tree node in the first place because it would prevent any driver from properly setting up the translations. +Optional properties: + +- iommu-reserved-mapping: A list of entries describing additional + reserved mapping, that will be inserted to the default IO address space + created for given master device. Each entry consist of IO address, + physical memory address and size of the region. + +Some devices (like frame buffers) are enabled by bootloader and configured +to perform DMA operations automatically (like displaying boot logo or splash +screen). Such devices operate and perform DMA operation usually until the +proper driver for them is loaded and probed. However before that happens, +system usually loads IOMMU drivers and configures dma parameters for each +device. When such initial configuration is created and enabled, it usually +contains empty translation rules betweem IO address space and physical +memory, because no buffers nor memory regions have been requested by the +respective driver. + +To avoid IOMMU page fault, one can provide "iommu-reserved-mapping" +property, which defines all memory regions which must be mapped to IO +address space to boot properly when device has been enabled by the +bootloader. More than one region can be defined for given master device. +Each region is defined by the following triplet: first entry is IO +address (encoded in "address" cells), second is base physical memory +address for this regions (also encoded in "address" cells) and the last +is size of the region (encoded in "size" cells). To ensure that that +given master device will not trigger page fault after enabling IOMMU, +one should define identity mapping between physical memory and IO +address space for the range of addresses accessed by the device. + Notes: == @@ -113,6 +142,21 @@ Single-master IOMMU: iommus = <&{/iommu}>; }; + +Single-master IOMMU, which has been left enabled by bootloader: +--- + + iommu { + #iommu-cells = <0>; + }; + + master { + iommus = <&{/iommu}>; + /* bootloader configures framebuffer at 0x4000 (32MiB) + iommu-reserved-mapping = <0x4000 0x4000 0x200>; + }; + + Multiple-master IOMMU with fixed associations: -- diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 7e7583ddd607..3b4a94695b68 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1019,6 +1019,50 @@ fs_initcall(dma_debug_do_init); static int extend_iommu_mapping(struct dma_iommu_mapping *mapping); +static inline int __reserve_iova(struct dma_iommu_mapping *mapping, +dma_addr_t iova, size_t size) +{ + unsigned long count, start; + unsigned long flags; + int i, sbitmap, ebitmap; + + if (iova < mapping->base) + return -EINVAL; + + start = (iova - mapping->base) >> PAGE_SHIFT; + count = PAGE_ALIGN(size) >> PAGE_SHIFT; + + sbitmap = start / mapping->bits; + ebitmap = (start + count) / mapping->bits; + start = start % mapping->bits; + + if (ebitmap > mapping->extensions) + return -EINVAL; + + spin_lock_irqsave(&mapping->lock, flags); + + for (i = mapping->nr_bitmaps; i <= ebitmap; i++) { + if (extend_iommu_mapping(mapping)) { +
[PATCH v6 00/25] Exynos SYSMMU (IOMMU) integration with DT and DMA-mapping subsystem
Hello Everyone, This is yet another attempt to get Exynos SYSMMU driver with integrated with IOMMU & DMA-mapping subsystems. The main change from previous version is addition of the patches to define iommu-mapping, which need to be created during system boot to avoid IOMMU fault by devices, which has been left enabled by bootloader (i.e. framebuffer displaying slash screen). Patches has been also rebased onto v4.1-rc2 with 'arm: dma-mapping: fix off-by-one check in arm_setup_iommu_dma_ops' patch applied (see commit 1424532b2163bf1580f4b1091a5801e12310fac5 on fixes branch in git://ftp.arm.linux.org.uk/pub/linux/arm/kernel/git-cur/linux-arm.git, more information: http://www.spinics.net/lists/arm-kernel/msg414722.html). All patches are also available in the following git repository: https://git.linaro.org/people/marek.szyprowski/linux-srpol.git branch v4.1-exynos-iommu. Best regards Marek Szyprowski Samsung R&D Institute Poland Changelog: v6: - rebased onto v4.1-rc2 with 'arm: dma-mapping: fix off-by-one check in arm_setup_iommu_dma_ops' patch - added exynos 3250 and 4415 dts patches - added support for devices, which have been left enabled by bootloader (i.e. framebuffer displaying slash screen) - fixed freeze in fimd iommu initialization caused by lack of proper runtime pm management - resolved issues with power domains by moving pd initialization to core_initcall v5: https://lists.linaro.org/pipermail/linaro-mm-sig/2015-February/004442.html - rebased onto 'Add HDMI support for Exynos5420 platform' patchset - fixed 'const' issue in 'iommu: exynos: init from dt-specific callback instead of initcall' patch, thanks to Tobias Jakobi for reporting it - fixed copy-paste typo in exynos5250 dts patch v4: http://www.spinics.net/lists/linux-samsung-soc/msg41177.html - rebased onto v3.19-rc4 and other Exynos DTS queued patches - added DTS patch for Exynos 5250 & 5420/5422/5800 v3: http://www.spinics.net/lists/linux-samsung-soc/msg39168.html - rebased onto "[RFC PATCH v4 0/8] Introduce automatic DMA configuration for IOMMU masters" - added some minor fixes for iommu and dma-mapping frameworks v2: http://thread.gmane.org/gmane.linux.kernel.iommu/6472/ - rebased onto "[RFC PATCH v3 0/7] Introduce automatic DMA configuration for IOMMU masters" patches: http://www.spinics.net/lists/arm-kernel/msg362076.html - changed initialization from bus notifiers to DT related callbacks - removed support for separate IO address spaces - this will be discussed separately after the basic support gets merged - removed support for power domain notifier-based runtime power management - this also will be discussed separately later v1: https://lkml.org/lkml/2014/8/5/183 - initial version, feature complete, completely rewrote integration approach Patch summary: Marek Szyprowski (25): arm: dma-mapping: add support for creating reserved mappings in iova space arm: exynos: pm_domains: register power domain driver from core_initcall drm/exynos: iommu: detach from default dma-mapping domain on init drm/exynos: fimd: ensure proper hw state in fimd_clear_channel() iommu: exynos: don't read version register on every tlb operation iommu: exynos: remove unused functions iommu: exynos: remove useless spinlock iommu: exynos: refactor function parameters to simplify code iommu: exynos: remove unused functions, part 2 iommu: exynos: remove useless device_add/remove callbacks iommu: exynos: add support for binding more than one sysmmu to master device iommu: exynos: add support for runtime_pm iommu: exynos: rename variables to reflect their purpose iommu: exynos: use struct exynos_iommu_domain in internal structures iommu: exynos: document internal structures iommu: exynos: remove excessive includes and sort others alphabetically iommu: exynos: init from dt-specific callback instead of initcall iommu: exynos: add callback for initializing devices from device tree iommu: exynos: remove unneeded code ARM: dts: exynos4: add sysmmu nodes ARM: dts: exynos3250: add sysmmu nodes ARM: dts: exynos4415: add sysmmu nodes ARM: dts: exynos5250: add sysmmu nodes ARM: dts: exynos5420: add sysmmu nodes ARM: dts: exynos: add iommu reserved regions for bootloader's splash screen Documentation/devicetree/bindings/iommu/iommu.txt | 44 ++ arch/arm/boot/dts/exynos3250-rinato.dts | 1 + arch/arm/boot/dts/exynos3250.dtsi | 22 + arch/arm/boot/dts/exynos4.dtsi| 118 ++ arch/arm/boot/dts/exynos4210-trats.dts| 1 + arch/arm/boot/dts/exynos4210-universal_c210.dts | 1 + arch/arm/boot/dts/exynos4210.dtsi | 23 + arch/arm/boot/dts/exynos4412-trats2.dts | 1 + arch/arm/boot/dts/exynos4415.dtsi | 11 + arch/arm/boot/dts/exynos4x12.dtsi | 82 arch/arm/boot/dts/exynos5250-snow.dts | 1 + arch/arm/boot/dts/exynos5250-spring.dts
[PATCH v6 04/25] drm/exynos: fimd: ensure proper hw state in fimd_clear_channel()
One should not do any assumptions on the stare of the fimd hardware during driver initialization, so to properly reset fimd before enabling IOMMU, one should ensure that all power domains and clocks are really enabled. This patch adds calls to power on/off in the fimd_clear_channel() function to ensure that any access to fimd registers will be performed with clocks and power domains enabled. Signed-off-by: Marek Szyprowski --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 27 +-- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 9819fa6a9e2a..cf64550df59d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -242,12 +242,20 @@ static void fimd_enable_shadow_channel_path(struct fimd_context *ctx, int win, writel(val, ctx->regs + SHADOWCON); } -static void fimd_clear_channel(struct fimd_context *ctx) +static int fimd_poweron(struct fimd_context *ctx); +static int fimd_poweroff(struct fimd_context *ctx); + +static int fimd_clear_channel(struct fimd_context *ctx) { - int win, ch_enabled = 0; + int ret, win, ch_enabled = 0; DRM_DEBUG_KMS("%s\n", __FILE__); + /* Hardware is in unknown state, so ensure it get enabled properly */ + ret = fimd_poweron(ctx); + if (ret) + return ret; + /* Check if any channel is enabled. */ for (win = 0; win < WINDOWS_NR; win++) { u32 val = readl(ctx->regs + WINCON(win)); @@ -258,19 +266,15 @@ static void fimd_clear_channel(struct fimd_context *ctx) if (ctx->driver_data->has_shadowcon) fimd_enable_shadow_channel_path(ctx, win, false); - ch_enabled = 1; } } /* Wait for vsync, as disable channel takes effect at next vsync */ - if (ch_enabled) { - unsigned int state = ctx->suspended; - - ctx->suspended = 0; + if (ch_enabled) fimd_wait_for_vblank(ctx->crtc); - ctx->suspended = state; - } + + return fimd_poweroff(ctx); } static int fimd_iommu_attach_devices(struct fimd_context *ctx, @@ -285,7 +289,10 @@ static int fimd_iommu_attach_devices(struct fimd_context *ctx, * If any channel is already active, iommu will throw * a PAGE FAULT when enabled. So clear any channel if enabled. */ - fimd_clear_channel(ctx); + ret = fimd_clear_channel(ctx); + if (ret) + return ret; + ret = drm_iommu_attach_device(ctx->drm_dev, ctx->dev); if (ret) { DRM_ERROR("drm_iommu_attach failed.\n"); -- 1.9.2 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu