Skip to content

Commit e6f66fc

Browse files
dlechnunojsa
authored andcommitted
spi: add offload TX/RX streaming APIs
Most configuration of SPI offloads is handled opaquely using the offload pointer that is passed to the various offload functions. However, there are some offload features that need to be controlled on a per transfer basis. This patch adds a flag field to struct spi_transfer to allow specifying such features. The first feature to be added is the ability to stream data to/from a hardware sink/source rather than using a tx or rx buffer. Additional flags can be added in the future as needed. A flags field is also added to the offload struct for providers to indicate which flags are supported. This allows for generic checking of offload capabilities during __spi_validate() so that each offload provider doesn't have to implement their own validation. As a first users of this streaming capability, getter functions are added to get a DMA channel that is directly connected to the offload. Peripheral drivers will use this to get a DMA channel and configure it to suit their needs. Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Reviewed-by: Nuno Sa <nuno.sa@analog.com> Signed-off-by: David Lechner <dlechner@baylibre.com> Link: https://patch.msgid.link/20250207-dlech-mainline-spi-engine-offload-2-v8-5-e48a489be48c@baylibre.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent ef2aaef commit e6f66fc

File tree

5 files changed

+107
-0
lines changed

5 files changed

+107
-0
lines changed

drivers/spi/spi-offload.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include <linux/cleanup.h>
2020
#include <linux/device.h>
21+
#include <linux/dmaengine.h>
2122
#include <linux/export.h>
2223
#include <linux/kref.h>
2324
#include <linux/list.h>
@@ -332,6 +333,75 @@ void spi_offload_trigger_disable(struct spi_offload *offload,
332333
}
333334
EXPORT_SYMBOL_GPL(spi_offload_trigger_disable);
334335

336+
static void spi_offload_release_dma_chan(void *chan)
337+
{
338+
dma_release_channel(chan);
339+
}
340+
341+
/**
342+
* devm_spi_offload_tx_stream_request_dma_chan - Get the DMA channel info for the TX stream
343+
* @dev: Device for devm purposes.
344+
* @offload: Offload instance
345+
*
346+
* This is the DMA channel that will provide data to transfers that use the
347+
* %SPI_OFFLOAD_XFER_TX_STREAM offload flag.
348+
*
349+
* Return: Pointer to DMA channel info, or negative error code
350+
*/
351+
struct dma_chan
352+
*devm_spi_offload_tx_stream_request_dma_chan(struct device *dev,
353+
struct spi_offload *offload)
354+
{
355+
struct dma_chan *chan;
356+
int ret;
357+
358+
if (!offload->ops || !offload->ops->tx_stream_request_dma_chan)
359+
return ERR_PTR(-EOPNOTSUPP);
360+
361+
chan = offload->ops->tx_stream_request_dma_chan(offload);
362+
if (IS_ERR(chan))
363+
return chan;
364+
365+
ret = devm_add_action_or_reset(dev, spi_offload_release_dma_chan, chan);
366+
if (ret)
367+
return ERR_PTR(ret);
368+
369+
return chan;
370+
}
371+
EXPORT_SYMBOL_GPL(devm_spi_offload_tx_stream_request_dma_chan);
372+
373+
/**
374+
* devm_spi_offload_rx_stream_request_dma_chan - Get the DMA channel info for the RX stream
375+
* @dev: Device for devm purposes.
376+
* @offload: Offload instance
377+
*
378+
* This is the DMA channel that will receive data from transfers that use the
379+
* %SPI_OFFLOAD_XFER_RX_STREAM offload flag.
380+
*
381+
* Return: Pointer to DMA channel info, or negative error code
382+
*/
383+
struct dma_chan
384+
*devm_spi_offload_rx_stream_request_dma_chan(struct device *dev,
385+
struct spi_offload *offload)
386+
{
387+
struct dma_chan *chan;
388+
int ret;
389+
390+
if (!offload->ops || !offload->ops->rx_stream_request_dma_chan)
391+
return ERR_PTR(-EOPNOTSUPP);
392+
393+
chan = offload->ops->rx_stream_request_dma_chan(offload);
394+
if (IS_ERR(chan))
395+
return chan;
396+
397+
ret = devm_add_action_or_reset(dev, spi_offload_release_dma_chan, chan);
398+
if (ret)
399+
return ERR_PTR(ret);
400+
401+
return chan;
402+
}
403+
EXPORT_SYMBOL_GPL(devm_spi_offload_rx_stream_request_dma_chan);
404+
335405
/* Triggers providers */
336406

