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 Pci_root_bridge, public Hw::Device
26 typedef Hw::Pci::Cfg_width Cfg_width;
28 Pci_iomem_root_bridge()
29 : Pci_root_bridge(this), _iobase_virt(0), _iobase_phys(~0UL),
30 _dev_start(~0UL), _dev_end(~0UL), _iosize(0)
32 set_discover_bus_if(this);
35 int cfg_read(unsigned bus, l4_uint32_t devfn, l4_uint32_t reg,
36 l4_uint32_t *value, Cfg_width);
38 int cfg_write(unsigned bus, l4_uint32_t devfn, l4_uint32_t reg,
39 l4_uint32_t value, Cfg_width);
45 int set_property(cxx::String const &prop, Prop_val const &val);
47 int getval(const char *s, cxx::String const &prop,
48 Prop_val const &val, T *rval);
49 int int_map(int i) const { return _int_map[i]; }
52 l4_addr_t _iobase_virt, _iobase_phys, _dev_start, _dev_end;
57 // Irq router that maps INTA-D to GSI
58 class Irq_router_rs : public Resource_space
61 bool request(Resource *parent, Device *, Resource *child, Device *cdev);
62 bool alloc(Resource *, Device *, Resource *, Device *, bool)
67 Pci_iomem_root_bridge::init()
69 if (_iobase_phys == ~0UL)
71 d_printf(DBG_ERR, "ERROR: Pci_root_bridge: 'iobase' not set.\n");
77 d_printf(DBG_ERR, "ERROR: Pci_root_bridge: 'iosize' not set.\n");
81 if (_dev_start == ~0UL || _dev_end == ~0UL)
83 d_printf(DBG_ERR, "ERROR: Pci_root_bridge: 'dev_start' and/or 'dev_end' not set.\n");
87 _iobase_virt = res_map_iomem(_iobase_phys, _iosize);
91 add_resource(new Adr_resource(Resource::Mmio_res
92 | Resource::F_fixed_size
93 | Resource::F_fixed_addr,
95 _iobase_phys + _iosize - 1));
97 Adr_resource *r = new Adr_resource_provider(Resource::Mmio_res
98 | Resource::F_fixed_size
99 | Resource::F_fixed_addr);
100 r->alignment(0xfffff);
101 r->start_end(_dev_start, _dev_end);
104 r = new Adr_resource_provider(Resource::Io_res
105 | Resource::F_fixed_size
106 | Resource::F_fixed_addr);
107 r->start_end(0, 0xffff);
110 add_resource(new Pci_irq_router_res<Irq_router_rs>());
116 Pci_iomem_root_bridge::scan_bus()
120 Pci_root_bridge::scan_bus();
124 Pci_iomem_root_bridge::cfg_read(unsigned bus, l4_uint32_t devfn,
126 l4_uint32_t *value, Cfg_width order)
133 l4_uint32_t a = _iobase_virt + pci_conf_addr0(bus, devfn >> 16, devfn & 0xffff, reg);
136 case Pci::Cfg_byte: *value = *(volatile unsigned char *)(a + (reg & 3)); break;
137 case Pci::Cfg_short: *value = *(volatile unsigned short *)(a + (reg & 2)); break;
138 case Pci::Cfg_long: *value = *(volatile unsigned int *)a; break;
141 d_printf(DBG_ALL, "Pci_iomem_root_bridge::cfg_read(%x, %x, %x, %x, %d)\n",
142 bus, devfn, reg, *value, order);
148 Pci_iomem_root_bridge::cfg_write(unsigned bus, l4_uint32_t devfn,
150 l4_uint32_t value, Cfg_width order)
157 d_printf(DBG_ALL, "Pci_iomem_root_bridge::cfg_write(%x, %x, %x, %x, %d)\n",
158 bus, devfn, reg, value, order);
160 l4_uint32_t a = _iobase_virt + pci_conf_addr0(bus, devfn >> 16, devfn & 0xffff, reg);
163 case Pci::Cfg_byte: *(volatile unsigned char *)(a + (reg & 3)) = value; break;
164 case Pci::Cfg_short: *(volatile unsigned short *)(a + (reg & 2)) = value; break;
165 case Pci::Cfg_long: *(volatile unsigned int *)a = value; break;
170 template< typename T>
172 Pci_iomem_root_bridge::getval(const char *s, cxx::String const &prop,
173 Prop_val const &val, T *rval)
177 if (val.type != Prop_val::Int)
180 *rval = val.val.integer;
187 Pci_iomem_root_bridge::set_property(cxx::String const &prop, Prop_val const &val)
191 if ((r = getval("iobase", prop, val, &_iobase_phys)) != -E_no_prop)
193 else if ((r = getval("iosize", prop, val, &_iosize)) != -E_no_prop)
195 else if ((r = getval("dev_start", prop, val, &_dev_start)) != -E_no_prop)
197 else if ((r = getval("dev_end", prop, val, &_dev_end)) != -E_no_prop)
199 else if ((r = getval("int_a", prop, val, &_int_map[0])) != -E_no_prop)
201 else if ((r = getval("int_b", prop, val, &_int_map[1])) != -E_no_prop)
203 else if ((r = getval("int_c", prop, val, &_int_map[2])) != -E_no_prop)
205 else if ((r = getval("int_d", prop, val, &_int_map[3])) != -E_no_prop)
208 return Hw::Device::set_property(prop, val);
211 static Hw::Device_factory_t<Pci_iomem_root_bridge>
212 __hw_pci_root_bridge_factory("Pci_iomem_root_bridge");
214 bool Irq_router_rs::request(Resource *parent, Device *pdev,
215 Resource *child, Device *cdev)
217 Adr_resource *cr = dynamic_cast<Adr_resource*>(child);
221 child->parent(parent);
225 Hw::Device *cd = dynamic_cast<Hw::Device*>(cdev);
232 int i = (cr->start() + (cd->adr() >> 16)) & 3;
234 Pci_iomem_root_bridge *pd = dynamic_cast<Pci_iomem_root_bridge *>(pdev);
239 cr->del_flags(Resource::F_relative);
240 cr->start(pd->int_map(i));
241 cr->del_flags(Resource::Irq_info_base * 3);
242 cr->add_flags(Resource::Irq_level | Resource::Irq_low);