irqchip fixes for 5.6, take #1

- Guarantee allocation of L2 vPE table for GICv4.1
 - Fix GICv4.1 VPROPBASER programming
 - Numerous GICv4.1 tidy ups
 - Fix disabled GICv3 redistributor provisioning with ACPI
 - KConfig cleanup for C-SKY
 -----BEGIN PGP SIGNATURE-----
 
 iQJDBAABCgAtFiEEn9UcU+C1Yxj9lZw9I9DQutE9ekMFAl4+nyAPHG1hekBrZXJu
 ZWwub3JnAAoJECPQ0LrRPXpDNDAP/2Us9avq4NnTk9x8Kbe7Y6mCgBHcqFLfLH+t
 yiwGK+TbTvFoy9SXdlD9NCoTIKQGDH1qmWj9PG9WKUOGEpwYuerRmie2H3Lk9pF+
 KYcHmXi9PTfDmkFBavIupf+l7+PBj3CZa3pVqy/6Wo2iMbItZmJqLlPFqX3rmMbj
 NqAZWfs9nBtWqa5e8g99g233VAVW7JqEnCZJQdkD6Bm+IGWVX0cUQWftrCYkhkQl
 iLIpxc0lKuxydtGAeAZqvWJqkz+xd6k+UpxCoCwiORAaE8j6U0UPPJZmqu5JKBdN
 8nKwpya9eZzKxBTurmdiqXdgGfNfxyAG0SR8wgU80RrM6UzciJNlk/yYgCfRSpar
 zGhaKbqM2AauDULfmal09OIMnvrBW+8Swk36VeDVHzkjdBymaA2Tare9feeOHv6b
 eLVVIwQdPnNf5yB6lKWJpp1d5BIh+asASMpuyO10dMBfSMvyOqe1VhlPaInRQqh3
 qDaSdbKXR19aEZ3NTtps/3rRYPsAU2K/3gacraEMj5E1EW6aRoODjOzl3G0Gr23+
 f01VyKLgMs7PWCUBdcHNUrk8CBAELFZ6C/6KCXOPgnG445NpGt3BkAHvNCEvCqqQ
 EDPdImBeZzEi2u+/61567Irb/WwrbKrtWGYE8fESiaCK93eVHqxTUcSboIwWGz/s
 WNJdP8QZ
 =DQlH
 -----END PGP SIGNATURE-----

Merge tag 'irqchip-fixes-5.6-1' of git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms into irq/urgent

Pull irqchip fixes for 5.6, take #1 from Marc Zyngier:

 - Guarantee allocation of L2 vPE table for GICv4.1
 - Fix GICv4.1 VPROPBASER programming
 - Numerous GICv4.1 tidy ups
 - Fix disabled GICv3 redistributor provisioning with ACPI
 - KConfig cleanup for C-SKY
This commit is contained in:
Thomas Gleixner 2020-02-08 15:54:03 +01:00
commit 2f86e45a7f
6 changed files with 120 additions and 35 deletions

View File

