Skip to content

Commit 8087f40

Browse files
committed
Merge tag 'irqchip-5.0-3' of git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms into irq/urgent
Pull irqchip updates from Marc Zyngier: - Another GICv3 ITS fix for devices sharing the same DevID - Don't return invalid data on exhaustion of the GICv3 LPI pool - Fix a GICv3 field decoding bug leading to memory over-allocation - Init GICv4 at boot time instead of lazy init - Fix interrupt masking on PJ4
2 parents 37b144d + 5684107 commit 8087f40

File tree

3 files changed

+85
-24
lines changed

3 files changed

+85
-24
lines changed

drivers/irqchip/irq-gic-v3-its.c

Lines changed: 79 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,14 @@ struct its_device;
9797
* The ITS structure - contains most of the infrastructure, with the
9898
* top-level MSI domain, the command queue, the collections, and the
9999
* list of devices writing to it.
100+
*
101+
* dev_alloc_lock has to be taken for device allocations, while the
102+
* spinlock must be taken to parse data structures such as the device
103+
* list.
100104
*/
101105
struct its_node {
102106
raw_spinlock_t lock;
107+
struct mutex dev_alloc_lock;
103108
struct list_head entry;
104109
void __iomem *base;
105110
phys_addr_t phys_base;
@@ -156,6 +161,7 @@ struct its_device {
156161
void *itt;
157162
u32 nr_ites;
158163
u32 device_id;
164+
bool shared;
159165
};
160166

161167
static struct {
@@ -1580,6 +1586,9 @@ static unsigned long *its_lpi_alloc(int nr_irqs, u32 *base, int *nr_ids)
15801586
nr_irqs /= 2;
15811587
} while (nr_irqs > 0);
15821588

1589+
if (!nr_irqs)
1590+
err = -ENOSPC;
1591+
15831592
if (err)
15841593
goto out;
15851594

@@ -2059,6 +2068,29 @@ static int __init allocate_lpi_tables(void)
20592068
return 0;
20602069
}
20612070

2071+
static u64 its_clear_vpend_valid(void __iomem *vlpi_base)
2072+
{
2073+
u32 count = 1000000; /* 1s! */
2074+
bool clean;
2075+
u64 val;
2076+
2077+
val = gits_read_vpendbaser(vlpi_base + GICR_VPENDBASER);
2078+
val &= ~GICR_VPENDBASER_Valid;
2079+
gits_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);
2080+
2081+
do {
2082+
val = gits_read_vpendbaser(vlpi_base + GICR_VPENDBASER);
2083+
clean = !(val & GICR_VPENDBASER_Dirty);
2084+
if (!clean) {
2085+
count--;
2086+
cpu_relax();
2087+
udelay(1);
2088+
}
2089+
} while (!clean && count);
2090+
2091+
return val;
2092+
}
2093+
20622094
static void its_cpu_init_lpis(void)
20632095
{
20642096
void __iomem *rbase = gic_data_rdist_rd_base();
@@ -2144,6 +2176,30 @@ static void its_cpu_init_lpis(void)
21442176
val |= GICR_CTLR_ENABLE_LPIS;
21452177
writel_relaxed(val, rbase + GICR_CTLR);
21462178

2179+
if (gic_rdists->has_vlpis) {
2180+
void __iomem *vlpi_base = gic_data_rdist_vlpi_base();
2181+
2182+
/*
2183+
* It's possible for CPU to receive VLPIs before it is
2184+
* sheduled as a vPE, especially for the first CPU, and the
2185+
* VLPI with INTID larger than 2^(IDbits+1) will be considered
2186+
* as out of range and dropped by GIC.
2187+
* So we initialize IDbits to known value to avoid VLPI drop.
2188+
*/
2189+
val = (LPI_NRBITS - 1) & GICR_VPROPBASER_IDBITS_MASK;
2190+
pr_debug("GICv4: CPU%d: Init IDbits to 0x%llx for GICR_VPROPBASER\n",
2191+
smp_processor_id(), val);
2192+
gits_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER);
2193+
2194+
/*
2195+
* Also clear Valid bit of GICR_VPENDBASER, in case some
2196+
* ancient programming gets left in and has possibility of
2197+
* corrupting memory.
2198+
*/
2199+
val = its_clear_vpend_valid(vlpi_base);
2200+
WARN_ON(val & GICR_VPENDBASER_Dirty);
2201+
}
2202+
21472203
/* Make sure the GIC has seen the above */
21482204
dsb(sy);
21492205
out:
@@ -2422,6 +2478,7 @@ static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
24222478
struct its_device *its_dev;
24232479
struct msi_domain_info *msi_info;
24242480
u32 dev_id;
2481+
int err = 0;
24252482

24262483
/*
24272484
* We ignore "dev" entierely, and rely on the dev_id that has
@@ -2444,25 +2501,30 @@ static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
24442501
return -EINVAL;
24452502
}
24462503

2504+
mutex_lock(&its->dev_alloc_lock);
24472505
its_dev = its_find_device(its, dev_id);
24482506
if (its_dev) {
24492507
/*
24502508
* We already have seen this ID, probably through
24512509
* another alias (PCI bridge of some sort). No need to
24522510
* create the device.
24532511
*/
2512+
its_dev->shared = true;
24542513
pr_debug("Reusing ITT for devID %x\n", dev_id);
24552514
goto out;
24562515
}
24572516

24582517
its_dev = its_create_device(its, dev_id, nvec, true);
2459-
if (!its_dev)
2460-
return -ENOMEM;
2518+
if (!its_dev) {
2519+
err = -ENOMEM;
2520+
goto out;
2521+
}
24612522

