diff options
-rw-r--r-- | core/pci-opal.c | 39 | ||||
-rw-r--r-- | doc/opal-api/opal-pci-set-p2p-157.rst | 50 | ||||
-rw-r--r-- | hw/phb4.c | 62 | ||||
-rw-r--r-- | include/opal-api.h | 13 | ||||
-rw-r--r-- | include/pci.h | 4 | ||||
-rw-r--r-- | include/phb4-regs.h | 1 |
6 files changed, 168 insertions, 1 deletions
diff --git a/core/pci-opal.c b/core/pci-opal.c index 5d58a88..b8aec94 100644 --- a/core/pci-opal.c +++ b/core/pci-opal.c @@ -977,3 +977,42 @@ static int64_t opal_pci_set_phb_capi_mode(uint64_t phb_id, uint64_t mode, uint64 return rc; } opal_call(OPAL_PCI_SET_PHB_CAPI_MODE, opal_pci_set_phb_capi_mode, 3); + +static int64_t opal_pci_set_p2p(uint64_t phbid_init, uint64_t phbid_target, + uint64_t desc, uint16_t pe_number) +{ + struct phb *phb_init = pci_get_phb(phbid_init); + struct phb *phb_target = pci_get_phb(phbid_target); + + if (!phb_init || !phb_target) + return OPAL_PARAMETER; + /* + * Having the 2 devices under the same PHB may require tuning + * the configuration of intermediate switch(es), more easily + * done from linux. And it shouldn't require a PHB config + * change. + * Return an error for the time being. + */ + if (phb_init == phb_target) + return OPAL_UNSUPPORTED; + if (!phb_init->ops->set_p2p || !phb_target->ops->set_p2p) + return OPAL_UNSUPPORTED; + /* + * Loads would be supported on p9 if the 2 devices are under + * the same PHB, but we ruled it out above. + */ + if (desc & OPAL_PCI_P2P_LOAD) + return OPAL_UNSUPPORTED; + + phb_lock(phb_init); + phb_init->ops->set_p2p(phb_init, OPAL_PCI_P2P_INITIATOR, desc, + pe_number); + phb_unlock(phb_init); + + phb_lock(phb_target); + phb_target->ops->set_p2p(phb_target, OPAL_PCI_P2P_TARGET, desc, + pe_number); + phb_unlock(phb_target); + return OPAL_SUCCESS; +} +opal_call(OPAL_PCI_SET_P2P, opal_pci_set_p2p, 4); diff --git a/doc/opal-api/opal-pci-set-p2p-157.rst b/doc/opal-api/opal-pci-set-p2p-157.rst new file mode 100644 index 0000000..c34630c --- /dev/null +++ b/doc/opal-api/opal-pci-set-p2p-157.rst @@ -0,0 +1,50 @@ +OPAL_PCI_SET_P2P +================ +:: + + #define OPAL_PCI_SET_P2P 157 + + int64_t opal_pci_set_p2p(uint64_t phbid_init, uint64_t phbid_target, + uint64_t desc, uint16_t pe_number) + + /* PCI p2p descriptor */ + #define OPAL_PCI_P2P_ENABLE 0x1 + #define OPAL_PCI_P2P_LOAD 0x2 + #define OPAL_PCI_P2P_STORE 0x4 + +The host calls this function to enable PCI peer-to-peer on the PHBs. + +Parameters +---------- +:: + + uint64_t phbid_init + uint64_t phbid_target + uint64_t desc + uint16_t pe_number + + +``phbid_init`` + is the value from the PHB node ibm,opal-phbid property for the device initiating the p2p operation + +``phbid_target`` + is the value from the PHB node ibm,opal-phbid property for the device targeted by the p2p operation + +``desc`` + tells whether the p2p operation is a store (OPAL_PCI_P2P_STORE) or load (OPAL_PCI_P2P_LOAD). Can be both. + OPAL_PCI_P2P_ENABLE enables/disables the setting + +``pe_number`` + PE number for the initiating device + +Return Values +------------- + +``OPAL_SUCCESS`` + Configuration was successful + +``OPAL_PARAMETER`` + Invalid PHB or mode parameter + +``OPAL_UNSUPPORTED`` + Not supported by hardware @@ -3622,6 +3622,67 @@ static int64_t phb4_set_capi_mode(struct phb *phb, uint64_t mode, return OPAL_UNSUPPORTED; } +static void phb4_p2p_set_initiator(struct phb4 *p, uint16_t pe_number) +{ + uint64_t tve; + uint16_t window_id = (pe_number << 1) + 1; + + /* + * Initiator needs access to the MMIO space of the target, + * which is well beyond the 'normal' memory area. Set its TVE + * with no range checking. + */ + PHBDBG(p, "Setting TVE#1 for peer-to-peer for pe %d\n", pe_number); + tve = PPC_BIT(51); + phb4_ioda_sel(p, IODA3_TBL_TVT, window_id, false); + out_be64(p->regs + PHB_IODA_DATA0, tve); + p->tve_cache[window_id] = tve; +} + +static void phb4_p2p_set_target(struct phb4 *p, bool enable) +{ + uint64_t val; + + /* + * Enabling p2p on a target PHB reserves an outbound (as seen + * from the CPU) store queue for p2p + */ + PHBDBG(p, "%s peer-to-peer\n", (enable ? "Enabling" : "Disabling")); + xscom_read(p->chip_id, + p->pe_stk_xscom + XPEC_NEST_STK_PBCQ_MODE, &val); + if (enable) + val |= XPEC_NEST_STK_PBCQ_MODE_P2P; + else + val &= ~XPEC_NEST_STK_PBCQ_MODE_P2P; + xscom_write(p->chip_id, + p->pe_stk_xscom + XPEC_NEST_STK_PBCQ_MODE, val); +} + +static void phb4_set_p2p(struct phb *phb, uint64_t mode, uint64_t flags, + uint16_t pe_number) +{ + struct phb4 *p = phb_to_phb4(phb); + + switch (mode) { + case OPAL_PCI_P2P_INITIATOR: + if (flags & OPAL_PCI_P2P_ENABLE) + phb4_p2p_set_initiator(p, pe_number); + /* + * When disabling p2p on the initiator, we should + * reset the TVE to its default bypass setting, but it + * is more easily done from the OS, as it knows the + * the start and end address and there's already an + * opal call for it, so let linux handle it. + */ + break; + case OPAL_PCI_P2P_TARGET: + phb4_p2p_set_target(p, !!(flags & OPAL_PCI_P2P_ENABLE)); + break; + default: + assert(0); + } +} + static const struct phb_ops phb4_ops = { .cfg_read8 = phb4_pcicfg_read8, .cfg_read16 = phb4_pcicfg_read16, @@ -3655,6 +3716,7 @@ static const struct phb_ops phb4_ops = { .get_diag_data2 = phb4_get_diag_data, .tce_kill = phb4_tce_kill, .set_capi_mode = phb4_set_capi_mode, + .set_p2p = phb4_set_p2p, }; static void phb4_init_ioda3(struct phb4 *p) diff --git a/include/opal-api.h b/include/opal-api.h index 12716c5..0ff0db0 100644 --- a/include/opal-api.h +++ b/include/opal-api.h @@ -213,7 +213,8 @@ #define OPAL_GET_POWER_SHIFT_RATIO 154 #define OPAL_SET_POWER_SHIFT_RATIO 155 #define OPAL_SENSOR_GROUP_CLEAR 156 -#define OPAL_LAST 156 +#define OPAL_PCI_SET_P2P 157 +#define OPAL_LAST 157 /* Device tree flags */ @@ -1261,6 +1262,16 @@ enum { }; +/* PCI p2p descriptor */ +#define OPAL_PCI_P2P_ENABLE 0x1 +#define OPAL_PCI_P2P_LOAD 0x2 +#define OPAL_PCI_P2P_STORE 0x4 + +enum { + OPAL_PCI_P2P_INITIATOR = 0, + OPAL_PCI_P2P_TARGET = 1, +}; + #endif /* __ASSEMBLY__ */ #endif /* __OPAL_API_H */ diff --git a/include/pci.h b/include/pci.h index f216594..54a62fd 100644 --- a/include/pci.h +++ b/include/pci.h @@ -323,6 +323,10 @@ struct phb_ops { uint64_t pe_number); int64_t (*set_capp_recovery)(struct phb *phb); + + /* PCI peer-to-peer setup */ + void (*set_p2p)(struct phb *phb, uint64_t mode, uint64_t flags, + uint16_t pe_number); }; enum phb_type { diff --git a/include/phb4-regs.h b/include/phb4-regs.h index 932da5b..f06a154 100644 --- a/include/phb4-regs.h +++ b/include/phb4-regs.h @@ -335,6 +335,7 @@ #define XPEC_NEST_STK_ERR_RPT1 0xb #define XPEC_NEST_STK_PBCQ_STAT 0xc #define XPEC_NEST_STK_PBCQ_MODE 0xd +#define XPEC_NEST_STK_PBCQ_MODE_P2P PPC_BIT(0) #define XPEC_NEST_STK_MMIO_BAR0 0xe #define XPEC_NEST_STK_MMIO_BAR0_MASK 0xf #define XPEC_NEST_STK_MMIO_BAR1 0x10 |