diff options
| -rw-r--r-- | Documentation/devicetree/bindings/edac/socfpga-eccmgr.txt (renamed from Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt) | 35 | ||||
| -rw-r--r-- | arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts | 6 | ||||
| -rw-r--r-- | arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi | 83 | ||||
| -rw-r--r-- | arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts | 44 | ||||
| -rw-r--r-- | drivers/acpi/apei/ghes.c | 16 | ||||
| -rw-r--r-- | drivers/edac/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/edac/altera_edac.c | 504 | ||||
| -rw-r--r-- | drivers/edac/altera_edac.h | 132 | ||||
| -rw-r--r-- | drivers/edac/ghes_edac.c | 55 | ||||
| -rw-r--r-- | drivers/edac/i7core_edac.c | 2 | ||||
| -rw-r--r-- | include/acpi/ghes.h | 7 |
11 files changed, 817 insertions, 70 deletions
diff --git a/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt b/Documentation/devicetree/bindings/edac/socfpga-eccmgr.txt index 4a1714f96bab..5626560a6cfd 100644 --- a/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt +++ b/Documentation/devicetree/bindings/edac/socfpga-eccmgr.txt | |||
| @@ -231,3 +231,38 @@ Example: | |||
| 231 | <48 IRQ_TYPE_LEVEL_HIGH>; | 231 | <48 IRQ_TYPE_LEVEL_HIGH>; |
| 232 | }; | 232 | }; |
| 233 | }; | 233 | }; |
| 234 | |||
| 235 | Stratix10 SoCFPGA ECC Manager | ||
| 236 | The Stratix10 SoC ECC Manager handles the IRQs for each peripheral | ||
| 237 | in a shared register similar to the Arria10. However, ECC requires | ||
| 238 | access to registers that can only be read from Secure Monitor with | ||
| 239 | SMC calls. Therefore the device tree is slightly different. | ||
| 240 | |||
| 241 | Required Properties: | ||
| 242 | - compatible : Should be "altr,socfpga-s10-ecc-manager" | ||
| 243 | - interrupts : Should be single bit error interrupt, then double bit error | ||
| 244 | interrupt. | ||
| 245 | - interrupt-controller : boolean indicator that ECC Manager is an interrupt controller | ||
| 246 | - #interrupt-cells : must be set to 2. | ||
| 247 | |||
| 248 | Subcomponents: | ||
| 249 | |||
| 250 | SDRAM ECC | ||
| 251 | Required Properties: | ||
| 252 | - compatible : Should be "altr,sdram-edac-s10" | ||
| 253 | - interrupts : Should be single bit error interrupt, then double bit error | ||
| 254 | interrupt, in this order. | ||
| 255 | |||
| 256 | Example: | ||
| 257 | |||
| 258 | eccmgr { | ||
| 259 | compatible = "altr,socfpga-s10-ecc-manager"; | ||
| 260 | interrupts = <0 15 4>, <0 95 4>; | ||
| 261 | interrupt-controller; | ||
| 262 | #interrupt-cells = <2>; | ||
| 263 | |||
| 264 | sdramedac { | ||
| 265 | compatible = "altr,sdram-edac-s10"; | ||
| 266 | interrupts = <16 4>, <48 4>; | ||
| 267 | }; | ||
| 268 | }; | ||
diff --git a/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts b/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts index 2459d133f1be..f50b19447de6 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts | |||
| @@ -161,7 +161,7 @@ | |||
| 161 | }; | 161 | }; |
| 162 | 162 | ||
| 163 | at24@50 { | 163 | at24@50 { |
| 164 | compatible = "at24,24c01"; | 164 | compatible = "atmel,24c01"; |
| 165 | pagesize = <8>; | 165 | pagesize = <8>; |
| 166 | reg = <0x50>; | 166 | reg = <0x50>; |
| 167 | }; | 167 | }; |
| @@ -213,7 +213,7 @@ | |||
| 213 | #size-cells = <0>; | 213 | #size-cells = <0>; |
| 214 | reg = <6>; | 214 | reg = <6>; |
| 215 | eeprom@51 { | 215 | eeprom@51 { |
| 216 | compatible = "at,24c01"; | 216 | compatible = "atmel,24c01"; |
| 217 | pagesize = <8>; | 217 | pagesize = <8>; |
| 218 | reg = <0x51>; | 218 | reg = <0x51>; |
| 219 | }; | 219 | }; |
| @@ -224,7 +224,7 @@ | |||
| 224 | #size-cells = <0>; | 224 | #size-cells = <0>; |
| 225 | reg = <7>; | 225 | reg = <7>; |
| 226 | eeprom@51 { | 226 | eeprom@51 { |
| 227 | compatible = "at,24c01"; | 227 | compatible = "atmel,24c01"; |
| 228 | pagesize = <8>; | 228 | pagesize = <8>; |
| 229 | reg = <0x51>; | 229 | reg = <0x51>; |
| 230 | }; | 230 | }; |
diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi index c89d0c307f8d..e6b059378dc0 100644 --- a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi +++ b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | /dts-v1/; | 17 | /dts-v1/; |
| 18 | #include <dt-bindings/reset/altr,rst-mgr-s10.h> | 18 | #include <dt-bindings/reset/altr,rst-mgr-s10.h> |
| 19 | #include <dt-bindings/gpio/gpio.h> | 19 | #include <dt-bindings/gpio/gpio.h> |
| 20 | #include <dt-bindings/clock/stratix10-clock.h> | ||
| 20 | 21 | ||
| 21 | / { | 22 | / { |
| 22 | compatible = "altr,socfpga-stratix10"; | 23 | compatible = "altr,socfpga-stratix10"; |
| @@ -92,9 +93,32 @@ | |||
| 92 | interrupt-parent = <&intc>; | 93 | interrupt-parent = <&intc>; |
| 93 | ranges = <0 0 0 0xffffffff>; | 94 | ranges = <0 0 0 0xffffffff>; |
| 94 | 95 | ||
| 95 | clkmgr@ffd1000 { | 96 | clkmgr: clock-controller@ffd10000 { |
| 96 | compatible = "altr,clk-mgr"; | 97 | compatible = "intel,stratix10-clkmgr"; |
| 97 | reg = <0xffd10000 0x1000>; | 98 | reg = <0xffd10000 0x1000>; |
| 99 | #clock-cells = <1>; | ||
| 100 | }; | ||
| 101 | |||
| 102 | clocks { | ||
| 103 | cb_intosc_hs_div2_clk: cb-intosc-hs-div2-clk { | ||
| 104 | #clock-cells = <0>; | ||
| 105 | compatible = "fixed-clock"; | ||
| 106 | }; | ||
| 107 | |||
| 108 | cb_intosc_ls_clk: cb-intosc-ls-clk { | ||
| 109 | #clock-cells = <0>; | ||
| 110 | compatible = "fixed-clock"; | ||
| 111 | }; | ||
| 112 | |||
| 113 | f2s_free_clk: f2s-free-clk { | ||
| 114 | #clock-cells = <0>; | ||
| 115 | compatible = "fixed-clock"; | ||
| 116 | }; | ||
| 117 | |||
| 118 | osc1: osc1 { | ||
| 119 | #clock-cells = <0>; | ||
| 120 | compatible = "fixed-clock"; | ||
| 121 | }; | ||
| 98 | }; | 122 | }; |
| 99 | 123 | ||
| 100 | gmac0: ethernet@ff800000 { | 124 | gmac0: ethernet@ff800000 { |
| @@ -105,6 +129,8 @@ | |||
| 105 | mac-address = [00 00 00 00 00 00]; | 129 | mac-address = [00 00 00 00 00 00]; |
| 106 | resets = <&rst EMAC0_RESET>; | 130 | resets = <&rst EMAC0_RESET>; |
| 107 | reset-names = "stmmaceth"; | 131 | reset-names = "stmmaceth"; |
| 132 | clocks = <&clkmgr STRATIX10_EMAC0_CLK>; | ||
| 133 | clock-names = "stmmaceth"; | ||
| 108 | status = "disabled"; | 134 | status = "disabled"; |
| 109 | }; | 135 | }; |
| 110 | 136 | ||
| @@ -116,6 +142,8 @@ | |||
| 116 | mac-address = [00 00 00 00 00 00]; | 142 | mac-address = [00 00 00 00 00 00]; |
| 117 | resets = <&rst EMAC1_RESET>; | 143 | resets = <&rst EMAC1_RESET>; |
| 118 | reset-names = "stmmaceth"; | 144 | reset-names = "stmmaceth"; |
| 145 | clocks = <&clkmgr STRATIX10_EMAC1_CLK>; | ||
| 146 | clock-names = "stmmaceth"; | ||
| 119 | status = "disabled"; | 147 | status = "disabled"; |
| 120 | }; | 148 | }; |
| 121 | 149 | ||
| @@ -127,6 +155,8 @@ | |||
| 127 | mac-address = [00 00 00 00 00 00]; | 155 | mac-address = [00 00 00 00 00 00]; |
| 128 | resets = <&rst EMAC2_RESET>; | 156 | resets = <&rst EMAC2_RESET>; |
| 129 | reset-names = "stmmaceth"; | 157 | reset-names = "stmmaceth"; |
| 158 | clocks = <&clkmgr STRATIX10_EMAC2_CLK>; | ||
| 159 | clock-names = "stmmaceth"; | ||
| 130 | status = "disabled"; | 160 | status = "disabled"; |
| 131 | }; | 161 | }; |
| 132 | 162 | ||
| @@ -177,6 +207,7 @@ | |||
| 177 | reg = <0xffc02800 0x100>; | 207 | reg = <0xffc02800 0x100>; |
| 178 | interrupts = <0 103 4>; | 208 | interrupts = <0 103 4>; |
| 179 | resets = <&rst I2C0_RESET>; | 209 | resets = <&rst I2C0_RESET>; |
| 210 | clocks = <&clkmgr STRATIX10_L4_SP_CLK>; | ||
| 180 | status = "disabled"; | 211 | status = "disabled"; |
| 181 | }; | 212 | }; |
| 182 | 213 | ||
| @@ -187,6 +218,7 @@ | |||
| 187 | reg = <0xffc02900 0x100>; | 218 | reg = <0xffc02900 0x100>; |
| 188 | interrupts = <0 104 4>; | 219 | interrupts = <0 104 4>; |
| 189 | resets = <&rst I2C1_RESET>; | 220 | resets = <&rst I2C1_RESET>; |
| 221 | clocks = <&clkmgr STRATIX10_L4_SP_CLK>; | ||
| 190 | status = "disabled"; | 222 | status = "disabled"; |
| 191 | }; | 223 | }; |
| 192 | 224 | ||
| @@ -197,6 +229,7 @@ | |||
| 197 | reg = <0xffc02a00 0x100>; | 229 | reg = <0xffc02a00 0x100>; |
| 198 | interrupts = <0 105 4>; | 230 | interrupts = <0 105 4>; |
| 199 | resets = <&rst I2C2_RESET>; | 231 | resets = <&rst I2C2_RESET>; |
| 232 | clocks = <&clkmgr STRATIX10_L4_SP_CLK>; | ||
| 200 | status = "disabled"; | 233 | status = "disabled"; |
| 201 | }; | 234 | }; |
| 202 | 235 | ||
| @@ -207,6 +240,7 @@ | |||
| 207 | reg = <0xffc02b00 0x100>; | 240 | reg = <0xffc02b00 0x100>; |
| 208 | interrupts = <0 106 4>; | 241 | interrupts = <0 106 4>; |
| 209 | resets = <&rst I2C3_RESET>; | 242 | resets = <&rst I2C3_RESET>; |
| 243 | clocks = <&clkmgr STRATIX10_L4_SP_CLK>; | ||
| 210 | status = "disabled"; | 244 | status = "disabled"; |
| 211 | }; | 245 | }; |
| 212 | 246 | ||
| @@ -217,6 +251,7 @@ | |||
| 217 | reg = <0xffc02c00 0x100>; | 251 | reg = <0xffc02c00 0x100>; |
| 218 | interrupts = <0 107 4>; | 252 | interrupts = <0 107 4>; |
| 219 | resets = <&rst I2C4_RESET>; | 253 | resets = <&rst I2C4_RESET>; |
| 254 | clocks = <&clkmgr STRATIX10_L4_SP_CLK>; | ||
| 220 | status = "disabled"; | 255 | status = "disabled"; |
| 221 | }; | 256 | }; |
| 222 | 257 | ||
| @@ -229,6 +264,9 @@ | |||
| 229 | fifo-depth = <0x400>; | 264 | fifo-depth = <0x400>; |
| 230 | resets = <&rst SDMMC_RESET>; | 265 | resets = <&rst SDMMC_RESET>; |
| 231 | reset-names = "reset"; | 266 | reset-names = "reset"; |
| 267 | clocks = <&clkmgr STRATIX10_L4_MP_CLK>, | ||
| 268 | <&clkmgr STRATIX10_SDMMC_CLK>; | ||
| 269 | clock-names = "biu", "ciu"; | ||
| 232 | status = "disabled"; | 270 | status = "disabled"; |
| 233 | }; | 271 | }; |
| 234 | 272 | ||
| @@ -237,6 +275,25 @@ | |||
| 237 | reg = <0xffe00000 0x100000>; | 275 | reg = <0xffe00000 0x100000>; |
| 238 | }; | 276 | }; |
| 239 | 277 | ||
| 278 | pdma: pdma@ffda0000 { | ||
| 279 | compatible = "arm,pl330", "arm,primecell"; | ||
| 280 | reg = <0xffda0000 0x1000>; | ||
| 281 | interrupts = <0 81 4>, | ||
| 282 | <0 82 4>, | ||
| 283 | <0 83 4>, | ||
| 284 | <0 84 4>, | ||
| 285 | <0 85 4>, | ||
| 286 | <0 86 4>, | ||
| 287 | <0 87 4>, | ||
| 288 | <0 88 4>, | ||
| 289 | <0 89 4>; | ||
| 290 | #dma-cells = <1>; | ||
| 291 | #dma-channels = <8>; | ||
| 292 | #dma-requests = <32>; | ||
| 293 | clocks = <&clkmgr STRATIX10_L4_MAIN_CLK>; | ||
| 294 | clock-names = "apb_pclk"; | ||
| 295 | }; | ||
| 296 | |||
| 240 | rst: rstmgr@ffd11000 { | 297 | rst: rstmgr@ffd11000 { |
| 241 | #reset-cells = <1>; | 298 | #reset-cells = <1>; |
| 242 | compatible = "altr,rst-mgr"; | 299 | compatible = "altr,rst-mgr"; |
| @@ -288,24 +345,32 @@ | |||
| 288 | compatible = "snps,dw-apb-timer"; | 345 | compatible = "snps,dw-apb-timer"; |
| 289 | interrupts = <0 113 4>; | 346 | interrupts = <0 113 4>; |
| 290 | reg = <0xffc03000 0x100>; | 347 | reg = <0xffc03000 0x100>; |
| 348 | clocks = <&clkmgr STRATIX10_L4_SP_CLK>; | ||
| 349 | clock-names = "timer"; | ||
| 291 | }; | 350 | }; |
| 292 | 351 | ||
| 293 | timer1: timer1@ffc03100 { | 352 | timer1: timer1@ffc03100 { |
| 294 | compatible = "snps,dw-apb-timer"; | 353 | compatible = "snps,dw-apb-timer"; |
| 295 | interrupts = <0 114 4>; | 354 | interrupts = <0 114 4>; |
| 296 | reg = <0xffc03100 0x100>; | 355 | reg = <0xffc03100 0x100>; |
| 356 | clocks = <&clkmgr STRATIX10_L4_SP_CLK>; | ||
| 357 | clock-names = "timer"; | ||
| 297 | }; | 358 | }; |
| 298 | 359 | ||
| 299 | timer2: timer2@ffd00000 { | 360 | timer2: timer2@ffd00000 { |
| 300 | compatible = "snps,dw-apb-timer"; | 361 | compatible = "snps,dw-apb-timer"; |
| 301 | interrupts = <0 115 4>; | 362 | interrupts = <0 115 4>; |
| 302 | reg = <0xffd00000 0x100>; | 363 | reg = <0xffd00000 0x100>; |
| 364 | clocks = <&clkmgr STRATIX10_L4_SP_CLK>; | ||
| 365 | clock-names = "timer"; | ||
| 303 | }; | 366 | }; |
| 304 | 367 | ||
| 305 | timer3: timer3@ffd00100 { | 368 | timer3: timer3@ffd00100 { |
| 306 | compatible = "snps,dw-apb-timer"; | 369 | compatible = "snps,dw-apb-timer"; |
| 307 | interrupts = <0 116 4>; | 370 | interrupts = <0 116 4>; |
| 308 | reg = <0xffd00100 0x100>; | 371 | reg = <0xffd00100 0x100>; |
| 372 | clocks = <&clkmgr STRATIX10_L4_SP_CLK>; | ||
| 373 | clock-names = "timer"; | ||
| 309 | }; | 374 | }; |
| 310 | 375 | ||
| 311 | uart0: serial0@ffc02000 { | 376 | uart0: serial0@ffc02000 { |
| @@ -315,6 +380,7 @@ | |||
| 315 | reg-shift = <2>; | 380 | reg-shift = <2>; |
| 316 | reg-io-width = <4>; | 381 | reg-io-width = <4>; |
| 317 | resets = <&rst UART0_RESET>; | 382 | resets = <&rst UART0_RESET>; |
| 383 | clocks = <&clkmgr STRATIX10_L4_SP_CLK>; | ||
| 318 | status = "disabled"; | 384 | status = "disabled"; |
| 319 | }; | 385 | }; |
| 320 | 386 | ||
| @@ -325,6 +391,7 @@ | |||
| 325 | reg-shift = <2>; | 391 | reg-shift = <2>; |
| 326 | reg-io-width = <4>; | 392 | reg-io-width = <4>; |
| 327 | resets = <&rst UART1_RESET>; | 393 | resets = <&rst UART1_RESET>; |
| 394 | clocks = <&clkmgr STRATIX10_L4_SP_CLK>; | ||
| 328 | status = "disabled"; | 395 | status = "disabled"; |
| 329 | }; | 396 | }; |
| 330 | 397 | ||
| @@ -387,5 +454,17 @@ | |||
| 387 | resets = <&rst WATCHDOG3_RESET>; | 454 | resets = <&rst WATCHDOG3_RESET>; |
| 388 | status = "disabled"; | 455 | status = "disabled"; |
| 389 | }; | 456 | }; |
| 457 | |||
| 458 | eccmgr { | ||
| 459 | compatible = "altr,socfpga-s10-ecc-manager"; | ||
| 460 | interrupts = <0 15 4>, <0 95 4>; | ||
| 461 | interrupt-controller; | ||
| 462 | #interrupt-cells = <2>; | ||
| 463 | |||
| 464 | sdramedac { | ||
| 465 | compatible = "altr,sdram-edac-s10"; | ||
| 466 | interrupts = <16 4>, <48 4>; | ||
| 467 | }; | ||
| 468 | }; | ||
| 390 | }; | 469 | }; |
| 391 | }; | 470 | }; |
diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts index eaf13fe29287..f9b1ef12db48 100644 --- a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts +++ b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts | |||
| @@ -50,6 +50,21 @@ | |||
| 50 | /* We expect the bootloader to fill in the reg */ | 50 | /* We expect the bootloader to fill in the reg */ |
| 51 | reg = <0 0 0 0>; | 51 | reg = <0 0 0 0>; |
| 52 | }; | 52 | }; |
| 53 | |||
| 54 | ref_033v: 033-v-ref { | ||
| 55 | compatible = "regulator-fixed"; | ||
| 56 | regulator-name = "0.33V"; | ||
| 57 | regulator-min-microvolt = <330000>; | ||
| 58 | regulator-max-microvolt = <330000>; | ||
| 59 | }; | ||
| 60 | |||
| 61 | soc { | ||
| 62 | clocks { | ||
| 63 | osc1 { | ||
| 64 | clock-frequency = <25000000>; | ||
| 65 | }; | ||
| 66 | }; | ||
| 67 | }; | ||
| 53 | }; | 68 | }; |
| 54 | 69 | ||
| 55 | &gpio1 { | 70 | &gpio1 { |
| @@ -79,7 +94,7 @@ | |||
| 79 | rxd2-skew-ps = <420>; /* 0ps */ | 94 | rxd2-skew-ps = <420>; /* 0ps */ |
| 80 | rxd3-skew-ps = <420>; /* 0ps */ | 95 | rxd3-skew-ps = <420>; /* 0ps */ |
| 81 | txen-skew-ps = <0>; /* -420ps */ | 96 | txen-skew-ps = <0>; /* -420ps */ |
| 82 | txc-skew-ps = <1860>; /* 960ps */ | 97 | txc-skew-ps = <900>; /* 0ps */ |
| 83 | rxdv-skew-ps = <420>; /* 0ps */ | 98 | rxdv-skew-ps = <420>; /* 0ps */ |
| 84 | rxc-skew-ps = <1680>; /* 780ps */ | 99 | rxc-skew-ps = <1680>; /* 780ps */ |
| 85 | }; | 100 | }; |
| @@ -105,3 +120,30 @@ | |||
| 105 | &watchdog0 { | 120 | &watchdog0 { |
| 106 | status = "okay"; | 121 | status = "okay"; |
| 107 | }; | 122 | }; |
| 123 | |||
| 124 | &i2c1 { | ||
| 125 | status = "okay"; | ||
| 126 | clock-frequency = <100000>; | ||
| 127 | |||
| 128 | adc@14 { | ||
| 129 | compatible = "lltc,ltc2497"; | ||
| 130 | reg = <0x14>; | ||
| 131 | vref-supply = <&ref_033v>; | ||
| 132 | }; | ||
| 133 | |||
| 134 | temp@4c { | ||
| 135 | compatible = "maxim,max1619"; | ||
| 136 | reg = <0x4c>; | ||
| 137 | }; | ||
| 138 | |||
| 139 | eeprom@51 { | ||
| 140 | compatible = "atmel,24c32"; | ||
| 141 | reg = <0x51>; | ||
| 142 | pagesize = <32>; | ||
| 143 | }; | ||
| 144 | |||
| 145 | rtc@68 { | ||
| 146 | compatible = "dallas,ds1339"; | ||
| 147 | reg = <0x68>; | ||
| 148 | }; | ||
| 149 | }; | ||
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 1efefe919555..02c6fd9caff7 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c | |||
| @@ -481,7 +481,7 @@ static void ghes_do_proc(struct ghes *ghes, | |||
| 481 | if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) { | 481 | if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) { |
| 482 | struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata); | 482 | struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata); |
| 483 | 483 | ||
| 484 | ghes_edac_report_mem_error(ghes, sev, mem_err); | 484 | ghes_edac_report_mem_error(sev, mem_err); |
| 485 | 485 | ||
| 486 | arch_apei_report_mem_error(sev, mem_err); | 486 | arch_apei_report_mem_error(sev, mem_err); |
| 487 | ghes_handle_memory_failure(gdata, sev); | 487 | ghes_handle_memory_failure(gdata, sev); |
| @@ -1087,10 +1087,6 @@ static int ghes_probe(struct platform_device *ghes_dev) | |||
| 1087 | goto err; | 1087 | goto err; |
| 1088 | } | 1088 | } |
| 1089 | 1089 | ||
| 1090 | rc = ghes_edac_register(ghes, &ghes_dev->dev); | ||
| 1091 | if (rc < 0) | ||
| 1092 | goto err; | ||
| 1093 | |||
| 1094 | switch (generic->notify.type) { | 1090 | switch (generic->notify.type) { |
| 1095 | case ACPI_HEST_NOTIFY_POLLED: | 1091 | case ACPI_HEST_NOTIFY_POLLED: |
| 1096 | timer_setup(&ghes->timer, ghes_poll_func, TIMER_DEFERRABLE); | 1092 | timer_setup(&ghes->timer, ghes_poll_func, TIMER_DEFERRABLE); |
| @@ -1102,14 +1098,14 @@ static int ghes_probe(struct platform_device *ghes_dev) | |||
| 1102 | if (rc) { | 1098 | if (rc) { |
| 1103 | pr_err(GHES_PFX "Failed to map GSI to IRQ for generic hardware error source: %d\n", | 1099 | pr_err(GHES_PFX "Failed to map GSI to IRQ for generic hardware error source: %d\n", |
| 1104 | generic->header.source_id); | 1100 | generic->header.source_id); |
| 1105 | goto err_edac_unreg; | 1101 | goto err; |
| 1106 | } | 1102 | } |
| 1107 | rc = request_irq(ghes->irq, ghes_irq_func, IRQF_SHARED, | 1103 | rc = request_irq(ghes->irq, ghes_irq_func, IRQF_SHARED, |
| 1108 | "GHES IRQ", ghes); | 1104 | "GHES IRQ", ghes); |
| 1109 | if (rc) { | 1105 | if (rc) { |
| 1110 | pr_err(GHES_PFX "Failed to register IRQ for generic hardware error source: %d\n", | 1106 | pr_err(GHES_PFX "Failed to register IRQ for generic hardware error source: %d\n", |
| 1111 | generic->header.source_id); | 1107 | generic->header.source_id); |
| 1112 | goto err_edac_unreg; | 1108 | goto err; |
| 1113 | } | 1109 | } |
| 1114 | break; | 1110 | break; |
| 1115 | 1111 | ||
| @@ -1132,14 +1128,16 @@ static int ghes_probe(struct platform_device *ghes_dev) | |||
| 1132 | default: | 1128 | default: |
| 1133 | BUG(); | 1129 | BUG(); |
| 1134 | } | 1130 | } |
| 1131 | |||
| 1135 | platform_set_drvdata(ghes_dev, ghes); | 1132 | platform_set_drvdata(ghes_dev, ghes); |
| 1136 | 1133 | ||
| 1134 | ghes_edac_register(ghes, &ghes_dev->dev); | ||
| 1135 | |||
| 1137 | /* Handle any pending errors right away */ | 1136 | /* Handle any pending errors right away */ |
| 1138 | ghes_proc(ghes); | 1137 | ghes_proc(ghes); |
| 1139 | 1138 | ||
| 1140 | return 0; | 1139 | return 0; |
| 1141 | err_edac_unreg: | 1140 | |
| 1142 | ghes_edac_unregister(ghes); | ||
| 1143 | err: | 1141 | err: |
| 1144 | if (ghes) { | 1142 | if (ghes) { |
| 1145 | ghes_fini(ghes); | 1143 | ghes_fini(ghes); |
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index da2da53bca6d..57304b2e989f 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig | |||
| @@ -232,6 +232,7 @@ config EDAC_SBRIDGE | |||
| 232 | config EDAC_SKX | 232 | config EDAC_SKX |
| 233 | tristate "Intel Skylake server Integrated MC" | 233 | tristate "Intel Skylake server Integrated MC" |
| 234 | depends on PCI && X86_64 && X86_MCE_INTEL && PCI_MMCONFIG | 234 | depends on PCI && X86_64 && X86_MCE_INTEL && PCI_MMCONFIG |
| 235 | depends on ACPI_NFIT || !ACPI_NFIT # if ACPI_NFIT=m, EDAC_SKX can't be y | ||
| 235 | select DMI | 236 | select DMI |
| 236 | help | 237 | help |
| 237 | Support for error detection and correction the Intel | 238 | Support for error detection and correction the Intel |
| @@ -374,7 +375,7 @@ config EDAC_THUNDERX | |||
| 374 | 375 | ||
| 375 | config EDAC_ALTERA | 376 | config EDAC_ALTERA |
| 376 | bool "Altera SOCFPGA ECC" | 377 | bool "Altera SOCFPGA ECC" |
| 377 | depends on EDAC=y && ARCH_SOCFPGA | 378 | depends on EDAC=y && (ARCH_SOCFPGA || ARCH_STRATIX10) |
| 378 | help | 379 | help |
| 379 | Support for error detection and correction on the | 380 | Support for error detection and correction on the |
| 380 | Altera SOCs. This must be selected for SDRAM ECC. | 381 | Altera SOCs. This must be selected for SDRAM ECC. |
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 11d6419788c2..d0d5c4dbe097 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c | |||
| @@ -1,20 +1,8 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 1 | /* | 2 | /* |
| 3 | * Copyright (C) 2017-2018, Intel Corporation. All rights reserved | ||
| 2 | * Copyright Altera Corporation (C) 2014-2016. All rights reserved. | 4 | * Copyright Altera Corporation (C) 2014-2016. All rights reserved. |
| 3 | * Copyright 2011-2012 Calxeda, Inc. | 5 | * Copyright 2011-2012 Calxeda, Inc. |
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms and conditions of the GNU General Public License, | ||
| 7 | * version 2, as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License along with | ||
| 15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | * | ||
| 17 | * Adapted from the highbank_mc_edac driver. | ||
| 18 | */ | 6 | */ |
| 19 | 7 | ||
| 20 | #include <asm/cacheflush.h> | 8 | #include <asm/cacheflush.h> |
| @@ -26,6 +14,7 @@ | |||
| 26 | #include <linux/irqchip/chained_irq.h> | 14 | #include <linux/irqchip/chained_irq.h> |
| 27 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 28 | #include <linux/mfd/syscon.h> | 16 | #include <linux/mfd/syscon.h> |
| 17 | #include <linux/notifier.h> | ||
| 29 | #include <linux/of_address.h> | 18 | #include <linux/of_address.h> |
| 30 | #include <linux/of_irq.h> | 19 | #include <linux/of_irq.h> |
| 31 | #include <linux/of_platform.h> | 20 | #include <linux/of_platform.h> |
| @@ -80,6 +69,25 @@ static const struct altr_sdram_prv_data a10_data = { | |||
| 80 | .ue_set_mask = A10_DIAGINT_TDERRA_MASK, | 69 | .ue_set_mask = A10_DIAGINT_TDERRA_MASK, |
| 81 | }; | 70 | }; |
| 82 | 71 | ||
| 72 | static const struct altr_sdram_prv_data s10_data = { | ||
| 73 | .ecc_ctrl_offset = S10_ECCCTRL1_OFST, | ||
| 74 | .ecc_ctl_en_mask = A10_ECCCTRL1_ECC_EN, | ||
| 75 | .ecc_stat_offset = S10_INTSTAT_OFST, | ||
| 76 | .ecc_stat_ce_mask = A10_INTSTAT_SBEERR, | ||
| 77 | .ecc_stat_ue_mask = A10_INTSTAT_DBEERR, | ||
| 78 | .ecc_saddr_offset = S10_SERRADDR_OFST, | ||
| 79 | .ecc_daddr_offset = S10_DERRADDR_OFST, | ||
| 80 | .ecc_irq_en_offset = S10_ERRINTEN_OFST, | ||
| 81 | .ecc_irq_en_mask = A10_ECC_IRQ_EN_MASK, | ||
| 82 | .ecc_irq_clr_offset = S10_INTSTAT_OFST, | ||
| 83 | .ecc_irq_clr_mask = (A10_INTSTAT_SBEERR | A10_INTSTAT_DBEERR), | ||
| 84 | .ecc_cnt_rst_offset = S10_ECCCTRL1_OFST, | ||
| 85 | .ecc_cnt_rst_mask = A10_ECC_CNT_RESET_MASK, | ||
| 86 | .ce_ue_trgr_offset = S10_DIAGINTTEST_OFST, | ||
| 87 | .ce_set_mask = A10_DIAGINT_TSERRA_MASK, | ||
| 88 | .ue_set_mask = A10_DIAGINT_TDERRA_MASK, | ||
| 89 | }; | ||
| 90 | |||
| 83 | /*********************** EDAC Memory Controller Functions ****************/ | 91 | /*********************** EDAC Memory Controller Functions ****************/ |
| 84 | 92 | ||
| 85 | /* The SDRAM controller uses the EDAC Memory Controller framework. */ | 93 | /* The SDRAM controller uses the EDAC Memory Controller framework. */ |
| @@ -231,6 +239,7 @@ static unsigned long get_total_mem(void) | |||
| 231 | static const struct of_device_id altr_sdram_ctrl_of_match[] = { | 239 | static const struct of_device_id altr_sdram_ctrl_of_match[] = { |
| 232 | { .compatible = "altr,sdram-edac", .data = &c5_data}, | 240 | { .compatible = "altr,sdram-edac", .data = &c5_data}, |
| 233 | { .compatible = "altr,sdram-edac-a10", .data = &a10_data}, | 241 | { .compatible = "altr,sdram-edac-a10", .data = &a10_data}, |
| 242 | { .compatible = "altr,sdram-edac-s10", .data = &s10_data}, | ||
| 234 | {}, | 243 | {}, |
| 235 | }; | 244 | }; |
| 236 | MODULE_DEVICE_TABLE(of, altr_sdram_ctrl_of_match); | 245 | MODULE_DEVICE_TABLE(of, altr_sdram_ctrl_of_match); |
| @@ -477,6 +486,292 @@ static int altr_sdram_remove(struct platform_device *pdev) | |||
| 477 | return 0; | 486 | return 0; |
| 478 | } | 487 | } |
| 479 | 488 | ||
| 489 | /**************** Stratix 10 EDAC Memory Controller Functions ************/ | ||
| 490 | |||
| 491 | /** | ||
| 492 | * s10_protected_reg_write | ||
| 493 | * Write to a protected SMC register. | ||
| 494 | * @context: Not used. | ||
| 495 | * @reg: Address of register | ||
| 496 | * @value: Value to write | ||
| 497 | * Return: INTEL_SIP_SMC_STATUS_OK (0) on success | ||
| 498 | * INTEL_SIP_SMC_REG_ERROR on error | ||
| 499 | * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION if not supported | ||
| 500 | */ | ||
| 501 | static int s10_protected_reg_write(void *context, unsigned int reg, | ||
| 502 | unsigned int val) | ||
| 503 | { | ||
| 504 | struct arm_smccc_res result; | ||
| 505 | |||
| 506 | arm_smccc_smc(INTEL_SIP_SMC_REG_WRITE, reg, val, 0, 0, | ||
| 507 | 0, 0, 0, &result); | ||
| 508 | |||
| 509 | return (int)result.a0; | ||
| 510 | } | ||
| 511 | |||
| 512 | /** | ||
| 513 | * s10_protected_reg_read | ||
| 514 | * Read the status of a protected SMC register | ||
| 515 | * @context: Not used. | ||
| 516 | * @reg: Address of register | ||
| 517 | * @value: Value read. | ||
| 518 | * Return: INTEL_SIP_SMC_STATUS_OK (0) on success | ||
| 519 | * INTEL_SIP_SMC_REG_ERROR on error | ||
| 520 | * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION if not supported | ||
| 521 | */ | ||
| 522 | static int s10_protected_reg_read(void *context, unsigned int reg, | ||
| 523 | unsigned int *val) | ||
| 524 | { | ||
| 525 | struct arm_smccc_res result; | ||
| 526 | |||
| 527 | arm_smccc_smc(INTEL_SIP_SMC_REG_READ, reg, 0, 0, 0, | ||
| 528 | 0, 0, 0, &result); | ||
| 529 | |||
| 530 | *val = (unsigned int)result.a1; | ||
| 531 | |||
| 532 | return (int)result.a0; | ||
| 533 | } | ||
| 534 | |||
| 535 | static bool s10_sdram_writeable_reg(struct device *dev, unsigned int reg) | ||
| 536 | { | ||
| 537 | switch (reg) { | ||
| 538 | case S10_ECCCTRL1_OFST: | ||
| 539 | case S10_ERRINTEN_OFST: | ||
| 540 | case S10_INTMODE_OFST: | ||
| 541 | case S10_INTSTAT_OFST: | ||
| 542 | case S10_DIAGINTTEST_OFST: | ||
| 543 | case S10_SYSMGR_ECC_INTMASK_VAL_OFST: | ||
| 544 | case S10_SYSMGR_ECC_INTMASK_SET_OFST: | ||
| 545 | case S10_SYSMGR_ECC_INTMASK_CLR_OFST: | ||
| 546 | return true; | ||
| 547 | } | ||
| 548 | return false; | ||
| 549 | } | ||
| 550 | |||
| 551 | static bool s10_sdram_readable_reg(struct device *dev, unsigned int reg) | ||
| 552 | { | ||
| 553 | switch (reg) { | ||
| 554 | case S10_ECCCTRL1_OFST: | ||
| 555 | case S10_ERRINTEN_OFST: | ||
| 556 | case S10_INTMODE_OFST: | ||
| 557 | case S10_INTSTAT_OFST: | ||
| 558 | case S10_DERRADDR_OFST: | ||
| 559 | case S10_SERRADDR_OFST: | ||
| 560 | case S10_DIAGINTTEST_OFST: | ||
| 561 | case S10_SYSMGR_ECC_INTMASK_VAL_OFST: | ||
| 562 | case S10_SYSMGR_ECC_INTMASK_SET_OFST: | ||
| 563 | case S10_SYSMGR_ECC_INTMASK_CLR_OFST: | ||
| 564 | case S10_SYSMGR_ECC_INTSTAT_SERR_OFST: | ||
| 565 | case S10_SYSMGR_ECC_INTSTAT_DERR_OFST: | ||
| 566 | return true; | ||
| 567 | } | ||
| 568 | return false; | ||
| 569 | } | ||
| 570 | |||
| 571 | static bool s10_sdram_volatile_reg(struct device *dev, unsigned int reg) | ||
| 572 | { | ||
| 573 | switch (reg) { | ||
| 574 | case S10_ECCCTRL1_OFST: | ||
| 575 | case S10_ERRINTEN_OFST: | ||
| 576 | case S10_INTMODE_OFST: | ||
| 577 | case S10_INTSTAT_OFST: | ||
| 578 | case S10_DERRADDR_OFST: | ||
| 579 | case S10_SERRADDR_OFST: | ||
| 580 | case S10_DIAGINTTEST_OFST: | ||
| 581 | case S10_SYSMGR_ECC_INTMASK_VAL_OFST: | ||
| 582 | case S10_SYSMGR_ECC_INTMASK_SET_OFST: | ||
| 583 | case S10_SYSMGR_ECC_INTMASK_CLR_OFST: | ||
| 584 | case S10_SYSMGR_ECC_INTSTAT_SERR_OFST: | ||
| 585 | case S10_SYSMGR_ECC_INTSTAT_DERR_OFST: | ||
| 586 | return true; | ||
| 587 | } | ||
| 588 | return false; | ||
| 589 | } | ||
| 590 | |||
| 591 | static const struct regmap_config s10_sdram_regmap_cfg = { | ||
| 592 | .name = "s10_ddr", | ||
| 593 | .reg_bits = 32, | ||
| 594 | .reg_stride = 4, | ||
| 595 | .val_bits = 32, | ||
| 596 | .max_register = 0xffffffff, | ||
| 597 | .writeable_reg = s10_sdram_writeable_reg, | ||
| 598 | .readable_reg = s10_sdram_readable_reg, | ||
| 599 | .volatile_reg = s10_sdram_volatile_reg, | ||
| 600 | .reg_read = s10_protected_reg_read, | ||
| 601 | .reg_write = s10_protected_reg_write, | ||
| 602 | .use_single_rw = true, | ||
| 603 | }; | ||
| 604 | |||
| 605 | static int altr_s10_sdram_probe(struct platform_device *pdev) | ||
| 606 | { | ||
| 607 | const struct of_device_id *id; | ||
| 608 | struct edac_mc_layer layers[2]; | ||
| 609 | struct mem_ctl_info *mci; | ||
| 610 | struct altr_sdram_mc_data *drvdata; | ||
| 611 | const struct altr_sdram_prv_data *priv; | ||
| 612 | struct regmap *regmap; | ||
| 613 | struct dimm_info *dimm; | ||
| 614 | u32 read_reg; | ||
| 615 | int irq, ret = 0; | ||
| 616 | unsigned long mem_size; | ||
| 617 | |||
| 618 | id = of_match_device(altr_sdram_ctrl_of_match, &pdev->dev); | ||
| 619 | if (!id) | ||
| 620 | return -ENODEV; | ||
| 621 | |||
| 622 | /* Grab specific offsets and masks for Stratix10 */ | ||
| 623 | priv = of_match_node(altr_sdram_ctrl_of_match, | ||
| 624 | pdev->dev.of_node)->data; | ||
| 625 | |||
| 626 | regmap = devm_regmap_init(&pdev->dev, NULL, (void *)priv, | ||
| 627 | &s10_sdram_regmap_cfg); | ||
| 628 | if (IS_ERR(regmap)) | ||
| 629 | return PTR_ERR(regmap); | ||
| 630 | |||
| 631 | /* Validate the SDRAM controller has ECC enabled */ | ||
| 632 | if (regmap_read(regmap, priv->ecc_ctrl_offset, &read_reg) || | ||
| 633 | ((read_reg & priv->ecc_ctl_en_mask) != priv->ecc_ctl_en_mask)) { | ||
| 634 | edac_printk(KERN_ERR, EDAC_MC, | ||
| 635 | "No ECC/ECC disabled [0x%08X]\n", read_reg); | ||
| 636 | return -ENODEV; | ||
| 637 | } | ||
| 638 | |||
| 639 | /* Grab memory size from device tree. */ | ||
| 640 | mem_size = get_total_mem(); | ||
| 641 | if (!mem_size) { | ||
| 642 | edac_printk(KERN_ERR, EDAC_MC, "Unable to calculate memory size\n"); | ||
| 643 | return -ENODEV; | ||
| 644 | } | ||
| 645 | |||
| 646 | /* Ensure the SDRAM Interrupt is disabled */ | ||
| 647 | if (regmap_update_bits(regmap, priv->ecc_irq_en_offset, | ||
| 648 | priv->ecc_irq_en_mask, 0)) { | ||
| 649 | edac_printk(KERN_ERR, EDAC_MC, | ||
| 650 | "Error disabling SDRAM ECC IRQ\n"); | ||
| 651 | return -ENODEV; | ||
| 652 | } | ||
| 653 | |||
| 654 | /* Toggle to clear the SDRAM Error count */ | ||
| 655 | if (regmap_update_bits(regmap, priv->ecc_cnt_rst_offset, | ||
| 656 | priv->ecc_cnt_rst_mask, | ||
| 657 | priv->ecc_cnt_rst_mask)) { | ||
| 658 | edac_printk(KERN_ERR, EDAC_MC, | ||
| 659 | "Error clearing SDRAM ECC count\n"); | ||
| 660 | return -ENODEV; | ||
| 661 | } | ||
| 662 | |||
| 663 | if (regmap_update_bits(regmap, priv->ecc_cnt_rst_offset, | ||
| 664 | priv->ecc_cnt_rst_mask, 0)) { | ||
| 665 | edac_printk(KERN_ERR, EDAC_MC, | ||
| 666 | "Error clearing SDRAM ECC count\n"); | ||
| 667 | return -ENODEV; | ||
| 668 | } | ||
| 669 | |||
| 670 | irq = platform_get_irq(pdev, 0); | ||
| 671 | if (irq < 0) { | ||
| 672 | edac_printk(KERN_ERR, EDAC_MC, | ||
| 673 | "No irq %d in DT\n", irq); | ||
| 674 | return -ENODEV; | ||
| 675 | } | ||
| 676 | |||
| 677 | layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; | ||
| 678 | layers[0].size = 1; | ||
| 679 | layers[0].is_virt_csrow = true; | ||
| 680 | layers[1].type = EDAC_MC_LAYER_CHANNEL; | ||
| 681 | layers[1].size = 1; | ||
| 682 | layers[1].is_virt_csrow = false; | ||
| 683 | mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, | ||
| 684 | sizeof(struct altr_sdram_mc_data)); | ||
| 685 | if (!mci) | ||
| 686 | return -ENOMEM; | ||
| 687 | |||
| 688 | mci->pdev = &pdev->dev; | ||
| 689 | drvdata = mci->pvt_info; | ||
| 690 | drvdata->mc_vbase = regmap; | ||
| 691 | drvdata->data = priv; | ||
| 692 | platform_set_drvdata(pdev, mci); | ||
| 693 | |||
| 694 | if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) { | ||
| 695 | edac_printk(KERN_ERR, EDAC_MC, | ||
| 696 | "Unable to get managed device resource\n"); | ||
| 697 | ret = -ENOMEM; | ||
| 698 | goto free; | ||
| 699 | } | ||
| 700 | |||
| 701 | mci->mtype_cap = MEM_FLAG_DDR3; | ||
| 702 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; | ||
| 703 | mci->edac_cap = EDAC_FLAG_SECDED; | ||
| 704 | mci->mod_name = EDAC_MOD_STR; | ||
| 705 | mci->ctl_name = dev_name(&pdev->dev); | ||
| 706 | mci->scrub_mode = SCRUB_SW_SRC; | ||
| 707 | mci->dev_name = dev_name(&pdev->dev); | ||
| 708 | |||
| 709 | dimm = *mci->dimms; | ||
| 710 | dimm->nr_pages = ((mem_size - 1) >> PAGE_SHIFT) + 1; | ||
| 711 | dimm->grain = 8; | ||
| 712 | dimm->dtype = DEV_X8; | ||
| 713 | dimm->mtype = MEM_DDR3; | ||
| 714 | dimm->edac_mode = EDAC_SECDED; | ||
| 715 | |||
| 716 | ret = edac_mc_add_mc(mci); | ||
| 717 | if (ret < 0) | ||
| 718 | goto err; | ||
| 719 | |||
| 720 | ret = devm_request_irq(&pdev->dev, irq, altr_sdram_mc_err_handler, | ||
| 721 | IRQF_SHARED, dev_name(&pdev->dev), mci); | ||
| 722 | if (ret < 0) { | ||
| 723 | edac_mc_printk(mci, KERN_ERR, | ||
| 724 | "Unable to request irq %d\n", irq); | ||
| 725 | ret = -ENODEV; | ||
| 726 | goto err2; | ||
| 727 | } | ||
| 728 | |||
| 729 | if (regmap_write(regmap, S10_SYSMGR_ECC_INTMASK_CLR_OFST, | ||
| 730 | S10_DDR0_IRQ_MASK)) { | ||
| 731 | edac_printk(KERN_ERR, EDAC_MC, | ||
| 732 | "Error clearing SDRAM ECC count\n"); | ||
| 733 | return -ENODEV; | ||
| 734 | } | ||
| 735 | |||
| 736 | if (regmap_update_bits(drvdata->mc_vbase, priv->ecc_irq_en_offset, | ||
| 737 | priv->ecc_irq_en_mask, priv->ecc_irq_en_mask)) { | ||
| 738 | edac_mc_printk(mci, KERN_ERR, | ||
| 739 | "Error enabling SDRAM ECC IRQ\n"); | ||
| 740 | ret = -ENODEV; | ||
| 741 | goto err2; | ||
| 742 | } | ||
| 743 | |||
| 744 | altr_sdr_mc_create_debugfs_nodes(mci); | ||
| 745 | |||
| 746 | devres_close_group(&pdev->dev, NULL); | ||
| 747 | |||
| 748 | return 0; | ||
| 749 | |||
| 750 | err2: | ||
| 751 | edac_mc_del_mc(&pdev->dev); | ||
| 752 | err: | ||
| 753 | devres_release_group(&pdev->dev, NULL); | ||
| 754 | free: | ||
| 755 | edac_mc_free(mci); | ||
| 756 | edac_printk(KERN_ERR, EDAC_MC, | ||
| 757 | "EDAC Probe Failed; Error %d\n", ret); | ||
| 758 | |||
| 759 | return ret; | ||
| 760 | } | ||
| 761 | |||
| 762 | static int altr_s10_sdram_remove(struct platform_device *pdev) | ||
| 763 | { | ||
| 764 | struct mem_ctl_info *mci = platform_get_drvdata(pdev); | ||
| 765 | |||
| 766 | edac_mc_del_mc(&pdev->dev); | ||
| 767 | edac_mc_free(mci); | ||
| 768 | platform_set_drvdata(pdev, NULL); | ||
| 769 | |||
| 770 | return 0; | ||
| 771 | } | ||
| 772 | |||
| 773 | /************** </Stratix10 EDAC Memory Controller Functions> ***********/ | ||
| 774 | |||
| 480 | /* | 775 | /* |
| 481 | * If you want to suspend, need to disable EDAC by removing it | 776 | * If you want to suspend, need to disable EDAC by removing it |
| 482 | * from the device tree or defconfig. | 777 | * from the device tree or defconfig. |
| @@ -508,6 +803,20 @@ static struct platform_driver altr_sdram_edac_driver = { | |||
| 508 | 803 | ||
| 509 | module_platform_driver(altr_sdram_edac_driver); | 804 | module_platform_driver(altr_sdram_edac_driver); |
| 510 | 805 | ||
| 806 | static struct platform_driver altr_s10_sdram_edac_driver = { | ||
| 807 | .probe = altr_s10_sdram_probe, | ||
| 808 | .remove = altr_s10_sdram_remove, | ||
| 809 | .driver = { | ||
| 810 | .name = "altr_s10_sdram_edac", | ||
| 811 | #ifdef CONFIG_PM | ||
| 812 | .pm = &altr_sdram_pm_ops, | ||
| 813 | #endif | ||
| 814 | .of_match_table = altr_sdram_ctrl_of_match, | ||
| 815 | }, | ||
| 816 | }; | ||
| 817 | |||
| 818 | module_platform_driver(altr_s10_sdram_edac_driver); | ||
| 819 | |||
| 511 | /************************* EDAC Parent Probe *************************/ | 820 | /************************* EDAC Parent Probe *************************/ |
| 512 | 821 | ||
| 513 | static const struct of_device_id altr_edac_device_of_match[]; | 822 | static const struct of_device_id altr_edac_device_of_match[]; |
| @@ -1106,7 +1415,7 @@ static void *ocram_alloc_mem(size_t size, void **other) | |||
| 1106 | 1415 | ||
| 1107 | static void ocram_free_mem(void *p, size_t size, void *other) | 1416 | static void ocram_free_mem(void *p, size_t size, void *other) |
| 1108 | { | 1417 | { |
| 1109 | gen_pool_free((struct gen_pool *)other, (u32)p, size); | 1418 | gen_pool_free((struct gen_pool *)other, (unsigned long)p, size); |
| 1110 | } | 1419 | } |
| 1111 | 1420 | ||
| 1112 | static const struct edac_device_prv_data ocramecc_data = { | 1421 | static const struct edac_device_prv_data ocramecc_data = { |
| @@ -1925,6 +2234,171 @@ static struct platform_driver altr_edac_a10_driver = { | |||
| 1925 | }; | 2234 | }; |
| 1926 | module_platform_driver(altr_edac_a10_driver); | 2235 | module_platform_driver(altr_edac_a10_driver); |
| 1927 | 2236 | ||
| 2237 | /************** Stratix 10 EDAC Device Controller Functions> ************/ | ||
| 2238 | |||
| 2239 | #define to_s10edac(p, m) container_of(p, struct altr_stratix10_edac, m) | ||
| 2240 | |||
| 2241 | /* | ||
| 2242 | * The double bit error is handled through SError which is fatal. This is | ||
| 2243 | * called as a panic notifier to printout ECC error info as part of the panic. | ||
| 2244 | */ | ||
| 2245 | static int s10_edac_dberr_handler(struct notifier_block *this, | ||
| 2246 | unsigned long event, void *ptr) | ||
| 2247 | { | ||
| 2248 | struct altr_stratix10_edac *edac = to_s10edac(this, panic_notifier); | ||
| 2249 | int err_addr, dberror; | ||
| 2250 | |||
| 2251 | s10_protected_reg_read(edac, S10_SYSMGR_ECC_INTSTAT_DERR_OFST, | ||
| 2252 | &dberror); | ||
| 2253 | /* Remember the UE Errors for a reboot */ | ||
| 2254 | s10_protected_reg_write(edac, S10_SYSMGR_UE_VAL_OFST, dberror); | ||
| 2255 | if (dberror & S10_DDR0_IRQ_MASK) { | ||
| 2256 | s10_protected_reg_read(edac, S10_DERRADDR_OFST, &err_addr); | ||
| 2257 | /* Remember the UE Error address */ | ||
| 2258 | s10_protected_reg_write(edac, S10_SYSMGR_UE_ADDR_OFST, | ||
| 2259 | err_addr); | ||
| 2260 | edac_printk(KERN_ERR, EDAC_MC, | ||
| 2261 | "EDAC: [Uncorrectable errors @ 0x%08X]\n\n", | ||
| 2262 | err_addr); | ||
| 2263 | } | ||
| 2264 | |||
| 2265 | return NOTIFY_DONE; | ||
| 2266 | } | ||
| 2267 | |||
| 2268 | static void altr_edac_s10_irq_handler(struct irq_desc *desc) | ||
| 2269 | { | ||
| 2270 | struct altr_stratix10_edac *edac = irq_desc_get_handler_data(desc); | ||
| 2271 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
| 2272 | int irq = irq_desc_get_irq(desc); | ||
| 2273 | int bit, sm_offset, irq_status; | ||
| 2274 | |||
| 2275 | sm_offset = S10_SYSMGR_ECC_INTSTAT_SERR_OFST; | ||
| 2276 | |||
| 2277 | chained_irq_enter(chip, desc); | ||
| 2278 | |||
| 2279 | s10_protected_reg_read(NULL, sm_offset, &irq_status); | ||
| 2280 | |||
| 2281 | for_each_set_bit(bit, (unsigned long *)&irq_status, 32) { | ||
| 2282 | irq = irq_linear_revmap(edac->domain, bit); | ||
| 2283 | if (irq) | ||
| 2284 | generic_handle_irq(irq); | ||
| 2285 | } | ||
| 2286 | |||
| 2287 | chained_irq_exit(chip, desc); | ||
| 2288 | } | ||
| 2289 | |||
| 2290 | static void s10_eccmgr_irq_mask(struct irq_data *d) | ||
| 2291 | { | ||
| 2292 | struct altr_stratix10_edac *edac = irq_data_get_irq_chip_data(d); | ||
| 2293 | |||
| 2294 | s10_protected_reg_write(edac, S10_SYSMGR_ECC_INTMASK_SET_OFST, | ||
| 2295 | BIT(d->hwirq)); | ||
| 2296 | } | ||
| 2297 | |||
| 2298 | static void s10_eccmgr_irq_unmask(struct irq_data *d) | ||
| 2299 | { | ||
| 2300 | struct altr_stratix10_edac *edac = irq_data_get_irq_chip_data(d); | ||
| 2301 | |||
| 2302 | s10_protected_reg_write(edac, S10_SYSMGR_ECC_INTMASK_CLR_OFST, | ||
| 2303 | BIT(d->hwirq)); | ||
| 2304 | } | ||
| 2305 | |||
| 2306 | static int s10_eccmgr_irqdomain_map(struct irq_domain *d, unsigned int irq, | ||
| 2307 | irq_hw_number_t hwirq) | ||
| 2308 | { | ||
| 2309 | struct altr_stratix10_edac *edac = d->host_data; | ||
| 2310 | |||
| 2311 | irq_set_chip_and_handler(irq, &edac->irq_chip, handle_simple_irq); | ||
| 2312 | irq_set_chip_data(irq, edac); | ||
| 2313 | irq_set_noprobe(irq); | ||
| 2314 | |||
| 2315 | return 0; | ||
| 2316 | } | ||
| 2317 | |||
| 2318 | static const struct irq_domain_ops s10_eccmgr_ic_ops = { | ||
| 2319 | .map = s10_eccmgr_irqdomain_map, | ||
| 2320 | .xlate = irq_domain_xlate_twocell, | ||
| 2321 | }; | ||
| 2322 | |||
| 2323 | static int altr_edac_s10_probe(struct platform_device *pdev) | ||
| 2324 | { | ||
| 2325 | struct altr_stratix10_edac *edac; | ||
| 2326 | struct device_node *child; | ||
| 2327 | int dberror, err_addr; | ||
| 2328 | |||
| 2329 | edac = devm_kzalloc(&pdev->dev, sizeof(*edac), GFP_KERNEL); | ||
| 2330 | if (!edac) | ||
| 2331 | return -ENOMEM; | ||
| 2332 | |||
| 2333 | edac->dev = &pdev->dev; | ||
| 2334 | platform_set_drvdata(pdev, edac); | ||
| 2335 | INIT_LIST_HEAD(&edac->s10_ecc_devices); | ||
| 2336 | |||
| 2337 | edac->irq_chip.name = pdev->dev.of_node->name; | ||
| 2338 | edac->irq_chip.irq_mask = s10_eccmgr_irq_mask; | ||
| 2339 | edac->irq_chip.irq_unmask = s10_eccmgr_irq_unmask; | ||
| 2340 | edac->domain = irq_domain_add_linear(pdev->dev.of_node, 64, | ||
| 2341 | &s10_eccmgr_ic_ops, edac); | ||
| 2342 | if (!edac->domain) { | ||
| 2343 | dev_err(&pdev->dev, "Error adding IRQ domain\n"); | ||
| 2344 | return -ENOMEM; | ||
| 2345 | } | ||
| 2346 | |||
| 2347 | edac->sb_irq = platform_get_irq(pdev, 0); | ||
| 2348 | if (edac->sb_irq < 0) { | ||
| 2349 | dev_err(&pdev->dev, "No SBERR IRQ resource\n"); | ||
| 2350 | return edac->sb_irq; | ||
| 2351 | } | ||
| 2352 | |||
| 2353 | irq_set_chained_handler_and_data(edac->sb_irq, | ||
| 2354 | altr_edac_s10_irq_handler, | ||
| 2355 | edac); | ||
| 2356 | |||
| 2357 | edac->panic_notifier.notifier_call = s10_edac_dberr_handler; | ||
| 2358 | atomic_notifier_chain_register(&panic_notifier_list, | ||
| 2359 | &edac->panic_notifier); | ||
| 2360 | |||
| 2361 | /* Printout a message if uncorrectable error previously. */ | ||
| 2362 | s10_protected_reg_read(edac, S10_SYSMGR_UE_VAL_OFST, &dberror); | ||
| 2363 | if (dberror) { | ||
| 2364 | s10_protected_reg_read(edac, S10_SYSMGR_UE_ADDR_OFST, | ||
| 2365 | &err_addr); | ||
| 2366 | edac_printk(KERN_ERR, EDAC_DEVICE, | ||
| 2367 | "Previous Boot UE detected[0x%X] @ 0x%X\n", | ||
| 2368 | dberror, err_addr); | ||
| 2369 | /* Reset the sticky registers */ | ||
| 2370 | s10_protected_reg_write(edac, S10_SYSMGR_UE_VAL_OFST, 0); | ||
| 2371 | s10_protected_reg_write(edac, S10_SYSMGR_UE_ADDR_OFST, 0); | ||
| 2372 | } | ||
| 2373 | |||
| 2374 | for_each_child_of_node(pdev->dev.of_node, child) { | ||
| 2375 | if (!of_device_is_available(child)) | ||
| 2376 | continue; | ||
| 2377 | |||
| 2378 | if (of_device_is_compatible(child, "altr,sdram-edac-s10")) | ||
| 2379 | of_platform_populate(pdev->dev.of_node, | ||
| 2380 | altr_sdram_ctrl_of_match, | ||
| 2381 | NULL, &pdev->dev); | ||
| 2382 | } | ||
| 2383 | |||
| 2384 | return 0; | ||
| 2385 | } | ||
| 2386 | |||
| 2387 | static const struct of_device_id altr_edac_s10_of_match[] = { | ||
| 2388 | { .compatible = "altr,socfpga-s10-ecc-manager" }, | ||
| 2389 | {}, | ||
| 2390 | }; | ||
| 2391 | MODULE_DEVICE_TABLE(of, altr_edac_s10_of_match); | ||
| 2392 | |||
| 2393 | static struct platform_driver altr_edac_s10_driver = { | ||
| 2394 | .probe = altr_edac_s10_probe, | ||
| 2395 | .driver = { | ||
| 2396 | .name = "socfpga_s10_ecc_manager", | ||
| 2397 | .of_match_table = altr_edac_s10_of_match, | ||
| 2398 | }, | ||
| 2399 | }; | ||
| 2400 | module_platform_driver(altr_edac_s10_driver); | ||
| 2401 | |||
| 1928 | MODULE_LICENSE("GPL v2"); | 2402 | MODULE_LICENSE("GPL v2"); |
| 1929 | MODULE_AUTHOR("Thor Thayer"); | 2403 | MODULE_AUTHOR("Thor Thayer"); |
| 1930 | MODULE_DESCRIPTION("EDAC Driver for Altera Memories"); | 2404 | MODULE_DESCRIPTION("EDAC Driver for Altera Memories"); |
diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h index cbc96290f743..81f0554e09de 100644 --- a/drivers/edac/altera_edac.h +++ b/drivers/edac/altera_edac.h | |||
| @@ -1,23 +1,13 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 1 | /* | 2 | /* |
| 2 | * | 3 | * Copyright (C) 2017-2018, Intel Corporation |
| 3 | * Copyright (C) 2015 Altera Corporation | 4 | * Copyright (C) 2015 Altera Corporation |
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms and conditions of the GNU General Public License, | ||
| 7 | * version 2, as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License along with | ||
| 15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | 5 | */ |
| 17 | 6 | ||
| 18 | #ifndef _ALTERA_EDAC_H | 7 | #ifndef _ALTERA_EDAC_H |
| 19 | #define _ALTERA_EDAC_H | 8 | #define _ALTERA_EDAC_H |
| 20 | 9 | ||
| 10 | #include <linux/arm-smccc.h> | ||
| 21 | #include <linux/edac.h> | 11 | #include <linux/edac.h> |
| 22 | #include <linux/types.h> | 12 | #include <linux/types.h> |
| 23 | 13 | ||
| @@ -94,6 +84,7 @@ | |||
| 94 | /* SDRAM Controller Address Width Register */ | 84 | /* SDRAM Controller Address Width Register */ |
| 95 | #define CV_DRAMADDRW 0xFFC2502C | 85 | #define CV_DRAMADDRW 0xFFC2502C |
| 96 | #define A10_DRAMADDRW 0xFFCFA0A8 | 86 | #define A10_DRAMADDRW 0xFFCFA0A8 |
| 87 | #define S10_DRAMADDRW 0xF80110E0 | ||
| 97 | 88 | ||
| 98 | /* SDRAM Controller Address Widths Field Register */ | 89 | /* SDRAM Controller Address Widths Field Register */ |
| 99 | #define DRAMADDRW_COLBIT_MASK 0x001F | 90 | #define DRAMADDRW_COLBIT_MASK 0x001F |
| @@ -115,6 +106,7 @@ | |||
| 115 | /* SDRAM Controller Interface Data Width Register */ | 106 | /* SDRAM Controller Interface Data Width Register */ |
| 116 | #define CV_DRAMIFWIDTH 0xFFC25030 | 107 | #define CV_DRAMIFWIDTH 0xFFC25030 |
| 117 | #define A10_DRAMIFWIDTH 0xFFCFB008 | 108 | #define A10_DRAMIFWIDTH 0xFFCFB008 |
| 109 | #define S10_DRAMIFWIDTH 0xF8011008 | ||
| 118 | 110 | ||
| 119 | /* SDRAM Controller Interface Data Width Defines */ | 111 | /* SDRAM Controller Interface Data Width Defines */ |
| 120 | #define CV_DRAMIFWIDTH_16B_ECC 24 | 112 | #define CV_DRAMIFWIDTH_16B_ECC 24 |
| @@ -164,6 +156,34 @@ | |||
| 164 | #define A10_INTMASK_CLR_OFST 0x10 | 156 | #define A10_INTMASK_CLR_OFST 0x10 |
| 165 | #define A10_DDR0_IRQ_MASK BIT(17) | 157 | #define A10_DDR0_IRQ_MASK BIT(17) |
| 166 | 158 | ||
| 159 | /************* Stratix10 Defines **************/ | ||
| 160 | |||
| 161 | /* SDRAM Controller EccCtrl Register */ | ||
| 162 | #define S10_ECCCTRL1_OFST 0xF8011100 | ||
| 163 | |||
| 164 | /* SDRAM Controller DRAM IRQ Register */ | ||
| 165 | #define S10_ERRINTEN_OFST 0xF8011110 | ||
| 166 | |||
| 167 | /* SDRAM Interrupt Mode Register */ | ||
| 168 | #define S10_INTMODE_OFST 0xF801111C | ||
| 169 | |||
| 170 | /* SDRAM Controller Error Status Register */ | ||
| 171 | #define S10_INTSTAT_OFST 0xF8011120 | ||
| 172 | |||
| 173 | /* SDRAM Controller ECC Error Address Register */ | ||
| 174 | #define S10_DERRADDR_OFST 0xF801112C | ||
| 175 | #define S10_SERRADDR_OFST 0xF8011130 | ||
| 176 | |||
| 177 | /* SDRAM Controller ECC Diagnostic Register */ | ||
| 178 | #define S10_DIAGINTTEST_OFST 0xF8011124 | ||
| 179 | |||
| 180 | /* SDRAM Single Bit Error Count Compare Set Register */ | ||
| 181 | #define S10_SERRCNTREG_OFST 0xF801113C | ||
| 182 | |||
| 183 | /* Sticky registers for Uncorrected Errors */ | ||
| 184 | #define S10_SYSMGR_UE_VAL_OFST 0xFFD12220 | ||
| 185 | #define S10_SYSMGR_UE_ADDR_OFST 0xFFD12224 | ||
| 186 | |||
| 167 | struct altr_sdram_prv_data { | 187 | struct altr_sdram_prv_data { |
| 168 | int ecc_ctrl_offset; | 188 | int ecc_ctrl_offset; |
| 169 | int ecc_ctl_en_mask; | 189 | int ecc_ctl_en_mask; |
| @@ -296,6 +316,18 @@ struct altr_sdram_mc_data { | |||
| 296 | /* A10 ECC Controller memory initialization timeout */ | 316 | /* A10 ECC Controller memory initialization timeout */ |
| 297 | #define ALTR_A10_ECC_INIT_WATCHDOG_10US 10000 | 317 | #define ALTR_A10_ECC_INIT_WATCHDOG_10US 10000 |
| 298 | 318 | ||
| 319 | /************* Stratix10 Defines **************/ | ||
| 320 | |||
| 321 | /* Stratix10 ECC Manager Defines */ | ||
| 322 | #define S10_SYSMGR_ECC_INTMASK_VAL_OFST 0xFFD12090 | ||
| 323 | #define S10_SYSMGR_ECC_INTMASK_SET_OFST 0xFFD12094 | ||
| 324 | #define S10_SYSMGR_ECC_INTMASK_CLR_OFST 0xFFD12098 | ||
| 325 | |||
| 326 | #define S10_SYSMGR_ECC_INTSTAT_SERR_OFST 0xFFD1209C | ||
| 327 | #define S10_SYSMGR_ECC_INTSTAT_DERR_OFST 0xFFD120A0 | ||
| 328 | |||
| 329 | #define S10_DDR0_IRQ_MASK BIT(16) | ||
| 330 | |||
| 299 | struct altr_edac_device_dev; | 331 | struct altr_edac_device_dev; |
| 300 | 332 | ||
| 301 | struct edac_device_prv_data { | 333 | struct edac_device_prv_data { |
| @@ -340,4 +372,78 @@ struct altr_arria10_edac { | |||
| 340 | struct list_head a10_ecc_devices; | 372 | struct list_head a10_ecc_devices; |
| 341 | }; | 373 | }; |
| 342 | 374 | ||
| 375 | /* | ||
| 376 | * Functions specified by ARM SMC Calling convention: | ||
| 377 | * | ||
| 378 | * FAST call executes atomic operations, returns when the requested operation | ||
| 379 | * has completed. | ||
| 380 | * STD call starts a operation which can be preempted by a non-secure | ||
| 381 | * interrupt. The call can return before the requested operation has | ||
| 382 | * completed. | ||
| 383 | * | ||
| 384 | * a0..a7 is used as register names in the descriptions below, on arm32 | ||
| 385 | * that translates to r0..r7 and on arm64 to w0..w7. | ||
| 386 | */ | ||
| 387 | |||
| 388 | #define INTEL_SIP_SMC_STD_CALL_VAL(func_num) \ | ||
| 389 | ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, ARM_SMCCC_SMC_64, \ | ||
| 390 | ARM_SMCCC_OWNER_SIP, (func_num)) | ||
| 391 | |||
| 392 | #define INTEL_SIP_SMC_FAST_CALL_VAL(func_num) \ | ||
| 393 | ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, \ | ||
| 394 | ARM_SMCCC_OWNER_SIP, (func_num)) | ||
| 395 | |||
| 396 | #define INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION 0xFFFFFFFF | ||
| 397 | #define INTEL_SIP_SMC_STATUS_OK 0x0 | ||
| 398 | #define INTEL_SIP_SMC_REG_ERROR 0x5 | ||
| 399 | |||
| 400 | /* | ||
| 401 | * Request INTEL_SIP_SMC_REG_READ | ||
| 402 | * | ||
| 403 | * Read a protected register using SMCCC | ||
| 404 | * | ||
| 405 | * Call register usage: | ||
| 406 | * a0: INTEL_SIP_SMC_REG_READ. | ||
| 407 | * a1: register address. | ||
| 408 | * a2-7: not used. | ||
| 409 | * | ||
| 410 | * Return status: | ||
| 411 | * a0: INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_REG_ERROR, or | ||
| 412 | * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION | ||
| 413 | * a1: Value in the register | ||
| 414 | * a2-3: not used. | ||
| 415 | */ | ||
| 416 | #define INTEL_SIP_SMC_FUNCID_REG_READ 7 | ||
| 417 | #define INTEL_SIP_SMC_REG_READ \ | ||
| 418 | INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_REG_READ) | ||
| 419 | |||
| 420 | /* | ||
| 421 | * Request INTEL_SIP_SMC_REG_WRITE | ||
| 422 | * | ||
| 423 | * Write a protected register using SMCCC | ||
| 424 | * | ||
| 425 | * Call register usage: | ||
| 426 | * a0: INTEL_SIP_SMC_REG_WRITE. | ||
| 427 | * a1: register address | ||
| 428 | * a2: value to program into register. | ||
| 429 | * a3-7: not used. | ||
| 430 | * | ||
| 431 | * Return status: | ||
| 432 | * a0: INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_REG_ERROR, or | ||
| 433 | * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION | ||
| 434 | * a1-3: not used. | ||
| 435 | */ | ||
| 436 | #define INTEL_SIP_SMC_FUNCID_REG_WRITE 8 | ||
| 437 | #define INTEL_SIP_SMC_REG_WRITE \ | ||
| 438 | INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_REG_WRITE) | ||
| 439 | |||
| 440 | struct altr_stratix10_edac { | ||
| 441 | struct device *dev; | ||
| 442 | int sb_irq; | ||
| 443 | struct irq_domain *domain; | ||
| 444 | struct irq_chip irq_chip; | ||
| 445 | struct list_head s10_ecc_devices; | ||
| 446 | struct notifier_block panic_notifier; | ||
| 447 | }; | ||
| 448 | |||
| 343 | #endif /* #ifndef _ALTERA_EDAC_H */ | 449 | #endif /* #ifndef _ALTERA_EDAC_H */ |
diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c index 68b6ee18bea6..473aeec4b1da 100644 --- a/drivers/edac/ghes_edac.c +++ b/drivers/edac/ghes_edac.c | |||
| @@ -91,6 +91,7 @@ static void ghes_edac_dmidecode(const struct dmi_header *dh, void *arg) | |||
| 91 | struct dimm_info *dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, | 91 | struct dimm_info *dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, |
| 92 | mci->n_layers, | 92 | mci->n_layers, |
| 93 | dimm_fill->count, 0, 0); | 93 | dimm_fill->count, 0, 0); |
| 94 | u16 rdr_mask = BIT(7) | BIT(13); | ||
| 94 | 95 | ||
| 95 | if (entry->size == 0xffff) { | 96 | if (entry->size == 0xffff) { |
| 96 | pr_info("Can't get DIMM%i size\n", | 97 | pr_info("Can't get DIMM%i size\n", |
| @@ -99,22 +100,21 @@ static void ghes_edac_dmidecode(const struct dmi_header *dh, void *arg) | |||
| 99 | } else if (entry->size == 0x7fff) { | 100 | } else if (entry->size == 0x7fff) { |
| 100 | dimm->nr_pages = MiB_TO_PAGES(entry->extended_size); | 101 | dimm->nr_pages = MiB_TO_PAGES(entry->extended_size); |
| 101 | } else { | 102 | } else { |
| 102 | if (entry->size & 1 << 15) | 103 | if (entry->size & BIT(15)) |
| 103 | dimm->nr_pages = MiB_TO_PAGES((entry->size & | 104 | dimm->nr_pages = MiB_TO_PAGES((entry->size & 0x7fff) << 10); |
| 104 | 0x7fff) << 10); | ||
| 105 | else | 105 | else |
| 106 | dimm->nr_pages = MiB_TO_PAGES(entry->size); | 106 | dimm->nr_pages = MiB_TO_PAGES(entry->size); |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | switch (entry->memory_type) { | 109 | switch (entry->memory_type) { |
| 110 | case 0x12: | 110 | case 0x12: |
| 111 | if (entry->type_detail & 1 << 13) | 111 | if (entry->type_detail & BIT(13)) |
| 112 | dimm->mtype = MEM_RDDR; | 112 | dimm->mtype = MEM_RDDR; |
| 113 | else | 113 | else |
| 114 | dimm->mtype = MEM_DDR; | 114 | dimm->mtype = MEM_DDR; |
| 115 | break; | 115 | break; |
| 116 | case 0x13: | 116 | case 0x13: |
| 117 | if (entry->type_detail & 1 << 13) | 117 | if (entry->type_detail & BIT(13)) |
| 118 | dimm->mtype = MEM_RDDR2; | 118 | dimm->mtype = MEM_RDDR2; |
| 119 | else | 119 | else |
| 120 | dimm->mtype = MEM_DDR2; | 120 | dimm->mtype = MEM_DDR2; |
| @@ -123,20 +123,29 @@ static void ghes_edac_dmidecode(const struct dmi_header *dh, void *arg) | |||
| 123 | dimm->mtype = MEM_FB_DDR2; | 123 | dimm->mtype = MEM_FB_DDR2; |
| 124 | break; | 124 | break; |
| 125 | case 0x18: | 125 | case 0x18: |
| 126 | if (entry->type_detail & 1 << 13) | 126 | if (entry->type_detail & BIT(12)) |
| 127 | dimm->mtype = MEM_NVDIMM; | ||
| 128 | else if (entry->type_detail & BIT(13)) | ||
| 127 | dimm->mtype = MEM_RDDR3; | 129 | dimm->mtype = MEM_RDDR3; |
| 128 | else | 130 | else |
| 129 | dimm->mtype = MEM_DDR3; | 131 | dimm->mtype = MEM_DDR3; |
| 130 | break; | 132 | break; |
| 133 | case 0x1a: | ||
| 134 | if (entry->type_detail & BIT(12)) | ||
| 135 | dimm->mtype = MEM_NVDIMM; | ||
| 136 | else if (entry->type_detail & BIT(13)) | ||
| 137 | dimm->mtype = MEM_RDDR4; | ||
| 138 | else | ||
| 139 | dimm->mtype = MEM_DDR4; | ||
| 140 | break; | ||
| 131 | default: | 141 | default: |
| 132 | if (entry->type_detail & 1 << 6) | 142 | if (entry->type_detail & BIT(6)) |
| 133 | dimm->mtype = MEM_RMBS; | 143 | dimm->mtype = MEM_RMBS; |
| 134 | else if ((entry->type_detail & ((1 << 7) | (1 << 13))) | 144 | else if ((entry->type_detail & rdr_mask) == rdr_mask) |
| 135 | == ((1 << 7) | (1 << 13))) | ||
| 136 | dimm->mtype = MEM_RDR; | 145 | dimm->mtype = MEM_RDR; |
| 137 | else if (entry->type_detail & 1 << 7) | 146 | else if (entry->type_detail & BIT(7)) |
| 138 | dimm->mtype = MEM_SDR; | 147 | dimm->mtype = MEM_SDR; |
| 139 | else if (entry->type_detail & 1 << 9) | 148 | else if (entry->type_detail & BIT(9)) |
| 140 | dimm->mtype = MEM_EDO; | 149 | dimm->mtype = MEM_EDO; |
| 141 | else | 150 | else |
| 142 | dimm->mtype = MEM_UNKNOWN; | 151 | dimm->mtype = MEM_UNKNOWN; |
| @@ -172,8 +181,7 @@ static void ghes_edac_dmidecode(const struct dmi_header *dh, void *arg) | |||
| 172 | } | 181 | } |
| 173 | } | 182 | } |
| 174 | 183 | ||
| 175 | void ghes_edac_report_mem_error(struct ghes *ghes, int sev, | 184 | void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err) |
| 176 | struct cper_sec_mem_err *mem_err) | ||
| 177 | { | 185 | { |
| 178 | enum hw_event_mc_err_type type; | 186 | enum hw_event_mc_err_type type; |
| 179 | struct edac_raw_error_desc *e; | 187 | struct edac_raw_error_desc *e; |
| @@ -183,10 +191,8 @@ void ghes_edac_report_mem_error(struct ghes *ghes, int sev, | |||
| 183 | char *p; | 191 | char *p; |
| 184 | u8 grain_bits; | 192 | u8 grain_bits; |
| 185 | 193 | ||
| 186 | if (!pvt) { | 194 | if (!pvt) |
| 187 | pr_err("Internal error: Can't find EDAC structure\n"); | ||
| 188 | return; | 195 | return; |
| 189 | } | ||
| 190 | 196 | ||
| 191 | /* | 197 | /* |
| 192 | * We can do the locking below because GHES defers error processing | 198 | * We can do the locking below because GHES defers error processing |
| @@ -434,12 +440,16 @@ int ghes_edac_register(struct ghes *ghes, struct device *dev) | |||
| 434 | struct mem_ctl_info *mci; | 440 | struct mem_ctl_info *mci; |
| 435 | struct edac_mc_layer layers[1]; | 441 | struct edac_mc_layer layers[1]; |
| 436 | struct ghes_edac_dimm_fill dimm_fill; | 442 | struct ghes_edac_dimm_fill dimm_fill; |
| 437 | int idx; | 443 | int idx = -1; |
| 438 | 444 | ||
| 439 | /* Check if safe to enable on this system */ | 445 | if (IS_ENABLED(CONFIG_X86)) { |
| 440 | idx = acpi_match_platform_list(plat_list); | 446 | /* Check if safe to enable on this system */ |
| 441 | if (!force_load && idx < 0) | 447 | idx = acpi_match_platform_list(plat_list); |
| 442 | return 0; | 448 | if (!force_load && idx < 0) |
| 449 | return -ENODEV; | ||
| 450 | } else { | ||
| 451 | idx = 0; | ||
| 452 | } | ||
| 443 | 453 | ||
| 444 | /* | 454 | /* |
| 445 | * We have only one logical memory controller to which all DIMMs belong. | 455 | * We have only one logical memory controller to which all DIMMs belong. |
| @@ -519,6 +529,9 @@ void ghes_edac_unregister(struct ghes *ghes) | |||
| 519 | { | 529 | { |
| 520 | struct mem_ctl_info *mci; | 530 | struct mem_ctl_info *mci; |
| 521 | 531 | ||
| 532 | if (!ghes_pvt) | ||
| 533 | return; | ||
| 534 | |||
| 522 | mci = ghes_pvt->mci; | 535 | mci = ghes_pvt->mci; |
| 523 | edac_mc_del_mc(mci->pdev); | 536 | edac_mc_del_mc(mci->pdev); |
| 524 | edac_mc_free(mci); | 537 | edac_mc_free(mci); |
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 8c5540160a23..4d0ea3563d47 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c | |||
| @@ -1743,7 +1743,7 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, | |||
| 1743 | err = "write parity error"; | 1743 | err = "write parity error"; |
| 1744 | break; | 1744 | break; |
| 1745 | case 19: | 1745 | case 19: |
| 1746 | err = "redundacy loss"; | 1746 | err = "redundancy loss"; |
| 1747 | break; | 1747 | break; |
| 1748 | case 20: | 1748 | case 20: |
| 1749 | err = "reserved"; | 1749 | err = "reserved"; |
diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h index 8feb0c866ee0..1624e2be485c 100644 --- a/include/acpi/ghes.h +++ b/include/acpi/ghes.h | |||
| @@ -55,22 +55,21 @@ enum { | |||
| 55 | /* From drivers/edac/ghes_edac.c */ | 55 | /* From drivers/edac/ghes_edac.c */ |
| 56 | 56 | ||
| 57 | #ifdef CONFIG_EDAC_GHES | 57 | #ifdef CONFIG_EDAC_GHES |
| 58 | void ghes_edac_report_mem_error(struct ghes *ghes, int sev, | 58 | void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err); |
| 59 | struct cper_sec_mem_err *mem_err); | ||
| 60 | 59 | ||
| 61 | int ghes_edac_register(struct ghes *ghes, struct device *dev); | 60 | int ghes_edac_register(struct ghes *ghes, struct device *dev); |
| 62 | 61 | ||
| 63 | void ghes_edac_unregister(struct ghes *ghes); | 62 | void ghes_edac_unregister(struct ghes *ghes); |
| 64 | 63 | ||
| 65 | #else | 64 | #else |
| 66 | static inline void ghes_edac_report_mem_error(struct ghes *ghes, int sev, | 65 | static inline void ghes_edac_report_mem_error(int sev, |
| 67 | struct cper_sec_mem_err *mem_err) | 66 | struct cper_sec_mem_err *mem_err) |
| 68 | { | 67 | { |
| 69 | } | 68 | } |
| 70 | 69 | ||
| 71 | static inline int ghes_edac_register(struct ghes *ghes, struct device *dev) | 70 | static inline int ghes_edac_register(struct ghes *ghes, struct device *dev) |
| 72 | { | 71 | { |
| 73 | return 0; | 72 | return -ENODEV; |
| 74 | } | 73 | } |
| 75 | 74 | ||
| 76 | static inline void ghes_edac_unregister(struct ghes *ghes) | 75 | static inline void ghes_edac_unregister(struct ghes *ghes) |
