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>
12 #include <l4/vbus/vbus_pci-ops.h>
17 #include <l4/cxx/exceptions>
18 #include <l4/io/pciids.h>
19 #include <l4/sys/err.h>
24 #include "virt/vbus_factory.h"
28 // -----------------------------------------------------------------------
30 // -----------------------------------------------------------------------
32 Pci_virtual_dev::Pci_virtual_dev()
34 memset(&_h, 0, sizeof(_h));
38 Pci_virtual_dev::cfg_read(int reg, l4_uint32_t *v, Cfg_width order)
41 if ((unsigned)reg >= (_h_len >> order))
44 #define RC(x) *v = *((Hw::Pci::Cfg_type<x>::Type const *)_h + reg); break
48 case Hw::Pci::Cfg_byte: RC(Hw::Pci::Cfg_byte);
49 case Hw::Pci::Cfg_short: RC(Hw::Pci::Cfg_short);
50 case Hw::Pci::Cfg_long: RC(Hw::Pci::Cfg_long);
58 Pci_virtual_dev::cfg_write(int reg, l4_uint32_t v, Cfg_width order)
62 case 0x4: // status is RO
63 v &= 0x0000ffff << (reg & (3 >> order));
71 if ((unsigned)reg >= (_h_len >> order))
74 #define RC(x) *((Hw::Pci::Cfg_type<x>::Type *)_h + reg) = v; break
77 case Hw::Pci::Cfg_byte: RC(Hw::Pci::Cfg_byte);
78 case Hw::Pci::Cfg_short: RC(Hw::Pci::Cfg_short);
79 case Hw::Pci::Cfg_long: RC(Hw::Pci::Cfg_long);
86 // -----------------------------------------------------------------------
88 // -----------------------------------------------------------------------
93 Pci_dev_feature::dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc::Iostream& ios)
95 if (l4vbus_subinterface(func) != L4VBUS_INTERFACE_PCIDEV)
99 l4_uint32_t value = 0;
101 Pci_dev::Irq_info info;
106 case L4vbus_pcidev_cfg_read:
108 res = cfg_read(reg, &value, Hw::Pci::cfg_w_to_o(width));
113 case L4vbus_pcidev_cfg_write:
114 ios >> reg >> value >> width;
115 return cfg_write(reg, value, Hw::Pci::cfg_w_to_o(width));
116 case L4vbus_pcidev_cfg_irq_enable:
117 res = irq_enable(&info);
120 ios << info.irq << info.trigger << info.polarity;
122 default: return -L4_ENOSYS;
129 // -----------------------------------------------------------------------
131 // -----------------------------------------------------------------------
134 Pci_proxy_dev::scan_pci_caps()
137 _hwf->cfg_read(Hw::Pci::Config::Capability_ptr, &pci_cap);
138 bool is_pci_express = false;
142 _hwf->cfg_read(pci_cap, &cap);
145 case Hw::Pci::Cap::Pcie:
146 is_pci_express = true;
148 case Hw::Pci::Cap::Pcix:
149 case Hw::Pci::Cap::Msi:
150 case Hw::Pci::Cap::Msi_x:
151 case Hw::Pci::Cap::Vndr:
153 add_pci_cap(new Pci_proxy_cap(_hwf, pci_cap));
159 return is_pci_express;
163 Pci_proxy_dev::scan_pcie_caps()
165 l4_uint16_t offset = 0x100;
169 _hwf->cfg_read(offset, &c);
170 if (offset == 0x100 && ((c & 0xffff) == 0xffff))
173 add_pcie_cap(new Pcie_proxy_cap(_hwf, c, offset, offset));
180 assert (!_pcie_caps || _pcie_caps->offset() == 0x100);
182 if (_pcie_caps && _pcie_caps->offset() != 0x100)
183 _pcie_caps->set_offset(0x100);
187 Pci_proxy_dev::Pci_proxy_dev(Hw::Pci::If *hwf)
191 for (int i = 0; i < 6; ++i)
193 Resource *r = _hwf->bar(i);
201 if (_hwf->is_64bit_high_bar(i))
203 _vbars[i] = l4_uint64_t(r->start()) >> 32;
207 _vbars[i] = r->start();
208 if (r->type() == Resource::Io_res)
214 if (r->prefetchable())
219 //printf(" bar: %d = %08x\n", i, _vbars[i]);
223 _rom = _hwf->rom()->start();
230 Pci_proxy_dev::irq_enable(Irq_info *irq)
232 for (Resource_list::const_iterator i = host()->resources()->begin();
233 i != host()->resources()->end(); ++i)
237 if (!res->disabled() && res->type() == Resource::Irq_res)
239 irq->irq = res->start();
240 irq->trigger = !res->irq_is_level_triggered();
241 irq->polarity = res->irq_is_low_polarity();
242 d_printf(DBG_DEBUG, "Enable IRQ: irq=%d trg=%x pol=%x\n",
243 irq->irq, irq->trigger, irq->polarity);
244 if (dlevel(DBG_DEBUG2))
255 Pci_proxy_dev::read_bar(int bar)
257 // d_printf(DBG_ALL, " read bar[%x]: %08x\n", bar, _vbars[bar]);
262 Pci_proxy_dev::write_bar(int bar, l4_uint32_t v)
264 Hw::Pci::If *p = _hwf;
266 Resource *r = p->bar(bar);
270 // printf(" write bar[%x]: %llx-%llx...\n", bar, r->abs_start(), r->abs_end());
271 l4_uint64_t size_mask = r->alignment();
273 if (r->type() == Resource::Io_res)
274 size_mask |= 0xffff0000;
276 if (p->is_64bit_high_bar(bar))
279 _vbars[bar] = (_vbars[bar] & size_mask) | (v & ~size_mask);
281 // printf(" bar=%lx\n", _vbars[bar]);
285 Pci_proxy_dev::write_rom(l4_uint32_t v)
287 Hw::Pci::If *p = _hwf;
289 // printf("write rom bar %x %p\n", v, _dev->rom());
290 Resource *r = p->rom();
294 l4_uint64_t size_mask = r->alignment();
296 _rom = (_rom & size_mask) | (v & (~size_mask | 1));
298 p->cfg_write(0x30, (r->start() & ~1U) | (v & 1), Hw::Pci::Cfg_long);
302 Pci_proxy_dev::find_pci_cap(unsigned offset) const
304 if (!_pci_caps || offset < 0x3c)
307 for (Pci_capability *c = _pci_caps; c; c = c->next())
308 if (c->is_inside(offset))
315 Pci_proxy_dev::add_pci_cap(Pci_capability *c)
318 for (i = &_pci_caps; *i; i = &(*i)->next())
319 if ((*i)->offset() > c->offset())
327 Pci_proxy_dev::find_pcie_cap(unsigned offset) const
329 if (!_pcie_caps || offset < 0x100)
332 for (Pcie_capability *c = _pcie_caps; c; c = c->next())
333 if (c->is_inside(offset))
340 Pci_proxy_dev::add_pcie_cap(Pcie_capability *c)
343 for (i = &_pcie_caps; *i; i = &(*i)->next())
344 if ((*i)->offset() > c->offset())
352 Pci_proxy_dev::cfg_read(int reg, l4_uint32_t *v, Cfg_width order)
354 Hw::Pci::If *p = _hwf;
358 l4_uint32_t const *r = &buf;
360 int dw_reg = reg & ~3;
362 if (Pci_capability *cap = find_pci_cap(dw_reg))
363 return cap->cfg_read(reg, v, order);
365 if (Pcie_capability *cap = find_pcie_cap(dw_reg))
366 return cap->cfg_read(reg, v, order);
370 case 0x00: buf = p->vendor_device_ids(); break;
371 case 0x08: buf = p->class_rev(); break;
372 case 0x04: buf = p->checked_cmd_read(); break;
373 /* simulate multi function on hdr type */
374 case 0x0c: p->cfg_read(dw_reg, &buf); buf |= 0x00800000; break;
375 case 0x10: /* bars 0 to 5 */
380 case 0x24: buf = read_bar((dw_reg - 0x10) / 4); break;
381 case 0x2c: buf = p->subsys_vendor_ids(); break;
382 case 0x30: buf = read_rom(); break;
383 case 0x34: /* CAPS */
385 buf = _pci_caps->offset();
389 case 0x38: buf = 0; break; /* PCI 3.0 reserved */
391 case 0x100: /* empty PCIe cap */
393 default: if (0) printf("pass unknown PCI cfg read for device %s: %x\n",
394 host()->name(), reg);
398 /* pass trough the rest ... */
399 p->cfg_read(dw_reg, &buf);
403 unsigned mask = ~0U >> (32 - (8U << order));
404 *v = (*r >> ((reg & 3) *8)) & mask;
410 Pci_proxy_dev::_do_cmd_write(unsigned mask,unsigned value)
412 _hwf->checked_cmd_write(mask, value);
416 Pci_proxy_dev::_do_status_cmd_write(l4_uint32_t mask, l4_uint32_t value)
419 _do_cmd_write(mask & 0xffff, value & 0xffff);
421 // status register has 'write 1 to clear' semantics so we can always write
422 // 16bit with the bits masked that we do not want to affect.
423 if (mask & value & 0xffff0000)
424 _hwf->cfg_write(Pci::Config::Status, (value & mask) >> 16, Hw::Pci::Cfg_short);
430 Pci_proxy_dev::_do_rom_bar_write(l4_uint32_t mask, l4_uint32_t value)
432 l4_uint32_t b = read_rom();
434 if ((value & mask & 1) && !(b & mask & 1) && !_hwf->enable_rom())
435 return 0; // failed to enable
445 Pci_proxy_dev::cfg_write(int reg, l4_uint32_t v, Cfg_width order)
447 Hw::Pci::If *p = _hwf;
450 l4_uint32_t const offset_32 = reg & 3;
451 l4_uint32_t const mask_32 = (~0U >> (32 - (8U << order))) << (offset_32 * 8);
452 l4_uint32_t const value_32 = v << (offset_32 * 8);
454 if (Pci_capability *cap = find_pci_cap(reg & ~3))
455 return cap->cfg_write(reg, v, order);
457 if (Pcie_capability *cap = find_pcie_cap(reg & ~3))
458 return cap->cfg_write(reg, v, order);
464 case 0x04: return _do_status_cmd_write(mask_32, value_32);
465 /* simulate multi function on hdr type */
466 case 0x10: /* bars 0 to 5 */
473 l4_uint32_t b = read_bar(reg / 4 - 4);
475 b |= value_32 & mask_32;
476 write_bar(reg / 4 - 4, b);
479 case Hw::Pci::Config::Subsys_vendor: return 0;
480 case Hw::Pci::Config::Rom_address: return _do_rom_bar_write(mask_32, value_32);
481 case Hw::Pci::Config::Capability_ptr: return 0;
483 /* pass trough the rest ... */
484 default: if (0) printf("pass unknown PCI cfg write for device %s: %x\n",
485 host()->name(), reg);
489 case 0x3c: return p->cfg_write(reg, v, order);
494 Pci_proxy_dev::dump() const
496 Hw::Pci::If *p = _hwf;
498 printf(" %04x:%02x:%02x.%x:\n",
499 0, p->bus_nr(), _hwf->device_nr(), _hwf->function_nr());
502 libpciids_name_device(buf, sizeof(buf), _dev->vendor(), _dev->device());
503 printf(" %s\n", buf);
508 Pci_proxy_dev::msi_src() const
511 return hwf()->get_msi_src();
514 // -----------------------------------------------------------------------
515 // Virtual PCI dummy device
516 // -----------------------------------------------------------------------
518 class Pci_dummy : public Pci_virtual_dev, public Device
521 unsigned char _cfg_space[4*4];
524 int irq_enable(Irq_info *irq)
534 _h_len = sizeof(_cfg_space);
535 cfg_hdr()->hdr_type = 0x80;
536 cfg_hdr()->vendor_device = 0x02000400;
537 cfg_hdr()->status = 0;
538 cfg_hdr()->class_rev = 0x36440000;
539 cfg_hdr()->cmd = 0x0;
542 bool match_hw_feature(const Hw::Dev_feature*) const { return false; }
543 void set_host(Device *d) { _host = d; }
544 Device *host() const { return _host; }
551 // ----------------------------------------------------------------------
552 // Basic virtual PCI bridge functionality
553 // ----------------------------------------------------------------------
555 Pci_bridge::Dev::Dev()
557 memset(_fns, 0, sizeof(_fns));
561 Pci_bridge::Dev::add_fn(Pci_dev *f)
563 for (unsigned i = 0; i < sizeof(_fns)/sizeof(_fns[0]); ++i)
574 Pci_bridge::Dev::sort_fns()
576 // disabled sorting because the relation of two functions is questionable
579 for (n = 0; n < sizeof(_fns)/sizeof(_fns[0]) && _fns[n]; ++n)
590 for (unsigned i = 0; i < n - 1; ++i)
592 if (_fns[i]->dev()->function_nr() > _fns[i+1]->dev()->function_nr())
594 Pci_dev *t = _fns[i];
602 while (exchg && n >= 1);
607 Pci_bridge::Bus::add_fn(Pci_dev *pd, int slot)
611 _devs[slot].add_fn(pd);
612 _devs[slot].sort_fns();
616 for (unsigned d = 0; d < Devs && !_devs[d].empty(); ++d)
617 if (_devs[d].cmp(pd))
624 for (unsigned d = 0; d < Devs; ++d)
625 if (_devs[d].empty())
633 Pci_bridge::add_child(Device *d)
635 Pci_dev *vp = d->find_feature<Pci_dev>();
637 // hm, we do currently not add non PCI devices.
642 Device::add_child(d);
647 Pci_bridge::add_child_fixed(Device *d, Pci_dev *vp, unsigned dn, unsigned fn)
649 _bus.dev(dn)->fn(fn, vp);
650 Device::add_child(d);
655 Pci_bridge::find_bridge(unsigned bus)
657 // printf("PCI[%p]: look for bridge for bus %x %02x %02x\n", this, bus, _subordinate, _secondary);
658 if (bus == _secondary)
661 if (bus < _secondary || bus > _subordinate)
664 for (unsigned d = 0; d < Bus::Devs; ++d)
665 for (unsigned f = 0; f < Dev::Fns; ++f)
667 Pci_dev *p = _bus.dev(d)->fn(f);
671 Pci_bridge *b = dynamic_cast<Pci_bridge*>(p);
672 if (b && (b = b->find_bridge(bus)))
681 Pci_bridge::child_dev(unsigned bus, unsigned char dev, unsigned char fn)
683 Pci_bridge *b = find_bridge(bus);
687 if (dev >= Bus::Devs || fn >= Dev::Fns)
690 return b->_bus.dev(dev)->fn(fn);
694 Pci_bridge::setup_bus()
696 for (unsigned d = 0; d < Bus::Devs; ++d)
697 for (unsigned f = 0; f < Dev::Fns; ++f)
699 Pci_dev *p = _bus.dev(d)->fn(f);
703 Pci_bridge *b = dynamic_cast<Pci_bridge*>(p);
706 b->_primary = _secondary;
707 if (b->_secondary <= _secondary)
709 b->_secondary = ++_subordinate;
710 b->_subordinate = b->_secondary;
715 if (_subordinate < b->_subordinate)
716 _subordinate = b->_subordinate;
722 Pci_bridge::finalize_setup()
724 for (unsigned dn = 0; dn < Bus::Devs; ++dn)
726 if (!_bus.dev(dn)->empty())
729 for (unsigned fn = 0; fn < Dev::Fns; ++fn)
730 if (_bus.dev(dn)->fn(fn))
732 Pci_dummy *dummy = new Pci_dummy();
733 _bus.dev(dn)->fn(0, dummy);
734 Device::add_child(dummy);
739 for (VDevice *c = dynamic_cast<VDevice*>(children()); c; c = c->next())
745 static Feature_factory_t<Pci_proxy_dev, Hw::Pci::Dev> __pci_f_factory1;
746 static Dev_factory_t<Pci_dummy> __pci_dummy_factory("PCI_dummy_device");