diff options
-rw-r--r-- | discover/Makefile.am | 2 | ||||
-rw-r--r-- | discover/dt.c | 61 | ||||
-rw-r--r-- | discover/dt.h | 8 | ||||
-rw-r--r-- | discover/ipmi.h | 8 | ||||
-rw-r--r-- | discover/platform-powerpc.c | 45 |
5 files changed, 122 insertions, 2 deletions
diff --git a/discover/Makefile.am b/discover/Makefile.am index 1e4df0b..7808110 100644 --- a/discover/Makefile.am +++ b/discover/Makefile.am @@ -71,6 +71,8 @@ discover_platform_ro_SOURCES = \ discover/platform.h \ discover/ipmi.c \ discover/ipmi.h \ + discover/dt.c \ + discover/dt.h \ discover/platform-powerpc.c discover_platform_ro_LINK = \ diff --git a/discover/dt.c b/discover/dt.c new file mode 100644 index 0000000..a7383e1 --- /dev/null +++ b/discover/dt.c @@ -0,0 +1,61 @@ +#include <asm/byteorder.h> +#include <dirent.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include <talloc/talloc.h> +#include <file/file.h> + +#include "dt.h" + +static int filter_sensors(const struct dirent *ent) +{ + /* Check for prefix "sensor@" */ + return strncmp(ent->d_name, "sensor@", strlen("sensor@")) == 0; +} + +int get_ipmi_sensor(void *t, enum ipmi_sensor_ids sensor_id) +{ + int rc, len, n; + struct dirent **namelist; + char *buf, *filename; + const char sensor_dir[] = "/proc/device-tree/bmc/sensors/"; + + n = scandir(sensor_dir, &namelist, filter_sensors, alphasort); + if (n <= 0) + return -1; + + while (n--) { + filename = talloc_asprintf(t, "%s%s/ipmi-sensor-type", + sensor_dir, namelist[n]->d_name); + rc = read_file(t, filename, &buf, &len); + if (rc == 0 && len == 4 && + __be32_to_cpu(*(uint32_t *)buf) == sensor_id) + break; + free(namelist[n]); + } + if (n < 0) { + rc = -1; + goto out; + } + + filename = talloc_asprintf(t, "%s%s/reg", sensor_dir, + namelist[n]->d_name); + /* Free the rest of the scandir strings, if there are any */ + do { + free(namelist[n]); + } while (n-- > 0); + + rc = read_file(t, filename, &buf, &len); + if (rc != 0 || len != 4) { + rc = -1; + goto out; + } + + rc = __be32_to_cpu(*(uint32_t *)buf); + +out: + free(namelist); + return rc; +} diff --git a/discover/dt.h b/discover/dt.h new file mode 100644 index 0000000..4692d04 --- /dev/null +++ b/discover/dt.h @@ -0,0 +1,8 @@ +#ifndef _DT_H +#define _DT_H + +#include "ipmi.h" + +int get_ipmi_sensor(void *t, enum ipmi_sensor_ids sensor_id); + +#endif /* _IPMI_H */ diff --git a/discover/ipmi.h b/discover/ipmi.h index e60ff61..83f2910 100644 --- a/discover/ipmi.h +++ b/discover/ipmi.h @@ -5,12 +5,14 @@ #include <stdint.h> enum ipmi_netfn { - IPMI_NETFN_CHASSIS = 0x0, + IPMI_NETFN_CHASSIS = 0x0, + IPMI_NETFN_SE = 0x04, }; enum ipmi_cmd { IPMI_CMD_CHASSIS_SET_SYSTEM_BOOT_OPTIONS = 0x08, IPMI_CMD_CHASSIS_GET_SYSTEM_BOOT_OPTIONS = 0x09, + IPMI_CMD_SENSOR_SET = 0x30, }; enum ipmi_bootdev { @@ -22,6 +24,10 @@ enum ipmi_bootdev { IPMI_BOOTDEV_SETUP = 0x6, }; +enum ipmi_sensor_ids { + IPMI_SENSOR_ID_OS_BOOT = 0x1F, +}; + struct ipmi; bool ipmi_present(void); diff --git a/discover/platform-powerpc.c b/discover/platform-powerpc.c index a293ce9..4cc91fa 100644 --- a/discover/platform-powerpc.c +++ b/discover/platform-powerpc.c @@ -17,6 +17,7 @@ #include "platform.h" #include "ipmi.h" +#include "dt.h" static const char *partition = "common"; static const char *sysparams_dir = "/sys/firmware/opal/sysparams/"; @@ -39,6 +40,8 @@ struct platform_powerpc { uint8_t *bootdev, bool *persistent); int (*clear_ipmi_bootdev)( struct platform_powerpc *platform); + int (*set_os_boot_sensor)( + struct platform_powerpc *platform); }; static const char *known_params[] = { @@ -792,6 +795,42 @@ static int get_ipmi_bootdev_ipmi(struct platform_powerpc *platform, return 0; } +static int set_ipmi_os_boot_sensor(struct platform_powerpc *platform) +{ + int sensor_number; + uint16_t resp_len; + uint8_t resp[1]; + uint8_t req[] = { + 0x00, /* sensor number: os boot */ + 0x10, /* operation: set assertion bits */ + 0x00, /* sensor reading: none */ + 0x40, /* assertion mask lsb: set state 6 */ + 0x00, /* assertion mask msb: none */ + 0x00, /* deassertion mask lsb: none */ + 0x00, /* deassertion mask msb: none */ + 0x00, /* event data 1: none */ + 0x00, /* event data 2: none */ + 0x00, /* event data 3: none */ + }; + + sensor_number = get_ipmi_sensor(platform, IPMI_SENSOR_ID_OS_BOOT); + if (sensor_number < 0) { + pb_log("Couldn't find OS boot sensor in device tree\n"); + return -1; + } + + req[0] = sensor_number; + + resp_len = sizeof(resp); + + ipmi_transaction(platform->ipmi, IPMI_NETFN_SE, + IPMI_CMD_SENSOR_SET, + req, sizeof(req), + resp, &resp_len, + ipmi_timeout); return 0; + + return 0; +} static int load_config(struct platform *p, struct config *config) { @@ -838,6 +877,9 @@ static void pre_boot(struct platform *p, const struct config *config) if (!config->ipmi_bootdev_persistent && platform->clear_ipmi_bootdev) platform->clear_ipmi_bootdev(platform); + + if (platform->set_os_boot_sensor) + platform->set_os_boot_sensor(platform); } static int get_sysinfo(struct platform *p, struct system_info *sysinfo) @@ -875,7 +917,7 @@ static bool probe(struct platform *p, void *ctx) if (!S_ISDIR(statbuf.st_mode)) return false; - platform = talloc(ctx, struct platform_powerpc); + platform = talloc_zero(ctx, struct platform_powerpc); list_init(&platform->params); p->platform_data = platform; @@ -885,6 +927,7 @@ static bool probe(struct platform *p, void *ctx) platform->ipmi = ipmi_open(platform); platform->get_ipmi_bootdev = get_ipmi_bootdev_ipmi; platform->clear_ipmi_bootdev = clear_ipmi_bootdev_ipmi; + platform->set_os_boot_sensor = set_ipmi_os_boot_sensor; } else if (!stat(sysparams_dir, &statbuf)) { pb_debug("platform: using sysparams for IPMI paramters\n"); |