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