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