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/config.h>
8 #include <linux/kernel.h>
9 #include <linux/threads.h>
10 #include <linux/init.h>
11 #include <linux/ioport.h>
12 #include <linux/string.h>
13 #include <linux/spinlock.h>
14 #include <linux/errno.h>
15 #include <linux/bootmem.h>
18 #include <asm/oplib.h>
19 #include <asm/system.h>
21 #include <asm/spitfire.h>
22 #include <asm/timer.h>
23 #include <asm/cpudata.h>
27 /* Used to synchronize acceses to NatSemi SUPER I/O chip configure
28 * operations in asm/ns87303.h
30 DEFINE_SPINLOCK(ns87303_lock);
32 extern void cpu_probe(void);
33 extern void central_probe(void);
35 u32 sun4v_vdev_devhandle;
36 struct device_node *sun4v_vdev_root;
42 unsigned int cinterrupt;
47 unsigned int interrupt;
48 unsigned int __unused;
51 static struct vdev_intmap *vdev_intmap;
52 static int vdev_num_intmap;
53 static struct vdev_intmask *vdev_intmask;
55 static void __init sun4v_virtual_device_probe(void)
57 struct linux_prom64_registers *regs;
58 struct property *prop;
59 struct device_node *dp;
62 if (tlb_type != hypervisor)
65 dp = of_find_node_by_name(NULL, "virtual-devices");
67 prom_printf("SUN4V: Fatal error, no virtual-devices node.\n");
73 prop = of_find_property(dp, "reg", NULL);
75 sun4v_vdev_devhandle = (regs[0].phys_addr >> 32UL) & 0x0fffffff;
77 prop = of_find_property(dp, "interrupt-map", &sz);
78 vdev_intmap = prop->value;
79 vdev_num_intmap = sz / sizeof(struct vdev_intmap);
81 prop = of_find_property(dp, "interrupt-map-mask", NULL);
82 vdev_intmask = prop->value;
84 printk("%s: Virtual Device Bus devhandle[%x]\n",
85 dp->full_name, sun4v_vdev_devhandle);
88 unsigned int sun4v_vdev_device_interrupt(struct device_node *dev_node)
90 struct property *prop;
91 unsigned int irq, reg;
94 prop = of_find_property(dev_node, "interrupts", NULL);
96 printk("VDEV: Cannot get \"interrupts\" "
97 "property for OBP node %s\n",
101 irq = *(unsigned int *) prop->value;
103 prop = of_find_property(dev_node, "reg", NULL);
105 printk("VDEV: Cannot get \"reg\" "
106 "property for OBP node %s\n",
107 dev_node->full_name);
110 reg = *(unsigned int *) prop->value;
112 for (i = 0; i < vdev_num_intmap; i++) {
113 if (vdev_intmap[i].phys == (reg & vdev_intmask->phys) &&
114 vdev_intmap[i].irq == (irq & vdev_intmask->interrupt)) {
115 irq = vdev_intmap[i].cinterrupt;
120 if (i == vdev_num_intmap) {
121 printk("VDEV: No matching interrupt map entry "
122 "for OBP node %s\n", dev_node->full_name);
126 return sun4v_build_irq(sun4v_vdev_devhandle, irq);
129 static const char *cpu_mid_prop(void)
131 if (tlb_type == spitfire)
136 static int get_cpu_mid(struct device_node *dp)
138 struct property *prop;
140 if (tlb_type == hypervisor) {
141 struct linux_prom64_registers *reg;
144 prop = of_find_property(dp, "cpuid", &len);
145 if (prop && len == 4)
146 return *(int *) prop->value;
148 prop = of_find_property(dp, "reg", NULL);
150 return (reg[0].phys_addr >> 32) & 0x0fffffffUL;
152 const char *prop_name = cpu_mid_prop();
154 prop = of_find_property(dp, prop_name, NULL);
156 return *(int *) prop->value;
161 static int check_cpu_node(struct device_node *dp, int *cur_inst,
162 int (*compare)(struct device_node *, int, void *),
164 struct device_node **dev_node, int *mid)
166 if (strcmp(dp->type, "cpu"))
169 if (!compare(dp, *cur_inst, compare_arg)) {
173 *mid = get_cpu_mid(dp);
182 static int __cpu_find_by(int (*compare)(struct device_node *, int, void *),
184 struct device_node **dev_node, int *mid)
186 struct device_node *dp;
190 for_each_node_by_type(dp, "cpu") {
191 int err = check_cpu_node(dp, &cur_inst,
192 compare, compare_arg,
201 static int cpu_instance_compare(struct device_node *dp, int instance, void *_arg)
203 int desired_instance = (int) (long) _arg;
205 if (instance == desired_instance)
210 int cpu_find_by_instance(int instance, struct device_node **dev_node, int *mid)
212 return __cpu_find_by(cpu_instance_compare, (void *)(long)instance,
216 static int cpu_mid_compare(struct device_node *dp, int instance, void *_arg)
218 int desired_mid = (int) (long) _arg;
221 this_mid = get_cpu_mid(dp);
222 if (this_mid == desired_mid)
227 int cpu_find_by_mid(int mid, struct device_node **dev_node)
229 return __cpu_find_by(cpu_mid_compare, (void *)(long)mid,
233 void __init device_scan(void)
235 /* FIX ME FAST... -DaveM */
236 ioport_resource.end = 0xffffffffffffffffUL;
238 prom_printf("Booting Linux...\n");
242 struct device_node *dp;
245 err = cpu_find_by_instance(0, &dp, NULL);
247 prom_printf("No cpu nodes, cannot continue\n");
250 cpu_data(0).clock_tick =
251 of_getintprop_default(dp, "clock-frequency", 0);
253 def = ((tlb_type == hypervisor) ?
256 cpu_data(0).dcache_size = of_getintprop_default(dp,
261 cpu_data(0).dcache_line_size =
262 of_getintprop_default(dp, "dcache-line-size", def);
265 cpu_data(0).icache_size = of_getintprop_default(dp,
270 cpu_data(0).icache_line_size =
271 of_getintprop_default(dp, "icache-line-size", def);
273 def = ((tlb_type == hypervisor) ?
276 cpu_data(0).ecache_size = of_getintprop_default(dp,
281 cpu_data(0).ecache_line_size =
282 of_getintprop_default(dp, "ecache-line-size", def);
283 printk("CPU[0]: Caches "
284 "D[sz(%d):line_sz(%d)] "
285 "I[sz(%d):line_sz(%d)] "
286 "E[sz(%d):line_sz(%d)]\n",
287 cpu_data(0).dcache_size, cpu_data(0).dcache_line_size,
288 cpu_data(0).icache_size, cpu_data(0).icache_line_size,
289 cpu_data(0).ecache_size, cpu_data(0).ecache_line_size);
293 sun4v_virtual_device_probe();