drivers: spi: report synchronous completion status

The SPI API allows waiters to block until SPI I/O has completed. The
asynchronous subset of the API allows waiters to learn a status value
for the result of the I/O. However, the synchronous API does not allow
this.

Due to this limitation, synchronous API users cannot learn when
interrupt-driven I/O fails, which precludes proper error handling.

Resolve this limitation by adding a sync_status field to struct
spi_context, and using it to return operation results to the waiter.

Since there is only one status field, reduce the maximum number of
supported waiters from UINT_MAX to 1. This is not a problem for
current users, which all wait with the entire context locked.

Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
This commit is contained in:
Marti Bolivar 2017-07-17 11:37:22 -04:00 committed by Anas Nashif
commit 6c717095b8

View file

@ -24,6 +24,7 @@ struct spi_context {
struct k_sem lock;
struct k_sem sync;
int sync_status;
#ifdef CONFIG_POLL
struct k_poll_signal *signal;
@ -44,7 +45,7 @@ struct spi_context {
._ctx_name.lock = _K_SEM_INITIALIZER(_data._ctx_name.lock, 0, 1)
#define SPI_CONTEXT_INIT_SYNC(_data, _ctx_name) \
._ctx_name.sync = _K_SEM_INITIALIZER(_data._ctx_name.sync, 0, UINT_MAX)
._ctx_name.sync = _K_SEM_INITIALIZER(_data._ctx_name.sync, 0, 1)
static inline bool spi_context_configured(struct spi_context *ctx,
struct spi_config *config)
@ -86,21 +87,26 @@ static inline void spi_context_unlock_unconditionally(struct spi_context *ctx)
}
}
static inline void spi_context_wait_for_completion(struct spi_context *ctx)
static inline int spi_context_wait_for_completion(struct spi_context *ctx)
{
int status = 0;
#ifdef CONFIG_POLL
if (!ctx->asynchronous) {
k_sem_take(&ctx->sync, K_FOREVER);
status = ctx->sync_status;
}
#else
k_sem_take(&ctx->sync, K_FOREVER);
status = ctx->sync_status;
#endif
return status;
}
static inline void spi_context_complete(struct spi_context *ctx, int status)
{
#ifdef CONFIG_POLL
if (!ctx->asynchronous) {
ctx->sync_status = status;
k_sem_give(&ctx->sync);
} else {
if (ctx->signal) {
@ -112,6 +118,7 @@ static inline void spi_context_complete(struct spi_context *ctx, int status)
}
}
#else
ctx->sync_status = status;
k_sem_give(&ctx->sync);
#endif
}
@ -176,6 +183,8 @@ static inline void spi_context_buffers_setup(struct spi_context *ctx,
ctx->rx_len = 0;
}
ctx->sync_status = 0;
SYS_LOG_DBG("current_tx %p (%zu), current_rx %p (%zu),"
" tx buf/len %p/%zu, rx buf/len %p/%zu",
ctx->current_tx, ctx->tx_count,