From 446a72c9f93d9d8a88440102138d7f19d88b9d91 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Sat, 28 Feb 2015 08:00:47 +0800 Subject: external/opal-prd: Add asm directory for opal-prd link Signed-off-by: Jeremy Kerr --- external/opal-prd/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/external/opal-prd/Makefile b/external/opal-prd/Makefile index 7006431..e69c4a3 100644 --- a/external/opal-prd/Makefile +++ b/external/opal-prd/Makefile @@ -10,6 +10,7 @@ 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 +27,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 -- cgit v1.1 From 6669d8655e0d3e7e184fd55e7db409403bd805b9 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Sat, 28 Feb 2015 12:35:04 +0800 Subject: external/opal-prd: Add install target Signed-off-by: Jeremy Kerr --- external/opal-prd/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/external/opal-prd/Makefile b/external/opal-prd/Makefile index e69c4a3..4f4175c 100644 --- a/external/opal-prd/Makefile +++ b/external/opal-prd/Makefile @@ -5,6 +5,9 @@ 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 ' $@; @@ -50,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 -- cgit v1.1 From dd57098db9df493881b37811d070835b679b9a2c Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 4 Mar 2015 10:09:50 +0800 Subject: external/opal-prd: Fix prototypes of i2c read/write callbacks Signed-off-by: Jeremy Kerr --- external/opal-prd/opal-prd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/external/opal-prd/opal-prd.c b/external/opal-prd/opal-prd.c index 402820a..5681f19 100644 --- a/external/opal-prd/opal-prd.c +++ b/external/opal-prd/opal-prd.c @@ -316,8 +316,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 +333,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; -- cgit v1.1 From f51aeaa4fa5074f747684643bf6ebff3e0884f67 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 4 Mar 2015 10:22:03 +0800 Subject: external/opal-prd: NULL-out FSP-only callbacks The HBRT code will check for NULL callbacks, so don't provide them in the hinterface table. Signed-off-by: Jeremy Kerr --- external/opal-prd/opal-prd.c | 30 ++---------------------------- external/opal-prd/thunk.S | 12 +++++++----- 2 files changed, 9 insertions(+), 33 deletions(-) diff --git a/external/opal-prd/opal-prd.c b/external/opal-prd/opal-prd.c index 5681f19..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); @@ -1095,8 +1077,7 @@ out_close: static void usage(const char *progname) { printf("Usage:\n"); - printf("\t%s [--debug] [--file ] [--pnor ]\n" - "\t\t[--allow-fsp-calls]\n", + printf("\t%s [--debug] [--file ] [--pnor ]\n", progname); printf("\t%s occ \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) -- cgit v1.1 From d6fb45e3b29df30e30ac400cfb8b030719207213 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Thu, 29 Jan 2015 14:47:54 +1030 Subject: hw/ipmi: Disable flash access when requested BMC based systems contain a PNOR to provide flash storage. The host normally has exclusive access to the PNOR, however the BMC may use IPMI to request access to perform functions such as update the firmware. Indicate to users of the flash that the device is busy by taking the lock, and setting a per-flash busy flag, which causes flash operations to return OPAL_BUSY. Minor changes from Jeremy Kerr Signed-off-by: Joel Stanley Signed-off-by: Jeremy Kerr --- core/flash.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++---- hw/ipmi/ipmi-sel.c | 36 +++++++++++++++++++++++++++++++-- include/ipmi.h | 5 +++-- include/skiboot.h | 3 +++ 4 files changed, 94 insertions(+), 8 deletions(-) diff --git a/core/flash.c b/core/flash.c index 3a06d1d..9912add 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/hw/ipmi/ipmi-sel.c b/hw/ipmi/ipmi-sel.c index 173b7be..c86c2c9 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,33 @@ 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(); + + /* 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(); + break; + default: + prlog(PR_ERR, "IPMI: invalid PNOR access requested: %02x\n", + access); + } +} + static void sel_power(uint8_t power) { switch (power) { @@ -271,9 +301,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/include/ipmi.h b/include/ipmi.h index 9e52916..de5a61b 100644 --- a/include/ipmi.h +++ b/include/ipmi.h @@ -91,7 +91,6 @@ #define IPMI_NETFN_CHASSIS 0x00 #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) @@ -110,7 +109,9 @@ #define IPMI_GET_MESSAGE IPMI_CODE(IPMI_NETFN_APP, 0x33) #define IPMI_READ_EVENT IPMI_CODE(IPMI_NETFN_APP, 0x35) -#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. diff --git a/include/skiboot.h b/include/skiboot.h index 9dfe0e7..beaa7db 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); -- cgit v1.1 From 0f2343075276a6bcc15c679b4270d0843e002da0 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Fri, 27 Feb 2015 17:35:03 +0800 Subject: occ: Inform OCC of BMC PNOR ownership requests We need to pass the PNOR access status to the OCCs, as they may write to the PNOR in the event of a checkstop. Signed-off-by: Jeremy Kerr --- hw/ipmi/ipmi-sel.c | 3 +++ hw/occ.c | 28 ++++++++++++++++++++++++++++ include/skiboot.h | 7 +++++++ 3 files changed, 38 insertions(+) diff --git a/hw/ipmi/ipmi-sel.c b/hw/ipmi/ipmi-sel.c index c86c2c9..8851dc3 100644 --- a/hw/ipmi/ipmi-sel.c +++ b/hw/ipmi/ipmi-sel.c @@ -195,6 +195,8 @@ static void sel_pnor(uint8_t 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); @@ -203,6 +205,7 @@ static void sel_pnor(uint8_t access) 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", 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/skiboot.h b/include/skiboot.h index beaa7db..0fe50e9 100644 --- a/include/skiboot.h +++ b/include/skiboot.h @@ -221,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); -- cgit v1.1 From 81791e5da50b9804a19f2bfbc25916791b28d499 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Wed, 24 Sep 2014 14:44:20 +1000 Subject: hw/ipmi: Add API for setting sensors This allows setting a given IPMI sensor to a given value. There are helpers for setting the firmware boot progress that will be used for updating the BMC with the host boot progress. The sensor ids are parsed from the device tree. If the sensor cannot be found we will silently continue. Signed-off-by: Joel Stanley --- hw/ipmi/Makefile.inc | 3 +- hw/ipmi/ipmi-sensor.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/ipmi.h | 9 +++++ 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 hw/ipmi/ipmi-sensor.c 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-sensor.c b/hw/ipmi/ipmi-sensor.c new file mode 100644 index 0000000..9b08d30 --- /dev/null +++ b/hw/ipmi/ipmi-sensor.c @@ -0,0 +1,102 @@ +/* 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 +#include +#include +#include +#include + +/* This field controls whether the sensor reading byte is written or left + * unchanged according to the sensor */ +#define IPMI_WRITE_SENSOR 0x01 + +#define FW_PROGRESS_SENSOR 0x0F + +/* Ghetto. TODO: Do something smarter */ +int16_t sensors[255]; + +struct set_sensor_req { + u8 sensor; + u8 operation; + u8 reading[8]; +}; + +int ipmi_set_fw_progress_sensor(uint8_t state) +{ + int fw_sensor_id = sensors[FW_PROGRESS_SENSOR]; + + 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) +{ + struct dt_node *n; + const struct dt_property *type, *num; + + memset(sensors, -1, sizeof(sensors)); + + dt_for_each_compatible(dt_root, n, "ibm,ipmi-sensor") { + type = dt_find_property(n, "ipmi-sensor-type"); + if (!type) { + prerror("IPMI: sensor doesn't have ipmi-sensor-type\n"); + continue; + } + + num = dt_find_property(n, "reg"); + if (!num) { + prerror("IPMI: sensor doesn't have reg property\n"); + continue; + } + sensors[(uint8_t)num->prop[0]] = type->prop[0]; + } +} diff --git a/include/ipmi.h b/include/ipmi.h index de5a61b..0b403eb 100644 --- a/include/ipmi.h +++ b/include/ipmi.h @@ -89,6 +89,7 @@ #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 @@ -108,6 +109,7 @@ #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) /* AMI OEM comamnds. AMI uses NETFN 0x3a and 0x32 */ #define IPMI_PARTIAL_ADD_ESEL IPMI_CODE(0x32, 0xf0) @@ -210,6 +212,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); @@ -239,4 +245,7 @@ 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); + #endif -- cgit v1.1 From 573d0a9af9e46afbefc34cf95510f3d91bc778f6 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 4 Nov 2014 00:02:02 +1100 Subject: hw/ipmi: Set firmware progress sensor We set the IPMI firmware progress sensor to indicate the boot progress of the system. The x86-centric IPMI names don't fit perfectly into what skiboot does, but they do give some indication of the system state. Signed-off-by: Joel Stanley --- core/init.c | 5 +++++ include/ipmi.h | 5 +++++ platforms/astbmc/common.c | 3 +++ 3 files changed, 13 insertions(+) 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 #include #include +#include #include @@ -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/include/ipmi.h b/include/ipmi.h index 0b403eb..c078471 100644 --- a/include/ipmi.h +++ b/include/ipmi.h @@ -84,6 +84,11 @@ #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) diff --git a/platforms/astbmc/common.c b/platforms/astbmc/common.c index a9878bf..93090b2 100644 --- a/platforms/astbmc/common.c +++ b/platforms/astbmc/common.c @@ -101,6 +101,7 @@ void astbmc_init(void) ipmi_opal_init(); ipmi_fru_init(0x01); 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 +109,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(); -- cgit v1.1 From a736f60aaed6bb33047646949df7ab08697a896c Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Fri, 27 Feb 2015 16:12:01 +1030 Subject: hw/ipmi: Set boot count sensor The boot count sensor is a discrete sensor that is set once the system is up and running. On successful boot, the BMC expects the sensor to be set to 2. Signed-off-by: Joel Stanley --- core/ipmi.c | 9 +++++++-- hw/ipmi/ipmi-sensor.c | 30 ++++++++++++++++++++++++++---- include/ipmi.h | 3 +++ 3 files changed, 36 insertions(+), 6 deletions(-) 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/hw/ipmi/ipmi-sensor.c b/hw/ipmi/ipmi-sensor.c index 9b08d30..cdaf5fb 100644 --- a/hw/ipmi/ipmi-sensor.c +++ b/hw/ipmi/ipmi-sensor.c @@ -20,11 +20,12 @@ #include #include -/* This field controls whether the sensor reading byte is written or left - * unchanged according to the sensor */ -#define IPMI_WRITE_SENSOR 0x01 +#define IPMI_WRITE_SENSOR (1 << 1) +#define IPMI_SET_ASSERTION (1 << 5) +#define IPMI_ASSERTION_STATE(state) (1 << state) -#define FW_PROGRESS_SENSOR 0x0F +#define FW_PROGRESS_SENSOR 0x0F +#define BOOT_COUNT_SENSOR 0xAA /* Ghetto. TODO: Do something smarter */ int16_t sensors[255]; @@ -35,6 +36,27 @@ struct set_sensor_req { u8 reading[8]; }; +int ipmi_set_boot_count(void) +{ + struct set_sensor_req req; + struct ipmi_msg *msg; + + memset(&req, 0, sizeof(req)); + + req.sensor = BOOT_COUNT_SENSOR; + /* 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]; diff --git a/include/ipmi.h b/include/ipmi.h index c078471..77e4b9a 100644 --- a/include/ipmi.h +++ b/include/ipmi.h @@ -253,4 +253,7 @@ 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 -- cgit v1.1 From e9e83d2f03dc947e665177af53414347fdcc03a1 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Sat, 28 Feb 2015 10:32:20 +0800 Subject: hw/ipmi: Fix sensor type mappings We're doing the IPMI sensor type mapping the wrong way around; we want to map sensor types to sensor IDs. Also, change the #defines to property reflect that they're types. Signed-off-by: Jeremy Kerr --- hw/ipmi/ipmi-sensor.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/hw/ipmi/ipmi-sensor.c b/hw/ipmi/ipmi-sensor.c index cdaf5fb..a3112ee 100644 --- a/hw/ipmi/ipmi-sensor.c +++ b/hw/ipmi/ipmi-sensor.c @@ -24,8 +24,8 @@ #define IPMI_SET_ASSERTION (1 << 5) #define IPMI_ASSERTION_STATE(state) (1 << state) -#define FW_PROGRESS_SENSOR 0x0F -#define BOOT_COUNT_SENSOR 0xAA +#define FW_PROGRESS_SENSOR_TYPE 0x0F +#define BOOT_COUNT_SENSOR_TYPE 0xAA /* Ghetto. TODO: Do something smarter */ int16_t sensors[255]; @@ -40,10 +40,17 @@ 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 = BOOT_COUNT_SENSOR; + req.sensor = sensor_id; /* Set assertion bit */ req.operation = IPMI_SET_ASSERTION; /* Set state 2 */ @@ -59,7 +66,7 @@ int ipmi_set_boot_count(void) int ipmi_set_fw_progress_sensor(uint8_t state) { - int fw_sensor_id = sensors[FW_PROGRESS_SENSOR]; + 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"); @@ -102,23 +109,26 @@ int ipmi_set_sensor(uint8_t sensor, uint8_t *reading, size_t len) void ipmi_sensor_init(void) { + const struct dt_property *type_prop, *num_prop; + uint8_t num, type; struct dt_node *n; - const struct dt_property *type, *num; memset(sensors, -1, sizeof(sensors)); dt_for_each_compatible(dt_root, n, "ibm,ipmi-sensor") { - type = dt_find_property(n, "ipmi-sensor-type"); - if (!type) { + type_prop = dt_find_property(n, "ipmi-sensor-type"); + if (!type_prop) { prerror("IPMI: sensor doesn't have ipmi-sensor-type\n"); continue; } - num = dt_find_property(n, "reg"); - if (!num) { + num_prop = dt_find_property(n, "reg"); + if (!num_prop) { prerror("IPMI: sensor doesn't have reg property\n"); continue; } - sensors[(uint8_t)num->prop[0]] = type->prop[0]; + num = (uint8_t)dt_property_get_cell(num_prop, 0); + type = (uint8_t)dt_property_get_cell(type_prop, 0); + sensors[type] = num; } } -- cgit v1.1 From 12a7f2863075e2b21053d5874050f3d0bf3f60a9 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Sat, 28 Feb 2015 11:10:02 +0800 Subject: platforms/astbmc: Fixup hostboot sensor nodes The sensor nodes should have the compatible properties, not the "bmc" and "sensors" nodes. Signed-off-by: Jeremy Kerr --- platforms/astbmc/common.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/platforms/astbmc/common.c b/platforms/astbmc/common.c index 93090b2..7e84ec9 100644 --- a/platforms/astbmc/common.c +++ b/platforms/astbmc/common.c @@ -213,6 +213,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; @@ -237,6 +268,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) -- cgit v1.1 From bd90edea34c562aa91346cc1116c1568e202f3d4 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Tue, 3 Mar 2015 12:17:09 +0800 Subject: platforms/habanero: sync platform definition with palemtto We're missing callbacks for elog_commit and exit. Signed-off-by: Jeremy Kerr --- platforms/astbmc/habanero.c | 3 +++ 1 file changed, 3 insertions(+) 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 #include #include +#include #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, }; -- cgit v1.1 From b8a5d006c7d4319ce498bd8e6a1f34cf2f231fe8 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 4 Mar 2015 08:55:05 +0800 Subject: astbmc: Use firmware FRU ID from the device tree Rather than using the hardcoded FRU ID, parse it from the device tree. Signed-off-by: Jeremy Kerr --- platforms/astbmc/common.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/platforms/astbmc/common.c b/platforms/astbmc/common.c index 7e84ec9..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,7 +118,7 @@ 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(); -- cgit v1.1 From dddd88034e069ba2c1fe540f1a701d94cd01710e Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Wed, 4 Mar 2015 17:11:29 +1030 Subject: external/opal-prd: Enhance PNOR error messages Provide detailed feedback when encountering errors in the PNOR code. Signed-off-by: Joel Stanley Signed-off-by: Jeremy Kerr --- external/opal-prd/pnor.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/external/opal-prd/pnor.c b/external/opal-prd/pnor.c index 0eca693..e5609fe 100644 --- a/external/opal-prd/pnor.c +++ b/external/opal-prd/pnor.c @@ -105,8 +105,8 @@ void dump_parts(struct ffs_handle *ffs) { } } -int mtd_write(struct pnor *pnor, int fd, void *data, uint64_t offset, - size_t len) +static int mtd_write(struct pnor *pnor, int fd, void *data, uint64_t offset, + size_t len) { int write_start, write_len, start_waste, rc; bool end_waste = false; @@ -115,7 +115,7 @@ int mtd_write(struct pnor *pnor, int fd, void *data, uint64_t offset, if (len > pnor->size || offset > pnor->size || len + offset > pnor->size) - return -1; + return -ERANGE; start_waste = offset % pnor->erasesize; write_start = offset - start_waste; @@ -191,8 +191,8 @@ out: return rc; } -int mtd_read(struct pnor *pnor, int fd, void *data, uint64_t offset, - size_t len) +static int mtd_read(struct pnor *pnor, int fd, void *data, uint64_t offset, + size_t len) { int read_start, read_len, start_waste, rc; int mask = pnor->erasesize - 1; @@ -200,7 +200,7 @@ int mtd_read(struct pnor *pnor, int fd, void *data, uint64_t offset, if (len > pnor->size || offset > pnor->size || len + offset > pnor->size) - return -1; + return -ERANGE; /* Align start to erase block size */ start_waste = offset % pnor->erasesize; @@ -214,7 +214,7 @@ int mtd_read(struct pnor *pnor, int fd, void *data, uint64_t offset, /* Ensure read is not out of bounds */ if (read_start + read_len > pnor->size) { fprintf(stderr, "PNOR: read out of bounds\n"); - return -1; + return -ERANGE; } buf = malloc(read_len); @@ -231,7 +231,7 @@ int mtd_read(struct pnor *pnor, int fd, void *data, uint64_t offset, goto out; } - /* Copy data into destination, cafefully avoiding the extra data we + /* Copy data into destination, carefully avoiding the extra data we * added to align to block size */ memcpy(data, buf + start_waste, len); rc = len; @@ -246,19 +246,28 @@ int pnor_operation(struct pnor *pnor, const char *name, uint64_t offset, int rc, fd; uint32_t pstart, psize, idx; - if (!pnor->ffsh) - return -1; + if (!pnor->ffsh) { + warnx("PNOR: ffs not initialised"); + return -EBUSY; + } rc = ffs_lookup_part(pnor->ffsh, name, &idx); - if (rc) - return -1; + if (rc) { + warnx("PNOR: failed to find partition '%s'", name); + return -ENOENT; + } ffs_part_info(pnor->ffsh, idx, NULL, &pstart, &psize, NULL, NULL); - if (rc) - return -1; + if (rc) { + warnx("PNOR: unable to fetch partition info"); + return -ENOENT; + } - if (size > psize || offset > psize || size + offset > psize) - return -1; + if (size > psize || offset > psize || size + offset > psize) { + warnx("PNOR: offset (%ld) or size (%ld) out of bounds (%d)", + offset, size, psize); + return -ERANGE; + } fd = open(pnor->path, O_RDWR); if (fd < 0) { @@ -280,7 +289,7 @@ int pnor_operation(struct pnor *pnor, const char *name, uint64_t offset, rc = mtd_write(pnor, fd, data, offset, size); break; default: - rc = -1; + rc = -EIO; fprintf(stderr, "PNOR: Invalid operation\n"); goto out; } -- cgit v1.1 From 5ae13c25766b0025ffab99b9f8622182af2d4b36 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Wed, 4 Mar 2015 17:11:30 +1030 Subject: external/opal-prd: Allow partial ops with PNOR API The PNOR operations will now return the number of bytes successfully written, which may be less than the number of bytes requested, similar to read(2) and write(2). The hostboot interface is updated with this information. The signature does not change. Signed-off-by: Joel Stanley Signed-off-by: Jeremy Kerr --- external/opal-prd/hostboot-interface.h | 4 ++-- external/opal-prd/pnor.c | 32 ++++++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/external/opal-prd/hostboot-interface.h b/external/opal-prd/hostboot-interface.h index 1088178..a518f50 100644 --- a/external/opal-prd/hostboot-interface.h +++ b/external/opal-prd/hostboot-interface.h @@ -170,7 +170,7 @@ struct host_interfaces { * @param[in] i_offset: offset within the partition * @param[out] o_data: pointer to the data read * @param[in] i_sizeBytes: size of data to read - * @retval rc - non-zero on error + * @retval rc - number of bytes read, or non-zero on error * @platform OpenPOWER */ int (*pnor_read) ( uint32_t i_proc, const char* i_partitionName, @@ -183,7 +183,7 @@ struct host_interfaces { * @param[in] i_offset: offset withing the partition * @param[in] i_data: pointer to the data to write * @param[in] i_sizeBytes: size of data to write - * @retval rc - non-zero on error + * @retval rc - number of bytes written, or non-zero on error * @platform OpenPOWER */ int (*pnor_write) ( uint32_t i_proc, const char* i_partitionName, diff --git a/external/opal-prd/pnor.c b/external/opal-prd/pnor.c index e5609fe..e40d292 100644 --- a/external/opal-prd/pnor.c +++ b/external/opal-prd/pnor.c @@ -240,11 +240,16 @@ out: return rc; } +/* Similar to read(2), this performs partial operations where the number of + * bytes read/written may be less than size. + * + * Returns number of bytes written, or a negative value on failure. */ int pnor_operation(struct pnor *pnor, const char *name, uint64_t offset, - void *data, size_t size, enum pnor_op op) + void *data, size_t requested_size, enum pnor_op op) { int rc, fd; uint32_t pstart, psize, idx; + int size; if (!pnor->ffsh) { warnx("PNOR: ffs not initialised"); @@ -263,9 +268,23 @@ int pnor_operation(struct pnor *pnor, const char *name, uint64_t offset, return -ENOENT; } - if (size > psize || offset > psize || size + offset > psize) { - warnx("PNOR: offset (%ld) or size (%ld) out of bounds (%d)", - offset, size, psize); + if (offset > psize) { + warnx("PNOR: offset (%ld) out of bounds (%d)", offset, psize); + return -ERANGE; + } + + /* Large requests are trimmed */ + if (requested_size > psize) + size = psize; + else + size = requested_size; + + if (size + offset > psize) + size = psize - offset; + + if (size < 0) { + warnx("PNOR: size (%zd) and offset (%ld) out of bounds (%d)", + requested_size, offset, psize); return -ERANGE; } @@ -297,11 +316,8 @@ int pnor_operation(struct pnor *pnor, const char *name, uint64_t offset, if (rc < 0) warn("PNOR: MTD operation failed"); else if (rc != size) - warnx("PNOR: mtd operation returned %d, expected %zd", + warnx("PNOR: mtd operation returned %d, expected %d", rc, size); - else - rc = 0; - out: close(fd); -- cgit v1.1 From 29289f44e289afeb7eb7e7ce0687d787cebae90e Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Wed, 4 Mar 2015 17:11:31 +1030 Subject: external/opal-prd: Correct partition offset The start of the partition was not used when sending the size to the mtd_{read,write} calls. This meant they were unconditionally reading and writing to the start of the flash, instead of the partition. Signed-off-by: Joel Stanley Signed-off-by: Jeremy Kerr --- external/opal-prd/pnor.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/external/opal-prd/pnor.c b/external/opal-prd/pnor.c index e40d292..3ae7fcd 100644 --- a/external/opal-prd/pnor.c +++ b/external/opal-prd/pnor.c @@ -294,18 +294,12 @@ int pnor_operation(struct pnor *pnor, const char *name, uint64_t offset, return fd; } - rc = lseek(fd, pstart, SEEK_SET); - if (rc < 0) { - perror(pnor->path); - goto out; - } - switch (op) { case PNOR_OP_READ: - rc = mtd_read(pnor, fd, data, offset, size); + rc = mtd_read(pnor, fd, data, pstart + offset, size); break; case PNOR_OP_WRITE: - rc = mtd_write(pnor, fd, data, offset, size); + rc = mtd_write(pnor, fd, data, pstart + offset, size); break; default: rc = -EIO; -- cgit v1.1 From 3955cd2be2067b5db1d9dcace986b88aeccf1f20 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Thu, 5 Mar 2015 09:25:31 +1100 Subject: core/flash: Fix invalid try_lock check in flash_nvram_write We have the logic inverted here. Signed-off-by: Jeremy Kerr --- core/flash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/flash.c b/core/flash.c index 9912add..b0c5050 100644 --- a/core/flash.c +++ b/core/flash.c @@ -121,7 +121,7 @@ static int flash_nvram_write(uint32_t dst, void *src, uint32_t len) { int rc; - if (try_lock(&flash_lock)) + if (!try_lock(&flash_lock)) return OPAL_BUSY; if (nvram_flash->busy) { -- cgit v1.1 From 9a3f68b499e686ff3b543633f59192890f6c740b Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Thu, 5 Mar 2015 15:20:34 +1100 Subject: hw/ipmmi: Disable watchdog on final reset Rather than doing the last disable in the interrupt path, do it on final reset. This is a temporary workaround for incorrect pretimeout behaviour. Signed-off-by: Jeremy Kerr --- hw/ipmi/ipmi-watchdog.c | 6 ++++++ 1 file changed, 6 insertions(+) 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); } -- cgit v1.1