diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2020-07-07 19:24:45 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-07-07 19:24:45 +0000 |
commit | 706ce391054ec7150c638f5aa3e65fae98aef3e5 (patch) | |
tree | 734ecb920e39b241a71d0b52bbd809fca8c9da36 | |
parent | 8565c8f7453fb77351eff8e582f2dc134d6d2daa (diff) | |
parent | ade246280d99bcef36149134643cc7cdf2de48d9 (diff) | |
download | device_google_contexthub-706ce391054ec7150c638f5aa3e65fae98aef3e5.tar.gz device_google_contexthub-706ce391054ec7150c638f5aa3e65fae98aef3e5.tar.bz2 device_google_contexthub-706ce391054ec7150c638f5aa3e65fae98aef3e5.zip |
Merge "nanohub: i2c: fix transfer ID race" am: efce4bfadc am: ade246280d
Original change: https://android-review.googlesource.com/c/device/google/contexthub/+/1328935
Change-Id: I6bb6964ed8ce40b6c7cc1a93e88be0219053a1e9
-rw-r--r-- | firmware/os/platform/stm32/i2c.c | 77 |
1 files changed, 43 insertions, 34 deletions
diff --git a/firmware/os/platform/stm32/i2c.c b/firmware/os/platform/stm32/i2c.c index 8ae35cf7..d553202d 100644 --- a/firmware/os/platform/stm32/i2c.c +++ b/firmware/os/platform/stm32/i2c.c @@ -177,7 +177,6 @@ struct StmI2cDev { const struct StmI2cBoardCfg *board; struct I2cStmState state; - uint32_t next; uint32_t last; struct Gpio *scl; @@ -244,8 +243,10 @@ static inline struct StmI2cXfer *stmI2cGetXfer(void) static inline void stmI2cPutXfer(struct StmI2cXfer *xfer) { - if (xfer) + if (xfer) { + atomicWrite32bits(&xfer->id, 0); atomicBitsetClearBit(mXfersValid, xfer - mXfers); + } } static inline void stmI2cAckEnable(struct StmI2cDev *pdev) @@ -486,13 +487,30 @@ static void stmI2cSlaveNakRxed(struct StmI2cDev *pdev) regs->SR1 &= ~I2C_SR1_AF; } +static inline struct StmI2cXfer *stmI2cGetNextPendingXfer(uint8_t busId) +{ + uint32_t currId = UINT32_MAX; + struct StmI2cXfer *pendingXfer = NULL; + + for (int i = 0; i < I2C_MAX_QUEUE_DEPTH; i++) { + struct StmI2cXfer *xfer = &mXfers[i]; + if (xfer->busId == busId) { + uint32_t xferId = atomicRead32bits(&xfer->id); + if (xferId > 0 && xferId <= currId) { + pendingXfer = xfer; + currId = xferId; + } + } + } + + return pendingXfer; +} + static inline void stmI2cMasterTxRxDone(struct StmI2cDev *pdev, int err) { struct I2cStmState *state = &pdev->state; size_t txOffst = state->tx.offset; size_t rxOffst = state->rx.offset; - uint32_t id; - int i; struct StmI2cXfer *xfer; if (pdev->board->sleepDev >= 0) @@ -502,34 +520,26 @@ static inline void stmI2cMasterTxRxDone(struct StmI2cDev *pdev, int err) state->rx.offset = 0; stmI2cInvokeTxCallback(state, txOffst, rxOffst, err); - do { - id = atomicAdd32bits(&pdev->next, 1); - } while (!id); - - for (i=0; i<I2C_MAX_QUEUE_DEPTH; i++) { - xfer = &mXfers[i]; - - if (xfer->busId == (pdev - mStmI2cDevs) && - atomicCmpXchg32bits(&xfer->id, id, 0)) { - pdev->addr = xfer->addr; - state->tx.cbuf = xfer->txBuf; - state->tx.offset = 0; - state->tx.size = xfer->txSize; - state->tx.callback = xfer->callback; - state->tx.cookie = xfer->cookie; - state->rx.buf = xfer->rxBuf; - state->rx.offset = 0; - state->rx.size = xfer->rxSize; - state->rx.callback = NULL; - state->rx.cookie = NULL; - state->tid = xfer->tid; - atomicWriteByte(&state->masterState, STM_I2C_MASTER_START); - if (pdev->board->sleepDev >= 0) - platRequestDevInSleepMode(pdev->board->sleepDev, 12); - stmI2cPutXfer(xfer); - stmI2cStartEnable(pdev); - return; - } + xfer = stmI2cGetNextPendingXfer(pdev - mStmI2cDevs); + if (xfer) { + atomicWriteByte(&state->masterState, STM_I2C_MASTER_START); + pdev->addr = xfer->addr; + state->tx.cbuf = xfer->txBuf; + state->tx.offset = 0; + state->tx.size = xfer->txSize; + state->tx.callback = xfer->callback; + state->tx.cookie = xfer->cookie; + state->rx.buf = xfer->rxBuf; + state->rx.offset = 0; + state->rx.size = xfer->rxSize; + state->rx.callback = NULL; + state->rx.cookie = NULL; + state->tid = xfer->tid; + if (pdev->board->sleepDev >= 0) + platRequestDevInSleepMode(pdev->board->sleepDev, 12); + stmI2cPutXfer(xfer); + stmI2cStartEnable(pdev); + return; } atomicWriteByte(&state->masterState, STM_I2C_MASTER_IDLE); @@ -839,7 +849,6 @@ int i2cMasterRequest(uint32_t busId, uint32_t speed) pdev->cfg = cfg; pdev->board = board; - pdev->next = 2; pdev->last = 1; atomicBitsetInit(mXfersValid, I2C_MAX_QUEUE_DEPTH); @@ -943,7 +952,7 @@ int i2cMasterTxRx(uint32_t busId, uint32_t addr, STM_I2C_MASTER_IDLE, STM_I2C_MASTER_START)) { // it is possible for this transfer to already be complete by the // time we get here. if so, transfer->id will have been set to 0. - if (atomicCmpXchg32bits(&xfer->id, id, 0)) { + if (atomicRead32bits(&xfer->id) != 0) { pdev->addr = xfer->addr; state->tx.cbuf = xfer->txBuf; state->tx.offset = 0; |