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 "virt/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 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() == 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::const_iterator i = host()->resources()->begin();
134 i != host()->resources()->end(); ++i)
138 if (!res->disabled() && res->type() == Resource::Irq_res)
140 irq->irq = res->start();
141 irq->trigger = !res->irq_is_level_triggered();
142 irq->polarity = res->irq_is_low_polarity();
143 d_printf(DBG_DEBUG, "Enable IRQ: %d %x %x\n", irq->irq, irq->trigger, irq->polarity);
144 if (dlevel(DBG_DEBUG2))
155 Pci_proxy_dev::read_bar(int bar)
157 // d_printf(DBG_ALL, " read bar[%x]: %08x\n", bar, _vbars[bar]);
162 Pci_proxy_dev::write_bar(int bar, l4_uint32_t v)
164 Hw::Pci::If *p = _hwf;
166 Resource *r = p->bar(bar);
170 // printf(" write bar[%x]: %llx-%llx...\n", bar, r->abs_start(), r->abs_end());
171 l4_uint64_t size_mask = r->alignment();
173 if (r->type() == Resource::Io_res)
174 size_mask |= 0xffff0000;
176 if (p->is_64bit_high_bar(bar))
179 _vbars[bar] = (_vbars[bar] & size_mask) | (v & ~size_mask);
181 // printf(" bar=%lx\n", _vbars[bar]);
185 Pci_proxy_dev::write_rom(l4_uint32_t v)
187 Hw::Pci::If *p = _hwf;
189 // printf("write rom bar %x %p\n", v, _dev->rom());
190 Resource *r = p->rom();
194 l4_uint64_t size_mask = r->alignment();
196 _rom = (_rom & size_mask) | (v & (~size_mask | 1));
198 p->cfg_write(0x30, (r->start() & ~1U) | (v & 1), Hw::Pci::Cfg_long);
202 Pci_proxy_dev::cfg_read(int reg, l4_uint32_t *v, Cfg_width order)
204 Hw::Pci::If *p = _hwf;
208 l4_uint32_t const *r = &buf;
210 int dw_reg = reg & ~3;
213 case 0x00: buf = p->vendor_device_ids(); break;
214 case 0x08: buf = p->class_rev(); break;
215 case 0x04: p->cfg_read(dw_reg, &buf); break;
216 /* simulate multi function on hdr type */
217 case 0x0c: p->cfg_read(dw_reg, &buf); buf |= 0x00800000; break;
218 case 0x10: /* bars 0 to 5 */
223 case 0x24: buf = read_bar((dw_reg - 0x10) / 4); break;
224 case 0x2c: buf = p->subsys_vendor_ids(); break;
225 case 0x30: buf = read_rom(); break;
226 case 0x34: /* CAPS */
227 case 0x38: buf = 0; break; /* PCI 3.0 reserved */
228 /* latency and IRQs */
229 case 0x3c: p->cfg_read(dw_reg, &buf); break;
230 /* pass trough the rest ... */
231 default: p->cfg_read(dw_reg, &buf); break;
234 unsigned mask = ~0U >> (32 - (8U << order));
235 *v = (*r >> ((reg & 3) *8)) & mask;
241 Pci_proxy_dev::_do_cmd_write(unsigned mask,unsigned value)
243 l4_uint16_t cmd = _hwf->cfg_read<l4_uint16_t>(Pci::Config::Command);
244 l4_uint16_t ncmd = cmd & ~mask; // get unmodified bits
245 ncmd |= value & mask; // set new bits
247 if (ncmd == cmd) // nothing modified so ignore the write
250 unsigned enable_decoders = _hwf->recheck_bars(ncmd & ~cmd & 3);
251 if ((ncmd & ~cmd & 3) && !enable_decoders)
253 d_printf(DBG_WARN, "warning: could not set bars, disable decoders\n");
254 ncmd &= (~3U | enable_decoders);
257 _hwf->cfg_write(Pci::Config::Command, ncmd);
261 Pci_proxy_dev::_do_status_cmd_write(l4_uint32_t mask, l4_uint32_t value)
264 _do_cmd_write(mask & 0xffff, value & 0xffff);
266 // status register has 'write 1 to clear' semantics so we can always write
267 // 16bit with the bits masked that we do not want to affect.
268 if (mask & value & 0xffff0000)
269 _hwf->cfg_write(Pci::Config::Status, (value & mask) >> 16, Hw::Pci::Cfg_short);
275 Pci_proxy_dev::_do_rom_bar_write(l4_uint32_t mask, l4_uint32_t value)
277 l4_uint32_t b = read_rom();
279 if ((value & mask & 1) && !(b & mask & 1) && !_hwf->enable_rom())
280 return 0; // failed to enable
290 Pci_proxy_dev::cfg_write(int reg, l4_uint32_t v, Cfg_width order)
292 Hw::Pci::If *p = _hwf;
295 l4_uint32_t const offset_32 = reg & 3;
296 l4_uint32_t const mask_32 = (~0U >> (32 - (8U << order))) << (offset_32 * 8);
297 l4_uint32_t const value_32 = v << (offset_32 * 8);
304 case 0x04: return _do_status_cmd_write(mask_32, value_32);
305 /* simulate multi function on hdr type */
306 case 0x10: /* bars 0 to 5 */
313 l4_uint32_t b = read_bar(reg / 4 - 4);
315 b |= value_32 & mask_32;
316 write_bar(reg / 4 - 4, b);
320 case 0x30: return _do_rom_bar_write(mask_32, value_32);
323 /* pass trough the rest ... */
324 default: return p->cfg_write(reg, v, order);
329 Pci_proxy_dev::dump() const
331 Hw::Pci::If *p = _hwf;
333 printf(" %04x:%02x:%02x.%x:\n",
334 0, p->bus_nr(), _hwf->device_nr(), _hwf->function_nr());
337 libpciids_name_device(buf, sizeof(buf), _dev->vendor(), _dev->device());
338 printf(" %s\n", buf);
343 // -----------------------------------------------------------------------
344 // Virtual PCI dummy device
345 // -----------------------------------------------------------------------
347 class Pci_dummy : public Pci_virtual_dev, public Device
350 unsigned char _cfg_space[4*4];
353 int irq_enable(Irq_info *irq)
363 _h_len = sizeof(_cfg_space);
364 cfg_hdr()->hdr_type = 0x80;
365 cfg_hdr()->vendor_device = 0x02000400;
366 cfg_hdr()->status = 0;
367 cfg_hdr()->class_rev = 0x36440000;
368 cfg_hdr()->cmd = 0x0;
371 bool match_hw_feature(const Hw::Dev_feature*) const { return false; }
372 int dispatch(l4_umword_t, l4_uint32_t, L4::Ipc::Iostream&)
373 { return -L4_ENOSYS; }
374 void set_host(Device *d) { _host = d; }
375 Device *host() const { return _host; }
382 // ----------------------------------------------------------------------
383 // Basic virtual PCI bridge functionality
384 // ----------------------------------------------------------------------
386 Pci_bridge::Dev::Dev()
388 memset(_fns, 0, sizeof(_fns));
392 Pci_bridge::Dev::add_fn(Pci_dev *f)
394 for (unsigned i = 0; i < sizeof(_fns)/sizeof(_fns[0]); ++i)
405 Pci_bridge::Dev::sort_fns()
407 // disabled sorting because the relation of two functions is questionable
410 for (n = 0; n < sizeof(_fns)/sizeof(_fns[0]) && _fns[n]; ++n)
421 for (unsigned i = 0; i < n - 1; ++i)
423 if (_fns[i]->dev()->function_nr() > _fns[i+1]->dev()->function_nr())
425 Pci_dev *t = _fns[i];
433 while (exchg && n >= 1);
438 Pci_bridge::Bus::add_fn(Pci_dev *pd, int slot)
442 _devs[slot].add_fn(pd);
443 _devs[slot].sort_fns();
447 for (unsigned d = 0; d < Devs && !_devs[d].empty(); ++d)
448 if (_devs[d].cmp(pd))
455 for (unsigned d = 0; d < Devs; ++d)
456 if (_devs[d].empty())
464 Pci_bridge::add_child(Device *d)
466 Pci_dev *vp = d->find_feature<Pci_dev>();
468 // hm, we do currently not add non PCI devices.
473 Device::add_child(d);
478 Pci_bridge::add_child_fixed(Device *d, Pci_dev *vp, unsigned dn, unsigned fn)
480 _bus.dev(dn)->fn(fn, vp);
481 Device::add_child(d);
486 Pci_bridge::find_bridge(unsigned bus)
488 // printf("PCI[%p]: look for bridge for bus %x %02x %02x\n", this, bus, _subordinate, _secondary);
489 if (bus == _secondary)
492 if (bus < _secondary || bus > _subordinate)
495 for (unsigned d = 0; d < Bus::Devs; ++d)
496 for (unsigned f = 0; f < Dev::Fns; ++f)
498 Pci_dev *p = _bus.dev(d)->fn(f);
502 Pci_bridge *b = dynamic_cast<Pci_bridge*>(p);
503 if (b && (b = b->find_bridge(bus)))
512 Pci_bridge::child_dev(unsigned bus, unsigned char dev, unsigned char fn,
515 Pci_bridge *b = find_bridge(bus);
522 if (dev >= Bus::Devs || fn >= Dev::Fns)
528 *rd = b->_bus.dev(dev)->fn(fn);
533 Pci_bridge::setup_bus()
535 for (unsigned d = 0; d < Bus::Devs; ++d)
536 for (unsigned f = 0; f < Dev::Fns; ++f)
538 Pci_dev *p = _bus.dev(d)->fn(f);
542 Pci_bridge *b = dynamic_cast<Pci_bridge*>(p);
545 b->_primary = _secondary;
546 if (b->_secondary <= _secondary)
548 b->_secondary = ++_subordinate;
549 b->_subordinate = b->_secondary;
554 if (_subordinate < b->_subordinate)
555 _subordinate = b->_subordinate;
561 Pci_bridge::finalize_setup()
563 for (unsigned dn = 0; dn < Bus::Devs; ++dn)
565 if (!_bus.dev(dn)->empty())
568 for (unsigned fn = 0; fn < Dev::Fns; ++fn)
569 if (_bus.dev(dn)->fn(fn))
571 Pci_dummy *dummy = new Pci_dummy();
572 _bus.dev(dn)->fn(0, dummy);
573 Device::add_child(dummy);
578 for (VDevice *c = dynamic_cast<VDevice*>(children()); c; c = c->next())
584 static Feature_factory_t<Pci_proxy_dev, Hw::Pci::Dev> __pci_f_factory1;
585 static Dev_factory_t<Pci_dummy> __pci_dummy_factory("PCI_dummy_device");