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
190typedef 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
202typedef struct _hw_phb_device  {
203  phb_space space[nr_hw_phb_spaces];
204} hw_phb_device;
205
206
207static const char *
208hw_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
219static void
220hw_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
299static void
300hw_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
349static unsigned
350extract_n(const device_unit *address)
351{
352  return EXTRACTED32(address->cells[0], 0, 0);
353}
354
355static void
356set_n(device_unit *address)
357{
358  BLIT32(address->cells[0], 0, 1);
359}
360
361
362/* prefetchable bit p */
363
364static unsigned
365extract_p(const device_unit *address)
366{
367  ASSERT(address->nr_cells == 3);
368  return EXTRACTED32(address->cells[0], 1, 1);
369}
370
371static void
372set_p(device_unit *address)
373{
374  BLIT32(address->cells[0], 1, 1);
375}
376
377
378/* aliased bit t */
379
380static unsigned
381extract_t(const device_unit *address)
382{
383  ASSERT(address->nr_cells == 3);
384  return EXTRACTED32(address->cells[0], 2, 2);
385}
386
387static void
388set_t(device_unit *address)
389{
390  BLIT32(address->cells[0], 2, 1);
391}
392
393
394/* space code ss */
395
396typedef 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
403static ss_type
404extract_ss(const device_unit *address)
405{
406  ASSERT(address->nr_cells == 3);
407  return EXTRACTED32(address->cells[0], 6, 7);
408}
409
410static void
411set_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
420static unsigned
421extract_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
429static void
430set_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
439static unsigned
440extract_ddddd(const device_unit *address)
441{
442  ASSERT(address->nr_cells == 3);
443  return EXTRACTED32(address->cells[0], 16, 20);
444}
445
446static void
447set_ddddd(device_unit *address, unsigned val)
448{
449  MBLIT32(address->cells[0], 16, 20, val);
450}
451
452
453/* function number fff */
454
455static unsigned
456extract_fff(const device_unit *address)
457{
458  ASSERT(address->nr_cells == 3);
459  return EXTRACTED32(address->cells[0], 21, 23);
460}
461
462static void
463set_fff(device_unit *address, unsigned val)
464{
465  MBLIT32(address->cells[0], 21, 23, val);
466}
467
468
469/* register number rrrrrrrr */
470
471static unsigned
472extract_rrrrrrrr(const device_unit *address)
473{
474  ASSERT(address->nr_cells == 3);
475  return EXTRACTED32(address->cells[0], 24, 31);
476}
477
478static void
479set_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
487static unsigned
488extract_hh_hh(const device_unit *address)
489{
490  ASSERT(address->nr_cells == 3);
491  return address->cells[1];
492}
493
494static void
495set_hh_hh(device_unit *address, unsigned val)
496{
497  address->cells[2] = val;
498}
499
500
501/* LSW of 64bit address ll..ll */
502
503static unsigned
504extract_ll_ll(const device_unit *address)
505{
506  ASSERT(address->nr_cells == 3);
507  return address->cells[2];
508}
509
510static void
511set_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
519static int
520hw_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
725static int
726hw_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
800static int
801hw_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
865static int
866hw_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
880static const phb_space *
881find_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
898static unsigned_word
899map_phb_addr(const phb_space *space,
900	     unsigned_word addr)
901{
902  return addr - space->parent_base + space->my_base;
903}
904
905
906
907static unsigned
908hw_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
930static unsigned
931hw_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
953static unsigned
954hw_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
981static unsigned
982hw_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
1011static 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
1024static void *
1025hw_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
1062const 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_ */
1069