1 /* devices.c: Initial scan of the prom device tree for important
2 * Sparc device nodes which we need to find.
4 * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
7 #include <linux/kernel.h>
8 #include <linux/threads.h>
9 #include <linux/init.h>
10 #include <linux/ioport.h>
11 #include <linux/string.h>
12 #include <linux/spinlock.h>
13 #include <linux/errno.h>
14 #include <linux/bootmem.h>
17 #include <asm/oplib.h>
18 #include <asm/system.h>
20 #include <asm/spitfire.h>
21 #include <asm/timer.h>
22 #include <asm/cpudata.h>
26 /* Used to synchronize acceses to NatSemi SUPER I/O chip configure
27 * operations in asm/ns87303.h
29 DEFINE_SPINLOCK(ns87303_lock);
31 extern void cpu_probe(void);
32 extern void central_probe(void);
34 u32 sun4v_vdev_devhandle;
35 struct device_node *sun4v_vdev_root;
41 unsigned int cinterrupt;
46 unsigned int interrupt;
47 unsigned int __unused;
50 static struct vdev_intmap *vdev_intmap;
51 static int vdev_num_intmap;
52 static struct vdev_intmask *vdev_intmask;
54 static void __init sun4v_virtual_device_probe(void)
56 struct linux_prom64_registers *regs;
57 struct property *prop;
58 struct device_node *dp;
61 if (tlb_type != hypervisor)
64 dp = of_find_node_by_name(NULL, "virtual-devices");
66 prom_printf("SUN4V: Fatal error, no virtual-devices node.\n");
72 prop = of_find_property(dp, "reg", NULL);
74 sun4v_vdev_devhandle = (regs[0].phys_addr >> 32UL) & 0x0fffffff;
76 prop = of_find_property(dp, "interrupt-map", &sz);
77 vdev_intmap = prop->value;
78 vdev_num_intmap = sz / sizeof(struct vdev_intmap);
80 prop = of_find_property(dp, "interrupt-map-mask", NULL);
81 vdev_intmask = prop->value;
83 printk("%s: Virtual Device Bus devhandle[%x]\n",
84 dp->full_name, sun4v_vdev_devhandle);
87 unsigned int sun4v_vdev_device_interrupt(struct device_node *dev_node)
89 struct property *prop;
90 unsigned int irq, reg;
93 prop = of_find_property(dev_node, "interrupts", NULL);
95 printk("VDEV: Cannot get \"interrupts\" "
96 "property for OBP node %s\n",
100 irq = *(unsigned int *) prop->value;
102 prop = of_find_property(dev_node, "reg", NULL);
104 printk("VDEV: Cannot get \"reg\" "
105 "property for OBP node %s\n",
106 dev_node->full_name);
109 reg = *(unsigned int *) prop->value;
111 for (i = 0; i < vdev_num_intmap; i++) {
112 if (vdev_intmap[i].phys == (reg & vdev_intmask->phys) &&
113 vdev_intmap[i].irq == (irq & vdev_intmask->interrupt)) {
114 irq = vdev_intmap[i].cinterrupt;
119 if (i == vdev_num_intmap) {
120 printk("VDEV: No matching interrupt map entry "
121 "for OBP node %s\n", dev_node->full_name);
125 return sun4v_build_irq(sun4v_vdev_devhandle, irq);
128 static const char *cpu_mid_prop(void)
130 if (tlb_type == spitfire)
135 static int get_cpu_mid(struct device_node *dp)
137 struct property *prop;
139 if (tlb_type == hypervisor) {
140 struct linux_prom64_registers *reg;
143 prop = of_find_property(dp, "cpuid", &len);
144 if (prop && len == 4)
145 return *(int *) prop->value;
147 prop = of_find_property(dp, "reg", NULL);
149 return (reg[0].phys_addr >> 32) & 0x0fffffffUL;
151 const char *prop_name = cpu_mid_prop();
153 prop = of_find_property(dp, prop_name, NULL);
155 return *(int *) prop->value;
160 static int check_cpu_node(struct device_node *dp, int *cur_inst,
161 int (*compare)(struct device_node *, int, void *),
163 struct device_node **dev_node, int *mid)
165 if (strcmp(dp->type, "cpu"))
168 if (!compare(dp, *cur_inst, compare_arg)) {
172 *mid = get_cpu_mid(dp);
181 static int __cpu_find_by(int (*compare)(struct device_node *, int, void *),
183 struct device_node **dev_node, int *mid)
185 struct device_node *dp;
189 for_each_node_by_type(dp, "cpu") {
190 int err = check_cpu_node(dp, &cur_inst,
191 compare, compare_arg,
200 static int cpu_instance_compare(struct device_node *dp, int instance, void *_arg)
202 int desired_instance = (int) (long) _arg;
204 if (instance == desired_instance)
209 int cpu_find_by_instance(int instance, struct device_node **dev_node, int *mid)
211 return __cpu_find_by(cpu_instance_compare, (void *)(long)instance,
215 static int cpu_mid_compare(struct device_node *dp, int instance, void *_arg)
217 int desired_mid = (int) (long) _arg;
220 this_mid = get_cpu_mid(dp);
221 if (this_mid == desired_mid)
226 int cpu_find_by_mid(int mid, struct device_node **dev_node)
228 return __cpu_find_by(cpu_mid_compare, (void *)(long)mid,
232 void __init device_scan(void)
234 /* FIX ME FAST... -DaveM */
235 ioport_resource.end = 0xffffffffffffffffUL;
237 prom_printf("Booting Linux...\n");
241 struct device_node *dp;
244 err = cpu_find_by_instance(0, &dp, NULL);
246 prom_printf("No cpu nodes, cannot continue\n");
249 cpu_data(0).clock_tick =
250 of_getintprop_default(dp, "clock-frequency", 0);
252 def = ((tlb_type == hypervisor) ?
255 cpu_data(0).dcache_size = of_getintprop_default(dp,
260 cpu_data(0).dcache_line_size =
261 of_getintprop_default(dp, "dcache-line-size", def);
264 cpu_data(0).icache_size = of_getintprop_default(dp,
269 cpu_data(0).icache_line_size =
270 of_getintprop_default(dp, "icache-line-size", def);
272 def = ((tlb_type == hypervisor) ?
275 cpu_data(0).ecache_size = of_getintprop_default(dp,
280 cpu_data(0).ecache_line_size =
281 of_getintprop_default(dp, "ecache-line-size", def);
282 printk("CPU[0]: Caches "
283 "D[sz(%d):line_sz(%d)] "
284 "I[sz(%d):line_sz(%d)] "
285 "E[sz(%d):line_sz(%d)]\n",
286 cpu_data(0).dcache_size, cpu_data(0).dcache_line_size,
287 cpu_data(0).icache_size, cpu_data(0).icache_line_size,
288 cpu_data(0).ecache_size, cpu_data(0).ecache_line_size);
292 sun4v_virtual_device_probe();