blob: cd13c68a7f5bfff809ad784463fbb6116b34bad0 [file] [log] [blame]
Brad Bishop77390492016-04-13 10:47:19 -04001#include <stdint.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <fcntl.h>
6#include <unistd.h>
7#include <sys/stat.h>
8#include <sys/mman.h>
9#include <syslog.h>
Brad Bishopf6c85682016-06-27 11:56:39 -040010#include <openbmc_intf.h>
11#include <openbmc.h>
12#include <gpio.h>
Xo Wang20a19412016-09-22 11:26:14 -070013#include <power_gpio.h>
Brad Bishop77390492016-04-13 10:47:19 -040014
15/* ------------------------------------------------------------------------- */
16static const gchar* dbus_object_path = "/org/openbmc/control";
17static const gchar* instance_name = "power0";
18static const gchar* dbus_name = "org.openbmc.control.Power";
19
Xo Wang20a19412016-09-22 11:26:14 -070020static PowerGpio g_power_gpio;
Brad Bishop77390492016-04-13 10:47:19 -040021
22static GDBusObjectManagerServer *manager = NULL;
23
24time_t pgood_timeout_start = 0;
25
26// TODO: Change to interrupt driven instead of polling
27static gboolean
28poll_pgood(gpointer user_data)
29{
30 ControlPower *control_power = object_get_control_power((Object*)user_data);
31 Control* control = object_get_control((Object*)user_data);
32
33 //send the heartbeat
Brad Bishop77390492016-04-13 10:47:19 -040034 guint poll_int = control_get_poll_interval(control);
35 if(poll_int == 0)
36 {
Xo Wang20a19412016-09-22 11:26:14 -070037 g_print("ERROR PowerControl: Poll interval cannot be 0\n");
Brad Bishop77390492016-04-13 10:47:19 -040038 return FALSE;
39 }
40 //handle timeout
41 time_t current_time = time(NULL);
42 if(difftime(current_time,pgood_timeout_start) > control_power_get_pgood_timeout(control_power)
43 && pgood_timeout_start != 0)
44 {
Xo Wang20a19412016-09-22 11:26:14 -070045 g_print("ERROR PowerControl: Pgood poll timeout\n");
Brad Bishop77390492016-04-13 10:47:19 -040046 // set timeout to 0 so timeout doesn't happen again
47 control_power_set_pgood_timeout(control_power,0);
48 pgood_timeout_start = 0;
49 return TRUE;
50 }
Xo Wang20a19412016-09-22 11:26:14 -070051 uint8_t pgood_state;
Brad Bishop77390492016-04-13 10:47:19 -040052
Xo Wang20a19412016-09-22 11:26:14 -070053 int rc = gpio_open(&g_power_gpio.power_good_in);
54 if(rc != GPIO_OK) {
55 g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
56 g_power_gpio.power_good_in.name, rc);
57 return FALSE;
58 }
59 rc = gpio_read(&g_power_gpio.power_good_in, &pgood_state);
60 gpio_close(&g_power_gpio.power_good_in);
Brad Bishop77390492016-04-13 10:47:19 -040061 if(rc == GPIO_OK)
62 {
63 //if changed, set property and emit signal
Xo Wang20a19412016-09-22 11:26:14 -070064 if(pgood_state != control_power_get_pgood(control_power))
Brad Bishop77390492016-04-13 10:47:19 -040065 {
Xo Wang20a19412016-09-22 11:26:14 -070066 int i;
67 uint8_t reset_state;
68 control_power_set_pgood(control_power, pgood_state);
69 if(pgood_state == 0)
Brad Bishop77390492016-04-13 10:47:19 -040070 {
71 control_power_emit_power_lost(control_power);
72 control_emit_goto_system_state(control,"HOST_POWERED_OFF");
Brad Bishop77390492016-04-13 10:47:19 -040073 }
74 else
75 {
76 control_power_emit_power_good(control_power);
77 control_emit_goto_system_state(control,"HOST_POWERED_ON");
Xo Wang20a19412016-09-22 11:26:14 -070078 }
Brad Bishop77390492016-04-13 10:47:19 -040079
Xo Wang20a19412016-09-22 11:26:14 -070080 for(i = 0; i < g_power_gpio.num_reset_outs; i++)
81 {
82 GPIO *reset_out = &g_power_gpio.reset_outs[i];
83 rc = gpio_open(reset_out);
84 if(rc != GPIO_OK)
85 {
86 g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
87 reset_out->name, rc);
88 continue;
89 }
90
91 reset_state = pgood_state ^ g_power_gpio.reset_pols[i];
92 g_print("PowerControl: setting reset %s to %d\n", reset_out->name,
93 (int)reset_state);
94 gpio_write(reset_out, reset_state);
95 gpio_close(reset_out);
Brad Bishop77390492016-04-13 10:47:19 -040096 }
97 }
98 } else {
Xo Wang20a19412016-09-22 11:26:14 -070099 g_print("ERROR PowerControl: GPIO read error (gpio=%s,rc=%d)\n",
100 g_power_gpio.power_good_in.name, rc);
Brad Bishop77390492016-04-13 10:47:19 -0400101 //return false so poll won't get called anymore
102 return FALSE;
103 }
104 //pgood is not at desired state yet
Xo Wang20a19412016-09-22 11:26:14 -0700105 if(pgood_state != control_power_get_state(control_power) &&
Brad Bishop77390492016-04-13 10:47:19 -0400106 control_power_get_pgood_timeout(control_power) > 0)
107 {
108 if(pgood_timeout_start == 0 ) {
109 pgood_timeout_start = current_time;
110 }
111 }
112 else
113 {
114 pgood_timeout_start = 0;
115 }
116 return TRUE;
117}
118
119static gboolean
120on_set_power_state(ControlPower *pwr,
121 GDBusMethodInvocation *invocation,
122 guint state,
123 gpointer user_data)
124{
125 Control* control = object_get_control((Object*)user_data);
Brad Bishop77390492016-04-13 10:47:19 -0400126 if(state > 1)
127 {
128 g_dbus_method_invocation_return_dbus_error(invocation,
129 "org.openbmc.ControlPower.Error.Failed",
130 "Invalid power state");
131 return TRUE;
132 }
133 // return from method call
134 control_power_complete_set_power_state(pwr,invocation);
135 if(state == control_power_get_state(pwr))
136 {
137 g_print("Power already at requested state: %d\n",state);
138 }
139 else
140 {
141 int error = 0;
142 do {
Xo Wang20a19412016-09-22 11:26:14 -0700143 int i;
144 uint8_t power_up_out;
Brad Bishop77390492016-04-13 10:47:19 -0400145 if(state == 1) {
146 control_emit_goto_system_state(control,"HOST_POWERING_ON");
147 } else {
148 control_emit_goto_system_state(control,"HOST_POWERING_OFF");
149 }
Xo Wang20a19412016-09-22 11:26:14 -0700150 for (i = 0; i < g_power_gpio.num_power_up_outs; i++) {
151 GPIO *power_pin = &g_power_gpio.power_up_outs[i];
152 error = gpio_open(power_pin);
153 if(error != GPIO_OK) {
154 g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
155 g_power_gpio.power_up_outs[i].name, error);
156 continue;
157 }
158 power_up_out = state ^ g_power_gpio.power_up_pols[i];
159 g_print("PowerControl: setting power up %s to %d\n",
160 g_power_gpio.power_up_outs[i].name, (int)power_up_out);
161 error = gpio_write(power_pin, power_up_out);
162 if(error != GPIO_OK) {
163 continue;
164 }
165 gpio_close(power_pin);
166 }
Brad Bishop77390492016-04-13 10:47:19 -0400167 if(error != GPIO_OK) { break; }
Brad Bishop77390492016-04-13 10:47:19 -0400168 control_power_set_state(pwr,state);
169 } while(0);
170 if(error != GPIO_OK)
171 {
Xo Wang20a19412016-09-22 11:26:14 -0700172 g_print("ERROR PowerControl: GPIO set power state (rc=%d)\n",error);
Brad Bishop77390492016-04-13 10:47:19 -0400173 }
174 }
175 return TRUE;
176}
177
178static gboolean
179on_init(Control *control,
180 GDBusMethodInvocation *invocation,
181 gpointer user_data)
182{
183 pgood_timeout_start = 0;
184 //guint poll_interval = control_get_poll_interval(control);
185 //g_timeout_add(poll_interval, poll_pgood, user_data);
186 control_complete_init(control,invocation);
187 return TRUE;
188}
189
190static gboolean
191on_get_power_state(ControlPower *pwr,
192 GDBusMethodInvocation *invocation,
193 gpointer user_data)
194{
195 guint pgood = control_power_get_pgood(pwr);
196 control_power_complete_get_power_state(pwr,invocation,pgood);
197 return TRUE;
198}
199
Xo Wang20a19412016-09-22 11:26:14 -0700200static int
201set_up_gpio(GDBusConnection *connection,
202 PowerGpio *power_gpio,
203 ControlPower* control_power)
204{
205 int error = GPIO_OK;
206 int rc;
207 int i;
208 uint8_t pgood_state;
209
210 // get gpio device paths
211 rc = gpio_init(connection, &power_gpio->power_good_in);
212 if(rc != GPIO_OK) {
213 error = rc;
214 }
215 for(int i = 0; i < power_gpio->num_power_up_outs; i++) {
216 rc = gpio_init(connection, &power_gpio->power_up_outs[i]);
217 if(rc != GPIO_OK) {
218 error = rc;
219 }
220 }
221 for(int i = 0; i < power_gpio->num_reset_outs; i++) {
222 rc = gpio_init(connection, &power_gpio->reset_outs[i]);
223 if(rc != GPIO_OK) {
224 error = rc;
225 }
226 }
227
228 rc = gpio_open(&power_gpio->power_good_in);
229 if(rc != GPIO_OK) {
230 return rc;
231 }
232 rc = gpio_read(&power_gpio->power_good_in, &pgood_state);
233 if(rc != GPIO_OK) {
234 return rc;
235 }
236 gpio_close(&power_gpio->power_good_in);
237 control_power_set_pgood(control_power, pgood_state);
238 control_power_set_state(control_power, pgood_state);
239 g_print("Pgood state: %d\n", pgood_state);
240
241 return error;
242}
243
Brad Bishop77390492016-04-13 10:47:19 -0400244static void
245on_bus_acquired(GDBusConnection *connection,
246 const gchar *name,
247 gpointer user_data)
248{
249 ObjectSkeleton *object;
250 cmdline *cmd = user_data;
251 if(cmd->argc < 3)
252 {
253 g_print("Usage: power_control.exe [poll interval] [timeout]\n");
254 return;
255 }
256 manager = g_dbus_object_manager_server_new(dbus_object_path);
257 gchar *s;
258 s = g_strdup_printf("%s/%s",dbus_object_path,instance_name);
259 object = object_skeleton_new(s);
260 g_free(s);
261
262 ControlPower* control_power = control_power_skeleton_new();
263 object_skeleton_set_control_power(object, control_power);
264 g_object_unref(control_power);
265
266 Control* control = control_skeleton_new();
267 object_skeleton_set_control(object, control);
268 g_object_unref(control);
269
Brad Bishop77390492016-04-13 10:47:19 -0400270 //define method callbacks here
271 g_signal_connect(control_power,
272 "handle-set-power-state",
273 G_CALLBACK(on_set_power_state),
274 object); /* user_data */
275
276 g_signal_connect(control_power,
277 "handle-get-power-state",
278 G_CALLBACK(on_get_power_state),
279 NULL); /* user_data */
280
281 g_signal_connect(control,
282 "handle-init",
283 G_CALLBACK(on_init),
284 object); /* user_data */
285
286
287 /* Export the object (@manager takes its own reference to @object) */
Brad Bishop58e694d2016-04-13 16:04:32 -0400288 g_dbus_object_manager_server_set_connection(manager, connection);
Brad Bishop77390492016-04-13 10:47:19 -0400289 g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object));
290 g_object_unref(object);
291
Xo Wang20a19412016-09-22 11:26:14 -0700292 if(read_power_gpio(connection, &g_power_gpio) != TRUE) {
293 g_print("ERROR PowerControl: could not read power GPIO configuration\n");
294 }
Brad Bishop77390492016-04-13 10:47:19 -0400295
Xo Wang20a19412016-09-22 11:26:14 -0700296 int rc = set_up_gpio(connection, &g_power_gpio, control_power);
297 if(rc != GPIO_OK) {
298 g_print("ERROR PowerControl: GPIO setup (rc=%d)\n",rc);
Brad Bishop77390492016-04-13 10:47:19 -0400299 }
300 //start poll
301 pgood_timeout_start = 0;
302 int poll_interval = atoi(cmd->argv[1]);
303 int pgood_timeout = atoi(cmd->argv[2]);
304 if(poll_interval < 1000 || pgood_timeout <5) {
Xo Wang20a19412016-09-22 11:26:14 -0700305 g_print("ERROR PowerControl: poll_interval < 1000 or pgood_timeout < 5\n");
Brad Bishop77390492016-04-13 10:47:19 -0400306 } else {
307 control_set_poll_interval(control,poll_interval);
308 control_power_set_pgood_timeout(control_power,pgood_timeout);
309 g_timeout_add(poll_interval, poll_pgood, object);
310 }
Brad Bishop77390492016-04-13 10:47:19 -0400311}
312
313static void
314on_name_acquired(GDBusConnection *connection,
315 const gchar *name,
316 gpointer user_data)
317{
318}
319
320static void
321on_name_lost(GDBusConnection *connection,
322 const gchar *name,
323 gpointer user_data)
324{
Xo Wang20a19412016-09-22 11:26:14 -0700325 free_power_gpio(&g_power_gpio);
Brad Bishop77390492016-04-13 10:47:19 -0400326}
327
328/*----------------------------------------------------------------*/
329/* Main Event Loop */
330
331gint
332main(gint argc, gchar *argv[])
333{
334 GMainLoop *loop;
335 cmdline cmd;
336 cmd.argc = argc;
337 cmd.argv = argv;
338
339 guint id;
340 loop = g_main_loop_new(NULL, FALSE);
341
342 id = g_bus_own_name(DBUS_TYPE,
343 dbus_name,
344 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
345 G_BUS_NAME_OWNER_FLAGS_REPLACE,
346 on_bus_acquired,
347 on_name_acquired,
348 on_name_lost,
349 &cmd,
350 NULL);
351
352 g_main_loop_run(loop);
353
354 g_bus_unown_name(id);
355 g_main_loop_unref(loop);
356 return 0;
357}