123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- #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
|