]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/io/server/src/pci_iomem_root_bridge.cc
d4e14baa53a8a27931dd7e0cb9996816cd4d0575
[l4.git] / l4 / pkg / io / server / src / pci_iomem_root_bridge.cc
1
2 #include "hw_device.h"
3 #include "pci.h"
4 #include "main.h"
5
6 namespace {
7
8 inline
9 l4_uint32_t
10 pci_conf_addr0(l4_uint32_t bus, l4_uint32_t dev,
11                l4_uint32_t fn, l4_uint32_t reg)
12 { return (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3); }
13
14 class Pci_iomem_root_bridge : public Pci_root_bridge, public Hw::Device
15 {
16 public:
17   typedef Hw::Pci::Cfg_width Cfg_width;
18
19   Pci_iomem_root_bridge()
20   : Pci_root_bridge(this), _iobase_virt(0), _iobase_phys(~0UL),
21     _dev_start(~0UL), _dev_end(~0UL), _iosize(0)
22   {
23     set_discover_bus_if(this);
24   }
25
26   int cfg_read(unsigned bus, l4_uint32_t devfn, l4_uint32_t reg,
27                l4_uint32_t *value, Cfg_width);
28
29   int cfg_write(unsigned bus, l4_uint32_t devfn, l4_uint32_t reg,
30                 l4_uint32_t value, Cfg_width);
31
32   void scan_bus();
33
34   void init();
35
36   int set_property(cxx::String const &prop, Prop_val const &val);
37   template< typename T>
38   int getval(const char *s, cxx::String const &prop,
39              Prop_val const &val, T *rval);
40   int int_map(int i) const { return _int_map[i]; }
41
42 private:
43   l4_addr_t _iobase_virt, _iobase_phys, _dev_start, _dev_end;
44   int _int_map[4];
45   l4_size_t _iosize;
46 };
47
48 // Irq router that maps INTA-D to GSI
49 class Irq_router_rs : public Resource_space
50 {
51 public:
52   bool request(Resource *parent, Device *, Resource *child, Device *cdev);
53   bool alloc(Resource *, Device *, Resource *, Device *, bool)
54   { return false; }
55 };
56
57 void
58 Pci_iomem_root_bridge::init()
59 {
60   if (_iobase_phys == ~0UL)
61     {
62       printf("ERROR: Pci_root_bridge: 'iobase' not set.\n");
63       return;
64     }
65
66   if (_iosize == 0U)
67     {
68       printf("ERROR: Pci_root_bridge: 'iosize' not set.\n");
69       return;
70     }
71
72   if (_dev_start == ~0UL || _dev_end == ~0UL)
73     {
74       printf("ERROR: Pci_root_bridge: 'dev_start' and/or 'dev_end' not set.\n");
75       return;
76     }
77
78   _iobase_virt = res_map_iomem(_iobase_phys, _iosize);
79   if (!_iobase_virt)
80     return;
81
82   add_resource(new Adr_resource(Resource::Mmio_res
83                                 | Resource::F_fixed_size
84                                 | Resource::F_fixed_addr,
85                                 _iobase_phys,
86                                 _iobase_phys + _iosize - 1));
87
88   Adr_resource *r = new Adr_resource_provider(Resource::Mmio_res
89                                               | Resource::F_fixed_size
90                                               | Resource::F_fixed_addr);
91   r->alignment(0xfffff);
92   r->start_end(_dev_start, _dev_end);
93   add_resource(r);
94
95   r = new Adr_resource_provider(Resource::Io_res
96                                 | Resource::F_fixed_size
97                                 | Resource::F_fixed_addr);
98   r->start_end(0, 0xffff);
99   add_resource(r);
100
101   add_resource(new Pci_irq_router_res<Irq_router_rs>());
102
103   Hw::Device::init();
104 }
105
106 void
107 Pci_iomem_root_bridge::scan_bus()
108 {
109   if (!_iobase_virt)
110     return;
111   Pci_root_bridge::scan_bus();
112 }
113
114 int
115 Pci_iomem_root_bridge::cfg_read(unsigned bus, l4_uint32_t devfn,
116                                 l4_uint32_t reg,
117                                 l4_uint32_t *value, Cfg_width order)
118 {
119   using namespace Hw;
120
121   if (!_iobase_virt)
122     return -1;
123
124   l4_uint32_t a = _iobase_virt + pci_conf_addr0(bus, devfn >> 16, devfn & 0xffff, reg);
125   switch (order)
126     {
127     case Pci::Cfg_byte: *value = *(volatile unsigned char *)(a + (reg & 3)); break;
128     case Pci::Cfg_short: *value = *(volatile unsigned short *)(a + (reg & 2)); break;
129     case Pci::Cfg_long: *value = *(volatile unsigned int *)a; break;
130     }
131
132   if (0)
133     printf("Pci_iomem_root_bridge::cfg_read(%x, %x, %x, %x, %d)\n",
134            bus, devfn, reg, *value, order);
135
136   return 0;
137 }
138
139 int
140 Pci_iomem_root_bridge::cfg_write(unsigned bus, l4_uint32_t devfn,
141                                  l4_uint32_t reg,
142                                  l4_uint32_t value, Cfg_width order)
143 {
144   using namespace Hw;
145
146   if (!_iobase_virt)
147     return -1;
148
149   if (0)
150     printf("Pci_iomem_root_bridge::cfg_write(%x, %x, %x, %x, %d)\n",
151            bus, devfn, reg, value, order);
152
153   l4_uint32_t a = _iobase_virt + pci_conf_addr0(bus, devfn >> 16, devfn & 0xffff, reg);
154   switch (order)
155     {
156     case Pci::Cfg_byte: *(volatile unsigned char *)(a + (reg & 3)) = value; break;
157     case Pci::Cfg_short: *(volatile unsigned short *)(a + (reg & 2)) = value; break;
158     case Pci::Cfg_long: *(volatile unsigned int *)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   Adr_resource *cr = dynamic_cast<Adr_resource*>(child);
211
212   if (!cr)
213     {
214       child->parent(parent);
215       return true;
216     }
217
218   Hw::Device *cd = dynamic_cast<Hw::Device*>(cdev);
219   if (!cd)
220     return false;
221
222   if (cr->start() > 3)
223     return false;
224
225   int i = (cr->start() + (cd->adr() >> 16)) & 3;
226
227   Pci_iomem_root_bridge *pd = dynamic_cast<Pci_iomem_root_bridge *>(pdev);
228   if (!pd)
229     return false;
230
231
232   cr->del_flags(Resource::F_relative);
233   cr->start(pd->int_map(i));
234   cr->del_flags(Resource::Irq_info_base * 3);
235   cr->add_flags(Resource::Irq_level | Resource::Irq_low);
236
237   cr->parent(parent);
238
239   return true;
240 }
241 }