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>
23 #include "vbus_factory.h"
27 // -----------------------------------------------------------------------
29 // -----------------------------------------------------------------------
31 Pci_virtual_dev::Pci_virtual_dev()
33 memset(&_h, 0, sizeof(_h));
37 Pci_virtual_dev::cfg_read(int reg, l4_uint32_t *v, Cfg_width order)
40 if ((unsigned)reg >= (_h_len >> order))
43 #define RC(x) *v = *((Hw::Pci::Cfg_type<x>::Type const *)_h + reg); break
47 case Hw::Pci::Cfg_byte: RC(Hw::Pci::Cfg_byte);
48 case Hw::Pci::Cfg_short: RC(Hw::Pci::Cfg_short);
49 case Hw::Pci::Cfg_long: RC(Hw::Pci::Cfg_long);
57 Pci_virtual_dev::cfg_write(int reg, l4_uint32_t v, Cfg_width order)
61 case 0x4: // status is RO
62 v &= 0x0000ffff << (reg & (3 >> order));
70 if ((unsigned)reg >= (_h_len >> order))
73 #define RC(x) *((Hw::Pci::Cfg_type<x>::Type *)_h + reg) = v; break
76 case Hw::Pci::Cfg_byte: RC(Hw::Pci::Cfg_byte);
77 case Hw::Pci::Cfg_short: RC(Hw::Pci::Cfg_short);
78 case Hw::Pci::Cfg_long: RC(Hw::Pci::Cfg_long);
87 // -----------------------------------------------------------------------
89 // -----------------------------------------------------------------------
91 Pci_proxy_dev::Pci_proxy_dev(Hw::Pci::If *hwf)
95 for (int i = 0; i < 6; ++i)
97 Adr_resource *r = _hwf->bar(i);
105 if (_hwf->is_64bit_high_bar(i))
107 _vbars[i] = l4_uint64_t(r->start()) >> 32;
111 _vbars[i] = r->start();
112 if (r->type() == Adr_resource::Io_res)
118 if (r->prefetchable())
123 //printf(" bar: %d = %08x\n", i, _vbars[i]);
127 _rom = _hwf->rom()->start();
131 Pci_proxy_dev::irq_enable(Irq_info *irq)
133 for (Resource_list::iterator i = host()->resources()->begin();
134 i != host()->resources()->end(); ++i)
136 Adr_resource *res = dynamic_cast<Adr_resource*>(*i);
140 if (res->type() == Adr_resource::Irq_res)
142 irq->irq = res->start();
143 irq->trigger = !(res->flags() & Resource::Irq_info_base);
144 irq->polarity = !!(res->flags() & (Resource::Irq_info_base * 2));
145 d_printf(DBG_DEBUG, "Enable IRQ: %d %x %x\n", irq->irq, irq->trigger, irq->polarity);
146 if (dlevel(DBG_DEBUG2))
157 Pci_proxy_dev::read_bar(int bar)
159 // d_printf(DBG_ALL, " read bar[%x]: %08x\n", bar, _vbars[bar]);
164 Pci_proxy_dev::write_bar(int bar, l4_uint32_t v)
166 Hw::Pci::If *p = _hwf;
168 Adr_resource *r = p->bar(bar);
172 // printf(" write bar[%x]: %llx-%llx...\n", bar, r->abs_start(), r->abs_end());
173 l4_uint64_t size_mask = r->alignment();
175 if (r->type() == Adr_resource::Io_res)
176 size_mask |= 0xffff0000;
178 if (p->is_64bit_high_bar(bar))
181 _vbars[bar] = (_vbars[bar] & size_mask) | (v & ~size_mask);
183 // printf(" bar=%lx\n", _vbars[bar]);
187 Pci_proxy_dev::write_rom(l4_uint32_t v)
189 Hw::Pci::If *p = _hwf;
191 // printf("write rom bar %x %p\n", v, _dev->rom());
192 Adr_resource *r = p->rom();
196 l4_uint64_t size_mask = r->alignment();
198 _rom = (_rom & size_mask) | (v & (~size_mask | 1));
200 p->cfg_write(0x30, (r->start() & ~1U) | (v & 1), Hw::Pci::Cfg_long);
204 Pci_proxy_dev::cfg_read(int reg, l4_uint32_t *v, Cfg_width order)
206 Hw::Pci::If *p = _hwf;
209 l4_uint32_t const *r = &buf;
214 case 0: case 2: case 11:
215 r = p->cfg_word(dw); break;
216 case 1: return p->cfg_read(reg, v, order);
217 case 3: //buf = l4_uint32_t(_dev->hdr_type) << 16; break;
218 p->cfg_read(dw * 4, &buf, Hw::Pci::Cfg_long);
221 case 4: case 5: case 6: case 7: case 8: case 9:
222 buf = read_bar(dw-4); break;
223 case 12: buf = read_rom(); break;
224 default: return p->cfg_read(reg, v, order); //buf = 0; break;
227 unsigned mask = ~0U >> (32 - (1U << (order + 3)));
228 *v = (*r >> ((reg & 3) *8)) & mask;
233 Pci_proxy_dev::cfg_write(int reg, l4_uint32_t v, Cfg_width order)
235 Hw::Pci::If *p = _hwf;
241 case 4: case 5: case 6: case 7: case 8: case 9: case 12: break;
242 default: return p->cfg_write(reg, v, order);
247 cfg_read(reg, &old, Hw::Pci::Cfg_long);
249 l4_uint32_t mask = ~0U >> (32 - (1U << (order + 3)));
250 l4_uint32_t sh = (reg & 3) * 8;
251 old &= ~(mask << sh);
252 old |= (v & mask) << sh;
256 case 4: case 5: case 6: case 7: case 8: case 9:
257 write_bar(dw-4, old); break;
258 case 12: write_rom(old); break;
265 Pci_proxy_dev::dump() const
267 Hw::Pci::If *p = _hwf;
269 printf(" %04x:%02x:%02x.%x:\n",
270 0, p->bus_nr(), _hwf->host()->adr() >> 16, _hwf->host()->adr() & 0xffff);
273 libpciids_name_device(buf, sizeof(buf), _dev->vendor(), _dev->device());
274 printf(" %s\n", buf);
279 // -----------------------------------------------------------------------
280 // Virtual PCI dummy device
281 // -----------------------------------------------------------------------
283 class Pci_dummy : public Pci_virtual_dev, public Device
286 unsigned char _cfg_space[4*4];
289 int irq_enable(Irq_info *irq)
299 _h_len = sizeof(_cfg_space);
300 cfg_hdr()->hdr_type = 0x80;
301 cfg_hdr()->vendor_device = 0x02000400;
302 cfg_hdr()->status = 0;
303 cfg_hdr()->class_rev = 0x36440000;
304 cfg_hdr()->cmd = 0x0;
307 bool match_hw_feature(const Hw::Dev_feature*) const { return false; }
308 int dispatch(l4_umword_t, l4_uint32_t, L4::Ipc_iostream&)
309 { return -L4_ENOSYS; }
310 void set_host(Device *d) { _host = d; }
311 Device *host() const { return _host; }
318 // ----------------------------------------------------------------------
319 // Basic virtual PCI bridge functionality
320 // ----------------------------------------------------------------------
322 Pci_bridge::Dev::Dev()
324 memset(_fns, 0, sizeof(_fns));
328 Pci_bridge::Dev::add_fn(Pci_dev *f)
330 for (unsigned i = 0; i < sizeof(_fns)/sizeof(_fns[0]); ++i)
341 Pci_bridge::Dev::sort_fns()
343 // disabled sorting because the relation of two functions is questionable
346 for (n = 0; n < sizeof(_fns)/sizeof(_fns[0]) && _fns[n]; ++n)
357 for (unsigned i = 0; i < n - 1; ++i)
359 if (_fns[i]->dev()->function_nr() > _fns[i+1]->dev()->function_nr())
361 Pci_dev *t = _fns[i];
369 while (exchg && n >= 1);
374 Pci_bridge::Bus::add_fn(Pci_dev *pd, int slot)
378 _devs[slot].add_fn(pd);
379 _devs[slot].sort_fns();
383 for (unsigned d = 0; d < Devs && !_devs[d].empty(); ++d)
384 if (_devs[d].cmp(pd))
391 for (unsigned d = 0; d < Devs; ++d)
392 if (_devs[d].empty())
400 Pci_bridge::add_child(Device *d)
402 Pci_dev *vp = d->find_feature<Pci_dev>();
404 // hm, we do currently not add non PCI devices.
409 Device::add_child(d);
414 Pci_bridge::add_child_fixed(Device *d, Pci_dev *vp, unsigned dn, unsigned fn)
416 _bus.dev(dn)->fn(fn, vp);
417 Device::add_child(d);
422 Pci_bridge::find_bridge(unsigned bus)
424 // printf("PCI[%p]: look for bridge for bus %x %02x %02x\n", this, bus, _subordinate, _secondary);
425 if (bus == _secondary)
428 if (bus < _secondary || bus > _subordinate)
431 for (unsigned d = 0; d < Bus::Devs; ++d)
432 for (unsigned f = 0; f < Dev::Fns; ++f)
434 Pci_dev *p = _bus.dev(d)->fn(f);
438 Pci_bridge *b = dynamic_cast<Pci_bridge*>(p);
439 if (b && (b = b->find_bridge(bus)))
448 Pci_bridge::child_dev(unsigned bus, unsigned char dev, unsigned char fn,
451 Pci_bridge *b = find_bridge(bus);
458 if (dev >= Bus::Devs || fn >= Dev::Fns)
464 *rd = b->_bus.dev(dev)->fn(fn);
469 Pci_bridge::setup_bus()
471 for (unsigned d = 0; d < Bus::Devs; ++d)
472 for (unsigned f = 0; f < Dev::Fns; ++f)
474 Pci_dev *p = _bus.dev(d)->fn(f);
478 Pci_bridge *b = dynamic_cast<Pci_bridge*>(p);
481 b->_primary = _secondary;
482 if (b->_secondary <= _secondary)
484 b->_secondary = ++_subordinate;
485 b->_subordinate = b->_secondary;
490 if (_subordinate < b->_subordinate)
491 _subordinate = b->_subordinate;
497 Pci_bridge::finalize_setup()
499 for (unsigned dn = 0; dn < Bus::Devs; ++dn)
501 if (!_bus.dev(dn)->empty())
504 for (unsigned fn = 0; fn < Dev::Fns; ++fn)
505 if (_bus.dev(dn)->fn(fn))
507 Pci_dummy *dummy = new Pci_dummy();
508 _bus.dev(dn)->fn(0, dummy);
509 Device::add_child(dummy);
514 for (VDevice *c = dynamic_cast<VDevice*>(children()); c; c = c->next())
520 static Feature_factory_t<Pci_proxy_dev, ::Pci_dev> __pci_f_factory1;
521 static Dev_factory_t<Pci_dummy> __pci_dummy_factory("PCI_dummy_device");