Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[pandora-kernel.git] / arch / sparc64 / kernel / devices.c
1 /* devices.c: Initial scan of the prom device tree for important
2  *            Sparc device nodes which we need to find.
3  *
4  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
5  */
6
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>
15
16 #include <asm/page.h>
17 #include <asm/oplib.h>
18 #include <asm/system.h>
19 #include <asm/smp.h>
20 #include <asm/spitfire.h>
21 #include <asm/timer.h>
22 #include <asm/cpudata.h>
23 #include <asm/vdev.h>
24 #include <asm/irq.h>
25
26 /* Used to synchronize acceses to NatSemi SUPER I/O chip configure
27  * operations in asm/ns87303.h
28  */
29 DEFINE_SPINLOCK(ns87303_lock);
30
31 extern void cpu_probe(void);
32 extern void central_probe(void);
33
34 u32 sun4v_vdev_devhandle;
35 struct device_node *sun4v_vdev_root;
36
37 struct vdev_intmap {
38         unsigned int phys;
39         unsigned int irq;
40         unsigned int cnode;
41         unsigned int cinterrupt;
42 };
43
44 struct vdev_intmask {
45         unsigned int phys;
46         unsigned int interrupt;
47         unsigned int __unused;
48 };
49
50 static struct vdev_intmap *vdev_intmap;
51 static int vdev_num_intmap;
52 static struct vdev_intmask *vdev_intmask;
53
54 static void __init sun4v_virtual_device_probe(void)
55 {
56         struct linux_prom64_registers *regs;
57         struct property *prop;
58         struct device_node *dp;
59         int sz;
60
61         if (tlb_type != hypervisor)
62                 return;
63
64         dp = of_find_node_by_name(NULL, "virtual-devices");
65         if (!dp) {
66                 prom_printf("SUN4V: Fatal error, no virtual-devices node.\n");
67                 prom_halt();
68         }
69
70         sun4v_vdev_root = dp;
71
72         prop = of_find_property(dp, "reg", NULL);
73         regs = prop->value;
74         sun4v_vdev_devhandle = (regs[0].phys_addr >> 32UL) & 0x0fffffff;
75
76         prop = of_find_property(dp, "interrupt-map", &sz);
77         vdev_intmap = prop->value;
78         vdev_num_intmap = sz / sizeof(struct vdev_intmap);
79
80         prop = of_find_property(dp, "interrupt-map-mask", NULL);
81         vdev_intmask = prop->value;
82
83         printk("%s: Virtual Device Bus devhandle[%x]\n",
84                dp->full_name, sun4v_vdev_devhandle);
85 }
86
87 unsigned int sun4v_vdev_device_interrupt(struct device_node *dev_node)
88 {
89         struct property *prop;
90         unsigned int irq, reg;
91         int i;
92
93         prop = of_find_property(dev_node, "interrupts", NULL);
94         if (!prop) {
95                 printk("VDEV: Cannot get \"interrupts\" "
96                        "property for OBP node %s\n",
97                        dev_node->full_name);
98                 return 0;
99         }
100         irq = *(unsigned int *) prop->value;
101
102         prop = of_find_property(dev_node, "reg", NULL);
103         if (!prop) {
104                 printk("VDEV: Cannot get \"reg\" "
105                        "property for OBP node %s\n",
106                        dev_node->full_name);
107                 return 0;
108         }
109         reg = *(unsigned int *) prop->value;
110
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;
115                         break;
116                 }
117         }
118
119         if (i == vdev_num_intmap) {
120                 printk("VDEV: No matching interrupt map entry "
121                        "for OBP node %s\n", dev_node->full_name);
122                 return 0;
123         }
124
125         return sun4v_build_irq(sun4v_vdev_devhandle, irq);
126 }
127
128 static const char *cpu_mid_prop(void)
129 {
130         if (tlb_type == spitfire)
131                 return "upa-portid";
132         return "portid";
133 }
134
135 static int get_cpu_mid(struct device_node *dp)
136 {
137         struct property *prop;
138
139         if (tlb_type == hypervisor) {
140                 struct linux_prom64_registers *reg;
141                 int len;
142
143                 prop = of_find_property(dp, "cpuid", &len);
144                 if (prop && len == 4)
145                         return *(int *) prop->value;
146
147                 prop = of_find_property(dp, "reg", NULL);
148                 reg = prop->value;
149                 return (reg[0].phys_addr >> 32) & 0x0fffffffUL;
150         } else {
151                 const char *prop_name = cpu_mid_prop();
152
153                 prop = of_find_property(dp, prop_name, NULL);
154                 if (prop)
155                         return *(int *) prop->value;
156                 return 0;
157         }
158 }
159
160 static int check_cpu_node(struct device_node *dp, int *cur_inst,
161                           int (*compare)(struct device_node *, int, void *),
162                           void *compare_arg,
163                           struct device_node **dev_node, int *mid)
164 {
165         if (strcmp(dp->type, "cpu"))
166                 return -ENODEV;
167
168         if (!compare(dp, *cur_inst, compare_arg)) {
169                 if (dev_node)
170                         *dev_node = dp;
171                 if (mid)
172                         *mid = get_cpu_mid(dp);
173                 return 0;
174         }
175
176         (*cur_inst)++;
177
178         return -ENODEV;
179 }
180
181 static int __cpu_find_by(int (*compare)(struct device_node *, int, void *),
182                          void *compare_arg,
183                          struct device_node **dev_node, int *mid)
184 {
185         struct device_node *dp;
186         int cur_inst;
187
188         cur_inst = 0;
189         for_each_node_by_type(dp, "cpu") {
190                 int err = check_cpu_node(dp, &cur_inst,
191                                          compare, compare_arg,
192                                          dev_node, mid);
193                 if (err == 0)
194                         return 0;
195         }
196
197         return -ENODEV;
198 }
199
200 static int cpu_instance_compare(struct device_node *dp, int instance, void *_arg)
201 {
202         int desired_instance = (int) (long) _arg;
203
204         if (instance == desired_instance)
205                 return 0;
206         return -ENODEV;
207 }
208
209 int cpu_find_by_instance(int instance, struct device_node **dev_node, int *mid)
210 {
211         return __cpu_find_by(cpu_instance_compare, (void *)(long)instance,
212                              dev_node, mid);
213 }
214
215 static int cpu_mid_compare(struct device_node *dp, int instance, void *_arg)
216 {
217         int desired_mid = (int) (long) _arg;
218         int this_mid;
219
220         this_mid = get_cpu_mid(dp);
221         if (this_mid == desired_mid)
222                 return 0;
223         return -ENODEV;
224 }
225
226 int cpu_find_by_mid(int mid, struct device_node **dev_node)
227 {
228         return __cpu_find_by(cpu_mid_compare, (void *)(long)mid,
229                              dev_node, NULL);
230 }
231
232 void __init device_scan(void)
233 {
234         /* FIX ME FAST... -DaveM */
235         ioport_resource.end = 0xffffffffffffffffUL;
236
237         prom_printf("Booting Linux...\n");
238
239 #ifndef CONFIG_SMP
240         {
241                 struct device_node *dp;
242                 int err, def;
243
244                 err = cpu_find_by_instance(0, &dp, NULL);
245                 if (err) {
246                         prom_printf("No cpu nodes, cannot continue\n");
247                         prom_halt();
248                 }
249                 cpu_data(0).clock_tick =
250                         of_getintprop_default(dp, "clock-frequency", 0);
251
252                 def = ((tlb_type == hypervisor) ?
253                        (8 * 1024) :
254                        (16 * 1024));
255                 cpu_data(0).dcache_size = of_getintprop_default(dp,
256                                                                 "dcache-size",
257                                                                 def);
258
259                 def = 32;
260                 cpu_data(0).dcache_line_size =
261                         of_getintprop_default(dp, "dcache-line-size", def);
262
263                 def = 16 * 1024;
264                 cpu_data(0).icache_size = of_getintprop_default(dp,
265                                                                 "icache-size",
266                                                                 def);
267
268                 def = 32;
269                 cpu_data(0).icache_line_size =
270                         of_getintprop_default(dp, "icache-line-size", def);
271
272                 def = ((tlb_type == hypervisor) ?
273                        (3 * 1024 * 1024) :
274                        (4 * 1024 * 1024));
275                 cpu_data(0).ecache_size = of_getintprop_default(dp,
276                                                                 "ecache-size",
277                                                                 def);
278
279                 def = 64;
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);
289         }
290 #endif
291
292         sun4v_virtual_device_probe();
293         central_probe();
294
295         cpu_probe();
296 }