Skip to content

Commit

Permalink
Merge tag 'irq-core-2022-01-13' of git://git.kernel.org/pub/scm/linux…
Browse files Browse the repository at this point in the history
…/kernel/git/tip/tip

Pull irq updates from Thomas Gleixner:
 "Updates for the interrupt subsystem:

  Core:

   - Provide a new interface for affinity hints to provide a separation
     between hint and actual affinity change which has become a hidden
     property of the current interface

   - Fix up the in tree usage of the affinity hint interfaces

  Drivers:

   - No new irqchip drivers!

   - Fix GICv3 redistributor table reservation with RT across kexec

   - Fix GICv4.1 redistributor view of the VPE table across kexec

   - Add support for extra interrupts on spear-shirq

   - Make obtaining some interrupts optional for the Renesas drivers

   - Various cleanups and bug fixes"

* tag 'irq-core-2022-01-13' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (25 commits)
  irqchip/renesas-intc-irqpin: Use platform_get_irq_optional() to get the interrupt
  irqchip/renesas-irqc: Use platform_get_irq_optional() to get the interrupt
  irqchip/gic-v4: Disable redistributors' view of the VPE table at boot time
  irqchip/ingenic-tcu: Use correctly sized arguments for bit field
  irqchip/gic-v2m: Add const to of_device_id
  irqchip/imx-gpcv2: Mark imx_gpcv2_instance with __ro_after_init
  irqchip/spear-shirq: Add support for IRQ 0..6
  irqchip/gic-v3-its: Limit memreserve cpuhp state lifetime
  irqchip/gic-v3-its: Postpone LPI pending table freeing and memreserve
  irqchip/gic-v3-its: Give the percpu rdist struct its own flags field
  net/mlx4: Use irq_update_affinity_hint()
  net/mlx5: Use irq_set_affinity_and_hint()
  hinic: Use irq_set_affinity_and_hint()
  scsi: lpfc: Use irq_set_affinity()
  mailbox: Use irq_update_affinity_hint()
  ixgbe: Use irq_update_affinity_hint()
  be2net: Use irq_update_affinity_hint()
  enic: Use irq_update_affinity_hint()
  RDMA/irdma: Use irq_update_affinity_hint()
  scsi: mpt3sas: Use irq_set_affinity_and_hint()
  ...
  • Loading branch information
Linus Torvalds committed Jan 13, 2022
2 parents 455e73a + 67d50b5 commit 147cc58
Show file tree
Hide file tree
Showing 26 changed files with 228 additions and 86 deletions.
4 changes: 2 additions & 2 deletions drivers/infiniband/hw/irdma/hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ static void irdma_destroy_irq(struct irdma_pci_f *rf,
struct irdma_sc_dev *dev = &rf->sc_dev;

dev->irq_ops->irdma_dis_irq(dev, msix_vec->idx);
irq_set_affinity_hint(msix_vec->irq, NULL);
irq_update_affinity_hint(msix_vec->irq, NULL);
free_irq(msix_vec->irq, dev_id);
}

Expand Down Expand Up @@ -1100,7 +1100,7 @@ irdma_cfg_ceq_vector(struct irdma_pci_f *rf, struct irdma_ceq *iwceq,
}
cpumask_clear(&msix_vec->mask);
cpumask_set_cpu(msix_vec->cpu_affinity, &msix_vec->mask);
irq_set_affinity_hint(msix_vec->irq, &msix_vec->mask);
irq_update_affinity_hint(msix_vec->irq, &msix_vec->mask);
if (status) {
ibdev_dbg(&rf->iwdev->ibdev, "ERR: ceq irq config fail\n");
return IRDMA_ERR_CFG;
Expand Down
2 changes: 1 addition & 1 deletion drivers/irqchip/irq-gic-v2m.c
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
return ret;
}

