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