Skip to content

Commit 7b1d87a

Browse files
dlechbroonie
authored andcommitted
spi: add spi_optimize_message() APIs
This adds a new spi_optimize_message() function that can be used to optimize SPI messages that are used more than once. Peripheral drivers that use the same message multiple times can use this API to perform SPI message validation and controller-specific optimizations once and then reuse the message while avoiding the overhead of revalidating the message on each spi_(a)sync() call. Internally, the SPI core will also call this function for each message if the peripheral driver did not explicitly call it. This is done to so that controller drivers don't have to have multiple code paths for optimized and non-optimized messages. A hook is provided for controller drivers to perform controller-specific optimizations. Suggested-by: Martin Sperl <[email protected]> Link: https://lore.kernel.org/linux-spi/[email protected]/ Signed-off-by: David Lechner <[email protected]> Link: https://msgid.link/r/20240219-mainline-spi-precook-message-v2-1-4a762c6701b9@baylibre.com Reviewed-by: Jonathan Cameron <[email protected]> Signed-off-by: Mark Brown <[email protected]>
1 parent 0f3841a commit 7b1d87a

File tree

2 files changed

+167
-4
lines changed

2 files changed

+167
-4
lines changed

drivers/spi/spi.c

Lines changed: 147 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2106,6 +2106,41 @@ struct spi_message *spi_get_next_queued_message(struct spi_controller *ctlr)
21062106
}
21072107
EXPORT_SYMBOL_GPL(spi_get_next_queued_message);
21082108

2109+
/*
2110+
* __spi_unoptimize_message - shared implementation of spi_unoptimize_message()
2111+
* and spi_maybe_unoptimize_message()
2112+
* @msg: the message to unoptimize
2113+
*
2114+
* Peripheral drivers should use spi_unoptimize_message() and callers inside
2115+
* core should use spi_maybe_unoptimize_message() rather than calling this
2116+
* function directly.
2117+
*
2118+
* It is not valid to call this on a message that is not currently optimized.
2119+
*/
2120+
static void __spi_unoptimize_message(struct spi_message *msg)
2121+
{
2122+
struct spi_controller *ctlr = msg->spi->controller;
2123+
2124+
if (ctlr->unoptimize_message)
2125+
ctlr->unoptimize_message(msg);
2126+
2127+
msg->optimized = false;
2128+
msg->opt_state = NULL;
2129+
}
2130+
2131+
/*
2132+
* spi_maybe_unoptimize_message - unoptimize msg not managed by a peripheral
2133+
* @msg: the message to unoptimize
2134+
*
2135+
* This function is used to unoptimize a message if and only if it was
2136+
* optimized by the core (via spi_maybe_optimize_message()).
2137+
*/
2138+
static void spi_maybe_unoptimize_message(struct spi_message *msg)
2139+
{
2140+
if (!msg->pre_optimized && msg->optimized)
2141+
__spi_unoptimize_message(msg);
2142+
}
2143+
21092144
/**
21102145
* spi_finalize_current_message() - the current message is complete
21112146
* @ctlr: the controller to return the message to
@@ -2153,6 +2188,8 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
21532188

21542189
mesg->prepared = false;
21552190

2191+
spi_maybe_unoptimize_message(mesg);
2192+
21562193
WRITE_ONCE(ctlr->cur_msg_incomplete, false);
21572194
smp_mb(); /* See __spi_pump_transfer_message()... */
21582195
if (READ_ONCE(ctlr->cur_msg_need_completion))
@@ -4194,6 +4231,110 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
41944231
return 0;
41954232
}
41964233

