Skip to content

Commit fab53fe

Browse files
dlechbroonie
authored andcommitted
spi: move splitting transfers to spi_optimize_message()
Splitting transfers is an expensive operation so we can potentially optimize it by doing it only once per optimization of the message instead of repeating each time the message is transferred. The transfer splitting functions are currently the only user of spi_res_alloc() so spi_res_release() can be safely moved at this time from spi_finalize_current_message() to spi_unoptimize_message(). The doc comments of the public functions for splitting transfers are also updated so that callers will know when it is safe to call them to ensure proper resource management. Reviewed-by: Jonathan Cameron <[email protected]> Signed-off-by: David Lechner <[email protected]> Link: https://msgid.link/r/20240219-mainline-spi-precook-message-v2-2-4a762c6701b9@baylibre.com Signed-off-by: Mark Brown <[email protected]>
1 parent 7b1d87a commit fab53fe

File tree

1 file changed

+68
-42
lines changed

1 file changed

+68
-42
lines changed

drivers/spi/spi.c

Lines changed: 68 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1747,38 +1747,6 @@ static int __spi_pump_transfer_message(struct spi_controller *ctlr,
17471747

17481748
trace_spi_message_start(msg);
17491749

1750-
/*
1751-
* If an SPI controller does not support toggling the CS line on each
1752-
* transfer (indicated by the SPI_CS_WORD flag) or we are using a GPIO
1753-
* for the CS line, we can emulate the CS-per-word hardware function by
1754-
* splitting transfers into one-word transfers and ensuring that
1755-
* cs_change is set for each transfer.
1756-
*/
1757-
if ((msg->spi->mode & SPI_CS_WORD) && (!(ctlr->mode_bits & SPI_CS_WORD) ||
1758-
spi_is_csgpiod(msg->spi))) {
1759-
ret = spi_split_transfers_maxwords(ctlr, msg, 1);
1760-
if (ret) {
1761-
msg->status = ret;
1762-
spi_finalize_current_message(ctlr);
1763-
return ret;
1764-
}
1765-
1766-
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
1767-
/* Don't change cs_change on the last entry in the list */
1768-
if (list_is_last(&xfer->transfer_list, &msg->transfers))
1769-
break;
1770-
xfer->cs_change = 1;
1771-
}
1772-
} else {
1773-
ret = spi_split_transfers_maxsize(ctlr, msg,
1774-
spi_max_transfer_size(msg->spi));
1775-
if (ret) {
1776-
msg->status = ret;
1777-
spi_finalize_current_message(ctlr);
1778-
return ret;
1779-
}
1780-
}
1781-
17821750
if (ctlr->prepare_message) {
17831751
ret = ctlr->prepare_message(ctlr, msg);
17841752
if (ret) {
@@ -2124,6 +2092,8 @@ static void __spi_unoptimize_message(struct spi_message *msg)
21242092
if (ctlr->unoptimize_message)
21252093
ctlr->unoptimize_message(msg);
21262094

2095+
spi_res_release(ctlr, msg);
2096+
21272097
msg->optimized = false;
21282098
msg->opt_state = NULL;
21292099
}
@@ -2169,15 +2139,6 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
21692139

21702140
spi_unmap_msg(ctlr, mesg);
21712141

2172-
/*
2173-
* In the prepare_messages callback the SPI bus has the opportunity
2174-
* to split a transfer to smaller chunks.
2175-
*
2176-
* Release the split transfers here since spi_map_msg() is done on
2177-
* the split transfers.
2178-
*/
2179-
spi_res_release(ctlr, mesg);
2180-
21812142
if (mesg->prepared && ctlr->unprepare_message) {
21822143
ret = ctlr->unprepare_message(ctlr, mesg);
21832144
if (ret) {
@@ -3819,6 +3780,10 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr,
38193780
* @msg: the @spi_message to transform
38203781
* @maxsize: the maximum when to apply this
38213782
*
3783+
* This function allocates resources that are automatically freed during the
3784+
* spi message unoptimize phase so this function should only be called from
3785+
* optimize_message callbacks.
3786+
*
38223787
* Return: status of transformation
38233788
*/
38243789
int spi_split_transfers_maxsize(struct spi_controller *ctlr,
@@ -3857,6 +3822,10 @@ EXPORT_SYMBOL_GPL(spi_split_transfers_maxsize);
38573822
* @msg: the @spi_message to transform
38583823
* @maxwords: the number of words to limit each transfer to
38593824
*
3825+
* This function allocates resources that are automatically freed during the
3826+
* spi message unoptimize phase so this function should only be called from
3827+
* optimize_message callbacks.
3828+
*
38603829
* Return: status of transformation
38613830
*/
38623831
int spi_split_transfers_maxwords(struct spi_controller *ctlr,
@@ -4231,6 +4200,57 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
42314200
return 0;
42324201
}
42334202

4203+
/*
4204+
* spi_split_transfers - generic handling of transfer splitting
4205+
* @msg: the message to split
4206+
*
4207+
* Under certain conditions, a SPI controller may not support arbitrary
4208+
* transfer sizes or other features required by a peripheral. This function
4209+
* will split the transfers in the message into smaller transfers that are
4210+
* supported by the controller.
4211+
*
4212+
* Controllers with special requirements not covered here can also split
4213+
* transfers in the optimize_message() callback.
4214+
*
4215+
* Context: can sleep
4216+
* Return: zero on success, else a negative error code
4217+
*/
4218+
static int spi_split_transfers(struct spi_message *msg)
4219+
{
4220+
struct spi_controller *ctlr = msg->spi->controller;
4221+
struct spi_transfer *xfer;
4222+
int ret;
4223+
4224+
/*
4225+
* If an SPI controller does not support toggling the CS line on each
4226+
* transfer (indicated by the SPI_CS_WORD flag) or we are using a GPIO
4227+
* for the CS line, we can emulate the CS-per-word hardware function by
4228+
* splitting transfers into one-word transfers and ensuring that
4229+
* cs_change is set for each transfer.
4230+
*/
4231+
if ((msg->spi->mode & SPI_CS_WORD) &&
4232+
(!(ctlr->mode_bits & SPI_CS_WORD) || spi_is_csgpiod(msg->spi))) {
4233+
ret = spi_split_transfers_maxwords(ctlr, msg, 1);
4234+
if (ret)
4235+
return ret;
4236+
4237+
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
4238+
/* Don't change cs_change on the last entry in the list */
4239+
if (list_is_last(&xfer->transfer_list, &msg->transfers))
4240+
break;
4241+
4242+
xfer->cs_change = 1;
4243+
}
4244+
} else {
4245+
ret = spi_split_transfers_maxsize(ctlr, msg,
4246+
spi_max_transfer_size(msg->spi));
4247+
if (ret)
4248+
return ret;
4249+
}
4250+
4251+
return 0;
4252+
}
4253+
42344254
/*
42354255
* __spi_optimize_message - shared implementation for spi_optimize_message()
42364256
* and spi_maybe_optimize_message()
@@ -4254,10 +4274,16 @@ static int __spi_optimize_message(struct spi_device *spi,
42544274
if (ret)
42554275
return ret;
42564276

4277+
ret = spi_split_transfers(msg);
4278+
if (ret)
4279+
return ret;
4280+
42574281
if (ctlr->optimize_message) {
42584282
ret = ctlr->optimize_message(msg);
4259-
if (ret)
4283+
if (ret) {
4284+
spi_res_release(ctlr, msg);
42604285
return ret;
4286+
}
42614287
}
42624288

42634289
msg->optimized = true;

0 commit comments

Comments
 (0)