24622523
pr_debug("ITT %d entries, %d bits\n", nvec, ilog2(nvec));
24632524
out:
2525+
mutex_unlock(&its->dev_alloc_lock);
24642526
info->scratchpad[0].ptr = its_dev;
2465-
return 0;
2527+
return err;
24662528
}
24672529

24682530
static struct msi_domain_ops its_msi_domain_ops = {
@@ -2566,6 +2628,7 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq,
25662628
{
25672629
struct irq_data *d = irq_domain_get_irq_data(domain, virq);
25682630
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
2631+
struct its_node *its = its_dev->its;
25692632
int i;
25702633

25712634
for (i = 0; i < nr_irqs; i++) {
@@ -2580,8 +2643,14 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq,
25802643
irq_domain_reset_irq_data(data);
25812644
}
25822645

2583-
/* If all interrupts have been freed, start mopping the floor */
2584-
if (bitmap_empty(its_dev->event_map.lpi_map,
2646+
mutex_lock(&its->dev_alloc_lock);
2647+
2648+
/*
2649+
* If all interrupts have been freed, start mopping the
2650+
* floor. This is conditionned on the device not being shared.
2651+
*/
2652+
if (!its_dev->shared &&
2653+
bitmap_empty(its_dev->event_map.lpi_map,
25852654
its_dev->event_map.nr_lpis)) {
25862655
its_lpi_free(its_dev->event_map.lpi_map,
25872656
its_dev->event_map.lpi_base,
@@ -2593,6 +2662,8 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq,
25932662
its_free_device(its_dev);
25942663
}
25952664

2665+
mutex_unlock(&its->dev_alloc_lock);
2666+
25962667
irq_domain_free_irqs_parent(domain, virq, nr_irqs);
25972668
}
25982669

@@ -2755,26 +2826,11 @@ static void its_vpe_schedule(struct its_vpe *vpe)
27552826
static void its_vpe_deschedule(struct its_vpe *vpe)
27562827
{
27572828
void __iomem *vlpi_base = gic_data_rdist_vlpi_base();
2758-
u32 count = 1000000; /* 1s! */
2759-
bool clean;
27602829
u64 val;
27612830

2762-
/* We're being scheduled out */
2763-
val = gits_read_vpendbaser(vlpi_base + GICR_VPENDBASER);
2764-
val &= ~GICR_VPENDBASER_Valid;
2765-
gits_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);
2766-
2767-
do {
2768-
val = gits_read_vpendbaser(vlpi_base + GICR_VPENDBASER);
2769-
clean = !(val & GICR_VPENDBASER_Dirty);
2770-
if (!clean) {
2771-
count--;
2772-
cpu_relax();
2773-
udelay(1);
2774-
}
2775-
} while (!clean && count);
2831+
val = its_clear_vpend_valid(vlpi_base);
27762832

2777-
if (unlikely(!clean && !count)) {
2833+
if (unlikely(val & GICR_VPENDBASER_Dirty)) {
27782834
pr_err_ratelimited("ITS virtual pending table not cleaning\n");
27792835
vpe->idai = false;
27802836
vpe->pending_last = true;
@@ -3517,6 +3573,7 @@ static int __init its_probe_one(struct resource *res,
35173573
}
35183574

35193575
raw_spin_lock_init(&its->lock);
3576+
mutex_init(&its->dev_alloc_lock);
35203577
INIT_LIST_HEAD(&its->entry);
35213578
INIT_LIST_HEAD(&its->its_device_list);
35223579
typer = gic_read_typer(its_base + GITS_TYPER);

drivers/irqchip/irq-mmp.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
#define SEL_INT_PENDING (1 << 6)
3535
#define SEL_INT_NUM_MASK 0x3f
3636

37+
#define MMP2_ICU_INT_ROUTE_PJ4_IRQ (1 << 5)
38+
#define MMP2_ICU_INT_ROUTE_PJ4_FIQ (1 << 6)
39+
3740
struct icu_chip_data {
3841
int nr_irqs;
3942
unsigned int virq_base;
@@ -190,7 +193,8 @@ static const struct mmp_intc_conf mmp_conf = {
190193
static const struct mmp_intc_conf mmp2_conf = {
191194
.conf_enable = 0x20,
192195
.conf_disable = 0x0,
193-
.conf_mask = 0x7f,
196+
.conf_mask = MMP2_ICU_INT_ROUTE_PJ4_IRQ |
197+
MMP2_ICU_INT_ROUTE_PJ4_FIQ,
194198
};
195199

196200
static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs)

include/linux/irqchip/arm-gic-v3.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@
319319
#define GITS_TYPER_PLPIS (1UL << 0)
320320
#define GITS_TYPER_VLPIS (1UL << 1)
321321
#define GITS_TYPER_ITT_ENTRY_SIZE_SHIFT 4
322-
#define GITS_TYPER_ITT_ENTRY_SIZE(r) ((((r) >> GITS_TYPER_ITT_ENTRY_SIZE_SHIFT) & 0x1f) + 1)
322+
#define GITS_TYPER_ITT_ENTRY_SIZE(r) ((((r) >> GITS_TYPER_ITT_ENTRY_SIZE_SHIFT) & 0xf) + 1)
323323
#define GITS_TYPER_IDBITS_SHIFT 8
324324
#define GITS_TYPER_DEVBITS_SHIFT 13
325325
#define GITS_TYPER_DEVBITS(r) ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)

0 commit comments

Comments
 (0)