Message ID | 1497356482-6731-4-git-send-email-clombard@linux.vnet.ibm.com |
---|---|
State | Accepted |
Headers | show |
Le 13/06/2017 à 14:21, Christophe Lombard a écrit : > Enable the Coherently attached processor interface. The PHB is used as > a CAPI interface. > CAPI Adapters can be connected to either PEC0 or PEC2. Single port > CAPI adapter can be connected to either PEC0 or PEC2, but Dual-Port > Adapter can be only connected to PEC2 > CAPP0 attached to PHB0(PEC0 - single port) > CAPP1 attached to PHB3(PEC2 - single or dual port) > As we did for PHB3, a new specific file 'phb4-capp.h' is created to > contain the CAPP register definitions. > > Signed-off-by: Christophe Lombard <clombard@linux.vnet.ibm.com> > --- Thanks for the modifications, looks ok to me. Reviewed-by: Frederic Barrat <fbarrat@linux.vnet.ibm.com> > hw/phb4.c | 359 +++++++++++++++++++++++++++++++++++++++++++++++++++- > include/chip.h | 1 + > include/opal-api.h | 1 + > include/phb4-capp.h | 60 +++++++++ > include/phb4-regs.h | 7 +- > 5 files changed, 422 insertions(+), 6 deletions(-) > create mode 100644 include/phb4-capp.h > > diff --git a/hw/phb4.c b/hw/phb4.c > index 3843456..5ea6138 100644 > --- a/hw/phb4.c > +++ b/hw/phb4.c > @@ -47,7 +47,7 @@ > #include <affinity.h> > #include <phb4.h> > #include <phb4-regs.h> > -#include <capp.h> > +#include <phb4-capp.h> > #include <fsp.h> > #include <chip.h> > #include <chiptod.h> > @@ -77,6 +77,11 @@ static void phb4_init_hw(struct phb4 *p, bool first_init); > #define PHBLOGCFG(p, fmt, a...) do {} while (0) > #endif > > +enum capi_dma_tvt { > + CAPI_DMA_TVT0, > + CAPI_DMA_TVT1, > +}; > + > /* Note: The "ASB" name is historical, practically this means access via > * the XSCOM backdoor > */ > @@ -2111,6 +2116,8 @@ static int64_t phb4_freset(struct pci_slot *slot) > return OPAL_HARDWARE; > } > > +extern struct lock capi_lock; > + > static int64_t phb4_creset(struct pci_slot *slot) > { > struct phb4 *p = phb_to_phb4(slot->phb); > @@ -2509,6 +2516,344 @@ static int64_t phb4_get_diag_data(struct phb *phb, > return OPAL_SUCCESS; > } > > +static uint64_t tve_encode_50b_noxlate(uint64_t start_addr, uint64_t end_addr) > +{ > + uint64_t tve; > + > + /* > + * Put start address bits 49:24 into TVE[52:53]||[0:23] > + * and end address bits 49:24 into TVE[54:55]||[24:47] > + * and set TVE[51] > + */ > + tve = (start_addr << 16) & (0xffffffull << 40); > + tve |= (start_addr >> 38) & (3ull << 10); > + tve |= (end_addr >> 8) & (0xfffffful << 16); > + tve |= (end_addr >> 40) & (3ull << 8); > + tve |= PPC_BIT(51) | IODA3_TVT_NON_TRANSLATE_50; > + return tve; > +} > + > +static void phb4_init_capp_regs(struct phb4 *p) > +{ > + uint64_t reg; > + uint32_t offset; > + > + offset = PHB4_CAPP_REG_OFFSET(p); > + > + /* Enable cresp examination by CAPP */ > + xscom_read(p->chip_id, APC_MASTER_PB_CTRL + offset, ®); > + reg |= PPC_BIT(0); > + if (p->rev == PHB4_REV_NIMBUS_DD10) { > + reg |= PPC_BIT(1); > + /* disable vg not sys */ > + reg |= PPC_BIT(3); > + } > + xscom_write(p->chip_id, APC_MASTER_PB_CTRL + offset, reg); > + > + /* Set PHB mode, HPC Dir State and P9 mode */ > + xscom_write(p->chip_id, APC_MASTER_CAPI_CTRL + offset, > + 0x1772000000000000); > + PHBINF(p, "CAPP: port attached\n"); > + > + /* Set snoop ttype decoding , dir size to 256k */ > + xscom_write(p->chip_id, SNOOP_CAPI_CONFIG + offset, 0xA000000000000000); > + > + /* Use Read Epsilon Tier2 for all scopes, Address Pipeline Master > + * Wait Count to highest(1023) and Number of rpt_hang.data to 3 > + */ > + xscom_write(p->chip_id, SNOOP_CONTROL + offset, 0x8000000010072000); > + > + /* TLBI Hang Divider = 16. CI Store Buffer Threshold initialized > + * to b’0101’ = use 6 buffers. X16 PCIe(14 buffers) > + */ > + xscom_read(p->chip_id, TRANSPORT_CONTROL + offset, ®); > + if (!(reg & PPC_BIT(4))) { > + if (p->index == CAPP0_PHB_INDEX) > + xscom_write(p->chip_id, TRANSPORT_CONTROL + offset, > + 0x081400000000000A); > + > + if (p->index == CAPP1_PHB_INDEX) > + xscom_write(p->chip_id, TRANSPORT_CONTROL + offset, > + 0x0814000000000008); > + > + /* Initialize CI Store Buffers */ > + xscom_read(p->chip_id, TRANSPORT_CONTROL + offset, ®); > + reg |= PPC_BIT(63); > + xscom_write(p->chip_id, TRANSPORT_CONTROL + offset, reg); > + } > + > + /* Enable epoch timer */ > + xscom_write(p->chip_id, EPOCH_RECOVERY_TIMERS_CTRL + offset, > + 0xC0000000FFF0FFFE); > + > + xscom_write(p->chip_id, FLUSH_SUE_STATE_MAP + offset, > + 0x1DCF5F6600000000); > + xscom_write(p->chip_id, FLUSH_SUE_UOP1 + offset, 0xE310280428000000); > + > + /* capp owns PHB read buffers */ > + if (p->index == CAPP0_PHB_INDEX) { > + xscom_write(p->chip_id, APC_FSM_READ_MASK + offset, > + 0xFFFFFFFFFFFF0000); > + xscom_write(p->chip_id, XPT_FSM_RMM + offset, > + 0xFFFFFFFFFFFF0000); > + } > + if (p->index == CAPP1_PHB_INDEX) { > + xscom_write(p->chip_id, APC_FSM_READ_MASK + offset, > + 0xFFFFFFFE00000000); > + xscom_write(p->chip_id, XPT_FSM_RMM + offset, > + 0xFFFFFFFE00000000); > + } > + > + /* Deassert TLBI_FENCED and tlbi_psl_is_dead */ > + xscom_write(p->chip_id, CAPP_ERR_STATUS_CTRL + offset, 0); > +} > + > +/* override some inits with CAPI defaults */ > +static void phb4_init_capp_errors(struct phb4 *p) > +{ > + /* Init_77: TXE Error AIB Fence Enable Register */ > + out_be64(p->regs + 0x0d30, 0xdff7ff0bf7ddfff0ull); > + > + /* Init_86: RXE_ARB Error AIB Fence Enable Register */ > + out_be64(p->regs + 0x0db0, 0xfbffd7bbff7fbfefull); > + > + /* Init_95: RXE_MRG Error AIB Fence Enable Register */ > + out_be64(p->regs + 0x0e30, 0xfffffeffff7fff57ull); > + > + /* Init_104: RXE_TCE Error AIB Fence Enable Register */ > + out_be64(p->regs + 0x0eb0, 0xffaeffafffffffffull); > + > + /* Init_113: PHB Error AIB Fence Enable Register */ > + out_be64(p->regs + 0x0cb0, 0x35777073ff000000ull); > +} > + > +/* Power Bus Common Queue Registers > + * All PBCQ and PBAIB registers are accessed via SCOM > + * NestBase = 4010C00 for PEC0 > + * 4011000 for PEC1 > + * 4011400 for PEC2 > + * > + * Some registers are shared amongst all of the stacks and will only > + * have 1 copy. Other registers are implemented one per stack. > + * Registers that are duplicated will have an additional offset > + * of “StackBase” so that they have a unique address. > + * Stackoffset = 00000040 for Stack0 > + * = 00000080 for Stack1 > + * = 000000C0 for Stack2 > + */ > +static int64_t enable_capi_mode(struct phb4 *p, uint64_t pe_number, > + enum capi_dma_tvt dma_tvt) > +{ > + uint64_t reg, start_addr, end_addr; > + uint32_t offset; > + int i; > + > + xscom_read(p->chip_id, p->pe_xscom + 0x7, ®); > + if (reg & PPC_BIT(0)) > + PHBDBG(p, "Already in CAPP mode\n"); > + > + /* PEC Phase 3 (PBCQ) registers Init */ > + /* poll cqstat > + * CAPP0 attached to PHB0(PEC0) > + * CAPP1 attached to PHB3(PEC2) > + */ > + if (p->index == 0) { > + /* PEC 0 */ > + offset = 0x40; > + } else if (p->index == 1 || p->index == 2) { > + /* PEC 1 */ > + offset = 0x80; > + } else { > + /* PEC 2 */ > + offset = 0xC0; > + } > + > + for (i = 0; i < 500000; i++) { > + xscom_read(p->chip_id, p->pe_xscom + offset + 0xC, ®); > + if (!(reg & 0xC000000000000000)) > + break; > + time_wait_us(10); > + } > + if (reg & 0xC000000000000000) { > + PHBERR(p, "CAPP: Timeout waiting for pending transaction\n"); > + return OPAL_HARDWARE; > + } > + > + /* Enable CAPP Mode , Set 14 CI Store buffers for CAPP, > + * Set 48 Read machines for CAPP. > + */ > + if (p->index == CAPP0_PHB_INDEX) > + reg = 0x800EFFFFFFFFFFFF; > + > + if (p->index == CAPP1_PHB_INDEX) > + reg = 0x8006FFFFFFFE0000; > + xscom_write(p->chip_id, p->pe_xscom + 0x7, reg); > + > + if (p->rev == PHB4_REV_NIMBUS_DD10) { > + /* Ignores the PB init signal */ > + xscom_read(p->chip_id, p->pe_xscom + 0x0, ®); > + reg |= PPC_BIT(12); > + xscom_write(p->chip_id, p->pe_xscom + 0x0, reg); > + } > + > + /* PEC Phase 4 (PHB) registers adjustment > + * Bit [0:7] XSL_DSNCTL[capiind] > + * Init_25 - CAPI Compare/Mask > + */ > + out_be64(p->regs + PHB_CAPI_CMPM, > + 0x0200FE0000000000Ull | PHB_CAPI_CMPM_ENABLE); > + > + if (!(p->rev == PHB4_REV_NIMBUS_DD10)) { > + /* Init_123 : NBW Compare/Mask Register */ > + out_be64(p->regs + PHB_PBL_NBW_CMP_MASK, > + 0x0300FF0000000000Ull | PHB_PBL_NBW_MASK_ENABLE); > + > + /* Init_24 - ASN Compare/Mask */ > + out_be64(p->regs + PHB_PBL_ASN_CMPM, > + 0x0400FF0000000000Ull | PHB_PBL_ASN_ENABLE); > + } > + > + /* non-translate/50-bit mode */ > + out_be64(p->regs + PHB_NXLATE_PREFIX, 0x0000000000000000Ull); > + > + /* set tve no translate mode allow mmio window */ > + memset(p->tve_cache, 0x0, sizeof(p->tve_cache)); > + > + /* > + * In 50-bit non-translate mode, the fields of the TVE are > + * used to perform an address range check. In this mode TCE > + * Table Size(0) must be a '1' (TVE[51] = 1) > + * PCI Addr(49:24) >= TVE[52:53]+TVE[0:23] and > + * PCI Addr(49:24) < TVE[54:55]+TVE[24:47] > + * > + * TVE[51] = 1 > + * TVE[56] = 1: 50-bit Non-Translate Mode Enable > + * TVE[0:23] = 0x000000 > + * TVE[24:47] = 0xFFFFFF > + * > + * capi dma mode: CAPP DMA mode needs access to all of memory > + * capi mode: Allow address range (bit 14 = 1) > + * 0x0002000000000000: 0x0002FFFFFFFFFFFF > + * TVE[52:53] = '10' and TVE[54:55] = '10' > + */ > + > + /* TVT#0: CAPI window + DMA, all memory */ > + start_addr = 0ull; > + end_addr = 0x0003ffffffffffffull; > + p->tve_cache[pe_number * 2] = > + tve_encode_50b_noxlate(start_addr, end_addr); > + > + /* TVT#1: DMA, all memory, in bypass mode */ > + if (dma_tvt == CAPI_DMA_TVT1) { > + start_addr = (1ull << 59); > + end_addr = start_addr + 0x0003ffffffffffffull; > + p->tve_cache[pe_number * 2 + 1] = > + tve_encode_50b_noxlate(start_addr, end_addr); > + } > + > + phb4_ioda_sel(p, IODA3_TBL_TVT, 0, true); > + for (i = 0; i < p->tvt_size; i++) > + out_be64(p->regs + PHB_IODA_DATA0, p->tve_cache[i]); > + > + /* set mbt bar to pass capi mmio window. First applied cleared > + * values to HW > + */ > + for (i = 0; i < p->mbt_size; i++) { > + p->mbt_cache[i][0] = 0; > + p->mbt_cache[i][1] = 0; > + } > + phb4_ioda_sel(p, IODA3_TBL_MBT, 0, true); > + for (i = 0; i < p->mbt_size; i++) { > + out_be64(p->regs + PHB_IODA_DATA0, p->mbt_cache[i][0]); > + out_be64(p->regs + PHB_IODA_DATA0, p->mbt_cache[i][1]); > + } > + > + p->mbt_cache[0][0] = IODA3_MBT0_ENABLE | > + IODA3_MBT0_TYPE_M64 | > + SETFIELD(IODA3_MBT0_MODE, 0ull, IODA3_MBT0_MODE_SINGLE_PE) | > + SETFIELD(IODA3_MBT0_MDT_COLUMN, 0ull, 0) | > + (p->mm0_base & IODA3_MBT0_BASE_ADDR); > + p->mbt_cache[0][1] = IODA3_MBT1_ENABLE | > + ((~(p->mm0_size - 1)) & IODA3_MBT1_MASK) | > + SETFIELD(IODA3_MBT1_SINGLE_PE_NUM, 0ull, pe_number); > + > + p->mbt_cache[1][0] = IODA3_MBT0_ENABLE | > + IODA3_MBT0_TYPE_M64 | > + SETFIELD(IODA3_MBT0_MODE, 0ull, IODA3_MBT0_MODE_SINGLE_PE) | > + SETFIELD(IODA3_MBT0_MDT_COLUMN, 0ull, 0) | > + (0x0002000000000000ULL & IODA3_MBT0_BASE_ADDR); > + p->mbt_cache[1][1] = IODA3_MBT1_ENABLE | > + (0x00ff000000000000ULL & IODA3_MBT1_MASK) | > + SETFIELD(IODA3_MBT1_SINGLE_PE_NUM, 0ull, pe_number); > + > + phb4_ioda_sel(p, IODA3_TBL_MBT, 0, true); > + for (i = 0; i < p->mbt_size; i++) { > + out_be64(p->regs + PHB_IODA_DATA0, p->mbt_cache[i][0]); > + out_be64(p->regs + PHB_IODA_DATA0, p->mbt_cache[i][1]); > + } > + > + phb4_init_capp_errors(p); > + > + phb4_init_capp_regs(p); > + > + if (!chiptod_capp_timebase_sync(p->chip_id, CAPP_TFMR, > + CAPP_TB, > + PHB4_CAPP_REG_OFFSET(p))) { > + PHBERR(p, "CAPP: Failed to sync timebase\n"); > + return OPAL_HARDWARE; > + } > + return OPAL_SUCCESS; > +} > + > +static int64_t phb4_set_capi_mode(struct phb *phb, uint64_t mode, > + uint64_t pe_number) > +{ > + struct phb4 *p = phb_to_phb4(phb); > + struct proc_chip *chip = get_chip(p->chip_id); > + uint64_t reg; > + uint32_t offset; > + > + > + lock(&capi_lock); > + chip->capp_phb4_attached_mask |= 1 << p->index; > + unlock(&capi_lock); > + > + offset = PHB4_CAPP_REG_OFFSET(p); > + xscom_read(p->chip_id, CAPP_ERR_STATUS_CTRL + offset, ®); > + if ((reg & PPC_BIT(5))) { > + PHBERR(p, "CAPP: recovery failed (%016llx)\n", reg); > + return OPAL_HARDWARE; > + } else if ((reg & PPC_BIT(0)) && (!(reg & PPC_BIT(1)))) { > + PHBDBG(p, "CAPP: recovery in progress\n"); > + return OPAL_BUSY; > + } > + > + switch (mode) { > + case OPAL_PHB_CAPI_MODE_PCIE: > + return OPAL_UNSUPPORTED; > + > + case OPAL_PHB_CAPI_MODE_CAPI: > + return enable_capi_mode(p, pe_number, CAPI_DMA_TVT0); > + > + case OPAL_PHB_CAPI_MODE_DMA: > + /* shouldn't be called, enabled by default on p9 */ > + return OPAL_UNSUPPORTED; > + > + case OPAL_PHB_CAPI_MODE_DMA_TVT1: > + return enable_capi_mode(p, pe_number, CAPI_DMA_TVT1); > + > + case OPAL_PHB_CAPI_MODE_SNOOP_OFF: > + /* shouldn't be called */ > + return OPAL_UNSUPPORTED; > + > + case OPAL_PHB_CAPI_MODE_SNOOP_ON: > + /* nothing to do */ > + return OPAL_SUCCESS; > + } > + > + return OPAL_UNSUPPORTED; > +} > + > static const struct phb_ops phb4_ops = { > .cfg_read8 = phb4_pcicfg_read8, > .cfg_read16 = phb4_pcicfg_read16, > @@ -2541,6 +2886,7 @@ static const struct phb_ops phb4_ops = { > .get_diag_data = NULL, > .get_diag_data2 = phb4_get_diag_data, > .tce_kill = phb4_tce_kill, > + .set_capi_mode = phb4_set_capi_mode, > }; > > static void phb4_init_ioda3(struct phb4 *p) > @@ -2572,13 +2918,13 @@ static void phb4_init_ioda3(struct phb4 *p) > p->tbl_pest | PHB_PEST_BAR_ENABLE); > > /* Init_23 - CRW Base Address Reg */ > - // XXX FIXME learn CAPI :-( > + /* See enable_capi_mode() */ > > /* Init_24 - ASN Compare/Mask */ > - // XXX FIXME learn CAPI :-( > + /* See enable_capi_mode() */ > > /* Init_25 - CAPI Compare/Mask */ > - // XXX FIXME learn CAPI :-( > + /* See enable_capi_mode() */ > > /* Init_26 - PCIE Outbound upper address */ > out_be64(p->regs + PHB_M64_UPPER_BITS, 0); > @@ -2883,7 +3229,7 @@ static void phb4_init_hw(struct phb4 *p, bool first_init) > */ > > /* Init_123 : NBW. XXX TODO */ > - // XXX FIXME learn CAPI :-( > + /* See enable_capi_mode() */ > > /* Init_124 : Setup PCI command/status on root complex > * I don't know why the spec does this now and not earlier, so > @@ -3104,6 +3450,9 @@ static void phb4_add_properties(struct phb4 *p) > > dt_add_property_cells(np, "ibm,phb-diag-data-size", > sizeof(struct OpalIoPhb4ErrorData)); > + > + /* Indicate to Linux that CAPP timebase sync is supported */ > + dt_add_property_string(np, "ibm,capp-timebase-sync", NULL); > } > > static bool phb4_calculate_windows(struct phb4 *p) > diff --git a/include/chip.h b/include/chip.h > index b957e45..17f062b 100644 > --- a/include/chip.h > +++ b/include/chip.h > @@ -191,6 +191,7 @@ struct proc_chip { > > /* Must hold capi_lock to change */ > uint8_t capp_phb3_attached_mask; > + uint8_t capp_phb4_attached_mask; > uint8_t capp_ucode_loaded; > > /* Used by hw/centaur.c */ > diff --git a/include/opal-api.h b/include/opal-api.h > index 37af5f7..2713490 100644 > --- a/include/opal-api.h > +++ b/include/opal-api.h > @@ -1144,6 +1144,7 @@ enum { > OPAL_PHB_CAPI_MODE_SNOOP_OFF = 2, > OPAL_PHB_CAPI_MODE_SNOOP_ON = 3, > OPAL_PHB_CAPI_MODE_DMA = 4, > + OPAL_PHB_CAPI_MODE_DMA_TVT1 = 5, > }; > > /* CAPI feature flags (in device-tree) */ > diff --git a/include/phb4-capp.h b/include/phb4-capp.h > new file mode 100644 > index 0000000..89de034 > --- /dev/null > +++ b/include/phb4-capp.h > @@ -0,0 +1,60 @@ > +/* Copyright 2013-2017 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. > + */ > + > +#ifndef __PHB4_CAPP_H > +#define __PHB4_CAPP_H > + > +#define CAPP_SNP_ARRAY_WRITE_REG 0x2010841 /* Satellite 2 */ > +#define CAPP_SNP_ARRAY_ADDR_REG 0x2010828 > +#define CAPP_APC_MASTER_ARRAY_ADDR_REG 0x201082A > +#define CAPP_APC_MASTER_ARRAY_WRITE_REG 0x2010842 /* Satellite 2 */ > + > +#define CAPP_FIR 0x2010800 > +#define CAPP_ERR_RPT_CLR 0x2010813 > +#define APC_MASTER_PB_CTRL 0x2010818 > +#define APC_MASTER_CAPI_CTRL 0x2010819 > +#define LCO_MASTER_TARGET 0x2010821 > +#define EPOCH_RECOVERY_TIMERS_CTRL 0x201082C > +#define SNOOP_CAPI_CONFIG 0x201081A > +#define SNOOP_CONTROL 0x201081B > +#define TRANSPORT_CONTROL 0x201081C > +#define CAPP_TB 0x2010826 > +#define CAPP_TFMR 0x2010827 > +#define CAPP_ERR_STATUS_CTRL 0x201080E > +#define FLUSH_SUE_STATE_MAP 0x201080F > +#define FLUSH_CPIG_STATE_MAP 0x2010820 > +#define FLUSH_SUE_UOP1 0x2010843 /* Satellite 2 */ > +#define APC_FSM_READ_MASK 0x2010823 > +#define XPT_FSM_RMM 0x2010831 > + > +/* CAPP0 attached to PHB0(PEC0 - single port) > + * CAPP1 attached to PHB3(PEC2 - single or dual port) > + */ > +#define CAPP0_PHB_INDEX 0 > +#define CAPP1_PHB_INDEX 3 > + > +/* SCOM address Base (Ring = ‘0010’b) > + * CAPP Unit Satellite SCOM address Base > + * CAPP 0 S1 (sat = ‘0000’b) x02010800 > + * CAPP 0 S2 (sat = ‘0001’b) x02010840 > + * CAPP 1 S1 (sat = ‘0000’b) x04010800 > + * CAPP 1 S2 (sat = ‘0001’b) x04010840 > + */ > +#define CAPP1_REG_OFFSET 0x2000000 > + > +#define PHB4_CAPP_REG_OFFSET(p) ((p)->index == 0 ? 0x0 : CAPP1_REG_OFFSET) > + > +#endif /* __PHB4_CAPP_H */ > diff --git a/include/phb4-regs.h b/include/phb4-regs.h > index 92bee88..5ec47a5 100644 > --- a/include/phb4-regs.h > +++ b/include/phb4-regs.h > @@ -71,8 +71,12 @@ > #define PHB_PEST_BAR 0x1a8 > #define PHB_PEST_BAR_ENABLE PPC_BIT(0) > #define PHB_PEST_BASE_ADDRESS PPC_BITMASK(8,51) > +#define PHB_PBL_ASN_CMPM 0x1C0 > +#define PHB_PBL_ASN_ENABLE PPC_BIT(63) > +#define PHB_CAPI_CMPM 0x1C8 > +#define PHB_CAPI_CMPM_ENABLE PPC_BIT(63) > #define PHB_M64_UPPER_BITS 0x1f0 > -#define PHB_INTREP_TIMER 0x1f8 > +#define PHB_NXLATE_PREFIX 0x1f8 > #define PHB_DMARD_SYNC 0x200 > #define PHB_DMARD_SYNC_START PPC_BIT(0) > #define PHB_DMARD_SYNC_COMPLETE PPC_BIT(1) > @@ -242,6 +246,7 @@ > #define PHB_PBL_TIMEOUT_CTRL 0x1810 > #define PHB_PBL_NPTAG_ENABLE 0x1820 > #define PHB_PBL_NBW_CMP_MASK 0x1830 > +#define PHB_PBL_NBW_MASK_ENABLE PPC_BIT(63) > #define PHB_PBL_SYS_LINK_INIT 0x1838 > #define PHB_PBL_BUF_STATUS 0x1840 > #define PHB_PBL_ERR_STATUS 0x1900 >
diff --git a/hw/phb4.c b/hw/phb4.c index 3843456..5ea6138 100644 --- a/hw/phb4.c +++ b/hw/phb4.c @@ -47,7 +47,7 @@ #include <affinity.h> #include <phb4.h> #include <phb4-regs.h> -#include <capp.h> +#include <phb4-capp.h> #include <fsp.h> #include <chip.h> #include <chiptod.h> @@ -77,6 +77,11 @@ static void phb4_init_hw(struct phb4 *p, bool first_init); #define PHBLOGCFG(p, fmt, a...) do {} while (0) #endif +enum capi_dma_tvt { + CAPI_DMA_TVT0, + CAPI_DMA_TVT1, +}; + /* Note: The "ASB" name is historical, practically this means access via * the XSCOM backdoor */ @@ -2111,6 +2116,8 @@ static int64_t phb4_freset(struct pci_slot *slot) return OPAL_HARDWARE; } +extern struct lock capi_lock; + static int64_t phb4_creset(struct pci_slot *slot) { struct phb4 *p = phb_to_phb4(slot->phb); @@ -2509,6 +2516,344 @@ static int64_t phb4_get_diag_data(struct phb *phb, return OPAL_SUCCESS; } +static uint64_t tve_encode_50b_noxlate(uint64_t start_addr, uint64_t end_addr) +{ + uint64_t tve; + + /* + * Put start address bits 49:24 into TVE[52:53]||[0:23] + * and end address bits 49:24 into TVE[54:55]||[24:47] + * and set TVE[51] + */ + tve = (start_addr << 16) & (0xffffffull << 40); + tve |= (start_addr >> 38) & (3ull << 10); + tve |= (end_addr >> 8) & (0xfffffful << 16); + tve |= (end_addr >> 40) & (3ull << 8); + tve |= PPC_BIT(51) | IODA3_TVT_NON_TRANSLATE_50; + return tve; +} + +static void phb4_init_capp_regs(struct phb4 *p) +{ + uint64_t reg; + uint32_t offset; + + offset = PHB4_CAPP_REG_OFFSET(p); + + /* Enable cresp examination by CAPP */ + xscom_read(p->chip_id, APC_MASTER_PB_CTRL + offset, ®); + reg |= PPC_BIT(0); + if (p->rev == PHB4_REV_NIMBUS_DD10) { + reg |= PPC_BIT(1); + /* disable vg not sys */ + reg |= PPC_BIT(3); + } + xscom_write(p->chip_id, APC_MASTER_PB_CTRL + offset, reg); + + /* Set PHB mode, HPC Dir State and P9 mode */ + xscom_write(p->chip_id, APC_MASTER_CAPI_CTRL + offset, + 0x1772000000000000); + PHBINF(p, "CAPP: port attached\n"); + + /* Set snoop ttype decoding , dir size to 256k */ + xscom_write(p->chip_id, SNOOP_CAPI_CONFIG + offset, 0xA000000000000000); + + /* Use Read Epsilon Tier2 for all scopes, Address Pipeline Master + * Wait Count to highest(1023) and Number of rpt_hang.data to 3 + */ + xscom_write(p->chip_id, SNOOP_CONTROL + offset, 0x8000000010072000); + + /* TLBI Hang Divider = 16. CI Store Buffer Threshold initialized + * to b’0101’ = use 6 buffers. X16 PCIe(14 buffers) + */ + xscom_read(p->chip_id, TRANSPORT_CONTROL + offset, ®); + if (!(reg & PPC_BIT(4))) { + if (p->index == CAPP0_PHB_INDEX) + xscom_write(p->chip_id, TRANSPORT_CONTROL + offset, + 0x081400000000000A); + + if (p->index == CAPP1_PHB_INDEX) + xscom_write(p->chip_id, TRANSPORT_CONTROL + offset, + 0x0814000000000008); + + /* Initialize CI Store Buffers */ + xscom_read(p->chip_id, TRANSPORT_CONTROL + offset, ®); + reg |= PPC_BIT(63); + xscom_write(p->chip_id, TRANSPORT_CONTROL + offset, reg); + } + + /* Enable epoch timer */ + xscom_write(p->chip_id, EPOCH_RECOVERY_TIMERS_CTRL + offset, + 0xC0000000FFF0FFFE); + + xscom_write(p->chip_id, FLUSH_SUE_STATE_MAP + offset, + 0x1DCF5F6600000000); + xscom_write(p->chip_id, FLUSH_SUE_UOP1 + offset, 0xE310280428000000); + + /* capp owns PHB read buffers */ + if (p->index == CAPP0_PHB_INDEX) { + xscom_write(p->chip_id, APC_FSM_READ_MASK + offset, + 0xFFFFFFFFFFFF0000); + xscom_write(p->chip_id, XPT_FSM_RMM + offset, + 0xFFFFFFFFFFFF0000); + } + if (p->index == CAPP1_PHB_INDEX) { + xscom_write(p->chip_id, APC_FSM_READ_MASK + offset, + 0xFFFFFFFE00000000); + xscom_write(p->chip_id, XPT_FSM_RMM + offset, + 0xFFFFFFFE00000000); + } + + /* Deassert TLBI_FENCED and tlbi_psl_is_dead */ + xscom_write(p->chip_id, CAPP_ERR_STATUS_CTRL + offset, 0); +} + +/* override some inits with CAPI defaults */ +static void phb4_init_capp_errors(struct phb4 *p) +{ + /* Init_77: TXE Error AIB Fence Enable Register */ + out_be64(p->regs + 0x0d30, 0xdff7ff0bf7ddfff0ull); + + /* Init_86: RXE_ARB Error AIB Fence Enable Register */ + out_be64(p->regs + 0x0db0, 0xfbffd7bbff7fbfefull); + + /* Init_95: RXE_MRG Error AIB Fence Enable Register */ + out_be64(p->regs + 0x0e30, 0xfffffeffff7fff57ull); + + /* Init_104: RXE_TCE Error AIB Fence Enable Register */ + out_be64(p->regs + 0x0eb0, 0xffaeffafffffffffull); + + /* Init_113: PHB Error AIB Fence Enable Register */ + out_be64(p->regs + 0x0cb0, 0x35777073ff000000ull); +} + +/* Power Bus Common Queue Registers + * All PBCQ and PBAIB registers are accessed via SCOM + * NestBase = 4010C00 for PEC0 + * 4011000 for PEC1 + * 4011400 for PEC2 + * + * Some registers are shared amongst all of the stacks and will only + * have 1 copy. Other registers are implemented one per stack. + * Registers that are duplicated will have an additional offset + * of “StackBase” so that they have a unique address. + * Stackoffset = 00000040 for Stack0 + * = 00000080 for Stack1 + * = 000000C0 for Stack2 + */ +static int64_t enable_capi_mode(struct phb4 *p, uint64_t pe_number, + enum capi_dma_tvt dma_tvt) +{ + uint64_t reg, start_addr, end_addr; + uint32_t offset; + int i; + + xscom_read(p->chip_id, p->pe_xscom + 0x7, ®); + if (reg & PPC_BIT(0)) + PHBDBG(p, "Already in CAPP mode\n"); + + /* PEC Phase 3 (PBCQ) registers Init */ + /* poll cqstat + * CAPP0 attached to PHB0(PEC0) + * CAPP1 attached to PHB3(PEC2) + */ + if (p->index == 0) { + /* PEC 0 */ + offset = 0x40; + } else if (p->index == 1 || p->index == 2) { + /* PEC 1 */ + offset = 0x80; + } else { + /* PEC 2 */ + offset = 0xC0; + } + + for (i = 0; i < 500000; i++) { + xscom_read(p->chip_id, p->pe_xscom + offset + 0xC, ®); + if (!(reg & 0xC000000000000000)) + break; + time_wait_us(10); + } + if (reg & 0xC000000000000000) { + PHBERR(p, "CAPP: Timeout waiting for pending transaction\n"); + return OPAL_HARDWARE; + } + + /* Enable CAPP Mode , Set 14 CI Store buffers for CAPP, + * Set 48 Read machines for CAPP. + */ + if (p->index == CAPP0_PHB_INDEX) + reg = 0x800EFFFFFFFFFFFF; + + if (p->index == CAPP1_PHB_INDEX) + reg = 0x8006FFFFFFFE0000; + xscom_write(p->chip_id, p->pe_xscom + 0x7, reg); + + if (p->rev == PHB4_REV_NIMBUS_DD10) { + /* Ignores the PB init signal */ + xscom_read(p->chip_id, p->pe_xscom + 0x0, ®); + reg |= PPC_BIT(12); + xscom_write(p->chip_id, p->pe_xscom + 0x0, reg); + } + + /* PEC Phase 4 (PHB) registers adjustment + * Bit [0:7] XSL_DSNCTL[capiind] + * Init_25 - CAPI Compare/Mask + */ + out_be64(p->regs + PHB_CAPI_CMPM, + 0x0200FE0000000000Ull | PHB_CAPI_CMPM_ENABLE); + + if (!(p->rev == PHB4_REV_NIMBUS_DD10)) { + /* Init_123 : NBW Compare/Mask Register */ + out_be64(p->regs + PHB_PBL_NBW_CMP_MASK, + 0x0300FF0000000000Ull | PHB_PBL_NBW_MASK_ENABLE); + + /* Init_24 - ASN Compare/Mask */ + out_be64(p->regs + PHB_PBL_ASN_CMPM, + 0x0400FF0000000000Ull | PHB_PBL_ASN_ENABLE); + } + + /* non-translate/50-bit mode */ + out_be64(p->regs + PHB_NXLATE_PREFIX, 0x0000000000000000Ull); + + /* set tve no translate mode allow mmio window */ + memset(p->tve_cache, 0x0, sizeof(p->tve_cache)); + + /* + * In 50-bit non-translate mode, the fields of the TVE are + * used to perform an address range check. In this mode TCE + * Table Size(0) must be a '1' (TVE[51] = 1) + * PCI Addr(49:24) >= TVE[52:53]+TVE[0:23] and + * PCI Addr(49:24) < TVE[54:55]+TVE[24:47] + * + * TVE[51] = 1 + * TVE[56] = 1: 50-bit Non-Translate Mode Enable + * TVE[0:23] = 0x000000 + * TVE[24:47] = 0xFFFFFF + * + * capi dma mode: CAPP DMA mode needs access to all of memory + * capi mode: Allow address range (bit 14 = 1) + * 0x0002000000000000: 0x0002FFFFFFFFFFFF + * TVE[52:53] = '10' and TVE[54:55] = '10' + */ + + /* TVT#0: CAPI window + DMA, all memory */ + start_addr = 0ull; + end_addr = 0x0003ffffffffffffull; + p->tve_cache[pe_number * 2] = + tve_encode_50b_noxlate(start_addr, end_addr); + + /* TVT#1: DMA, all memory, in bypass mode */ + if (dma_tvt == CAPI_DMA_TVT1) { + start_addr = (1ull << 59); + end_addr = start_addr + 0x0003ffffffffffffull; + p->tve_cache[pe_number * 2 + 1] = + tve_encode_50b_noxlate(start_addr, end_addr); + } + + phb4_ioda_sel(p, IODA3_TBL_TVT, 0, true); + for (i = 0; i < p->tvt_size; i++) + out_be64(p->regs + PHB_IODA_DATA0, p->tve_cache[i]); + + /* set mbt bar to pass capi mmio window. First applied cleared + * values to HW + */ + for (i = 0; i < p->mbt_size; i++) { + p->mbt_cache[i][0] = 0; + p->mbt_cache[i][1] = 0; + } + phb4_ioda_sel(p, IODA3_TBL_MBT, 0, true); + for (i = 0; i < p->mbt_size; i++) { + out_be64(p->regs + PHB_IODA_DATA0, p->mbt_cache[i][0]); + out_be64(p->regs + PHB_IODA_DATA0, p->mbt_cache[i][1]); + } + + p->mbt_cache[0][0] = IODA3_MBT0_ENABLE | + IODA3_MBT0_TYPE_M64 | + SETFIELD(IODA3_MBT0_MODE, 0ull, IODA3_MBT0_MODE_SINGLE_PE) | + SETFIELD(IODA3_MBT0_MDT_COLUMN, 0ull, 0) | + (p->mm0_base & IODA3_MBT0_BASE_ADDR); + p->mbt_cache[0][1] = IODA3_MBT1_ENABLE | + ((~(p->mm0_size - 1)) & IODA3_MBT1_MASK) | + SETFIELD(IODA3_MBT1_SINGLE_PE_NUM, 0ull, pe_number); + + p->mbt_cache[1][0] = IODA3_MBT0_ENABLE | + IODA3_MBT0_TYPE_M64 | + SETFIELD(IODA3_MBT0_MODE, 0ull, IODA3_MBT0_MODE_SINGLE_PE) | + SETFIELD(IODA3_MBT0_MDT_COLUMN, 0ull, 0) | + (0x0002000000000000ULL & IODA3_MBT0_BASE_ADDR); + p->mbt_cache[1][1] = IODA3_MBT1_ENABLE | + (0x00ff000000000000ULL & IODA3_MBT1_MASK) | + SETFIELD(IODA3_MBT1_SINGLE_PE_NUM, 0ull, pe_number); + + phb4_ioda_sel(p, IODA3_TBL_MBT, 0, true); + for (i = 0; i < p->mbt_size; i++) { + out_be64(p->regs + PHB_IODA_DATA0, p->mbt_cache[i][0]); + out_be64(p->regs + PHB_IODA_DATA0, p->mbt_cache[i][1]); + } + + phb4_init_capp_errors(p); + + phb4_init_capp_regs(p); + + if (!chiptod_capp_timebase_sync(p->chip_id, CAPP_TFMR, + CAPP_TB, + PHB4_CAPP_REG_OFFSET(p))) { + PHBERR(p, "CAPP: Failed to sync timebase\n"); + return OPAL_HARDWARE; + } + return OPAL_SUCCESS; +} + +static int64_t phb4_set_capi_mode(struct phb *phb, uint64_t mode, + uint64_t pe_number) +{ + struct phb4 *p = phb_to_phb4(phb); + struct proc_chip *chip = get_chip(p->chip_id); + uint64_t reg; + uint32_t offset; + + + lock(&capi_lock); + chip->capp_phb4_attached_mask |= 1 << p->index; + unlock(&capi_lock); + + offset = PHB4_CAPP_REG_OFFSET(p); + xscom_read(p->chip_id, CAPP_ERR_STATUS_CTRL + offset, ®); + if ((reg & PPC_BIT(5))) { + PHBERR(p, "CAPP: recovery failed (%016llx)\n", reg); + return OPAL_HARDWARE; + } else if ((reg & PPC_BIT(0)) && (!(reg & PPC_BIT(1)))) { + PHBDBG(p, "CAPP: recovery in progress\n"); + return OPAL_BUSY; + } + + switch (mode) { + case OPAL_PHB_CAPI_MODE_PCIE: + return OPAL_UNSUPPORTED; + + case OPAL_PHB_CAPI_MODE_CAPI: + return enable_capi_mode(p, pe_number, CAPI_DMA_TVT0); + + case OPAL_PHB_CAPI_MODE_DMA: + /* shouldn't be called, enabled by default on p9 */ + return OPAL_UNSUPPORTED; + + case OPAL_PHB_CAPI_MODE_DMA_TVT1: + return enable_capi_mode(p, pe_number, CAPI_DMA_TVT1); + + case OPAL_PHB_CAPI_MODE_SNOOP_OFF: + /* shouldn't be called */ + return OPAL_UNSUPPORTED; + + case OPAL_PHB_CAPI_MODE_SNOOP_ON: + /* nothing to do */ + return OPAL_SUCCESS; + } + + return OPAL_UNSUPPORTED; +} + static const struct phb_ops phb4_ops = { .cfg_read8 = phb4_pcicfg_read8, .cfg_read16 = phb4_pcicfg_read16, @@ -2541,6 +2886,7 @@ static const struct phb_ops phb4_ops = { .get_diag_data = NULL, .get_diag_data2 = phb4_get_diag_data, .tce_kill = phb4_tce_kill, + .set_capi_mode = phb4_set_capi_mode, }; static void phb4_init_ioda3(struct phb4 *p) @@ -2572,13 +2918,13 @@ static void phb4_init_ioda3(struct phb4 *p) p->tbl_pest | PHB_PEST_BAR_ENABLE); /* Init_23 - CRW Base Address Reg */ - // XXX FIXME learn CAPI :-( + /* See enable_capi_mode() */ /* Init_24 - ASN Compare/Mask */ - // XXX FIXME learn CAPI :-( + /* See enable_capi_mode() */ /* Init_25 - CAPI Compare/Mask */ - // XXX FIXME learn CAPI :-( + /* See enable_capi_mode() */ /* Init_26 - PCIE Outbound upper address */ out_be64(p->regs + PHB_M64_UPPER_BITS, 0); @@ -2883,7 +3229,7 @@ static void phb4_init_hw(struct phb4 *p, bool first_init) */ /* Init_123 : NBW. XXX TODO */ - // XXX FIXME learn CAPI :-( + /* See enable_capi_mode() */ /* Init_124 : Setup PCI command/status on root complex * I don't know why the spec does this now and not earlier, so @@ -3104,6 +3450,9 @@ static void phb4_add_properties(struct phb4 *p) dt_add_property_cells(np, "ibm,phb-diag-data-size", sizeof(struct OpalIoPhb4ErrorData)); + + /* Indicate to Linux that CAPP timebase sync is supported */ + dt_add_property_string(np, "ibm,capp-timebase-sync", NULL); } static bool phb4_calculate_windows(struct phb4 *p) diff --git a/include/chip.h b/include/chip.h index b957e45..17f062b 100644 --- a/include/chip.h +++ b/include/chip.h @@ -191,6 +191,7 @@ struct proc_chip { /* Must hold capi_lock to change */ uint8_t capp_phb3_attached_mask; + uint8_t capp_phb4_attached_mask; uint8_t capp_ucode_loaded; /* Used by hw/centaur.c */ diff --git a/include/opal-api.h b/include/opal-api.h index 37af5f7..2713490 100644 --- a/include/opal-api.h +++ b/include/opal-api.h @@ -1144,6 +1144,7 @@ enum { OPAL_PHB_CAPI_MODE_SNOOP_OFF = 2, OPAL_PHB_CAPI_MODE_SNOOP_ON = 3, OPAL_PHB_CAPI_MODE_DMA = 4, + OPAL_PHB_CAPI_MODE_DMA_TVT1 = 5, }; /* CAPI feature flags (in device-tree) */ diff --git a/include/phb4-capp.h b/include/phb4-capp.h new file mode 100644 index 0000000..89de034 --- /dev/null +++ b/include/phb4-capp.h @@ -0,0 +1,60 @@ +/* Copyright 2013-2017 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. + */ + +#ifndef __PHB4_CAPP_H +#define __PHB4_CAPP_H + +#define CAPP_SNP_ARRAY_WRITE_REG 0x2010841 /* Satellite 2 */ +#define CAPP_SNP_ARRAY_ADDR_REG 0x2010828 +#define CAPP_APC_MASTER_ARRAY_ADDR_REG 0x201082A +#define CAPP_APC_MASTER_ARRAY_WRITE_REG 0x2010842 /* Satellite 2 */ + +#define CAPP_FIR 0x2010800 +#define CAPP_ERR_RPT_CLR 0x2010813 +#define APC_MASTER_PB_CTRL 0x2010818 +#define APC_MASTER_CAPI_CTRL 0x2010819 +#define LCO_MASTER_TARGET 0x2010821 +#define EPOCH_RECOVERY_TIMERS_CTRL 0x201082C +#define SNOOP_CAPI_CONFIG 0x201081A +#define SNOOP_CONTROL 0x201081B +#define TRANSPORT_CONTROL 0x201081C +#define CAPP_TB 0x2010826 +#define CAPP_TFMR 0x2010827 +#define CAPP_ERR_STATUS_CTRL 0x201080E +#define FLUSH_SUE_STATE_MAP 0x201080F +#define FLUSH_CPIG_STATE_MAP 0x2010820 +#define FLUSH_SUE_UOP1 0x2010843 /* Satellite 2 */ +#define APC_FSM_READ_MASK 0x2010823 +#define XPT_FSM_RMM 0x2010831 + +/* CAPP0 attached to PHB0(PEC0 - single port) + * CAPP1 attached to PHB3(PEC2 - single or dual port) + */ +#define CAPP0_PHB_INDEX 0 +#define CAPP1_PHB_INDEX 3 + +/* SCOM address Base (Ring = ‘0010’b) + * CAPP Unit Satellite SCOM address Base + * CAPP 0 S1 (sat = ‘0000’b) x02010800 + * CAPP 0 S2 (sat = ‘0001’b) x02010840 + * CAPP 1 S1 (sat = ‘0000’b) x04010800 + * CAPP 1 S2 (sat = ‘0001’b) x04010840 + */ +#define CAPP1_REG_OFFSET 0x2000000 + +#define PHB4_CAPP_REG_OFFSET(p) ((p)->index == 0 ? 0x0 : CAPP1_REG_OFFSET) + +#endif /* __PHB4_CAPP_H */ diff --git a/include/phb4-regs.h b/include/phb4-regs.h index 92bee88..5ec47a5 100644 --- a/include/phb4-regs.h +++ b/include/phb4-regs.h @@ -71,8 +71,12 @@ #define PHB_PEST_BAR 0x1a8 #define PHB_PEST_BAR_ENABLE PPC_BIT(0) #define PHB_PEST_BASE_ADDRESS PPC_BITMASK(8,51) +#define PHB_PBL_ASN_CMPM 0x1C0 +#define PHB_PBL_ASN_ENABLE PPC_BIT(63) +#define PHB_CAPI_CMPM 0x1C8 +#define PHB_CAPI_CMPM_ENABLE PPC_BIT(63) #define PHB_M64_UPPER_BITS 0x1f0 -#define PHB_INTREP_TIMER 0x1f8 +#define PHB_NXLATE_PREFIX 0x1f8 #define PHB_DMARD_SYNC 0x200 #define PHB_DMARD_SYNC_START PPC_BIT(0) #define PHB_DMARD_SYNC_COMPLETE PPC_BIT(1) @@ -242,6 +246,7 @@ #define PHB_PBL_TIMEOUT_CTRL 0x1810 #define PHB_PBL_NPTAG_ENABLE 0x1820 #define PHB_PBL_NBW_CMP_MASK 0x1830 +#define PHB_PBL_NBW_MASK_ENABLE PPC_BIT(63) #define PHB_PBL_SYS_LINK_INIT 0x1838 #define PHB_PBL_BUF_STATUS 0x1840 #define PHB_PBL_ERR_STATUS 0x1900
Enable the Coherently attached processor interface. The PHB is used as a CAPI interface. CAPI Adapters can be connected to either PEC0 or PEC2. Single port CAPI adapter can be connected to either PEC0 or PEC2, but Dual-Port Adapter can be only connected to PEC2 CAPP0 attached to PHB0(PEC0 - single port) CAPP1 attached to PHB3(PEC2 - single or dual port) As we did for PHB3, a new specific file 'phb4-capp.h' is created to contain the CAPP register definitions. Signed-off-by: Christophe Lombard <clombard@linux.vnet.ibm.com> --- hw/phb4.c | 359 +++++++++++++++++++++++++++++++++++++++++++++++++++- include/chip.h | 1 + include/opal-api.h | 1 + include/phb4-capp.h | 60 +++++++++ include/phb4-regs.h | 7 +- 5 files changed, 422 insertions(+), 6 deletions(-) create mode 100644 include/phb4-capp.h