L4Re - L4 Runtime Environment
icu_svr
1 // vi:set ft=cpp: -*- Mode: C++ -*-
2 
3 #pragma once
4 
5 
6 #include <l4/sys/types.h>
7 
8 #include <l4/sys/icu>
9 #include <l4/sys/task>
10 #include <l4/re/env>
11 #include <l4/re/util/cap_alloc>
12 #include <l4/sys/cxx/ipc_legacy>
13 
14 namespace L4Re { namespace Util {
15 
16 template< typename ICU >
17 class Icu_svr
18 {
19 private:
20  ICU const *this_icu() const { return static_cast<ICU const *>(this); }
21  ICU *this_icu() { return static_cast<ICU*>(this); }
22 
23 public:
24  L4_RPC_LEGACY_DISPATCH(L4::Icu);
25 
26  int op_bind(L4::Icu::Rights, l4_umword_t irqnum,
27  L4::Ipc::Snd_fpage irq_fp);
28  int op_unbind(L4::Icu::Rights, l4_umword_t irqnum,
29  L4::Ipc::Snd_fpage irq_fp);
30  int op_info(L4::Icu::Rights, L4::Icu::_Info &info);
31  int op_msi_info(L4::Icu::Rights, l4_umword_t irqnum,
32  l4_uint64_t source, l4_icu_msi_info_t &info);
33  int op_mask(L4::Icu::Rights, l4_umword_t irqnum);
34  int op_unmask(L4::Icu::Rights, l4_umword_t irqnum);
35  int op_set_mode(L4::Icu::Rights, l4_umword_t, l4_umword_t)
36  { return 0; }
37 };
38 
39 template<typename ICU> inline
40 int
41 Icu_svr<ICU>::op_bind(L4::Icu::Rights, l4_umword_t irqnum,
42  L4::Ipc::Snd_fpage irq_fp)
43 {
44  typename ICU::Irq *irq = this_icu()->icu_get_irq(irqnum);
45  if (!irq)
46  return -L4_EINVAL;
47 
48  return irq->bind(this_icu(), irq_fp);
49 }
50 
51 template<typename ICU> inline
52 int
53 Icu_svr<ICU>::op_unbind(L4::Icu::Rights, l4_umword_t irqnum,
54  L4::Ipc::Snd_fpage irq_fp)
55 {
56  typename ICU::Irq *irq = this_icu()->icu_get_irq(irqnum);
57  if (!irq)
58  return -L4_EINVAL;
59 
60  return irq->unbind(this_icu(), irq_fp);
61 }
62 
63 template<typename ICU> inline
64 int
65 Icu_svr<ICU>::op_info(L4::Icu::Rights, L4::Icu::_Info &info)
66 {
67  l4_icu_info_t i;
68  this_icu()->icu_get_info(&i);
69  info.features = i.features;
70  info.nr_irqs = i.nr_irqs;
71  info.nr_msis = i.nr_msis;
72  return 0;
73 }
74 
75 template<typename ICU> inline
76 int
77 Icu_svr<ICU>::op_msi_info(L4::Icu::Rights, l4_umword_t irqnum,
78  l4_uint64_t source, l4_icu_msi_info_t &info)
79 {
80  typename ICU::Irq *irq = this_icu()->icu_get_irq(irqnum);
81  if (!irq)
82  return -L4_EINVAL;
83  return irq->msi_info(source, &info);
84 }
85 
86 template<typename ICU> inline
87 int
88 Icu_svr<ICU>::op_mask(L4::Icu::Rights, l4_umword_t irqnum)
89 {
90  typename ICU::Irq *irq = this_icu()->icu_get_irq(irqnum);
91  if (irq)
92  irq->mask(true);
93  return -L4_ENOREPLY;
94 }
95 
96 template<typename ICU> inline
97 int
98 Icu_svr<ICU>::op_unmask(L4::Icu::Rights, l4_umword_t irqnum)
99 {
100  typename ICU::Irq *irq = this_icu()->icu_get_irq(irqnum);
101  if (irq)
102  irq->mask(false);
103  return -L4_ENOREPLY;
104 }
105 
106 
107 template< typename ICU >
108 class Icu_cap_array_svr : public Icu_svr<ICU>
109 {
110 protected:
111  static void free_irq_cap(L4::Cap<L4::Irq> &cap)
112  {
113  if (cap)
114  {
115  L4Re::Util::cap_alloc.free(cap);
116  cap.invalidate();
117  }
118  }
119 
120 public:
121  class Irq
122  {
123  public:
124  Irq() {}
125  ~Irq() { ICU::free_irq_cap(_cap); }
126 
127  void trigger() const
128  { if (_cap) _cap->trigger(); }
129 
130  int bind(ICU *, L4::Ipc::Snd_fpage const &irq_fp);
131  int unbind(ICU *, L4::Ipc::Snd_fpage const &irq_fp);
132  void mask(bool mask) const
133  { (void)mask; }
134 
135  int msi_info(l4_uint64_t, l4_icu_msi_info_t *) const
136  { return -L4_EINVAL; }
137 
138  L4::Cap<L4::Irq> cap() const { return _cap; }
139 
140  private:
141  L4::Cap<L4::Irq> _cap;
142  };
143 
144 private:
145  Irq *_irqs;
146  unsigned _nr_irqs;
147 
148 public:
149 
150  Icu_cap_array_svr(unsigned nr_irqs, Irq *irqs)
151  : _irqs(irqs), _nr_irqs(nr_irqs)
152  {}
153 
154  Irq *icu_get_irq(l4_umword_t irqnum)
155  {
156  if (irqnum >= _nr_irqs)
157  return 0;
158 
159  return _irqs + irqnum;
160  }
161 
162  void icu_get_info(l4_icu_info_t *inf)
163  {
164  inf->features = 0;
165  inf->nr_irqs = _nr_irqs;
166  inf->nr_msis = 0;
167  }
168 };
169 
170 template< typename ICU >
171 int
172 Icu_cap_array_svr<ICU>::Irq::bind(ICU *cfb, L4::Ipc::Snd_fpage const &irq_fp)
173 {
174  if (!irq_fp.cap_received())
175  return -L4_EINVAL;
176 
177  L4::Cap<L4::Irq> irq = cfb->server_iface()->template rcv_cap<L4::Irq>(0);
178  if (!irq)
179  return -L4_EINVAL;
180 
181  int r = cfb->server_iface()->realloc_rcv_cap(0);
182  if (r < 0)
183  return r;
184 
185  _cap = irq;
186  return 0;
187 }
188 
189 template< typename ICU >
190 int
191 Icu_cap_array_svr<ICU>::Irq::unbind(ICU *, L4::Ipc::Snd_fpage const &/*irq_fp*/)
192 {
193  L4Re::Env::env()->task()->unmap(_cap.fpage(L4_FPAGE_RWX), L4_FP_ALL_SPACES);
194  _cap = L4::Cap<L4::Irq>::Invalid;
195  return 0;
196 }
197 
198 
199 }}