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