* [PATCH 1/6] iommu/tegra: Rename -i hw{grp,group} to sw{grp,group}
@ 2013-01-15 8:17 Hiroshi Doyu
[not found] ` <1358237848-968-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
0 siblings, 1 reply; 22+ messages in thread
From: Hiroshi Doyu @ 2013-01-15 8:17 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
joro-zLv9SwRftAIdnm+yROfE0A
Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA
Use correct name/prefix from TRM to avoid confusion.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/iommu/tegra-smmu.c | 160 ++++++++++++++++++++++----------------------
1 file changed, 80 insertions(+), 80 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index fc17889..224c0a0 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -39,45 +39,45 @@
#include <asm/page.h>
#include <asm/cacheflush.h>
-enum smmu_hwgrp {
- HWGRP_AFI,
- HWGRP_AVPC,
- HWGRP_DC,
- HWGRP_DCB,
- HWGRP_EPP,
- HWGRP_G2,
- HWGRP_HC,
- HWGRP_HDA,
- HWGRP_ISP,
- HWGRP_MPE,
- HWGRP_NV,
- HWGRP_NV2,
- HWGRP_PPCS,
- HWGRP_SATA,
- HWGRP_VDE,
- HWGRP_VI,
-
- HWGRP_COUNT,
-
- HWGRP_END = ~0,
+enum smmu_swgrp {
+ SWGRP_AFI,
+ SWGRP_AVPC,
+ SWGRP_DC,
+ SWGRP_DCB,
+ SWGRP_EPP,
+ SWGRP_G2,
+ SWGRP_HC,
+ SWGRP_HDA,
+ SWGRP_ISP,
+ SWGRP_MPE,
+ SWGRP_NV,
+ SWGRP_NV2,
+ SWGRP_PPCS,
+ SWGRP_SATA,
+ SWGRP_VDE,
+ SWGRP_VI,
+
+ SWGRP_COUNT,
+
+ SWGRP_END = ~0,
};
-#define HWG_AFI (1 << HWGRP_AFI)
-#define HWG_AVPC (1 << HWGRP_AVPC)
-#define HWG_DC (1 << HWGRP_DC)
-#define HWG_DCB (1 << HWGRP_DCB)
-#define HWG_EPP (1 << HWGRP_EPP)
-#define HWG_G2 (1 << HWGRP_G2)
-#define HWG_HC (1 << HWGRP_HC)
-#define HWG_HDA (1 << HWGRP_HDA)
-#define HWG_ISP (1 << HWGRP_ISP)
-#define HWG_MPE (1 << HWGRP_MPE)
-#define HWG_NV (1 << HWGRP_NV)
-#define HWG_NV2 (1 << HWGRP_NV2)
-#define HWG_PPCS (1 << HWGRP_PPCS)
-#define HWG_SATA (1 << HWGRP_SATA)
-#define HWG_VDE (1 << HWGRP_VDE)
-#define HWG_VI (1 << HWGRP_VI)
+#define SWG_AFI (1 << SWGRP_AFI)
+#define SWG_AVPC (1 << SWGRP_AVPC)
+#define SWG_DC (1 << SWGRP_DC)
+#define SWG_DCB (1 << SWGRP_DCB)
+#define SWG_EPP (1 << SWGRP_EPP)
+#define SWG_G2 (1 << SWGRP_G2)
+#define SWG_HC (1 << SWGRP_HC)
+#define SWG_HDA (1 << SWGRP_HDA)
+#define SWG_ISP (1 << SWGRP_ISP)
+#define SWG_MPE (1 << SWGRP_MPE)
+#define SWG_NV (1 << SWGRP_NV)
+#define SWG_NV2 (1 << SWGRP_NV2)
+#define SWG_PPCS (1 << SWGRP_PPCS)
+#define SWG_SATA (1 << SWGRP_SATA)
+#define SWG_VDE (1 << SWGRP_VDE)
+#define SWG_VI (1 << SWGRP_VI)
/* bitmap of the page sizes currently supported */
#define SMMU_IOMMU_PGSIZES (SZ_4K)
@@ -229,32 +229,32 @@ enum {
#define NUM_SMMU_REG_BANKS 3
-#define smmu_client_enable_hwgrp(c, m) smmu_client_set_hwgrp(c, m, 1)
-#define smmu_client_disable_hwgrp(c) smmu_client_set_hwgrp(c, 0, 0)
-#define __smmu_client_enable_hwgrp(c, m) __smmu_client_set_hwgrp(c, m, 1)
-#define __smmu_client_disable_hwgrp(c) __smmu_client_set_hwgrp(c, 0, 0)
-
-#define HWGRP_INIT(client) [HWGRP_##client] = SMMU_##client##_ASID
-
-static const u32 smmu_hwgrp_asid_reg[] = {
- HWGRP_INIT(AFI),
- HWGRP_INIT(AVPC),
- HWGRP_INIT(DC),
- HWGRP_INIT(DCB),
- HWGRP_INIT(EPP),
- HWGRP_INIT(G2),
- HWGRP_INIT(HC),
- HWGRP_INIT(HDA),
- HWGRP_INIT(ISP),
- HWGRP_INIT(MPE),
- HWGRP_INIT(NV),
- HWGRP_INIT(NV2),
- HWGRP_INIT(PPCS),
- HWGRP_INIT(SATA),
- HWGRP_INIT(VDE),
- HWGRP_INIT(VI),
+#define smmu_client_enable_swgrp(c, m) smmu_client_set_swgrp(c, m, 1)
+#define smmu_client_disable_swgrp(c) smmu_client_set_swgrp(c, 0, 0)
+#define __smmu_client_enable_swgrp(c, m) __smmu_client_set_swgrp(c, m, 1)
+#define __smmu_client_disable_swgrp(c) __smmu_client_set_swgrp(c, 0, 0)
+
+#define SWGRP_INIT(client) [SWGRP_##client] = SMMU_##client##_ASID
+
+static const u32 smmu_swgrp_asid_reg[] = {
+ SWGRP_INIT(AFI),
+ SWGRP_INIT(AVPC),
+ SWGRP_INIT(DC),
+ SWGRP_INIT(DCB),
+ SWGRP_INIT(EPP),
+ SWGRP_INIT(G2),
+ SWGRP_INIT(HC),
+ SWGRP_INIT(HDA),
+ SWGRP_INIT(ISP),
+ SWGRP_INIT(MPE),
+ SWGRP_INIT(NV),
+ SWGRP_INIT(NV2),
+ SWGRP_INIT(PPCS),
+ SWGRP_INIT(SATA),
+ SWGRP_INIT(VDE),
+ SWGRP_INIT(VI),
};
-#define HWGRP_ASID_REG(x) (smmu_hwgrp_asid_reg[x])
+#define SWGRP_ASID_REG(x) (smmu_swgrp_asid_reg[x])
/*
* Per client for address space
@@ -263,7 +263,7 @@ struct smmu_client {
struct device *dev;
struct list_head list;
struct smmu_as *as;
- u32 hwgrp;
+ u32 swgrp;
};
/*
@@ -375,9 +375,9 @@ static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
*/
#define FLUSH_SMMU_REGS(smmu) smmu_read(smmu, SMMU_CONFIG)
-#define smmu_client_hwgrp(c) (u32)((c)->dev->platform_data)
+#define smmu_client_swgrp(c) (u32)((c)->dev->platform_data)
-static int __smmu_client_set_hwgrp(struct smmu_client *c,
+static int __smmu_client_set_swgrp(struct smmu_client *c,
unsigned long map, int on)
{
int i;
@@ -389,10 +389,10 @@ static int __smmu_client_set_hwgrp(struct smmu_client *c,
if (on && !map)
return -EINVAL;
if (!on)
- map = smmu_client_hwgrp(c);
+ map = smmu_client_swgrp(c);
- for_each_set_bit(i, &map, HWGRP_COUNT) {
- offs = HWGRP_ASID_REG(i);
+ for_each_set_bit(i, &map, SWGRP_COUNT) {
+ offs = SWGRP_ASID_REG(i);
val = smmu_read(smmu, offs);
if (on) {
if (WARN_ON(val & mask))
@@ -405,12 +405,12 @@ static int __smmu_client_set_hwgrp(struct smmu_client *c,
smmu_write(smmu, val, offs);
}
FLUSH_SMMU_REGS(smmu);
- c->hwgrp = map;
+ c->swgrp = map;
return 0;
err_hw_busy:
- for_each_set_bit(i, &map, HWGRP_COUNT) {
- offs = HWGRP_ASID_REG(i);
+ for_each_set_bit(i, &map, SWGRP_COUNT) {
+ offs = SWGRP_ASID_REG(i);
val = smmu_read(smmu, offs);
val &= ~mask;
smmu_write(smmu, val, offs);
@@ -418,7 +418,7 @@ err_hw_busy:
return -EBUSY;
}
-static int smmu_client_set_hwgrp(struct smmu_client *c, u32 map, int on)
+static int smmu_client_set_swgrp(struct smmu_client *c, u32 map, int on)
{
u32 val;
unsigned long flags;
@@ -426,7 +426,7 @@ static int smmu_client_set_hwgrp(struct smmu_client *c, u32 map, int on)
struct smmu_device *smmu = as->smmu;
spin_lock_irqsave(&smmu->lock, flags);
- val = __smmu_client_set_hwgrp(c, map, on);
+ val = __smmu_client_set_swgrp(c, map, on);
spin_unlock_irqrestore(&smmu->lock, flags);
return val;
}
@@ -466,7 +466,7 @@ static int smmu_setup_regs(struct smmu_device *smmu)
smmu_write(smmu, val, SMMU_PTB_DATA);
list_for_each_entry(c, &as->client, list)
- __smmu_client_set_hwgrp(c, c->hwgrp, 1);
+ __smmu_client_set_swgrp(c, c->swgrp, 1);
}
smmu_write(smmu, smmu->translation_enable_0, SMMU_TRANSLATION_ENABLE_0);
@@ -798,9 +798,9 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
if (!map)
return -EINVAL;
- err = smmu_client_enable_hwgrp(client, map);
+ err = smmu_client_enable_swgrp(client, map);
if (err)
- goto err_hwgrp;
+ goto err_swgrp;
spin_lock(&as->client_lock);
list_for_each_entry(c, &as->client, list) {
@@ -818,7 +818,7 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
* Reserve "page zero" for AVP vectors using a common dummy
* page.
*/
- if (map & HWG_AVPC) {
+ if (map & SWG_AVPC) {
struct page *page;
page = as->smmu->avp_vector_page;
@@ -831,9 +831,9 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
return 0;
err_client:
- smmu_client_disable_hwgrp(client);
+ smmu_client_disable_swgrp(client);
spin_unlock(&as->client_lock);
-err_hwgrp:
+err_swgrp:
devm_kfree(smmu->dev, client);
return err;
}
@@ -849,7 +849,7 @@ static void smmu_iommu_detach_dev(struct iommu_domain *domain,
list_for_each_entry(c, &as->client, list) {
if (c->dev == dev) {
- smmu_client_disable_hwgrp(c);
+ smmu_client_disable_swgrp(c);
list_del(&c->list);
devm_kfree(smmu->dev, c);
c->as = NULL;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 2/6] iommu/tegra: smmu: Pass swgroup info from DT
[not found] ` <1358237848-968-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-15 8:17 ` Hiroshi Doyu
[not found] ` <1358237848-968-2-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-15 8:17 ` [PATCH 3/6] iommu/tegra: smmu: Support variable length of swgroups bitmap Hiroshi Doyu
` (4 subsequent siblings)
5 siblings, 1 reply; 22+ messages in thread
From: Hiroshi Doyu @ 2013-01-15 8:17 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
joro-zLv9SwRftAIdnm+yROfE0A
Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA, Hiroshi Doyu
Pass available H/W client component(software client group) info from
DT in bitmap. This info is specific to a certain generation of Tegra
SoC. With this, Tegra SMMU driver could be identical among Tegra
generations. This also removes the old way of passing this bit from
each device pdata, which could configure(enable/disable) each device
IOMMU'able, but it belongs to a kind of "policy", which can be done by
kernel/system later. Now DT passes just pure H/W info.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
.../bindings/iommu/nvidia,tegra30-smmu.txt | 41 ++++++++
drivers/iommu/tegra-smmu.c | 99 +++-----------------
2 files changed, 55 insertions(+), 85 deletions(-)
diff --git a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
index 89fb543..de449d0 100644
--- a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
@@ -8,6 +8,46 @@ Required properties:
- nvidia,#asids : # of ASIDs
- dma-window : IOVA start address and length.
- nvidia,ahb : phandle to the ahb bus connected to SMMU.
+- nvidia,swgroups: Available H/W client component(software client
+ group) in bitmap in SoC. Those IDs are calculated as below:
+
+ <ID> = (<OFFSET> - MC_SMMU_AFI_ASID_0) / 4;
+
+ This <ID>/<OFFSET> can grow if SWGROUP is added in the future
+ SoC. Please refer to Tegra SoC TRM to find which SWGROUPs are
+ implemented in SoC.
+
+------------------------
+ID Offset SWGROUP
+=======================
+0 238 AFI
+1 23c AVP
+2 240 DC
+3 244 DCB
+------------------------
+4 248 EPP
+5 24c G2
+6 250 HC
+7 254 HDA
+------------------------
+8 258 ISP
+9 25c -
+10 260 -
+11 264 MPE
+------------------------
+12 268 NV
+13 26c NV2
+14 270 PPC
+15 274 -
+------------------------
+16 278 SAT
+17 27c VDE
+18 280 VI
+19 284 -
+------------------------
+20 288 -
+21 29c -
+......
Example:
smmu {
@@ -17,5 +57,6 @@ Example:
0x7000f228 0x05c>;
nvidia,#asids = <4>; /* # of ASIDs */
dma-window = <0 0x40000000>; /* IOVA start & length */
+ nvidia,swgroups = <0x775ff>;
nvidia,ahb = <&ahb>;
};
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 224c0a0..e83797b 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -39,46 +39,6 @@
#include <asm/page.h>
#include <asm/cacheflush.h>
-enum smmu_swgrp {
- SWGRP_AFI,
- SWGRP_AVPC,
- SWGRP_DC,
- SWGRP_DCB,
- SWGRP_EPP,
- SWGRP_G2,
- SWGRP_HC,
- SWGRP_HDA,
- SWGRP_ISP,
- SWGRP_MPE,
- SWGRP_NV,
- SWGRP_NV2,
- SWGRP_PPCS,
- SWGRP_SATA,
- SWGRP_VDE,
- SWGRP_VI,
-
- SWGRP_COUNT,
-
- SWGRP_END = ~0,
-};
-
-#define SWG_AFI (1 << SWGRP_AFI)
-#define SWG_AVPC (1 << SWGRP_AVPC)
-#define SWG_DC (1 << SWGRP_DC)
-#define SWG_DCB (1 << SWGRP_DCB)
-#define SWG_EPP (1 << SWGRP_EPP)
-#define SWG_G2 (1 << SWGRP_G2)
-#define SWG_HC (1 << SWGRP_HC)
-#define SWG_HDA (1 << SWGRP_HDA)
-#define SWG_ISP (1 << SWGRP_ISP)
-#define SWG_MPE (1 << SWGRP_MPE)
-#define SWG_NV (1 << SWGRP_NV)
-#define SWG_NV2 (1 << SWGRP_NV2)
-#define SWG_PPCS (1 << SWGRP_PPCS)
-#define SWG_SATA (1 << SWGRP_SATA)
-#define SWG_VDE (1 << SWGRP_VDE)
-#define SWG_VI (1 << SWGRP_VI)
-
/* bitmap of the page sizes currently supported */
#define SMMU_IOMMU_PGSIZES (SZ_4K)
@@ -148,21 +108,10 @@ enum {
#define SMMU_TRANSLATION_ENABLE_2 0x230
#define SMMU_AFI_ASID 0x238 /* PCIE */
+#define SMMU_SWGRP_ASID_BASE SMMU_AFI_ASID
+
#define SMMU_AVPC_ASID 0x23c /* AVP */
-#define SMMU_DC_ASID 0x240 /* Display controller */
-#define SMMU_DCB_ASID 0x244 /* Display controller B */
-#define SMMU_EPP_ASID 0x248 /* Encoder pre-processor */
-#define SMMU_G2_ASID 0x24c /* 2D engine */
-#define SMMU_HC_ASID 0x250 /* Host1x */
-#define SMMU_HDA_ASID 0x254 /* High-def audio */
-#define SMMU_ISP_ASID 0x258 /* Image signal processor */
-#define SMMU_MPE_ASID 0x264 /* MPEG encoder */
-#define SMMU_NV_ASID 0x268 /* (3D) */
-#define SMMU_NV2_ASID 0x26c /* (3D) */
-#define SMMU_PPCS_ASID 0x270 /* AHB */
-#define SMMU_SATA_ASID 0x278 /* SATA */
-#define SMMU_VDE_ASID 0x27c /* Video decoder */
-#define SMMU_VI_ASID 0x280 /* Video input */
+#define SWG_AVPC ((SMMU_AVPC_ASID - SMMU_SWGRP_ASID_BASE) / 4)
#define SMMU_PDE_NEXT_SHIFT 28
@@ -234,27 +183,7 @@ enum {
#define __smmu_client_enable_swgrp(c, m) __smmu_client_set_swgrp(c, m, 1)
#define __smmu_client_disable_swgrp(c) __smmu_client_set_swgrp(c, 0, 0)
-#define SWGRP_INIT(client) [SWGRP_##client] = SMMU_##client##_ASID
-
-static const u32 smmu_swgrp_asid_reg[] = {
- SWGRP_INIT(AFI),
- SWGRP_INIT(AVPC),
- SWGRP_INIT(DC),
- SWGRP_INIT(DCB),
- SWGRP_INIT(EPP),
- SWGRP_INIT(G2),
- SWGRP_INIT(HC),
- SWGRP_INIT(HDA),
- SWGRP_INIT(ISP),
- SWGRP_INIT(MPE),
- SWGRP_INIT(NV),
- SWGRP_INIT(NV2),
- SWGRP_INIT(PPCS),
- SWGRP_INIT(SATA),
- SWGRP_INIT(VDE),
- SWGRP_INIT(VI),
-};
-#define SWGRP_ASID_REG(x) (smmu_swgrp_asid_reg[x])
+#define SWGRP_ASID_REG(id) (4 * (id) + SMMU_SWGRP_ASID_BASE)
/*
* Per client for address space
@@ -263,7 +192,6 @@ struct smmu_client {
struct device *dev;
struct list_head list;
struct smmu_as *as;
- u32 swgrp;
};
/*
@@ -313,6 +241,7 @@ struct smmu_device {
struct smmu_debugfs_info *debugfs_info;
struct device_node *ahb;
+ u32 swgrp;
int num_as;
struct smmu_as as[0]; /* Run-time allocated array */
@@ -375,8 +304,6 @@ static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
*/
#define FLUSH_SMMU_REGS(smmu) smmu_read(smmu, SMMU_CONFIG)
-#define smmu_client_swgrp(c) (u32)((c)->dev->platform_data)
-
static int __smmu_client_set_swgrp(struct smmu_client *c,
unsigned long map, int on)
{
@@ -388,10 +315,8 @@ static int __smmu_client_set_swgrp(struct smmu_client *c,
WARN_ON(!on && map);
if (on && !map)
return -EINVAL;
- if (!on)
- map = smmu_client_swgrp(c);
- for_each_set_bit(i, &map, SWGRP_COUNT) {
+ for_each_set_bit(i, &map, BITS_PER_LONG) {
offs = SWGRP_ASID_REG(i);
val = smmu_read(smmu, offs);
if (on) {
@@ -405,11 +330,10 @@ static int __smmu_client_set_swgrp(struct smmu_client *c,
smmu_write(smmu, val, offs);
}
FLUSH_SMMU_REGS(smmu);
- c->swgrp = map;
return 0;
err_hw_busy:
- for_each_set_bit(i, &map, SWGRP_COUNT) {
+ for_each_set_bit(i, &map, BITS_PER_LONG) {
offs = SWGRP_ASID_REG(i);
val = smmu_read(smmu, offs);
val &= ~mask;
@@ -466,7 +390,7 @@ static int smmu_setup_regs(struct smmu_device *smmu)
smmu_write(smmu, val, SMMU_PTB_DATA);
list_for_each_entry(c, &as->client, list)
- __smmu_client_set_swgrp(c, c->swgrp, 1);
+ __smmu_client_set_swgrp(c, smmu->swgrp, 1);
}
smmu_write(smmu, smmu->translation_enable_0, SMMU_TRANSLATION_ENABLE_0);
@@ -794,7 +718,7 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
return -ENOMEM;
client->dev = dev;
client->as = as;
- map = (unsigned long)dev->platform_data;
+ map = smmu->swgrp;
if (!map)
return -EINVAL;
@@ -1154,12 +1078,16 @@ static int tegra_smmu_probe(struct platform_device *pdev)
int i, asids, err = 0;
dma_addr_t uninitialized_var(base);
size_t bytes, uninitialized_var(size);
+ u32 swgrp;
if (smmu_handle)
return -EIO;
BUILD_BUG_ON(PAGE_SHIFT != SMMU_PAGE_SHIFT);
+ if (of_property_read_u32(dev->of_node, "nvidia,swgroups", &swgrp))
+ return -ENODEV;
+
if (of_property_read_u32(dev->of_node, "nvidia,#asids", &asids))
return -ENODEV;
@@ -1198,6 +1126,7 @@ static int tegra_smmu_probe(struct platform_device *pdev)
smmu->dev = dev;
smmu->num_as = asids;
+ smmu->swgrp = swgrp;
smmu->iovmm_base = base;
smmu->page_count = size;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 3/6] iommu/tegra: smmu: Support variable length of swgroups bitmap
[not found] ` <1358237848-968-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-15 8:17 ` [PATCH 2/6] iommu/tegra: smmu: Pass swgroup info from DT Hiroshi Doyu
@ 2013-01-15 8:17 ` Hiroshi Doyu
2013-01-15 8:17 ` [PATCH 4/6] iommu/tegra: smmu: Support variable MMIO range Hiroshi Doyu
` (3 subsequent siblings)
5 siblings, 0 replies; 22+ messages in thread
From: Hiroshi Doyu @ 2013-01-15 8:17 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
joro-zLv9SwRftAIdnm+yROfE0A
Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA, Hiroshi Doyu
The definition of swgroups can grow in the future SoCs. This patch
allows to have longer bitmaps for that.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/iommu/tegra-smmu.c | 67 ++++++++++++++++++++++++++------------------
1 file changed, 40 insertions(+), 27 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index e83797b..e80312c 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -178,10 +178,10 @@ enum {
#define NUM_SMMU_REG_BANKS 3
-#define smmu_client_enable_swgrp(c, m) smmu_client_set_swgrp(c, m, 1)
-#define smmu_client_disable_swgrp(c) smmu_client_set_swgrp(c, 0, 0)
-#define __smmu_client_enable_swgrp(c, m) __smmu_client_set_swgrp(c, m, 1)
-#define __smmu_client_disable_swgrp(c) __smmu_client_set_swgrp(c, 0, 0)
+#define smmu_client_enable_swgrp(c) smmu_client_set_swgrp(c, 1)
+#define smmu_client_disable_swgrp(c) smmu_client_set_swgrp(c, 0)
+#define __smmu_client_enable_swgrp(c) __smmu_client_set_swgrp(c, 1)
+#define __smmu_client_disable_swgrp(c) __smmu_client_set_swgrp(c, 0)
#define SWGRP_ASID_REG(id) (4 * (id) + SMMU_SWGRP_ASID_BASE)
@@ -241,7 +241,9 @@ struct smmu_device {
struct smmu_debugfs_info *debugfs_info;
struct device_node *ahb;
- u32 swgrp;
+
+ unsigned long *swgrp; /* software client group bitmap */
+ size_t swgrp_bits; /* size of bitmap in bits */
int num_as;
struct smmu_as as[0]; /* Run-time allocated array */
@@ -304,19 +306,14 @@ static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
*/
#define FLUSH_SMMU_REGS(smmu) smmu_read(smmu, SMMU_CONFIG)
-static int __smmu_client_set_swgrp(struct smmu_client *c,
- unsigned long map, int on)
+static int __smmu_client_set_swgrp(struct smmu_client *c, int on)
{
int i;
struct smmu_as *as = c->as;
u32 val, offs, mask = SMMU_ASID_ENABLE(as->asid);
struct smmu_device *smmu = as->smmu;
- WARN_ON(!on && map);
- if (on && !map)
- return -EINVAL;
-
- for_each_set_bit(i, &map, BITS_PER_LONG) {
+ for_each_set_bit(i, smmu->swgrp, smmu->swgrp_bits) {
offs = SWGRP_ASID_REG(i);
val = smmu_read(smmu, offs);
if (on) {
@@ -333,7 +330,7 @@ static int __smmu_client_set_swgrp(struct smmu_client *c,
return 0;
err_hw_busy:
- for_each_set_bit(i, &map, BITS_PER_LONG) {
+ for_each_set_bit(i, smmu->swgrp, smmu->swgrp_bits) {
offs = SWGRP_ASID_REG(i);
val = smmu_read(smmu, offs);
val &= ~mask;
@@ -342,7 +339,7 @@ err_hw_busy:
return -EBUSY;
}
-static int smmu_client_set_swgrp(struct smmu_client *c, u32 map, int on)
+static int smmu_client_set_swgrp(struct smmu_client *c, int on)
{
u32 val;
unsigned long flags;
@@ -350,7 +347,7 @@ static int smmu_client_set_swgrp(struct smmu_client *c, u32 map, int on)
struct smmu_device *smmu = as->smmu;
spin_lock_irqsave(&smmu->lock, flags);
- val = __smmu_client_set_swgrp(c, map, on);
+ val = __smmu_client_set_swgrp(c, on);
spin_unlock_irqrestore(&smmu->lock, flags);
return val;
}
@@ -390,7 +387,7 @@ static int smmu_setup_regs(struct smmu_device *smmu)
smmu_write(smmu, val, SMMU_PTB_DATA);
list_for_each_entry(c, &as->client, list)
- __smmu_client_set_swgrp(c, smmu->swgrp, 1);
+ __smmu_client_set_swgrp(c, 1);
}
smmu_write(smmu, smmu->translation_enable_0, SMMU_TRANSLATION_ENABLE_0);
@@ -710,7 +707,6 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
struct smmu_as *as = domain->priv;
struct smmu_device *smmu = as->smmu;
struct smmu_client *client, *c;
- u32 map;
int err;
client = devm_kzalloc(smmu->dev, sizeof(*c), GFP_KERNEL);
@@ -718,11 +714,8 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
return -ENOMEM;
client->dev = dev;
client->as = as;
- map = smmu->swgrp;
- if (!map)
- return -EINVAL;
- err = smmu_client_enable_swgrp(client, map);
+ err = smmu_client_enable_swgrp(client);
if (err)
goto err_swgrp;
@@ -742,7 +735,7 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain,
* Reserve "page zero" for AVP vectors using a common dummy
* page.
*/
- if (map & SWG_AVPC) {
+ if (test_bit(SWG_AVPC, smmu->swgrp)) {
struct page *page;
page = as->smmu->avp_vector_page;
@@ -1071,6 +1064,27 @@ static int tegra_smmu_resume(struct device *dev)
return err;
}
+static int tegra_smmu_of_get_swgrp(struct smmu_device *smmu)
+{
+ size_t bytes, num;
+ const char *propname = "nvidia,swgroups";
+ const __be32 *prop;
+
+ prop = of_get_property(smmu->dev->of_node, propname, &bytes);
+ if (!prop || !bytes)
+ return -EINVAL;
+
+ num = BITS_TO_LONGS(bytes * BITS_PER_BYTE);
+ bytes = num * sizeof(unsigned long);
+ smmu->swgrp_bits = bytes * BITS_PER_BYTE;
+ smmu->swgrp = devm_kzalloc(smmu->dev, bytes, GFP_KERNEL);
+ if (!smmu->swgrp)
+ return -ENOMEM;
+
+ return of_property_read_u32_array(smmu->dev->of_node, propname,
+ (u32 *)smmu->swgrp, num);
+}
+
static int tegra_smmu_probe(struct platform_device *pdev)
{
struct smmu_device *smmu;
@@ -1078,16 +1092,12 @@ static int tegra_smmu_probe(struct platform_device *pdev)
int i, asids, err = 0;
dma_addr_t uninitialized_var(base);
size_t bytes, uninitialized_var(size);
- u32 swgrp;
if (smmu_handle)
return -EIO;
BUILD_BUG_ON(PAGE_SHIFT != SMMU_PAGE_SHIFT);
- if (of_property_read_u32(dev->of_node, "nvidia,swgroups", &swgrp))
- return -ENODEV;
-
if (of_property_read_u32(dev->of_node, "nvidia,#asids", &asids))
return -ENODEV;
@@ -1126,7 +1136,6 @@ static int tegra_smmu_probe(struct platform_device *pdev)
smmu->dev = dev;
smmu->num_as = asids;
- smmu->swgrp = swgrp;
smmu->iovmm_base = base;
smmu->page_count = size;
@@ -1135,6 +1144,10 @@ static int tegra_smmu_probe(struct platform_device *pdev)
smmu->translation_enable_2 = ~0;
smmu->asid_security = 0;
+ err = tegra_smmu_of_get_swgrp(smmu);
+ if (!err)
+ return -ENODEV;
+
for (i = 0; i < smmu->num_as; i++) {
struct smmu_as *as = &smmu->as[i];
--
1.7.9.5
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 4/6] iommu/tegra: smmu: Support variable MMIO range
[not found] ` <1358237848-968-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-15 8:17 ` [PATCH 2/6] iommu/tegra: smmu: Pass swgroup info from DT Hiroshi Doyu
2013-01-15 8:17 ` [PATCH 3/6] iommu/tegra: smmu: Support variable length of swgroups bitmap Hiroshi Doyu
@ 2013-01-15 8:17 ` Hiroshi Doyu
[not found] ` <1358237848-968-4-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-15 8:17 ` [PATCH 5/6] ARM: dt: tegra114: Add AHB entry Hiroshi Doyu
` (2 subsequent siblings)
5 siblings, 1 reply; 22+ messages in thread
From: Hiroshi Doyu @ 2013-01-15 8:17 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
joro-zLv9SwRftAIdnm+yROfE0A
Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA
There are 3 SMMU MMIO register blocks. They may get bigger as new
Tegra SoC comes. This patch enables to support variable size of those
register blocks.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/iommu/tegra-smmu.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index e80312c..4f3a2a5 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -222,6 +222,7 @@ struct smmu_debugfs_info {
*/
struct smmu_device {
void __iomem *regs[NUM_SMMU_REG_BANKS];
+ resource_size_t regsz[NUM_SMMU_REG_BANKS];
unsigned long iovmm_base; /* remappable base address */
unsigned long page_count; /* total remappable size */
spinlock_t lock;
@@ -257,13 +258,13 @@ static struct smmu_device *smmu_handle; /* unique for a system */
static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
{
BUG_ON(offs < 0x10);
- if (offs < 0x3c)
+ if (offs < 0x10 + smmu->regsz[0])
return readl(smmu->regs[0] + offs - 0x10);
BUG_ON(offs < 0x1f0);
- if (offs < 0x200)
+ if (offs < 0x1f0 + smmu->regsz[1])
return readl(smmu->regs[1] + offs - 0x1f0);
BUG_ON(offs < 0x228);
- if (offs < 0x284)
+ if (offs < 0x228 + smmu->regsz[2])
return readl(smmu->regs[2] + offs - 0x228);
BUG();
}
@@ -271,17 +272,17 @@ static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
{
BUG_ON(offs < 0x10);
- if (offs < 0x3c) {
+ if (offs < 0x10 + smmu->regsz[0]) {
writel(val, smmu->regs[0] + offs - 0x10);
return;
}
BUG_ON(offs < 0x1f0);
- if (offs < 0x200) {
+ if (offs < 0x1f0 + smmu->regsz[1]) {
writel(val, smmu->regs[1] + offs - 0x1f0);
return;
}
BUG_ON(offs < 0x228);
- if (offs < 0x284) {
+ if (offs < 0x228 + smmu->regsz[2]) {
writel(val, smmu->regs[2] + offs - 0x228);
return;
}
@@ -1117,6 +1118,7 @@ static int tegra_smmu_probe(struct platform_device *pdev)
smmu->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
if (!smmu->regs[i])
return -EBUSY;
+ smmu->regsz[i] = resource_size(res);
}
err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 5/6] ARM: dt: tegra114: Add AHB entry
[not found] ` <1358237848-968-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (2 preceding siblings ...)
2013-01-15 8:17 ` [PATCH 4/6] iommu/tegra: smmu: Support variable MMIO range Hiroshi Doyu
@ 2013-01-15 8:17 ` Hiroshi Doyu
[not found] ` <1358237848-968-5-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-15 8:17 ` [PATCH 6/6] ARM: dt: tegra114: Add SMMU entry Hiroshi Doyu
2013-01-15 13:22 ` [PATCH 7/6] iommu/tegra: smmu: Add dependency on ARCH_TEGRA_114_SOC Hiroshi Doyu
5 siblings, 1 reply; 22+ messages in thread
From: Hiroshi Doyu @ 2013-01-15 8:17 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
joro-zLv9SwRftAIdnm+yROfE0A
Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA, Hiroshi Doyu
Add AHB entry.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
arch/arm/boot/dts/tegra114.dtsi | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi
index 175cbc3..fd2fd0e 100644
--- a/arch/arm/boot/dts/tegra114.dtsi
+++ b/arch/arm/boot/dts/tegra114.dtsi
@@ -26,6 +26,11 @@
0 122 0x04>;
};
+ ahb: ahb {
+ compatible = "nvidia,tegra114-ahb", "nvidia,tegra30-ahb";
+ reg = <0x6000c004 0x14c>;
+ };
+
serial@70006000 {
compatible = "nvidia,tegra114-uart", "nvidia,tegra20-uart";
reg = <0x70006000 0x40>;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 6/6] ARM: dt: tegra114: Add SMMU entry
[not found] ` <1358237848-968-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (3 preceding siblings ...)
2013-01-15 8:17 ` [PATCH 5/6] ARM: dt: tegra114: Add AHB entry Hiroshi Doyu
@ 2013-01-15 8:17 ` Hiroshi Doyu
[not found] ` <1358237848-968-6-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-15 13:22 ` [PATCH 7/6] iommu/tegra: smmu: Add dependency on ARCH_TEGRA_114_SOC Hiroshi Doyu
5 siblings, 1 reply; 22+ messages in thread
From: Hiroshi Doyu @ 2013-01-15 8:17 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
joro-zLv9SwRftAIdnm+yROfE0A
Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA, Hiroshi Doyu
Add SMMU entry.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
arch/arm/boot/dts/tegra114.dtsi | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi
index fd2fd0e..c3a602c 100644
--- a/arch/arm/boot/dts/tegra114.dtsi
+++ b/arch/arm/boot/dts/tegra114.dtsi
@@ -82,6 +82,17 @@
reg = <0x7000e400 0x400>;
};
+ smmu {
+ compatible = "nvidia,tegra114-smmu", "nvidia,tegra30-smmu";
+ reg = <0x7000f010 0x02c
+ 0x7000f1f0 0x010
+ 0x7000f228 0x074>;
+ nvidia,#asids = <4>;
+ dma-window = <0 0x40000000>;
+ nvidia,swgroups = <0x18659fe>;
+ nvidia,ahb = <&ahb>;
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 7/6] iommu/tegra: smmu: Add dependency on ARCH_TEGRA_114_SOC
[not found] ` <1358237848-968-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (4 preceding siblings ...)
2013-01-15 8:17 ` [PATCH 6/6] ARM: dt: tegra114: Add SMMU entry Hiroshi Doyu
@ 2013-01-15 13:22 ` Hiroshi Doyu
[not found] ` <1358256149-28700-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
5 siblings, 1 reply; 22+ messages in thread
From: Hiroshi Doyu @ 2013-01-15 13:22 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
joro-zLv9SwRftAIdnm+yROfE0A
Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA, Hiroshi Doyu
TEGRA_IOMMU_SMMU depends on ARCH_TEGRA_114_SOC too.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/iommu/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index e39f9db..90cc484 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -158,7 +158,7 @@ config TEGRA_IOMMU_GART
config TEGRA_IOMMU_SMMU
bool "Tegra SMMU IOMMU Support"
- depends on ARCH_TEGRA_3x_SOC && TEGRA_AHB
+ depends on (ARCH_TEGRA_114_SOC || ARCH_TEGRA_3x_SOC) && TEGRA_AHB
select IOMMU_API
help
Enables support for remapping discontiguous physical memory
--
1.7.9.5
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 2/6] iommu/tegra: smmu: Pass swgroup info from DT
[not found] ` <1358237848-968-2-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-16 21:07 ` Stephen Warren
0 siblings, 0 replies; 22+ messages in thread
From: Stephen Warren @ 2013-01-16 21:07 UTC (permalink / raw)
To: Hiroshi Doyu
Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
joro-zLv9SwRftAIdnm+yROfE0A, linux-tegra-u79uwXL29TY76Z2rM5mHXA
On 01/15/2013 01:17 AM, Hiroshi Doyu wrote:
> Pass available H/W client component(software client group) info from
> DT in bitmap. This info is specific to a certain generation of Tegra
> SoC. With this, Tegra SMMU driver could be identical among Tegra
> generations. This also removes the old way of passing this bit from
> each device pdata, which could configure(enable/disable) each device
> IOMMU'able, but it belongs to a kind of "policy", which can be done by
> kernel/system later. Now DT passes just pure H/W info.
> diff --git a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
> index 89fb543..de449d0 100644
> --- a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
> +++ b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
> @@ -8,6 +8,46 @@ Required properties:
> - nvidia,#asids : # of ASIDs
> - dma-window : IOVA start address and length.
> - nvidia,ahb : phandle to the ahb bus connected to SMMU.
> +- nvidia,swgroups: Available H/W client component(software client
> + group) in bitmap in SoC. Those IDs are calculated as below:
> +
> + <ID> = (<OFFSET> - MC_SMMU_AFI_ASID_0) / 4;
OK, so I understand the addition to the DT defines which clients exist,
and hence which ASID-selection registers exist. This addition makes
sense to me.
> diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
> /*
> * Per client for address space
> @@ -263,7 +192,6 @@ struct smmu_client {
> struct device *dev;
> struct list_head list;
> struct smmu_as *as;
> - u32 swgrp;
> };
What I don't quite understand is that change, but perhaps that's because
I'm not sure what that field meant before, and/or where the
client<->ASID mapping comes from.
Before this patch, did each client use that removed "u32 swgrp" to tell
the SMMU driver which ASID-selection register was used to configure it,
and then the SMMU took the union of all clients to know which
ASID-selection registers existed? If so, then perhaps this change makes
more sense than I thought... But, how does the SMMU driver know which of
the bits in the new nvidia,swgroups property is related to each struct
smmu_client?
Or, did the removed "u32 swgrp" indicate which of the SMMU's ASIDs
should be assigned to the client?
I guess what I'm missing is: How does the SMMU know which ASID to assign
to each client, either before or after this change? Or, does the driver
just assign every client to ASID 0 right now, and there's no provision
for separate ASIDs?
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 4/6] iommu/tegra: smmu: Support variable MMIO range
[not found] ` <1358237848-968-4-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-16 21:12 ` Stephen Warren
[not found] ` <50F717B8.6050800-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
0 siblings, 1 reply; 22+ messages in thread
From: Stephen Warren @ 2013-01-16 21:12 UTC (permalink / raw)
To: Hiroshi Doyu
Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
joro-zLv9SwRftAIdnm+yROfE0A, linux-tegra-u79uwXL29TY76Z2rM5mHXA
On 01/15/2013 01:17 AM, Hiroshi Doyu wrote:
> There are 3 SMMU MMIO register blocks. They may get bigger as new
> Tegra SoC comes. This patch enables to support variable size of those
> register blocks.
Why would the register blocks move around? In the HW, there's one single
chunk of memory containing all the SMMU registers, and we simply carve
out a few holes since some unrelated registers are stuck in the middle,
thus leaving us with 3 register ranges. If the size of those carved out
chunks changes, then doesn't that mean all the registers moved around
within the single chunk, and hence all the register offsets in the
driver become invalid?
It may help if you provide an explicit example of what the register
layout change is...
> diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
> static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
> {
> BUG_ON(offs < 0x10);
> - if (offs < 0x3c)
> + if (offs < 0x10 + smmu->regsz[0])
> return readl(smmu->regs[0] + offs - 0x10);
> BUG_ON(offs < 0x1f0);
> - if (offs < 0x200)
> + if (offs < 0x1f0 + smmu->regsz[1])
Wouldn't you need to adjust that BUG_ON() in a similar way to how the if
condition was adjusted?
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 6/6] ARM: dt: tegra114: Add SMMU entry
[not found] ` <1358237848-968-6-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-16 21:17 ` Stephen Warren
0 siblings, 0 replies; 22+ messages in thread
From: Stephen Warren @ 2013-01-16 21:17 UTC (permalink / raw)
To: Hiroshi Doyu
Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
On 01/15/2013 01:17 AM, Hiroshi Doyu wrote:
> Add SMMU entry.
> diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi
> + smmu {
> + compatible = "nvidia,tegra114-smmu", "nvidia,tegra30-smmu";
> + reg = <0x7000f010 0x02c
> + 0x7000f1f0 0x010
> + 0x7000f228 0x074>;
Oh, so the only change here relative to Tegra30 is that the final memory
range is larger; the others don't move around at all. Is that all that
patch 4/6 is trying to cope with? If so, I'd suggest simplifying that
patch a bunch; perhaps just remove the final if() check in each function
and make all accesses with (offs > 0x200) go to smmu->regs[2]?
You can always add checks to probe() that memory range 0 and 1 have the
expected size such that the code in smmu_{read,write} will work as expected.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 7/6] iommu/tegra: smmu: Add dependency on ARCH_TEGRA_114_SOC
[not found] ` <1358256149-28700-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-16 21:18 ` Stephen Warren
0 siblings, 0 replies; 22+ messages in thread
From: Stephen Warren @ 2013-01-16 21:18 UTC (permalink / raw)
To: Hiroshi Doyu
Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
joro-zLv9SwRftAIdnm+yROfE0A, linux-tegra-u79uwXL29TY76Z2rM5mHXA
On 01/15/2013 06:22 AM, Hiroshi Doyu wrote:
> TEGRA_IOMMU_SMMU depends on ARCH_TEGRA_114_SOC too.
> diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
> config TEGRA_IOMMU_SMMU
> bool "Tegra SMMU IOMMU Support"
> - depends on ARCH_TEGRA_3x_SOC && TEGRA_AHB
> + depends on (ARCH_TEGRA_114_SOC || ARCH_TEGRA_3x_SOC) && TEGRA_AHB
I think instead of listing out each SoC version individually, just
depend on ARCH_TEGRA. This will mean the SMMU driver can be enabled in a
Tegra20-only kernel, but that's not a big deal, and it means we won't
have to keep editing this Kconfig entry every time we add a new chip.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 4/6] iommu/tegra: smmu: Support variable MMIO range
[not found] ` <50F717B8.6050800-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
@ 2013-01-18 9:05 ` Hiroshi Doyu
[not found] ` <20130118.110546.1909336134474854222.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
0 siblings, 1 reply; 22+ messages in thread
From: Hiroshi Doyu @ 2013-01-18 9:05 UTC (permalink / raw)
To: swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org
Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org,
linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote @ Wed, 16 Jan 2013 22:12:24 +0100:
> On 01/15/2013 01:17 AM, Hiroshi Doyu wrote:
> > There are 3 SMMU MMIO register blocks. They may get bigger as new
> > Tegra SoC comes. This patch enables to support variable size of those
> > register blocks.
>
> Why would the register blocks move around? In the HW, there's one single
> chunk of memory containing all the SMMU registers, and we simply carve
> out a few holes since some unrelated registers are stuck in the middle,
> thus leaving us with 3 register ranges. If the size of those carved out
> chunks changes, then doesn't that mean all the registers moved around
> within the single chunk, and hence all the register offsets in the
> driver become invalid?
Presently there are 3 register blocks. In the future chips over some
generations, some of register block "size" can be extended to the end
and also more new register blocks will be added, which is expected at
most a few blocks. Usually the starting address of each block won't
change. Ideally SMMU register blocks should be in one block, but it
was a bit too late to change this design(or H/W). Considering this
situation, in this driver, number of register blocks should be
allocated dynamically, based on the info from DT. Its range checks
should be done in the accessors as below(*1) if necessary. This way
may sacrifice some perf because a new accessor prevents compiler
optimization of register offset calculation, but I think that SMMU
register accesses are not so frequent and it's acceptable in order to
unify "tegra-smmu" over Tegra SoCs.
*1:
/*
* SMMU register accessors
*/
static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
{
void __iommu *addr = smmu->regbase + offs;
#ifdef DEBUG
int i;
for (i = 0; i < smmu->num_regblks; i++) {
BUG_ON(addr < smmu->reg[i].start);
if (addr <= smmu->reg[i].end)
break;
}
#endfi
return readl(addr);
}
Even the checks if "offs" is in some of register blocks could be
ifdef'ed out with DEBUG. "smmu->regbase" can be calculated in probe()
as below. I don't think that we don't need to access "mc" DT entry to
get this address. since "smmu"'s 1st reg block always starts at 0x10.
/* same as "mc"'s 1st reg block */
smmu->regbase = smmu->reg[0] & PAGE_MASK;
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 4/6] iommu/tegra: smmu: Support variable MMIO range
[not found] ` <20130118.110546.1909336134474854222.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-18 16:44 ` Stephen Warren
[not found] ` <50F97BDD.8010502-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
0 siblings, 1 reply; 22+ messages in thread
From: Stephen Warren @ 2013-01-18 16:44 UTC (permalink / raw)
To: Hiroshi Doyu
Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org,
linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
On 01/18/2013 02:05 AM, Hiroshi Doyu wrote:
> Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote @ Wed, 16 Jan 2013 22:12:24 +0100:
>
>> On 01/15/2013 01:17 AM, Hiroshi Doyu wrote:
>>> There are 3 SMMU MMIO register blocks. They may get bigger as new
>>> Tegra SoC comes. This patch enables to support variable size of those
>>> register blocks.
>>
>> Why would the register blocks move around? In the HW, there's one single
>> chunk of memory containing all the SMMU registers, and we simply carve
>> out a few holes since some unrelated registers are stuck in the middle,
>> thus leaving us with 3 register ranges. If the size of those carved out
>> chunks changes, then doesn't that mean all the registers moved around
>> within the single chunk, and hence all the register offsets in the
>> driver become invalid?
>
> Presently there are 3 register blocks. In the future chips over some
> generations, some of register block "size" can be extended to the end
> and also more new register blocks will be added, which is expected at
> most a few blocks.
> Usually the starting address of each block won't change.
I would hope that was guaranteed; the only reason to move one of the
ranges would be a HW design change, and if there is a HW design change,
HW should take that opportunity to fix the interleaved register mess
instead of making it worse, and hence we could just have a single
register range after that point.
> Ideally SMMU register blocks should be in one block, but it
> was a bit too late to change this design(or H/W). Considering this
> situation, in this driver, number of register blocks should be
> allocated dynamically, based on the info from DT. Its range checks
> should be done in the accessors as below(*1) if necessary. This way
> may sacrifice some perf because a new accessor prevents compiler
> optimization of register offset calculation, but I think that SMMU
> register accesses are not so frequent and it's acceptable in order to
> unify "tegra-smmu" over Tegra SoCs.
>
> *1:
>
> /*
> * SMMU register accessors
> */
> static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
> {
> void __iommu *addr = smmu->regbase + offs;
> #ifdef DEBUG
> int i;
>
> for (i = 0; i < smmu->num_regblks; i++) {
> BUG_ON(addr < smmu->reg[i].start);
> if (addr <= smmu->reg[i].end)
> break;
> }
> #endfi
> return readl(addr);
> }
Yes, that kind of checking looks much better if this is all going to be
dynamic.
I would suggest enabling the checking all the time rather than hiding it
inside an ifdef; how many people build that file with DEBUG enabled?
Or perhaps you could check each register in probe() somehow.
> Even the checks if "offs" is in some of register blocks could be
> ifdef'ed out with DEBUG. "smmu->regbase" can be calculated in probe()
> as below. I don't think that we don't need to access "mc" DT entry to
> get this address. since "smmu"'s 1st reg block always starts at 0x10.
>
> /* same as "mc"'s 1st reg block */
> smmu->regbase = smmu->reg[0] & PAGE_MASK;
I don't see regbase in the existing driver or your patch. Are you
proposing to simply make readl/writel add the offset onto a base address
that's calculated like that? That may not work in general; if the SMMU
register ranges cross a page boundary, and the various separate ranges
end up getting mapped to non-contiguous virtual addresses, using a
single base address won't work.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 4/6] iommu/tegra: smmu: Support variable MMIO range
[not found] ` <50F97BDD.8010502-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
@ 2013-01-21 7:36 ` Hiroshi Doyu
[not found] ` <20130121.093603.449745485344660335.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
0 siblings, 1 reply; 22+ messages in thread
From: Hiroshi Doyu @ 2013-01-21 7:36 UTC (permalink / raw)
To: swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org
Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote @ Fri, 18 Jan 2013 17:44:13 +0100:
> > Even the checks if "offs" is in some of register blocks could be
> > ifdef'ed out with DEBUG. "smmu->regbase" can be calculated in probe()
> > as below. I don't think that we don't need to access "mc" DT entry to
> > get this address. since "smmu"'s 1st reg block always starts at 0x10.
> >
> > /* same as "mc"'s 1st reg block */
> > smmu->regbase = smmu->reg[0] & PAGE_MASK;
>
> I don't see regbase in the existing driver or your patch. Are you
I attached the update one below just for "regbase".
> proposing to simply make readl/writel add the offset onto a base address
> that's calculated like that? That may not work in general; if the SMMU
> register ranges cross a page boundary, and the various separate ranges
> end up getting mapped to non-contiguous virtual addresses, using a
> single base address won't work.
That's not in general, but I think that this works because the 1st
SMMU register block offset is fixed(0x10) against MC base. If this is
not acceptable, then, I think that SMMU driver needs to access to MC
node to get the its base. What do you think?
>From 71de7ddfed8b3341f18e97b92bdf76c193e5127a Mon Sep 17 00:00:00 2001
From: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Date: Wed, 9 Jan 2013 12:38:47 +0200
Subject: [PATCH 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
Presently there are 3 register blocks. In the future chips over some
generations, some of register block "size" can be extended to the end
and also more new register blocks will be added, which is expected at
most a few blocks. Usually the starting address of each block won't
change. Ideally SMMU register blocks should be in one block, but it
was a bit too late to change this design(or H/W). Considering this
situation, in this driver, number of register blocks should be
allocated dynamically, based on the info from DT. Its range checks
can be done in the accessors. This way may sacrifice some perf because
a new accessors prevents compiler optimization of register offset
calculation, but I think that SMMU register accesses are not so
frequent and it's acceptable, but it's ifdef'ed out. This patch is
necessary to unify "tegra-smmu.ko" over Tegra SoCs.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/iommu/tegra-smmu.c | 62 ++++++++++++++++++++++++--------------------
1 file changed, 34 insertions(+), 28 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index e80312c..96ac4241 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -221,7 +221,11 @@ struct smmu_debugfs_info {
* Per SMMU device - IOMMU device
*/
struct smmu_device {
- void __iomem *regs[NUM_SMMU_REG_BANKS];
+ void __iomem *regbase; /* register offset base */
+ void __iomem **regs; /* register block start address array */
+ void __iomem **rege; /* register block end address array */
+ int nregs; /* number of register blocks */
+
unsigned long iovmm_base; /* remappable base address */
unsigned long page_count; /* total remappable size */
spinlock_t lock;
@@ -254,38 +258,31 @@ static struct smmu_device *smmu_handle; /* unique for a system */
/*
* SMMU register accessors
*/
+#ifdef DEBUG
+static inline void smmu_check_reg_range(size_t offs)
+{
+ int i;
+
+ for (i = 0; i < smmu->nregs; i++) {
+ BUG_ON(offs < smmu->regs[i] - smmu->regbase);
+ if (offs <= smmu->rege[i] - smmu->regbase)
+ break;
+ }
+}
+#else
+static inline void smmu_check_reg_range(size_t offs) { }
+#endif
+
static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
{
- BUG_ON(offs < 0x10);
- if (offs < 0x3c)
- return readl(smmu->regs[0] + offs - 0x10);
- BUG_ON(offs < 0x1f0);
- if (offs < 0x200)
- return readl(smmu->regs[1] + offs - 0x1f0);
- BUG_ON(offs < 0x228);
- if (offs < 0x284)
- return readl(smmu->regs[2] + offs - 0x228);
- BUG();
+ smmu_check_reg_range(offs);
+ return readl(smmu->regbase + offs);
}
static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
{
- BUG_ON(offs < 0x10);
- if (offs < 0x3c) {
- writel(val, smmu->regs[0] + offs - 0x10);
- return;
- }
- BUG_ON(offs < 0x1f0);
- if (offs < 0x200) {
- writel(val, smmu->regs[1] + offs - 0x1f0);
- return;
- }
- BUG_ON(offs < 0x228);
- if (offs < 0x284) {
- writel(val, smmu->regs[2] + offs - 0x228);
- return;
- }
- BUG();
+ smmu_check_reg_range(offs);
+ writel(val, smmu->regbase + offs);
}
#define VA_PAGE_TO_PA(va, page) \
@@ -1108,7 +1105,13 @@ static int tegra_smmu_probe(struct platform_device *pdev)
return -ENOMEM;
}
- for (i = 0; i < ARRAY_SIZE(smmu->regs); i++) {
+ smmu->nregs = pdev->num_resources;
+ smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs),
+ GFP_KERNEL);
+ smmu->rege = smmu->regs + smmu->nregs;
+ if (!smmu->regs)
+ return -ENOMEM;
+ for (i = 0; i < smmu->nregs; i++) {
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
@@ -1117,7 +1120,10 @@ static int tegra_smmu_probe(struct platform_device *pdev)
smmu->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
if (!smmu->regs[i])
return -EBUSY;
+ smmu->rege[i] = smmu->regs[i] + resource_size(res);
}
+ /* Same as "mc" 1st regiter block start address */
+ smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & ~PAGE_MASK);
err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size);
if (err)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 4/6] iommu/tegra: smmu: Support variable MMIO range
[not found] ` <20130121.093603.449745485344660335.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-21 17:04 ` Stephen Warren
[not found] ` <50FD752A.6060706-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
0 siblings, 1 reply; 22+ messages in thread
From: Stephen Warren @ 2013-01-21 17:04 UTC (permalink / raw)
To: Hiroshi Doyu
Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org,
linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
On 01/21/2013 12:36 AM, Hiroshi Doyu wrote:
> Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote @ Fri, 18 Jan 2013 17:44:13 +0100:
>
>>> Even the checks if "offs" is in some of register blocks could be
>>> ifdef'ed out with DEBUG. "smmu->regbase" can be calculated in probe()
>>> as below. I don't think that we don't need to access "mc" DT entry to
>>> get this address. since "smmu"'s 1st reg block always starts at 0x10.
>>>
>>> /* same as "mc"'s 1st reg block */
>>> smmu->regbase = smmu->reg[0] & PAGE_MASK;
>>
>> I don't see regbase in the existing driver or your patch. Are you
>
> I attached the update one below just for "regbase".
>
>> proposing to simply make readl/writel add the offset onto a base address
>> that's calculated like that? That may not work in general; if the SMMU
>> register ranges cross a page boundary, and the various separate ranges
>> end up getting mapped to non-contiguous virtual addresses, using a
>> single base address won't work.
>
> That's not in general, but I think that this works because the 1st
> SMMU register block offset is fixed(0x10) against MC base. If this is
> not acceptable, then, I think that SMMU driver needs to access to MC
> node to get the its base. What do you think?
> drivers/iommu/tegra-smmu.c | 62 ++++++++++++++++++++++++--------------------
> 1 file changed, 34 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
> +#ifdef DEBUG
> +static inline void smmu_check_reg_range(size_t offs)
Like I said before, when is DEBUG defined? Rarely I suspect. It'd be
best to simply enable smmu_check_reg_range() all the time. As such ...
> +{
> + int i;
> +
> + for (i = 0; i < smmu->nregs; i++) {
> + BUG_ON(offs < smmu->regs[i] - smmu->regbase);
> + if (offs <= smmu->rege[i] - smmu->regbase)
> + break;
> + }
> +}
> +#else
> +static inline void smmu_check_reg_range(size_t offs) { }
> +#endif
> +
> static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
> {
> - BUG_ON(offs < 0x10);
> - if (offs < 0x3c)
> - return readl(smmu->regs[0] + offs - 0x10);
> - BUG_ON(offs < 0x1f0);
> - if (offs < 0x200)
> - return readl(smmu->regs[1] + offs - 0x1f0);
> - BUG_ON(offs < 0x228);
> - if (offs < 0x284)
> - return readl(smmu->regs[2] + offs - 0x228);
> - BUG();
> + smmu_check_reg_range(offs);
... here, you'd be doing the loop every access anyway, so you may as
well not calculate regbase at all, move the body of
smmu_check_reg_range() into smmu_read()/smmu_write(), and do the access
inside the if statement inside the loop, with the per-range mapping.
> + return readl(smmu->regbase + offs);
> }
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 5/6] ARM: dt: tegra114: Add AHB entry
[not found] ` <1358237848-968-5-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-28 19:00 ` Stephen Warren
0 siblings, 0 replies; 22+ messages in thread
From: Stephen Warren @ 2013-01-28 19:00 UTC (permalink / raw)
To: Hiroshi Doyu
Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
joro-zLv9SwRftAIdnm+yROfE0A, linux-tegra-u79uwXL29TY76Z2rM5mHXA
On 01/15/2013 01:17 AM, Hiroshi Doyu wrote:
> Add AHB entry.
I've applied patches 5/6 and 6/6 to Tegra's for-3.9/soc-t114 branch.
^ permalink raw reply [flat|nested] 22+ messages in thread
* [v2 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
[not found] ` <50FD752A.6060706-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
@ 2013-01-29 8:34 ` Hiroshi Doyu
[not found] ` <1359448450-24894-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
0 siblings, 1 reply; 22+ messages in thread
From: Hiroshi Doyu @ 2013-01-29 8:34 UTC (permalink / raw)
To: joro-zLv9SwRftAIdnm+yROfE0A
Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
Presently SMMU registers are located in discontiguous 3 blocks. They
are interleaved by MC registers. Ideally SMMU register blocks should
be in an independent one block, but it is too late to change this H/W
design. In the future Tegra chips over some generations, it is
expected that some of register block "size" can be extended towards
the end and also more new register blocks will be added at most a few
blocks. The starting address of each existing block won't change. This
patch allocates multiple number of register blocks dynamically based
on the info passed from DT. Those ranges are verified in the
accessors{read,write}. This may sacrifice some performance because a
new accessors prevents compiler optimization of a fixed size register
offset calculation. Since SMMU register accesses are not so frequent,
this would be acceptable. This patch is necessary to unify
"tegra-smmu.ko" over some Tegra SoC generations.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/iommu/tegra-smmu.c | 61 ++++++++++++++++++++++++++------------------
1 file changed, 36 insertions(+), 25 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index fc17889..e62f735 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -293,7 +293,11 @@ struct smmu_debugfs_info {
* Per SMMU device - IOMMU device
*/
struct smmu_device {
- void __iomem *regs[NUM_SMMU_REG_BANKS];
+ void __iomem *regbase; /* register offset base */
+ void __iomem **regs; /* register block start address array */
+ void __iomem **rege; /* register block end address array */
+ int nregs; /* number of register blocks */
+
unsigned long iovmm_base; /* remappable base address */
unsigned long page_count; /* total remappable size */
spinlock_t lock;
@@ -325,35 +329,33 @@ static struct smmu_device *smmu_handle; /* unique for a system */
*/
static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
{
- BUG_ON(offs < 0x10);
- if (offs < 0x3c)
- return readl(smmu->regs[0] + offs - 0x10);
- BUG_ON(offs < 0x1f0);
- if (offs < 0x200)
- return readl(smmu->regs[1] + offs - 0x1f0);
- BUG_ON(offs < 0x228);
- if (offs < 0x284)
- return readl(smmu->regs[2] + offs - 0x228);
+ int i;
+
+ for (i = 0; i < smmu->nregs; i++) {
+ void __iomem *addr = smmu->regbase + offs;
+
+ BUG_ON(addr < smmu->regs[i]);
+ if (addr <= smmu->rege[i])
+ return readl(addr);
+ }
+
BUG();
}
static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
{
- BUG_ON(offs < 0x10);
- if (offs < 0x3c) {
- writel(val, smmu->regs[0] + offs - 0x10);
- return;
- }
- BUG_ON(offs < 0x1f0);
- if (offs < 0x200) {
- writel(val, smmu->regs[1] + offs - 0x1f0);
- return;
- }
- BUG_ON(offs < 0x228);
- if (offs < 0x284) {
- writel(val, smmu->regs[2] + offs - 0x228);
- return;
+ int i;
+
+ for (i = 0; i < smmu->nregs; i++) {
+ void __iomem *addr = smmu->regbase + offs;
+
+ BUG_ON(addr < smmu->regs[i]);
+ if (addr <= smmu->rege[i]) {
+ writel(val, addr);
+ return;
+ }
}
+
BUG();
}
@@ -1170,7 +1172,13 @@ static int tegra_smmu_probe(struct platform_device *pdev)
return -ENOMEM;
}
- for (i = 0; i < ARRAY_SIZE(smmu->regs); i++) {
+ smmu->nregs = pdev->num_resources;
+ smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs),
+ GFP_KERNEL);
+ smmu->rege = smmu->regs + smmu->nregs;
+ if (!smmu->regs)
+ return -ENOMEM;
+ for (i = 0; i < smmu->nregs; i++) {
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
@@ -1179,7 +1187,10 @@ static int tegra_smmu_probe(struct platform_device *pdev)
smmu->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
if (!smmu->regs[i])
return -EBUSY;
+ smmu->rege[i] = smmu->regs[i] + resource_size(res);
}
+ /* Same as "mc" 1st regiter block start address */
+ smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & ~PAGE_MASK);
err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size);
if (err)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [v2 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
[not found] ` <1359448450-24894-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-29 17:03 ` Stephen Warren
[not found] ` <510800F7.7020507-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
0 siblings, 1 reply; 22+ messages in thread
From: Stephen Warren @ 2013-01-29 17:03 UTC (permalink / raw)
To: Hiroshi Doyu
Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
On 01/29/2013 01:34 AM, Hiroshi Doyu wrote:
> Presently SMMU registers are located in discontiguous 3 blocks. They
> are interleaved by MC registers. Ideally SMMU register blocks should
> be in an independent one block, but it is too late to change this H/W
> design. In the future Tegra chips over some generations, it is
> expected that some of register block "size" can be extended towards
> the end and also more new register blocks will be added at most a few
> blocks. The starting address of each existing block won't change. This
> patch allocates multiple number of register blocks dynamically based
> on the info passed from DT. Those ranges are verified in the
> accessors{read,write}. This may sacrifice some performance because a
> new accessors prevents compiler optimization of a fixed size register
> offset calculation. Since SMMU register accesses are not so frequent,
> this would be acceptable. This patch is necessary to unify
> "tegra-smmu.ko" over some Tegra SoC generations.
> diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
> static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
> + for (i = 0; i < smmu->nregs; i++) {
> + void __iomem *addr = smmu->regbase + offs;
I don't really like the concept of "regbase", but I suppose it works
just fine and isn't entirely avoidable, so I won't object.
> + BUG_ON(addr < smmu->regs[i]);
> + if (addr <= smmu->rege[i])
> + return readl(addr);
So here we assume that rege points at the last valid address in the range...
> @@ -1170,7 +1172,13 @@ static int tegra_smmu_probe(struct platform_device *pdev)
> return -ENOMEM;
> }
>
> - for (i = 0; i < ARRAY_SIZE(smmu->regs); i++) {
> + smmu->nregs = pdev->num_resources;
> + smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs),
> + GFP_KERNEL);
> + smmu->rege = smmu->regs + smmu->nregs;
... but here rege is set to the first address after the range. I think
the simplest solution is to change the <= to < in smmu_{read,write}().
> + /* Same as "mc" 1st regiter block start address */
> + smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & ~PAGE_MASK);
I'm not sure if it's relevant how these register ranges are related to
the MC registers, given this is the SMMU driver?
s/regiter/register/ in the comment if you keep it.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [v2 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
[not found] ` <510800F7.7020507-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
@ 2013-01-29 17:40 ` Hiroshi Doyu
[not found] ` <20130129.194007.2143867447969494923.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-29 17:56 ` [v3 " Hiroshi Doyu
1 sibling, 1 reply; 22+ messages in thread
From: Hiroshi Doyu @ 2013-01-29 17:40 UTC (permalink / raw)
To: swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org
Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote @ Tue, 29 Jan 2013 18:03:51 +0100:
> > + /* Same as "mc" 1st regiter block start address */
> > + smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & ~PAGE_MASK);
>
> I'm not sure if it's relevant how these register ranges are related to
> the MC registers, given this is the SMMU driver?
All SMMU register offsets are against MC[0]'s start address and SMMU
register blocks are interleaved as below. The 1st SMMU register block
SMMU[0]'s offset is always 0x10.
Address Register block
-----------------------
000-010 MC[0]
010-03c SMMU[0]
03c-1f0 MC[1]
1f0-200 SMMU[1]
200-228 MC[2]
228-284 SMMU[2]
284-... MC[3]
If the above assumption is not acceptable, alternatively we need to
access MC's node to get the 1st MC register block start address, for
example, via embedded in MC's phandle in smmu entry.
Modified arch/arm/boot/dts/tegra30.dtsi
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index c5db29d..e9fb9ef 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -397,7 +397,7 @@
reg = <0x7000e400 0x400>;
};
- memory-controller {
+ mc: memory-controller {
compatible = "nvidia,tegra30-mc";
reg = <0x7000f000 0x010
0x7000f03c 0x1b4
@@ -414,6 +414,7 @@
nvidia,#asids = <4>; /* # of ASIDs */
dma-window = <0 0x40000000>; /* IOVA start & length */
nvidia,ahb = <&ahb>;
+ nvidia.mc = <&mc>;
};
ahub {
I may think that above may be a bit too much since we know that the
1st SMMU offset(0x10) and also that the MC register is aligned with
page boundary, and the following works actually.
smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & ~PAGE_MASK);
I don't think that the existing SMMU/MC register offsets will change so easily.
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [v3 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
[not found] ` <510800F7.7020507-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2013-01-29 17:40 ` Hiroshi Doyu
@ 2013-01-29 17:56 ` Hiroshi Doyu
[not found] ` <1359482169-26756-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
1 sibling, 1 reply; 22+ messages in thread
From: Hiroshi Doyu @ 2013-01-29 17:56 UTC (permalink / raw)
To: joro-zLv9SwRftAIdnm+yROfE0A, swarren-3lzwWm7+Weoh9ZMKESR00Q
Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
Presently SMMU registers are located in discontiguous 3 blocks. They
are interleaved by MC registers. Ideally SMMU register blocks should
be in an independent one block, but it is too late to change this H/W
design. In the future Tegra chips over some generations, it is
expected that some of register block "size" can be extended towards
the end and also more new register blocks will be added at most a few
blocks. The starting address of each existing block won't change. This
patch allocates multiple number of register blocks dynamically based
on the info passed from DT. Those ranges are verified in the
accessors{read,write}. This may sacrifice some performance because a
new accessors prevents compiler optimization of a fixed size register
offset calculation. Since SMMU register accesses are not so frequent,
this would be acceptable. This patch is necessary to unify
"tegra-smmu.ko" over some Tegra SoC generations.
Signed-off-by: Hiroshi Doyu <hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
v3:
Fixed overlapped register validation. (Stephen Warren)
Fixed typo s/regiter/register/. (Stephen Warren)
---
drivers/iommu/tegra-smmu.c | 61 ++++++++++++++++++++++++++------------------
1 file changed, 36 insertions(+), 25 deletions(-)
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index fc17889..d1448f9 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -293,7 +293,11 @@ struct smmu_debugfs_info {
* Per SMMU device - IOMMU device
*/
struct smmu_device {
- void __iomem *regs[NUM_SMMU_REG_BANKS];
+ void __iomem *regbase; /* register offset base */
+ void __iomem **regs; /* register block start address array */
+ void __iomem **rege; /* register block end address array */
+ int nregs; /* number of register blocks */
+
unsigned long iovmm_base; /* remappable base address */
unsigned long page_count; /* total remappable size */
spinlock_t lock;
@@ -325,35 +329,33 @@ static struct smmu_device *smmu_handle; /* unique for a system */
*/
static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
{
- BUG_ON(offs < 0x10);
- if (offs < 0x3c)
- return readl(smmu->regs[0] + offs - 0x10);
- BUG_ON(offs < 0x1f0);
- if (offs < 0x200)
- return readl(smmu->regs[1] + offs - 0x1f0);
- BUG_ON(offs < 0x228);
- if (offs < 0x284)
- return readl(smmu->regs[2] + offs - 0x228);
+ int i;
+
+ for (i = 0; i < smmu->nregs; i++) {
+ void __iomem *addr = smmu->regbase + offs;
+
+ BUG_ON(addr < smmu->regs[i]);
+ if (addr < smmu->rege[i])
+ return readl(addr);
+ }
+
BUG();
}
static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
{
- BUG_ON(offs < 0x10);
- if (offs < 0x3c) {
- writel(val, smmu->regs[0] + offs - 0x10);
- return;
- }
- BUG_ON(offs < 0x1f0);
- if (offs < 0x200) {
- writel(val, smmu->regs[1] + offs - 0x1f0);
- return;
- }
- BUG_ON(offs < 0x228);
- if (offs < 0x284) {
- writel(val, smmu->regs[2] + offs - 0x228);
- return;
+ int i;
+
+ for (i = 0; i < smmu->nregs; i++) {
+ void __iomem *addr = smmu->regbase + offs;
+
+ BUG_ON(addr < smmu->regs[i]);
+ if (addr < smmu->rege[i]) {
+ writel(val, addr);
+ return;
+ }
}
+
BUG();
}
@@ -1170,7 +1172,13 @@ static int tegra_smmu_probe(struct platform_device *pdev)
return -ENOMEM;
}
- for (i = 0; i < ARRAY_SIZE(smmu->regs); i++) {
+ smmu->nregs = pdev->num_resources;
+ smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs),
+ GFP_KERNEL);
+ smmu->rege = smmu->regs + smmu->nregs;
+ if (!smmu->regs)
+ return -ENOMEM;
+ for (i = 0; i < smmu->nregs; i++) {
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
@@ -1179,7 +1187,10 @@ static int tegra_smmu_probe(struct platform_device *pdev)
smmu->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
if (!smmu->regs[i])
return -EBUSY;
+ smmu->rege[i] = smmu->regs[i] + resource_size(res);
}
+ /* Same as "mc" 1st register block start address */
+ smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & ~PAGE_MASK);
err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size);
if (err)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [v2 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
[not found] ` <20130129.194007.2143867447969494923.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-29 17:57 ` Stephen Warren
0 siblings, 0 replies; 22+ messages in thread
From: Stephen Warren @ 2013-01-29 17:57 UTC (permalink / raw)
To: Hiroshi Doyu
Cc: joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
On 01/29/2013 10:40 AM, Hiroshi Doyu wrote:
> Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote @ Tue, 29 Jan 2013 18:03:51 +0100:
>
>>> + /* Same as "mc" 1st regiter block start address */
>>> + smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & ~PAGE_MASK);
>>
>> I'm not sure if it's relevant how these register ranges are related to
>> the MC registers, given this is the SMMU driver?
>
> All SMMU register offsets are against MC[0]'s start address and SMMU
> register blocks are interleaved as below. The 1st SMMU register block
> SMMU[0]'s offset is always 0x10.
>
> Address Register block
> -----------------------
> 000-010 MC[0]
> 010-03c SMMU[0]
> 03c-1f0 MC[1]
> 1f0-200 SMMU[1]
> 200-228 MC[2]
> 228-284 SMMU[2]
> 284-... MC[3]
I know that's true, but it's still not really relevant to the SMMU
driver. What is relevant is that the SMMU has a bunch of chunks of
address space containing SMMU registers, and there are gaps, and all the
register offsets in the SMMU driver are relative to the page-aligned
base of the first chunk. The fact the gaps contain MC registers is what
isn't relevant.
> If the above assumption is not acceptable, alternatively we need to
> access MC's node to get the 1st MC register block start address, for
> example, via embedded in MC's phandle in smmu entry.
Like I said, the code is fine so I'm not really objecting to it.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [v3 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks
[not found] ` <1359482169-26756-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2013-01-29 17:58 ` Stephen Warren
0 siblings, 0 replies; 22+ messages in thread
From: Stephen Warren @ 2013-01-29 17:58 UTC (permalink / raw)
To: Hiroshi Doyu
Cc: linux-tegra-u79uwXL29TY76Z2rM5mHXA,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
On 01/29/2013 10:56 AM, Hiroshi Doyu wrote:
> Presently SMMU registers are located in discontiguous 3 blocks. They
> are interleaved by MC registers. Ideally SMMU register blocks should
> be in an independent one block, but it is too late to change this H/W
> design. In the future Tegra chips over some generations, it is
> expected that some of register block "size" can be extended towards
> the end and also more new register blocks will be added at most a few
> blocks. The starting address of each existing block won't change. This
> patch allocates multiple number of register blocks dynamically based
> on the info passed from DT. Those ranges are verified in the
> accessors{read,write}. This may sacrifice some performance because a
> new accessors prevents compiler optimization of a fixed size register
> offset calculation. Since SMMU register accesses are not so frequent,
> this would be acceptable. This patch is necessary to unify
> "tegra-smmu.ko" over some Tegra SoC generations.
Reviewed-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2013-01-29 17:58 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-01-15 8:17 [PATCH 1/6] iommu/tegra: Rename -i hw{grp,group} to sw{grp,group} Hiroshi Doyu
[not found] ` <1358237848-968-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-15 8:17 ` [PATCH 2/6] iommu/tegra: smmu: Pass swgroup info from DT Hiroshi Doyu
[not found] ` <1358237848-968-2-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-16 21:07 ` Stephen Warren
2013-01-15 8:17 ` [PATCH 3/6] iommu/tegra: smmu: Support variable length of swgroups bitmap Hiroshi Doyu
2013-01-15 8:17 ` [PATCH 4/6] iommu/tegra: smmu: Support variable MMIO range Hiroshi Doyu
[not found] ` <1358237848-968-4-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-16 21:12 ` Stephen Warren
[not found] ` <50F717B8.6050800-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2013-01-18 9:05 ` Hiroshi Doyu
[not found] ` <20130118.110546.1909336134474854222.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-18 16:44 ` Stephen Warren
[not found] ` <50F97BDD.8010502-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2013-01-21 7:36 ` Hiroshi Doyu
[not found] ` <20130121.093603.449745485344660335.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-21 17:04 ` Stephen Warren
[not found] ` <50FD752A.6060706-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2013-01-29 8:34 ` [v2 1/1] iommu/tegra: smmu: Support variable MMIO ranges/blocks Hiroshi Doyu
[not found] ` <1359448450-24894-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-29 17:03 ` Stephen Warren
[not found] ` <510800F7.7020507-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2013-01-29 17:40 ` Hiroshi Doyu
[not found] ` <20130129.194007.2143867447969494923.hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-29 17:57 ` Stephen Warren
2013-01-29 17:56 ` [v3 " Hiroshi Doyu
[not found] ` <1359482169-26756-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-29 17:58 ` Stephen Warren
2013-01-15 8:17 ` [PATCH 5/6] ARM: dt: tegra114: Add AHB entry Hiroshi Doyu
[not found] ` <1358237848-968-5-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-28 19:00 ` Stephen Warren
2013-01-15 8:17 ` [PATCH 6/6] ARM: dt: tegra114: Add SMMU entry Hiroshi Doyu
[not found] ` <1358237848-968-6-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-16 21:17 ` Stephen Warren
2013-01-15 13:22 ` [PATCH 7/6] iommu/tegra: smmu: Add dependency on ARCH_TEGRA_114_SOC Hiroshi Doyu
[not found] ` <1358256149-28700-1-git-send-email-hdoyu-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-01-16 21:18 ` Stephen Warren
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).