aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStewart Smith <stewart@linux.vnet.ibm.com>2015-03-06 14:18:45 +1100
committerStewart Smith <stewart@linux.vnet.ibm.com>2015-03-06 14:18:45 +1100
commitdaa340ae58bbf774628d87505b2696e6f63f75d1 (patch)
tree757209560a71e40cffbe92a3e779232d4a0b5574
parent6cf8b663e7d7cb1e827b6d9c90e694ea583f6f87 (diff)
parent9a3f68b499e686ff3b543633f59192890f6c740b (diff)
downloadskiboot-daa340ae58bbf774628d87505b2696e6f63f75d1.zip
skiboot-daa340ae58bbf774628d87505b2696e6f63f75d1.tar.gz
skiboot-daa340ae58bbf774628d87505b2696e6f63f75d1.tar.bz2
Merge branch 'openpower'
-rw-r--r--core/flash.c58
-rw-r--r--core/init.c5
-rw-r--r--core/ipmi.c9
-rw-r--r--external/opal-prd/Makefile8
-rw-r--r--external/opal-prd/opal-prd.c38
-rw-r--r--external/opal-prd/thunk.S12
-rw-r--r--hw/ipmi/Makefile.inc3
-rw-r--r--hw/ipmi/ipmi-sel.c39
-rw-r--r--hw/ipmi/ipmi-sensor.c134
-rw-r--r--hw/ipmi/ipmi-watchdog.c6
-rw-r--r--hw/occ.c28
-rw-r--r--include/ipmi.h22
-rw-r--r--include/skiboot.h10
-rw-r--r--platforms/astbmc/common.c57
-rw-r--r--platforms/astbmc/habanero.c3
15 files changed, 383 insertions, 49 deletions
diff --git a/core/flash.c b/core/flash.c
index 37827b3..f2d7501 100644
--- a/core/flash.c
+++ b/core/flash.c
@@ -26,6 +26,7 @@
struct flash {
bool registered;
+ bool busy;
struct flash_chip *chip;
uint32_t size;
uint32_t block_size;
@@ -42,12 +43,39 @@ static struct lock flash_lock;
static struct flash *nvram_flash;
static u32 nvram_offset, nvram_size;
+bool flash_reserve(void)
+{
+ bool rc = false;
+
+ if (!try_lock(&flash_lock))
+ return false;
+
+ if (!system_flash->busy) {
+ system_flash->busy = true;
+ rc = true;
+ }
+ unlock(&flash_lock);
+
+ return rc;
+}
+
+void flash_release(void)
+{
+ lock(&flash_lock);
+ system_flash->busy = false;
+ unlock(&flash_lock);
+}
+
static int flash_nvram_info(uint32_t *total_size)
{
- int rc = OPAL_HARDWARE;
+ int rc;
lock(&flash_lock);
- if (nvram_flash) {
+ if (!nvram_flash) {
+ rc = OPAL_HARDWARE;
+ } else if (nvram_flash->busy) {
+ rc = OPAL_BUSY;
+ } else {
*total_size = nvram_size;
rc = OPAL_SUCCESS;
}
@@ -60,13 +88,19 @@ static int flash_nvram_start_read(void *dst, uint32_t src, uint32_t len)
{
int rc;
- lock(&flash_lock);
+ if (!try_lock(&flash_lock))
+ return OPAL_BUSY;
if (!nvram_flash) {
rc = OPAL_HARDWARE;
goto out;
}
+ if (nvram_flash->busy) {
+ rc = OPAL_BUSY;
+ goto out;
+ }
+
if ((src + len) > nvram_size) {
prerror("FLASH_NVRAM: read out of bound (0x%x,0x%x)\n",
src, len);
@@ -87,7 +121,13 @@ static int flash_nvram_write(uint32_t dst, void *src, uint32_t len)
{
int rc;
- lock(&flash_lock);
+ if (!try_lock(&flash_lock))
+ return OPAL_BUSY;
+
+ if (nvram_flash->busy) {
+ rc = OPAL_BUSY;
+ goto out;
+ }
/* TODO: When we have async jobs for PRD, turn this into one */
@@ -235,6 +275,7 @@ int flash_register(struct flash_chip *chip, bool is_system_flash)
flash = &flashes[i];
flash->registered = true;
+ flash->busy = false;
flash->chip = chip;
flash->size = size;
flash->block_size = block_size;
@@ -286,6 +327,12 @@ static int64_t opal_flash_op(enum flash_op op, uint64_t id, uint64_t offset,
return OPAL_BUSY;
flash = &flashes[id];
+
+ if (flash->busy) {
+ rc = OPAL_BUSY;
+ goto err;
+ }
+
if (!flash->registered) {
rc = OPAL_PARAMETER;
goto err;
@@ -493,6 +540,9 @@ bool flash_load_resource(enum resource_id id, uint32_t subid,
flash = system_flash;
+ if (flash->busy)
+ goto out_unlock;
+
for (i = 0, name = NULL; i < ARRAY_SIZE(part_name_map); i++) {
if (part_name_map[i].id == id) {
name = part_name_map[i].name;
diff --git a/core/init.c b/core/init.c
index ac61c37..1fd8d2e 100644
--- a/core/init.c
+++ b/core/init.c
@@ -43,6 +43,7 @@
#include <centaur.h>
#include <libfdt/libfdt.h>
#include <timer.h>
+#include <ipmi.h>
#include <ipmi.h>
@@ -374,6 +375,8 @@ void __noreturn load_and_boot_kernel(bool is_reboot)
load_initramfs();
+ ipmi_set_fw_progress_sensor(IPMI_FW_OS_BOOT);
+
if (!is_reboot) {
/* We wait for the nvram read to complete here so we can
* grab stuff from there such as the kernel arguments
@@ -668,6 +671,8 @@ void __noreturn main_cpu_entry(const void *fdt, u32 master_cpu)
/* Add OPAL timer related properties */
late_init_timers();
+ ipmi_set_fw_progress_sensor(IPMI_FW_PCI_INIT);
+
/*
* These last few things must be done as late as possible
* because they rely on various other things having been setup,
diff --git a/core/ipmi.c b/core/ipmi.c
index 6c1179f..78a54de 100644
--- a/core/ipmi.c
+++ b/core/ipmi.c
@@ -156,9 +156,14 @@ static void ipmi_get_message_flags_complete(struct ipmi_msg *msg)
/* Once we see an interrupt we assume the payload has
* booted. We disable the wdt and let the OS setup its own
- * wdt. */
- if (flags & IPMI_MESSAGE_FLAGS_WATCHDOG_PRE_TIMEOUT)
+ * wdt.
+ *
+ * This is also where we consider the OS to be booted, so we set
+ * the boot count sensor */
+ if (flags & IPMI_MESSAGE_FLAGS_WATCHDOG_PRE_TIMEOUT) {
ipmi_wdt_stop();
+ ipmi_set_boot_count();
+ }
/* Message available in the event buffer? Queue a Read Event command
* to retrieve it. The flag is cleared by performing a read */
diff --git a/external/opal-prd/Makefile b/external/opal-prd/Makefile
index 7006431..4f4175c 100644
--- a/external/opal-prd/Makefile
+++ b/external/opal-prd/Makefile
@@ -5,11 +5,15 @@ LDFLAGS = -m64
ASFLAGS = -m64
CPPFLAGS = -I. -I../../include -I../../
+prefix = /usr/local/
+sbindir = $(prefix)/sbin
+
# Use make V=1 for a verbose build.
ifndef V
Q_CC= @echo ' CC ' $@;
Q_LINK= @echo ' LINK ' $@;
Q_LN= @echo ' LN ' $@;
+ Q_MKDIR=@echo ' MKDIR ' $@;
endif
OBJS = opal-prd.o thunk.o pnor.o i2c.o libffs.o libflash.o ecc.o
@@ -26,6 +30,7 @@ ccan:
$(Q_LN)ln -sfr ../../ccan ./ccan
asm/opal-prd.h:
+ $(Q_MKDIR)mkdir -p asm
$(Q_LN)ln -sfr $(KERNEL_DIR)/arch/powerpc/include/uapi/asm/opal-prd.h \
asm/opal-prd.h
@@ -48,6 +53,9 @@ test: test/test_pnor
test/test_pnor: test/test_pnor.o pnor.o libflash/libflash.o libflash/libffs.o
$(Q_LINK)$(LINK.o) -o $@ $^
+install: all
+ install -D opal-prd $(DESTDIR)$(sbindir)/opal-prd
+
clean:
$(RM) *.[odsa] opal-prd
$(RM) test/*.[odsa] test/test_pnor
diff --git a/external/opal-prd/opal-prd.c b/external/opal-prd/opal-prd.c
index 402820a..a209e82 100644
--- a/external/opal-prd/opal-prd.c
+++ b/external/opal-prd/opal-prd.c
@@ -58,7 +58,6 @@ struct opal_prd_ctx {
void *code_addr;
size_t code_size;
bool debug;
- bool allow_fsp_calls;
struct pnor pnor;
char *hbrt_file_name;
};
@@ -150,23 +149,6 @@ extern int call_enable_attns(void);
extern int call_enable_occ_actuation(bool i_occActivation);
extern void call_process_occ_reset(uint64_t i_chipId);
-/* Dummy calls for hservices */
-static inline int __fsp_only_assert(const char *name)
-{
- printf("error: %s is only implemented for FSP\n", name);
- if (!ctx->allow_fsp_calls)
- exit(EXIT_FAILURE);
- return 0;
-}
-#define fsp_stub(name) \
- int hservice_ ##name(void) { return __fsp_only_assert(#name); }
-
-fsp_stub(send_error_log);
-fsp_stub(lid_load);
-fsp_stub(lid_unload);
-fsp_stub(wakeup);
-fsp_stub(report_occ_failure);
-
void hservice_puts(const char *str)
{
printf("%s\n", str);
@@ -316,8 +298,8 @@ int hservice_pnor_write(uint32_t i_proc, const char* i_partitionName,
i_sizeBytes, PNOR_OP_WRITE);
}
-int hservice_i2c_read(uint64_t i_master, uint8_t i_engine, uint8_t i_port,
- uint16_t i_devAddr, uint32_t i_offsetSize, uint32_t i_offset,
+int hservice_i2c_read(uint64_t i_master, uint16_t i_devAddr,
+ uint32_t i_offsetSize, uint32_t i_offset,
uint32_t i_length, void* o_data)
{
uint32_t chip_id;
@@ -333,8 +315,8 @@ int hservice_i2c_read(uint64_t i_master, uint8_t i_engine, uint8_t i_port,
i_offset, i_length, o_data);
}
-int hservice_i2c_write(uint64_t i_master, uint8_t i_engine, uint8_t i_port,
- uint16_t i_devAddr, uint32_t i_offsetSize, uint32_t i_offset,
+int hservice_i2c_write(uint64_t i_master, uint16_t i_devAddr,
+ uint32_t i_offsetSize, uint32_t i_offset,
uint32_t i_length, void* i_data)
{
uint32_t chip_id;
@@ -1095,8 +1077,7 @@ out_close:
static void usage(const char *progname)
{
printf("Usage:\n");
- printf("\t%s [--debug] [--file <hbrt-image>] [--pnor <device>]\n"
- "\t\t[--allow-fsp-calls]\n",
+ printf("\t%s [--debug] [--file <hbrt-image>] [--pnor <device>]\n",
progname);
printf("\t%s occ <enable|disable>\n", progname);
printf("\n");
@@ -1104,17 +1085,13 @@ static void usage(const char *progname)
"\t--debug verbose logging for debug information\n"
"\t--pnor DEVICE use PNOR MTD device\n"
"\t--file FILE use FILE for hostboot runtime code (instead of code\n"
-"\t exported by firmware)\n"
-"\t--allow-fsp-calls don't exit on FSP-only callbacks from HBRT code, but\n"
-"\t return success instead. Intended for workarounds\n"
-"\t during PRD testing only.\n");
+"\t exported by firmware)\n");
}
static struct option opal_diag_options[] = {
{"file", required_argument, NULL, 'f'},
{"pnor", required_argument, NULL, 'p'},
{"debug", no_argument, NULL, 'd'},
- {"allow-fsp-calls", no_argument, NULL, 'a'},
{"help", no_argument, NULL, 'h'},
{ 0 },
};
@@ -1167,9 +1144,6 @@ int main(int argc, char *argv[])
case 'p':
ctx->pnor.path = strndup(optarg, PATH_MAX);
break;
- case 'a':
- ctx->allow_fsp_calls = true;
- break;
case 'h':
usage(argv[0]);
return EXIT_SUCCESS;
diff --git a/external/opal-prd/thunk.S b/external/opal-prd/thunk.S
index 064138c..9d97183 100644
--- a/external/opal-prd/thunk.S
+++ b/external/opal-prd/thunk.S
@@ -139,6 +139,8 @@ name##_thunk: ;\
.llong name
#endif
+#define DISABLED_THUNK(name) .llong 0x0
+
/* Here's the callback table generation. It creates the table and
* all the thunks for all the callbacks from HBRT to us
*/
@@ -155,15 +157,15 @@ hinterface:
CALLBACK_THUNK(hservice_malloc)
CALLBACK_THUNK(hservice_free)
CALLBACK_THUNK(hservice_realloc)
- CALLBACK_THUNK(hservice_send_error_log)
+ DISABLED_THUNK(hservice_send_error_log)
CALLBACK_THUNK(hservice_scom_read)
CALLBACK_THUNK(hservice_scom_write)
- CALLBACK_THUNK(hservice_lid_load)
- CALLBACK_THUNK(hservice_lid_unload)
+ DISABLED_THUNK(hservice_lid_load)
+ DISABLED_THUNK(hservice_lid_unload)
CALLBACK_THUNK(hservice_get_reserved_mem)
- CALLBACK_THUNK(hservice_wakeup)
+ DISABLED_THUNK(hservice_wakeup)
CALLBACK_THUNK(hservice_nanosleep)
- CALLBACK_THUNK(hservice_report_occ_failure)
+ DISABLED_THUNK(hservice_report_occ_failure)
CALLBACK_THUNK(hservice_clock_gettime)
CALLBACK_THUNK(hservice_pnor_read)
CALLBACK_THUNK(hservice_pnor_write)
diff --git a/hw/ipmi/Makefile.inc b/hw/ipmi/Makefile.inc
index 1c358a9..06cdc96 100644
--- a/hw/ipmi/Makefile.inc
+++ b/hw/ipmi/Makefile.inc
@@ -1,6 +1,7 @@
SUBDIRS += hw/ipmi
IPMI_OBJS = ipmi-rtc.o ipmi-power.o ipmi-opal.o ipmi-fru.o ipmi-sel.o
-IPMI_OBJS += ipmi-watchdog.o
+IPMI_OBJS += ipmi-watchdog.o ipmi-sensor.o
+
IPMI = hw/ipmi/built-in.o
$(IPMI): $(IPMI_OBJS:%=hw/ipmi/%)
diff --git a/hw/ipmi/ipmi-sel.c b/hw/ipmi/ipmi-sel.c
index 173b7be..8851dc3 100644
--- a/hw/ipmi/ipmi-sel.c
+++ b/hw/ipmi/ipmi-sel.c
@@ -41,6 +41,9 @@
#define SOFT_OFF 0x00
#define SOFT_REBOOT 0x01
+#define RELEASE_PNOR 0x00
+#define REQUEST_PNOR 0x01
+
struct oem_sel {
/* SEL header */
uint8_t id[2];
@@ -180,6 +183,36 @@ int ipmi_elog_commit(struct errorlog *elog_buf)
return 0;
}
+#define ACCESS_DENIED 0x00
+#define ACCESS_GRANTED 0x01
+
+static void sel_pnor(uint8_t access)
+{
+ struct ipmi_msg *msg;
+ uint8_t granted = ACCESS_GRANTED;
+
+ switch (access) {
+ case REQUEST_PNOR:
+ prlog(PR_NOTICE, "IPMI: PNOR access requested\n");
+ granted = flash_reserve();
+ if (granted)
+ occ_pnor_set_owner(PNOR_OWNER_EXTERNAL);
+
+ /* Ack the request */
+ msg = ipmi_mkmsg_simple(IPMI_PNOR_ACCESS_STATUS, &granted, 1);
+ ipmi_queue_msg(msg);
+ break;
+ case RELEASE_PNOR:
+ prlog(PR_NOTICE, "IPMI: PNOR access released\n");
+ flash_release();
+ occ_pnor_set_owner(PNOR_OWNER_HOST);
+ break;
+ default:
+ prlog(PR_ERR, "IPMI: invalid PNOR access requested: %02x\n",
+ access);
+ }
+}
+
static void sel_power(uint8_t power)
{
switch (power) {
@@ -271,9 +304,11 @@ void ipmi_parse_sel(struct ipmi_msg *msg)
sel_occ_reset(sel.data[0]);
break;
case CMD_AMI_PNOR_ACCESS:
+ sel_pnor(sel.data[0]);
break;
default:
- printf("IPMI: unknown OEM SEL command %02x received\n",
- sel.cmd);
+ prlog(PR_WARNING,
+ "IPMI: unknown OEM SEL command %02x received\n",
+ sel.cmd);
}
}
diff --git a/hw/ipmi/ipmi-sensor.c b/hw/ipmi/ipmi-sensor.c
new file mode 100644
index 0000000..a3112ee
--- /dev/null
+++ b/hw/ipmi/ipmi-sensor.c
@@ -0,0 +1,134 @@
+/* Copyright 2013-2014 IBM Corp.
+ *
+ * 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 <device.h>
+#include <ipmi.h>
+#include <opal.h>
+#include <skiboot.h>
+#include <string.h>
+
+#define IPMI_WRITE_SENSOR (1 << 1)
+#define IPMI_SET_ASSERTION (1 << 5)
+#define IPMI_ASSERTION_STATE(state) (1 << state)
+
+#define FW_PROGRESS_SENSOR_TYPE 0x0F
+#define BOOT_COUNT_SENSOR_TYPE 0xAA
+
+/* Ghetto. TODO: Do something smarter */
+int16_t sensors[255];
+
+struct set_sensor_req {
+ u8 sensor;
+ u8 operation;
+ u8 reading[8];
+};
+
+int ipmi_set_boot_count(void)
+{
+ struct set_sensor_req req;
+ struct ipmi_msg *msg;
+ int sensor_id;
+
+ sensor_id = sensors[BOOT_COUNT_SENSOR_TYPE];
+ if (sensor_id < 0) {
+ prlog(PR_DEBUG, "SENSOR: boot count set but not present\n");
+ return OPAL_HARDWARE;
+ }
+
+ memset(&req, 0, sizeof(req));
+
+ req.sensor = sensor_id;
+ /* Set assertion bit */
+ req.operation = IPMI_SET_ASSERTION;
+ /* Set state 2 */
+ req.reading[1] = IPMI_ASSERTION_STATE(2);
+
+ /* We just need the first 4 bytes */
+ msg = ipmi_mkmsg_simple(IPMI_SET_SENSOR_READING, &req, 4);
+ if (!msg)
+ return OPAL_HARDWARE;
+
+ return ipmi_queue_msg(msg);
+}
+
+int ipmi_set_fw_progress_sensor(uint8_t state)
+{
+ int fw_sensor_id = sensors[FW_PROGRESS_SENSOR_TYPE];
+
+ if (fw_sensor_id < 0) {
+ prlog(PR_DEBUG, "SENSOR: fw progress set but not present\n");
+ return OPAL_HARDWARE;
+ }
+
+ return ipmi_set_sensor(fw_sensor_id, &state, sizeof(state));
+}
+
+int ipmi_set_sensor(uint8_t sensor, uint8_t *reading, size_t len)
+{
+ struct ipmi_msg *msg;
+ struct set_sensor_req request;
+
+ if (!ipmi_present())
+ return OPAL_CLOSED;
+
+ if (len > 8) {
+ prlog(PR_ERR, "IPMI: sensor setting length %zd invalid\n",
+ len);
+ return OPAL_PARAMETER;
+ }
+
+ memset(&request, 0, sizeof(request));
+
+ request.sensor = sensor;
+ request.operation = IPMI_WRITE_SENSOR;
+ memcpy(request.reading, reading, len);
+
+ prlog(PR_INFO, "IPMI: setting sensor %02x to %02x ...\n",
+ request.sensor, request.reading[0]);
+
+ /* Send the minimial length message: header plus the reading bytes */
+ msg = ipmi_mkmsg_simple(IPMI_SET_SENSOR_READING, &request, len + 2);
+ if (!msg)
+ return OPAL_HARDWARE;
+
+ return ipmi_queue_msg(msg);
+}
+
+void ipmi_sensor_init(void)
+{
+ const struct dt_property *type_prop, *num_prop;
+ uint8_t num, type;
+ struct dt_node *n;
+
+ memset(sensors, -1, sizeof(sensors));
+
+ dt_for_each_compatible(dt_root, n, "ibm,ipmi-sensor") {
+ type_prop = dt_find_property(n, "ipmi-sensor-type");
+ if (!type_prop) {
+ prerror("IPMI: sensor doesn't have ipmi-sensor-type\n");
+ continue;
+ }
+
+ num_prop = dt_find_property(n, "reg");
+ if (!num_prop) {
+ prerror("IPMI: sensor doesn't have reg property\n");
+ continue;
+ }
+ num = (uint8_t)dt_property_get_cell(num_prop, 0);
+ type = (uint8_t)dt_property_get_cell(type_prop, 0);
+ sensors[type] = num;
+ }
+}
diff --git a/hw/ipmi/ipmi-watchdog.c b/hw/ipmi/ipmi-watchdog.c
index de766cf..a3db53b 100644
--- a/hw/ipmi/ipmi-watchdog.c
+++ b/hw/ipmi/ipmi-watchdog.c
@@ -105,9 +105,15 @@ void ipmi_wdt_stop(void)
void ipmi_wdt_final_reset(void)
{
+ /* todo: this is disabled while we're waiting on fixed watchdog
+ * behaviour */
+#if 0
set_wdt(WDT_POWER_CYCLE_ACTION | WDT_PRETIMEOUT_SMI, WDT_TIMEOUT,
WDT_MARGIN/10);
reset_wdt(NULL, (void *) 1);
+#endif
+ set_wdt(WDT_NO_ACTION, 100, 0);
+ ipmi_set_boot_count();
cancel_timer(&wdt_timer);
}
diff --git a/hw/occ.c b/hw/occ.c
index 8eb6469..657f2ad 100644
--- a/hw/occ.c
+++ b/hw/occ.c
@@ -537,6 +537,34 @@ static void occ_do_reset(u8 scope, u32 dbob_id, u32 seq_id)
}
}
+#define PV_OCC_GP0 0x01000000
+#define PV_OCC_GP0_AND 0x01000004
+#define PV_OCC_GP0_OR 0x01000005
+#define PV_OCC_GP0_PNOR_OWNER PPC_BIT(18) /* 1 = OCC / Host, 0 = BMC */
+
+static void occ_pnor_set_one_owner(uint32_t chip_id, enum pnor_owner owner)
+{
+ uint64_t reg, mask;
+
+ if (owner == PNOR_OWNER_HOST) {
+ reg = PV_OCC_GP0_OR;
+ mask = PV_OCC_GP0_PNOR_OWNER;
+ } else {
+ reg = PV_OCC_GP0_AND;
+ mask = ~PV_OCC_GP0_PNOR_OWNER;
+ }
+
+ xscom_write(chip_id, reg, mask);
+}
+
+void occ_pnor_set_owner(enum pnor_owner owner)
+{
+ struct proc_chip *chip;
+
+ for_each_chip(chip)
+ occ_pnor_set_one_owner(chip->id, owner);
+}
+
static bool fsp_occ_msg(u32 cmd_sub_mod, struct fsp_msg *msg)
{
u32 dbob_id, seq_id;
diff --git a/include/ipmi.h b/include/ipmi.h
index 9e52916..77e4b9a 100644
--- a/include/ipmi.h
+++ b/include/ipmi.h
@@ -84,14 +84,19 @@
#define IPMI_MESSAGE_FLAGS_OEM1 (1<<6)
#define IPMI_MESSAGE_FLAGS_OEM2 (1<<7)
+/* Firmware Progress Sensor states */
+#define IPMI_FW_PCI_INIT 0x07
+#define IPMI_FW_OS_BOOT 0x13
+#define IPMI_FW_MOTHERBOARD_INIT 0x14
+
#define IPMI_CODE(netfn, cmd) ((netfn) << 8 | (cmd))
#define IPMI_CMD(code) ((code) & 0xff)
#define IPMI_NETFN(code) ((code) >> 8 & 0xff)
#define IPMI_NETFN_CHASSIS 0x00
+#define IPMI_NETFN_SE 0x04
#define IPMI_NETFN_STORAGE 0x0a
#define IPMI_NETFN_APP 0x06
-#define IPMI_NETFN_OEM 0x32
#define IPMI_WRITE_FRU IPMI_CODE(IPMI_NETFN_STORAGE, 0x12)
#define IPMI_GET_SEL_INFO IPMI_CODE(IPMI_NETFN_STORAGE, 0x40)
@@ -109,8 +114,11 @@
#define IPMI_GET_MESSAGE_FLAGS IPMI_CODE(IPMI_NETFN_APP, 0x31)
#define IPMI_GET_MESSAGE IPMI_CODE(IPMI_NETFN_APP, 0x33)
#define IPMI_READ_EVENT IPMI_CODE(IPMI_NETFN_APP, 0x35)
+#define IPMI_SET_SENSOR_READING IPMI_CODE(IPMI_NETFN_SE, 0x30)
-#define IPMI_PARTIAL_ADD_ESEL IPMI_CODE(IPMI_NETFN_OEM, 0xf0)
+/* AMI OEM comamnds. AMI uses NETFN 0x3a and 0x32 */
+#define IPMI_PARTIAL_ADD_ESEL IPMI_CODE(0x32, 0xf0)
+#define IPMI_PNOR_ACCESS_STATUS IPMI_CODE(0x3a, 0x07)
/*
* IPMI response codes.
@@ -209,6 +217,10 @@ int ipmi_chassis_control(uint8_t request);
* use chassis control to perform power off and reboot. */
int ipmi_set_power_state(uint8_t system, uint8_t device);
+/* 35.17 Set Sensor Reading Command */
+int ipmi_set_sensor(uint8_t sensor, uint8_t *reading, size_t len);
+int ipmi_set_fw_progress_sensor(uint8_t state);
+
/* Register a backend with the ipmi core. Currently we only support one. */
void ipmi_register_backend(struct ipmi_backend *backend);
@@ -238,4 +250,10 @@ void ipmi_wdt_stop(void);
* reset and does not schedule future resets. */
void ipmi_wdt_final_reset(void);
+/* Discover id of settable ipmi sensors */
+void ipmi_sensor_init(void);
+
+/* Set the boot count once the OS is up and running */
+int ipmi_set_boot_count(void);
+
#endif
diff --git a/include/skiboot.h b/include/skiboot.h
index 9dfe0e7..0fe50e9 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -201,6 +201,9 @@ struct flash_chip;
extern int flash_register(struct flash_chip *chip, bool is_system_flash);
extern bool flash_load_resource(enum resource_id id, uint32_t subid,
void *buf, size_t *len);
+extern bool flash_reserve(void);
+extern void flash_release(void);
+
/* NVRAM support */
extern void nvram_init(void);
@@ -218,6 +221,13 @@ extern void occ_send_dummy_interrupt(void);
/* OCC load support */
extern void occ_poke_load_queue(void);
+/* OCC/Host PNOR ownership */
+enum pnor_owner {
+ PNOR_OWNER_HOST,
+ PNOR_OWNER_EXTERNAL,
+};
+extern void occ_pnor_set_owner(enum pnor_owner owner);
+
/* PRD */
extern void prd_psi_interrupt(uint32_t proc);
extern void prd_tmgt_interrupt(uint32_t proc);
diff --git a/platforms/astbmc/common.c b/platforms/astbmc/common.c
index a9878bf..c89af63 100644
--- a/platforms/astbmc/common.c
+++ b/platforms/astbmc/common.c
@@ -88,6 +88,25 @@ static void astbmc_ipmi_setenables(void)
}
+static int astbmc_fru_init(void)
+{
+ const struct dt_property *prop;
+ struct dt_node *node;
+ uint8_t fru_id;
+
+ node = dt_find_by_path(dt_root, "bmc");
+ if (!node)
+ return -1;
+
+ prop = dt_find_property(node, "firmware-fru-id");
+ if (!prop)
+ return -1;
+
+ fru_id = dt_property_get_cell(prop, 0) & 0xff;
+ ipmi_fru_init(fru_id);
+ return 0;
+}
+
void astbmc_init(void)
{
@@ -99,8 +118,9 @@ void astbmc_init(void)
ipmi_wdt_init();
ipmi_rtc_init();
ipmi_opal_init();
- ipmi_fru_init(0x01);
+ astbmc_fru_init();
elog_init();
+ ipmi_sensor_init();
/* As soon as IPMI is up, inform BMC we are in "S0" */
ipmi_set_power_state(IPMI_PWR_SYS_S0_WORKING, IPMI_PWR_NOCHANGE);
@@ -108,6 +128,8 @@ void astbmc_init(void)
/* Enable IPMI OEM message interrupts */
astbmc_ipmi_setenables();
+ ipmi_set_fw_progress_sensor(IPMI_FW_MOTHERBOARD_INIT);
+
/* Setup UART console for use by Linux via OPAL API */
if (!dummy_console_enabled())
uart_setup_opal_console();
@@ -210,6 +232,37 @@ static void astbmc_fixup_dt_uart(struct dt_node *lpc)
dt_add_property_cells(uart, "ibm,irq-chip-id", dt_get_chip_id(lpc));
}
+static void del_compatible(struct dt_node *node)
+{
+ struct dt_property *prop;
+
+ prop = __dt_find_property(node, "compatible");
+ if (prop)
+ dt_del_property(node, prop);
+}
+
+
+static void astbmc_fixup_bmc_sensors(void)
+{
+ struct dt_node *parent, *node;
+
+ parent = dt_find_by_path(dt_root, "bmc");
+ if (!parent)
+ return;
+ del_compatible(parent);
+
+ parent = dt_find_by_name(parent, "sensors");
+ if (!parent)
+ return;
+ del_compatible(parent);
+
+ dt_for_each_child(parent, node) {
+ if (dt_find_property(node, "compatible"))
+ continue;
+ dt_add_property_string(node, "compatible", "ibm,ipmi-sensor");
+ }
+}
+
static void astbmc_fixup_dt(void)
{
struct dt_node *n, *primary_lpc = NULL;
@@ -234,6 +287,8 @@ static void astbmc_fixup_dt(void)
/* The pel logging code needs a system-id property to work so
make sure we have one. */
astbmc_fixup_dt_system_id();
+
+ astbmc_fixup_bmc_sensors();
}
static void astbmc_fixup_psi_bar(void)
diff --git a/platforms/astbmc/habanero.c b/platforms/astbmc/habanero.c
index 8575be5..c4875ef 100644
--- a/platforms/astbmc/habanero.c
+++ b/platforms/astbmc/habanero.c
@@ -19,6 +19,7 @@
#include <device.h>
#include <console.h>
#include <chip.h>
+#include <ipmi.h>
#include "astbmc.h"
@@ -51,5 +52,7 @@ DECLARE_PLATFORM(habanero) = {
.external_irq = astbmc_ext_irq,
.cec_power_down = astbmc_ipmi_power_down,
.cec_reboot = astbmc_ipmi_reboot,
+ .elog_commit = ipmi_elog_commit,
.load_resource = flash_load_resource,
+ .exit = ipmi_wdt_final_reset,
};