1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (C) 2020-2022 Loongson Technology Corporation Limited |
4 | */ |
5 | #include <linux/kernel.h> |
6 | #include <linux/acpi.h> |
7 | #include <linux/atomic.h> |
8 | #include <linux/delay.h> |
9 | #include <linux/init.h> |
10 | #include <linux/interrupt.h> |
11 | #include <linux/irqchip.h> |
12 | #include <linux/kernel_stat.h> |
13 | #include <linux/proc_fs.h> |
14 | #include <linux/mm.h> |
15 | #include <linux/sched.h> |
16 | #include <linux/seq_file.h> |
17 | #include <linux/kallsyms.h> |
18 | #include <linux/uaccess.h> |
19 | |
20 | #include <asm/irq.h> |
21 | #include <asm/loongson.h> |
22 | #include <asm/setup.h> |
23 | |
24 | DEFINE_PER_CPU(unsigned long, irq_stack); |
25 | DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat); |
26 | EXPORT_PER_CPU_SYMBOL(irq_stat); |
27 | |
28 | struct acpi_vector_group pch_group[MAX_IO_PICS]; |
29 | struct acpi_vector_group msi_group[MAX_IO_PICS]; |
30 | /* |
31 | * 'what should we do if we get a hw irq event on an illegal vector'. |
32 | * each architecture has to answer this themselves. |
33 | */ |
34 | void ack_bad_irq(unsigned int irq) |
35 | { |
36 | pr_warn("Unexpected IRQ # %d\n" , irq); |
37 | } |
38 | |
39 | atomic_t irq_err_count; |
40 | |
41 | asmlinkage void spurious_interrupt(void) |
42 | { |
43 | atomic_inc(v: &irq_err_count); |
44 | } |
45 | |
46 | int arch_show_interrupts(struct seq_file *p, int prec) |
47 | { |
48 | #ifdef CONFIG_SMP |
49 | show_ipi_list(p, prec); |
50 | #endif |
51 | seq_printf(m: p, fmt: "%*s: %10u\n" , prec, "ERR" , atomic_read(v: &irq_err_count)); |
52 | return 0; |
53 | } |
54 | |
55 | static int __init early_pci_mcfg_parse(struct acpi_table_header *) |
56 | { |
57 | struct acpi_table_mcfg *mcfg; |
58 | struct acpi_mcfg_allocation *mptr; |
59 | int i, n; |
60 | |
61 | if (header->length < sizeof(struct acpi_table_mcfg)) |
62 | return -EINVAL; |
63 | |
64 | n = (header->length - sizeof(struct acpi_table_mcfg)) / |
65 | sizeof(struct acpi_mcfg_allocation); |
66 | mcfg = (struct acpi_table_mcfg *)header; |
67 | mptr = (struct acpi_mcfg_allocation *) &mcfg[1]; |
68 | |
69 | for (i = 0; i < n; i++, mptr++) { |
70 | msi_group[i].pci_segment = mptr->pci_segment; |
71 | pch_group[i].node = msi_group[i].node = (mptr->address >> 44) & 0xf; |
72 | } |
73 | |
74 | return 0; |
75 | } |
76 | |
77 | static void __init init_vec_parent_group(void) |
78 | { |
79 | int i; |
80 | |
81 | for (i = 0; i < MAX_IO_PICS; i++) { |
82 | msi_group[i].pci_segment = -1; |
83 | msi_group[i].node = -1; |
84 | pch_group[i].node = -1; |
85 | } |
86 | |
87 | acpi_table_parse(ACPI_SIG_MCFG, handler: early_pci_mcfg_parse); |
88 | } |
89 | |
90 | static int __init get_ipi_irq(void) |
91 | { |
92 | struct irq_domain *d = irq_find_matching_fwnode(fwnode: cpuintc_handle, bus_token: DOMAIN_BUS_ANY); |
93 | |
94 | if (d) |
95 | return irq_create_mapping(host: d, hwirq: INT_IPI); |
96 | |
97 | return -EINVAL; |
98 | } |
99 | |
100 | void __init init_IRQ(void) |
101 | { |
102 | int i; |
103 | #ifdef CONFIG_SMP |
104 | int r, ipi_irq; |
105 | static int ipi_dummy_dev; |
106 | #endif |
107 | unsigned int order = get_order(IRQ_STACK_SIZE); |
108 | struct page *page; |
109 | |
110 | clear_csr_ecfg(ECFG0_IM); |
111 | clear_csr_estat(ESTATF_IP); |
112 | |
113 | init_vec_parent_group(); |
114 | irqchip_init(); |
115 | #ifdef CONFIG_SMP |
116 | ipi_irq = get_ipi_irq(); |
117 | if (ipi_irq < 0) |
118 | panic(fmt: "IPI IRQ mapping failed\n" ); |
119 | irq_set_percpu_devid(irq: ipi_irq); |
120 | r = request_percpu_irq(irq: ipi_irq, handler: loongson_ipi_interrupt, devname: "IPI" , percpu_dev_id: &ipi_dummy_dev); |
121 | if (r < 0) |
122 | panic(fmt: "IPI IRQ request failed\n" ); |
123 | #endif |
124 | |
125 | for (i = 0; i < NR_IRQS; i++) |
126 | irq_set_noprobe(irq: i); |
127 | |
128 | for_each_possible_cpu(i) { |
129 | page = alloc_pages_node(cpu_to_node(cpu: i), GFP_KERNEL, order); |
130 | |
131 | per_cpu(irq_stack, i) = (unsigned long)page_address(page); |
132 | pr_debug("CPU%d IRQ stack at 0x%lx - 0x%lx\n" , i, |
133 | per_cpu(irq_stack, i), per_cpu(irq_stack, i) + IRQ_STACK_SIZE); |
134 | } |
135 | |
136 | set_csr_ecfg(ECFGF_IP0 | ECFGF_IP1 | ECFGF_IP2 | ECFGF_IPI | ECFGF_PMC); |
137 | } |
138 | |