]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/io/server/src/vpci.cc
090ae3b6531886b08307bf4ce4e1a7408505765e
[l4.git] / l4 / pkg / io / server / src / vpci.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/vbus/vdevice-ops.h>
12
13 #include <cassert>
14 #include <cstring>
15 #include <cstdlib>
16 #include <l4/cxx/exceptions>
17 #include <l4/io/pciids.h>
18 #include <l4/sys/err.h>
19
20 #include "pci.h"
21 #include "vpci.h"
22 #include "vbus_factory.h"
23
24 namespace Vi {
25
26 // -----------------------------------------------------------------------
27 // Pci_virtual_dev
28 // -----------------------------------------------------------------------
29
30 Pci_virtual_dev::Pci_virtual_dev()
31 {
32   memset(&_h, 0, sizeof(_h));
33 }
34
35 int
36 Pci_virtual_dev::cfg_read(int reg, l4_uint32_t *v, Cfg_width order)
37 {
38   reg >>= order;
39   if ((unsigned)reg >= (_h_len >> order))
40     return -L4_ERANGE;
41
42 #define RC(x) *v = *((Hw::Pci::Cfg_type<x>::Type const *)_h + reg); break
43   *v = 0;
44   switch (order)
45     {
46     case Hw::Pci::Cfg_byte: RC(Hw::Pci::Cfg_byte);
47     case Hw::Pci::Cfg_short: RC(Hw::Pci::Cfg_short);
48     case Hw::Pci::Cfg_long: RC(Hw::Pci::Cfg_long);
49     }
50
51   return 0;
52 #undef RC
53 }
54
55 int
56 Pci_virtual_dev::cfg_write(int reg, l4_uint32_t v, Cfg_width order)
57 {
58   switch (reg & ~3)
59     {
60     case 0x4: // status is RO
61       v &= 0x0000ffff << (reg & (3 >> order));
62       break;
63
64     default:
65       break;
66     }
67
68   reg >>= order;
69   if ((unsigned)reg >= (_h_len >> order))
70     return -L4_ERANGE;
71
72 #define RC(x) *((Hw::Pci::Cfg_type<x>::Type *)_h + reg) = v; break
73   switch (order)
74     {
75     case Hw::Pci::Cfg_byte: RC(Hw::Pci::Cfg_byte);
76     case Hw::Pci::Cfg_short: RC(Hw::Pci::Cfg_short);
77     case Hw::Pci::Cfg_long: RC(Hw::Pci::Cfg_long);
78     }
79
80   return 0;
81 #undef RC
82 }
83
84
85
86 // -----------------------------------------------------------------------
87 // Pci_proxy_dev
88 // -----------------------------------------------------------------------
89
90 Pci_proxy_dev::Pci_proxy_dev(Hw::Pci::If *hwf)
91 : _hwf(hwf), _rom(0)
92 {
93   assert (hwf);
94   for (int i = 0; i < 6; ++i)
95     {
96       Adr_resource *r = _hwf->bar(i);
97
98       if (!r)
99         {
100           _vbars[i] = 0;
101           continue;
102         }
103
104       if (_hwf->is_64bit_high_bar(i))
105         {
106           _vbars[i] = l4_uint64_t(r->start()) >> 32;
107         }
108       else
109         {
110           _vbars[i] = r->start();
111           if (r->type() == Adr_resource::Io_res)
112             _vbars[i] |= 1;
113
114           if (r->is_64bit())
115             _vbars[i] |= 4;
116
117           if (r->prefetchable())
118             _vbars[i] |= 8;
119
120         }
121
122       //printf("  bar: %d = %08x\n", i, _vbars[i]);
123     }
124
125   if (_hwf->rom())
126     _rom = _hwf->rom()->start();
127 }
128
129 int
130 Pci_proxy_dev::irq_enable(Irq_info *irq)
131 {
132   for (Resource_list::iterator i = hwf()->host()->resources()->begin();
133       i != hwf()->host()->resources()->end(); ++i)
134     {
135       Adr_resource *res = dynamic_cast<Adr_resource*>(*i);
136       if (!res)
137         continue;
138
139       if (res->type() == Adr_resource::Irq_res /* && (res->start() & 0x80) */)
140         {
141           irq->irq = res->start();
142           irq->trigger = !(res->flags() & Resource::Irq_info_base);
143           irq->polarity = !!(res->flags() & (Resource::Irq_info_base * 2));
144           return 0;
145         }
146     }
147   return -L4_EINVAL;
148 }
149
150
151
152 l4_uint32_t
153 Pci_proxy_dev::read_bar(int bar)
154 {
155   //printf("   read bar[%x]: %08x\n", bar, _vbars[bar]);
156   return _vbars[bar];
157 }
158
159 void
160 Pci_proxy_dev::write_bar(int bar, l4_uint32_t v)
161 {
162   Hw::Pci::If *p = _hwf;
163
164   Adr_resource *r = p->bar(bar);
165   if (!r)
166     return;
167
168   // printf("  write bar[%x]: %llx-%llx...\n", bar, r->abs_start(), r->abs_end());
169   l4_uint64_t size_mask = r->alignment();
170
171   if (r->type() == Adr_resource::Io_res)
172     size_mask |= 0xffff0000;
173
174   if (p->is_64bit_high_bar(bar))
175     size_mask >>= 32;
176
177   _vbars[bar] = (_vbars[bar] & size_mask) | (v & ~size_mask);
178
179   // printf("    bar=%lx\n", _vbars[bar]);
180 }
181
182 void
183 Pci_proxy_dev::write_rom(l4_uint32_t v)
184 {
185   Hw::Pci::If *p = _hwf;
186
187   // printf("write rom bar %x %p\n", v, _dev->rom());
188   Adr_resource *r = p->rom();
189   if (!r)
190     return;
191
192   l4_uint64_t size_mask = r->alignment();
193
194   _rom = (_rom & size_mask) | (v & (~size_mask | 1));
195
196   p->cfg_write(0x30, (r->start() & ~1U) | (v & 1), Hw::Pci::Cfg_long);
197 }
198
199 int
200 Pci_proxy_dev::cfg_read(int reg, l4_uint32_t *v, Cfg_width order)
201 {
202   Hw::Pci::If *p = _hwf;
203
204   l4_uint32_t buf;
205   l4_uint32_t const *r = &buf;
206   reg &= ~0U << order;
207   int dw = reg >> 2;
208   switch (dw)
209     {
210     case 0: case 2: case 11:
211       r = p->cfg_word(dw); break;
212     case 1: return p->cfg_read(reg, v, order);
213     case 3: //buf = l4_uint32_t(_dev->hdr_type) << 16; break;
214             p->cfg_read(dw * 4, &buf, Hw::Pci::Cfg_long);
215             buf |= 0x00800000;
216             break;
217     case 4: case 5: case 6: case 7: case 8: case 9:
218       buf = read_bar(dw-4); break;
219     case 12: buf = read_rom(); break;
220     default: return p->cfg_read(reg, v, order); //buf = 0; break;
221     }
222
223   unsigned mask = ~0U >> (32 - (1U << (order + 3)));
224   *v = (*r >> ((reg & 3) *8)) & mask;
225   return L4_EOK;
226 }
227
228 int
229 Pci_proxy_dev::cfg_write(int reg, l4_uint32_t v, Cfg_width order)
230 {
231   Hw::Pci::If *p = _hwf;
232
233   reg &= ~0U << order;
234   int dw = reg >> 2;
235   switch (dw)
236     {
237     case 4: case 5: case 6: case 7: case 8: case 9: case 12: break;
238     default: return p->cfg_write(reg, v, order);
239     }
240
241   l4_uint32_t old;
242   if (order < 2)
243     cfg_read(reg, &old, Hw::Pci::Cfg_long);
244
245   l4_uint32_t mask = ~0U >> (32 - (1U << (order + 3)));
246   l4_uint32_t sh = (reg & 3) * 8;
247   old &= ~(mask << sh);
248   old |= (v & mask) << sh;
249
250   switch (dw)
251     {
252     case 4: case 5: case 6: case 7: case 8: case 9:
253           write_bar(dw-4, old); break;
254     case 12: write_rom(old); break;
255     default: break;
256     }
257   return L4_EOK;
258 }
259
260 void
261 Pci_proxy_dev::dump() const
262 {
263   Hw::Pci::If *p = _hwf;
264
265   printf("       %04x:%02x:%02x.%x:\n",
266          0, p->bus_nr(), _hwf->host()->adr() >> 16, _hwf->host()->adr() & 0xffff);
267 #if 0
268   char buf[130];
269   libpciids_name_device(buf, sizeof(buf), _dev->vendor(), _dev->device());
270   printf("              %s\n", buf);
271 #endif
272 }
273
274
275 // -----------------------------------------------------------------------
276 // Virtual PCI dummy device
277 // -----------------------------------------------------------------------
278
279 class Pci_dummy : public Pci_virtual_dev, public Device
280 {
281 private:
282   unsigned char _cfg_space[4*4];
283
284 public:
285   int irq_enable(Irq_info *irq)
286   {
287     irq->irq = -1;
288     return -1;
289   }
290
291   Pci_dummy()
292   {
293     add_feature(this);
294     _h = &_cfg_space[0];
295     _h_len = sizeof(_cfg_space);
296     cfg_hdr()->hdr_type = 0x80;
297     cfg_hdr()->vendor_device = 0x02000400;
298     cfg_hdr()->status = 0;
299     cfg_hdr()->class_rev = 0x36440000;
300     cfg_hdr()->cmd = 0x0;
301   }
302
303   bool match_hw_feature(const Hw::Dev_feature*) const { return false; }
304   int dispatch(l4_umword_t, l4_uint32_t, L4::Ipc_iostream&)
305   { return -L4_ENOSYS; }
306 };
307
308
309 // ----------------------------------------------------------------------
310 // Basic virtual PCI bridge functionality
311 // ----------------------------------------------------------------------
312
313 Pci_bridge::Dev::Dev()
314 {
315   memset(_fns, 0, sizeof(_fns));
316 }
317
318 void
319 Pci_bridge::Dev::add_fn(Pci_dev *f)
320 {
321   for (unsigned i = 0; i < sizeof(_fns)/sizeof(_fns[0]); ++i)
322     {
323       if (!_fns[i])
324         {
325           _fns[i] = f;
326           return;
327         }
328     }
329 }
330
331 void
332 Pci_bridge::Dev::sort_fns()
333 {
334   // disabled sorting because the relation of two functions is questionable
335 #if 0
336   unsigned n;
337   for (n = 0; n < sizeof(_fns)/sizeof(_fns[0]) && _fns[n]; ++n)
338     ;
339
340   if (n < 2)
341     return;
342
343   bool exchg = false;
344
345   do
346     {
347       exchg = false;
348       for (unsigned i = 0; i < n - 1; ++i)
349         {
350           if (_fns[i]->dev()->function_nr() > _fns[i+1]->dev()->function_nr())
351             {
352               Pci_dev *t = _fns[i];
353               _fns[i] = _fns[i+1];
354               _fns[i+1] = t;
355               exchg = true;
356             }
357         }
358       n -= 1;
359     }
360   while (exchg && n >= 1);
361 #endif
362 }
363
364 void
365 Pci_bridge::Bus::add_fn(Pci_dev *pd, int slot)
366 {
367   if (slot >= 0)
368     {
369       _devs[slot].add_fn(pd);
370       _devs[slot].sort_fns();
371       return;
372     }
373
374   for (unsigned d = 0; d < Devs && !_devs[d].empty(); ++d)
375     if (_devs[d].cmp(pd))
376       {
377         _devs[d].add_fn(pd);
378         _devs[d].sort_fns();
379         return;
380       }
381
382   for (unsigned d = 0; d < Devs; ++d)
383     if (_devs[d].empty())
384       {
385         _devs[d].add_fn(pd);
386         return;
387       }
388 }
389
390 void
391 Pci_bridge::add_child(Device *d)
392 {
393   Pci_dev *vp = d->find_feature<Pci_dev>();
394
395   // hm, we do currently not add non PCI devices.
396   if (!vp)
397     return;
398
399   _bus.add_fn(vp);
400   Device::add_child(d);
401 }
402
403
404 void
405 Pci_bridge::add_child_fixed(Device *d, Pci_dev *vp, unsigned dn, unsigned fn)
406 {
407   _bus.dev(dn)->fn(fn, vp);
408   Device::add_child(d);
409 }
410
411
412 Pci_bridge *
413 Pci_bridge::find_bridge(unsigned bus)
414 {
415   // printf("PCI[%p]: look for bridge for bus %x %02x %02x\n", this, bus, _subordinate, _secondary);
416   if (bus == _secondary)
417     return this;
418
419   if (bus < _secondary || bus > _subordinate)
420     return 0;
421
422   for (unsigned d = 0; d < Bus::Devs; ++d)
423     for (unsigned f = 0; f < Dev::Fns; ++f)
424       {
425         Pci_dev *p = _bus.dev(d)->fn(f);
426         if (!p)
427           break;
428
429         Pci_bridge *b = dynamic_cast<Pci_bridge*>(p);
430         if (b && (b = b->find_bridge(bus)))
431           return b;
432       }
433
434   return 0;
435 }
436
437
438 bool
439 Pci_bridge::child_dev(unsigned bus, unsigned char dev, unsigned char fn,
440                        Pci_dev **rd)
441 {
442   Pci_bridge *b = find_bridge(bus);
443   if (!b)
444     {
445       *rd = 0;
446       return true;
447     }
448
449   if (dev >= Bus::Devs || fn >= Dev::Fns)
450     {
451       *rd = 0;
452       return true;
453     }
454
455   *rd = b->_bus.dev(dev)->fn(fn);
456   return true;
457 }
458
459 void
460 Pci_bridge::setup_bus()
461 {
462   for (unsigned d = 0; d < Bus::Devs; ++d)
463     for (unsigned f = 0; f < Dev::Fns; ++f)
464       {
465         Pci_dev *p = _bus.dev(d)->fn(f);
466         if (!p)
467           break;
468
469         Pci_bridge *b = dynamic_cast<Pci_bridge*>(p);
470         if (b)
471           {
472             b->_primary = _secondary;
473             if (b->_secondary <= _secondary)
474               {
475                 b->_secondary = ++_subordinate;
476                 b->_subordinate = b->_secondary;
477               }
478
479             b->setup_bus();
480
481             if (_subordinate < b->_subordinate)
482               _subordinate = b->_subordinate;
483           }
484       }
485 }
486
487 void
488 Pci_bridge::finalize_setup()
489 {
490   for (unsigned dn = 0; dn < Bus::Devs; ++dn)
491     {
492       if (!_bus.dev(dn)->empty())
493         continue;
494
495       for (unsigned fn = 0; fn < Dev::Fns; ++fn)
496         if (_bus.dev(dn)->fn(fn))
497           {
498             Pci_dummy *dummy = new Pci_dummy();
499             _bus.dev(dn)->fn(0, dummy);
500             Device::add_child(dummy);
501             break;
502           }
503     }
504 #if 0
505   for (VDevice *c = dynamic_cast<VDevice*>(children()); c; c = c->next())
506     c->finalize_setup();
507 #endif
508 }
509
510 namespace {
511   static Feature_factory_t<Pci_proxy_dev, ::Pci_dev> __pci_f_factory1;
512   static Dev_factory_t<Pci_dummy> __pci_dummy_factory("PCI_dummy_device");
513 }
514
515 }
516