From ff445a14d39756f37264de9347fd0ff2219579d3 Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Tue, 11 Jun 2024 16:38:50 +0800 Subject: [PATCH 1/4] LoongArch: fix KASLR can not be disabled by nokaslr when boot from old BPI After this patch,KASLR is really disabled when nokaslr passed from boot parameter for old BPI. Fixes: 59eab58e4779 ("LoongArch: Old BPI compatibility") Signed-off-by: Hongchen Zhang Signed-off-by: Ming Wang Signed-off-by: Yanteng Si --- arch/loongarch/kernel/legacy_boot.h | 3 +++ arch/loongarch/kernel/relocate.c | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/loongarch/kernel/legacy_boot.h b/arch/loongarch/kernel/legacy_boot.h index f69011a2f6bb5..0d0b428dd7f26 100644 --- a/arch/loongarch/kernel/legacy_boot.h +++ b/arch/loongarch/kernel/legacy_boot.h @@ -4,6 +4,7 @@ #include #include #include +#include #define ADDRESS_TYPE_SYSRAM 1 #define ADDRESS_TYPE_RESERVED 2 @@ -89,4 +90,6 @@ extern int __init pch_msi_parse_madt(union acpi_subtable_headers *header, const unsigned long end); extern struct irq_domain *get_pchpic_irq_domain(void); + +extern __init void fw_init_cmdline(unsigned long argc, unsigned long cmdp); #endif diff --git a/arch/loongarch/kernel/relocate.c b/arch/loongarch/kernel/relocate.c index 1acfa704c8d09..aaa27823ea29d 100644 --- a/arch/loongarch/kernel/relocate.c +++ b/arch/loongarch/kernel/relocate.c @@ -15,6 +15,7 @@ #include #include #include +#include "legacy_boot.h" #define RELOCATED(x) ((void *)((long)x + reloc_offset)) #define RELOCATED_KASLR(x) ((void *)((long)x + random_offset)) @@ -172,7 +173,10 @@ unsigned long __init relocate_kernel(void) void *location_new = _text; /* Default to original kernel start */ char *cmdline = early_ioremap(fw_arg1, COMMAND_LINE_SIZE); /* Boot command line is passed in fw_arg1 */ - strscpy(boot_command_line, cmdline, COMMAND_LINE_SIZE); + if (fw_arg0 < 2) + strscpy(boot_command_line, cmdline, COMMAND_LINE_SIZE); + else + fw_init_cmdline(fw_arg0, TO_CACHE(fw_arg1)); /* OLD BPI parameters */ #ifdef CONFIG_RANDOMIZE_BASE location_new = determine_relocation_address(); From c5c3da15e2da2134d283037bef4cabe0eaf190f3 Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Tue, 11 Jun 2024 16:38:52 +0800 Subject: [PATCH 2/4] irqchip/loongson-pch-pic: Update interrupt registration policy The current code is using a fixed mapping between the LS7A interrupt source and the HT interrupt vector. This prevents the utilization of the full interrupt vector space and therefore limits the number of interrupt source in a system. Replace the fixed mapping with a dynamic mapping which allocates a vector when an interrupt source is set up. This avoids that unused sources prevent vectors from being used for other devices. Introduce a mapping table in struct pch_pic, where each interrupt source will allocate an index as a 'hwirq' number from the table in the order of application and set table value as interrupt source number. This hwirq number will be configured as vector in the HT interrupt controller. For an interrupt source, the validity period of the obtained hwirq will last until the system reset. Co-developed-by: Biao Dong Signed-off-by: Biao Dong Co-developed-by: Tianyang Zhang Signed-off-by: Tianyang Zhang Signed-off-by: Baoqi Zhang Signed-off-by: Yanteng Si --- drivers/irqchip/irq-loongson-pch-pic.c | 70 ++++++++++++++++++++------ 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/drivers/irqchip/irq-loongson-pch-pic.c b/drivers/irqchip/irq-loongson-pch-pic.c index 372215f2b9ed4..bccb415d20152 100644 --- a/drivers/irqchip/irq-loongson-pch-pic.c +++ b/drivers/irqchip/irq-loongson-pch-pic.c @@ -28,6 +28,7 @@ #define PCH_INT_HTVEC(irq) (0x200 + irq) #define PCH_PIC_POL 0x3e0 +#define PIC_UNDEF_VECTOR 255 #define PIC_COUNT_PER_REG 32 #define PIC_REG_COUNT 2 #define PIC_COUNT (PIC_COUNT_PER_REG * PIC_REG_COUNT) @@ -46,6 +47,8 @@ struct pch_pic { u32 saved_vec_en[PIC_REG_COUNT]; u32 saved_vec_pol[PIC_REG_COUNT]; u32 saved_vec_edge[PIC_REG_COUNT]; + u8 table[PIC_COUNT]; + int inuse; }; static struct pch_pic *pch_pic_priv[MAX_IO_PICS]; @@ -57,6 +60,11 @@ struct irq_domain *get_pchpic_irq_domain(void) return pch_pic_priv[0]->pic_domain; } +static inline u8 hwirq_to_bit(struct pch_pic *priv, int hirq) +{ + return priv->table[hirq]; +} + static void pch_pic_bitset(struct pch_pic *priv, int offset, int bit) { u32 reg; @@ -85,45 +93,47 @@ static void pch_pic_mask_irq(struct irq_data *d) { struct pch_pic *priv = irq_data_get_irq_chip_data(d); - pch_pic_bitset(priv, PCH_PIC_MASK, d->hwirq); + pch_pic_bitset(priv, PCH_PIC_MASK, hwirq_to_bit(priv, d->hwirq)); irq_chip_mask_parent(d); } static void pch_pic_unmask_irq(struct irq_data *d) { struct pch_pic *priv = irq_data_get_irq_chip_data(d); + int bit = hwirq_to_bit(priv, d->hwirq); writel(BIT(PIC_REG_BIT(d->hwirq)), - priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4); + priv->base + PCH_PIC_CLR + PIC_REG_IDX(bit) * 4); irq_chip_unmask_parent(d); - pch_pic_bitclr(priv, PCH_PIC_MASK, d->hwirq); + pch_pic_bitclr(priv, PCH_PIC_MASK, bit); } static int pch_pic_set_type(struct irq_data *d, unsigned int type) { struct pch_pic *priv = irq_data_get_irq_chip_data(d); + int bit = hwirq_to_bit(priv, d->hwirq); int ret = 0; switch (type) { case IRQ_TYPE_EDGE_RISING: - pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq); - pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq); + pch_pic_bitset(priv, PCH_PIC_EDGE, bit); + pch_pic_bitclr(priv, PCH_PIC_POL, bit); irq_set_handler_locked(d, handle_edge_irq); break; case IRQ_TYPE_EDGE_FALLING: - pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq); - pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq); + pch_pic_bitset(priv, PCH_PIC_EDGE, bit); + pch_pic_bitset(priv, PCH_PIC_POL, bit); irq_set_handler_locked(d, handle_edge_irq); break; case IRQ_TYPE_LEVEL_HIGH: - pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq); - pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq); + pch_pic_bitclr(priv, PCH_PIC_EDGE, bit); + pch_pic_bitclr(priv, PCH_PIC_POL, bit); irq_set_handler_locked(d, handle_level_irq); break; case IRQ_TYPE_LEVEL_LOW: - pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq); - pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq); + pch_pic_bitclr(priv, PCH_PIC_EDGE, bit); + pch_pic_bitset(priv, PCH_PIC_POL, bit); irq_set_handler_locked(d, handle_level_irq); break; default: @@ -138,11 +148,12 @@ static void pch_pic_ack_irq(struct irq_data *d) { unsigned int reg; struct pch_pic *priv = irq_data_get_irq_chip_data(d); + int bit = hwirq_to_bit(priv, d->hwirq); - reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(d->hwirq) * 4); + reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(bit) * 4); if (reg & BIT(PIC_REG_BIT(d->hwirq))) { writel(BIT(PIC_REG_BIT(d->hwirq)), - priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4); + priv->base + PCH_PIC_CLR + PIC_REG_IDX(bit) * 4); } irq_chip_ack_parent(d); } @@ -164,6 +175,8 @@ static int pch_pic_domain_translate(struct irq_domain *d, { struct pch_pic *priv = d->host_data; struct device_node *of_node = to_of_node(fwspec->fwnode); + unsigned long flags; + int i; if (of_node) { if (fwspec->param_count < 2) @@ -176,12 +189,33 @@ static int pch_pic_domain_translate(struct irq_domain *d, return -EINVAL; *hwirq = fwspec->param[0] - priv->gsi_base; + if (fwspec->param_count > 1) *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; else *type = IRQ_TYPE_NONE; } + raw_spin_lock_irqsave(&priv->pic_lock, flags); + /* Check pic-table to confirm if the hwirq has been assigned */ + for (i = 0; i < priv->inuse; i++) { + if (priv->table[i] == *hwirq) { + *hwirq = i; + break; + } + } + if (i == priv->inuse) { + /* Assign a new hwirq in pic-table */ + if (priv->inuse >= PIC_COUNT) { + pr_err("pch-pic domain has no free vectors\n"); + raw_spin_unlock_irqrestore(&priv->pic_lock, flags); + return -EINVAL; + } + priv->table[priv->inuse] = *hwirq; + *hwirq = priv->inuse++; + } + raw_spin_unlock_irqrestore(&priv->pic_lock, flags); + return 0; } @@ -199,6 +233,9 @@ static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq, if (err) return err; + /* Write vector ID */ + writeb(priv->ht_vec_base + hwirq, priv->base + PCH_INT_HTVEC(hwirq_to_bit(priv, hwirq))); + parent_fwspec.fwnode = domain->parent->fwnode; parent_fwspec.param_count = 1; parent_fwspec.param[0] = hwirq + priv->ht_vec_base; @@ -227,7 +264,7 @@ static void pch_pic_reset(struct pch_pic *priv) for (i = 0; i < PIC_COUNT; i++) { /* Write vector ID */ - writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(i)); + writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(hwirq_to_bit(priv, i))); /* Hardcode route to HT0 Lo */ writeb(1, priv->base + PCH_INT_ROUTE(i)); } @@ -289,6 +326,7 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base, u32 gsi_base) { struct pch_pic *priv; + int i; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) @@ -299,6 +337,10 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base, if (!priv->base) goto free_priv; + priv->inuse = 0; + for (i = 0; i < PIC_COUNT; i++) + priv->table[i] = PIC_UNDEF_VECTOR; + priv->ht_vec_base = vec_base; priv->vec_count = ((readq(priv->base) >> 48) & 0xff) + 1; priv->gsi_base = gsi_base; From 16b46d963210d7dbd0bfc9d3a46c99681756414a Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Tue, 11 Jun 2024 15:16:25 +0800 Subject: [PATCH 3/4] irqchip/loongson-eiointc: fix gsi register error When we boot a 3C5000-7A2000 2Node server using "nr_cpus=1 maxcpus=1", we get the following Call Trace: 4.807397] ------------[ cut here ]------------ [ 4.811996] WARNING: CPU: 0 PID: 1 at drivers/acpi/irq.c:63 acpi_register_gsi+0xe0/0x100 [ 4.820048] Modules linked in: [ 4.823082] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 6.9.0-rc7-next-20240509+ #26 [ 4.830604] Hardware name: LOONGSON Dabieshan/Loongson-LS2C50C2, BIOS Loongson UEFI (3C50007A2000_Ls2c5lc2) V4.0.13-Dual 12/06/23 17:33:54 [ 4.842964] pc 9000000000bdc6e0 ra 9000000000bdc66c tp 90000002051d4000 sp 90000002051d7ae0 [ 4.851269] a0 0000000000000000 a1 00000000000000a0 a2 0000000000000000 a3 0000000000000000 [ 4.859567] a4 9000000200014518 a5 000000000000003c a6 90000000018876b0 a7 00302e39303a3030 [ 4.867866] t0 0000000000000000 t1 0000000000000080 t2 0000000000000040 t3 0000000000036800 [ 4.876165] t4 0000000000036800 t5 0000000000000004 t6 0000000000000000 t7 0000000000000000 [ 4.884464] t8 900000000800d910 u0 0000000000000000 s9 90000000014bf9e8 s0 00000000000000a0 [ 4.892763] s1 0000000000000000 s2 0000000000000000 s3 9000000001985000 s4 90000002051d7b88 [ 4.901063] s5 0000000000000001 s6 90000002055470b8 s7 90000000014400ac s8 0000000000000008 [ 4.909362] ra: 9000000000bdc66c acpi_register_gsi+0x6c/0x100 [ 4.915330] ERA: 9000000000bdc6e0 acpi_register_gsi+0xe0/0x100 [ 4.921297] CRMD: 000000b0 (PLV0 -IE -DA +PG DACF=CC DACM=CC -WE) [ 4.927446] PRMD: 00000004 (PPLV0 +PIE -PWE) [ 4.931777] EUEN: 00000000 (-FPE -SXE -ASXE -BTE) [ 4.936538] ECFG: 00071c1d (LIE=0,2-4,10-12 VS=7) [ 4.941301] ESTAT: 000c0000 [BRK] (IS= ECode=12 EsubCode=0) [ 4.946838] PRID: 0014c011 (Loongson-64bit, Loongson-3C5000) [ 4.952545] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 6.9.0-rc7-next-20240509+ #26 [ 4.960066] Hardware name: LOONGSON Dabieshan/Loongson-LS2C50C2, BIOS Loongson UEFI (3C50007A2000_Ls2c5lc2) V4.0.13-Dual 12/06/23 17:33:54 [ 4.972425] Stack : 9000000001985000 0000000000000000 9000000000223524 90000002051d4000 [ 4.980382] 90000002051d7740 90000002051d7748 0000000000000000 90000002051d7888 [ 4.988338] 90000002051d7880 90000002051d7880 90000002051d7690 0000000000000001 [ 4.996294] 0000000000000001 90000002051d7748 420a070366b7e75d 90000002054f4500 [ 5.004251] 0000000000000001 0000000000000000 4137303030354333 c0000000ffffdfff [ 5.012206] 0000000000000003 00000000000ea642 0000000006b3c000 90000000014bf9e8 [ 5.020163] 0000000000000000 0000000000000000 90000000017f7e80 9000000001985000 [ 5.028119] 0000000000000001 0000000000000000 ffffffffffd7f549 90000000014400ac [ 5.036075] 0000000000000008 0000000000000000 900000000022353c 00007ffff1354000 [ 5.044031] 00000000000000b0 0000000000000004 0000000000000000 0000000000071c1d [ 5.051987] ... [ 5.054410] Call Trace: [ 5.054412] [<900000000022353c>] show_stack+0x5c/0x1a0 [ 5.061940] [<900000000141e86c>] dump_stack_lvl+0x9c/0xc4 [ 5.067305] [<900000000140170c>] __warn+0x94/0xcc [ 5.071977] [<90000000013cd900>] report_bug+0x160/0x220 [ 5.077170] [<900000000141facc>] do_bp+0x26c/0x2e0 [ 5.081929] [<0000000000000000>] 0x0 [ 5.085475] [<9000000000bdc6e0>] acpi_register_gsi+0xe0/0x100 [ 5.091182] [<9000000000bd5350>] acpi_pci_irq_enable+0xd0/0x220 [ 5.097061] [<9000000000b5e8d4>] pci_device_probe+0x54/0x260 [ 5.102683] [<9000000000d1fefc>] really_probe+0xbc/0x320 [ 5.107960] [<9000000000d201f0>] __driver_probe_device+0x90/0x160 [ 5.114012] [<9000000000d202f8>] driver_probe_device+0x38/0x120 [ 5.119892] [<9000000000d205d4>] __driver_attach+0x94/0x1c0 [ 5.125426] [<9000000000d1d7ac>] bus_for_each_dev+0x8c/0x100 [ 5.131046] [<9000000000d1ee30>] bus_add_driver+0xf0/0x240 [ 5.136494] [<9000000000d21688>] driver_register+0x68/0x140 [ 5.142028] [<9000000000220158>] do_one_initcall+0x78/0x200 [ 5.147561] [<9000000001440fcc>] kernel_init_freeable+0x23c/0x2b0 [ 5.153614] [<900000000142123c>] kernel_init+0x1c/0x120 [ 5.158802] [<9000000000221348>] ret_from_kernel_thread+0xc/0xa4 [ 5.166244] ---[ end trace 0000000000000000 ]--- [ 5.170998] GSI: No registered irqchip, giving up The root cause is that when the CPU boot from flat mode, it is unreliable to use cpu_to node to calculate the node number. Therefore, we use NODES_PER_FLATMODE_NODE to calculate the physical node number. According to the 3C5000 user manual, the value of NODES_PER_FLATMODE_NODE should be 4. Signed-off-by: Ming Wang Signed-off-by: Hongchen Zhang Signed-off-by: Yanteng Si --- arch/loongarch/include/asm/numa.h | 1 + drivers/irqchip/irq-loongson-eiointc.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/loongarch/include/asm/numa.h b/arch/loongarch/include/asm/numa.h index 27f319b498625..564c27d2de726 100644 --- a/arch/loongarch/include/asm/numa.h +++ b/arch/loongarch/include/asm/numa.h @@ -12,6 +12,7 @@ #include #define NODE_ADDRSPACE_SHIFT 44 +#define NODES_PER_FLATMODE_NODE 4 #define pa_to_nid(addr) (((addr) & 0xf00000000000) >> NODE_ADDRSPACE_SHIFT) #define nid_to_addrbase(nid) (_ULCAST_(nid) << NODE_ADDRSPACE_SHIFT) diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c index 79715b9f80d6b..a346795b4f176 100644 --- a/drivers/irqchip/irq-loongson-eiointc.c +++ b/drivers/irqchip/irq-loongson-eiointc.c @@ -363,7 +363,7 @@ int __init pch_msi_parse_madt(union acpi_subtable_headers *header, int node; if (cpu_has_flatmode) - node = cpu_to_node(eiointc_priv[nr_pics - 1]->node * CORES_PER_EIO_NODE); + node = eiointc_priv[nr_pics - 1]->node / NODES_PER_FLATMODE_NODE; else node = eiointc_priv[nr_pics - 1]->node; @@ -455,7 +455,7 @@ int __init eiointc_acpi_init(struct irq_domain *parent, goto out_free_handle; if (cpu_has_flatmode) - node = cpu_to_node(acpi_eiointc->node * CORES_PER_EIO_NODE); + node = acpi_eiointc->node / NODES_PER_FLATMODE_NODE; else node = acpi_eiointc->node; acpi_set_vec_parent(node, priv->eiointc_domain, pch_group); From a74a325ea3e84c4c3cfd214996d92d99dae1477e Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Tue, 11 Jun 2024 10:15:07 +0800 Subject: [PATCH 4/4] LoongArch: fix efi map page table error Fixes: d7aad0cbaf25 ("LoongArch: add kernel setvirtmap for runtime") Signed-off-by: Yun Liu Signed-off-by: Hongchen Zhang Signed-off-by: Yanteng Si --- arch/loongarch/kernel/efi.c | 39 +++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c index b132af112664b..140b43d3f1825 100644 --- a/arch/loongarch/kernel/efi.c +++ b/arch/loongarch/kernel/efi.c @@ -69,8 +69,10 @@ static int __init efimap_populate_hugepages( if (pud_none(*pud)) { void *p = memblock_alloc_low(PAGE_SIZE, PAGE_SIZE); - if (!p) + if (!p) { + pr_err("can not alloc efimap huge pages!\n"); return -1; + } pmd_init(p); pud_populate(&init_mm, pud, p); } @@ -88,7 +90,8 @@ static void __init efi_map_pgt(void) { unsigned long node; unsigned long start, end; - unsigned long start_pfn, end_pfn; + efi_memory_desc_t *md; + u32 mem_type; pgd_efi = memblock_alloc_low(PAGE_SIZE, PAGE_SIZE); if (!pgd_efi) { @@ -105,13 +108,33 @@ static void __init efi_map_pgt(void) /* MMIO Registers, Uncached */ efimap_populate_hugepages(SZ_256M | (node << 44), SZ_512M | (node << 44), PAGE_KERNEL_SUC); + } - get_pfn_range_for_nid(node, &start_pfn, &end_pfn); - start = ALIGN_DOWN(start_pfn << PAGE_SHIFT, PMD_SIZE); - end = ALIGN(end_pfn << PAGE_SHIFT, PMD_SIZE); - - /* System memory, Cached */ - efimap_populate_hugepages(node ? start : SZ_512M, end, PAGE_KERNEL); + /* Parse memory information */ + for_each_efi_memory_desc(md) { + mem_type = md->type; + start = ALIGN_DOWN(md->phys_addr, PMD_SIZE); + end = ALIGN(start + (md->num_pages << EFI_PAGE_SHIFT), PMD_SIZE); + node = start >> 44; + + switch (mem_type) { + case EFI_LOADER_CODE: + case EFI_LOADER_DATA: + case EFI_BOOT_SERVICES_CODE: + case EFI_BOOT_SERVICES_DATA: + case EFI_PAL_CODE: + case EFI_UNUSABLE_MEMORY: + case EFI_ACPI_RECLAIM_MEMORY: + case EFI_RESERVED_TYPE: + case EFI_RUNTIME_SERVICES_CODE: + case EFI_RUNTIME_SERVICES_DATA: + efimap_populate_hugepages(node ? start : SZ_512M, end, PAGE_KERNEL); + break; + case EFI_MEMORY_MAPPED_IO: + case EFI_MEMORY_MAPPED_IO_PORT_SPACE: + efimap_populate_hugepages(node ? start : SZ_512M, end, PAGE_KERNEL_SUC); + break; + } } }