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; }
static int get_alias_pasid_table(struct pci_dev *pdev, u16 alias, void *opaque) { struct pasid_table_opaque *data = opaque; data->segment = pci_domain_nr(pdev->bus); data->bus = PCI_BUS_NUM(alias); data->devfn = alias & 0xff; return for_each_device_domain(&search_pasid_table, data); }
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; }
/** * is_error_source - check whether the device is source of reported error * @dev: pointer to pci_dev to be checked * @e_info: pointer to reported error info */ static bool is_error_source(struct pci_dev *dev, struct aer_err_info *e_info) { int pos; u32 status, mask; u16 reg16; /* * When bus id is equal to 0, it might be a bad id * reported by root port. */ if ((PCI_BUS_NUM(e_info->id) != 0) && !(dev->bus->bus_flags & PCI_BUS_FLAGS_NO_AERSID)) { /* Device ID match? */ if (e_info->id == ((dev->bus->number << 8) | dev->devfn)) return true; /* Continue id comparing if there is no multiple error */ if (!e_info->multi_error_valid) return false; } /* * When either * 1) bus id is equal to 0. Some ports might lose the bus * id of error source id; * 2) bus flag PCI_BUS_FLAGS_NO_AERSID is set * 3) There are multiple errors and prior ID comparing fails; * We check AER status registers to find possible reporter. */ if (atomic_read(&dev->enable_cnt) == 0) return false; /* Check if AER is enabled */ pcie_capability_read_word(dev, PCI_EXP_DEVCTL, ®16); if (!(reg16 & PCI_EXP_AER_FLAGS)) return false; pos = dev->aer_cap; if (!pos) return false; /* Check if error is recorded */ if (e_info->severity == AER_CORRECTABLE) { pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status); pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &mask); } else { pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, &mask); } if (status & ~mask) return true; return false; }
static int set_msi_sid_cb(struct pci_dev *pdev, u16 alias, void *opaque) { struct set_msi_sid_data *data = opaque; data->pdev = pdev; data->alias = alias; data->count++; if (PCI_BUS_NUM(alias) == pdev->bus->number) data->busmatch_count++; return 0; }
/* * This function called by IOMMU driver on PPR failure */ static int iommu_invalid_ppr_cb(struct pci_dev *pdev, int pasid, unsigned long address, u16 flags) { struct kfd_dev *dev; dev_warn(kfd_device, "Invalid PPR device %x:%x.%x pasid %d address 0x%lX flags 0x%X", PCI_BUS_NUM(pdev->devfn), PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pasid, address, flags); dev = kfd_device_by_pci_dev(pdev); BUG_ON(dev == NULL); kfd_signal_iommu_event(dev, pasid, address, flags & PPR_FAULT_WRITE, flags & PPR_FAULT_EXEC); return AMD_IOMMU_INV_PRI_RSP_INVALID; }