summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--discover/Makefile.am2
-rw-r--r--discover/dt.c61
-rw-r--r--discover/dt.h8
-rw-r--r--discover/ipmi.h8
-rw-r--r--discover/platform-powerpc.c45
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");
OpenPOWER on IntegriCloud