4234+
/*
4235+
* __spi_optimize_message - shared implementation for spi_optimize_message()
4236+
* and spi_maybe_optimize_message()
4237+
* @spi: the device that will be used for the message
4238+
* @msg: the message to optimize
4239+
*
4240+
* Peripheral drivers will call spi_optimize_message() and the spi core will
4241+
* call spi_maybe_optimize_message() instead of calling this directly.
4242+
*
4243+
* It is not valid to call this on a message that has already been optimized.
4244+
*
4245+
* Return: zero on success, else a negative error code
4246+
*/
4247+
static int __spi_optimize_message(struct spi_device *spi,
4248+
struct spi_message *msg)
4249+
{
4250+
struct spi_controller *ctlr = spi->controller;
4251+
int ret;
4252+
4253+
ret = __spi_validate(spi, msg);
4254+
if (ret)
4255+
return ret;
4256+
4257+
if (ctlr->optimize_message) {
4258+
ret = ctlr->optimize_message(msg);
4259+
if (ret)
4260+
return ret;
4261+
}
4262+
4263+
msg->optimized = true;
4264+
4265+
return 0;
4266+
}
4267+
4268+
/*
4269+
* spi_maybe_optimize_message - optimize message if it isn't already pre-optimized
4270+
* @spi: the device that will be used for the message
4271+
* @msg: the message to optimize
4272+
* Return: zero on success, else a negative error code
4273+
*/
4274+
static int spi_maybe_optimize_message(struct spi_device *spi,
4275+
struct spi_message *msg)
4276+
{
4277+
if (msg->pre_optimized)
4278+
return 0;
4279+
4280+
return __spi_optimize_message(spi, msg);
4281+
}
4282+
4283+
/**
4284+
* spi_optimize_message - do any one-time validation and setup for a SPI message
4285+
* @spi: the device that will be used for the message
4286+
* @msg: the message to optimize
4287+
*
4288+
* Peripheral drivers that reuse the same message repeatedly may call this to
4289+
* perform as much message prep as possible once, rather than repeating it each
4290+
* time a message transfer is performed to improve throughput and reduce CPU
4291+
* usage.
4292+
*
4293+
* Once a message has been optimized, it cannot be modified with the exception
4294+
* of updating the contents of any xfer->tx_buf (the pointer can't be changed,
4295+
* only the data in the memory it points to).
4296+
*
4297+
* Calls to this function must be balanced with calls to spi_unoptimize_message()
4298+
* to avoid leaking resources.
4299+
*
4300+
* Context: can sleep
4301+
* Return: zero on success, else a negative error code
4302+
*/
4303+
int spi_optimize_message(struct spi_device *spi, struct spi_message *msg)
4304+
{
4305+
int ret;
4306+
4307+
ret = __spi_optimize_message(spi, msg);
4308+
if (ret)
4309+
return ret;
4310+
4311+
/*
4312+
* This flag indicates that the peripheral driver called spi_optimize_message()
4313+
* and therefore we shouldn't unoptimize message automatically when finalizing
4314+
* the message but rather wait until spi_unoptimize_message() is called
4315+
* by the peripheral driver.
4316+
*/
4317+
msg->pre_optimized = true;
4318+
4319+
return 0;
4320+
}
4321+
EXPORT_SYMBOL_GPL(spi_optimize_message);
4322+
4323+
/**
4324+
* spi_unoptimize_message - releases any resources allocated by spi_optimize_message()
4325+
* @msg: the message to unoptimize
4326+
*
4327+
* Calls to this function must be balanced with calls to spi_optimize_message().
4328+
*
4329+
* Context: can sleep
4330+
*/
4331+
void spi_unoptimize_message(struct spi_message *msg)
4332+
{
4333+
__spi_unoptimize_message(msg);
4334+
msg->pre_optimized = false;
4335+
}
4336+
EXPORT_SYMBOL_GPL(spi_unoptimize_message);
4337+
41974338
static int __spi_async(struct spi_device *spi, struct spi_message *message)
41984339
{
41994340
struct spi_controller *ctlr = spi->controller;
@@ -4258,8 +4399,8 @@ int spi_async(struct spi_device *spi, struct spi_message *message)
42584399
int ret;
42594400
unsigned long flags;
42604401

4261-
ret = __spi_validate(spi, message);
4262-
if (ret != 0)
4402+
ret = spi_maybe_optimize_message(spi, message);
4403+
if (ret)
42634404
return ret;
42644405

42654406
spin_lock_irqsave(&ctlr->bus_lock_spinlock, flags);
@@ -4271,6 +4412,8 @@ int spi_async(struct spi_device *spi, struct spi_message *message)
42714412

42724413
spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);
42734414

