Skip to content

Commit 4527e83

Browse files
committed
Merge tag 'irq-msi-2024-03-10' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull MSI updates from Thomas Gleixner: "Updates for the MSI interrupt subsystem and initial RISC-V MSI support. The core changes have been adopted from previous work which converted ARM[64] to the new per device MSI domain model, which was merged to support multiple MSI domain per device. The ARM[64] changes are being worked on too, but have not been ready yet. The core and platform-MSI changes have been split out to not hold up RISC-V and to avoid that RISC-V builds on the scheduled for removal interfaces. The core support provides new interfaces to handle wire to MSI bridges in a straight forward way and introduces new platform-MSI interfaces which are built on top of the per device MSI domain model. Once ARM[64] is converted over the old platform-MSI interfaces and the related ugliness in the MSI core code will be removed. The actual MSI parts for RISC-V were finalized late and have been post-poned for the next merge window. Drivers: - Add a new driver for the Andes hart-level interrupt controller - Rework the SiFive PLIC driver to prepare for MSI suport - Expand the RISC-V INTC driver to support the new RISC-V AIA controller which provides the basis for MSI on RISC-V - A few fixup for the fallout of the core changes" * tag 'irq-msi-2024-03-10' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (29 commits) irqchip/riscv-intc: Fix low-level interrupt handler setup for AIA x86/apic/msi: Use DOMAIN_BUS_GENERIC_MSI for HPET/IO-APIC domain search genirq/matrix: Dynamic bitmap allocation irqchip/riscv-intc: Add support for RISC-V AIA irqchip/sifive-plic: Improve locking safety by using irqsave/irqrestore irqchip/sifive-plic: Parse number of interrupts and contexts early in plic_probe() irqchip/sifive-plic: Cleanup PLIC contexts upon irqdomain creation failure irqchip/sifive-plic: Use riscv_get_intc_hwnode() to get parent fwnode irqchip/sifive-plic: Use devm_xyz() for managed allocation irqchip/sifive-plic: Use dev_xyz() in-place of pr_xyz() irqchip/sifive-plic: Convert PLIC driver into a platform driver irqchip/riscv-intc: Introduce Andes hart-level interrupt controller irqchip/riscv-intc: Allow large non-standard interrupt number genirq/irqdomain: Don't call ops->select for DOMAIN_BUS_ANY tokens irqchip/imx-intmux: Handle pure domain searches correctly genirq/msi: Provide MSI_FLAG_PARENT_PM_DEV genirq/irqdomain: Reroute device MSI create_mapping genirq/msi: Provide allocation/free functions for "wired" MSI interrupts genirq/msi: Optionally use dev->fwnode for device domain genirq/msi: Provide DOMAIN_BUS_WIRED_TO_MSI ...
2 parents 02d4df7 + 678c607 commit 4527e83

File tree

21 files changed

+637
-217
lines changed

21 files changed

+637
-217
lines changed

arch/x86/include/asm/hw_irq.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
#include <asm/irq_vectors.h>
1818

19-
#define IRQ_MATRIX_BITS NR_VECTORS
20-
2119
#ifndef __ASSEMBLY__
2220

2321
#include <linux/percpu.h>

arch/x86/kernel/apic/io_apic.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2354,7 +2354,7 @@ static int mp_irqdomain_create(int ioapic)
23542354
fwspec.param_count = 1;
23552355
fwspec.param[0] = mpc_ioapic_id(ioapic);
23562356

2357-
parent = irq_find_matching_fwspec(&fwspec, DOMAIN_BUS_ANY);
2357+
parent = irq_find_matching_fwspec(&fwspec, DOMAIN_BUS_GENERIC_MSI);
23582358
if (!parent) {
23592359
if (!cfg->dev)
23602360
irq_domain_free_fwnode(fn);

arch/x86/kernel/hpet.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,7 @@ static struct irq_domain *hpet_create_irq_domain(int hpet_id)
568568
fwspec.param_count = 1;
569569
fwspec.param[0] = hpet_id;
570570

571-
parent = irq_find_matching_fwspec(&fwspec, DOMAIN_BUS_ANY);
571+
parent = irq_find_matching_fwspec(&fwspec, DOMAIN_BUS_GENERIC_MSI);
572572
if (!parent) {
573573
irq_domain_free_fwnode(fn);
574574
kfree(domain_info);

drivers/base/platform-msi.c

Lines changed: 105 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include <linux/msi.h>
1414
#include <linux/slab.h>
1515

16+
/* Begin of removal area. Once everything is converted over. Cleanup the includes too! */
17+
1618
#define DEV_ID_SHIFT 21
1719
#define MAX_DEV_MSIS (1 << (32 - DEV_ID_SHIFT))
1820

@@ -204,8 +206,8 @@ static void platform_msi_free_priv_data(struct device *dev)
204206
* Returns:
205207
* Zero for success, or an error code in case of failure
206208
*/
207-
int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
208-
irq_write_msi_msg_t write_msi_msg)
209+
static int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
210+
irq_write_msi_msg_t write_msi_msg)
209211
{
210212
int err;
211213

@@ -219,18 +221,6 @@ int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
219221

220222
return err;
221223
}
222-
EXPORT_SYMBOL_GPL(platform_msi_domain_alloc_irqs);
223-
224-
/**
225-
* platform_msi_domain_free_irqs - Free MSI interrupts for @dev
226-
* @dev: The device for which to free interrupts
227-
*/
228-
void platform_msi_domain_free_irqs(struct device *dev)
229-
{
230-
msi_domain_free_irqs_all(dev, MSI_DEFAULT_DOMAIN);
231-
platform_msi_free_priv_data(dev);
232-
}
233-
EXPORT_SYMBOL_GPL(platform_msi_domain_free_irqs);
234224

