diff --git a/drivers/pci/msi/irqdomain.c b/drivers/pci/msi/irqdomain.c index f569d575fa72ab6f2db8611944ce7b92e6f2b42f..2bad86354b2ae647d178f8fc35e5c9e00ad015ac 100644 --- a/drivers/pci/msi/irqdomain.c +++ b/drivers/pci/msi/irqdomain.c @@ -325,8 +325,11 @@ bool pci_setup_msix_device_domain(struct pci_dev *pdev, unsigned int hwsize) if (WARN_ON_ONCE(pdev->msi_enabled)) return false; - if (pci_match_device_domain(pdev, DOMAIN_BUS_PCI_DEVICE_MSIX)) + if (pci_match_device_domain(pdev, DOMAIN_BUS_PCI_DEVICE_MSIX)) { + if (msi_domain_update_hwsize(&pdev->dev, MSI_DEFAULT_DOMAIN, hwsize)) + pr_warn("too big MSI-X hwsize:%u\n", hwsize); return true; + } if (pci_match_device_domain(pdev, DOMAIN_BUS_PCI_DEVICE_MSI)) msi_remove_device_irq_domain(&pdev->dev, MSI_DEFAULT_DOMAIN); diff --git a/include/linux/msi.h b/include/linux/msi.h index 78046c06a0a1c43951d4e57d1b2b81eac6e0da4e..de51fc3c9f827096897533b50b8d55b6ea2293e8 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -622,6 +622,9 @@ bool msi_create_device_irq_domain(struct device *dev, unsigned int domid, void *chip_data); void msi_remove_device_irq_domain(struct device *dev, unsigned int domid); +int msi_domain_update_hwsize(struct device *dev, unsigned int domid, + unsigned int hwsize_new); + bool msi_match_device_irq_domain(struct device *dev, unsigned int domid, enum irq_domain_bus_token bus_token); diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index ac3361da4fe1e21bab0fbee86a895f82127be234..cb5bcfbab43ab96d174cf9bf20dedc61bbb02969 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -1079,6 +1079,34 @@ void msi_remove_device_irq_domain(struct device *dev, unsigned int domid) msi_unlock_descs(dev); } +int msi_domain_update_hwsize(struct device *dev, unsigned int domid, + unsigned int hwsize_new) +{ + struct msi_domain_info *info; + struct irq_domain *domain; + int ret = 0; + + if (hwsize_new > MSI_XA_DOMAIN_SIZE) + return -EINVAL; + if (!hwsize_new) + hwsize_new = MSI_XA_DOMAIN_SIZE; + + msi_lock_descs(dev); + + domain = msi_get_device_domain(dev, domid); + if (!domain) { + ret = -ENODEV; + goto out; + } + + info = domain->host_data; + if (hwsize_new != info->hwsize) + info->hwsize = hwsize_new; +out: + msi_unlock_descs(dev); + return ret; +} + /** * msi_match_device_irq_domain - Match a device irq domain against a bus token * @dev: Pointer to the device