diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c index 5883e7634a2b..f37ad34c80ec 100644 --- a/drivers/base/platform-msi.c +++ b/drivers/base/platform-msi.c @@ -324,6 +324,7 @@ void platform_msi_device_domain_free(struct irq_domain *domain, unsigned int vir struct platform_msi_priv_data *data = domain->host_data; msi_lock_descs(data->dev); + msi_domain_depopulate_descs(data->dev, virq, nr_irqs); irq_domain_free_irqs_common(domain, virq, nr_irqs); msi_free_msi_descs_range(data->dev, virq, virq + nr_irqs - 1); msi_unlock_descs(data->dev); diff --git a/drivers/pci/msi/api.c b/drivers/pci/msi/api.c index b8009aa11f3c..be679aa5db64 100644 --- a/drivers/pci/msi/api.c +++ b/drivers/pci/msi/api.c @@ -163,11 +163,11 @@ EXPORT_SYMBOL_GPL(pci_msix_alloc_irq_at); /** * pci_msix_free_irq - Free an interrupt on a PCI/MSIX interrupt domain - * which was allocated via pci_msix_alloc_irq_at() * * @dev: The PCI device to operate on * @map: A struct msi_map describing the interrupt to free - * as returned from the allocation function. + * + * Undo an interrupt vector allocation. Does not disable MSI-X. */ void pci_msix_free_irq(struct pci_dev *dev, struct msi_map map) { diff --git a/include/linux/msi.h b/include/linux/msi.h index 13c9b74a4575..cdb14a1ef268 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -635,6 +635,8 @@ int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev, int nvec, msi_alloc_info_t *args); int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev, int virq, int nvec, msi_alloc_info_t *args); +void msi_domain_depopulate_descs(struct device *dev, int virq, int nvec); + struct irq_domain * __platform_msi_create_device_domain(struct device *dev, unsigned int nvec, diff --git a/kernel/irq/ipi.c b/kernel/irq/ipi.c index bbd945bacef0..961d4af76af3 100644 --- a/kernel/irq/ipi.c +++ b/kernel/irq/ipi.c @@ -188,9 +188,9 @@ EXPORT_SYMBOL_GPL(ipi_get_hwirq); static int ipi_send_verify(struct irq_chip *chip, struct irq_data *data, const struct cpumask *dest, unsigned int cpu) { - const struct cpumask *ipimask = irq_data_get_affinity_mask(data); + const struct cpumask *ipimask; - if (!chip || !ipimask) + if (!chip || !data) return -EINVAL; if (!chip->ipi_send_single && !chip->ipi_send_mask) @@ -199,6 +199,10 @@ static int ipi_send_verify(struct irq_chip *chip, struct irq_data *data, if (cpu >= nr_cpu_ids) return -EINVAL; + ipimask = irq_data_get_affinity_mask(data); + if (!ipimask) + return -EINVAL; + if (dest) { if (!cpumask_subset(dest, ipimask)) return -EINVAL; diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index fd0996274401..240e145e969f 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -277,7 +277,7 @@ static struct attribute *irq_attrs[] = { }; ATTRIBUTE_GROUPS(irq); -static struct kobj_type irq_kobj_type = { +static const struct kobj_type irq_kobj_type = { .release = irq_kobj_release, .sysfs_ops = &kobj_sysfs_ops, .default_groups = irq_groups, @@ -335,7 +335,7 @@ postcore_initcall(irq_sysfs_init); #else /* !CONFIG_SYSFS */ -static struct kobj_type irq_kobj_type = { +static const struct kobj_type irq_kobj_type = { .release = irq_kobj_release, }; diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 7d4fc6479062..f34760a1e222 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -1147,7 +1147,8 @@ struct irq_domain *irq_domain_create_hierarchy(struct irq_domain *parent, domain = __irq_domain_create(fwnode, 0, ~0, 0, ops, host_data); if (domain) { - domain->root = parent->root; + if (parent) + domain->root = parent->root; domain->parent = parent; domain->flags |= flags; diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index d0f0389920c1..7a97bcb086bf 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -830,11 +830,8 @@ static struct irq_domain *__msi_create_irq_domain(struct fwnode_handle *fwnode, domain = irq_domain_create_hierarchy(parent, flags | IRQ_DOMAIN_FLAG_MSI, 0, fwnode, &msi_domain_ops, info); - if (domain) { - if (!domain->name && info->chip) - domain->name = info->chip->name; + if (domain) irq_domain_update_bus_token(domain, info->bus_token); - } return domain; } @@ -1084,10 +1081,13 @@ int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev, struct xarray *xa; int ret, virq; - if (!msi_ctrl_valid(dev, &ctrl)) - return -EINVAL; - msi_lock_descs(dev); + + if (!msi_ctrl_valid(dev, &ctrl)) { + ret = -EINVAL; + goto unlock; + } + ret = msi_domain_add_simple_msi_descs(dev, &ctrl); if (ret) goto unlock; @@ -1109,14 +1109,35 @@ int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev, return 0; fail: - for (--virq; virq >= virq_base; virq--) + for (--virq; virq >= virq_base; virq--) { + msi_domain_depopulate_descs(dev, virq, 1); irq_domain_free_irqs_common(domain, virq, 1); + } msi_domain_free_descs(dev, &ctrl); unlock: msi_unlock_descs(dev); return ret; } +void msi_domain_depopulate_descs(struct device *dev, int virq_base, int nvec) +{ + struct msi_ctrl ctrl = { + .domid = MSI_DEFAULT_DOMAIN, + .first = virq_base, + .last = virq_base + nvec - 1, + }; + struct msi_desc *desc; + struct xarray *xa; + unsigned long idx; + + if (!msi_ctrl_valid(dev, &ctrl)) + return; + + xa = &dev->msi.data->__domains[ctrl.domid].store; + xa_for_each_range(xa, idx, desc, ctrl.first, ctrl.last) + desc->irq = 0; +} + /* * Carefully check whether the device can use reservation mode. If * reservation mode is enabled then the early activation will assign a