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)
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.
11 #include <l4/vbus/vdevice-ops.h>
16 #include <l4/cxx/exceptions>
17 #include <l4/io/pciids.h>
18 #include <l4/sys/err.h>
22 #include "vbus_factory.h"
26 // -----------------------------------------------------------------------
28 // -----------------------------------------------------------------------
30 Pci_virtual_dev::Pci_virtual_dev()
32 memset(&_h, 0, sizeof(_h));
36 Pci_virtual_dev::cfg_read(int reg, l4_uint32_t *v, Cfg_width order)
39 if ((unsigned)reg >= (_h_len >> order))
42 #define RC(x) *v = *((Hw::Pci::Cfg_type<x>::Type const *)_h + reg); break
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);
56 Pci_virtual_dev::cfg_write(int reg, l4_uint32_t v, Cfg_width order)
60 case 0x4: // status is RO
61 v &= 0x0000ffff << (reg & (3 >> order));
69 if ((unsigned)reg >= (_h_len >> order))
72 #define RC(x) *((Hw::Pci::Cfg_type<x>::Type *)_h + reg) = v; break
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);
86 // -----------------------------------------------------------------------
88 // -----------------------------------------------------------------------
90 Pci_proxy_dev::Pci_proxy_dev(Hw::Pci::If *hwf)
94 for (int i = 0; i < 6; ++i)
96 Adr_resource *r = _hwf->bar(i);
104 if (_hwf->is_64bit_high_bar(i))
106 _vbars[i] = l4_uint64_t(r->start()) >> 32;
110 _vbars[i] = r->start();
111 if (r->type() == Adr_resource::Io_res)
117 if (r->prefetchable())
122 //printf(" bar: %d = %08x\n", i, _vbars[i]);
126 _rom = _hwf->rom()->start();
130 Pci_proxy_dev::irq_enable(Irq_info *irq)
132 for (Resource_list::iterator i = hwf()->host()->resources()->begin();
133 i != hwf()->host()->resources()->end(); ++i)
135 Adr_resource *res = dynamic_cast<Adr_resource*>(*i);
139 if (res->type() == Adr_resource::Irq_res /* && (res->start() & 0x80) */)
141 irq->irq = res->start();
142 irq->trigger = !(res->flags() & Resource::Irq_info_base);
143 irq->polarity = !!(res->flags() & (Resource::Irq_info_base * 2));
153 Pci_proxy_dev::read_bar(int bar)
155 //printf(" read bar[%x]: %08x\n", bar, _vbars[bar]);
160 Pci_proxy_dev::write_bar(int bar, l4_uint32_t v)
162 Hw::Pci::If *p = _hwf;
164 Adr_resource *r = p->bar(bar);
168 // printf(" write bar[%x]: %llx-%llx...\n", bar, r->abs_start(), r->abs_end());
169 l4_uint64_t size_mask = r->alignment();
171 if (r->type() == Adr_resource::Io_res)
172 size_mask |= 0xffff0000;
174 if (p->is_64bit_high_bar(bar))
177 _vbars[bar] = (_vbars[bar] & size_mask) | (v & ~size_mask);
179 // printf(" bar=%lx\n", _vbars[bar]);
183 Pci_proxy_dev::write_rom(l4_uint32_t v)
185 Hw::Pci::If *p = _hwf;
187 // printf("write rom bar %x %p\n", v, _dev->rom());
188 Adr_resource *r = p->rom();
192 l4_uint64_t size_mask = r->alignment();
194 _rom = (_rom & size_mask) | (v & (~size_mask | 1));
196 p->cfg_write(0x30, (r->start() & ~1U) | (v & 1), Hw::Pci::Cfg_long);
200 Pci_proxy_dev::cfg_read(int reg, l4_uint32_t *v, Cfg_width order)
202 Hw::Pci::If *p = _hwf;
205 l4_uint32_t const *r = &buf;
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);
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;
223 unsigned mask = ~0U >> (32 - (1U << (order + 3)));
224 *v = (*r >> ((reg & 3) *8)) & mask;
229 Pci_proxy_dev::cfg_write(int reg, l4_uint32_t v, Cfg_width order)
231 Hw::Pci::If *p = _hwf;
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);
243 cfg_read(reg, &old, Hw::Pci::Cfg_long);
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;
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;
261 Pci_proxy_dev::dump() const
263 Hw::Pci::If *p = _hwf;
265 printf(" %04x:%02x:%02x.%x:\n",
266 0, p->bus_nr(), _hwf->host()->adr() >> 16, _hwf->host()->adr() & 0xffff);
269 libpciids_name_device(buf, sizeof(buf), _dev->vendor(), _dev->device());
270 printf(" %s\n", buf);
275 // -----------------------------------------------------------------------
276 // Virtual PCI dummy device
277 // -----------------------------------------------------------------------
279 class Pci_dummy : public Pci_virtual_dev, public Device
282 unsigned char _cfg_space[4*4];
285 int irq_enable(Irq_info *irq)
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;
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; }
309 // ----------------------------------------------------------------------
310 // Basic virtual PCI bridge functionality
311 // ----------------------------------------------------------------------
313 Pci_bridge::Dev::Dev()
315 memset(_fns, 0, sizeof(_fns));
319 Pci_bridge::Dev::add_fn(Pci_dev *f)
321 for (unsigned i = 0; i < sizeof(_fns)/sizeof(_fns[0]); ++i)
332 Pci_bridge::Dev::sort_fns()
334 // disabled sorting because the relation of two functions is questionable
337 for (n = 0; n < sizeof(_fns)/sizeof(_fns[0]) && _fns[n]; ++n)
348 for (unsigned i = 0; i < n - 1; ++i)
350 if (_fns[i]->dev()->function_nr() > _fns[i+1]->dev()->function_nr())
352 Pci_dev *t = _fns[i];
360 while (exchg && n >= 1);
365 Pci_bridge::Bus::add_fn(Pci_dev *pd, int slot)
369 _devs[slot].add_fn(pd);
370 _devs[slot].sort_fns();
374 for (unsigned d = 0; d < Devs && !_devs[d].empty(); ++d)
375 if (_devs[d].cmp(pd))
382 for (unsigned d = 0; d < Devs; ++d)
383 if (_devs[d].empty())
391 Pci_bridge::add_child(Device *d)
393 Pci_dev *vp = d->find_feature<Pci_dev>();
395 // hm, we do currently not add non PCI devices.
400 Device::add_child(d);
405 Pci_bridge::add_child_fixed(Device *d, Pci_dev *vp, unsigned dn, unsigned fn)
407 _bus.dev(dn)->fn(fn, vp);
408 Device::add_child(d);
413 Pci_bridge::find_bridge(unsigned bus)
415 // printf("PCI[%p]: look for bridge for bus %x %02x %02x\n", this, bus, _subordinate, _secondary);
416 if (bus == _secondary)
419 if (bus < _secondary || bus > _subordinate)
422 for (unsigned d = 0; d < Bus::Devs; ++d)
423 for (unsigned f = 0; f < Dev::Fns; ++f)
425 Pci_dev *p = _bus.dev(d)->fn(f);
429 Pci_bridge *b = dynamic_cast<Pci_bridge*>(p);
430 if (b && (b = b->find_bridge(bus)))
439 Pci_bridge::child_dev(unsigned bus, unsigned char dev, unsigned char fn,
442 Pci_bridge *b = find_bridge(bus);
449 if (dev >= Bus::Devs || fn >= Dev::Fns)
455 *rd = b->_bus.dev(dev)->fn(fn);
460 Pci_bridge::setup_bus()
462 for (unsigned d = 0; d < Bus::Devs; ++d)
463 for (unsigned f = 0; f < Dev::Fns; ++f)
465 Pci_dev *p = _bus.dev(d)->fn(f);
469 Pci_bridge *b = dynamic_cast<Pci_bridge*>(p);
472 b->_primary = _secondary;
473 if (b->_secondary <= _secondary)
475 b->_secondary = ++_subordinate;
476 b->_subordinate = b->_secondary;
481 if (_subordinate < b->_subordinate)
482 _subordinate = b->_subordinate;
488 Pci_bridge::finalize_setup()
490 for (unsigned dn = 0; dn < Bus::Devs; ++dn)
492 if (!_bus.dev(dn)->empty())
495 for (unsigned fn = 0; fn < Dev::Fns; ++fn)
496 if (_bus.dev(dn)->fn(fn))
498 Pci_dummy *dummy = new Pci_dummy();
499 _bus.dev(dn)->fn(0, dummy);
500 Device::add_child(dummy);
505 for (VDevice *c = dynamic_cast<VDevice*>(children()); c; c = c->next())
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");