aboutsummaryrefslogtreecommitdiff
path: root/hw/phb4.c
diff options
context:
space:
mode:
authorChristophe Lombard <clombard@linux.vnet.ibm.com>2017-06-13 14:21:20 +0200
committerStewart Smith <stewart@linux.vnet.ibm.com>2017-06-19 14:49:29 +1000
commit37ea3cfdc8523cb5fbbde6e364eaed3c1c67f8bb (patch)
tree59a817c8ea18aec57db33c545fecc19ac25e26ef /hw/phb4.c
parent43eb0ae6c2d4d05c4802b2de553f14234fe2cddf (diff)
downloadskiboot-37ea3cfdc8523cb5fbbde6e364eaed3c1c67f8bb.zip
skiboot-37ea3cfdc8523cb5fbbde6e364eaed3c1c67f8bb.tar.gz
skiboot-37ea3cfdc8523cb5fbbde6e364eaed3c1c67f8bb.tar.bz2
capi: Enable capi mode for PHB4
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> Reviewed-by: Frederic Barrat <fbarrat@linux.vnet.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'hw/phb4.c')
-rw-r--r--hw/phb4.c359
1 files changed, 354 insertions, 5 deletions
diff --git a/hw/phb4.c b/hw/phb4.c
index fa9e911..459b627 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>
@@ -78,6 +78,11 @@ static bool phb4_init_rc_cfg(struct phb4 *p);
#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
*/
@@ -2100,6 +2105,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);
@@ -2722,6 +2729,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);
+ 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, &reg);
+ 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);
+ 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, &reg);
+ 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, &reg);
+ 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);
+ 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, &reg);
+ 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,
@@ -2754,6 +3099,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)
@@ -2785,13 +3131,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);
@@ -3096,7 +3442,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
@@ -3317,6 +3663,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)