|
@@ -60,7 +60,7 @@
|
|
|
#define CXL_VSEC_PROTOCOL_MASK 0xe0
|
|
|
#define CXL_VSEC_PROTOCOL_1024TB 0x80
|
|
|
#define CXL_VSEC_PROTOCOL_512TB 0x40
|
|
|
-#define CXL_VSEC_PROTOCOL_256TB 0x20 /* Power 8 uses this */
|
|
|
+#define CXL_VSEC_PROTOCOL_256TB 0x20 /* Power 8/9 uses this */
|
|
|
#define CXL_VSEC_PROTOCOL_ENABLE 0x01
|
|
|
|
|
|
#define CXL_READ_VSEC_PSL_REVISION(dev, vsec, dest) \
|
|
@@ -326,14 +326,18 @@ static void dump_afu_descriptor(struct cxl_afu *afu)
|
|
|
|
|
|
#define P8_CAPP_UNIT0_ID 0xBA
|
|
|
#define P8_CAPP_UNIT1_ID 0XBE
|
|
|
+#define P9_CAPP_UNIT0_ID 0xC0
|
|
|
+#define P9_CAPP_UNIT1_ID 0xE0
|
|
|
|
|
|
-static u64 get_capp_unit_id(struct device_node *np)
|
|
|
+static int get_phb_index(struct device_node *np, u32 *phb_index)
|
|
|
{
|
|
|
- u32 phb_index;
|
|
|
-
|
|
|
- if (of_property_read_u32(np, "ibm,phb-index", &phb_index))
|
|
|
- return 0;
|
|
|
+ if (of_property_read_u32(np, "ibm,phb-index", phb_index))
|
|
|
+ return -ENODEV;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
+static u64 get_capp_unit_id(struct device_node *np, u32 phb_index)
|
|
|
+{
|
|
|
/*
|
|
|
* POWER 8:
|
|
|
* - For chips other than POWER8NVL, we only have CAPP 0,
|
|
@@ -352,11 +356,27 @@ static u64 get_capp_unit_id(struct device_node *np)
|
|
|
return P8_CAPP_UNIT1_ID;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * POWER 9:
|
|
|
+ * PEC0 (PHB0). Capp ID = CAPP0 (0b1100_0000)
|
|
|
+ * PEC1 (PHB1 - PHB2). No capi mode
|
|
|
+ * PEC2 (PHB3 - PHB4 - PHB5): Capi mode on PHB3 only. Capp ID = CAPP1 (0b1110_0000)
|
|
|
+ */
|
|
|
+ if (cxl_is_power9()) {
|
|
|
+ if (phb_index == 0)
|
|
|
+ return P9_CAPP_UNIT0_ID;
|
|
|
+
|
|
|
+ if (phb_index == 3)
|
|
|
+ return P9_CAPP_UNIT1_ID;
|
|
|
+ }
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int calc_capp_routing(struct pci_dev *dev, u64 *chipid, u64 *capp_unit_id)
|
|
|
+static int calc_capp_routing(struct pci_dev *dev, u64 *chipid,
|
|
|
+ u32 *phb_index, u64 *capp_unit_id)
|
|
|
{
|
|
|
+ int rc;
|
|
|
struct device_node *np;
|
|
|
const __be32 *prop;
|
|
|
|
|
@@ -367,8 +387,16 @@ static int calc_capp_routing(struct pci_dev *dev, u64 *chipid, u64 *capp_unit_id
|
|
|
np = of_get_next_parent(np);
|
|
|
if (!np)
|
|
|
return -ENODEV;
|
|
|
+
|
|
|
*chipid = be32_to_cpup(prop);
|
|
|
- *capp_unit_id = get_capp_unit_id(np);
|
|
|
+
|
|
|
+ rc = get_phb_index(np, phb_index);
|
|
|
+ if (rc) {
|
|
|
+ pr_err("cxl: invalid phb index\n");
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
+
|
|
|
+ *capp_unit_id = get_capp_unit_id(np, *phb_index);
|
|
|
of_node_put(np);
|
|
|
if (!*capp_unit_id) {
|
|
|
pr_err("cxl: invalid capp unit id\n");
|
|
@@ -378,14 +406,104 @@ static int calc_capp_routing(struct pci_dev *dev, u64 *chipid, u64 *capp_unit_id
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int init_implementation_adapter_regs_psl9(struct cxl *adapter, struct pci_dev *dev)
|
|
|
+{
|
|
|
+ u64 xsl_dsnctl, psl_fircntl;
|
|
|
+ u64 chipid;
|
|
|
+ u32 phb_index;
|
|
|
+ u64 capp_unit_id;
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ rc = calc_capp_routing(dev, &chipid, &phb_index, &capp_unit_id);
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * CAPI Identifier bits [0:7]
|
|
|
+ * bit 61:60 MSI bits --> 0
|
|
|
+ * bit 59 TVT selector --> 0
|
|
|
+ */
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Tell XSL where to route data to.
|
|
|
+ * The field chipid should match the PHB CAPI_CMPM register
|
|
|
+ */
|
|
|
+ xsl_dsnctl = ((u64)0x2 << (63-7)); /* Bit 57 */
|
|
|
+ xsl_dsnctl |= (capp_unit_id << (63-15));
|
|
|
+
|
|
|
+ /* nMMU_ID Defaults to: b’000001001’*/
|
|
|
+ xsl_dsnctl |= ((u64)0x09 << (63-28));
|
|
|
+
|
|
|
+ if (cxl_is_power9() && !cpu_has_feature(CPU_FTR_POWER9_DD1)) {
|
|
|
+ /*
|
|
|
+ * Used to identify CAPI packets which should be sorted into
|
|
|
+ * the Non-Blocking queues by the PHB. This field should match
|
|
|
+ * the PHB PBL_NBW_CMPM register
|
|
|
+ * nbwind=0x03, bits [57:58], must include capi indicator.
|
|
|
+ * Not supported on P9 DD1.
|
|
|
+ */
|
|
|
+ xsl_dsnctl |= ((u64)0x03 << (63-47));
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Upper 16b address bits of ASB_Notify messages sent to the
|
|
|
+ * system. Need to match the PHB’s ASN Compare/Mask Register.
|
|
|
+ * Not supported on P9 DD1.
|
|
|
+ */
|
|
|
+ xsl_dsnctl |= ((u64)0x04 << (63-55));
|
|
|
+ }
|
|
|
+
|
|
|
+ cxl_p1_write(adapter, CXL_XSL9_DSNCTL, xsl_dsnctl);
|
|
|
+
|
|
|
+ /* Set fir_cntl to recommended value for production env */
|
|
|
+ psl_fircntl = (0x2ULL << (63-3)); /* ce_report */
|
|
|
+ psl_fircntl |= (0x1ULL << (63-6)); /* FIR_report */
|
|
|
+ psl_fircntl |= 0x1ULL; /* ce_thresh */
|
|
|
+ cxl_p1_write(adapter, CXL_PSL9_FIR_CNTL, psl_fircntl);
|
|
|
+
|
|
|
+ /* vccredits=0x1 pcklat=0x4 */
|
|
|
+ cxl_p1_write(adapter, CXL_PSL9_DSNDCTL, 0x0000000000001810ULL);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * For debugging with trace arrays.
|
|
|
+ * Configure RX trace 0 segmented mode.
|
|
|
+ * Configure CT trace 0 segmented mode.
|
|
|
+ * Configure LA0 trace 0 segmented mode.
|
|
|
+ * Configure LA1 trace 0 segmented mode.
|
|
|
+ */
|
|
|
+ cxl_p1_write(adapter, CXL_PSL9_TRACECFG, 0x8040800080000000ULL);
|
|
|
+ cxl_p1_write(adapter, CXL_PSL9_TRACECFG, 0x8040800080000003ULL);
|
|
|
+ cxl_p1_write(adapter, CXL_PSL9_TRACECFG, 0x8040800080000005ULL);
|
|
|
+ cxl_p1_write(adapter, CXL_PSL9_TRACECFG, 0x8040800080000006ULL);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * A response to an ASB_Notify request is returned by the
|
|
|
+ * system as an MMIO write to the address defined in
|
|
|
+ * the PSL_TNR_ADDR register
|
|
|
+ */
|
|
|
+ /* PSL_TNR_ADDR */
|
|
|
+
|
|
|
+ /* NORST */
|
|
|
+ cxl_p1_write(adapter, CXL_PSL9_DEBUG, 0x8000000000000000ULL);
|
|
|
+
|
|
|
+ /* allocate the apc machines */
|
|
|
+ cxl_p1_write(adapter, CXL_PSL9_APCDEDTYPE, 0x40000003FFFF0000ULL);
|
|
|
+
|
|
|
+ /* Disable vc dd1 fix */
|
|
|
+ if ((cxl_is_power9() && cpu_has_feature(CPU_FTR_POWER9_DD1)))
|
|
|
+ cxl_p1_write(adapter, CXL_PSL9_GP_CT, 0x0400000000000001ULL);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int init_implementation_adapter_regs_psl8(struct cxl *adapter, struct pci_dev *dev)
|
|
|
{
|
|
|
u64 psl_dsnctl, psl_fircntl;
|
|
|
u64 chipid;
|
|
|
+ u32 phb_index;
|
|
|
u64 capp_unit_id;
|
|
|
int rc;
|
|
|
|
|
|
- rc = calc_capp_routing(dev, &chipid, &capp_unit_id);
|
|
|
+ rc = calc_capp_routing(dev, &chipid, &phb_index, &capp_unit_id);
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
|
|
@@ -414,10 +532,11 @@ static int init_implementation_adapter_regs_xsl(struct cxl *adapter, struct pci_
|
|
|
{
|
|
|
u64 xsl_dsnctl;
|
|
|
u64 chipid;
|
|
|
+ u32 phb_index;
|
|
|
u64 capp_unit_id;
|
|
|
int rc;
|
|
|
|
|
|
- rc = calc_capp_routing(dev, &chipid, &capp_unit_id);
|
|
|
+ rc = calc_capp_routing(dev, &chipid, &phb_index, &capp_unit_id);
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
|
|
@@ -435,6 +554,12 @@ static int init_implementation_adapter_regs_xsl(struct cxl *adapter, struct pci_
|
|
|
/* For the PSL this is a multiple for 0 < n <= 7: */
|
|
|
#define PSL_2048_250MHZ_CYCLES 1
|
|
|
|
|
|
+static void write_timebase_ctrl_psl9(struct cxl *adapter)
|
|
|
+{
|
|
|
+ cxl_p1_write(adapter, CXL_PSL9_TB_CTLSTAT,
|
|
|
+ TBSYNC_CNT(2 * PSL_2048_250MHZ_CYCLES));
|
|
|
+}
|
|
|
+
|
|
|
static void write_timebase_ctrl_psl8(struct cxl *adapter)
|
|
|
{
|
|
|
cxl_p1_write(adapter, CXL_PSL_TB_CTLSTAT,
|
|
@@ -456,6 +581,11 @@ static void write_timebase_ctrl_xsl(struct cxl *adapter)
|
|
|
TBSYNC_CNT(XSL_4000_CLOCKS));
|
|
|
}
|
|
|
|
|
|
+static u64 timebase_read_psl9(struct cxl *adapter)
|
|
|
+{
|
|
|
+ return cxl_p1_read(adapter, CXL_PSL9_Timebase);
|
|
|
+}
|
|
|
+
|
|
|
static u64 timebase_read_psl8(struct cxl *adapter)
|
|
|
{
|
|
|
return cxl_p1_read(adapter, CXL_PSL_Timebase);
|
|
@@ -514,6 +644,11 @@ static void cxl_setup_psl_timebase(struct cxl *adapter, struct pci_dev *dev)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+static int init_implementation_afu_regs_psl9(struct cxl_afu *afu)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int init_implementation_afu_regs_psl8(struct cxl_afu *afu)
|
|
|
{
|
|
|
/* read/write masks for this slice */
|
|
@@ -612,7 +747,7 @@ static int setup_cxl_bars(struct pci_dev *dev)
|
|
|
/*
|
|
|
* BAR 4/5 has a special meaning for CXL and must be programmed with a
|
|
|
* special value corresponding to the CXL protocol address range.
|
|
|
- * For POWER 8 that means bits 48:49 must be set to 10
|
|
|
+ * For POWER 8/9 that means bits 48:49 must be set to 10
|
|
|
*/
|
|
|
pci_write_config_dword(dev, PCI_BASE_ADDRESS_4, 0x00000000);
|
|
|
pci_write_config_dword(dev, PCI_BASE_ADDRESS_5, 0x00020000);
|
|
@@ -997,6 +1132,52 @@ static int cxl_afu_descriptor_looks_ok(struct cxl_afu *afu)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int sanitise_afu_regs_psl9(struct cxl_afu *afu)
|
|
|
+{
|
|
|
+ u64 reg;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Clear out any regs that contain either an IVTE or address or may be
|
|
|
+ * waiting on an acknowledgment to try to be a bit safer as we bring
|
|
|
+ * it online
|
|
|
+ */
|
|
|
+ reg = cxl_p2n_read(afu, CXL_AFU_Cntl_An);
|
|
|
+ if ((reg & CXL_AFU_Cntl_An_ES_MASK) != CXL_AFU_Cntl_An_ES_Disabled) {
|
|
|
+ dev_warn(&afu->dev, "WARNING: AFU was not disabled: %#016llx\n", reg);
|
|
|
+ if (cxl_ops->afu_reset(afu))
|
|
|
+ return -EIO;
|
|
|
+ if (cxl_afu_disable(afu))
|
|
|
+ return -EIO;
|
|
|
+ if (cxl_psl_purge(afu))
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+ cxl_p1n_write(afu, CXL_PSL_SPAP_An, 0x0000000000000000);
|
|
|
+ cxl_p1n_write(afu, CXL_PSL_AMBAR_An, 0x0000000000000000);
|
|
|
+ reg = cxl_p2n_read(afu, CXL_PSL_DSISR_An);
|
|
|
+ if (reg) {
|
|
|
+ dev_warn(&afu->dev, "AFU had pending DSISR: %#016llx\n", reg);
|
|
|
+ if (reg & CXL_PSL9_DSISR_An_TF)
|
|
|
+ cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE);
|
|
|
+ else
|
|
|
+ cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A);
|
|
|
+ }
|
|
|
+ if (afu->adapter->native->sl_ops->register_serr_irq) {
|
|
|
+ reg = cxl_p1n_read(afu, CXL_PSL_SERR_An);
|
|
|
+ if (reg) {
|
|
|
+ if (reg & ~0x000000007fffffff)
|
|
|
+ dev_warn(&afu->dev, "AFU had pending SERR: %#016llx\n", reg);
|
|
|
+ cxl_p1n_write(afu, CXL_PSL_SERR_An, reg & ~0xffff);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ reg = cxl_p2n_read(afu, CXL_PSL_ErrStat_An);
|
|
|
+ if (reg) {
|
|
|
+ dev_warn(&afu->dev, "AFU had pending error status: %#016llx\n", reg);
|
|
|
+ cxl_p2n_write(afu, CXL_PSL_ErrStat_An, reg);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int sanitise_afu_regs_psl8(struct cxl_afu *afu)
|
|
|
{
|
|
|
u64 reg;
|
|
@@ -1254,10 +1435,10 @@ int cxl_pci_reset(struct cxl *adapter)
|
|
|
|
|
|
/*
|
|
|
* The adapter is about to be reset, so ignore errors.
|
|
|
- * Not supported on P9 DD1 but don't forget to enable it
|
|
|
- * on P9 DD2
|
|
|
+ * Not supported on P9 DD1
|
|
|
*/
|
|
|
- if (cxl_is_power8())
|
|
|
+ if ((cxl_is_power8()) ||
|
|
|
+ ((cxl_is_power9() && !cpu_has_feature(CPU_FTR_POWER9_DD1))))
|
|
|
cxl_data_cache_flush(adapter);
|
|
|
|
|
|
/* pcie_warm_reset requests a fundamental pci reset which includes a
|
|
@@ -1393,6 +1574,9 @@ static bool cxl_compatible_caia_version(struct cxl *adapter)
|
|
|
if (cxl_is_power8() && (adapter->caia_major == 1))
|
|
|
return true;
|
|
|
|
|
|
+ if (cxl_is_power9() && (adapter->caia_major == 2))
|
|
|
+ return true;
|
|
|
+
|
|
|
return false;
|
|
|
}
|
|
|
|
|
@@ -1460,8 +1644,12 @@ static int sanitise_adapter_regs(struct cxl *adapter)
|
|
|
/* Clear PSL tberror bit by writing 1 to it */
|
|
|
cxl_p1_write(adapter, CXL_PSL_ErrIVTE, CXL_PSL_ErrIVTE_tberror);
|
|
|
|
|
|
- if (adapter->native->sl_ops->invalidate_all)
|
|
|
+ if (adapter->native->sl_ops->invalidate_all) {
|
|
|
+ /* do not invalidate ERAT entries when not reloading on PERST */
|
|
|
+ if (cxl_is_power9() && (adapter->perst_loads_image))
|
|
|
+ return 0;
|
|
|
rc = adapter->native->sl_ops->invalidate_all(adapter);
|
|
|
+ }
|
|
|
|
|
|
return rc;
|
|
|
}
|
|
@@ -1546,6 +1734,30 @@ static void cxl_deconfigure_adapter(struct cxl *adapter)
|
|
|
pci_disable_device(pdev);
|
|
|
}
|
|
|
|
|
|
+static const struct cxl_service_layer_ops psl9_ops = {
|
|
|
+ .adapter_regs_init = init_implementation_adapter_regs_psl9,
|
|
|
+ .invalidate_all = cxl_invalidate_all_psl9,
|
|
|
+ .afu_regs_init = init_implementation_afu_regs_psl9,
|
|
|
+ .sanitise_afu_regs = sanitise_afu_regs_psl9,
|
|
|
+ .register_serr_irq = cxl_native_register_serr_irq,
|
|
|
+ .release_serr_irq = cxl_native_release_serr_irq,
|
|
|
+ .handle_interrupt = cxl_irq_psl9,
|
|
|
+ .fail_irq = cxl_fail_irq_psl,
|
|
|
+ .activate_dedicated_process = cxl_activate_dedicated_process_psl9,
|
|
|
+ .attach_afu_directed = cxl_attach_afu_directed_psl9,
|
|
|
+ .attach_dedicated_process = cxl_attach_dedicated_process_psl9,
|
|
|
+ .update_dedicated_ivtes = cxl_update_dedicated_ivtes_psl9,
|
|
|
+ .debugfs_add_adapter_regs = cxl_debugfs_add_adapter_regs_psl9,
|
|
|
+ .debugfs_add_afu_regs = cxl_debugfs_add_afu_regs_psl9,
|
|
|
+ .psl_irq_dump_registers = cxl_native_irq_dump_regs_psl9,
|
|
|
+ .err_irq_dump_registers = cxl_native_err_irq_dump_regs,
|
|
|
+ .debugfs_stop_trace = cxl_stop_trace_psl9,
|
|
|
+ .write_timebase_ctrl = write_timebase_ctrl_psl9,
|
|
|
+ .timebase_read = timebase_read_psl9,
|
|
|
+ .capi_mode = OPAL_PHB_CAPI_MODE_CAPI,
|
|
|
+ .needs_reset_before_disable = true,
|
|
|
+};
|
|
|
+
|
|
|
static const struct cxl_service_layer_ops psl8_ops = {
|
|
|
.adapter_regs_init = init_implementation_adapter_regs_psl8,
|
|
|
.invalidate_all = cxl_invalidate_all_psl8,
|
|
@@ -1597,6 +1809,9 @@ static void set_sl_ops(struct cxl *adapter, struct pci_dev *dev)
|
|
|
if (cxl_is_power8()) {
|
|
|
dev_info(&dev->dev, "Device uses a PSL8\n");
|
|
|
adapter->native->sl_ops = &psl8_ops;
|
|
|
+ } else {
|
|
|
+ dev_info(&dev->dev, "Device uses a PSL9\n");
|
|
|
+ adapter->native->sl_ops = &psl9_ops;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -1667,8 +1882,13 @@ static void cxl_pci_remove_adapter(struct cxl *adapter)
|
|
|
cxl_sysfs_adapter_remove(adapter);
|
|
|
cxl_debugfs_adapter_remove(adapter);
|
|
|
|
|
|
- /* Flush adapter datacache as its about to be removed */
|
|
|
- cxl_data_cache_flush(adapter);
|
|
|
+ /*
|
|
|
+ * Flush adapter datacache as its about to be removed.
|
|
|
+ * Not supported on P9 DD1.
|
|
|
+ */
|
|
|
+ if ((cxl_is_power8()) ||
|
|
|
+ ((cxl_is_power9() && !cpu_has_feature(CPU_FTR_POWER9_DD1))))
|
|
|
+ cxl_data_cache_flush(adapter);
|
|
|
|
|
|
cxl_deconfigure_adapter(adapter);
|
|
|
|
|
@@ -1752,6 +1972,11 @@ static int cxl_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
|
|
|
+ if (cxl_is_power9() && !radix_enabled()) {
|
|
|
+ dev_info(&dev->dev, "Only Radix mode supported\n");
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
if (cxl_verbose)
|
|
|
dump_cxl_config_space(dev);
|
|
|
|