Skip to content

Commit

Permalink
Reinvent x86 power control application
Browse files Browse the repository at this point in the history
The previous application that was posted here had a TON of timing
issues that made it basically unworkable, and was missing several
features (like power button override, VR timers, ect) that weren't
really possible in the old scheme.

This commit shows a reimagining of power control on the AST2500, and
seems to work much more reliably in testing across several platforms.

The key differentiators here are:
1. It gets rid of the target files.  Despite _many_ attempts to make the
target file approach reliable across 1000/10000 reboot cycle testings,
it was clear that the timing differences in the activation times caused
too many hard to fix race conditions.  To this end, the power state
machine has been moved into c++, where we can be very explicit about our
IO, and event timings.
2. It implements several features that were not present in the old
implementation, like soft power cycle.  These were required to implement
the full Redfish ComputerSystem schema properly.
3. It implements proper handling when collisions occur.  For example
when two power off requests come in at the same time.  Because of #1 we
can now service both of these requests "correctly" and remove the
possibility of desyncronizing the state machine from the host state.

A majority of this work was accomplished by Jason Bills.  The history is
available here, which can be pushed if needed, but I don't beleive it's
wanted.

https://github.com/Intel-BMC/intel-chassis-control/commits/master

Signed-off-by: Ed Tanous <ed.tanous@intel.com>
Change-Id: I2eb7fb1dbcab3d374df9d2e8c62407f0277e2583
  • Loading branch information
edtanous committed Sep 26, 2019
1 parent 2c71405 commit f61ca6f
Show file tree
Hide file tree
Showing 35 changed files with 2,341 additions and 1,030 deletions.
6 changes: 3 additions & 3 deletions CMakeLists.txt
Expand Up @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/gpio/inc)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/i2c/inc)

add_subdirectory(gpio)
add_subdirectory(power-control)
add_subdirectory(i2c)
add_subdirectory(power-control-x86)
47 changes: 46 additions & 1 deletion README.md
@@ -1 +1,46 @@
# x86-power-control
# X86 power control

This repository contains an OpenBMC compliant implementation of power control
for x86 servers. It relies on a number of features to do its job. It has
several intentional design goals.
1. The BMC should maintain the Host state machine internally, and be able to
track state changes.
2. The implementation should either give the requested power control result, or
should log an error on the failure it detected.
3. The BMC should support all the common operations, hard power on/off/cycle,
soft power on/off/cycle.

At this point in time, this daemon targets Lewisburg based, dual socket x86
server platforms, such as S2600WFT. It is likely that other platforms will work
as well.

Because this relies on the hardware passthrough support in the AST2500 to
function, it requires a few patches to work correctly.

This patch adds support to UBOOT to keep the passthrough enabled
https://github.com/Intel-BMC/openbmc/blob/intel/meta-openbmc-mods/meta-common/
recipes-bsp/u-boot/files/0005-enable-passthrough-in-uboot.patch

The DTS file for your platform will need the following GPIO definitions
RESET_BUTTON
RESET_OUT
POWER_BUTTON
POWER_OUT

On an aspeed, these are generally connected to E0, E1, E2, and E3 respecitvely.
An example of this is available in the s2600WF config.

This patch allows the passthrough to be reenabled to the default condition when
the appropriate pin is released. This allows power control to take control
when needed by a user power action, but leave the hardware in control a majority
of the time, reducing the possibilty of bricking a system due to a failed BMC.

https://github.com/Intel-BMC/openbmc/blob/intel/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/0002-Enable-pass-through-on-GPIOE1-and-GPIOE3-free.patch
https://github.com/Intel-BMC/openbmc/blob/intel/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/0003-Enable-GPIOE0-and-GPIOE2-pass-through-by-default.patch
https://github.com/Intel-BMC/openbmc/blob/intel/meta-openbmc-mods/meta-ast2500/recipes-kernel/linux/linux-aspeed/0006-Allow-monitoring-of-power-control-input-GPIOs.patch


