PCIDeviceClass and PCIDevice are defined in pci.h. Many users of the header don't actually need them. Similar structs live in their own headers: PCIBusClass and PCIBus in pci_bus.h, PCIBridge in pci_bridge.h, PCIHostBridgeClass and PCIHostState in pci_host.h, PCIExpressHost in pcie_host.h, and PCIERootPortClass, PCIEPort, and PCIESlot in pcie_port.h. Move PCIDeviceClass and PCIDeviceClass to new pci_device.h, along with the code that needs them. Adjust include directives. This also enables the next commit. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <20221222100330.380143-6-armbru@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
		
			
				
	
	
		
			351 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			351 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#ifndef QEMU_PCI_DEVICE_H
 | 
						|
#define QEMU_PCI_DEVICE_H
 | 
						|
 | 
						|
#include "hw/pci/pci.h"
 | 
						|
#include "hw/pci/pcie.h"
 | 
						|
 | 
						|
#define TYPE_PCI_DEVICE "pci-device"
 | 
						|
typedef struct PCIDeviceClass PCIDeviceClass;
 | 
						|
DECLARE_OBJ_CHECKERS(PCIDevice, PCIDeviceClass,
 | 
						|
                     PCI_DEVICE, TYPE_PCI_DEVICE)
 | 
						|
 | 
						|
/*
 | 
						|
 * Implemented by devices that can be plugged on CXL buses. In the spec, this is
 | 
						|
 * actually a "CXL Component, but we name it device to match the PCI naming.
 | 
						|
 */
 | 
						|
#define INTERFACE_CXL_DEVICE "cxl-device"
 | 
						|
 | 
						|
/* Implemented by devices that can be plugged on PCI Express buses */
 | 
						|
#define INTERFACE_PCIE_DEVICE "pci-express-device"
 | 
						|
 | 
						|
/* Implemented by devices that can be plugged on Conventional PCI buses */
 | 
						|
#define INTERFACE_CONVENTIONAL_PCI_DEVICE "conventional-pci-device"
 | 
						|
 | 
						|
struct PCIDeviceClass {
 | 
						|
    DeviceClass parent_class;
 | 
						|
 | 
						|
    void (*realize)(PCIDevice *dev, Error **errp);
 | 
						|
    PCIUnregisterFunc *exit;
 | 
						|
    PCIConfigReadFunc *config_read;
 | 
						|
    PCIConfigWriteFunc *config_write;
 | 
						|
 | 
						|
    uint16_t vendor_id;
 | 
						|
    uint16_t device_id;
 | 
						|
    uint8_t revision;
 | 
						|
    uint16_t class_id;
 | 
						|
    uint16_t subsystem_vendor_id;       /* only for header type = 0 */
 | 
						|
    uint16_t subsystem_id;              /* only for header type = 0 */
 | 
						|
 | 
						|
    const char *romfile;                /* rom bar */
 | 
						|
};
 | 
						|
 | 
						|
enum PCIReqIDType {
 | 
						|
    PCI_REQ_ID_INVALID = 0,
 | 
						|
    PCI_REQ_ID_BDF,
 | 
						|
    PCI_REQ_ID_SECONDARY_BUS,
 | 
						|
    PCI_REQ_ID_MAX,
 | 
						|
};
 | 
						|
typedef enum PCIReqIDType PCIReqIDType;
 | 
						|
 | 
						|
struct PCIReqIDCache {
 | 
						|
    PCIDevice *dev;
 | 
						|
    PCIReqIDType type;
 | 
						|
};
 | 
						|
typedef struct PCIReqIDCache PCIReqIDCache;
 | 
						|
 | 
						|
