diff options
author | Andy Gross <andy.gross@linaro.org> | 2018-09-30 13:44:33 -0400 |
---|---|---|
committer | Andy Gross <andy.gross@linaro.org> | 2018-09-30 13:44:33 -0400 |
commit | 579fde69dc1467a033ff44ced75ff368b9d3d072 (patch) | |
tree | 590e07ada6c72f4d8e1acbd6ddb8ca4a1c9f50fe | |
parent | bbd4b28bb8f65fc7347202f32ac82901201ac02f (diff) | |
parent | bb85ce5122487b2b1de1b48b557c5fdf9828dc6e (diff) |
Merge branch 'drivers-for-4.20' into drivers-for-4.20-final
-rw-r--r-- | Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt | 19 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/firmware/qcom,scm.txt | 33 | ||||
-rw-r--r-- | MAINTAINERS | 8 | ||||
-rw-r--r-- | drivers/edac/Kconfig | 14 | ||||
-rw-r--r-- | drivers/edac/Makefile | 1 | ||||
-rw-r--r-- | drivers/edac/qcom_edac.c | 414 | ||||
-rw-r--r-- | drivers/firmware/qcom_scm.c | 74 | ||||
-rw-r--r-- | drivers/soc/qcom/Kconfig | 21 | ||||
-rw-r--r-- | drivers/soc/qcom/apr.c | 6 | ||||
-rw-r--r-- | drivers/soc/qcom/llcc-slice.c | 74 | ||||
-rw-r--r-- | drivers/soc/qcom/rmtfs_mem.c | 5 | ||||
-rw-r--r-- | drivers/soc/qcom/rpmh-rsc.c | 2 | ||||
-rw-r--r-- | drivers/soc/qcom/smem.c | 174 | ||||
-rw-r--r-- | drivers/soc/qcom/spm.c | 3 | ||||
-rw-r--r-- | drivers/soc/qcom/wcnss_ctrl.c | 2 | ||||
-rw-r--r-- | include/linux/soc/qcom/llcc-qcom.h | 30 |
16 files changed, 704 insertions, 176 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt index 5e85749262ae..eaee06b2d8f2 100644 --- a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt +++ b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt | |||
@@ -16,11 +16,26 @@ Properties: | |||
16 | - reg: | 16 | - reg: |
17 | Usage: required | 17 | Usage: required |
18 | Value Type: <prop-encoded-array> | 18 | Value Type: <prop-encoded-array> |
19 | Definition: Start address and the the size of the register region. | 19 | Definition: The first element specifies the llcc base start address and |
20 | the size of the register region. The second element specifies | ||
21 | the llcc broadcast base address and size of the register region. | ||
22 | |||
23 | - reg-names: | ||
24 | Usage: required | ||
25 | Value Type: <stringlist> | ||
26 | Definition: Register region names. Must be "llcc_base", "llcc_broadcast_base". | ||
27 | |||
28 | - interrupts: | ||
29 | Usage: required | ||
30 | Definition: The interrupt is associated with the llcc edac device. | ||
31 | It's used for llcc cache single and double bit error detection | ||
32 | and reporting. | ||
20 | 33 | ||
21 | Example: | 34 | Example: |
22 | 35 | ||
23 | cache-controller@1100000 { | 36 | cache-controller@1100000 { |
24 | compatible = "qcom,sdm845-llcc"; | 37 | compatible = "qcom,sdm845-llcc"; |
25 | reg = <0x1100000 0x250000>; | 38 | reg = <0x1100000 0x200000>, <0x1300000 0x50000> ; |
39 | reg-names = "llcc_base", "llcc_broadcast_base"; | ||
40 | interrupts = <GIC_SPI 582 IRQ_TYPE_LEVEL_HIGH>; | ||
26 | }; | 41 | }; |
diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.txt b/Documentation/devicetree/bindings/firmware/qcom,scm.txt index fcf6979c0b6d..41f133a4e2fa 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.txt +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.txt | |||
@@ -7,16 +7,23 @@ assorted actions. | |||
7 | 7 | ||
8 | Required properties: | 8 | Required properties: |
9 | - compatible: must contain one of the following: | 9 | - compatible: must contain one of the following: |
10 | * "qcom,scm-apq8064" for APQ8064 platforms | 10 | * "qcom,scm-apq8064" |
11 | * "qcom,scm-msm8660" for MSM8660 platforms | 11 | * "qcom,scm-apq8084" |
12 | * "qcom,scm-msm8690" for MSM8690 platforms | 12 | * "qcom,scm-msm8660" |
13 | * "qcom,scm-msm8996" for MSM8996 platforms | 13 | * "qcom,scm-msm8916" |
14 | * "qcom,scm-ipq4019" for IPQ4019 platforms | 14 | * "qcom,scm-msm8960" |
15 | * "qcom,scm" for later processors (MSM8916, APQ8084, MSM8974, etc) | 15 | * "qcom,scm-msm8974" |
16 | - clocks: One to three clocks may be required based on compatible. | 16 | * "qcom,scm-msm8996" |
17 | * No clock required for "qcom,scm-msm8996", "qcom,scm-ipq4019" | 17 | * "qcom,scm-msm8998" |
18 | * Only core clock required for "qcom,scm-apq8064", "qcom,scm-msm8660", and "qcom,scm-msm8960" | 18 | * "qcom,scm-ipq4019" |
19 | * Core, iface, and bus clocks required for "qcom,scm" | 19 | * "qcom,scm-sdm845" |
20 | and: | ||
21 | * "qcom,scm" | ||
22 | - clocks: Specifies clocks needed by the SCM interface, if any: | ||
23 | * core clock required for "qcom,scm-apq8064", "qcom,scm-msm8660" and | ||
24 | "qcom,scm-msm8960" | ||
25 | * core, iface and bus clocks required for "qcom,scm-apq8084", | ||
26 | "qcom,scm-msm8916" and "qcom,scm-msm8974" | ||
20 | - clock-names: Must contain "core" for the core clock, "iface" for the interface | 27 | - clock-names: Must contain "core" for the core clock, "iface" for the interface |
21 | clock and "bus" for the bus clock per the requirements of the compatible. | 28 | clock and "bus" for the bus clock per the requirements of the compatible. |
22 | - qcom,dload-mode: phandle to the TCSR hardware block and offset of the | 29 | - qcom,dload-mode: phandle to the TCSR hardware block and offset of the |
@@ -26,8 +33,10 @@ Example for MSM8916: | |||
26 | 33 | ||
27 | firmware { | 34 | firmware { |
28 | scm { | 35 | scm { |
29 | compatible = "qcom,scm"; | 36 | compatible = "qcom,msm8916", "qcom,scm"; |
30 | clocks = <&gcc GCC_CRYPTO_CLK> , <&gcc GCC_CRYPTO_AXI_CLK>, <&gcc GCC_CRYPTO_AHB_CLK>; | 37 | clocks = <&gcc GCC_CRYPTO_CLK> , |
38 | <&gcc GCC_CRYPTO_AXI_CLK>, | ||
39 | <&gcc GCC_CRYPTO_AHB_CLK>; | ||
31 | clock-names = "core", "bus", "iface"; | 40 | clock-names = "core", "bus", "iface"; |
32 | }; | 41 | }; |
33 | }; | 42 | }; |
diff --git a/MAINTAINERS b/MAINTAINERS index a5b256b25905..f7d7213ca293 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -5346,6 +5346,14 @@ L: linux-edac@vger.kernel.org | |||
5346 | S: Maintained | 5346 | S: Maintained |
5347 | F: drivers/edac/ti_edac.c | 5347 | F: drivers/edac/ti_edac.c |
5348 | 5348 | ||
5349 | EDAC-QCOM | ||
5350 | M: Channagoud Kadabi <ckadabi@codeaurora.org> | ||
5351 | M: Venkata Narendra Kumar Gutta <vnkgutta@codeaurora.org> | ||
5352 | L: linux-arm-msm@vger.kernel.org | ||
5353 | L: linux-edac@vger.kernel.org | ||
5354 | S: Maintained | ||
5355 | F: drivers/edac/qcom_edac.c | ||
5356 | |||
5349 | EDIROL UA-101/UA-1000 DRIVER | 5357 | EDIROL UA-101/UA-1000 DRIVER |
5350 | M: Clemens Ladisch <clemens@ladisch.de> | 5358 | M: Clemens Ladisch <clemens@ladisch.de> |
5351 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) | 5359 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) |
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 57304b2e989f..df9467eef32a 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig | |||
@@ -460,4 +460,18 @@ config EDAC_TI | |||
460 | Support for error detection and correction on the | 460 | Support for error detection and correction on the |
461 | TI SoCs. | 461 | TI SoCs. |
462 | 462 | ||
463 | config EDAC_QCOM | ||
464 | tristate "QCOM EDAC Controller" | ||
465 | depends on ARCH_QCOM && QCOM_LLCC | ||
466 | help | ||
467 | Support for error detection and correction on the | ||
468 | Qualcomm Technologies, Inc. SoCs. | ||
469 | |||
470 | This driver reports Single Bit Errors (SBEs) and Double Bit Errors (DBEs). | ||
471 | As of now, it supports error reporting for Last Level Cache Controller (LLCC) | ||
472 | of Tag RAM and Data RAM. | ||
473 | |||
474 | For debugging issues having to do with stability and overall system | ||
475 | health, you should probably say 'Y' here. | ||
476 | |||
463 | endif # EDAC | 477 | endif # EDAC |
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 02b43a7d8c3e..716096d08ea0 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile | |||
@@ -77,3 +77,4 @@ obj-$(CONFIG_EDAC_ALTERA) += altera_edac.o | |||
77 | obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o | 77 | obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o |
78 | obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o | 78 | obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o |
79 | obj-$(CONFIG_EDAC_TI) += ti_edac.o | 79 | obj-$(CONFIG_EDAC_TI) += ti_edac.o |
80 | obj-$(CONFIG_EDAC_QCOM) += qcom_edac.o | ||
diff --git a/drivers/edac/qcom_edac.c b/drivers/edac/qcom_edac.c new file mode 100644 index 000000000000..82bd775124f2 --- /dev/null +++ b/drivers/edac/qcom_edac.c | |||
@@ -0,0 +1,414 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Copyright (c) 2018, The Linux Foundation. All rights reserved. | ||
4 | */ | ||
5 | |||
6 | #include <linux/edac.h> | ||
7 | #include <linux/interrupt.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/of.h> | ||
10 | #include <linux/platform_device.h> | ||
11 | #include <linux/regmap.h> | ||
12 | #include <linux/soc/qcom/llcc-qcom.h> | ||
13 | |||
14 | #include "edac_mc.h" | ||
15 | #include "edac_device.h" | ||
16 | |||
17 | #define EDAC_LLCC "qcom_llcc" | ||
18 | |||
19 | #define LLCC_ERP_PANIC_ON_UE 1 | ||
20 | |||
21 | #define TRP_SYN_REG_CNT 6 | ||
22 | #define DRP_SYN_REG_CNT 8 | ||
23 | |||
24 | #define LLCC_COMMON_STATUS0 0x0003000c | ||
25 | #define LLCC_LB_CNT_MASK GENMASK(31, 28) | ||
26 | #define LLCC_LB_CNT_SHIFT 28 | ||
27 | |||
28 | /* Single & double bit syndrome register offsets */ | ||
29 | #define TRP_ECC_SB_ERR_SYN0 0x0002304c | ||
30 | #define TRP_ECC_DB_ERR_SYN0 0x00020370 | ||
31 | #define DRP_ECC_SB_ERR_SYN0 0x0004204c | ||
32 | #define DRP_ECC_DB_ERR_SYN0 0x00042070 | ||
33 | |||
34 | /* Error register offsets */ | ||
35 | #define TRP_ECC_ERROR_STATUS1 0x00020348 | ||
36 | #define TRP_ECC_ERROR_STATUS0 0x00020344 | ||
37 | #define DRP_ECC_ERROR_STATUS1 0x00042048 | ||
38 | #define DRP_ECC_ERROR_STATUS0 0x00042044 | ||
39 | |||
40 | /* TRP, DRP interrupt register offsets */ | ||
41 | #define DRP_INTERRUPT_STATUS 0x00041000 | ||
42 | #define TRP_INTERRUPT_0_STATUS 0x00020480 | ||
43 | #define DRP_INTERRUPT_CLEAR 0x00041008 | ||
44 | #define DRP_ECC_ERROR_CNTR_CLEAR 0x00040004 | ||
45 | #define TRP_INTERRUPT_0_CLEAR 0x00020484 | ||
46 | #define TRP_ECC_ERROR_CNTR_CLEAR 0x00020440 | ||
47 | |||
48 | /* Mask and shift macros */ | ||
49 | #define ECC_DB_ERR_COUNT_MASK GENMASK(4, 0) | ||
50 | #define ECC_DB_ERR_WAYS_MASK GENMASK(31, 16) | ||
51 | #define ECC_DB_ERR_WAYS_SHIFT BIT(4) | ||
52 | |||
53 | #define ECC_SB_ERR_COUNT_MASK GENMASK(23, 16) | ||
54 | #define ECC_SB_ERR_COUNT_SHIFT BIT(4) | ||
55 | #define ECC_SB_ERR_WAYS_MASK GENMASK(15, 0) | ||
56 | |||
57 | #define SB_ECC_ERROR BIT(0) | ||
58 | #define DB_ECC_ERROR BIT(1) | ||
59 | |||
60 | #define DRP_TRP_INT_CLEAR GENMASK(1, 0) | ||
61 | #define DRP_TRP_CNT_CLEAR GENMASK(1, 0) | ||
62 | |||
63 | /* Config registers offsets*/ | ||
64 | #define DRP_ECC_ERROR_CFG 0x00040000 | ||
65 | |||
66 | /* Tag RAM, Data RAM interrupt register offsets */ | ||
67 | #define CMN_INTERRUPT_0_ENABLE 0x0003001c | ||
68 | #define CMN_INTERRUPT_2_ENABLE 0x0003003c | ||
69 | #define TRP_INTERRUPT_0_ENABLE 0x00020488 | ||
70 | #define DRP_INTERRUPT_ENABLE 0x0004100c | ||
71 | |||
72 | #define SB_ERROR_THRESHOLD 0x1 | ||
73 | #define SB_ERROR_THRESHOLD_SHIFT 24 | ||
74 | #define SB_DB_TRP_INTERRUPT_ENABLE 0x3 | ||
75 | #define TRP0_INTERRUPT_ENABLE 0x1 | ||
76 | #define DRP0_INTERRUPT_ENABLE BIT(6) | ||
77 | #define SB_DB_DRP_INTERRUPT_ENABLE 0x3 | ||
78 | |||
79 | enum { | ||
80 | LLCC_DRAM_CE = 0, | ||
81 | LLCC_DRAM_UE, | ||
82 | LLCC_TRAM_CE, | ||
83 | LLCC_TRAM_UE, | ||
84 | }; | ||
85 | |||
86 | static const struct llcc_edac_reg_data edac_reg_data[] = { | ||
87 | [LLCC_DRAM_CE] = { | ||
88 | .name = "DRAM Single-bit", | ||
89 | .synd_reg = DRP_ECC_SB_ERR_SYN0, | ||
90 | .count_status_reg = DRP_ECC_ERROR_STATUS1, | ||
91 | .ways_status_reg = DRP_ECC_ERROR_STATUS0, | ||
92 | .reg_cnt = DRP_SYN_REG_CNT, | ||
93 | .count_mask = ECC_SB_ERR_COUNT_MASK, | ||
94 | .ways_mask = ECC_SB_ERR_WAYS_MASK, | ||
95 | .count_shift = ECC_SB_ERR_COUNT_SHIFT, | ||
96 | }, | ||
97 | [LLCC_DRAM_UE] = { | ||
98 | .name = "DRAM Double-bit", | ||
99 | .synd_reg = DRP_ECC_DB_ERR_SYN0, | ||
100 | .count_status_reg = DRP_ECC_ERROR_STATUS1, | ||
101 | .ways_status_reg = DRP_ECC_ERROR_STATUS0, | ||
102 | .reg_cnt = DRP_SYN_REG_CNT, | ||
103 | .count_mask = ECC_DB_ERR_COUNT_MASK, | ||
104 | .ways_mask = ECC_DB_ERR_WAYS_MASK, | ||
105 | .ways_shift = ECC_DB_ERR_WAYS_SHIFT, | ||
106 | }, | ||
107 | [LLCC_TRAM_CE] = { | ||
108 | .name = "TRAM Single-bit", | ||
109 | .synd_reg = TRP_ECC_SB_ERR_SYN0, | ||
110 | .count_status_reg = TRP_ECC_ERROR_STATUS1, | ||
111 | .ways_status_reg = TRP_ECC_ERROR_STATUS0, | ||
112 | .reg_cnt = TRP_SYN_REG_CNT, | ||
113 | .count_mask = ECC_SB_ERR_COUNT_MASK, | ||
114 | .ways_mask = ECC_SB_ERR_WAYS_MASK, | ||
115 | .count_shift = ECC_SB_ERR_COUNT_SHIFT, | ||
116 | }, | ||
117 | [LLCC_TRAM_UE] = { | ||
118 | .name = "TRAM Double-bit", | ||
119 | .synd_reg = TRP_ECC_DB_ERR_SYN0, | ||
120 | .count_status_reg = TRP_ECC_ERROR_STATUS1, | ||
121 | .ways_status_reg = TRP_ECC_ERROR_STATUS0, | ||
122 | .reg_cnt = TRP_SYN_REG_CNT, | ||
123 | .count_mask = ECC_DB_ERR_COUNT_MASK, | ||
124 | .ways_mask = ECC_DB_ERR_WAYS_MASK, | ||
125 | .ways_shift = ECC_DB_ERR_WAYS_SHIFT, | ||
126 | }, | ||
127 | }; | ||
128 | |||
129 | static int qcom_llcc_core_setup(struct regmap *llcc_bcast_regmap) | ||
130 | { | ||
131 | u32 sb_err_threshold; | ||
132 | int ret; | ||
133 | |||
134 | /* | ||
135 | * Configure interrupt enable registers such that Tag, Data RAM related | ||
136 | * interrupts are propagated to interrupt controller for servicing | ||
137 | */ | ||
138 | ret = regmap_update_bits(llcc_bcast_regmap, CMN_INTERRUPT_2_ENABLE, | ||
139 | TRP0_INTERRUPT_ENABLE, | ||
140 | TRP0_INTERRUPT_ENABLE); | ||
141 | if (ret) | ||
142 | return ret; | ||
143 | |||
144 | ret = regmap_update_bits(llcc_bcast_regmap, TRP_INTERRUPT_0_ENABLE, | ||
145 | SB_DB_TRP_INTERRUPT_ENABLE, | ||
146 | SB_DB_TRP_INTERRUPT_ENABLE); | ||
147 | if (ret) | ||
148 | return ret; | ||
149 | |||
150 | sb_err_threshold = (SB_ERROR_THRESHOLD << SB_ERROR_THRESHOLD_SHIFT); | ||
151 | ret = regmap_write(llcc_bcast_regmap, DRP_ECC_ERROR_CFG, | ||
152 | sb_err_threshold); | ||
153 | if (ret) | ||
154 | return ret; | ||
155 | |||
156 | ret = regmap_update_bits(llcc_bcast_regmap, CMN_INTERRUPT_2_ENABLE, | ||
157 | DRP0_INTERRUPT_ENABLE, | ||
158 | DRP0_INTERRUPT_ENABLE); | ||
159 | if (ret) | ||
160 | return ret; | ||
161 | |||
162 | ret = regmap_write(llcc_bcast_regmap, DRP_INTERRUPT_ENABLE, | ||
163 | SB_DB_DRP_INTERRUPT_ENABLE); | ||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | /* Clear the error interrupt and counter registers */ | ||
168 | static int | ||
169 | qcom_llcc_clear_error_status(int err_type, struct llcc_drv_data *drv) | ||
170 | { | ||
171 | int ret = 0; | ||
172 | |||
173 | switch (err_type) { | ||
174 | case LLCC_DRAM_CE: | ||
175 | case LLCC_DRAM_UE: | ||
176 | ret = regmap_write(drv->bcast_regmap, DRP_INTERRUPT_CLEAR, | ||
177 | DRP_TRP_INT_CLEAR); | ||
178 | if (ret) | ||
179 | return ret; | ||
180 | |||
181 | ret = regmap_write(drv->bcast_regmap, DRP_ECC_ERROR_CNTR_CLEAR, | ||
182 | DRP_TRP_CNT_CLEAR); | ||
183 | if (ret) | ||
184 | return ret; | ||
185 | break; | ||
186 | case LLCC_TRAM_CE: | ||
187 | case LLCC_TRAM_UE: | ||
188 | ret = regmap_write(drv->bcast_regmap, TRP_INTERRUPT_0_CLEAR, | ||
189 | DRP_TRP_INT_CLEAR); | ||
190 | if (ret) | ||
191 | return ret; | ||
192 | |||
193 | ret = regmap_write(drv->bcast_regmap, TRP_ECC_ERROR_CNTR_CLEAR, | ||
194 | DRP_TRP_CNT_CLEAR); | ||
195 | if (ret) | ||
196 | return ret; | ||
197 | break; | ||
198 | default: | ||
199 | ret = -EINVAL; | ||
200 | edac_printk(KERN_CRIT, EDAC_LLCC, "Unexpected error type: %d\n", | ||
201 | err_type); | ||
202 | } | ||
203 | return ret; | ||
204 | } | ||
205 | |||
206 | /* Dump Syndrome registers data for Tag RAM, Data RAM bit errors*/ | ||
207 | static int | ||
208 | dump_syn_reg_values(struct llcc_drv_data *drv, u32 bank, int err_type) | ||
209 | { | ||
210 | struct llcc_edac_reg_data reg_data = edac_reg_data[err_type]; | ||
211 | int err_cnt, err_ways, ret, i; | ||
212 | u32 synd_reg, synd_val; | ||
213 | |||
214 | for (i = 0; i < reg_data.reg_cnt; i++) { | ||
215 | synd_reg = reg_data.synd_reg + (i * 4); | ||
216 | ret = regmap_read(drv->regmap, drv->offsets[bank] + synd_reg, | ||
217 | &synd_val); | ||
218 | if (ret) | ||
219 | goto clear; | ||
220 | |||
221 | edac_printk(KERN_CRIT, EDAC_LLCC, "%s: ECC_SYN%d: 0x%8x\n", | ||
222 | reg_data.name, i, synd_val); | ||
223 | } | ||
224 | |||
225 | ret = regmap_read(drv->regmap, | ||
226 | drv->offsets[bank] + reg_data.count_status_reg, | ||
227 | &err_cnt); | ||
228 | if (ret) | ||
229 | goto clear; | ||
230 | |||
231 | err_cnt &= reg_data.count_mask; | ||
232 | err_cnt >>= reg_data.count_shift; | ||
233 | edac_printk(KERN_CRIT, EDAC_LLCC, "%s: Error count: 0x%4x\n", | ||
234 | reg_data.name, err_cnt); | ||
235 | |||
236 | ret = regmap_read(drv->regmap, | ||
237 | drv->offsets[bank] + reg_data.ways_status_reg, | ||
238 | &err_ways); | ||
239 | if (ret) | ||
240 | goto clear; | ||
241 | |||
242 | err_ways &= reg_data.ways_mask; | ||
243 | err_ways >>= reg_data.ways_shift; | ||
244 | |||
245 | edac_printk(KERN_CRIT, EDAC_LLCC, "%s: Error ways: 0x%4x\n", | ||
246 | reg_data.name, err_ways); | ||
247 | |||
248 | clear: | ||
249 | return qcom_llcc_clear_error_status(err_type, drv); | ||
250 | } | ||
251 | |||
252 | static int | ||
253 | dump_syn_reg(struct edac_device_ctl_info *edev_ctl, int err_type, u32 bank) | ||
254 | { | ||
255 | struct llcc_drv_data *drv = edev_ctl->pvt_info; | ||
256 | int ret; | ||
257 | |||
258 | ret = dump_syn_reg_values(drv, bank, err_type); | ||
259 | if (ret) | ||
260 | return ret; | ||
261 | |||
262 | switch (err_type) { | ||
263 | case LLCC_DRAM_CE: | ||
264 | edac_device_handle_ce(edev_ctl, 0, bank, | ||
265 | "LLCC Data RAM correctable Error"); | ||
266 | break; | ||
267 | case LLCC_DRAM_UE: | ||
268 | edac_device_handle_ue(edev_ctl, 0, bank, | ||
269 | "LLCC Data RAM uncorrectable Error"); | ||
270 | break; | ||
271 | case LLCC_TRAM_CE: | ||
272 | edac_device_handle_ce(edev_ctl, 0, bank, | ||
273 | "LLCC Tag RAM correctable Error"); | ||
274 | break; | ||
275 | case LLCC_TRAM_UE: | ||
276 | edac_device_handle_ue(edev_ctl, 0, bank, | ||
277 | "LLCC Tag RAM uncorrectable Error"); | ||
278 | break; | ||
279 | default: | ||
280 | ret = -EINVAL; | ||
281 | edac_printk(KERN_CRIT, EDAC_LLCC, "Unexpected error type: %d\n", | ||
282 | err_type); | ||
283 | } | ||
284 | |||
285 | return ret; | ||
286 | } | ||
287 | |||
288 | static irqreturn_t | ||
289 | llcc_ecc_irq_handler(int irq, void *edev_ctl) | ||
290 | { | ||
291 | struct edac_device_ctl_info *edac_dev_ctl = edev_ctl; | ||
292 | struct llcc_drv_data *drv = edac_dev_ctl->pvt_info; | ||
293 | irqreturn_t irq_rc = IRQ_NONE; | ||
294 | u32 drp_error, trp_error, i; | ||
295 | bool irq_handled; | ||
296 | int ret; | ||
297 | |||
298 | /* Iterate over the banks and look for Tag RAM or Data RAM errors */ | ||
299 | for (i = 0; i < drv->num_banks; i++) { | ||
300 | ret = regmap_read(drv->regmap, | ||
301 | drv->offsets[i] + DRP_INTERRUPT_STATUS, | ||
302 | &drp_error); | ||
303 | |||
304 | if (!ret && (drp_error & SB_ECC_ERROR)) { | ||
305 | edac_printk(KERN_CRIT, EDAC_LLCC, | ||
306 | "Single Bit Error detected in Data RAM\n"); | ||
307 | ret = dump_syn_reg(edev_ctl, LLCC_DRAM_CE, i); | ||
308 | } else if (!ret && (drp_error & DB_ECC_ERROR)) { | ||
309 | edac_printk(KERN_CRIT, EDAC_LLCC, | ||
310 | "Double Bit Error detected in Data RAM\n"); | ||
311 | ret = dump_syn_reg(edev_ctl, LLCC_DRAM_UE, i); | ||
312 | } | ||
313 | if (!ret) | ||
314 | irq_handled = true; | ||
315 | |||
316 | ret = regmap_read(drv->regmap, | ||
317 | drv->offsets[i] + TRP_INTERRUPT_0_STATUS, | ||
318 | &trp_error); | ||
319 | |||
320 | if (!ret && (trp_error & SB_ECC_ERROR)) { | ||
321 | edac_printk(KERN_CRIT, EDAC_LLCC, | ||
322 | "Single Bit Error detected in Tag RAM\n"); | ||
323 | ret = dump_syn_reg(edev_ctl, LLCC_TRAM_CE, i); | ||
324 | } else if (!ret && (trp_error & DB_ECC_ERROR)) { | ||
325 | edac_printk(KERN_CRIT, EDAC_LLCC, | ||
326 | "Double Bit Error detected in Tag RAM\n"); | ||
327 | ret = dump_syn_reg(edev_ctl, LLCC_TRAM_UE, i); | ||
328 | } | ||
329 | if (!ret) | ||
330 | irq_handled = true; | ||
331 | } | ||
332 | |||
333 | if (irq_handled) | ||
334 | irq_rc = IRQ_HANDLED; | ||
335 | |||
336 | return irq_rc; | ||
337 | } | ||
338 | |||
339 | static int qcom_llcc_edac_probe(struct platform_device *pdev) | ||
340 | { | ||
341 | struct llcc_drv_data *llcc_driv_data = pdev->dev.platform_data; | ||
342 | struct edac_device_ctl_info *edev_ctl; | ||
343 | struct device *dev = &pdev->dev; | ||
344 | int ecc_irq; | ||
345 | int rc; | ||
346 | |||
347 | rc = qcom_llcc_core_setup(llcc_driv_data->bcast_regmap); | ||
348 | if (rc) | ||
349 | return rc; | ||
350 | |||
351 | /* Allocate edac control info */ | ||
352 | edev_ctl = edac_device_alloc_ctl_info(0, "qcom-llcc", 1, "bank", | ||
353 | llcc_driv_data->num_banks, 1, | ||
354 | NULL, 0, | ||
355 | edac_device_alloc_index()); | ||
356 | |||
357 | if (!edev_ctl) | ||
358 | return -ENOMEM; | ||
359 | |||
360 | edev_ctl->dev = dev; | ||
361 | edev_ctl->mod_name = dev_name(dev); | ||
362 | edev_ctl->dev_name = dev_name(dev); | ||
363 | edev_ctl->ctl_name = "llcc"; | ||
364 | edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE; | ||
365 | edev_ctl->pvt_info = llcc_driv_data; | ||
366 | |||
367 | rc = edac_device_add_device(edev_ctl); | ||
368 | if (rc) | ||
369 | goto out_mem; | ||
370 | |||
371 | platform_set_drvdata(pdev, edev_ctl); | ||
372 | |||
373 | /* Request for ecc irq */ | ||
374 | ecc_irq = llcc_driv_data->ecc_irq; | ||
375 | if (ecc_irq < 0) { | ||
376 | rc = -ENODEV; | ||
377 | goto out_dev; | ||
378 | } | ||
379 | rc = devm_request_irq(dev, ecc_irq, llcc_ecc_irq_handler, | ||
380 | IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl); | ||
381 | if (rc) | ||
382 | goto out_dev; | ||
383 | |||
384 | return rc; | ||
385 | |||
386 | out_dev: | ||
387 | edac_device_del_device(edev_ctl->dev); | ||
388 | out_mem: | ||
389 | edac_device_free_ctl_info(edev_ctl); | ||
390 | |||
391 | return rc; | ||
392 | } | ||
393 | |||
394 | static int qcom_llcc_edac_remove(struct platform_device *pdev) | ||
395 | { | ||
396 | struct edac_device_ctl_info *edev_ctl = dev_get_drvdata(&pdev->dev); | ||
397 | |||
398 | edac_device_del_device(edev_ctl->dev); | ||
399 | edac_device_free_ctl_info(edev_ctl); | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static struct platform_driver qcom_llcc_edac_driver = { | ||
405 | .probe = qcom_llcc_edac_probe, | ||
406 | .remove = qcom_llcc_edac_remove, | ||
407 | .driver = { | ||
408 | .name = "qcom_llcc_edac", | ||
409 | }, | ||
410 | }; | ||
411 | module_platform_driver(qcom_llcc_edac_driver); | ||
412 | |||
413 | MODULE_DESCRIPTION("QCOM EDAC driver"); | ||
414 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index e778af766fae..af4eee86919d 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c | |||
@@ -525,34 +525,44 @@ static int qcom_scm_probe(struct platform_device *pdev) | |||
525 | return ret; | 525 | return ret; |
526 | 526 | ||
527 | clks = (unsigned long)of_device_get_match_data(&pdev->dev); | 527 | clks = (unsigned long)of_device_get_match_data(&pdev->dev); |
528 | if (clks & SCM_HAS_CORE_CLK) { | 528 | |
529 | scm->core_clk = devm_clk_get(&pdev->dev, "core"); | 529 | scm->core_clk = devm_clk_get(&pdev->dev, "core"); |
530 | if (IS_ERR(scm->core_clk)) { | 530 | if (IS_ERR(scm->core_clk)) { |
531 | if (PTR_ERR(scm->core_clk) != -EPROBE_DEFER) | 531 | if (PTR_ERR(scm->core_clk) == -EPROBE_DEFER) |
532 | dev_err(&pdev->dev, | 532 | return PTR_ERR(scm->core_clk); |
533 | "failed to acquire core clk\n"); | 533 | |
534 | if (clks & SCM_HAS_CORE_CLK) { | ||
535 | dev_err(&pdev->dev, "failed to acquire core clk\n"); | ||
534 | return PTR_ERR(scm->core_clk); | 536 | return PTR_ERR(scm->core_clk); |
535 | } | 537 | } |
538 | |||
539 | scm->core_clk = NULL; | ||
536 | } | 540 | } |
537 | 541 | ||
538 | if (clks & SCM_HAS_IFACE_CLK) { | 542 | scm->iface_clk = devm_clk_get(&pdev->dev, "iface"); |
539 | scm->iface_clk = devm_clk_get(&pdev->dev, "iface"); | 543 | if (IS_ERR(scm->iface_clk)) { |
540 | if (IS_ERR(scm->iface_clk)) { | 544 | if (PTR_ERR(scm->iface_clk) == -EPROBE_DEFER) |
541 | if (PTR_ERR(scm->iface_clk) != -EPROBE_DEFER) | 545 | return PTR_ERR(scm->iface_clk); |
542 | dev_err(&pdev->dev, | 546 | |
543 | "failed to acquire iface clk\n"); | 547 | if (clks & SCM_HAS_IFACE_CLK) { |
548 | dev_err(&pdev->dev, "failed to acquire iface clk\n"); | ||
544 | return PTR_ERR(scm->iface_clk); | 549 | return PTR_ERR(scm->iface_clk); |
545 | } | 550 | } |
551 | |||
552 | scm->iface_clk = NULL; | ||
546 | } | 553 | } |
547 | 554 | ||
548 | if (clks & SCM_HAS_BUS_CLK) { | 555 | scm->bus_clk = devm_clk_get(&pdev->dev, "bus"); |
549 | scm->bus_clk = devm_clk_get(&pdev->dev, "bus"); | 556 | if (IS_ERR(scm->bus_clk)) { |
550 | if (IS_ERR(scm->bus_clk)) { | 557 | if (PTR_ERR(scm->bus_clk) == -EPROBE_DEFER) |
551 | if (PTR_ERR(scm->bus_clk) != -EPROBE_DEFER) | 558 | return PTR_ERR(scm->bus_clk); |
552 | dev_err(&pdev->dev, | 559 | |
553 | "failed to acquire bus clk\n"); | 560 | if (clks & SCM_HAS_BUS_CLK) { |
561 | dev_err(&pdev->dev, "failed to acquire bus clk\n"); | ||
554 | return PTR_ERR(scm->bus_clk); | 562 | return PTR_ERR(scm->bus_clk); |
555 | } | 563 | } |
564 | |||
565 | scm->bus_clk = NULL; | ||
556 | } | 566 | } |
557 | 567 | ||
558 | scm->reset.ops = &qcom_scm_pas_reset_ops; | 568 | scm->reset.ops = &qcom_scm_pas_reset_ops; |
@@ -594,23 +604,23 @@ static const struct of_device_id qcom_scm_dt_match[] = { | |||
594 | { .compatible = "qcom,scm-apq8064", | 604 | { .compatible = "qcom,scm-apq8064", |
595 | /* FIXME: This should have .data = (void *) SCM_HAS_CORE_CLK */ | 605 | /* FIXME: This should have .data = (void *) SCM_HAS_CORE_CLK */ |
596 | }, | 606 | }, |
597 | { .compatible = "qcom,scm-msm8660", | 607 | { .compatible = "qcom,scm-apq8084", .data = (void *)(SCM_HAS_CORE_CLK | |
598 | .data = (void *) SCM_HAS_CORE_CLK, | 608 | SCM_HAS_IFACE_CLK | |
599 | }, | 609 | SCM_HAS_BUS_CLK) |
600 | { .compatible = "qcom,scm-msm8960", | ||
601 | .data = (void *) SCM_HAS_CORE_CLK, | ||
602 | }, | ||
603 | { .compatible = "qcom,scm-msm8996", | ||
604 | .data = NULL, /* no clocks */ | ||
605 | }, | 610 | }, |
606 | { .compatible = "qcom,scm-ipq4019", | 611 | { .compatible = "qcom,scm-ipq4019" }, |
607 | .data = NULL, /* no clocks */ | 612 | { .compatible = "qcom,scm-msm8660", .data = (void *) SCM_HAS_CORE_CLK }, |
613 | { .compatible = "qcom,scm-msm8960", .data = (void *) SCM_HAS_CORE_CLK }, | ||
614 | { .compatible = "qcom,scm-msm8916", .data = (void *)(SCM_HAS_CORE_CLK | | ||
615 | SCM_HAS_IFACE_CLK | | ||
616 | SCM_HAS_BUS_CLK) | ||
608 | }, | 617 | }, |
609 | { .compatible = "qcom,scm", | 618 | { .compatible = "qcom,scm-msm8974", .data = (void *)(SCM_HAS_CORE_CLK | |
610 | .data = (void *)(SCM_HAS_CORE_CLK | 619 | SCM_HAS_IFACE_CLK | |
611 | | SCM_HAS_IFACE_CLK | 620 | SCM_HAS_BUS_CLK) |
612 | | SCM_HAS_BUS_CLK), | ||
613 | }, | 621 | }, |
622 | { .compatible = "qcom,scm-msm8996" }, | ||
623 | { .compatible = "qcom,scm" }, | ||
614 | {} | 624 | {} |
615 | }; | 625 | }; |
616 | 626 | ||
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index ba79b609aca2..684cb51694d1 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig | |||
@@ -33,7 +33,7 @@ config QCOM_GLINK_SSR | |||
33 | 33 | ||
34 | config QCOM_GSBI | 34 | config QCOM_GSBI |
35 | tristate "QCOM General Serial Bus Interface" | 35 | tristate "QCOM General Serial Bus Interface" |
36 | depends on ARCH_QCOM | 36 | depends on ARCH_QCOM || COMPILE_TEST |
37 | select MFD_SYSCON | 37 | select MFD_SYSCON |
38 | help | 38 | help |
39 | Say y here to enable GSBI support. The GSBI provides control | 39 | Say y here to enable GSBI support. The GSBI provides control |
@@ -42,7 +42,7 @@ config QCOM_GSBI | |||
42 | 42 | ||
43 | config QCOM_LLCC | 43 | config QCOM_LLCC |
44 | tristate "Qualcomm Technologies, Inc. LLCC driver" | 44 | tristate "Qualcomm Technologies, Inc. LLCC driver" |
45 | depends on ARCH_QCOM | 45 | depends on ARCH_QCOM || COMPILE_TEST |
46 | help | 46 | help |
47 | Qualcomm Technologies, Inc. platform specific | 47 | Qualcomm Technologies, Inc. platform specific |
48 | Last Level Cache Controller(LLCC) driver. This provides interfaces | 48 | Last Level Cache Controller(LLCC) driver. This provides interfaces |
@@ -73,7 +73,8 @@ config QCOM_PM | |||
73 | 73 | ||
74 | config QCOM_QMI_HELPERS | 74 | config QCOM_QMI_HELPERS |
75 | tristate | 75 | tristate |
76 | depends on ARCH_QCOM && NET | 76 | depends on ARCH_QCOM || COMPILE_TEST |
77 | depends on NET | ||
77 | help | 78 | help |
78 | Helper library for handling QMI encoded messages. QMI encoded | 79 | Helper library for handling QMI encoded messages. QMI encoded |
79 | messages are used in communication between the majority of QRTR | 80 | messages are used in communication between the majority of QRTR |
@@ -94,7 +95,7 @@ config QCOM_RMTFS_MEM | |||
94 | 95 | ||
95 | config QCOM_RPMH | 96 | config QCOM_RPMH |
96 | bool "Qualcomm RPM-Hardened (RPMH) Communication" | 97 | bool "Qualcomm RPM-Hardened (RPMH) Communication" |
97 | depends on ARCH_QCOM && ARM64 && OF || COMPILE_TEST | 98 | depends on ARCH_QCOM && ARM64 || COMPILE_TEST |
98 | help | 99 | help |
99 | Support for communication with the hardened-RPM blocks in | 100 | Support for communication with the hardened-RPM blocks in |
100 | Qualcomm Technologies Inc (QTI) SoCs. RPMH communication uses an | 101 | Qualcomm Technologies Inc (QTI) SoCs. RPMH communication uses an |
@@ -104,7 +105,7 @@ config QCOM_RPMH | |||
104 | 105 | ||
105 | config QCOM_SMEM | 106 | config QCOM_SMEM |
106 | tristate "Qualcomm Shared Memory Manager (SMEM)" | 107 | tristate "Qualcomm Shared Memory Manager (SMEM)" |
107 | depends on ARCH_QCOM | 108 | depends on ARCH_QCOM || COMPILE_TEST |
108 | depends on HWSPINLOCK | 109 | depends on HWSPINLOCK |
109 | help | 110 | help |
110 | Say y here to enable support for the Qualcomm Shared Memory Manager. | 111 | Say y here to enable support for the Qualcomm Shared Memory Manager. |
@@ -113,8 +114,8 @@ config QCOM_SMEM | |||
113 | 114 | ||
114 | config QCOM_SMD_RPM | 115 | config QCOM_SMD_RPM |
115 | tristate "Qualcomm Resource Power Manager (RPM) over SMD" | 116 | tristate "Qualcomm Resource Power Manager (RPM) over SMD" |
116 | depends on ARCH_QCOM | 117 | depends on ARCH_QCOM || COMPILE_TEST |
117 | depends on RPMSG && OF | 118 | depends on RPMSG |
118 | help | 119 | help |
119 | If you say yes to this option, support will be included for the | 120 | If you say yes to this option, support will be included for the |
120 | Resource Power Manager system found in the Qualcomm 8974 based | 121 | Resource Power Manager system found in the Qualcomm 8974 based |
@@ -134,6 +135,7 @@ config QCOM_SMP2P | |||
134 | depends on MAILBOX | 135 | depends on MAILBOX |
135 | depends on QCOM_SMEM | 136 | depends on QCOM_SMEM |
136 | select QCOM_SMEM_STATE | 137 | select QCOM_SMEM_STATE |
138 | select IRQ_DOMAIN | ||
137 | help | 139 | help |
138 | Say yes here to support the Qualcomm Shared Memory Point to Point | 140 | Say yes here to support the Qualcomm Shared Memory Point to Point |
139 | protocol. | 141 | protocol. |
@@ -142,13 +144,14 @@ config QCOM_SMSM | |||
142 | tristate "Qualcomm Shared Memory State Machine" | 144 | tristate "Qualcomm Shared Memory State Machine" |
143 | depends on QCOM_SMEM | 145 | depends on QCOM_SMEM |
144 | select QCOM_SMEM_STATE | 146 | select QCOM_SMEM_STATE |
147 | select IRQ_DOMAIN | ||
145 | help | 148 | help |
146 | Say yes here to support the Qualcomm Shared Memory State Machine. | 149 | Say yes here to support the Qualcomm Shared Memory State Machine. |
147 | The state machine is represented by bits in shared memory. | 150 | The state machine is represented by bits in shared memory. |
148 | 151 | ||
149 | config QCOM_WCNSS_CTRL | 152 | config QCOM_WCNSS_CTRL |
150 | tristate "Qualcomm WCNSS control driver" | 153 | tristate "Qualcomm WCNSS control driver" |
151 | depends on ARCH_QCOM | 154 | depends on ARCH_QCOM || COMPILE_TEST |
152 | depends on RPMSG | 155 | depends on RPMSG |
153 | help | 156 | help |
154 | Client driver for the WCNSS_CTRL SMD channel, used to download nv | 157 | Client driver for the WCNSS_CTRL SMD channel, used to download nv |
@@ -156,7 +159,7 @@ config QCOM_WCNSS_CTRL | |||
156 | 159 | ||
157 | config QCOM_APR | 160 | config QCOM_APR |
158 | tristate "Qualcomm APR Bus (Asynchronous Packet Router)" | 161 | tristate "Qualcomm APR Bus (Asynchronous Packet Router)" |
159 | depends on ARCH_QCOM | 162 | depends on ARCH_QCOM || COMPILE_TEST |
160 | depends on RPMSG | 163 | depends on RPMSG |
161 | help | 164 | help |
162 | Enable APR IPC protocol support between | 165 | Enable APR IPC protocol support between |
diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c index 57af8a537332..716762d59c1f 100644 --- a/drivers/soc/qcom/apr.c +++ b/drivers/soc/qcom/apr.c | |||
@@ -87,7 +87,7 @@ static int apr_callback(struct rpmsg_device *rpdev, void *buf, | |||
87 | } | 87 | } |
88 | 88 | ||
89 | if (hdr->pkt_size < APR_HDR_SIZE || hdr->pkt_size != len) { | 89 | if (hdr->pkt_size < APR_HDR_SIZE || hdr->pkt_size != len) { |
90 | dev_err(apr->dev, "APR: Wrong paket size\n"); | 90 | dev_err(apr->dev, "APR: Wrong packet size\n"); |
91 | return -EINVAL; | 91 | return -EINVAL; |
92 | } | 92 | } |
93 | 93 | ||
@@ -219,9 +219,9 @@ static int apr_add_device(struct device *dev, struct device_node *np, | |||
219 | adev->domain_id = id->domain_id; | 219 | adev->domain_id = id->domain_id; |
220 | adev->version = id->svc_version; | 220 | adev->version = id->svc_version; |
221 | if (np) | 221 | if (np) |
222 | strncpy(adev->name, np->name, APR_NAME_SIZE); | 222 | strscpy(adev->name, np->name, APR_NAME_SIZE); |
223 | else | 223 | else |
224 | strncpy(adev->name, id->name, APR_NAME_SIZE); | 224 | strscpy(adev->name, id->name, APR_NAME_SIZE); |
225 | 225 | ||
226 | dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name, | 226 | dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name, |
227 | id->domain_id, id->svc_id); | 227 | id->domain_id, id->svc_id); |
diff --git a/drivers/soc/qcom/llcc-slice.c b/drivers/soc/qcom/llcc-slice.c index 54063a31132f..192ca761b2cb 100644 --- a/drivers/soc/qcom/llcc-slice.c +++ b/drivers/soc/qcom/llcc-slice.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/mutex.h> | 13 | #include <linux/mutex.h> |
14 | #include <linux/of_device.h> | 14 | #include <linux/of_device.h> |
15 | #include <linux/regmap.h> | 15 | #include <linux/regmap.h> |
16 | #include <linux/sizes.h> | ||
16 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
17 | #include <linux/soc/qcom/llcc-qcom.h> | 18 | #include <linux/soc/qcom/llcc-qcom.h> |
18 | 19 | ||
@@ -106,22 +107,24 @@ static int llcc_update_act_ctrl(u32 sid, | |||
106 | u32 slice_status; | 107 | u32 slice_status; |
107 | int ret; | 108 | int ret; |
108 | 109 | ||
109 | act_ctrl_reg = drv_data->bcast_off + LLCC_TRP_ACT_CTRLn(sid); | 110 | act_ctrl_reg = LLCC_TRP_ACT_CTRLn(sid); |
110 | status_reg = drv_data->bcast_off + LLCC_TRP_STATUSn(sid); | 111 | status_reg = LLCC_TRP_STATUSn(sid); |
111 | 112 | ||
112 | /* Set the ACTIVE trigger */ | 113 | /* Set the ACTIVE trigger */ |
113 | act_ctrl_reg_val |= ACT_CTRL_ACT_TRIG; | 114 | act_ctrl_reg_val |= ACT_CTRL_ACT_TRIG; |
114 | ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val); | 115 | ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg, |
116 | act_ctrl_reg_val); | ||
115 | if (ret) | 117 | if (ret) |
116 | return ret; | 118 | return ret; |
117 | 119 | ||
118 | /* Clear the ACTIVE trigger */ | 120 | /* Clear the ACTIVE trigger */ |
119 | act_ctrl_reg_val &= ~ACT_CTRL_ACT_TRIG; | 121 | act_ctrl_reg_val &= ~ACT_CTRL_ACT_TRIG; |
120 | ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val); | 122 | ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg, |
123 | act_ctrl_reg_val); | ||
121 | if (ret) | 124 | if (ret) |
122 | return ret; | 125 | return ret; |
123 | 126 | ||
124 | ret = regmap_read_poll_timeout(drv_data->regmap, status_reg, | 127 | ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg, |
125 | slice_status, !(slice_status & status), | 128 | slice_status, !(slice_status & status), |
126 | 0, LLCC_STATUS_READ_DELAY); | 129 | 0, LLCC_STATUS_READ_DELAY); |
127 | return ret; | 130 | return ret; |
@@ -223,19 +226,16 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev) | |||
223 | u32 attr0_val; | 226 | u32 attr0_val; |
224 | u32 max_cap_cacheline; | 227 | u32 max_cap_cacheline; |
225 | u32 sz; | 228 | u32 sz; |
226 | int ret; | 229 | int ret = 0; |
227 | const struct llcc_slice_config *llcc_table; | 230 | const struct llcc_slice_config *llcc_table; |
228 | struct llcc_slice_desc desc; | 231 | struct llcc_slice_desc desc; |
229 | u32 bcast_off = drv_data->bcast_off; | ||
230 | 232 | ||
231 | sz = drv_data->cfg_size; | 233 | sz = drv_data->cfg_size; |
232 | llcc_table = drv_data->cfg; | 234 | llcc_table = drv_data->cfg; |
233 | 235 | ||
234 | for (i = 0; i < sz; i++) { | 236 | for (i = 0; i < sz; i++) { |
235 | attr1_cfg = bcast_off + | 237 | attr1_cfg = LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id); |
236 | LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id); | 238 | attr0_cfg = LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id); |
237 | attr0_cfg = bcast_off + | ||
238 | LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id); | ||
239 | 239 | ||
240 | attr1_val = llcc_table[i].cache_mode; | 240 | attr1_val = llcc_table[i].cache_mode; |
241 | attr1_val |= llcc_table[i].probe_target_ways << | 241 | attr1_val |= llcc_table[i].probe_target_ways << |
@@ -260,10 +260,12 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev) | |||
260 | attr0_val = llcc_table[i].res_ways & ATTR0_RES_WAYS_MASK; | 260 | attr0_val = llcc_table[i].res_ways & ATTR0_RES_WAYS_MASK; |
261 | attr0_val |= llcc_table[i].bonus_ways << ATTR0_BONUS_WAYS_SHIFT; | 261 | attr0_val |= llcc_table[i].bonus_ways << ATTR0_BONUS_WAYS_SHIFT; |
262 | 262 | ||
263 | ret = regmap_write(drv_data->regmap, attr1_cfg, attr1_val); | 263 | ret = regmap_write(drv_data->bcast_regmap, attr1_cfg, |
264 | attr1_val); | ||
264 | if (ret) | 265 | if (ret) |
265 | return ret; | 266 | return ret; |
266 | ret = regmap_write(drv_data->regmap, attr0_cfg, attr0_val); | 267 | ret = regmap_write(drv_data->bcast_regmap, attr0_cfg, |
268 | attr0_val); | ||
267 | if (ret) | 269 | if (ret) |
268 | return ret; | 270 | return ret; |
269 | if (llcc_table[i].activate_on_init) { | 271 | if (llcc_table[i].activate_on_init) { |
@@ -279,24 +281,37 @@ int qcom_llcc_probe(struct platform_device *pdev, | |||
279 | { | 281 | { |
280 | u32 num_banks; | 282 | u32 num_banks; |
281 | struct device *dev = &pdev->dev; | 283 | struct device *dev = &pdev->dev; |
282 | struct resource *res; | 284 | struct resource *llcc_banks_res, *llcc_bcast_res; |
283 | void __iomem *base; | 285 | void __iomem *llcc_banks_base, *llcc_bcast_base; |
284 | int ret, i; | 286 | int ret, i; |
287 | struct platform_device *llcc_edac; | ||
285 | 288 | ||
286 | drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL); | 289 | drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL); |
287 | if (!drv_data) | 290 | if (!drv_data) |
288 | return -ENOMEM; | 291 | return -ENOMEM; |
289 | 292 | ||
290 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 293 | llcc_banks_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
291 | base = devm_ioremap_resource(&pdev->dev, res); | 294 | "llcc_base"); |
292 | if (IS_ERR(base)) | 295 | llcc_banks_base = devm_ioremap_resource(&pdev->dev, llcc_banks_res); |
293 | return PTR_ERR(base); | 296 | if (IS_ERR(llcc_banks_base)) |
297 | return PTR_ERR(llcc_banks_base); | ||
294 | 298 | ||
295 | drv_data->regmap = devm_regmap_init_mmio(dev, base, | 299 | drv_data->regmap = devm_regmap_init_mmio(dev, llcc_banks_base, |
296 | &llcc_regmap_config); | 300 | &llcc_regmap_config); |
297 | if (IS_ERR(drv_data->regmap)) | 301 | if (IS_ERR(drv_data->regmap)) |
298 | return PTR_ERR(drv_data->regmap); | 302 | return PTR_ERR(drv_data->regmap); |
299 | 303 | ||
304 | llcc_bcast_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | ||
305 | "llcc_broadcast_base"); | ||
306 | llcc_bcast_base = devm_ioremap_resource(&pdev->dev, llcc_bcast_res); | ||
307 | if (IS_ERR(llcc_bcast_base)) | ||
308 | return PTR_ERR(llcc_bcast_base); | ||
309 | |||
310 | drv_data->bcast_regmap = devm_regmap_init_mmio(dev, llcc_bcast_base, | ||
311 | &llcc_regmap_config); | ||
312 | if (IS_ERR(drv_data->bcast_regmap)) | ||
313 | return PTR_ERR(drv_data->bcast_regmap); | ||
314 | |||
300 | ret = regmap_read(drv_data->regmap, LLCC_COMMON_STATUS0, | 315 | ret = regmap_read(drv_data->regmap, LLCC_COMMON_STATUS0, |
301 | &num_banks); | 316 | &num_banks); |
302 | if (ret) | 317 | if (ret) |
@@ -318,8 +333,6 @@ int qcom_llcc_probe(struct platform_device *pdev, | |||
318 | for (i = 0; i < num_banks; i++) | 333 | for (i = 0; i < num_banks; i++) |
319 | drv_data->offsets[i] = i * BANK_OFFSET_STRIDE; | 334 | drv_data->offsets[i] = i * BANK_OFFSET_STRIDE; |
320 | 335 | ||
321 | drv_data->bcast_off = num_banks * BANK_OFFSET_STRIDE; | ||
322 | |||
323 | drv_data->bitmap = devm_kcalloc(dev, | 336 | drv_data->bitmap = devm_kcalloc(dev, |
324 | BITS_TO_LONGS(drv_data->max_slices), sizeof(unsigned long), | 337 | BITS_TO_LONGS(drv_data->max_slices), sizeof(unsigned long), |
325 | GFP_KERNEL); | 338 | GFP_KERNEL); |
@@ -331,7 +344,20 @@ int qcom_llcc_probe(struct platform_device *pdev, | |||
331 | mutex_init(&drv_data->lock); | 344 | mutex_init(&drv_data->lock); |
332 | platform_set_drvdata(pdev, drv_data); | 345 | platform_set_drvdata(pdev, drv_data); |
333 | 346 | ||
334 | return qcom_llcc_cfg_program(pdev); | 347 | ret = qcom_llcc_cfg_program(pdev); |
348 | if (ret) | ||
349 | return ret; | ||
350 | |||
351 | drv_data->ecc_irq = platform_get_irq(pdev, 0); | ||
352 | if (drv_data->ecc_irq >= 0) { | ||
353 | llcc_edac = platform_device_register_data(&pdev->dev, | ||
354 | "qcom_llcc_edac", -1, drv_data, | ||
355 | sizeof(*drv_data)); | ||
356 | if (IS_ERR(llcc_edac)) | ||
357 | dev_err(dev, "Failed to register llcc edac driver\n"); | ||
358 | } | ||
359 | |||
360 | return ret; | ||
335 | } | 361 | } |
336 | EXPORT_SYMBOL_GPL(qcom_llcc_probe); | 362 | EXPORT_SYMBOL_GPL(qcom_llcc_probe); |
337 | 363 | ||
diff --git a/drivers/soc/qcom/rmtfs_mem.c b/drivers/soc/qcom/rmtfs_mem.c index 8a3678c2e83c..97bb5989aa21 100644 --- a/drivers/soc/qcom/rmtfs_mem.c +++ b/drivers/soc/qcom/rmtfs_mem.c | |||
@@ -212,6 +212,11 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev) | |||
212 | dev_err(&pdev->dev, "failed to parse qcom,vmid\n"); | 212 | dev_err(&pdev->dev, "failed to parse qcom,vmid\n"); |
213 | goto remove_cdev; | 213 | goto remove_cdev; |
214 | } else if (!ret) { | 214 | } else if (!ret) { |
215 | if (!qcom_scm_is_available()) { | ||
216 | ret = -EPROBE_DEFER; | ||
217 | goto remove_cdev; | ||
218 | } | ||
219 | |||
215 | perms[0].vmid = QCOM_SCM_VMID_HLOS; | 220 | perms[0].vmid = QCOM_SCM_VMID_HLOS; |
216 | perms[0].perm = QCOM_SCM_PERM_RW; | 221 | perms[0].perm = QCOM_SCM_PERM_RW; |
217 | perms[1].vmid = vmid; | 222 | perms[1].vmid = vmid; |
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index ee75da66d64b..75bd9a83aef0 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c | |||
@@ -121,6 +121,7 @@ static int tcs_invalidate(struct rsc_drv *drv, int type) | |||
121 | return -EAGAIN; | 121 | return -EAGAIN; |
122 | } | 122 | } |
123 | write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0); | 123 | write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0); |
124 | write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, m, 0); | ||
124 | } | 125 | } |
125 | bitmap_zero(tcs->slots, MAX_TCS_SLOTS); | 126 | bitmap_zero(tcs->slots, MAX_TCS_SLOTS); |
126 | spin_unlock(&tcs->lock); | 127 | spin_unlock(&tcs->lock); |
@@ -239,6 +240,7 @@ static irqreturn_t tcs_tx_done(int irq, void *p) | |||
239 | skip: | 240 | skip: |
240 | /* Reclaim the TCS */ | 241 | /* Reclaim the TCS */ |
241 | write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0); | 242 | write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0); |
243 | write_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, i, 0); | ||
242 | write_tcs_reg(drv, RSC_DRV_IRQ_CLEAR, 0, BIT(i)); | 244 | write_tcs_reg(drv, RSC_DRV_IRQ_CLEAR, 0, BIT(i)); |
243 | spin_lock(&drv->lock); | 245 | spin_lock(&drv->lock); |
244 | clear_bit(i, drv->tcs_in_use); | 246 | clear_bit(i, drv->tcs_in_use); |
diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index bf4bd71ab53f..f80d040601fd 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/of.h> | 18 | #include <linux/of.h> |
19 | #include <linux/of_address.h> | 19 | #include <linux/of_address.h> |
20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/sizes.h> | ||
21 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
22 | #include <linux/soc/qcom/smem.h> | 23 | #include <linux/soc/qcom/smem.h> |
23 | 24 | ||
@@ -277,7 +278,7 @@ struct qcom_smem { | |||
277 | u32 item_count; | 278 | u32 item_count; |
278 | 279 | ||
279 | unsigned num_regions; | 280 | unsigned num_regions; |
280 | struct smem_region regions[0]; | 281 | struct smem_region regions[]; |
281 | }; | 282 | }; |
282 | 283 | ||
283 | static void * | 284 | static void * |
@@ -489,7 +490,7 @@ static void *qcom_smem_get_global(struct qcom_smem *smem, | |||
489 | size_t *size) | 490 | size_t *size) |
490 | { | 491 | { |
491 | struct smem_header *header; | 492 | struct smem_header *header; |
492 | struct smem_region *area; | 493 | struct smem_region *region; |
493 | struct smem_global_entry *entry; | 494 | struct smem_global_entry *entry; |
494 | u32 aux_base; | 495 | u32 aux_base; |
495 | unsigned i; | 496 | unsigned i; |
@@ -502,12 +503,12 @@ static void *qcom_smem_get_global(struct qcom_smem *smem, | |||
502 | aux_base = le32_to_cpu(entry->aux_base) & AUX_BASE_MASK; | 503 | aux_base = le32_to_cpu(entry->aux_base) & AUX_BASE_MASK; |
503 | 504 | ||
504 | for (i = 0; i < smem->num_regions; i++) { | 505 | for (i = 0; i < smem->num_regions; i++) { |
505 | area = &smem->regions[i]; | 506 | region = &smem->regions[i]; |
506 | 507 | ||
507 | if (area->aux_base == aux_base || !aux_base) { | 508 | if (region->aux_base == aux_base || !aux_base) { |
508 | if (size != NULL) | 509 | if (size != NULL) |
509 | *size = le32_to_cpu(entry->size); | 510 | *size = le32_to_cpu(entry->size); |
510 | return area->virt_base + le32_to_cpu(entry->offset); | 511 | return region->virt_base + le32_to_cpu(entry->offset); |
511 | } | 512 | } |
512 | } | 513 | } |
513 | 514 | ||
@@ -722,12 +723,59 @@ static u32 qcom_smem_get_item_count(struct qcom_smem *smem) | |||
722 | return le16_to_cpu(info->num_items); | 723 | return le16_to_cpu(info->num_items); |
723 | } | 724 | } |
724 | 725 | ||
726 | /* | ||
727 | * Validate the partition header for a partition whose partition | ||
728 | * table entry is supplied. Returns a pointer to its header if | ||
729 | * valid, or a null pointer otherwise. | ||
730 | */ | ||
731 | static struct smem_partition_header * | ||
732 | qcom_smem_partition_header(struct qcom_smem *smem, | ||
733 | struct smem_ptable_entry *entry, u16 host0, u16 host1) | ||
734 | { | ||
735 | struct smem_partition_header *header; | ||
736 | u32 size; | ||
737 | |||
738 | header = smem->regions[0].virt_base + le32_to_cpu(entry->offset); | ||
739 | |||
740 | if (memcmp(header->magic, SMEM_PART_MAGIC, sizeof(header->magic))) { | ||
741 | dev_err(smem->dev, "bad partition magic %02x %02x %02x %02x\n", | ||
742 | header->magic[0], header->magic[1], | ||
743 | header->magic[2], header->magic[3]); | ||
744 | return NULL; | ||
745 | } | ||
746 | |||
747 | if (host0 != le16_to_cpu(header->host0)) { | ||
748 | dev_err(smem->dev, "bad host0 (%hu != %hu)\n", | ||
749 | host0, le16_to_cpu(header->host0)); | ||
750 | return NULL; | ||
751 | } | ||
752 | if (host1 != le16_to_cpu(header->host1)) { | ||
753 | dev_err(smem->dev, "bad host1 (%hu != %hu)\n", | ||
754 | host1, le16_to_cpu(header->host1)); | ||
755 | return NULL; | ||
756 | } | ||
757 | |||
758 | size = le32_to_cpu(header->size); | ||
759 | if (size != le32_to_cpu(entry->size)) { | ||
760 | dev_err(smem->dev, "bad partition size (%u != %u)\n", | ||
761 | size, le32_to_cpu(entry->size)); | ||
762 | return NULL; | ||
763 | } | ||
764 | |||
765 | if (le32_to_cpu(header->offset_free_uncached) > size) { | ||
766 | dev_err(smem->dev, "bad partition free uncached (%u > %u)\n", | ||
767 | le32_to_cpu(header->offset_free_uncached), size); | ||
768 | return NULL; | ||
769 | } | ||
770 | |||
771 | return header; | ||
772 | } | ||
773 | |||
725 | static int qcom_smem_set_global_partition(struct qcom_smem *smem) | 774 | static int qcom_smem_set_global_partition(struct qcom_smem *smem) |
726 | { | 775 | { |
727 | struct smem_partition_header *header; | 776 | struct smem_partition_header *header; |
728 | struct smem_ptable_entry *entry; | 777 | struct smem_ptable_entry *entry; |
729 | struct smem_ptable *ptable; | 778 | struct smem_ptable *ptable; |
730 | u32 host0, host1, size; | ||
731 | bool found = false; | 779 | bool found = false; |
732 | int i; | 780 | int i; |
733 | 781 | ||
@@ -742,10 +790,15 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem) | |||
742 | 790 | ||
743 | for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) { | 791 | for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) { |
744 | entry = &ptable->entry[i]; | 792 | entry = &ptable->entry[i]; |
745 | host0 = le16_to_cpu(entry->host0); | 793 | if (!le32_to_cpu(entry->offset)) |
746 | host1 = le16_to_cpu(entry->host1); | 794 | continue; |
795 | if (!le32_to_cpu(entry->size)) | ||
796 | continue; | ||
797 | |||
798 | if (le16_to_cpu(entry->host0) != SMEM_GLOBAL_HOST) | ||
799 | continue; | ||
747 | 800 | ||
748 | if (host0 == SMEM_GLOBAL_HOST && host0 == host1) { | 801 | if (le16_to_cpu(entry->host1) == SMEM_GLOBAL_HOST) { |
749 | found = true; | 802 | found = true; |
750 | break; | 803 | break; |
751 | } | 804 | } |
@@ -756,36 +809,10 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem) | |||
756 | return -EINVAL; | 809 | return -EINVAL; |
757 | } | 810 | } |
758 | 811 | ||
759 | if (!le32_to_cpu(entry->offset) || !le32_to_cpu(entry->size)) { | 812 | header = qcom_smem_partition_header(smem, entry, |
760 | dev_err(smem->dev, "Invalid entry for global partition\n"); | 813 | SMEM_GLOBAL_HOST, SMEM_GLOBAL_HOST); |
814 | if (!header) | ||
761 | return -EINVAL; | 815 | return -EINVAL; |
762 | } | ||
763 | |||
764 | header = smem->regions[0].virt_base + le32_to_cpu(entry->offset); | ||
765 | host0 = le16_to_cpu(header->host0); | ||
766 | host1 = le16_to_cpu(header->host1); | ||
767 | |||
768 | if (memcmp(header->magic, SMEM_PART_MAGIC, sizeof(header->magic))) { | ||
769 | dev_err(smem->dev, "Global partition has invalid magic\n"); | ||
770 | return -EINVAL; | ||
771 | } | ||
772 | |||
773 | if (host0 != SMEM_GLOBAL_HOST && host1 != SMEM_GLOBAL_HOST) { | ||
774 | dev_err(smem->dev, "Global partition hosts are invalid\n"); | ||
775 | return -EINVAL; | ||
776 | } | ||
777 | |||
778 | if (le32_to_cpu(header->size) != le32_to_cpu(entry->size)) { | ||
779 | dev_err(smem->dev, "Global partition has invalid size\n"); | ||
780 | return -EINVAL; | ||
781 | } | ||
782 | |||
783 | size = le32_to_cpu(header->offset_free_uncached); | ||
784 | if (size > le32_to_cpu(header->size)) { | ||
785 | dev_err(smem->dev, | ||
786 | "Global partition has invalid free pointer\n"); | ||
787 | return -EINVAL; | ||
788 | } | ||
789 | 816 | ||
790 | smem->global_partition = header; | 817 | smem->global_partition = header; |
791 | smem->global_cacheline = le32_to_cpu(entry->cacheline); | 818 | smem->global_cacheline = le32_to_cpu(entry->cacheline); |
@@ -793,14 +820,14 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem) | |||
793 | return 0; | 820 | return 0; |
794 | } | 821 | } |
795 | 822 | ||
796 | static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, | 823 | static int |
797 | unsigned int local_host) | 824 | qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host) |
798 | { | 825 | { |
799 | struct smem_partition_header *header; | 826 | struct smem_partition_header *header; |
800 | struct smem_ptable_entry *entry; | 827 | struct smem_ptable_entry *entry; |
801 | struct smem_ptable *ptable; | 828 | struct smem_ptable *ptable; |
802 | unsigned int remote_host; | 829 | unsigned int remote_host; |
803 | u32 host0, host1; | 830 | u16 host0, host1; |
804 | int i; | 831 | int i; |
805 | 832 | ||
806 | ptable = qcom_smem_get_ptable(smem); | 833 | ptable = qcom_smem_get_ptable(smem); |
@@ -809,71 +836,33 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, | |||
809 | 836 | ||
810 | for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) { | 837 | for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) { |
811 | entry = &ptable->entry[i]; | 838 | entry = &ptable->entry[i]; |
812 | host0 = le16_to_cpu(entry->host0); | ||
813 | host1 = le16_to_cpu(entry->host1); | ||
814 | |||
815 | if (host0 != local_host && host1 != local_host) | ||
816 | continue; | ||
817 | |||
818 | if (!le32_to_cpu(entry->offset)) | 839 | if (!le32_to_cpu(entry->offset)) |
819 | continue; | 840 | continue; |
820 | |||
821 | if (!le32_to_cpu(entry->size)) | 841 | if (!le32_to_cpu(entry->size)) |
822 | continue; | 842 | continue; |
823 | 843 | ||
844 | host0 = le16_to_cpu(entry->host0); | ||
845 | host1 = le16_to_cpu(entry->host1); | ||
824 | if (host0 == local_host) | 846 | if (host0 == local_host) |
825 | remote_host = host1; | 847 | remote_host = host1; |
826 | else | 848 | else if (host1 == local_host) |
827 | remote_host = host0; | 849 | remote_host = host0; |
850 | else | ||
851 | continue; | ||
828 | 852 | ||
829 | if (remote_host >= SMEM_HOST_COUNT) { | 853 | if (remote_host >= SMEM_HOST_COUNT) { |
830 | dev_err(smem->dev, | 854 | dev_err(smem->dev, "bad host %hu\n", remote_host); |
831 | "Invalid remote host %d\n", | ||
832 | remote_host); | ||
833 | return -EINVAL; | 855 | return -EINVAL; |
834 | } | 856 | } |
835 | 857 | ||
836 | if (smem->partitions[remote_host]) { | 858 | if (smem->partitions[remote_host]) { |
837 | dev_err(smem->dev, | 859 | dev_err(smem->dev, "duplicate host %hu\n", remote_host); |
838 | "Already found a partition for host %d\n", | ||
839 | remote_host); | ||
840 | return -EINVAL; | ||
841 | } | ||
842 | |||
843 | header = smem->regions[0].virt_base + le32_to_cpu(entry->offset); | ||
844 | host0 = le16_to_cpu(header->host0); | ||
845 | host1 = le16_to_cpu(header->host1); | ||
846 | |||
847 | if (memcmp(header->magic, SMEM_PART_MAGIC, | ||
848 | sizeof(header->magic))) { | ||
849 | dev_err(smem->dev, | ||
850 | "Partition %d has invalid magic\n", i); | ||
851 | return -EINVAL; | 860 | return -EINVAL; |
852 | } | 861 | } |
853 | 862 | ||
854 | if (host0 != local_host && host1 != local_host) { | 863 | header = qcom_smem_partition_header(smem, entry, host0, host1); |
855 | dev_err(smem->dev, | 864 | if (!header) |
856 | "Partition %d hosts are invalid\n", i); | ||
857 | return -EINVAL; | 865 | return -EINVAL; |
858 | } | ||
859 | |||
860 | if (host0 != remote_host && host1 != remote_host) { | ||
861 | dev_err(smem->dev, | ||
862 | "Partition %d hosts are invalid\n", i); | ||
863 | return -EINVAL; | ||
864 | } | ||
865 | |||
866 | if (le32_to_cpu(header->size) != le32_to_cpu(entry->size)) { | ||
867 | dev_err(smem->dev, | ||
868 | "Partition %d has invalid size\n", i); | ||
869 | return -EINVAL; | ||
870 | } | ||
871 | |||
872 | if (le32_to_cpu(header->offset_free_uncached) > le32_to_cpu(header->size)) { | ||
873 | dev_err(smem->dev, | ||
874 | "Partition %d has invalid free pointer\n", i); | ||
875 | return -EINVAL; | ||
876 | } | ||
877 | 866 | ||
878 | smem->partitions[remote_host] = header; | 867 | smem->partitions[remote_host] = header; |
879 | smem->cacheline[remote_host] = le32_to_cpu(entry->cacheline); | 868 | smem->cacheline[remote_host] = le32_to_cpu(entry->cacheline); |
@@ -887,6 +876,7 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev, | |||
887 | { | 876 | { |
888 | struct device_node *np; | 877 | struct device_node *np; |
889 | struct resource r; | 878 | struct resource r; |
879 | resource_size_t size; | ||
890 | int ret; | 880 | int ret; |
891 | 881 | ||
892 | np = of_parse_phandle(dev->of_node, name, 0); | 882 | np = of_parse_phandle(dev->of_node, name, 0); |
@@ -899,12 +889,13 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev, | |||
899 | of_node_put(np); | 889 | of_node_put(np); |
900 | if (ret) | 890 | if (ret) |
901 | return ret; | 891 | return ret; |
892 | size = resource_size(&r); | ||
902 | 893 | ||
903 | smem->regions[i].aux_base = (u32)r.start; | 894 | smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, size); |
904 | smem->regions[i].size = resource_size(&r); | ||
905 | smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, resource_size(&r)); | ||
906 | if (!smem->regions[i].virt_base) | 895 | if (!smem->regions[i].virt_base) |
907 | return -ENOMEM; | 896 | return -ENOMEM; |
897 | smem->regions[i].aux_base = (u32)r.start; | ||
898 | smem->regions[i].size = size; | ||
908 | 899 | ||
909 | return 0; | 900 | return 0; |
910 | } | 901 | } |
@@ -962,6 +953,7 @@ static int qcom_smem_probe(struct platform_device *pdev) | |||
962 | return -EINVAL; | 953 | return -EINVAL; |
963 | } | 954 | } |
964 | 955 | ||
956 | BUILD_BUG_ON(SMEM_HOST_APPS >= SMEM_HOST_COUNT); | ||
965 | ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS); | 957 | ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS); |
966 | if (ret < 0 && ret != -ENOENT) | 958 | if (ret < 0 && ret != -ENOENT) |
967 | return ret; | 959 | return ret; |
diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c index f9d7a85b2822..53807e839664 100644 --- a/drivers/soc/qcom/spm.c +++ b/drivers/soc/qcom/spm.c | |||
@@ -219,6 +219,9 @@ static int __init qcom_cpuidle_init(struct device_node *cpu_node, int cpu) | |||
219 | cpumask_t mask; | 219 | cpumask_t mask; |
220 | bool use_scm_power_down = false; | 220 | bool use_scm_power_down = false; |
221 | 221 | ||
222 | if (!qcom_scm_is_available()) | ||
223 | return -EPROBE_DEFER; | ||
224 | |||
222 | for (i = 0; ; i++) { | 225 | for (i = 0; ; i++) { |
223 | state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i); | 226 | state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i); |
224 | if (!state_node) | 227 | if (!state_node) |
diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c index df3ccb30bc2d..373400dd816d 100644 --- a/drivers/soc/qcom/wcnss_ctrl.c +++ b/drivers/soc/qcom/wcnss_ctrl.c | |||
@@ -281,7 +281,7 @@ struct rpmsg_endpoint *qcom_wcnss_open_channel(void *wcnss, const char *name, rp | |||
281 | struct rpmsg_channel_info chinfo; | 281 | struct rpmsg_channel_info chinfo; |
282 | struct wcnss_ctrl *_wcnss = wcnss; | 282 | struct wcnss_ctrl *_wcnss = wcnss; |
283 | 283 | ||
284 | strncpy(chinfo.name, name, sizeof(chinfo.name)); | 284 | strscpy(chinfo.name, name, sizeof(chinfo.name)); |
285 | chinfo.src = RPMSG_ADDR_ANY; | 285 | chinfo.src = RPMSG_ADDR_ANY; |
286 | chinfo.dst = RPMSG_ADDR_ANY; | 286 | chinfo.dst = RPMSG_ADDR_ANY; |
287 | 287 | ||
diff --git a/include/linux/soc/qcom/llcc-qcom.h b/include/linux/soc/qcom/llcc-qcom.h index 7e3b9c605ab2..69c285b1c990 100644 --- a/include/linux/soc/qcom/llcc-qcom.h +++ b/include/linux/soc/qcom/llcc-qcom.h | |||
@@ -70,25 +70,51 @@ struct llcc_slice_config { | |||
70 | /** | 70 | /** |
71 | * llcc_drv_data - Data associated with the llcc driver | 71 | * llcc_drv_data - Data associated with the llcc driver |
72 | * @regmap: regmap associated with the llcc device | 72 | * @regmap: regmap associated with the llcc device |
73 | * @bcast_regmap: regmap associated with llcc broadcast offset | ||
73 | * @cfg: pointer to the data structure for slice configuration | 74 | * @cfg: pointer to the data structure for slice configuration |
74 | * @lock: mutex associated with each slice | 75 | * @lock: mutex associated with each slice |
75 | * @cfg_size: size of the config data table | 76 | * @cfg_size: size of the config data table |
76 | * @max_slices: max slices as read from device tree | 77 | * @max_slices: max slices as read from device tree |
77 | * @bcast_off: Offset of the broadcast bank | ||
78 | * @num_banks: Number of llcc banks | 78 | * @num_banks: Number of llcc banks |
79 | * @bitmap: Bit map to track the active slice ids | 79 | * @bitmap: Bit map to track the active slice ids |
80 | * @offsets: Pointer to the bank offsets array | 80 | * @offsets: Pointer to the bank offsets array |
81 | * @ecc_irq: interrupt for llcc cache error detection and reporting | ||
81 | */ | 82 | */ |
82 | struct llcc_drv_data { | 83 | struct llcc_drv_data { |
83 | struct regmap *regmap; | 84 | struct regmap *regmap; |
85 | struct regmap *bcast_regmap; | ||
84 | const struct llcc_slice_config *cfg; | 86 | const struct llcc_slice_config *cfg; |
85 | struct mutex lock; | 87 | struct mutex lock; |
86 | u32 cfg_size; | 88 | u32 cfg_size; |
87 | u32 max_slices; | 89 | u32 max_slices; |
88 | u32 bcast_off; | ||
89 | u32 num_banks; | 90 | u32 num_banks; |
90 | unsigned long *bitmap; | 91 | unsigned long *bitmap; |
91 | u32 *offsets; | 92 | u32 *offsets; |
93 | int ecc_irq; | ||
94 | }; | ||
95 | |||
96 | /** | ||
97 | * llcc_edac_reg_data - llcc edac registers data for each error type | ||
98 | * @name: Name of the error | ||
99 | * @synd_reg: Syndrome register address | ||
100 | * @count_status_reg: Status register address to read the error count | ||
101 | * @ways_status_reg: Status register address to read the error ways | ||
102 | * @reg_cnt: Number of registers | ||
103 | * @count_mask: Mask value to get the error count | ||
104 | * @ways_mask: Mask value to get the error ways | ||
105 | * @count_shift: Shift value to get the error count | ||
106 | * @ways_shift: Shift value to get the error ways | ||
107 | */ | ||
108 | struct llcc_edac_reg_data { | ||
109 | char *name; | ||
110 | u64 synd_reg; | ||
111 | u64 count_status_reg; | ||
112 | u64 ways_status_reg; | ||
113 | u32 reg_cnt; | ||
114 | u32 count_mask; | ||
115 | u32 ways_mask; | ||
116 | u8 count_shift; | ||
117 | u8 ways_shift; | ||
92 | }; | 118 | }; |
93 | 119 | ||
94 | #if IS_ENABLED(CONFIG_QCOM_LLCC) | 120 | #if IS_ENABLED(CONFIG_QCOM_LLCC) |