int set_msi_sid(struct irte *irte, struct pci_dev *dev) { struct pci_dev *bridge; if (!irte || !dev) return -1; /* PCIe device or Root Complex integrated PCI device */ if (pci_is_pcie(dev) || !dev->bus->parent) { set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, (dev->bus->number << 8) | dev->devfn); return 0; } bridge = pci_find_upstream_pcie_bridge(dev); if (bridge) { if (pci_is_pcie(bridge))/* this is a PCIe-to-PCI/PCIX bridge */ set_irte_sid(irte, SVT_VERIFY_BUS, SQ_ALL_16, (bridge->bus->number << 8) | dev->bus->number); else /* this is a legacy PCI bridge */ set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, (bridge->bus->number << 8) | bridge->devfn); } return 0; }
static int set_msi_sid(struct irte *irte, struct pci_dev *dev) { struct set_msi_sid_data data; if (!irte || !dev) return -1; pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); /* * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the * device is the case of a PCIe-to-PCI bridge, where the alias is for * the subordinate bus. In this case we can only verify the bus. * * If the alias device is on a different bus than our source device * then we have a topology based alias, use it. * * Otherwise, the alias is for a device DMA quirk and we cannot * assume that MSI uses the same requester ID. Therefore use the * original device. */ if (PCI_BUS_NUM(data.alias) != data.pdev->bus->number) set_irte_sid(irte, SVT_VERIFY_BUS, SQ_ALL_16, PCI_DEVID(PCI_BUS_NUM(data.alias), dev->bus->number)); else if (data.pdev->bus->number != dev->bus->number) set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, data.alias); else set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, PCI_DEVID(dev->bus->number, dev->devfn)); return 0; }
int set_msi_sid(struct irte *irte, struct pci_dev *dev) { struct pci_dev *bridge; if (!irte || !dev) return -1; if (pci_is_pcie(dev) || !dev->bus->parent) { set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, (dev->bus->number << 8) | dev->devfn); return 0; } bridge = pci_find_upstream_pcie_bridge(dev); if (bridge) { if (pci_is_pcie(bridge)) set_irte_sid(irte, SVT_VERIFY_BUS, SQ_ALL_16, (bridge->bus->number << 8) | dev->bus->number); else set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, (bridge->bus->number << 8) | bridge->devfn); } return 0; }
int set_hpet_sid(struct irte *irte, u8 id) { int i; u16 sid = 0; if (!irte) return -1; for (i = 0; i < MAX_HPET_TBS; i++) { if (ir_hpet[i].id == id) { sid = (ir_hpet[i].bus << 8) | ir_hpet[i].devfn; break; } } if (sid == 0) { pr_warning("Failed to set source-id of HPET block (%d)\n", id); return -1; } /* * Should really use SQ_ALL_16. Some platforms are broken. * While we figure out the right quirks for these broken platforms, use * SQ_13_IGNORE_3 for now. */ set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_13_IGNORE_3, sid); return 0; }
static int set_ioapic_sid(struct irte *irte, int apic) { int i; u16 sid = 0; if (!irte) return -1; down_read(&dmar_global_lock); for (i = 0; i < MAX_IO_APICS; i++) { if (ir_ioapic[i].id == apic) { sid = (ir_ioapic[i].bus << 8) | ir_ioapic[i].devfn; break; } } up_read(&dmar_global_lock); if (sid == 0) { pr_warning("Failed to set source-id of IOAPIC (%d)\n", apic); return -1; } set_irte_sid(irte, 1, 0, sid); return 0; }
static int set_msi_sid(struct irte *irte, struct pci_dev *dev) { struct set_msi_sid_data data; if (!irte || !dev) return -1; data.count = 0; data.busmatch_count = 0; pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); /* * DMA alias provides us with a PCI device and alias. The only case * where the it will return an alias on a different bus than the * device is the case of a PCIe-to-PCI bridge, where the alias is for * the subordinate bus. In this case we can only verify the bus. * * If there are multiple aliases, all with the same bus number, * then all we can do is verify the bus. This is typical in NTB * hardware which use proxy IDs where the device will generate traffic * from multiple devfn numbers on the same bus. * * If the alias device is on a different bus than our source device * then we have a topology based alias, use it. * * Otherwise, the alias is for a device DMA quirk and we cannot * assume that MSI uses the same requester ID. Therefore use the * original device. */ if (PCI_BUS_NUM(data.alias) != data.pdev->bus->number) set_irte_verify_bus(irte, PCI_BUS_NUM(data.alias), dev->bus->number); else if (data.count >= 2 && data.busmatch_count == data.count) set_irte_verify_bus(irte, dev->bus->number, dev->bus->number); else if (data.pdev->bus->number != dev->bus->number) set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, data.alias); else set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, pci_dev_id(dev)); return 0; }
int set_hpet_sid(struct irte *irte, u8 id) { int i; u16 sid = 0; if (!irte) return -1; for (i = 0; i < MAX_HPET_TBS; i++) { if (ir_hpet[i].id == id) { sid = (ir_hpet[i].bus << 8) | ir_hpet[i].devfn; break; } } if (sid == 0) { pr_warning("Failed to set source-id of HPET block (%d)\n", id); return -1; } set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_13_IGNORE_3, sid); return 0; }
/* * Set an IRTE to match only the bus number. Interrupt requests that reference * this IRTE must have a requester-id whose bus number is between or equal * to the start_bus and end_bus arguments. */ static void set_irte_verify_bus(struct irte *irte, unsigned int start_bus, unsigned int end_bus) { set_irte_sid(irte, SVT_VERIFY_BUS, SQ_ALL_16, (start_bus << 8) | end_bus); }