blob: eb6be2126e38b7bfabdeb13a4ca9498a6c4f5fd3 [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
Xo Wang3ab54362016-10-04 14:37:32 -070091 reset_state = pgood_state ^ !g_power_gpio.reset_pols[i];
Xo Wang20a19412016-09-22 11:26:14 -070092 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 }
Xo Wang3ab54362016-10-04 14:37:32 -0700158 power_up_out = state ^ !g_power_gpio.power_up_pols[i];
Xo Wang20a19412016-09-22 11:26:14 -0700159 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
Xo Wangc1ce68b2016-09-22 16:34:37 -0700211 if(power_gpio->latch_out.name != NULL) { /* latch is optional */
212 rc = gpio_init(connection, &power_gpio->latch_out);
213 if(rc != GPIO_OK) {
214 error = rc;
215 }
216 }
Xo Wang20a19412016-09-22 11:26:14 -0700217 rc = gpio_init(connection, &power_gpio->power_good_in);
218 if(rc != GPIO_OK) {
219 error = rc;
220 }
221 for(int i = 0; i < power_gpio->num_power_up_outs; i++) {
222 rc = gpio_init(connection, &power_gpio->power_up_outs[i]);
223 if(rc != GPIO_OK) {
224 error = rc;
225 }
226 }
227 for(int i = 0; i < power_gpio->num_reset_outs; i++) {
228 rc = gpio_init(connection, &power_gpio->reset_outs[i]);
229 if(rc != GPIO_OK) {
230 error = rc;
231 }
232 }
233
Xo Wangc1ce68b2016-09-22 16:34:37 -0700234 /* If there's a latch, it only needs to be set once. */
235 if(power_gpio->latch_out.name != NULL) {
236 do {
237 rc = gpio_open(&power_gpio->latch_out);
238 if(rc != GPIO_OK) {
239 /* Failures are non-fatal. */
240 break;
241 }
242 rc = gpio_write(&power_gpio->latch_out, 1);
243 gpio_close(&power_gpio->latch_out);
244 } while(0);
245 if (rc != GPIO_OK) {
246 error = rc;
247 g_print("PowerControl ERROR failed to assert latch %s rc=%d\n",
248 power_gpio->latch_out.name, rc);
249 } else {
250 g_print("PowerControl asserted latch %s\n", power_gpio->latch_out.name);
251 }
252 }
253
Xo Wang20a19412016-09-22 11:26:14 -0700254 rc = gpio_open(&power_gpio->power_good_in);
255 if(rc != GPIO_OK) {
256 return rc;
257 }
258 rc = gpio_read(&power_gpio->power_good_in, &pgood_state);
259 if(rc != GPIO_OK) {
260 return rc;
261 }
262 gpio_close(&power_gpio->power_good_in);
263 control_power_set_pgood(control_power, pgood_state);
264 control_power_set_state(control_power, pgood_state);
265 g_print("Pgood state: %d\n", pgood_state);
266
267 return error;
268}
269
Brad Bishop77390492016-04-13 10:47:19 -0400270static void
271on_bus_acquired(GDBusConnection *connection,
272 const gchar *name,
273 gpointer user_data)
274{
275 ObjectSkeleton *object;
276 cmdline *cmd = user_data;
277 if(cmd->argc < 3)
278 {
279 g_print("Usage: power_control.exe [poll interval] [timeout]\n");
280 return;
281 }
282 manager = g_dbus_object_manager_server_new(dbus_object_path);
283 gchar *s;
284 s = g_strdup_printf("%s/%s",dbus_object_path,instance_name);
285 object = object_skeleton_new(s);
286 g_free(s);
287
288 ControlPower* control_power = control_power_skeleton_new();
289 object_skeleton_set_control_power(object, control_power);
290 g_object_unref(control_power);
291
292 Control* control = control_skeleton_new();
293 object_skeleton_set_control(object, control);
294 g_object_unref(control);
295
Brad Bishop77390492016-04-13 10:47:19 -0400296 //define method callbacks here
297 g_signal_connect(control_power,
298 "handle-set-power-state",
299 G_CALLBACK(on_set_power_state),
300 object); /* user_data */
301
302 g_signal_connect(control_power,
303 "handle-get-power-state",
304 G_CALLBACK(on_get_power_state),
305 NULL); /* user_data */
306
307 g_signal_connect(control,
308 "handle-init",
309 G_CALLBACK(on_init),
310 object); /* user_data */
311
312
313 /* Export the object (@manager takes its own reference to @object) */
Brad Bishop58e694d2016-04-13 16:04:32 -0400314 g_dbus_object_manager_server_set_connection(manager, connection);
Brad Bishop77390492016-04-13 10:47:19 -0400315 g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object));
316 g_object_unref(object);
317
Xo Wang20a19412016-09-22 11:26:14 -0700318 if(read_power_gpio(connection, &g_power_gpio) != TRUE) {
319 g_print("ERROR PowerControl: could not read power GPIO configuration\n");
320 }
Brad Bishop77390492016-04-13 10:47:19 -0400321
Xo Wang20a19412016-09-22 11:26:14 -0700322 int rc = set_up_gpio(connection, &g_power_gpio, control_power);
323 if(rc != GPIO_OK) {
324 g_print("ERROR PowerControl: GPIO setup (rc=%d)\n",rc);
Brad Bishop77390492016-04-13 10:47:19 -0400325 }
326 //start poll
327 pgood_timeout_start = 0;
328 int poll_interval = atoi(cmd->argv[1]);
329 int pgood_timeout = atoi(cmd->argv[2]);
330 if(poll_interval < 1000 || pgood_timeout <5) {
Xo Wang20a19412016-09-22 11:26:14 -0700331 g_print("ERROR PowerControl: poll_interval < 1000 or pgood_timeout < 5\n");
Brad Bishop77390492016-04-13 10:47:19 -0400332 } else {
333 control_set_poll_interval(control,poll_interval);
334 control_power_set_pgood_timeout(control_power,pgood_timeout);
335 g_timeout_add(poll_interval, poll_pgood, object);
336 }
Brad Bishop77390492016-04-13 10:47:19 -0400337}
338
339static void
340on_name_acquired(GDBusConnection *connection,
341 const gchar *name,
342 gpointer user_data)
343{
344}
345
346static void
347on_name_lost(GDBusConnection *connection,
348 const gchar *name,
349 gpointer user_data)
350{
Xo Wang20a19412016-09-22 11:26:14 -0700351 free_power_gpio(&g_power_gpio);
Brad Bishop77390492016-04-13 10:47:19 -0400352}
353
354/*----------------------------------------------------------------*/
355/* Main Event Loop */
356
357gint
358main(gint argc, gchar *argv[])
359{
360 GMainLoop *loop;
361 cmdline cmd;
362 cmd.argc = argc;
363 cmd.argv = argv;
364
365 guint id;
366 loop = g_main_loop_new(NULL, FALSE);
367
368 id = g_bus_own_name(DBUS_TYPE,
369 dbus_name,
370 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
371 G_BUS_NAME_OWNER_FLAGS_REPLACE,
372 on_bus_acquired,
373 on_name_acquired,
374 on_name_lost,
375 &cmd,
376 NULL);
377
378 g_main_loop_run(loop);
379
380 g_bus_unown_name(id);
381 g_main_loop_unref(loop);
382 return 0;
383}