Skip to content

Commit

Permalink
Merge tag 'irq-msi-2024-03-10' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…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
  ...
  • Loading branch information
Linus Torvalds committed Mar 11, 2024
2 parents 02d4df7 + 678c607 commit 4527e83
Show file tree
Hide file tree
Showing 21 changed files with 637 additions and 217 deletions.
2 changes: 0 additions & 2 deletions arch/x86/include/asm/hw_irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

#include <asm/irq_vectors.h>

#define IRQ_MATRIX_BITS NR_VECTORS

#ifndef __ASSEMBLY__

#include <linux/percpu.h>
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/kernel/apic/io_apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -2354,7 +2354,7 @@ static int mp_irqdomain_create(int ioapic)
fwspec.param_count = 1;
fwspec.param[0] = mpc_ioapic_id(ioapic);

parent = irq_find_matching_fwspec(&fwspec, DOMAIN_BUS_ANY);
parent = irq_find_matching_fwspec(&fwspec, DOMAIN_BUS_GENERIC_MSI);
if (!parent) {
if (!cfg->dev)
irq_domain_free_fwnode(fn);
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/kernel/hpet.c
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ static struct irq_domain *hpet_create_irq_domain(int hpet_id)
fwspec.param_count = 1;
fwspec.param[0] = hpet_id;

parent = irq_find_matching_fwspec(&fwspec, DOMAIN_BUS_ANY);
parent = irq_find_matching_fwspec(&fwspec, DOMAIN_BUS_GENERIC_MSI);
if (!parent) {
irq_domain_free_fwnode(fn);
kfree(domain_info);
Expand Down
119 changes: 105 additions & 14 deletions drivers/base/platform-msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <linux/msi.h>
#include <linux/slab.h>

/* Begin of removal area. Once everything is converted over. Cleanup the includes too! */

#define DEV_ID_SHIFT 21
#define MAX_DEV_MSIS (1 << (32 - DEV_ID_SHIFT))

Expand Down Expand Up @@ -204,8 +206,8 @@ static void platform_msi_free_priv_data(struct device *dev)
* Returns:
* Zero for success, or an error code in case of failure
*/
int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
irq_write_msi_msg_t write_msi_msg)
static int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
irq_write_msi_msg_t write_msi_msg)
{
int err;

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

return err;
}
EXPORT_SYMBOL_GPL(platform_msi_domain_alloc_irqs);

/**
* platform_msi_domain_free_irqs - Free MSI interrupts for @dev
* @dev: The device for which to free interrupts
*/
void platform_msi_domain_free_irqs(struct device *dev)
{
msi_domain_free_irqs_all(dev, MSI_DEFAULT_DOMAIN);
platform_msi_free_priv_data(dev);
}
EXPORT_SYMBOL_GPL(platform_msi_domain_free_irqs);

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

return msi_domain_populate_irqs(domain->parent, dev, virq, nr_irqs, &data->arg);
}

/* End of removal area */

/* Real per device domain interfaces */

/*
* This indirection can go when platform_device_msi_init_and_alloc_irqs()
* is switched to a proper irq_chip::irq_write_msi_msg() callback. Keep it
* simple for now.
*/
static void platform_msi_write_msi_msg(struct irq_data *d, struct msi_msg *msg)
{
irq_write_msi_msg_t cb = d->chip_data;

cb(irq_data_get_msi_desc(d), msg);
}

static void platform_msi_set_desc_byindex(msi_alloc_info_t *arg, struct msi_desc *desc)
{
arg->desc = desc;
arg->hwirq = desc->msi_index;
}

static const struct msi_domain_template platform_msi_template = {
.chip = {
.name = "pMSI",
.irq_mask = irq_chip_mask_parent,
.irq_unmask = irq_chip_unmask_parent,
.irq_write_msi_msg = platform_msi_write_msi_msg,
/* The rest is filled in by the platform MSI parent */
},

.ops = {
.set_desc = platform_msi_set_desc_byindex,
},

.info = {
.bus_token = DOMAIN_BUS_DEVICE_MSI,
},
};

/**
* platform_device_msi_init_and_alloc_irqs - Initialize platform device MSI
* and allocate interrupts for @dev
* @dev: The device for which to allocate interrupts
* @nvec: The number of interrupts to allocate
* @write_msi_msg: Callback to write an interrupt message for @dev
*
* Returns:
* Zero for success, or an error code in case of failure
*
* This creates a MSI domain on @dev which has @dev->msi.domain as
* parent. The parent domain sets up the new domain. The domain has
* a fixed size of @nvec. The domain is managed by devres and will
* be removed when the device is removed.
*
* Note: For migration purposes this falls back to the original platform_msi code
* up to the point where all platforms have been converted to the MSI
* parent model.
*/
int platform_device_msi_init_and_alloc_irqs(struct device *dev, unsigned int nvec,
irq_write_msi_msg_t write_msi_msg)
{
struct irq_domain *domain = dev->msi.domain;

if (!domain || !write_msi_msg)
return -EINVAL;

/* Migration support. Will go away once everything is converted */
if (!irq_domain_is_msi_parent(domain))
return platform_msi_domain_alloc_irqs(dev, nvec, write_msi_msg);

/*
* @write_msi_msg is stored in the resulting msi_domain_info::data.
* The underlying domain creation mechanism will assign that
* callback to the resulting irq chip.
*/
if (!msi_create_device_irq_domain(dev, MSI_DEFAULT_DOMAIN,
&platform_msi_template,
nvec, NULL, write_msi_msg))
return -ENODEV;

return msi_domain_alloc_irqs_range(dev, MSI_DEFAULT_DOMAIN, 0, nvec - 1);
}
EXPORT_SYMBOL_GPL(platform_device_msi_init_and_alloc_irqs);