337407
static void spi_offload_trigger_unregister(void *data)

drivers/spi/spi.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <linux/ptp_clock_kernel.h>
3232
#include <linux/sched/rt.h>
3333
#include <linux/slab.h>
34+
#include <linux/spi/offload/types.h>
3435
#include <linux/spi/spi.h>
3536
#include <linux/spi/spi-mem.h>
3637
#include <uapi/linux/sched/types.h>
@@ -4187,6 +4188,15 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
41874188

41884189
if (_spi_xfer_word_delay_update(xfer, spi))
41894190
return -EINVAL;
4191+
4192+
/* Make sure controller supports required offload features. */
4193+
if (xfer->offload_flags) {
4194+
if (!message->offload)
4195+
return -EINVAL;
4196+
4197+
if (xfer->offload_flags & ~message->offload->xfer_flags)
4198+
return -EINVAL;
4199+
}
41904200
}
41914201

41924202
message->status = -EINPROGRESS;

include/linux/spi/offload/consumer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,9 @@ int spi_offload_trigger_enable(struct spi_offload *offload,
3131
void spi_offload_trigger_disable(struct spi_offload *offload,
3232
struct spi_offload_trigger *trigger);
3333

34+
struct dma_chan *devm_spi_offload_tx_stream_request_dma_chan(struct device *dev,
35+
struct spi_offload *offload);
36+
struct dma_chan *devm_spi_offload_rx_stream_request_dma_chan(struct device *dev,
37+
struct spi_offload *offload);
38+
3439
#endif /* __LINUX_SPI_OFFLOAD_CONSUMER_H */

include/linux/spi/offload/types.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111

1212
struct device;
1313

14+
/* This is write xfer but TX uses external data stream rather than tx_buf. */
15+
#define SPI_OFFLOAD_XFER_TX_STREAM BIT(0)
16+
/* This is read xfer but RX uses external data stream rather than rx_buf. */
17+
#define SPI_OFFLOAD_XFER_RX_STREAM BIT(1)
18+
1419
/* Offload can be triggered by external hardware event. */
1520
#define SPI_OFFLOAD_CAP_TRIGGER BIT(0)
1621
/* Offload can record and then play back TX data when triggered. */
@@ -40,6 +45,8 @@ struct spi_offload {
4045
void *priv;
4146
/** @ops: callbacks for offload support */
4247
const struct spi_offload_ops *ops;
48+
/** @xfer_flags: %SPI_OFFLOAD_XFER_* flags supported by provider */
49+
u32 xfer_flags;
4350
};
4451

4552
enum spi_offload_trigger_type {
@@ -75,6 +82,18 @@ struct spi_offload_ops {
7582
* given offload instance.
7683
*/
7784
void (*trigger_disable)(struct spi_offload *offload);
85+
/**
86+
* @tx_stream_request_dma_chan: Optional callback for controllers that
87+
* have an offload where the TX data stream is connected directly to a
88+
* DMA channel.
89+
*/
90+
struct dma_chan *(*tx_stream_request_dma_chan)(struct spi_offload *offload);
91+
/**
92+
* @rx_stream_request_dma_chan: Optional callback for controllers that
93+
* have an offload where the RX data stream is connected directly to a
94+
* DMA channel.
95+
*/
96+
struct dma_chan *(*rx_stream_request_dma_chan)(struct spi_offload *offload);
7897
};
7998

8099
#endif /* __LINUX_SPI_OFFLOAD_TYPES_H */

include/linux/spi/spi.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,6 +1116,9 @@ struct spi_transfer {
11161116

11171117
u32 effective_speed_hz;
11181118

1119+
/* Use %SPI_OFFLOAD_XFER_* from spi-offload.h */
1120+
unsigned int offload_flags;
1121+
11191122
unsigned int ptp_sts_word_pre;
11201123
unsigned int ptp_sts_word_post;
11211124

0 commit comments

Comments
 (0)