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 "hw_device.h"
19 pci_conf_addr0(l4_uint32_t bus, l4_uint32_t dev,
20 l4_uint32_t fn, l4_uint32_t reg)
21 { return (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3); }
23 class Pci_iomem_root_bridge : public Hw::Pci::Root_bridge, public Hw::Device
26 typedef Hw::Pci::Cfg_width Cfg_width;
27 typedef Hw::Pci::Cfg_addr Cfg_addr;
29 explicit Pci_iomem_root_bridge(unsigned bus_nr = 0)
30 : Hw::Pci::Root_bridge(bus_nr, this), _iobase_virt(0), _iobase_phys(~0UL),
31 _dev_start(~0UL), _dev_end(~0UL), _iosize(0)
34 int cfg_read(Cfg_addr addr, l4_uint32_t *value, Cfg_width);
35 int cfg_write(Cfg_addr addr, l4_uint32_t value, Cfg_width);
37 void discover_bus(Hw::Device *host);
41 int set_property(cxx::String const &prop, Prop_val const &val);
43 int getval(const char *s, cxx::String const &prop,
44 Prop_val const &val, T *rval);
45 int int_map(int i) const { return _int_map[i]; }
48 l4_addr_t _iobase_virt, _iobase_phys, _dev_start, _dev_end;
53 // Irq router that maps INTA-D to GSI
54 class Irq_router_rs : public Resource_space
57 bool request(Resource *parent, Device *, Resource *child, Device *cdev);
58 bool alloc(Resource *, Device *, Resource *, Device *, bool)
63 Pci_iomem_root_bridge::init()
65 if (_iobase_phys == ~0UL)
67 d_printf(DBG_ERR, "ERROR: Hw::Pci::Root_bridge: 'iobase' not set.\n");
73 d_printf(DBG_ERR, "ERROR: Hw::Pci::Root_bridge: 'iosize' not set.\n");
77 if (_dev_start == ~0UL || _dev_end == ~0UL)
79 d_printf(DBG_ERR, "ERROR: Hw::Pci::Root_bridge: 'dev_start' and/or 'dev_end' not set.\n");
83 _iobase_virt = res_map_iomem(_iobase_phys, _iosize);
87 add_resource_rq(new Resource(Resource::Mmio_res,
89 _iobase_phys + _iosize - 1));
91 Resource *r = new Resource_provider(Resource::Mmio_res);
92 r->alignment(0xfffff);
93 r->start_end(_dev_start, _dev_end);
96 r = new Resource_provider(Resource::Io_res);
97 r->start_end(0, 0xffff);
100 add_resource_rq(new Hw::Pci::Irq_router_res<Irq_router_rs>());
108 Pci_iomem_root_bridge::discover_bus(Hw::Device *host)
112 Hw::Pci::Root_bridge::discover_bus(host);
116 Pci_iomem_root_bridge::cfg_read(Cfg_addr addr, l4_uint32_t *value, Cfg_width w)
123 l4_uint32_t volatile *a = (l4_uint32_t volatile *)(_iobase_virt + addr.to_compat_addr());
126 case Pci::Cfg_byte: *value = (l4_uint8_t)*a; break;
127 case Pci::Cfg_short: *value = (l4_uint16_t)*a; break;
128 case Pci::Cfg_long: *value = (l4_uint32_t)*a; break;
131 d_printf(DBG_ALL, "Pci_iomem_root_bridge::cfg_read(%x, %x, %x, %x, %x, %d)\n",
132 addr.bus(), addr.dev(), addr.fn(), addr.reg(), *value, w);
138 Pci_iomem_root_bridge::cfg_write(Cfg_addr addr, l4_uint32_t value, Cfg_width w)
145 d_printf(DBG_ALL, "Pci_iomem_root_bridge::cfg_write(%x, %x, %x, %x, %x, %d)\n",
146 addr.bus(), addr.dev(), addr.fn(), addr.reg(), value, w);
148 l4_addr_t a = _iobase_virt + addr.to_compat_addr();
151 case Pci::Cfg_byte: *(volatile l4_uint8_t *)a = value; break;
152 case Pci::Cfg_short: *(volatile l4_uint16_t *)a = value; break;
153 case Pci::Cfg_long: *(volatile l4_uint32_t *)a = value; break;
158 template< typename T>
160 Pci_iomem_root_bridge::getval(const char *s, cxx::String const &prop,
161 Prop_val const &val, T *rval)
165 if (val.type != Prop_val::Int)
168 *rval = val.val.integer;
175 Pci_iomem_root_bridge::set_property(cxx::String const &prop, Prop_val const &val)
179 if ((r = getval("iobase", prop, val, &_iobase_phys)) != -E_no_prop)
181 else if ((r = getval("iosize", prop, val, &_iosize)) != -E_no_prop)
183 else if ((r = getval("dev_start", prop, val, &_dev_start)) != -E_no_prop)
185 else if ((r = getval("dev_end", prop, val, &_dev_end)) != -E_no_prop)
187 else if ((r = getval("int_a", prop, val, &_int_map[0])) != -E_no_prop)
189 else if ((r = getval("int_b", prop, val, &_int_map[1])) != -E_no_prop)
191 else if ((r = getval("int_c", prop, val, &_int_map[2])) != -E_no_prop)
193 else if ((r = getval("int_d", prop, val, &_int_map[3])) != -E_no_prop)
196 return Hw::Device::set_property(prop, val);
199 static Hw::Device_factory_t<Pci_iomem_root_bridge>
200 __hw_pci_root_bridge_factory("Pci_iomem_root_bridge");
202 bool Irq_router_rs::request(Resource *parent, Device *pdev,
203 Resource *child, Device *cdev)
205 Hw::Device *cd = dynamic_cast<Hw::Device*>(cdev);
209 if (child->start() > 3)
212 int i = (child->start() + (cd->adr() >> 16)) & 3;
214 Pci_iomem_root_bridge *pd = dynamic_cast<Pci_iomem_root_bridge *>(pdev);
219 child->del_flags(Resource::F_relative);
220 child->start(pd->int_map(i));
221 child->del_flags(Resource::Irq_type_mask);
222 child->add_flags(Resource::Irq_type_level_low);
224 child->parent(parent);