1 #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>
10 #include <openbmc_intf.h>
11 #include <openbmc.h>
12 #include <gpio.h>
13 #include <power_gpio.h>
14 
15 /* ------------------------------------------------------------------------- */
16 static const gchar* dbus_object_path = "/org/openbmc/control";
17 static const gchar* instance_name = "power0";
18 static const gchar* dbus_name = "org.openbmc.control.Power";
19 
20 static int g_pci_reset_held = 1;
21 
22 static PowerGpio g_power_gpio;
23 
24 static GDBusObjectManagerServer *manager = NULL;
25 
26 time_t pgood_timeout_start = 0;
27 
28 // TODO:  Change to interrupt driven instead of polling
29 static gboolean
30 poll_pgood(gpointer user_data)
31 {
32 	ControlPower *control_power = object_get_control_power((Object*)user_data);
33 	Control* control = object_get_control((Object*)user_data);
34 
35 	//send the heartbeat
36 	guint poll_int = control_get_poll_interval(control);
37 	if(poll_int == 0)
38 	{
39 		g_print("ERROR PowerControl: Poll interval cannot be 0\n");
40 		return FALSE;
41 	}
42 	//handle timeout
43 	time_t current_time = time(NULL);
44 	if(difftime(current_time,pgood_timeout_start) > control_power_get_pgood_timeout(control_power)
45 			&& pgood_timeout_start != 0)
46 	{
47 		g_print("ERROR PowerControl: Pgood poll timeout\n");
48 		// set timeout to 0 so timeout doesn't happen again
49 		control_power_set_pgood_timeout(control_power,0);
50 		pgood_timeout_start = 0;
51 		return TRUE;
52 	}
53 	uint8_t pgood_state;
54 
55 	int rc = gpio_open(&g_power_gpio.power_good_in);
56 	if(rc != GPIO_OK) {
57 		g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
58 				g_power_gpio.power_good_in.name, rc);
59 		return FALSE;
60 	}
61 	rc = gpio_read(&g_power_gpio.power_good_in, &pgood_state);
62 	gpio_close(&g_power_gpio.power_good_in);
63 	if(rc == GPIO_OK)
64 	{
65 		//if changed, set property and emit signal
66 		if(pgood_state != control_power_get_pgood(control_power))
67 		{
68 			int i;
69 			uint8_t reset_state;
70 			control_power_set_pgood(control_power, pgood_state);
71 			if(pgood_state == 0)
72 			{
73 				control_power_emit_power_lost(control_power);
74 				control_emit_goto_system_state(control,"HOST_POWERED_OFF");
75 				g_pci_reset_held = 1;
76 			}
77 			else
78 			{
79 				control_power_emit_power_good(control_power);
80 				control_emit_goto_system_state(control,"HOST_POWERED_ON");
81 			}
82 
83 			for(i = 0; i < g_power_gpio.num_reset_outs; i++)
84 			{
85 				GPIO *reset_out = &g_power_gpio.reset_outs[i];
86 				rc = gpio_open(reset_out);
87 				if(rc != GPIO_OK)
88 				{
89 					g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
90 							reset_out->name, rc);
91 					continue;
92 				}
93 
94 				reset_state = pgood_state ^ g_power_gpio.reset_pols[i];
95 				g_print("PowerControl: pgood: %d, setting reset %s to %d\n",
96 					(int)pgood_state, reset_out->name, (int)reset_state);
97 				gpio_write(reset_out, reset_state);
98 				gpio_close(reset_out);
99 			}
100 
101 			for(i = 0; i < g_power_gpio.num_pci_reset_outs; i++)
102 			{
103 				GPIO *pci_reset_out = &g_power_gpio.pci_reset_outs[i];
104 				if(pgood_state == 1)
105 				{
106 					/*
107 					 * When powering on, hold PCI reset until
108 					 * the processor can forward clocks and control reset.
109 					 */
110 					if(g_power_gpio.pci_reset_holds[i])
111 					{
112 						g_print("Holding pci reset: %s\n", pci_reset_out->name);
113 						continue;
114 					}
115 				}
116 				rc = gpio_open(pci_reset_out);
117 				if(rc != GPIO_OK)
118 				{
119 					g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
120 							pci_reset_out->name, rc);
121 					continue;
122 				}
123 
124 				reset_state = pgood_state ^ g_power_gpio.pci_reset_pols[i];
125 				g_print("PowerControl: pgood: %d, setting pci reset %s to %d\n",
126 					(int)pgood_state, pci_reset_out->name, (int)reset_state);
127 				gpio_write(pci_reset_out, reset_state);
128 				gpio_close(pci_reset_out);
129 			}
130 		}
131 	} else {
132 		g_print("ERROR PowerControl: GPIO read error (gpio=%s,rc=%d)\n",
133 				g_power_gpio.power_good_in.name, rc);
134 		//return false so poll won't get called anymore
135 		return FALSE;
136 	}
137 	//pgood is not at desired state yet
138 	if(pgood_state != control_power_get_state(control_power) &&
139 			control_power_get_pgood_timeout(control_power) > 0)
140 	{
141 		if(pgood_timeout_start == 0 ) {
142 			pgood_timeout_start = current_time;
143 		}
144 	}
145 	else
146 	{
147 		pgood_timeout_start = 0;
148 	}
149 	return TRUE;
150 }
151 
152 /* Handler for BootProgress signal from BootProgress sensor */
153 static void
154 on_boot_progress(GDBusConnection *connection,
155 		const gchar *sender_name,
156 		const gchar *object_path,
157 		const gchar *interface_name,
158 		const gchar *signal_name,
159 		GVariant *parameters,
160 		gpointer user_data)
161 {
162 	gchar *boot_progress;
163 	uint8_t pgood_state;
164 	uint8_t reset_state;
165 	int rc;
166 	int i;
167 
168 	if(!parameters)
169 		return;
170 
171 	/* prevent release again */
172 	if(!g_pci_reset_held)
173 		return;
174 
175 	g_variant_get(parameters, "(s)", &boot_progress);
176 	/* Release PCI reset when FW boot progress goes beyond 'Baseboard Init' */
177 	if(strcmp(boot_progress, "FW Progress, Baseboard Init") == 0)
178 		return;
179 
180 	rc = gpio_open(&g_power_gpio.power_good_in);
181 	if(rc != GPIO_OK)
182 	{
183 		g_print("ERROR PowerControl: on_boot_progress(): GPIO open error (gpio=%s,rc=%d)\n",
184 			g_power_gpio.power_good_in.name, rc);
185 		return;
186 	}
187 	rc = gpio_read(&g_power_gpio.power_good_in, &pgood_state);
188 	gpio_close(&g_power_gpio.power_good_in);
189 	if(rc != GPIO_OK || pgood_state != 1)
190 		return;
191 
192 	for(i = 0; i < g_power_gpio.num_pci_reset_outs; i++)
193 	{
194 		GPIO *pci_reset_out = &g_power_gpio.pci_reset_outs[i];
195 
196 		if(!g_power_gpio.pci_reset_holds[i])
197 			continue;
198 		rc = gpio_open(pci_reset_out);
199 		if(rc != GPIO_OK)
200 		{
201 			g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
202 					pci_reset_out->name, rc);
203 			continue;
204 		}
205 
206 		reset_state = pgood_state ^ g_power_gpio.pci_reset_pols[i];
207 		g_print("PowerControl: pgood: %d, setting pci reset %s to %d\n",
208 			(int)pgood_state, pci_reset_out->name, (int)reset_state);
209 		gpio_write(pci_reset_out, reset_state);
210 		gpio_close(pci_reset_out);
211 		g_print("Released pci reset: %s - %s\n", pci_reset_out->name, boot_progress);
212 	}
213 	g_pci_reset_held = 0;
214 }
215 
216 static gboolean
217 on_set_power_state(ControlPower *pwr,
218 		GDBusMethodInvocation *invocation,
219 		guint state,
220 		gpointer user_data)
221 {
222 	Control* control = object_get_control((Object*)user_data);
223 	if(state > 1)
224 	{
225 		g_dbus_method_invocation_return_dbus_error(invocation,
226 				"org.openbmc.ControlPower.Error.Failed",
227 				"Invalid power state");
228 		return TRUE;
229 	}
230 	// return from method call
231 	control_power_complete_set_power_state(pwr,invocation);
232 	if(state == control_power_get_state(pwr))
233 	{
234 		g_print("Power already at requested state: %d\n",state);
235 	}
236 	else
237 	{
238 		int error = 0;
239 		do {
240 			int i;
241 			uint8_t power_up_out;
242 			if(state == 1) {
243 				control_emit_goto_system_state(control,"HOST_POWERING_ON");
244 			} else {
245 				control_emit_goto_system_state(control,"HOST_POWERING_OFF");
246 			}
247 			for (i = 0; i < g_power_gpio.num_power_up_outs; i++) {
248 				GPIO *power_pin = &g_power_gpio.power_up_outs[i];
249 				error = gpio_open(power_pin);
250 				if(error != GPIO_OK) {
251 					g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
252 							g_power_gpio.power_up_outs[i].name, error);
253 					continue;
254 				}
255 				power_up_out = state ^ !g_power_gpio.power_up_pols[i];
256 				g_print("PowerControl: setting power up %s to %d\n",
257 						g_power_gpio.power_up_outs[i].name, (int)power_up_out);
258 				error = gpio_write(power_pin, power_up_out);
259 				if(error != GPIO_OK) {
260 					continue;
261 				}
262 				gpio_close(power_pin);
263 			}
264 			if(error != GPIO_OK) { break;	}
265 			control_power_set_state(pwr,state);
266 		} while(0);
267 		if(error != GPIO_OK)
268 		{
269 			g_print("ERROR PowerControl: GPIO set power state (rc=%d)\n",error);
270 		}
271 	}
272 	return TRUE;
273 }
274 
275 static gboolean
276 on_init(Control *control,
277 		GDBusMethodInvocation *invocation,
278 		gpointer user_data)
279 {
280 	pgood_timeout_start = 0;
281 	//guint poll_interval = control_get_poll_interval(control);
282 	//g_timeout_add(poll_interval, poll_pgood, user_data);
283 	control_complete_init(control,invocation);
284 	return TRUE;
285 }
286 
287 static gboolean
288 on_get_power_state(ControlPower *pwr,
289 		GDBusMethodInvocation *invocation,
290 		gpointer user_data)
291 {
292 	guint pgood = control_power_get_pgood(pwr);
293 	control_power_complete_get_power_state(pwr,invocation,pgood);
294 	return TRUE;
295 }
296 
297 static int
298 set_up_gpio(GDBusConnection *connection,
299 		PowerGpio *power_gpio,
300 		ControlPower* control_power)
301 {
302 	int error = GPIO_OK;
303 	int rc;
304 	int i;
305 	uint8_t pgood_state;
306 
307 	// get gpio device paths
308 	if(power_gpio->latch_out.name != NULL) {  /* latch is optional */
309 		rc = gpio_init(connection, &power_gpio->latch_out);
310 		if(rc != GPIO_OK) {
311 			error = rc;
312 		}
313 	}
314 	rc = gpio_init(connection, &power_gpio->power_good_in);
315 	if(rc != GPIO_OK) {
316 		error = rc;
317 	}
318 	for(int i = 0; i < power_gpio->num_power_up_outs; i++) {
319 		rc = gpio_init(connection, &power_gpio->power_up_outs[i]);
320 		if(rc != GPIO_OK) {
321 			error = rc;
322 		}
323 	}
324 	for(int i = 0; i < power_gpio->num_reset_outs; i++) {
325 		rc = gpio_init(connection, &power_gpio->reset_outs[i]);
326 		if(rc != GPIO_OK) {
327 			error = rc;
328 		}
329 	}
330 	for(int i = 0; i < power_gpio->num_pci_reset_outs; i++) {
331 		rc = gpio_init(connection, &power_gpio->pci_reset_outs[i]);
332 		if(rc != GPIO_OK) {
333 			error = rc;
334 		}
335 	}
336 
337 	/* If there's a latch, it only needs to be set once. */
338 	if(power_gpio->latch_out.name != NULL) {
339 		do {
340 			rc = gpio_open(&power_gpio->latch_out);
341 			if(rc != GPIO_OK) {
342 				/* Failures are non-fatal. */
343 				break;
344 			}
345 			rc = gpio_write(&power_gpio->latch_out, 1);
346 			gpio_close(&power_gpio->latch_out);
347 		} while(0);
348 		if (rc != GPIO_OK) {
349 			error = rc;
350 			g_print("PowerControl ERROR failed to assert latch %s rc=%d\n",
351 					power_gpio->latch_out.name, rc);
352 		} else {
353 			g_print("PowerControl asserted latch %s\n", power_gpio->latch_out.name);
354 		}
355 	}
356 
357 	rc = gpio_open(&power_gpio->power_good_in);
358 	if(rc != GPIO_OK) {
359 		return rc;
360 	}
361 	rc = gpio_read(&power_gpio->power_good_in, &pgood_state);
362 	if(rc != GPIO_OK) {
363 		return rc;
364 	}
365 	gpio_close(&power_gpio->power_good_in);
366 	control_power_set_pgood(control_power, pgood_state);
367 	control_power_set_state(control_power, pgood_state);
368 	g_print("Pgood state: %d\n", pgood_state);
369 
370 	return error;
371 }
372 
373 static void
374 on_bus_acquired(GDBusConnection *connection,
375 		const gchar *name,
376 		gpointer user_data)
377 {
378 	ObjectSkeleton *object;
379 	cmdline *cmd = user_data;
380 	if(cmd->argc < 3)
381 	{
382 		g_print("Usage: power_control.exe [poll interval] [timeout]\n");
383 		return;
384 	}
385 	manager = g_dbus_object_manager_server_new(dbus_object_path);
386 	gchar *s;
387 	s = g_strdup_printf("%s/%s",dbus_object_path,instance_name);
388 	object = object_skeleton_new(s);
389 	g_free(s);
390 
391 	ControlPower* control_power = control_power_skeleton_new();
392 	object_skeleton_set_control_power(object, control_power);
393 	g_object_unref(control_power);
394 
395 	Control* control = control_skeleton_new();
396 	object_skeleton_set_control(object, control);
397 	g_object_unref(control);
398 
399 	//define method callbacks here
400 	g_signal_connect(control_power,
401 			"handle-set-power-state",
402 			G_CALLBACK(on_set_power_state),
403 			object); /* user_data */
404 
405 	g_signal_connect(control_power,
406 			"handle-get-power-state",
407 			G_CALLBACK(on_get_power_state),
408 			NULL); /* user_data */
409 
410 	g_signal_connect(control,
411 			"handle-init",
412 			G_CALLBACK(on_init),
413 			object); /* user_data */
414 
415 	/* Listen for BootProgress signal from BootProgress sensor */
416 	g_dbus_connection_signal_subscribe(connection,
417 			NULL, /* service */
418 			NULL, /* interface_name */
419 			"BootProgress", /* member: name of the signal */
420 			"/org/openbmc/sensors/host/BootProgress", /* obj path */
421 			NULL, /* arg0 */
422 			G_DBUS_SIGNAL_FLAGS_NONE,
423 			(GDBusSignalCallback) on_boot_progress,
424 			object, /* user data */
425 			NULL );
426 
427 	/* Export the object (@manager takes its own reference to @object) */
428 	g_dbus_object_manager_server_set_connection(manager, connection);
429 	g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object));
430 	g_object_unref(object);
431 
432 	if(read_power_gpio(connection, &g_power_gpio) != TRUE) {
433 		g_print("ERROR PowerControl: could not read power GPIO configuration\n");
434 	}
435 
436 	int rc = set_up_gpio(connection, &g_power_gpio, control_power);
437 	if(rc != GPIO_OK) {
438 		g_print("ERROR PowerControl: GPIO setup (rc=%d)\n",rc);
439 	}
440 	//start poll
441 	pgood_timeout_start = 0;
442 	int poll_interval = atoi(cmd->argv[1]);
443 	int pgood_timeout = atoi(cmd->argv[2]);
444 	if(poll_interval < 1000 || pgood_timeout <5) {
445 		g_print("ERROR PowerControl: poll_interval < 1000 or pgood_timeout < 5\n");
446 	} else {
447 		control_set_poll_interval(control,poll_interval);
448 		control_power_set_pgood_timeout(control_power,pgood_timeout);
449 		g_timeout_add(poll_interval, poll_pgood, object);
450 	}
451 }
452 
453 static void
454 on_name_acquired(GDBusConnection *connection,
455 		const gchar *name,
456 		gpointer user_data)
457 {
458 }
459 
460 static void
461 on_name_lost(GDBusConnection *connection,
462 		const gchar *name,
463 		gpointer user_data)
464 {
465 	free_power_gpio(&g_power_gpio);
466 }
467 
468 /*----------------------------------------------------------------*/
469 /* Main Event Loop                                                */
470 
471 gint
472 main(gint argc, gchar *argv[])
473 {
474 	GMainLoop *loop;
475 	cmdline cmd;
476 	cmd.argc = argc;
477 	cmd.argv = argv;
478 
479 	guint id;
480 	loop = g_main_loop_new(NULL, FALSE);
481 
482 	id = g_bus_own_name(DBUS_TYPE,
483 			dbus_name,
484 			G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
485 			G_BUS_NAME_OWNER_FLAGS_REPLACE,
486 			on_bus_acquired,
487 			on_name_acquired,
488 			on_name_lost,
489 			&cmd,
490 			NULL);
491 
492 	g_main_loop_run(loop);
493 
494 	g_bus_unown_name(id);
495 	g_main_loop_unref(loop);
496 	return 0;
497 }
498