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