Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soc/tegra: cbb: Check firewall before enabling error reporting

To enable error reporting for a fabric to CCPLEX, we need to write its
register for enabling error interrupt to CCPLEX during boot and later
clear the error status register after error occurs. If a fabric's
registers are protected and not accessible from CCPLEX, then accessing
the registers will cause CBB firewall error.

Add support to check whether write access from CCPLEX to the registers
of a fabric is not blocked by it's firewall before enabling error
reporting to CCPLEX for that fabric.

Fixes: fc2f151d2314 ("soc/tegra: cbb: Add driver for Tegra234 CBB 2.0")
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>

authored by

Sumit Gupta and committed by
Thierry Reding
2927cf85 55084947

+81 -2
+81 -2
drivers/soc/tegra/cbb/tegra234-cbb.c
··· 72 72 73 73 #define REQ_SOCKET_ID GENMASK(27, 24) 74 74 75 + #define CCPLEX_MSTRID 0x1 76 + #define FIREWALL_APERTURE_SZ 0x10000 77 + /* Write firewall check enable */ 78 + #define WEN 0x20000 79 + 75 80 enum tegra234_cbb_fabric_ids { 76 81 CBB_FAB_ID, 77 82 SCE_FAB_ID, ··· 97 92 struct tegra234_cbb_fabric { 98 93 const char *name; 99 94 phys_addr_t off_mask_erd; 95 + phys_addr_t firewall_base; 96 + unsigned int firewall_ctl; 97 + unsigned int firewall_wr_ctl; 100 98 const char * const *master_id; 101 99 unsigned int notifier_offset; 102 100 const struct tegra_cbb_error *errors; ··· 136 128 137 129 static LIST_HEAD(cbb_list); 138 130 static DEFINE_SPINLOCK(cbb_lock); 131 + 132 + static bool 133 + tegra234_cbb_write_access_allowed(struct platform_device *pdev, struct tegra234_cbb *cbb) 134 + { 135 + u32 val; 136 + 137 + if (!cbb->fabric->firewall_base || 138 + !cbb->fabric->firewall_ctl || 139 + !cbb->fabric->firewall_wr_ctl) { 140 + dev_info(&pdev->dev, "SoC data missing for firewall\n"); 141 + return false; 142 + } 143 + 144 + if ((cbb->fabric->firewall_ctl > FIREWALL_APERTURE_SZ) || 145 + (cbb->fabric->firewall_wr_ctl > FIREWALL_APERTURE_SZ)) { 146 + dev_err(&pdev->dev, "wrong firewall offset value\n"); 147 + return false; 148 + } 149 + 150 + val = readl(cbb->regs + cbb->fabric->firewall_base + cbb->fabric->firewall_ctl); 151 + /* 152 + * If the firewall check feature for allowing or blocking the 153 + * write accesses through the firewall of a fabric is disabled 154 + * then CCPLEX can write to the registers of that fabric. 155 + */ 156 + if (!(val & WEN)) 157 + return true; 158 + 159 + /* 160 + * If the firewall check is enabled then check whether CCPLEX 161 + * has write access to the fabric's error notifier registers 162 + */ 163 + val = readl(cbb->regs + cbb->fabric->firewall_base + cbb->fabric->firewall_wr_ctl); 164 + if (val & (BIT(CCPLEX_MSTRID))) 165 + return true; 166 + 167 + return false; 168 + } 139 169 140 170 static void tegra234_cbb_fault_enable(struct tegra_cbb *cbb) 141 171 { ··· 597 551 */ 598 552 if (priv->fabric->off_mask_erd) { 599 553 mstr_id = FIELD_GET(USRBITS_MSTR_ID, priv->mn_user_bits); 600 - if (mstr_id == 0x1) 554 + if (mstr_id == CCPLEX_MSTRID) 601 555 is_inband_err = 1; 602 556 } 603 557 } ··· 711 665 .errors = tegra234_cbb_errors, 712 666 .max_errors = ARRAY_SIZE(tegra234_cbb_errors), 713 667 .notifier_offset = 0x17000, 668 + .firewall_base = 0x30000, 669 + .firewall_ctl = 0x8d0, 670 + .firewall_wr_ctl = 0x8c8, 714 671 }; 715 672 716 673 static const struct tegra234_slave_lookup tegra234_bpmp_slave_map[] = { ··· 732 683 .errors = tegra234_cbb_errors, 733 684 .max_errors = ARRAY_SIZE(tegra234_cbb_errors), 734 685 .notifier_offset = 0x19000, 686 + .firewall_base = 0x30000, 687 + .firewall_ctl = 0x8f0, 688 + .firewall_wr_ctl = 0x8e8, 735 689 }; 736 690 737 691 static const struct tegra234_slave_lookup tegra234_cbb_slave_map[] = { ··· 809 757 .errors = tegra234_cbb_errors, 810 758 .max_errors = ARRAY_SIZE(tegra234_cbb_errors), 811 759 .notifier_offset = 0x60000, 812 - .off_mask_erd = 0x3a004 760 + .off_mask_erd = 0x3a004, 761 + .firewall_base = 0x10000, 762 + .firewall_ctl = 0x23f0, 763 + .firewall_wr_ctl = 0x23e8, 813 764 }; 814 765 815 766 static const struct tegra234_slave_lookup tegra234_common_slave_map[] = { ··· 832 777 .errors = tegra234_cbb_errors, 833 778 .max_errors = ARRAY_SIZE(tegra234_cbb_errors), 834 779 .notifier_offset = 0x19000, 780 + .firewall_base = 0x30000, 781 + .firewall_ctl = 0x290, 782 + .firewall_wr_ctl = 0x288, 835 783 }; 836 784 837 785 static const struct tegra234_cbb_fabric tegra234_rce_fabric = { ··· 845 787 .errors = tegra234_cbb_errors, 846 788 .max_errors = ARRAY_SIZE(tegra234_cbb_errors), 847 789 .notifier_offset = 0x19000, 790 + .firewall_base = 0x30000, 791 + .firewall_ctl = 0x290, 792 + .firewall_wr_ctl = 0x288, 848 793 }; 849 794 850 795 static const struct tegra234_cbb_fabric tegra234_sce_fabric = { ··· 858 797 .errors = tegra234_cbb_errors, 859 798 .max_errors = ARRAY_SIZE(tegra234_cbb_errors), 860 799 .notifier_offset = 0x19000, 800 + .firewall_base = 0x30000, 801 + .firewall_ctl = 0x290, 802 + .firewall_wr_ctl = 0x288, 861 803 }; 862 804 863 805 static const char * const tegra241_master_id[] = { ··· 1043 979 .max_errors = ARRAY_SIZE(tegra241_cbb_errors), 1044 980 .notifier_offset = 0x60000, 1045 981 .off_mask_erd = 0x40004, 982 + .firewall_base = 0x20000, 983 + .firewall_ctl = 0x2370, 984 + .firewall_wr_ctl = 0x2368, 1046 985 }; 1047 986 1048 987 static const struct tegra234_slave_lookup tegra241_bpmp_slave_map[] = { ··· 1067 1000 .errors = tegra241_cbb_errors, 1068 1001 .max_errors = ARRAY_SIZE(tegra241_cbb_errors), 1069 1002 .notifier_offset = 0x19000, 1003 + .firewall_base = 0x30000, 1004 + .firewall_ctl = 0x8f0, 1005 + .firewall_wr_ctl = 0x8e8, 1070 1006 }; 1071 1007 1072 1008 static const struct of_device_id tegra234_cbb_dt_ids[] = { ··· 1153 1083 return err; 1154 1084 1155 1085 platform_set_drvdata(pdev, cbb); 1086 + 1087 + /* 1088 + * Don't enable error reporting for a Fabric if write to it's registers 1089 + * is blocked by CBB firewall. 1090 + */ 1091 + if (!tegra234_cbb_write_access_allowed(pdev, cbb)) { 1092 + dev_info(&pdev->dev, "error reporting not enabled due to firewall\n"); 1093 + return 0; 1094 + } 1156 1095 1157 1096 spin_lock_irqsave(&cbb_lock, flags); 1158 1097 list_add(&cbb->base.node, &cbb_list);