]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/io/io/server/src/platform_control.cc
Update
[l4.git] / l4 / pkg / io / io / server / src / platform_control.cc
1 /*
2  * (c) 2014 Alexander Warg <warg@os.inf.tu-dresden.de>
3  *
4  * This file is part of TUD:OS and distributed under the terms of the
5  * GNU General Public License 2.
6  * Please see the COPYING-GPL-2 file for details.
7  */
8
9 #include "hw_root_bus.h"
10 #include "platform_control.h"
11 #include "server.h"
12 #include "debug.h"
13
14 #include <l4/cxx/static_container>
15 #include <l4/sys/platform_control>
16 #include <l4/cxx/ipc_timeout_queue>
17
18
19 namespace {
20 struct Suspend_timeout : L4::Ipc_svr::Timeout
21 {
22   Platform_control *ctl;
23   explicit Suspend_timeout(Platform_control *ctl) : ctl(ctl) {}
24
25   void expired()
26   {
27     d_printf(DBG_ERR, "error: timeout during suspend, abort suspend\n");
28     ctl->print_lock_holders(L4VBUS_INHIBITOR_SUSPEND);
29     ctl->inhibitor_signal(L4VBUS_INHIBITOR_WAKEUP);
30     ctl->cancel_op();
31   }
32 };
33
34 struct Shutdown_timeout : L4::Ipc_svr::Timeout
35 {
36   Platform_control *ctl;
37   explicit Shutdown_timeout(Platform_control *ctl) : ctl(ctl) {}
38
39   void expired()
40   {
41     d_printf(DBG_ERR,
42              "error: timeout during shutdown / reboot, force operation\n");
43     ctl->print_lock_holders(L4VBUS_INHIBITOR_SHUTDOWN);
44     // this will do a reboot if the operation in progress is reboot
45     ctl->all_inhibitors_free(L4VBUS_INHIBITOR_SHUTDOWN);
46     ctl->cancel_op();
47   }
48 };
49
50 union Timeouts
51 {
52   cxx::Static_container<Suspend_timeout> suspend;
53   cxx::Static_container<Shutdown_timeout> shutdown;
54 } op_timeout;
55
56 }
57
58 int
59 Platform_control::start_operation(unsigned op)
60 {
61   using L4::Ipc_svr::Timeout_queue;
62
63   if (in_progress_ops())
64     return -L4_EBUSY;
65
66   unsigned inhibitor;
67   Timeout_queue::Timeout *timeout;
68   switch (op)
69     {
70     case Suspend_in_progress:
71       inhibitor = L4VBUS_INHIBITOR_SUSPEND;
72       op_timeout.suspend.construct(this);
73       timeout   = op_timeout.suspend;
74       break;
75
76     case Shutdown_in_progress: /* fall through */
77     case Reboot_in_progress:
78       inhibitor = L4VBUS_INHIBITOR_SHUTDOWN;
79       op_timeout.shutdown.construct(this);
80       timeout   = op_timeout.shutdown;
81       break;
82
83     default:
84       return -L4_EINVAL;
85     }
86
87   _state |= op;
88   if (inhibitors_free(inhibitor))
89     {
90       all_inhibitors_free(inhibitor);
91       return L4_EOK;
92     }
93   inhibitor_signal(inhibitor);
94   server_iface()->add_timeout(timeout, l4_kip_clock(l4re_kip()) + 10000000);
95   return L4_EOK;
96 }
97
98 void
99 Platform_control::all_inhibitors_free(l4_umword_t id)
100 {
101   if (!_hw_root->supports_pm())
102     return;
103
104   unsigned in_progress = in_progress_ops();
105
106   if (!in_progress)
107     return;
108
109   switch (id)
110     {
111     default:
112       return;
113
114     case L4VBUS_INHIBITOR_SUSPEND:
115       if (in_progress & Suspend_in_progress)
116         {
117           server_iface()->remove_timeout(op_timeout.suspend);
118           _hw_root->suspend();
119           _state &= ~Suspend_in_progress;
120           inhibitor_signal(L4VBUS_INHIBITOR_WAKEUP);
121         }
122       return;
123
124     case L4VBUS_INHIBITOR_SHUTDOWN:
125       // reboot overrides shutdown (HMM: this is policy)
126       server_iface()->remove_timeout(op_timeout.shutdown);
127       if (in_progress & Reboot_in_progress)
128         {
129           _hw_root->reboot();
130           d_printf(DBG_ERR, "fatal: platform reboot returned\n");
131           exit(255);
132         }
133
134       if (in_progress & Shutdown_in_progress)
135         {
136           _hw_root->shutdown();
137           d_printf(DBG_ERR, "fatal: platform shutdown returned\n");
138           exit(255);
139         }
140       return;
141     }
142 }
143