diff options
Diffstat (limited to 'drivers/soc/tegra/cbb')
-rw-r--r-- | drivers/soc/tegra/cbb/tegra-cbb.c | 13 | ||||
-rw-r--r-- | drivers/soc/tegra/cbb/tegra194-cbb.c | 18 | ||||
-rw-r--r-- | drivers/soc/tegra/cbb/tegra234-cbb.c | 170 |
3 files changed, 148 insertions, 53 deletions
diff --git a/drivers/soc/tegra/cbb/tegra-cbb.c b/drivers/soc/tegra/cbb/tegra-cbb.c index d200937353c7..a8566b9dd8de 100644 --- a/drivers/soc/tegra/cbb/tegra-cbb.c +++ b/drivers/soc/tegra/cbb/tegra-cbb.c @@ -72,18 +72,7 @@ static int tegra_cbb_err_show(struct seq_file *file, void *data) return cbb->ops->debugfs_show(cbb, file, data); } - -static int tegra_cbb_err_open(struct inode *inode, struct file *file) -{ - return single_open(file, tegra_cbb_err_show, inode->i_private); -} - -static const struct file_operations tegra_cbb_err_fops = { - .open = tegra_cbb_err_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release -}; +DEFINE_SHOW_ATTRIBUTE(tegra_cbb_err); static int tegra_cbb_err_debugfs_init(struct tegra_cbb *cbb) { diff --git a/drivers/soc/tegra/cbb/tegra194-cbb.c b/drivers/soc/tegra/cbb/tegra194-cbb.c index 1ae0bd9a1ac1..d4112b683f00 100644 --- a/drivers/soc/tegra/cbb/tegra194-cbb.c +++ b/drivers/soc/tegra/cbb/tegra194-cbb.c @@ -102,8 +102,6 @@ #define CLUSTER_NOC_VQC GENMASK(17, 16) #define CLUSTER_NOC_MSTR_ID GENMASK(21, 18) -#define USRBITS_MSTR_ID GENMASK(21, 18) - #define CBB_ERR_OPC GENMASK(4, 1) #define CBB_ERR_ERRCODE GENMASK(10, 8) #define CBB_ERR_LEN1 GENMASK(27, 16) @@ -2038,15 +2036,17 @@ static irqreturn_t tegra194_cbb_err_isr(int irq, void *data) smp_processor_id(), priv->noc->name, priv->res->start, irq); - mstr_id = FIELD_GET(USRBITS_MSTR_ID, priv->errlog5) - 1; is_fatal = print_errlog(NULL, priv, status); /* - * If illegal request is from CCPLEX(0x1) - * initiator then call BUG() to crash system. + * If illegal request is from CCPLEX(0x1) initiator + * and error is fatal then call BUG() to crash system. */ - if ((mstr_id == 0x1) && priv->noc->erd_mask_inband_err) - is_inband_err = 1; + if (priv->noc->erd_mask_inband_err) { + mstr_id = FIELD_GET(CBB_NOC_MSTR_ID, priv->errlog5); + if (mstr_id == 0x1) + is_inband_err = 1; + } } } @@ -2226,10 +2226,8 @@ static int tegra194_cbb_get_bridges(struct tegra194_cbb *cbb, struct device_node cbb->bridges[i].base = devm_ioremap_resource(cbb->base.dev, &cbb->bridges[i].res); - if (IS_ERR(cbb->bridges[i].base)) { - dev_err(cbb->base.dev, "failed to map AXI2APB range\n"); + if (IS_ERR(cbb->bridges[i].base)) return PTR_ERR(cbb->bridges[i].base); - } } } diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c index 3528f9e15d5c..f33d094e5ea6 100644 --- a/drivers/soc/tegra/cbb/tegra234-cbb.c +++ b/drivers/soc/tegra/cbb/tegra234-cbb.c @@ -72,6 +72,11 @@ #define REQ_SOCKET_ID GENMASK(27, 24) +#define CCPLEX_MSTRID 0x1 +#define FIREWALL_APERTURE_SZ 0x10000 +/* Write firewall check enable */ +#define WEN 0x20000 + enum tegra234_cbb_fabric_ids { CBB_FAB_ID, SCE_FAB_ID, @@ -92,11 +97,15 @@ struct tegra234_slave_lookup { struct tegra234_cbb_fabric { const char *name; phys_addr_t off_mask_erd; - bool erd_mask_inband_err; + phys_addr_t firewall_base; + unsigned int firewall_ctl; + unsigned int firewall_wr_ctl; const char * const *master_id; unsigned int notifier_offset; const struct tegra_cbb_error *errors; + const int max_errors; const struct tegra234_slave_lookup *slave_map; + const int max_slaves; }; struct tegra234_cbb { @@ -128,6 +137,44 @@ static inline struct tegra234_cbb *to_tegra234_cbb(struct tegra_cbb *cbb) static LIST_HEAD(cbb_list); static DEFINE_SPINLOCK(cbb_lock); +static bool +tegra234_cbb_write_access_allowed(struct platform_device *pdev, struct tegra234_cbb *cbb) +{ + u32 val; + + if (!cbb->fabric->firewall_base || + !cbb->fabric->firewall_ctl || + !cbb->fabric->firewall_wr_ctl) { + dev_info(&pdev->dev, "SoC data missing for firewall\n"); + return false; + } + + if ((cbb->fabric->firewall_ctl > FIREWALL_APERTURE_SZ) || + (cbb->fabric->firewall_wr_ctl > FIREWALL_APERTURE_SZ)) { + dev_err(&pdev->dev, "wrong firewall offset value\n"); + return false; + } + + val = readl(cbb->regs + cbb->fabric->firewall_base + cbb->fabric->firewall_ctl); + /* + * If the firewall check feature for allowing or blocking the + * write accesses through the firewall of a fabric is disabled + * then CCPLEX can write to the registers of that fabric. + */ + if (!(val & WEN)) + return true; + + /* + * If the firewall check is enabled then check whether CCPLEX + * has write access to the fabric's error notifier registers + */ + val = readl(cbb->regs + cbb->fabric->firewall_base + cbb->fabric->firewall_wr_ctl); + if (val & (BIT(CCPLEX_MSTRID))) + return true; + + return false; +} + static void tegra234_cbb_fault_enable(struct tegra_cbb *cbb) { struct tegra234_cbb *priv = to_tegra234_cbb(cbb); @@ -271,6 +318,12 @@ static void tegra234_cbb_print_error(struct seq_file *file, struct tegra234_cbb tegra_cbb_print_err(file, "\t Multiple type of errors reported\n"); while (status) { + if (type >= cbb->fabric->max_errors) { + tegra_cbb_print_err(file, "\t Wrong type index:%u, status:%u\n", + type, status); + return; + } + if (status & 0x1) tegra_cbb_print_err(file, "\t Error Code\t\t: %s\n", cbb->fabric->errors[type].code); @@ -282,6 +335,12 @@ static void tegra234_cbb_print_error(struct seq_file *file, struct tegra234_cbb type = 0; while (overflow) { + if (type >= cbb->fabric->max_errors) { + tegra_cbb_print_err(file, "\t Wrong type index:%u, overflow:%u\n", + type, overflow); + return; + } + if (overflow & 0x1) tegra_cbb_print_err(file, "\t Overflow\t\t: Multiple %s\n", cbb->fabric->errors[type].code); @@ -334,8 +393,11 @@ static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb) access_type = FIELD_GET(FAB_EM_EL_ACCESSTYPE, cbb->mn_attr0); tegra_cbb_print_err(file, "\n"); - tegra_cbb_print_err(file, "\t Error Code\t\t: %s\n", - cbb->fabric->errors[cbb->type].code); + if (cbb->type < cbb->fabric->max_errors) + tegra_cbb_print_err(file, "\t Error Code\t\t: %s\n", + cbb->fabric->errors[cbb->type].code); + else + tegra_cbb_print_err(file, "\t Wrong type index:%u\n", cbb->type); tegra_cbb_print_err(file, "\t MASTER_ID\t\t: %s\n", cbb->fabric->master_id[mstr_id]); tegra_cbb_print_err(file, "\t Address\t\t: %#llx\n", cbb->access); @@ -374,6 +436,11 @@ static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb) if ((fab_id == PSC_FAB_ID) || (fab_id == FSI_FAB_ID)) return; + if (slave_id >= cbb->fabric->max_slaves) { + tegra_cbb_print_err(file, "\t Invalid slave_id:%d\n", slave_id); + return; + } + if (!strcmp(cbb->fabric->errors[cbb->type].code, "TIMEOUT_ERR")) { tegra234_lookup_slave_timeout(file, cbb, slave_id, fab_id); return; @@ -517,7 +584,7 @@ static irqreturn_t tegra234_cbb_isr(int irq, void *data) u32 status = tegra_cbb_get_status(cbb); if (status && (irq == priv->sec_irq)) { - tegra_cbb_print_err(NULL, "CPU:%d, Error: %s@%llx, irq=%d\n", + tegra_cbb_print_err(NULL, "CPU:%d, Error: %s@0x%llx, irq=%d\n", smp_processor_id(), priv->fabric->name, priv->res->start, irq); @@ -525,14 +592,14 @@ static irqreturn_t tegra234_cbb_isr(int irq, void *data) if (err) goto unlock; - mstr_id = FIELD_GET(USRBITS_MSTR_ID, priv->mn_user_bits); - /* - * If illegal request is from CCPLEX(id:0x1) master then call BUG() to - * crash system. + * If illegal request is from CCPLEX(id:0x1) master then call WARN() */ - if ((mstr_id == 0x1) && priv->fabric->off_mask_erd) - is_inband_err = 1; + if (priv->fabric->off_mask_erd) { + mstr_id = FIELD_GET(USRBITS_MSTR_ID, priv->mn_user_bits); + if (mstr_id == CCPLEX_MSTRID) + is_inband_err = 1; + } } } @@ -640,8 +707,13 @@ static const struct tegra234_cbb_fabric tegra234_aon_fabric = { .name = "aon-fabric", .master_id = tegra234_master_id, .slave_map = tegra234_aon_slave_map, + .max_slaves = ARRAY_SIZE(tegra234_aon_slave_map), .errors = tegra234_cbb_errors, + .max_errors = ARRAY_SIZE(tegra234_cbb_errors), .notifier_offset = 0x17000, + .firewall_base = 0x30000, + .firewall_ctl = 0x8d0, + .firewall_wr_ctl = 0x8c8, }; static const struct tegra234_slave_lookup tegra234_bpmp_slave_map[] = { @@ -656,8 +728,13 @@ static const struct tegra234_cbb_fabric tegra234_bpmp_fabric = { .name = "bpmp-fabric", .master_id = tegra234_master_id, .slave_map = tegra234_bpmp_slave_map, + .max_slaves = ARRAY_SIZE(tegra234_bpmp_slave_map), .errors = tegra234_cbb_errors, + .max_errors = ARRAY_SIZE(tegra234_cbb_errors), .notifier_offset = 0x19000, + .firewall_base = 0x30000, + .firewall_ctl = 0x8f0, + .firewall_wr_ctl = 0x8e8, }; static const struct tegra234_slave_lookup tegra234_cbb_slave_map[] = { @@ -728,55 +805,62 @@ static const struct tegra234_cbb_fabric tegra234_cbb_fabric = { .name = "cbb-fabric", .master_id = tegra234_master_id, .slave_map = tegra234_cbb_slave_map, + .max_slaves = ARRAY_SIZE(tegra234_cbb_slave_map), .errors = tegra234_cbb_errors, + .max_errors = ARRAY_SIZE(tegra234_cbb_errors), .notifier_offset = 0x60000, - .off_mask_erd = 0x3a004 + .off_mask_erd = 0x3a004, + .firewall_base = 0x10000, + .firewall_ctl = 0x23f0, + .firewall_wr_ctl = 0x23e8, }; -static const struct tegra234_slave_lookup tegra234_dce_slave_map[] = { +static const struct tegra234_slave_lookup tegra234_common_slave_map[] = { { "AXI2APB", 0x00000 }, { "AST0", 0x15000 }, { "AST1", 0x16000 }, + { "CBB", 0x17000 }, + { "RSVD", 0x00000 }, { "CPU", 0x18000 }, }; static const struct tegra234_cbb_fabric tegra234_dce_fabric = { .name = "dce-fabric", .master_id = tegra234_master_id, - .slave_map = tegra234_dce_slave_map, + .slave_map = tegra234_common_slave_map, + .max_slaves = ARRAY_SIZE(tegra234_common_slave_map), .errors = tegra234_cbb_errors, + .max_errors = ARRAY_SIZE(tegra234_cbb_errors), .notifier_offset = 0x19000, -}; - -static const struct tegra234_slave_lookup tegra234_rce_slave_map[] = { - { "AXI2APB", 0x00000 }, - { "AST0", 0x15000 }, - { "AST1", 0x16000 }, - { "CPU", 0x18000 }, + .firewall_base = 0x30000, + .firewall_ctl = 0x290, + .firewall_wr_ctl = 0x288, }; static const struct tegra234_cbb_fabric tegra234_rce_fabric = { .name = "rce-fabric", .master_id = tegra234_master_id, - .slave_map = tegra234_rce_slave_map, + .slave_map = tegra234_common_slave_map, + .max_slaves = ARRAY_SIZE(tegra234_common_slave_map), .errors = tegra234_cbb_errors, + .max_errors = ARRAY_SIZE(tegra234_cbb_errors), .notifier_offset = 0x19000, -}; - -static const struct tegra234_slave_lookup tegra234_sce_slave_map[] = { - { "AXI2APB", 0x00000 }, - { "AST0", 0x15000 }, - { "AST1", 0x16000 }, - { "CBB", 0x17000 }, - { "CPU", 0x18000 }, + .firewall_base = 0x30000, + .firewall_ctl = 0x290, + .firewall_wr_ctl = 0x288, }; static const struct tegra234_cbb_fabric tegra234_sce_fabric = { .name = "sce-fabric", .master_id = tegra234_master_id, - .slave_map = tegra234_sce_slave_map, + .slave_map = tegra234_common_slave_map, + .max_slaves = ARRAY_SIZE(tegra234_common_slave_map), .errors = tegra234_cbb_errors, + .max_errors = ARRAY_SIZE(tegra234_cbb_errors), .notifier_offset = 0x19000, + .firewall_base = 0x30000, + .firewall_ctl = 0x290, + .firewall_wr_ctl = 0x288, }; static const char * const tegra241_master_id[] = { @@ -889,7 +973,7 @@ static const struct tegra_cbb_error tegra241_cbb_errors[] = { }; static const struct tegra234_slave_lookup tegra241_cbb_slave_map[] = { - { "CCPLEX", 0x50000 }, + { "RSVD", 0x00000 }, { "PCIE_C8", 0x51000 }, { "PCIE_C9", 0x52000 }, { "RSVD", 0x00000 }, @@ -942,22 +1026,32 @@ static const struct tegra234_slave_lookup tegra241_cbb_slave_map[] = { { "PCIE_C3", 0x58000 }, { "PCIE_C0", 0x59000 }, { "PCIE_C1", 0x5a000 }, + { "CCPLEX", 0x50000 }, { "AXI2APB_29", 0x85000 }, { "AXI2APB_30", 0x86000 }, + { "CBB_CENTRAL", 0x00000 }, + { "AXI2APB_31", 0x8E000 }, + { "AXI2APB_32", 0x8F000 }, }; static const struct tegra234_cbb_fabric tegra241_cbb_fabric = { .name = "cbb-fabric", .master_id = tegra241_master_id, .slave_map = tegra241_cbb_slave_map, + .max_slaves = ARRAY_SIZE(tegra241_cbb_slave_map), .errors = tegra241_cbb_errors, + .max_errors = ARRAY_SIZE(tegra241_cbb_errors), .notifier_offset = 0x60000, .off_mask_erd = 0x40004, + .firewall_base = 0x20000, + .firewall_ctl = 0x2370, + .firewall_wr_ctl = 0x2368, }; static const struct tegra234_slave_lookup tegra241_bpmp_slave_map[] = { { "RSVD", 0x00000 }, { "RSVD", 0x00000 }, + { "RSVD", 0x00000 }, { "CBB", 0x15000 }, { "CPU", 0x16000 }, { "AXI2APB", 0x00000 }, @@ -969,8 +1063,13 @@ static const struct tegra234_cbb_fabric tegra241_bpmp_fabric = { .name = "bpmp-fabric", .master_id = tegra241_master_id, .slave_map = tegra241_bpmp_slave_map, + .max_slaves = ARRAY_SIZE(tegra241_bpmp_slave_map), .errors = tegra241_cbb_errors, + .max_errors = ARRAY_SIZE(tegra241_cbb_errors), .notifier_offset = 0x19000, + .firewall_base = 0x30000, + .firewall_ctl = 0x8f0, + .firewall_wr_ctl = 0x8e8, }; static const struct of_device_id tegra234_cbb_dt_ids[] = { @@ -1055,6 +1154,15 @@ static int tegra234_cbb_probe(struct platform_device *pdev) platform_set_drvdata(pdev, cbb); + /* + * Don't enable error reporting for a Fabric if write to it's registers + * is blocked by CBB firewall. + */ + if (!tegra234_cbb_write_access_allowed(pdev, cbb)) { + dev_info(&pdev->dev, "error reporting not enabled due to firewall\n"); + return 0; + } + spin_lock_irqsave(&cbb_lock, flags); list_add(&cbb->base.node, &cbb_list); spin_unlock_irqrestore(&cbb_lock, flags); |