Skip to content

Commit

Permalink
Merge pull request #269 from sterling-teng/linux-6.6.y
Browse files Browse the repository at this point in the history
LoongArch: Fix some issues and update interrupt registration policy
  • Loading branch information
opsiff authored Jun 14, 2024
2 parents 439d101 + a74a325 commit b739577
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 25 deletions.
1 change: 1 addition & 0 deletions arch/loongarch/include/asm/numa.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <linux/nodemask.h>

#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)
Expand Down
39 changes: 31 additions & 8 deletions arch/loongarch/kernel/efi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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) {
Expand All @@ -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;
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions arch/loongarch/kernel/legacy_boot.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <linux/acpi.h>
#include <linux/of_address.h>
#include <linux/screen_info.h>
#include <asm/loongson.h>

#define ADDRESS_TYPE_SYSRAM 1
#define ADDRESS_TYPE_RESERVED 2
Expand Down Expand Up @@ -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
6 changes: 5 additions & 1 deletion arch/loongarch/kernel/relocate.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <asm/inst.h>
#include <asm/sections.h>
#include <asm/setup.h>
#include "legacy_boot.h"

#define RELOCATED(x) ((void *)((long)x + reloc_offset))
#define RELOCATED_KASLR(x) ((void *)((long)x + random_offset))
Expand Down Expand Up @@ -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();
Expand Down
4 changes: 2 additions & 2 deletions drivers/irqchip/irq-loongson-eiointc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down
70 changes: 56 additions & 14 deletions drivers/irqchip/irq-loongson-pch-pic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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];
Expand All @@ -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;
Expand Down Expand Up @@ -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:
Expand All @@ -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);
}
Expand All @@ -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)
Expand All @@ -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;
}

Expand All @@ -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;
Expand Down Expand Up @@ -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));
}
Expand Down Expand Up @@ -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)
Expand All @@ -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;
Expand Down

0 comments on commit b739577

Please sign in to comment.