sim: constify prog_name
[external/binutils.git] / sim / ppc / hw_phb.c
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_ */