f55d281536
The main improvement is that mcux_i3c_transfer() and mcux_i3c_i2c_api_transfer() will try much harder to not return an error that could be caused by the bus being busy. The bus could be busy because of IBI handling, especially if there are multiple I3C devices all raising IBI that need to be processed, which can involve a number of context switches and delays and take considerable time such that an application initiated I3C transfer request might have returned busy. Replaced the code that polled for idle state with a timeout with an infinite loop on a condvar. The condvar is broadcast to at the end of every stop, which should be when the bus goes idle. Details of other changes: * Remove ibi_lock, which seemed not useful. Use the single lock (switched from semaphore to mutex so it can be released by condvar) for both IBI handling and application requests. * Remove code that disables i3c controller interrupts during transfers. Since the only interrupt is SLVSTART, and that just posts a work, it didn't seem necessary to disable that interrupt. * Don't clear SLVSTART interrupt in mcux_i3c_status_clear_all(), to prevent any application transfers from accidentally clearing the SLVSTART interrupt or the handling of one IBI clearing the START initiated by another I3C device immeidately as the other one finishes. The only clearing of SLVSTART is in the isr. * Add back a wait in mcux_i3c_request_auto_ibi(), otherwise the ibitype could be 0 if the processor is faster than the auto ibi handling. An earlier change removed a wait for MCTRLDONE, which isn't always set when AUTO_IBI is requested, but that could mean we try to read the ibitype before it's ready. Waiting for IBIWON instead should be correct and better, since the AUTO_IBI should result in IBIWON status bit being set (and MCTRLDONE being set would not guarantee that IBIWON was set). * Change mcux_i3c_request_emit_stop() to still wait for idle if requested, even if the STOP wasn't actually issued, and add the release of the new condvar * Change mcux_i3c_do_one_xfer_read() to handle the IBI use case differently than the regular application requested transfer case. In the application requested transfer case, the rx_len is known and set in RDTERM, so we could check for the COMPLETE status bit, but for IBI transfers, we just do a read to the payload buffer without knowing how many bytes the target may send us so never get a COMPLETE. Rather than check for a COMPLETE bit that might never occur, just have both cases read until we either read all requested bytes or we get a timeout error. But for the timeout error, if it's IBI and non-zero bytes were received, return the bytes received instead of an error. * Change mcux_i3c_do_one_xfer() to return the error returned by mcux_i3c_do_one_xfer_read/write(). * Remove spurious return -EIO from end of mcux_i3c_do_daa() * Change mcux_i3c_ibi_enable() to restore SLVSTART on error, and add some LOG_ERR() messages for error cases. Also add check to make sure idx is valid since there is a limit to how many IBI this controller can support. * Change mcux_i3c_ibi_disable() to always reenable SLVSTART interrupt, even if the CCC to tell the target to disable IBI events fails. * Change mcux_i3c_isr() to reenable SLVSTART interrupt if the work_enqueue() fails. Signed-off-by: Mike J. Chen <mjchen@google.com> |
||
---|---|---|
.. | ||
CMakeLists.txt | ||
i3c_ccc.c | ||
i3c_cdns.c | ||
i3c_common.c | ||
i3c_handlers.c | ||
i3c_ibi_workq.c | ||
i3c_mcux.c | ||
i3c_test.c | ||
Kconfig | ||
Kconfig.cdns | ||
Kconfig.nxp | ||
Kconfig.test |