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