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 *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_gpio_configs.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_gpio_configs.power_gpio.power_good_in.name, rc);
185 		return;
186 	}
187 	rc = gpio_read(&g_gpio_configs.power_gpio.power_good_in, &pgood_state);
188 	gpio_close(&g_gpio_configs.power_gpio.power_good_in);
189 	if(rc != GPIO_OK || pgood_state != 1)
190 		return;
191 
192 	for(i = 0; i < g_gpio_configs.power_gpio.num_pci_reset_outs; i++)
193 	{
194 		GPIO *pci_reset_out = &g_gpio_configs.power_gpio.pci_reset_outs[i];
195 
196 		if(!g_gpio_configs.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_gpio_configs.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 	PowerGpio *power_gpio = &g_gpio_configs.power_gpio;
224 	if(state > 1)
225 	{
226 		g_dbus_method_invocation_return_dbus_error(invocation,
227 				"org.openbmc.ControlPower.Error.Failed",
228 				"Invalid power state");
229 		return TRUE;
230 	}
231 	// return from method call
232 	control_power_complete_set_power_state(pwr,invocation);
233 	if(state == control_power_get_state(pwr))
234 	{
235 		g_print("Power already at requested state: %d\n",state);
236 	}
237 	else
238 	{
239 		int error = 0;
240 		do {
241 			int i;
242 			uint8_t power_up_out;
243 			if(state == 1) {
244 				control_emit_goto_system_state(control,"HOST_POWERING_ON");
245 			} else {
246 				control_emit_goto_system_state(control,"HOST_POWERING_OFF");
247 			}
248 			for (i = 0; i < power_gpio->num_power_up_outs; i++) {
249 				GPIO *power_pin = &power_gpio->power_up_outs[i];
250 				error = gpio_open(power_pin);
251 				if(error != GPIO_OK) {
252 					g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
253 							power_gpio->power_up_outs[i].name, error);
254 					continue;
255 				}
256 				power_up_out = state ^ !power_gpio->power_up_pols[i];
257 				g_print("PowerControl: setting power up %s to %d\n",
258 						power_gpio->power_up_outs[i].name, (int)power_up_out);
259 				error = gpio_write(power_pin, power_up_out);
260 				if(error != GPIO_OK) {
261 					continue;
262 				}
263 				gpio_close(power_pin);
264 			}
265 			if(error != GPIO_OK) { break;	}
266 			control_power_set_state(pwr,state);
267 		} while(0);
268 		if(error != GPIO_OK)
269 		{
270 			g_print("ERROR PowerControl: GPIO set power state (rc=%d)\n",error);
271 		}
272 
273 		/* If there's a latch, it should be enabled following changes to the
274 		 * power pins' states. This commits the changes to the latch states. */
275 		if (power_gpio->latch_out.name != NULL) {
276 			int rc;
277 			uint8_t latch_value = 0;
278 			rc = gpio_open(&power_gpio->latch_out);
279 			if (rc != GPIO_OK) {
280 				/* Failures are non-fatal. */
281 				g_print("PowerControl ERROR failed to open latch %s rc=%d\n",
282 						power_gpio->latch_out.name, rc);
283 				return TRUE;
284 			}
285 			/* Make the latch transparent for as brief of a time as possible. */
286 			rc = gpio_write(&power_gpio->latch_out, 1);
287 			if (rc != GPIO_OK) {
288 				g_print("PowerControl ERROR failed to assert latch %s rc=%d\n",
289 						power_gpio->latch_out.name, rc);
290 			} else {
291 				g_print("PowerControl asserted latch %s\n",
292 						power_gpio->latch_out.name);
293 			}
294 			rc = gpio_write(&power_gpio->latch_out, 0);
295 			if (rc != GPIO_OK) {
296 				g_print("PowerControl ERROR failed to clear latch %s rc=%d\n",
297 						power_gpio->latch_out.name, rc);
298 			}
299 			gpio_close(&power_gpio->latch_out);
300 		}
301 	}
302 
303 	return TRUE;
304 }
305 
306 static gboolean
307 on_init(Control *control,
308 		GDBusMethodInvocation *invocation,
309 		gpointer user_data)
310 {
311 	pgood_timeout_start = 0;
312 	//guint poll_interval = control_get_poll_interval(control);
313 	//g_timeout_add(poll_interval, poll_pgood, user_data);
314 	control_complete_init(control,invocation);
315 	return TRUE;
316 }
317 
318 static gboolean
319 on_get_power_state(ControlPower *pwr,
320 		GDBusMethodInvocation *invocation,
321 		gpointer user_data)
322 {
323 	guint pgood = control_power_get_pgood(pwr);
324 	control_power_complete_get_power_state(pwr,invocation,pgood);
325 	return TRUE;
326 }
327 
328 static int
329 set_up_gpio(GDBusConnection *connection,
330 		PowerGpio *power_gpio,
331 		ControlPower* control_power)
332 {
333 	int error = GPIO_OK;
334 	int rc;
335 	int i;
336 	uint8_t pgood_state;
337 
338 	// get gpio device paths
339 	if(power_gpio->latch_out.name != NULL) {  /* latch is optional */
340 		rc = gpio_init(connection, &power_gpio->latch_out);
341 		if(rc != GPIO_OK) {
342 			error = rc;
343 		}
344 	}
345 	rc = gpio_init(connection, &power_gpio->power_good_in);
346 	if(rc != GPIO_OK) {
347 		error = rc;
348 	}
349 	for(int i = 0; i < power_gpio->num_power_up_outs; i++) {
350 		rc = gpio_init(connection, &power_gpio->power_up_outs[i]);
351 		if(rc != GPIO_OK) {
352 			error = rc;
353 		}
354 	}
355 	for(int i = 0; i < power_gpio->num_reset_outs; i++) {
356 		rc = gpio_init(connection, &power_gpio->reset_outs[i]);
357 		if(rc != GPIO_OK) {
358 			error = rc;
359 		}
360 	}
361 	for(int i = 0; i < power_gpio->num_pci_reset_outs; i++) {
362 		rc = gpio_init(connection, &power_gpio->pci_reset_outs[i]);
363 		if(rc != GPIO_OK) {
364 			error = rc;
365 		}
366 	}
367 
368 	rc = gpio_open(&power_gpio->power_good_in);
369 	if(rc != GPIO_OK) {
370 		return rc;
371 	}
372 	rc = gpio_read(&power_gpio->power_good_in, &pgood_state);
373 	if(rc != GPIO_OK) {
374 		return rc;
375 	}
376 	gpio_close(&power_gpio->power_good_in);
377 	control_power_set_pgood(control_power, pgood_state);
378 	control_power_set_state(control_power, pgood_state);
379 	g_print("Pgood state: %d\n", pgood_state);
380 
381 	return error;
382 }
383 
384 static void
385 on_bus_acquired(GDBusConnection *connection,
386 		const gchar *name,
387 		gpointer user_data)
388 {
389 	ObjectSkeleton *object;
390 	cmdline *cmd = user_data;
391 	if(cmd->argc < 3)
392 	{
393 		g_print("Usage: power_control.exe [poll interval] [timeout]\n");
394 		return;
395 	}
396 	manager = g_dbus_object_manager_server_new(dbus_object_path);
397 	gchar *s;
398 	s = g_strdup_printf("%s/%s",dbus_object_path,instance_name);
399 	object = object_skeleton_new(s);
400 	g_free(s);
401 
402 	ControlPower* control_power = control_power_skeleton_new();
403 	object_skeleton_set_control_power(object, control_power);
404 	g_object_unref(control_power);
405 
406 	Control* control = control_skeleton_new();
407 	object_skeleton_set_control(object, control);
408 	g_object_unref(control);
409 
410 	//define method callbacks here
411 	g_signal_connect(control_power,
412 			"handle-set-power-state",
413 			G_CALLBACK(on_set_power_state),
414 			object); /* user_data */
415 
416 	g_signal_connect(control_power,
417 			"handle-get-power-state",
418 			G_CALLBACK(on_get_power_state),
419 			NULL); /* user_data */
420 
421 	g_signal_connect(control,
422 			"handle-init",
423 			G_CALLBACK(on_init),
424 			object); /* user_data */
425 
426 	/* Listen for BootProgress signal from BootProgress sensor */
427 	g_dbus_connection_signal_subscribe(connection,
428 			NULL, /* service */
429 			NULL, /* interface_name */
430 			"BootProgress", /* member: name of the signal */
431 			"/org/openbmc/sensors/host/BootProgress", /* obj path */
432 			NULL, /* arg0 */
433 			G_DBUS_SIGNAL_FLAGS_NONE,
434 			(GDBusSignalCallback) on_boot_progress,
435 			object, /* user data */
436 			NULL );
437 
438 	/* Export the object (@manager takes its own reference to @object) */
439 	g_dbus_object_manager_server_set_connection(manager, connection);
440 	g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object));
441 	g_object_unref(object);
442 
443 	if(read_gpios(connection, &g_gpio_configs) != TRUE) {
444 		g_print("ERROR PowerControl: could not read power GPIO configuration\n");
445 	}
446 
447 	int rc = set_up_gpio(connection, &g_gpio_configs.power_gpio, control_power);
448 	if(rc != GPIO_OK) {
449 		g_print("ERROR PowerControl: GPIO setup (rc=%d)\n",rc);
450 	}
451 	//start poll
452 	pgood_timeout_start = 0;
453 	int poll_interval = atoi(cmd->argv[1]);
454 	int pgood_timeout = atoi(cmd->argv[2]);
455 	if(poll_interval < 1000 || pgood_timeout <5) {
456 		g_print("ERROR PowerControl: poll_interval < 1000 or pgood_timeout < 5\n");
457 	} else {
458 		control_set_poll_interval(control,poll_interval);
459 		control_power_set_pgood_timeout(control_power,pgood_timeout);
460 		g_timeout_add(poll_interval, poll_pgood, object);
461 	}
462 }
463 
464 static void
465 on_name_acquired(GDBusConnection *connection,
466 		const gchar *name,
467 		gpointer user_data)
468 {
469 }
470 
471 static void
472 on_name_lost(GDBusConnection *connection,
473 		const gchar *name,
474 		gpointer user_data)
475 {
476 	free_gpios(&g_gpio_configs);
477 }
478 
479 /*----------------------------------------------------------------*/
480 /* Main Event Loop                                                */
481 
482 gint
483 main(gint argc, gchar *argv[])
484 {
485 	GMainLoop *loop;
486 	cmdline cmd;
487 	cmd.argc = argc;
488 	cmd.argv = argv;
489 
490 	guint id;
491 	loop = g_main_loop_new(NULL, FALSE);
492 
493 	id = g_bus_own_name(DBUS_TYPE,
494 			dbus_name,
495 			G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
496 			G_BUS_NAME_OWNER_FLAGS_REPLACE,
497 			on_bus_acquired,
498 			on_name_acquired,
499 			on_name_lost,
500 			&cmd,
501 			NULL);
502 
503 	g_main_loop_run(loop);
504 
505 	g_bus_unown_name(id);
506 	g_main_loop_unref(loop);
507 	return 0;
508 }
509