Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

David Lechner and committed by
Mark Brown
700a2819 ebb398ae

+107
+70
drivers/spi/spi-offload.c
··· 18 18 19 19 #include <linux/cleanup.h> 20 20 #include <linux/device.h> 21 + #include <linux/dmaengine.h> 21 22 #include <linux/export.h> 22 23 #include <linux/kref.h> 23 24 #include <linux/list.h> ··· 332 331 trigger->ops->disable(trigger); 333 332 } 334 333 EXPORT_SYMBOL_GPL(spi_offload_trigger_disable); 334 + 335 + static void spi_offload_release_dma_chan(void *chan) 336 + { 337 + dma_release_channel(chan); 338 + } 339 + 340 + /** 341 + * devm_spi_offload_tx_stream_request_dma_chan - Get the DMA channel info for the TX stream 342 + * @dev: Device for devm purposes. 343 + * @offload: Offload instance 344 + * 345 + * This is the DMA channel that will provide data to transfers that use the 346 + * %SPI_OFFLOAD_XFER_TX_STREAM offload flag. 347 + * 348 + * Return: Pointer to DMA channel info, or negative error code 349 + */ 350 + struct dma_chan 351 + *devm_spi_offload_tx_stream_request_dma_chan(struct device *dev, 352 + struct spi_offload *offload) 353 + { 354 + struct dma_chan *chan; 355 + int ret; 356 + 357 + if (!offload->ops || !offload->ops->tx_stream_request_dma_chan) 358 + return ERR_PTR(-EOPNOTSUPP); 359 + 360 + chan = offload->ops->tx_stream_request_dma_chan(offload); 361 + if (IS_ERR(chan)) 362 + return chan; 363 + 364 + ret = devm_add_action_or_reset(dev, spi_offload_release_dma_chan, chan); 365 + if (ret) 366 + return ERR_PTR(ret); 367 + 368 + return chan; 369 + } 370 + EXPORT_SYMBOL_GPL(devm_spi_offload_tx_stream_request_dma_chan); 371 + 372 + /** 373 + * devm_spi_offload_rx_stream_request_dma_chan - Get the DMA channel info for the RX stream 374 + * @dev: Device for devm purposes. 375 + * @offload: Offload instance 376 + * 377 + * This is the DMA channel that will receive data from transfers that use the 378 + * %SPI_OFFLOAD_XFER_RX_STREAM offload flag. 379 + * 380 + * Return: Pointer to DMA channel info, or negative error code 381 + */ 382 + struct dma_chan 383 + *devm_spi_offload_rx_stream_request_dma_chan(struct device *dev, 384 + struct spi_offload *offload) 385 + { 386 + struct dma_chan *chan; 387 + int ret; 388 + 389 + if (!offload->ops || !offload->ops->rx_stream_request_dma_chan) 390 + return ERR_PTR(-EOPNOTSUPP); 391 + 392 + chan = offload->ops->rx_stream_request_dma_chan(offload); 393 + if (IS_ERR(chan)) 394 + return chan; 395 + 396 + ret = devm_add_action_or_reset(dev, spi_offload_release_dma_chan, chan); 397 + if (ret) 398 + return ERR_PTR(ret); 399 + 400 + return chan; 401 + } 402 + EXPORT_SYMBOL_GPL(devm_spi_offload_rx_stream_request_dma_chan); 335 403 336 404 /* Triggers providers */ 337 405
+10
drivers/spi/spi.c
··· 31 31 #include <linux/ptp_clock_kernel.h> 32 32 #include <linux/sched/rt.h> 33 33 #include <linux/slab.h> 34 + #include <linux/spi/offload/types.h> 34 35 #include <linux/spi/spi.h> 35 36 #include <linux/spi/spi-mem.h> 36 37 #include <uapi/linux/sched/types.h> ··· 4159 4158 4160 4159 if (_spi_xfer_word_delay_update(xfer, spi)) 4161 4160 return -EINVAL; 4161 + 4162 + /* Make sure controller supports required offload features. */ 4163 + if (xfer->offload_flags) { 4164 + if (!message->offload) 4165 + return -EINVAL; 4166 + 4167 + if (xfer->offload_flags & ~message->offload->xfer_flags) 4168 + return -EINVAL; 4169 + } 4162 4170 } 4163 4171 4164 4172 message->status = -EINPROGRESS;
+5
include/linux/spi/offload/consumer.h
··· 31 31 void spi_offload_trigger_disable(struct spi_offload *offload, 32 32 struct spi_offload_trigger *trigger); 33 33 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 + 34 39 #endif /* __LINUX_SPI_OFFLOAD_CONSUMER_H */
+19
include/linux/spi/offload/types.h
··· 11 11 12 12 struct device; 13 13 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 + 14 19 /* Offload can be triggered by external hardware event. */ 15 20 #define SPI_OFFLOAD_CAP_TRIGGER BIT(0) 16 21 /* Offload can record and then play back TX data when triggered. */ ··· 45 40 void *priv; 46 41 /** @ops: callbacks for offload support */ 47 42 const struct spi_offload_ops *ops; 43 + /** @xfer_flags: %SPI_OFFLOAD_XFER_* flags supported by provider */ 44 + u32 xfer_flags; 48 45 }; 49 46 50 47 enum spi_offload_trigger_type { ··· 82 75 * given offload instance. 83 76 */ 84 77 void (*trigger_disable)(struct spi_offload *offload); 78 + /** 79 + * @tx_stream_request_dma_chan: Optional callback for controllers that 80 + * have an offload where the TX data stream is connected directly to a 81 + * DMA channel. 82 + */ 83 + struct dma_chan *(*tx_stream_request_dma_chan)(struct spi_offload *offload); 84 + /** 85 + * @rx_stream_request_dma_chan: Optional callback for controllers that 86 + * have an offload where the RX data stream is connected directly to a 87 + * DMA channel. 88 + */ 89 + struct dma_chan *(*rx_stream_request_dma_chan)(struct spi_offload *offload); 85 90 }; 86 91 87 92 #endif /* __LINUX_SPI_OFFLOAD_TYPES_H */
+3
include/linux/spi/spi.h
··· 1093 1093 1094 1094 u32 effective_speed_hz; 1095 1095 1096 + /* Use %SPI_OFFLOAD_XFER_* from spi-offload.h */ 1097 + unsigned int offload_flags; 1098 + 1096 1099 unsigned int ptp_sts_word_pre; 1097 1100 unsigned int ptp_sts_word_post; 1098 1101