/**
* platform_device_msi_free_irqs_all - Free all interrupts for @dev
* @dev: The device for which to free interrupts
*/
void platform_device_msi_free_irqs_all(struct device *dev)
{
struct irq_domain *domain = dev->msi.domain;

msi_domain_free_irqs_all(dev, MSI_DEFAULT_DOMAIN);

/* Migration support. Will go away once everything is converted */
if (!irq_domain_is_msi_parent(domain))
platform_msi_free_priv_data(dev);
}
EXPORT_SYMBOL_GPL(platform_device_msi_free_irqs_all);
8 changes: 4 additions & 4 deletions drivers/dma/mv_xor_v2.c
Original file line number Diff line number Diff line change
Expand Up @@ -747,8 +747,8 @@ static int mv_xor_v2_probe(struct platform_device *pdev)
if (IS_ERR(xor_dev->clk))
return PTR_ERR(xor_dev->clk);

ret = platform_msi_domain_alloc_irqs(&pdev->dev, 1,
mv_xor_v2_set_msi_msg);
ret = platform_device_msi_init_and_alloc_irqs(&pdev->dev, 1,
mv_xor_v2_set_msi_msg);
if (ret)
return ret;

Expand Down Expand Up @@ -851,7 +851,7 @@ static int mv_xor_v2_probe(struct platform_device *pdev)
xor_dev->desc_size * MV_XOR_V2_DESC_NUM,
xor_dev->hw_desq_virt, xor_dev->hw_desq);
free_msi_irqs:
platform_msi_domain_free_irqs(&pdev->dev);
platform_device_msi_free_irqs_all(&pdev->dev);
return ret;
}

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

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

platform_msi_domain_free_irqs(&pdev->dev);
platform_device_msi_free_irqs_all(&pdev->dev);

tasklet_kill(&xor_dev->irq_tasklet);
}
Expand Down
6 changes: 3 additions & 3 deletions drivers/dma/qcom/hidma.c
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@ static void hidma_free_msis(struct hidma_dev *dmadev)
devm_free_irq(dev, virq, &dmadev->lldev);
}

platform_msi_domain_free_irqs(dev);
platform_device_msi_free_irqs_all(dev);
#endif
}

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

rc = platform_msi_domain_alloc_irqs(&pdev->dev, HIDMA_MSI_INTS,
hidma_write_msi_msg);
rc = platform_device_msi_init_and_alloc_irqs(&pdev->dev, HIDMA_MSI_INTS,
hidma_write_msi_msg);
if (rc)
return rc;

Expand Down
5 changes: 3 additions & 2 deletions drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -3125,7 +3125,8 @@ static int arm_smmu_update_gbpa(struct arm_smmu_device *smmu, u32 set, u32 clr)
static void arm_smmu_free_msis(void *data)
{
struct device *dev = data;
platform_msi_domain_free_irqs(dev);

platform_device_msi_free_irqs_all(dev);
}

static void arm_smmu_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
Expand Down Expand Up @@ -3166,7 +3167,7 @@ static void arm_smmu_setup_msis(struct arm_smmu_device *smmu)
}

/* Allocate MSIs for evtq, gerror and priq. Ignore cmdq */
ret = platform_msi_domain_alloc_irqs(dev, nvec, arm_smmu_write_msi_msg);
ret = platform_device_msi_init_and_alloc_irqs(dev, nvec, arm_smmu_write_msi_msg);
if (ret) {
dev_warn(dev, "failed to allocate MSIs - falling back to wired irqs\n");
return;
Expand Down
6 changes: 5 additions & 1 deletion drivers/irqchip/irq-gic-v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -1691,9 +1691,13 @@ static int gic_irq_domain_select(struct irq_domain *d,
irq_hw_number_t hwirq;

/* Not for us */
if (fwspec->fwnode != d->fwnode)
if (fwspec->fwnode != d->fwnode)
return 0;

/* Handle pure domain searches */
if (!fwspec->param_count)
return d->bus_token == bus_token;

/* If this is not DT, then we have a single domain */
if (!is_of_node(fwspec->fwnode))
return 1;
Expand Down
4 changes: 4 additions & 0 deletions drivers/irqchip/irq-imx-intmux.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ static int imx_intmux_irq_select(struct irq_domain *d, struct irq_fwspec *fwspec
if (fwspec->fwnode != d->fwnode)
return false;

/* Handle pure domain searches */
if (!fwspec->param_count)
return d->bus_token == bus_token;

return irqchip_data->chanidx == fwspec->param[1];
}

Expand Down
Loading

0 comments on commit 4527e83

Please sign in to comment.