]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/io/server/src/vpci_virtual_root.cc
update
[l4.git] / l4 / pkg / io / server / src / vpci_virtual_root.cc
1 /*
2  * (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
3  *     economic rights: Technische Universität Dresden (Germany)
4  *
5  * This file is part of TUD:OS and distributed under the terms of the
6  * GNU General Public License 2.
7  * Please see the COPYING-GPL-2 file for details.
8  */
9
10 #include "vpci.h"
11 #include "vpci_pci_bridge.h"
12 #include "vbus_factory.h"
13
14 namespace Vi {
15
16 /**
17  * \brief A virtual Host-to-PCI bridge.
18  */
19 class Pci_vroot : public Pci_bridge, public Dev_feature
20 {
21 public:
22
23   explicit Pci_vroot();
24
25   int dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc_iostream &ios);
26
27   ~Pci_vroot() {}
28
29   char const *hid() const
30   { return "PNP0A03"; }
31
32   void set_host(Device *d) { _host = d; }
33   Device *host() const { return _host; }
34
35 private:
36   Device *_host;
37
38 public:
39   int cfg_read(L4::Ipc_iostream &ios);
40   int cfg_write(L4::Ipc_iostream &ios);
41   int irq_enable(L4::Ipc_iostream &ios);
42   bool match_hw_feature(const Hw::Dev_feature*) const
43   { return false; }
44 };
45
46 // -----------------------------------------------------------------------
47 // Virtual PCI root bridge with identity mapping of phys devices
48 // -----------------------------------------------------------------------
49
50
51 class Pci_vroot_id : public Pci_vroot
52 {
53 public:
54   void add_child(Device *d);
55
56 };
57
58
59
60 // -------------------------------------------------------------------
61 // Virtual PCI Root bridge
62 // -------------------------------------------------------------------
63
64 Pci_vroot::Pci_vroot() : Pci_bridge()
65 {
66   add_feature(this);
67   _subordinate = 100;
68 }
69
70 int
71 Pci_vroot::cfg_read(L4::Ipc_iostream &ios)
72 {
73   l4_uint32_t bus;
74   l4_uint32_t devfn;
75   l4_uint32_t reg;
76   l4_uint32_t value = 0;
77   l4_uint32_t width;
78
79   ios >> bus >> devfn >> reg >> width;
80   value = ~0U >> (32 - width);
81
82   //printf("cfg read: %02x:%02x.%1x: reg=%x w=%d\n", bus, devfn >> 16, devfn & 0xffff, reg, width);
83
84   if ((devfn >> 16) >= 32 || (devfn & 0xffff) >= 8)
85     {
86       ios << value;
87       return L4_EOK;
88     }
89
90   Pci_dev *d = 0;
91   child_dev(bus, (devfn >> 16), (devfn & 0xffff), &d);
92
93   if (!d)
94     {
95       ios << value;
96       return L4_EOK;
97     }
98
99   int res = d->cfg_read(reg, &value, Hw::Pci::cfg_w_to_o(width));
100
101   if (res < 0)
102     return res;
103
104   //printf("  value=%x\n", value);
105   ios << value;
106   return L4_EOK;
107 }
108 int
109 Pci_vroot::irq_enable(L4::Ipc_iostream &ios)
110 {
111   l4_uint32_t bus;
112   l4_uint32_t devfn;
113
114   ios >> bus >> devfn;
115
116   // printf("irq enable: %02x:%02x.%1x: pin=%d\n", bus, devfn >> 16, devfn & 0xffff, pin);
117
118   if ((devfn >> 16) >= 32 || (devfn & 0xffff) >= 8)
119     {
120       ios << (int)-1;
121       return L4_EOK;
122     }
123
124   Pci_dev *d = 0;
125   child_dev(bus, (devfn >> 16), (devfn & 0xffff), &d);
126   // printf("dev = %p\n", d);
127   if (!d)
128     {
129       ios << (int)-1;
130       return L4_EOK;
131     }
132
133   Pci_dev::Irq_info info;
134   int res = d->irq_enable(&info);
135   if (res < 0)
136     {
137       ios << (int)-1;
138       return res;
139     }
140
141   // printf("  irq = %d\n", info.irq);
142   ios << info.irq << info.trigger << info.polarity;
143   return L4_EOK;
144 }
145
146 int
147 Pci_vroot::cfg_write(L4::Ipc_iostream &ios)
148 {
149   l4_uint32_t bus;
150   l4_uint32_t devfn;
151   l4_uint32_t reg;
152   l4_uint32_t value;
153   l4_uint32_t width;
154
155   ios >> bus >> devfn >> reg >> value >> width;
156   // printf("cfg write: %02x:%02x.%1x: reg=%x w=%x v=%08x\n", bus, devfn >> 16, devfn & 0xffff, reg, width, value);
157
158   if ((devfn >> 16) >= 32 || (devfn & 0xffff) >= 8)
159     return L4_EOK;
160
161   Pci_dev *d = 0;
162   child_dev(bus, (devfn >> 16), (devfn & 0xffff), &d);
163
164   if (!d)
165     return L4_EOK;
166
167   return d->cfg_write(reg, value, Hw::Pci::cfg_w_to_o(width));
168 }
169
170 int
171 Pci_vroot::dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc_iostream &ios)
172 {
173   switch (func)
174     {
175     case 0: return cfg_read(ios);
176     case 1: return cfg_write(ios);
177     case 2: return irq_enable(ios);
178     default: return -L4_ENOSYS;
179     }
180 }
181
182
183 void
184 Pci_vroot_id::add_child(Device *d)
185 {
186   Pci_dev *vp = d->find_feature<Pci_dev>();
187
188   // hm, also here, drom non PCI devices
189   if (!vp)
190     return;
191
192   if (Pci_proxy_dev *proxy = dynamic_cast<Pci_proxy_dev*>(vp))
193     {
194       Pci_pci_bridge_basic const *hw_br
195         = dynamic_cast<Pci_pci_bridge_basic const *>(proxy->hwf()->bus());
196
197       l4_uint32_t hwadr = proxy->hwf()->host()->adr();
198       // printf("VPCI: add proxy PCI device %p (hwbr=%p)\n", proxy, hw_br);
199       unsigned dn = (hwadr >> 16) & (Bus::Devs-1);
200       unsigned fn = hwadr & (Dev::Fns-1);
201
202       if (!hw_br)
203         {
204           // MUST be a device on the root PCI bus
205           _bus.dev(dn)->fn(fn, vp);
206           Device::add_child(d);
207           return;
208         }
209
210       Pci_bridge *sw_br = find_bridge(hw_br->num);
211       if (!sw_br)
212         {
213           Pci_to_pci_bridge *b = new Pci_to_pci_bridge();
214           sw_br = b;
215           sw_br->primary(hw_br->pri);
216           sw_br->secondary(hw_br->num);
217           sw_br->subordinate(hw_br->subordinate);
218
219           unsigned dn = (hw_br->host()->adr() >> 16) & (Bus::Devs-1);
220           unsigned fn = hw_br->host()->adr() & (Dev::Fns-1);
221           _bus.dev(dn)->fn(fn, b);
222           Device::add_child(b);
223         }
224
225       sw_br->add_child_fixed(d, vp, dn, fn);
226       return;
227     }
228   else
229     {
230       _bus.add_fn(vp);
231       Device::add_child(d);
232     }
233 }
234
235
236
237 static Dev_factory_t<Pci_vroot> __pci_root_factory("PCI_bus");
238 static Dev_factory_t<Pci_vroot_id> __pci_root_id_factory("PCI_bus_ident");
239
240 }