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