xref: /netbsd-src/external/gpl3/gdb/dist/sim/ppc/hw_phb.c (revision ae87de8892f277bece3527c15b186ebcfa188227)
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 ((hw_phb_decode)type != hw_phb_normal_decode
316       && (hw_phb_decode)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, (unsigned long)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, (unsigned long)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_ */
1065