]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/io/server/src/pci/pci_iomem_root_bridge.cc
update
[l4.git] / l4 / pkg / io / server / src / pci / pci_iomem_root_bridge.cc
1 /*
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)
5  *
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.
9  */
10 #include "debug.h"
11 #include "hw_device.h"
12 #include "pci.h"
13 #include "main.h"
14
15 namespace {
16
17 inline
18 l4_uint32_t
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); }
22
23 class Pci_iomem_root_bridge : public Hw::Pci::Root_bridge, public Hw::Device
24 {
25 public:
26   typedef Hw::Pci::Cfg_width Cfg_width;
27   typedef Hw::Pci::Cfg_addr Cfg_addr;
28
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)
32   {}
33
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);
36
37   void discover_bus(Hw::Device *host);
38
39   void init();
40
41   int set_property(cxx::String const &prop, Prop_val const &val);
42   template< typename T>
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]; }
46
47 private:
48   l4_addr_t _iobase_virt, _iobase_phys, _dev_start, _dev_end;
49   int _int_map[4];
50   l4_size_t _iosize;
51 };
52
53 // Irq router that maps INTA-D to GSI
54 class Irq_router_rs : public Resource_space
55 {
56 public:
57   bool request(Resource *parent, Device *, Resource *child, Device *cdev);
58   bool alloc(Resource *, Device *, Resource *, Device *, bool)
59   { return false; }
60 };
61
62 void
63 Pci_iomem_root_bridge::init()
64 {
65   if (_iobase_phys == ~0UL)
66     {
67       d_printf(DBG_ERR, "ERROR: Hw::Pci::Root_bridge: 'iobase' not set.\n");
68       return;
69     }
70
71   if (_iosize == 0U)
72     {
73       d_printf(DBG_ERR, "ERROR: Hw::Pci::Root_bridge: 'iosize' not set.\n");
74       return;
75     }
76
77   if (_dev_start == ~0UL || _dev_end == ~0UL)
78     {
79       d_printf(DBG_ERR, "ERROR: Hw::Pci::Root_bridge: 'dev_start' and/or 'dev_end' not set.\n");
80       return;
81     }
82
83   _iobase_virt = res_map_iomem(_iobase_phys, _iosize);
84   if (!_iobase_virt)
85     return;
86
87   add_resource_rq(new Resource(Resource::Mmio_res,
88                                _iobase_phys,
89                                _iobase_phys + _iosize - 1));
90
91   Resource *r = new Resource_provider(Resource::Mmio_res);
92   r->alignment(0xfffff);
93   r->start_end(_dev_start, _dev_end);
94   add_resource_rq(r);
95
96   r = new Resource_provider(Resource::Io_res);
97   r->start_end(0, 0xffff);
98   add_resource_rq(r);
99
100   add_resource_rq(new Hw::Pci::Irq_router_res<Irq_router_rs>());
101
102   discover_bus(this);
103
104   Hw::Device::init();
105 }
106
107 void
108 Pci_iomem_root_bridge::discover_bus(Hw::Device *host)
109 {
110   if (!_iobase_virt)
111     return;
112   Hw::Pci::Root_bridge::discover_bus(host);
113 }
114
115 int
116 Pci_iomem_root_bridge::cfg_read(Cfg_addr addr, l4_uint32_t *value, Cfg_width w)
117 {
118   using namespace Hw;
119
120   if (!_iobase_virt)
121     return -1;
122
123   l4_uint32_t volatile *a = (l4_uint32_t volatile *)(_iobase_virt + addr.to_compat_addr());
124   switch (w)
125     {
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;
129     }
130
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);
133
134   return 0;
135 }
136
137 int
138 Pci_iomem_root_bridge::cfg_write(Cfg_addr addr, l4_uint32_t value, Cfg_width w)
139 {
140   using namespace Hw;
141
142   if (!_iobase_virt)
143     return -1;
144
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);
147
148   l4_addr_t a = _iobase_virt + addr.to_compat_addr();
149   switch (w)
150     {
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;
154     }
155   return 0;
156 }
157
158 template< typename T>
159 int
160 Pci_iomem_root_bridge::getval(const char *s, cxx::String const &prop,
161                               Prop_val const &val, T *rval)
162 {
163   if (prop == s)
164     {
165       if (val.type != Prop_val::Int)
166         return -E_inval;
167
168       *rval = val.val.integer;
169       return E_ok;
170     }
171   return -E_no_prop;
172 }
173
174 int
175 Pci_iomem_root_bridge::set_property(cxx::String const &prop, Prop_val const &val)
176 {
177   int r;
178
179   if ((r = getval("iobase", prop, val, &_iobase_phys)) != -E_no_prop)
180     return r;
181   else if ((r = getval("iosize", prop, val, &_iosize)) != -E_no_prop)
182     return r;
183   else if ((r = getval("dev_start", prop, val, &_dev_start)) != -E_no_prop)
184     return r;
185   else if ((r = getval("dev_end", prop, val, &_dev_end)) != -E_no_prop)
186     return r;
187   else if ((r = getval("int_a", prop, val, &_int_map[0])) != -E_no_prop)
188     return r;
189   else if ((r = getval("int_b", prop, val, &_int_map[1])) != -E_no_prop)
190     return r;
191   else if ((r = getval("int_c", prop, val, &_int_map[2])) != -E_no_prop)
192     return r;
193   else if ((r = getval("int_d", prop, val, &_int_map[3])) != -E_no_prop)
194     return r;
195
196   return Hw::Device::set_property(prop, val);
197 }
198
199 static Hw::Device_factory_t<Pci_iomem_root_bridge>
200               __hw_pci_root_bridge_factory("Pci_iomem_root_bridge");
201
202 bool Irq_router_rs::request(Resource *parent, Device *pdev,
203                             Resource *child, Device *cdev)
204 {
205   Hw::Device *cd = dynamic_cast<Hw::Device*>(cdev);
206   if (!cd)
207     return false;
208
209   if (child->start() > 3)
210     return false;
211
212   int i = (child->start() + (cd->adr() >> 16)) & 3;
213
214   Pci_iomem_root_bridge *pd = dynamic_cast<Pci_iomem_root_bridge *>(pdev);
215   if (!pd)
216     return false;
217
218
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);
223
224   child->parent(parent);
225
226   return true;
227 }
228 }