Skip to content

Commit 393d66f

Browse files
thierryredingkrzk
authored andcommitted
memory: tegra: Implement SID override programming
Instead of programming all SID overrides during early boot, perform the operation on-demand after the SMMU translations have been set up for a device. This reuses data from device tree to match memory clients for a device and programs the SID specified in device tree, which corresponds to the SID used for the SMMU context banks for the device. Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://lore.kernel.org/r/20210603164632.1000458-2-thierry.reding@gmail.com Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
1 parent 8fd9f63 commit 393d66f

3 files changed

Lines changed: 84 additions & 0 deletions

File tree

drivers/memory/tegra/mc.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,15 @@ struct tegra_mc *devm_tegra_memory_controller_get(struct device *dev)
9797
}
9898
EXPORT_SYMBOL_GPL(devm_tegra_memory_controller_get);
9999

100+
int tegra_mc_probe_device(struct tegra_mc *mc, struct device *dev)
101+
{
102+
if (mc->soc->ops && mc->soc->ops->probe_device)
103+
return mc->soc->ops->probe_device(mc, dev);
104+
105+
return 0;
106+
}
107+
EXPORT_SYMBOL_GPL(tegra_mc_probe_device);
108+
100109
static int tegra_mc_block_dma_common(struct tegra_mc *mc,
101110
const struct tegra_mc_reset *rst)
102111
{

drivers/memory/tegra/tegra186.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
#include <linux/io.h>
7+
#include <linux/iommu.h>
78
#include <linux/module.h>
89
#include <linux/mod_devicetable.h>
910
#include <linux/of_device.h>
@@ -15,6 +16,10 @@
1516
#include <dt-bindings/memory/tegra186-mc.h>
1617
#endif
1718

19+
#define MC_SID_STREAMID_OVERRIDE_MASK GENMASK(7, 0)
20+
#define MC_SID_STREAMID_SECURITY_WRITE_ACCESS_DISABLED BIT(16)
21+
#define MC_SID_STREAMID_SECURITY_OVERRIDE BIT(8)
22+
1823
static void tegra186_mc_program_sid(struct tegra_mc *mc)
1924
{
2025
unsigned int i;
@@ -66,10 +71,77 @@ static int tegra186_mc_resume(struct tegra_mc *mc)
6671
return 0;
6772
}
6873

74+
static void tegra186_mc_client_sid_override(struct tegra_mc *mc,
75+
const struct tegra_mc_client *client,
76+
unsigned int sid)
77+
{
78+
u32 value, old;
79+
80+
value = readl(mc->regs + client->regs.sid.security);
81+
if ((value & MC_SID_STREAMID_SECURITY_OVERRIDE) == 0) {
82+
/*
83+
* If the secure firmware has locked this down the override
84+
* for this memory client, there's nothing we can do here.
85+
*/
86+
if (value & MC_SID_STREAMID_SECURITY_WRITE_ACCESS_DISABLED)
87+
return;
88+
89+
/*
90+
* Otherwise, try to set the override itself. Typically the
91+
* secure firmware will never have set this configuration.
92+
* Instead, it will either have disabled write access to
93+
* this field, or it will already have set an explicit
94+
* override itself.
95+
*/
96+
WARN_ON((value & MC_SID_STREAMID_SECURITY_OVERRIDE) == 0);
97+
98+
value |= MC_SID_STREAMID_SECURITY_OVERRIDE;
99+
writel(value, mc->regs + client->regs.sid.security);
100+
}
101+
102+
value = readl(mc->regs + client->regs.sid.override);
103+
old = value & MC_SID_STREAMID_OVERRIDE_MASK;
104+
105+
if (old != sid) {
106+
dev_dbg(mc->dev, "overriding SID %x for %s with %x\n", old,
107+
client->name, sid);
108+
writel(sid, mc->regs + client->regs.sid.override);
109+
}
110+
}
111+
112+
static int tegra186_mc_probe_device(struct tegra_mc *mc, struct device *dev)
113+
{
114+
#if IS_ENABLED(CONFIG_IOMMU_API)
115+
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
116+
struct of_phandle_args args;
117+
unsigned int i, index = 0;
118+
119+
while (!of_parse_phandle_with_args(dev->of_node, "interconnects", "#interconnect-cells",
120+
index, &args)) {
121+
if (args.np == mc->dev->of_node && args.args_count != 0) {
122+
for (i = 0; i < mc->soc->num_clients; i++) {
123+
const struct tegra_mc_client *client = &mc->soc->clients[i];
124+
125+
if (client->id == args.args[0]) {
126+
u32 sid = fwspec->ids[0] & MC_SID_STREAMID_OVERRIDE_MASK;
127+
128+
tegra186_mc_client_sid_override(mc, client, sid);
129+
}
130+
}
131+
}
132+
133+
index++;
134+
}
135+
#endif
136+
137+
return 0;
138+
}
139+
69140
const struct tegra_mc_ops tegra186_mc_ops = {
70141
.probe = tegra186_mc_probe,
71142
.remove = tegra186_mc_remove,
72143
.resume = tegra186_mc_resume,
144+
.probe_device = tegra186_mc_probe_device,
73145
};
74146

75147
#if defined(CONFIG_ARCH_TEGRA_186_SOC)

include/soc/tegra/mc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ struct tegra_mc_ops {
180180
int (*suspend)(struct tegra_mc *mc);
181181
int (*resume)(struct tegra_mc *mc);
182182
irqreturn_t (*handle_irq)(int irq, void *data);
183+
int (*probe_device)(struct tegra_mc *mc, struct device *dev);
183184
};
184185

185186
struct tegra_mc_soc {
@@ -244,4 +245,6 @@ devm_tegra_memory_controller_get(struct device *dev)
244245
}
245246
#endif
246247

248+
int tegra_mc_probe_device(struct tegra_mc *mc, struct device *dev);
249+
247250
#endif /* __SOC_TEGRA_MC_H__ */

0 commit comments

Comments
 (0)