1/*  This file is part of the program psim.
2
3    Copyright 1994, 1995, 1996, 2003, 2004 Andrew Cagney
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_HTAB_C_
23#define _HW_HTAB_C_
24
25#include "device_table.h"
26
27#include "bfd.h"
28
29
30/* DEVICE
31
32
33   htab - pseudo-device describing a PowerPC hash table
34
35
36   DESCRIPTION
37
38
39   During the initialization of the device tree, the pseudo-device
40   <<htab>>, in conjunction with any child <<pte>> pseudo-devices,
41   will create a PowerPC hash table in memory.  The hash table values
42   are written using dma transfers.
43
44   The size and address of the hash table are determined by properties
45   of the htab node.
46
47   By convention, the htab device is made a child of the
48   <</openprom/init>> node.
49
50   By convention, the real address of the htab is used as the htab
51   nodes unit address.
52
53
54   PROPERTIES
55
56
57   real-address = <address> (required)
58
59   The physical address of the hash table.  The PowerPC architecture
60   places limitations on what is a valid hash table real-address.
61
62
63   nr-bytes = <size> (required)
64
65   The size of the hash table (in bytes) that is to be created at
66   <<real-address>>.  The PowerPC architecture places limitations on
67   what is a valid hash table size.
68
69
70   claim = <anything> (optional)
71
72   If this property is present, the memory used to construct the hash
73   table will be claimed from the memory device.  The memory device
74   being specified by the <</chosen/memory>> ihandle property.
75
76
77   EXAMPLES
78
79   Enable tracing.
80
81   |  $  psim -t htab-device \
82
83
84   Create a htab specifying the base address and minimum size.
85
86   |    -o '/openprom/init/htab@0x10000/real-address 0x10000' \
87   |    -o '/openprom/init/htab@0x10000/claim 0' \
88   |    -o '/openprom/init/htab@0x10000/nr-bytes 65536' \
89
90
91   BUGS
92
93
94   See the <<pte>> device.
95
96
97   */
98
99
100/* DEVICE
101
102
103   pte - pseudo-device describing a htab entry
104
105
106   DESCRIPTION
107
108
109   The <<pte>> pseudo-device, which must be a child of a <<htabl>>
110   node, describes a virtual to physical mapping that is to be entered
111   into the parents hash table.
112
113   Two alternative specifications of the mapping are allowed.  Either
114   a section of physical memory can be mapped to a virtual address, or
115   the header of an executible image can be used to define the
116   mapping.
117
118   By convention, the real address of the map is specified as the pte
119   devices unit address.
120
121
122   PROPERTIES
123
124
125   real-address = <address> (required)
126
127   The starting physical address that is to be mapped by the hash
128   table.
129
130
131   wimg = <int> (required)
132   pp = <int> (required)
133
134   The value of hash table protection bits that are to be used when
135   creating the virtual to physical address map.
136
137
138   claim = <anything> (optional)
139
140   If this property is present, the real memory that is being mapped by the
141   hash table will be claimed from the memory node (specified by the
142   ihandle <</chosen/memory>>).
143
144
145   virtual-address = <integer> [ <integer> ]  (option A)
146   nr-bytes = <size>  (option A)
147
148   Option A - Virtual virtual address (and size) at which the physical
149   address is to be mapped.  If multiple values are specified for the
150   virtual address then they are concatenated to gether to form a
151   longer virtual address.
152
153
154   file-name = <string>  (option B)
155
156   Option B - An executable image that is to be loaded (starting at
157   the physical address specified above) and then mapped in using
158   informatioin taken from the executables header.  information found
159   in the files header.
160
161
162   EXAMPLES
163
164
165   Enable tracing (note that both the <<htab>> and <<pte>> device use the
166   same trace option).
167
168   |   -t htab-device \
169
170
171   Map a block of physical memory into a specified virtual address:
172
173   |  -o '/openprom/init/htab/pte@0x0/real-address 0' \
174   |  -o '/openprom/init/htab/pte@0x0/nr-bytes 4096' \
175   |  -o '/openprom/init/htab/pte@0x0/virtual-address 0x1000000' \
176   |  -o '/openprom/init/htab/pte@0x0/claim 0' \
177   |  -o '/openprom/init/htab/pte@0x0/wimg 0x7' \
178   |  -o '/openprom/init/htab/pte@0x0/pp 0x2' \
179
180
181   Map a file into memory.
182
183   |  -o '/openprom/init/htab/pte@0x10000/real-address 0x10000' \
184   |  -o '/openprom/init/htab/pte@0x10000/file-name "netbsd.elf' \
185   |  -o '/openprom/init/htab/pte@0x10000/wimg 0x7' \
186   |  -o '/openprom/init/htab/pte@0x10000/pp 0x2' \
187
188
189   BUGS
190
191
192   For an ELF executable, the header defines both the virtual and real
193   address at which each file section should be loaded.  At present, the
194   real addresses that are specified in the header are ignored, the file
195   instead being loaded in to physical memory in a linear fashion.
196
197   When claiming memory, this device assumes that the #address-cells
198   and #size-cells is one.  For future implementations, this may not
199   be the case.
200
201   */
202
203
204
205static void
206htab_decode_hash_table(device *me,
207		       unsigned32 *htaborg,
208		       unsigned32 *htabmask)
209{
210  unsigned_word htab_ra;
211  unsigned htab_nr_bytes;
212  unsigned n;
213  device *parent = device_parent(me);
214  /* determine the location/size of the hash table */
215  if (parent == NULL
216      || strcmp(device_name(parent), "htab") != 0)
217    device_error(parent, "must be a htab device");
218  htab_ra = device_find_integer_property(parent, "real-address");
219  htab_nr_bytes = device_find_integer_property(parent, "nr-bytes");
220  if (htab_nr_bytes < 0x10000) {
221    device_error(parent, "htab size 0x%x less than 0x1000",
222		 htab_nr_bytes);
223  }
224  for (n = htab_nr_bytes; n > 1; n = n / 2) {
225    if (n % 2 != 0)
226      device_error(parent, "htab size 0x%x not a power of two",
227		   htab_nr_bytes);
228  }
229  *htaborg = htab_ra;
230  /* Position the HTABMASK ready for use against a hashed address and
231     not ready for insertion into SDR1.HTABMASK.  */
232  *htabmask = MASKED32(htab_nr_bytes - 1, 7, 31-6);
233  /* Check that the MASK and ADDRESS do not overlap.  */
234  if ((htab_ra & (*htabmask)) != 0) {
235    device_error(parent, "htaborg 0x%lx not aligned to htabmask 0x%lx",
236		 (unsigned long)*htaborg, (unsigned long)*htabmask);
237  }
238  DTRACE(htab, ("htab - htaborg=0x%lx htabmask=0x%lx\n",
239		(unsigned long)*htaborg, (unsigned long)*htabmask));
240}
241
242static void
243htab_map_page(device *me,
244	      unsigned_word ra,
245	      unsigned64 va,
246	      unsigned wimg,
247	      unsigned pp,
248	      unsigned32 htaborg,
249	      unsigned32 htabmask)
250{
251  /* keep everything left shifted so that the numbering is easier */
252  unsigned64 vpn = va << 12;
253  unsigned32 vsid = INSERTED32(EXTRACTED64(vpn, 0, 23), 0, 23);
254  unsigned32 vpage = INSERTED32(EXTRACTED64(vpn, 24, 39), 0, 15);
255  unsigned32 hash = INSERTED32(EXTRACTED32(vsid, 5, 23)
256			       ^ EXTRACTED32(vpage, 0, 15),
257			       7, 31-6);
258  int h;
259  for (h = 0; h < 2; h++) {
260    unsigned32 pteg = (htaborg | (hash & htabmask));
261    int pti;
262    for (pti = 0; pti < 8; pti++) {
263      unsigned32 pte = pteg + 8 * pti;
264      unsigned32 current_target_pte0;
265      unsigned32 current_pte0;
266      if (device_dma_read_buffer(device_parent(me),
267				 &current_target_pte0,
268				 0, /*space*/
269				 pte,
270				 sizeof(current_target_pte0)) != 4)
271	device_error(me, "failed to read a pte at 0x%lx", (unsigned long)pte);
272      current_pte0 = T2H_4(current_target_pte0);
273      if (MASKED32(current_pte0, 0, 0)) {
274	/* full pte, check it isn't already mapping the same virtual
275           address */
276	unsigned32 curr_vsid = INSERTED32(EXTRACTED32(current_pte0, 1, 24), 0, 23);
277	unsigned32 curr_api = INSERTED32(EXTRACTED32(current_pte0, 26, 31), 0, 5);
278	unsigned32 curr_h = EXTRACTED32(current_pte0, 25, 25);
279	if (curr_h == h
280	    && curr_vsid == vsid
281	    && curr_api == MASKED32(vpage, 0, 5))
282	  device_error(me, "duplicate map - va=0x%08lx ra=0x%lx vsid=0x%lx h=%d vpage=0x%lx hash=0x%lx pteg=0x%lx+%2d pte0=0x%lx",
283		       (unsigned long)va,
284		       (unsigned long)ra,
285		       (unsigned long)vsid,
286		       h,
287		       (unsigned long)vpage,
288		       (unsigned long)hash,
289		       (unsigned long)pteg,
290		       pti * 8,
291		       (unsigned long)current_pte0);
292      }
293      else {
294	/* empty pte fill it */
295	unsigned32 pte0 = (MASK32(0, 0)
296			   | INSERTED32(EXTRACTED32(vsid, 0, 23), 1, 24)
297			   | INSERTED32(h, 25, 25)
298			   | INSERTED32(EXTRACTED32(vpage, 0, 5), 26, 31));
299	unsigned32 target_pte0 = H2T_4(pte0);
300	unsigned32 pte1 = (INSERTED32(EXTRACTED32(ra, 0, 19), 0, 19)
301			   | INSERTED32(wimg, 25, 28)
302			   | INSERTED32(pp, 30, 31));
303	unsigned32 target_pte1 = H2T_4(pte1);
304	if (device_dma_write_buffer(device_parent(me),
305				    &target_pte0,
306				    0, /*space*/
307				    pte,
308				    sizeof(target_pte0),
309				    1/*ro?*/) != 4
310	    || device_dma_write_buffer(device_parent(me),
311				       &target_pte1,
312				       0, /*space*/
313				       pte + 4,
314				       sizeof(target_pte1),
315				       1/*ro?*/) != 4)
316	  device_error(me, "failed to write a pte a 0x%lx", (unsigned long)pte);
317	DTRACE(htab, ("map - va=0x%08lx ra=0x%lx vsid=0x%lx h=%d vpage=0x%lx hash=0x%lx pteg=0x%lx+%2d pte0=0x%lx pte1=0x%lx\n",
318		      (unsigned long)va,
319		      (unsigned long)ra,
320		      (unsigned long)vsid,
321		      h,
322		      (unsigned long)vpage,
323		      (unsigned long)hash,
324		      (unsigned long)pteg,
325		      pti * 8,
326		      (unsigned long)pte0,
327		      (unsigned long)pte1));
328	return;
329      }
330    }
331    /* re-hash */
332    hash = MASKED32(~hash, 0, 18);
333  }
334}
335
336static unsigned_word
337claim_memory(device *me,
338	     device_instance *memory,
339	     unsigned_word ra,
340	     unsigned_word size)
341{
342  unsigned32 args[3];
343  unsigned32 results[1];
344  int status;
345  args[0] = 0; /* alignment */
346  args[1] = size;
347  args[2] = ra;
348  status = device_instance_call_method(memory, "claim", 3, args, 1, results);
349  if (status != 0)
350    device_error(me, "failed to claim memory");
351  return results[0];
352}
353
354static void
355htab_map_region(device *me,
356		device_instance *memory,
357		unsigned_word pte_ra,
358		unsigned64 pte_va,
359		unsigned nr_bytes,
360		unsigned wimg,
361		unsigned pp,
362		unsigned32 htaborg,
363		unsigned32 htabmask)
364{
365  unsigned_word ra;
366  unsigned64 va;
367  /* claim the memory */
368  if (memory != NULL)
369    claim_memory(me, memory, pte_ra, nr_bytes);
370  /* go through all pages and create a pte for each */
371  for (ra = pte_ra, va = pte_va;
372       ra < pte_ra + nr_bytes;
373       ra += 0x1000, va += 0x1000) {
374    htab_map_page(me, ra, va, wimg, pp, htaborg, htabmask);
375  }
376}
377
378typedef struct _htab_binary_sizes {
379  unsigned_word text_ra;
380  unsigned_word text_base;
381  unsigned_word text_bound;
382  unsigned_word data_ra;
383  unsigned_word data_base;
384  unsigned data_bound;
385  device *me;
386} htab_binary_sizes;
387
388static void
389htab_sum_binary(bfd *abfd,
390		sec_ptr sec,
391		PTR data)
392{
393  htab_binary_sizes *sizes = (htab_binary_sizes*)data;
394  unsigned_word size = bfd_get_section_size (sec);
395  unsigned_word vma = bfd_get_section_vma (abfd, sec);
396  unsigned_word ra = bfd_get_section_lma (abfd, sec);
397
398  /* skip the section if no memory to allocate */
399  if (! (bfd_get_section_flags(abfd, sec) & SEC_ALLOC))
400    return;
401
402  if ((bfd_get_section_flags (abfd, sec) & SEC_CODE)
403      || (bfd_get_section_flags (abfd, sec) & SEC_READONLY)) {
404    if (sizes->text_bound < vma + size)
405      sizes->text_bound = ALIGN_PAGE(vma + size);
406    if (sizes->text_base > vma)
407      sizes->text_base = FLOOR_PAGE(vma);
408    if (sizes->text_ra > ra)
409      sizes->text_ra = FLOOR_PAGE(ra);
410  }
411  else if ((bfd_get_section_flags (abfd, sec) & SEC_DATA)
412	   || (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)) {
413    if (sizes->data_bound < vma + size)
414      sizes->data_bound = ALIGN_PAGE(vma + size);
415    if (sizes->data_base > vma)
416      sizes->data_base = FLOOR_PAGE(vma);
417    if (sizes->data_ra > ra)
418      sizes->data_ra = FLOOR_PAGE(ra);
419  }
420}
421
422static void
423htab_dma_binary(bfd *abfd,
424		sec_ptr sec,
425		PTR data)
426{
427  htab_binary_sizes *sizes = (htab_binary_sizes*)data;
428  void *section_init;
429  unsigned_word section_vma;
430  unsigned_word section_size;
431  unsigned_word section_ra;
432  device *me = sizes->me;
433
434  /* skip the section if no memory to allocate */
435  if (! (bfd_get_section_flags(abfd, sec) & SEC_ALLOC))
436    return;
437
438  /* check/ignore any sections of size zero */
439  section_size = bfd_get_section_size (sec);
440  if (section_size == 0)
441    return;
442
443  /* if nothing to load, ignore this one */
444  if (! (bfd_get_section_flags(abfd, sec) & SEC_LOAD))
445    return;
446
447  /* find where it is to go */
448  section_vma = bfd_get_section_vma(abfd, sec);
449  section_ra = 0;
450  if ((bfd_get_section_flags (abfd, sec) & SEC_CODE)
451      || (bfd_get_section_flags (abfd, sec) & SEC_READONLY))
452    section_ra = (section_vma - sizes->text_base + sizes->text_ra);
453  else if ((bfd_get_section_flags (abfd, sec) & SEC_DATA))
454    section_ra = (section_vma - sizes->data_base + sizes->data_ra);
455  else
456    return; /* just ignore it */
457
458  DTRACE(htab,
459	 ("load - name=%-7s vma=0x%.8lx size=%6ld ra=0x%.8lx flags=%3lx(%s%s%s%s%s )\n",
460	  bfd_get_section_name(abfd, sec),
461	  (long)section_vma,
462	  (long)section_size,
463	  (long)section_ra,
464	  (long)bfd_get_section_flags(abfd, sec),
465	  bfd_get_section_flags(abfd, sec) & SEC_LOAD ? " LOAD" : "",
466	  bfd_get_section_flags(abfd, sec) & SEC_CODE ? " CODE" : "",
467	  bfd_get_section_flags(abfd, sec) & SEC_DATA ? " DATA" : "",
468	  bfd_get_section_flags(abfd, sec) & SEC_ALLOC ? " ALLOC" : "",
469	  bfd_get_section_flags(abfd, sec) & SEC_READONLY ? " READONLY" : ""
470	  ));
471
472  /* dma in the sections data */
473  section_init = zalloc(section_size);
474  if (!bfd_get_section_contents(abfd,
475				sec,
476				section_init, 0,
477				section_size)) {
478    bfd_perror("devices/pte");
479    device_error(me, "no data loaded");
480  }
481  if (device_dma_write_buffer(device_parent(me),
482			      section_init,
483			      0 /*space*/,
484			      section_ra,
485			      section_size,
486			      1 /*violate_read_only*/)
487      != section_size)
488    device_error(me, "broken dma transfer");
489  zfree(section_init); /* only free if load */
490}
491
492/* create a memory map from a binaries virtual addresses to a copy of
493   the binary laid out linearly in memory */
494
495static void
496htab_map_binary(device *me,
497		device_instance *memory,
498		unsigned_word ra,
499		unsigned wimg,
500		unsigned pp,
501		const char *file_name,
502		unsigned32 htaborg,
503		unsigned32 htabmask)
504{
505  htab_binary_sizes sizes;
506  bfd *image;
507  sizes.text_ra = -1;
508  sizes.data_ra = -1;
509  sizes.text_base = -1;
510  sizes.data_base = -1;
511  sizes.text_bound = 0;
512  sizes.data_bound = 0;
513  sizes.me = me;
514
515  /* open the file */
516  image = bfd_openr(file_name, NULL);
517  if (image == NULL) {
518    bfd_perror("devices/pte");
519    device_error(me, "the file %s not loaded", file_name);
520  }
521
522  /* check it is valid */
523  if (!bfd_check_format(image, bfd_object)) {
524    bfd_close(image);
525    device_error(me, "the file %s has an invalid binary format", file_name);
526  }
527
528  /* determine the size of each of the files regions */
529  bfd_map_over_sections (image, htab_sum_binary, (PTR) &sizes);
530
531  /* if needed, determine the real addresses of the sections */
532  if (ra != -1) {
533    sizes.text_ra = ra;
534    sizes.data_ra = ALIGN_PAGE(sizes.text_ra +
535			       (sizes.text_bound - sizes.text_base));
536  }
537
538  DTRACE(htab, ("text map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n",
539		(unsigned long)sizes.text_base,
540		(unsigned long)sizes.text_bound,
541		(unsigned long)sizes.text_ra));
542  DTRACE(htab, ("data map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n",
543		(unsigned long)sizes.data_base,
544		(unsigned long)sizes.data_bound,
545		(unsigned long)sizes.data_ra));
546
547  /* check for and fix a botched image (text and data segments
548     overlap) */
549  if ((sizes.text_base <= sizes.data_base
550       && sizes.text_bound >= sizes.data_bound)
551      || (sizes.data_base <= sizes.text_base
552	  && sizes.data_bound >= sizes.data_bound)
553      || (sizes.text_bound > sizes.data_base
554	  && sizes.text_bound <= sizes.data_bound)
555      || (sizes.text_base >= sizes.data_base
556	  && sizes.text_base < sizes.data_bound)) {
557    DTRACE(htab, ("text and data segment overlaped - using just data segment\n"));
558    /* check va->ra linear */
559    if ((sizes.text_base - sizes.text_ra)
560	!= (sizes.data_base - sizes.data_ra))
561      device_error(me, "overlapping but missaligned text and data segments");
562    /* enlarge the data segment */
563    if (sizes.text_base < sizes.data_base)
564      sizes.data_base = sizes.text_base;
565    if (sizes.text_bound > sizes.data_bound)
566      sizes.data_bound = sizes.text_bound;
567    if (sizes.text_ra < sizes.data_ra)
568      sizes.data_ra = sizes.text_ra;
569    /* zap the text segment */
570    sizes.text_base = 0;
571    sizes.text_bound = 0;
572    sizes.text_ra = 0;
573    DTRACE(htab, ("common map - base=0x%lx bound=0x%lx-1 ra=0x%lx\n",
574		  (unsigned long)sizes.data_base,
575		  (unsigned long)sizes.data_bound,
576		  (unsigned long)sizes.data_ra));
577  }
578
579  /* set up virtual memory maps for each of the regions */
580  if (sizes.text_bound - sizes.text_base > 0) {
581    htab_map_region(me, memory, sizes.text_ra, sizes.text_base,
582		    sizes.text_bound - sizes.text_base,
583		    wimg, pp,
584		    htaborg, htabmask);
585  }
586
587  htab_map_region(me, memory, sizes.data_ra, sizes.data_base,
588		  sizes.data_bound - sizes.data_base,
589		  wimg, pp,
590		  htaborg, htabmask);
591
592  /* dma the sections into physical memory */
593  bfd_map_over_sections (image, htab_dma_binary, (PTR) &sizes);
594}
595
596static void
597htab_init_data_callback(device *me)
598{
599  device_instance *memory = NULL;
600  if (WITH_TARGET_WORD_BITSIZE != 32)
601    device_error(me, "only 32bit targets currently suported");
602
603  /* find memory device */
604  if (device_find_property(me, "claim") != NULL)
605    memory = tree_find_ihandle_property(me, "/chosen/memory");
606
607  /* for the htab, just allocate space for it */
608  if (strcmp(device_name(me), "htab") == 0) {
609    unsigned_word address = device_find_integer_property(me, "real-address");
610    unsigned_word length = device_find_integer_property(me, "nr-bytes");
611    unsigned_word base = claim_memory(me, memory, address, length);
612    if (base == -1 || base != address)
613      device_error(me, "cannot allocate hash table");
614  }
615
616  /* for the pte, do all the real work */
617  if (strcmp(device_name(me), "pte") == 0) {
618    unsigned32 htaborg;
619    unsigned32 htabmask;
620
621    htab_decode_hash_table(me, &htaborg, &htabmask);
622
623    if (device_find_property(me, "file-name") != NULL) {
624      /* map in a binary */
625      unsigned pte_wimg = device_find_integer_property(me, "wimg");
626      unsigned pte_pp = device_find_integer_property(me, "pp");
627      const char *file_name = device_find_string_property(me, "file-name");
628      if (device_find_property(me, "real-address") != NULL) {
629	unsigned32 pte_ra = device_find_integer_property(me, "real-address");
630	DTRACE(htab, ("pte - ra=0x%lx, wimg=%ld, pp=%ld, file-name=%s\n",
631		      (unsigned long)pte_ra,
632		      (unsigned long)pte_wimg,
633		      (long)pte_pp,
634		      file_name));
635	htab_map_binary(me, memory, pte_ra, pte_wimg, pte_pp, file_name,
636			htaborg, htabmask);
637      }
638      else {
639	DTRACE(htab, ("pte - wimg=%ld, pp=%ld, file-name=%s\n",
640		      (unsigned long)pte_wimg,
641		      (long)pte_pp,
642		      file_name));
643	htab_map_binary(me, memory, -1, pte_wimg, pte_pp, file_name,
644			htaborg, htabmask);
645      }
646    }
647    else {
648      /* handle a normal mapping definition */
649      unsigned64 pte_va = 0;
650      unsigned32 pte_ra = device_find_integer_property(me, "real-address");
651      unsigned pte_nr_bytes = device_find_integer_property(me, "nr-bytes");
652      unsigned pte_wimg = device_find_integer_property(me, "wimg");
653      unsigned pte_pp = device_find_integer_property(me, "pp");
654      signed_cell partial_va;
655      int i;
656      for (i = 0;
657	   device_find_integer_array_property(me, "virtual-address", i, &partial_va);
658	   i++) {
659	pte_va = (pte_va << WITH_TARGET_WORD_BITSIZE) | (unsigned_cell)partial_va;
660      }
661      DTRACE(htab, ("pte - ra=0x%lx, wimg=%ld, pp=%ld, va=0x%lx, nr_bytes=%ld\n",
662		    (unsigned long)pte_ra,
663		    (long)pte_wimg,
664		    (long)pte_pp,
665		    (unsigned long)pte_va,
666		    (long)pte_nr_bytes));
667      htab_map_region(me, memory, pte_ra, pte_va, pte_nr_bytes, pte_wimg, pte_pp,
668		      htaborg, htabmask);
669    }
670  }
671}
672
673
674static device_callbacks const htab_callbacks = {
675  { NULL, htab_init_data_callback, },
676  { NULL, }, /* address */
677  { NULL, }, /* IO */
678  { passthrough_device_dma_read_buffer,
679    passthrough_device_dma_write_buffer, },
680  { NULL, }, /* interrupt */
681  { generic_device_unit_decode,
682    generic_device_unit_encode, },
683};
684
685const device_descriptor hw_htab_device_descriptor[] = {
686  { "htab", NULL, &htab_callbacks },
687  { "pte", NULL, &htab_callbacks }, /* yep - uses htab's table */
688  { NULL },
689};
690
691#endif /* _HW_HTAB_C_ */
692