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