4415+
spi_maybe_unoptimize_message(message);
4416+
42744417
return ret;
42754418
}
42764419
EXPORT_SYMBOL_GPL(spi_async);
@@ -4331,8 +4474,8 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message)
43314474
return -ESHUTDOWN;
43324475
}
43334476

4334-
status = __spi_validate(spi, message);
4335-
if (status != 0)
4477+
status = spi_maybe_optimize_message(spi, message);
4478+
if (status)
43364479
return status;
43374480

43384481
SPI_STATISTICS_INCREMENT_FIELD(ctlr->pcpu_statistics, spi_sync);

include/linux/spi/spi.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,8 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch
475475
*
476476
* @set_cs: set the logic level of the chip select line. May be called
477477
* from interrupt context.
478+
* @optimize_message: optimize the message for reuse
479+
* @unoptimize_message: release resources allocated by optimize_message
478480
* @prepare_message: set up the controller to transfer a single message,
479481
* for example doing DMA mapping. Called from threaded
480482
* context.
@@ -715,6 +717,8 @@ struct spi_controller {
715717
struct completion xfer_completion;
716718
size_t max_dma_len;
717719

720+
int (*optimize_message)(struct spi_message *msg);
721+
int (*unoptimize_message)(struct spi_message *msg);
718722
int (*prepare_transfer_hardware)(struct spi_controller *ctlr);
719723
int (*transfer_one_message)(struct spi_controller *ctlr,
720724
struct spi_message *mesg);
@@ -1111,6 +1115,8 @@ struct spi_transfer {
11111115
* @spi: SPI device to which the transaction is queued
11121116
* @is_dma_mapped: if true, the caller provided both DMA and CPU virtual
11131117
* addresses for each transfer buffer
1118+
* @pre_optimized: peripheral driver pre-optimized the message
1119+
* @optimized: the message is in the optimized state
11141120
* @prepared: spi_prepare_message was called for the this message
11151121
* @status: zero for success, else negative errno
11161122
* @complete: called to report transaction completions
@@ -1120,6 +1126,7 @@ struct spi_transfer {
11201126
* successful segments
11211127
* @queue: for use by whichever driver currently owns the message
11221128
* @state: for use by whichever driver currently owns the message
1129+
* @opt_state: for use by whichever driver currently owns the message
11231130
* @resources: for resource management when the SPI message is processed
11241131
*
11251132
* A @spi_message is used to execute an atomic sequence of data transfers,
@@ -1143,6 +1150,11 @@ struct spi_message {
11431150

11441151
unsigned is_dma_mapped:1;
11451152

1153+
/* spi_optimize_message() was called for this message */
1154+
bool pre_optimized;
1155+
/* __spi_optimize_message() was called for this message */
1156+
bool optimized;
1157+
11461158
/* spi_prepare_message() was called for this message */
11471159
bool prepared;
11481160

@@ -1172,6 +1184,11 @@ struct spi_message {
11721184
*/
11731185
struct list_head queue;
11741186
void *state;
1187+
/*
1188+
* Optional state for use by controller driver between calls to
1189+
* __spi_optimize_message() and __spi_unoptimize_message().
1190+
*/
1191+
void *opt_state;
11751192

11761193
/* List of spi_res resources when the SPI message is processed */
11771194
struct list_head resources;
@@ -1255,6 +1272,9 @@ static inline void spi_message_free(struct spi_message *m)
12551272
kfree(m);
12561273
}
12571274

1275+
extern int spi_optimize_message(struct spi_device *spi, struct spi_message *msg);
1276+
extern void spi_unoptimize_message(struct spi_message *msg);
1277+
12581278
extern int spi_setup(struct spi_device *spi);
12591279
extern int spi_async(struct spi_device *spi, struct spi_message *message);
12601280
extern int spi_slave_abort(struct spi_device *spi);

0 commit comments

Comments
 (0)