* [PATCH 00/18] Clean up exposure of arch-internal code
@ 2015-07-27 12:28 Russell King - ARM Linux
2015-07-27 12:28 ` [PATCH 01/18] ARM: reduce visibility of dmac_* functions Russell King
` (19 more replies)
0 siblings, 20 replies; 30+ messages in thread
From: Russell King - ARM Linux @ 2015-07-27 12:28 UTC (permalink / raw)
To: linux-arm-kernel
This series of patches attempts to clean up the use of architecture
internal functions in drivers, and removes some functions from view
in the asm/ headers. I'm also considering whether we need to add
some linker magic to hide symbols when building the built-in.o files.
This was triggered by 3rd party drivers "going under the covers" of
the DMA API and calling the dmac_*() functions directly, a practice
which I have always refused to allow. This also breaks module
building (which is the big hint that they're doing something wrong.)
However, it also came to light that various drivers are using
__cpuc_* functions directly, which are non-portable, and is another
instance of "going under the covers" and tinkering with what should
be kept as architecture implementation details.
This series addresses some of these points. It:
(a) moves dmac_map_area() and dmac_unmap_area() prototypes out of
asm/cacheflush.h and into arch/arm/mm.
(b) provide a secure_flush() call for the Qualcomm secure monitor
code.
(c) stop tegra smmu driver(s) from using __cpuc_flush_dcache_area,
something which necessitates additional complexity to deal with
the ARM vs ARM64 differences. It should be using the DMA API.
However, the Tegra SMMU driver is in really bad shape, and this
isn't a simple conversion - it requires a lot of additional
fixes to bring the code up to scratch.
It leaves the Rockchip IOMMU driver for the time being, but that is also
something which needs cleaning up in the same way as the Tegra SMMU
driver.
arch/arm/include/asm/cacheflush.h | 21 ++-
arch/arm/include/asm/glue-cache.h | 2 -
arch/arm/mm/dma-mapping.c | 1 +
arch/arm/mm/dma.h | 32 ++++
drivers/firmware/qcom_scm-32.c | 4 +-
drivers/iommu/tegra-smmu.c | 297 ++++++++++++++++++++++++--------------
drivers/memory/tegra/tegra114.c | 17 ---
drivers/memory/tegra/tegra124.c | 30 ----
drivers/memory/tegra/tegra30.c | 17 ---
include/soc/tegra/mc.h | 7 -
10 files changed, 242 insertions(+), 186 deletions(-)
--
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 01/18] ARM: reduce visibility of dmac_* functions
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
@ 2015-07-27 12:28 ` Russell King
2015-07-27 12:28 ` [PATCH 02/18] firmware: qcom_scm-32: replace open-coded call to __cpuc_flush_dcache_area() Russell King
` (18 subsequent siblings)
19 siblings, 0 replies; 30+ messages in thread
From: Russell King @ 2015-07-27 12:28 UTC (permalink / raw)
To: linux-arm-kernel
The dmac_* functions are private to the ARM DMA API implementation, and
should not be used by drivers. In order to discourage their use, remove
their prototypes and macros from asm/*.h.
We have to leave dmac_flush_range() behind as Exynos and MSM IOMMU code
use these; once these sites are fixed, this can be moved also.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
arch/arm/include/asm/cacheflush.h | 4 ----
arch/arm/include/asm/glue-cache.h | 2 --
arch/arm/mm/dma-mapping.c | 1 +
arch/arm/mm/dma.h | 32 ++++++++++++++++++++++++++++++++
4 files changed, 33 insertions(+), 6 deletions(-)
create mode 100644 arch/arm/mm/dma.h
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 4812cda8fd17..c5230a44eeca 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -140,8 +140,6 @@ extern struct cpu_cache_fns cpu_cache;
* is visible to DMA, or data written by DMA to system memory is
* visible to the CPU.
*/
-#define dmac_map_area cpu_cache.dma_map_area
-#define dmac_unmap_area cpu_cache.dma_unmap_area
#define dmac_flush_range cpu_cache.dma_flush_range
#else
@@ -161,8 +159,6 @@ extern void __cpuc_flush_dcache_area(void *, size_t);
* is visible to DMA, or data written by DMA to system memory is
* visible to the CPU.
*/
-extern void dmac_map_area(const void *, size_t, int);
-extern void dmac_unmap_area(const void *, size_t, int);
extern void dmac_flush_range(const void *, const void *);
#endif
diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h
index a3c24cd5b7c8..cab07f69382d 100644
--- a/arch/arm/include/asm/glue-cache.h
+++ b/arch/arm/include/asm/glue-cache.h
@@ -158,8 +158,6 @@ static inline void nop_dma_unmap_area(const void *s, size_t l, int f) { }
#define __cpuc_coherent_user_range __glue(_CACHE,_coherent_user_range)
#define __cpuc_flush_dcache_area __glue(_CACHE,_flush_kern_dcache_area)
-#define dmac_map_area __glue(_CACHE,_dma_map_area)
-#define dmac_unmap_area __glue(_CACHE,_dma_unmap_area)
#define dmac_flush_range __glue(_CACHE,_dma_flush_range)
#endif
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index cba12f34ff77..b7998df043ef 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -39,6 +39,7 @@
#include <asm/system_info.h>
#include <asm/dma-contiguous.h>
+#include "dma.h"
#include "mm.h"
/*
diff --git a/arch/arm/mm/dma.h b/arch/arm/mm/dma.h
new file mode 100644
index 000000000000..70ea6852f94e
--- /dev/null
+++ b/arch/arm/mm/dma.h
@@ -0,0 +1,32 @@
+#ifndef DMA_H
+#define DMA_H
+
+#include <asm/glue-cache.h>
+
+#ifndef MULTI_CACHE
+#define dmac_map_area __glue(_CACHE,_dma_map_area)
+#define dmac_unmap_area __glue(_CACHE,_dma_unmap_area)
+
+/*
+ * These are private to the dma-mapping API. Do not use directly.
+ * Their sole purpose is to ensure that data held in the cache
+ * is visible to DMA, or data written by DMA to system memory is
+ * visible to the CPU.
+ */
+extern void dmac_map_area(const void *, size_t, int);
+extern void dmac_unmap_area(const void *, size_t, int);
+
+#else
+
+/*
+ * These are private to the dma-mapping API. Do not use directly.
+ * Their sole purpose is to ensure that data held in the cache
+ * is visible to DMA, or data written by DMA to system memory is
+ * visible to the CPU.
+ */
+#define dmac_map_area cpu_cache.dma_map_area
+#define dmac_unmap_area cpu_cache.dma_unmap_area
+
+#endif
+
+#endif
--
2.1.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 02/18] firmware: qcom_scm-32: replace open-coded call to __cpuc_flush_dcache_area()
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
2015-07-27 12:28 ` [PATCH 01/18] ARM: reduce visibility of dmac_* functions Russell King
@ 2015-07-27 12:28 ` Russell King
2015-08-04 18:48 ` Andy Gross
2015-08-04 18:50 ` Stephen Boyd
2015-07-27 12:29 ` [PATCH 03/18] iommu: tegra-smmu: fix iova_to_phys() method Russell King
` (17 subsequent siblings)
19 siblings, 2 replies; 30+ messages in thread
From: Russell King @ 2015-07-27 12:28 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
arch/arm/include/asm/cacheflush.h | 17 +++++++++++++++++
drivers/firmware/qcom_scm-32.c | 4 +---
2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index c5230a44eeca..d5525bfc7e3e 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -502,4 +502,21 @@ static inline void set_kernel_text_ro(void) { }
void flush_uprobe_xol_access(struct page *page, unsigned long uaddr,
void *kaddr, unsigned long len);
+/**
+ * secure_flush_area - ensure coherency across the secure boundary
+ * @addr: virtual address
+ * @size: size of region
+ *
+ * Ensure that the specified area of memory is coherent across the secure
+ * boundary from the non-secure side. This is used when calling secure
+ * firmware where the secure firmware does not ensure coherency.
+ */
+static inline void secure_flush_area(const void *addr, size_t size)
+{
+ phys_addr_t phys = __pa(addr);
+
+ __cpuc_flush_dcache_area((void *)addr, size);
+ outer_flush_range(phys, phys + size);
+}
+
#endif
diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
index 1bd6f9c34331..29e6850665eb 100644
--- a/drivers/firmware/qcom_scm-32.c
+++ b/drivers/firmware/qcom_scm-32.c
@@ -24,7 +24,6 @@
#include <linux/err.h>
#include <linux/qcom_scm.h>
-#include <asm/outercache.h>
#include <asm/cacheflush.h>
#include "qcom_scm.h"
@@ -219,8 +218,7 @@ static int __qcom_scm_call(const struct qcom_scm_command *cmd)
* Flush the command buffer so that the secure world sees
* the correct data.
*/
- __cpuc_flush_dcache_area((void *)cmd, cmd->len);
- outer_flush_range(cmd_addr, cmd_addr + cmd->len);
+ secure_flush_area(cmd, cmd->len);
ret = smc(cmd_addr);
if (ret < 0)
--
2.1.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 03/18] iommu: tegra-smmu: fix iova_to_phys() method
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
2015-07-27 12:28 ` [PATCH 01/18] ARM: reduce visibility of dmac_* functions Russell King
2015-07-27 12:28 ` [PATCH 02/18] firmware: qcom_scm-32: replace open-coded call to __cpuc_flush_dcache_area() Russell King
@ 2015-07-27 12:29 ` Russell King
2015-07-27 12:29 ` [PATCH 04/18] iommu: tegra-smmu: fix unmap() method Russell King
` (16 subsequent siblings)
19 siblings, 0 replies; 30+ messages in thread
From: Russell King @ 2015-07-27 12:29 UTC (permalink / raw)
To: linux-arm-kernel
iova_to_phys() has several problems:
(a) iova_to_phys() is supposed to return 0 if there is no entry present
for the iova.
(b) if as_get_pte() fails, we oops the kernel by dereferencing a NULL
pointer. Really, we should not even be trying to allocate a page
table at all, but should only be returning the presence of the 2nd
level page table. This will be fixed in a subsequent patch.
Treat both of these conditions as "no mapping" conditions.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/iommu/tegra-smmu.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index c1f2e521dc52..083354903a1a 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -592,6 +592,9 @@ static phys_addr_t tegra_smmu_iova_to_phys(struct iommu_domain *domain,
u32 *pte;
pte = as_get_pte(as, iova, &page);
+ if (!pte || !*pte)
+ return 0;
+
pfn = *pte & as->smmu->pfn_mask;
return PFN_PHYS(pfn);
--
2.1.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 04/18] iommu: tegra-smmu: fix unmap() method
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
` (2 preceding siblings ...)
2015-07-27 12:29 ` [PATCH 03/18] iommu: tegra-smmu: fix iova_to_phys() method Russell King
@ 2015-07-27 12:29 ` Russell King
2015-07-27 12:29 ` [PATCH 05/18] iommu: tegra-smmu: factor out common pte setting Russell King
` (15 subsequent siblings)
19 siblings, 0 replies; 30+ messages in thread
From: Russell King @ 2015-07-27 12:29 UTC (permalink / raw)
To: linux-arm-kernel
The Tegra SMMU unmap path has several problems:
1. as_pte_put() can perform a write-after-free
2. tegra_smmu_unmap() can perform cache maintanence on a page we have
just freed.
3. when a page table is unmapped, there is no CPU cache maintanence of
the write clearing the page directory entry, nor is there any
maintanence of the IOMMU to ensure that it sees the page table has
gone.
Fix this by getting rid of as_pte_put(), and instead coding the PTE
unmap separately from the PDE unmap, placing the PDE unmap after the
PTE unmap has been completed.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/iommu/tegra-smmu.c | 37 +++++++++++++++++++++++--------------
1 file changed, 23 insertions(+), 14 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 083354903a1a..a7a7645fb268 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -509,29 +509,35 @@ static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
return &pt[pte];
}
-static void as_put_pte(struct tegra_smmu_as *as, dma_addr_t iova)
+static void tegra_smmu_pte_put_use(struct tegra_smmu_as *as, unsigned long iova)
{
+ struct tegra_smmu *smmu = as->smmu;
u32 pde = (iova >> SMMU_PDE_SHIFT) & 0x3ff;
- u32 pte = (iova >> SMMU_PTE_SHIFT) & 0x3ff;
u32 *count = page_address(as->count);
- u32 *pd = page_address(as->pd), *pt;
+ u32 *pd = page_address(as->pd);
struct page *page;
- page = pfn_to_page(pd[pde] & as->smmu->pfn_mask);
- pt = page_address(page);
+ page = pfn_to_page(pd[pde] & smmu->pfn_mask);
/*
* When no entries in this page table are used anymore, return the
* memory page to the system.
*/
- if (pt[pte] != 0) {
- if (--count[pde] == 0) {
- ClearPageReserved(page);
- __free_page(page);
- pd[pde] = 0;
- }
+ if (--count[pde] == 0) {
+ unsigned int offset = pde * sizeof(*pd);
- pt[pte] = 0;
+ /* Clear the page directory entry first */
+ pd[pde] = 0;
+
+ /* Flush the page directory entry */
+ smmu->soc->ops->flush_dcache(as->pd, offset, sizeof(*pd));
+ smmu_flush_ptc(smmu, as->pd, offset);
+ smmu_flush_tlb_section(smmu, as->id, iova);
+ smmu_flush(smmu);
+
+ /* Finally, free the page */
+ ClearPageReserved(page);
+ __free_page(page);
}
}
@@ -569,17 +575,20 @@ static size_t tegra_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
u32 *pte;
pte = as_get_pte(as, iova, &page);
- if (!pte)
+ if (!pte || !*pte)
return 0;
+ *pte = 0;
+
offset = offset_in_page(pte);
- as_put_pte(as, iova);
smmu->soc->ops->flush_dcache(page, offset, 4);
smmu_flush_ptc(smmu, page, offset);
smmu_flush_tlb_group(smmu, as->id, iova);
smmu_flush(smmu);
+ tegra_smmu_pte_put_use(as, iova);
+
return size;
}
--
2.1.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 05/18] iommu: tegra-smmu: factor out common pte setting
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
` (3 preceding siblings ...)
2015-07-27 12:29 ` [PATCH 04/18] iommu: tegra-smmu: fix unmap() method Russell King
@ 2015-07-27 12:29 ` Russell King
2015-07-27 12:29 ` [PATCH 06/18] iommu: tegra-smmu: add iova_pd_index() and iova_pt_index() helpers Russell King
` (14 subsequent siblings)
19 siblings, 0 replies; 30+ messages in thread
From: Russell King @ 2015-07-27 12:29 UTC (permalink / raw)
To: linux-arm-kernel
Factor out the common pte setting code into a separate function.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/iommu/tegra-smmu.c | 37 +++++++++++++++++--------------------
1 file changed, 17 insertions(+), 20 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index a7a7645fb268..53d0f15dac6f 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -541,12 +541,24 @@ static void tegra_smmu_pte_put_use(struct tegra_smmu_as *as, unsigned long iova)
}
}
+static void tegra_smmu_set_pte(struct tegra_smmu_as *as, unsigned long iova,
+ u32 *pte, struct page *pte_page, u32 val)
+{
+ struct tegra_smmu *smmu = as->smmu;
+ unsigned long offset = offset_in_page(pte);
+
+ *pte = val;
+
+ smmu->soc->ops->flush_dcache(pte_page, offset, 4);
+ smmu_flush_ptc(smmu, pte_page, offset);
+ smmu_flush_tlb_group(smmu, as->id, iova);
+ smmu_flush(smmu);
+}
+
static int tegra_smmu_map(struct iommu_domain *domain, unsigned long iova,
phys_addr_t paddr, size_t size, int prot)
{
struct tegra_smmu_as *as = to_smmu_as(domain);
- struct tegra_smmu *smmu = as->smmu;
- unsigned long offset;
struct page *page;
u32 *pte;
@@ -554,13 +566,8 @@ static int tegra_smmu_map(struct iommu_domain *domain, unsigned long iova,
if (!pte)
return -ENOMEM;
- *pte = __phys_to_pfn(paddr) | SMMU_PTE_ATTR;
- offset = offset_in_page(pte);
-
- smmu->soc->ops->flush_dcache(page, offset, 4);
- smmu_flush_ptc(smmu, page, offset);
- smmu_flush_tlb_group(smmu, as->id, iova);
- smmu_flush(smmu);
+ tegra_smmu_set_pte(as, iova, pte, page,
+ __phys_to_pfn(paddr) | SMMU_PTE_ATTR);
return 0;
}
@@ -569,8 +576,6 @@ static size_t tegra_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
size_t size)
{
struct tegra_smmu_as *as = to_smmu_as(domain);
- struct tegra_smmu *smmu = as->smmu;
- unsigned long offset;
struct page *page;
u32 *pte;
@@ -578,15 +583,7 @@ static size_t tegra_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
if (!pte || !*pte)
return 0;
- *pte = 0;
-
- offset = offset_in_page(pte);
-
- smmu->soc->ops->flush_dcache(page, offset, 4);
- smmu_flush_ptc(smmu, page, offset);
- smmu_flush_tlb_group(smmu, as->id, iova);
- smmu_flush(smmu);
-
+ tegra_smmu_set_pte(as, iova, pte, page, 0);
tegra_smmu_pte_put_use(as, iova);
return size;
--
2.1.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 06/18] iommu: tegra-smmu: add iova_pd_index() and iova_pt_index() helpers
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
` (4 preceding siblings ...)
2015-07-27 12:29 ` [PATCH 05/18] iommu: tegra-smmu: factor out common pte setting Russell King
@ 2015-07-27 12:29 ` Russell King
2015-07-27 12:29 ` [PATCH 07/18] iommu: tegra-smmu: fix page table lookup in unmap/iova_to_phys methods Russell King
` (13 subsequent siblings)
19 siblings, 0 replies; 30+ messages in thread
From: Russell King @ 2015-07-27 12:29 UTC (permalink / raw)
To: linux-arm-kernel
Add a pair of helpers to get the page directory and page table indexes.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/iommu/tegra-smmu.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 53d0f15dac6f..4c4bc7966046 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -134,6 +134,16 @@ static inline u32 smmu_readl(struct tegra_smmu *smmu, unsigned long offset)
#define SMMU_PTE_ATTR (SMMU_PTE_READABLE | SMMU_PTE_WRITABLE | \
SMMU_PTE_NONSECURE)
+static unsigned int iova_pd_index(unsigned long iova)
+{
+ return (iova >> SMMU_PDE_SHIFT) & (SMMU_NUM_PDE - 1);
+}
+
+static unsigned int iova_pt_index(unsigned long iova)
+{
+ return (iova >> SMMU_PTE_SHIFT) & (SMMU_NUM_PTE - 1);
+}
+
static inline void smmu_flush_ptc(struct tegra_smmu *smmu, struct page *page,
unsigned long offset)
{
@@ -469,8 +479,8 @@ static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
struct page **pagep)
{
u32 *pd = page_address(as->pd), *pt, *count;
- u32 pde = (iova >> SMMU_PDE_SHIFT) & 0x3ff;
- u32 pte = (iova >> SMMU_PTE_SHIFT) & 0x3ff;
+ unsigned int pde = iova_pd_index(iova);
+ unsigned int pte = iova_pt_index(iova);
struct tegra_smmu *smmu = as->smmu;
struct page *page;
unsigned int i;
@@ -512,7 +522,7 @@ static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
static void tegra_smmu_pte_put_use(struct tegra_smmu_as *as, unsigned long iova)
{
struct tegra_smmu *smmu = as->smmu;
- u32 pde = (iova >> SMMU_PDE_SHIFT) & 0x3ff;
+ unsigned int pde = iova_pd_index(iova);
u32 *count = page_address(as->count);
u32 *pd = page_address(as->pd);
struct page *page;
--
2.1.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 07/18] iommu: tegra-smmu: fix page table lookup in unmap/iova_to_phys methods
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
` (5 preceding siblings ...)
2015-07-27 12:29 ` [PATCH 06/18] iommu: tegra-smmu: add iova_pd_index() and iova_pt_index() helpers Russell King
@ 2015-07-27 12:29 ` Russell King
2015-07-27 12:29 ` [PATCH 08/18] iommu: tegra-smmu: store struct page pointer for page tables Russell King
` (12 subsequent siblings)
19 siblings, 0 replies; 30+ messages in thread
From: Russell King @ 2015-07-27 12:29 UTC (permalink / raw)
To: linux-arm-kernel
Fix the page table lookup in the unmap and iova_to_phys methods.
Neither of these methods should allocate a page table; a missing page
table should be treated the same as no mapping present.
More importantly, using as_get_pte() for an IOVA corresponding with a
non-present page table entry increments the use-count for the page
table, on the assumption that the caller of as_get_pte() is going to
setup a mapping. This is an incorrect assumption.
Fix both of these bugs by providing a separate helper which only looks
up the page table, but never allocates it. This is akin to pte_offset()
for CPU page tables.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/iommu/tegra-smmu.c | 43 ++++++++++++++++++++++++++++++++++---------
1 file changed, 34 insertions(+), 9 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 4c4bc7966046..bbff5b647183 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -475,12 +475,36 @@ static void tegra_smmu_detach_dev(struct iommu_domain *domain, struct device *de
}
}
+static u32 *tegra_smmu_pte_offset(struct page *pt_page, unsigned long iova)
+{
+ u32 *pt = page_address(pt_page);
+
+ return pt + iova_pt_index(iova);
+}
+
+static u32 *tegra_smmu_pte_lookup(struct tegra_smmu_as *as, unsigned long iova,
+ struct page **pagep)
+{
+ unsigned int pd_index = iova_pd_index(iova);
+ struct page *pt_page;
+ u32 *pd;
+
+ pd = page_address(as->pd);
+
+ if (!pd[pd_index])
+ return NULL;
+
+ pt_page = pfn_to_page(pd[pd_index] & as->smmu->pfn_mask);
+ *pagep = pt_page;
+
+ return tegra_smmu_pte_offset(pt_page, iova);
+}
+
static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
struct page **pagep)
{
u32 *pd = page_address(as->pd), *pt, *count;
unsigned int pde = iova_pd_index(iova);
- unsigned int pte = iova_pt_index(iova);
struct tegra_smmu *smmu = as->smmu;
struct page *page;
unsigned int i;
@@ -506,17 +530,18 @@ static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
smmu_flush(smmu);
} else {
page = pfn_to_page(pd[pde] & smmu->pfn_mask);
- pt = page_address(page);
}
*pagep = page;
+ pt = page_address(page);
+
/* Keep track of entries in this page table. */
count = page_address(as->count);
- if (pt[pte] == 0)
+ if (pt[iova_pt_index(iova)] == 0)
count[pde]++;
- return &pt[pte];
+ return tegra_smmu_pte_offset(page, iova);
}
static void tegra_smmu_pte_put_use(struct tegra_smmu_as *as, unsigned long iova)
@@ -586,14 +611,14 @@ static size_t tegra_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
size_t size)
{
struct tegra_smmu_as *as = to_smmu_as(domain);
- struct page *page;
+ struct page *pte_page;
u32 *pte;
- pte = as_get_pte(as, iova, &page);
+ pte = tegra_smmu_pte_lookup(as, iova, &pte_page);
if (!pte || !*pte)
return 0;
- tegra_smmu_set_pte(as, iova, pte, page, 0);
+ tegra_smmu_set_pte(as, iova, pte, pte_page, 0);
tegra_smmu_pte_put_use(as, iova);
return size;
@@ -603,11 +628,11 @@ static phys_addr_t tegra_smmu_iova_to_phys(struct iommu_domain *domain,
dma_addr_t iova)
{
struct tegra_smmu_as *as = to_smmu_as(domain);
- struct page *page;
+ struct page *pte_page;
unsigned long pfn;
u32 *pte;
- pte = as_get_pte(as, iova, &page);
+ pte = tegra_smmu_pte_lookup(as, iova, &pte_page);
if (!pte || !*pte)
return 0;
--
2.1.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 08/18] iommu: tegra-smmu: store struct page pointer for page tables
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
` (6 preceding siblings ...)
2015-07-27 12:29 ` [PATCH 07/18] iommu: tegra-smmu: fix page table lookup in unmap/iova_to_phys methods Russell King
@ 2015-07-27 12:29 ` Russell King
2015-07-27 12:29 ` [PATCH 09/18] iommu: tegra-smmu: use kcalloc() to allocate counter array Russell King
` (11 subsequent siblings)
19 siblings, 0 replies; 30+ messages in thread
From: Russell King @ 2015-07-27 12:29 UTC (permalink / raw)
To: linux-arm-kernel
Store the struct page pointer for the second level page tables, rather
than working back from the page directory entry. This is necessary as
we want to eliminate the use of physical addresses used with
arch-private functions, switching instead to use the streaming DMA API.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/iommu/tegra-smmu.c | 27 +++++++++++++++++----------
1 file changed, 17 insertions(+), 10 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index bbff5b647183..8ec5ac45caab 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -41,6 +41,7 @@ struct tegra_smmu_as {
struct tegra_smmu *smmu;
unsigned int use_count;
struct page *count;
+ struct page **pts;
struct page *pd;
unsigned id;
u32 attr;
@@ -271,6 +272,14 @@ static struct iommu_domain *tegra_smmu_domain_alloc(unsigned type)
return NULL;
}
+ as->pts = kcalloc(SMMU_NUM_PDE, sizeof(*as->pts), GFP_KERNEL);
+ if (!as->pts) {
+ __free_page(as->count);
+ __free_page(as->pd);
+ kfree(as);
+ return NULL;
+ }
+
/* clear PDEs */
pd = page_address(as->pd);
SetPageReserved(as->pd);
@@ -487,14 +496,11 @@ static u32 *tegra_smmu_pte_lookup(struct tegra_smmu_as *as, unsigned long iova,
{
unsigned int pd_index = iova_pd_index(iova);
struct page *pt_page;
- u32 *pd;
- pd = page_address(as->pd);
-
- if (!pd[pd_index])
+ pt_page = as->pts[pd_index];
+ if (!pt_page)
return NULL;
- pt_page = pfn_to_page(pd[pd_index] & as->smmu->pfn_mask);
*pagep = pt_page;
return tegra_smmu_pte_offset(pt_page, iova);
@@ -509,7 +515,7 @@ static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
struct page *page;
unsigned int i;
- if (pd[pde] == 0) {
+ if (!as->pts[pde]) {
page = alloc_page(GFP_KERNEL | __GFP_DMA);
if (!page)
return NULL;
@@ -520,6 +526,8 @@ static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
for (i = 0; i < SMMU_NUM_PTE; i++)
pt[i] = 0;
+ as->pts[pde] = page;
+
smmu->soc->ops->flush_dcache(page, 0, SMMU_SIZE_PT);
pd[pde] = SMMU_MK_PDE(page, SMMU_PDE_ATTR | SMMU_PDE_NEXT);
@@ -529,7 +537,7 @@ static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
smmu_flush_tlb_section(smmu, as->id, iova);
smmu_flush(smmu);
} else {
- page = pfn_to_page(pd[pde] & smmu->pfn_mask);
+ page = as->pts[pde];
}
*pagep = page;
@@ -550,9 +558,7 @@ static void tegra_smmu_pte_put_use(struct tegra_smmu_as *as, unsigned long iova)
unsigned int pde = iova_pd_index(iova);
u32 *count = page_address(as->count);
u32 *pd = page_address(as->pd);
- struct page *page;
-
- page = pfn_to_page(pd[pde] & smmu->pfn_mask);
+ struct page *page = as->pts[pde];
/*
* When no entries in this page table are used anymore, return the
@@ -573,6 +579,7 @@ static void tegra_smmu_pte_put_use(struct tegra_smmu_as *as, unsigned long iova)
/* Finally, free the page */
ClearPageReserved(page);
__free_page(page);
+ as->pts[pde] = NULL;
}
}
--
2.1.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 09/18] iommu: tegra-smmu: use kcalloc() to allocate counter array
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
` (7 preceding siblings ...)
2015-07-27 12:29 ` [PATCH 08/18] iommu: tegra-smmu: store struct page pointer for page tables Russell King
@ 2015-07-27 12:29 ` Russell King
2015-07-27 12:29 ` [PATCH 10/18] iommu: tegra-smmu: move flush_dcache to tegra-smmu.c Russell King
` (10 subsequent siblings)
19 siblings, 0 replies; 30+ messages in thread
From: Russell King @ 2015-07-27 12:29 UTC (permalink / raw)
To: linux-arm-kernel
Use kcalloc() to allocate the use-counter array for the page directory
entries/page tables. Using kcalloc() allows us to be provided with
zero-initialised memory from the allocators, rather than initialising
it ourselves.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/iommu/tegra-smmu.c | 21 ++++++---------------
1 file changed, 6 insertions(+), 15 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 8ec5ac45caab..d649b06cc4ca 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -40,7 +40,7 @@ struct tegra_smmu_as {
struct iommu_domain domain;
struct tegra_smmu *smmu;
unsigned int use_count;
- struct page *count;
+ u32 *count;
struct page **pts;
struct page *pd;
unsigned id;
@@ -265,7 +265,7 @@ static struct iommu_domain *tegra_smmu_domain_alloc(unsigned type)
return NULL;
}
- as->count = alloc_page(GFP_KERNEL);
+ as->count = kcalloc(SMMU_NUM_PDE, sizeof(u32), GFP_KERNEL);
if (!as->count) {
__free_page(as->pd);
kfree(as);
@@ -274,7 +274,7 @@ static struct iommu_domain *tegra_smmu_domain_alloc(unsigned type)
as->pts = kcalloc(SMMU_NUM_PDE, sizeof(*as->pts), GFP_KERNEL);
if (!as->pts) {
- __free_page(as->count);
+ kfree(as->count);
__free_page(as->pd);
kfree(as);
return NULL;
@@ -287,13 +287,6 @@ static struct iommu_domain *tegra_smmu_domain_alloc(unsigned type)
for (i = 0; i < SMMU_NUM_PDE; i++)
pd[i] = 0;
- /* clear PDE usage counters */
- pd = page_address(as->count);
- SetPageReserved(as->count);
-
- for (i = 0; i < SMMU_NUM_PDE; i++)
- pd[i] = 0;
-
/* setup aperture */
as->domain.geometry.aperture_start = 0;
as->domain.geometry.aperture_end = 0xffffffff;
@@ -509,7 +502,7 @@ static u32 *tegra_smmu_pte_lookup(struct tegra_smmu_as *as, unsigned long iova,
static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
struct page **pagep)
{
- u32 *pd = page_address(as->pd), *pt, *count;
+ u32 *pd = page_address(as->pd), *pt;
unsigned int pde = iova_pd_index(iova);
struct tegra_smmu *smmu = as->smmu;
struct page *page;
@@ -545,9 +538,8 @@ static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
pt = page_address(page);
/* Keep track of entries in this page table. */
- count = page_address(as->count);
if (pt[iova_pt_index(iova)] == 0)
- count[pde]++;
+ as->count[pde]++;
return tegra_smmu_pte_offset(page, iova);
}
@@ -556,7 +548,6 @@ static void tegra_smmu_pte_put_use(struct tegra_smmu_as *as, unsigned long iova)
{
struct tegra_smmu *smmu = as->smmu;
unsigned int pde = iova_pd_index(iova);
- u32 *count = page_address(as->count);
u32 *pd = page_address(as->pd);
struct page *page = as->pts[pde];
@@ -564,7 +555,7 @@ static void tegra_smmu_pte_put_use(struct tegra_smmu_as *as, unsigned long iova)
* When no entries in this page table are used anymore, return the
* memory page to the system.
*/
- if (--count[pde] == 0) {
+ if (--as->count[pde] == 0) {
unsigned int offset = pde * sizeof(*pd);
/* Clear the page directory entry first */
--
2.1.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 10/18] iommu: tegra-smmu: move flush_dcache to tegra-smmu.c
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
` (8 preceding siblings ...)
2015-07-27 12:29 ` [PATCH 09/18] iommu: tegra-smmu: use kcalloc() to allocate counter array Russell King
@ 2015-07-27 12:29 ` Russell King
2015-07-27 12:29 ` [PATCH 11/18] iommu: tegra-smmu: split smmu_flush_ptc() Russell King
` (9 subsequent siblings)
19 siblings, 0 replies; 30+ messages in thread
From: Russell King @ 2015-07-27 12:29 UTC (permalink / raw)
To: linux-arm-kernel
Drivers should not be using __cpuc_* functions nor outer_cache_flush()
directly. This change partly cleans up tegra-smmu.c.
The only difference between cache handling of the tegra variants is
Denver, which omits the call to outer_cache_flush(). This is due to
Denver being an ARM64 CPU, and the ARM64 architecture does not provide
this function. (This, in itself, is a good reason why these should not
be used.)
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/iommu/tegra-smmu.c | 24 +++++++++++++++++++-----
drivers/memory/tegra/tegra114.c | 17 -----------------
drivers/memory/tegra/tegra124.c | 30 ------------------------------
drivers/memory/tegra/tegra30.c | 17 -----------------
include/soc/tegra/mc.h | 7 -------
5 files changed, 19 insertions(+), 76 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index d649b06cc4ca..fa26b76017cf 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -16,6 +16,8 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <asm/cacheflush.h>
+
#include <soc/tegra/ahb.h>
#include <soc/tegra/mc.h>
@@ -145,6 +147,18 @@ static unsigned int iova_pt_index(unsigned long iova)
return (iova >> SMMU_PTE_SHIFT) & (SMMU_NUM_PTE - 1);
}
+static void smmu_flush_dcache(struct page *page, unsigned long offset,
+ size_t size)
+{
+ phys_addr_t phys = page_to_phys(page) + offset;
+ void *virt = page_address(page) + offset;
+
+ __cpuc_flush_dcache_area(virt, size);
+#ifdef CONFIG_ARM
+ outer_flush_range(phys, phys + size);
+#endif
+}
+
static inline void smmu_flush_ptc(struct tegra_smmu *smmu, struct page *page,
unsigned long offset)
{
@@ -392,7 +406,7 @@ static int tegra_smmu_as_prepare(struct tegra_smmu *smmu,
if (err < 0)
return err;
- smmu->soc->ops->flush_dcache(as->pd, 0, SMMU_SIZE_PD);
+ smmu_flush_dcache(as->pd, 0, SMMU_SIZE_PD);
smmu_flush_ptc(smmu, as->pd, 0);
smmu_flush_tlb_asid(smmu, as->id);
@@ -521,11 +535,11 @@ static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
as->pts[pde] = page;
- smmu->soc->ops->flush_dcache(page, 0, SMMU_SIZE_PT);
+ smmu_flush_dcache(page, 0, SMMU_SIZE_PT);
pd[pde] = SMMU_MK_PDE(page, SMMU_PDE_ATTR | SMMU_PDE_NEXT);
- smmu->soc->ops->flush_dcache(as->pd, pde << 2, 4);
+ smmu_flush_dcache(as->pd, pde << 2, 4);
smmu_flush_ptc(smmu, as->pd, pde << 2);
smmu_flush_tlb_section(smmu, as->id, iova);
smmu_flush(smmu);
@@ -562,7 +576,7 @@ static void tegra_smmu_pte_put_use(struct tegra_smmu_as *as, unsigned long iova)
pd[pde] = 0;
/* Flush the page directory entry */
- smmu->soc->ops->flush_dcache(as->pd, offset, sizeof(*pd));
+ smmu_flush_dcache(as->pd, offset, sizeof(*pd));
smmu_flush_ptc(smmu, as->pd, offset);
smmu_flush_tlb_section(smmu, as->id, iova);
smmu_flush(smmu);
@@ -582,7 +596,7 @@ static void tegra_smmu_set_pte(struct tegra_smmu_as *as, unsigned long iova,
*pte = val;
- smmu->soc->ops->flush_dcache(pte_page, offset, 4);
+ smmu_flush_dcache(pte_page, offset, 4);
smmu_flush_ptc(smmu, pte_page, offset);
smmu_flush_tlb_group(smmu, as->id, iova);
smmu_flush(smmu);
diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c
index 9f579589e800..7122f39be9cc 100644
--- a/drivers/memory/tegra/tegra114.c
+++ b/drivers/memory/tegra/tegra114.c
@@ -9,8 +9,6 @@
#include <linux/of.h>
#include <linux/mm.h>
-#include <asm/cacheflush.h>
-
#include <dt-bindings/memory/tegra114-mc.h>
#include "mc.h"
@@ -914,20 +912,6 @@ static const struct tegra_smmu_swgroup tegra114_swgroups[] = {
{ .name = "tsec", .swgroup = TEGRA_SWGROUP_TSEC, .reg = 0x294 },
};
-static void tegra114_flush_dcache(struct page *page, unsigned long offset,
- size_t size)
-{
- phys_addr_t phys = page_to_phys(page) + offset;
- void *virt = page_address(page) + offset;
-
- __cpuc_flush_dcache_area(virt, size);
- outer_flush_range(phys, phys + size);
-}
-
-static const struct tegra_smmu_ops tegra114_smmu_ops = {
- .flush_dcache = tegra114_flush_dcache,
-};
-
static const struct tegra_smmu_soc tegra114_smmu_soc = {
.clients = tegra114_mc_clients,
.num_clients = ARRAY_SIZE(tegra114_mc_clients),
@@ -936,7 +920,6 @@ static const struct tegra_smmu_soc tegra114_smmu_soc = {
.supports_round_robin_arbitration = false,
.supports_request_limit = false,
.num_asids = 4,
- .ops = &tegra114_smmu_ops,
};
const struct tegra_mc_soc tegra114_mc_soc = {
diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c
index 966e1557e6f4..ebda63283853 100644
--- a/drivers/memory/tegra/tegra124.c
+++ b/drivers/memory/tegra/tegra124.c
@@ -9,8 +9,6 @@
#include <linux/of.h>
#include <linux/mm.h>
-#include <asm/cacheflush.h>
-
#include <dt-bindings/memory/tegra124-mc.h>
#include "mc.h"
@@ -1002,20 +1000,6 @@ static const struct tegra_smmu_swgroup tegra124_swgroups[] = {
};
#ifdef CONFIG_ARCH_TEGRA_124_SOC
-static void tegra124_flush_dcache(struct page *page, unsigned long offset,
- size_t size)
-{
- phys_addr_t phys = page_to_phys(page) + offset;
- void *virt = page_address(page) + offset;
-
- __cpuc_flush_dcache_area(virt, size);
- outer_flush_range(phys, phys + size);
-}
-
-static const struct tegra_smmu_ops tegra124_smmu_ops = {
- .flush_dcache = tegra124_flush_dcache,
-};
-
static const struct tegra_smmu_soc tegra124_smmu_soc = {
.clients = tegra124_mc_clients,
.num_clients = ARRAY_SIZE(tegra124_mc_clients),
@@ -1024,7 +1008,6 @@ static const struct tegra_smmu_soc tegra124_smmu_soc = {
.supports_round_robin_arbitration = true,
.supports_request_limit = true,
.num_asids = 128,
- .ops = &tegra124_smmu_ops,
};
const struct tegra_mc_soc tegra124_mc_soc = {
@@ -1039,18 +1022,6 @@ const struct tegra_mc_soc tegra124_mc_soc = {
#endif /* CONFIG_ARCH_TEGRA_124_SOC */
#ifdef CONFIG_ARCH_TEGRA_132_SOC
-static void tegra132_flush_dcache(struct page *page, unsigned long offset,
- size_t size)
-{
- void *virt = page_address(page) + offset;
-
- __flush_dcache_area(virt, size);
-}
-
-static const struct tegra_smmu_ops tegra132_smmu_ops = {
- .flush_dcache = tegra132_flush_dcache,
-};
-
static const struct tegra_smmu_soc tegra132_smmu_soc = {
.clients = tegra124_mc_clients,
.num_clients = ARRAY_SIZE(tegra124_mc_clients),
@@ -1059,7 +1030,6 @@ static const struct tegra_smmu_soc tegra132_smmu_soc = {
.supports_round_robin_arbitration = true,
.supports_request_limit = true,
.num_asids = 128,
- .ops = &tegra132_smmu_ops,
};
const struct tegra_mc_soc tegra132_mc_soc = {
diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c
index 1abcd8f6f3ba..3cb30b69d95b 100644
--- a/drivers/memory/tegra/tegra30.c
+++ b/drivers/memory/tegra/tegra30.c
@@ -9,8 +9,6 @@
#include <linux/of.h>
#include <linux/mm.h>
-#include <asm/cacheflush.h>
-
#include <dt-bindings/memory/tegra30-mc.h>
#include "mc.h"
@@ -936,20 +934,6 @@ static const struct tegra_smmu_swgroup tegra30_swgroups[] = {
{ .name = "isp", .swgroup = TEGRA_SWGROUP_ISP, .reg = 0x258 },
};
-static void tegra30_flush_dcache(struct page *page, unsigned long offset,
- size_t size)
-{
- phys_addr_t phys = page_to_phys(page) + offset;
- void *virt = page_address(page) + offset;
-
- __cpuc_flush_dcache_area(virt, size);
- outer_flush_range(phys, phys + size);
-}
-
-static const struct tegra_smmu_ops tegra30_smmu_ops = {
- .flush_dcache = tegra30_flush_dcache,
-};
-
static const struct tegra_smmu_soc tegra30_smmu_soc = {
.clients = tegra30_mc_clients,
.num_clients = ARRAY_SIZE(tegra30_mc_clients),
@@ -958,7 +942,6 @@ static const struct tegra_smmu_soc tegra30_smmu_soc = {
.supports_round_robin_arbitration = false,
.supports_request_limit = false,
.num_asids = 4,
- .ops = &tegra30_smmu_ops,
};
const struct tegra_mc_soc tegra30_mc_soc = {
diff --git a/include/soc/tegra/mc.h b/include/soc/tegra/mc.h
index 1ab2813273cd..d6c3190ec852 100644
--- a/include/soc/tegra/mc.h
+++ b/include/soc/tegra/mc.h
@@ -51,11 +51,6 @@ struct tegra_smmu_swgroup {
unsigned int reg;
};
-struct tegra_smmu_ops {
- void (*flush_dcache)(struct page *page, unsigned long offset,
- size_t size);
-};
-
struct tegra_smmu_soc {
const struct tegra_mc_client *clients;
unsigned int num_clients;
@@ -67,8 +62,6 @@ struct tegra_smmu_soc {
bool supports_request_limit;
unsigned int num_asids;
-
- const struct tegra_smmu_ops *ops;
};
struct tegra_mc;
--
2.1.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 11/18] iommu: tegra-smmu: split smmu_flush_ptc()
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
` (9 preceding siblings ...)
2015-07-27 12:29 ` [PATCH 10/18] iommu: tegra-smmu: move flush_dcache to tegra-smmu.c Russell King
@ 2015-07-27 12:29 ` Russell King
2015-07-27 12:29 ` [PATCH 12/18] iommu: tegra-smmu: smmu_flush_ptc() wants device address Russell King
` (8 subsequent siblings)
19 siblings, 0 replies; 30+ messages in thread
From: Russell King @ 2015-07-27 12:29 UTC (permalink / raw)
To: linux-arm-kernel
smmu_flush_ptc() is used in two modes: one is to flush an individual
entry, the other is to flush all entries. We know at the call site
which we require. Split the function into smmu_flush_ptc_all() and
smmu_flush_ptc().
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/iommu/tegra-smmu.c | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index fa26b76017cf..89e7961f4848 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -159,29 +159,29 @@ static void smmu_flush_dcache(struct page *page, unsigned long offset,
#endif
}
+static void smmu_flush_ptc_all(struct tegra_smmu *smmu)
+{
+ smmu_writel(smmu, SMMU_PTC_FLUSH_TYPE_ALL, SMMU_PTC_FLUSH);
+}
+
static inline void smmu_flush_ptc(struct tegra_smmu *smmu, struct page *page,
unsigned long offset)
{
- phys_addr_t phys = page ? page_to_phys(page) : 0;
+ phys_addr_t phys = page_to_phys(page);
u32 value;
- if (page) {
- offset &= ~(smmu->mc->soc->atom_size - 1);
+ offset &= ~(smmu->mc->soc->atom_size - 1);
- if (smmu->mc->soc->num_address_bits > 32) {
+ if (smmu->mc->soc->num_address_bits > 32) {
#ifdef CONFIG_PHYS_ADDR_T_64BIT
- value = (phys >> 32) & SMMU_PTC_FLUSH_HI_MASK;
+ value = (phys >> 32) & SMMU_PTC_FLUSH_HI_MASK;
#else
- value = 0;
+ value = 0;
#endif
- smmu_writel(smmu, value, SMMU_PTC_FLUSH_HI);
- }
-
- value = (phys + offset) | SMMU_PTC_FLUSH_TYPE_ADR;
- } else {
- value = SMMU_PTC_FLUSH_TYPE_ALL;
+ smmu_writel(smmu, value, SMMU_PTC_FLUSH_HI);
}
+ value = (phys + offset) | SMMU_PTC_FLUSH_TYPE_ADR;
smmu_writel(smmu, value, SMMU_PTC_FLUSH);
}
@@ -888,7 +888,7 @@ struct tegra_smmu *tegra_smmu_probe(struct device *dev,
smmu_writel(smmu, value, SMMU_TLB_CONFIG);
- smmu_flush_ptc(smmu, NULL, 0);
+ smmu_flush_ptc_all(smmu);
smmu_flush_tlb(smmu);
smmu_writel(smmu, SMMU_CONFIG_ENABLE, SMMU_CONFIG);
smmu_flush(smmu);
--
2.1.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 12/18] iommu: tegra-smmu: smmu_flush_ptc() wants device address
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
` (10 preceding siblings ...)
2015-07-27 12:29 ` [PATCH 11/18] iommu: tegra-smmu: split smmu_flush_ptc() Russell King
@ 2015-07-27 12:29 ` Russell King
2015-07-27 12:29 ` [PATCH 13/18] iommu: tegra-smmu: convert to use DMA API Russell King
` (7 subsequent siblings)
19 siblings, 0 replies; 30+ messages in thread
From: Russell King @ 2015-07-27 12:29 UTC (permalink / raw)
To: linux-arm-kernel
Pass smmu_flush_ptc() the device address rather than struct page
poiner.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/iommu/tegra-smmu.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 89e7961f4848..c54b0afda475 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -164,10 +164,9 @@ static void smmu_flush_ptc_all(struct tegra_smmu *smmu)
smmu_writel(smmu, SMMU_PTC_FLUSH_TYPE_ALL, SMMU_PTC_FLUSH);
}
-static inline void smmu_flush_ptc(struct tegra_smmu *smmu, struct page *page,
+static inline void smmu_flush_ptc(struct tegra_smmu *smmu, phys_addr_t phys,
unsigned long offset)
{
- phys_addr_t phys = page_to_phys(page);
u32 value;
offset &= ~(smmu->mc->soc->atom_size - 1);
@@ -407,7 +406,7 @@ static int tegra_smmu_as_prepare(struct tegra_smmu *smmu,
return err;
smmu_flush_dcache(as->pd, 0, SMMU_SIZE_PD);
- smmu_flush_ptc(smmu, as->pd, 0);
+ smmu_flush_ptc(smmu, page_to_phys(as->pd), 0);
smmu_flush_tlb_asid(smmu, as->id);
smmu_writel(smmu, as->id & 0x7f, SMMU_PTB_ASID);
@@ -540,7 +539,7 @@ static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
pd[pde] = SMMU_MK_PDE(page, SMMU_PDE_ATTR | SMMU_PDE_NEXT);
smmu_flush_dcache(as->pd, pde << 2, 4);
- smmu_flush_ptc(smmu, as->pd, pde << 2);
+ smmu_flush_ptc(smmu, page_to_phys(as->pd), pde << 2);
smmu_flush_tlb_section(smmu, as->id, iova);
smmu_flush(smmu);
} else {
@@ -577,7 +576,7 @@ static void tegra_smmu_pte_put_use(struct tegra_smmu_as *as, unsigned long iova)
/* Flush the page directory entry */
smmu_flush_dcache(as->pd, offset, sizeof(*pd));
- smmu_flush_ptc(smmu, as->pd, offset);
+ smmu_flush_ptc(smmu, page_to_phys(as->pd), offset);
smmu_flush_tlb_section(smmu, as->id, iova);
smmu_flush(smmu);
@@ -597,7 +596,7 @@ static void tegra_smmu_set_pte(struct tegra_smmu_as *as, unsigned long iova,
*pte = val;
smmu_flush_dcache(pte_page, offset, 4);
- smmu_flush_ptc(smmu, pte_page, offset);
+ smmu_flush_ptc(smmu, page_to_phys(pte_page), offset);
smmu_flush_tlb_group(smmu, as->id, iova);
smmu_flush(smmu);
}
--
2.1.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 13/18] iommu: tegra-smmu: convert to use DMA API
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
` (11 preceding siblings ...)
2015-07-27 12:29 ` [PATCH 12/18] iommu: tegra-smmu: smmu_flush_ptc() wants device address Russell King
@ 2015-07-27 12:29 ` Russell King
2015-07-27 12:29 ` [PATCH 14/18] iommu: tegra-smmu: remove PageReserved manipulation Russell King
` (6 subsequent siblings)
19 siblings, 0 replies; 30+ messages in thread
From: Russell King @ 2015-07-27 12:29 UTC (permalink / raw)
To: linux-arm-kernel
Use the DMA API instead of calling architecture internal functions in
the Tegra SMMU driver.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/iommu/tegra-smmu.c | 129 +++++++++++++++++++++++++++++----------------
1 file changed, 84 insertions(+), 45 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index c54b0afda475..d4264e2bdd69 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -45,6 +45,7 @@ struct tegra_smmu_as {
u32 *count;
struct page **pts;
struct page *pd;
+ dma_addr_t pd_dma;
unsigned id;
u32 attr;
};
@@ -82,9 +83,9 @@ static inline u32 smmu_readl(struct tegra_smmu *smmu, unsigned long offset)
#define SMMU_PTB_ASID_VALUE(x) ((x) & 0x7f)
#define SMMU_PTB_DATA 0x020
-#define SMMU_PTB_DATA_VALUE(page, attr) (page_to_phys(page) >> 12 | (attr))
+#define SMMU_PTB_DATA_VALUE(dma, attr) ((dma) >> 12 | (attr))
-#define SMMU_MK_PDE(page, attr) (page_to_phys(page) >> SMMU_PTE_SHIFT | (attr))
+#define SMMU_MK_PDE(dma, attr) ((dma) >> SMMU_PTE_SHIFT | (attr))
#define SMMU_TLB_FLUSH 0x030
#define SMMU_TLB_FLUSH_VA_MATCH_ALL (0 << 0)
@@ -147,16 +148,15 @@ static unsigned int iova_pt_index(unsigned long iova)
return (iova >> SMMU_PTE_SHIFT) & (SMMU_NUM_PTE - 1);
}
-static void smmu_flush_dcache(struct page *page, unsigned long offset,
- size_t size)
+static bool smmu_dma_addr_valid(struct tegra_smmu *smmu, dma_addr_t addr)
{
- phys_addr_t phys = page_to_phys(page) + offset;
- void *virt = page_address(page) + offset;
+ addr >>= 12;
+ return (addr & smmu->pfn_mask) == addr;
+}
- __cpuc_flush_dcache_area(virt, size);
-#ifdef CONFIG_ARM
- outer_flush_range(phys, phys + size);
-#endif
+static dma_addr_t smmu_pde_to_dma(u32 pde)
+{
+ return pde << 12;
}
static void smmu_flush_ptc_all(struct tegra_smmu *smmu)
@@ -164,7 +164,7 @@ static void smmu_flush_ptc_all(struct tegra_smmu *smmu)
smmu_writel(smmu, SMMU_PTC_FLUSH_TYPE_ALL, SMMU_PTC_FLUSH);
}
-static inline void smmu_flush_ptc(struct tegra_smmu *smmu, phys_addr_t phys,
+static inline void smmu_flush_ptc(struct tegra_smmu *smmu, dma_addr_t dma,
unsigned long offset)
{
u32 value;
@@ -172,15 +172,15 @@ static inline void smmu_flush_ptc(struct tegra_smmu *smmu, phys_addr_t phys,
offset &= ~(smmu->mc->soc->atom_size - 1);
if (smmu->mc->soc->num_address_bits > 32) {
-#ifdef CONFIG_PHYS_ADDR_T_64BIT
- value = (phys >> 32) & SMMU_PTC_FLUSH_HI_MASK;
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ value = (dma >> 32) & SMMU_PTC_FLUSH_HI_MASK;
#else
value = 0;
#endif
smmu_writel(smmu, value, SMMU_PTC_FLUSH_HI);
}
- value = (phys + offset) | SMMU_PTC_FLUSH_TYPE_ADR;
+ value = (dma + offset) | SMMU_PTC_FLUSH_TYPE_ADR;
smmu_writel(smmu, value, SMMU_PTC_FLUSH);
}
@@ -401,16 +401,26 @@ static int tegra_smmu_as_prepare(struct tegra_smmu *smmu,
return 0;
}
+ as->pd_dma = dma_map_page(smmu->dev, as->pd, 0, SMMU_SIZE_PD,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(smmu->dev, as->pd_dma))
+ return -ENOMEM;
+
+ /* We can't handle 64-bit DMA addresses */
+ if (!smmu_dma_addr_valid(smmu, as->pd_dma)) {
+ err = -ENOMEM;
+ goto err_unmap;
+ }
+
err = tegra_smmu_alloc_asid(smmu, &as->id);
if (err < 0)
- return err;
+ goto err_unmap;
- smmu_flush_dcache(as->pd, 0, SMMU_SIZE_PD);
- smmu_flush_ptc(smmu, page_to_phys(as->pd), 0);
+ smmu_flush_ptc(smmu, as->pd_dma, 0);
smmu_flush_tlb_asid(smmu, as->id);
smmu_writel(smmu, as->id & 0x7f, SMMU_PTB_ASID);
- value = SMMU_PTB_DATA_VALUE(as->pd, as->attr);
+ value = SMMU_PTB_DATA_VALUE(as->pd_dma, as->attr);
smmu_writel(smmu, value, SMMU_PTB_DATA);
smmu_flush(smmu);
@@ -418,6 +428,10 @@ static int tegra_smmu_as_prepare(struct tegra_smmu *smmu,
as->use_count++;
return 0;
+
+err_unmap:
+ dma_unmap_page(smmu->dev, as->pd_dma, SMMU_SIZE_PD, DMA_TO_DEVICE);
+ return err;
}
static void tegra_smmu_as_unprepare(struct tegra_smmu *smmu,
@@ -427,6 +441,9 @@ static void tegra_smmu_as_unprepare(struct tegra_smmu *smmu,
return;
tegra_smmu_free_asid(smmu, as->id);
+
+ dma_unmap_page(smmu->dev, as->pd_dma, SMMU_SIZE_PD, DMA_TO_DEVICE);
+
as->smmu = NULL;
}
@@ -498,63 +515,81 @@ static u32 *tegra_smmu_pte_offset(struct page *pt_page, unsigned long iova)
}
static u32 *tegra_smmu_pte_lookup(struct tegra_smmu_as *as, unsigned long iova,
- struct page **pagep)
+ dma_addr_t *dmap)
{
unsigned int pd_index = iova_pd_index(iova);
struct page *pt_page;
+ u32 *pd;
pt_page = as->pts[pd_index];
if (!pt_page)
return NULL;
- *pagep = pt_page;
+ pd = page_address(as->pd);
+ *dmap = smmu_pde_to_dma(pd[pd_index]);
return tegra_smmu_pte_offset(pt_page, iova);
}
static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
- struct page **pagep)
+ dma_addr_t *dmap)
{
u32 *pd = page_address(as->pd), *pt;
unsigned int pde = iova_pd_index(iova);
struct tegra_smmu *smmu = as->smmu;
- struct page *page;
unsigned int i;
if (!as->pts[pde]) {
+ struct page *page;
+ dma_addr_t dma;
+
page = alloc_page(GFP_KERNEL | __GFP_DMA);
if (!page)
return NULL;
pt = page_address(page);
- SetPageReserved(page);
for (i = 0; i < SMMU_NUM_PTE; i++)
pt[i] = 0;
+ dma = dma_map_page(smmu->dev, page, 0, SMMU_SIZE_PT,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(smmu->dev, dma)) {
+ __free_page(page);
+ return NULL;
+ }
+
+ if (!smmu_dma_addr_valid(smmu, dma)) {
+ dma_unmap_page(smmu->dev, dma, SMMU_SIZE_PT,
+ DMA_TO_DEVICE);
+ __free_page(page);
+ return NULL;
+ }
+
as->pts[pde] = page;
- smmu_flush_dcache(page, 0, SMMU_SIZE_PT);
+ SetPageReserved(page);
- pd[pde] = SMMU_MK_PDE(page, SMMU_PDE_ATTR | SMMU_PDE_NEXT);
+ pd[pde] = SMMU_MK_PDE(dma, SMMU_PDE_ATTR | SMMU_PDE_NEXT);
- smmu_flush_dcache(as->pd, pde << 2, 4);
- smmu_flush_ptc(smmu, page_to_phys(as->pd), pde << 2);
+ dma_sync_single_range_for_device(smmu->dev, as->pd_dma,
+ pde << 2, 4, DMA_TO_DEVICE);
+ smmu_flush_ptc(smmu, as->pd_dma, pde << 2);
smmu_flush_tlb_section(smmu, as->id, iova);
smmu_flush(smmu);
+
+ *dmap = dma;
} else {
- page = as->pts[pde];
+ *dmap = smmu_pde_to_dma(pd[pde]);
}
- *pagep = page;
-
- pt = page_address(page);
+ pt = page_address(as->pts[pde]);
/* Keep track of entries in this page table. */
if (pt[iova_pt_index(iova)] == 0)
as->count[pde]++;
- return tegra_smmu_pte_offset(page, iova);
+ return tegra_smmu_pte_offset(as->pts[pde], iova);
}
static void tegra_smmu_pte_put_use(struct tegra_smmu_as *as, unsigned long iova)
@@ -570,17 +605,20 @@ static void tegra_smmu_pte_put_use(struct tegra_smmu_as *as, unsigned long iova)
*/
if (--as->count[pde] == 0) {
unsigned int offset = pde * sizeof(*pd);
+ dma_addr_t pte_dma = smmu_pde_to_dma(pd[pde]);
/* Clear the page directory entry first */
pd[pde] = 0;
/* Flush the page directory entry */
- smmu_flush_dcache(as->pd, offset, sizeof(*pd));
- smmu_flush_ptc(smmu, page_to_phys(as->pd), offset);
+ dma_sync_single_range_for_device(smmu->dev, as->pd_dma, offset,
+ sizeof(*pd), DMA_TO_DEVICE);
+ smmu_flush_ptc(smmu, as->pd_dma, offset);
smmu_flush_tlb_section(smmu, as->id, iova);
smmu_flush(smmu);
/* Finally, free the page */
+ dma_unmap_page(smmu->dev, pte_dma, SMMU_SIZE_PT, DMA_TO_DEVICE);
ClearPageReserved(page);
__free_page(page);
as->pts[pde] = NULL;
@@ -588,15 +626,16 @@ static void tegra_smmu_pte_put_use(struct tegra_smmu_as *as, unsigned long iova)
}
static void tegra_smmu_set_pte(struct tegra_smmu_as *as, unsigned long iova,
- u32 *pte, struct page *pte_page, u32 val)
+ u32 *pte, dma_addr_t pte_dma, u32 val)
{
struct tegra_smmu *smmu = as->smmu;
unsigned long offset = offset_in_page(pte);
*pte = val;
- smmu_flush_dcache(pte_page, offset, 4);
- smmu_flush_ptc(smmu, page_to_phys(pte_page), offset);
+ dma_sync_single_range_for_device(smmu->dev, pte_dma, offset,
+ 4, DMA_TO_DEVICE);
+ smmu_flush_ptc(smmu, pte_dma, offset);
smmu_flush_tlb_group(smmu, as->id, iova);
smmu_flush(smmu);
}
@@ -605,14 +644,14 @@ static int tegra_smmu_map(struct iommu_domain *domain, unsigned long iova,
phys_addr_t paddr, size_t size, int prot)
{
struct tegra_smmu_as *as = to_smmu_as(domain);
- struct page *page;
+ dma_addr_t pte_dma;
u32 *pte;
- pte = as_get_pte(as, iova, &page);
+ pte = as_get_pte(as, iova, &pte_dma);
if (!pte)
return -ENOMEM;
- tegra_smmu_set_pte(as, iova, pte, page,
+ tegra_smmu_set_pte(as, iova, pte, pte_dma,
__phys_to_pfn(paddr) | SMMU_PTE_ATTR);
return 0;
@@ -622,14 +661,14 @@ static size_t tegra_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
size_t size)
{
struct tegra_smmu_as *as = to_smmu_as(domain);
- struct page *pte_page;
+ dma_addr_t pte_dma;
u32 *pte;
- pte = tegra_smmu_pte_lookup(as, iova, &pte_page);
+ pte = tegra_smmu_pte_lookup(as, iova, &pte_dma);
if (!pte || !*pte)
return 0;
- tegra_smmu_set_pte(as, iova, pte, pte_page, 0);
+ tegra_smmu_set_pte(as, iova, pte, pte_dma, 0);
tegra_smmu_pte_put_use(as, iova);
return size;
@@ -639,11 +678,11 @@ static phys_addr_t tegra_smmu_iova_to_phys(struct iommu_domain *domain,
dma_addr_t iova)
{
struct tegra_smmu_as *as = to_smmu_as(domain);
- struct page *pte_page;
unsigned long pfn;
+ dma_addr_t pte_dma;
u32 *pte;
- pte = tegra_smmu_pte_lookup(as, iova, &pte_page);
+ pte = tegra_smmu_pte_lookup(as, iova, &pte_dma);
if (!pte || !*pte)
return 0;
--
2.1.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 14/18] iommu: tegra-smmu: remove PageReserved manipulation
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
` (12 preceding siblings ...)
2015-07-27 12:29 ` [PATCH 13/18] iommu: tegra-smmu: convert to use DMA API Russell King
@ 2015-07-27 12:29 ` Russell King
2015-07-27 12:30 ` [PATCH 15/18] iommu: tegra-smmu: use __GFP_ZERO to allocate zeroed pages Russell King
` (5 subsequent siblings)
19 siblings, 0 replies; 30+ messages in thread
From: Russell King @ 2015-07-27 12:29 UTC (permalink / raw)
To: linux-arm-kernel
Remove the unnecessary manipulation of the PageReserved flags in the
Tegra SMMU driver. None of this is required as the page(s) remain
private to the SMMU driver.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/iommu/tegra-smmu.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index d4264e2bdd69..b826362ce96b 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -295,7 +295,6 @@ static struct iommu_domain *tegra_smmu_domain_alloc(unsigned type)
/* clear PDEs */
pd = page_address(as->pd);
- SetPageReserved(as->pd);
for (i = 0; i < SMMU_NUM_PDE; i++)
pd[i] = 0;
@@ -313,7 +312,6 @@ static void tegra_smmu_domain_free(struct iommu_domain *domain)
struct tegra_smmu_as *as = to_smmu_as(domain);
/* TODO: free page directory and page tables */
- ClearPageReserved(as->pd);
kfree(as);
}
@@ -568,8 +566,6 @@ static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
as->pts[pde] = page;
- SetPageReserved(page);
-
pd[pde] = SMMU_MK_PDE(dma, SMMU_PDE_ATTR | SMMU_PDE_NEXT);
dma_sync_single_range_for_device(smmu->dev, as->pd_dma,
@@ -619,7 +615,6 @@ static void tegra_smmu_pte_put_use(struct tegra_smmu_as *as, unsigned long iova)
/* Finally, free the page */
dma_unmap_page(smmu->dev, pte_dma, SMMU_SIZE_PT, DMA_TO_DEVICE);
- ClearPageReserved(page);
__free_page(page);
as->pts[pde] = NULL;
}
--
2.1.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 15/18] iommu: tegra-smmu: use __GFP_ZERO to allocate zeroed pages
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
` (13 preceding siblings ...)
2015-07-27 12:29 ` [PATCH 14/18] iommu: tegra-smmu: remove PageReserved manipulation Russell King
@ 2015-07-27 12:30 ` Russell King
2015-07-27 12:30 ` [PATCH 16/18] iommu: tegra-smmu: get_use Russell King
` (4 subsequent siblings)
19 siblings, 0 replies; 30+ messages in thread
From: Russell King @ 2015-07-27 12:30 UTC (permalink / raw)
To: linux-arm-kernel
Rather than explicitly zeroing pages allocated via alloc_page(), add
__GFP_ZERO to the gfp mask to ask the allocator for zeroed pages.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/iommu/tegra-smmu.c | 18 ++----------------
1 file changed, 2 insertions(+), 16 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index b826362ce96b..bc179c759805 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -260,8 +260,6 @@ static bool tegra_smmu_capable(enum iommu_cap cap)
static struct iommu_domain *tegra_smmu_domain_alloc(unsigned type)
{
struct tegra_smmu_as *as;
- unsigned int i;
- uint32_t *pd;
if (type != IOMMU_DOMAIN_UNMANAGED)
return NULL;
@@ -272,7 +270,7 @@ static struct iommu_domain *tegra_smmu_domain_alloc(unsigned type)
as->attr = SMMU_PD_READABLE | SMMU_PD_WRITABLE | SMMU_PD_NONSECURE;
- as->pd = alloc_page(GFP_KERNEL | __GFP_DMA);
+ as->pd = alloc_page(GFP_KERNEL | __GFP_DMA | __GFP_ZERO);
if (!as->pd) {
kfree(as);
return NULL;
@@ -293,12 +291,6 @@ static struct iommu_domain *tegra_smmu_domain_alloc(unsigned type)
return NULL;
}
- /* clear PDEs */
- pd = page_address(as->pd);
-
- for (i = 0; i < SMMU_NUM_PDE; i++)
- pd[i] = 0;
-
/* setup aperture */
as->domain.geometry.aperture_start = 0;
as->domain.geometry.aperture_end = 0xffffffff;
@@ -535,21 +527,15 @@ static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
u32 *pd = page_address(as->pd), *pt;
unsigned int pde = iova_pd_index(iova);
struct tegra_smmu *smmu = as->smmu;
- unsigned int i;
if (!as->pts[pde]) {
struct page *page;
dma_addr_t dma;
- page = alloc_page(GFP_KERNEL | __GFP_DMA);
+ page = alloc_page(GFP_KERNEL | __GFP_DMA | __GFP_ZERO);
if (!page)
return NULL;
- pt = page_address(page);
-
- for (i = 0; i < SMMU_NUM_PTE; i++)
- pt[i] = 0;
-
dma = dma_map_page(smmu->dev, page, 0, SMMU_SIZE_PT,
DMA_TO_DEVICE);
if (dma_mapping_error(smmu->dev, dma)) {
--
2.1.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 16/18] iommu: tegra-smmu: get_use
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
` (14 preceding siblings ...)
2015-07-27 12:30 ` [PATCH 15/18] iommu: tegra-smmu: use __GFP_ZERO to allocate zeroed pages Russell King
@ 2015-07-27 12:30 ` Russell King
2015-07-27 14:11 ` Thierry Reding
2015-07-27 12:30 ` [PATCH 17/18] iommu: tegra-smmu: more cleanups Russell King
` (3 subsequent siblings)
19 siblings, 1 reply; 30+ messages in thread
From: Russell King @ 2015-07-27 12:30 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/iommu/tegra-smmu.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index bc179c759805..8bf38b95cdd5 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -524,7 +524,7 @@ static u32 *tegra_smmu_pte_lookup(struct tegra_smmu_as *as, unsigned long iova,
static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
dma_addr_t *dmap)
{
- u32 *pd = page_address(as->pd), *pt;
+ u32 *pd = page_address(as->pd);
unsigned int pde = iova_pd_index(iova);
struct tegra_smmu *smmu = as->smmu;
@@ -565,13 +565,14 @@ static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
*dmap = smmu_pde_to_dma(pd[pde]);
}
- pt = page_address(as->pts[pde]);
+ return tegra_smmu_pte_offset(as->pts[pde], iova);
+}
- /* Keep track of entries in this page table. */
- if (pt[iova_pt_index(iova)] == 0)
- as->count[pde]++;
+static void tegra_smmu_pte_get_use(struct tegra_smmu_as *as, unsigned long iova)
+{
+ unsigned int pd_index = iova_pd_index(iova);
- return tegra_smmu_pte_offset(as->pts[pde], iova);
+ as->count[pd_index]++;
}
static void tegra_smmu_pte_put_use(struct tegra_smmu_as *as, unsigned long iova)
@@ -632,6 +633,10 @@ static int tegra_smmu_map(struct iommu_domain *domain, unsigned long iova,
if (!pte)
return -ENOMEM;
+ /* If we aren't overwriting a pre-existing entry, increment use */
+ if (!*pte)
+ tegra_smmu_pte_get_use(as, iova);
+
tegra_smmu_set_pte(as, iova, pte, pte_dma,
__phys_to_pfn(paddr) | SMMU_PTE_ATTR);
--
2.1.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 17/18] iommu: tegra-smmu: more cleanups
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
` (15 preceding siblings ...)
2015-07-27 12:30 ` [PATCH 16/18] iommu: tegra-smmu: get_use Russell King
@ 2015-07-27 12:30 ` Russell King
2015-07-27 14:12 ` Thierry Reding
2015-07-27 12:30 ` [PATCH 18/18] iommu: tegra-smmu: remove cacheflush.h Russell King
` (2 subsequent siblings)
19 siblings, 1 reply; 30+ messages in thread
From: Russell King @ 2015-07-27 12:30 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/iommu/tegra-smmu.c | 49 ++++++++++++++++++++++++++--------------------
1 file changed, 28 insertions(+), 21 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 8bf38b95cdd5..e5d6bc45c58f 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -497,6 +497,27 @@ static void tegra_smmu_detach_dev(struct iommu_domain *domain, struct device *de
}
}
+static void tegra_smmu_set_pge(struct tegra_smmu_as *as, unsigned long iova,
+ u32 val)
+{
+ struct tegra_smmu *smmu = as->smmu;
+ unsigned int pd_index = iova_pd_index(iova);
+ u32 *pd = page_address(as->pd);
+ unsigned long offset = pd_index * sizeof(*pd);
+
+ /* Set the page directory entry first */
+ pd[pd_index] = val;
+
+ /* The flush the page directory entry from caches */
+ dma_sync_single_range_for_device(smmu->dev, as->pd_dma, offset,
+ sizeof(*pd), DMA_TO_DEVICE);
+
+ /* And flush the iommu */
+ smmu_flush_ptc(smmu, as->pd_dma, offset);
+ smmu_flush_tlb_section(smmu, as->id, iova);
+ smmu_flush(smmu);
+}
+
static u32 *tegra_smmu_pte_offset(struct page *pt_page, unsigned long iova)
{
u32 *pt = page_address(pt_page);
@@ -524,7 +545,6 @@ static u32 *tegra_smmu_pte_lookup(struct tegra_smmu_as *as, unsigned long iova,
static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
dma_addr_t *dmap)
{
- u32 *pd = page_address(as->pd);
unsigned int pde = iova_pd_index(iova);
struct tegra_smmu *smmu = as->smmu;
@@ -552,16 +572,13 @@ static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
as->pts[pde] = page;
- pd[pde] = SMMU_MK_PDE(dma, SMMU_PDE_ATTR | SMMU_PDE_NEXT);
-
- dma_sync_single_range_for_device(smmu->dev, as->pd_dma,
- pde << 2, 4, DMA_TO_DEVICE);
- smmu_flush_ptc(smmu, as->pd_dma, pde << 2);
- smmu_flush_tlb_section(smmu, as->id, iova);
- smmu_flush(smmu);
+ tegra_smmu_set_pge(as, iova, SMMU_MK_PDE(dma, SMMU_PDE_ATTR |
+ SMMU_PDE_NEXT));
*dmap = dma;
} else {
+ u32 *pd = page_address(as->pd);
+
*dmap = smmu_pde_to_dma(pd[pde]);
}
@@ -577,9 +594,7 @@ static void tegra_smmu_pte_get_use(struct tegra_smmu_as *as, unsigned long iova)
static void tegra_smmu_pte_put_use(struct tegra_smmu_as *as, unsigned long iova)
{
- struct tegra_smmu *smmu = as->smmu;
unsigned int pde = iova_pd_index(iova);
- u32 *pd = page_address(as->pd);
struct page *page = as->pts[pde];
/*
@@ -587,20 +602,12 @@ static void tegra_smmu_pte_put_use(struct tegra_smmu_as *as, unsigned long iova)
* memory page to the system.
*/
if (--as->count[pde] == 0) {
- unsigned int offset = pde * sizeof(*pd);
+ struct tegra_smmu *smmu = as->smmu;
+ u32 *pd = page_address(as->pd);
dma_addr_t pte_dma = smmu_pde_to_dma(pd[pde]);
- /* Clear the page directory entry first */
- pd[pde] = 0;
-
- /* Flush the page directory entry */
- dma_sync_single_range_for_device(smmu->dev, as->pd_dma, offset,
- sizeof(*pd), DMA_TO_DEVICE);
- smmu_flush_ptc(smmu, as->pd_dma, offset);
- smmu_flush_tlb_section(smmu, as->id, iova);
- smmu_flush(smmu);
+ tegra_smmu_set_pge(as, iova, 0);
- /* Finally, free the page */
dma_unmap_page(smmu->dev, pte_dma, SMMU_SIZE_PT, DMA_TO_DEVICE);
__free_page(page);
as->pts[pde] = NULL;
--
2.1.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 18/18] iommu: tegra-smmu: remove cacheflush.h
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
` (16 preceding siblings ...)
2015-07-27 12:30 ` [PATCH 17/18] iommu: tegra-smmu: more cleanups Russell King
@ 2015-07-27 12:30 ` Russell King
2015-07-27 14:13 ` Thierry Reding
2015-07-27 13:13 ` [PATCH 00/18] Clean up exposure of arch-internal code Joerg Roedel
2015-07-27 14:09 ` Thierry Reding
19 siblings, 1 reply; 30+ messages in thread
From: Russell King @ 2015-07-27 12:30 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/iommu/tegra-smmu.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index e5d6bc45c58f..4a8b66f05d8f 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -16,8 +16,6 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <asm/cacheflush.h>
-
#include <soc/tegra/ahb.h>
#include <soc/tegra/mc.h>
--
2.1.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 00/18] Clean up exposure of arch-internal code
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
` (17 preceding siblings ...)
2015-07-27 12:30 ` [PATCH 18/18] iommu: tegra-smmu: remove cacheflush.h Russell King
@ 2015-07-27 13:13 ` Joerg Roedel
2015-07-27 14:45 ` Heiko Stübner
2015-07-27 14:09 ` Thierry Reding
19 siblings, 1 reply; 30+ messages in thread
From: Joerg Roedel @ 2015-07-27 13:13 UTC (permalink / raw)
To: linux-arm-kernel
[+ Heiko for comment on Rockchip IOMMU]
On Mon, Jul 27, 2015 at 01:28:24PM +0100, Russell King - ARM Linux wrote:
> This series of patches attempts to clean up the use of architecture
> internal functions in drivers, and removes some functions from view
> in the asm/ headers. I'm also considering whether we need to add
> some linker magic to hide symbols when building the built-in.o files.
>
> This was triggered by 3rd party drivers "going under the covers" of
> the DMA API and calling the dmac_*() functions directly, a practice
> which I have always refused to allow. This also breaks module
> building (which is the big hint that they're doing something wrong.)
>
> However, it also came to light that various drivers are using
> __cpuc_* functions directly, which are non-portable, and is another
> instance of "going under the covers" and tinkering with what should
> be kept as architecture implementation details.
>
> This series addresses some of these points. It:
>
> (a) moves dmac_map_area() and dmac_unmap_area() prototypes out of
> asm/cacheflush.h and into arch/arm/mm.
> (b) provide a secure_flush() call for the Qualcomm secure monitor
> code.
> (c) stop tegra smmu driver(s) from using __cpuc_flush_dcache_area,
> something which necessitates additional complexity to deal with
> the ARM vs ARM64 differences. It should be using the DMA API.
> However, the Tegra SMMU driver is in really bad shape, and this
> isn't a simple conversion - it requires a lot of additional
> fixes to bring the code up to scratch.
>
> It leaves the Rockchip IOMMU driver for the time being, but that is also
> something which needs cleaning up in the same way as the Tegra SMMU
> driver.
>
> arch/arm/include/asm/cacheflush.h | 21 ++-
> arch/arm/include/asm/glue-cache.h | 2 -
> arch/arm/mm/dma-mapping.c | 1 +
> arch/arm/mm/dma.h | 32 ++++
> drivers/firmware/qcom_scm-32.c | 4 +-
> drivers/iommu/tegra-smmu.c | 297 ++++++++++++++++++++++++--------------
> drivers/memory/tegra/tegra114.c | 17 ---
> drivers/memory/tegra/tegra124.c | 30 ----
> drivers/memory/tegra/tegra30.c | 17 ---
> include/soc/tegra/mc.h | 7 -
> 10 files changed, 242 insertions(+), 186 deletions(-)
>
> --
> FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
> according to speedtest.net.
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 00/18] Clean up exposure of arch-internal code
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
` (18 preceding siblings ...)
2015-07-27 13:13 ` [PATCH 00/18] Clean up exposure of arch-internal code Joerg Roedel
@ 2015-07-27 14:09 ` Thierry Reding
2015-07-27 14:16 ` Russell King - ARM Linux
2015-08-03 11:33 ` Joerg Roedel
19 siblings, 2 replies; 30+ messages in thread
From: Thierry Reding @ 2015-07-27 14:09 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Jul 27, 2015 at 01:28:24PM +0100, Russell King - ARM Linux wrote:
> This series of patches attempts to clean up the use of architecture
> internal functions in drivers, and removes some functions from view
> in the asm/ headers. I'm also considering whether we need to add
> some linker magic to hide symbols when building the built-in.o files.
>
> This was triggered by 3rd party drivers "going under the covers" of
> the DMA API and calling the dmac_*() functions directly, a practice
> which I have always refused to allow. This also breaks module
> building (which is the big hint that they're doing something wrong.)
>
> However, it also came to light that various drivers are using
> __cpuc_* functions directly, which are non-portable, and is another
> instance of "going under the covers" and tinkering with what should
> be kept as architecture implementation details.
>
> This series addresses some of these points. It:
>
> (a) moves dmac_map_area() and dmac_unmap_area() prototypes out of
> asm/cacheflush.h and into arch/arm/mm.
> (b) provide a secure_flush() call for the Qualcomm secure monitor
> code.
> (c) stop tegra smmu driver(s) from using __cpuc_flush_dcache_area,
> something which necessitates additional complexity to deal with
> the ARM vs ARM64 differences. It should be using the DMA API.
> However, the Tegra SMMU driver is in really bad shape, and this
> isn't a simple conversion - it requires a lot of additional
> fixes to bring the code up to scratch.
Out of curiosity, did you have any hardware to test this on? I've given
it a quick spin and haven't seen anything out of the ordinary. I have a
couple of nitpicks towards the end of the series, but other than that,
very nice work.
What's the plan for merging this? Should it all go in through Joerg's
tree so that potentially other driver conversions can go in on top of
this, or would you prefer to take it through the ARM tree?
> It leaves the Rockchip IOMMU driver for the time being, but that is also
> something which needs cleaning up in the same way as the Tegra SMMU
> driver.
>From a cursory look, MSM, OMAP and Exynos are in the same boat as well.
Thanks,
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150727/e1d4912f/attachment-0001.sig>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 16/18] iommu: tegra-smmu: get_use
2015-07-27 12:30 ` [PATCH 16/18] iommu: tegra-smmu: get_use Russell King
@ 2015-07-27 14:11 ` Thierry Reding
0 siblings, 0 replies; 30+ messages in thread
From: Thierry Reding @ 2015-07-27 14:11 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Jul 27, 2015 at 01:30:07PM +0100, Russell King wrote:
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> ---
> drivers/iommu/tegra-smmu.c | 17 +++++++++++------
> 1 file changed, 11 insertions(+), 6 deletions(-)
Joerg may want to have a proper commit message here. If you're too busy
I can probably come up with something.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150727/de180f7a/attachment.sig>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 17/18] iommu: tegra-smmu: more cleanups
2015-07-27 12:30 ` [PATCH 17/18] iommu: tegra-smmu: more cleanups Russell King
@ 2015-07-27 14:12 ` Thierry Reding
0 siblings, 0 replies; 30+ messages in thread
From: Thierry Reding @ 2015-07-27 14:12 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Jul 27, 2015 at 01:30:12PM +0100, Russell King wrote:
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> ---
> drivers/iommu/tegra-smmu.c | 49 ++++++++++++++++++++++++++--------------------
> 1 file changed, 28 insertions(+), 21 deletions(-)
Same here.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150727/09eb379e/attachment-0001.sig>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 18/18] iommu: tegra-smmu: remove cacheflush.h
2015-07-27 12:30 ` [PATCH 18/18] iommu: tegra-smmu: remove cacheflush.h Russell King
@ 2015-07-27 14:13 ` Thierry Reding
0 siblings, 0 replies; 30+ messages in thread
From: Thierry Reding @ 2015-07-27 14:13 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Jul 27, 2015 at 01:30:17PM +0100, Russell King wrote:
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> ---
> drivers/iommu/tegra-smmu.c | 2 --
> 1 file changed, 2 deletions(-)
>
> diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
> index e5d6bc45c58f..4a8b66f05d8f 100644
> --- a/drivers/iommu/tegra-smmu.c
> +++ b/drivers/iommu/tegra-smmu.c
> @@ -16,8 +16,6 @@
> #include <linux/platform_device.h>
> #include <linux/slab.h>
>
> -#include <asm/cacheflush.h>
> -
Doesn't this logically belong in patch 13/18, along with the DMA API
conversion that drops the last reference to these functions?
Again, I can take care of squashing this into 13/18 if you don't have
any objections and send a pull request to Joerg.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150727/17e208af/attachment.sig>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 00/18] Clean up exposure of arch-internal code
2015-07-27 14:09 ` Thierry Reding
@ 2015-07-27 14:16 ` Russell King - ARM Linux
2015-07-27 14:31 ` Thierry Reding
2015-08-03 11:33 ` Joerg Roedel
1 sibling, 1 reply; 30+ messages in thread
From: Russell King - ARM Linux @ 2015-07-27 14:16 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Jul 27, 2015 at 04:09:06PM +0200, Thierry Reding wrote:
> On Mon, Jul 27, 2015 at 01:28:24PM +0100, Russell King - ARM Linux wrote:
> > This series of patches attempts to clean up the use of architecture
> > internal functions in drivers, and removes some functions from view
> > in the asm/ headers. I'm also considering whether we need to add
> > some linker magic to hide symbols when building the built-in.o files.
> >
> > This was triggered by 3rd party drivers "going under the covers" of
> > the DMA API and calling the dmac_*() functions directly, a practice
> > which I have always refused to allow. This also breaks module
> > building (which is the big hint that they're doing something wrong.)
> >
> > However, it also came to light that various drivers are using
> > __cpuc_* functions directly, which are non-portable, and is another
> > instance of "going under the covers" and tinkering with what should
> > be kept as architecture implementation details.
> >
> > This series addresses some of these points. It:
> >
> > (a) moves dmac_map_area() and dmac_unmap_area() prototypes out of
> > asm/cacheflush.h and into arch/arm/mm.
> > (b) provide a secure_flush() call for the Qualcomm secure monitor
> > code.
> > (c) stop tegra smmu driver(s) from using __cpuc_flush_dcache_area,
> > something which necessitates additional complexity to deal with
> > the ARM vs ARM64 differences. It should be using the DMA API.
> > However, the Tegra SMMU driver is in really bad shape, and this
> > isn't a simple conversion - it requires a lot of additional
> > fixes to bring the code up to scratch.
>
> Out of curiosity, did you have any hardware to test this on?
Nope - it only got build-tested, and it's partly why there's soo many
incremental small patches.
> I've given
> it a quick spin and haven't seen anything out of the ordinary. I have a
> couple of nitpicks towards the end of the series, but other than that,
> very nice work.
Good news.
> What's the plan for merging this? Should it all go in through Joerg's
> tree so that potentially other driver conversions can go in on top of
> this, or would you prefer to take it through the ARM tree?
I don't mind the series being split - there's nothing dependent between
the individual drivers, so all the Tegra SMMU stuff can go through
Joerg's tree if that'll be easiest.
> > It leaves the Rockchip IOMMU driver for the time being, but that is also
> > something which needs cleaning up in the same way as the Tegra SMMU
> > driver.
>
> From a cursory look, MSM, OMAP and Exynos are in the same boat as well.
Yes. There is a question here though:
Is it a good idea to use normal cacheable memory for the IOMMU page table
entries, or would DMA coherent memory be better?
If the latter, then we don't need to do any cache maintanence of the
tables, and all the hacks can go. If the former, using the streaming
DMA API in all IOMMU drivers would be a good idea, like Tegra SMMU now
does as a result of these patches.
--
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 00/18] Clean up exposure of arch-internal code
2015-07-27 14:16 ` Russell King - ARM Linux
@ 2015-07-27 14:31 ` Thierry Reding
0 siblings, 0 replies; 30+ messages in thread
From: Thierry Reding @ 2015-07-27 14:31 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Jul 27, 2015 at 03:16:54PM +0100, Russell King - ARM Linux wrote:
> On Mon, Jul 27, 2015 at 04:09:06PM +0200, Thierry Reding wrote:
> > On Mon, Jul 27, 2015 at 01:28:24PM +0100, Russell King - ARM Linux wrote:
> > > This series of patches attempts to clean up the use of architecture
> > > internal functions in drivers, and removes some functions from view
> > > in the asm/ headers. I'm also considering whether we need to add
> > > some linker magic to hide symbols when building the built-in.o files.
> > >
> > > This was triggered by 3rd party drivers "going under the covers" of
> > > the DMA API and calling the dmac_*() functions directly, a practice
> > > which I have always refused to allow. This also breaks module
> > > building (which is the big hint that they're doing something wrong.)
> > >
> > > However, it also came to light that various drivers are using
> > > __cpuc_* functions directly, which are non-portable, and is another
> > > instance of "going under the covers" and tinkering with what should
> > > be kept as architecture implementation details.
> > >
> > > This series addresses some of these points. It:
> > >
> > > (a) moves dmac_map_area() and dmac_unmap_area() prototypes out of
> > > asm/cacheflush.h and into arch/arm/mm.
> > > (b) provide a secure_flush() call for the Qualcomm secure monitor
> > > code.
> > > (c) stop tegra smmu driver(s) from using __cpuc_flush_dcache_area,
> > > something which necessitates additional complexity to deal with
> > > the ARM vs ARM64 differences. It should be using the DMA API.
> > > However, the Tegra SMMU driver is in really bad shape, and this
> > > isn't a simple conversion - it requires a lot of additional
> > > fixes to bring the code up to scratch.
> >
> > Out of curiosity, did you have any hardware to test this on?
>
> Nope - it only got build-tested, and it's partly why there's soo many
> incremental small patches.
All the more impressive. =)
> > > It leaves the Rockchip IOMMU driver for the time being, but that is also
> > > something which needs cleaning up in the same way as the Tegra SMMU
> > > driver.
> >
> > From a cursory look, MSM, OMAP and Exynos are in the same boat as well.
>
> Yes. There is a question here though:
>
> Is it a good idea to use normal cacheable memory for the IOMMU page table
> entries, or would DMA coherent memory be better?
Currently I think coherent memory would do just as well as cacheable
memory, maybe even better given that we wouldn't need the cache
maintenance. However, I think cacheable memory might come in handy if
ever the ->map_sg() callback gets implemented, because it would allow us
to batch up a bunch of PTE writes and flush whole pages in one go.
Unfortunately I don't have the tools handy to provide any numbers, so
the above is really just guesswork. Cc'ing Rob Clark who, I think, did
performance measurements a while ago. Not sure if those included
coherent vs. cacheable memory, though.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150727/3cbb9673/attachment.sig>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 00/18] Clean up exposure of arch-internal code
2015-07-27 13:13 ` [PATCH 00/18] Clean up exposure of arch-internal code Joerg Roedel
@ 2015-07-27 14:45 ` Heiko Stübner
0 siblings, 0 replies; 30+ messages in thread
From: Heiko Stübner @ 2015-07-27 14:45 UTC (permalink / raw)
To: linux-arm-kernel
Am Montag, 27. Juli 2015, 15:13:13 schrieb Joerg Roedel:
> [+ Heiko for comment on Rockchip IOMMU]
adding also Daniel Kurtz and Tomasz Figa who did most of the iommu stuff if I
remember correctly.
While I'm not this versed in the iommu world I see the issue Russell pointed
out, as especially the cache flushes won't work like this on arm64, which uses
the same iommu on the rk3368.
I'll also try to understand what this does and what needs to be done to the
Rockchip iommu, but I guess that'll still take a bit.
> On Mon, Jul 27, 2015 at 01:28:24PM +0100, Russell King - ARM Linux wrote:
> > This series of patches attempts to clean up the use of architecture
> > internal functions in drivers, and removes some functions from view
> > in the asm/ headers. I'm also considering whether we need to add
> > some linker magic to hide symbols when building the built-in.o files.
> >
> > This was triggered by 3rd party drivers "going under the covers" of
> > the DMA API and calling the dmac_*() functions directly, a practice
> > which I have always refused to allow. This also breaks module
> > building (which is the big hint that they're doing something wrong.)
> >
> > However, it also came to light that various drivers are using
> > __cpuc_* functions directly, which are non-portable, and is another
> > instance of "going under the covers" and tinkering with what should
> > be kept as architecture implementation details.
> >
> > This series addresses some of these points. It:
> >
> > (a) moves dmac_map_area() and dmac_unmap_area() prototypes out of
> >
> > asm/cacheflush.h and into arch/arm/mm.
> >
> > (b) provide a secure_flush() call for the Qualcomm secure monitor
> >
> > code.
> >
> > (c) stop tegra smmu driver(s) from using __cpuc_flush_dcache_area,
> >
> > something which necessitates additional complexity to deal with
> > the ARM vs ARM64 differences. It should be using the DMA API.
> > However, the Tegra SMMU driver is in really bad shape, and this
> > isn't a simple conversion - it requires a lot of additional
> > fixes to bring the code up to scratch.
> >
> > It leaves the Rockchip IOMMU driver for the time being, but that is also
> > something which needs cleaning up in the same way as the Tegra SMMU
> > driver.
> >
> > arch/arm/include/asm/cacheflush.h | 21 ++-
> > arch/arm/include/asm/glue-cache.h | 2 -
> > arch/arm/mm/dma-mapping.c | 1 +
> > arch/arm/mm/dma.h | 32 ++++
> > drivers/firmware/qcom_scm-32.c | 4 +-
> > drivers/iommu/tegra-smmu.c | 297
> > ++++++++++++++++++++++++-------------- drivers/memory/tegra/tegra114.c
> > | 17 ---
> > drivers/memory/tegra/tegra124.c | 30 ----
> > drivers/memory/tegra/tegra30.c | 17 ---
> > include/soc/tegra/mc.h | 7 -
> > 10 files changed, 242 insertions(+), 186 deletions(-)
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 00/18] Clean up exposure of arch-internal code
2015-07-27 14:09 ` Thierry Reding
2015-07-27 14:16 ` Russell King - ARM Linux
@ 2015-08-03 11:33 ` Joerg Roedel
1 sibling, 0 replies; 30+ messages in thread
From: Joerg Roedel @ 2015-08-03 11:33 UTC (permalink / raw)
To: linux-arm-kernel
Hey Thierry,
On Mon, Jul 27, 2015 at 04:09:06PM +0200, Thierry Reding wrote:
> What's the plan for merging this? Should it all go in through Joerg's
> tree so that potentially other driver conversions can go in on top of
> this, or would you prefer to take it through the ARM tree?
So it would be great if you can work in your review comments and send me
a pull request with the result. I'll put it into the iommu-tree for v4.3
then.
Joerg
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 02/18] firmware: qcom_scm-32: replace open-coded call to __cpuc_flush_dcache_area()
2015-07-27 12:28 ` [PATCH 02/18] firmware: qcom_scm-32: replace open-coded call to __cpuc_flush_dcache_area() Russell King
@ 2015-08-04 18:48 ` Andy Gross
2015-08-04 18:50 ` Stephen Boyd
1 sibling, 0 replies; 30+ messages in thread
From: Andy Gross @ 2015-08-04 18:48 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Jul 27, 2015 at 01:28:55PM +0100, Russell King wrote:
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> ---
Acked-by: Andy Gross <agross@codeaurora.org>
--
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 02/18] firmware: qcom_scm-32: replace open-coded call to __cpuc_flush_dcache_area()
2015-07-27 12:28 ` [PATCH 02/18] firmware: qcom_scm-32: replace open-coded call to __cpuc_flush_dcache_area() Russell King
2015-08-04 18:48 ` Andy Gross
@ 2015-08-04 18:50 ` Stephen Boyd
1 sibling, 0 replies; 30+ messages in thread
From: Stephen Boyd @ 2015-08-04 18:50 UTC (permalink / raw)
To: linux-arm-kernel
On 07/27/2015 05:28 AM, Russell King wrote:
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> ---
Thanks!
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
> arch/arm/include/asm/cacheflush.h | 17 +++++++++++++++++
> drivers/firmware/qcom_scm-32.c | 4 +---
> 2 files changed, 18 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
> index c5230a44eeca..d5525bfc7e3e 100644
> --- a/arch/arm/include/asm/cacheflush.h
> +++ b/arch/arm/include/asm/cacheflush.h
> @@ -502,4 +502,21 @@ static inline void set_kernel_text_ro(void) { }
> void flush_uprobe_xol_access(struct page *page, unsigned long uaddr,
> void *kaddr, unsigned long len);
>
> +/**
> + * secure_flush_area - ensure coherency across the secure boundary
> + * @addr: virtual address
> + * @size: size of region
> + *
> + * Ensure that the specified area of memory is coherent across the secure
> + * boundary from the non-secure side. This is used when calling secure
> + * firmware where the secure firmware does not ensure coherency.
> + */
> +static inline void secure_flush_area(const void *addr, size_t size)
> +{
> + phys_addr_t phys = __pa(addr);
> +
> + __cpuc_flush_dcache_area((void *)addr, size);
> + outer_flush_range(phys, phys + size);
> +}
> +
> #endif
> diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
> index 1bd6f9c34331..29e6850665eb 100644
> --- a/drivers/firmware/qcom_scm-32.c
> +++ b/drivers/firmware/qcom_scm-32.c
> @@ -24,7 +24,6 @@
> #include <linux/err.h>
> #include <linux/qcom_scm.h>
>
> -#include <asm/outercache.h>
> #include <asm/cacheflush.h>
>
> #include "qcom_scm.h"
> @@ -219,8 +218,7 @@ static int __qcom_scm_call(const struct qcom_scm_command *cmd)
> * Flush the command buffer so that the secure world sees
> * the correct data.
> */
> - __cpuc_flush_dcache_area((void *)cmd, cmd->len);
> - outer_flush_range(cmd_addr, cmd_addr + cmd->len);
> + secure_flush_area(cmd, cmd->len);
>
> ret = smc(cmd_addr);
> if (ret < 0)
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2015-08-04 18:50 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-07-27 12:28 [PATCH 00/18] Clean up exposure of arch-internal code Russell King - ARM Linux
2015-07-27 12:28 ` [PATCH 01/18] ARM: reduce visibility of dmac_* functions Russell King
2015-07-27 12:28 ` [PATCH 02/18] firmware: qcom_scm-32: replace open-coded call to __cpuc_flush_dcache_area() Russell King
2015-08-04 18:48 ` Andy Gross
2015-08-04 18:50 ` Stephen Boyd
2015-07-27 12:29 ` [PATCH 03/18] iommu: tegra-smmu: fix iova_to_phys() method Russell King
2015-07-27 12:29 ` [PATCH 04/18] iommu: tegra-smmu: fix unmap() method Russell King
2015-07-27 12:29 ` [PATCH 05/18] iommu: tegra-smmu: factor out common pte setting Russell King
2015-07-27 12:29 ` [PATCH 06/18] iommu: tegra-smmu: add iova_pd_index() and iova_pt_index() helpers Russell King
2015-07-27 12:29 ` [PATCH 07/18] iommu: tegra-smmu: fix page table lookup in unmap/iova_to_phys methods Russell King
2015-07-27 12:29 ` [PATCH 08/18] iommu: tegra-smmu: store struct page pointer for page tables Russell King
2015-07-27 12:29 ` [PATCH 09/18] iommu: tegra-smmu: use kcalloc() to allocate counter array Russell King
2015-07-27 12:29 ` [PATCH 10/18] iommu: tegra-smmu: move flush_dcache to tegra-smmu.c Russell King
2015-07-27 12:29 ` [PATCH 11/18] iommu: tegra-smmu: split smmu_flush_ptc() Russell King
2015-07-27 12:29 ` [PATCH 12/18] iommu: tegra-smmu: smmu_flush_ptc() wants device address Russell King
2015-07-27 12:29 ` [PATCH 13/18] iommu: tegra-smmu: convert to use DMA API Russell King
2015-07-27 12:29 ` [PATCH 14/18] iommu: tegra-smmu: remove PageReserved manipulation Russell King
2015-07-27 12:30 ` [PATCH 15/18] iommu: tegra-smmu: use __GFP_ZERO to allocate zeroed pages Russell King
2015-07-27 12:30 ` [PATCH 16/18] iommu: tegra-smmu: get_use Russell King
2015-07-27 14:11 ` Thierry Reding
2015-07-27 12:30 ` [PATCH 17/18] iommu: tegra-smmu: more cleanups Russell King
2015-07-27 14:12 ` Thierry Reding
2015-07-27 12:30 ` [PATCH 18/18] iommu: tegra-smmu: remove cacheflush.h Russell King
2015-07-27 14:13 ` Thierry Reding
2015-07-27 13:13 ` [PATCH 00/18] Clean up exposure of arch-internal code Joerg Roedel
2015-07-27 14:45 ` Heiko Stübner
2015-07-27 14:09 ` Thierry Reding
2015-07-27 14:16 ` Russell King - ARM Linux
2015-07-27 14:31 ` Thierry Reding
2015-08-03 11:33 ` Joerg Roedel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).