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