Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/kernel/devicetree.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Architecture specific OF callbacks.
4
*/
5
#include <linux/acpi.h>
6
#include <linux/export.h>
7
#include <linux/io.h>
8
#include <linux/interrupt.h>
9
#include <linux/list.h>
10
#include <linux/of.h>
11
#include <linux/of_fdt.h>
12
#include <linux/of_address.h>
13
#include <linux/of_platform.h>
14
#include <linux/of_irq.h>
15
#include <linux/libfdt.h>
16
#include <linux/slab.h>
17
#include <linux/pci.h>
18
#include <linux/of_pci.h>
19
#include <linux/initrd.h>
20
21
#include <asm/irqdomain.h>
22
#include <asm/hpet.h>
23
#include <asm/apic.h>
24
#include <asm/io_apic.h>
25
#include <asm/pci_x86.h>
26
#include <asm/setup.h>
27
#include <asm/i8259.h>
28
#include <asm/numa.h>
29
#include <asm/prom.h>
30
31
__initdata u64 initial_dtb;
32
char __initdata cmd_line[COMMAND_LINE_SIZE];
33
34
int __initdata of_ioapic;
35
36
void __init add_dtb(u64 data)
37
{
38
initial_dtb = data + offsetof(struct setup_data, data);
39
}
40
41
/*
42
* CE4100 ids. Will be moved to machine_device_initcall() once we have it.
43
*/
44
static struct of_device_id __initdata ce4100_ids[] = {
45
{ .compatible = "intel,ce4100-cp", },
46
{ .compatible = "isa", },
47
{ .compatible = "pci", },
48
{},
49
};
50
51
static int __init add_bus_probe(void)
52
{
53
if (!of_have_populated_dt())
54
return 0;
55
56
return of_platform_bus_probe(NULL, ce4100_ids, NULL);
57
}
58
device_initcall(add_bus_probe);
59
60
#ifdef CONFIG_PCI
61
struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
62
{
63
struct device_node *np;
64
65
for_each_node_by_type(np, "pci") {
66
const void *prop;
67
unsigned int bus_min;
68
69
prop = of_get_property(np, "bus-range", NULL);
70
if (!prop)
71
continue;
72
bus_min = be32_to_cpup(prop);
73
if (bus->number == bus_min)
74
return np;
75
}
76
return NULL;
77
}
78
79
static int x86_of_pci_irq_enable(struct pci_dev *dev)
80
{
81
u32 virq;
82
int ret;
83
u8 pin;
84
85
ret = pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
86
if (ret)
87
return pcibios_err_to_errno(ret);
88
if (!pin)
89
return 0;
90
91
virq = of_irq_parse_and_map_pci(dev, 0, 0);
92
if (virq == 0)
93
return -EINVAL;
94
dev->irq = virq;
95
return 0;
96
}
97
98
static void x86_of_pci_irq_disable(struct pci_dev *dev)
99
{
100
}
101
102
void x86_of_pci_init(void)
103
{
104
pcibios_enable_irq = x86_of_pci_irq_enable;
105
pcibios_disable_irq = x86_of_pci_irq_disable;
106
}
107
#endif
108
109
static void __init dtb_setup_hpet(void)
110
{
111
#ifdef CONFIG_HPET_TIMER
112
struct device_node *dn;
113
struct resource r;
114
int ret;
115
116
dn = of_find_compatible_node(NULL, NULL, "intel,ce4100-hpet");
117
if (!dn)
118
return;
119
ret = of_address_to_resource(dn, 0, &r);
120
if (ret) {
121
WARN_ON(1);
122
return;
123
}
124
hpet_address = r.start;
125
#endif
126
}
127
128
#ifdef CONFIG_X86_LOCAL_APIC
129
130
static void __init dtb_cpu_setup(void)
131
{
132
struct device_node *dn;
133
u32 apic_id;
134
135
for_each_of_cpu_node(dn) {
136
apic_id = of_get_cpu_hwid(dn, 0);
137
if (apic_id == ~0U) {
138
pr_warn("%pOF: missing local APIC ID\n", dn);
139
continue;
140
}
141
topology_register_apic(apic_id, CPU_ACPIID_INVALID, true);
142
set_apicid_to_node(apic_id, of_node_to_nid(dn));
143
}
144
}
145
146
static void __init dtb_lapic_setup(void)
147
{
148
struct device_node *dn;
149
struct resource r;
150
unsigned long lapic_addr = APIC_DEFAULT_PHYS_BASE;
151
int ret;
152
153
dn = of_find_compatible_node(NULL, NULL, "intel,ce4100-lapic");
154
if (dn) {
155
ret = of_address_to_resource(dn, 0, &r);
156
if (WARN_ON(ret))
157
return;
158
lapic_addr = r.start;
159
}
160
161
/* Did the boot loader setup the local APIC ? */
162
if (!boot_cpu_has(X86_FEATURE_APIC)) {
163
/* Try force enabling, which registers the APIC address */
164
if (!apic_force_enable(lapic_addr))
165
return;
166
} else {
167
register_lapic_address(lapic_addr);
168
}
169
smp_found_config = 1;
170
pic_mode = !of_property_read_bool(dn, "intel,virtual-wire-mode");
171
pr_info("%s compatibility mode.\n", pic_mode ? "IMCR and PIC" : "Virtual Wire");
172
}
173
174
#endif /* CONFIG_X86_LOCAL_APIC */
175
176
#ifdef CONFIG_X86_IO_APIC
177
static unsigned int ioapic_id;
178
179
struct of_ioapic_type {
180
u32 out_type;
181
u32 is_level;
182
u32 active_low;
183
};
184
185
static struct of_ioapic_type of_ioapic_type[] =
186
{
187
{
188
.out_type = IRQ_TYPE_EDGE_FALLING,
189
.is_level = 0,
190
.active_low = 1,
191
},
192
{
193
.out_type = IRQ_TYPE_LEVEL_HIGH,
194
.is_level = 1,
195
.active_low = 0,
196
},
197
{
198
.out_type = IRQ_TYPE_LEVEL_LOW,
199
.is_level = 1,
200
.active_low = 1,
201
},
202
{
203
.out_type = IRQ_TYPE_EDGE_RISING,
204
.is_level = 0,
205
.active_low = 0,
206
},
207
};
208
209
static int dt_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
210
unsigned int nr_irqs, void *arg)
211
{
212
struct irq_fwspec *fwspec = (struct irq_fwspec *)arg;
213
struct of_ioapic_type *it;
214
struct irq_alloc_info tmp;
215
int type_index;
216
217
if (WARN_ON(fwspec->param_count < 2))
218
return -EINVAL;
219
220
type_index = fwspec->param[1];
221
if (type_index >= ARRAY_SIZE(of_ioapic_type))
222
return -EINVAL;
223
224
it = &of_ioapic_type[type_index];
225
ioapic_set_alloc_attr(&tmp, NUMA_NO_NODE, it->is_level, it->active_low);
226
tmp.devid = mpc_ioapic_id(mp_irqdomain_ioapic_idx(domain));
227
tmp.ioapic.pin = fwspec->param[0];
228
229
return mp_irqdomain_alloc(domain, virq, nr_irqs, &tmp);
230
}
231
232
static const struct irq_domain_ops ioapic_irq_domain_ops = {
233
.alloc = dt_irqdomain_alloc,
234
.free = mp_irqdomain_free,
235
.activate = mp_irqdomain_activate,
236
.deactivate = mp_irqdomain_deactivate,
237
};
238
239
static void __init dtb_add_ioapic(struct device_node *dn)
240
{
241
struct resource r;
242
int ret;
243
struct ioapic_domain_cfg cfg = {
244
.type = IOAPIC_DOMAIN_DYNAMIC,
245
.ops = &ioapic_irq_domain_ops,
246
.dev = dn,
247
};
248
249
ret = of_address_to_resource(dn, 0, &r);
250
if (ret) {
251
pr_err("Can't obtain address from device node %pOF.\n", dn);
252
return;
253
}
254
mp_register_ioapic(++ioapic_id, r.start, gsi_top, &cfg);
255
}
256
257
static void __init dtb_ioapic_setup(void)
258
{
259
struct device_node *dn;
260
261
for_each_compatible_node(dn, NULL, "intel,ce4100-ioapic")
262
dtb_add_ioapic(dn);
263
264
if (nr_ioapics) {
265
of_ioapic = 1;
266
return;
267
}
268
pr_err("Error: No information about IO-APIC in OF.\n");
269
}
270
#else
271
static void __init dtb_ioapic_setup(void) {}
272
#endif
273
274
static void __init dtb_apic_setup(void)
275
{
276
#ifdef CONFIG_X86_LOCAL_APIC
277
dtb_lapic_setup();
278
dtb_cpu_setup();
279
#endif
280
dtb_ioapic_setup();
281
}
282
283
static void __init x86_dtb_parse_smp_config(void)
284
{
285
if (!of_have_populated_dt())
286
return;
287
288
dtb_setup_hpet();
289
dtb_apic_setup();
290
}
291
292
void __init x86_flattree_get_config(void)
293
{
294
#ifdef CONFIG_OF_EARLY_FLATTREE
295
u32 size, map_len;
296
void *dt;
297
298
if (initial_dtb) {
299
map_len = max(PAGE_SIZE - (initial_dtb & ~PAGE_MASK), (u64)128);
300
301
dt = early_memremap(initial_dtb, map_len);
302
size = fdt_totalsize(dt);
303
if (map_len < size) {
304
early_memunmap(dt, map_len);
305
dt = early_memremap(initial_dtb, size);
306
map_len = size;
307
}
308
309
early_init_dt_verify(dt, __pa(dt));
310
}
311
312
unflatten_and_copy_device_tree();
313
314
if (initial_dtb)
315
early_memunmap(dt, map_len);
316
#endif
317
if (acpi_disabled && of_have_populated_dt())
318
x86_init.mpparse.parse_smp_cfg = x86_dtb_parse_smp_config;
319
}
320
321