From 21185b30cd99a00f01e15edba28402cdc00de1d1 Mon Sep 17 00:00:00 2001 From: "Terry J. Opie" Date: Wed, 17 Aug 2011 14:12:26 -0500 Subject: I2C Device Driver Good Machine Path Change-Id: I88bf5ce464cdeceb3e151bde72fb51295ede07c0 Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/428 Tested-by: Jenkins Server Reviewed-by: A. Patrick Williams III Reviewed-by: Terry J. Opie --- src/usr/i2c/i2c.C | 859 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 783 insertions(+), 76 deletions(-) (limited to 'src/usr/i2c/i2c.C') diff --git a/src/usr/i2c/i2c.C b/src/usr/i2c/i2c.C index e172f9e63..8b2239b63 100755 --- a/src/usr/i2c/i2c.C +++ b/src/usr/i2c/i2c.C @@ -31,6 +31,8 @@ // Includes // ---------------------------------------------- #include +#include + #include #include #include @@ -40,10 +42,13 @@ #include "i2c.H" // ---------------------------------------------- -// Trace definition +// Trace definitions trace_desc_t* g_trac_i2c = NULL; TRAC_INIT( & g_trac_i2c, "I2C", 4096 ); +trace_desc_t* g_trac_i2cr = NULL; +TRAC_INIT( & g_trac_i2cr, "I2CR", 4096 ); + namespace I2C { @@ -53,14 +58,11 @@ DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, TARGETING::TYPE_PROC, i2cPerformOp ); -// TODO - This will be added back in once the bug in the registration -// code has been fixed. Right now it will not compile with 2 registrations -// to the same function. // Register the perform Op with the routing code for Memory Buffers. -//DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, -// DeviceFW::I2C, -// TARGETING::TYPE_MEMBUF, -// i2cPerformOp ); +DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, + DeviceFW::I2C, + TARGETING::TYPE_MEMBUF, + i2cPerformOp ); // ------------------------------------------------------------------ // i2cPerformOp @@ -73,55 +75,99 @@ errlHndl_t i2cPerformOp( DeviceFW::OperationType i_opType, va_list i_args ) { errlHndl_t err = NULL; - uint64_t addr = va_arg( i_args, uint64_t ); - TRACFCOMP( g_trac_i2c, + // Get the input args our of the va_list + // Address, Port, Engine, Device Addr. + input_args_t args; + args.addr = va_arg( i_args, uint64_t ); + args.port = va_arg( i_args, uint64_t ); + args.engine = va_arg( i_args, uint64_t ); + args.devAddr = va_arg( i_args, uint64_t ); + + TRACDCOMP( g_trac_i2c, ENTER_MRK"i2cPerformOp()" ); - // -------------------------------------------------------------- - // NOTE: There are attributes that can be read for targetted - // devices (slaves). But since we don't have any of those - // targets yet, there isn't a way to test reading those - // attributes yet. I assume those will be added as full device - // driver testing is started on Simics. - // -------------------------------------------------------------- - if( i_opType == DeviceFW::READ ) - { - err = i2cRead( i_target, - addr, - io_buffer, - io_buflen ); - } - else if( i_opType == DeviceFW::WRITE ) - { - err = i2cWrite( i_target, - addr, - io_buffer, - io_buflen ); - } - else + do { - TRACFCOMP( g_trac_i2c, - ERR_MRK"i2cPerformOp() - Unknown Operation Type!" ); - - /*@ - * @errortype - * @reasoncode I2C_INVALID_OP_TYPE - * @severity ERRL_SEV_UNRECOVERABLE - * @moduleid I2C_PERFORM_OP - * @userdata1 i_opType - * @userdata2 addr - * @devdesc Invalid Operation type. - */ - err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, - I2C_PERFORM_OP, - I2C_INVALID_OP_TYPE, - i_opType, - addr ); - - } - - TRACFCOMP( g_trac_i2c, + // Check for Master Sentinel chip + if( TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL == i_target ) + { + TRACFCOMP( g_trac_i2c, + ERR_MRK"i2cPerformOp() - Cannot target Master Sentinel Chip " + "for an I2C Operation!" ); + + /*@ + * @errortype + * @reasoncode I2C_MASTER_SENTINEL_TARGET + * @severity ERRORLOG_SEV_UNRECOVERABLE + * @moduleid I2C_PERFORM_OP + * @userdata1 Operation Type requested + * @userdata2 + * @devdesc Master Sentinel chip was used as a target for an + * I2C operation. This is NOT permitted. + */ + err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, + I2C_PERFORM_OP, + I2C_MASTER_SENTINEL_TARGET, + i_opType, + 0x0 ); + + break; + } + + // TODO - Locking needs to be implemented for each engine on each + // possible chip. The details of this still need to be worked out. + // This will be implemented with the bad machine path story (3629). + + if( i_opType == DeviceFW::READ ) + { + err = i2cRead( i_target, + io_buffer, + io_buflen, + args ); + + if( err ) + { + break; + } + } + else if( i_opType == DeviceFW::WRITE ) + { + err = i2cWrite( i_target, + io_buffer, + io_buflen, + args ); + + if( err ) + { + break; + } + } + else + { + TRACFCOMP( g_trac_i2c, + ERR_MRK"i2cPerformOp() - Unknown Operation Type!" ); + + /*@ + * @errortype + * @reasoncode I2C_INVALID_OP_TYPE + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid I2C_PERFORM_OP + * @userdata1 i_opType + * @userdata2 addr + * @devdesc Invalid Operation type. + */ + err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, + I2C_PERFORM_OP, + I2C_INVALID_OP_TYPE, + i_opType, + args.addr ); + + break; + } + } while( 0 ); + + TRACDCOMP( g_trac_i2c, EXIT_MRK"i2cPerformOp() - %s", ((NULL == err) ? "No Error" : "With Error") ); @@ -132,26 +178,188 @@ errlHndl_t i2cPerformOp( DeviceFW::OperationType i_opType, // i2cRead // ------------------------------------------------------------------ errlHndl_t i2cRead ( TARGETING::Target * i_target, - uint64_t i_addr, void * o_buffer, - size_t & i_size ) + size_t & i_buflen, + input_args_t i_args ) { errlHndl_t err = NULL; + size_t size = sizeof(uint64_t); + uint64_t bytesRead = 0x0; + + uint64_t addr = i_args.addr; + uint64_t engine = i_args.engine; + uint64_t devAddr = i_args.devAddr; + + // TODO - hardcoded to 400KHz for now + uint64_t interval = I2C_TIMEOUT_INTERVAL( I2C_CLOCK_DIVISOR_400KHZ ); + uint64_t timeoutCount = I2C_TIMEOUT_COUNT( interval ); - TRACFCOMP( g_trac_i2c, + // Define the regs we'll be using + cmdreg cmd; + statusreg status; + fiforeg fifo; + + TRACDCOMP( g_trac_i2c, ENTER_MRK"i2cRead()" ); + TRACSCOMP( g_trac_i2cr, + "I2C READ START : engine %.2X : devAddr %.2X : addr %.4X : len %d", + engine, devAddr, addr, i_buflen ); + do { - // TODO - Functionality still needs to be added. + // Do Command/Mode reg setups. + size_t tmpSize = 0; err = i2cSetup( i_target, - i_addr, - i_size, - true, - true ); + tmpSize, // First length is always 0 for reads (byte addr) + false, // RnW, false to do initial setup of byte addr + false, + i_args ); + + if( err ) + { + break; + } + + // Write the 2byte address to the FIFO + err = i2cWriteByteAddr( i_target, + i_args ); + + if( err ) + { + break; + } + + // Wait for cmd complete before continuing + err = i2cWaitForCmdComp( i_target, + engine ); + + if( err ) + { + break; + } + + // Setup the Command register to start the read operation + cmd.value = 0x0ull; + cmd.with_start = 1; + cmd.with_stop = 1; + cmd.with_addr = 1; + cmd.device_addr = devAddr; + cmd.read_not_write = 1; // Now doing a read + cmd.length_b = i_buflen; + + err = deviceWrite( i_target, + &cmd.value, + size, + DEVICE_SCOM_ADDRESS( masterAddrs[engine].command ) ); + + if( err ) + { + break; + } + + for( bytesRead = 0; bytesRead < i_buflen; bytesRead++ ) + { + TRACDCOMP( g_trac_i2c, + INFO_MRK"Reading byte (%d) out of (%d)", + (bytesRead+1), i_buflen ); + + // Read the status reg to see if there is data in the FIFO + status.value = 0x0ull; + err = i2cReadStatusReg( i_target, + engine, + status ); + + if( err ) + { + break; + } + + while( 0 == status.fifo_entry_count ) + { + nanosleep( 0, (interval * 1000) ); + + status.value = 0x0ull; + err = i2cReadStatusReg( i_target, + engine, + status ); + + if( err ) + { + break; + } + + if( 0 == timeoutCount-- ) + { + TRACFCOMP( g_trac_i2c, + ERR_MRK"i2cRead() - Timed out waiting for data in FIFO!" ); + + /*@ + * @errortype + * @reasoncode I2C_FIFO_TIMEOUT + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid I2C_READ + * @userdata1 Status Register Value + * @userdata2 Byte Address of write + * @devdesc Timed out waiting for data in FIFO to read + */ + err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, + I2C_READ, + I2C_FIFO_TIMEOUT, + status.value, + addr ); + + break; + } + } + + if( err ) + { + break; + } + + // Read the data from the fifo + fifo.value = 0x0ull; + err = deviceRead( i_target, + &fifo.value, + size, + DEVICE_SCOM_ADDRESS( masterAddrs[engine].fifo ) ); + + if( err ) + { + break; + } + + *((uint8_t*)o_buffer + bytesRead) = fifo.byte_0; + + TRACSCOMP( g_trac_i2cr, + "I2C READ DATA : engine %.2X : devAddr %.2X : addr %.4X : " + // TODO - when trace parameter limit is lifted, add byte count back in +// "byte %d : %.2X", + "%.2X", + engine, devAddr, addr, /*bytesRead,*/ fifo.byte_0 ); + } + + if( err ) + { + break; + } + + // Poll for Command Complete + err = i2cWaitForCmdComp( i_target, + engine ); + + if( err ) + { + break; + } } while( 0 ); - TRACFCOMP( g_trac_i2c, + TRACSCOMP( g_trac_i2cr, + "I2C READ END : engine %.2X : devAddr %.2X : addr %.4X : len %d", + engine, devAddr, addr, i_buflen ); + + TRACDCOMP( g_trac_i2c, EXIT_MRK"i2cRead()" ); return err; @@ -161,26 +369,107 @@ errlHndl_t i2cRead ( TARGETING::Target * i_target, // i2cWrite // ------------------------------------------------------------------ errlHndl_t i2cWrite ( TARGETING::Target * i_target, - uint64_t i_addr, void * i_buffer, - size_t & io_size ) + size_t & io_buflen, + input_args_t i_args ) { errlHndl_t err = NULL; + size_t size = sizeof(uint64_t); + uint64_t bytesWritten = 0x0; + + uint64_t addr = i_args.addr; + uint64_t engine = i_args.engine; + uint64_t devAddr = i_args.devAddr; - TRACFCOMP( g_trac_i2c, + // Define regs we'll be using + fiforeg fifo; + + TRACDCOMP( g_trac_i2c, ENTER_MRK"i2cWrite()" ); + TRACSCOMP( g_trac_i2cr, + "I2C WRITE START : engine %.2X : devAddr %.2X : addr %.4X : len %d", + engine, devAddr, addr, io_buflen ); + do { - // TODO - Functionality still needs to be added. + // Do Command/Mode reg setups err = i2cSetup( i_target, - i_addr, - io_size, + io_buflen, + false, true, - false ); + i_args ); + + if( err ) + { + break; + } + + // Write the 2 byte address to the FIFO + err = i2cWriteByteAddr( i_target, + i_args ); + + if( err ) + { + break; + } + + for( bytesWritten = 0x0; bytesWritten < io_buflen; bytesWritten++ ) + { + // Wait for FIFO space to be available for the write + err = i2cWaitForFifoSpace( i_target, + i_args ); + + if( err ) + { + break; + } + + // Write data to FIFO + fifo.value = 0x0ull; + fifo.byte_0 = *((uint8_t*)i_buffer + bytesWritten); + + err = deviceWrite( i_target, + &fifo.value, + size, + DEVICE_SCOM_ADDRESS( masterAddrs[engine].fifo ) ); + + if( err ) + { + break; + } + + TRACSCOMP( g_trac_i2cr, + "I2C WRITE DATA : engine %.2X : devAddr %.2X : addr %.4X : " + // TODO - Once trace paramenter limit is lifted add byte count in + "%.2X", +// "byte %d : %.2X", + engine, devAddr, addr, /*bytesWritten,*/ fifo.byte_0 ); + } + + if( err ) + { + break; + } + + // Check for Command complete, and make sure no errors + err = i2cWaitForCmdComp( i_target, + engine ); + + if( err ) + { + break; + } + + // Make sure we send back how many bytes were written + io_buflen = bytesWritten; } while( 0 ); - TRACFCOMP( g_trac_i2c, + TRACSCOMP( g_trac_i2cr, + "I2C WRITE END : engine %.2X : devAddr %.2X : addr %.4X : len %d", + engine, devAddr, addr, io_buflen ); + + TRACDCOMP( g_trac_i2c, EXIT_MRK"i2cWrite()" ); return err; @@ -190,25 +479,443 @@ errlHndl_t i2cWrite ( TARGETING::Target * i_target, // i2cSetup // ------------------------------------------------------------------ errlHndl_t i2cSetup ( TARGETING::Target * i_target, - uint64_t i_addr, - size_t & i_size, + size_t & i_buflen, + bool i_readNotWrite, bool i_withStop, - bool i_readNotWrite ) + input_args_t i_args ) { errlHndl_t err = NULL; + size_t size = sizeof(uint64_t); - TRACFCOMP( g_trac_i2c, + uint64_t port = i_args.port; + uint64_t engine = i_args.engine; + uint64_t devAddr = i_args.devAddr; + + TRACDCOMP( g_trac_i2c, ENTER_MRK"i2cSetup()" ); + // Define the registers that we'll use + statusreg status; + modereg mode; + cmdreg cmd; + do { - // TODO - Functionality still needs to be added. + // TODO - Validate some of the arg values passed in + + // Wait for Command complete before we start + status.value = 0x0ull; + err = i2cWaitForCmdComp( i_target, + engine ); + + if( err ) + { + break; + } + + // Write Mode Register: + // - bit rate divisor + // - port number + mode.value = 0x0ull; + + // Hard code to 400KHz until we get attributes in place to get this from + // the target. + mode.bit_rate_div = I2C_CLOCK_DIVISOR_400KHZ; + mode.port_num = port; + + err = deviceWrite( i_target, + &mode.value, + size, + DEVICE_SCOM_ADDRESS( masterAddrs[engine].mode ) ); + + if( err ) + { + break; + } + + // Write Command Register: + // - with start + // - with stop + // - RnW + // - length + cmd.value = 0x0ull; + cmd.with_start = 1; + cmd.with_stop = (i_withStop ? 1 : 0); + cmd.with_addr = 1; + cmd.device_addr = devAddr; + cmd.read_not_write = (i_readNotWrite ? 1 : 0); + + // Need to accomodate the byte addr length when writing + // to the FIFO, so add 2 bytes to the length. + cmd.length_b = i_buflen + 2; + + err = deviceWrite( i_target, + &cmd.value, + size, + DEVICE_SCOM_ADDRESS( masterAddrs[engine].command ) ); + + if( err ) + { + break; + } } while( 0 ); - TRACFCOMP( g_trac_i2c, + TRACDCOMP( g_trac_i2c, EXIT_MRK"i2cSetup()" ); return err; } // end i2cSetup +// ------------------------------------------------------------------ +// i2cWaitForCmdComp +// ------------------------------------------------------------------ +errlHndl_t i2cWaitForCmdComp ( TARGETING::Target * i_target, + uint64_t i_engine ) +{ + errlHndl_t err = NULL; + + TRACDCOMP( g_trac_i2c, + ENTER_MRK"i2cWaitForCmdComp()" ); + + // Define the registers that we'll use + statusreg status; + + // TODO - hardcoded to 400KHz for now. + uint64_t interval = I2C_TIMEOUT_INTERVAL( I2C_CLOCK_DIVISOR_400KHZ ); + uint64_t timeoutCount = I2C_TIMEOUT_COUNT( interval ); + + do + { + // Check the Command Complete bit + do + { + nanosleep( 0, (interval * 1000) ); + status.value = 0x0ull; + err = i2cReadStatusReg( i_target, + i_engine, + status ); + + if( err ) + { + break; + } + + if( 0 == timeoutCount-- ) + { + TRACFCOMP( g_trac_i2c, + ERR_MRK"i2cWaitForCmdComp() - Timed out waiting for Command Complete!" ); + + /*@ + * @errortype + * @reasoncode I2C_CMD_COMP_TIMEOUT + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid I2C_WAIT_FOR_CMD_COMP + * @userdata1 Status Register Value + * @userdata2 Master Engine + * @devdesc Timed out waiting for command complete. + */ + err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, + I2C_WAIT_FOR_CMD_COMP, + I2C_CMD_COMP_TIMEOUT, + status.value, + i_engine ); + + break; + } + } while( 0 == status.command_complete ); /* Command Complete */ + + if( err ) + { + break; + } + } while( 0 ); + + TRACDCOMP( g_trac_i2c, + EXIT_MRK"i2cWaitForCmdComp()" ); + + return err; +} // end i2cWaitForBus + +// ------------------------------------------------------------------ +// i2cReadStatusReg +// ------------------------------------------------------------------ +errlHndl_t i2cReadStatusReg ( TARGETING::Target * i_target, + uint64_t i_engine, + statusreg & o_statusReg ) +{ + errlHndl_t err = NULL; + size_t size = sizeof(uint64_t); + + TRACDCOMP( g_trac_i2c, + ENTER_MRK"i2cReadStatusReg()" ); + + do + { + // Read the status Reg + err = deviceRead( i_target, + &o_statusReg.value, + size, + DEVICE_SCOM_ADDRESS( masterAddrs[i_engine].status ) ); + + if( err ) + { + break; + } + + // Check for Errors + // Per the specification it is a requirement to check for errors each time + // that the status register is read. + err = i2cCheckForErrors( i_target, + o_statusReg ); + + if( err ) + { + break; + } + } while( 0 ); + + TRACDCOMP( g_trac_i2c, + EXIT_MRK"i2cReadStatusReg()" ); + + return err; +} // end i2cReadStatusReg + +// ------------------------------------------------------------------ +// i2cCheckForErrors +// ------------------------------------------------------------------ +errlHndl_t i2cCheckForErrors ( TARGETING::Target * i_target, + statusreg i_statusVal ) +{ + errlHndl_t err = NULL; + i2cReasonCode reasonCode = I2C_INVALID_REASONCODE; + + TRACDCOMP( g_trac_i2c, + ENTER_MRK"i2cCheckForErrors()" ); + + do + { + if( 1 == i_statusVal.invalid_cmd ) + { + reasonCode = I2C_INVALID_COMMAND; + } + else if( 1 == i_statusVal.lbus_parity_error ) + { + reasonCode = I2C_LBUS_PARITY_ERROR; + } + else if( 1 == i_statusVal.backend_overrun_error ) + { + reasonCode = I2C_BACKEND_OVERRUN_ERROR; + } + else if( 1 == i_statusVal.backend_access_error ) + { + reasonCode = I2C_BACKEND_ACCESS_ERROR; + } + else if( 1 == i_statusVal.arbitration_lost_error ) + { + reasonCode = I2C_ARBITRATION_LOST_ERROR; + } + else if( 1 == i_statusVal.nack_received ) + { + reasonCode = I2C_NACK_RECEIVED; + } + else if( 1 == i_statusVal.data_request ) + { + reasonCode = I2C_DATA_REQUEST; + } + else if( 1 == i_statusVal.stop_error ) + { + reasonCode = I2C_STOP_ERROR; + } + else if( 1 == i_statusVal.any_i2c_interrupt ) + { + // TODO - This will be expanded during bad machine path to specify + // which interrupts have fired. + reasonCode = I2C_INTERRUPT; + } + + if( I2C_INVALID_REASONCODE != reasonCode ) + { + TRACFCOMP( g_trac_i2c, + ERR_MRK"i2cCheckForErrors() - Error found after command complete!" ); + + /*@ + * @errortype + * @reasoncode I2C_HW_ERROR_FOUND + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid I2C_CHECK_FOR_ERRORS + * @userdata1 Reasoncode + * @userdata2 + * @devdesc Error was found in I2C status register. Check userdata1 + * to determine what the error was. + */ + err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, + I2C_CHECK_FOR_ERRORS, + I2C_HW_ERROR_FOUND, + reasonCode, + 0x0 ); + + // TODO - RTC entry to be created to allow for adding a target to an errorlog. + // Once that is implemented, the target will be used here to add to the log. + + break; + } + } while( 0 ); + + TRACDCOMP( g_trac_i2c, + EXIT_MRK"i2cCheckForErrors()" ); + + return err; +} // end i2cCheckForErrors + +// ------------------------------------------------------------------ +// i2cWriteByteAddr +// ------------------------------------------------------------------ +errlHndl_t i2cWriteByteAddr ( TARGETING::Target * i_target, + input_args_t i_args ) +{ + errlHndl_t err = NULL; + size_t size = sizeof(uint64_t); + + uint64_t engine = i_args.engine; + uint64_t addr = i_args.addr; + + // Define the reg(s) we'll be accessing + fiforeg fifo; + + TRACDCOMP( g_trac_i2c, + ENTER_MRK"i2cWriteByteAddr( %04x )", + addr ); + + do + { + // Make sure there is space in the FIFO + err = i2cWaitForFifoSpace( i_target, + i_args ); + + if( err ) + { + break; + } + + // Write first byte of address to the FIFO + fifo.value = 0x0ull; + fifo.byte_0 = ((addr & 0xFF00) >> 8); + + err = deviceWrite( i_target, + &fifo.value, + size, + DEVICE_SCOM_ADDRESS( masterAddrs[engine].fifo ) ); + + if( err ) + { + break; + } + + // Write 2nd byte of address to the FIFO + fifo.value = 0x0ull; + fifo.byte_0 = (addr & 0xFF); + + err = deviceWrite( i_target, + &fifo.value, + size, + DEVICE_SCOM_ADDRESS( masterAddrs[engine].fifo ) ); + + if( err ) + { + break; + } + } while( 0 ); + + TRACDCOMP( g_trac_i2c, + EXIT_MRK"i2cWriteByteAddr( %04x )", + addr ); + + return err; +} // end i2cWriteByteAddr + + +// ------------------------------------------------------------------ +// i2cWaitForFifoSpace +// ------------------------------------------------------------------ +errlHndl_t i2cWaitForFifoSpace ( TARGETING::Target * i_target, + input_args_t i_args ) +{ + errlHndl_t err = NULL; + uint64_t engine = i_args.engine; + uint64_t addr = i_args.addr; + + // TODO - hardcoded to 400KHz for now + uint64_t interval = I2C_TIMEOUT_INTERVAL( I2C_CLOCK_DIVISOR_400KHZ ); + uint64_t timeoutCount = I2C_TIMEOUT_COUNT( interval ); + + // Define regs we'll be using + statusreg status; + + TRACDCOMP( g_trac_i2c, + ENTER_MRK"i2cWaitForFifoSpace()" ); + + do + { + // Read Status reg to get available FIFO bytes + status.value = 0x0ull; + err = i2cReadStatusReg( i_target, + engine, + status ); + + if( err ) + { + break; + } + + while( I2C_MAX_FIFO_CAPACITY <= status.fifo_entry_count ) + { + // FIFO is full, wait before writing any data + nanosleep( 0, (interval * 1000) ); + + status.value = 0x0ull; + err = i2cReadStatusReg( i_target, + engine, + status ); + + if( err ) + { + break; + } + + if( 0 == timeoutCount-- ) + { + TRACFCOMP( g_trac_i2c, + ERR_MRK"i2cWrite() - Timed out waiting for space in FIFO!" ); + + /*@ + * @errortype + * @reasoncode I2C_FIFO_TIMEOUT + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid I2C_WRITE + * @userdata1 Status Register Value + * @userdata2 Requested Byte Address + * @devdesc Timed out waiting for space to write into FIFO. + */ + err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, + I2C_WRITE, + I2C_FIFO_TIMEOUT, + status.value, + addr ); + + break; + } + } + + if( err ) + { + break; + } + } while( 0 ); + + TRACDCOMP( g_trac_i2c, + EXIT_MRK"i2cWaitForFifoSpace()" ); + + return err; +} // end i2cWaitForFifoSpace + } // end namespace I2C -- cgit v1.2.1