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