struct PCIDevice {
 | 
						|
    DeviceState qdev;
 | 
						|
    bool partially_hotplugged;
 | 
						|
    bool has_power;
 | 
						|
 | 
						|
    /* PCI config space */
 | 
						|
    uint8_t *config;
 | 
						|
 | 
						|
    /*
 | 
						|
     * Used to enable config checks on load. Note that writable bits are
 | 
						|
     * never checked even if set in cmask.
 | 
						|
     */
 | 
						|
    uint8_t *cmask;
 | 
						|
 | 
						|
    /* Used to implement R/W bytes */
 | 
						|
    uint8_t *wmask;
 | 
						|
 | 
						|
    /* Used to implement RW1C(Write 1 to Clear) bytes */
 | 
						|
    uint8_t *w1cmask;
 | 
						|
 | 
						|
    /* Used to allocate config space for capabilities. */
 | 
						|
    uint8_t *used;
 | 
						|
 | 
						|
    /* the following fields are read only */
 | 
						|
    int32_t devfn;
 | 
						|
    /*
 | 
						|
     * Cached device to fetch requester ID from, to avoid the PCI tree
 | 
						|
     * walking every time we invoke PCI request (e.g., MSI). For
 | 
						|
     * conventional PCI root complex, this field is meaningless.
 | 
						|
     */
 | 
						|
    PCIReqIDCache requester_id_cache;
 | 
						|
    char name[64];
 | 
						|
    PCIIORegion io_regions[PCI_NUM_REGIONS];
 | 
						|
    AddressSpace bus_master_as;
 | 
						|
    MemoryRegion bus_master_container_region;
 | 
						|
    MemoryRegion bus_master_enable_region;
 | 
						|
 | 
						|
    /* do not access the following fields */
 | 
						|
    PCIConfigReadFunc *config_read;
 | 
						|
    PCIConfigWriteFunc *config_write;
 | 
						|
 | 
						|
    /* Legacy PCI VGA regions */
 | 
						|
    MemoryRegion *vga_regions[QEMU_PCI_VGA_NUM_REGIONS];
 | 
						|
    bool has_vga;
 | 
						|
 | 
						|
    /* Current IRQ levels.  Used internally by the generic PCI code.  */
 | 
						|
    uint8_t irq_state;
 | 
						|
 | 
						|
    /* Capability bits */
 | 
						|
    uint32_t cap_present;
 | 
						|
 | 
						|
    /* Offset of MSI-X capability in config space */
 | 
						|
    uint8_t msix_cap;
 | 
						|
 | 
						|
    /* MSI-X entries */
 | 
						|
    int msix_entries_nr;
 | 
						|
 | 
						|
    /* Space to store MSIX table & pending bit array */
 | 
						|
    uint8_t *msix_table;
 | 
						|
    uint8_t *msix_pba;
 | 
						|
 | 
						|
    /* May be used by INTx or MSI during interrupt notification */
 | 
						|
    void *irq_opaque;
 | 
						|
 | 
						|
    MSITriggerFunc *msi_trigger;
 | 
						|
    MSIPrepareMessageFunc *msi_prepare_message;
 | 
						|
    MSIxPrepareMessageFunc *msix_prepare_message;
 | 
						|
 | 
						|
    /* MemoryRegion container for msix exclusive BAR setup */
 | 
						|
    MemoryRegion msix_exclusive_bar;
 | 
						|
    /* Memory Regions for MSIX table and pending bit entries. */
 | 
						|
    MemoryRegion msix_table_mmio;
 | 
						|
    MemoryRegion msix_pba_mmio;
 | 
						|
    /* Reference-count for entries actually in use by driver. */
 | 
						|
    unsigned *msix_entry_used;
 | 
						|
    /* MSIX function mask set or MSIX disabled */
 | 
						|
    bool msix_function_masked;
 | 
						|
    /* Version id needed for VMState */
 | 
						|
    int32_t version_id;
 | 
						|
 | 
						|
    /* Offset of MSI capability in config space */
 | 
						|
    uint8_t msi_cap;
 | 
						|
 | 
						|
    /* PCI Express */
 | 
						|
    PCIExpressDevice exp;
 | 
						|
 | 
						|
    /* SHPC */
 | 
						|
    SHPCDevice *shpc;
 | 
						|
 | 
						|
    /* Location of option rom */
 | 
						|
    char *romfile;
 | 
						|
    uint32_t romsize;
 | 
						|
    bool has_rom;
 | 
						|
    MemoryRegion rom;
 | 
						|
    uint32_t rom_bar;
 | 
						|
 | 
						|
    /* INTx routing notifier */
 | 
						|
    PCIINTxRoutingNotifier intx_routing_notifier;
 | 
						|
 | 
						|
    /* MSI-X notifiers */
 | 
						|
    MSIVectorUseNotifier msix_vector_use_notifier;
 | 
						|
    MSIVectorReleaseNotifier msix_vector_release_notifier;
 | 
						|
    MSIVectorPollNotifier msix_vector_poll_notifier;
 | 
						|
 | 
						|
    /* ID of standby device in net_failover pair */
 | 
						|
    char *failover_pair_id;
 | 
						|
    uint32_t acpi_index;
 | 
						|
};
 | 
						|
 | 
						|
static inline int pci_intx(PCIDevice *pci_dev)
 | 
						|
{
 | 
						|
    return pci_get_byte(pci_dev->config + PCI_INTERRUPT_PIN) - 1;
 | 
						|
}
 | 
						|
 | 
						|
static inline int pci_is_cxl(const PCIDevice *d)
 | 
						|
{
 | 
						|
    return d->cap_present & QEMU_PCIE_CAP_CXL;
 | 
						|
}
 | 
						|
 | 
						|
