1 /******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation
3 * All rights reserved.
4 * This program and the accompanying materials
5 * are made available under the terms of the BSD License
6 * which accompanies this distribution, and is available at
7 * http://www.opensource.org/licenses/bsd-license.php
8 *
9 * Contributors:
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
12
13 #include <stdint.h>
14 #include <of.h>
15 #include <rtas.h>
16 #include <string.h>
17 #include <libbootmsg.h>
18 #include <kernel.h>
19
20 extern void call_client_interface(of_arg_t *);
21
22 static int claim_rc = 0;
23 static void* client_start;
24 static size_t client_size;
25
26 static inline int
of_0_1(const char * serv)27 of_0_1(const char *serv)
28 {
29 of_arg_t arg = {
30 p32cast serv,
31 0, 1,
32 { 0 }
33 };
34
35 call_client_interface(&arg);
36
37 return arg.args[0];
38 }
39
40 static inline void
of_1_0(const char * serv,int arg0)41 of_1_0(const char *serv, int arg0)
42 {
43 of_arg_t arg = {
44 p32cast serv,
45 1, 0,
46 {arg0, 0}
47 };
48
49 call_client_interface(&arg);
50 }
51
52 static inline unsigned int
of_1_1(const char * serv,int arg0)53 of_1_1(const char *serv, int arg0)
54 {
55 of_arg_t arg = {
56 p32cast serv,
57 1, 1,
58 {arg0, 0}
59 };
60
61 call_client_interface(&arg);
62 return arg.args[1];
63 }
64
65 static inline unsigned int
of_1_2(const char * serv,int arg0,int * ret0)66 of_1_2(const char *serv, int arg0, int *ret0)
67 {
68 of_arg_t arg = {
69 p32cast serv,
70 1, 2,
71 {arg0, 0, 0}
72 };
73
74 call_client_interface(&arg);
75 *ret0 = arg.args[2];
76 return arg.args[1];
77 }
78
79 static inline void
of_2_0(const char * serv,int arg0,int arg1)80 of_2_0(const char *serv, int arg0, int arg1)
81 {
82 of_arg_t arg = {
83 p32cast serv,
84 2, 0,
85 {arg0, arg1, 0}
86 };
87
88 call_client_interface(&arg);
89 }
90
91 static inline unsigned int
of_2_1(const char * serv,int arg0,int arg1)92 of_2_1(const char *serv, int arg0, int arg1)
93 {
94 of_arg_t arg = {
95 p32cast serv,
96 2, 1,
97 {arg0, arg1, 0}
98 };
99
100 call_client_interface(&arg);
101 return arg.args[2];
102 }
103
104 static inline unsigned int
of_2_2(const char * serv,int arg0,int arg1,int * ret0)105 of_2_2(const char *serv, int arg0, int arg1, int *ret0)
106 {
107 of_arg_t arg = {
108 p32cast serv,
109 2, 2,
110 {arg0, arg1, 0, 0}
111 };
112
113 call_client_interface(&arg);
114 *ret0 = arg.args[3];
115 return arg.args[2];
116 }
117
118 static inline unsigned int
of_2_3(const char * serv,int arg0,int arg1,int * ret0,int * ret1)119 of_2_3(const char *serv, int arg0, int arg1, int *ret0, int *ret1)
120 {
121 of_arg_t arg = {
122 p32cast serv,
123 2, 3,
124 {arg0, arg1, 0, 0, 0}
125 };
126
127 call_client_interface(&arg);
128 *ret0 = arg.args[3];
129 *ret1 = arg.args[4];
130 return arg.args[2];
131 }
132
133 static inline void
of_3_0(const char * serv,int arg0,int arg1,int arg2)134 of_3_0(const char *serv, int arg0, int arg1, int arg2)
135 {
136 of_arg_t arg = {
137 p32cast serv,
138 3, 0,
139 {arg0, arg1, arg2, 0}
140 };
141
142 call_client_interface(&arg);
143 return;
144 }
145
146 static inline unsigned int
of_3_1(const char * serv,int arg0,int arg1,int arg2)147 of_3_1(const char *serv, int arg0, int arg1, int arg2)
148 {
149 of_arg_t arg = {
150 p32cast serv,
151 3, 1,
152 {arg0, arg1, arg2, 0}
153 };
154
155 call_client_interface(&arg);
156 return arg.args[3];
157 }
158
159 static inline unsigned int
of_3_2(const char * serv,int arg0,int arg1,int arg2,int * ret0)160 of_3_2(const char *serv, int arg0, int arg1, int arg2, int *ret0)
161 {
162 of_arg_t arg = {
163 p32cast serv,
164 3, 2,
165 {arg0, arg1, arg2, 0, 0}
166 };
167
168 call_client_interface(&arg);
169 *ret0 = arg.args[4];
170 return arg.args[3];
171 }
172
173 static inline unsigned int
of_3_3(const char * serv,int arg0,int arg1,int arg2,int * ret0,int * ret1)174 of_3_3(const char *serv, int arg0, int arg1, int arg2, int *ret0, int *ret1)
175 {
176 of_arg_t arg = {
177 p32cast serv,
178 3, 3,
179 {arg0, arg1, arg2, 0, 0, 0}
180 };
181
182 call_client_interface(&arg);
183 *ret0 = arg.args[4];
184 *ret1 = arg.args[5];
185 return arg.args[3];
186 }
187
188 static inline unsigned int
of_4_1(const char * serv,int arg0,int arg1,int arg2,int arg3)189 of_4_1(const char *serv, int arg0, int arg1, int arg2, int arg3)
190 {
191 of_arg_t arg = {
192 p32cast serv,
193 4, 1,
194 {arg0, arg1, arg2, arg3, 0}
195 };
196
197 call_client_interface(&arg);
198 return arg.args[4];
199 }
200
201 int
of_test(const char * name)202 of_test(const char *name)
203 {
204 return (int) of_1_1("test", p32cast name);
205 }
206
207 int
of_interpret_1(void * s,void * ret)208 of_interpret_1(void *s, void *ret)
209 {
210 return of_1_2("interpret", p32cast s, ret);
211 }
212
213 void
of_close(ihandle_t ihandle)214 of_close(ihandle_t ihandle)
215 {
216 of_1_0("close", ihandle);
217 }
218
219 int
of_write(ihandle_t ihandle,void * s,int len)220 of_write(ihandle_t ihandle, void *s, int len)
221 {
222 return of_3_1("write", ihandle, p32cast s, len);
223 }
224
225 int
of_read(ihandle_t ihandle,void * s,int len)226 of_read(ihandle_t ihandle, void *s, int len)
227 {
228 return of_3_1("read", ihandle, p32cast s, len);
229 }
230
231 int
of_seek(ihandle_t ihandle,int poshi,int poslo)232 of_seek(ihandle_t ihandle, int poshi, int poslo)
233 {
234 return of_3_1("seek", ihandle, poshi, poslo);
235 }
236
237 int
of_getprop(phandle_t phandle,const char * name,void * buf,int len)238 of_getprop(phandle_t phandle, const char *name, void *buf, int len)
239 {
240 return of_4_1("getprop", phandle, p32cast name, p32cast buf, len);
241 }
242
243 phandle_t
of_peer(phandle_t phandle)244 of_peer(phandle_t phandle)
245 {
246 return (phandle_t) of_1_1("peer", phandle);
247 }
248
249 phandle_t
of_child(phandle_t phandle)250 of_child(phandle_t phandle)
251 {
252 return (phandle_t) of_1_1("child", phandle);
253 }
254
255 phandle_t
of_parent(phandle_t phandle)256 of_parent(phandle_t phandle)
257 {
258 return (phandle_t) of_1_1("parent", phandle);
259 }
260
261 phandle_t
of_instance_to_package(ihandle_t ihandle)262 of_instance_to_package(ihandle_t ihandle)
263 {
264 return (phandle_t) of_1_1("instance-to-package", ihandle);
265 }
266
267
268 phandle_t
of_finddevice(const char * name)269 of_finddevice(const char *name)
270 {
271 return (phandle_t) of_1_1("finddevice", p32cast name);
272 }
273
274 ihandle_t
of_open(const char * name)275 of_open(const char *name)
276 {
277 return (ihandle_t) of_1_1("open", p32cast name);
278 }
279
280 void *
of_claim(void * start,unsigned int size,unsigned int align)281 of_claim(void *start, unsigned int size, unsigned int align)
282 {
283 return(void *)(long)(size_t)of_3_1("claim", p32cast start, size, align);
284 }
285
286 void
of_release(void * start,unsigned int size)287 of_release(void *start, unsigned int size)
288 {
289 (void) of_2_0("release", p32cast start, size);
290 }
291
292 void *
of_call_method_3(const char * name,ihandle_t ihandle,int arg0)293 of_call_method_3(const char *name, ihandle_t ihandle, int arg0)
294 {
295 int entry, rc;
296 rc = of_3_2("call-method", p32cast name, ihandle, arg0, &entry);
297 return rc != 0 ? 0 : (void *) (long) entry;
298 }
299
300 int
vpd_read(unsigned int offset,unsigned int length,char * data)301 vpd_read(unsigned int offset, unsigned int length, char *data)
302 {
303 int result;
304 long tmp = (long) data;
305 result = of_3_1("rtas-read-vpd", offset, length, (int) tmp);
306 return result;
307 }
308
309 int
vpd_write(unsigned int offset,unsigned int length,char * data)310 vpd_write(unsigned int offset, unsigned int length, char *data)
311 {
312 int result;
313 long tmp = (long) data;
314 result = of_3_1("rtas-write-vpd", offset, length, (int) tmp);
315 return result;
316 }
317
318 static void
ipmi_oem_led_set(int type,int instance,int state)319 ipmi_oem_led_set(int type, int instance, int state)
320 {
321 return of_3_0("set-led", type, instance, state);
322 }
323
324 int
write_mm_log(char * data,unsigned int length,unsigned short type)325 write_mm_log(char *data, unsigned int length, unsigned short type)
326 {
327 long tmp = (long) data;
328
329 ipmi_oem_led_set(2, 0, 1);
330 return of_3_1("write-mm-log", (int) tmp, length, type);
331 }
332
333 int
of_yield(void)334 of_yield(void)
335 {
336 return of_0_1("yield");
337 }
338
339 void *
of_set_callback(void * addr)340 of_set_callback(void *addr)
341 {
342 return (void *) (long) (size_t) of_1_1("set-callback", p32cast addr);
343 }
344
345 void
bootmsg_warning(short id,const char * str,short lvl)346 bootmsg_warning(short id, const char *str, short lvl)
347 {
348 (void) of_3_0("bootmsg-warning", id, lvl, p32cast str);
349 }
350
351 void
bootmsg_error(short id,const char * str)352 bootmsg_error(short id, const char *str)
353 {
354 (void) of_2_0("bootmsg-error", id, p32cast str);
355 }
356
357 /*
358 void
359 bootmsg_debugcp(short id, const char *str, short lvl)
360 {
361 (void) of_3_0("bootmsg-debugcp", id, lvl, p32cast str);
362 }
363
364 void
365 bootmsg_cp(short id)
366 {
367 (void) of_1_0("bootmsg-cp", id);
368 }
369 */
370
371 #define CONFIG_SPACE 0
372 #define IO_SPACE 1
373 #define MEM_SPACE 2
374
375 #define ASSIGNED_ADDRESS_PROPERTY 0
376 #define REG_PROPERTY 1
377
378 #define DEBUG_TRANSLATE_ADDRESS 0
379 #if DEBUG_TRANSLATE_ADDRESS != 0
380 #define DEBUG_TR(str...) printf(str)
381 #else
382 #define DEBUG_TR(str...)
383 #endif
384
385 /**
386 * pci_address_type tries to find the type for which a
387 * mapping should be done. This is PCI specific and is done by
388 * looking at the first 32bit of the phys-addr in
389 * assigned-addresses
390 *
391 * @param node the node of the device which requests
392 * translatation
393 * @param address the address which needs to be translated
394 * @param prop_type the type of the property to search in (either REG_PROPERTY or ASSIGNED_ADDRESS_PROPERTY)
395 * @return the corresponding type (config, i/o, mem)
396 */
397 static int
pci_address_type(phandle_t node,uint64_t address,uint8_t prop_type)398 pci_address_type(phandle_t node, uint64_t address, uint8_t prop_type)
399 {
400 char *prop_name = "assigned-addresses";
401 if (prop_type == REG_PROPERTY)
402 prop_name = "reg";
403 /* #address-cells */
404 const unsigned int nac = 3; //PCI
405 /* #size-cells */
406 const unsigned int nsc = 2; //PCI
407 /* up to 11 pairs of (phys-addr(3) size(2)) */
408 unsigned char buf[11 * (nac + nsc) * sizeof(int)];
409 unsigned int *assigned_ptr;
410 int result = -1;
411 int len;
412 len = of_getprop(node, prop_name, buf, 11 * (nac + nsc) * sizeof(int));
413 assigned_ptr = (unsigned int *) &buf[0];
414 while (len > 0) {
415 if ((prop_type == REG_PROPERTY)
416 && ((assigned_ptr[0] & 0xFF) != 0)) {
417 //BARs and Expansion ROM must be in assigned-addresses... so in reg
418 // we only look for those without config space offset set...
419 assigned_ptr += (nac + nsc);
420 len -= (nac + nsc) * sizeof(int);
421 continue;
422 }
423 DEBUG_TR("%s %x size %x\n", prop_name, assigned_ptr[2],
424 assigned_ptr[4]);
425 if (address >= assigned_ptr[2]
426 && address <= assigned_ptr[2] + assigned_ptr[4]) {
427 DEBUG_TR("found a match\n");
428 result = (assigned_ptr[0] & 0x03000000) >> 24;
429 break;
430 }
431 assigned_ptr += (nac + nsc);
432 len -= (nac + nsc) * sizeof(int);
433 }
434 /* this can only handle 32bit memory space and should be
435 * removed as soon as translations for 64bit are available */
436 return (result == 3) ? MEM_SPACE : result;
437 }
438
439 /**
440 * this is a hack which returns the lower 64 bit of any number of cells
441 * all the higher bits will silently discarded
442 * right now this works pretty good as long 64 bit addresses is all we want
443 *
444 * @param addr a pointer to the first address cell
445 * @param nc number of cells addr points to
446 * @return the lower 64 bit to which addr points
447 */
448 static uint64_t
get_dt_address(uint32_t * addr,uint32_t nc)449 get_dt_address(uint32_t *addr, uint32_t nc)
450 {
451 uint64_t result = 0;
452 while (nc--)
453 result = (result << 32) | *(addr++);
454 return result;
455 }
456
457 /**
458 * this functions tries to find a mapping for the given address
459 * it assumes that if we have #address-cells == 3 that we are trying
460 * to do a PCI translation
461 *
462 * @param addr a pointer to the address that should be translated
463 * if a translation has been found the address will
464 * be modified
465 * @param type this is required for PCI devices to find the
466 * correct translation
467 * @param ranges this is one "range" containing the translation
468 * information (one range = nac + pnac + nsc)
469 * @param nac the OF property #address-cells
470 * @param nsc the OF property #size-cells
471 * @param pnac the OF property #address-cells from the parent node
472 * @return -1 if no translation was possible; else 0
473 */
474 static int
map_one_range(uint64_t * addr,int type,uint32_t * ranges,uint32_t nac,uint32_t nsc,uint32_t pnac)475 map_one_range(uint64_t *addr, int type, uint32_t *ranges, uint32_t nac,
476 uint32_t nsc, uint32_t pnac)
477 {
478 long offset;
479 /* cm - child mapping */
480 /* pm - parent mapping */
481 uint64_t cm, size, pm;
482 /* only check for the type if nac == 3 (PCI) */
483 DEBUG_TR("type %x, nac %x\n", ranges[0], nac);
484 if (((ranges[0] & 0x03000000) >> 24) != type && nac == 3)
485 return -1;
486 /* okay, it is the same type let's see if we find a mapping */
487 size = get_dt_address(ranges + nac + pnac, nsc);
488 if (nac == 3) /* skip type if PCI */
489 cm = get_dt_address(ranges + 1, nac - 1);
490 else
491 cm = get_dt_address(ranges, nac);
492
493 DEBUG_TR("\t\tchild_mapping %lx\n", cm);
494 DEBUG_TR("\t\tsize %lx\n", size);
495 DEBUG_TR("\t\t*address %lx\n", (uint64_t) * addr);
496 if (cm + size <= (uint64_t) * addr || cm > (uint64_t) * addr)
497 /* it is not inside the mapping range */
498 return -1;
499 /* get the offset */
500 offset = *addr - cm;
501 /* and add the offset on the parent mapping */
502 if (pnac == 3) /* skip type if PCI */
503 pm = get_dt_address(ranges + nac + 1, pnac - 1);
504 else
505 pm = get_dt_address(ranges + nac, pnac);
506 DEBUG_TR("\t\tparent_mapping %lx\n", pm);
507 *addr = pm + offset;
508 DEBUG_TR("\t\t*address %lx\n", *addr);
509 return 0;
510 }
511
512 /**
513 * translate_address_dev tries to translate the device specific address
514 * to a host specific address by walking up in the device tree
515 *
516 * @param address a pointer to a 64 bit value which will be
517 * translated
518 * @param current_node phandle of the device from which the
519 * translation will be started
520 */
521 void
translate_address_dev(uint64_t * addr,phandle_t current_node)522 translate_address_dev(uint64_t *addr, phandle_t current_node)
523 {
524 unsigned char buf[1024];
525 phandle_t parent;
526 unsigned int pnac;
527 unsigned int nac;
528 unsigned int nsc;
529 int addr_type;
530 int len;
531 unsigned int *ranges;
532 unsigned int one_range;
533 DEBUG_TR("translate address %lx, node: %lx\n", *addr, current_node);
534 of_getprop(current_node, "name", buf, 400);
535 DEBUG_TR("current node: %s\n", buf);
536 addr_type =
537 pci_address_type(current_node, *addr, ASSIGNED_ADDRESS_PROPERTY);
538 if (addr_type == -1) {
539 // check in "reg" property if not found in "assigned-addresses"
540 addr_type = pci_address_type(current_node, *addr, REG_PROPERTY);
541 }
542 DEBUG_TR("address_type %x\n", addr_type);
543 current_node = of_parent(current_node);
544 while (1) {
545 parent = of_parent(current_node);
546 if (!parent) {
547 DEBUG_TR("reached root node...\n");
548 break;
549 }
550 of_getprop(current_node, "#address-cells", &nac, 4);
551 of_getprop(current_node, "#size-cells", &nsc, 4);
552 of_getprop(parent, "#address-cells", &pnac, 4);
553 one_range = nac + pnac + nsc;
554 len = of_getprop(current_node, "ranges", buf, 400);
555 if (len < 0) {
556 DEBUG_TR("no 'ranges' property; not translatable\n");
557 return;
558 }
559 ranges = (unsigned int *) &buf[0];
560 while (len > 0) {
561 if (!map_one_range
562 ((uint64_t *) addr, addr_type, ranges, nac, nsc,
563 pnac))
564 /* after a successful mapping we stop
565 * going through the ranges */
566 break;
567 ranges += one_range;
568 len -= one_range * sizeof(int);
569 }
570 DEBUG_TR("address %lx\n", *addr);
571 of_getprop(current_node, "name", buf, 400);
572 DEBUG_TR("current node: %s\n", buf);
573 DEBUG_TR("\t#address-cells: %x\n", nac);
574 DEBUG_TR("\t#size-cells: %x\n", nsc);
575 of_getprop(parent, "name", buf, 400);
576 DEBUG_TR("parent node: %s\n", buf);
577 DEBUG_TR("\t#address-cells: %x\n", pnac);
578 current_node = parent;
579 }
580 }
581
582 static phandle_t
get_boot_device(void)583 get_boot_device(void)
584 {
585 char buf[1024];
586 phandle_t dev = of_finddevice("/chosen");
587
588 if (dev == -1) {
589 dev = of_finddevice("/aliases");
590 if (dev == -1)
591 return dev;
592 of_getprop(dev, "net", buf, 1024);
593 } else
594 of_getprop(dev, "bootpath", buf, 1024);
595
596 return of_finddevice(buf);
597 }
598
599 /**
600 * translate_address tries to translate the device specific address
601 * of the boot device to a host specific address
602 *
603 * @param address a pointer to a 64 bit value which will be
604 * translated
605 */
606 void
translate_address(unsigned long * addr)607 translate_address(unsigned long *addr)
608 {
609 translate_address_dev((uint64_t*) addr, get_boot_device());
610 }
611
612 /**
613 * get_puid walks up in the device tree until it finds a parent
614 * node without a reg property. get_puid is assuming that if the
615 * parent node has no reg property it has found the pci host bridge
616 *
617 * this is not the correct way to find PHBs but it seems to work
618 * for all our systems
619 *
620 * @param node the device for which to find the puid
621 *
622 * @return the puid or 0
623 */
624 uint64_t
get_puid(phandle_t node)625 get_puid(phandle_t node)
626 {
627 uint64_t puid = 0;
628 uint64_t tmp = 0;
629 phandle_t curr_node, last_node;
630
631 curr_node = last_node = of_parent(node);
632
633 while (curr_node) {
634 puid = tmp;
635 if (of_getprop(curr_node, "reg", &tmp, 8) < 8) {
636 /* if the found PHB is not directly under
637 * root we need to translate the found address */
638 translate_address_dev(&puid, last_node);
639 return puid;
640 }
641 last_node = curr_node;
642 curr_node = of_parent(curr_node);
643 }
644
645 return 0;
646 }
647
of_get_mac(phandle_t device,char * mac)648 int of_get_mac(phandle_t device, char *mac)
649 {
650 uint8_t localmac[8];
651 int len;
652
653 len = of_getprop(device, "local-mac-address", localmac, 8);
654 if (len <= 0)
655 return -1;
656
657 if (len == 8) {
658 /* Some bad FDT nodes like veth use a 8-byte wide
659 * property instead of 6-byte wide MACs... :-( */
660 memcpy(mac, &localmac[2], 6);
661 }
662 else {
663 memcpy(mac, localmac, 6);
664 }
665 return 0;
666 }
667
668 static void
get_timebase(unsigned int * timebase)669 get_timebase(unsigned int *timebase)
670 {
671 phandle_t cpu;
672 phandle_t cpus = of_finddevice("/cpus");
673
674 if (cpus == -1)
675 return;
676
677 cpu = of_child(cpus);
678
679 if (cpu == -1)
680 return;
681
682 of_getprop(cpu, "timebase-frequency", timebase, 4);
683 }
684
of_glue_init(unsigned int * timebase,size_t _client_start,size_t _client_size)685 int of_glue_init(unsigned int * timebase,
686 size_t _client_start, size_t _client_size)
687 {
688 phandle_t chosen = of_finddevice("/chosen");
689 ihandle_t stdin_ih, stdout_ih;
690
691 client_start = (void *) (long) _client_start;
692 client_size = _client_size;
693
694 if (chosen == -1)
695 return -1;
696
697 of_getprop(chosen, "stdin", &stdin_ih, sizeof(ihandle_t));
698 of_getprop(chosen, "stdout", &stdout_ih, sizeof(ihandle_t));
699 pre_open_ih(0, stdin_ih);
700 pre_open_ih(1, stdout_ih);
701 pre_open_ih(2, stdout_ih);
702 get_timebase(timebase);
703 rtas_init();
704
705 claim_rc=(int)(long)of_claim(client_start, client_size, 0);
706
707 return 0;
708 }
709
of_glue_release(void)710 void of_glue_release(void)
711 {
712 if (claim_rc >= 0) {
713 of_release(client_start, client_size);
714 }
715 }
716