diff options
author | Stewart Smith <stewart@linux.vnet.ibm.com> | 2015-03-06 14:18:45 +1100 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2015-03-06 14:18:45 +1100 |
commit | daa340ae58bbf774628d87505b2696e6f63f75d1 (patch) | |
tree | 757209560a71e40cffbe92a3e779232d4a0b5574 | |
parent | 6cf8b663e7d7cb1e827b6d9c90e694ea583f6f87 (diff) | |
parent | 9a3f68b499e686ff3b543633f59192890f6c740b (diff) | |
download | skiboot-daa340ae58bbf774628d87505b2696e6f63f75d1.zip skiboot-daa340ae58bbf774628d87505b2696e6f63f75d1.tar.gz skiboot-daa340ae58bbf774628d87505b2696e6f63f75d1.tar.bz2 |
Merge branch 'openpower'
-rw-r--r-- | core/flash.c | 58 | ||||
-rw-r--r-- | core/init.c | 5 | ||||
-rw-r--r-- | core/ipmi.c | 9 | ||||
-rw-r--r-- | external/opal-prd/Makefile | 8 | ||||
-rw-r--r-- | external/opal-prd/opal-prd.c | 38 | ||||
-rw-r--r-- | external/opal-prd/thunk.S | 12 | ||||
-rw-r--r-- | hw/ipmi/Makefile.inc | 3 | ||||
-rw-r--r-- | hw/ipmi/ipmi-sel.c | 39 | ||||
-rw-r--r-- | hw/ipmi/ipmi-sensor.c | 134 | ||||
-rw-r--r-- | hw/ipmi/ipmi-watchdog.c | 6 | ||||
-rw-r--r-- | hw/occ.c | 28 | ||||
-rw-r--r-- | include/ipmi.h | 22 | ||||
-rw-r--r-- | include/skiboot.h | 10 | ||||
-rw-r--r-- | platforms/astbmc/common.c | 57 | ||||
-rw-r--r-- | platforms/astbmc/habanero.c | 3 |
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); } @@ -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, }; |