Skip to content

Commit b5ca5b7

Browse files
ubiedakartben
authored andcommitted
spi_rtio: fix transactions for default handler
This patch fixes transaction op items not performed within a single SPI transfer. This is common for Write + Read commands, that depend on the CS kept asserted until the end, otherwise the context will be lost. A similar fix was applied to i2c_rtio_default on #79890. Signed-off-by: Luis Ubieda <[email protected]>
1 parent 15c5541 commit b5ca5b7

File tree

2 files changed

+94
-39
lines changed

2 files changed

+94
-39
lines changed

drivers/spi/Kconfig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,24 @@ config SPI_RTIO
3737
This option enables the RTIO API calls. RTIO support is
3838
experimental as the API itself is unstable.
3939

40+
if SPI_RTIO
41+
42+
config SPI_RTIO_FALLBACK_MSGS
43+
int "Number of available spi_buf structs for the default handler to use"
44+
default 4
45+
help
46+
When RTIO is used with a driver that does not yet implement the submit API
47+
natively the submissions are converted back to struct spi_buf values that
48+
are given to spi_transfer. This requires some number of msgs be available to convert
49+
the submissions into on the stack. MISRA rules dictate we must know this in
50+
advance.
51+
52+
In all likelihood 4 is going to work for everyone, but in case you do end up with
53+
an issue where you are using RTIO, your driver does not implement submit natively,
54+
and get an error relating to not enough spi msgs this is the Kconfig to manipulate.
55+
56+
endif # SPI_RTIO
57+
4058
config SPI_SLAVE
4159
bool "Slave support [EXPERIMENTAL]"
4260
select EXPERIMENTAL

drivers/spi/spi_rtio.c

