]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/io/server/src/pci.cc
update
[l4.git] / l4 / pkg / io / server / src / pci.cc
1 /*
2  * (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3  *          Alexander Warg <warg@os.inf.tu-dresden.de>
4  *     economic rights: Technische Universität Dresden (Germany)
5  *
6  * This file is part of TUD:OS and distributed under the terms of the
7  * GNU General Public License 2.
8  * Please see the COPYING-GPL-2 file for details.
9  */
10
11 #include <l4/sys/types.h>
12 #include <l4/cxx/string>
13 #include <l4/cxx/minmax>
14 #include <l4/io/pciids.h>
15
16 #include <cstdio>
17 #include <typeinfo>
18
19 #include "debug.h"
20 #include "main.h"
21 #include "pci.h"
22 #include "phys_space.h"
23 #include "cfg.h"
24 #include "hw_msi.h"
25
26 static Pci_root_bridge *__pci_root_bridge;
27 static unsigned _last_msi;
28
29 class Pci_cardbus_bridge : public Pci_pci_bridge_basic
30 {
31 public:
32   Pci_cardbus_bridge(Hw::Device *host, Pci_bridge *bus)
33   : Pci_pci_bridge_basic(host, bus)
34   {}
35
36   void discover_resources(Hw::Device *host);
37 };
38
39 Pci_root_bridge *pci_root_bridge(int segment)
40 {
41   if (segment != 0)
42     return 0;
43   return __pci_root_bridge;
44 }
45
46 #if defined(ARCH_x86) || defined(ARCH_amd64)
47
48 #include <l4/util/port_io.h>
49
50 int
51 pci_register_root_bridge(int segment, Pci_root_bridge *b)
52 {
53   if (segment != 0)
54     return -1;
55
56   __pci_root_bridge = b;
57   return 0;
58 }
59
60 inline
61 l4_uint32_t
62 pci_conf_addr(l4_uint32_t bus, l4_uint32_t dev, l4_uint32_t fn, l4_uint32_t reg)
63 { return 0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3); }
64
65 int
66 Pci_port_root_bridge::cfg_read(unsigned bus, l4_uint32_t devfn,
67                               l4_uint32_t reg,
68                               l4_uint32_t *value, Cfg_width order)
69 {
70   l4util_out32(pci_conf_addr(bus, devfn >> 16, devfn & 0xffff, reg), 0xcf8);
71   using namespace Hw::Pci;
72
73   switch (order)
74     {
75     case Cfg_byte:  *value = l4util_in8(0xcfc + (reg & 3)); break;
76     case Cfg_short: *value = l4util_in16((0xcfc + (reg & 3)) & ~1UL); break;
77     case Cfg_long:  *value = l4util_in32(0xcfc); break;
78     }
79   return 0;
80 }
81
82 int
83 Pci_port_root_bridge::cfg_write(unsigned bus, l4_uint32_t devfn,
84                                l4_uint32_t reg,
85                                l4_uint32_t value, Cfg_width order)
86 {
87   l4util_out32(pci_conf_addr(bus, devfn >> 16, devfn & 0xffff, reg), 0xcf8);
88   using namespace Hw::Pci;
89
90   switch (order)
91     {
92     case Cfg_byte:  l4util_out8(value, 0xcfc + (reg & 3)); break;
93     case Cfg_short: l4util_out16(value, (0xcfc + (reg & 3)) & ~1UL); break;
94     case Cfg_long:  l4util_out32(value, 0xcfc); break;
95     }
96   return 0;
97 }
98
99 #endif
100
101 namespace {
102 static inline l4_uint32_t
103 devfn(unsigned dev, unsigned fn)
104 { return (dev << 16) | fn; }
105
106 }
107
108 void
109 Pci_bridge::scan_bus()
110 {
111   using namespace Hw::Pci;
112
113   int device = 0;
114   for (device = 0; device < 32; ++device)
115     {
116       l4_uint32_t hdr_type;
117       cfg_read(num, devfn(device, 0), Pci_dev::C_header_type, &hdr_type, Cfg_byte);
118       int funcs = (hdr_type & 0x80) ? 8 : 1;
119       for (int function = 0; function < funcs; ++function)
120         {
121           l4_uint32_t vendor, _class;
122           cfg_read(num, devfn(device, function), Pci_dev::C_vendor, &vendor, Cfg_short);
123           if (vendor == 0xffff)
124             {
125               if (function == 0)
126                 break;
127               else
128                 continue;
129             }
130
131           cfg_read(num, devfn(device, function), Pci_dev::C_vendor, &vendor, Cfg_long);
132           cfg_read(num, devfn(device, function), Pci_dev::C_class_rev, &_class, Cfg_long);
133
134           if (function)
135             cfg_read(num, devfn(device, function), Pci_dev::C_header_type, &hdr_type, Cfg_byte);
136
137           Hw::Device *child = host()->get_child_dev_adr(devfn(device, function), true);
138
139           Pci_dev *d;
140           if ((_class >> 16) == 0x0604 || (_class >> 16) == 0x0607)
141             {
142               Pci_pci_bridge_basic *b = 0;
143               if ((hdr_type & 0x7f) == 1)
144                 b = new Pci_pci_bridge(child, this);
145               else if((hdr_type & 0x7f) == 2)
146                 b = new Pci_cardbus_bridge(child, this);
147
148               child->set_discover_bus_if(b);
149
150               l4_uint32_t busses;
151               bool reassign_busses = false;
152
153               cfg_read(num, devfn(device, function), Pci_dev::C_primary, &busses, Cfg_long);
154
155               if ((busses & 0xff) != num
156                   || ((busses >> 8) & 0xff) <= num)
157                 reassign_busses = true;
158
159               if (reassign_busses)
160                 {
161                   unsigned new_so = subordinate + 1;
162                   b->pri = num;
163                   b->num = new_so;
164                   b->subordinate = b->num;
165
166                   busses = (busses & 0xff000000)
167                     | ((l4_uint32_t)(b->pri))
168                     | ((l4_uint32_t)(b->num) << 8)
169                     | ((l4_uint32_t)(b->subordinate) << 16);
170
171                   cfg_write(num, devfn(device, function), Pci_dev::C_primary, busses, Cfg_long);
172                   increase_subordinate(new_so);
173                 }
174               else
175                 {
176                   b->pri = busses & 0xff;
177                   b->num = (busses >> 8) & 0xff;
178                   b->subordinate = (busses >> 16) & 0xff;
179                 }
180
181               d = b;
182             }
183           else
184             d = new Pci_dev(child, this);
185
186           child->add_feature(d);
187           child->add_resource_discoverer(d);
188
189           d->vendor_device = vendor;
190           d->cls_rev = _class;
191           d->hdr_type = hdr_type;
192         }
193     }
194 }
195
196
197 class Msi
198 {
199 public:
200   enum Addrs
201   {
202     Base_hi = 0,
203     Base_lo = 0xfee00000,
204   };
205
206   enum Mode
207   {
208     Dest_mode_phys = 0 << 2,
209     Dest_mode_log  = 1 << 2,
210   };
211
212   enum Redir
213   {
214     Dest_redir_cpu     = 0 << 3,
215     Dest_redir_lowprio = 1 << 3,
216   };
217
218   enum Delivery
219   {
220     Data_del_fixed   = 0 << 8,
221     Data_del_lowprio = 1 << 8,
222   };
223
224   enum Level
225   {
226     Data_level_deassert = 0 << 14,
227     Data_level_assert   = 1 << 14,
228   };
229
230   enum Trigger
231   {
232     Data_trigger_edge  = 0 << 15,
233     Data_trigger_level = 1 << 15,
234   };
235
236   static unsigned data(int vector) { return vector & 0xff; }
237 };
238
239 l4_uint32_t const *
240 Pci_dev::cfg_word(unsigned w) const
241 {
242   switch (w)
243     {
244     default: return 0;
245     case 0: return &vendor_device;
246     case 2: return &cls_rev;
247     case 11: return &subsys_ids;
248     }
249 }
250
251 unsigned
252 Pci_dev::bus_nr() const
253 { return _bus->num; }
254
255 unsigned
256 Pci_dev::disable_decoders()
257 {
258   l4_uint32_t v = 0;
259   // disable decoders
260   cfg_read(C_command, &v, Hw::Pci::Cfg_byte);
261   cfg_write(C_command, v & ~3, Hw::Pci::Cfg_byte);
262   return v & 0xff;
263 }
264
265 void
266 Pci_dev::restore_decoders(unsigned cmd)
267 {
268   cfg_write(C_command, cmd, Hw::Pci::Cfg_byte);
269 }
270
271 int
272 Pci_dev::discover_bar(int bar)
273 {
274   using namespace Hw::Pci;
275   l4_uint32_t v, x;
276
277   _bars[bar] = 0;
278   int r = C_bar_0 + bar * 4;
279   l4_uint8_t cmd = disable_decoders();
280
281   cfg_read(r, &v, Cfg_long);
282   cfg_write(r, ~0U, Cfg_long);
283   cfg_read(r, &x, Cfg_long);
284   cfg_write(r, v, Cfg_long);
285
286   restore_decoders(cmd);
287
288   if (!x)
289     return bar + 1;
290
291   unsigned io_flags = (cmd & CC_io) ? 0 : Resource::F_disabled;
292   unsigned mem_flags = (cmd & CC_mem) ? 0 : Resource::F_disabled;
293
294   io_flags |= Resource::Io_res
295            | Resource::F_size_aligned
296            | Resource::F_hierarchical;
297
298   mem_flags |= Resource::Mmio_res
299             | Resource::F_size_aligned
300             | Resource::F_hierarchical;
301
302   Adr_resource *res = 0;
303   if (!(x & 1))
304     {
305       //printf("%08x: BAR[%d] mmio ... %x\n", adr(), bar, x );
306       res = new Adr_resource(mem_flags);
307       if ((x & 0x6) == 0x4)
308         res->add_flags(Adr_resource::F_width_64bit);
309
310       if (x & 0x8)
311         res->add_flags(Resource::F_prefetchable);
312
313       int order;
314       l4_uint64_t size = x & ~0x7f;
315       l4_uint64_t a = v & ~0x7f;
316       if (res->is_64bit())
317         {
318           ++bar;
319           r = 0x10 + bar * 4;
320           cmd = disable_decoders();
321           cfg_read(r, &v, Cfg_long);
322           cfg_write(r, ~0U, Cfg_long);
323           cfg_read(r, &x, Cfg_long);
324           cfg_write(r, v, Cfg_long);
325           restore_decoders(cmd);
326           a |= l4_uint64_t(v) << 32;
327           size |= l4_uint64_t(x) << 32;
328         }
329
330       for (int s = 7; s < 64; ++s)
331         if ((size >> s) & 1)
332           {
333             order = s;
334             size = 1 << s;
335             break;
336           }
337
338       res->start_size(a, size);
339
340       // printf("%08x: BAR[%d] mem ...\n", adr(), bar*4 + 10 );
341       _bars[bar - res->is_64bit()] = res;
342       if (res->is_64bit())
343         _bars[bar] = (Adr_resource*)1;
344
345     }
346   else
347     {
348       // printf("%08x: BAR[%d] io ...\n", adr(), bar );
349       int s;
350       for (s = 2; s < 32; ++s)
351         if ((x >> s) & 1)
352           break;
353
354       res = new Adr_resource(io_flags);
355
356       _bars[bar] = res;
357       res->start_size(v & ~3, 1 << s);
358     }
359
360   res->validate();
361   _host->add_resource(res);
362   return bar + 1;
363 }
364
365 void
366 Pci_dev::discover_legacy_ide_resources()
367 {
368
369   if (!Io_config::cfg->legacy_ide_resources(_host))
370     return;
371
372   unsigned io_flags = Resource::Io_res
373            | Resource::F_size_aligned
374            | Resource::F_hierarchical;
375
376   // IDE legacy IO interface
377   if (cls_rev >> 16 == 0x101 && !(cls_rev & 0x100))
378     {
379       _host->add_resource(new Adr_resource(io_flags, 0x1f0, 0x1f7));
380       _host->add_resource(new Adr_resource(io_flags, 0x3f6, 0x3f6));
381       _host->add_resource(new Adr_resource(Resource::Irq_res | Resource::Irq_edge, 14, 14));
382     }
383   if (cls_rev >> 16 == 0x101 && !(cls_rev & 0x400))
384     {
385       _host->add_resource(new Adr_resource(io_flags, 0x170, 0x177));
386       _host->add_resource(new Adr_resource(io_flags, 0x376, 0x376));
387       _host->add_resource(new Adr_resource(Resource::Irq_res | Resource::Irq_edge, 15, 15));
388     }
389 }
390
391 void
392 Pci_dev::quirk_8086_8108()
393 {
394   using namespace Hw::Pci;
395
396   if (!(vendor() == 0x8086 && device() == 0x8108))
397     return;
398
399   l4_uint32_t v;
400
401   // GC - Graphics Control
402   cfg_read(0x52, &v, Cfg_short);
403
404   unsigned gfx_mem_sz = 0;
405
406   // VGA disabled?
407   if (v & 2)
408     return;
409
410   switch ((v >> 4) & 7)
411     {
412     case 1: gfx_mem_sz = 1 << 20; break;
413     case 2: gfx_mem_sz = 4 << 20; break;
414     case 3: gfx_mem_sz = 8 << 20; break;
415     default: return;
416     }
417
418   // BSM - Base of Stolen Memory
419   cfg_read(0x5c, &v, Cfg_long);
420   v &= 0xfff00000;
421
422   unsigned flags = Resource::Mmio_res
423                    | Resource::F_prefetchable
424                    | Resource::F_fixed_addr
425                    | Resource::F_fixed_size;
426   l4_addr_t end = v + gfx_mem_sz - 1;
427
428   _host->add_resource(new Adr_resource(flags, v, end));
429   for (Pci_bridge *p = _bus; p;)
430     {
431       p->host()->add_resource(new Adr_resource_provider(flags, v, end));
432       if (Pci_dev *d = dynamic_cast<Pci_dev *>(p))
433         p = d->_bus;
434       else
435         break;
436     }
437 }
438
439 void
440 Pci_dev::discover_expansion_rom()
441 {
442   using namespace Hw::Pci;
443
444   if (!Io_config::cfg->expansion_rom(host()))
445     return;
446
447   l4_uint32_t v, x;
448   unsigned rom_register = ((hdr_type & 0x7f) == 0) ? 12 * 4 : 14 * 4;
449
450   cfg_read(rom_register, &v, Cfg_long);
451
452   if (v == 0xffffffff || v == 0)
453     return; // no expansion ROM
454
455   cfg_write(rom_register, 0xfffffffe, Cfg_long);
456   cfg_read(rom_register, &x, Cfg_long);
457   cfg_write(rom_register, v, Cfg_long);
458
459   v &= ~0x3ff;
460   x &= ~0x3ff;
461
462   //printf("ROM %08x: %08x %08x\n", adr(), x, v);
463
464   int s;
465   for (s = 2; s < 32; ++s)
466     if ((x >> s) & 1)
467       break;
468
469   if (0) // currently we do not add a resource record for ROMs
470     {
471       unsigned flags = Adr_resource::Mmio_res | Adr_resource::F_size_aligned
472                        | Adr_resource::F_rom | Adr_resource::F_prefetchable;
473       Adr_resource *res = new Adr_resource(flags);
474
475       _rom = res;
476       res->start_size(v & ~3, 1 << s);
477       res->validate();
478       _host->add_resource(res);
479     }
480 }
481
482 void
483 Pci_dev::discover_pci_caps()
484 {
485   using namespace Hw::Pci;
486
487     {
488       l4_uint32_t status;
489       cfg_read(C_status, &status, Cfg_short);
490       if (!(status & CS_cap_list))
491         return;
492     }
493
494   l4_uint32_t cap_ptr;
495   cfg_read(C_capability_ptr, &cap_ptr, Cfg_byte);
496   cap_ptr &= ~0x3;
497   for (; cap_ptr; cfg_read(cap_ptr + 1, &cap_ptr, Cfg_byte), cap_ptr &= ~0x3)
498     {
499       l4_uint32_t id;
500       cfg_read(cap_ptr, &id, Cfg_byte);
501       // printf("  PCI-cap: %x %s %s\n", id, Io_config::cfg->transparent_msi(host()) ? "yes" : "no", system_icu()->info.supports_msi() ? "yes" : "no" );
502       if (id == 0x05 && Io_config::cfg->transparent_msi(host())
503           && system_icu()->info.supports_msi())
504         {
505           // MSI capability
506           l4_uint32_t t, ctl, data;
507           l4_uint64_t addr = 0;
508
509           int msg_offs = 8;
510           cfg_read(cap_ptr + 2, &ctl, Cfg_short);
511           cfg_read(cap_ptr + 4, &t, Cfg_long);
512           addr |= t;
513           if (ctl & (1 << 7))
514             {
515               cfg_read(cap_ptr + 8, &t, Cfg_long);
516               addr |= ((l4_uint64_t)t) << 32;
517               msg_offs = 12;
518             }
519
520           cfg_read(cap_ptr + msg_offs, &data, Cfg_short);
521
522           cfg_write(cap_ptr + 4, Msi::Base_lo | Msi::Dest_mode_phys | Msi::Dest_redir_cpu, Cfg_long);
523
524           if (ctl & (1 << 7))
525             cfg_write(cap_ptr + 8, Msi::Base_hi, Cfg_long);
526
527           unsigned msi = _last_msi++;
528           if (msi >= system_icu()->info.nr_msis)
529             {
530               d_printf(DBG_WARN, "WARNING: run out of MSI vectors, use normal IRQ\n");
531               continue;
532             }
533
534           l4_umword_t msg = 0;
535           if (l4_error(system_icu()->icu->msi_info(msi, &msg)) < 0)
536             {
537               d_printf(DBG_WARN, "WARNING: could not get MSI message, use normal IRQ\n");
538               continue;
539             }
540
541           cfg_write(cap_ptr + msg_offs, Msi::Data_level_assert | Msi::Data_trigger_edge | Msi::Data_del_fixed | Msi::data(msg), Cfg_short);
542
543           cfg_write(cap_ptr + 2, ctl | 1, Cfg_short);
544
545           d_printf(DBG_DEBUG2, "  MSI cap: %x %llx %x\n", ctl, addr, data);
546           for (Resource_list::iterator i = host()->resources()->begin();
547                i != host()->resources()->end(); ++i)
548             {
549               if ((*i)->type() == Resource::Irq_res)
550                 {
551                   (*i)->set_empty(true);
552                   (*i)->add_flags(Resource::F_disabled);
553                 }
554             }
555
556           Adr_resource *res = new Hw::Msi_resource(msi);
557           flags |= F_msi;
558           _host->add_resource(res);
559         }
560     }
561 }
562
563 void
564 Pci_dev::discover_resources(Hw::Device *host)
565 {
566   using namespace Hw::Pci;
567
568   // printf("survey ... %x.%x\n", dynamic_cast<Pci_bridge*>(parent())->num, adr());
569   l4_uint32_t v;
570   cfg_read(C_subsys_vendor, &v, Cfg_long);
571   subsys_ids = v;
572   cfg_read(C_irq_pin, &v, Cfg_byte);
573   irq_pin = v;
574
575   if (irq_pin)
576     host->add_resource(new Adr_resource(Resource::Irq_res | Resource::F_relative
577                                   | Resource::F_hierarchical,
578                                   irq_pin - 1, irq_pin - 1));
579
580   cfg_read(C_command, &v, Cfg_short);
581
582   int bars = ((hdr_type & 0x7f) == 0) ? 6 : 2;
583
584   discover_legacy_ide_resources();
585
586   quirk_8086_8108();
587
588   for (int bar = 0; bar < bars;)
589     bar = discover_bar(bar);
590
591   discover_expansion_rom();
592   discover_pci_caps();
593 }
594
595 void
596 Pci_dev::setup_resources(Hw::Device *)
597 {
598   using namespace Hw::Pci;
599
600   for (unsigned i = 0; i < sizeof(_bars)/sizeof(_bars[0]); ++i)
601     {
602       Adr_resource *r = bar(i);
603       if (!r || r->type() == Resource::Io_res)
604         continue;
605
606       if (r->empty())
607         continue;
608
609       int reg = 0x10 + i * 4;
610       l4_uint64_t s = r->start();
611       l4_uint8_t cmd = disable_decoders();
612       cfg_write(reg, s, Cfg_long);
613       if (r->is_64bit())
614         {
615           cfg_write(reg + 4, s >> 32, Cfg_long);
616           ++i;
617         }
618       restore_decoders(cmd);
619
620
621       l4_uint32_t v;
622       cfg_read(reg, &v, Cfg_long);
623       if (l4_uint32_t(v & ~0x7f) != l4_uint32_t(s & 0xffffffff))
624         d_printf(DBG_ERR, "ERROR: could not set PCI BAR %d\n", i);
625
626       // printf("%08x: set BAR[%d] to %08x\n", adr(), i, v);
627     }
628 }
629
630
631 bool
632 Pci_dev::match_cid(cxx::String const &_cid) const
633 {
634   cxx::String const prefix("PCI/");
635   cxx::String cid(_cid);
636   if (!cid.starts_with(prefix))
637     return false;
638
639   cid = cid.substr(prefix.len());
640   cxx::String::Index n;
641   for (; cid.len() > 0; cid = cid.substr(n + 1))
642     {
643       n = cid.find("&");
644       cxx::String tok = cid.head(n);
645       if (tok.empty())
646         continue;
647
648       if (tok.starts_with("CC_"))
649         {
650           tok = tok.substr(3);
651           if (tok.len() < 2)
652             return false;
653
654           l4_uint32_t _csr;
655           int l = tok.from_hex(&_csr);
656           if (l < 0 || l > 6 || l % 2)
657             return false;
658
659           if ((cls_rev >> (8 + (6-l) * 4)) == _csr)
660             continue;
661           else
662             return false;
663         }
664       else if (tok.starts_with("REV_"))
665         {
666           tok = tok.substr(4);
667           unsigned char r;
668           if (tok.len() != 2 || tok.from_hex(&r) != 2)
669             return false;
670
671           if (r != (cls_rev & 0xff))
672             return false;
673         }
674       else if (tok.starts_with("VEN_"))
675         {
676           tok = tok.substr(4);
677           l4_uint32_t v;
678           if (tok.len() != 4 || tok.from_hex(&v) != 4)
679             return false;
680
681           if (((vendor_device >> 16) & 0xffff) != v)
682             return false;
683         }
684       else if (tok.starts_with("DEV_"))
685         {
686           tok = tok.substr(4);
687           l4_uint32_t d;
688           if (tok.len() != 4 || tok.from_hex(&d) != 4)
689             return false;
690
691           if ((vendor_device & 0xffff) != d)
692             return false;
693         }
694       else if (tok.starts_with("SUBSYS_"))
695         {
696           l4_uint32_t s;
697           tok = tok.substr(7);
698           if (tok.len() != 8 || tok.from_hex(&s) != 8)
699             return false;
700           if (subsys_ids != s)
701             return false;
702         }
703       else
704         return false;
705     }
706
707   return true;
708 }
709
710 void
711 Pci_pci_bridge::setup_resources(Hw::Device *host)
712 {
713   using namespace Hw::Pci;
714
715   Pci_dev::setup_resources(host);
716
717   if (!mmio->empty() && mmio->valid())
718     {
719       l4_uint32_t v = (mmio->start() >> 16) & 0xfff0;
720       v |= mmio->end() & 0xfff00000;
721       cfg_write(0x20, v, Cfg_long);
722       // printf("%08x: set mmio to %08x\n", adr(), v);
723       l4_uint32_t r;
724       cfg_read(0x20, &r, Cfg_long);
725       // printf("%08x: mmio =      %08x\n", adr(), r);
726       cfg_read(0x04, &r, Cfg_short);
727       r |= 3;
728       cfg_write(0x4, r, Cfg_short);
729     }
730
731   if (!pref_mmio->empty() && pref_mmio->valid())
732     {
733       l4_uint32_t v = (pref_mmio->start() >> 16) & 0xfff0;
734       v |= pref_mmio->end() & 0xfff00000;
735       cfg_write(0x24, v, Cfg_long);
736       // printf("%08x: set pref mmio to %08x\n", adr(), v);
737     }
738 }
739
740 void
741 Pci_pci_bridge::discover_resources(Hw::Device *host)
742 {
743   using namespace Hw::Pci;
744
745   l4_uint32_t v;
746   l4_uint64_t s, e;
747
748   cfg_read(C_mem_base, &v, Cfg_long);
749   s = (v & 0xfff0) << 16;
750   e = (v & 0xfff00000) | 0xfffff;
751
752   Adr_resource *r = new Adr_resource_provider(Resource::Mmio_res);
753   r->alignment(0xfffff);
754   if (s < e)
755     r->start_end(s, e);
756   else
757     r->set_empty();
758
759   // printf("%08x: mmio = %08x\n", adr(), v);
760   mmio = r;
761   mmio->validate();
762   _host->add_resource(mmio);
763
764   r = new Adr_resource_provider(Resource::Mmio_res | Resource::F_prefetchable);
765   cfg_read(C_pref_mem_base, &v, Cfg_long);
766   s = (v & 0xfff0) << 16;
767   e = (v & 0xfff00000) | 0xfffff;
768
769   if ((v & 0x0f) == 1)
770     {
771       r->add_flags(Adr_resource::F_width_64bit);
772       cfg_read(C_pref_mem_base_hi, &v, Cfg_long);
773       s |= l4_uint64_t(v) << 32;
774       cfg_read(C_pref_mem_limit_hi, &v, Cfg_long);
775       e |= l4_uint64_t(v) << 32;
776     }
777
778   r->alignment(0xfffff);
779   if (s < e)
780     r->start_end(s, e);
781   else
782     r->set_empty();
783
784   pref_mmio = r;
785   r->validate();
786   _host->add_resource(r);
787
788   cfg_read(C_io_base, &v, Cfg_short);
789   s = (v & 0xf0) << 8;
790   e = (v & 0xf000) | 0xfff;
791
792   r = new Adr_resource_provider(Resource::Io_res);
793   r->alignment(0xfff);
794   if (s < e)
795     r->start_end(s, e);
796   else
797     r->set_empty();
798   io = r;
799   r->validate();
800   _host->add_resource(r);
801
802   Pci_dev::discover_resources(host);
803 }
804
805
806 void
807 Pci_root_bridge::discover_resources(Hw::Device *)
808 {}
809
810
811
812
813 static const char * const pci_classes[] =
814     { "unknown", "mass storage contoller", "network controller", 
815       "display controller", "multimedia device", "memory controller",
816       "bridge device", "simple communication controller", 
817       "system peripheral", "input device", "docking station", 
818       "processor", "serial bus controller", "wireless controller",
819       "intelligent I/O controller", "satellite communication controller",
820       "encryption/decryption controller", 
821       "data aquisition/signal processing controller" };
822
823 static char const * const pci_bridges[] =
824 { "Host/PCI Bridge", "ISA Bridge", "EISA Bridge", "Micro Channel Bridge",
825   "PCI Bridge", "PCMCIA Bridge", "NuBus Bridge", "CardBus Bridge" };
826
827
828 static void
829 dump_res_rec(Resource_list const *r, int indent)
830 {
831   for (Resource_list::iterator i = r->begin(); i!= r->end(); ++i)
832     if (*i)
833       {
834         i->dump(indent + 2);
835         //dump_res_rec(i->child(), indent + 2);
836       }
837 }
838
839 void
840 Pci_dev::dump(int indent) const
841 {
842   char const *classname = "";
843
844   if (cls_rev >> 24 < sizeof(pci_classes)/sizeof(pci_classes[0]))
845     classname = pci_classes[cls_rev >> 24];
846
847   if ((cls_rev >> 24) == 0x06)
848     {
849       unsigned sc = (cls_rev >> 16) & 0xff;
850       if (sc < sizeof(pci_bridges)/sizeof(pci_bridges[0]))
851         classname = pci_bridges[sc];
852     }
853
854   printf("%*.s%04x:%02x:%02x.%x: %s [%d]\n", indent, " ",
855          0, (int)_bus->num, _host->adr() >> 16, _host->adr() & 0xffff,
856          classname, (int)hdr_type);
857
858   char buf[130];
859   printf("%*.s              0x%04x 0x%04x\n", indent, " ", vendor(), device());
860   libpciids_name_device(buf, sizeof(buf), vendor(), device());
861   printf("%*.s              %s\n", indent, " ", buf);
862 #if 0
863   if (verbose_lvl)
864     dump_res_rec(resources(), 0);
865 #endif
866 }
867
868 void
869 Pci_bridge::dump(int) const
870 {
871 #if 0
872   "bridge %04x:%02x:%02x.%x\n",
873          b->num, 0, b->parent() ? (int)static_cast<Pci_bridge*>(b->parent())->num : 0,
874          b->adr() >> 16, b->adr() & 0xffff);
875 #endif
876 #if 0
877   //dump_res_rec(resources(), 0);
878
879   for (iterator c = begin(0); c != end(); ++c)
880     c->dump();
881 #endif
882 };
883
884
885
886 void
887 Pci_cardbus_bridge::discover_resources(Hw::Device *host)
888 {
889   using namespace Hw::Pci;
890   l4_uint32_t v;
891   cfg_read(C_subsys_vendor, &v, Cfg_long);
892   subsys_ids = v;
893
894   Adr_resource *r = new Adr_resource_provider(Resource::Mmio_res);
895   cfg_read(C_cb_mem_base_0, &v, Cfg_long);
896   r->start(v);
897   cfg_read(C_cb_mem_limit_0, &v, Cfg_long);
898   r->end(v);
899   if (!r->end())
900     r->set_empty();
901   r->validate();
902   host->add_resource(r);
903
904   r = new Adr_resource_provider(Resource::Mmio_res);
905   cfg_read(C_cb_mem_base_1, &v, Cfg_long);
906   r->start(v);
907   cfg_read(C_cb_mem_limit_1, &v, Cfg_long);
908   r->end(v);
909   if (!r->end())
910     r->set_empty();
911   r->validate();
912   host->add_resource(r);
913
914   r = new Adr_resource_provider(Resource::Io_res);
915   cfg_read(C_cb_io_base_0, &v, Cfg_long);
916   r->start(v);
917   cfg_read(C_cb_io_limit_0, &v, Cfg_long);
918   r->end(v);
919   if (!r->end())
920     r->set_empty();
921   r->validate();
922   host->add_resource(r);
923
924   r = new Adr_resource_provider(Resource::Io_res);
925   cfg_read(C_cb_io_base_1, &v, Cfg_long);
926   r->start(v);
927   cfg_read(C_cb_io_limit_1, &v, Cfg_long);
928   r->end(v);
929   if (!r->end())
930     r->set_empty();
931   r->validate();
932   host->add_resource(r);
933 }
934
935 void
936 Pci_irq_router::dump(int indent) const
937 {
938   printf("%*sPCI IRQ ROUTER: %s (%p)\n", indent, "", typeid(*this).name(),
939          this);
940 }
941
942 bool
943 Pci_pci_bridge_irq_router_rs::request(Resource *parent, Device *pdev,
944                                       Resource *child, Device *cdev)
945 {
946   Adr_resource *cr = dynamic_cast<Adr_resource*>(child);
947
948   if (!cr)
949     {
950       // assume we allocate an abstract IRQ router resource as a child
951       // that always fits
952       child->parent(parent);
953       return true;
954     }
955
956   bool res = false;
957
958   Hw::Device *cd = dynamic_cast<Hw::Device*>(cdev);
959
960   if (!cd)
961     return res;
962
963   if (pdev->parent())
964     {
965       cr->start((cr->start() + (cd->adr() >> 16)) & 3);
966       res = pdev->parent()->request_child_resource(cr, pdev);
967       if (res)
968         cr->parent(parent);
969     }
970
971   return res;
972 }
973