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