static inline int pci_is_express(const PCIDevice *d)
 | 
						|
{
 | 
						|
    return d->cap_present & QEMU_PCI_CAP_EXPRESS;
 | 
						|
}
 | 
						|
 | 
						|
static inline int pci_is_express_downstream_port(const PCIDevice *d)
 | 
						|
{
 | 
						|
    uint8_t type;
 | 
						|
 | 
						|
    if (!pci_is_express(d) || !d->exp.exp_cap) {
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    type = pcie_cap_get_type(d);
 | 
						|
 | 
						|
    return type == PCI_EXP_TYPE_DOWNSTREAM || type == PCI_EXP_TYPE_ROOT_PORT;
 | 
						|
}
 | 
						|
 | 
						|
static inline int pci_is_vf(const PCIDevice *d)
 | 
						|
{
 | 
						|
    return d->exp.sriov_vf.pf != NULL;
 | 
						|
}
 | 
						|
 | 
						|
static inline uint32_t pci_config_size(const PCIDevice *d)
 | 
						|
{
 | 
						|
    return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE;
 | 
						|
}
 | 
						|
 | 
						|
static inline uint16_t pci_get_bdf(PCIDevice *dev)
 | 
						|
{
 | 
						|
    return PCI_BUILD_BDF(pci_bus_num(pci_get_bus(dev)), dev->devfn);
 | 
						|
}
 | 
						|
 | 
						|
uint16_t pci_requester_id(PCIDevice *dev);
 | 
						|
 | 
						|
/* DMA access functions */
 | 
						|
static inline AddressSpace *pci_get_address_space(PCIDevice *dev)
 | 
						|
{
 | 
						|
    return &dev->bus_master_as;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * pci_dma_rw: Read from or write to an address space from PCI device.
 | 
						|
 *
 | 
						|
 * Return a MemTxResult indicating whether the operation succeeded
 | 
						|
 * or failed (eg unassigned memory, device rejected the transaction,
 | 
						|
 * IOMMU fault).
 | 
						|
 *
 | 
						|
 * @dev: #PCIDevice doing the memory access
 | 
						|
 * @addr: address within the #PCIDevice address space
 | 
						|
 * @buf: buffer with the data transferred
 | 
						|
 * @len: the number of bytes to read or write
 | 
						|
 * @dir: indicates the transfer direction
 | 
						|
 */
 | 
						|
static inline MemTxResult pci_dma_rw(PCIDevice *dev, dma_addr_t addr,
 | 
						|
                                     void *buf, dma_addr_t len,
 | 
						|
                                     DMADirection dir, MemTxAttrs attrs)
 | 
						|
{
 | 
						|
    return dma_memory_rw(pci_get_address_space(dev), addr, buf, len,
 | 
						|
                         dir, attrs);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * pci_dma_read: Read from an address space from PCI device.
 | 
						|
 *
 | 
						|
 * Return a MemTxResult indicating whether the operation succeeded
 | 
						|
 * or failed (eg unassigned memory, device rejected the transaction,
 | 
						|
 * IOMMU fault).  Called within RCU critical section.
 | 
						|
 *
 | 
						|
 * @dev: #PCIDevice doing the memory access
 | 
						|
 * @addr: address within the #PCIDevice address space
 | 
						|
 * @buf: buffer with the data transferred
 | 
						|
 * @len: length of the data transferred
 | 
						|
 */
 | 
						|
static inline MemTxResult pci_dma_read(PCIDevice *dev, dma_addr_t addr,
 | 
						|
                                       void *buf, dma_addr_t len)
 | 
						|
{
 | 
						|
    return pci_dma_rw(dev, addr, buf, len,
 | 
						|
                      DMA_DIRECTION_TO_DEVICE, MEMTXATTRS_UNSPECIFIED);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * pci_dma_write: Write to address space from PCI device.
 | 
						|
 *
 | 
						|
 * Return a MemTxResult indicating whether the operation succeeded
 | 
						|
 * or failed (eg unassigned memory, device rejected the transaction,
 | 
						|
 * IOMMU fault).
 | 
						|
 *
 | 
						|
 * @dev: #PCIDevice doing the memory access
 | 
						|
 * @addr: address within the #PCIDevice address space
 | 
						|
 * @buf: buffer with the data transferred
 | 
						|
 * @len: the number of bytes to write
 | 
						|
 */
 | 
						|
static inline MemTxResult pci_dma_write(PCIDevice *dev, dma_addr_t addr,
 | 
						|
                                        const void *buf, dma_addr_t len)
 | 
						|
{
 | 
						|
    return pci_dma_rw(dev, addr, (void *) buf, len,
 | 
						|
                      DMA_DIRECTION_FROM_DEVICE, MEMTXATTRS_UNSPECIFIED);
 | 
						|
}
 | 
						|
 | 
						|
#define PCI_DMA_DEFINE_LDST(_l, _s, _bits) \
 | 
						|
    static inline MemTxResult ld##_l##_pci_dma(PCIDevice *dev, \
 | 
						|
                                               dma_addr_t addr, \
 | 
						|
                                               uint##_bits##_t *val, \
 | 
						|
                                               MemTxAttrs attrs) \
 | 
						|
    { \
 | 
						|
        return ld##_l##_dma(pci_get_address_space(dev), addr, val, attrs); \
 | 
						|
    } \
 | 
						|
    static inline MemTxResult st##_s##_pci_dma(PCIDevice *dev, \
 | 
						|
                                               dma_addr_t addr, \
 | 
						|
                                               uint##_bits##_t val, \
 | 
						|
                                               MemTxAttrs attrs) \
 | 
						|
    { \
 | 
						|
        return st##_s##_dma(pci_get_address_space(dev), addr, val, attrs); \
 | 
						|
    }
 | 
						|
 | 
						|
PCI_DMA_DEFINE_LDST(ub, b, 8);
 | 
						|
PCI_DMA_DEFINE_LDST(uw_le, w_le, 16)
 | 
						|
PCI_DMA_DEFINE_LDST(l_le, l_le, 32);
 | 
						|
PCI_DMA_DEFINE_LDST(q_le, q_le, 64);
 | 
						|
PCI_DMA_DEFINE_LDST(uw_be, w_be, 16)
 | 
						|
PCI_DMA_DEFINE_LDST(l_be, l_be, 32);
 | 
						|
PCI_DMA_DEFINE_LDST(q_be, q_be, 64);
 | 
						|
 | 
						|
#undef PCI_DMA_DEFINE_LDST
 | 
						|
 | 
						|
/**
 | 
						|
 * pci_dma_map: Map device PCI address space range into host virtual address
 | 
						|
 * @dev: #PCIDevice to be accessed
 | 
						|
 * @addr: address within that device's address space
 | 
						|
 * @plen: pointer to length of buffer; updated on return to indicate
 | 
						|
 *        if only a subset of the requested range has been mapped
 | 
						|
 * @dir: indicates the transfer direction
 | 
						|
 *
 | 
						|
 * Return: A host pointer, or %NULL if the resources needed to
 | 
						|
 *         perform the mapping are exhausted (in that case *@plen
 | 
						|
 *         is set to zero).
 | 
						|
 */
 | 
						|
static inline void *pci_dma_map(PCIDevice *dev, dma_addr_t addr,
 | 
						|
                                dma_addr_t *plen, DMADirection dir)
 | 
						|
{
 | 
						|
    return dma_memory_map(pci_get_address_space(dev), addr, plen, dir,
 | 
						|
                          MEMTXATTRS_UNSPECIFIED);
 | 
						|
}
 | 
						|
 | 
						|
static inline void pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t len,
 | 
						|
                                 DMADirection dir, dma_addr_t access_len)
 | 
						|
{
 | 
						|
    dma_memory_unmap(pci_get_address_space(dev), buffer, len, dir, access_len);
 | 
						|
}
 | 
						|
 | 
						|
static inline void pci_dma_sglist_init(QEMUSGList *qsg, PCIDevice *dev,
 | 
						|
                                       int alloc_hint)
 | 
						|
{
 | 
						|
    qemu_sglist_init(qsg, DEVICE(dev), alloc_hint, pci_get_address_space(dev));
 | 
						|
}
 | 
						|
 | 
						|
extern const VMStateDescription vmstate_pci_device;
 | 
						|
 | 
						|
#define VMSTATE_PCI_DEVICE(_field, _state) {                         \
 | 
						|
    .name       = (stringify(_field)),                               \
 | 
						|
    .size       = sizeof(PCIDevice),                                 \
 | 
						|
    .vmsd       = &vmstate_pci_device,                               \
 | 
						|
    .flags      = VMS_STRUCT,                                        \
 | 
						|
    .offset     = vmstate_offset_value(_state, _field, PCIDevice),   \
 | 
						|
}
 | 
						|
 | 
						|
#define VMSTATE_PCI_DEVICE_POINTER(_field, _state) {                 \
 | 
						|
    .name       = (stringify(_field)),                               \
 | 
						|
    .size       = sizeof(PCIDevice),                                 \
 | 
						|
    .vmsd       = &vmstate_pci_device,                               \
 | 
						|
    .flags      = VMS_STRUCT | VMS_POINTER,                          \
 | 
						|
    .offset     = vmstate_offset_pointer(_state, _field, PCIDevice), \
 | 
						|
}
 | 
						|
 | 
						|
#endif
 |