Caveats:
This implementation does not currently implement the common targets that other
implementations do. There were several attempts to, but all ended in timing
issues and boot inconsistencies during stress operations.
192 changes: 0 additions & 192 deletions gpio/src/gpio.cpp

This file was deleted.

6 changes: 3 additions & 3 deletions gpio/CMakeLists.txt → i2c/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR)
project(chassisgpio CXX)
project(chassisi2c CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

Expand All @@ -15,7 +15,7 @@ set(INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR})
include(GNUInstallDirs)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc)

add_library(${PROJECT_NAME} SHARED src/gpio.cpp)
add_library(${PROJECT_NAME} SHARED src/i2c.cpp)

set_target_properties(${PROJECT_NAME} PROPERTIES VERSION "0.1.0")
set_target_properties(${PROJECT_NAME} PROPERTIES SOVERSION "0")
Expand All @@ -27,7 +27,7 @@ install(TARGETS ${PROJECT_NAME}
ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" COMPONENT stlib
COMPONENT dev)

install(FILES "inc/gpio.hpp"
install(FILES "inc/i2c.hpp"
DESTINATION "${INSTALL_INCLUDE_DIR}/" )

install(EXPORT "${PROJECT_NAME}EXPORT"
Expand Down
9 changes: 6 additions & 3 deletions gpio/inc/gpio.hpp → i2c/inc/i2c.hpp
Expand Up @@ -15,8 +15,11 @@
*/

#pragma once
#include <cstdint>

#include <sdbusplus/bus.hpp>
extern "C" {
#include <i2c/smbus.h>
#include <linux/i2c-dev.h>
}

int configGpio(const char* gpioName, int* fd, sdbusplus::bus::bus& bus);
int closeGpio(int fd);
int i2cSet(uint8_t bus, uint8_t slaveAddr, uint8_t regAddr, uint8_t value);
93 changes: 93 additions & 0 deletions i2c/src/i2c.cpp
@@ -0,0 +1,93 @@
/*
// Copyright (c) 2018 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/

#include "i2c.hpp"

#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include <phosphor-logging/elog-errors.hpp>
#include <xyz/openbmc_project/Common/error.hpp>

// TODO Add 16-bit I2C support in the furture
int i2cSet(uint8_t bus, uint8_t slaveAddr, uint8_t regAddr, uint8_t value)
{
unsigned long funcs = 0;
std::string devPath = "/dev/i2c-" + std::to_string(bus);

int fd = ::open(devPath.c_str(), O_RDWR);
if (fd < 0)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
"Error in open!",
phosphor::logging::entry("PATH=%s", devPath.c_str()),
phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
return -1;
}

if (::ioctl(fd, I2C_FUNCS, &funcs) < 0)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
"Error in I2C_FUNCS!",
phosphor::logging::entry("PATH=%s", devPath.c_str()),
phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));

::close(fd);
return -1;
}

if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
{

phosphor::logging::log<phosphor::logging::level::ERR>(
"i2c bus does not support write!",
phosphor::logging::entry("PATH=%s", devPath.c_str()),
phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
::close(fd);
return -1;
}

if (::ioctl(fd, I2C_SLAVE_FORCE, slaveAddr) < 0)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
"Error in I2C_SLAVE_FORCE!",
phosphor::logging::entry("PATH=%s", devPath.c_str()),
phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
::close(fd);
return -1;
}

if (::i2c_smbus_write_byte_data(fd, regAddr, value) < 0)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
"Error in i2c write!",
phosphor::logging::entry("PATH=%s", devPath.c_str()),
phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
::close(fd);
return -1;
}

// TODO For testing, will remove the below debug loging in the future
phosphor::logging::log<phosphor::logging::level::DEBUG>(
"i2cset successfully",
phosphor::logging::entry("PATH=%s", devPath.c_str()),
phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr),
phosphor::logging::entry("REGADDR=0x%x", regAddr),
phosphor::logging::entry("VALUE=0x%x", value));
::close(fd);
return 0;
}

0 comments on commit f61ca6f

Please sign in to comment.