powerpc/powernv: Enable PCI peer-to-peer

P9 has support for PCI peer-to-peer, enabling a device to write in the
MMIO space of another device directly, without interrupting the CPU.

This patch adds support for it on powernv, by adding a new API to be
called by drivers. The pnv_pci_set_p2p(...) call configures an
'initiator', i.e the device which will issue the MMIO operation, and a
'target', i.e. the device on the receiving side.

P9 really only supports MMIO stores for the time being but that's
expected to change in the future, so the API allows to define both
load and store operations.

  /* PCI p2p descriptor */
  #define OPAL_PCI_P2P_ENABLE           0x1
  #define OPAL_PCI_P2P_LOAD             0x2
  #define OPAL_PCI_P2P_STORE            0x4

  int pnv_pci_set_p2p(struct pci_dev *initiator, struct pci_dev *target,
                      u64 desc)

It uses a new OPAL call, as the configuration magic is done on the
PHBs by skiboot.

Signed-off-by: Frederic Barrat <fbarrat@linux.vnet.ibm.com>
Reviewed-by: Russell Currey <ruscur@russell.cc>
[mpe: Drop unrelated OPAL calls, s/uint64_t/u64/, minor formatting]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
这个提交包含在:
Frederic Barrat
2017-08-04 11:55:14 +02:00
提交者 Michael Ellerman
父节点 6ff4d3e966
当前提交 2552910084
修改 7 个文件,包含 93 行新增3 行删除

查看文件

@@ -37,6 +37,8 @@
#include "powernv.h"
#include "pci.h"
static DEFINE_MUTEX(p2p_mutex);
int pnv_pci_get_slot_id(struct device_node *np, uint64_t *id)
{
struct device_node *parent = np;
@@ -1017,6 +1019,79 @@ void pnv_pci_dma_bus_setup(struct pci_bus *bus)
}
}
int pnv_pci_set_p2p(struct pci_dev *initiator, struct pci_dev *target, u64 desc)
{
struct pci_controller *hose;
struct pnv_phb *phb_init, *phb_target;
struct pnv_ioda_pe *pe_init;
int rc;
if (!opal_check_token(OPAL_PCI_SET_P2P))
return -ENXIO;
hose = pci_bus_to_host(initiator->bus);
phb_init = hose->private_data;
hose = pci_bus_to_host(target->bus);
phb_target = hose->private_data;
pe_init = pnv_ioda_get_pe(initiator);
if (!pe_init)
return -ENODEV;
/*
* Configuring the initiator's PHB requires to adjust its
* TVE#1 setting. Since the same device can be an initiator
* several times for different target devices, we need to keep
* a reference count to know when we can restore the default
* bypass setting on its TVE#1 when disabling. Opal is not
* tracking PE states, so we add a reference count on the PE
* in linux.
*
* For the target, the configuration is per PHB, so we keep a
* target reference count on the PHB.
*/
mutex_lock(&p2p_mutex);
if (desc & OPAL_PCI_P2P_ENABLE) {
/* always go to opal to validate the configuration */
rc = opal_pci_set_p2p(phb_init->opal_id, phb_target->opal_id,
desc, pe_init->pe_number);
if (rc != OPAL_SUCCESS) {
rc = -EIO;
goto out;
}
pe_init->p2p_initiator_count++;
phb_target->p2p_target_count++;
} else {
if (!pe_init->p2p_initiator_count ||
!phb_target->p2p_target_count) {
rc = -EINVAL;
goto out;
}
if (--pe_init->p2p_initiator_count == 0)
pnv_pci_ioda2_set_bypass(pe_init, true);
if (--phb_target->p2p_target_count == 0) {
rc = opal_pci_set_p2p(phb_init->opal_id,
phb_target->opal_id, desc,
pe_init->pe_number);
if (rc != OPAL_SUCCESS) {
rc = -EIO;
goto out;
}
}
}
rc = 0;
out:
mutex_unlock(&p2p_mutex);
return rc;
}
EXPORT_SYMBOL_GPL(pnv_pci_set_p2p);
void pnv_pci_shutdown(void)
{
struct pci_controller *hose;