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:
parent
721c866d63
commit
df64877c50
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue