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