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

Configure Feed

Select the types of activity you want to include in your feed.

spi: add basic support for SPI offloading

Add the basic infrastructure to support SPI offload providers and
consumers.

SPI offloading is a feature that allows the SPI controller to perform
transfers without any CPU intervention. This is useful, e.g. for
high-speed data acquisition.

SPI controllers with offload support need to implement the get_offload
and put_offload callbacks and can use the devm_spi_offload_alloc() to
allocate offload instances.

SPI peripheral drivers will call devm_spi_offload_get() to get a
reference to the matching offload instance. This offload instance can
then be attached to a SPI message to request offloading that message.

It is expected that SPI controllers with offload support will check for
the offload instance in the SPI message in the ctlr->optimize_message()
callback and handle it accordingly.

CONFIG_SPI_OFFLOAD is intended to be a select-only option. Both
consumer and provider drivers should `select SPI_OFFLOAD` in their
Kconfig to ensure that the SPI core is built with offload support.

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-1-e48a489be48c@baylibre.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

David Lechner and committed by
Mark Brown
8e02d188 2014c95a

+225
+6
MAINTAINERS
··· 22295 22295 F: drivers/mtd/spi-nor/ 22296 22296 F: include/linux/mtd/spi-nor.h 22297 22297 22298 + SPI OFFLOAD 22299 + R: David Lechner <dlechner@baylibre.com> 22300 + F: drivers/spi/spi-offload.c 22301 + F: include/linux/spi/spi-offload.h 22302 + K: spi_offload 22303 + 22298 22304 SPI SUBSYSTEM 22299 22305 M: Mark Brown <broonie@kernel.org> 22300 22306 L: linux-spi@vger.kernel.org
+3
drivers/spi/Kconfig
··· 55 55 This extension is meant to simplify interaction with SPI memories 56 56 by providing a high-level interface to send memory-like commands. 57 57 58 + config SPI_OFFLOAD 59 + bool 60 + 58 61 comment "SPI Master Controller Drivers" 59 62 60 63 config SPI_AIROHA_SNFI
+1
drivers/spi/Makefile
··· 10 10 obj-$(CONFIG_SPI_MASTER) += spi.o 11 11 obj-$(CONFIG_SPI_MEM) += spi-mem.o 12 12 obj-$(CONFIG_SPI_MUX) += spi-mux.o 13 + obj-$(CONFIG_SPI_OFFLOAD) += spi-offload.o 13 14 obj-$(CONFIG_SPI_SPIDEV) += spidev.o 14 15 obj-$(CONFIG_SPI_LOOPBACK_TEST) += spi-loopback-test.o 15 16
+114
drivers/spi/spi-offload.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (C) 2024 Analog Devices Inc. 4 + * Copyright (C) 2024 BayLibre, SAS 5 + */ 6 + 7 + /* 8 + * SPI Offloading support. 9 + * 10 + * Some SPI controllers support offloading of SPI transfers. Essentially, this 11 + * is the ability for a SPI controller to perform SPI transfers with minimal 12 + * or even no CPU intervention, e.g. via a specialized SPI controller with a 13 + * hardware trigger or via a conventional SPI controller using a non-Linux MCU 14 + * processor core to offload the work. 15 + */ 16 + 17 + #define DEFAULT_SYMBOL_NAMESPACE "SPI_OFFLOAD" 18 + 19 + #include <linux/cleanup.h> 20 + #include <linux/device.h> 21 + #include <linux/export.h> 22 + #include <linux/mutex.h> 23 + #include <linux/spi/offload/consumer.h> 24 + #include <linux/spi/offload/provider.h> 25 + #include <linux/spi/offload/types.h> 26 + #include <linux/spi/spi.h> 27 + #include <linux/types.h> 28 + 29 + struct spi_controller_and_offload { 30 + struct spi_controller *controller; 31 + struct spi_offload *offload; 32 + }; 33 + 34 + /** 35 + * devm_spi_offload_alloc() - Allocate offload instance 36 + * @dev: Device for devm purposes and assigned to &struct spi_offload.provider_dev 37 + * @priv_size: Size of private data to allocate 38 + * 39 + * Offload providers should use this to allocate offload instances. 40 + * 41 + * Return: Pointer to new offload instance or error on failure. 42 + */ 43 + struct spi_offload *devm_spi_offload_alloc(struct device *dev, 44 + size_t priv_size) 45 + { 46 + struct spi_offload *offload; 47 + void *priv; 48 + 49 + offload = devm_kzalloc(dev, sizeof(*offload), GFP_KERNEL); 50 + if (!offload) 51 + return ERR_PTR(-ENOMEM); 52 + 53 + priv = devm_kzalloc(dev, priv_size, GFP_KERNEL); 54 + if (!priv) 55 + return ERR_PTR(-ENOMEM); 56 + 57 + offload->provider_dev = dev; 58 + offload->priv = priv; 59 + 60 + return offload; 61 + } 62 + EXPORT_SYMBOL_GPL(devm_spi_offload_alloc); 63 + 64 + static void spi_offload_put(void *data) 65 + { 66 + struct spi_controller_and_offload *resource = data; 67 + 68 + resource->controller->put_offload(resource->offload); 69 + kfree(resource); 70 + } 71 + 72 + /** 73 + * devm_spi_offload_get() - Get an offload instance 74 + * @dev: Device for devm purposes 75 + * @spi: SPI device to use for the transfers 76 + * @config: Offload configuration 77 + * 78 + * Peripheral drivers call this function to get an offload instance that meets 79 + * the requirements specified in @config. If no suitable offload instance is 80 + * available, -ENODEV is returned. 81 + * 82 + * Return: Offload instance or error on failure. 83 + */ 84 + struct spi_offload *devm_spi_offload_get(struct device *dev, 85 + struct spi_device *spi, 86 + const struct spi_offload_config *config) 87 + { 88 + struct spi_controller_and_offload *resource; 89 + int ret; 90 + 91 + if (!spi || !config) 92 + return ERR_PTR(-EINVAL); 93 + 94 + if (!spi->controller->get_offload) 95 + return ERR_PTR(-ENODEV); 96 + 97 + resource = kzalloc(sizeof(*resource), GFP_KERNEL); 98 + if (!resource) 99 + return ERR_PTR(-ENOMEM); 100 + 101 + resource->controller = spi->controller; 102 + resource->offload = spi->controller->get_offload(spi, config); 103 + if (IS_ERR(resource->offload)) { 104 + kfree(resource); 105 + return resource->offload; 106 + } 107 + 108 + ret = devm_add_action_or_reset(dev, spi_offload_put, resource); 109 + if (ret) 110 + return ERR_PTR(ret); 111 + 112 + return resource->offload; 113 + } 114 + EXPORT_SYMBOL_GPL(devm_spi_offload_get);
+22
include/linux/spi/offload/consumer.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (C) 2024 Analog Devices Inc. 4 + * Copyright (C) 2024 BayLibre, SAS 5 + */ 6 + 7 + #ifndef __LINUX_SPI_OFFLOAD_CONSUMER_H 8 + #define __LINUX_SPI_OFFLOAD_CONSUMER_H 9 + 10 + #include <linux/module.h> 11 + #include <linux/spi/offload/types.h> 12 + #include <linux/types.h> 13 + 14 + MODULE_IMPORT_NS("SPI_OFFLOAD"); 15 + 16 + struct device; 17 + struct spi_device; 18 + 19 + struct spi_offload *devm_spi_offload_get(struct device *dev, struct spi_device *spi, 20 + const struct spi_offload_config *config); 21 + 22 + #endif /* __LINUX_SPI_OFFLOAD_CONSUMER_H */
+19
include/linux/spi/offload/provider.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (C) 2024 Analog Devices Inc. 4 + * Copyright (C) 2024 BayLibre, SAS 5 + */ 6 + 7 + #ifndef __LINUX_SPI_OFFLOAD_PROVIDER_H 8 + #define __LINUX_SPI_OFFLOAD_PROVIDER_H 9 + 10 + #include <linux/module.h> 11 + #include <linux/types.h> 12 + 13 + MODULE_IMPORT_NS("SPI_OFFLOAD"); 14 + 15 + struct device; 16 + 17 + struct spi_offload *devm_spi_offload_alloc(struct device *dev, size_t priv_size); 18 + 19 + #endif /* __LINUX_SPI_OFFLOAD_PROVIDER_H */
+43
include/linux/spi/offload/types.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (C) 2024 Analog Devices Inc. 4 + * Copyright (C) 2024 BayLibre, SAS 5 + */ 6 + 7 + #ifndef __LINUX_SPI_OFFLOAD_TYPES_H 8 + #define __LINUX_SPI_OFFLOAD_TYPES_H 9 + 10 + #include <linux/types.h> 11 + 12 + struct device; 13 + 14 + /* Offload can be triggered by external hardware event. */ 15 + #define SPI_OFFLOAD_CAP_TRIGGER BIT(0) 16 + /* Offload can record and then play back TX data when triggered. */ 17 + #define SPI_OFFLOAD_CAP_TX_STATIC_DATA BIT(1) 18 + /* Offload can get TX data from an external stream source. */ 19 + #define SPI_OFFLOAD_CAP_TX_STREAM_DMA BIT(2) 20 + /* Offload can send RX data to an external stream sink. */ 21 + #define SPI_OFFLOAD_CAP_RX_STREAM_DMA BIT(3) 22 + 23 + /** 24 + * struct spi_offload_config - offload configuration 25 + * 26 + * This is used to request an offload with specific configuration. 27 + */ 28 + struct spi_offload_config { 29 + /** @capability_flags: required capabilities. See %SPI_OFFLOAD_CAP_* */ 30 + u32 capability_flags; 31 + }; 32 + 33 + /** 34 + * struct spi_offload - offload instance 35 + */ 36 + struct spi_offload { 37 + /** @provider_dev: for get/put reference counting */ 38 + struct device *provider_dev; 39 + /** @priv: provider driver private data */ 40 + void *priv; 41 + }; 42 + 43 + #endif /* __LINUX_SPI_OFFLOAD_TYPES_H */
+17
include/linux/spi/spi.h
··· 31 31 struct spi_controller_mem_ops; 32 32 struct spi_controller_mem_caps; 33 33 struct spi_message; 34 + struct spi_offload; 35 + struct spi_offload_config; 34 36 35 37 /* 36 38 * INTERFACES between SPI master-side drivers and SPI slave protocol handlers, ··· 498 496 * @mem_ops: optimized/dedicated operations for interactions with SPI memory. 499 497 * This field is optional and should only be implemented if the 500 498 * controller has native support for memory like operations. 499 + * @get_offload: callback for controllers with offload support to get matching 500 + * offload instance. Implementations should return -ENODEV if no match is 501 + * found. 502 + * @put_offload: release the offload instance acquired by @get_offload. 501 503 * @mem_caps: controller capabilities for the handling of memory operations. 502 504 * @unprepare_message: undo any work done by prepare_message(). 503 505 * @target_abort: abort the ongoing transfer request on an SPI target controller ··· 745 739 /* Optimized handlers for SPI memory-like operations. */ 746 740 const struct spi_controller_mem_ops *mem_ops; 747 741 const struct spi_controller_mem_caps *mem_caps; 742 + 743 + struct spi_offload *(*get_offload)(struct spi_device *spi, 744 + const struct spi_offload_config *config); 745 + void (*put_offload)(struct spi_offload *offload); 748 746 749 747 /* GPIO chip select */ 750 748 struct gpio_desc **cs_gpiods; ··· 1118 1108 * @state: for use by whichever driver currently owns the message 1119 1109 * @opt_state: for use by whichever driver currently owns the message 1120 1110 * @resources: for resource management when the SPI message is processed 1111 + * @offload: (optional) offload instance used by this message 1121 1112 * 1122 1113 * A @spi_message is used to execute an atomic sequence of data transfers, 1123 1114 * each represented by a struct spi_transfer. The sequence is "atomic" ··· 1178 1167 * __spi_optimize_message() and __spi_unoptimize_message(). 1179 1168 */ 1180 1169 void *opt_state; 1170 + 1171 + /* 1172 + * Optional offload instance used by this message. This must be set 1173 + * by the peripheral driver before calling spi_optimize_message(). 1174 + */ 1175 + struct spi_offload *offload; 1181 1176 1182 1177 /* List of spi_res resources when the SPI message is processed */ 1183 1178 struct list_head resources;