diff options
author | Martin Sperl <kernel@martin.sperl.org> | 2015-12-14 18:20:18 +0300 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-02-09 22:25:43 +0300 |
commit | d780c3711d9df9bacd56b71cf23443b895a331ca (patch) | |
tree | 4c6cf9ae8b0cd70fd6128a9bc2cec1ba1676dc47 /drivers/spi/spi.c | |
parent | 92e963f50fc74041b5e9e744c330dca48e04f08d (diff) | |
download | linux-d780c3711d9df9bacd56b71cf23443b895a331ca.tar.xz |
spi: core: added spi_resource management
SPI resource management framework used while processing a spi_message
via the spi-core.
The basic idea is taken from devres, but as the allocation may happen
fairly frequently, some provisioning (in the form of an unused spi_device
pointer argument to spi_res_alloc) has been made so that at a later stage
we may implement reuse objects allocated earlier avoiding the repeated
allocation by keeping a cache of objects that we can reuse.
This framework can get used for:
* rewriting spi_messages
* to fullfill alignment requirements of the spi_master HW
* to fullfill transfer length requirements
(e.g: transfers need to be less than 64k)
* consolidate spi_messages with multiple transfers into a single transfer
when the total transfer length is below a threshold.
* reimplement spi_unmap_buf without explicitly needing to check if it has
been mapped
Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/spi/spi.c')
-rw-r--r-- | drivers/spi/spi.c | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 47eff8012a77..894ed0357dd7 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1024,6 +1024,8 @@ out: if (msg->status && master->handle_err) master->handle_err(master, msg); + spi_res_release(master, msg); + spi_finalize_current_message(master); return ret; @@ -2013,6 +2015,95 @@ struct spi_master *spi_busnum_to_master(u16 bus_num) } EXPORT_SYMBOL_GPL(spi_busnum_to_master); +/*-------------------------------------------------------------------------*/ + +/* Core methods for SPI resource management */ + +/** + * spi_res_alloc - allocate a spi resource that is life-cycle managed + * during the processing of a spi_message while using + * spi_transfer_one + * @spi: the spi device for which we allocate memory + * @release: the release code to execute for this resource + * @size: size to alloc and return + * @gfp: GFP allocation flags + * + * Return: the pointer to the allocated data + * + * This may get enhanced in the future to allocate from a memory pool + * of the @spi_device or @spi_master to avoid repeated allocations. + */ +void *spi_res_alloc(struct spi_device *spi, + spi_res_release_t release, + size_t size, gfp_t gfp) +{ + struct spi_res *sres; + + sres = kzalloc(sizeof(*sres) + size, gfp); + if (!sres) + return NULL; + + INIT_LIST_HEAD(&sres->entry); + sres->release = release; + + return sres->data; +} +EXPORT_SYMBOL_GPL(spi_res_alloc); + +/** + * spi_res_free - free an spi resource + * @res: pointer to the custom data of a resource + * + */ +void spi_res_free(void *res) +{ + struct spi_res *sres = container_of(res, struct spi_res, data); + + if (!res) + return; + + WARN_ON(!list_empty(&sres->entry)); + kfree(sres); +} +EXPORT_SYMBOL_GPL(spi_res_free); + +/** + * spi_res_add - add a spi_res to the spi_message + * @message: the spi message + * @res: the spi_resource + */ +void spi_res_add(struct spi_message *message, void *res) +{ + struct spi_res *sres = container_of(res, struct spi_res, data); + + WARN_ON(!list_empty(&sres->entry)); + list_add_tail(&sres->entry, &message->resources); +} +EXPORT_SYMBOL_GPL(spi_res_add); + +/** + * spi_res_release - release all spi resources for this message + * @master: the @spi_master + * @message: the @spi_message + */ +void spi_res_release(struct spi_master *master, + struct spi_message *message) +{ + struct spi_res *res; + + while (!list_empty(&message->resources)) { + res = list_last_entry(&message->resources, + struct spi_res, entry); + + if (res->release) + res->release(master, message, res->data); + + list_del(&res->entry); + + kfree(res); + } +} +EXPORT_SYMBOL_GPL(spi_res_release); /*-------------------------------------------------------------------------*/ |