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 <gpio_configs.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 GpioConfigs g_gpio_configs;
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_gpio_configs.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_gpio_configs.power_gpio.power_good_in.name, rc);
59 		return FALSE;
60 	}
61 	rc = gpio_read(&g_gpio_configs.power_gpio.power_good_in, &pgood_state);
62 	gpio_close(&g_gpio_configs.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_gpio_configs.power_gpio.num_reset_outs; i++)
84 			{
85 				GPIO *reset_out = &g_gpio_configs.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_gpio_configs.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_gpio_configs.power_gpio.num_pci_reset_outs; i++)
102 			{
103 				GPIO *pci_reset_out = &g_gpio_configs.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_gpio_configs.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_gpio_configs.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_gpio_configs.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 *interface;
163 	GVariantIter *properties;
164 	GVariantIter *dummy;
165 	gchar *boot_progress = NULL;
166 	gchar *property;
167 	GVariant *value;
168 	uint8_t pgood_state;
169 	uint8_t reset_state;
170 	int rc;
171 	int i;
172 	int ignore;
173 
174 	if(!parameters)
175 		return;
176 
177 	/* prevent release again */
178 	if(!g_pci_reset_held)
179 		return;
180 
181 	g_variant_get(parameters, "(&sa{sv}as)", &interface, &properties, &dummy);
182 	for(i = 0; g_variant_iter_next(properties, "{&sv}", &property, &value); i++)
183 	{
184 		if (strcmp(property, "BootProgress") == 0)
185 		{
186 			gchar* tmp;
187 			g_variant_get(value, "&s", &tmp);
188 			boot_progress = g_strdup(tmp);
189 			g_print("BootProgress: %s\n", boot_progress);
190 			g_variant_unref(value);
191 		}
192 	}
193 
194 	g_variant_iter_free(properties);
195 	g_variant_iter_free(dummy);
196 	if (boot_progress == NULL)
197 		return;
198 
199 	/* Release PCI reset when FW boot progress goes beyond 'Baseboard Init' */
200 	ignore = strcmp(boot_progress,
201 		"xyz.openbmc_project.State.Boot.Progress.ProgressStages.MotherboardInit") == 0;
202 	g_free(boot_progress);
203 
204 	if (ignore)
205 		return;
206 
207 	rc = gpio_open(&g_gpio_configs.power_gpio.power_good_in);
208 	if(rc != GPIO_OK)
209 	{
210 		g_print("ERROR PowerControl: on_boot_progress(): GPIO open error (gpio=%s,rc=%d)\n",
211 			g_gpio_configs.power_gpio.power_good_in.name, rc);
212 		return;
213 	}
214 	rc = gpio_read(&g_gpio_configs.power_gpio.power_good_in, &pgood_state);
215 	gpio_close(&g_gpio_configs.power_gpio.power_good_in);
216 	if(rc != GPIO_OK || pgood_state != 1)
217 		return;
218 
219 	for(i = 0; i < g_gpio_configs.power_gpio.num_pci_reset_outs; i++)
220 	{
221 		GPIO *pci_reset_out = &g_gpio_configs.power_gpio.pci_reset_outs[i];
222 
223 		if(!g_gpio_configs.power_gpio.pci_reset_holds[i])
224 			continue;
225 		rc = gpio_open(pci_reset_out);
226 		if(rc != GPIO_OK)
227 		{
228 			g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
229 					pci_reset_out->name, rc);
230 			continue;
231 		}
232 
233 		reset_state = pgood_state ^ g_gpio_configs.power_gpio.pci_reset_pols[i];
234 		g_print("PowerControl: pgood: %d, setting pci reset %s to %d\n",
235 				(int)pgood_state, pci_reset_out->name, (int)reset_state);
236 		gpio_write(pci_reset_out, reset_state);
237 		gpio_close(pci_reset_out);
238 		g_print("Released pci reset: %s\n", pci_reset_out->name);
239 	}
240 	g_pci_reset_held = 0;
241 }
242 
243 static gboolean
244 on_set_power_state(ControlPower *pwr,
245 		GDBusMethodInvocation *invocation,
246 		guint state,
247 		gpointer user_data)
248 {
249 	Control* control = object_get_control((Object*)user_data);
250 	PowerGpio *power_gpio = &g_gpio_configs.power_gpio;
251 	if(state > 1)
252 	{
253 		g_dbus_method_invocation_return_dbus_error(invocation,
254 				"org.openbmc.ControlPower.Error.Failed",
255 				"Invalid power state");
256 		return TRUE;
257 	}
258 	// return from method call
259 	control_power_complete_set_power_state(pwr,invocation);
260 	if(state == control_power_get_state(pwr))
261 	{
262 		g_print("Power already at requested state: %d\n",state);
263 	}
264 	else
265 	{
266 		int error = 0;
267 		do {
268 			int i;
269 			uint8_t power_up_out;
270 			if(state == 1) {
271 				control_emit_goto_system_state(control,"HOST_POWERING_ON");
272 			} else {
273 				control_emit_goto_system_state(control,"HOST_POWERING_OFF");
274 			}
275 			for (i = 0; i < power_gpio->num_power_up_outs; i++) {
276 				GPIO *power_pin = &power_gpio->power_up_outs[i];
277 				error = gpio_open(power_pin);
278 				if(error != GPIO_OK) {
279 					g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
280 							power_gpio->power_up_outs[i].name, error);
281 					continue;
282 				}
283 				power_up_out = state ^ !power_gpio->power_up_pols[i];
284 				g_print("PowerControl: setting power up %s to %d\n",
285 						power_gpio->power_up_outs[i].name, (int)power_up_out);
286 				error = gpio_write(power_pin, power_up_out);
287 				if(error != GPIO_OK) {
288 					continue;
289 				}
290 				gpio_close(power_pin);
291 			}
292 			if(error != GPIO_OK) { break;	}
293 			control_power_set_state(pwr,state);
294 		} while(0);
295 		if(error != GPIO_OK)
296 		{
297 			g_print("ERROR PowerControl: GPIO set power state (rc=%d)\n",error);
298 		}
299 
300 		/* If there's a latch, it should be enabled following changes to the
301 		 * power pins' states. This commits the changes to the latch states. */
302 		if (power_gpio->latch_out.name != NULL) {
303 			int rc;
304 			uint8_t latch_value = 0;
305 			rc = gpio_open(&power_gpio->latch_out);
306 			if (rc != GPIO_OK) {
307 				/* Failures are non-fatal. */
308 				g_print("PowerControl ERROR failed to open latch %s rc=%d\n",
309 						power_gpio->latch_out.name, rc);
310 				return TRUE;
311 			}
312 			/* Make the latch transparent for as brief of a time as possible. */
313 			rc = gpio_write(&power_gpio->latch_out, 1);
314 			if (rc != GPIO_OK) {
315 				g_print("PowerControl ERROR failed to assert latch %s rc=%d\n",
316 						power_gpio->latch_out.name, rc);
317 			} else {
318 				g_print("PowerControl asserted latch %s\n",
319 						power_gpio->latch_out.name);
320 			}
321 			rc = gpio_write(&power_gpio->latch_out, 0);
322 			if (rc != GPIO_OK) {
323 				g_print("PowerControl ERROR failed to clear latch %s rc=%d\n",
324 						power_gpio->latch_out.name, rc);
325 			}
326 			gpio_close(&power_gpio->latch_out);
327 		}
328 	}
329 
330 	return TRUE;
331 }
332 
333 static gboolean
334 on_init(Control *control,
335 		GDBusMethodInvocation *invocation,
336 		gpointer user_data)
337 {
338 	pgood_timeout_start = 0;
339 	//guint poll_interval = control_get_poll_interval(control);
340 	//g_timeout_add(poll_interval, poll_pgood, user_data);
341 	control_complete_init(control,invocation);
342 	return TRUE;
343 }
344 
345 static gboolean
346 on_get_power_state(ControlPower *pwr,
347 		GDBusMethodInvocation *invocation,
348 		gpointer user_data)
349 {
350 	guint pgood = control_power_get_pgood(pwr);
351 	control_power_complete_get_power_state(pwr,invocation,pgood);
352 	return TRUE;
353 }
354 
355 static int
356 set_up_gpio(GDBusConnection *connection,
357 		PowerGpio *power_gpio,
358 		ControlPower* control_power)
359 {
360 	int error = GPIO_OK;
361 	int rc;
362 	int i;
363 	uint8_t pgood_state;
364 
365 	// get gpio device paths
366 	if(power_gpio->latch_out.name != NULL) {  /* latch is optional */
367 		rc = gpio_init(connection, &power_gpio->latch_out);
368 		if(rc != GPIO_OK) {
369 			error = rc;
370 		}
371 	}
372 	rc = gpio_init(connection, &power_gpio->power_good_in);
373 	if(rc != GPIO_OK) {
374 		error = rc;
375 	}
376 	for(int i = 0; i < power_gpio->num_power_up_outs; i++) {
377 		rc = gpio_init(connection, &power_gpio->power_up_outs[i]);
378 		if(rc != GPIO_OK) {
379 			error = rc;
380 		}
381 	}
382 	for(int i = 0; i < power_gpio->num_reset_outs; i++) {
383 		rc = gpio_init(connection, &power_gpio->reset_outs[i]);
384 		if(rc != GPIO_OK) {
385 			error = rc;
386 		}
387 	}
388 	for(int i = 0; i < power_gpio->num_pci_reset_outs; i++) {
389 		rc = gpio_init(connection, &power_gpio->pci_reset_outs[i]);
390 		if(rc != GPIO_OK) {
391 			error = rc;
392 		}
393 	}
394 
395 	rc = gpio_open(&power_gpio->power_good_in);
396 	if(rc != GPIO_OK) {
397 		return rc;
398 	}
399 	rc = gpio_read(&power_gpio->power_good_in, &pgood_state);
400 	if(rc != GPIO_OK) {
401 		return rc;
402 	}
403 	gpio_close(&power_gpio->power_good_in);
404 	control_power_set_pgood(control_power, pgood_state);
405 	control_power_set_state(control_power, pgood_state);
406 	g_print("Pgood state: %d\n", pgood_state);
407 
408 	return error;
409 }
410 
411 static void
412 on_bus_acquired(GDBusConnection *connection,
413 		const gchar *name,
414 		gpointer user_data)
415 {
416 	ObjectSkeleton *object;
417 	cmdline *cmd = user_data;
418 	if(cmd->argc < 3)
419 	{
420 		g_print("Usage: power_control.exe [poll interval] [timeout]\n");
421 		return;
422 	}
423 	manager = g_dbus_object_manager_server_new(dbus_object_path);
424 	gchar *s;
425 	s = g_strdup_printf("%s/%s",dbus_object_path,instance_name);
426 	object = object_skeleton_new(s);
427 	g_free(s);
428 
429 	ControlPower* control_power = control_power_skeleton_new();
430 	object_skeleton_set_control_power(object, control_power);
431 	g_object_unref(control_power);
432 
433 	Control* control = control_skeleton_new();
434 	object_skeleton_set_control(object, control);
435 	g_object_unref(control);
436 
437 	//define method callbacks here
438 	g_signal_connect(control_power,
439 			"handle-set-power-state",
440 			G_CALLBACK(on_set_power_state),
441 			object); /* user_data */
442 
443 	g_signal_connect(control_power,
444 			"handle-get-power-state",
445 			G_CALLBACK(on_get_power_state),
446 			NULL); /* user_data */
447 
448 	g_signal_connect(control,
449 			"handle-init",
450 			G_CALLBACK(on_init),
451 			object); /* user_data */
452 
453 	/* Listen for BootProgress signal from BootProgress sensor */
454 	g_dbus_connection_signal_subscribe(connection,
455 			NULL, /* service */
456 			"org.freedesktop.DBus.Properties", /* interface_name */
457 			"PropertiesChanged", /* member: name of the signal */
458 			"/xyz/openbmc_project/state/host0", /* obj path */
459 			NULL, /* arg0 */
460 			G_DBUS_SIGNAL_FLAGS_NONE,
461 			(GDBusSignalCallback) on_boot_progress,
462 			object, /* user data */
463 			NULL );
464 
465 	/* Export the object (@manager takes its own reference to @object) */
466 	g_dbus_object_manager_server_set_connection(manager, connection);
467 	g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object));
468 	g_object_unref(object);
469 
470 	if(read_gpios(connection, &g_gpio_configs) != TRUE) {
471 		g_print("ERROR PowerControl: could not read power GPIO configuration\n");
472 	}
473 
474 	int rc = set_up_gpio(connection, &g_gpio_configs.power_gpio, control_power);
475 	if(rc != GPIO_OK) {
476 		g_print("ERROR PowerControl: GPIO setup (rc=%d)\n",rc);
477 	}
478 	//start poll
479 	pgood_timeout_start = 0;
480 	int poll_interval = atoi(cmd->argv[1]);
481 	int pgood_timeout = atoi(cmd->argv[2]);
482 	if(poll_interval < 500 || pgood_timeout <5) {
483 		g_print("ERROR PowerControl: poll_interval < 500 or pgood_timeout < 5\n");
484 	} else {
485 		control_set_poll_interval(control,poll_interval);
486 		control_power_set_pgood_timeout(control_power,pgood_timeout);
487 		g_timeout_add(poll_interval, poll_pgood, object);
488 	}
489 }
490 
491 static void
492 on_name_acquired(GDBusConnection *connection,
493 		const gchar *name,
494 		gpointer user_data)
495 {
496 }
497 
498 static void
499 on_name_lost(GDBusConnection *connection,
500 		const gchar *name,
501 		gpointer user_data)
502 {
503 	free_gpios(&g_gpio_configs);
504 }
505 
506 /*----------------------------------------------------------------*/
507 /* Main Event Loop                                                */
508 
509 gint
510 main(gint argc, gchar *argv[])
511 {
512 	GMainLoop *loop;
513 	cmdline cmd;
514 	cmd.argc = argc;
515 	cmd.argv = argv;
516 
517 	guint id;
518 	loop = g_main_loop_new(NULL, FALSE);
519 
520 	id = g_bus_own_name(DBUS_TYPE,
521 			dbus_name,
522 			G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
523 			G_BUS_NAME_OWNER_FLAGS_REPLACE,
524 			on_bus_acquired,
525 			on_name_acquired,
526 			on_name_lost,
527 			&cmd,
528 			NULL);
529 
530 	g_main_loop_run(loop);
531 
532 	g_bus_unown_name(id);
533 	g_main_loop_unref(loop);
534 	return 0;
535 }
536