235225
/**
236226
* platform_msi_get_host_data - Query the private data associated with
@@ -350,3 +340,104 @@ int platform_msi_device_domain_alloc(struct irq_domain *domain, unsigned int vir
350340

351341
return msi_domain_populate_irqs(domain->parent, dev, virq, nr_irqs, &data->arg);
352342
}
343+
344+
/* End of removal area */
345+
346+
/* Real per device domain interfaces */
347+
348+
/*
349+
* This indirection can go when platform_device_msi_init_and_alloc_irqs()
350+
* is switched to a proper irq_chip::irq_write_msi_msg() callback. Keep it
351+
* simple for now.
352+
*/
353+
static void platform_msi_write_msi_msg(struct irq_data *d, struct msi_msg *msg)
354+
{
355+
irq_write_msi_msg_t cb = d->chip_data;
356+
357+
cb(irq_data_get_msi_desc(d), msg);
358+
}
359+
360+
static void platform_msi_set_desc_byindex(msi_alloc_info_t *arg, struct msi_desc *desc)
361+
{
362+
arg->desc = desc;
363+
arg->hwirq = desc->msi_index;
364+
}
365+
366+
static const struct msi_domain_template platform_msi_template = {
367+
.chip = {
368+
.name = "pMSI",
369+
.irq_mask = irq_chip_mask_parent,
370+
.irq_unmask = irq_chip_unmask_parent,
371+
.irq_write_msi_msg = platform_msi_write_msi_msg,
372+
/* The rest is filled in by the platform MSI parent */
373+
},
374+
375+
.ops = {
376+
.set_desc = platform_msi_set_desc_byindex,
377+
},
378+
379+
.info = {
380+
.bus_token = DOMAIN_BUS_DEVICE_MSI,
381+
},
382+
};
383+
384+
/**
385+
* platform_device_msi_init_and_alloc_irqs - Initialize platform device MSI
386+
* and allocate interrupts for @dev
387+
* @dev: The device for which to allocate interrupts
388+
* @nvec: The number of interrupts to allocate
389+
* @write_msi_msg: Callback to write an interrupt message for @dev
390+
*
391+
* Returns:
392+
* Zero for success, or an error code in case of failure
393+
*
394+
* This creates a MSI domain on @dev which has @dev->msi.domain as
395+
* parent. The parent domain sets up the new domain. The domain has
396+
* a fixed size of @nvec. The domain is managed by devres and will
397+
* be removed when the device is removed.
398+
*
399+
* Note: For migration purposes this falls back to the original platform_msi code
400+
* up to the point where all platforms have been converted to the MSI
401+
* parent model.
402+
*/
403+
int platform_device_msi_init_and_alloc_irqs(struct device *dev, unsigned int nvec,
404+
irq_write_msi_msg_t write_msi_msg)
405+
{
406+
struct irq_domain *domain = dev->msi.domain;
407+
408+
if (!domain || !write_msi_msg)
409+
return -EINVAL;
410+
411+
/* Migration support. Will go away once everything is converted */
412+
if (!irq_domain_is_msi_parent(domain))
413+
return platform_msi_domain_alloc_irqs(dev, nvec, write_msi_msg);
414+
415+
/*
416+
* @write_msi_msg is stored in the resulting msi_domain_info::data.
417+
* The underlying domain creation mechanism will assign that
418+
* callback to the resulting irq chip.
419+
*/
420+
if (!msi_create_device_irq_domain(dev, MSI_DEFAULT_DOMAIN,
421+
&platform_msi_template,
422+
nvec, NULL, write_msi_msg))
423+
return -ENODEV;
424+
425+
return msi_domain_alloc_irqs_range(dev, MSI_DEFAULT_DOMAIN, 0, nvec - 1);
426+
}
427+
EXPORT_SYMBOL_GPL(platform_device_msi_init_and_alloc_irqs);
428+
429+
/**
430+
* platform_device_msi_free_irqs_all - Free all interrupts for @dev
431+
* @dev: The device for which to free interrupts
432+
*/
433+
void platform_device_msi_free_irqs_all(struct device *dev)
434+
{
435+
struct irq_domain *domain = dev->msi.domain;
436+
437+
msi_domain_free_irqs_all(dev, MSI_DEFAULT_DOMAIN);
438+
439+
/* Migration support. Will go away once everything is converted */
440+
if (!irq_domain_is_msi_parent(domain))
441+
platform_msi_free_priv_data(dev);
442+
}
443+
EXPORT_SYMBOL_GPL(platform_device_msi_free_irqs_all);

