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 exit(-1); 466 } 467 468 int rc = set_up_gpio(connection, &g_gpio_configs.power_gpio, control_power); 469 if(rc != GPIO_OK) { 470 g_print("ERROR PowerControl: GPIO setup (rc=%d)\n",rc); 471 exit(-1); 472 } 473 //start poll 474 pgood_timeout_start = 0; 475 int poll_interval = atoi(cmd->argv[1]); 476 int pgood_timeout = atoi(cmd->argv[2]); 477 if(poll_interval < 500 || pgood_timeout <5) { 478 g_print("ERROR PowerControl: poll_interval < 500 or pgood_timeout < 5\n"); 479 exit(-1); 480 } else { 481 control_set_poll_interval(control,poll_interval); 482 control_power_set_pgood_timeout(control_power,pgood_timeout); 483 g_timeout_add(poll_interval, poll_pgood, object); 484 } 485 } 486 487 static void 488 on_name_acquired(GDBusConnection *connection, 489 const gchar *name, 490 gpointer user_data) 491 { 492 } 493 494 static void 495 on_name_lost(GDBusConnection *connection, 496 const gchar *name, 497 gpointer user_data) 498 { 499 free_gpios(&g_gpio_configs); 500 } 501 502 /*----------------------------------------------------------------*/ 503 /* Main Event Loop */ 504 505 gint 506 main(gint argc, gchar *argv[]) 507 { 508 GMainLoop *loop; 509 cmdline cmd; 510 cmd.argc = argc; 511 cmd.argv = argv; 512 513 guint id; 514 loop = g_main_loop_new(NULL, FALSE); 515 516 id = g_bus_own_name(DBUS_TYPE, 517 dbus_name, 518 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | 519 G_BUS_NAME_OWNER_FLAGS_REPLACE, 520 on_bus_acquired, 521 on_name_acquired, 522 on_name_lost, 523 &cmd, 524 NULL); 525 526 g_main_loop_run(loop); 527 528 g_bus_unown_name(id); 529 g_main_loop_unref(loop); 530 return 0; 531 } 532