From 781be84cdb27e7985f8521f855f92190404a33b4 Mon Sep 17 00:00:00 2001 From: Xin Hao Date: Thu, 22 Apr 2021 16:33:35 +0800 Subject: [PATCH 2915/2944] ck: kdump: Fix the bug that no vmcore file created This patch is used to solve the problem that there no vmcore files can be created when we case a painc, just like this: echo 1 >/proc/sys/kernel/sysrq echo c >/proc/sysrq-trigger Signed-off-by: Xin Hao Reviewed-by: Baolin Wang --- .../gic_phytium_2500/irq-gic-phytium-2500-its.c | 156 ++++++++++++++++----- .../gic_phytium_2500/irq-gic-phytium-2500.c | 37 +++-- include/linux/irqchip/arm-gic-phytium-2500.h | 3 +- 3 files changed, 153 insertions(+), 43 deletions(-) diff --git a/drivers/staging/gic_phytium_2500/irq-gic-phytium-2500-its.c b/drivers/staging/gic_phytium_2500/irq-gic-phytium-2500-its.c index d72bb95..d8433c8 100644 --- a/drivers/staging/gic_phytium_2500/irq-gic-phytium-2500-its.c +++ b/drivers/staging/gic_phytium_2500/irq-gic-phytium-2500-its.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -53,7 +54,8 @@ #define ITS_FLAGS_WORKAROUND_CAVIUM_23144 (1ULL << 2) #define ITS_FLAGS_SAVE_SUSPEND_STATE (1ULL << 3) -#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0) +#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1ULL << 0) +#define RDIST_FLAGS_RD_TABLES_PREALLOCATED (1ULL << 1) static u32 lpi_id_bits; @@ -1032,7 +1034,7 @@ static inline u32 its_get_event_id(struct irq_data *d) static void lpi_write_config(struct irq_data *d, u8 clr, u8 set) { irq_hw_number_t hwirq; - struct page *prop_page; + void *va; u8 *cfg; if (irqd_is_forwarded_to_vcpu(d)) { @@ -1040,7 +1042,7 @@ static void lpi_write_config(struct irq_data *d, u8 clr, u8 set) u32 event = its_get_event_id(d); struct its_vlpi_map *map; - prop_page = its_dev->event_map.vm->vprop_page; + va = page_address(its_dev->event_map.vm->vprop_page); map = &its_dev->event_map.vlpi_maps[event]; hwirq = map->vintid; @@ -1048,11 +1050,11 @@ static void lpi_write_config(struct irq_data *d, u8 clr, u8 set) map->properties &= ~clr; map->properties |= set | LPI_PROP_GROUP1; } else { - prop_page = gic_rdists->prop_page; + va = gic_rdists->prop_table_va; hwirq = d->hwirq; } - cfg = page_address(prop_page) + hwirq - 8192; + cfg = va + hwirq - 8192; *cfg &= ~clr; *cfg |= set | LPI_PROP_GROUP1; @@ -1137,7 +1139,7 @@ static int its_cpumask_select(struct its_device *its_dev, its_phys_base = its_dev->its->phys_base; skt_id = (its_phys_base >> 41) & 0x7; - if (0 != skt_id) { + if (skt_id != 0) { for (i = 0; i < skt_id; i++) cpus += skt_cpu_cnt[i]; } @@ -1146,6 +1148,22 @@ static int its_cpumask_select(struct its_device *its_dev, if ((cpu > cpus) && (cpu < (cpus + skt_cpu_cnt[skt_id]))) cpus = cpu; + if (is_kdump_kernel()) { + skt = (cpu_logical_map(cpu) >> 16) & 0xff; + if (skt == skt_id) + return cpu; + + for (i = 0; i < nr_cpu_ids; i++) { + skt = (cpu_logical_map(i) >> 16) & 0xff; + if ((skt >= 0) && (skt < MAX_MARS3_SKT_COUNT)) { + if (skt == skt_id) + return i; + } else if (skt != 0xff) { + pr_err("socket address: %d is out of range.", skt); + } + } + } + return cpus; } @@ -1634,6 +1652,15 @@ static void its_lpi_free(unsigned long *bitmap, u32 base, u32 nr_ids) kfree(bitmap); } +static void gic_reset_prop_table(void *va) +{ + /* Priority 0xa0, Group-1, disabled */ + memset(va, LPI_PROP_DEFAULT_PRIO | LPI_PROP_GROUP1, LPI_PROPBASE_SZ); + + /* Make sure the GIC will observe the written configuration */ + gic_flush_dcache_to_poc(va, LPI_PROPBASE_SZ); +} + static struct page *its_allocate_prop_table(gfp_t gfp_flags) { struct page *prop_page; @@ -1642,13 +1669,7 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags) if (!prop_page) return NULL; - /* Priority 0xa0, Group-1, disabled */ - memset(page_address(prop_page), - LPI_PROP_DEFAULT_PRIO | LPI_PROP_GROUP1, - LPI_PROPBASE_SZ); - - /* Make sure the GIC will observe the written configuration */ - gic_flush_dcache_to_poc(page_address(prop_page), LPI_PROPBASE_SZ); + gic_reset_prop_table(page_address(prop_page)); return prop_page; } @@ -1661,18 +1682,35 @@ static void its_free_prop_table(struct page *prop_page) static int __init its_setup_lpi_prop_table(void) { - phys_addr_t paddr; + if (gic_rdists->flags & RDIST_FLAGS_RD_TABLES_PREALLOCATED) { + u64 val; - lpi_id_bits = min_t(u32, GICD_TYPER_ID_BITS(gic_rdists->gicd_typer), - ITS_MAX_LPI_NRBITS); - gic_rdists->prop_page = its_allocate_prop_table(GFP_NOWAIT); - if (!gic_rdists->prop_page) { - pr_err("Failed to allocate PROPBASE\n"); - return -ENOMEM; + val = gicr_read_propbaser(gic_data_rdist_rd_base() + GICR_PROPBASER); + lpi_id_bits = (val & GICR_PROPBASER_IDBITS_MASK) + 1; + + gic_rdists->prop_table_pa = val & GENMASK_ULL(51, 12); + gic_rdists->prop_table_va = memremap(gic_rdists->prop_table_pa, + LPI_PROPBASE_SZ, + MEMREMAP_WB); + gic_reset_prop_table(gic_rdists->prop_table_va); + } else { + struct page *page; + + lpi_id_bits = min_t(u32, + GICD_TYPER_ID_BITS(gic_rdists->gicd_typer), + ITS_MAX_LPI_NRBITS); + page = its_allocate_prop_table(GFP_NOWAIT); + if (!page) { + pr_err("Failed to allocate PROPBASE\n"); + return -ENOMEM; + } + + gic_rdists->prop_table_pa = page_to_phys(page); + gic_rdists->prop_table_va = page_address(page); } - paddr = page_to_phys(gic_rdists->prop_page); - pr_info("GIC: using LPI property table @%pa\n", &paddr); + pr_info("GICv-2500: using LPI property table @%pa\n", + &gic_rdists->prop_table_pa); return its_lpi_init(lpi_id_bits); } @@ -1961,12 +1999,9 @@ static int its_alloc_collections(struct its_node *its) static struct page *its_allocate_pending_table(gfp_t gfp_flags) { struct page *pend_page; - /* - * The pending pages have to be at least 64kB aligned, - * hence the 'max(LPI_PENDBASE_SZ, SZ_64K)' below. - */ + pend_page = alloc_pages(gfp_flags | __GFP_ZERO, - get_order(max_t(u32, LPI_PENDBASE_SZ, SZ_64K))); + get_order(LPI_PENDBASE_SZ)); if (!pend_page) return NULL; @@ -1978,14 +2013,37 @@ static struct page *its_allocate_pending_table(gfp_t gfp_flags) static void its_free_pending_table(struct page *pt) { - free_pages((unsigned long)page_address(pt), - get_order(max_t(u32, LPI_PENDBASE_SZ, SZ_64K))); + free_pages((unsigned long)page_address(pt), get_order(LPI_PENDBASE_SZ)); +} + +/* + * Booting with kdump and LPIs enabled is generally fine. + */ +static bool enabled_lpis_allowed(void) +{ + /* Allow a kdump kernel */ + if (is_kdump_kernel()) + return true; + + return false; } static int __init allocate_lpi_tables(void) { + u64 val; int err, cpu; + /* + * If LPIs are enabled while we run this from the boot CPU, + * flag the RD tables as pre-allocated if the stars do align. + */ + val = readl_relaxed(gic_data_rdist_rd_base() + GICR_CTLR); + if ((val & GICR_CTLR_ENABLE_LPIS) && enabled_lpis_allowed()) { + gic_rdists->flags |= (RDIST_FLAGS_RD_TABLES_PREALLOCATED | + RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING); + pr_info("GICv3: Using preallocated redistributor tables\n"); + } + err = its_setup_lpi_prop_table(); if (err) return err; @@ -2020,11 +2078,23 @@ static void its_cpu_init_lpis(void) if (gic_data_rdist()->lpi_enabled) return; + val = readl_relaxed(rbase + GICR_CTLR); + if ((gic_rdists->flags & RDIST_FLAGS_RD_TABLES_PREALLOCATED) && + (val & GICR_CTLR_ENABLE_LPIS)) { + paddr = gicr_read_pendbaser(rbase + GICR_PENDBASER); + paddr &= GENMASK_ULL(51, 16); + + its_free_pending_table(gic_data_rdist()->pend_page); + gic_data_rdist()->pend_page = NULL; + + goto out; + } + pend_page = gic_data_rdist()->pend_page; paddr = page_to_phys(pend_page); /* set PROPBASE */ - val = (page_to_phys(gic_rdists->prop_page) | + val = (gic_rdists->prop_table_pa | GICR_PROPBASER_InnerShareable | GICR_PROPBASER_RaWaWb | ((LPI_NRBITS - 1) & GICR_PROPBASER_IDBITS_MASK)); @@ -2074,9 +2144,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; - pr_info("GICv3: CPU%d: using LPI pending table @%pa\n", + pr_info("GICv-2500: CPU%d: using %s LPI pending table @%pa\n", smp_processor_id(), + gic_data_rdist()->pend_page ? "allocated" : "reserved", &paddr); } @@ -2481,6 +2553,21 @@ static int its_cpumask_first(struct its_device *its_dev, if ((cpu > cpus) && (cpu < (cpus + skt_cpu_cnt[skt_id]))) cpus = cpu; + if (is_kdump_kernel()) { + skt = (cpu_logical_map(cpu) >> 16) & 0xff; + if (skt == skt_id) + return cpu; + + for (i = 0; i < nr_cpu_ids; i++) { + skt = (cpu_logical_map(i) >> 16) & 0xff; + if ((skt >= 0) && (skt < MAX_MARS3_SKT_COUNT)) { + if (skt == skt_id) + return i; + } else if (skt != 0xff) { + pr_err("socket address: %d is out of range.", skt); + } + } + } return cpus; } @@ -2498,8 +2585,6 @@ static int its_irq_domain_activate(struct irq_domain *domain, /* Bind the LPI to the first possible CPU */ cpu = its_cpumask_first(its_dev, cpu_mask); - printk("its_irq_domain_activate: MAPTI irq %d hwirq %ld on cpu %d\n", - d->irq, d->hwirq, cpu); its_dev->event_map.col_map[event] = cpu; irq_data_update_effective_affinity(d, cpumask_of(cpu)); @@ -3602,8 +3687,11 @@ static int redist_disable_lpis(void) * If coming via a CPU hotplug event, we don't need to disable * LPIs before trying to re-enable them. They are already * configured and all is well in the world. + * + * If running with preallocated tables, there is nothing to do. */ - if (gic_data_rdist()->lpi_enabled) + if (gic_data_rdist()->lpi_enabled || + (gic_rdists->flags & RDIST_FLAGS_RD_TABLES_PREALLOCATED)) return 0; /* diff --git a/drivers/staging/gic_phytium_2500/irq-gic-phytium-2500.c b/drivers/staging/gic_phytium_2500/irq-gic-phytium-2500.c index be6afa0..4f3e3f2 100644 --- a/drivers/staging/gic_phytium_2500/irq-gic-phytium-2500.c +++ b/drivers/staging/gic_phytium_2500/irq-gic-phytium-2500.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -799,10 +800,6 @@ static void gic_cpu_init(void) } } - /* Give LPIs a spin */ - if (gic_dist_supports_lpis()) - phytium_its_cpu_init(); - /* initialise system registers */ gic_cpu_sys_reg_init(); } @@ -815,6 +812,10 @@ static void gic_cpu_init(void) static int gic_starting_cpu(unsigned int cpu) { gic_cpu_init(); + + if (gic_dist_supports_lpis()) + phytium_its_cpu_init(); + return 0; } @@ -922,6 +923,21 @@ static int gic_cpumask_select(struct irq_data *d, const struct cpumask *mask_val if ((cpu > cpus) && (cpu < (cpus + skt_cpu_cnt[irq_skt]))) cpus = cpu; + if (is_kdump_kernel()) { + skt = (cpu_logical_map(cpu) >> 16) & 0xff; + if (irq_skt == skt) + return cpu; + + for (i = 0; i < nr_cpu_ids; i++) { + skt = (cpu_logical_map(i) >> 16) & 0xff; + if ((skt >= 0) && (skt < MAX_MARS3_SOC_COUNT)) { + if (irq_skt == skt) + return i; + } else if (skt != 0xff) { + pr_err("socket address: %d is out of range.", skt); + } + } + } return cpus; } @@ -1276,14 +1292,16 @@ static int __init gic_init_bases(void __iomem *dist_base, gic_update_vlpi_properties(); - if (gic_dist_supports_lpis()) - phytium_its_init(handle, &gic_data.rdists, gic_data.domain); - gic_smp_init(); gic_dist_init(); gic_cpu_init(); gic_cpu_pm_init(); + if (gic_dist_supports_lpis()) { + phytium_its_init(handle, &gic_data.rdists, gic_data.domain); + phytium_its_cpu_init(); + } + return 0; out_free: @@ -1441,7 +1459,6 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare } if (of_address_to_resource(node, 0, &res)) { - printk("Error: No GIC Distributor in FDT\n"); goto out_unmap_dist; } @@ -1802,6 +1819,10 @@ static void __init gic_acpi_setup_kvm_info(void) mars3_gic_dists[0].dist_base = acpi_data.dist_base; mars3_sockets_bitmap = gic_mars3_sockets_bitmap(); + if (is_kdump_kernel()) { + mars3_sockets_bitmap = 0x3; + } + if (mars3_sockets_bitmap == 0) { mars3_sockets_bitmap = 0x1; pr_err("No socket, please check cpus MPIDR_AFFINITY_LEVEL!"); diff --git a/include/linux/irqchip/arm-gic-phytium-2500.h b/include/linux/irqchip/arm-gic-phytium-2500.h index 17518fa..2ae61f3 100644 --- a/include/linux/irqchip/arm-gic-phytium-2500.h +++ b/include/linux/irqchip/arm-gic-phytium-2500.h @@ -587,7 +587,8 @@ struct rdists { phys_addr_t phys_base; bool lpi_enabled; } __percpu *rdist; - struct page *prop_page; + phys_addr_t prop_table_pa; + void *prop_table_va; u64 flags; u32 gicd_typer; bool has_vlpis; -- 1.8.3.1