drivers/dma/mv_xor_v2.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -747,8 +747,8 @@ static int mv_xor_v2_probe(struct platform_device *pdev)
747747
if (IS_ERR(xor_dev->clk))
748748
return PTR_ERR(xor_dev->clk);
749749

750-
ret = platform_msi_domain_alloc_irqs(&pdev->dev, 1,
751-
mv_xor_v2_set_msi_msg);
750+
ret = platform_device_msi_init_and_alloc_irqs(&pdev->dev, 1,
751+
mv_xor_v2_set_msi_msg);
752752
if (ret)
753753
return ret;
754754

@@ -851,7 +851,7 @@ static int mv_xor_v2_probe(struct platform_device *pdev)
851851
xor_dev->desc_size * MV_XOR_V2_DESC_NUM,
852852
xor_dev->hw_desq_virt, xor_dev->hw_desq);
853853
free_msi_irqs:
854-
platform_msi_domain_free_irqs(&pdev->dev);
854+
platform_device_msi_free_irqs_all(&pdev->dev);
855855
return ret;
856856
}
857857

@@ -867,7 +867,7 @@ static void mv_xor_v2_remove(struct platform_device *pdev)
867867

868868
devm_free_irq(&pdev->dev, xor_dev->irq, xor_dev);
869869

870-
platform_msi_domain_free_irqs(&pdev->dev);
870+
platform_device_msi_free_irqs_all(&pdev->dev);
871871

872872
tasklet_kill(&xor_dev->irq_tasklet);
873873
}

drivers/dma/qcom/hidma.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,7 @@ static void hidma_free_msis(struct hidma_dev *dmadev)
696696
devm_free_irq(dev, virq, &dmadev->lldev);
697697
}
698698

699-
platform_msi_domain_free_irqs(dev);
699+
platform_device_msi_free_irqs_all(dev);
700700
#endif
701701
}
702702

@@ -706,8 +706,8 @@ static int hidma_request_msi(struct hidma_dev *dmadev,
706706
#ifdef CONFIG_GENERIC_MSI_IRQ
707707
int rc, i, virq;
708708

709-
rc = platform_msi_domain_alloc_irqs(&pdev->dev, HIDMA_MSI_INTS,
710-
hidma_write_msi_msg);
709+
rc = platform_device_msi_init_and_alloc_irqs(&pdev->dev, HIDMA_MSI_INTS,
710+
hidma_write_msi_msg);
711711
if (rc)
712712
return rc;
713713

drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3125,7 +3125,8 @@ static int arm_smmu_update_gbpa(struct arm_smmu_device *smmu, u32 set, u32 clr)
31253125
static void arm_smmu_free_msis(void *data)
31263126
{
31273127
struct device *dev = data;
3128-
platform_msi_domain_free_irqs(dev);
3128+
3129+
platform_device_msi_free_irqs_all(dev);
31293130
}
31303131

31313132
static void arm_smmu_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
@@ -3166,7 +3167,7 @@ static void arm_smmu_setup_msis(struct arm_smmu_device *smmu)
31663167
}
31673168

31683169
/* Allocate MSIs for evtq, gerror and priq. Ignore cmdq */
3169-
ret = platform_msi_domain_alloc_irqs(dev, nvec, arm_smmu_write_msi_msg);
3170+
ret = platform_device_msi_init_and_alloc_irqs(dev, nvec, arm_smmu_write_msi_msg);
31703171
if (ret) {
31713172
dev_warn(dev, "failed to allocate MSIs - falling back to wired irqs\n");
31723173
return;

drivers/irqchip/irq-gic-v3.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1691,9 +1691,13 @@ static int gic_irq_domain_select(struct irq_domain *d,
16911691
irq_hw_number_t hwirq;
16921692

16931693
/* Not for us */
1694-
if (fwspec->fwnode != d->fwnode)
1694+
if (fwspec->fwnode != d->fwnode)
16951695
return 0;
16961696

1697+
/* Handle pure domain searches */
1698+
if (!fwspec->param_count)
1699+
return d->bus_token == bus_token;
1700+
16971701
/* If this is not DT, then we have a single domain */
16981702
if (!is_of_node(fwspec->fwnode))
16991703
return 1;

drivers/irqchip/irq-imx-intmux.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ static int imx_intmux_irq_select(struct irq_domain *d, struct irq_fwspec *fwspec
166166
if (fwspec->fwnode != d->fwnode)
167167
return false;
168168

169+
/* Handle pure domain searches */
170+
if (!fwspec->param_count)
171+
return d->bus_token == bus_token;
172+
169173
return irqchip_data->chanidx == fwspec->param[1];
170174
}
171175

0 commit comments

Comments
 (0)