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 < 1000 || pgood_timeout <5) { 483 g_print("ERROR PowerControl: poll_interval < 1000 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