diff options
Diffstat (limited to 'drivers/irqchip')
-rw-r--r-- | drivers/irqchip/irq-ls-scfg-msi.c | 68 |
1 files changed, 63 insertions, 5 deletions
diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c index 8d57a599c0fb..119f4ef0d421 100644 --- a/drivers/irqchip/irq-ls-scfg-msi.c +++ b/drivers/irqchip/irq-ls-scfg-msi.c @@ -40,6 +40,7 @@ struct ls_scfg_msir { unsigned int gic_irq; unsigned int bit_start; unsigned int bit_end; + unsigned int srs; /* Shared interrupt register select */ void __iomem *reg; }; @@ -70,6 +71,19 @@ static struct msi_domain_info ls_scfg_msi_domain_info = { .chip = &ls_scfg_msi_irq_chip, }; +static int msi_affinity_flag = 1; + +static int __init early_parse_ls_scfg_msi(char *p) +{ + if (p && strncmp(p, "no-affinity", 11) == 0) + msi_affinity_flag = 0; + else + msi_affinity_flag = 1; + + return 0; +} +early_param("lsmsi", early_parse_ls_scfg_msi); + static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg) { struct ls_scfg_msi *msi_data = irq_data_get_irq_chip_data(data); @@ -77,12 +91,36 @@ static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg) msg->address_hi = upper_32_bits(msi_data->msiir_addr); msg->address_lo = lower_32_bits(msi_data->msiir_addr); msg->data = data->hwirq; + + if (msi_affinity_flag) + msg->data |= cpumask_first(data->common->affinity); } static int ls_scfg_msi_set_affinity(struct irq_data *irq_data, const struct cpumask *mask, bool force) { - return -EINVAL; + struct ls_scfg_msi *msi_data = irq_data_get_irq_chip_data(irq_data); + u32 cpu; + + if (!msi_affinity_flag) + return -EINVAL; + + if (!force) + cpu = cpumask_any_and(mask, cpu_online_mask); + else + cpu = cpumask_first(mask); + + if (cpu >= msi_data->msir_num) + return -EINVAL; + + if (msi_data->msir[cpu].gic_irq <= 0) { + pr_warn("cannot bind the irq to cpu%d\n", cpu); + return -EINVAL; + } + + cpumask_copy(irq_data->common->affinity, mask); + + return IRQ_SET_MASK_OK; } static struct irq_chip ls_scfg_msi_parent_chip = { @@ -158,7 +196,7 @@ static void ls_scfg_msi_irq_handler(struct irq_desc *desc) for_each_set_bit_from(pos, &val, size) { hwirq = ((msir->bit_end - pos) << msi_data->cfg->ibs_shift) | - msir->index; + msir->srs; virq = irq_find_mapping(msi_data->parent, hwirq); if (virq) generic_handle_irq(virq); @@ -221,10 +259,19 @@ static int ls_scfg_msi_setup_hwirq(struct ls_scfg_msi *msi_data, int index) ls_scfg_msi_irq_handler, msir); + if (msi_affinity_flag) { + /* Associate MSIR interrupt to the cpu */ + irq_set_affinity(msir->gic_irq, get_cpu_mask(index)); + msir->srs = 0; /* This value is determined by the CPU */ + } else + msir->srs = index; + /* Release the hwirqs corresponding to this MSIR */ - for (i = 0; i < msi_data->cfg->msir_irqs; i++) { - hwirq = i << msi_data->cfg->ibs_shift | msir->index; - bitmap_clear(msi_data->used, hwirq, 1); + if (!msi_affinity_flag || msir->index == 0) { + for (i = 0; i < msi_data->cfg->msir_irqs; i++) { + hwirq = i << msi_data->cfg->ibs_shift | msir->index; + bitmap_clear(msi_data->used, hwirq, 1); + } } return 0; @@ -320,6 +367,17 @@ static int ls_scfg_msi_probe(struct platform_device *pdev) bitmap_set(msi_data->used, 0, msi_data->irqs_num); msi_data->msir_num = of_irq_count(pdev->dev.of_node); + + if (msi_affinity_flag) { + u32 cpu_num; + + cpu_num = num_possible_cpus(); + if (msi_data->msir_num >= cpu_num) + msi_data->msir_num = cpu_num; + else + msi_affinity_flag = 0; + } + msi_data->msir = devm_kcalloc(&pdev->dev, msi_data->msir_num, sizeof(*msi_data->msir), GFP_KERNEL); |