diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/Makefile.inc | 3 | ||||
-rw-r--r-- | hw/cec.c | 2 | ||||
-rw-r--r-- | hw/chiptod.c | 3 | ||||
-rw-r--r-- | hw/dts.c | 64 | ||||
-rw-r--r-- | hw/fsp/fsp.c | 1 | ||||
-rw-r--r-- | hw/gx.c | 158 | ||||
-rw-r--r-- | hw/nx-842.c | 6 | ||||
-rw-r--r-- | hw/nx-crypto.c | 16 | ||||
-rw-r--r-- | hw/nx-rng.c | 6 | ||||
-rw-r--r-- | hw/p7ioc-inits.c | 1096 | ||||
-rw-r--r-- | hw/p7ioc-phb.c | 3242 | ||||
-rw-r--r-- | hw/p7ioc.c | 688 | ||||
-rw-r--r-- | hw/psi.c | 105 | ||||
-rw-r--r-- | hw/slw.c | 6 | ||||
-rw-r--r-- | hw/xscom.c | 10 |
15 files changed, 15 insertions, 5391 deletions
diff --git a/hw/Makefile.inc b/hw/Makefile.inc index 2885b50..e90f5cd 100644 --- a/hw/Makefile.inc +++ b/hw/Makefile.inc @@ -1,9 +1,8 @@ # -*-Makefile-*- SUBDIRS += hw -HW_OBJS = xscom.o chiptod.o gx.o cec.o lpc.o lpc-uart.o psi.o +HW_OBJS = xscom.o chiptod.o cec.o lpc.o lpc-uart.o psi.o HW_OBJS += homer.o slw.o occ.o fsi-master.o centaur.o imc.o HW_OBJS += nx.o nx-rng.o nx-crypto.o nx-compress.o nx-842.o nx-gzip.o -HW_OBJS += p7ioc.o p7ioc-inits.o p7ioc-phb.o HW_OBJS += phb3.o sfc-ctrl.o fake-rtc.o bt.o p8-i2c.o prd.o HW_OBJS += dts.o lpc-rtc.o npu.o npu-hw-procedures.o xive.o phb4.o HW_OBJS += fake-nvram.o lpc-mbox.o npu2.o npu2-hw-procedures.o @@ -16,9 +16,9 @@ #include <skiboot.h> #include <cec.h> -#include <p7ioc.h> #include <interrupts.h> #include <opal-api.h> +#include <opal-internal.h> /* * Note: This file os only used on P7/P7+ diff --git a/hw/chiptod.c b/hw/chiptod.c index 668789e..a2eaf02 100644 --- a/hw/chiptod.c +++ b/hw/chiptod.c @@ -132,7 +132,6 @@ static enum chiptod_type { chiptod_unknown, - chiptod_p7, chiptod_p8, chiptod_p9 } chiptod_type; @@ -1647,8 +1646,6 @@ static bool chiptod_probe(void) if (dt_has_node_property(np, "primary", NULL)) { chiptod_primary = chip; - if (dt_node_is_compatible(np, "ibm,power7-chiptod")) - chiptod_type = chiptod_p7; if (dt_node_is_compatible(np, "ibm,power8-chiptod")) chiptod_type = chiptod_p8; if (dt_node_is_compatible(np, "ibm,power9-chiptod")) @@ -38,67 +38,6 @@ enum { SENSOR_DTS_ATTR_TEMP_TRIP }; -/* Different sensor locations */ -#define P7_CT_ZONE_LSU 0 -#define P7_CT_ZONE_ISU 1 -#define P7_CT_ZONE_IFU 2 -#define P7_CT_ZONE_VFU 3 -#define P7_CT_ZONE_L3C 4 -#define P7_CT_ZONES 5 - -/* Per core Digital Thermal Sensors */ -#define EX_THERM_P7_DTS_RESULT0 0x8050000 -#define EX_THERM_P7_DTS_RESULT1 0x8050001 - -/* - * DTS2 Thermal Sensor Results - * - * 0..7 sensor with id 0. - * 8..15 sensor with id 1. (Only chiplets) - * 16..23 sensor with id 2. (Only chiplets) - * 24..31 sensor with id 3. (Only chiplets) - * 32..39 sensor with id 4. (Only chiplets) - * 40..56 reserved0 - * 57 Trip warning history - * 58 Trip critical history - * 59 Trip fatal history - * 60 reserved1 - * 61..63 ID of worst case DTS2 (Only valid in EX core chiplets) - */ -static int dts_read_core_temp_p7(uint32_t pir, struct dts *dts) -{ - int32_t chip_id = pir_to_chip_id(pir); - int32_t core = pir_to_core_id(pir); - uint64_t dts0; - struct dts temps[P7_CT_ZONES]; - int i; - int rc; - - rc = xscom_read(chip_id, - XSCOM_ADDR_P8_EX(core, EX_THERM_P7_DTS_RESULT0), - &dts0); - if (rc) - return rc; - - temps[P7_CT_ZONE_LSU].temp = (dts0 >> 56) & 0xff; - temps[P7_CT_ZONE_ISU].temp = (dts0 >> 48) & 0xff; - temps[P7_CT_ZONE_IFU].temp = (dts0 >> 40) & 0xff; - temps[P7_CT_ZONE_VFU].temp = (dts0 >> 32) & 0xff; - temps[P7_CT_ZONE_L3C].temp = (dts0 >> 24) & 0xff; - - /* keep the max DTS */ - for (i = 0; i < P7_CT_ZONES; i++) { - int16_t t = temps[i].temp; - if (t > dts->temp) - dts->temp = t; - } - dts->trip = (dts0 >> 3) & 0xf; - - prlog(PR_TRACE, "DTS: Chip %x Core %x temp:%dC trip:%x\n", - chip_id, core, dts->temp, dts->trip); - - return 0; -} /* Therm mac result masking for DTS (result(0:15) * 0:3 - 0x0 @@ -271,9 +210,6 @@ static int dts_read_core_temp(u32 pir, struct dts *dts, u8 attr, int rc; switch (proc_gen) { - case proc_gen_p7: - rc = dts_read_core_temp_p7(pir, dts); - break; case proc_gen_p8: rc = dts_read_core_temp_p8(pir, dts); break; diff --git a/hw/fsp/fsp.c b/hw/fsp/fsp.c index 8fe2aed..aa393c7 100644 --- a/hw/fsp/fsp.c +++ b/hw/fsp/fsp.c @@ -29,7 +29,6 @@ #include <fsp.h> #include <lock.h> #include <interrupts.h> -#include <gx.h> #include <device.h> #include <trace.h> #include <timebase.h> diff --git a/hw/gx.c b/hw/gx.c deleted file mode 100644 index 12cea5b..0000000 --- a/hw/gx.c +++ /dev/null @@ -1,158 +0,0 @@ -/* Copyright 2013-2014 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - * implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <skiboot.h> -#include <gx.h> -#include <xscom.h> - -/* - * Note: This file os only used on P7/P7+ - */ - -/* Configuration of the PSI BUID, see the explanation in - * interrupts.h - */ -static int gx_p7_configure_psi_buid(uint32_t chip, uint32_t buid) -{ - uint64_t mode1; - int rc; - - rc = xscom_read(chip, GX_P7_MODE1_REG, &mode1); - if (rc) { - prerror("GX: XSCOM error %d reading GX MODE1 REG\n", rc); - return rc; - } - - mode1 = SETFIELD(GX_P7_MODE1_PSI_BUID, mode1, buid); - mode1 &= ~GX_P7_MODE1_PSI_BUID_DISABLE; - - printf("GX: MODE1_REG set to 0x%llx\n", mode1); - rc = xscom_write(chip, GX_P7_MODE1_REG, mode1); - if (rc) { - prerror("GX: XSCOM error %d writing GX MODE1 REG\n", rc); - return rc; - } - - return 0; -} - -static int gx_p7p_configure_psi_buid(uint32_t chip, uint32_t buid) -{ - uint64_t mode4; - int rc; - - rc = xscom_read(chip, GX_P7P_MODE4_REG, &mode4); - if (rc) { - prerror("GX: XSCOM error %d reading GX MODE1 REG\n", rc); - return rc; - } - - mode4 = SETFIELD(GX_P7P_MODE4_PSI_BUID, mode4, buid); - mode4 &= ~GX_P7P_MODE4_PSI_BUID_DISABLE; - - rc = xscom_write(chip, GX_P7P_MODE4_REG, mode4); - if (rc) { - prerror("GX: XSCOM error %d writing GX MODE1 REG\n", rc); - return rc; - } - - return 0; -} - -/* Configure the BUID of the PSI interrupt in the GX - * controller. - * - * @chip: Chip number (0..31) - * @buid: 9-bit BUID value - */ -int gx_configure_psi_buid(uint32_t chip, uint32_t buid) -{ - uint32_t pvr = mfspr(SPR_PVR); - - printf("GX: PSI BUID for PVR %x (type %x) chip %d BUID 0x%x\n", - pvr, PVR_TYPE(pvr), chip, buid); - - switch (PVR_TYPE(pvr)) { - case PVR_TYPE_P7: - return gx_p7_configure_psi_buid(chip, buid); - case PVR_TYPE_P7P: - return gx_p7p_configure_psi_buid(chip, buid); - } - return -1; -} - - -static int gx_p7_configure_tce_bar(uint32_t chip, uint32_t gx, uint64_t addr, - uint64_t size) -{ - uint32_t areg, mreg; - int rc; - - switch (gx) { - case 0: - areg = GX_P7_GX0_TCE_BAR; - mreg = GX_P7_GX0_TCE_MASK; - break; - case 1: - areg = GX_P7_GX1_TCE_BAR; - mreg = GX_P7_GX1_TCE_MASK; - break; - default: - return -EINVAL; - } - - if (addr) { - uint64_t taddr, tmask; - - /* The address field contains bits 18 to 43 of the address */ - taddr = SETFIELD(GX_P7_TCE_BAR_ADDR, 0ul, - (addr >> GX_P7_TCE_BAR_ADDR_SHIFT)); - taddr |= GX_P7_TCE_BAR_ENABLE; - tmask = SETFIELD(GX_P7_TCE_MASK, 0ul, - ~((size - 1) >> GX_P7_TCE_BAR_ADDR_SHIFT)); - rc = xscom_write(chip, areg, 0); - rc |= xscom_write(chip, mreg, tmask); - rc |= xscom_write(chip, areg, taddr); - } else { - rc = xscom_write(chip, areg, 0); - } - return rc ? -EIO : 0; -} - -/* Configure the TCE BAR of a given GX bus - * - * @chip: Chip number (0..31) - * @gx : GX bus index - * @addr: base address of TCE table - * @size: size of TCE table - */ -int gx_configure_tce_bar(uint32_t chip, uint32_t gx, uint64_t addr, - uint64_t size) -{ - uint32_t pvr = mfspr(SPR_PVR); - - printf("GX: TCE BAR for PVR %x (type %x) chip %d gx %d\n", - pvr, PVR_TYPE(pvr), chip, gx); - - /* We only support P7... is there a P7+ with P5IOC2 ? */ - switch (PVR_TYPE(pvr)) { - case PVR_TYPE_P7: - return gx_p7_configure_tce_bar(chip, gx, addr, size); - } - return -EINVAL; -} - - diff --git a/hw/nx-842.c b/hw/nx-842.c index 8009f03..d4abe08 100644 --- a/hw/nx-842.c +++ b/hw/nx-842.c @@ -191,11 +191,7 @@ void nx_enable_842(struct dt_node *node, u32 gcid, u32 pb_base) u64 cfg_dma, cfg_842, cfg_ee; int rc; - if (dt_node_is_compatible(node, "ibm,power7-nx")) { - cfg_dma = pb_base + NX_P7_DMA_CFG; - cfg_842 = pb_base + NX_P7_842_CFG; - cfg_ee = pb_base + NX_P7_EE_CFG; - } else if (dt_node_is_compatible(node, "ibm,power8-nx")) { + if (dt_node_is_compatible(node, "ibm,power8-nx")) { cfg_dma = pb_base + NX_P8_DMA_CFG; cfg_842 = pb_base + NX_P8_842_CFG; cfg_ee = pb_base + NX_P8_EE_CFG; diff --git a/hw/nx-crypto.c b/hw/nx-crypto.c index 769112f..04cc789 100644 --- a/hw/nx-crypto.c +++ b/hw/nx-crypto.c @@ -38,10 +38,10 @@ #define AMF_COMPLETION_MODE NX_DMA_COMPLETION_MODE_PDMA #define AMF_CPB_WR (0) /* CPB WR not done with AMF */ #define AMF_OUTPUT_DATA_WR NX_DMA_OUTPUT_DATA_WR_DMA -#define EE_CH7 (0) /* disable engine AMF 2(P7) / 3(P8) */ -#define EE_CH6 (0) /* disable engine AMF 1(P7) / 2(P8) */ -#define EE_CH5 (0) /* disable engine AMF 0(P7) / 1(P8) */ -#define EE_CH4 (0) /* disable engine SYM 2(P7) / AMF 0(P8) */ +#define EE_CH7 (0) /* disable engine AMF 3(P8) */ +#define EE_CH6 (0) /* disable engine AMF 2(P8) */ +#define EE_CH5 (0) /* disable engine AMF 1(P8) */ +#define EE_CH4 (0) /* disable engine SYM AMF 0(P8) */ #define EE_CH3 (0) /* disable engine SYM 1 */ #define EE_CH2 (0) /* disable engine SYM 0 */ @@ -268,13 +268,7 @@ void nx_create_crypto_node(struct dt_node *node) prlog(PR_INFO, "NX%d: Crypto at 0x%x\n", gcid, pb_base); - if (dt_node_is_compatible(node, "ibm,power7-nx")) { - cfg_dma = pb_base + NX_P7_DMA_CFG; - cfg_sym = pb_base + NX_P7_SYM_CFG; - cfg_asym = pb_base + NX_P7_ASYM_CFG; - cfg_iq = pb_base + NX_P7_CRB_IQ; - cfg_ee = pb_base + NX_P7_EE_CFG; - } else if (dt_node_is_compatible(node, "ibm,power8-nx")) { + if (dt_node_is_compatible(node, "ibm,power8-nx")) { cfg_dma = pb_base + NX_P8_DMA_CFG; cfg_sym = pb_base + NX_P8_SYM_CFG; cfg_asym = pb_base + NX_P8_ASYM_CFG; diff --git a/hw/nx-rng.c b/hw/nx-rng.c index c0c90f5..d2fc7a3 100644 --- a/hw/nx-rng.c +++ b/hw/nx-rng.c @@ -58,11 +58,7 @@ void nx_create_rng_node(struct dt_node *node) gcid = dt_get_chip_id(node); pb_base = dt_get_address(node, 0, NULL); - if (dt_node_is_compatible(node, "ibm,power7-nx")) { - xbar = pb_base + NX_P7_RNG_BAR; - xcfg = pb_base + NX_P7_RNG_CFG; - addr_mask = NX_P7_RNG_BAR_ADDR; - } else if (dt_node_is_compatible(node, "ibm,power8-nx")) { + if (dt_node_is_compatible(node, "ibm,power8-nx")) { xbar = pb_base + NX_P8_RNG_BAR; xcfg = pb_base + NX_P8_RNG_CFG; addr_mask = NX_P8_RNG_BAR_ADDR; diff --git a/hw/p7ioc-inits.c b/hw/p7ioc-inits.c deleted file mode 100644 index 0d50694..0000000 --- a/hw/p7ioc-inits.c +++ /dev/null @@ -1,1096 +0,0 @@ -/* Copyright 2013-2014 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - * implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * This inits are in part auto-generated from tables coming - * from the HW guys, then hand updated - */ -#include <skiboot.h> -#include <p7ioc.h> -#include <p7ioc-regs.h> -#include <io.h> -#include <processor.h> -#include <timebase.h> - -#undef DUMP_CI_ROUTING -#undef DUMP_REG_WRITES - -#ifdef DUMP_REG_WRITES -#define REGW(offset, value) do { \ - out_be64(ioc->regs + (offset), (value)); \ - printf(" REGW: %06lx=%016lx RB: %016llx\n", \ - (unsigned long)(offset), \ - (unsigned long)(value), \ - in_be64(ioc->regs + (offset))); \ - in_be64(ioc->regs + (offset)); \ - } while(0) -#else -#define REGW(offset, value) do { \ - out_be64(ioc->regs + (offset), (value)); \ - in_be64(ioc->regs + (offset)); \ - } while(0) -#endif -#define REGR(offset) in_be64(ioc->regs + (offset)) - -static void p7ioc_init_BI(struct p7ioc *ioc) -{ - printf("P7IOC: Init BI...\n"); - - /*** General settings ***/ - - /* Init_1 and Init_2: Different between P7 and P7+ */ - if (PVR_TYPE(mfspr(SPR_PVR)) == PVR_TYPE_P7P) { - printf("P7IOC: -> Configured for P7+\n"); - - /* Chicken switches */ - REGW(0x3c00d8, 0x0004000000000600UL); - /* GX config */ - REGW(0x3c00a0, 0x9F8929BE00880085UL); - } else { - printf("P7IOC: -> Configured for P7\n"); - - /* P7 setting assumes "early write done" mode is - * enabled in the GX controller. It seems to be - * the case but maybe we want to check/set it via - * xscom ? - */ - /* Chicken switches */ - REGW(0x3c00d8, 0x00040000000004C0UL); - /* GX config */ - REGW(0x3c00a0, 0x9C8929BE00880085UL); - } - - /* - * Note: While running skiboot on Firebird-L, I have - * to print something or wait for a while. The root - * cause wasn't identified yet. - */ - time_wait_ms(100); - - /* Init_3: Upbound Credit Config */ - REGW(0x3c00c8, 0x0303060403030000UL); - /* Init_4: Credit Init Timer */ - REGW(0x3c00e8, 0x00000000000000FFUL); - - /* Init_4.1: BI Ack Timing */ - REGW(0x3c00e8, 0x0000FC0000000000UL); - /* Init_5: Ordering Override 0*/ - REGW(0x3c0200, 0x0000000000000000UL); - /* Init_6: Ordering Override 1*/ - REGW(0x3c0208, 0x0000000000000000UL); - - /*** Downbound TTYPE table ***/ - - /* Init_7: Enable sequence / speculation for CI Loads */ - REGW(0x3c00a8, 0x0000000000000004UL); - /* Init_8: */ - REGW(0x3c00b0, 0x700800C000000000UL); - /* Init_9: Enable sequence / speculation for CI Stores */ - REGW(0x3c00a8, 0x0000000000000005UL); - /* Init_10: */ - REGW(0x3c00b0, 0x704820C000000000UL); - /* Init_11: Enable speculation for EOI */ - REGW(0x3c00a8, 0x000000000000001BUL); - /* Init_12: */ - REGW(0x3c00b0, 0x3590204000000000UL); - /* Init_13: ENable speculation for DMA Rd Responses */ - REGW(0x3c00a8, 0x0000000000000020UL); - /* Init_14: */ - REGW(0x3c00b0, 0x1103C4C000000000UL); - /* Init_15: Enable sequence for DMA RWNITC */ - REGW(0x3c00a8, 0x0000000000000001UL); - /* Init_16: */ - REGW(0x3c00b0, 0xC000000000000000UL); - /* Init_17: Enable sequence for IOKill */ - REGW(0x3c00a8, 0x0000000000000009UL); - /* Init_18: */ - REGW(0x3c00b0, 0x4208210000000000UL); - /* Init_19: Enable sequence for IOKill */ - REGW(0x3c00a8, 0x000000000000000AUL); - /* Init_20: */ - REGW(0x3c00b0, 0x4200210000000000UL); - /* Init_21: Enable sequence for FMTC CI Store w/Kill */ - REGW(0x3c00a8, 0x0000000000000021UL); - - /*** Timer controls ***/ - - /* Init_22: */ - REGW(0x3c00b0, 0x4200300000000000UL); - /* Init_23: Dnbound timer mask */ - REGW(0x3c0190, 0x0040000000000000UL); - /* Init_24: Upbound timer mask 0 */ - REGW(0x3c0180, 0x0010001000100010UL); - /* Init_25: Upbound timer mask 1 */ - REGW(0x3c0188, 0x0010000000000000UL); - /* Init_26: Credit sync check config */ - REGW(0x3c00f0, 0xC102000000000000UL); - - /*** Setup trace ***/ - - /* Init_27: DBG stop trace */ - REGW(0x3c0410, 0x4000000000000000UL); - /* Init_28: DBG control */ - REGW(0x3c0400, 0x0000000000000000UL); - /* Init_29: DBG Mode */ - REGW(0x3c0408, 0xA0000000F0CC3300UL); - /* Init_29a: DBG C0 (Stop on Error) */ - REGW(0x3c0418, 0xF4F00FFF00000000UL); - /* Init_30: DBG pre-mux select */ - REGW(0x3c0478, 0x0023000000000000UL); - /* Init_31: CA0 mode */ - REGW(0x3c04b0, 0x8000000000000000UL); - /* Init_32: CA0 Compression 0 */ - REGW(0x3c04b8, 0x0000000000000000UL); - /* Init_33: CA0 Compression 1 */ - REGW(0x3c04c0, 0x0000000000000000UL); - /* Init_34: CA0 Pattern A march (cmd1 selected val) */ - REGW(0x3c0480, 0x008000007FFFFF00UL); - /* Init_35: CA0 Trigger 0 definition (pattern A) */ - REGW(0x3c04a0, 0x8000000000000000UL); - /* Init_36: CA1 mode */ - REGW(0x3c0530, 0x8000000000000000UL); - /* Init_37: CA1 Compression 0 */ - REGW(0x3c0538, 0x0000000000000000UL); - /* Init_38: CA1 Compression 1 */ - REGW(0x3c0540, 0x0000000000000000UL); - /* Init_39: CA2 mode */ - REGW(0x3c05b0, 0x8000000000000000UL); - /* Init_40: CA2 Compression 0 */ - REGW(0x3c05b8, 0x0000000000000000UL); - /* Init_41: CA2 Compression 1 */ - REGW(0x3c05c0, 0x0000000000000000UL); - /* Init_42: CA3 Mode */ - REGW(0x3c0630, 0x8000000000000000UL); - /* Init_43: CA3 Compression 0 */ - REGW(0x3c0638, 0x0000000000000000UL); - /* Init_44: CA3 Compression 1 */ - REGW(0x3c0640, 0x0000000000000000UL); - /* Init_45: CA3 Pattern A match (AIB val) */ - REGW(0x3c0600, 0x80000100FFFEFF00UL); - /* Init_46: CA3 Trigger 0 definition (pattern A) */ - REGW(0x3c0620, 0x8000000000000000UL); - /* Init_47: DBG unfreeze trace */ - REGW(0x3c0410, 0x1000000000000000UL); - /* Init_48: DBG start trace */ - REGW(0x3c0410, 0x8000000000000000UL); - - /*** AIB Port Config ***/ - - /* Init_49: AIB Port Information */ - REGW(0x3c00d0, 0x0888888800000000UL); - /* Init_50: Port Ordering controls */ - REGW(0x3c0200, 0x0000000000000000UL); - - /*** LEMs (need to match recov. tables) ***/ - - /* Init_51: Clear upbound LEM */ - REGW(0x3c0000, 0x0000000000000000UL); - /* Init_52: Clear upbound WOF */ - REGW(0x3c0040, 0x0000000000000000UL); - /* Init_53: Clear Dnbound LEM */ - REGW(0x3c0050, 0x0000000000000000UL); - /* Init_54: Clear Dnbound WOF */ - REGW(0x3c0090, 0x0000000000000000UL); - /* Init_55: Clear Fences */ - REGW(0x3c0130, 0x0000000000000000UL); - /* Init_56: Clear Erpt latches */ - REGW(0x3c0148, 0x0080000000000000UL); - /* Init_57: Set Upbound LEM Action0 */ - REGW(0x3c0030, 0x0800000000800000UL); - /* Init_58: Set Upbound LEN Action1 */ - REGW(0x3c0038, 0x0000000000000000UL); - /* Init_59: Set Upbound LEM Mask (AND write) */ - REGW(0x3c0020, 0x0800000000000000UL); - /* Init_60: Set Dnbound LEM Action0 */ - REGW(0x3c0080, 0x2000080CA07FFF40UL); - /* Init_61: Set Dnbound LEM Action1 */ - REGW(0x3c0088, 0x0000000000000000UL); - /* Init_62: Set Dnbound LEM Mask (AND write) */ - REGW(0x3c0070, 0x00000800200FFE00UL); - - /*** Setup Fences (need to match recov. tables) ***/ - - /* Init_63: Set Upbound Damage Control 0 (GX Err) */ - REGW(0x3c0100, 0xF7FFFFFFFF7FFFFFUL); - /* Init_64: Set Upbound Damage Control 1 (AIB Fence) */ - REGW(0x3c0108, 0xF7FFFFFFFF7FFFFFUL); - /* Init_65: Set Upbound Damage Control 2 (Drop Pkt) */ - REGW(0x3c0110, 0x0010054000000000UL); - /* Init_66: Set Dnbound Damage Control 0 (GX Err) */ - REGW(0x3c0118, 0xDFFFF7F35F8000BFUL); - /* Init_67: Set Dnbound Damage Control 1 (AIB Fence) */ - REGW(0x3c0120, 0xDFFFF7F35F8000BFUL); - /* Init_68: Set Dnbound Damage Control 2 (Drop Pkt) */ - REGW(0x3c0128, 0x0000000C00000000UL); -} - -static void p7ioc_init_MISC_HSS(struct p7ioc *ioc) -{ - unsigned int i, regbase; - - printf("P7IOC: Init HSS...\n"); - - /* Note: These values might need to be tweaked per system and - * per physical port depending on electrical characteristics. - * - * For now we stick to the defaults provided by the spec. - */ - for (i = 0; i < P7IOC_NUM_PHBS; i++) { - regbase = P7IOC_HSS_BASE + i * P7IOC_HSS_STRIDE; - - if (!p7ioc_phb_enabled(ioc, i)) - continue; - - /* Init_1: HSSn CTL2 */ - REGW(regbase + P7IOC_HSSn_CTL2_OFFSET, 0xFFFF6DB6DB000000UL); - /* Init_2: HSSn CTL3 */ - REGW(regbase + P7IOC_HSSn_CTL3_OFFSET, 0x1130000320000000UL); - /* Init_3: HSSn CTL8 */ - REGW(regbase + P7IOC_HSSn_CTL8_OFFSET, 0xDDDDDDDD00000000UL); - -#if 0 /* All these remain set to the values configured by the FSP */ - /* Init_4: HSSn CTL9 */ - REGW(regbase + P7IOC_HSSn_CTL9_OFFSET, 0x9999999900000000); - /* Init_5: HSSn CTL10 */ - REGW(regbase + P7IOC_HSSn_CTL10_OFFSET, 0x8888888800000000); - /* Init_6: HSSn CTL11 */ - REGW(regbase + P7IOC_HSSn_CTL11_OFFSET, 0x4444444400000000); - /* Init_7: HSSn CTL12 */ - REGW(regbase + P7IOC_HSSn_CTL12_OFFSET, 0x3333333300000000); - /* Init_8: HSSn CTL13 */ - REGW(regbase + P7IOC_HSSn_CTL13_OFFSET, 0x2222222200000000); - /* Init_9: HSSn CTL14 */ - REGW(regbase + P7IOC_HSSn_CTL14_OFFSET, 0x1111111100000000); - /* Init_10: HSSn CTL15 */ - REGW(regbase + P7IOC_HSSn_CTL15_OFFSET, 0x1111111100000000); - /* Init_11: HSSn CTL16 */ - REGW(regbase + P7IOC_HSSn_CTL16_OFFSET, 0x9999999900000000); - /* Init_12: HSSn CTL17 */ - REGW(regbase + P7IOC_HSSn_CTL17_OFFSET, 0x8888888800000000); - /* Init_13: HSSn CTL18 */ - REGW(regbase + P7IOC_HSSn_CTL18_OFFSET, 0xDDDDDDDD00000000); - /* Init_14: HSSn CTL19 */ - REGW(regbase + P7IOC_HSSn_CTL19_OFFSET, 0xCCCCCCCC00000000); - /* Init_15: HSSn CTL20 */ - REGW(regbase + P7IOC_HSSn_CTL20_OFFSET, 0xBBBBBBBB00000000); - /* Init_16: HSSn CTL21 */ - REGW(regbase + P7IOC_HSSn_CTL21_OFFSET, 0x9999999900000000); - /* Init_17: HSSn CTL22 */ - REGW(regbase + P7IOC_HSSn_CTL22_OFFSET, 0x8888888800000000); - /* Init_18: HSSn CTL23 */ - REGW(regbase + P7IOC_HSSn_CTL23_OFFSET, 0x7777777700000000); -#endif - } -} - -static void p7ioc_init_RGC(struct p7ioc *ioc) -{ - unsigned int i; - uint64_t val, cfg; - - printf("P7IOC: Init RGC...\n"); - - /*** Clear ERPT Macros ***/ - - /* Init_1: RGC Configuration reg */ - cfg = REGR(0x3e1c08); - REGW(0x3e1c08, cfg | PPC_BIT(1)); - time_wait_ms(1); - - /* Init_2: RGC Configuration reg */ - REGW(0x3e1c08, cfg); - - /*** Set LEM regs (needs to match recov. code) */ - - /* Init_3: LEM FIR Accumulator */ - REGW(0x3e1e00, 0x0000000000000000UL); - /* Init_4: LEM Action 0 */ - REGW(0x3e1e30, 0x0FFF791F0B030000UL); - /* Init_5: LEN Action 1 */ - REGW(0x3e1e38, 0x0000000000000000UL); - /* Init_6: LEM WOF */ - REGW(0x3e1e40, 0x0000000000000000UL); - /* Init_7: LEM Mask Reg (AND write) */ - REGW(0x3e1e20, 0x0FFF001F03030000UL); - - /*** Set GEM regs (masks still on, no irpts can occur yet) ***/ - - /* Init_8: GEM XFIR */ - REGW(0x3e0008, 0x0000000000000000UL); - /* Init_9: GEM WOF */ - REGW(0x3e0028, 0x0000000000000000UL); - - /*** Set Damage Controls (needs to match recov.) ***/ - - /* Init_10: LDCP */ - REGW(0x3e1c18, 0xF00086C0B4FCFFFFUL); - - /*** Read status (optional) ***/ - - /* Init_11: Read status */ - val = REGR(0x3e1c10); - printf("P7IOC: Init_11 Status: %016llx\n", val); - - /*** Set running configuration **/ - - /* Init_12: Configuration reg (modes, values, timers) */ - REGW(0x3e1c08, 0x10000077CE100000UL); - - /* Init_13: Cmd/Dat Crd Allocation */ - REGW(0x3e1c20, 0x00000103000700FFUL); - /* Init_14: GP reg - disable errs, wrap, stop_trc */ - REGW(0x3e1018, 0x0000000000000000UL); - /* Init_15: Configuration reg (start init timers) */ - cfg = REGR(0x3e1c08); - REGW(0x3e1c08, cfg | 0x00003f0000000000UL); - - /*** Setup interrupts ***/ - - /* Init_16: BUID Register - * - * XXX NOTE: This needs to be clarified. According to the doc - * the register contains a 9-bit BUID, which makes sense so far. - * - * However, the initialization sequence says "depends on which - * GX bus) which doesn't since afaik the GX bus number is encoded - * in the BUID Extension bit which is right *above* the 9-bit - * BUID in the interrupt message. - * - * So I must be missing something here... For now I'll just - * write my 9-bit BUID and we'll see what happens. - * - */ - REGW(0x3e1800, (uint64_t)ioc->rgc_buid << PPC_BITLSHIFT(31)); - - /* Init_17: Supposed to lock the IODA table but we aren't racing - * with anybody so there is little point. - * - * Note: If/when we support some kind of error recovery that - * involves re-initializing the IOC, then we might have - * to take some locks but it's assumed that the necessary - * lock(s) will be obtained by the caller. - */ - //REGR(0x3e1840, 0x0000000000000000); - - /* Init_18: IODA Table Addr: Select IST*/ - REGW(0x3e1820, 0x8001000000000000UL); - /* Init_19: IODA Table Data: IRPT 0 */ - REGW(0x3e1830, 0x0000000000000000UL); - /* Init_20: IODA Table Data: IRPT 1 */ - REGW(0x3e1830, 0x0000000000000000UL); - /* Init_21: IODA Table Addr: Select HRT */ - REGW(0x3e1820, 0x8000000000000000UL); - /* Init_22: IODA Table Data: HRT - * - * XXX Figure out what this actually is and what value should - * we use. For now, do like BML and use 0 - */ - for (i = 0; i < 4; i++) - REGW(0x3e1830, 0x0000000000000000UL); - - /* Init_23: IODA Table Addr: select XIVT */ - REGW(0x3e1820, 0x8002000000000000UL); - /* Init_24: IODA Table Data: Mask all interrupts */ - for (i = 0; i < 16; i++) - REGW(0x3e1830, 0x000000ff00000000UL); - - /* Init_25: Clear table lock if any was stale */ - REGW(0x3e1840, 0x0000000000000000UL); - - /* Init_32..37: Set the PHB AIB addresses. We configure those - * to the values recommended in the p7IOC doc. - * - * XXX NOTE: I cannot find a documentation for these, I assume - * they just take the full 64-bit address, but we may want to - * dbl check just in case (it seems to be what BML does but - * I'm good at mis-reading Milton's Perl). - */ - for (i = 0; i < P7IOC_NUM_PHBS; i++) { - if (!p7ioc_phb_enabled(ioc, i)) - continue; - REGW(0x3e1080 + (i << 3), - ioc->mmio1_win_start + PHBn_AIB_BASE(i)); - } -} - -static void p7ioc_init_ci_routing(struct p7ioc *ioc) -{ - unsigned int i, j = 0; - uint64_t rmatch[47]; - uint64_t rmask[47]; - uint64_t pmask; - - /* Init_130: clear all matches (except 47 which routes to the RGC) */ - for (i = 0; i < 47; i++) { - rmatch[i] = REGR(P7IOC_CI_RMATC_REG(i)) & - ~(P7IOC_CI_RMATC_ADDR_VALID | - P7IOC_CI_RMATC_BUID_VALID | - P7IOC_CI_RMATC_TYPE_VALID); - rmask[i] = 0; - REGW(P7IOC_CI_RMATC_REG(i), rmatch[i]); - } - - /* Init_131...224: configure routing for everything except RGC - * - * We are using a slightly different routing setup than the - * example to make the code easier. We configure all PHB - * routing entries by doing all of PHB0 first, then all of PHB1 - * etc... - * - * Then we append everything else except the RGC itself which - * remains hard wired at entry 47. So the unused entries live - * at 39..46. - * - * - 0 : PHB0 LSI BUID - * - 1 : PHB0 MSI BUID - * - 2 : PHB0 AIB Registers - * - 3 : PHB0 IO Space - * - 4 : PHB0 M32 Space - * - 5 : PHB0 M64 Space - * - 6..11 : PHB1 - * - 12..17 : PHB2 - * - 18..23 : PHB3 - * - 24..29 : PHB4 - * - 30..35 : PHB5 - * - 36 : Invalidates broadcast (FMTC) - * - 37 : Interrupt response for RGC - * - 38 : RGC GEM BUID - * - 39..46 : Unused (alternate M64 ?) - * - 47 : RGC ASB Registers (catch all) - */ - - /* Helper macro to set a rule */ -#define CI_ADD_RULE(p, k, d, m) do { \ - rmask[j] = P7IOC_CI_RMATC_ENCODE_##k(m); \ - rmatch[j]= P7IOC_CI_RMATC_PORT(p) | \ - P7IOC_CI_RMATC_##k##_VALID | \ - P7IOC_CI_RMATC_ENCODE_##k(d); \ - j++; \ - } while (0) - - pmask = 0; - for (i = 0; i < P7IOC_NUM_PHBS; i++) { - unsigned int buid_base = ioc->buid_base + PHBn_BUID_BASE(i); - - if (!p7ioc_phb_enabled(ioc, i)) - continue; - - /* LSI BUIDs, match all 9 bits (1 BUID per PHB) */ - CI_ADD_RULE(P7IOC_CI_PHB_PORT(i), BUID, - buid_base + PHB_BUID_LSI_OFFSET, 0x1ff); - - /* MSI BUIDs, match 4 bits (16 BUIDs per PHB) */ - CI_ADD_RULE(P7IOC_CI_PHB_PORT(i), BUID, - buid_base + PHB_BUID_MSI_OFFSET, 0x1f0); - - /* AIB reg space */ - CI_ADD_RULE(P7IOC_CI_PHB_PORT(i), ADDR, - ioc->mmio1_win_start + PHBn_AIB_BASE(i), - ~(PHBn_AIB_SIZE - 1)); - - /* IO space */ - CI_ADD_RULE(P7IOC_CI_PHB_PORT(i), ADDR, - ioc->mmio1_win_start + PHBn_IO_BASE(i), - ~(PHB_IO_SIZE - 1)); - - /* M32 space */ - CI_ADD_RULE(P7IOC_CI_PHB_PORT(i), ADDR, - ioc->mmio2_win_start + PHBn_M32_BASE(i), - ~(PHB_M32_SIZE - 1)); - - /* M64 space */ - CI_ADD_RULE(P7IOC_CI_PHB_PORT(i), ADDR, - ioc->mmio2_win_start + PHBn_M64_BASE(i), - ~(PHB_M64_SIZE - 1)); - - /* For use with invalidate bcasts */ - pmask |= P7IOC_CI_PHB_PORT(i); - } - - /* Invalidates broadcast to all PHBs */ - CI_ADD_RULE(pmask, TYPE, 0x80, 0xf0); - - /* Interrupt responses go to RGC */ - CI_ADD_RULE(P7IOC_CI_RGC_PORT, TYPE, 0x60, 0xf0); - - /* RGC GEM BUID (1 BUID) */ - CI_ADD_RULE(P7IOC_CI_RGC_PORT, BUID, ioc->rgc_buid, 0x1ff); - - /* Program the values masks first */ - for (i = 0; i < 47; i++) - REGW(P7IOC_CI_RMASK_REG(i), rmask[i]); - for (i = 0; i < 47; i++) - REGW(P7IOC_CI_RMATC_REG(i), rmatch[i]); - - /* Init_225: CI Match 47 (Configure RGC catch all) */ - REGW(P7IOC_CI_RMASK_REG(47), 0x0000000000000000UL); - REGW(P7IOC_CI_RMATC_REG(47), 0x4000800000000000UL); - -#ifdef DUMP_CI_ROUTING - printf("P7IOC: CI Routing table:\n"); - for (i = 0; i < 48; i++) - printf(" [%.2d] MTCH: %016llx MSK: %016llx\n", i, - REGR(P7IOC_CI_RMATC_REG(i)), - REGR(P7IOC_CI_RMASK_REG(i))); -#endif /* DUMP_CI_ROUTING */ -} - -static void p7ioc_init_CI(struct p7ioc *ioc) -{ - printf("P7IOC: Init CI...\n"); - - /*** Clear ERPT macros ***/ - - /* XXX NOTE: The doc seems to also provide "alternate freq ratio" - * settings. Not sure what they are about, let's stick to the - * original values for now. - */ - - /* Init_1: CI Port 0 Configuration */ - REGW(0x3d0000, 0x420000C0073F0002UL); - /* Init_2: CI Port 0 Configuration */ - REGW(0x3d0000, 0x020000C0073F0002UL); - /* Init_3: CI Port 1 Configuration */ - REGW(0x3d1000, 0x42000FCF07200002UL); - /* Init_4: CI Port 1 Configuration */ - REGW(0x3d1000, 0x02000FCF07200002UL); - /* Init_5: CI Port 2 Configuration */ - REGW(0x3d2000, 0x420000C307200002UL); - /* Init_6: CI Port 2 Configuration */ - REGW(0x3d2000, 0x020000C307200002UL); - /* Init_7: CI Port 3 Configuration */ - REGW(0x3d3000, 0x420000C307200002UL); - /* Init_8: CI Port 3 Configuration */ - REGW(0x3d3000, 0x020000C307200002UL); - /* Init_9: CI Port 4 Configuration */ - REGW(0x3d4000, 0x420000C307200002UL); - /* Init_10: CI Port 4 Configuration */ - REGW(0x3d4000, 0x020000C307200002UL); - /* Init_11: CI Port 5 Configuration */ - REGW(0x3d5000, 0x420000C307200002UL); - /* Init_12: CI Port 5 Configuration */ - REGW(0x3d5000, 0x020000C307200002UL); - /* Init_13: CI Port 6 Configuration */ - REGW(0x3d6000, 0x420000C307200002UL); - /* Init_14: CI Port 6 Configuration */ - REGW(0x3d6000, 0x020000C307200002UL); - /* Init_15: CI Port 7 Configuration */ - REGW(0x3d7000, 0x420000C307200002UL); - /* Init_16: CI Port 7 Configuration */ - REGW(0x3d7000, 0x020000C307200002UL); - - /*** Set LEM regs (need to match recov.) ***/ - - /* Init_17: CI Port 0 LEM FIR Accumulator */ - REGW(0x3d0200, 0x0000000000000000UL); - /* Init_18: CI Port 0 LEM Action 0 */ - REGW(0x3d0230, 0x0A00000000000000UL); - /* Init_19: CI Port 0 LEM Action 1 */ - REGW(0x3d0238, 0x0000000000000000UL); - /* Init_20: CI Port 0 LEM WOF */ - REGW(0x3d0240, 0x0000000000000000UL); - /* Init_21: CI Port 0 LEM Mask (AND write) */ - REGW(0x3d0220, 0x0200000000000000UL); - /* Init_22: CI Port 1 LEM FIR Accumularor */ - REGW(0x3d1200, 0x0000000000000000UL); - /* Init_23: CI Port 1 LEM Action 0 */ - REGW(0x3d1230, 0x0000000000000000UL); - /* Init_24: CI Port 1 LEM Action 1 */ - REGW(0x3d1238, 0x0000000000000000UL); - /* Init_25: CI Port 1 LEM WOF */ - REGW(0x3d1240, 0x0000000000000000UL); - /* Init_26: CI Port 1 LEM Mask (AND write) */ - REGW(0x3d1220, 0x0000000000000000UL); - /* Init_27: CI Port 2 LEM FIR Accumulator */ - REGW(0x3d2200, 0x0000000000000000UL); - /* Init_28: CI Port 2 LEM Action 0 */ - REGW(0x3d2230, 0xA4F4000000000000UL); - /* Init_29: CI Port 2 LEM Action 1 */ - REGW(0x3d2238, 0x0000000000000000UL); - /* Init_30: CI Port 2 LEM WOF */ - REGW(0x3d2240, 0x0000000000000000UL); - /* Init_31: CI Port 2 LEM Mask (AND write) */ - REGW(0x3d2220, 0x0000000000000000UL); - /* Init_32: CI Port 3 LEM FIR Accumulator */ - REGW(0x3d3200, 0x0000000000000000UL); - /* Init_33: CI Port 3 LEM Action 0 */ - REGW(0x3d3230, 0xA4F4000000000000UL); - /* Init_34: CI Port 3 LEM Action 1 */ - REGW(0x3d3238, 0x0000000000000000UL); - /* Init_35: CI Port 3 LEM WOF */ - REGW(0x3d3240, 0x0000000000000000UL); - /* Init_36: CI Port 3 LEM Mask (AND write) */ - REGW(0x3d3220, 0x0000000000000000UL); - /* Init_37: CI Port 4 LEM FIR Accumulator */ - REGW(0x3d4200, 0x0000000000000000UL); - /* Init_38: CI Port 4 Action 0 */ - REGW(0x3d4230, 0xA4F4000000000000UL); - /* Init_39: CI Port 4 Action 1 */ - REGW(0x3d4238, 0x0000000000000000UL); - /* Init_40: CI Port 4 WOF */ - REGW(0x3d4240, 0x0000000000000000UL); - /* Init_41: CI Port 4 Mask (AND write) */ - REGW(0x3d4220, 0x0000000000000000UL); - /* Init_42: CI Port 5 LEM FIR Accumulator */ - REGW(0x3d5200, 0x0000000000000000UL); - /* Init_43: CI Port 5 Action 0 */ - REGW(0x3d5230, 0xA4F4000000000000UL); - /* Init_44: CI Port 5 Action 1 */ - REGW(0x3d5238, 0x0000000000000000UL); - /* Init_45: CI Port 4 WOF */ - REGW(0x3d5240, 0x0000000000000000UL); - /* Init_46: CI Port 5 Mask (AND write) */ - REGW(0x3d5220, 0x0000000000000000UL); - /* Init_47: CI Port 6 LEM FIR Accumulator */ - REGW(0x3d6200, 0x0000000000000000UL); - /* Init_48: CI Port 6 Action 0 */ - REGW(0x3d6230, 0xA4F4000000000000UL); - /* Init_49: CI Port 6 Action 1 */ - REGW(0x3d6238, 0x0000000000000000UL); - /* Init_50: CI Port 6 WOF */ - REGW(0x3d6240, 0x0000000000000000UL); - /* Init_51: CI Port 6 Mask (AND write) */ - REGW(0x3d6220, 0x0000000000000000UL); - /* Init_52: CI Port 7 LEM FIR Accumulator */ - REGW(0x3d7200, 0x0000000000000000UL); - /* Init_53: CI Port 7 Action 0 */ - REGW(0x3d7230, 0xA4F4000000000000UL); - /* Init_54: CI Port 7 Action 1 */ - REGW(0x3d7238, 0x0000000000000000UL); - /* Init_55: CI Port 7 WOF */ - REGW(0x3d7240, 0x0000000000000000UL); - /* Init_56: CI Port 7 Mask (AND write) */ - REGW(0x3d7220, 0x0000000000000000UL); - - /*** Set Damage Controls (need match recov.) ***/ - - /* Init_57: CI Port 0 LDCP*/ - REGW(0x3d0010, 0x421A0000000075FFUL); - /* Init_58: CI Port 1 LDCP */ - REGW(0x3d1010, 0x421A000000007FFFUL); - /* Init_59: CI Port 2 LDCP */ - REGW(0x3d2010, 0x421A24F400005B0BUL); - /* Init_60: CI Port 3 LDCP */ - REGW(0x3d3010, 0x421A24F400005B0BUL); - /* Init_61: CI Port 4 LDCP */ - REGW(0x3d4010, 0x421A24F400005B0BUL); - /* Init_62: CI Port 5 LDCP */ - REGW(0x3d5010, 0x421A24F400005B0BUL); - /* Init_63: CI Port 6 LDCP */ - REGW(0x3d6010, 0x421A24F400005B0BUL); - /* Init_64: CI Port 7 LDCP */ - REGW(0x3d7010, 0x421A24F400005B0BUL); - - /*** Setup Trace 0 ***/ - - /* Init_65: CI Trc 0 DBG - Run/Status (stop trace) */ - REGW(0x3d0810, 0x5000000000000000UL); - /* Init_66: CI Trc 0 DBG - Mode (not cross trig CA's) */ - REGW(0x3d0808, 0xB0000000F0000000UL); - /* Init_66a: CI Trc 0 DBG - C0 (stop on error) */ - REGW(0x3d0818, 0xF4F00FFF00000000UL); - /* Init_67: CI Trc 0 DBG - Select (port 0 mode 2) */ - REGW(0x3d0878, 0x0002000000000000UL); - /* Init_68: CI Trc 0 CA0 - Pattern A (RX cmd val) */ - REGW(0x3d0880, 0xC0200000DFFFFF00UL); - /* Init_69: CI Trc 0 CA0 - Trigger 0 (Pattern A) */ - REGW(0x3d08a0, 0x8000000000000000UL); - /* Init_70: CI Trc 0 - Mode */ - REGW(0x3d08b0, 0x8000000000000000UL); - /* Init_71: CI Trc 0 CA1 - Pattern A (TX cmd val) */ - REGW(0x3d0900, 0xC0200000DFFFFF00UL); - /* Init_72: CI Trc 0 CA1 - Trigger 0 (Pattern A) */ - REGW(0x3d0920, 0x8000000000000000UL); - /* Init_73: CI Trc 0 CA1 - Mode */ - REGW(0x3d0930, 0x8000000000000000UL); - /* Init_74: CI Trc 0 DBG - Run/Status (start trace) */ - REGW(0x3d0810, 0x8000000000000000UL); - - /*** Setup Trace 1 ***/ - - /* Init_75: CI Trc 1 DBG - Run/Status (stop trace) */ - REGW(0x3d0c10, 0x5000000000000000UL); - /* Init_76: CI Trc 1 DBG - Mode (not cross trig CA's) */ - REGW(0x3d0c08, 0xB0000000F0000000UL); - /* Init_76a: CI Trc 1 DBG - C0 (stop on error) */ - REGW(0x3d0c18, 0xF4F00FFF00000000UL); - /* Init_77: CI Trc 1 DBG - Select (port 1 mode 2) */ - REGW(0x3d0c78, 0x0102000000000000UL); - /* Init_78: CI Trc 1 CA0 - Pattern A (RX cmd val) */ - REGW(0x3d0c80, 0xC0200000DFFFFF00UL); - /* Init_79: CI Trc 1 CA0 - Trigger 0 (Pattern A) */ - REGW(0x3d0ca0, 0x8000000000000000UL); - /* Init_80: CI Trc 1 CA0 - Mode */ - REGW(0x3d0cb0, 0x8000000000000000UL); - /* Init_81: CI Trc 1 CA1 - Pattern A (TX cmd val) */ - REGW(0x3d0d00, 0xC0200000DFFFFF00UL); - /* Init_82: CI Trc 1 CA1 - Trigger 0 (Pattern A) */ - REGW(0x3d0d20, 0x8000000000000000UL); - /* Init_83: CI Trc 1 CA1 - Mode */ - REGW(0x3d0d30, 0x8000000000000000UL); - /* Init_84: CI Trc 1 DBG - Run/Status (start trace) */ - REGW(0x3d0c10, 0x8000000000000000UL); - - /* Init_85...92: - * - * XXX NOTE: Here we normally read the Port 0 to 7 status regs - * which is optional. Eventually we might want to do it to check - * if the status matches expectations - * - * (regs 0x3d0008 to 0x3d7008) - */ - - /*** Set buffer allocations (credits) ***/ - - /* Init_93: CI Port 0 Rx Cmd Buffer Allocation */ - REGW(0x3d0050, 0x0808040400000000UL); - /* Init_94: CI Port 0 Rx Dat Buffer Allocation */ - REGW(0x3d0060, 0x0006000200000000UL); - /* Init_95: CI Port 1 Tx Cmd Buffer Allocation */ - REGW(0x3d1030, 0x0000040400000000UL); - /* Init_96: CI Port 1 Tx Dat Buffer Allocation */ - REGW(0x3d1040, 0x0000004800000000UL); - /* Init_97: CI Port 1 Rx Cmd Buffer Allocation */ - REGW(0x3d1050, 0x0008000000000000UL); - /* Init_98: CI Port 1 Rx Dat Buffer Allocation */ - REGW(0x3d1060, 0x0048000000000000UL); - /* Init_99: CI Port 2 Tx Cmd Buffer Allocation */ - REGW(0x3d2030, 0x0808080800000000UL); - /* Init_100: CI Port 2 Tx Dat Buffer Allocation */ - REGW(0x3d2040, 0x0086008200000000UL); - /* Init_101: CI Port 2 Rx Cmd Buffer Allocation */ - REGW(0x3d2050, 0x0808080800000000UL); - /* Init_102: CI Port 2 Rx Dat Buffer Allocation */ - REGW(0x3d2060, 0x8648000000000000UL); - /* Init_103: CI Port 3 Tx Cmd Buffer Allocation */ - REGW(0x3d3030, 0x0808080800000000UL); - /* Init_104: CI Port 3 Tx Dat Buffer Allocation */ - REGW(0x3d3040, 0x0086008200000000UL); - /* Init_105: CI Port 3 Rx Cmd Buffer Allocation */ - REGW(0x3d3050, 0x0808080800000000UL); - /* Init_106: CI Port 3 Rx Dat Buffer Allocation */ - REGW(0x3d3060, 0x8648000000000000UL); - /* Init_107: CI Port 4 Tx Cmd Buffer Allocation */ - REGW(0x3d4030, 0x0808080800000000UL); - /* Init_108: CI Port 4 Tx Dat Buffer Allocation */ - REGW(0x3d4040, 0x0086008200000000UL); - /* Init_109: CI Port 4 Rx Cmd Buffer Allocation */ - REGW(0x3d4050, 0x0808080800000000UL); - /* Init_110: CI Port 4 Rx Dat Buffer Allocation */ - REGW(0x3d4060, 0x8648000000000000UL); - /* Init_111: CI Port 5 Tx Cmd Buffer Allocation */ - REGW(0x3d5030, 0x0808080800000000UL); - /* Init_112: CI Port 5 Tx Dat Buffer Allocation */ - REGW(0x3d5040, 0x0086008200000000UL); - /* Init_113: CI Port 5 Rx Cmd Buffer Allocation */ - REGW(0x3d5050, 0x0808080800000000UL); - /* Init_114: CI Port 5 Rx Dat Buffer Allocation */ - REGW(0x3d5060, 0x8648000000000000UL); - /* Init_115: CI Port 6 Tx Cmd Buffer Allocation */ - REGW(0x3d6030, 0x0808080800000000UL); - /* Init_116: CI Port 6 Tx Dat Buffer Allocation */ - REGW(0x3d6040, 0x0086008200000000UL); - /* Init_117: CI Port 6 Rx Cmd Buffer Allocation */ - REGW(0x3d6050, 0x0808080800000000UL); - /* Init_118: CI Port 6 Rx Dat Buffer Allocation */ - REGW(0x3d6060, 0x8648000000000000UL); - /* Init_119: CI Port 7 Tx Cmd Buffer Allocation */ - REGW(0x3d7030, 0x0808080800000000UL); - /* Init_120: CI Port 7 Tx Dat Buffer Allocation */ - REGW(0x3d7040, 0x0086008200000000UL); - /* Init_121: CI Port 7 Rx Cmd Buffer Allocation */ - REGW(0x3d7050, 0x0808080800000000UL); - /* Init_122: CI Port 6 Rx Dat Buffer Allocation */ - REGW(0x3d7060, 0x8648000000000000UL); - - /*** Channel ordering ***/ - - /* Init_123: CI Port 1 Ordering */ - REGW(0x3d1070, 0x73D0735E00000000UL); - /* Init_124: CI Port 2 Ordering */ - REGW(0x3d2070, 0x73D0735E00000000UL); - /* Init_125: CI Port 3 Ordering */ - REGW(0x3d3070, 0x73D0735E00000000UL); - /* Init_126: CI Port 4 Ordering */ - REGW(0x3d4070, 0x73D0735E00000000UL); - /* Init_127: CI Port 5 Ordering */ - REGW(0x3d5070, 0x73D0735E00000000UL); - /* Init_128: CI Port 6 Ordering */ - REGW(0x3d6070, 0x73D0735E00000000UL); - /* Init_129: CI POrt 7 Ordering */ - REGW(0x3d7070, 0x73D0735E00000000UL); - - /*** Setup routing (port 0 only) */ - - p7ioc_init_ci_routing(ioc); - - /*** Set Running Configuration/Crd Init Timers *** - * - * XXX NOTE: Supposed to only modify bits 8:15 - */ - - /* Init_226: CI Port 1 Configuration */ - REGW(0x3d1000, 0x023F0FCF07200002UL); - /* Init_227: CI Port 2 Configuration */ - REGW(0x3d2000, 0x023F00C307200002UL); - /* Init_228: CI Port 3 Configuration */ - REGW(0x3d3000, 0x023F00C307200002UL); - /* Init_229: CI Port 4 Configuration */ - REGW(0x3d4000, 0x023F00C307200002UL); - /* Init_230: CI Port 5 Configuration */ - REGW(0x3d5000, 0x023F00C307200002UL); - /* Init_231: CI Port 6 Configuration */ - REGW(0x3d6000, 0x023F00C307200002UL); - /* Init_232: CI Port 7 Configuration */ - REGW(0x3d7000, 0x023F00C307200002UL); - /* Init_233: CI Port 0 Configuration */ - REGW(0x3d0000, 0x023F00C0073F0002UL); -} - -static void p7ioc_init_PHBs(struct p7ioc *ioc) -{ - unsigned int i; - - printf("P7IOC: Init PHBs...\n"); - - /* We use the same reset sequence that we use for - * fast reboot for consistency - */ - for (i = 0; i < P7IOC_NUM_PHBS; i++) { - if (p7ioc_phb_enabled(ioc, i)) - p7ioc_phb_reset(&ioc->phbs[i].phb); - } -} - -static void p7ioc_init_MISC(struct p7ioc *ioc) -{ - printf("P7IOC: Init MISC...\n"); - - /*** Set LEM regs ***/ - - /* Init_1: LEM FIR Accumulator */ - REGW(0x3ea000, 0x0000000000000000UL); - /* Init_2: LEM Action 0 */ - REGW(0x3ea030, 0xFFFFFFFCEE3FFFFFUL); - /* Init_3: LEM Action 1 */ - REGW(0x3ea038, 0x0000000001C00000UL); - /* Init_4: LEM WOF */ - REGW(0x3ea040, 0x0000000000000000UL); - /* Init_5: LEM Mask (AND write) */ - REGW(0x3ea020, 0x000F03F0CD3FFFFFUL); - /* Init_5.1: I2C LEM FIR Accumulator */ - REGW(0x3eb000, 0x0000000000000000UL); - /* Init_5.2: I2C LEM Action 0 */ - REGW(0x3eb030, 0xEE00000000000000UL); - /* Init_5.3: I2C LEM Action 1 */ - REGW(0x3eb038, 0x0000000000000000UL); - /* Init_5.4: I2C LEM WOF */ - REGW(0x3eb040, 0x0000000000000000UL); - /* Init_5.5: I2C LEM Mask (AND write) */ - REGW(0x3eb020, 0x4600000000000000UL); - - /*** Set RGC GP bits (error enables) ***/ - - /* Init_7: RGC GP0 control (enable umux errors) */ - REGW(0x3e1018, 0x8888880000000000ULL); - - /*** Central Trace Setup *** - * - * By default trace 4 PHBs Rx/Tx, but this can be changed - * for debugging purposes - */ - - /* Init_8: */ - REGW(0x3ea810, 0x5000000000000000UL); - /* Init_9: */ - REGW(0x3ea800, 0x0000000000000000UL); - /* Init_10: */ - REGW(0x3ea808, 0xB0000000F0000000UL); - /* Init_11: */ - REGW(0x3ea818, 0xF4F00FFF00000000UL); - /* Init_12: */ - REGW(0x3ea820, 0x0000000000000000UL); - /* Init_13: */ - REGW(0x3ea828, 0x0000000000000000UL); - /* Init_14: */ - REGW(0x3ea830, 0x0000000000000000UL); - /* Init_15: */ - REGW(0x3ea838, 0x0000000000000000UL); - /* Init_16: */ - REGW(0x3ea840, 0x0000000000000000UL); - /* Init_17: */ - REGW(0x3ea878, 0x0300000000000000UL); - - /* Init_18: PHB0 mux select (Rx/Tx) */ - REGW(0x000F80, 0x0000000000000000UL); - /* Init_19: PHB1 mux select (Rx/Tx) */ - REGW(0x010F80, 0x0000000000000000UL); - /* Init_19.0: PHB2 mux select (Rx/Tx) */ - REGW(0x020F80, 0x0000000000000000UL); - /* Init_19.1: PHB3 mux select (Rx/Tx) */ - REGW(0x030F80, 0x0000000000000000UL); - /* Init_19.2: PHB4 mux select (Rx/Tx) */ - REGW(0x040F80, 0x0000000000000000UL); - /* Init_19.3: PHB5 mux select (Rx/Tx) */ - REGW(0x050F80, 0x0000000000000000UL); - - /* Init_20: */ - REGW(0x3ea880, 0x40008000FF7F0000UL); - /* Init_21: */ - REGW(0x3ea888, 0x0000000000000000UL); - /* Init_22: */ - REGW(0x3ea890, 0x0000000000000000UL); - /* Init_23: */ - REGW(0x3ea898, 0x0000000000000000UL); - /* Init_24: */ - REGW(0x3ea8a0, 0x8000000000000000UL); - /* Init_25: */ - REGW(0x3ea8a8, 0x0000000000000000UL); - /* Init_26: */ - REGW(0x3ea8b0, 0x8000000000000000UL); - /* Init_27: */ - REGW(0x3ea8b8, 0x0000000000000000UL); - /* Init_28: */ - REGW(0x3ea8c0, 0x0000000000000000UL); - /* Init_29: */ - REGW(0x3ea900, 0x40008000FF7F0000UL); - /* Init_30: */ - REGW(0x3ea908, 0x0000000000000000UL); - /* Init_31: */ - REGW(0x3ea910, 0x0000000000000000UL); - /* Init_32: */ - REGW(0x3ea918, 0x0000000000000000UL); - /* Init_33: */ - REGW(0x3ea920, 0x8000000000000000UL); - /* Init_34: */ - REGW(0x3ea928, 0x0000000000000000UL); - /* Init_35: */ - REGW(0x3ea930, 0x8000000000000000UL); - /* Init_36: */ - REGW(0x3ea938, 0x0000000000000000UL); - /* Init_37: */ - REGW(0x3ea940, 0x0000000000000000UL); - /* Init_38: */ - REGW(0x3ea980, 0x40008000FF7F0000UL); - /* Init_39: */ - REGW(0x3ea988, 0x0000000000000000UL); - /* Init_40: */ - REGW(0x3ea990, 0x0000000000000000UL); - /* Init_41: */ - REGW(0x3ea998, 0x0000000000000000UL); - /* Init_42: */ - REGW(0x3ea9a0, 0x8000000000000000UL); - /* Init_43: */ - REGW(0x3ea9a8, 0x0000000000000000UL); - /* Init_44: */ - REGW(0x3ea9b0, 0x8000000000000000UL); - /* Init_45: */ - REGW(0x3ea9b8, 0x0000000000000000UL); - /* Init_46: */ - REGW(0x3ea9c0, 0x0000000000000000UL); - /* Init_47: */ - REGW(0x3eaa00, 0x40008000FF7F0000UL); - /* Init_48: */ - REGW(0x3eaa08, 0x0000000000000000UL); - /* Init_49: */ - REGW(0x3eaa10, 0x0000000000000000UL); - /* Init_50: */ - REGW(0x3eaa18, 0x0000000000000000UL); - /* Init_51: */ - REGW(0x3eaa20, 0x8000000000000000UL); - /* Init_52: */ - REGW(0x3eaa28, 0x0000000000000000UL); - /* Init_53: */ - REGW(0x3eaa30, 0x8000000000000000UL); - /* Init_54: */ - REGW(0x3eaa38, 0x0000000000000000UL); - /* Init_55: */ - REGW(0x3eaa40, 0x0000000000000000UL); - /* Init_56: */ - REGW(0x3ea810, 0x1000000000000000UL); - /* Init_57: */ - REGW(0x3ea810, 0x8000000000000000UL); - - /*** I2C Master init fixup */ - - /* Init_58: I2C Master Operation Control */ - REGW(0x3eb0a8, 0x8100000000000000UL); -} - -static void p7ioc_init_GEM(struct p7ioc *ioc) -{ - printf("P7IOC: Init GEM...\n"); - - /*** Check for errors */ - - /* XXX TODO */ -#if 0 - /* Init_1: */ - REGR(0x3e0008, 0); - /* Init_2: */ - REGR(0x3e0010, 0); - /* Init_3: */ - REGR(0x3e0018, 0); -#endif - - /*** Get ready for new errors, allow interrupts *** - * - * XXX: Need to leave all unused port masked to prevent - * invalid errors - */ - - /* Init_4: GEM XFIR */ - REGW(0x3e0008, 0x0000000000000000); - /* Init_5: GEM Mask (See FIXME) */ - REGW(0x3e0020, 0x000F033FFFFFFFFFUL); - /* Init_6: GEM WOF */ - REGW(0x3e0028, 0x0000000000000000); -} - -int64_t p7ioc_inits(struct p7ioc *ioc) -{ - p7ioc_init_BI(ioc); - p7ioc_init_MISC_HSS(ioc); - p7ioc_init_RGC(ioc); - p7ioc_init_CI(ioc); - p7ioc_init_PHBs(ioc); - p7ioc_init_MISC(ioc); - p7ioc_init_GEM(ioc); - - return OPAL_SUCCESS; - -} - -void p7ioc_reset(struct io_hub *hub) -{ - struct p7ioc *ioc = iohub_to_p7ioc(hub); - unsigned int i; - - /* We could do a full cold reset of P7IOC but for now, let's - * not bother and just try to clean up the interrupts as best - * as possible - */ - - /* XXX TODO: RGC interrupts */ - - printf("P7IOC: Clearing IODA...\n"); - - /* First clear all IODA tables and wait a bit */ - for (i = 0; i < 6; i++) { - if (p7ioc_phb_enabled(ioc, i)) - p7ioc_phb_reset(&ioc->phbs[i].phb); - } -} diff --git a/hw/p7ioc-phb.c b/hw/p7ioc-phb.c deleted file mode 100644 index ac01103..0000000 --- a/hw/p7ioc-phb.c +++ /dev/null @@ -1,3242 +0,0 @@ -/* Copyright 2013-2014 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - * implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <skiboot.h> -#include <p7ioc.h> -#include <p7ioc-regs.h> -#include <io.h> -#include <timebase.h> -#include <affinity.h> -#include <pci-cfg.h> -#include <pci.h> -#include <pci-slot.h> -#include <interrupts.h> -#include <opal.h> -#include <ccan/str/str.h> - -#define PHBDBG(p, fmt, a...) prlog(PR_DEBUG, "PHB#%04x: " fmt, \ - (p)->phb.opal_id, ## a) -#define PHBERR(p, fmt, a...) prlog(PR_ERR, "PHB#%04x: " fmt, \ - (p)->phb.opal_id, ## a) - -/* Helper to select an IODA table entry */ -static inline void p7ioc_phb_ioda_sel(struct p7ioc_phb *p, uint32_t table, - uint32_t addr, bool autoinc) -{ - out_be64(p->regs + PHB_IODA_ADDR, - (autoinc ? PHB_IODA_AD_AUTOINC : 0) | - SETFIELD(PHB_IODA_AD_TSEL, 0ul, table) | - SETFIELD(PHB_IODA_AD_TADR, 0ul, addr)); -} - -static bool p7ioc_phb_fenced(struct p7ioc_phb *p) -{ - struct p7ioc *ioc = p->ioc; - uint64_t fence, fbits; - - fbits = 0x0003000000000000UL >> (p->index * 4); - fence = in_be64(ioc->regs + P7IOC_CHIP_FENCE_SHADOW); - - return (fence & fbits) != 0; -} - -/* - * Configuration space access - * - * The PHB lock is assumed to be already held - */ -static int64_t p7ioc_pcicfg_check(struct p7ioc_phb *p, uint32_t bdfn, - uint32_t offset, uint32_t size) -{ - uint32_t sm = size - 1; - - if (offset > 0xfff || bdfn > 0xffff) - return OPAL_PARAMETER; - if (offset & sm) - return OPAL_PARAMETER; - - /* The root bus only has a device at 0 and we get into an - * error state if we try to probe beyond that, so let's - * avoid that and just return an error to Linux - */ - if ((bdfn >> 8) == 0 && (bdfn & 0xff)) - return OPAL_HARDWARE; - - /* Check PHB state */ - if (p->broken) - return OPAL_HARDWARE; - - return OPAL_SUCCESS; -} - -#define P7IOC_PCI_CFG_READ(size, type) \ -static int64_t p7ioc_pcicfg_read##size(struct phb *phb, uint32_t bdfn, \ - uint32_t offset, type *data) \ -{ \ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); \ - uint64_t addr; \ - void *base = p->regs; \ - int64_t rc; \ - \ - /* Initialize data in case of error */ \ - *data = (type)0xffffffff; \ - \ - rc = p7ioc_pcicfg_check(p, bdfn, offset, sizeof(type)); \ - if (rc) \ - return rc; \ - \ - if (p7ioc_phb_fenced(p)) { \ - if (!(p->flags & P7IOC_PHB_CFG_USE_ASB)) \ - return OPAL_HARDWARE; \ - \ - base = p->regs_asb; \ - } else if ((p->flags & P7IOC_PHB_CFG_BLOCKED) && bdfn != 0) { \ - return OPAL_HARDWARE; \ - } \ - \ - addr = PHB_CA_ENABLE; \ - addr = SETFIELD(PHB_CA_BDFN, addr, bdfn); \ - addr = SETFIELD(PHB_CA_REG, addr, offset); \ - out_be64(base + PHB_CONFIG_ADDRESS, addr); \ - *data = in_le##size(base + PHB_CONFIG_DATA + \ - (offset & (4 - sizeof(type)))); \ - \ - return OPAL_SUCCESS; \ -} - -#define P7IOC_PCI_CFG_WRITE(size, type) \ -static int64_t p7ioc_pcicfg_write##size(struct phb *phb, uint32_t bdfn, \ - uint32_t offset, type data) \ -{ \ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); \ - void *base = p->regs; \ - uint64_t addr; \ - int64_t rc; \ - \ - rc = p7ioc_pcicfg_check(p, bdfn, offset, sizeof(type)); \ - if (rc) \ - return rc; \ - \ - if (p7ioc_phb_fenced(p)) { \ - if (!(p->flags & P7IOC_PHB_CFG_USE_ASB)) \ - return OPAL_HARDWARE; \ - \ - base = p->regs_asb; \ - } else if ((p->flags & P7IOC_PHB_CFG_BLOCKED) && bdfn != 0) { \ - return OPAL_HARDWARE; \ - } \ - \ - addr = PHB_CA_ENABLE; \ - addr = SETFIELD(PHB_CA_BDFN, addr, bdfn); \ - addr = SETFIELD(PHB_CA_REG, addr, offset); \ - out_be64(base + PHB_CONFIG_ADDRESS, addr); \ - out_le##size(base + PHB_CONFIG_DATA + \ - (offset & (4 - sizeof(type))), data); \ - \ - return OPAL_SUCCESS; \ -} - -P7IOC_PCI_CFG_READ(8, uint8_t) -P7IOC_PCI_CFG_READ(16, uint16_t) -P7IOC_PCI_CFG_READ(32, uint32_t) -P7IOC_PCI_CFG_WRITE(8, uint8_t) -P7IOC_PCI_CFG_WRITE(16, uint16_t) -P7IOC_PCI_CFG_WRITE(32, uint32_t) - -static void p7ioc_eeh_read_phb_status(struct p7ioc_phb *p, - struct OpalIoP7IOCPhbErrorData *stat) -{ - uint16_t tmp16; - unsigned int i; - - memset(stat, 0, sizeof(struct OpalIoP7IOCPhbErrorData)); - - - /* Error data common part */ - stat->common.version = OPAL_PHB_ERROR_DATA_VERSION_1; - stat->common.ioType = OPAL_PHB_ERROR_DATA_TYPE_P7IOC; - stat->common.len = sizeof(struct OpalIoP7IOCPhbErrorData); - - /* - * We read some registers using config space through AIB. - * - * Get to other registers using ASB when possible to get to them - * through a fence if one is present. - * - * Note that the OpalIoP7IOCPhbErrorData has oddities, such as the - * bridge control being 32-bit and the UTL registers being 32-bit - * (which they really are, but they use the top 32-bit of a 64-bit - * register so we need to be a bit careful). - */ - - /* Use ASB to access PCICFG if the PHB has been fenced */ - p->flags |= P7IOC_PHB_CFG_USE_ASB; - - /* Grab RC bridge control, make it 32-bit */ - p7ioc_pcicfg_read16(&p->phb, 0, PCI_CFG_BRCTL, &tmp16); - stat->brdgCtl = tmp16; - - /* Grab UTL status registers */ - stat->portStatusReg = hi32(in_be64(p->regs_asb - + UTL_PCIE_PORT_STATUS)); - stat->rootCmplxStatus = hi32(in_be64(p->regs_asb - + UTL_RC_STATUS)); - stat->busAgentStatus = hi32(in_be64(p->regs_asb - + UTL_SYS_BUS_AGENT_STATUS)); - - /* - * Grab various RC PCIe capability registers. All device, slot - * and link status are 16-bit, so we grab the pair control+status - * for each of them - */ - p7ioc_pcicfg_read32(&p->phb, 0, p->ecap + PCICAP_EXP_DEVCTL, - &stat->deviceStatus); - p7ioc_pcicfg_read32(&p->phb, 0, p->ecap + PCICAP_EXP_SLOTCTL, - &stat->slotStatus); - p7ioc_pcicfg_read32(&p->phb, 0, p->ecap + PCICAP_EXP_LCTL, - &stat->linkStatus); - - /* - * I assume those are the standard config space header, cmd & status - * together makes 32-bit. Secondary status is 16-bit so I'll clear - * the top on that one - */ - p7ioc_pcicfg_read32(&p->phb, 0, PCI_CFG_CMD, &stat->devCmdStatus); - p7ioc_pcicfg_read16(&p->phb, 0, PCI_CFG_SECONDARY_STATUS, &tmp16); - stat->devSecStatus = tmp16; - - /* Grab a bunch of AER regs */ - p7ioc_pcicfg_read32(&p->phb, 0, p->aercap + PCIECAP_AER_RERR_STA, - &stat->rootErrorStatus); - p7ioc_pcicfg_read32(&p->phb, 0, p->aercap + PCIECAP_AER_UE_STATUS, - &stat->uncorrErrorStatus); - p7ioc_pcicfg_read32(&p->phb, 0, p->aercap + PCIECAP_AER_CE_STATUS, - &stat->corrErrorStatus); - p7ioc_pcicfg_read32(&p->phb, 0, p->aercap + PCIECAP_AER_HDR_LOG0, - &stat->tlpHdr1); - p7ioc_pcicfg_read32(&p->phb, 0, p->aercap + PCIECAP_AER_HDR_LOG1, - &stat->tlpHdr2); - p7ioc_pcicfg_read32(&p->phb, 0, p->aercap + PCIECAP_AER_HDR_LOG2, - &stat->tlpHdr3); - p7ioc_pcicfg_read32(&p->phb, 0, p->aercap + PCIECAP_AER_HDR_LOG3, - &stat->tlpHdr4); - p7ioc_pcicfg_read32(&p->phb, 0, p->aercap + PCIECAP_AER_SRCID, - &stat->sourceId); - - /* Restore to AIB */ - p->flags &= ~P7IOC_PHB_CFG_USE_ASB; - - /* - * No idea what that that is supposed to be, opal.h says - * "Record data about the call to allocate a buffer." - * - * Let's leave them alone for now... - * - * uint64_t errorClass; - * uint64_t correlator; - */ - - /* P7IOC MMIO Error Regs */ - stat->p7iocPlssr = in_be64(p->regs_asb + PHB_CPU_LOADSTORE_STATUS); - stat->p7iocCsr = in_be64(p->regs_asb + PHB_DMA_CHAN_STATUS); - stat->lemFir = in_be64(p->regs_asb + PHB_LEM_FIR_ACCUM); - stat->lemErrorMask = in_be64(p->regs_asb + PHB_LEM_ERROR_MASK); - stat->lemWOF = in_be64(p->regs_asb + PHB_LEM_WOF); - stat->phbErrorStatus = in_be64(p->regs_asb + PHB_ERR_STATUS); - stat->phbFirstErrorStatus = in_be64(p->regs_asb + PHB_ERR1_STATUS); - stat->phbErrorLog0 = in_be64(p->regs_asb + PHB_ERR_LOG_0); - stat->phbErrorLog1 = in_be64(p->regs_asb + PHB_ERR_LOG_1); - stat->mmioErrorStatus = in_be64(p->regs_asb + PHB_OUT_ERR_STATUS); - stat->mmioFirstErrorStatus = in_be64(p->regs_asb + PHB_OUT_ERR1_STATUS); - stat->mmioErrorLog0 = in_be64(p->regs_asb + PHB_OUT_ERR_LOG_0); - stat->mmioErrorLog1 = in_be64(p->regs_asb + PHB_OUT_ERR_LOG_1); - stat->dma0ErrorStatus = in_be64(p->regs_asb + PHB_INA_ERR_STATUS); - stat->dma0FirstErrorStatus = in_be64(p->regs_asb + PHB_INA_ERR1_STATUS); - stat->dma0ErrorLog0 = in_be64(p->regs_asb + PHB_INA_ERR_LOG_0); - stat->dma0ErrorLog1 = in_be64(p->regs_asb + PHB_INA_ERR_LOG_1); - stat->dma1ErrorStatus = in_be64(p->regs_asb + PHB_INB_ERR_STATUS); - stat->dma1FirstErrorStatus = in_be64(p->regs_asb + PHB_INB_ERR1_STATUS); - stat->dma1ErrorLog0 = in_be64(p->regs_asb + PHB_INB_ERR_LOG_0); - stat->dma1ErrorLog1 = in_be64(p->regs_asb + PHB_INB_ERR_LOG_1); - - /* Grab PESTA & B content */ - p7ioc_phb_ioda_sel(p, IODA_TBL_PESTA, 0, true); - for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) - stat->pestA[i] = in_be64(p->regs_asb + PHB_IODA_DATA0); - p7ioc_phb_ioda_sel(p, IODA_TBL_PESTB, 0, true); - for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) - stat->pestB[i] = in_be64(p->regs_asb + PHB_IODA_DATA0); -} - -static int64_t p7ioc_eeh_freeze_status(struct phb *phb, uint64_t pe_number, - uint8_t *freeze_state, - uint16_t *pci_error_type, - uint16_t *severity) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); - uint64_t peev_bit = PPC_BIT(pe_number & 0x3f); - uint64_t peev, pesta, pestb; - - /* Defaults: not frozen */ - *freeze_state = OPAL_EEH_STOPPED_NOT_FROZEN; - *pci_error_type = OPAL_EEH_NO_ERROR; - - /* Check dead */ - if (p->broken) { - *freeze_state = OPAL_EEH_STOPPED_MMIO_DMA_FREEZE; - *pci_error_type = OPAL_EEH_PHB_ERROR; - if (severity) - *severity = OPAL_EEH_SEV_PHB_DEAD; - return OPAL_SUCCESS; - } - - /* Check fence */ - if (p7ioc_phb_fenced(p)) { - /* Should be OPAL_EEH_STOPPED_TEMP_UNAVAIL ? */ - *freeze_state = OPAL_EEH_STOPPED_MMIO_DMA_FREEZE; - *pci_error_type = OPAL_EEH_PHB_ERROR; - if (severity) - *severity = OPAL_EEH_SEV_PHB_FENCED; - return OPAL_SUCCESS; - } - - /* Check the PEEV */ - p7ioc_phb_ioda_sel(p, IODA_TBL_PEEV, 0, true); - peev = in_be64(p->regs + PHB_IODA_DATA0); - if (pe_number > 63) - peev = in_be64(p->regs + PHB_IODA_DATA0); - if (!(peev & peev_bit)) - return OPAL_SUCCESS; - - /* Indicate that we have an ER pending */ - p7ioc_phb_set_err_pending(p, true); - if (severity) - *severity = OPAL_EEH_SEV_PE_ER; - - /* Read the PESTA & PESTB */ - p7ioc_phb_ioda_sel(p, IODA_TBL_PESTA, pe_number, false); - pesta = in_be64(p->regs + PHB_IODA_DATA0); - p7ioc_phb_ioda_sel(p, IODA_TBL_PESTB, pe_number, false); - pestb = in_be64(p->regs + PHB_IODA_DATA0); - - /* Convert them */ - if (pesta & IODA_PESTA_MMIO_FROZEN) - *freeze_state |= OPAL_EEH_STOPPED_MMIO_FREEZE; - if (pestb & IODA_PESTB_DMA_STOPPED) - *freeze_state |= OPAL_EEH_STOPPED_DMA_FREEZE; - - /* XXX Handle more causes */ - if (pesta & IODA_PESTA_MMIO_CAUSE) - *pci_error_type = OPAL_EEH_PE_MMIO_ERROR; - else - *pci_error_type = OPAL_EEH_PE_DMA_ERROR; - - return OPAL_SUCCESS; -} - -static int64_t p7ioc_eeh_next_error(struct phb *phb, uint64_t *first_frozen_pe, - uint16_t *pci_error_type, uint16_t *severity) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); - struct p7ioc *ioc = p->ioc; - uint64_t fir, peev0, peev1; - uint32_t cfg32, i; - - /* Check if there're pending errors on the IOC. */ - if (p7ioc_err_pending(ioc) && - p7ioc_check_LEM(ioc, pci_error_type, severity)) - return OPAL_SUCCESS; - - /* Clear result */ - *pci_error_type = OPAL_EEH_NO_ERROR; - *severity = OPAL_EEH_SEV_NO_ERROR; - *first_frozen_pe = (uint64_t)-1; - - /* Check dead */ - if (p->broken) { - *pci_error_type = OPAL_EEH_PHB_ERROR; - *severity = OPAL_EEH_SEV_PHB_DEAD; - return OPAL_SUCCESS; - } - - /* Check fence */ - if (p7ioc_phb_fenced(p)) { - /* Should be OPAL_EEH_STOPPED_TEMP_UNAVAIL ? */ - *pci_error_type = OPAL_EEH_PHB_ERROR; - *severity = OPAL_EEH_SEV_PHB_FENCED; - p7ioc_phb_set_err_pending(p, false); - return OPAL_SUCCESS; - } - - /* - * If we don't have pending errors, which might be moved - * from IOC to the PHB, then check if there has any frozen PEs. - */ - if (!p7ioc_phb_err_pending(p)) { - p7ioc_phb_ioda_sel(p, IODA_TBL_PEEV, 0, true); - peev0 = in_be64(p->regs + PHB_IODA_DATA0); - peev1 = in_be64(p->regs + PHB_IODA_DATA0); - if (peev0 || peev1) { - p->err.err_src = P7IOC_ERR_SRC_PHB0 + p->index; - p->err.err_class = P7IOC_ERR_CLASS_ER; - p->err.err_bit = 0; - p7ioc_phb_set_err_pending(p, true); - } - } - - /* Check the pending errors, which might come from IOC */ - if (p7ioc_phb_err_pending(p)) { - /* - * If the frozen PE is caused by a malfunctioning TLP, we - * need reset the PHB. So convert ER to PHB-fatal error - * for the case. - */ - if (p->err.err_class == P7IOC_ERR_CLASS_ER) { - fir = in_be64(p->regs_asb + PHB_LEM_FIR_ACCUM); - if (fir & PPC_BIT(60)) { - p7ioc_pcicfg_read32(&p->phb, 0, - p->aercap + PCIECAP_AER_UE_STATUS, &cfg32); - if (cfg32 & PCIECAP_AER_UE_MALFORMED_TLP) - p->err.err_class = P7IOC_ERR_CLASS_PHB; - } - } - - /* - * Map P7IOC internal error class to that one OS can handle. - * For P7IOC_ERR_CLASS_ER, we also need figure out the frozen - * PE. - */ - switch (p->err.err_class) { - case P7IOC_ERR_CLASS_PHB: - *pci_error_type = OPAL_EEH_PHB_ERROR; - *severity = OPAL_EEH_SEV_PHB_FENCED; - p7ioc_phb_set_err_pending(p, false); - break; - case P7IOC_ERR_CLASS_MAL: - case P7IOC_ERR_CLASS_INF: - *pci_error_type = OPAL_EEH_PHB_ERROR; - *severity = OPAL_EEH_SEV_INF; - p7ioc_phb_set_err_pending(p, false); - break; - case P7IOC_ERR_CLASS_ER: - *pci_error_type = OPAL_EEH_PE_ERROR; - *severity = OPAL_EEH_SEV_PE_ER; - p7ioc_phb_ioda_sel(p, IODA_TBL_PEEV, 0, true); - peev0 = in_be64(p->regs + PHB_IODA_DATA0); - peev1 = in_be64(p->regs + PHB_IODA_DATA0); - - for (i = 0 ; i < 64; i++) { - if (PPC_BIT(i) & peev1) { - *first_frozen_pe = i + 64; - break; - } - } - for (i = 0 ; - *first_frozen_pe == (uint64_t)-1 && i < 64; - i++) { - if (PPC_BIT(i) & peev0) { - *first_frozen_pe = i; - break; - } - } - - /* No frozen PE? */ - if (*first_frozen_pe == (uint64_t)-1) { - *pci_error_type = OPAL_EEH_NO_ERROR; - *severity = OPAL_EEH_SEV_NO_ERROR; - p7ioc_phb_set_err_pending(p, false); - } - - break; - default: - *pci_error_type = OPAL_EEH_NO_ERROR; - *severity = OPAL_EEH_SEV_NO_ERROR; - p7ioc_phb_set_err_pending(p, false); - } - } - - return OPAL_SUCCESS; -} - -static void p7ioc_ER_err_clear(struct p7ioc_phb *p) -{ - u64 err, lem; - u32 val; - - /* Rec 1,2 */ - lem = in_be64(p->regs + PHB_LEM_FIR_ACCUM); - - /* Rec 3,4,5 AER registers (could use cfg space accessors) */ - out_be64(p->regs + PHB_CONFIG_ADDRESS, 0x8000001c00000000ull); - out_be32(p->regs + PHB_CONFIG_DATA, 0x10000000); - - /* Rec 6,7,8 XXX DOC whacks payload & req size ... we don't */ - out_be64(p->regs + PHB_CONFIG_ADDRESS, 0x8000005000000000ull); - val = in_be32(p->regs + PHB_CONFIG_DATA); - out_be32(p->regs + PHB_CONFIG_DATA, (val & 0xe0700000) | 0x0f000f00); - - /* Rec 9,10,11 */ - out_be64(p->regs + PHB_CONFIG_ADDRESS, 0x8000010400000000ull); - out_be32(p->regs + PHB_CONFIG_DATA, 0xffffffff); - - /* Rec 12,13,14 */ - out_be64(p->regs + PHB_CONFIG_ADDRESS, 0x8000011000000000ull); - out_be32(p->regs + PHB_CONFIG_DATA, 0xffffffff); - - /* Rec 23,24,25 */ - out_be64(p->regs + PHB_CONFIG_ADDRESS, 0x8000013000000000ull); - out_be32(p->regs + PHB_CONFIG_DATA, 0xffffffff); - - /* Rec 26,27,28 */ - out_be64(p->regs + PHB_CONFIG_ADDRESS, 0x8000004000000000ull); - out_be32(p->regs + PHB_CONFIG_DATA, 0x470100f8); - - /* Rec 29..34 UTL registers */ - err = in_be64(p->regs + UTL_SYS_BUS_AGENT_STATUS); - out_be64(p->regs + UTL_SYS_BUS_AGENT_STATUS, err); - err = in_be64(p->regs + UTL_PCIE_PORT_STATUS); - out_be64(p->regs + UTL_PCIE_PORT_STATUS, err); - err = in_be64(p->regs + UTL_RC_STATUS); - out_be64(p->regs + UTL_RC_STATUS, err); - - /* PHB error traps registers */ - err = in_be64(p->regs + PHB_ERR_STATUS); - out_be64(p->regs + PHB_ERR_STATUS, err); - out_be64(p->regs + PHB_ERR1_STATUS, 0); - out_be64(p->regs + PHB_ERR_LOG_0, 0); - out_be64(p->regs + PHB_ERR_LOG_1, 0); - - err = in_be64(p->regs + PHB_OUT_ERR_STATUS); - out_be64(p->regs + PHB_OUT_ERR_STATUS, err); - out_be64(p->regs + PHB_OUT_ERR1_STATUS, 0); - out_be64(p->regs + PHB_OUT_ERR_LOG_0, 0); - out_be64(p->regs + PHB_OUT_ERR_LOG_1, 0); - - err = in_be64(p->regs + PHB_INA_ERR_STATUS); - out_be64(p->regs + PHB_INA_ERR_STATUS, err); - out_be64(p->regs + PHB_INA_ERR1_STATUS, 0); - out_be64(p->regs + PHB_INA_ERR_LOG_0, 0); - out_be64(p->regs + PHB_INA_ERR_LOG_1, 0); - - err = in_be64(p->regs + PHB_INB_ERR_STATUS); - out_be64(p->regs + PHB_INB_ERR_STATUS, err); - out_be64(p->regs + PHB_INB_ERR1_STATUS, 0); - out_be64(p->regs + PHB_INB_ERR_LOG_0, 0); - out_be64(p->regs + PHB_INB_ERR_LOG_1, 0); - - /* Rec 67, 68 LEM */ - out_be64(p->regs + PHB_LEM_FIR_AND_MASK, ~lem); - out_be64(p->regs + PHB_LEM_WOF, 0); -} - -static int64_t p7ioc_eeh_freeze_clear(struct phb *phb, uint64_t pe_number, - uint64_t eeh_action_token) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); - uint64_t peev0, peev1; - - /* XXX Now this is a heavy hammer, coming roughly from the P7IOC doc - * and my old "pseudopal" code. It will need to be refined. In general - * error handling will have to be reviewed and probably done properly - * "from scratch" based on the description in the p7IOC spec. - * - * XXX Additionally, when handling interrupts, we might want to consider - * masking while processing and/or ack'ing interrupt bits etc... - */ - u64 err; - - /* Summary. If nothing, move to clearing the PESTs which can - * contain a freeze state from a previous error or simply set - * explicitly by the user - */ - err = in_be64(p->regs + PHB_ETU_ERR_SUMMARY); - if (err == 0) - goto clear_pest; - - p7ioc_ER_err_clear(p); - - clear_pest: - /* XXX We just clear the whole PESTA for MMIO clear and PESTB - * for DMA clear. We might want to only clear the frozen bit - * as to not clobber the rest of the state. However, we expect - * the state to have been harvested before the clear operations - * so this might not be an issue - */ - if (eeh_action_token & OPAL_EEH_ACTION_CLEAR_FREEZE_MMIO) { - p7ioc_phb_ioda_sel(p, IODA_TBL_PESTA, pe_number, false); - out_be64(p->regs + PHB_IODA_DATA0, 0); - } - if (eeh_action_token & OPAL_EEH_ACTION_CLEAR_FREEZE_DMA) { - p7ioc_phb_ioda_sel(p, IODA_TBL_PESTB, pe_number, false); - out_be64(p->regs + PHB_IODA_DATA0, 0); - } - - /* Update ER pending indication */ - p7ioc_phb_ioda_sel(p, IODA_TBL_PEEV, 0, true); - peev0 = in_be64(p->regs + PHB_IODA_DATA0); - peev1 = in_be64(p->regs + PHB_IODA_DATA0); - if (peev0 || peev1) { - p->err.err_src = P7IOC_ERR_SRC_PHB0 + p->index; - p->err.err_class = P7IOC_ERR_CLASS_ER; - p->err.err_bit = 0; - p7ioc_phb_set_err_pending(p, true); - } else - p7ioc_phb_set_err_pending(p, false); - - return OPAL_SUCCESS; -} - -static int64_t p7ioc_eeh_freeze_set(struct phb *phb, uint64_t pe_number, - uint64_t eeh_action_token) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); - uint64_t data; - - if (pe_number > 127) - return OPAL_PARAMETER; - - if (eeh_action_token != OPAL_EEH_ACTION_SET_FREEZE_MMIO && - eeh_action_token != OPAL_EEH_ACTION_SET_FREEZE_DMA && - eeh_action_token != OPAL_EEH_ACTION_SET_FREEZE_ALL) - return OPAL_PARAMETER; - - if (eeh_action_token & OPAL_EEH_ACTION_SET_FREEZE_MMIO) { - p7ioc_phb_ioda_sel(p, IODA_TBL_PESTA, pe_number, false); - data = in_be64(p->regs + PHB_IODA_DATA0); - data |= IODA_PESTA_MMIO_FROZEN; - out_be64(p->regs + PHB_IODA_DATA0, data); - } - - if (eeh_action_token & OPAL_EEH_ACTION_SET_FREEZE_DMA) { - p7ioc_phb_ioda_sel(p, IODA_TBL_PESTB, pe_number, false); - data = in_be64(p->regs + PHB_IODA_DATA0); - data |= IODA_PESTB_DMA_STOPPED; - out_be64(p->regs + PHB_IODA_DATA0, data); - } - - return OPAL_SUCCESS; -} - -static int64_t p7ioc_err_inject_finalize(struct p7ioc_phb *p, uint64_t addr, - uint64_t mask, uint64_t ctrl, - bool is_write) -{ - if (is_write) - ctrl |= PHB_PAPR_ERR_INJ_CTL_WR; - else - ctrl |= PHB_PAPR_ERR_INJ_CTL_RD; - - /* HW100549: Take read and write for outbound errors - * on DD10 chip - */ - if (p->rev == P7IOC_REV_DD10) - ctrl |= (PHB_PAPR_ERR_INJ_CTL_RD | PHB_PAPR_ERR_INJ_CTL_WR); - - out_be64(p->regs + PHB_PAPR_ERR_INJ_ADDR, addr); - out_be64(p->regs + PHB_PAPR_ERR_INJ_MASK, mask); - out_be64(p->regs + PHB_PAPR_ERR_INJ_CTL, ctrl); - - return OPAL_SUCCESS; -} - -static int64_t p7ioc_err_inject_mem32(struct p7ioc_phb *p, uint64_t pe_number, - uint64_t addr, uint64_t mask, - bool is_write) -{ - uint64_t a, m, prefer, base; - uint64_t ctrl = PHB_PAPR_ERR_INJ_CTL_OUTB; - int32_t index; - - a = 0x0ull; - prefer = 0x0ull; - for (index = 0; index < 128; index++) { - if (GETFIELD(IODA_XXDT_PE, p->m32d_cache[index]) != pe_number) - continue; - - base = p->m32_base + M32_PCI_START + - (M32_PCI_SIZE / 128) * index; - - /* Update preferred address */ - if (!prefer) { - prefer = GETFIELD(PHB_PAPR_ERR_INJ_MASK_MMIO, base); - prefer = SETFIELD(PHB_PAPR_ERR_INJ_MASK_MMIO, - 0x0ull, prefer); - } - - /* The input address matches ? */ - if (addr >= base && - addr < base + (M32_PCI_SIZE / 128)) { - a = addr; - break; - } - } - - /* Invalid PE number */ - if (!prefer) - return OPAL_PARAMETER; - - /* Specified address is out of range */ - if (!a) { - a = prefer; - m = PHB_PAPR_ERR_INJ_MASK_MMIO; - } else { - m = mask; - } - - return p7ioc_err_inject_finalize(p, a, m, ctrl, is_write); -} - -static int64_t p7ioc_err_inject_io32(struct p7ioc_phb *p, uint64_t pe_number, - uint64_t addr, uint64_t mask, - bool is_write) -{ - uint64_t a, m, prefer, base; - uint64_t ctrl = PHB_PAPR_ERR_INJ_CTL_OUTB; - int32_t index; - - a = 0x0ull; - prefer = 0x0ull; - for (index = 0; index < 128; index++) { - if (GETFIELD(IODA_XXDT_PE, p->iod_cache[index]) != pe_number) - continue; - - base = p->io_base + (PHB_IO_SIZE / 128) * index; - - /* Update preferred address */ - if (!prefer) { - prefer = GETFIELD(PHB_PAPR_ERR_INJ_MASK_IO, base); - prefer = SETFIELD(PHB_PAPR_ERR_INJ_MASK_IO, 0x0ull, prefer); - } - - /* The input address matches ? */ - if (addr >= base && - addr < base + (PHB_IO_SIZE / 128)) { - a = addr; - break; - } - } - - /* Invalid PE number */ - if (!prefer) - return OPAL_PARAMETER; - - /* Specified address is out of range */ - if (!a) { - a = prefer; - m = PHB_PAPR_ERR_INJ_MASK_IO; - } else { - m = mask; - } - - return p7ioc_err_inject_finalize(p, a, m, ctrl, is_write); -} - -static int64_t p7ioc_err_inject_cfg(struct p7ioc_phb *p, uint64_t pe_number, - uint64_t addr, uint64_t mask, - bool is_write) -{ - uint64_t a, m; - uint64_t ctrl = PHB_PAPR_ERR_INJ_CTL_CFG; - uint8_t v_bits, base, bus_no; - - /* Looking into PELTM to see if the PCI bus# is owned - * by the PE#. Otherwise, we have to figure one out. - */ - base = GETFIELD(IODA_PELTM_BUS, p->peltm_cache[pe_number]); - v_bits = GETFIELD(IODA_PELTM_BUS_VALID, p->peltm_cache[pe_number]); - switch (v_bits) { - case IODA_BUS_VALID_3_BITS: - case IODA_BUS_VALID_4_BITS: - case IODA_BUS_VALID_5_BITS: - case IODA_BUS_VALID_6_BITS: - case IODA_BUS_VALID_7_BITS: - case IODA_BUS_VALID_ALL: - base = GETFIELD(IODA_PELTM_BUS, p->peltm_cache[pe_number]); - base &= (0xff - (((1 << (7 - v_bits)) - 1))); - a = SETFIELD(PHB_PAPR_ERR_INJ_MASK_CFG, 0x0ul, base); - m = PHB_PAPR_ERR_INJ_MASK_CFG; - - bus_no = GETFIELD(PHB_PAPR_ERR_INJ_MASK_CFG, addr); - bus_no &= (0xff - (((1 << (7 - v_bits)) - 1))); - if (base == bus_no) { - a = addr; - m = mask; - } - - break; - case IODA_BUS_VALID_ANY: - default: - return OPAL_PARAMETER; - } - - return p7ioc_err_inject_finalize(p, a, m, ctrl, is_write); -} - -static int64_t p7ioc_err_inject_dma(struct p7ioc_phb *p, uint64_t pe_number, - uint64_t addr, uint64_t mask, - bool is_write) -{ - uint64_t ctrl = PHB_PAPR_ERR_INJ_CTL_INB; - int32_t index; - - /* For DMA, we just pick address from TVT */ - for (index = 0; index < 128; index++) { - if (GETFIELD(IODA_TVT1_PE_NUM, p->tve_hi_cache[index]) != - pe_number) - continue; - - addr = SETFIELD(PHB_PAPR_ERR_INJ_MASK_DMA, 0ul, index); - mask = PHB_PAPR_ERR_INJ_MASK_DMA; - break; - } - - /* Some PE might not have DMA capability */ - if (index >= 128) - return OPAL_PARAMETER; - - return p7ioc_err_inject_finalize(p, addr, mask, ctrl, is_write); -} - -static int64_t p7ioc_err_inject(struct phb *phb, uint64_t pe_number, - uint32_t type, uint32_t func, - uint64_t addr, uint64_t mask) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); - int64_t (*handler)(struct p7ioc_phb *p, uint64_t pe_number, - uint64_t addr, uint64_t mask, bool is_write); - bool is_write; - - /* To support 64-bits error later */ - if (type == OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR64) - return OPAL_UNSUPPORTED; - - /* We can't inject error to the reserved PE#127 */ - if (pe_number > 126) - return OPAL_PARAMETER; - - /* Clear the leftover from last time */ - out_be64(p->regs + PHB_PAPR_ERR_INJ_CTL, 0x0ul); - - /* Check if PE number is valid one in PELTM cache */ - if (p->peltm_cache[pe_number] == 0x0001f80000000000ull) - return OPAL_PARAMETER; - - /* Clear the leftover from last time */ - out_be64(p->regs + PHB_PAPR_ERR_INJ_CTL, 0x0ul); - - switch (func) { - case OPAL_ERR_INJECT_FUNC_IOA_LD_MEM_ADDR: - case OPAL_ERR_INJECT_FUNC_IOA_LD_MEM_DATA: - is_write = false; - handler = p7ioc_err_inject_mem32; - break; - case OPAL_ERR_INJECT_FUNC_IOA_ST_MEM_ADDR: - case OPAL_ERR_INJECT_FUNC_IOA_ST_MEM_DATA: - is_write = true; - handler = p7ioc_err_inject_mem32; - break; - case OPAL_ERR_INJECT_FUNC_IOA_LD_IO_ADDR: - case OPAL_ERR_INJECT_FUNC_IOA_LD_IO_DATA: - is_write = false; - handler = p7ioc_err_inject_io32; - break; - case OPAL_ERR_INJECT_FUNC_IOA_ST_IO_ADDR: - case OPAL_ERR_INJECT_FUNC_IOA_ST_IO_DATA: - is_write = true; - handler = p7ioc_err_inject_io32; - break; - case OPAL_ERR_INJECT_FUNC_IOA_LD_CFG_ADDR: - case OPAL_ERR_INJECT_FUNC_IOA_LD_CFG_DATA: - is_write = false; - handler = p7ioc_err_inject_cfg; - break; - case OPAL_ERR_INJECT_FUNC_IOA_ST_CFG_ADDR: - case OPAL_ERR_INJECT_FUNC_IOA_ST_CFG_DATA: - is_write = true; - handler = p7ioc_err_inject_cfg; - break; - case OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_ADDR: - case OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_DATA: - case OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_MASTER: - case OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_TARGET: - is_write = false; - handler = p7ioc_err_inject_dma; - break; - case OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_ADDR: - case OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_DATA: - case OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_MASTER: - case OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_TARGET: - is_write = true; - handler = p7ioc_err_inject_dma; - break; - default: - return OPAL_PARAMETER; - } - - return handler(p, pe_number, addr, mask, is_write); -} - -static int64_t p7ioc_get_diag_data(struct phb *phb, void *diag_buffer, - uint64_t diag_buffer_len) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); - struct OpalIoP7IOCPhbErrorData *diag = diag_buffer; - - if (diag_buffer_len < sizeof(struct OpalIoP7IOCPhbErrorData)) - return OPAL_PARAMETER; - - /* Specific error data */ - p7ioc_eeh_read_phb_status(p, diag); - - /* - * We're running to here probably because of errors (MAL - * or INF class) from IOC. For the case, we need clear - * the pending errors and mask the error bit for MAL class - * error. Fortunately, we shouldn't get MAL class error from - * IOC on P7IOC. - */ - if (p7ioc_phb_err_pending(p) && - p->err.err_class == P7IOC_ERR_CLASS_INF && - p->err.err_src >= P7IOC_ERR_SRC_PHB0 && - p->err.err_src <= P7IOC_ERR_SRC_PHB5) { - p7ioc_ER_err_clear(p); - p7ioc_phb_set_err_pending(p, false); - } - - return OPAL_SUCCESS; -} - -/* - * We don't support address remapping now since all M64 - * BARs are sharing on remapping base address. We might - * introduce flag to the PHB in order to trace that. The - * flag allows to be changed for once. It's something to - * do in future. - */ -static int64_t p7ioc_set_phb_mem_window(struct phb *phb, - uint16_t window_type, - uint16_t window_num, - uint64_t base, - uint64_t __unused pci_base, - uint64_t size) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); - uint64_t data64; - - switch (window_type) { - case OPAL_IO_WINDOW_TYPE: - case OPAL_M32_WINDOW_TYPE: - return OPAL_UNSUPPORTED; - case OPAL_M64_WINDOW_TYPE: - if (window_num >= 16) - return OPAL_PARAMETER; - /* The base and size should be 16MB aligned */ - if (base & 0xFFFFFF || size & 0xFFFFFF) - return OPAL_PARAMETER; - data64 = p->m64b_cache[window_num]; - data64 = SETFIELD(IODA_M64BT_BASE, data64, base >> 24); - size = (size >> 24); - data64 = SETFIELD(IODA_M64BT_MASK, data64, 0x1000000 - size); - break; - default: - return OPAL_PARAMETER; - } - - /* - * If the M64 BAR hasn't enabled yet, we needn't flush - * the setting to hardware and just keep it to the cache - */ - p->m64b_cache[window_num] = data64; - if (!(data64 & IODA_M64BT_ENABLE)) - return OPAL_SUCCESS; - p7ioc_phb_ioda_sel(p, IODA_TBL_M64BT, window_num, false); - out_be64(p->regs + PHB_IODA_DATA0, data64); - - return OPAL_SUCCESS; -} - -/* - * We can't enable or disable I/O and M32 dynamically, even - * unnecessary. So the function only support M64 BARs. - */ -static int64_t p7ioc_phb_mmio_enable(struct phb *phb, - uint16_t window_type, - uint16_t window_num, - uint16_t enable) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); - uint64_t data64, base, mask; - - switch (window_type) { - case OPAL_IO_WINDOW_TYPE: - case OPAL_M32_WINDOW_TYPE: - return OPAL_UNSUPPORTED; - case OPAL_M64_WINDOW_TYPE: - if (window_num >= 16 || - enable >= OPAL_ENABLE_M64_NON_SPLIT) - return OPAL_PARAMETER; - - break; - default: - return OPAL_PARAMETER; - } - - /* - * While enabling one specific M64 BAR, we should have - * the base/size configured correctly. Otherwise, it - * probably incurs fenced AIB. - */ - data64 = p->m64b_cache[window_num]; - if (enable == OPAL_ENABLE_M64_SPLIT) { - base = GETFIELD(IODA_M64BT_BASE, data64); - base = (base << 24); - mask = GETFIELD(IODA_M64BT_MASK, data64); - if (base < p->m64_base || mask == 0x0ul) - return OPAL_PARTIAL; - - data64 |= IODA_M64BT_ENABLE; - } else if (enable == OPAL_DISABLE_M64) { - data64 &= ~IODA_M64BT_ENABLE; - } - - p7ioc_phb_ioda_sel(p, IODA_TBL_M64BT, window_num, false); - out_be64(p->regs + PHB_IODA_DATA0, data64); - p->m64b_cache[window_num] = data64; - - return OPAL_SUCCESS; -} - -static int64_t p7ioc_map_pe_mmio_window(struct phb *phb, uint64_t pe_number, - uint16_t window_type, - uint16_t window_num, - uint16_t segment_num) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); - uint64_t tbl, index; - uint64_t *cache; - - if (pe_number > 127) - return OPAL_PARAMETER; - - switch(window_type) { - case OPAL_IO_WINDOW_TYPE: - if (window_num != 0 || segment_num > 127) - return OPAL_PARAMETER; - tbl = IODA_TBL_IODT; - index = segment_num; - cache = &p->iod_cache[index]; - break; - case OPAL_M32_WINDOW_TYPE: - if (window_num != 0 || segment_num > 127) - return OPAL_PARAMETER; - tbl = IODA_TBL_M32DT; - index = segment_num; - cache = &p->m32d_cache[index]; - break; - case OPAL_M64_WINDOW_TYPE: - if (window_num > 15 || segment_num > 7) - return OPAL_PARAMETER; - - tbl = IODA_TBL_M64DT; - index = window_num << 3 | segment_num; - cache = &p->m64d_cache[index]; - break; - default: - return OPAL_PARAMETER; - } - - p7ioc_phb_ioda_sel(p, tbl, index, false); - out_be64(p->regs + PHB_IODA_DATA0, - SETFIELD(IODA_XXDT_PE, 0ull, pe_number)); - - /* Update cache */ - *cache = SETFIELD(IODA_XXDT_PE, 0ull, pe_number); - - return OPAL_SUCCESS; -} - - -static int64_t p7ioc_set_pe(struct phb *phb, uint64_t pe_number, - uint64_t bdfn, uint8_t bus_compare, - uint8_t dev_compare, uint8_t func_compare, - uint8_t pe_action) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); - uint64_t pelt; - uint64_t *cache = &p->peltm_cache[pe_number]; - - if (pe_number > 127 || bdfn > 0xffff) - return OPAL_PARAMETER; - if (pe_action != OPAL_MAP_PE && pe_action != OPAL_UNMAP_PE) - return OPAL_PARAMETER; - if (bus_compare > 7) - return OPAL_PARAMETER; - - if (pe_action == OPAL_MAP_PE) { - pelt = SETFIELD(IODA_PELTM_BUS, 0ul, bdfn >> 8); - pelt |= SETFIELD(IODA_PELTM_DEV, 0ul, (bdfn >> 3) & 0x1f); - pelt |= SETFIELD(IODA_PELTM_FUNC, 0ul, bdfn & 0x7); - pelt |= SETFIELD(IODA_PELTM_BUS_VALID, 0ul, bus_compare); - if (dev_compare) - pelt |= IODA_PELTM_DEV_VALID; - if (func_compare) - pelt |= IODA_PELTM_FUNC_VALID; - } else - pelt = 0; - - p7ioc_phb_ioda_sel(p, IODA_TBL_PELTM, pe_number, false); - out_be64(p->regs + PHB_IODA_DATA0, pelt); - - /* Update cache */ - *cache = pelt; - - return OPAL_SUCCESS; -} - - -static int64_t p7ioc_set_peltv(struct phb *phb, uint32_t parent_pe, - uint32_t child_pe, uint8_t state) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); - uint32_t reg; - uint64_t mask, peltv; - uint64_t *cache; - if (parent_pe > 127 || child_pe > 127) - return OPAL_PARAMETER; - - cache = (child_pe >> 6) ? &p->peltv_hi_cache[parent_pe] : - &p->peltv_lo_cache[parent_pe]; - reg = (child_pe >> 6) ? PHB_IODA_DATA1 : PHB_IODA_DATA0; - child_pe &= 0x2f; - mask = 1ull << (63 - child_pe); - - p7ioc_phb_ioda_sel(p, IODA_TBL_PELTV, parent_pe, false); - peltv = in_be64(p->regs + reg); - if (state) - peltv |= mask; - else - peltv &= ~mask; - out_be64(p->regs + reg, peltv); - - /* Update cache */ - *cache = peltv; - - return OPAL_SUCCESS; -} - -static int64_t p7ioc_map_pe_dma_window(struct phb *phb, uint64_t pe_number, - uint16_t window_id, uint16_t tce_levels, - uint64_t tce_table_addr, - uint64_t tce_table_size, - uint64_t tce_page_size) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); - uint64_t tvt0, tvt1, t, pelt; - uint64_t dma_window_size; - uint64_t *cache_lo, *cache_hi; - - if (pe_number > 127 || window_id > 127 || tce_levels != 1) - return OPAL_PARAMETER; - cache_lo = &p->tve_lo_cache[window_id]; - cache_hi = &p->tve_hi_cache[window_id]; - - /* Encode table size */ - dma_window_size = tce_page_size * (tce_table_size >> 3); - t = ilog2(dma_window_size); - if (t < 27) - return OPAL_PARAMETER; - tvt0 = SETFIELD(IODA_TVT0_TCE_TABLE_SIZE, 0ul, (t - 26)); - - /* Encode TCE page size */ - switch(tce_page_size) { - case 0x1000: /* 4K */ - tvt1 = SETFIELD(IODA_TVT1_IO_PSIZE, 0ul, 1ul); - break; - case 0x10000: /* 64K */ - tvt1 = SETFIELD(IODA_TVT1_IO_PSIZE, 0ul, 5ul); - break; - case 0x1000000: /* 16M */ - tvt1 = SETFIELD(IODA_TVT1_IO_PSIZE, 0ul, 13ul); - break; - case 0x400000000UL: /* 16G */ - tvt1 = SETFIELD(IODA_TVT1_IO_PSIZE, 0ul, 23ul); - break; - default: - return OPAL_PARAMETER; - } - - /* XXX Hub number ... leave 0 for now */ - - /* Shift in the address. The table address is "off by 4 bits" - * but since the field is itself shifted by 16, we basically - * need to write the address >> 12, which basically boils down - * to writing a 4k page address - */ - tvt0 = SETFIELD(IODA_TVT0_TABLE_ADDR, tvt0, tce_table_addr >> 12); - - /* Read the PE filter info from the PELT-M */ - p7ioc_phb_ioda_sel(p, IODA_TBL_PELTM, pe_number, false); - pelt = in_be64(p->regs + PHB_IODA_DATA0); - - /* Copy in filter bits from PELT */ - tvt0 = SETFIELD(IODA_TVT0_BUS_VALID, tvt0, - GETFIELD(IODA_PELTM_BUS_VALID, pelt)); - tvt0 = SETFIELD(IODA_TVT0_BUS_NUM, tvt0, - GETFIELD(IODA_PELTM_BUS, pelt)); - tvt1 = SETFIELD(IODA_TVT1_DEV_NUM, tvt1, - GETFIELD(IODA_PELTM_DEV, pelt)); - tvt1 = SETFIELD(IODA_TVT1_FUNC_NUM, tvt1, - GETFIELD(IODA_PELTM_FUNC, pelt)); - if (pelt & IODA_PELTM_DEV_VALID) - tvt1 |= IODA_TVT1_DEV_VALID; - if (pelt & IODA_PELTM_FUNC_VALID) - tvt1 |= IODA_TVT1_FUNC_VALID; - tvt1 = SETFIELD(IODA_TVT1_PE_NUM, tvt1, pe_number); - - /* Write the TVE */ - p7ioc_phb_ioda_sel(p, IODA_TBL_TVT, window_id, false); - out_be64(p->regs + PHB_IODA_DATA1, tvt1); - out_be64(p->regs + PHB_IODA_DATA0, tvt0); - - /* Update cache */ - *cache_lo = tvt0; - *cache_hi = tvt1; - - return OPAL_SUCCESS; -} - -static int64_t p7ioc_map_pe_dma_window_real(struct phb *phb __unused, - uint64_t pe_number __unused, - uint16_t dma_window_num __unused, - uint64_t pci_start_addr __unused, - uint64_t pci_mem_size __unused) -{ - /* XXX Not yet implemented (not yet used by Linux) */ - return OPAL_UNSUPPORTED; -} - -static int64_t p7ioc_set_mve(struct phb *phb, uint32_t mve_number, - uint64_t pe_number) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); - uint64_t pelt, mve = 0; - uint64_t *cache = &p->mve_cache[mve_number]; - - if (pe_number > 127 || mve_number > 255) - return OPAL_PARAMETER; - - /* Read the PE filter info from the PELT-M */ - p7ioc_phb_ioda_sel(p, IODA_TBL_PELTM, pe_number, false); - pelt = in_be64(p->regs + PHB_IODA_DATA0); - - mve = SETFIELD(IODA_MVT_BUS_VALID, mve, - GETFIELD(IODA_PELTM_BUS_VALID, pelt)); - mve = SETFIELD(IODA_MVT_BUS_NUM, mve, - GETFIELD(IODA_PELTM_BUS, pelt)); - mve = SETFIELD(IODA_MVT_DEV_NUM, mve, - GETFIELD(IODA_PELTM_DEV, pelt)); - mve = SETFIELD(IODA_MVT_FUNC_NUM, mve, - GETFIELD(IODA_PELTM_FUNC, pelt)); - if (pelt & IODA_PELTM_DEV_VALID) - mve |= IODA_MVT_DEV_VALID; - if (pelt & IODA_PELTM_FUNC_VALID) - mve |= IODA_MVT_FUNC_VALID; - mve = SETFIELD(IODA_MVT_PE_NUM, mve, pe_number); - - p7ioc_phb_ioda_sel(p, IODA_TBL_MVT, mve_number, false); - out_be64(p->regs + PHB_IODA_DATA0, mve); - - /* Update cache */ - *cache = mve; - - return OPAL_SUCCESS; -} - -static int64_t p7ioc_set_mve_enable(struct phb *phb, uint32_t mve_number, - uint32_t state) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); - uint64_t mve; - uint64_t *cache = &p->mve_cache[mve_number]; - - if (mve_number > 255) - return OPAL_PARAMETER; - - p7ioc_phb_ioda_sel(p, IODA_TBL_MVT, mve_number, false); - mve = in_be64(p->regs + PHB_IODA_DATA0); - if (state) - mve |= IODA_MVT_VALID; - else - mve &= ~IODA_MVT_VALID; - out_be64(p->regs + PHB_IODA_DATA0, mve); - - /* Update cache */ - *cache = mve; - - return OPAL_SUCCESS; -} - -static int64_t p7ioc_set_xive_pe(struct phb *phb, uint64_t pe_number, - uint32_t xive_num) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); - uint64_t xive; - - if (pe_number > 127 || xive_num > 255) - return OPAL_PARAMETER; - - /* Update MXIVE cache */ - xive = p->mxive_cache[xive_num]; - xive = SETFIELD(IODA_XIVT_PENUM, xive, pe_number); - p->mxive_cache[xive_num] = xive; - - /* Update HW */ - p7ioc_phb_ioda_sel(p, IODA_TBL_MXIVT, xive_num, false); - xive = in_be64(p->regs + PHB_IODA_DATA0); - xive = SETFIELD(IODA_XIVT_PENUM, xive, pe_number); - out_be64(p->regs + PHB_IODA_DATA0, xive); - - return OPAL_SUCCESS; -} - -static int64_t p7ioc_get_msi_32(struct phb *phb __unused, uint64_t mve_number, - uint32_t xive_num, uint8_t msi_range, - uint32_t *msi_address, uint32_t *message_data) -{ - if (mve_number > 255 || xive_num > 255 || msi_range != 1) - return OPAL_PARAMETER; - - *msi_address = 0xffff0000 | (mve_number << 4); - *message_data = xive_num; - - return OPAL_SUCCESS; -} - -static int64_t p7ioc_get_msi_64(struct phb *phb __unused, uint64_t mve_number, - uint32_t xive_num, uint8_t msi_range, - uint64_t *msi_address, uint32_t *message_data) -{ - if (mve_number > 255 || xive_num > 255 || msi_range != 1) - return OPAL_PARAMETER; - - *msi_address = (9ul << 60) | (((u64)mve_number) << 48); - *message_data = xive_num; - - return OPAL_SUCCESS; -} - -static void p7ioc_root_port_init(struct phb *phb, struct pci_device *dev, - int ecap, int aercap) -{ - uint16_t bdfn = dev->bdfn; - uint16_t val16; - uint32_t val32; - - /* Enable SERR and parity checking */ - pci_cfg_read16(phb, bdfn, PCI_CFG_CMD, &val16); - val16 |= (PCI_CFG_CMD_SERR_EN | PCI_CFG_CMD_PERR_RESP); - pci_cfg_write16(phb, bdfn, PCI_CFG_CMD, val16); - - /* Enable reporting various errors */ - if (!ecap) return; - pci_cfg_read16(phb, bdfn, ecap + PCICAP_EXP_DEVCTL, &val16); - val16 |= (PCICAP_EXP_DEVCTL_CE_REPORT | - PCICAP_EXP_DEVCTL_NFE_REPORT | - PCICAP_EXP_DEVCTL_FE_REPORT | - PCICAP_EXP_DEVCTL_UR_REPORT); - pci_cfg_write16(phb, bdfn, ecap + PCICAP_EXP_DEVCTL, val16); - - /* Mask various unrecoverable errors */ - if (!aercap) return; - pci_cfg_read32(phb, bdfn, aercap + PCIECAP_AER_UE_MASK, &val32); - val32 |= (PCIECAP_AER_UE_MASK_POISON_TLP | - PCIECAP_AER_UE_MASK_COMPL_TIMEOUT | - PCIECAP_AER_UE_MASK_COMPL_ABORT | - PCIECAP_AER_UE_MASK_ECRC); - pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_UE_MASK, val32); - - /* Report various unrecoverable errors as fatal errors */ - pci_cfg_read32(phb, bdfn, aercap + PCIECAP_AER_UE_SEVERITY, &val32); - val32 |= (PCIECAP_AER_UE_SEVERITY_DLLP | - PCIECAP_AER_UE_SEVERITY_SURPRISE_DOWN | - PCIECAP_AER_UE_SEVERITY_FLOW_CTL_PROT | - PCIECAP_AER_UE_SEVERITY_UNEXP_COMPL | - PCIECAP_AER_UE_SEVERITY_RECV_OVFLOW | - PCIECAP_AER_UE_SEVERITY_MALFORMED_TLP); - pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_UE_SEVERITY, val32); - - /* Mask various recoverable errors */ - pci_cfg_read32(phb, bdfn, aercap + PCIECAP_AER_CE_MASK, &val32); - val32 |= PCIECAP_AER_CE_MASK_ADV_NONFATAL; - pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_CE_MASK, val32); - - /* Enable ECRC check */ - pci_cfg_read32(phb, bdfn, aercap + PCIECAP_AER_CAPCTL, &val32); - val32 |= (PCIECAP_AER_CAPCTL_ECRCG_EN | - PCIECAP_AER_CAPCTL_ECRCC_EN); - pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_CAPCTL, val32); - - /* Enable all error reporting */ - pci_cfg_read32(phb, bdfn, aercap + PCIECAP_AER_RERR_CMD, &val32); - val32 |= (PCIECAP_AER_RERR_CMD_FE | - PCIECAP_AER_RERR_CMD_NFE | - PCIECAP_AER_RERR_CMD_CE); - pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_RERR_CMD, val32); -} - -static void p7ioc_switch_port_init(struct phb *phb, - struct pci_device *dev, - int ecap, int aercap) -{ - uint16_t bdfn = dev->bdfn; - uint16_t val16; - uint32_t val32; - - /* Enable SERR and parity checking and disable INTx */ - pci_cfg_read16(phb, bdfn, PCI_CFG_CMD, &val16); - val16 |= (PCI_CFG_CMD_PERR_RESP | - PCI_CFG_CMD_SERR_EN | - PCI_CFG_CMD_INTx_DIS); - pci_cfg_write16(phb, bdfn, PCI_CFG_CMD, val16); - - /* Disable partity error and enable system error */ - pci_cfg_read16(phb, bdfn, PCI_CFG_BRCTL, &val16); - val16 &= ~PCI_CFG_BRCTL_PERR_RESP_EN; - val16 |= PCI_CFG_BRCTL_SERR_EN; - pci_cfg_write16(phb, bdfn, PCI_CFG_BRCTL, val16); - - /* Enable reporting various errors */ - if (!ecap) return; - pci_cfg_read16(phb, bdfn, ecap + PCICAP_EXP_DEVCTL, &val16); - val16 |= (PCICAP_EXP_DEVCTL_CE_REPORT | - PCICAP_EXP_DEVCTL_NFE_REPORT | - PCICAP_EXP_DEVCTL_FE_REPORT); - pci_cfg_write16(phb, bdfn, ecap + PCICAP_EXP_DEVCTL, val16); - - /* Unmask all unrecoverable errors */ - if (!aercap) return; - pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_UE_MASK, 0x0); - - /* Severity of unrecoverable errors */ - if (dev->dev_type == PCIE_TYPE_SWITCH_UPPORT) - val32 = (PCIECAP_AER_UE_SEVERITY_DLLP | - PCIECAP_AER_UE_SEVERITY_SURPRISE_DOWN | - PCIECAP_AER_UE_SEVERITY_FLOW_CTL_PROT | - PCIECAP_AER_UE_SEVERITY_RECV_OVFLOW | - PCIECAP_AER_UE_SEVERITY_MALFORMED_TLP | - PCIECAP_AER_UE_SEVERITY_INTERNAL); - else - val32 = (PCIECAP_AER_UE_SEVERITY_FLOW_CTL_PROT | - PCIECAP_AER_UE_SEVERITY_INTERNAL); - pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_UE_SEVERITY, val32); - - /* Mask various correctable errors */ - val32 = PCIECAP_AER_CE_MASK_ADV_NONFATAL; - pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_CE_MASK, val32); - - /* Enable ECRC generation and disable ECRC check */ - pci_cfg_read32(phb, bdfn, aercap + PCIECAP_AER_CAPCTL, &val32); - val32 |= PCIECAP_AER_CAPCTL_ECRCG_EN; - val32 &= ~PCIECAP_AER_CAPCTL_ECRCC_EN; - pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_CAPCTL, val32); -} - -static void p7ioc_endpoint_init(struct phb *phb, - struct pci_device *dev, - int ecap, int aercap) -{ - uint16_t bdfn = dev->bdfn; - uint16_t val16; - uint32_t val32; - - /* Enable SERR and parity checking */ - pci_cfg_read16(phb, bdfn, PCI_CFG_CMD, &val16); - val16 |= (PCI_CFG_CMD_PERR_RESP | - PCI_CFG_CMD_SERR_EN); - pci_cfg_write16(phb, bdfn, PCI_CFG_CMD, val16); - - /* Enable reporting various errors */ - if (!ecap) return; - pci_cfg_read16(phb, bdfn, ecap + PCICAP_EXP_DEVCTL, &val16); - val16 &= ~PCICAP_EXP_DEVCTL_CE_REPORT; - val16 |= (PCICAP_EXP_DEVCTL_NFE_REPORT | - PCICAP_EXP_DEVCTL_FE_REPORT | - PCICAP_EXP_DEVCTL_UR_REPORT); - pci_cfg_write16(phb, bdfn, ecap + PCICAP_EXP_DEVCTL, val16); - - /* Enable ECRC generation and check */ - pci_cfg_read32(phb, bdfn, aercap + PCIECAP_AER_CAPCTL, &val32); - val32 |= (PCIECAP_AER_CAPCTL_ECRCG_EN | - PCIECAP_AER_CAPCTL_ECRCC_EN); - pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_CAPCTL, val32); -} - -static int p7ioc_device_init(struct phb *phb, - struct pci_device *dev, - void *data __unused) -{ - int ecap, aercap; - - /* Common initialization for the device */ - pci_device_init(phb, dev); - - ecap = pci_cap(dev, PCI_CFG_CAP_ID_EXP, false); - aercap = pci_cap(dev, PCIECAP_ID_AER, true); - if (dev->dev_type == PCIE_TYPE_ROOT_PORT) - p7ioc_root_port_init(phb, dev, ecap, aercap); - else if (dev->dev_type == PCIE_TYPE_SWITCH_UPPORT || - dev->dev_type == PCIE_TYPE_SWITCH_DNPORT) - p7ioc_switch_port_init(phb, dev, ecap, aercap); - else - p7ioc_endpoint_init(phb, dev, ecap, aercap); - - return 0; -} - -static int64_t p7ioc_pci_reinit(struct phb *phb, - uint64_t scope, uint64_t data) -{ - struct pci_device *pd; - uint16_t bdfn = data; - int ret; - - if (scope != OPAL_REINIT_PCI_DEV) - return OPAL_PARAMETER; - - pd = pci_find_dev(phb, bdfn); - if (!pd) - return OPAL_PARAMETER; - - ret = p7ioc_device_init(phb, pd, NULL); - if (ret) - return OPAL_HARDWARE; - - return OPAL_SUCCESS; -} - -static uint8_t p7ioc_choose_bus(struct phb *phb __unused, - struct pci_device *bridge, - uint8_t candidate, uint8_t *max_bus, - bool *use_max) -{ - uint8_t m, al; - int i; - - /* Bus number selection is nasty on P7IOC. Our EEH HW can only cope - * with bus ranges that are naturally aligned powers of two. It also - * has "issues" with dealing with more than 32 bus numbers. - * - * On the other hand we can deal with overlaps to some extent as - * the PELT-M entries are ordered. - * - * We also don't need to bother with the busses between the upstream - * and downstream ports of switches. - * - * For now we apply this simple mechanism which matche what OFW does - * under OPAL: - * - * - Top level bus (PHB to RC) is 0 - * - RC to first device is 1..ff - * - Then going down, a switch gets (N = parent bus, M = parent max) - * * Upstream bridge is N+1, M, use_max = false - * * Downstream bridge is closest power of two from 32 down and - * * use max - * - * XXX NOTE: If we have access to HW VPDs, we could know whether - * this is a bridge with a single device on it such as IPR and - * limit ourselves to a single bus number. - */ - - /* Default use_max is false (legacy) */ - *use_max = false; - - /* If we are the root complex or we are not in PCIe land anymore, just - * use legacy algorithm - */ - if (!bridge || !pci_has_cap(bridge, PCI_CFG_CAP_ID_EXP, false)) - return candidate; - - /* Figure out the bridge type */ - switch(bridge->dev_type) { - case PCIE_TYPE_PCIX_TO_PCIE: - /* PCI-X to PCIE ... hrm, let's not bother too much with that */ - return candidate; - case PCIE_TYPE_SWITCH_UPPORT: - case PCIE_TYPE_ROOT_PORT: - /* Upstream port, we use legacy handling as well */ - return candidate; - case PCIE_TYPE_SWITCH_DNPORT: - case PCIE_TYPE_PCIE_TO_PCIX: - /* That leaves us with the interesting cases that we handle */ - break; - default: - /* Should not happen, treat as legacy */ - prerror("PCI: Device %04x has unsupported type %d in choose_bus\n", - bridge->bdfn, bridge->dev_type); - return candidate; - } - - /* Ok, let's find a power of two that fits, fallback to 1 */ - for (i = 5; i >= 0; i--) { - m = (1 << i) - 1; - al = (candidate + m) & ~m; - if (al <= *max_bus && (al + m) <= *max_bus) - break; - } - if (i < 0) - return 0; - *use_max = true; - *max_bus = al + m; - return al; -} - -static int64_t p7ioc_get_reserved_pe_number(struct phb *phb __unused) -{ - return 127; -} - -/* p7ioc_phb_init_ioda_cache - Reset the IODA cache values - */ -static void p7ioc_phb_init_ioda_cache(struct p7ioc_phb *p) -{ - unsigned int i; - - for (i = 0; i < 8; i++) - p->lxive_cache[i] = SETFIELD(IODA_XIVT_PRIORITY, 0ull, 0xff); - for (i = 0; i < 256; i++) { - p->mxive_cache[i] = SETFIELD(IODA_XIVT_PRIORITY, 0ull, 0xff); - p->mve_cache[i] = 0; - } - for (i = 0; i < 16; i++) - p->m64b_cache[i] = 0; - - /* - * Since there is only one root port under the PHB, - * We make all PELTM entries except last one to be - * invalid by configuring their RID to 00:00.1. The - * last entry is to encompass all RIDs. - */ - for (i = 0; i < 127; i++) - p->peltm_cache[i] = 0x0001f80000000000UL; - p->peltm_cache[127] = 0x0ul; - - for (i = 0; i < 128; i++) { - p->peltv_lo_cache[i] = 0; - p->peltv_hi_cache[i] = 0; - p->tve_lo_cache[i] = 0; - p->tve_hi_cache[i] = 0; - p->iod_cache[i] = 0; - p->m32d_cache[i] = 0; - p->m64d_cache[i] = 0; - } -} - -/* p7ioc_phb_ioda_reset - Reset the IODA tables - * - * @purge: If true, the cache is cleared and the cleared values - * are applied to HW. If false, the cached values are - * applied to HW - * - * This reset the IODA tables in the PHB. It is called at - * initialization time, on PHB reset, and can be called - * explicitly from OPAL - */ -static int64_t p7ioc_ioda_reset(struct phb *phb, bool purge) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); - unsigned int i; - uint64_t reg64; - uint64_t data64, data64_hi; - uint8_t prio; - uint16_t server; - uint64_t m_server, m_prio; - - /* If the "purge" argument is set, we clear the table cache */ - if (purge) - p7ioc_phb_init_ioda_cache(p); - - /* Init_18..19: Setup the HRT - * - * XXX NOTE: I still don't completely get that HRT business so - * I'll just mimmic BML and put the PHB number + 1 in there - */ - p7ioc_phb_ioda_sel(p, IODA_TBL_HRT, 0, true); - out_be64(p->regs + PHB_IODA_DATA0, p->index + 1); - out_be64(p->regs + PHB_IODA_DATA0, p->index + 1); - out_be64(p->regs + PHB_IODA_DATA0, p->index + 1); - out_be64(p->regs + PHB_IODA_DATA0, p->index + 1); - - /* Init_20..21: Cleanup the LXIVT - * - * We set the priority to FF (masked) and clear everything - * else. That means we leave the HRT index to 0 which is - * going to remain unmodified... for now. - */ - p7ioc_phb_ioda_sel(p, IODA_TBL_LXIVT, 0, true); - for (i = 0; i < 8; i++) { - data64 = p->lxive_cache[i]; - server = GETFIELD(IODA_XIVT_SERVER, data64); - prio = GETFIELD(IODA_XIVT_PRIORITY, data64); - - /* Now we mangle the server and priority */ - if (prio == 0xff) { - m_server = 0; - m_prio = 0xff; - } else { - m_server = server >> 3; - m_prio = (prio >> 3) | ((server & 7) << 5); - } - - data64 = SETFIELD(IODA_XIVT_SERVER, data64, m_server); - data64 = SETFIELD(IODA_XIVT_PRIORITY, data64, m_prio); - out_be64(p->regs + PHB_IODA_DATA0, data64); - } - - /* Init_22..23: Cleanup the MXIVT - * - * We set the priority to FF (masked) and clear everything - * else. That means we leave the HRT index to 0 which is - * going to remain unmodified... for now. - */ - p7ioc_phb_ioda_sel(p, IODA_TBL_MXIVT, 0, true); - for (i = 0; i < 256; i++) { - data64 = p->mxive_cache[i]; - server = GETFIELD(IODA_XIVT_SERVER, data64); - prio = GETFIELD(IODA_XIVT_PRIORITY, data64); - - /* Now we mangle the server and priority */ - if (prio == 0xff) { - m_server = 0; - m_prio = 0xff; - } else { - m_server = server >> 3; - m_prio = (prio >> 3) | ((server & 7) << 5); - } - - data64 = SETFIELD(IODA_XIVT_SERVER, data64, m_server); - data64 = SETFIELD(IODA_XIVT_PRIORITY, data64, m_prio); - out_be64(p->regs + PHB_IODA_DATA0, data64); - } - - /* Init_24..25: Cleanup the MVT */ - p7ioc_phb_ioda_sel(p, IODA_TBL_MVT, 0, true); - for (i = 0; i < 256; i++) { - data64 = p->mve_cache[i]; - out_be64(p->regs + PHB_IODA_DATA0, data64); - } - - /* Init_26..27: Cleanup the PELTM - * - * A completely clear PELTM should make everything match PE 0 - */ - p7ioc_phb_ioda_sel(p, IODA_TBL_PELTM, 0, true); - for (i = 0; i < 127; i++) { - data64 = p->peltm_cache[i]; - out_be64(p->regs + PHB_IODA_DATA0, data64); - } - - /* Init_28..30: Cleanup the PELTV */ - p7ioc_phb_ioda_sel(p, IODA_TBL_PELTV, 0, true); - for (i = 0; i < 127; i++) { - data64 = p->peltv_lo_cache[i]; - data64_hi = p->peltv_hi_cache[i]; - out_be64(p->regs + PHB_IODA_DATA1, data64_hi); - out_be64(p->regs + PHB_IODA_DATA0, data64); - } - - /* Init_31..33: Cleanup the TVT */ - p7ioc_phb_ioda_sel(p, IODA_TBL_TVT, 0, true); - for (i = 0; i < 127; i++) { - data64 = p->tve_lo_cache[i]; - data64_hi = p->tve_hi_cache[i]; - out_be64(p->regs + PHB_IODA_DATA1, data64_hi); - out_be64(p->regs + PHB_IODA_DATA0, data64); - } - - /* Init_34..35: Cleanup the M64BT - * - * We don't enable M64 BARs by default. However, - * we shouldn't purge the hw and cache for it in - * future. - */ - p7ioc_phb_ioda_sel(p, IODA_TBL_M64BT, 0, true); - for (i = 0; i < 16; i++) - out_be64(p->regs + PHB_IODA_DATA0, 0); - - /* Init_36..37: Cleanup the IODT */ - p7ioc_phb_ioda_sel(p, IODA_TBL_IODT, 0, true); - for (i = 0; i < 127; i++) { - data64 = p->iod_cache[i]; - out_be64(p->regs + PHB_IODA_DATA0, data64); - } - - /* Init_38..39: Cleanup the M32DT */ - p7ioc_phb_ioda_sel(p, IODA_TBL_M32DT, 0, true); - for (i = 0; i < 127; i++) { - data64 = p->m32d_cache[i]; - out_be64(p->regs + PHB_IODA_DATA0, data64); - } - - /* Init_40..41: Cleanup the M64DT */ - p7ioc_phb_ioda_sel(p, IODA_TBL_M64BT, 0, true); - for (i = 0; i < 16; i++) { - data64 = p->m64b_cache[i]; - out_be64(p->regs + PHB_IODA_DATA0, data64); - } - - p7ioc_phb_ioda_sel(p, IODA_TBL_M64DT, 0, true); - for (i = 0; i < 127; i++) { - data64 = p->m64d_cache[i]; - out_be64(p->regs + PHB_IODA_DATA0, data64); - } - - /* Clear up the TCE cache */ - reg64 = in_be64(p->regs + PHB_PHB2_CONFIG); - reg64 &= ~PHB_PHB2C_64B_TCE_EN; - out_be64(p->regs + PHB_PHB2_CONFIG, reg64); - reg64 |= PHB_PHB2C_64B_TCE_EN; - out_be64(p->regs + PHB_PHB2_CONFIG, reg64); - in_be64(p->regs + PHB_PHB2_CONFIG); - - /* Clear PEST & PEEV */ - for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) { - uint64_t pesta, pestb; - - p7ioc_phb_ioda_sel(p, IODA_TBL_PESTA, i, false); - pesta = in_be64(p->regs + PHB_IODA_DATA0); - out_be64(p->regs + PHB_IODA_DATA0, 0); - p7ioc_phb_ioda_sel(p, IODA_TBL_PESTB, i, false); - pestb = in_be64(p->regs + PHB_IODA_DATA0); - out_be64(p->regs + PHB_IODA_DATA0, 0); - - if ((pesta & IODA_PESTA_MMIO_FROZEN) || - (pestb & IODA_PESTB_DMA_STOPPED)) - PHBDBG(p, "Frozen PE#%x (%s - %s)\n", - i, (pestb & IODA_PESTB_DMA_STOPPED) ? "DMA" : "", - (pesta & IODA_PESTA_MMIO_FROZEN) ? "MMIO" : ""); - } - - p7ioc_phb_ioda_sel(p, IODA_TBL_PEEV, 0, true); - for (i = 0; i < 2; i++) - out_be64(p->regs + PHB_IODA_DATA0, 0); - - return OPAL_SUCCESS; -} - -/* - * Clear anything we have in PAPR Error Injection registers. Though - * the spec says the PAPR error injection should be one-shot without - * the "sticky" bit. However, that's false according to the experiments - * I had. So we have to clear it at appropriate point in kernel to - * avoid endless frozen PE. - */ -static int64_t p7ioc_papr_errinjct_reset(struct phb *phb) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); - - out_be64(p->regs + PHB_PAPR_ERR_INJ_CTL, 0x0ul); - out_be64(p->regs + PHB_PAPR_ERR_INJ_ADDR, 0x0ul); - out_be64(p->regs + PHB_PAPR_ERR_INJ_MASK, 0x0ul); - - return OPAL_SUCCESS; -} - -static int64_t p7ioc_get_presence_state(struct pci_slot *slot, uint8_t *val) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(slot->phb); - uint64_t reg; - - reg = in_be64(p->regs + PHB_PCIE_SLOTCTL2); - if (reg & PHB_PCIE_SLOTCTL2_PRSTN_STAT) - *val = OPAL_PCI_SLOT_PRESENT; - else - *val = OPAL_PCI_SLOT_EMPTY; - - return OPAL_SUCCESS; -} - -static int64_t p7ioc_get_link_state(struct pci_slot *slot, uint8_t *val) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(slot->phb); - uint64_t reg64; - uint16_t state; - int64_t rc; - - /* Check if the link training is completed */ - reg64 = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL); - if (!(reg64 & PHB_PCIE_DLP_TC_DL_LINKACT)) { - *val = 0; - return OPAL_SUCCESS; - } - - /* Grab link width from PCIe capability */ - rc = p7ioc_pcicfg_read16(&p->phb, 0, p->ecap + PCICAP_EXP_LSTAT, - &state); - if (rc < 0) { - PHBERR(p, "%s: Error %lld reading link status\n", - __func__, rc); - return OPAL_HARDWARE; - } - - if (state & PCICAP_EXP_LSTAT_DLLL_ACT) - *val = ((state & PCICAP_EXP_LSTAT_WIDTH) >> 4); - else - *val = 0; - - return OPAL_SUCCESS; -} - -static int64_t p7ioc_get_power_state(struct pci_slot *slot, uint8_t *val) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(slot->phb); - uint64_t reg64; - - reg64 = in_be64(p->regs + PHB_PCIE_SLOTCTL2); - if (reg64 & PHB_PCIE_SLOTCTL2_PWR_EN_STAT) - *val = PCI_SLOT_POWER_ON; - else - *val = PCI_SLOT_POWER_OFF; - - return OPAL_SUCCESS; -} - -static int64_t p7ioc_set_power_state(struct pci_slot *slot, uint8_t val) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(slot->phb); - uint64_t reg64; - uint8_t state = PCI_SLOT_POWER_OFF; - - if (val != PCI_SLOT_POWER_OFF && val != PCI_SLOT_POWER_ON) - return OPAL_PARAMETER; - - /* If the power state has been put into the requested one */ - reg64 = in_be64(p->regs + PHB_PCIE_SLOTCTL2); - if (reg64 & PHB_PCIE_SLOTCTL2_PWR_EN_STAT) - state = PCI_SLOT_POWER_ON; - if (state == val) - return OPAL_SUCCESS; - - /* Power on/off */ - if (val == PCI_SLOT_POWER_ON) { - reg64 &= ~(0x8c00000000000000ul); - out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg64); - reg64 |= 0x8400000000000000ul; - out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg64); - } else { - reg64 &= ~(0x8c00000000000000ul); - reg64 |= 0x8400000000000000ul; - out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg64); - reg64 &= ~(0x8c00000000000000ul); - reg64 |= 0x0c00000000000000ul; - out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg64); - } - - return OPAL_SUCCESS; -} - -static void p7ioc_prepare_link_change(struct pci_slot *slot, bool up) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(slot->phb); - uint64_t ci_idx = p->index + 2; - uint32_t cfg32; - - if (!up) { - /* Mask PCIE port interrupts and AER receiver error */ - out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN, 0x7E00000000000000UL); - p7ioc_pcicfg_read32(&p->phb, 0, - p->aercap + PCIECAP_AER_CE_MASK, &cfg32); - cfg32 |= PCIECAP_AER_CE_RECVR_ERR; - p7ioc_pcicfg_write32(&p->phb, 0, - p->aercap + PCIECAP_AER_CE_MASK, cfg32); - - /* Mask CI port error and clear it */ - out_be64(p->ioc->regs + P7IOC_CIn_LEM_ERR_MASK(ci_idx), - 0xa4f4000000000000ul); - out_be64(p->regs + PHB_LEM_ERROR_MASK, - 0xadb650c9808dd051ul); - out_be64(p->ioc->regs + P7IOC_CIn_LEM_FIR(ci_idx), - 0x0ul); - - /* Block access to PCI-CFG space */ - p->flags |= P7IOC_PHB_CFG_BLOCKED; - } else { - /* Clear spurious errors and enable PCIE port interrupts */ - out_be64(p->regs + UTL_PCIE_PORT_STATUS, 0x00E0000000000000UL); - out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN, 0xFE65000000000000UL); - - /* Clear AER receiver error status */ - p7ioc_pcicfg_write32(&p->phb, 0, - p->aercap + PCIECAP_AER_CE_STATUS, - PCIECAP_AER_CE_RECVR_ERR); - /* Unmask receiver error status in AER */ - p7ioc_pcicfg_read32(&p->phb, 0, - p->aercap + PCIECAP_AER_CE_MASK, &cfg32); - cfg32 &= ~PCIECAP_AER_CE_RECVR_ERR; - p7ioc_pcicfg_write32(&p->phb, 0, - p->aercap + PCIECAP_AER_CE_MASK, cfg32); - /* Clear and Unmask CI port and PHB errors */ - out_be64(p->ioc->regs + P7IOC_CIn_LEM_FIR(ci_idx), 0x0ul); - out_be64(p->regs + PHB_LEM_FIR_ACCUM, 0x0ul); - out_be64(p->ioc->regs + P7IOC_CIn_LEM_ERR_MASK_AND(ci_idx), - 0x0ul); - out_be64(p->regs + PHB_LEM_ERROR_MASK, 0x1249a1147f500f2cul); - - /* Don't block access to PCI-CFG space */ - p->flags &= ~P7IOC_PHB_CFG_BLOCKED; - - /* Restore slot's state */ - pci_slot_set_state(slot, P7IOC_SLOT_NORMAL); - - /* - * We might lose the bus numbers in the reset and we need - * restore the bus numbers. Otherwise, some adpaters (e.g. - * IPR) can't be probed properly by kernel. We don't need - * restore bus numbers for all kinds of resets. However, - * it's not harmful to restore the bus numbers, which makes - * the logic simplified - */ - pci_restore_bridge_buses(slot->phb, slot->pd); - if (slot->phb->ops->device_init) - pci_walk_dev(slot->phb, slot->pd, - slot->phb->ops->device_init, NULL); - } -} - -static int64_t p7ioc_poll_link(struct pci_slot *slot) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(slot->phb); - uint64_t reg64; - - switch (slot->state) { - case P7IOC_SLOT_NORMAL: - case P7IOC_SLOT_LINK_START: - PHBDBG(p, "LINK: Start polling\n"); - reg64 = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL); - reg64 &= ~PHB_PCIE_DLP_TCTX_DISABLE; - out_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL, reg64); - slot->retries = 100; - pci_slot_set_state(slot, P7IOC_SLOT_LINK_WAIT); - return pci_slot_set_sm_timeout(slot, msecs_to_tb(10)); - case P7IOC_SLOT_LINK_WAIT: - reg64 = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL); - if (reg64 & PHB_PCIE_DLP_TC_DL_LINKACT) { - PHBDBG(p, "LINK: Up\n"); - slot->ops.prepare_link_change(slot, true); - return OPAL_SUCCESS; - } - - if (slot->retries-- == 0) { - PHBERR(p, "LINK: Timeout waiting for link up\n"); - goto out; - } - return pci_slot_set_sm_timeout(slot, msecs_to_tb(10)); - default: - PHBERR(p, "LINK: Unexpected slot state %08x\n", - slot->state); - } - -out: - pci_slot_set_state(slot, P7IOC_SLOT_NORMAL); - return OPAL_HARDWARE; -} - -static int64_t p7ioc_hreset(struct pci_slot *slot) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(slot->phb); - uint8_t presence = 1; - uint16_t brctl; - uint64_t reg64; - - switch (slot->state) { - case P7IOC_SLOT_NORMAL: - PHBDBG(p, "HRESET: Starts\n"); - if (slot->ops.get_presence_state) - slot->ops.get_presence_state(slot, &presence); - if (!presence) { - PHBDBG(p, "HRESET: No device\n"); - return OPAL_SUCCESS; - } - - PHBDBG(p, "HRESET: Prepare for link down\n"); - slot->ops.prepare_link_change(slot, false); - - /* Disable link to avoid training issues */ - PHBDBG(p, "HRESET: Disable link training\n"); - reg64 = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL); - reg64 |= PHB_PCIE_DLP_TCTX_DISABLE; - out_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL, reg64); - pci_slot_set_state(slot, P7IOC_SLOT_HRESET_TRAINING); - slot->retries = 15; - /* fall through */ - case P7IOC_SLOT_HRESET_TRAINING: - reg64 = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL); - if (!(reg64 & PHB_PCIE_DLP_TCRX_DISABLED)) { - if (slot->retries -- == 0) { - PHBERR(p, "HRESET: Timeout disabling link training\n"); - goto out; - } - - return pci_slot_set_sm_timeout(slot, msecs_to_tb(10)); - } - /* fall through */ - case P7IOC_SLOT_HRESET_START: - PHBDBG(p, "HRESET: Assert\n"); - p7ioc_pcicfg_read16(&p->phb, 0, PCI_CFG_BRCTL, &brctl); - brctl |= PCI_CFG_BRCTL_SECONDARY_RESET; - p7ioc_pcicfg_write16(&p->phb, 0, PCI_CFG_BRCTL, brctl); - - pci_slot_set_state(slot, P7IOC_SLOT_HRESET_DELAY); - return pci_slot_set_sm_timeout(slot, secs_to_tb(1)); - case P7IOC_SLOT_HRESET_DELAY: - PHBDBG(p, "HRESET: Deassert\n"); - p7ioc_pcicfg_read16(&p->phb, 0, PCI_CFG_BRCTL, &brctl); - brctl &= ~PCI_CFG_BRCTL_SECONDARY_RESET; - p7ioc_pcicfg_write16(&p->phb, 0, PCI_CFG_BRCTL, brctl); - pci_slot_set_state(slot, P7IOC_SLOT_HRESET_DELAY2); - return pci_slot_set_sm_timeout(slot, msecs_to_tb(200)); - case P7IOC_SLOT_HRESET_DELAY2: - pci_slot_set_state(slot, P7IOC_SLOT_LINK_START); - return slot->ops.poll_link(slot); - default: - PHBERR(p, "HRESET: Unexpected slot state %08x\n", - slot->state); - } - -out: - pci_slot_set_state(slot, P7IOC_SLOT_NORMAL); - return OPAL_HARDWARE; -} - -static int64_t p7ioc_freset(struct pci_slot *slot) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(slot->phb); - uint8_t presence = 1; - uint64_t reg64; - - switch (slot->state) { - case P7IOC_SLOT_NORMAL: - case P7IOC_SLOT_FRESET_START: - PHBDBG(p, "FRESET: Starts\n"); - if (slot->ops.get_presence_state) - slot->ops.get_presence_state(slot, &presence); - if (!presence) { - PHBDBG(p, "FRESET: No device\n"); - pci_slot_set_state(slot, P7IOC_SLOT_NORMAL); - return OPAL_SUCCESS; - } - - PHBDBG(p, "FRESET: Prepare for link down\n"); - slot->ops.prepare_link_change(slot, false); - - /* Check power state */ - reg64 = in_be64(p->regs + PHB_PCIE_SLOTCTL2); - if (reg64 & PHB_PCIE_SLOTCTL2_PWR_EN_STAT) { - PHBDBG(p, "FRESET: Power on, turn off\n"); - reg64 = in_be64(p->regs + PHB_HOTPLUG_OVERRIDE); - reg64 &= ~(0x8c00000000000000ul); - reg64 |= 0x8400000000000000ul; - out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg64); - reg64 &= ~(0x8c00000000000000ul); - reg64 |= 0x0c00000000000000ul; - out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg64); - pci_slot_set_state(slot, P7IOC_SLOT_FRESET_POWER_OFF); - return pci_slot_set_sm_timeout(slot, secs_to_tb(2)); - } - /* fall through */ - case P7IOC_SLOT_FRESET_POWER_OFF: - PHBDBG(p, "FRESET: Power off, turn on\n"); - reg64 = in_be64(p->regs + PHB_HOTPLUG_OVERRIDE); - reg64 &= ~(0x8c00000000000000ul); - out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg64); - reg64 |= 0x8400000000000000ul; - out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg64); - pci_slot_set_state(slot, P7IOC_SLOT_FRESET_POWER_ON); - return pci_slot_set_sm_timeout(slot, secs_to_tb(2)); - case P7IOC_SLOT_FRESET_POWER_ON: - PHBDBG(p, "FRESET: Disable link training\n"); - reg64 = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL); - reg64 |= PHB_PCIE_DLP_TCTX_DISABLE; - out_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL, reg64); - pci_slot_set_state(slot, P7IOC_SLOT_HRESET_TRAINING); - slot->retries = 200; - /* fall through */ - case P7IOC_SLOT_HRESET_TRAINING: - reg64 = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL); - if (!(reg64 & PHB_PCIE_DLP_TCRX_DISABLED)) { - if (slot->retries -- == 0) { - PHBERR(p, "HRESET: Timeout disabling link training\n"); - goto out; - } - - return pci_slot_set_sm_timeout(slot, msecs_to_tb(10)); - } - - PHBDBG(p, "FRESET: Assert\n"); - reg64 = in_be64(p->regs + PHB_RESET); - reg64 &= ~0x2000000000000000ul; - out_be64(p->regs + PHB_RESET, reg64); - pci_slot_set_state(slot, P7IOC_SLOT_FRESET_ASSERT); - return pci_slot_set_sm_timeout(slot, secs_to_tb(1)); - case P7IOC_SLOT_FRESET_ASSERT: - PHBDBG(p, "FRESET: Deassert\n"); - reg64 = in_be64(p->regs + PHB_RESET); - reg64 |= 0x2000000000000000ul; - out_be64(p->regs + PHB_RESET, reg64); - - pci_slot_set_state(slot, P7IOC_SLOT_LINK_START); - return slot->ops.poll_link(slot); - default: - PHBERR(p, "FRESET: Unexpected slot state %08x\n", - slot->state); - } - -out: - pci_slot_set_state(slot, P7IOC_SLOT_NORMAL); - return OPAL_HARDWARE; -} - -static int64_t p7ioc_creset(struct pci_slot *slot) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(slot->phb); - struct p7ioc *ioc = p->ioc; - uint64_t reg64; - - switch (slot->state) { - case P7IOC_SLOT_NORMAL: - PHBDBG(p, "CRESET: Starts\n"); - p->flags |= P7IOC_PHB_CFG_BLOCKED; - p7ioc_phb_reset(slot->phb); - - /* - * According to the experiment, we probably still have the - * fenced state with the corresponding PHB in the Fence WOF - * and we need clear that explicitly. Besides, the RGC might - * already have informational error and we should clear that - * explicitly as well. Otherwise, RGC XIVE#0 won't issue - * interrupt any more. - */ - reg64 = in_be64(ioc->regs + P7IOC_CHIP_FENCE_WOF); - reg64 &= ~PPC_BIT(15 + p->index * 4); - out_be64(ioc->regs + P7IOC_CHIP_FENCE_WOF, reg64); - - /* Clear informational error from RGC */ - reg64 = in_be64(ioc->regs + P7IOC_RGC_LEM_BASE + - P7IOC_LEM_WOF_OFFSET); - reg64 &= ~PPC_BIT(18); - out_be64(ioc->regs + P7IOC_RGC_LEM_BASE + - P7IOC_LEM_WOF_OFFSET, reg64); - reg64 = in_be64(ioc->regs + P7IOC_RGC_LEM_BASE + - P7IOC_LEM_FIR_OFFSET); - reg64 &= ~PPC_BIT(18); - out_be64(ioc->regs + P7IOC_RGC_LEM_BASE + - P7IOC_LEM_FIR_OFFSET, reg64); - - /* Swith to fundamental reset */ - pci_slot_set_state(slot, P7IOC_SLOT_FRESET_START); - return slot->ops.freset(slot); - default: - PHBERR(p, "CRESET: Unexpected slot state %08x\n", - slot->state); - } - - pci_slot_set_state(slot, P7IOC_SLOT_NORMAL); - return OPAL_HARDWARE; -} - -static struct pci_slot *p7ioc_phb_slot_create(struct phb *phb) -{ - struct pci_slot *slot; - - slot = pci_slot_alloc(phb, NULL); - if (!slot) - return NULL; - - /* Elementary functions */ - slot->ops.get_presence_state = p7ioc_get_presence_state; - slot->ops.get_link_state = p7ioc_get_link_state; - slot->ops.get_power_state = p7ioc_get_power_state; - slot->ops.get_attention_state = NULL; - slot->ops.get_latch_state = NULL; - slot->ops.set_power_state = p7ioc_set_power_state; - slot->ops.set_attention_state = NULL; - - /* - * For PHB slots, we have to split the fundamental reset - * into 2 steps. We might not have the first step which - * is to power off/on the slot, or it's controlled by - * individual platforms. - */ - slot->ops.prepare_link_change = p7ioc_prepare_link_change; - slot->ops.poll_link = p7ioc_poll_link; - slot->ops.hreset = p7ioc_hreset; - slot->ops.freset = p7ioc_freset; - slot->ops.creset = p7ioc_creset; - - return slot; -} - -static const struct phb_ops p7ioc_phb_ops = { - .cfg_read8 = p7ioc_pcicfg_read8, - .cfg_read16 = p7ioc_pcicfg_read16, - .cfg_read32 = p7ioc_pcicfg_read32, - .cfg_write8 = p7ioc_pcicfg_write8, - .cfg_write16 = p7ioc_pcicfg_write16, - .cfg_write32 = p7ioc_pcicfg_write32, - .choose_bus = p7ioc_choose_bus, - .get_reserved_pe_number = p7ioc_get_reserved_pe_number, - .device_init = p7ioc_device_init, - .device_remove = NULL, - .pci_reinit = p7ioc_pci_reinit, - .eeh_freeze_status = p7ioc_eeh_freeze_status, - .eeh_freeze_clear = p7ioc_eeh_freeze_clear, - .eeh_freeze_set = p7ioc_eeh_freeze_set, - .err_inject = p7ioc_err_inject, - .get_diag_data2 = p7ioc_get_diag_data, - .next_error = p7ioc_eeh_next_error, - .phb_mmio_enable = p7ioc_phb_mmio_enable, - .set_phb_mem_window = p7ioc_set_phb_mem_window, - .map_pe_mmio_window = p7ioc_map_pe_mmio_window, - .set_pe = p7ioc_set_pe, - .set_peltv = p7ioc_set_peltv, - .map_pe_dma_window = p7ioc_map_pe_dma_window, - .map_pe_dma_window_real = p7ioc_map_pe_dma_window_real, - .set_mve = p7ioc_set_mve, - .set_mve_enable = p7ioc_set_mve_enable, - .set_xive_pe = p7ioc_set_xive_pe, - .get_msi_32 = p7ioc_get_msi_32, - .get_msi_64 = p7ioc_get_msi_64, - .ioda_reset = p7ioc_ioda_reset, - .papr_errinjct_reset = p7ioc_papr_errinjct_reset, -}; - -/* p7ioc_phb_get_xive - Interrupt control from OPAL */ -static int64_t p7ioc_msi_get_xive(struct irq_source *is, uint32_t isn, - uint16_t *server, uint8_t *prio) -{ - struct p7ioc_phb *p = is->data; - uint32_t irq, fbuid = P7_IRQ_FBUID(isn); - uint64_t xive; - - if (fbuid < p->buid_msi || fbuid >= (p->buid_msi + 0x10)) - return OPAL_PARAMETER; - - irq = isn & 0xff; - xive = p->mxive_cache[irq]; - - *server = GETFIELD(IODA_XIVT_SERVER, xive); - *prio = GETFIELD(IODA_XIVT_PRIORITY, xive); - - return OPAL_SUCCESS; -} - -/* p7ioc_phb_set_xive - Interrupt control from OPAL */ -static int64_t p7ioc_msi_set_xive(struct irq_source *is, uint32_t isn, - uint16_t server, uint8_t prio) -{ - struct p7ioc_phb *p = is->data; - uint32_t irq, fbuid = P7_IRQ_FBUID(isn); - uint64_t xive, m_server, m_prio; - - if (fbuid < p->buid_msi || fbuid >= (p->buid_msi + 0x10)) - return OPAL_PARAMETER; - - /* We cache the arguments because we have to mangle - * it in order to hijack 3 bits of priority to extend - * the server number - */ - irq = isn & 0xff; - xive = p->mxive_cache[irq]; - xive = SETFIELD(IODA_XIVT_SERVER, xive, server); - xive = SETFIELD(IODA_XIVT_PRIORITY, xive, prio); - p->mxive_cache[irq] = xive; - - /* Now we mangle the server and priority */ - if (prio == 0xff) { - m_server = 0; - m_prio = 0xff; - } else { - m_server = server >> 3; - m_prio = (prio >> 3) | ((server & 7) << 5); - } - - /* We use HRT entry 0 always for now */ - p7ioc_phb_ioda_sel(p, IODA_TBL_MXIVT, irq, false); - xive = in_be64(p->regs + PHB_IODA_DATA0); - xive = SETFIELD(IODA_XIVT_SERVER, xive, m_server); - xive = SETFIELD(IODA_XIVT_PRIORITY, xive, m_prio); - out_be64(p->regs + PHB_IODA_DATA0, xive); - - return OPAL_SUCCESS; -} - -/* p7ioc_phb_get_xive - Interrupt control from OPAL */ -static int64_t p7ioc_lsi_get_xive(struct irq_source *is, uint32_t isn, - uint16_t *server, uint8_t *prio) -{ - struct p7ioc_phb *p = is->data; - uint32_t irq = (isn & 0x7); - uint32_t fbuid = P7_IRQ_FBUID(isn); - uint64_t xive; - - if (fbuid != p->buid_lsi) - return OPAL_PARAMETER; - - xive = p->lxive_cache[irq]; - *server = GETFIELD(IODA_XIVT_SERVER, xive); - *prio = GETFIELD(IODA_XIVT_PRIORITY, xive); - - return OPAL_SUCCESS; -} - -/* p7ioc_phb_set_xive - Interrupt control from OPAL */ -static int64_t p7ioc_lsi_set_xive(struct irq_source *is, uint32_t isn, - uint16_t server, uint8_t prio) -{ - struct p7ioc_phb *p = is->data; - uint32_t irq = (isn & 0x7); - uint32_t fbuid = P7_IRQ_FBUID(isn); - uint64_t xive, m_server, m_prio; - - if (fbuid != p->buid_lsi) - return OPAL_PARAMETER; - - xive = SETFIELD(IODA_XIVT_SERVER, 0ull, server); - xive = SETFIELD(IODA_XIVT_PRIORITY, xive, prio); - - /* - * We cache the arguments because we have to mangle - * it in order to hijack 3 bits of priority to extend - * the server number - */ - p->lxive_cache[irq] = xive; - - /* Now we mangle the server and priority */ - if (prio == 0xff) { - m_server = 0; - m_prio = 0xff; - } else { - m_server = server >> 3; - m_prio = (prio >> 3) | ((server & 7) << 5); - } - - /* We use HRT entry 0 always for now */ - p7ioc_phb_ioda_sel(p, IODA_TBL_LXIVT, irq, false); - xive = in_be64(p->regs + PHB_IODA_DATA0); - xive = SETFIELD(IODA_XIVT_SERVER, xive, m_server); - xive = SETFIELD(IODA_XIVT_PRIORITY, xive, m_prio); - out_be64(p->regs + PHB_IODA_DATA0, xive); - - return OPAL_SUCCESS; -} - -static void p7ioc_phb_err_interrupt(struct irq_source *is, uint32_t isn) -{ - struct p7ioc_phb *p = is->data; - uint64_t peev0, peev1; - - PHBDBG(p, "Got interrupt 0x%04x\n", isn); - - opal_pci_eeh_set_evt(p->phb.opal_id); - - /* If the PHB is broken, go away */ - if (p->broken) - return; - - /* - * Check if there's an error pending and update PHB fence - * state and return, the ER error is drowned at this point - */ - phb_lock(&p->phb); - if (p7ioc_phb_fenced(p)) { - PHBERR(p, "ER error ignored, PHB fenced\n"); - phb_unlock(&p->phb); - return; - } - - /* - * If we already had pending errors, which might be - * moved from IOC, then we needn't check PEEV to avoid - * overwriting the errors from IOC. - */ - if (!p7ioc_phb_err_pending(p)) { - phb_unlock(&p->phb); - return; - } - - /* - * We don't have pending errors from IOC, it's safe - * to check PEEV for frozen PEs. - */ - p7ioc_phb_ioda_sel(p, IODA_TBL_PEEV, 0, true); - peev0 = in_be64(p->regs + PHB_IODA_DATA0); - peev1 = in_be64(p->regs + PHB_IODA_DATA0); - if (peev0 || peev1) { - p->err.err_src = P7IOC_ERR_SRC_PHB0 + p->index; - p->err.err_class = P7IOC_ERR_CLASS_ER; - p->err.err_bit = 0; - p7ioc_phb_set_err_pending(p, true); - } - phb_unlock(&p->phb); -} - -static uint64_t p7ioc_lsi_attributes(struct irq_source *is __unused, - uint32_t isn) -{ - uint32_t irq = (isn & 0x7); - - if (irq == PHB_LSI_PCIE_ERROR) - return IRQ_ATTR_TARGET_OPAL | IRQ_ATTR_TARGET_RARE | IRQ_ATTR_TYPE_LSI; - return IRQ_ATTR_TARGET_LINUX; -} - - -/* MSIs (OS owned) */ -static const struct irq_source_ops p7ioc_msi_irq_ops = { - .get_xive = p7ioc_msi_get_xive, - .set_xive = p7ioc_msi_set_xive, -}; - -/* LSIs (OS owned) */ -static const struct irq_source_ops p7ioc_lsi_irq_ops = { - .get_xive = p7ioc_lsi_get_xive, - .set_xive = p7ioc_lsi_set_xive, - .attributes = p7ioc_lsi_attributes, - .interrupt = p7ioc_phb_err_interrupt, -}; - -static void p7ioc_pcie_add_node(struct p7ioc_phb *p) -{ - - uint64_t reg[2], iob, m32b, m64b, tkill; - uint32_t lsibase, icsp = get_ics_phandle(); - struct dt_node *np; - - reg[0] = cleanup_addr((uint64_t)p->regs); - reg[1] = 0x100000; - - np = dt_new_addr(p->ioc->dt_node, "pciex", reg[0]); - if (!np) - return; - - p->phb.dt_node = np; - dt_add_property_strings(np, "compatible", "ibm,p7ioc-pciex", - "ibm,ioda-phb"); - dt_add_property_strings(np, "device_type", "pciex"); - dt_add_property(np, "reg", reg, sizeof(reg)); - dt_add_property_cells(np, "#address-cells", 3); - dt_add_property_cells(np, "#size-cells", 2); - dt_add_property_cells(np, "#interrupt-cells", 1); - dt_add_property_cells(np, "bus-range", 0, 0xff); - dt_add_property_cells(np, "clock-frequency", 0x200, 0); /* ??? */ - dt_add_property_cells(np, "interrupt-parent", icsp); - /* XXX FIXME: add slot-name */ - //dt_property_cell("bus-width", 8); /* Figure it out from VPD ? */ - - /* "ranges", we only expose IO and M32 - * - * Note: The kernel expects us to have chopped of 64k from the - * M32 size (for the 32-bit MSIs). If we don't do that, it will - * get confused (OPAL does it) - */ - iob = cleanup_addr(p->io_base); - m32b = cleanup_addr(p->m32_base + M32_PCI_START); - dt_add_property_cells(np, "ranges", - /* IO space */ - 0x01000000, 0x00000000, 0x00000000, - hi32(iob), lo32(iob), 0, PHB_IO_SIZE, - /* M32 space */ - 0x02000000, 0x00000000, M32_PCI_START, - hi32(m32b), lo32(m32b), 0,M32_PCI_SIZE - 0x10000); - - /* XXX FIXME: add opal-memwin32, dmawins, etc... */ - m64b = cleanup_addr(p->m64_base); - dt_add_property_u64s(np, "ibm,opal-m64-window", - m64b, m64b, PHB_M64_SIZE); - dt_add_property_cells(np, "ibm,opal-msi-ports", 256); - dt_add_property_cells(np, "ibm,opal-num-pes", 128); - dt_add_property_cells(np, "ibm,opal-reserved-pe", 127); - dt_add_property_cells(np, "ibm,opal-msi-ranges", - p->buid_msi << 4, 0x100); - tkill = reg[0] + PHB_TCE_KILL; - dt_add_property_cells(np, "ibm,opal-tce-kill", - hi32(tkill), lo32(tkill)); - dt_add_property_cells(np, "ibm,supported-tce-sizes", - 12, // 4K - 16, // 64K - 24, // 16M - 34); // 16G - - /* - * Linux may use this property to allocate the diag data buffer, which - * can be used for either of these structs. Pass the largest to ensure - * they can both fit in this buffer. - */ - dt_add_property_cells(np, "ibm,phb-diag-data-size", - MAX(sizeof(struct OpalIoP7IOCPhbErrorData), - sizeof(struct OpalIoP7IOCErrorData))); - - /* Add associativity properties */ - add_chip_dev_associativity(np); - - /* The interrupt maps will be generated in the RC node by the - * PCI code based on the content of this structure: - */ - lsibase = p->buid_lsi << 4; - p->phb.lstate.int_size = 2; - p->phb.lstate.int_val[0][0] = lsibase + PHB_LSI_PCIE_INTA; - p->phb.lstate.int_val[0][1] = 1; - p->phb.lstate.int_val[1][0] = lsibase + PHB_LSI_PCIE_INTB; - p->phb.lstate.int_val[1][1] = 1; - p->phb.lstate.int_val[2][0] = lsibase + PHB_LSI_PCIE_INTC; - p->phb.lstate.int_val[2][1] = 1; - p->phb.lstate.int_val[3][0] = lsibase + PHB_LSI_PCIE_INTD; - p->phb.lstate.int_val[3][1] = 1; - p->phb.lstate.int_parent[0] = icsp; - p->phb.lstate.int_parent[1] = icsp; - p->phb.lstate.int_parent[2] = icsp; - p->phb.lstate.int_parent[3] = icsp; -} - -/* p7ioc_phb_setup - Setup a p7ioc_phb data structure - * - * WARNING: This is called before the AIB register routing is - * established. If this wants to access PHB registers, it must - * use the ASB hard coded variant (slower) - */ -void p7ioc_phb_setup(struct p7ioc *ioc, uint8_t index) -{ - struct p7ioc_phb *p = &ioc->phbs[index]; - unsigned int buid_base = ioc->buid_base + PHBn_BUID_BASE(index); - struct pci_slot *slot; - - p->index = index; - p->ioc = ioc; - p->gen = 2; /* Operate in Gen2 mode by default */ - p->phb.ops = &p7ioc_phb_ops; - p->phb.phb_type = phb_type_pcie_v2; - p->regs_asb = ioc->regs + PHBn_ASB_BASE(index); - p->regs = ioc->regs + PHBn_AIB_BASE(index); - p->buid_lsi = buid_base + PHB_BUID_LSI_OFFSET; - p->buid_msi = buid_base + PHB_BUID_MSI_OFFSET; - p->io_base = ioc->mmio1_win_start + PHBn_IO_BASE(index); - p->m32_base = ioc->mmio2_win_start + PHBn_M32_BASE(index); - p->m64_base = ioc->mmio2_win_start + PHBn_M64_BASE(index); - p->phb.scan_map = 0x1; /* Only device 0 to scan */ - - /* Find P7IOC base location code in IOC */ - p->phb.base_loc_code = dt_prop_get_def(ioc->dt_node, - "ibm,io-base-loc-code", NULL); - if (!p->phb.base_loc_code) - prerror("P7IOC: Base location code not found !\n"); - - /* Create device node for PHB */ - p7ioc_pcie_add_node(p); - - /* Register OS interrupt sources */ - register_irq_source(&p7ioc_msi_irq_ops, p, p->buid_msi << 4, 256); - register_irq_source(&p7ioc_lsi_irq_ops, p, p->buid_lsi << 4, 8); - - /* Initialize IODA table caches */ - p7ioc_phb_init_ioda_cache(p); - - /* We register the PHB before we initialize it so we - * get a useful OPAL ID for it - */ - pci_register_phb(&p->phb, OPAL_DYNAMIC_PHB_ID); - slot = p7ioc_phb_slot_create(&p->phb); - if (!slot) - prlog(PR_NOTICE, "P7IOC: Cannot create PHB#%x slot\n", - p->phb.opal_id); - - /* Platform additional setup */ - if (platform.pci_setup_phb) - platform.pci_setup_phb(&p->phb, p->index); -} - -static bool p7ioc_phb_wait_dlp_reset(struct p7ioc_phb *p) -{ - unsigned int i; - uint64_t val; - - /* - * Firmware cannot access the UTL core regs or PCI config space - * until the cores are out of DL_PGRESET. - * DL_PGRESET should be polled until it is inactive with a value - * of '0'. The recommended polling frequency is once every 1ms. - * Firmware should poll at least 200 attempts before giving up. - * MMIO Stores to the link are silently dropped by the UTL core if - * the link is down. - * MMIO Loads to the link will be dropped by the UTL core and will - * eventually time-out and will return an all ones response if the - * link is down. - */ -#define DLP_RESET_ATTEMPTS 400 - - printf("P7IOC: Waiting for DLP PG reset to complete...\n"); - for (i = 0; i < DLP_RESET_ATTEMPTS; i++) { - val = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL); - if (!(val & PHB_PCIE_DLP_TC_DL_PGRESET)) - break; - time_wait_ms(1); - } - if (val & PHB_PCIE_DLP_TC_DL_PGRESET) { - PHBERR(p, "Timeout waiting for DLP PG reset !\n"); - return false; - } - return true; -} - -/* p7ioc_phb_init_rc - Initialize the Root Complex config space - */ -static bool p7ioc_phb_init_rc_cfg(struct p7ioc_phb *p) -{ - int64_t ecap, aercap; - - /* XXX Handle errors ? */ - - /* Init_51..51: - * - * Set primary bus to 0, secondary to 1 and subordinate to 0xff - */ - p7ioc_pcicfg_write32(&p->phb, 0, PCI_CFG_PRIMARY_BUS, 0x00ff0100); - - /* Init_52..57 - * - * IO and Memory base & limits are set to base > limit, which - * allows all inbounds. - * - * XXX This has the potential of confusing the OS which might - * think that nothing is forwarded downstream. We probably need - * to fix this to match the IO and M32 PHB windows - */ - p7ioc_pcicfg_write16(&p->phb, 0, PCI_CFG_IO_BASE, 0x0010); - p7ioc_pcicfg_write32(&p->phb, 0, PCI_CFG_MEM_BASE, 0x00000010); - p7ioc_pcicfg_write32(&p->phb, 0, PCI_CFG_PREF_MEM_BASE, 0x00000010); - - /* Init_58..: Setup bridge control to enable forwarding of CORR, FATAL, - * and NONFATAL errors - */ - p7ioc_pcicfg_write16(&p->phb, 0, PCI_CFG_BRCTL, PCI_CFG_BRCTL_SERR_EN); - - /* Init_60..61 - * - * PCIE Device control/status, enable error reporting, disable relaxed - * ordering, set MPS to 128 (see note), clear errors. - * - * Note: The doc recommends to set MPS to 4K. This has proved to have - * some issues as it requires specific claming of MRSS on devices and - * we've found devices in the field that misbehave when doing that. - * - * We currently leave it all to 128 bytes (minimum setting) at init - * time. The generic PCIe probing later on might apply a different - * value, or the kernel will, but we play it safe at early init - */ - if (p->ecap <= 0) { - ecap = pci_find_cap(&p->phb, 0, PCI_CFG_CAP_ID_EXP); - if (ecap < 0) { - PHBERR(p, "Can't locate PCI-E capability\n"); - return false; - } - p->ecap = ecap; - } else { - ecap = p->ecap; - } - - p7ioc_pcicfg_write16(&p->phb, 0, ecap + PCICAP_EXP_DEVSTAT, - PCICAP_EXP_DEVSTAT_CE | - PCICAP_EXP_DEVSTAT_NFE | - PCICAP_EXP_DEVSTAT_FE | - PCICAP_EXP_DEVSTAT_UE); - - p7ioc_pcicfg_write16(&p->phb, 0, ecap + PCICAP_EXP_DEVCTL, - PCICAP_EXP_DEVCTL_CE_REPORT | - PCICAP_EXP_DEVCTL_NFE_REPORT | - PCICAP_EXP_DEVCTL_FE_REPORT | - PCICAP_EXP_DEVCTL_UR_REPORT | - SETFIELD(PCICAP_EXP_DEVCTL_MPS, 0, PCIE_MPS_128B)); - - /* Init_62..63 - * - * Root Control Register. Enable error reporting - * - * Note: Added CRS visibility. - */ - p7ioc_pcicfg_write16(&p->phb, 0, ecap + PCICAP_EXP_RC, - PCICAP_EXP_RC_SYSERR_ON_CE | - PCICAP_EXP_RC_SYSERR_ON_NFE | - PCICAP_EXP_RC_SYSERR_ON_FE | - PCICAP_EXP_RC_CRS_VISIBLE); - - /* Init_64..65 - * - * Device Control 2. Enable ARI fwd, set timer - */ - p7ioc_pcicfg_write16(&p->phb, 0, ecap + PCICAP_EXP_DCTL2, - SETFIELD(PCICAP_EXP_DCTL2_CMPTOUT, 0, 2) | - PCICAP_EXP_DCTL2_ARI_FWD); - - /* Init_66..81 - * - * AER inits - */ - aercap = pci_find_ecap(&p->phb, 0, PCIECAP_ID_AER, NULL); - if (aercap < 0) { - /* Shouldn't happen */ - PHBERR(p, "Failed to locate AER capability in bridge\n"); - return false; - } - p->aercap = aercap; - - /* Clear all UE status */ - p7ioc_pcicfg_write32(&p->phb, 0, aercap + PCIECAP_AER_UE_STATUS, - 0xffffffff); - /* Disable some error reporting as per the P7IOC spec */ - p7ioc_pcicfg_write32(&p->phb, 0, aercap + PCIECAP_AER_UE_MASK, - PCIECAP_AER_UE_POISON_TLP | - PCIECAP_AER_UE_COMPL_TIMEOUT | - PCIECAP_AER_UE_COMPL_ABORT | - PCIECAP_AER_UE_ECRC); - /* Report some errors as fatal */ - p7ioc_pcicfg_write32(&p->phb, 0, aercap + PCIECAP_AER_UE_SEVERITY, - PCIECAP_AER_UE_DLP | - PCIECAP_AER_UE_SURPRISE_DOWN | - PCIECAP_AER_UE_FLOW_CTL_PROT | - PCIECAP_AER_UE_UNEXP_COMPL | - PCIECAP_AER_UE_RECV_OVFLOW | - PCIECAP_AER_UE_MALFORMED_TLP); - /* Clear all CE status */ - p7ioc_pcicfg_write32(&p->phb, 0, aercap + PCIECAP_AER_CE_STATUS, - 0xffffffff); - /* Disable some error reporting as per the P7IOC spec */ - p7ioc_pcicfg_write32(&p->phb, 0, aercap + PCIECAP_AER_CE_MASK, - PCIECAP_AER_CE_ADV_NONFATAL); - /* Enable ECRC generation & checking */ - p7ioc_pcicfg_write32(&p->phb, 0, aercap + PCIECAP_AER_CAPCTL, - PCIECAP_AER_CAPCTL_ECRCG_EN | - PCIECAP_AER_CAPCTL_ECRCC_EN); - /* Enable reporting in root error control */ - p7ioc_pcicfg_write32(&p->phb, 0, aercap + PCIECAP_AER_RERR_CMD, - PCIECAP_AER_RERR_CMD_FE | - PCIECAP_AER_RERR_CMD_NFE | - PCIECAP_AER_RERR_CMD_CE); - /* Clear root error status */ - p7ioc_pcicfg_write32(&p->phb, 0, aercap + PCIECAP_AER_RERR_STA, - 0xffffffff); - - return true; -} - -static void p7ioc_phb_init_utl(struct p7ioc_phb *p) -{ - /* Init_82..84: Clear spurious errors and assign errors to the - * right "interrupt" signal - */ - out_be64(p->regs + UTL_SYS_BUS_AGENT_STATUS, 0xffffffffffffffffUL); - out_be64(p->regs + UTL_SYS_BUS_AGENT_ERR_SEVERITY, 0x0000000000000000UL); - out_be64(p->regs + UTL_SYS_BUS_AGENT_IRQ_EN, 0xac80000000000000UL); - - /* Init_85..89: Setup buffer allocations */ - out_be64(p->regs + UTL_OUT_POST_DAT_BUF_ALLOC, 0x0400000000000000UL); - out_be64(p->regs + UTL_IN_POST_HDR_BUF_ALLOC, 0x1000000000000000UL); - out_be64(p->regs + UTL_IN_POST_DAT_BUF_ALLOC, 0x4000000000000000UL); - out_be64(p->regs + UTL_PCIE_TAGS_ALLOC, 0x0800000000000000UL); - out_be64(p->regs + UTL_GBIF_READ_TAGS_ALLOC, 0x0800000000000000UL); - - /* Init_90: PCI Express port control */ - out_be64(p->regs + UTL_PCIE_PORT_CONTROL, 0x8480000000000000UL); - - /* Init_91..93: Clean & setup port errors */ - out_be64(p->regs + UTL_PCIE_PORT_STATUS, 0xff7fffffffffffffUL); - out_be64(p->regs + UTL_PCIE_PORT_ERROR_SEV, 0x00e0000000000000UL); - out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN, 0x7e65000000000000UL); - - /* Init_94 : Cleanup RC errors */ - out_be64(p->regs + UTL_RC_STATUS, 0xffffffffffffffffUL); -} - -static void p7ioc_phb_init_errors(struct p7ioc_phb *p) -{ - /* Init_98: LEM Error Mask : Temporarily disable error interrupts */ - out_be64(p->regs + PHB_LEM_ERROR_MASK, 0xffffffffffffffffUL); - - /* Init_99..107: Configure main error traps & clear old state */ - out_be64(p->regs + PHB_ERR_STATUS, 0xffffffffffffffffUL); - out_be64(p->regs + PHB_ERR1_STATUS, 0x0000000000000000UL); - out_be64(p->regs + PHB_ERR_LEM_ENABLE, 0xffffffffefffffffUL); - out_be64(p->regs + PHB_ERR_FREEZE_ENABLE, 0x0000000061c00000UL); - out_be64(p->regs + PHB_ERR_AIB_FENCE_ENABLE, 0xffffffc58c000000UL); - out_be64(p->regs + PHB_ERR_LOG_0, 0x0000000000000000UL); - out_be64(p->regs + PHB_ERR_LOG_1, 0x0000000000000000UL); - out_be64(p->regs + PHB_ERR_STATUS_MASK, 0x0000000000000000UL); - out_be64(p->regs + PHB_ERR1_STATUS_MASK, 0x0000000000000000UL); - - /* Init_108_116: Configure MMIO error traps & clear old state */ - out_be64(p->regs + PHB_OUT_ERR_STATUS, 0xffffffffffffffffUL); - out_be64(p->regs + PHB_OUT_ERR1_STATUS, 0x0000000000000000UL); - out_be64(p->regs + PHB_OUT_ERR_LEM_ENABLE, 0xffffffffffffffffUL); - out_be64(p->regs + PHB_OUT_ERR_FREEZE_ENABLE, 0x0000430803000000UL); - out_be64(p->regs + PHB_OUT_ERR_AIB_FENCE_ENABLE, 0x9df3bc00f0f0700fUL); - out_be64(p->regs + PHB_OUT_ERR_LOG_0, 0x0000000000000000UL); - out_be64(p->regs + PHB_OUT_ERR_LOG_1, 0x0000000000000000UL); - out_be64(p->regs + PHB_OUT_ERR_STATUS_MASK, 0x0000000000000000UL); - out_be64(p->regs + PHB_OUT_ERR1_STATUS_MASK, 0x0000000000000000UL); - - /* Init_117_125: Configure DMA_A error traps & clear old state */ - out_be64(p->regs + PHB_INA_ERR_STATUS, 0xffffffffffffffffUL); - out_be64(p->regs + PHB_INA_ERR1_STATUS, 0x0000000000000000UL); - out_be64(p->regs + PHB_INA_ERR_LEM_ENABLE, 0xffffffffffffffffUL); - out_be64(p->regs + PHB_INA_ERR_FREEZE_ENABLE, 0xc00003ff01006000UL); - out_be64(p->regs + PHB_INA_ERR_AIB_FENCE_ENABLE, 0x3fff50007e559fd8UL); - out_be64(p->regs + PHB_INA_ERR_LOG_0, 0x0000000000000000UL); - out_be64(p->regs + PHB_INA_ERR_LOG_1, 0x0000000000000000UL); - out_be64(p->regs + PHB_INA_ERR_STATUS_MASK, 0x0000000000000000UL); - out_be64(p->regs + PHB_INA_ERR1_STATUS_MASK, 0x0000000000000000UL); - - /* Init_126_134: Configure DMA_B error traps & clear old state */ - out_be64(p->regs + PHB_INB_ERR_STATUS, 0xffffffffffffffffUL); - out_be64(p->regs + PHB_INB_ERR1_STATUS, 0x0000000000000000UL); - out_be64(p->regs + PHB_INB_ERR_LEM_ENABLE, 0xffffffffffffffffUL); - out_be64(p->regs + PHB_INB_ERR_FREEZE_ENABLE, 0x0000000000000000UL); - out_be64(p->regs + PHB_INB_ERR_AIB_FENCE_ENABLE, 0x18ff80ffff7f0000UL); - out_be64(p->regs + PHB_INB_ERR_LOG_0, 0x0000000000000000UL); - out_be64(p->regs + PHB_INB_ERR_LOG_1, 0x0000000000000000UL); - out_be64(p->regs + PHB_INB_ERR_STATUS_MASK, 0x0000000000000000UL); - out_be64(p->regs + PHB_INB_ERR1_STATUS_MASK, 0x0000000000000000UL); - - /* Init_135..138: Cleanup & configure LEM */ - out_be64(p->regs + PHB_LEM_FIR_ACCUM, 0x0000000000000000UL); - out_be64(p->regs + PHB_LEM_ACTION0, 0xffffffffffffffffUL); - out_be64(p->regs + PHB_LEM_ACTION1, 0x0000000000000000UL); - out_be64(p->regs + PHB_LEM_WOF, 0x0000000000000000UL); -} - -/* p7ioc_phb_init - Initialize the PHB hardware - * - * This is currently only called at boot time. It will eventually - * be called at runtime, for example in some cases of error recovery - * after a PHB reset in which case we might need locks etc... - */ -int64_t p7ioc_phb_init(struct p7ioc_phb *p) -{ - uint64_t val; - - PHBDBG(p, "Initializing PHB %x...\n", p->index); - - /* - * We re-init the PHB on a creset (and a few other cases) - * so clear the broken flag - */ - p->broken = false; - - /* For some reason, the doc wants us to read the version - * register, so let's do it. We shoud probably check that - * the value makes sense... - */ - val = in_be64(p->regs_asb + PHB_VERSION); - p->rev = ((val >> 16) & 0xffff) | (val & 0xffff); - PHBDBG(p, "PHB version: %08x\n", p->rev); - - /* - * Configure AIB operations - * - * This register maps upbound commands to AIB channels. - * DMA Write=0, DMA Read=2, MMIO Load Response=1, - * Interrupt Request=1, TCE Read=3. - */ - /* Init_1: AIB TX Channel Mapping */ - out_be64(p->regs_asb + PHB_AIB_TX_CHAN_MAPPING, 0x0211300000000000UL); - - /* - * This group of steps initializes the AIB RX credits for - * the CI block’s port that is attached to this PHB. - * - * Channel 0 (Dkill): 32 command credits, 0 data credits - * (effectively infinite command credits) - * Channel 1 (DMA/TCE Read Responses): 32 command credits, 32 data - * credits (effectively infinite - * command and data credits) - * Channel 2 (Interrupt Reissue/Return): 32 command, 0 data credits - * (effectively infinite - * command credits) - * Channel 3 (MMIO Load/Stores, EOIs): 1 command, 1 data credit - */ - - /* Init_2: AIB RX Command Credit */ - out_be64(p->regs_asb + PHB_AIB_RX_CMD_CRED, 0x0020002000200001UL); - /* Init_3: AIB RX Data Credit */ - out_be64(p->regs_asb + PHB_AIB_RX_DATA_CRED, 0x0000002000000001UL); - /* Init_4: AXIB RX Credit Init Timer */ - out_be64(p->regs_asb + PHB_AIB_RX_CRED_INIT_TIMER, 0xFF00000000000000UL); - - /* - * Enable all 32 AIB and TCE tags. - * - * AIB tags are used for DMA read requests. - * TCE tags are used for every internal transaction as well as TCE - * read requests. - */ - - /* Init_5: PHB - AIB Tag Enable Register */ - out_be64(p->regs_asb + PHB_AIB_TAG_ENABLE, 0xFFFFFFFF00000000UL); - /* Init_6: PHB – TCE Tag Enable Register */ - out_be64(p->regs_asb + PHB_TCE_TAG_ENABLE, 0xFFFFFFFF00000000UL); - - /* Init_7: PCIE - System Configuration Register - * - * This is the default value out of reset. This register can be - * modified to change the following fields if needed: - * - * bits 04:09 - SYS_EC0C_MAXLINKWIDTH[5:0] - * The default link width is x8. This can be reduced - * to x1 or x4, if needed. - * - * bits 10:12 - SYS_EC04_MAX_PAYLOAD[2:0] - * - * The default max payload size is 4KB. This can be - * reduced to the allowed ranges from 128B - * to 2KB if needed. - */ - out_be64(p->regs + PHB_PCIE_SYSTEM_CONFIG, 0x422800FC20000000UL); - - /* Init_8: PHB - PCI-E Reset Register - * - * This will deassert reset for the PCI-E cores, including the - * PHY and HSS macros. The TLDLP core will begin link training - * shortly after this register is written. - * This will also assert reset for the internal scan-only error - * report macros. The error report macro reset will be deasserted - * in a later step. - * Firmware will verify in a later step whether the PCI-E link - * has been established. - * - * NOTE: We perform a PERST at the end of the init sequence so - * we could probably skip that link training. - */ - out_be64(p->regs + PHB_RESET, 0xE800000000000000UL); - - /* Init_9: BUID - * - * Only the top 5 bit of the MSI field are implemented, the bottom - * are always 0. Our buid_msi value should also be a multiple of - * 16 so it should all fit well - */ - val = SETFIELD(PHB_BUID_LSI, 0ul, P7_BUID_BASE(p->buid_lsi)); - val |= SETFIELD(PHB_BUID_MSI, 0ul, P7_BUID_BASE(p->buid_msi)); - out_be64(p->regs + PHB_BUID, val); - - /* Init_10..12: IO Space */ - out_be64(p->regs + PHB_IO_BASE_ADDR, p->io_base); - out_be64(p->regs + PHB_IO_BASE_MASK, ~(PHB_IO_SIZE - 1)); - out_be64(p->regs + PHB_IO_START_ADDR, 0); - - /* Init_13..15: M32 Space */ - out_be64(p->regs + PHB_M32_BASE_ADDR, p->m32_base + M32_PCI_START); - out_be64(p->regs + PHB_M32_BASE_MASK, ~(M32_PCI_SIZE - 1)); - out_be64(p->regs + PHB_M32_START_ADDR, M32_PCI_START); - - /* Init_16: PCIE-E Outbound Request Upper Address */ - out_be64(p->regs + PHB_M64_UPPER_BITS, 0); - - /* Init_17: PCIE-E PHB2 Configuration - * - * We enable IO, M32, 32-bit MSI and 64-bit MSI - */ - out_be64(p->regs + PHB_PHB2_CONFIG, - PHB_PHB2C_32BIT_MSI_EN | - PHB_PHB2C_IO_EN | - PHB_PHB2C_64BIT_MSI_EN | - PHB_PHB2C_M32_EN | - PHB_PHB2C_64B_TCE_EN); - - /* Init_18..xx: Reset all IODA tables */ - p7ioc_ioda_reset(&p->phb, false); - - /* Init_42..47: Clear UTL & DLP error log regs */ - out_be64(p->regs + PHB_PCIE_UTL_ERRLOG1, 0xffffffffffffffffUL); - out_be64(p->regs + PHB_PCIE_UTL_ERRLOG2, 0xffffffffffffffffUL); - out_be64(p->regs + PHB_PCIE_UTL_ERRLOG3, 0xffffffffffffffffUL); - out_be64(p->regs + PHB_PCIE_UTL_ERRLOG4, 0xffffffffffffffffUL); - out_be64(p->regs + PHB_PCIE_DLP_ERRLOG1, 0xffffffffffffffffUL); - out_be64(p->regs + PHB_PCIE_DLP_ERRLOG2, 0xffffffffffffffffUL); - - /* Init_48: Wait for DLP core to be out of reset */ - if (!p7ioc_phb_wait_dlp_reset(p)) - goto failed; - - /* Init_49 - Clear port status */ - out_be64(p->regs + UTL_PCIE_PORT_STATUS, 0xffffffffffffffffUL); - - /* Init_50..81: Init root complex config space */ - if (!p7ioc_phb_init_rc_cfg(p)) - goto failed; - - /* Init_82..94 : Init UTL */ - p7ioc_phb_init_utl(p); - - /* Init_95: PCI-E Reset, deassert reset for internal error macros */ - out_be64(p->regs + PHB_RESET, 0xe000000000000000UL); - - /* Init_96: PHB Control register. Various PHB settings: - * - * - Enable ECC for various internal RAMs - * - Enable all TCAM entries - * - Set failed DMA read requests to return Completer Abort on error - */ - out_be64(p->regs + PHB_CONTROL, 0x7f38000000000000UL); - - /* Init_97: Legacy Control register - * - * The spec sets bit 0 to enable DKill to flush the TCEs. We do not - * use that mechanism however, we require the OS to directly access - * the TCE Kill register, so we leave that bit set to 0 - */ - out_be64(p->regs + PHB_LEGACY_CTRL, 0x0000000000000000); - - /* Init_98..138 : Setup error registers */ - p7ioc_phb_init_errors(p); - - /* Init_139: Read error summary */ - val = in_be64(p->regs + PHB_ETU_ERR_SUMMARY); - if (val) { - PHBERR(p, "Errors detected during PHB init: 0x%16llx\n", val); - goto failed; - } - - /* Steps Init_140..142 have been removed from the spec. */ - - /* Init_143..144: Enable IO, MMIO, Bus master etc... and clear - * status bits - */ - p7ioc_pcicfg_write16(&p->phb, 0, PCI_CFG_STAT, - PCI_CFG_STAT_SENT_TABORT | - PCI_CFG_STAT_RECV_TABORT | - PCI_CFG_STAT_RECV_MABORT | - PCI_CFG_STAT_SENT_SERR | - PCI_CFG_STAT_RECV_PERR); - p7ioc_pcicfg_write16(&p->phb, 0, PCI_CFG_CMD, - PCI_CFG_CMD_SERR_EN | - PCI_CFG_CMD_PERR_RESP | - PCI_CFG_CMD_BUS_MASTER_EN | - PCI_CFG_CMD_MEM_EN | - PCI_CFG_CMD_IO_EN); - - /* At this point, the spec suggests doing a bus walk. However we - * haven't powered up the slots with the SHCP controller. We'll - * deal with that and link training issues later, for now, let's - * enable the full range of error detection - */ - - /* Init_145..149: Enable error interrupts and LEM */ - out_be64(p->regs + PHB_ERR_IRQ_ENABLE, 0x0000000061c00000UL); - out_be64(p->regs + PHB_OUT_ERR_IRQ_ENABLE, 0x0000430803000000UL); - out_be64(p->regs + PHB_INA_ERR_IRQ_ENABLE, 0xc00003ff01006000UL); - out_be64(p->regs + PHB_INB_ERR_IRQ_ENABLE, 0x0000000000000000UL); - out_be64(p->regs + PHB_LEM_ERROR_MASK, 0x1249a1147f500f2cUL); - - /* Init_150: Enable DMA read/write TLP address speculation */ - out_be64(p->regs + PHB_TCE_PREFETCH, 0x0000c00000000000UL); - - /* Init_151..152: Set various timeouts */ - out_be64(p->regs + PHB_TIMEOUT_CTRL1, 0x1611112010200000UL); - out_be64(p->regs + PHB_TIMEOUT_CTRL2, 0x0000561300000000UL); - - return OPAL_SUCCESS; - - failed: - PHBERR(p, "Initialization failed\n"); - p->broken = true; - - return OPAL_HARDWARE; -} - -void p7ioc_phb_reset(struct phb *phb) -{ - struct p7ioc_phb *p = phb_to_p7ioc_phb(phb); - struct p7ioc *ioc = p->ioc; - uint64_t ci_idx, rreg; - unsigned int i; - bool fenced; - - /* Check our fence status. The fence bits we care about are - * two bits per PHB at IBM bit location 14 and 15 + 4*phb - */ - fenced = p7ioc_phb_fenced(p); - - PHBDBG(p, "PHB reset... (fenced: %d)\n", (int)fenced); - - /* - * If not fenced and already functional, let's do an IODA reset - * to clear pending DMAs and wait a bit for thing to settle. It's - * notable that the IODA table cache won't be emptied so that we - * can restore them during error recovery. - */ - if (!p->broken && !fenced) { - PHBDBG(p, " ioda reset ...\n"); - p7ioc_ioda_reset(&p->phb, false); - time_wait_ms(100); - } - - /* CI port index */ - ci_idx = p->index + 2; - - /* Reset register bits for this PHB */ - rreg = 0;/*PPC_BIT(8 + ci_idx * 2);*/ /* CI port config reset */ - rreg |= PPC_BIT(9 + ci_idx * 2); /* CI port func reset */ - rreg |= PPC_BIT(32 + p->index); /* PHBn config reset */ - - /* Mask various errors during reset and clear pending errors */ - out_be64(ioc->regs + P7IOC_CIn_LEM_ERR_MASK(ci_idx), - 0xa4f4000000000000ul); - out_be64(p->regs_asb + PHB_LEM_ERROR_MASK, 0xadb650c9808dd051ul); - out_be64(ioc->regs + P7IOC_CIn_LEM_FIR(ci_idx), 0); - - /* We need to retry in case the fence doesn't lift due to a - * problem with lost credits (HW guys). How many times ? - */ -#define MAX_PHB_RESET_RETRIES 5 - for (i = 0; i < MAX_PHB_RESET_RETRIES; i++) { - PHBDBG(p, " reset try %d...\n", i); - /* Apply reset */ - out_be64(ioc->regs + P7IOC_CCRR, rreg); - time_wait_ms(1); - out_be64(ioc->regs + P7IOC_CCRR, 0); - - /* Check if fence lifed */ - fenced = p7ioc_phb_fenced(p); - PHBDBG(p, " fenced: %d...\n", (int)fenced); - if (!fenced) - break; - } - - /* Reset failed, not much to do, maybe add an error return */ - if (fenced) { - PHBERR(p, "Reset failed, fence still set !\n"); - p->broken = true; - return; - } - - /* Wait a bit */ - time_wait_ms(100); - - /* Re-initialize the PHB */ - p7ioc_phb_init(p); - - /* Restore the CI error mask */ - out_be64(ioc->regs + P7IOC_CIn_LEM_ERR_MASK_AND(ci_idx), 0); -} - - - diff --git a/hw/p7ioc.c b/hw/p7ioc.c deleted file mode 100644 index 44ce3d8..0000000 --- a/hw/p7ioc.c +++ /dev/null @@ -1,688 +0,0 @@ -/* Copyright 2013-2014 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - * implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <skiboot.h> -#include <p7ioc.h> -#include <p7ioc-regs.h> -#include <cec.h> -#include <opal.h> -#include <io.h> -#include <vpd.h> -#include <interrupts.h> -#include <ccan/str/str.h> - -/* - * Determine the base address of LEM registers according to - * the indicated error source. - */ -static void *p7ioc_LEM_base(struct p7ioc *ioc, uint32_t err_src) -{ - uint32_t index; - void *base = NULL; - - switch (err_src) { - case P7IOC_ERR_SRC_RGC: - base = ioc->regs + P7IOC_RGC_LEM_BASE; - break; - case P7IOC_ERR_SRC_BI_UP: - base = ioc->regs + P7IOC_BI_UP_LEM_BASE; - break; - case P7IOC_ERR_SRC_BI_DOWN: - base = ioc->regs + P7IOC_BI_DOWN_LEM_BASE; - break; - case P7IOC_ERR_SRC_CI_P0: - case P7IOC_ERR_SRC_CI_P1: - case P7IOC_ERR_SRC_CI_P2: - case P7IOC_ERR_SRC_CI_P3: - case P7IOC_ERR_SRC_CI_P4: - case P7IOC_ERR_SRC_CI_P5: - case P7IOC_ERR_SRC_CI_P6: - case P7IOC_ERR_SRC_CI_P7: - index = err_src - P7IOC_ERR_SRC_CI_P0; - base = ioc->regs + P7IOC_CI_PORTn_LEM_BASE(index); - break; - case P7IOC_ERR_SRC_PHB0: - case P7IOC_ERR_SRC_PHB1: - case P7IOC_ERR_SRC_PHB2: - case P7IOC_ERR_SRC_PHB3: - case P7IOC_ERR_SRC_PHB4: - case P7IOC_ERR_SRC_PHB5: - index = err_src - P7IOC_ERR_SRC_PHB0; - base = ioc->regs + P7IOC_PHBn_LEM_BASE(index); - break; - case P7IOC_ERR_SRC_MISC: - base = ioc->regs + P7IOC_MISC_LEM_BASE; - break; - case P7IOC_ERR_SRC_I2C: - base = ioc->regs + P7IOC_I2C_LEM_BASE; - break; - default: - prerror("%s: Unknown error source %d\n", - __func__, err_src); - } - - return base; -} - -static void p7ioc_get_diag_common(struct p7ioc *ioc, - void *base, - struct OpalIoP7IOCErrorData *data) -{ - /* GEM */ - data->gemXfir = in_be64(ioc->regs + P7IOC_GEM_XFIR); - data->gemRfir = in_be64(ioc->regs + P7IOC_GEM_RFIR); - data->gemRirqfir = in_be64(ioc->regs + P7IOC_GEM_RIRQFIR); - data->gemMask = in_be64(ioc->regs + P7IOC_GEM_MASK); - data->gemRwof = in_be64(ioc->regs + P7IOC_GEM_RWOF); - - /* LEM */ - data->lemFir = in_be64(base + P7IOC_LEM_FIR_OFFSET); - data->lemErrMask = in_be64(base + P7IOC_LEM_ERR_MASK_OFFSET); - data->lemAction0 = in_be64(base + P7IOC_LEM_ACTION_0_OFFSET); - data->lemAction1 = in_be64(base + P7IOC_LEM_ACTION_1_OFFSET); - data->lemWof = in_be64(base + P7IOC_LEM_WOF_OFFSET); -} - -static int64_t p7ioc_get_diag_data(struct io_hub *hub, - void *diag_buffer, - uint64_t diag_buffer_len) -{ - struct p7ioc *ioc = iohub_to_p7ioc(hub); - struct OpalIoP7IOCErrorData *data = diag_buffer; - void *base; - - /* Make sure we have enough buffer */ - if (diag_buffer_len < sizeof(struct OpalIoP7IOCErrorData)) - return OPAL_PARAMETER; - - /* We need do nothing if there're no pending errors */ - if (!p7ioc_err_pending(ioc)) - return OPAL_CLOSED; - - /* - * We needn't collect diag-data for CI Port{2, ..., 7} - * and PHB{0, ..., 5} since their errors (except GXE) - * have been cached to the specific PHB. - */ - base = p7ioc_LEM_base(ioc, ioc->err.err_src); - if (!base) { - p7ioc_set_err_pending(ioc, false); - return OPAL_INTERNAL_ERROR; - } - - switch (ioc->err.err_src) { - case P7IOC_ERR_SRC_RGC: - data->type = OPAL_P7IOC_DIAG_TYPE_RGC; - p7ioc_get_diag_common(ioc, base, data); - - data->rgc.rgcStatus = in_be64(ioc->regs + 0x3E1C10); - data->rgc.rgcLdcp = in_be64(ioc->regs + 0x3E1C18); - - break; - case P7IOC_ERR_SRC_BI_UP: - data->type = OPAL_P7IOC_DIAG_TYPE_BI; - data->bi.biDownbound = 0; - p7ioc_get_diag_common(ioc, base, data); - - data->bi.biLdcp0 = in_be64(ioc->regs + 0x3C0100); - data->bi.biLdcp1 = in_be64(ioc->regs + 0x3C0108); - data->bi.biLdcp2 = in_be64(ioc->regs + 0x3C0110); - data->bi.biFenceStatus = in_be64(ioc->regs + 0x3C0130); - - break; - case P7IOC_ERR_SRC_BI_DOWN: - data->type = OPAL_P7IOC_DIAG_TYPE_BI; - data->bi.biDownbound = 1; - p7ioc_get_diag_common(ioc, base, data); - - data->bi.biLdcp0 = in_be64(ioc->regs + 0x3C0118); - data->bi.biLdcp1 = in_be64(ioc->regs + 0x3C0120); - data->bi.biLdcp2 = in_be64(ioc->regs + 0x3C0128); - data->bi.biFenceStatus = in_be64(ioc->regs + 0x3C0130); - - break; - case P7IOC_ERR_SRC_CI_P0: - case P7IOC_ERR_SRC_CI_P1: - data->type = OPAL_P7IOC_DIAG_TYPE_CI; - data->ci.ciPort = ioc->err.err_src - P7IOC_ERR_SRC_CI_P0; - p7ioc_get_diag_common(ioc, base, data); - - data->ci.ciPortStatus = in_be64(base + 0x008); - data->ci.ciPortLdcp = in_be64(base + 0x010); - break; - case P7IOC_ERR_SRC_MISC: - data->type = OPAL_P7IOC_DIAG_TYPE_MISC; - p7ioc_get_diag_common(ioc, base, data); - break; - case P7IOC_ERR_SRC_I2C: - data->type = OPAL_P7IOC_DIAG_TYPE_I2C; - p7ioc_get_diag_common(ioc, base, data); - break; - default: - p7ioc_set_err_pending(ioc, false); - return OPAL_CLOSED; - } - - /* For errors of MAL class, we need mask it */ - if (ioc->err.err_class == P7IOC_ERR_CLASS_MAL) - out_be64(base + P7IOC_LEM_ERR_MASK_OR_OFFSET, - PPC_BIT(63 - ioc->err.err_bit)); - p7ioc_set_err_pending(ioc, false); - - return OPAL_SUCCESS; -} - -static const struct io_hub_ops p7ioc_hub_ops = { - .get_diag_data = p7ioc_get_diag_data, - .reset = p7ioc_reset, -}; - -static int64_t p7ioc_rgc_get_xive(struct irq_source *is, uint32_t isn, - uint16_t *server, uint8_t *prio) -{ - struct p7ioc *ioc = is->data; - uint32_t irq = (isn & 0xf); - uint32_t fbuid = P7_IRQ_FBUID(isn); - uint64_t xive; - - if (fbuid != ioc->rgc_buid) - return OPAL_PARAMETER; - - xive = ioc->xive_cache[irq]; - *server = GETFIELD(IODA_XIVT_SERVER, xive); - *prio = GETFIELD(IODA_XIVT_PRIORITY, xive); - - return OPAL_SUCCESS; - } - -static int64_t p7ioc_rgc_set_xive(struct irq_source *is, uint32_t isn, - uint16_t server, uint8_t prio) -{ - struct p7ioc *ioc = is->data; - uint32_t irq = (isn & 0xf); - uint32_t fbuid = P7_IRQ_FBUID(isn); - uint64_t xive; - uint64_t m_server, m_prio; - - if (fbuid != ioc->rgc_buid) - return OPAL_PARAMETER; - - xive = SETFIELD(IODA_XIVT_SERVER, 0ull, server); - xive = SETFIELD(IODA_XIVT_PRIORITY, xive, prio); - ioc->xive_cache[irq] = xive; - - /* Now we mangle the server and priority */ - if (prio == 0xff) { - m_server = 0; - m_prio = 0xff; - } else { - m_server = server >> 3; - m_prio = (prio >> 3) | ((server & 7) << 5); - } - - /* Update the XIVE. Don't care HRT entry on P7IOC */ - out_be64(ioc->regs + 0x3e1820, (0x0002000000000000UL | irq)); - xive = in_be64(ioc->regs + 0x3e1830); - xive = SETFIELD(IODA_XIVT_SERVER, xive, m_server); - xive = SETFIELD(IODA_XIVT_PRIORITY, xive, m_prio); - out_be64(ioc->regs + 0x3e1830, xive); - - return OPAL_SUCCESS; -} - -/* - * The function is used to figure out the error class and error - * bit according to LEM WOF. - * - * The bits of WOF register have been classified according to - * the error severity. Of course, we should process those errors - * with higher priority. For example, there have 2 errors (GXE, INF) - * pending, we should process GXE, and INF is meaningless in face - * of GXE. - */ -static bool p7ioc_err_bit(struct p7ioc *ioc, uint64_t wof) -{ - uint64_t val, severity[P7IOC_ERR_CLASS_LAST]; - int32_t class, bit, err_bit = -1; - - /* Clear severity array */ - memset(severity, 0, sizeof(uint64_t) * P7IOC_ERR_CLASS_LAST); - - /* - * The severity array has fixed values. However, it depends - * on the damage settings for individual components. We're - * using fixed values based on the assumption that damage settings - * are fixed for now. If we change it some day, we also need - * change the severity array accordingly. Anyway, it's something - * to improve in future so that we can figure out the severity - * array from hardware registers. - */ - switch (ioc->err.err_src) { - case P7IOC_ERR_SRC_EI: - /* EI won't create interrupt yet */ - break; - case P7IOC_ERR_SRC_RGC: - severity[P7IOC_ERR_CLASS_GXE] = 0xF00086E0F4FCFFFFUL; - severity[P7IOC_ERR_CLASS_RGA] = 0x0000010000000000UL; - severity[P7IOC_ERR_CLASS_INF] = 0x0FFF781F0B030000UL; - break; - case P7IOC_ERR_SRC_BI_UP: - severity[P7IOC_ERR_CLASS_GXE] = 0xF7FFFFFF7FFFFFFFUL; - severity[P7IOC_ERR_CLASS_INF] = 0x0800000080000000UL; - break; - case P7IOC_ERR_SRC_BI_DOWN: - severity[P7IOC_ERR_CLASS_GXE] = 0xDFFFF7F35F8000BFUL; - severity[P7IOC_ERR_CLASS_INF] = 0x2000080CA07FFF40UL; - break; - case P7IOC_ERR_SRC_CI_P0: - severity[P7IOC_ERR_CLASS_GXE] = 0xF5FF000000000000UL; - severity[P7IOC_ERR_CLASS_INF] = 0x0200FFFFFFFFFFFFUL; - severity[P7IOC_ERR_CLASS_MAL] = 0x0800000000000000UL; - break; - case P7IOC_ERR_SRC_CI_P1: - severity[P7IOC_ERR_CLASS_GXE] = 0xFFFF000000000000UL; - severity[P7IOC_ERR_CLASS_INF] = 0x0000FFFFFFFFFFFFUL; - break; - case P7IOC_ERR_SRC_CI_P2: - case P7IOC_ERR_SRC_CI_P3: - case P7IOC_ERR_SRC_CI_P4: - case P7IOC_ERR_SRC_CI_P5: - case P7IOC_ERR_SRC_CI_P6: - case P7IOC_ERR_SRC_CI_P7: - severity[P7IOC_ERR_CLASS_GXE] = 0x5B0B000000000000UL; - severity[P7IOC_ERR_CLASS_PHB] = 0xA4F4000000000000UL; - severity[P7IOC_ERR_CLASS_INF] = 0x0000FFFFFFFFFFFFUL; - break; - case P7IOC_ERR_SRC_MISC: - severity[P7IOC_ERR_CLASS_GXE] = 0x0000000310000000UL; - severity[P7IOC_ERR_CLASS_PLL] = 0x0000000001C00000UL; - severity[P7IOC_ERR_CLASS_INF] = 0x555FFFF0EE3FFFFFUL; - severity[P7IOC_ERR_CLASS_MAL] = 0xAAA0000C00000000UL; - break; - case P7IOC_ERR_SRC_I2C: - severity[P7IOC_ERR_CLASS_GXE] = 0x1100000000000000UL; - severity[P7IOC_ERR_CLASS_INF] = 0xEEFFFFFFFFFFFFFFUL; - break; - case P7IOC_ERR_SRC_PHB0: - case P7IOC_ERR_SRC_PHB1: - case P7IOC_ERR_SRC_PHB2: - case P7IOC_ERR_SRC_PHB3: - case P7IOC_ERR_SRC_PHB4: - case P7IOC_ERR_SRC_PHB5: - severity[P7IOC_ERR_CLASS_PHB] = 0xADB650CB808DD051UL; - severity[P7IOC_ERR_CLASS_ER] = 0x0000A0147F50092CUL; - severity[P7IOC_ERR_CLASS_INF] = 0x52490F2000222682UL; - break; - } - - /* - * The error class (ERR_CLASS) has been defined based on - * their severity. The priority of those errors out of same - * class should be defined based on the position of corresponding - * bit in LEM (Local Error Macro) register. - */ - for (class = P7IOC_ERR_CLASS_NONE + 1; - err_bit < 0 && class < P7IOC_ERR_CLASS_LAST; - class++) { - val = wof & severity[class]; - if (!val) continue; - - for (bit = 0; bit < 64; bit++) { - if (val & PPC_BIT(bit)) { - err_bit = 63 - bit; - break; - } - } - } - - /* If we don't find the error bit, we needn't go on. */ - if (err_bit < 0) - return false; - - ioc->err.err_class = class - 1; - ioc->err.err_bit = err_bit; - return true; -} - -/* - * Check LEM to determine the detailed error information. - * The function is expected to be called while OS calls - * to OPAL API opal_pci_next_error(). Eventually, the errors - * from CI Port{2, ..., 7} or PHB{0, ..., 5} would be cached - * to the specific PHB, the left errors would be cached to - * the IOC. - */ -bool p7ioc_check_LEM(struct p7ioc *ioc, - uint16_t *pci_error_type, - uint16_t *severity) -{ - void *base; - uint64_t fir, wof, mask; - struct p7ioc_phb *p; - int32_t index; - bool ret; - - /* Make sure we have error pending on IOC */ - if (!p7ioc_err_pending(ioc)) - return false; - - /* - * The IOC probably has been put to fatal error - * state (GXE) because of failure on reading on - * GEM FIR. - */ - if (ioc->err.err_src == P7IOC_ERR_SRC_NONE && - ioc->err.err_class != P7IOC_ERR_CLASS_NONE) - goto err; - - /* - * Get the base address of LEM registers according - * to the error source. If we failed to get that, - * the error pending flag would be cleared. - */ - base = p7ioc_LEM_base(ioc, ioc->err.err_src); - if (!base) { - p7ioc_set_err_pending(ioc, false); - return false; - } - - /* IOC would be broken upon broken FIR */ - fir = in_be64(base + P7IOC_LEM_FIR_OFFSET); - if (fir == 0xffffffffffffffffUL) { - ioc->err.err_src = P7IOC_ERR_SRC_NONE; - ioc->err.err_class = P7IOC_ERR_CLASS_GXE; - goto err; - } - - /* Read on ERR_MASK and WOF. However, we needn't do for PHBn */ - wof = in_be64(base + P7IOC_LEM_WOF_OFFSET); - if (ioc->err.err_src >= P7IOC_ERR_SRC_PHB0 && - ioc->err.err_src <= P7IOC_ERR_SRC_PHB5) { - mask = 0x0ull; - } else { - mask = in_be64(base + P7IOC_LEM_ERR_MASK_OFFSET); - in_be64(base + P7IOC_LEM_ACTION_0_OFFSET); - in_be64(base + P7IOC_LEM_ACTION_1_OFFSET); - } - - /* - * We need process those unmasked error first. If we're - * failing to get the error bit, we needn't proceed. - */ - if (wof & ~mask) - wof &= ~mask; - if (!wof) { - p7ioc_set_err_pending(ioc, false); - return false; - } - - if (!p7ioc_err_bit(ioc, wof)) { - p7ioc_set_err_pending(ioc, false); - return false; - } - -err: - /* - * We run into here because of valid error. Those errors - * from CI Port{2, ..., 7} and PHB{0, ..., 5} will be cached - * to the specific PHB. However, we will cache the global - * errors (e.g. GXE) to IOC directly. For the left errors, - * they will be cached to IOC. - */ - if (((ioc->err.err_src >= P7IOC_ERR_SRC_CI_P2 && - ioc->err.err_src <= P7IOC_ERR_SRC_CI_P7) || - (ioc->err.err_src >= P7IOC_ERR_SRC_PHB0 && - ioc->err.err_src <= P7IOC_ERR_SRC_PHB5)) && - ioc->err.err_class != P7IOC_ERR_CLASS_GXE) { - index = (ioc->err.err_src >= P7IOC_ERR_SRC_PHB0 && - ioc->err.err_src <= P7IOC_ERR_SRC_PHB5) ? - (ioc->err.err_src - P7IOC_ERR_SRC_PHB0) : - (ioc->err.err_src - P7IOC_ERR_SRC_CI_P2); - p = &ioc->phbs[index]; - - if (p7ioc_phb_enabled(ioc, index)) { - p->err.err_src = ioc->err.err_src; - p->err.err_class = ioc->err.err_class; - p->err.err_bit = ioc->err.err_bit; - p7ioc_phb_set_err_pending(p, true); - p7ioc_set_err_pending(ioc, false); - - return false; - } - } - - /* - * Map the internal error class to that OS can recognize. - * Errors from PHB or the associated CI port would be - * GXE, PHB-fatal, ER, or INF. For the case, GXE will be - * cached to IOC and the left classes will be cached to - * the specific PHB. - */ - switch (ioc->err.err_class) { - case P7IOC_ERR_CLASS_GXE: - case P7IOC_ERR_CLASS_PLL: - case P7IOC_ERR_CLASS_RGA: - *pci_error_type = OPAL_EEH_IOC_ERROR; - *severity = OPAL_EEH_SEV_IOC_DEAD; - ret = true; - break; - case P7IOC_ERR_CLASS_INF: - case P7IOC_ERR_CLASS_MAL: - *pci_error_type = OPAL_EEH_IOC_ERROR; - *severity = OPAL_EEH_SEV_INF; - ret = false; - break; - default: - p7ioc_set_err_pending(ioc, false); - ret = false; - } - - return ret; -} - -/* - * Check GEM to see if there has any problematic components. - * The function is expected to be called in RGC interrupt - * handler. Also, it's notable that failure on reading on - * XFIR will cause GXE directly. - */ -static bool p7ioc_check_GEM(struct p7ioc *ioc) -{ - uint64_t xfir, rwof; - - /* - * Recov_5: Read GEM Xfir - * Recov_6: go to GXE recovery? - */ - xfir = in_be64(ioc->regs + P7IOC_GEM_XFIR); - if (xfir == 0xffffffffffffffffUL) { - ioc->err.err_src = P7IOC_ERR_SRC_NONE; - ioc->err.err_class = P7IOC_ERR_CLASS_GXE; - p7ioc_set_err_pending(ioc, true); - return true; - } - - /* - * Recov_7: Read GEM Rfir - * Recov_8: Read GEM RIRQfir - * Recov_9: Read GEM RWOF - * Recov_10: Read Fence Shadow - * Recov_11: Read Fence Shadow WOF - */ - in_be64(ioc->regs + P7IOC_GEM_RFIR); - in_be64(ioc->regs + P7IOC_GEM_RIRQFIR); - rwof = in_be64(ioc->regs + P7IOC_GEM_RWOF); - in_be64(ioc->regs + P7IOC_CHIP_FENCE_SHADOW); - in_be64(ioc->regs + P7IOC_CHIP_FENCE_WOF); - - /* - * Check GEM RWOF to see which component has been - * put into problematic state. - */ - ioc->err.err_src = P7IOC_ERR_SRC_NONE; - if (rwof & PPC_BIT(1)) ioc->err.err_src = P7IOC_ERR_SRC_RGC; - else if (rwof & PPC_BIT(2)) ioc->err.err_src = P7IOC_ERR_SRC_BI_UP; - else if (rwof & PPC_BIT(3)) ioc->err.err_src = P7IOC_ERR_SRC_BI_DOWN; - else if (rwof & PPC_BIT(4)) ioc->err.err_src = P7IOC_ERR_SRC_CI_P0; - else if (rwof & PPC_BIT(5)) ioc->err.err_src = P7IOC_ERR_SRC_CI_P1; - else if (rwof & PPC_BIT(6)) ioc->err.err_src = P7IOC_ERR_SRC_CI_P2; - else if (rwof & PPC_BIT(7)) ioc->err.err_src = P7IOC_ERR_SRC_CI_P3; - else if (rwof & PPC_BIT(8)) ioc->err.err_src = P7IOC_ERR_SRC_CI_P4; - else if (rwof & PPC_BIT(9)) ioc->err.err_src = P7IOC_ERR_SRC_CI_P5; - else if (rwof & PPC_BIT(10)) ioc->err.err_src = P7IOC_ERR_SRC_CI_P6; - else if (rwof & PPC_BIT(11)) ioc->err.err_src = P7IOC_ERR_SRC_CI_P7; - else if (rwof & PPC_BIT(16)) ioc->err.err_src = P7IOC_ERR_SRC_PHB0; - else if (rwof & PPC_BIT(17)) ioc->err.err_src = P7IOC_ERR_SRC_PHB1; - else if (rwof & PPC_BIT(18)) ioc->err.err_src = P7IOC_ERR_SRC_PHB2; - else if (rwof & PPC_BIT(19)) ioc->err.err_src = P7IOC_ERR_SRC_PHB3; - else if (rwof & PPC_BIT(20)) ioc->err.err_src = P7IOC_ERR_SRC_PHB4; - else if (rwof & PPC_BIT(21)) ioc->err.err_src = P7IOC_ERR_SRC_PHB5; - else if (rwof & PPC_BIT(24)) ioc->err.err_src = P7IOC_ERR_SRC_MISC; - else if (rwof & PPC_BIT(25)) ioc->err.err_src = P7IOC_ERR_SRC_I2C; - - /* - * If we detect any problematic components, the OS is - * expected to poll that for more details through OPAL - * interface. - */ - if (ioc->err.err_src != P7IOC_ERR_SRC_NONE) { - p7ioc_set_err_pending(ioc, true); - return true; - } - - return false; -} - -static void p7ioc_rgc_interrupt(struct irq_source *is, uint32_t isn) -{ - struct p7ioc *ioc = is->data; - - printf("Got RGC interrupt 0x%04x\n", isn); - - /* We will notify OS while getting error from GEM */ - if (p7ioc_check_GEM(ioc)) - /* This is a bit hacky but works - we raise the event - on a downstream phb as the OS needs to call - opal_pci_next_error for all phbs to ensure all events - are cleared anyway. */ - opal_pci_eeh_set_evt(ioc->phbs[0].phb.opal_id); -} - -static uint64_t p7ioc_rgc_irq_attributes(struct irq_source *is __unused, - uint32_t isn __unused) -{ - return IRQ_ATTR_TARGET_OPAL | IRQ_ATTR_TARGET_RARE | IRQ_ATTR_TYPE_LSI; -} - -static const struct irq_source_ops p7ioc_rgc_irq_ops = { - .get_xive = p7ioc_rgc_get_xive, - .set_xive = p7ioc_rgc_set_xive, - .attributes = p7ioc_rgc_irq_attributes, - .interrupt = p7ioc_rgc_interrupt, -}; - -static void p7ioc_create_hub(struct dt_node *np) -{ - struct p7ioc *ioc; - unsigned int i, id; - u64 bar1, bar2; - u32 pdt; - char *path; - - /* Use the BUID extension as ID and add it to device-tree */ - id = dt_prop_get_u32(np, "ibm,buid-ext"); - path = dt_get_path(np); - printf("P7IOC: Found at %s ID 0x%x\n", path, id); - free(path); - - /* Load VPD LID */ - vpd_preload(np); - vpd_iohub_load(np); - - ioc = zalloc(sizeof(struct p7ioc)); - if (!ioc) - return; - ioc->hub.hub_id = id; - ioc->hub.ops = &p7ioc_hub_ops; - ioc->dt_node = np; - - bar1 = dt_prop_get_u64(np, "ibm,gx-bar-1"); - bar2 = dt_prop_get_u64(np, "ibm,gx-bar-2"); - - ioc->regs = (void *)bar1; - - ioc->mmio1_win_start = bar1; - ioc->mmio1_win_size = MWIN1_SIZE; - ioc->mmio2_win_start = bar2; - ioc->mmio2_win_size = MWIN2_SIZE; - - ioc->buid_base = id << 9; - ioc->rgc_buid = ioc->buid_base + RGC_BUID_OFFSET; - - /* Add some DT properties */ - dt_add_property_cells(np, "ibm,opal-hubid", 0, id); - - /* XXX Fixme: how many RGC interrupts ? */ - dt_add_property_cells(np, "interrupt-parent", get_ics_phandle()); - dt_add_property_cells(np, "interrupts", ioc->rgc_buid << 4, 1); - dt_add_property_cells(np, "interrupt-base", ioc->rgc_buid << 4); - - /* XXX What about ibm,opal-mmio-real ? */ - - /* Clear the RGC XIVE cache */ - for (i = 0; i < 16; i++) - ioc->xive_cache[i] = SETFIELD(IODA_XIVT_PRIORITY, 0ull, 0xff); - - /* - * Register RGC interrupts - * - * For now I assume only 0 is... to verify with Greg or HW guys, - * we support all 16 - */ - register_irq_source(&p7ioc_rgc_irq_ops, ioc, ioc->rgc_buid << 4, 1); - - /* Check for presence detect from HDAT, we use only BR1 on P7IOC */ - pdt = dt_prop_get_u32_def(np, "ibm,br1-presence-detect", 0xffffffff); - if (pdt != 0xffffffff) - printf("P7IOC: Presence detect from HDAT : 0x%02x\n", pdt); - else { - } - ioc->phb_pdt = pdt & 0xff; - - /* Setup PHB structures (no HW access yet) */ - for (i = 0; i < P7IOC_NUM_PHBS; i++) { - if (p7ioc_phb_enabled(ioc, i)) - p7ioc_phb_setup(ioc, i); - } - - /* Now, we do the bulk of the inits */ - p7ioc_inits(ioc); - - printf("P7IOC: Initialization complete\n"); - - cec_register(&ioc->hub); -} - -void probe_p7ioc(void) -{ - struct dt_node *np; - - dt_for_each_compatible(dt_root, np, "ibm,p7ioc") - p7ioc_create_hub(np); -} - - - @@ -21,7 +21,6 @@ #include <psi.h> #include <fsp.h> #include <opal.h> -#include <gx.h> #include <interrupts.h> #include <cpu.h> #include <dio-p9.h> @@ -286,8 +285,7 @@ static void psi_spurious_fsp_irq(struct psi *psi) reg = PSIHB_XSCOM_P8_HBCSR_CLR; bit = PSIHB_XSCOM_P8_HBSCR_FSP_IRQ; } else { - reg = PSIHB_XSCOM_P7_HBCSR_CLR; - bit = PSIHB_XSCOM_P7_HBSCR_FSP_IRQ; + assert(false); } xscom_write(psi->chip_id, psi->xscom_base + reg, bit); } @@ -345,42 +343,6 @@ static void psihb_interrupt(struct irq_source *is, uint32_t isn __unused) fsp_console_poll(NULL); } -static int64_t psi_p7_set_xive(struct irq_source *is, uint32_t isn __unused, - uint16_t server, uint8_t priority) -{ - struct psi *psi = is->data; - uint64_t xivr; - - /* Populate the XIVR */ - xivr = (uint64_t)server << 40; - xivr |= (uint64_t)priority << 32; - xivr |= P7_IRQ_BUID(psi->interrupt) << 16; - - out_be64(psi->regs + PSIHB_XIVR, xivr); - - return OPAL_SUCCESS; -} - -static int64_t psi_p7_get_xive(struct irq_source *is, uint32_t isn __unused, - uint16_t *server, uint8_t *priority) -{ - struct psi *psi = is->data; - uint64_t xivr; - - /* Read & decode the XIVR */ - xivr = in_be64(psi->regs + PSIHB_XIVR); - - *server = (xivr >> 40) & 0x7ff; - *priority = (xivr >> 32) & 0xff; - - return OPAL_SUCCESS; -} - -static uint64_t psi_p7_irq_attributes(struct irq_source *is __unused, - uint32_t isn __unused) -{ - return IRQ_ATTR_TARGET_OPAL | IRQ_ATTR_TARGET_FREQUENT | IRQ_ATTR_TYPE_LSI; -} static const uint32_t psi_p8_irq_to_xivr[P8_IRQ_PSI_IRQ_COUNT] = { [P8_IRQ_PSI_FSP] = PSIHB_XIVR_FSP, @@ -429,14 +391,6 @@ void psi_irq_reset(void) } } -static const struct irq_source_ops psi_p7_irq_ops = { - .get_xive = psi_p7_get_xive, - .set_xive = psi_p7_set_xive, - .interrupt = psihb_interrupt, - .attributes = psi_p7_irq_attributes, -}; - - static int64_t psi_p8_set_xive(struct irq_source *is, uint32_t isn, uint16_t server, uint8_t priority) { @@ -679,9 +633,6 @@ static void psi_tce_enable(struct psi *psi, bool enable) u64 val; switch (proc_gen) { - case proc_gen_p7: - addr = psi->regs + PSIHB_CR; - break; case proc_gen_p8: case proc_gen_p9: addr = psi->regs + PSIHB_PHBSCR; @@ -715,10 +666,6 @@ void psi_init_for_fsp(struct psi *psi) psi_tce_enable(psi, false); switch (proc_gen) { - case proc_gen_p7: - out_be64(psi->regs + PSIHB_TAR, PSI_TCE_TABLE_BASE | - PSIHB_TAR_16K_ENTRIES); - break; case proc_gen_p8: case proc_gen_p9: out_be64(psi->regs + PSIHB_TAR, PSI_TCE_TABLE_BASE | @@ -762,20 +709,6 @@ void psi_set_external_irq_policy(bool policy) psi_ext_irq_policy = policy; } -static void psi_init_p7_interrupt(struct psi *psi) -{ - /* On P7, we get a single interrupt */ - out_be64(psi->regs + PSIHB_XIVR, - P7_IRQ_BUID(psi->interrupt) << 16 | - 0xffull << 32); - - /* Configure it in the GX controller as well */ - gx_configure_psi_buid(psi->chip_id, P7_IRQ_BUID(psi->interrupt)); - - /* Register the IRQ source */ - register_irq_source(&psi_p7_irq_ops, psi, psi->interrupt, 1); -} - static void psi_init_p8_interrupts(struct psi *psi) { uint32_t irq; @@ -852,9 +785,6 @@ static void psi_init_interrupts(struct psi *psi) { /* Configure the interrupt BUID and mask it */ switch (proc_gen) { - case proc_gen_p7: - psi_init_p7_interrupt(psi); - break; case proc_gen_p8: psi_init_p8_interrupts(psi); break; @@ -935,10 +865,6 @@ static void psi_create_mm_dtnode(struct psi *psi) /* Hard wire size to 4G */ dt_add_property_u64s(np, "reg", addr, 0x100000000ull); switch (proc_gen) { - case proc_gen_p7: - dt_add_property_strings(np, "compatible", "ibm,psi", - "ibm,power7-psi"); - break; case proc_gen_p8: dt_add_property_strings(np, "compatible", "ibm,psi", "ibm,power8-psi"); @@ -971,31 +897,6 @@ static struct psi *alloc_psi(struct proc_chip *chip, uint64_t base) return psi; } -static struct psi *psi_probe_p7(struct proc_chip *chip, u64 base) -{ - struct psi *psi = NULL; - uint64_t rc, val; - - rc = xscom_read(chip->id, base + PSIHB_XSCOM_P7_HBBAR, &val); - if (rc) { - prerror("PSI: Error %llx reading PSIHB BAR on chip %d\n", - rc, chip->id); - return NULL; - } - if (val & PSIHB_XSCOM_P7_HBBAR_EN) { - psi = alloc_psi(chip, base); - if (!psi) - return NULL; - rc = val >> 36; /* Bits 0:1 = 0x00; 2:27 Bridge BAR... */ - rc <<= 20; /* ... corresponds to bits 18:43 of base addr */ - psi->regs = (void *)rc; - psi->interrupt = get_psi_interrupt(chip->id); - } else - printf("PSI[0x%03x]: Working link not found\n", chip->id); - - return psi; -} - static struct psi *psi_probe_p8(struct proc_chip *chip, u64 base) { struct psi *psi = NULL; @@ -1050,9 +951,7 @@ static bool psi_init_psihb(struct dt_node *psihb) base = dt_get_address(psihb, 0, NULL); - if (dt_node_is_compatible(psihb, "ibm,power7-psihb-x")) - psi = psi_probe_p7(chip, base); - else if (dt_node_is_compatible(psihb, "ibm,power8-psihb-x")) + if (dt_node_is_compatible(psihb, "ibm,power8-psihb-x")) psi = psi_probe_p8(chip, base); else if (dt_node_is_compatible(psihb, "ibm,power9-psihb-x")) psi = psi_probe_p9(chip, base); @@ -384,7 +384,7 @@ struct cpu_idle_states { u32 flags; }; -static struct cpu_idle_states power7_cpu_idle_states[] = { +static struct cpu_idle_states nap_only_cpu_idle_states[] = { { /* nap */ .name = "nap", .latency_ns = 4000, @@ -843,8 +843,8 @@ void add_cpu_idle_state_properties(void) } } else { - states = power7_cpu_idle_states; - nr_states = ARRAY_SIZE(power7_cpu_idle_states); + states = nap_only_cpu_idle_states; + nr_states = ARRAY_SIZE(nap_only_cpu_idle_states); } @@ -756,14 +756,6 @@ static void xscom_init_chip_info(struct proc_chip *chip) /* Identify chip */ switch(val & 0xff) { - case 0xf9: - chip->type = PROC_CHIP_P7; - assert(proc_gen == proc_gen_p7); - break; - case 0xe8: - chip->type = PROC_CHIP_P7P; - assert(proc_gen == proc_gen_p7); - break; case 0xef: chip->type = PROC_CHIP_P8_MURANO; assert(proc_gen == proc_gen_p8); @@ -864,7 +856,7 @@ void xscom_init(void) struct proc_chip *chip; const char *chip_name; static const char *chip_names[] = { - "UNKNOWN", "P7", "P7+", "P8E", "P8", "P8NVL", "P9N", "P9C", "P9P" + "UNKNOWN", "P8E", "P8", "P8NVL", "P9N", "P9C", "P9P" }; chip = get_chip(gcid); |