diff options
author | Daniel Berlin <dberlin@dberlin.org> | 2001-07-06 19:17:05 +0000 |
---|---|---|
committer | Daniel Berlin <dberlin@dberlin.org> | 2001-07-06 19:17:05 +0000 |
commit | efae50153d4577bd05fc34b76c47bdca79982233 (patch) | |
tree | ebfdde719009a58b2f719cb06926eb6aab787aba /sim/ppc/hw_phb.c | |
parent | d30f071864b3938dd9d197547c65b33980a243f8 (diff) | |
download | gdb-dberlin-typesystem-branch.tar.gz |
Typesystem work initial import.dberlin-typesystem-branchcvs/dberlin-typesystem-branch
Note that this currently isn't building, i'm in the middle of converting make_function_type/lookup_function_type
Diffstat (limited to 'sim/ppc/hw_phb.c')
-rw-r--r-- | sim/ppc/hw_phb.c | 1068 |
1 files changed, 0 insertions, 1068 deletions
diff --git a/sim/ppc/hw_phb.c b/sim/ppc/hw_phb.c deleted file mode 100644 index 0071f59faf3..00000000000 --- a/sim/ppc/hw_phb.c +++ /dev/null @@ -1,1068 +0,0 @@ -/* This file is part of the program psim. - - Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - */ - - -#ifndef _HW_PHB_C_ -#define _HW_PHB_C_ - -#include "device_table.h" - -#include "hw_phb.h" - -#include "corefile.h" - -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif - -#include <ctype.h> - - -/* DEVICE - - - phb - PCI Host Bridge - - - DESCRIPTION - - - PHB implements a model of the PCI-host bridge described in the PPCP - document. - - For bridge devices, Open Firmware specifies that the <<ranges>> - property be used to specify the mapping of address spaces between a - bridges parent and child busses. This PHB model configures itsself - according to the information specified in its ranges property. The - <<ranges>> property is described in detail in the Open Firmware - documentation. - - For DMA transfers, any access to a PCI address space which falls - outside of the mapped memory space is assumed to be a transfer - intended for the parent bus. - - - PROPERTIES - - - ranges = <my-phys-addr> <parent-phys-addr> <my-size> ... (required) - - Define a number of mappings from the parent bus to one of this - devices PCI busses. The exact format of the <<parent-phys-addr>> - is parent bus dependant. The format of <<my-phys-addr>> is - described in the Open Firmware PCI bindings document (note that the - address must be non-relocatable). - - - #address-cells = 3 (required) - - Number of cells used by an Open Firmware PCI address. This - property must be defined before specifying the <<ranges>> property. - - - #size-cells = 2 (required) - - Number of cells used by an Open Firmware PCI size. This property - must be defined before specifying the <<ranges>> property. - - - EXAMPLES - - - Enable tracing: - - | $ psim \ - | -t phb-device \ - - - Since device tree entries that are specified on the command line - are added before most of the device tree has been built it is often - necessary to explictly add certain device properties and thus - ensure they are already present in the device tree. For the - <<phb>> one such property is parent busses <<#address-cells>>. - - | -o '/#address-cells 1' \ - - - Create the PHB remembering to include the cell size properties: - - | -o '/phb@0x80000000/#address-cells 3' \ - | -o '/phb@0x80000000/#size-cells 2' \ - - - Specify that the memory address range <<0x80000000>> to - <<0x8fffffff>> should map directly onto the PCI memory address - space while the processor address range <<0xc0000000>> to - <<0xc000ffff>> should map onto the PCI I/O address range starting - at location zero: - - | -o '/phb@0x80000000/ranges \ - | nm0,0,0,80000000 0x80000000 0x10000000 \ - | ni0,0,0,0 0xc0000000 0x10000' \ - - - Insert a 4k <<nvram>> into slot zero of the PCI bus. Have it - directly accessible in both the I/O (address <<0x100>>) and memory - (address 0x80001000) spaces: - - | -o '/phb@0x80000000/nvram@0/assigned-addresses \ - | nm0,0,10,80001000 4096 \ - | ni0,0,14,100 4096' - | -o '/phb@0x80000000/nvram@0/reg \ - | 0 0 \ - | i0,0,14,0 4096' - | -o '/phb@0x80000000/nvram@0/alternate-reg \ - | 0 0 \ - | m0,0,10,0 4096' - - The <<assigned-address>> property corresponding to what (if it were - implemented) be found in the config base registers while the - <<reg>> and <<alternative-reg>> properties indicating the location - of registers within each address space. - - Of the possible addresses, only the non-relocatable versions are - used when attaching the device to the bus. - - - BUGS - - - The implementation of the PCI configuration space is left as an - exercise for the reader. Such a restriction should only impact on - systems wanting to dynamically configure devices on the PCI bus. - - The <<CHRP>> document specfies additional (optional) functionality - of the primary PHB. The implementation of such functionality is - left as an exercise for the reader. - - The Open Firmware PCI bus bindings document (rev 1.6 and 2.0) is - unclear on the value of the "ss" bits for a 64bit memory address. - The correct value, as used by this module, is 0b11. - - The Open Firmware PCI bus bindings document (rev 1.6) suggests that - the register field of non-relocatable PCI address should be zero. - Unfortunatly, PCI addresses specified in the <<assigned-addresses>> - property must be both non-relocatable and have non-zero register - fields. - - The unit-decode method is not inserting a bus number into any - address that it decodes. Instead the bus-number is left as zero. - - Support for aliased memory and I/O addresses is left as an exercise - for the reader. - - Support for interrupt-ack and special cycles are left as an - exercise for the reader. One issue to consider when attempting - this exercise is how to specify the address of the int-ack and - special cycle register. Hint: <</8259-interrupt-ackowledge>> is - the wrong answer. - - Children of this node can only use the client callback interface - when attaching themselves to the <<phb>>. - - - REFERENCES - - - http://playground.sun.com/1275/home.html#OFDbusPCI - - - */ - - -typedef struct _phb_space { - core *map; - core_map *readable; - core_map *writeable; - unsigned_word parent_base; - int parent_space; - unsigned_word my_base; - int my_space; - unsigned size; - const char *name; -} phb_space; - -typedef struct _hw_phb_device { - phb_space space[nr_hw_phb_spaces]; -} hw_phb_device; - - -static const char * -hw_phb_decode_name(hw_phb_decode level) -{ - switch (level) { - case hw_phb_normal_decode: return "normal"; - case hw_phb_subtractive_decode: return "subtractive"; - case hw_phb_master_abort_decode: return "master-abort"; - default: return "invalid decode"; - } -} - - -static void -hw_phb_init_address(device *me) -{ - hw_phb_device *phb = device_data(me); - - /* check some basic properties */ - if (device_nr_address_cells(me) != 3) - device_error(me, "incorrect #address-cells"); - if (device_nr_size_cells(me) != 2) - device_error(me, "incorrect #size-cells"); - - /* (re) initialize each PCI space */ - { - hw_phb_spaces space_nr; - for (space_nr = 0; space_nr < nr_hw_phb_spaces; space_nr++) { - phb_space *pci_space = &phb->space[space_nr]; - core_init(pci_space->map); - pci_space->size = 0; - } - } - - /* decode each of the ranges properties entering the information - into the space table */ - { - range_property_spec range; - int ranges_entry; - - for (ranges_entry = 0; - device_find_range_array_property(me, "ranges", ranges_entry, - &range); - ranges_entry++) { - int my_attach_space; - unsigned_word my_attach_address; - int parent_attach_space; - unsigned_word parent_attach_address; - unsigned size; - phb_space *pci_space; - /* convert the addresses into something meaningful */ - device_address_to_attach_address(me, &range.child_address, - &my_attach_space, - &my_attach_address, - me); - device_address_to_attach_address(device_parent(me), - &range.parent_address, - &parent_attach_space, - &parent_attach_address, - me); - device_size_to_attach_size(me, &range.size, &size, me); - if (my_attach_space < 0 || my_attach_space >= nr_hw_phb_spaces) - device_error(me, "ranges property contains an invalid address space"); - pci_space = &phb->space[my_attach_space]; - if (pci_space->size != 0) - device_error(me, "ranges property contains duplicate mappings for %s address space", - pci_space->name); - pci_space->parent_base = parent_attach_address; - pci_space->parent_space = parent_attach_space; - pci_space->my_base = my_attach_address; - pci_space->my_space = my_attach_space; - pci_space->size = size; - device_attach_address(device_parent(me), - attach_callback, - parent_attach_space, parent_attach_address, size, - access_read_write_exec, - me); - DTRACE(phb, ("map %d:0x%lx to %s:0x%lx (0x%lx bytes)\n", - (int)parent_attach_space, - (unsigned long)parent_attach_address, - pci_space->name, - (unsigned long)my_attach_address, - (unsigned long)size)); - } - - if (ranges_entry == 0) { - device_error(me, "Missing or empty ranges property"); - } - - } - -} - -static void -hw_phb_attach_address(device *me, - attach_type type, - int space, - unsigned_word addr, - unsigned nr_bytes, - access_type access, - device *client) /*callback/default*/ -{ - hw_phb_device *phb = device_data(me); - phb_space *pci_space; - /* sanity checks */ - if (space < 0 || space >= nr_hw_phb_spaces) - device_error(me, "attach space (%d) specified by %s invalid", - space, device_path(client)); - pci_space = &phb->space[space]; - if (addr + nr_bytes > pci_space->my_base + pci_space->size - || addr < pci_space->my_base) - device_error(me, "attach addr (0x%lx) specified by %s outside of bus address range", - (unsigned long)addr, device_path(client)); - if (type != hw_phb_normal_decode - && type != hw_phb_subtractive_decode) - device_error(me, "attach type (%d) specified by %s invalid", - type, device_path(client)); - /* attach it to the relevent bus */ - DTRACE(phb, ("attach %s - %s %s:0x%lx (0x%lx bytes)\n", - device_path(client), - hw_phb_decode_name(type), - pci_space->name, - (unsigned long)addr, - (unsigned long)nr_bytes)); - core_attach(pci_space->map, - type, - space, - access, - addr, - nr_bytes, - client); -} - - -/* Extract/set various fields from a PCI unit address. - - Note: only the least significant 32 bits of each cell is used. - - Note: for PPC MSB is 0 while for PCI it is 31. */ - - -/* relocatable bit n */ - -static unsigned -extract_n(const device_unit *address) -{ - return EXTRACTED32(address->cells[0], 0, 0); -} - -static void -set_n(device_unit *address) -{ - BLIT32(address->cells[0], 0, 1); -} - - -/* prefetchable bit p */ - -static unsigned -extract_p(const device_unit *address) -{ - ASSERT(address->nr_cells == 3); - return EXTRACTED32(address->cells[0], 1, 1); -} - -static void -set_p(device_unit *address) -{ - BLIT32(address->cells[0], 1, 1); -} - - -/* aliased bit t */ - -static unsigned -extract_t(const device_unit *address) -{ - ASSERT(address->nr_cells == 3); - return EXTRACTED32(address->cells[0], 2, 2); -} - -static void -set_t(device_unit *address) -{ - BLIT32(address->cells[0], 2, 1); -} - - -/* space code ss */ - -typedef enum { - ss_config_code = 0, - ss_io_code = 1, - ss_32bit_memory_code = 2, - ss_64bit_memory_code = 3, -} ss_type; - -static ss_type -extract_ss(const device_unit *address) -{ - ASSERT(address->nr_cells == 3); - return EXTRACTED32(address->cells[0], 6, 7); -} - -static void -set_ss(device_unit *address, ss_type val) -{ - MBLIT32(address->cells[0], 6, 7, val); -} - - -/* bus number bbbbbbbb */ - -#if 0 -static unsigned -extract_bbbbbbbb(const device_unit *address) -{ - ASSERT(address->nr_cells == 3); - return EXTRACTED32(address->cells[0], 8, 15); -} -#endif - -#if 0 -static void -set_bbbbbbbb(device_unit *address, unsigned val) -{ - MBLIT32(address->cells[0], 8, 15, val); -} -#endif - - -/* device number ddddd */ - -static unsigned -extract_ddddd(const device_unit *address) -{ - ASSERT(address->nr_cells == 3); - return EXTRACTED32(address->cells[0], 16, 20); -} - -static void -set_ddddd(device_unit *address, unsigned val) -{ - MBLIT32(address->cells[0], 16, 20, val); -} - - -/* function number fff */ - -static unsigned -extract_fff(const device_unit *address) -{ - ASSERT(address->nr_cells == 3); - return EXTRACTED32(address->cells[0], 21, 23); -} - -static void -set_fff(device_unit *address, unsigned val) -{ - MBLIT32(address->cells[0], 21, 23, val); -} - - -/* register number rrrrrrrr */ - -static unsigned -extract_rrrrrrrr(const device_unit *address) -{ - ASSERT(address->nr_cells == 3); - return EXTRACTED32(address->cells[0], 24, 31); -} - -static void -set_rrrrrrrr(device_unit *address, unsigned val) -{ - MBLIT32(address->cells[0], 24, 31, val); -} - - -/* MSW of 64bit address hh..hh */ - -static unsigned -extract_hh_hh(const device_unit *address) -{ - ASSERT(address->nr_cells == 3); - return address->cells[1]; -} - -static void -set_hh_hh(device_unit *address, unsigned val) -{ - address->cells[2] = val; -} - - -/* LSW of 64bit address ll..ll */ - -static unsigned -extract_ll_ll(const device_unit *address) -{ - ASSERT(address->nr_cells == 3); - return address->cells[2]; -} - -static void -set_ll_ll(device_unit *address, unsigned val) -{ - address->cells[2] = val; -} - - -/* Convert PCI textual bus address into a device unit */ - -static int -hw_phb_unit_decode(device *me, - const char *unit, - device_unit *address) -{ - char *end = NULL; - const char *chp = unit; - unsigned long val; - - if (device_nr_address_cells(me) != 3) - device_error(me, "PCI bus should have #address-cells == 3"); - memset(address, 0, sizeof(*address)); - - if (unit == NULL) - return 0; - - address->nr_cells = 3; - - if (isxdigit(*chp)) { - set_ss(address, ss_config_code); - } - else { - - /* non-relocatable? */ - if (*chp == 'n') { - set_n(address); - chp++; - } - - /* address-space? */ - if (*chp == 'i') { - set_ss(address, ss_io_code); - chp++; - } - else if (*chp == 'm') { - set_ss(address, ss_32bit_memory_code); - chp++; - } - else if (*chp == 'x') { - set_ss(address, ss_64bit_memory_code); - chp++; - } - else - device_error(me, "Problem parsing PCI address %s", unit); - - /* possible alias */ - if (*chp == 't') { - if (extract_ss(address) == ss_64bit_memory_code) - device_error(me, "Invalid alias bit in PCI address %s", unit); - set_t(address); - chp++; - } - - /* possible p */ - if (*chp == 'p') { - if (extract_ss(address) != ss_32bit_memory_code) - device_error(me, "Invalid prefetchable bit (p) in PCI address %s", - unit); - set_p(address); - chp++; - } - - } - - /* required DD */ - if (!isxdigit(*chp)) - device_error(me, "Missing device number in PCI address %s", unit); - val = strtoul(chp, &end, 16); - if (chp == end) - device_error(me, "Problem parsing device number in PCI address %s", unit); - if ((val & 0x1f) != val) - device_error(me, "Device number (0x%lx) out of range (0..0x1f) in PCI address %s", - val, unit); - set_ddddd(address, val); - chp = end; - - /* For config space, the F is optional */ - if (extract_ss(address) == ss_config_code - && (isspace(*chp) || *chp == '\0')) - return chp - unit; - - /* function number F */ - if (*chp != ',') - device_error(me, "Missing function number in PCI address %s", unit); - chp++; - val = strtoul(chp, &end, 10); - if (chp == end) - device_error(me, "Problem parsing function number in PCI address %s", - unit); - if ((val & 7) != val) - device_error(me, "Function number (%ld) out of range (0..7) in PCI address %s", - (long)val, unit); - set_fff(address, val); - chp = end; - - /* for config space, must be end */ - if (extract_ss(address) == ss_config_code) { - if (!isspace(*chp) && *chp != '\0') - device_error(me, "Problem parsing PCI config address %s", - unit); - return chp - unit; - } - - /* register number RR */ - if (*chp != ',') - device_error(me, "Missing register number in PCI address %s", unit); - chp++; - val = strtoul(chp, &end, 16); - if (chp == end) - device_error(me, "Problem parsing register number in PCI address %s", - unit); - switch (extract_ss(address)) { - case ss_io_code: -#if 0 - if (extract_n(address) && val != 0) - device_error(me, "non-relocatable I/O register must be zero in PCI address %s", unit); - else if (!extract_n(address) - && val != 0x10 && val != 0x14 && val != 0x18 - && val != 0x1c && val != 0x20 && val != 0x24) - device_error(me, "I/O register invalid in PCI address %s", unit); -#endif - break; - case ss_32bit_memory_code: -#if 0 - if (extract_n(address) && val != 0) - device_error(me, "non-relocatable memory register must be zero in PCI address %s", unit); - else if (!extract_n(address) - && val != 0x10 && val != 0x14 && val != 0x18 - && val != 0x1c && val != 0x20 && val != 0x24 && val != 0x30) - device_error(me, "I/O register (0x%lx) invalid in PCI address %s", - val, unit); -#endif - break; - case ss_64bit_memory_code: - if (extract_n(address) && val != 0) - device_error(me, "non-relocatable 32bit memory register must be zero in PCI address %s", unit); - else if (!extract_n(address) - && val != 0x10 && val != 0x18 && val != 0x20) - device_error(me, "Register number (0x%lx) invalid in 64bit PCI address %s", - val, unit); - case ss_config_code: - device_error(me, "internal error"); - } - if ((val & 0xff) != val) - device_error(me, "Register number (0x%lx) out of range (0..0xff) in PCI address %s", - val, unit); - set_rrrrrrrr(address, val); - chp = end; - - /* address */ - if (*chp != ',') - device_error(me, "Missing address in PCI address %s", unit); - chp++; - switch (extract_ss(address)) { - case ss_io_code: - case ss_32bit_memory_code: - val = strtoul(chp, &end, 16); - if (chp == end) - device_error(me, "Problem parsing address in PCI address %s", unit); - switch (extract_ss(address)) { - case ss_io_code: - if (extract_n(address) && extract_t(address) - && (val & 1024) != val) - device_error(me, "10bit aliased non-relocatable address (0x%lx) out of range in PCI address %s", - val, unit); - if (!extract_n(address) && extract_t(address) - && (val & 0xffff) != val) - device_error(me, "64k relocatable address (0x%lx) out of range in PCI address %s", - val, unit); - break; - case ss_32bit_memory_code: - if (extract_t(address) && (val & 0xfffff) != val) - device_error(me, "1mb memory address (0x%lx) out of range in PCI address %s", - val, unit); - if (!extract_t(address) && (val & 0xffffffff) != val) - device_error(me, "32bit memory address (0x%lx) out of range in PCI address %s", - val, unit); - break; - case ss_64bit_memory_code: - case ss_config_code: - device_error(me, "internal error"); - } - set_ll_ll(address, val); - chp = end; - break; - case ss_64bit_memory_code: - device_error(me, "64bit addresses unimplemented"); - set_hh_hh(address, val); - set_ll_ll(address, val); - break; - case ss_config_code: - device_error(me, "internal error"); - break; - } - - /* finished? */ - if (!isspace(*chp) && *chp != '\0') - device_error(me, "Problem parsing PCI address %s", unit); - - return chp - unit; -} - - -/* Convert PCI device unit into its corresponding textual - representation */ - -static int -hw_phb_unit_encode(device *me, - const device_unit *unit_address, - char *buf, - int sizeof_buf) -{ - if (unit_address->nr_cells != 3) - device_error(me, "Incorrect number of cells in PCI unit address"); - if (device_nr_address_cells(me) != 3) - device_error(me, "PCI bus should have #address-cells == 3"); - if (extract_ss(unit_address) == ss_config_code - && extract_fff(unit_address) == 0 - && extract_rrrrrrrr(unit_address) == 0 - && extract_hh_hh(unit_address) == 0 - && extract_ll_ll(unit_address) == 0) { - /* DD - Configuration Space address */ - sprintf(buf, "%x", - extract_ddddd(unit_address)); - } - else if (extract_ss(unit_address) == ss_config_code - && extract_fff(unit_address) != 0 - && extract_rrrrrrrr(unit_address) == 0 - && extract_hh_hh(unit_address) == 0 - && extract_ll_ll(unit_address) == 0) { - /* DD,F - Configuration Space */ - sprintf(buf, "%x,%d", - extract_ddddd(unit_address), - extract_fff(unit_address)); - } - else if (extract_ss(unit_address) == ss_io_code - && extract_hh_hh(unit_address) == 0) { - /* [n]i[t]DD,F,RR,NNNNNNNN - 32bit I/O space */ - sprintf(buf, "%si%s%x,%d,%x,%x", - extract_n(unit_address) ? "n" : "", - extract_t(unit_address) ? "t" : "", - extract_ddddd(unit_address), - extract_fff(unit_address), - extract_rrrrrrrr(unit_address), - extract_ll_ll(unit_address)); - } - else if (extract_ss(unit_address) == ss_32bit_memory_code - && extract_hh_hh(unit_address) == 0) { - /* [n]m[t][p]DD,F,RR,NNNNNNNN - 32bit memory space */ - sprintf(buf, "%sm%s%s%x,%d,%x,%x", - extract_n(unit_address) ? "n" : "", - extract_t(unit_address) ? "t" : "", - extract_p(unit_address) ? "p" : "", - extract_ddddd(unit_address), - extract_fff(unit_address), - extract_rrrrrrrr(unit_address), - extract_ll_ll(unit_address)); - } - else if (extract_ss(unit_address) == ss_32bit_memory_code) { - /* [n]x[p]DD,F,RR,NNNNNNNNNNNNNNNN - 64bit memory space */ - sprintf(buf, "%sx%s%x,%d,%x,%x%08x", - extract_n(unit_address) ? "n" : "", - extract_p(unit_address) ? "p" : "", - extract_ddddd(unit_address), - extract_fff(unit_address), - extract_rrrrrrrr(unit_address), - extract_hh_hh(unit_address), - extract_ll_ll(unit_address)); - } - else { - device_error(me, "Invalid PCI unit address 0x%08lx 0x%08lx 0x%08lx", - (unsigned long)unit_address->cells[0], - (unsigned long)unit_address->cells[1], - (unsigned long)unit_address->cells[2]); - } - if (strlen(buf) > sizeof_buf) - error("buffer overflow"); - return strlen(buf); -} - - -static int -hw_phb_address_to_attach_address(device *me, - const device_unit *address, - int *attach_space, - unsigned_word *attach_address, - device *client) -{ - if (address->nr_cells != 3) - device_error(me, "attach address has incorrect number of cells"); - if (address->cells[1] != 0) - device_error(me, "64bit attach address unsupported"); - - /* directly decode the address/space */ - *attach_address = address->cells[2]; - switch (extract_ss(address)) { - case ss_config_code: - *attach_space = hw_phb_config_space; - break; - case ss_io_code: - *attach_space = hw_phb_io_space; - break; - case ss_32bit_memory_code: - case ss_64bit_memory_code: - *attach_space = hw_phb_memory_space; - break; - } - - /* if non-relocatable finished */ - if (extract_n(address)) - return 1; - - /* make memory and I/O addresses absolute */ - if (*attach_space == hw_phb_io_space - || *attach_space == hw_phb_memory_space) { - int reg_nr; - reg_property_spec assigned; - if (extract_ss(address) == ss_64bit_memory_code) - device_error(me, "64bit memory address not unsuported"); - for (reg_nr = 0; - device_find_reg_array_property(client, "assigned-addresses", reg_nr, - &assigned); - reg_nr++) { - if (!extract_n(&assigned.address) - || extract_rrrrrrrr(&assigned.address) == 0) - device_error(me, "client %s has invalid assigned-address property", - device_path(client)); - if (extract_rrrrrrrr(address) == extract_rrrrrrrr(&assigned.address)) { - /* corresponding base register */ - if (extract_ss(address) != extract_ss(&assigned.address)) - device_error(me, "client %s has conflicting types for base register 0x%lx", - device_path(client), - (unsigned long)extract_rrrrrrrr(address)); - *attach_address += assigned.address.cells[2]; - return 0; - } - } - device_error(me, "client %s missing base address register 0x%lx in assigned-addresses property", - device_path(client), - (unsigned long)extract_rrrrrrrr(address)); - } - - return 0; -} - - -static int -hw_phb_size_to_attach_size(device *me, - const device_unit *size, - unsigned *nr_bytes, - device *client) -{ - if (size->nr_cells != 2) - device_error(me, "size has incorrect number of cells"); - if (size->cells[0] != 0) - device_error(me, "64bit size unsupported"); - *nr_bytes = size->cells[1]; - return size->cells[1]; -} - - -static const phb_space * -find_phb_space(hw_phb_device *phb, - unsigned_word addr, - unsigned nr_bytes) -{ - hw_phb_spaces space; - /* find the space that matches the address */ - for (space = 0; space < nr_hw_phb_spaces; space++) { - phb_space *pci_space = &phb->space[space]; - if (addr >= pci_space->parent_base - && (addr + nr_bytes) <= (pci_space->parent_base + pci_space->size)) { - return pci_space; - } - } - return NULL; -} - - -static unsigned_word -map_phb_addr(const phb_space *space, - unsigned_word addr) -{ - return addr - space->parent_base + space->my_base; -} - - - -static unsigned -hw_phb_io_read_buffer(device *me, - void *dest, - int space, - unsigned_word addr, - unsigned nr_bytes, - cpu *processor, - unsigned_word cia) -{ - hw_phb_device *phb = (hw_phb_device*)device_data(me); - const phb_space *pci_space = find_phb_space(phb, addr, nr_bytes); - unsigned_word bus_addr; - if (pci_space == NULL) - return 0; - bus_addr = map_phb_addr(pci_space, addr); - DTRACE(phb, ("io read - %d:0x%lx -> %s:0x%lx (%u bytes)\n", - space, (unsigned long)addr, pci_space->name, (unsigned long)bus_addr, - nr_bytes)); - return core_map_read_buffer(pci_space->readable, - dest, bus_addr, nr_bytes); -} - - -static unsigned -hw_phb_io_write_buffer(device *me, - const void *source, - int space, - unsigned_word addr, - unsigned nr_bytes, - cpu *processor, - unsigned_word cia) -{ - hw_phb_device *phb = (hw_phb_device*)device_data(me); - const phb_space *pci_space = find_phb_space(phb, addr, nr_bytes); - unsigned_word bus_addr; - if (pci_space == NULL) - return 0; - bus_addr = map_phb_addr(pci_space, addr); - DTRACE(phb, ("io write - %d:0x%lx -> %s:0x%lx (%u bytes)\n", - space, (unsigned long)addr, pci_space->name, (unsigned long)bus_addr, - nr_bytes)); - return core_map_write_buffer(pci_space->writeable, source, - bus_addr, nr_bytes); -} - - -static unsigned -hw_phb_dma_read_buffer(device *me, - void *dest, - int space, - unsigned_word addr, - unsigned nr_bytes) -{ - hw_phb_device *phb = (hw_phb_device*)device_data(me); - const phb_space *pci_space; - /* find the space */ - if (space != hw_phb_memory_space) - device_error(me, "invalid dma address space %d", space); - pci_space = &phb->space[space]; - /* check out the address */ - if ((addr >= pci_space->my_base - && addr <= pci_space->my_base + pci_space->size) - || (addr + nr_bytes >= pci_space->my_base - && addr + nr_bytes <= pci_space->my_base + pci_space->size)) - device_error(me, "Do not support DMA into own bus"); - /* do it */ - DTRACE(phb, ("dma read - %s:0x%lx (%d bytes)\n", - pci_space->name, addr, nr_bytes)); - return device_dma_read_buffer(device_parent(me), - dest, pci_space->parent_space, - addr, nr_bytes); -} - - -static unsigned -hw_phb_dma_write_buffer(device *me, - const void *source, - int space, - unsigned_word addr, - unsigned nr_bytes, - int violate_read_only_section) -{ - hw_phb_device *phb = (hw_phb_device*)device_data(me); - const phb_space *pci_space; - /* find the space */ - if (space != hw_phb_memory_space) - device_error(me, "invalid dma address space %d", space); - pci_space = &phb->space[space]; - /* check out the address */ - if ((addr >= pci_space->my_base - && addr <= pci_space->my_base + pci_space->size) - || (addr + nr_bytes >= pci_space->my_base - && addr + nr_bytes <= pci_space->my_base + pci_space->size)) - device_error(me, "Do not support DMA into own bus"); - /* do it */ - DTRACE(phb, ("dma write - %s:0x%lx (%d bytes)\n", - pci_space->name, addr, nr_bytes)); - return device_dma_write_buffer(device_parent(me), - source, pci_space->parent_space, - addr, nr_bytes, - violate_read_only_section); -} - - -static device_callbacks const hw_phb_callbacks = { - { hw_phb_init_address, }, - { hw_phb_attach_address, }, - { hw_phb_io_read_buffer, hw_phb_io_write_buffer }, - { hw_phb_dma_read_buffer, hw_phb_dma_write_buffer }, - { NULL, }, /* interrupt */ - { hw_phb_unit_decode, - hw_phb_unit_encode, - hw_phb_address_to_attach_address, - hw_phb_size_to_attach_size } -}; - - -static void * -hw_phb_create(const char *name, - const device_unit *unit_address, - const char *args) -{ - /* create the descriptor */ - hw_phb_device *phb = ZALLOC(hw_phb_device); - - /* create the core maps now */ - hw_phb_spaces space_nr; - for (space_nr = 0; space_nr < nr_hw_phb_spaces; space_nr++) { - phb_space *pci_space = &phb->space[space_nr]; - pci_space->map = core_create(); - pci_space->readable = core_readable(pci_space->map); - pci_space->writeable = core_writeable(pci_space->map); - switch (space_nr) { - case hw_phb_memory_space: - pci_space->name = "memory"; - break; - case hw_phb_io_space: - pci_space->name = "I/O"; - break; - case hw_phb_config_space: - pci_space->name = "config"; - break; - case hw_phb_special_space: - pci_space->name = "special"; - break; - default: - error ("internal error"); - break; - } - } - - return phb; -} - - -const device_descriptor hw_phb_device_descriptor[] = { - { "phb", hw_phb_create, &hw_phb_callbacks }, - { "pci", NULL, &hw_phb_callbacks }, - { NULL, }, -}; - -#endif /* _HW_PHB_ */ |