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 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 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_gpio_configs.power_gpio.num_power_up_outs; i++) { 248 GPIO *power_pin = &g_gpio_configs.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_gpio_configs.power_gpio.power_up_outs[i].name, error); 253 continue; 254 } 255 power_up_out = state ^ !g_gpio_configs.power_gpio.power_up_pols[i]; 256 g_print("PowerControl: setting power up %s to %d\n", 257 g_gpio_configs.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_gpios(connection, &g_gpio_configs) != TRUE) { 433 g_print("ERROR PowerControl: could not read power GPIO configuration\n"); 434 } 435 436 int rc = set_up_gpio(connection, &g_gpio_configs.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_gpios(&g_gpio_configs); 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