pci: fix pci_requester_id()

This fix SID verification failure when IOMMU IR is enabled with PCI
bridges. Existing pci_requester_id() is more like getting BDF info
only. Renaming it to pci_get_bdf(). Meanwhile, we provide the correct
implementation to get requester ID. VT-d spec 5.1.1 is a good reference
to go, though it talks only about interrupt delivery, the rule works
exactly the same for non-interrupt cases.

Currently, there are three use cases for pci_requester_id():

- PCIX status bits: here we need BDF only, not requester ID. Replacing
  with pci_get_bdf().
- PCIe Error injection and MSI delivery: for both these cases, we are
  looking for requester IDs. Here we should use the new impl.

To avoid a PCI walk every time we send MSI message, one requester_id
cache field is added to PCIDevice to cache the result when initialize
PCI device.

Signed-off-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Tested-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Peter Xu 2016-05-17 19:26:10 +08:00 committed by Michael S. Tsirkin
parent 49237b856a
commit 4a94b3aa6d
3 changed files with 101 additions and 3 deletions

View file

@ -15,6 +15,7 @@
#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
#define PCI_FUNC(devfn) ((devfn) & 0x07)
#define PCI_BUILD_BDF(bus, devfn) ((bus << 8) | (devfn))
#define PCI_SLOT_MAX 32
#define PCI_FUNC_MAX 8
@ -230,6 +231,20 @@ typedef void (*MSIVectorPollNotifier)(PCIDevice *dev,
unsigned int vector_start,
unsigned int vector_end);
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;
@ -252,6 +267,11 @@ struct PCIDevice {
/* the following fields are read only */
PCIBus *bus;
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;
@ -692,11 +712,13 @@ 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_requester_id(PCIDevice *dev)
static inline uint16_t pci_get_bdf(PCIDevice *dev)
{
return (pci_bus_num(dev->bus) << 8) | dev->devfn;
return PCI_BUILD_BDF(pci_bus_num(dev->bus), dev->devfn);
}
uint16_t pci_requester_id(PCIDevice *dev);
/* DMA access functions */
static inline AddressSpace *pci_get_address_space(PCIDevice *dev)
{