diff --git a/devicemodel/Makefile b/devicemodel/Makefile index a236929fa..4472dc6dd 100644 --- a/devicemodel/Makefile +++ b/devicemodel/Makefile @@ -131,6 +131,7 @@ SRCS += hw/pci/platform_gsi_info.c SRCS += hw/pci/gsi_sharing.c SRCS += hw/pci/passthrough.c SRCS += hw/pci/pci_util.c +SRCS += hw/pci/ptm.c SRCS += hw/pci/virtio/virtio_audio.c SRCS += hw/pci/virtio/virtio_net.c SRCS += hw/pci/virtio/virtio_rnd.c diff --git a/devicemodel/hw/pci/passthrough.c b/devicemodel/hw/pci/passthrough.c index 3221d53c3..f9c606de1 100644 --- a/devicemodel/hw/pci/passthrough.c +++ b/devicemodel/hw/pci/passthrough.c @@ -46,7 +46,7 @@ #include "pci_core.h" #include "acpi.h" #include "dm.h" - +#include "passthru.h" /* Some audio drivers get topology data from ACPI NHLT table. * For such drivers, we need to copy the host NHLT table to make it @@ -70,32 +70,6 @@ uint32_t gpu_opregion_gpa = 0; static int pciaccess_ref_cnt; static pthread_mutex_t ref_cnt_mtx = PTHREAD_MUTEX_INITIALIZER; - -struct passthru_dev { - struct pci_vdev *dev; - struct pcibar bar[PCI_BARMAX + 1]; - struct { - int capoff; - } msi; - struct { - int capoff; - } msix; - struct { - int capoff; - } pmcap; - bool pcie_cap; - struct pcisel sel; - int phys_pin; - uint16_t phys_bdf; - struct pci_device *phys_dev; - /* Options for passthrough device: - * need_reset - reset dev before passthrough - */ - bool need_reset; - bool d3hot_reset; - bool (*has_virt_pcicfg_regs)(int offset); -}; - static uint32_t read_config(struct pci_device *phys_dev, long reg, int width) { diff --git a/devicemodel/hw/pci/ptm.c b/devicemodel/hw/pci/ptm.c new file mode 100644 index 000000000..908389da6 --- /dev/null +++ b/devicemodel/hw/pci/ptm.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2021 Intel Corporation. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include +#include +#include +#include +#include + +#include "pcireg.h" +#include "pciaccess.h" +#include "pci_core.h" +#include "ptm.h" +#include "passthru.h" +#include "pci_util.h" +#include "vmmapi.h" + +/* PTM capability register ID*/ +#define PCIZ_PTM 0x1fU + +/* PTM register Definitions */ +/* PTM capability register */ +#define PCIR_PTM_CAP 0x04U + #define PCIM_PTM_CAP_REQ 0x01U /* Requestor capable */ + #define PCIM_PTM_CAP_ROOT 0x4U /* Root capable */ + #define PCIM_PTM_GRANULARITY 0xFF00 /* Clock granularity */ +/* PTM control register */ +#define PCIR_PTM_CTRL 0x08U + #define PCIM_PTM_CTRL_ENABLE 0x1U /* PTM enable */ + #define PCIM_PTM_CTRL_ROOT_SELECT 0x2U /* Root select */ + +/* get ptm capability register value */ +static int +get_ptm_cap(struct pci_device *pdev, int *offset) +{ + int pos; + uint32_t cap; + + pos = pci_find_ext_cap(pdev, PCIZ_PTM); + + if (!pos) { + *offset = 0; + return 0; + } + + *offset = pos; + pci_device_cfg_read_u32(pdev, &cap, pos + PCIR_PTM_CAP); + + pr_notice("-%s: device [%x:%x.%x]: ptm-cap=0x%x, offset=0x%x.\n", + __func__, pdev->bus, pdev->dev, pdev->func, cap, *offset); + + return cap; +} + +/* Probe whether device and its root port support PTM */ +int ptm_probe(struct vmctx *ctx, struct passthru_dev *ptdev) +{ + int pos, pcie_type, cap, rootport_ptm_offset, device_ptm_offset; + struct pci_device *phys_dev = ptdev->phys_dev; + struct pci_device *root_port; + + if (!ptdev->pcie_cap) { + pr_err("%s Error: %x:%x.%x is not a pci-e device.\n", __func__, + phys_dev->bus, phys_dev->dev, phys_dev->func); + return -EINVAL; + } + + pos = pci_find_ext_cap(phys_dev, PCIZ_PTM); + if (!pos) { + pr_err("%s Error: %x:%x.%x doesn't support ptm.\n", __func__, + phys_dev->bus, phys_dev->dev, phys_dev->func); + return -EINVAL; + } + + pcie_type = pci_get_pcie_type(phys_dev); + + /* Assume that PTM requestor can be enabled on pci ep or rcie. + * If PTM is enabled on an ep, PTM hierarchy requires it has an upstream + * PTM root. Based on available HW platforms, currently PTM root + * capability is implemented in pci root port. + */ + if (pcie_type == PCIEM_TYPE_ENDPOINT) { + cap = get_ptm_cap(phys_dev, &device_ptm_offset); + if (!(cap & PCIM_PTM_CAP_REQ)) { + pr_err("%s Error: %x:%x.%x must be PTM requestor.\n", __func__, + phys_dev->bus, phys_dev->dev, phys_dev->func); + return -EINVAL; + } + + root_port = pci_find_root_port(phys_dev); + if (root_port == 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); + 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); + return -EINVAL; + } + } else if (pcie_type == PCIEM_TYPE_ROOT_INT_EP) { + // No need to emulate root port if ptm requestor is RCIE + pr_notice("%s: ptm requestor is root complex integrated device.\n", + __func__); + } else { + pr_err("%s Error: PTM can only be enabled on pci root complex integrated device or endpoint device.\n", + __func__); + return -EINVAL; + } + + return 0; +} diff --git a/devicemodel/include/passthru.h b/devicemodel/include/passthru.h new file mode 100644 index 000000000..eaa4a0a63 --- /dev/null +++ b/devicemodel/include/passthru.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 Intel Corporation. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __PASSTHRU_H__ +#define __PASSTHRU_H__ + +#include + +#include "pciaccess.h" +#include "pci_core.h" +#include "pciio.h" + +struct passthru_dev { + struct pci_vdev *dev; + struct pcibar bar[PCI_BARMAX + 1]; + struct { + int capoff; + } msi; + struct { + int capoff; + } msix; + struct { + int capoff; + } pmcap; + bool pcie_cap; + struct pcisel sel; + int phys_pin; + uint16_t phys_bdf; + struct pci_device *phys_dev; + /* Options for passthrough device: + * need_reset - reset dev before passthrough + */ + bool need_reset; + bool d3hot_reset; + bool (*has_virt_pcicfg_regs)(int offset); +}; + +#endif \ No newline at end of file diff --git a/devicemodel/include/ptm.h b/devicemodel/include/ptm.h new file mode 100644 index 000000000..9bc9eaeb4 --- /dev/null +++ b/devicemodel/include/ptm.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2021 Intel Corporation. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __PTM_H__ +#define __PTM_H__ + +#include "passthru.h" + +int ptm_probe(struct vmctx *ctx, struct passthru_dev *pdev); + +#endif \ No newline at end of file