diff options
Diffstat (limited to 'src/usr/sio/siodd.C')
-rwxr-xr-x | src/usr/sio/siodd.C | 85 |
1 files changed, 64 insertions, 21 deletions
diff --git a/src/usr/sio/siodd.C b/src/usr/sio/siodd.C index 5301d9e1c..8bbc59f5b 100755 --- a/src/usr/sio/siodd.C +++ b/src/usr/sio/siodd.C @@ -37,6 +37,9 @@ #include <hbotcompid.H> #include <stdarg.h> #include <targeting/common/target.H> +#include <lpc/lpc_reasoncodes.H> + +#include <console/consoleif.H> // Trace definition trace_desc_t* g_trac_sio = NULL; @@ -191,32 +194,64 @@ DEVICE_REGISTER_ROUTE( DeviceFW::WRITE, TARGETING::TYPE_PROC, ahbSioWriteDD ); -//function to unlock superIO password register -void SioDD::unlock_SIO(TARGETING::Target* i_target) +errlHndl_t SIO::isAvailable(bool& available) { uint8_t l_byte = SIO::SIO_PASSWORD_REG; - errlHndl_t l_err = NULL; - do - { - // Unlock the SIO registers - // (write 0xA5 password to offset 0x2E two times) size_t l_len = sizeof(uint8_t); - l_err = deviceWrite(i_target, - &l_byte, - l_len, - DEVICE_LPC_ADDRESS(LPC::TRANS_IO, SIO::SIO_ADDR_REG_2E)); - if(l_err) { break; } - l_err = deviceWrite(i_target, - &l_byte, - l_len, + errlHndl_t l_err = NULL; + + l_err = deviceWrite(TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &l_byte, l_len, DEVICE_LPC_ADDRESS(LPC::TRANS_IO, SIO::SIO_ADDR_REG_2E)); - } while(0); if (l_err) { - TRACFCOMP(g_trac_sio,"Error in unlocking SIO password register\n"); - errlCommit(l_err, SIO_COMP_ID); + /* FIXME: The implementation assumes that any error indicates that the + * SIO device is not available. This, generally, is a terribe + * assumption. We should instead look for the specific failure, which + * is a LPC SYNC No Response (and this is what we see in skiboot). + * Currently there are open questions about the hardware behaviour as + * observed by hostboot: We see an OPBM Error Acknowledge state when we + * try to access an absent SIO device, but no error state is present in + * the LPCHC status register. + * + * We retain the interface of returning an errlHndl_t to future-proof + * the code. The caller should commit the errl if it is valid. + */ + TRACFCOMP(g_trac_sio, + "Received error during SIO availability test, assuming " + "absent. Reason code: 0x%x, user data: [0x%8x, 0x%8x]", + l_err->reasonCode(), l_err->getUserData1(), + l_err->getUserData2()); + available = false; + delete l_err; + l_err = NULL; + } + else + { + available = true; } + + return l_err; +} + +//function to unlock superIO password register +errlHndl_t SioDD::unlock_SIO(TARGETING::Target* i_target) +{ + uint8_t l_byte = SIO::SIO_PASSWORD_REG; + size_t l_len = sizeof(uint8_t); + errlHndl_t l_err = NULL; + int again = 1; + + do + { + // Unlock the SIO registers (write 0xA5 password to offset 0x2E two times) + l_err = deviceWrite(i_target, &l_byte, l_len, + DEVICE_LPC_ADDRESS(LPC::TRANS_IO, + SIO::SIO_ADDR_REG_2E)); + } while(!l_err && again--); + + return l_err; } //SioDD constructor @@ -225,7 +260,16 @@ SioDD::SioDD(TARGETING::Target* i_target) assert(i_target == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL); mutex_init(&iv_sio_mutex); iv_prev_dev = 0x00; - unlock_SIO(i_target); + + errlHndl_t err = unlock_SIO(i_target); + bool failed = (err != NULL); + delete err; + + /* Unlocked very early, so make some noise if we fail */ + if (failed) + { + printk("SuperIO unlock failed! Expect future errors\n"); + } } //SioDD destructor @@ -279,8 +323,7 @@ errlHndl_t SioDD::_readSIO(TARGETING::Target* i_target, //function to change logical device in SIO errlHndl_t SioDD::changeDevice(TARGETING::Target* i_target, uint8_t i_dev) { - uint8_t l_reg = SIO::SIO_DEVICE_SELECT_REG; - return _writeSIO(i_target, l_reg, &i_dev); + return _writeSIO(i_target, SIO::SIO_DEVICE_SELECT_REG, &i_dev); } //function to read from SIO register |