Lines changed: 76 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ static void spi_rtio_iodev_default_submit_sync(struct rtio_iodev_sqe *iodev_sqe)
2222
{
2323
struct spi_dt_spec *dt_spec = iodev_sqe->sqe.iodev->data;
2424
const struct device *dev = dt_spec->bus;
25+
uint8_t num_msgs = 0;
2526
int err = 0;
2627

2728
LOG_DBG("Sync RTIO work item for: %p", (void *)dev);
@@ -33,67 +34,103 @@ static void spi_rtio_iodev_default_submit_sync(struct rtio_iodev_sqe *iodev_sqe)
3334
struct rtio_iodev_sqe *txn_head = iodev_sqe;
3435
struct rtio_iodev_sqe *txn_curr = iodev_sqe;
3536

37+
/* We allocate the spi_buf's on the stack, to do so
38+
* the count of messages needs to be determined to
39+
* ensure we don't go over the statically sized array.
40+
*/
3641
do {
37-
struct rtio_sqe *sqe = &txn_curr->sqe;
38-
struct spi_buf tx_buf = {0};
39-
struct spi_buf_set tx_buf_set = {
40-
.buffers = &tx_buf,
41-
};
42+
switch (txn_curr->sqe.op) {
43+
case RTIO_OP_RX:
44+
case RTIO_OP_TX:
45+
case RTIO_OP_TINY_TX:
46+
case RTIO_OP_TXRX:
47+
num_msgs++;
48+
break;
49+
default:
50+
LOG_ERR("Invalid op code %d for submission %p", txn_curr->sqe.op,
51+
(void *)&txn_curr->sqe);
52+
err = -EIO;
53+
break;
54+
}
55+
txn_curr = rtio_txn_next(txn_curr);
56+
} while (err == 0 && txn_curr != NULL);
4257

43-
struct spi_buf rx_buf = {0};
44-
struct spi_buf_set rx_buf_set = {
45-
.buffers = &rx_buf,
46-
};
58+
if (err != 0) {
59+
rtio_iodev_sqe_err(txn_head, err);
60+
return;
61+
}
62+
63+
/* Allocate msgs on the stack, MISRA doesn't like VLAs so we need a statically
64+
* sized array here. It's pretty unlikely we have more than 4 spi messages
65+
* in a transaction as we typically would only have 2, one to write a
66+
* register address, and another to read/write the register into an array
67+
*/
68+
if (num_msgs > CONFIG_SPI_RTIO_FALLBACK_MSGS) {
69+
LOG_ERR("At most CONFIG_SPI_RTIO_FALLBACK_MSGS"
70+
" submissions in a transaction are"
71+
" allowed in the default handler");
72+
rtio_iodev_sqe_err(txn_head, -ENOMEM);
73+
return;
74+
}
75+
76+
struct spi_buf tx_bufs[CONFIG_SPI_RTIO_FALLBACK_MSGS];
77+
struct spi_buf rx_bufs[CONFIG_SPI_RTIO_FALLBACK_MSGS];
78+
struct spi_buf_set tx_buf_set = {
79+
.buffers = tx_bufs,
80+
.count = num_msgs,
81+
};
82+
struct spi_buf_set rx_buf_set = {
83+
.buffers = rx_bufs,
84+
.count = num_msgs,
85+
};
4786

48-
LOG_DBG("Preparing transfer: %p", txn_curr);
87+
txn_curr = txn_head;
88+
89+
for (size_t i = 0 ; i < num_msgs ; i++) {
90+
struct rtio_sqe *sqe = &txn_curr->sqe;
4991

5092
switch (sqe->op) {
5193
case RTIO_OP_RX:
52-
rx_buf.buf = sqe->rx.buf;
53-
rx_buf.len = sqe->rx.buf_len;
54-
rx_buf_set.count = 1;
94+
rx_bufs[i].buf = sqe->rx.buf;
95+
rx_bufs[i].len = sqe->rx.buf_len;
96+
tx_bufs[i].buf = NULL;
97+
tx_bufs[i].len = sqe->rx.buf_len;
5598
break;
5699
case RTIO_OP_TX:
57-
tx_buf.buf = (uint8_t *)sqe->tx.buf;
58-
tx_buf.len = sqe->tx.buf_len;
59-
tx_buf_set.count = 1;
100+
rx_bufs[i].buf = NULL;
101+
rx_bufs[i].len = sqe->tx.buf_len;
102+
tx_bufs[i].buf = (uint8_t *)sqe->tx.buf;
103+
tx_bufs[i].len = sqe->tx.buf_len;
60104
break;
61105
case RTIO_OP_TINY_TX:
62-
tx_buf.buf = (uint8_t *)sqe->tiny_tx.buf;
63-
tx_buf.len = sqe->tiny_tx.buf_len;
64-
tx_buf_set.count = 1;
106+
rx_bufs[i].buf = NULL;
107+
rx_bufs[i].len = sqe->tiny_tx.buf_len;
108+
tx_bufs[i].buf = (uint8_t *)sqe->tiny_tx.buf;
109+
tx_bufs[i].len = sqe->tiny_tx.buf_len;
65110
break;
66111
case RTIO_OP_TXRX:
67-
rx_buf.buf = sqe->txrx.rx_buf;
68-
rx_buf.len = sqe->txrx.buf_len;
69-
tx_buf.buf = (uint8_t *)sqe->txrx.tx_buf;
70-
tx_buf.len = sqe->txrx.buf_len;
71-
rx_buf_set.count = 1;
72-
tx_buf_set.count = 1;
112+
rx_bufs[i].buf = sqe->txrx.rx_buf;
113+
rx_bufs[i].len = sqe->txrx.buf_len;
114+
tx_bufs[i].buf = (uint8_t *)sqe->txrx.tx_buf;
115+
tx_bufs[i].len = sqe->txrx.buf_len;
73116
break;
74117
default:
75-
LOG_ERR("Invalid op code %d for submission %p\n", sqe->op, (void *)sqe);
76118
err = -EIO;
77119
break;
78120
}
79121

80-
if (!err) {
81-
struct spi_buf_set *tx_buf_ptr = tx_buf_set.count > 0 ? &tx_buf_set : NULL;
82-
struct spi_buf_set *rx_buf_ptr = rx_buf_set.count > 0 ? &rx_buf_set : NULL;
83-
84-
err = spi_transceive_dt(dt_spec, tx_buf_ptr, rx_buf_ptr);
122+
txn_curr = rtio_txn_next(txn_curr);
123+
}
85124

86-
/* NULL if this submission is not a transaction */
87-
txn_curr = rtio_txn_next(txn_curr);
88-
}
89-
} while (err >= 0 && txn_curr != NULL);
125+
if (err == 0) {
126+
__ASSERT_NO_MSG(num_msgs > 0);
127+
err = spi_transceive_dt(dt_spec, &tx_buf_set, &rx_buf_set);
128+
}
90129

91-
if (err < 0) {
92-
LOG_ERR("Transfer failed: %d", err);
130+
if (err != 0) {
93131
rtio_iodev_sqe_err(txn_head, err);
94132
} else {
95-
LOG_DBG("Transfer OK: %d", err);
96-
rtio_iodev_sqe_ok(txn_head, err);
133+
rtio_iodev_sqe_ok(txn_head, 0);
97134
}
98135
}
99136

0 commit comments

Comments
 (0)