static struct of_device_id gicv2m_device_id[] = {
static const struct of_device_id gicv2m_device_id[] = {
{ .compatible = "arm,gic-v2m-frame", },
{},
};
Expand Down
82 changes: 75 additions & 7 deletions drivers/irqchip/irq-gic-v3-its.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@
#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0)
#define RDIST_FLAGS_RD_TABLES_PREALLOCATED (1 << 1)

#define RD_LOCAL_LPI_ENABLED BIT(0)
#define RD_LOCAL_PENDTABLE_PREALLOCATED BIT(1)
#define RD_LOCAL_MEMRESERVE_DONE BIT(2)

static u32 lpi_id_bits;

/*
Expand Down Expand Up @@ -3044,7 +3048,7 @@ static void its_cpu_init_lpis(void)
phys_addr_t paddr;
u64 val, tmp;

if (gic_data_rdist()->lpi_enabled)
if (gic_data_rdist()->flags & RD_LOCAL_LPI_ENABLED)
return;

val = readl_relaxed(rbase + GICR_CTLR);
Expand All @@ -3063,15 +3067,13 @@ static void its_cpu_init_lpis(void)
paddr &= GENMASK_ULL(51, 16);

WARN_ON(!gic_check_reserved_range(paddr, LPI_PENDBASE_SZ));
its_free_pending_table(gic_data_rdist()->pend_page);
gic_data_rdist()->pend_page = NULL;
gic_data_rdist()->flags |= RD_LOCAL_PENDTABLE_PREALLOCATED;

goto out;
}

pend_page = gic_data_rdist()->pend_page;
paddr = page_to_phys(pend_page);
WARN_ON(gic_reserve_range(paddr, LPI_PENDBASE_SZ));

/* set PROPBASE */
val = (gic_rdists->prop_table_pa |
Expand Down Expand Up @@ -3158,10 +3160,11 @@ static void its_cpu_init_lpis(void)
/* Make sure the GIC has seen the above */
dsb(sy);
out:
gic_data_rdist()->lpi_enabled = true;
gic_data_rdist()->flags |= RD_LOCAL_LPI_ENABLED;
pr_info("GICv3: CPU%d: using %s LPI pending table @%pa\n",
smp_processor_id(),
gic_data_rdist()->pend_page ? "allocated" : "reserved",
gic_data_rdist()->flags & RD_LOCAL_PENDTABLE_PREALLOCATED ?
"reserved" : "allocated",
&paddr);
}

Expand Down Expand Up @@ -5138,7 +5141,7 @@ static int redist_disable_lpis(void)
*
* If running with preallocated tables, there is nothing to do.
*/
if (gic_data_rdist()->lpi_enabled ||
if ((gic_data_rdist()->flags & RD_LOCAL_LPI_ENABLED) ||
(gic_rdists->flags & RDIST_FLAGS_RD_TABLES_PREALLOCATED))
return 0;

Expand Down Expand Up @@ -5200,6 +5203,51 @@ int its_cpu_init(void)
return 0;
}

static void rdist_memreserve_cpuhp_cleanup_workfn(struct work_struct *work)
{
cpuhp_remove_state_nocalls(gic_rdists->cpuhp_memreserve_state);
gic_rdists->cpuhp_memreserve_state = CPUHP_INVALID;
}

static DECLARE_WORK(rdist_memreserve_cpuhp_cleanup_work,
rdist_memreserve_cpuhp_cleanup_workfn);

static int its_cpu_memreserve_lpi(unsigned int cpu)
{
struct page *pend_page;
int ret = 0;

/* This gets to run exactly once per CPU */
if (gic_data_rdist()->flags & RD_LOCAL_MEMRESERVE_DONE)
return 0;

pend_page = gic_data_rdist()->pend_page;
if (WARN_ON(!pend_page)) {
ret = -ENOMEM;
goto out;
}
/*
* If the pending table was pre-programmed, free the memory we
* preemptively allocated. Otherwise, reserve that memory for
* later kexecs.
*/
if (gic_data_rdist()->flags & RD_LOCAL_PENDTABLE_PREALLOCATED) {
its_free_pending_table(pend_page);
gic_data_rdist()->pend_page = NULL;
} else {
phys_addr_t paddr = page_to_phys(pend_page);
WARN_ON(gic_reserve_range(paddr, LPI_PENDBASE_SZ));
}

out:
/* Last CPU being brought up gets to issue the cleanup */
if (cpumask_equal(&cpus_booted_once_mask, cpu_possible_mask))
schedule_work(&rdist_memreserve_cpuhp_cleanup_work);

gic_data_rdist()->flags |= RD_LOCAL_MEMRESERVE_DONE;
return ret;
}

static const struct of_device_id its_device_id[] = {
{ .compatible = "arm,gic-v3-its", },
{},
Expand Down Expand Up @@ -5383,6 +5431,26 @@ static void __init its_acpi_probe(void)
static void __init its_acpi_probe(void) { }
#endif

int __init its_lpi_memreserve_init(void)
{
int state;

if (!efi_enabled(EFI_CONFIG_TABLES))
return 0;

gic_rdists->cpuhp_memreserve_state = CPUHP_INVALID;
state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
"irqchip/arm/gicv3/memreserve:online",
its_cpu_memreserve_lpi,
NULL);
if (state < 0)
return state;

gic_rdists->cpuhp_memreserve_state = state;

return 0;
}

int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
struct irq_domain *parent_domain)
{
Expand Down
17 changes: 17 additions & 0 deletions drivers/irqchip/irq-gic-v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -920,6 +920,22 @@ static int __gic_update_rdist_properties(struct redist_region *region,
{
u64 typer = gic_read_typer(ptr + GICR_TYPER);

/* Boot-time cleanip */
if ((typer & GICR_TYPER_VLPIS) && (typer & GICR_TYPER_RVPEID)) {
u64 val;

/* Deactivate any present vPE */
val = gicr_read_vpendbaser(ptr + SZ_128K + GICR_VPENDBASER);
if (val & GICR_VPENDBASER_Valid)
gicr_write_vpendbaser(GICR_VPENDBASER_PendingLast,
ptr + SZ_128K + GICR_VPENDBASER);

/* Mark the VPE table as invalid */
val = gicr_read_vpropbaser(ptr + SZ_128K + GICR_VPROPBASER);
val &= ~GICR_VPROPBASER_4_1_VALID;
gicr_write_vpropbaser(val, ptr + SZ_128K + GICR_VPROPBASER);
}

gic_data.rdists.has_vlpis &= !!(typer & GICR_TYPER_VLPIS);

/* RVPEID implies some form of DirectLPI, no matter what the doc says... :-/ */
Expand Down Expand Up @@ -1802,6 +1818,7 @@ static int __init gic_init_bases(void __iomem *dist_base,
if (gic_dist_supports_lpis()) {
its_init(handle, &gic_data.rdists, gic_data.domain);
its_cpu_init();
its_lpi_memreserve_init();
} else {
if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
gicv2m_init(handle, gic_data.domain);
Expand Down
2 changes: 1 addition & 1 deletion drivers/irqchip/irq-imx-gpcv2.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ struct gpcv2_irqchip_data {
u32 cpu2wakeup;
};

static struct gpcv2_irqchip_data *imx_gpcv2_instance;
static struct gpcv2_irqchip_data *imx_gpcv2_instance __ro_after_init;

static void __iomem *gpcv2_idx_to_reg(struct gpcv2_irqchip_data *cd, int i)
{
Expand Down
4 changes: 3 additions & 1 deletion drivers/irqchip/irq-ingenic-tcu.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ static void ingenic_tcu_intc_cascade(struct irq_desc *desc)
struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0);
struct regmap *map = gc->private;
uint32_t irq_reg, irq_mask;
unsigned long bits;
unsigned int i;

regmap_read(map, TCU_REG_TFR, &irq_reg);
Expand All @@ -36,8 +37,9 @@ static void ingenic_tcu_intc_cascade(struct irq_desc *desc)
chained_irq_enter(irq_chip, desc);

irq_reg &= ~irq_mask;
bits = irq_reg;

for_each_set_bit(i, (unsigned long *)&irq_reg, 32)
for_each_set_bit(i, &bits, 32)
generic_handle_domain_irq(domain, i);

chained_irq_exit(irq_chip, desc);
Expand Down
9 changes: 5 additions & 4 deletions drivers/irqchip/irq-renesas-intc-irqpin.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,6 @@ static int intc_irqpin_probe(struct platform_device *pdev)
struct intc_irqpin_priv *p;
struct intc_irqpin_iomem *i;
struct resource *io[INTC_IRQPIN_REG_NR];
struct resource *irq;
struct irq_chip *irq_chip;
void (*enable_fn)(struct irq_data *d);
void (*disable_fn)(struct irq_data *d);
Expand Down Expand Up @@ -418,12 +417,14 @@ static int intc_irqpin_probe(struct platform_device *pdev)

/* allow any number of IRQs between 1 and INTC_IRQPIN_MAX */
for (k = 0; k < INTC_IRQPIN_MAX; k++) {
irq = platform_get_resource(pdev, IORESOURCE_IRQ, k);
if (!irq)
ret = platform_get_irq_optional(pdev, k);
if (ret == -ENXIO)
break;
if (ret < 0)
goto err0;

p->irq[k].p = p;
p->irq[k].requested_irq = irq->start;
p->irq[k].requested_irq = ret;
}

nirqs = k;
Expand Down
9 changes: 5 additions & 4 deletions drivers/irqchip/irq-renesas-irqc.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ static int irqc_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
const char *name = dev_name(dev);
struct irqc_priv *p;
struct resource *irq;
int ret;
int k;

Expand All @@ -142,13 +141,15 @@ static int irqc_probe(struct platform_device *pdev)

/* allow any number of IRQs between 1 and IRQC_IRQ_MAX */
for (k = 0; k < IRQC_IRQ_MAX; k++) {
irq = platform_get_resource(pdev, IORESOURCE_IRQ, k);
if (!irq)
ret = platform_get_irq_optional(pdev, k);
if (ret == -ENXIO)
break;
if (ret < 0)
goto err_runtime_pm_disable;

p->irq[k].p = p;
p->irq[k].hw_irq = k;
p->irq[k].requested_irq = irq->start;
p->irq[k].requested_irq = ret;
}

p->number_of_irqs = k;
Expand Down
2 changes: 2 additions & 0 deletions drivers/irqchip/spear-shirq.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ static struct spear_shirq spear320_shirq_ras3 = {
.offset = 0,
.nr_irqs = 7,
.mask = ((0x1 << 7) - 1) << 0,
.irq_chip = &dummy_irq_chip,
.status_reg = SPEAR320_INT_STS_MASK_REG,
};

static struct spear_shirq spear320_shirq_ras1 = {
Expand Down
4 changes: 2 additions & 2 deletions drivers/mailbox/bcm-flexrm-mailbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -1298,7 +1298,7 @@ static int flexrm_startup(struct mbox_chan *chan)
val = (num_online_cpus() < val) ? val / num_online_cpus() : 1;
cpumask_set_cpu((ring->num / val) % num_online_cpus(),
&ring->irq_aff_hint);
ret = irq_set_affinity_hint(ring->irq, &ring->irq_aff_hint);
ret = irq_update_affinity_hint(ring->irq, &ring->irq_aff_hint);
if (ret) {
dev_err(ring->mbox->dev,
"failed to set IRQ affinity hint for ring%d\n",
Expand Down Expand Up @@ -1425,7 +1425,7 @@ static void flexrm_shutdown(struct mbox_chan *chan)

/* Release IRQ */
if (ring->irq_requested) {
irq_set_affinity_hint(ring->irq, NULL);
irq_update_affinity_hint(ring->irq, NULL);
free_irq(ring->irq, ring);
ring->irq_requested = false;
}
Expand Down
8 changes: 4 additions & 4 deletions drivers/net/ethernet/cisco/enic/enic_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,10 @@ static void enic_set_affinity_hint(struct enic *enic)
!cpumask_available(enic->msix[i].affinity_mask) ||
cpumask_empty(enic->msix[i].affinity_mask))
continue;
err = irq_set_affinity_hint(enic->msix_entry[i].vector,
enic->msix[i].affinity_mask);
err = irq_update_affinity_hint(enic->msix_entry[i].vector,
enic->msix[i].affinity_mask);
if (err)
netdev_warn(enic->netdev, "irq_set_affinity_hint failed, err %d\n",
netdev_warn(enic->netdev, "irq_update_affinity_hint failed, err %d\n",
err);
}

Expand All @@ -173,7 +173,7 @@ static void enic_unset_affinity_hint(struct enic *enic)
int i;

for (i = 0; i < enic->intr_count; i++)
irq_set_affinity_hint(enic->msix_entry[i].vector, NULL);
irq_update_affinity_hint(enic->msix_entry[i].vector, NULL);
}

static int enic_udp_tunnel_set_port(struct net_device *netdev,
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/ethernet/emulex/benet/be_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3491,7 +3491,7 @@ static int be_msix_register(struct be_adapter *adapter)
if (status)
goto err_msix;

irq_set_affinity_hint(vec, eqo->affinity_mask);
irq_update_affinity_hint(vec, eqo->affinity_mask);
}

return 0;
Expand Down Expand Up @@ -3552,7 +3552,7 @@ static void be_irq_unregister(struct be_adapter *adapter)
/* MSIx */
for_all_evt_queues(adapter, eqo, i) {
vec = be_msix_vec_get(adapter, eqo);
irq_set_affinity_hint(vec, NULL);
irq_update_affinity_hint(vec, NULL);
free_irq(vec, eqo);
}

Expand Down
4 changes: 2 additions & 2 deletions drivers/net/ethernet/huawei/hinic/hinic_rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ static int rx_request_irq(struct hinic_rxq *rxq)
goto err_req_irq;

cpumask_set_cpu(qp->q_id % num_online_cpus(), &rq->affinity_mask);
err = irq_set_affinity_hint(rq->irq, &rq->affinity_mask);
err = irq_set_affinity_and_hint(rq->irq, &rq->affinity_mask);
if (err)
goto err_irq_affinity;

Expand All @@ -565,7 +565,7 @@ static void rx_free_irq(struct hinic_rxq *rxq)
{
struct hinic_rq *rq = rxq->rq;

irq_set_affinity_hint(rq->irq, NULL);
irq_update_affinity_hint(rq->irq, NULL);
free_irq(rq->irq, rxq);
rx_del_napi(rxq);
}
Expand Down
8 changes: 4 additions & 4 deletions drivers/net/ethernet/intel/i40e/i40e_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3915,10 +3915,10 @@ static int i40e_vsi_request_irq_msix(struct i40e_vsi *vsi, char *basename)
*
* get_cpu_mask returns a static constant mask with
* a permanent lifetime so it's ok to pass to
* irq_set_affinity_hint without making a copy.
* irq_update_affinity_hint without making a copy.
*/
cpu = cpumask_local_spread(q_vector->v_idx, -1);
irq_set_affinity_hint(irq_num, get_cpu_mask(cpu));
irq_update_affinity_hint(irq_num, get_cpu_mask(cpu));
}

vsi->irqs_ready = true;
Expand All @@ -3929,7 +3929,7 @@ static int i40e_vsi_request_irq_msix(struct i40e_vsi *vsi, char *basename)
vector--;
irq_num = pf->msix_entries[base + vector].vector;
irq_set_affinity_notifier(irq_num, NULL);
irq_set_affinity_hint(irq_num, NULL);
irq_update_affinity_hint(irq_num, NULL);
free_irq(irq_num, &vsi->q_vectors[vector]);
}
return err;
Expand Down Expand Up @@ -4750,7 +4750,7 @@ static void i40e_vsi_free_irq(struct i40e_vsi *vsi)
/* clear the affinity notifier in the IRQ descriptor */
irq_set_affinity_notifier(irq_num, NULL);
/* remove our suggested affinity mask for this IRQ */
irq_set_affinity_hint(irq_num, NULL);
irq_update_affinity_hint(irq_num, NULL);
synchronize_irq(irq_num);
free_irq(irq_num, vsi->q_vectors[i]);

Expand Down
Loading

0 comments on commit 147cc58

Please sign in to comment.