Update objcopy's --section-alignment option so that it sets the alignment flag on...
[binutils-gdb.git] / sim / ppc / hw_phb.c
blob06eb29fc5a77f4c8b296eb7de774ac1c57b842e3
1 /* This file is part of the program psim.
3 Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
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.
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.
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/>.
21 #ifndef _HW_PHB_C_
22 #define _HW_PHB_C_
24 #include "device_table.h"
26 #include "hw_phb.h"
28 #include "corefile.h"
30 #include <stdlib.h>
31 #include <ctype.h>
34 /* DEVICE
37 phb - PCI Host Bridge
40 DESCRIPTION
43 PHB implements a model of the PCI-host bridge described in the PPCP
44 document.
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.
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.
58 PROPERTIES
61 ranges = <my-phys-addr> <parent-phys-addr> <my-size> ... (required)
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).
70 #address-cells = 3 (required)
72 Number of cells used by an Open Firmware PCI address. This
73 property must be defined before specifying the <<ranges>> property.
76 #size-cells = 2 (required)
78 Number of cells used by an Open Firmware PCI size. This property
79 must be defined before specifying the <<ranges>> property.
82 EXAMPLES
85 Enable tracing:
87 | $ psim \
88 | -t phb-device \
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>>.
97 | -o '/#address-cells 1' \
100 Create the PHB remembering to include the cell size properties:
102 | -o '/phb@0x80000000/#address-cells 3' \
103 | -o '/phb@0x80000000/#size-cells 2' \
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:
112 | -o '/phb@0x80000000/ranges \
113 | nm0,0,0,80000000 0x80000000 0x10000000 \
114 | ni0,0,0,0 0xc0000000 0x10000' \
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:
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'
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.
136 Of the possible addresses, only the non-relocatable versions are
137 used when attaching the device to the bus.
140 BUGS
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.
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.
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.
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.
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.
164 Support for aliased memory and I/O addresses is left as an exercise
165 for the reader.
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.
173 Children of this node can only use the client callback interface
174 when attaching themselves to the <<phb>>.
177 REFERENCES
180 http://playground.sun.com/1275/home.html#OFDbusPCI
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;
198 typedef struct _hw_phb_device {
199 phb_space space[nr_hw_phb_spaces];
200 } hw_phb_device;
203 static const char *
204 hw_phb_decode_name(hw_phb_decode level)
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";
215 static void
216 hw_phb_init_address(device *me)
218 hw_phb_device *phb = device_data(me);
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");
226 /* (re) initialize each PCI space */
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;
236 /* decode each of the ranges properties entering the information
237 into the space table */
239 range_property_spec range;
240 int ranges_entry;
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));
287 if (ranges_entry == 0) {
288 device_error(me, "Missing or empty ranges property");
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*/
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);
336 /* Extract/set various fields from a PCI unit address.
338 Note: only the least significant 32 bits of each cell is used.
340 Note: for PPC MSB is 0 while for PCI it is 31. */
343 /* relocatable bit n */
345 static unsigned
346 extract_n(const device_unit *address)
348 return EXTRACTED32(address->cells[0], 0, 0);
351 static void
352 set_n(device_unit *address)
354 BLIT32(address->cells[0], 0, 1);
358 /* prefetchable bit p */
360 static unsigned
361 extract_p(const device_unit *address)
363 ASSERT(address->nr_cells == 3);
364 return EXTRACTED32(address->cells[0], 1, 1);
367 static void
368 set_p(device_unit *address)
370 BLIT32(address->cells[0], 1, 1);
374 /* aliased bit t */
376 static unsigned
377 extract_t(const device_unit *address)
379 ASSERT(address->nr_cells == 3);
380 return EXTRACTED32(address->cells[0], 2, 2);
383 static void
384 set_t(device_unit *address)
386 BLIT32(address->cells[0], 2, 1);
390 /* space code ss */
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;
399 static ss_type
400 extract_ss(const device_unit *address)
402 ASSERT(address->nr_cells == 3);
403 return EXTRACTED32(address->cells[0], 6, 7);
406 static void
407 set_ss(device_unit *address, ss_type val)
409 MBLIT32(address->cells[0], 6, 7, val);
413 /* bus number bbbbbbbb */
415 #if 0
416 static unsigned
417 extract_bbbbbbbb(const device_unit *address)
419 ASSERT(address->nr_cells == 3);
420 return EXTRACTED32(address->cells[0], 8, 15);
422 #endif
424 #if 0
425 static void
426 set_bbbbbbbb(device_unit *address, unsigned val)
428 MBLIT32(address->cells[0], 8, 15, val);
430 #endif
433 /* device number ddddd */
435 static unsigned
436 extract_ddddd(const device_unit *address)
438 ASSERT(address->nr_cells == 3);
439 return EXTRACTED32(address->cells[0], 16, 20);
442 static void
443 set_ddddd(device_unit *address, unsigned val)
445 MBLIT32(address->cells[0], 16, 20, val);
449 /* function number fff */
451 static unsigned
452 extract_fff(const device_unit *address)
454 ASSERT(address->nr_cells == 3);
455 return EXTRACTED32(address->cells[0], 21, 23);
458 static void
459 set_fff(device_unit *address, unsigned val)
461 MBLIT32(address->cells[0], 21, 23, val);
465 /* register number rrrrrrrr */
467 static unsigned
468 extract_rrrrrrrr(const device_unit *address)
470 ASSERT(address->nr_cells == 3);
471 return EXTRACTED32(address->cells[0], 24, 31);
474 static void
475 set_rrrrrrrr(device_unit *address, unsigned val)
477 MBLIT32(address->cells[0], 24, 31, val);
481 /* MSW of 64bit address hh..hh */
483 static unsigned
484 extract_hh_hh(const device_unit *address)
486 ASSERT(address->nr_cells == 3);
487 return address->cells[1];
490 static void
491 set_hh_hh(device_unit *address, unsigned val)
493 address->cells[2] = val;
497 /* LSW of 64bit address ll..ll */
499 static unsigned
500 extract_ll_ll(const device_unit *address)
502 ASSERT(address->nr_cells == 3);
503 return address->cells[2];
506 static void
507 set_ll_ll(device_unit *address, unsigned val)
509 address->cells[2] = val;
513 /* Convert PCI textual bus address into a device unit */
515 static int
516 hw_phb_unit_decode(device *me,
517 const char *unit,
518 device_unit *address)
520 char *end = NULL;
521 const char *chp = unit;
522 unsigned long val;
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));
528 if (unit == NULL)
529 return 0;
531 address->nr_cells = 3;
533 if (isxdigit(*chp)) {
534 set_ss(address, ss_config_code);
536 else {
538 /* non-relocatable? */
539 if (*chp == 'n') {
540 set_n(address);
541 chp++;
544 /* address-space? */
545 if (*chp == 'i') {
546 set_ss(address, ss_io_code);
547 chp++;
549 else if (*chp == 'm') {
550 set_ss(address, ss_32bit_memory_code);
551 chp++;
553 else if (*chp == 'x') {
554 set_ss(address, ss_64bit_memory_code);
555 chp++;
557 else
558 device_error(me, "Problem parsing PCI address %s", unit);
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++;
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++;
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;
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;
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;
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;
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");
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;
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");
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;
711 /* finished? */
712 if (!isspace(*chp) && *chp != '\0')
713 device_error(me, "Problem parsing PCI address %s", unit);
715 return chp - unit;
719 /* Convert PCI device unit into its corresponding textual
720 representation */
722 static int
723 hw_phb_unit_encode(device *me,
724 const device_unit *unit_address,
725 char *buf,
726 int sizeof_buf)
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));
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));
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));
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));
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));
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]);
791 if (strlen(buf) > sizeof_buf)
792 error("buffer overflow");
793 return strlen(buf);
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)
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");
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;
824 /* if non-relocatable finished */
825 if (extract_n(address))
826 return 1;
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;
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));
858 return 0;
862 static int
863 hw_phb_size_to_attach_size(device *me,
864 const device_unit *size,
865 unsigned *nr_bytes,
866 device *client)
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];
877 static const phb_space *
878 find_phb_space(hw_phb_device *phb,
879 unsigned_word addr,
880 unsigned nr_bytes)
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;
891 return NULL;
895 static unsigned_word
896 map_phb_addr(const phb_space *space,
897 unsigned_word addr)
899 return addr - space->parent_base + space->my_base;
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)
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);
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)
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);
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)
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);
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)
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);
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 }
1021 static void *
1022 hw_phb_create(const char *name,
1023 const device_unit *unit_address,
1024 const char *args)
1026 /* create the descriptor */
1027 hw_phb_device *phb = ZALLOC(hw_phb_device);
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;
1055 return phb;
1059 const device_descriptor hw_phb_device_descriptor[] = {
1060 { "phb", hw_phb_create, &hw_phb_callbacks },
1061 { "pci", NULL, &hw_phb_callbacks },
1062 { NULL, },
1065 #endif /* _HW_PHB_ */