dm: PTM: Check PTM root has more than one child

Add one more sanity check: If the root port has more than
	one child, we won't enable PTM on the guest.
	This is not necessarily an error.  We flag it as
	error just because we don't have this type of hw
	configuration at development time thus this configuration
	is not tested.

Tracked-On: #5915
Signed-off-by: Rong Liu <rong.l.liu@intel.com>
Acked-by: Yu Wang <yu1.wang@intel.com>
This commit is contained in:
Rong Liu 2021-05-05 22:41:09 +00:00 committed by wenlingz
parent 721c866d63
commit df64877c50
4 changed files with 47 additions and 26 deletions

View File

@ -66,6 +66,7 @@
#include "virtio.h"
#include "pm_vuart.h"
#include "log.h"
#include "pci_util.h"
#define GUEST_NIO_PORT 0x488 /* guest upcalls via i/o port */
@ -1122,5 +1123,6 @@ fail:
create_fail:
uninit_hugetlb();
deinit_loggers();
clean_pci_cache();
exit(ret);
}

View File

@ -18,22 +18,6 @@
#define MAX_LEN (PCI_BUSMAX + 1)
struct pci_device_info {
bool is_bridge;
int primary_bus;
int secondary_bus;
int subordinate_bus;
uint16_t bdf;
struct pci_device_info *parent; /* pointer to its parent bridge */
struct pci_device_info *clist; /* children list */
/* cache of all pci devices
* FIXME: remove PCI_DEVICE_Q. To cleanup pci device cache:
* remove children, then remove parents
*/
TAILQ_ENTRY(pci_device_info) PCI_DEVICE_Q;
};
TAILQ_HEAD(ALL_PCI_DEVICES, pci_device_info);
static struct ALL_PCI_DEVICES pci_device_q;
@ -196,6 +180,9 @@ int scan_pci(void)
struct pci_device *dev;
int i;
if (pci_scanned)
return 0;
TAILQ_INIT(&pci_device_q);
pci_scanned = 1;
@ -243,7 +230,11 @@ int scan_pci(void)
done:
if (error < 0)
{
pr_err("%s: failed to build pci hierarchy.\n", __func__);
clean_pci_cache();
pci_scanned = false;
}
pci_iterator_destroy(iter);

View File

@ -106,10 +106,10 @@ add_vroot_port(struct vmctx *ctx, struct passthru_dev *ptdev, struct pci_device
int ptm_probe(struct vmctx *ctx, struct passthru_dev *ptdev, int *vrp_sec_bus)
{
int error = 0;
int pos, pcie_type, cap, rootport_ptm_offset, device_ptm_offset;
int pos, pcie_type, cap, rp_ptm_offset, device_ptm_offset;
struct pci_device *phys_dev = ptdev->phys_dev;
//struct pci_bridge_info bridge_info = {};
struct pci_device *root_port;
struct pci_device *rp;
struct pci_device_info rp_info = {};
*vrp_sec_bus = 0;
@ -146,23 +146,37 @@ int ptm_probe(struct vmctx *ctx, struct passthru_dev *ptdev, int *vrp_sec_bus)
return -EINVAL;
}
root_port = pci_find_root_port(phys_dev);
if (root_port == NULL) {
rp = pci_find_root_port(phys_dev);
if (rp == NULL) {
pr_err("%s Error: Cannot find root port of %x:%x.%x.\n", __func__,
phys_dev->bus, phys_dev->dev, phys_dev->func);
return -ENODEV;
}
cap = get_ptm_cap(root_port, &rootport_ptm_offset);
cap = get_ptm_cap(rp, &rp_ptm_offset);
if (!(cap & PCIM_PTM_CAP_ROOT)) {
pr_err("%s Error: root port %x:%x.%x of %x:%x.%x is not PTM root.\n",
__func__, root_port->bus, root_port->dev,
root_port->func, phys_dev->bus, phys_dev->dev, phys_dev->func);
__func__, rp->bus, rp->dev,
rp->func, phys_dev->bus, phys_dev->dev, phys_dev->func);
return -EINVAL;
}
/* check whether more than one devices are connected to the root port.
* if more than one devices are connected to the root port, we flag
* this as error and won't enable PTM. We do this just because we
* don't have this hw configuration and won't be able totest this case.
*/
error = pci_device_get_bridge_buses(rp, &(rp_info.primary_bus),
&(rp_info.secondary_bus), &(rp_info.subordinate_bus));
if (error || (get_device_count_on_bridge(&rp_info) != 1)) {
pr_err("%s Error: Failed to enable PTM on root port [%x:%x.%x] that has multiple children.\n",
__func__, rp->bus, rp->dev, rp->func);
return -EINVAL;
}
// add virtual root port
*vrp_sec_bus = add_vroot_port(ctx, ptdev, root_port, rootport_ptm_offset);
*vrp_sec_bus = add_vroot_port(ctx, ptdev, rp, rp_ptm_offset);
} else if (pcie_type == PCIEM_TYPE_ROOT_INT_EP) {
// No need to emulate root port if ptm requestor is RCIE

View File

@ -11,7 +11,21 @@
#include <stdbool.h>
#include "pciaccess.h"
struct pci_device_info;
struct pci_device_info {
bool is_bridge;
int primary_bus;
int secondary_bus;
int subordinate_bus;
uint16_t bdf;
struct pci_device_info *parent; /* pointer to its parent bridge */
struct pci_device_info *clist; /* children list */
/* cache of all pci devices
* FIXME: remove PCI_DEVICE_Q. To cleanup pci device cache:
* remove children, then remove parents
*/
TAILQ_ENTRY(pci_device_info) PCI_DEVICE_Q;
};
int pci_find_cap(struct pci_device *pdev, const int cap_id);
int pci_find_ext_cap(struct pci_device *pdev, int cap_id);