@ -326,16 +326,16 @@ static inline u64 __gic_readq_nonatomic(const volatile void __iomem *addr)
#define gits_write_cwriter(v, c) __gic_writeq_nonatomic(v, c) #define gits_write_cwriter(v, c) __gic_writeq_nonatomic(v, c)
/* /*
* GITS_VPROPBASER - hi and lo bits may be accessed independently. * GICR_VPROPBASER - hi and lo bits may be accessed independently.
*/ */
#define gits_read_vpropbaser(c) __gic_readq_nonatomic(c) #define gicr_read_vpropbaser(c) __gic_readq_nonatomic(c)
#define gits_write_vpropbaser(v, c) __gic_writeq_nonatomic(v, c) #define gicr_write_vpropbaser(v, c) __gic_writeq_nonatomic(v, c)
/* /*
* GITS_VPENDBASER - the Valid bit must be cleared before changing * GICR_VPENDBASER - the Valid bit must be cleared before changing
* anything else. * anything else.
*/ */
static inline void gits_write_vpendbaser(u64 val, void __iomem *addr) static inline void gicr_write_vpendbaser(u64 val, void __iomem *addr)
{ {
u32 tmp; u32 tmp;
@ -352,7 +352,7 @@ static inline void gits_write_vpendbaser(u64 val, void __iomem *addr)
__gic_writeq_nonatomic(val, addr); __gic_writeq_nonatomic(val, addr);
} }
#define gits_read_vpendbaser(c) __gic_readq_nonatomic(c) #define gicr_read_vpendbaser(c) __gic_readq_nonatomic(c)
static inline bool gic_prio_masking_enabled(void) static inline bool gic_prio_masking_enabled(void)
{ {

View File

@ -140,11 +140,11 @@ static inline u32 gic_read_rpr(void)
#define gicr_write_pendbaser(v, c) writeq_relaxed(v, c) #define gicr_write_pendbaser(v, c) writeq_relaxed(v, c)
#define gicr_read_pendbaser(c) readq_relaxed(c) #define gicr_read_pendbaser(c) readq_relaxed(c)
#define gits_write_vpropbaser(v, c) writeq_relaxed(v, c) #define gicr_write_vpropbaser(v, c) writeq_relaxed(v, c)
#define gits_read_vpropbaser(c) readq_relaxed(c) #define gicr_read_vpropbaser(c) readq_relaxed(c)
#define gits_write_vpendbaser(v, c) writeq_relaxed(v, c) #define gicr_write_vpendbaser(v, c) writeq_relaxed(v, c)
#define gits_read_vpendbaser(c) readq_relaxed(c) #define gicr_read_vpendbaser(c) readq_relaxed(c)
static inline bool gic_prio_masking_enabled(void) static inline bool gic_prio_masking_enabled(void)
{ {

View File

@ -438,7 +438,7 @@ config CSKY_MPINTC
help help
Say yes here to enable C-SKY SMP interrupt controller driver used Say yes here to enable C-SKY SMP interrupt controller driver used
for C-SKY SMP system. for C-SKY SMP system.
In fact it's not mmio map in hw and it use ld/st to visit the In fact it's not mmio map in hardware and it uses ld/st to visit the
controller's register inside CPU. controller's register inside CPU.
config CSKY_APB_INTC config CSKY_APB_INTC
@ -446,7 +446,7 @@ config CSKY_APB_INTC
depends on CSKY depends on CSKY
help help
Say yes here to enable C-SKY APB interrupt controller driver used Say yes here to enable C-SKY APB interrupt controller driver used
by C-SKY single core SOC system. It use mmio map apb-bus to visit by C-SKY single core SOC system. It uses mmio map apb-bus to visit
the controller's register. the controller's register.
config IMX_IRQSTEER config IMX_IRQSTEER

View File

@ -661,7 +661,7 @@ static struct its_collection *its_build_invall_cmd(struct its_node *its,
struct its_cmd_desc *desc) struct its_cmd_desc *desc)
{ {
its_encode_cmd(cmd, GITS_CMD_INVALL); its_encode_cmd(cmd, GITS_CMD_INVALL);
its_encode_collection(cmd, desc->its_mapc_cmd.col->col_id); its_encode_collection(cmd, desc->its_invall_cmd.col->col_id);
its_fixup_cmd(cmd); its_fixup_cmd(cmd);
@ -2376,6 +2376,8 @@ static u64 inherit_vpe_l1_table_from_its(void)
continue; continue;
/* We have a winner! */ /* We have a winner! */
gic_data_rdist()->vpe_l1_base = its->tables[2].base;
val = GICR_VPROPBASER_4_1_VALID; val = GICR_VPROPBASER_4_1_VALID;
if (baser & GITS_BASER_INDIRECT) if (baser & GITS_BASER_INDIRECT)
val |= GICR_VPROPBASER_4_1_INDIRECT; val |= GICR_VPROPBASER_4_1_INDIRECT;
@ -2413,14 +2415,12 @@ static u64 inherit_vpe_l1_table_from_rd(cpumask_t **mask)
for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) {
void __iomem *base = gic_data_rdist_cpu(cpu)->rd_base; void __iomem *base = gic_data_rdist_cpu(cpu)->rd_base;
u32 tmp;
if (!base || cpu == smp_processor_id()) if (!base || cpu == smp_processor_id())
continue; continue;
val = gic_read_typer(base + GICR_TYPER); val = gic_read_typer(base + GICR_TYPER);
tmp = compute_common_aff(val); if (aff != compute_common_aff(val))
if (tmp != aff)
continue; continue;
/* /*
@ -2429,9 +2429,10 @@ static u64 inherit_vpe_l1_table_from_rd(cpumask_t **mask)
* ours wrt CommonLPIAff. Let's use its own VPROPBASER. * ours wrt CommonLPIAff. Let's use its own VPROPBASER.
* Make sure we don't write the Z bit in that case. * Make sure we don't write the Z bit in that case.
*/ */
val = gits_read_vpropbaser(base + SZ_128K + GICR_VPROPBASER); val = gicr_read_vpropbaser(base + SZ_128K + GICR_VPROPBASER);
val &= ~GICR_VPROPBASER_4_1_Z; val &= ~GICR_VPROPBASER_4_1_Z;
gic_data_rdist()->vpe_l1_base = gic_data_rdist_cpu(cpu)->vpe_l1_base;
*mask = gic_data_rdist_cpu(cpu)->vpe_table_mask; *mask = gic_data_rdist_cpu(cpu)->vpe_table_mask;
return val; return val;
@ -2440,6 +2441,72 @@ static u64 inherit_vpe_l1_table_from_rd(cpumask_t **mask)
return 0; return 0;
} }
static bool allocate_vpe_l2_table(int cpu, u32 id)
{
void __iomem *base = gic_data_rdist_cpu(cpu)->rd_base;
u64 val, gpsz, npg;
unsigned int psz, esz, idx;
struct page *page;
__le64 *table;
if (!gic_rdists->has_rvpeid)
return true;
val = gicr_read_vpropbaser(base + SZ_128K + GICR_VPROPBASER);
esz = FIELD_GET(GICR_VPROPBASER_4_1_ENTRY_SIZE, val) + 1;
gpsz = FIELD_GET(GICR_VPROPBASER_4_1_PAGE_SIZE, val);
npg = FIELD_GET(GICR_VPROPBASER_4_1_SIZE, val) + 1;
switch (gpsz) {
default:
WARN_ON(1);
/* fall through */
case GIC_PAGE_SIZE_4K:
psz = SZ_4K;
break;
case GIC_PAGE_SIZE_16K:
psz = SZ_16K;
break;
case GIC_PAGE_SIZE_64K:
psz = SZ_64K;
break;
}
/* Don't allow vpe_id that exceeds single, flat table limit */
if (!(val & GICR_VPROPBASER_4_1_INDIRECT))
return (id < (npg * psz / (esz * SZ_8)));
/* Compute 1st level table index & check if that exceeds table limit */
idx = id >> ilog2(psz / (esz * SZ_8));
if (idx >= (npg * psz / GITS_LVL1_ENTRY_SIZE))
return false;
table = gic_data_rdist_cpu(cpu)->vpe_l1_base;
/* Allocate memory for 2nd level table */
if (!table[idx]) {
page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(psz));
if (!page)
return false;
/* Flush Lvl2 table to PoC if hw doesn't support coherency */
if (!(val & GICR_VPROPBASER_SHAREABILITY_MASK))
gic_flush_dcache_to_poc(page_address(page), psz);
table[idx] = cpu_to_le64(page_to_phys(page) | GITS_BASER_VALID);
/* Flush Lvl1 entry to PoC if hw doesn't support coherency */
if (!(val & GICR_VPROPBASER_SHAREABILITY_MASK))
gic_flush_dcache_to_poc(table + idx, GITS_LVL1_ENTRY_SIZE);
/* Ensure updated table contents are visible to RD hardware */
dsb(sy);
}
return true;
}
static int allocate_vpe_l1_table(void) static int allocate_vpe_l1_table(void)
{ {
void __iomem *vlpi_base = gic_data_rdist_vlpi_base(); void __iomem *vlpi_base = gic_data_rdist_vlpi_base();
@ -2457,8 +2524,8 @@ static int allocate_vpe_l1_table(void)
* effect of making sure no doorbell will be generated and we can * effect of making sure no doorbell will be generated and we can
* then safely clear VPROPBASER.Valid. * then safely clear VPROPBASER.Valid.
*/ */
if (gits_read_vpendbaser(vlpi_base + GICR_VPENDBASER) & GICR_VPENDBASER_Valid) if (gicr_read_vpendbaser(vlpi_base + GICR_VPENDBASER) & GICR_VPENDBASER_Valid)
gits_write_vpendbaser(GICR_VPENDBASER_PendingLast, gicr_write_vpendbaser(GICR_VPENDBASER_PendingLast,
vlpi_base + GICR_VPENDBASER); vlpi_base + GICR_VPENDBASER);
/* /*
@ -2481,8 +2548,8 @@ static int allocate_vpe_l1_table(void)
/* First probe the page size */ /* First probe the page size */
val = FIELD_PREP(GICR_VPROPBASER_4_1_PAGE_SIZE, GIC_PAGE_SIZE_64K); val = FIELD_PREP(GICR_VPROPBASER_4_1_PAGE_SIZE, GIC_PAGE_SIZE_64K);
gits_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER); gicr_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER);
val = gits_read_vpropbaser(vlpi_base + GICR_VPROPBASER); val = gicr_read_vpropbaser(vlpi_base + GICR_VPROPBASER);
gpsz = FIELD_GET(GICR_VPROPBASER_4_1_PAGE_SIZE, val); gpsz = FIELD_GET(GICR_VPROPBASER_4_1_PAGE_SIZE, val);
esz = FIELD_GET(GICR_VPROPBASER_4_1_ENTRY_SIZE, val); esz = FIELD_GET(GICR_VPROPBASER_4_1_ENTRY_SIZE, val);
@ -2531,7 +2598,7 @@ static int allocate_vpe_l1_table(void)
npg = 1; npg = 1;
} }
val |= FIELD_PREP(GICR_VPROPBASER_4_1_SIZE, npg); val |= FIELD_PREP(GICR_VPROPBASER_4_1_SIZE, npg - 1);
/* Right, that's the number of CPU pages we need for L1 */ /* Right, that's the number of CPU pages we need for L1 */
np = DIV_ROUND_UP(npg * psz, PAGE_SIZE); np = DIV_ROUND_UP(npg * psz, PAGE_SIZE);
@ -2542,7 +2609,7 @@ static int allocate_vpe_l1_table(void)
if (!page) if (!page)
return -ENOMEM; return -ENOMEM;
gic_data_rdist()->vpe_l1_page = page; gic_data_rdist()->vpe_l1_base = page_address(page);
pa = virt_to_phys(page_address(page)); pa = virt_to_phys(page_address(page));
WARN_ON(!IS_ALIGNED(pa, psz)); WARN_ON(!IS_ALIGNED(pa, psz));
@ -2553,7 +2620,7 @@ static int allocate_vpe_l1_table(void)
val |= GICR_VPROPBASER_4_1_VALID; val |= GICR_VPROPBASER_4_1_VALID;
out: out:
gits_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER); gicr_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER);
cpumask_set_cpu(smp_processor_id(), gic_data_rdist()->vpe_table_mask); cpumask_set_cpu(smp_processor_id(), gic_data_rdist()->vpe_table_mask);
pr_debug("CPU%d: VPROPBASER = %llx %*pbl\n", pr_debug("CPU%d: VPROPBASER = %llx %*pbl\n",
@ -2660,14 +2727,14 @@ static u64 its_clear_vpend_valid(void __iomem *vlpi_base, u64 clr, u64 set)
bool clean; bool clean;
u64 val; u64 val;
val = gits_read_vpendbaser(vlpi_base + GICR_VPENDBASER); val = gicr_read_vpendbaser(vlpi_base + GICR_VPENDBASER);
val &= ~GICR_VPENDBASER_Valid; val &= ~GICR_VPENDBASER_Valid;
val &= ~clr; val &= ~clr;
val |= set; val |= set;
gits_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER); gicr_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);
do { do {
val = gits_read_vpendbaser(vlpi_base + GICR_VPENDBASER); val = gicr_read_vpendbaser(vlpi_base + GICR_VPENDBASER);
clean = !(val & GICR_VPENDBASER_Dirty); clean = !(val & GICR_VPENDBASER_Dirty);
if (!clean) { if (!clean) {
count--; count--;
@ -2782,7 +2849,7 @@ static void its_cpu_init_lpis(void)
val = (LPI_NRBITS - 1) & GICR_VPROPBASER_IDBITS_MASK; val = (LPI_NRBITS - 1) & GICR_VPROPBASER_IDBITS_MASK;
pr_debug("GICv4: CPU%d: Init IDbits to 0x%llx for GICR_VPROPBASER\n", pr_debug("GICv4: CPU%d: Init IDbits to 0x%llx for GICR_VPROPBASER\n",
smp_processor_id(), val); smp_processor_id(), val);
gits_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER); gicr_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER);
/* /*
* Also clear Valid bit of GICR_VPENDBASER, in case some * Also clear Valid bit of GICR_VPENDBASER, in case some
@ -2790,7 +2857,6 @@ static void its_cpu_init_lpis(void)
* corrupting memory. * corrupting memory.
*/ */
val = its_clear_vpend_valid(vlpi_base, 0, 0); val = its_clear_vpend_valid(vlpi_base, 0, 0);
WARN_ON(val & GICR_VPENDBASER_Dirty);
} }
if (allocate_vpe_l1_table()) { if (allocate_vpe_l1_table()) {
@ -2954,6 +3020,7 @@ static bool its_alloc_device_table(struct its_node *its, u32 dev_id)
static bool its_alloc_vpe_table(u32 vpe_id) static bool its_alloc_vpe_table(u32 vpe_id)
{ {
struct its_node *its; struct its_node *its;
int cpu;
/* /*
* Make sure the L2 tables are allocated on *all* v4 ITSs. We * Make sure the L2 tables are allocated on *all* v4 ITSs. We
@ -2976,6 +3043,19 @@ static bool its_alloc_vpe_table(u32 vpe_id)
return false; return false;
} }
/* Non v4.1? No need to iterate RDs and go back early. */
if (!gic_rdists->has_rvpeid)
return true;
/*
* Make sure the L2 tables are allocated for all copies of
* the L1 table on *all* v4.1 RDs.
*/
for_each_possible_cpu(cpu) {
if (!allocate_vpe_l2_table(cpu, vpe_id))
return false;
}
return true; return true;
} }
@ -3443,7 +3523,7 @@ static void its_vpe_schedule(struct its_vpe *vpe)
val |= (LPI_NRBITS - 1) & GICR_VPROPBASER_IDBITS_MASK; val |= (LPI_NRBITS - 1) & GICR_VPROPBASER_IDBITS_MASK;
val |= GICR_VPROPBASER_RaWb; val |= GICR_VPROPBASER_RaWb;
val |= GICR_VPROPBASER_InnerShareable; val |= GICR_VPROPBASER_InnerShareable;
gits_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER); gicr_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER);
val = virt_to_phys(page_address(vpe->vpt_page)) & val = virt_to_phys(page_address(vpe->vpt_page)) &
GENMASK_ULL(51, 16); GENMASK_ULL(51, 16);
@ -3461,7 +3541,7 @@ static void its_vpe_schedule(struct its_vpe *vpe)
val |= GICR_VPENDBASER_PendingLast; val |= GICR_VPENDBASER_PendingLast;
val |= vpe->idai ? GICR_VPENDBASER_IDAI : 0; val |= vpe->idai ? GICR_VPENDBASER_IDAI : 0;
val |= GICR_VPENDBASER_Valid; val |= GICR_VPENDBASER_Valid;
gits_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER); gicr_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);
} }
static void its_vpe_deschedule(struct its_vpe *vpe) static void its_vpe_deschedule(struct its_vpe *vpe)
@ -3661,7 +3741,7 @@ static void its_vpe_4_1_schedule(struct its_vpe *vpe,
val |= info->g1en ? GICR_VPENDBASER_4_1_VGRP1EN : 0; val |= info->g1en ? GICR_VPENDBASER_4_1_VGRP1EN : 0;
val |= FIELD_PREP(GICR_VPENDBASER_4_1_VPEID, vpe->vpe_id); val |= FIELD_PREP(GICR_VPENDBASER_4_1_VPEID, vpe->vpe_id);
gits_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER); gicr_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);
} }
static void its_vpe_4_1_deschedule(struct its_vpe *vpe, static void its_vpe_4_1_deschedule(struct its_vpe *vpe,

View File

@ -1839,6 +1839,7 @@ static struct
struct redist_region *redist_regs; struct redist_region *redist_regs;
u32 nr_redist_regions; u32 nr_redist_regions;
bool single_redist; bool single_redist;
int enabled_rdists;
u32 maint_irq; u32 maint_irq;
int maint_irq_mode; int maint_irq_mode;
phys_addr_t vcpu_base; phys_addr_t vcpu_base;
@ -1933,8 +1934,10 @@ static int __init gic_acpi_match_gicc(union acpi_subtable_headers *header,
* If GICC is enabled and has valid gicr base address, then it means * If GICC is enabled and has valid gicr base address, then it means
* GICR base is presented via GICC * GICR base is presented via GICC
*/ */
if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address) if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address) {
acpi_data.enabled_rdists++;
return 0; return 0;
}
/* /*
* It's perfectly valid firmware can pass disabled GICC entry, driver * It's perfectly valid firmware can pass disabled GICC entry, driver
@ -1964,8 +1967,10 @@ static int __init gic_acpi_count_gicr_regions(void)
count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
gic_acpi_match_gicc, 0); gic_acpi_match_gicc, 0);
if (count > 0) if (count > 0) {
acpi_data.single_redist = true; acpi_data.single_redist = true;
count = acpi_data.enabled_rdists;
}
return count; return count;
} }

View File

@ -652,10 +652,10 @@ struct rdists {
struct { struct {
void __iomem *rd_base; void __iomem *rd_base;
struct page *pend_page; struct page *pend_page;
struct page *vpe_l1_page;
phys_addr_t phys_base; phys_addr_t phys_base;
bool lpi_enabled; bool lpi_enabled;
cpumask_t *vpe_table_mask; cpumask_t *vpe_table_mask;
void *vpe_l1_base;
} __percpu *rdist; } __percpu *rdist;
phys_addr_t prop_table_pa; phys_addr_t prop_table_pa;
void *prop_table_va; void *prop_table_va;