xref: /netbsd-src/external/gpl3/gdb/dist/sim/ppc/hw_phb.c (revision 71f621822dbfd5073a314948bec169b7bb05f7be)
1 /*  This file is part of the program psim.
2 
3     Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, see <http://www.gnu.org/licenses/>.
17 
18     */
19 
20 
21 #ifndef _HW_PHB_C_
22 #define _HW_PHB_C_
23 
24 #include "device_table.h"
25 
26 #include "hw_phb.h"
27 
28 #include "corefile.h"
29 
30 #include <stdlib.h>
31 #include <ctype.h>
32 
33 
34 /* DEVICE
35 
36 
37    phb - PCI Host Bridge
38 
39 
40    DESCRIPTION
41 
42 
43    PHB implements a model of the PCI-host bridge described in the PPCP
44    document.
45 
46    For bridge devices, Open Firmware specifies that the <<ranges>>
47    property be used to specify the mapping of address spaces between a
48    bridges parent and child busses.  This PHB model configures itsself
49    according to the information specified in its ranges property.  The
50    <<ranges>> property is described in detail in the Open Firmware
51    documentation.
52 
53    For DMA transfers, any access to a PCI address space which falls
54    outside of the mapped memory space is assumed to be a transfer
55    intended for the parent bus.
56 
57 
58    PROPERTIES
59 
60 
61    ranges = <my-phys-addr> <parent-phys-addr> <my-size> ...  (required)
62 
63    Define a number of mappings from the parent bus to one of this
64    devices PCI busses.  The exact format of the <<parent-phys-addr>>
65    is parent bus dependant.  The format of <<my-phys-addr>> is
66    described in the Open Firmware PCI bindings document (note that the
67    address must be non-relocatable).
68 
69 
70    #address-cells = 3  (required)
71 
72    Number of cells used by an Open Firmware PCI address.  This
73    property must be defined before specifying the <<ranges>> property.
74 
75 
76    #size-cells = 2  (required)
77 
78    Number of cells used by an Open Firmware PCI size.  This property
79    must be defined before specifying the <<ranges>> property.
80 
81 
82    EXAMPLES
83 
84 
85    Enable tracing:
86 
87    |  $ psim \
88    |    -t phb-device \
89 
90 
91    Since device tree entries that are specified on the command line
92    are added before most of the device tree has been built it is often
93    necessary to explictly add certain device properties and thus
94    ensure they are already present in the device tree.  For the
95    <<phb>> one such property is parent busses <<#address-cells>>.
96 
97    |    -o '/#address-cells 1' \
98 
99 
100    Create the PHB remembering to include the cell size properties:
101 
102    |    -o '/phb@0x80000000/#address-cells 3' \
103    |    -o '/phb@0x80000000/#size-cells 2' \
104 
105 
106    Specify that the memory address range <<0x80000000>> to
107    <<0x8fffffff>> should map directly onto the PCI memory address
108    space while the processor address range <<0xc0000000>> to
109    <<0xc000ffff>> should map onto the PCI I/O address range starting
110    at location zero:
111 
112    |    -o '/phb@0x80000000/ranges \
113    |                nm0,0,0,80000000 0x80000000 0x10000000 \
114    |                ni0,0,0,0 0xc0000000 0x10000' \
115 
116 
117    Insert a 4k <<nvram>> into slot zero of the PCI bus.  Have it
118    directly accessible in both the I/O (address <<0x100>>) and memory
119    (address 0x80001000) spaces:
120 
121    |    -o '/phb@0x80000000/nvram@0/assigned-addresses \
122    |                nm0,0,10,80001000 4096 \
123    |                ni0,0,14,100 4096'
124    |    -o '/phb@0x80000000/nvram@0/reg \
125    |                0 0 \
126    |                i0,0,14,0 4096'
127    |    -o '/phb@0x80000000/nvram@0/alternate-reg \
128    |                0 0 \
129    |                m0,0,10,0 4096'
130 
131    The <<assigned-address>> property corresponding to what (if it were
132    implemented) be found in the config base registers while the
133    <<reg>> and <<alternative-reg>> properties indicating the location
134    of registers within each address space.
135 
136    Of the possible addresses, only the non-relocatable versions are
137    used when attaching the device to the bus.
138 
139 
140    BUGS
141 
142 
143    The implementation of the PCI configuration space is left as an
144    exercise for the reader.  Such a restriction should only impact on
145    systems wanting to dynamically configure devices on the PCI bus.
146 
147    The <<CHRP>> document specfies additional (optional) functionality
148    of the primary PHB. The implementation of such functionality is
149    left as an exercise for the reader.
150 
151    The Open Firmware PCI bus bindings document (rev 1.6 and 2.0) is
152    unclear on the value of the "ss" bits for a 64bit memory address.
153    The correct value, as used by this module, is 0b11.
154 
155    The Open Firmware PCI bus bindings document (rev 1.6) suggests that
156    the register field of non-relocatable PCI address should be zero.
157    Unfortunatly, PCI addresses specified in the <<assigned-addresses>>
158    property must be both non-relocatable and have non-zero register
159    fields.
160 
161    The unit-decode method is not inserting a bus number into any
162    address that it decodes.  Instead the bus-number is left as zero.
163 
164    Support for aliased memory and I/O addresses is left as an exercise
165    for the reader.
166 
167    Support for interrupt-ack and special cycles are left as an
168    exercise for the reader.  One issue to consider when attempting
169    this exercise is how to specify the address of the int-ack and
170    special cycle register.  Hint: <</8259-interrupt-ackowledge>> is
171    the wrong answer.
172 
173    Children of this node can only use the client callback interface
174    when attaching themselves to the <<phb>>.
175 
176 
177    REFERENCES
178 
179 
180    http://playground.sun.com/1275/home.html#OFDbusPCI
181 
182 
183    */
184 
185 
186 typedef struct _phb_space {
187   core *map;
188   core_map *readable;
189   core_map *writeable;
190   unsigned_word parent_base;
191   int parent_space;
192   unsigned_word my_base;
193   int my_space;
194   unsigned size;
195   const char *name;
196 } phb_space;
197 
198 typedef struct _hw_phb_device  {
199   phb_space space[nr_hw_phb_spaces];
200 } hw_phb_device;
201 
202 
203 static const char *
204 hw_phb_decode_name(hw_phb_decode level)
205 {
206   switch (level) {
207   case hw_phb_normal_decode: return "normal";
208   case hw_phb_subtractive_decode: return "subtractive";
209   case hw_phb_master_abort_decode: return "master-abort";
210   default: return "invalid decode";
211   }
212 }
213 
214 
215 static void
216 hw_phb_init_address(device *me)
217 {
218   hw_phb_device *phb = device_data(me);
219 
220   /* check some basic properties */
221   if (device_nr_address_cells(me) != 3)
222     device_error(me, "incorrect #address-cells");
223   if (device_nr_size_cells(me) != 2)
224     device_error(me, "incorrect #size-cells");
225 
226   /* (re) initialize each PCI space */
227   {
228     hw_phb_spaces space_nr;
229     for (space_nr = 0; space_nr < nr_hw_phb_spaces; space_nr++) {
230       phb_space *pci_space = &phb->space[space_nr];
231       core_init(pci_space->map);
232       pci_space->size = 0;
233     }
234   }
235 
236   /* decode each of the ranges properties entering the information
237      into the space table */
238   {
239     range_property_spec range;
240     int ranges_entry;
241 
242     for (ranges_entry = 0;
243 	 device_find_range_array_property(me, "ranges", ranges_entry,
244 					  &range);
245 	 ranges_entry++) {
246       int my_attach_space;
247       unsigned_word my_attach_address;
248       int parent_attach_space;
249       unsigned_word parent_attach_address;
250       unsigned size;
251       phb_space *pci_space;
252       /* convert the addresses into something meaningful */
253       device_address_to_attach_address(me, &range.child_address,
254 				       &my_attach_space,
255 				       &my_attach_address,
256 				       me);
257       device_address_to_attach_address(device_parent(me),
258 				       &range.parent_address,
259 				       &parent_attach_space,
260 				       &parent_attach_address,
261 				       me);
262       device_size_to_attach_size(me, &range.size, &size, me);
263       if (my_attach_space < 0 || my_attach_space >= nr_hw_phb_spaces)
264 	device_error(me, "ranges property contains an invalid address space");
265       pci_space = &phb->space[my_attach_space];
266       if (pci_space->size != 0)
267 	device_error(me, "ranges property contains duplicate mappings for %s address space",
268 		     pci_space->name);
269       pci_space->parent_base = parent_attach_address;
270       pci_space->parent_space = parent_attach_space;
271       pci_space->my_base = my_attach_address;
272       pci_space->my_space = my_attach_space;
273       pci_space->size = size;
274       device_attach_address(device_parent(me),
275 			    attach_callback,
276 			    parent_attach_space, parent_attach_address, size,
277 			    access_read_write_exec,
278 			    me);
279       DTRACE(phb, ("map %d:0x%lx to %s:0x%lx (0x%lx bytes)\n",
280 		   (int)parent_attach_space,
281 		   (unsigned long)parent_attach_address,
282 		   pci_space->name,
283 		   (unsigned long)my_attach_address,
284 		   (unsigned long)size));
285     }
286 
287     if (ranges_entry == 0) {
288       device_error(me, "Missing or empty ranges property");
289     }
290 
291   }
292 
293 }
294 
295 static void
296 hw_phb_attach_address(device *me,
297 		      attach_type type,
298 		      int space,
299 		      unsigned_word addr,
300 		      unsigned nr_bytes,
301 		      access_type access,
302 		      device *client) /*callback/default*/
303 {
304   hw_phb_device *phb = device_data(me);
305   phb_space *pci_space;
306   hw_phb_decode phb_type = (hw_phb_decode)type;
307   /* sanity checks */
308   if (space < 0 || space >= nr_hw_phb_spaces)
309     device_error(me, "attach space (%d) specified by %s invalid",
310 		 space, device_path(client));
311   pci_space = &phb->space[space];
312   if (addr + nr_bytes > pci_space->my_base + pci_space->size
313       || addr < pci_space->my_base)
314     device_error(me, "attach addr (0x%lx) specified by %s outside of bus address range",
315 		 (unsigned long)addr, device_path(client));
316   if (phb_type != hw_phb_normal_decode && phb_type != hw_phb_subtractive_decode)
317     device_error(me, "attach type (%d) specified by %s invalid",
318 		 type, device_path(client));
319   /* attach it to the relevent bus */
320   DTRACE(phb, ("attach %s - %s %s:0x%lx (0x%lx bytes)\n",
321 	       device_path(client),
322 	       hw_phb_decode_name(phb_type),
323 	       pci_space->name,
324 	       (unsigned long)addr,
325 	       (unsigned long)nr_bytes));
326   core_attach(pci_space->map,
327 	      type,
328 	      space,
329 	      access,
330 	      addr,
331 	      nr_bytes,
332 	      client);
333 }
334 
335 
336 /* Extract/set various fields from a PCI unit address.
337 
338    Note: only the least significant 32 bits of each cell is used.
339 
340    Note: for PPC MSB is 0 while for PCI it is 31. */
341 
342 
343 /* relocatable bit n */
344 
345 static unsigned
346 extract_n(const device_unit *address)
347 {
348   return EXTRACTED32(address->cells[0], 0, 0);
349 }
350 
351 static void
352 set_n(device_unit *address)
353 {
354   BLIT32(address->cells[0], 0, 1);
355 }
356 
357 
358 /* prefetchable bit p */
359 
360 static unsigned
361 extract_p(const device_unit *address)
362 {
363   ASSERT(address->nr_cells == 3);
364   return EXTRACTED32(address->cells[0], 1, 1);
365 }
366 
367 static void
368 set_p(device_unit *address)
369 {
370   BLIT32(address->cells[0], 1, 1);
371 }
372 
373 
374 /* aliased bit t */
375 
376 static unsigned
377 extract_t(const device_unit *address)
378 {
379   ASSERT(address->nr_cells == 3);
380   return EXTRACTED32(address->cells[0], 2, 2);
381 }
382 
383 static void
384 set_t(device_unit *address)
385 {
386   BLIT32(address->cells[0], 2, 1);
387 }
388 
389 
390 /* space code ss */
391 
392 typedef enum {
393   ss_config_code = 0,
394   ss_io_code = 1,
395   ss_32bit_memory_code = 2,
396   ss_64bit_memory_code = 3,
397 } ss_type;
398 
399 static ss_type
400 extract_ss(const device_unit *address)
401 {
402   ASSERT(address->nr_cells == 3);
403   return EXTRACTED32(address->cells[0], 6, 7);
404 }
405 
406 static void
407 set_ss(device_unit *address, ss_type val)
408 {
409   MBLIT32(address->cells[0], 6, 7, val);
410 }
411 
412 
413 /* bus number bbbbbbbb */
414 
415 #if 0
416 static unsigned
417 extract_bbbbbbbb(const device_unit *address)
418 {
419   ASSERT(address->nr_cells == 3);
420   return EXTRACTED32(address->cells[0], 8, 15);
421 }
422 #endif
423 
424 #if 0
425 static void
426 set_bbbbbbbb(device_unit *address, unsigned val)
427 {
428   MBLIT32(address->cells[0], 8, 15, val);
429 }
430 #endif
431 
432 
433 /* device number ddddd */
434 
435 static unsigned
436 extract_ddddd(const device_unit *address)
437 {
438   ASSERT(address->nr_cells == 3);
439   return EXTRACTED32(address->cells[0], 16, 20);
440 }
441 
442 static void
443 set_ddddd(device_unit *address, unsigned val)
444 {
445   MBLIT32(address->cells[0], 16, 20, val);
446 }
447 
448 
449 /* function number fff */
450 
451 static unsigned
452 extract_fff(const device_unit *address)
453 {
454   ASSERT(address->nr_cells == 3);
455   return EXTRACTED32(address->cells[0], 21, 23);
456 }
457 
458 static void
459 set_fff(device_unit *address, unsigned val)
460 {
461   MBLIT32(address->cells[0], 21, 23, val);
462 }
463 
464 
465 /* register number rrrrrrrr */
466 
467 static unsigned
468 extract_rrrrrrrr(const device_unit *address)
469 {
470   ASSERT(address->nr_cells == 3);
471   return EXTRACTED32(address->cells[0], 24, 31);
472 }
473 
474 static void
475 set_rrrrrrrr(device_unit *address, unsigned val)
476 {
477   MBLIT32(address->cells[0], 24, 31, val);
478 }
479 
480 
481 /* MSW of 64bit address hh..hh */
482 
483 static unsigned
484 extract_hh_hh(const device_unit *address)
485 {
486   ASSERT(address->nr_cells == 3);
487   return address->cells[1];
488 }
489 
490 static void
491 set_hh_hh(device_unit *address, unsigned val)
492 {
493   address->cells[2] = val;
494 }
495 
496 
497 /* LSW of 64bit address ll..ll */
498 
499 static unsigned
500 extract_ll_ll(const device_unit *address)
501 {
502   ASSERT(address->nr_cells == 3);
503   return address->cells[2];
504 }
505 
506 static void
507 set_ll_ll(device_unit *address, unsigned val)
508 {
509   address->cells[2] = val;
510 }
511 
512 
513 /* Convert PCI textual bus address into a device unit */
514 
515 static int
516 hw_phb_unit_decode(device *me,
517 		   const char *unit,
518 		   device_unit *address)
519 {
520   char *end = NULL;
521   const char *chp = unit;
522   unsigned long val;
523 
524   if (device_nr_address_cells(me) != 3)
525     device_error(me, "PCI bus should have #address-cells == 3");
526   memset(address, 0, sizeof(*address));
527 
528   if (unit == NULL)
529     return 0;
530 
531   address->nr_cells = 3;
532 
533   if (isxdigit(*chp)) {
534     set_ss(address, ss_config_code);
535   }
536   else {
537 
538     /* non-relocatable? */
539     if (*chp == 'n') {
540       set_n(address);
541       chp++;
542     }
543 
544     /* address-space? */
545     if (*chp == 'i') {
546       set_ss(address, ss_io_code);
547       chp++;
548     }
549     else if (*chp == 'm') {
550       set_ss(address, ss_32bit_memory_code);
551       chp++;
552     }
553     else if (*chp == 'x') {
554       set_ss(address, ss_64bit_memory_code);
555       chp++;
556     }
557     else
558       device_error(me, "Problem parsing PCI address %s", unit);
559 
560     /* possible alias */
561     if (*chp == 't') {
562       if (extract_ss(address) == ss_64bit_memory_code)
563 	device_error(me, "Invalid alias bit in PCI address %s", unit);
564       set_t(address);
565       chp++;
566     }
567 
568     /* possible p */
569     if (*chp == 'p') {
570       if (extract_ss(address) != ss_32bit_memory_code)
571 	device_error(me, "Invalid prefetchable bit (p) in PCI address %s",
572 		     unit);
573       set_p(address);
574       chp++;
575     }
576 
577   }
578 
579   /* required DD */
580   if (!isxdigit(*chp))
581     device_error(me, "Missing device number in PCI address %s", unit);
582   val = strtoul(chp, &end, 16);
583   if (chp == end)
584     device_error(me, "Problem parsing device number in PCI address %s", unit);
585   if ((val & 0x1f) != val)
586     device_error(me, "Device number (0x%lx) out of range (0..0x1f) in PCI address %s",
587 		 val, unit);
588   set_ddddd(address, val);
589   chp = end;
590 
591   /* For config space, the F is optional */
592   if (extract_ss(address) == ss_config_code
593       && (isspace(*chp) || *chp == '\0'))
594     return chp - unit;
595 
596   /* function number F */
597   if (*chp != ',')
598     device_error(me, "Missing function number in PCI address %s", unit);
599   chp++;
600   val = strtoul(chp, &end, 10);
601   if (chp == end)
602     device_error(me, "Problem parsing function number in PCI address %s",
603 		 unit);
604   if ((val & 7) != val)
605     device_error(me, "Function number (%ld) out of range (0..7) in PCI address %s",
606 		 (long)val, unit);
607   set_fff(address, val);
608   chp = end;
609 
610   /* for config space, must be end */
611   if (extract_ss(address) == ss_config_code) {
612     if (!isspace(*chp) && *chp != '\0')
613       device_error(me, "Problem parsing PCI config address %s",
614 		   unit);
615     return chp - unit;
616   }
617 
618   /* register number RR */
619   if (*chp != ',')
620     device_error(me, "Missing register number in PCI address %s", unit);
621   chp++;
622   val = strtoul(chp, &end, 16);
623   if (chp == end)
624     device_error(me, "Problem parsing register number in PCI address %s",
625 		 unit);
626   switch (extract_ss(address)) {
627   case ss_io_code:
628 #if 0
629     if (extract_n(address) && val != 0)
630       device_error(me, "non-relocatable I/O register must be zero in PCI address %s", unit);
631     else if (!extract_n(address)
632 	     && val != 0x10 && val != 0x14 && val != 0x18
633 	     && val != 0x1c && val != 0x20 && val != 0x24)
634       device_error(me, "I/O register invalid in PCI address %s", unit);
635 #endif
636     break;
637   case ss_32bit_memory_code:
638 #if 0
639     if (extract_n(address) && val != 0)
640       device_error(me, "non-relocatable memory register must be zero in PCI address %s", unit);
641     else if (!extract_n(address)
642 	     && val != 0x10 && val != 0x14 && val != 0x18
643 	     && val != 0x1c && val != 0x20 && val != 0x24 && val != 0x30)
644       device_error(me, "I/O register (0x%lx) invalid in PCI address %s",
645 		   val, unit);
646 #endif
647     break;
648   case ss_64bit_memory_code:
649     if (extract_n(address) && val != 0)
650       device_error(me, "non-relocatable 32bit memory register must be zero in PCI address %s", unit);
651     else if (!extract_n(address)
652 	     && val != 0x10 && val != 0x18 && val != 0x20)
653       device_error(me, "Register number (0x%lx) invalid in 64bit PCI address %s",
654 		   val, unit);
655     break;
656   case ss_config_code:
657     device_error(me, "internal error");
658   }
659   if ((val & 0xff) != val)
660     device_error(me, "Register number (0x%lx) out of range (0..0xff) in PCI address %s",
661 		 val, unit);
662   set_rrrrrrrr(address, val);
663   chp = end;
664 
665   /* address */
666   if (*chp != ',')
667     device_error(me, "Missing address in PCI address %s", unit);
668   chp++;
669   switch (extract_ss(address)) {
670   case ss_io_code:
671   case ss_32bit_memory_code:
672     val = strtoul(chp, &end, 16);
673     if (chp == end)
674       device_error(me, "Problem parsing address in PCI address %s", unit);
675     switch (extract_ss(address)) {
676     case ss_io_code:
677       if (extract_n(address) && extract_t(address)
678 	  && (val & 1024) != val)
679 	device_error(me, "10bit aliased non-relocatable address (0x%lx) out of range in PCI address %s",
680 		     val, unit);
681       if (!extract_n(address) && extract_t(address)
682 	  && (val & 0xffff) != val)
683 	device_error(me, "64k relocatable address (0x%lx) out of range in PCI address %s",
684 		     val, unit);
685       break;
686     case ss_32bit_memory_code:
687       if (extract_t(address) && (val & 0xfffff) != val)
688 	device_error(me, "1mb memory address (0x%lx) out of range in PCI address %s",
689 		     val, unit);
690       if (!extract_t(address) && (val & 0xffffffff) != val)
691 	device_error(me, "32bit memory address (0x%lx) out of range in PCI address %s",
692 		     val, unit);
693       break;
694     case ss_64bit_memory_code:
695     case ss_config_code:
696       device_error(me, "internal error");
697     }
698     set_ll_ll(address, val);
699     chp = end;
700     break;
701   case ss_64bit_memory_code:
702     device_error(me, "64bit addresses unimplemented");
703     set_hh_hh(address, val);
704     set_ll_ll(address, val);
705     break;
706   case ss_config_code:
707     device_error(me, "internal error");
708     break;
709   }
710 
711   /* finished? */
712   if (!isspace(*chp) && *chp != '\0')
713     device_error(me, "Problem parsing PCI address %s", unit);
714 
715   return chp - unit;
716 }
717 
718 
719 /* Convert PCI device unit into its corresponding textual
720    representation */
721 
722 static int
723 hw_phb_unit_encode(device *me,
724 		   const device_unit *unit_address,
725 		   char *buf,
726 		   int sizeof_buf)
727 {
728   if (unit_address->nr_cells != 3)
729     device_error(me, "Incorrect number of cells in PCI unit address");
730   if (device_nr_address_cells(me) != 3)
731     device_error(me, "PCI bus should have #address-cells == 3");
732   if (extract_ss(unit_address) == ss_config_code
733       && extract_fff(unit_address) == 0
734       && extract_rrrrrrrr(unit_address) == 0
735       && extract_hh_hh(unit_address) == 0
736       && extract_ll_ll(unit_address) == 0) {
737     /* DD - Configuration Space address */
738     sprintf(buf, "%x",
739 	    extract_ddddd(unit_address));
740   }
741   else if (extract_ss(unit_address) == ss_config_code
742 	   && extract_fff(unit_address) != 0
743 	   && extract_rrrrrrrr(unit_address) == 0
744 	   && extract_hh_hh(unit_address) == 0
745 	   && extract_ll_ll(unit_address) == 0) {
746     /* DD,F - Configuration Space */
747     sprintf(buf, "%x,%d",
748 	    extract_ddddd(unit_address),
749 	    extract_fff(unit_address));
750   }
751   else if (extract_ss(unit_address) == ss_io_code
752 	   && extract_hh_hh(unit_address) == 0) {
753     /* [n]i[t]DD,F,RR,NNNNNNNN - 32bit I/O space */
754     sprintf(buf, "%si%s%x,%d,%x,%x",
755 	    extract_n(unit_address) ? "n" : "",
756 	    extract_t(unit_address) ? "t" : "",
757 	    extract_ddddd(unit_address),
758 	    extract_fff(unit_address),
759 	    extract_rrrrrrrr(unit_address),
760 	    extract_ll_ll(unit_address));
761   }
762   else if (extract_ss(unit_address) == ss_32bit_memory_code
763 	   && extract_hh_hh(unit_address) == 0) {
764     /* [n]m[t][p]DD,F,RR,NNNNNNNN - 32bit memory space */
765     sprintf(buf, "%sm%s%s%x,%d,%x,%x",
766 	    extract_n(unit_address) ? "n" : "",
767 	    extract_t(unit_address) ? "t" : "",
768 	    extract_p(unit_address) ? "p" : "",
769 	    extract_ddddd(unit_address),
770 	    extract_fff(unit_address),
771 	    extract_rrrrrrrr(unit_address),
772 	    extract_ll_ll(unit_address));
773   }
774   else if (extract_ss(unit_address) == ss_32bit_memory_code) {
775     /* [n]x[p]DD,F,RR,NNNNNNNNNNNNNNNN - 64bit memory space */
776     sprintf(buf, "%sx%s%x,%d,%x,%x%08x",
777 	    extract_n(unit_address) ? "n" : "",
778 	    extract_p(unit_address) ? "p" : "",
779 	    extract_ddddd(unit_address),
780 	    extract_fff(unit_address),
781 	    extract_rrrrrrrr(unit_address),
782 	    extract_hh_hh(unit_address),
783 	    extract_ll_ll(unit_address));
784   }
785   else {
786     device_error(me, "Invalid PCI unit address 0x%08lx 0x%08lx 0x%08lx",
787 		 (unsigned long)unit_address->cells[0],
788 		 (unsigned long)unit_address->cells[1],
789 		 (unsigned long)unit_address->cells[2]);
790   }
791   if (strlen(buf) > sizeof_buf)
792     error("buffer overflow");
793   return strlen(buf);
794 }
795 
796 
797 static int
798 hw_phb_address_to_attach_address(device *me,
799 				 const device_unit *address,
800 				 int *attach_space,
801 				 unsigned_word *attach_address,
802 				 device *client)
803 {
804   if (address->nr_cells != 3)
805     device_error(me, "attach address has incorrect number of cells");
806   if (address->cells[1] != 0)
807     device_error(me, "64bit attach address unsupported");
808 
809   /* directly decode the address/space */
810   *attach_address = address->cells[2];
811   switch (extract_ss(address)) {
812   case ss_config_code:
813     *attach_space = hw_phb_config_space;
814     break;
815   case ss_io_code:
816     *attach_space = hw_phb_io_space;
817     break;
818   case ss_32bit_memory_code:
819   case ss_64bit_memory_code:
820     *attach_space = hw_phb_memory_space;
821     break;
822   }
823 
824   /* if non-relocatable finished */
825   if (extract_n(address))
826     return 1;
827 
828   /* make memory and I/O addresses absolute */
829   if (*attach_space == hw_phb_io_space
830       || *attach_space == hw_phb_memory_space) {
831     int reg_nr;
832     reg_property_spec assigned;
833     if (extract_ss(address) == ss_64bit_memory_code)
834       device_error(me, "64bit memory address not unsuported");
835     for (reg_nr = 0;
836 	 device_find_reg_array_property(client, "assigned-addresses", reg_nr,
837 					&assigned);
838 	 reg_nr++) {
839       if (!extract_n(&assigned.address)
840 	  || extract_rrrrrrrr(&assigned.address) == 0)
841 	device_error(me, "client %s has invalid assigned-address property",
842 		     device_path(client));
843       if (extract_rrrrrrrr(address) == extract_rrrrrrrr(&assigned.address)) {
844 	/* corresponding base register */
845 	if (extract_ss(address) != extract_ss(&assigned.address))
846 	  device_error(me, "client %s has conflicting types for base register 0x%lx",
847 		       device_path(client),
848 		       (unsigned long)extract_rrrrrrrr(address));
849 	*attach_address += assigned.address.cells[2];
850 	return 0;
851       }
852     }
853     device_error(me, "client %s missing base address register 0x%lx in assigned-addresses property",
854 		 device_path(client),
855 		 (unsigned long)extract_rrrrrrrr(address));
856   }
857 
858   return 0;
859 }
860 
861 
862 static int
863 hw_phb_size_to_attach_size(device *me,
864 			   const device_unit *size,
865 			   unsigned *nr_bytes,
866 			   device *client)
867 {
868   if (size->nr_cells != 2)
869     device_error(me, "size has incorrect number of cells");
870   if (size->cells[0] != 0)
871     device_error(me, "64bit size unsupported");
872   *nr_bytes = size->cells[1];
873   return size->cells[1];
874 }
875 
876 
877 static const phb_space *
878 find_phb_space(hw_phb_device *phb,
879 	       unsigned_word addr,
880 	       unsigned nr_bytes)
881 {
882   hw_phb_spaces space;
883   /* find the space that matches the address */
884   for (space = 0; space < nr_hw_phb_spaces; space++) {
885     phb_space *pci_space = &phb->space[space];
886     if (addr >= pci_space->parent_base
887 	&& (addr + nr_bytes) <= (pci_space->parent_base + pci_space->size)) {
888       return pci_space;
889     }
890   }
891   return NULL;
892 }
893 
894 
895 static unsigned_word
896 map_phb_addr(const phb_space *space,
897 	     unsigned_word addr)
898 {
899   return addr - space->parent_base + space->my_base;
900 }
901 
902 
903 
904 static unsigned
905 hw_phb_io_read_buffer(device *me,
906 		      void *dest,
907 		      int space,
908 		      unsigned_word addr,
909 		      unsigned nr_bytes,
910 		      cpu *processor,
911 		      unsigned_word cia)
912 {
913   hw_phb_device *phb = (hw_phb_device*)device_data(me);
914   const phb_space *pci_space = find_phb_space(phb, addr, nr_bytes);
915   unsigned_word bus_addr;
916   if (pci_space == NULL)
917     return 0;
918   bus_addr = map_phb_addr(pci_space, addr);
919   DTRACE(phb, ("io read - %d:0x%lx -> %s:0x%lx (%u bytes)\n",
920 	       space, (unsigned long)addr, pci_space->name, (unsigned long)bus_addr,
921 	       nr_bytes));
922   return core_map_read_buffer(pci_space->readable,
923 			      dest, bus_addr, nr_bytes);
924 }
925 
926 
927 static unsigned
928 hw_phb_io_write_buffer(device *me,
929 		       const void *source,
930 		       int space,
931 		       unsigned_word addr,
932 		       unsigned nr_bytes,
933 		       cpu *processor,
934 		       unsigned_word cia)
935 {
936   hw_phb_device *phb = (hw_phb_device*)device_data(me);
937   const phb_space *pci_space = find_phb_space(phb, addr, nr_bytes);
938   unsigned_word bus_addr;
939   if (pci_space == NULL)
940     return 0;
941   bus_addr = map_phb_addr(pci_space, addr);
942   DTRACE(phb, ("io write - %d:0x%lx -> %s:0x%lx (%u bytes)\n",
943 	       space, (unsigned long)addr, pci_space->name, (unsigned long)bus_addr,
944 	       nr_bytes));
945   return core_map_write_buffer(pci_space->writeable, source,
946 			       bus_addr, nr_bytes);
947 }
948 
949 
950 static unsigned
951 hw_phb_dma_read_buffer(device *me,
952 		       void *dest,
953 		       int space,
954 		       unsigned_word addr,
955 		       unsigned nr_bytes)
956 {
957   hw_phb_device *phb = (hw_phb_device*)device_data(me);
958   const phb_space *pci_space;
959   /* find the space */
960   if (space != hw_phb_memory_space)
961     device_error(me, "invalid dma address space %d", space);
962   pci_space = &phb->space[space];
963   /* check out the address */
964   if ((addr >= pci_space->my_base
965        && addr <= pci_space->my_base + pci_space->size)
966       || (addr + nr_bytes >= pci_space->my_base
967 	  && addr + nr_bytes <= pci_space->my_base + pci_space->size))
968     device_error(me, "Do not support DMA into own bus");
969   /* do it */
970   DTRACE(phb, ("dma read - %s:0x%lx (%d bytes)\n",
971 	       pci_space->name, (unsigned long)addr, nr_bytes));
972   return device_dma_read_buffer(device_parent(me),
973 				dest, pci_space->parent_space,
974 				addr, nr_bytes);
975 }
976 
977 
978 static unsigned
979 hw_phb_dma_write_buffer(device *me,
980 			const void *source,
981 			int space,
982 			unsigned_word addr,
983 			unsigned nr_bytes,
984 			int violate_read_only_section)
985 {
986   hw_phb_device *phb = (hw_phb_device*)device_data(me);
987   const phb_space *pci_space;
988   /* find the space */
989   if (space != hw_phb_memory_space)
990     device_error(me, "invalid dma address space %d", space);
991   pci_space = &phb->space[space];
992   /* check out the address */
993   if ((addr >= pci_space->my_base
994        && addr <= pci_space->my_base + pci_space->size)
995       || (addr + nr_bytes >= pci_space->my_base
996 	  && addr + nr_bytes <= pci_space->my_base + pci_space->size))
997     device_error(me, "Do not support DMA into own bus");
998   /* do it */
999   DTRACE(phb, ("dma write - %s:0x%lx (%d bytes)\n",
1000 	       pci_space->name, (unsigned long)addr, nr_bytes));
1001   return device_dma_write_buffer(device_parent(me),
1002 				 source, pci_space->parent_space,
1003 				 addr, nr_bytes,
1004 				 violate_read_only_section);
1005 }
1006 
1007 
1008 static device_callbacks const hw_phb_callbacks = {
1009   { hw_phb_init_address, },
1010   { hw_phb_attach_address, },
1011   { hw_phb_io_read_buffer, hw_phb_io_write_buffer },
1012   { hw_phb_dma_read_buffer, hw_phb_dma_write_buffer },
1013   { NULL, }, /* interrupt */
1014   { hw_phb_unit_decode,
1015     hw_phb_unit_encode,
1016     hw_phb_address_to_attach_address,
1017     hw_phb_size_to_attach_size }
1018 };
1019 
1020 
1021 static void *
1022 hw_phb_create(const char *name,
1023 	      const device_unit *unit_address,
1024 	      const char *args)
1025 {
1026   /* create the descriptor */
1027   hw_phb_device *phb = ZALLOC(hw_phb_device);
1028 
1029   /* create the core maps now */
1030   hw_phb_spaces space_nr;
1031   for (space_nr = 0; space_nr < nr_hw_phb_spaces; space_nr++) {
1032     phb_space *pci_space = &phb->space[space_nr];
1033     pci_space->map = core_create();
1034     pci_space->readable = core_readable(pci_space->map);
1035     pci_space->writeable = core_writeable(pci_space->map);
1036     switch (space_nr) {
1037     case hw_phb_memory_space:
1038       pci_space->name = "memory";
1039       break;
1040     case hw_phb_io_space:
1041       pci_space->name = "I/O";
1042       break;
1043     case hw_phb_config_space:
1044       pci_space->name = "config";
1045       break;
1046     case hw_phb_special_space:
1047       pci_space->name = "special";
1048       break;
1049     default:
1050       error ("internal error");
1051       break;
1052     }
1053   }
1054 
1055   return phb;
1056 }
1057 
1058 
1059 const device_descriptor hw_phb_device_descriptor[] = {
1060   { "phb", hw_phb_create, &hw_phb_callbacks },
1061   { "pci", NULL, &hw_phb_callbacks },
1062   { NULL, },
1063 };
1064 
1065 #endif /* _HW_PHB_ */
1066