Upload Tizen:Base source
[external/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_ */