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