Commit 0fb7fb71 authored by Thomas Gleixner's avatar Thomas Gleixner
Browse files

genirq/msi, platform-msi: Ensure that MSI descriptors are unreferenced



Miquel reported a warning in the MSI core which is triggered when
interrupts are freed via platform_msi_device_domain_free().

This code got reworked to use core functions for freeing the MSI
descriptors, but nothing took care to clear the msi_desc->irq entry, which
then triggers the warning in msi_free_msi_desc() which uses desc->irq to
validate that the descriptor has been torn down. The same issue exists in
msi_domain_populate_irqs().

Up to the point that msi_free_msi_descs() grew a warning for this case,
this went un-noticed.

Provide the counterpart of msi_domain_populate_irqs() and invoke it in
platform_msi_device_domain_free() before freeing the interrupts and MSI
descriptors and also in the error path of msi_domain_populate_irqs().

Fixes: 2f2940d1 ("genirq/msi: Remove filter from msi_free_descs_free_range()")
Reported-by: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Tested-by: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/87mt4wkwnv.ffs@tglx
parent ea9a78c3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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);
+2 −0
Original line number Diff line number Diff line
@@ -631,6 +631,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,
+22 −1
Original line number Diff line number Diff line
@@ -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