diff --git a/devicemodel/Makefile b/devicemodel/Makefile index cea0b15bb..a236929fa 100644 --- a/devicemodel/Makefile +++ b/devicemodel/Makefile @@ -130,6 +130,7 @@ SRCS += hw/pci/hostbridge.c 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/virtio/virtio_audio.c SRCS += hw/pci/virtio/virtio_net.c SRCS += hw/pci/virtio/virtio_rnd.c diff --git a/devicemodel/hw/pci/pci_util.c b/devicemodel/hw/pci/pci_util.c new file mode 100644 index 000000000..498afb342 --- /dev/null +++ b/devicemodel/hw/pci/pci_util.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2021 Intel Corporation. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include +#include +#include +#include + +#include "pcireg.h" +#include "pciaccess.h" +#include "pci_core.h" +#include "pci_util.h" +#include "log.h" + +/* find position of specified pci capability register*/ +int pci_find_cap(struct pci_device *pdev, const int cap_id) +{ + uint8_t cap_pos, cap_data; + uint16_t status = 0; + + pci_device_cfg_read_u16(pdev, &status, PCIR_STATUS); + if (status & PCIM_STATUS_CAPPRESENT) { + pci_device_cfg_read_u8(pdev, &cap_pos, PCIR_CAP_PTR); + + while (cap_pos != 0 && cap_pos != 0xff) { + pci_device_cfg_read_u8(pdev, &cap_data, + cap_pos + PCICAP_ID); + + if (cap_data == cap_id) + return cap_pos; + + pci_device_cfg_read_u8(pdev, &cap_pos, + cap_pos + PCICAP_NEXTPTR); + } + } + + return 0; +} + +/* find extend capability register position from cap_id */ +int pci_find_ext_cap(struct pci_device *pdev, int cap_id) +{ + int offset = 0; + uint32_t data = 0; + + offset = PCIR_EXTCAP; + + do { + /* PCI Express Extended Capability must have 4 bytes header */ + pci_device_cfg_read_u32(pdev, &data, offset); + + if (PCI_EXTCAP_ID(data) == cap_id) + break; + + offset = PCI_EXTCAP_NEXTPTR(data); + } while (offset != 0); + + return offset; +} + +/* find pci-e device type */ +int pci_get_pcie_type(struct pci_device *dev) +{ + uint8_t data = 0; + int pcie_type; + int pos = 0; + + if (dev == NULL) + return -EINVAL; + + pos = pci_find_cap(dev, PCIY_EXPRESS); + if (!pos) + return -EINVAL; + + pci_device_cfg_read_u8(dev, &data, pos + PCIER_FLAGS); + pcie_type = data & PCIEM_FLAGS_TYPE; + + return pcie_type; +} + +/* check whether pdev is a pci root port */ +bool is_root_port(struct pci_device *pdev) +{ + int pcie_type; + + pcie_type = pci_get_pcie_type(pdev); + + return (pcie_type == PCIEM_TYPE_ROOT_PORT); +} + +/* check whether pdev is a bridge */ +bool is_bridge(struct pci_device *pdev) +{ + uint8_t hdr_type; + + pci_device_cfg_read_u8(pdev, &hdr_type, PCIR_HDRTYPE); + + return ((hdr_type & PCIM_HDRTYPE) == PCIM_HDRTYPE_BRIDGE); +} diff --git a/devicemodel/include/pci_util.h b/devicemodel/include/pci_util.h new file mode 100644 index 000000000..71cc8a2dc --- /dev/null +++ b/devicemodel/include/pci_util.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2021 Intel Corporation. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __PCI_UTIL_H +#define __PCI_UTIL_H + +#include +#include "pciaccess.h" + +int pci_find_cap(struct pci_device *pdev, const int cap_id); +int pci_find_ext_cap(struct pci_device *pdev, int cap_id); +int pci_get_pcie_type(struct pci_device *dev); +bool is_root_port(struct pci_device *pdev); +bool is_bridge(struct pci_device *pdev); + +#endif