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