diff options
Diffstat (limited to 'drivers/irqchip/irq-gic-v3-its-pci-msi.c')
-rw-r--r-- | drivers/irqchip/irq-gic-v3-its-pci-msi.c | 35 |
1 files changed, 17 insertions, 18 deletions
diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c index aee1c60d7ab5..77931214d954 100644 --- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c +++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c @@ -41,27 +41,22 @@ static struct irq_chip its_msi_irq_chip = { .irq_write_msi_msg = pci_msi_domain_write_msg, }; -struct its_pci_alias { - struct pci_dev *pdev; - u32 count; -}; - -static int its_pci_msi_vec_count(struct pci_dev *pdev) +static int its_pci_msi_vec_count(struct pci_dev *pdev, void *data) { - int msi, msix; + int msi, msix, *count = data; msi = max(pci_msi_vec_count(pdev), 0); msix = max(pci_msix_vec_count(pdev), 0); + *count += max(msi, msix); - return max(msi, msix); + return 0; } static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data) { - struct its_pci_alias *dev_alias = data; + struct pci_dev **alias_dev = data; - if (pdev != dev_alias->pdev) - dev_alias->count += its_pci_msi_vec_count(pdev); + *alias_dev = pdev; return 0; } @@ -69,9 +64,9 @@ static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data) static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec, msi_alloc_info_t *info) { - struct pci_dev *pdev; - struct its_pci_alias dev_alias; + struct pci_dev *pdev, *alias_dev; struct msi_domain_info *msi_info; + int alias_count = 0; if (!dev_is_pci(dev)) return -EINVAL; @@ -79,16 +74,20 @@ static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev, msi_info = msi_get_domain_info(domain->parent); pdev = to_pci_dev(dev); - dev_alias.pdev = pdev; - dev_alias.count = nvec; - - pci_for_each_dma_alias(pdev, its_get_pci_alias, &dev_alias); + /* + * If pdev is downstream of any aliasing bridges, take an upper + * bound of how many other vectors could map to the same DevID. + */ + pci_for_each_dma_alias(pdev, its_get_pci_alias, &alias_dev); + if (alias_dev != pdev && alias_dev->subordinate) + pci_walk_bus(alias_dev->subordinate, its_pci_msi_vec_count, + &alias_count); /* ITS specific DeviceID, as the core ITS ignores dev. */ info->scratchpad[0].ul = pci_msi_domain_get_msi_rid(domain, pdev); return msi_info->ops->msi_prepare(domain->parent, - dev, dev_alias.count, info); + dev, max(nvec, alias_count), info); } static struct msi_domain_ops its_pci_msi_ops = { |