When a fabric receives an error interrupt, the error may have
occurred on a different fabric. The target timeout lookup was using
the wrong base address (cbb->regs) with offsets from a different
fabric's target map, causing a kernel page fault.
Unable to handle kernel paging request at virtual address ffff80000954cc00
pc : tegra234_cbb_get_tmo_slv+0xc/0x28
Call trace:
tegra234_cbb_get_tmo_slv+0xc/0x28
print_err_notifier+0x6c0/0x7d0
tegra234_cbb_isr+0xe4/0x1b4
Add tegra234_cbb_get_fabric() to look up the correct fabric device
using fab_id, and use its base address for accessing target timeout
registers.
Fixes: 25de5c8fe0801 ("soc/tegra: cbb: Improve handling for per SoC fabric data")
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
---
drivers/soc/tegra/cbb/tegra234-cbb.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c
index 626e0e820329..7e387fc54c6b 100644
--- a/drivers/soc/tegra/cbb/tegra234-cbb.c
+++ b/drivers/soc/tegra/cbb/tegra234-cbb.c
@@ -313,12 +313,37 @@ static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *target
}
}
+static struct tegra234_cbb *tegra234_cbb_get_fabric(u8 fab_id)
+{
+ struct tegra_cbb *entry;
+
+ list_for_each_entry(entry, &cbb_list, node) {
+ struct tegra234_cbb *priv = to_tegra234_cbb(entry);
+
+ if (priv->fabric->fab_id == fab_id)
+ return priv;
+ }
+
+ return NULL;
+}
+
static void tegra234_sw_lookup_target_timeout(struct seq_file *file, struct tegra234_cbb *cbb,
u8 target_id, u8 fab_id)
{
const struct tegra234_target_lookup *map = cbb->fabric->fab_list[fab_id].target_map;
+ struct tegra234_cbb *target_cbb = NULL;
void __iomem *addr;
+ if (fab_id == cbb->fabric->fab_id)
+ target_cbb = cbb;
+ else
+ target_cbb = tegra234_cbb_get_fabric(fab_id);
+
+ if (!target_cbb) {
+ dev_err(cbb->base.dev, "could not find fabric for fab_id:%d\n", fab_id);
+ return;
+ }
+
if (target_id >= cbb->fabric->fab_list[fab_id].max_targets) {
tegra_cbb_print_err(file, "\t Invalid target_id:%d\n", target_id);
return;
@@ -341,7 +366,7 @@ static void tegra234_sw_lookup_target_timeout(struct seq_file *file, struct tegr
* e) Goto step-a till all bits are set.
*/
- addr = cbb->regs + map[target_id].offset;
+ addr = target_cbb->regs + map[target_id].offset;
if (strstr(map[target_id].name, "AXI2APB")) {
addr += APB_BLOCK_TMO_STATUS_0;
--
2.34.1