aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Sperl <kernel@martin.sperl.org>2015-12-14 10:20:18 -0500
committerMark Brown <broonie@kernel.org>2016-02-09 14:25:43 -0500
commitd780c3711d9df9bacd56b71cf23443b895a331ca (patch)
tree4c6cf9ae8b0cd70fd6128a9bc2cec1ba1676dc47
parent92e963f50fc74041b5e9e744c330dca48e04f08d (diff)
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>
-rw-r--r--drivers/spi/spi.c91
-rw-r--r--include/linux/spi/spi.h36
2 files changed, 127 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:
1024 if (msg->status && master->handle_err) 1024 if (msg->status && master->handle_err)
1025 master->handle_err(master, msg); 1025 master->handle_err(master, msg);
1026 1026
1027 spi_res_release(master, msg);
1028
1027 spi_finalize_current_message(master); 1029 spi_finalize_current_message(master);
1028 1030
1029 return ret; 1031 return ret;
@@ -2013,6 +2015,95 @@ struct spi_master *spi_busnum_to_master(u16 bus_num)
2013} 2015}
2014EXPORT_SYMBOL_GPL(spi_busnum_to_master); 2016EXPORT_SYMBOL_GPL(spi_busnum_to_master);
2015 2017
2018/*-------------------------------------------------------------------------*/
2019
2020/* Core methods for SPI resource management */
2021
2022/**
2023 * spi_res_alloc - allocate a spi resource that is life-cycle managed
2024 * during the processing of a spi_message while using
2025 * spi_transfer_one
2026 * @spi: the spi device for which we allocate memory
2027 * @release: the release code to execute for this resource
2028 * @size: size to alloc and return
2029 * @gfp: GFP allocation flags
2030 *
2031 * Return: the pointer to the allocated data
2032 *
2033 * This may get enhanced in the future to allocate from a memory pool
2034 * of the @spi_device or @spi_master to avoid repeated allocations.
2035 */
2036void *spi_res_alloc(struct spi_device *spi,
2037 spi_res_release_t release,
2038 size_t size, gfp_t gfp)
2039{
2040 struct spi_res *sres;
2041
2042 sres = kzalloc(sizeof(*sres) + size, gfp);
2043 if (!sres)
2044 return NULL;
2045
2046 INIT_LIST_HEAD(&sres->entry);
2047 sres->release = release;
2048
2049 return sres->data;
2050}
2051EXPORT_SYMBOL_GPL(spi_res_alloc);
2052
2053/**
2054 * spi_res_free - free an spi resource
2055 * @res: pointer to the custom data of a resource
2056 *
2057 */
2058void spi_res_free(void *res)
2059{
2060 struct spi_res *sres = container_of(res, struct spi_res, data);
2061
2062 if (!res)
2063 return;
2064
2065 WARN_ON(!list_empty(&sres->entry));
2066 kfree(sres);
2067}
2068EXPORT_SYMBOL_GPL(spi_res_free);
2069
2070/**
2071 * spi_res_add - add a spi_res to the spi_message
2072 * @message: the spi message
2073 * @res: the spi_resource
2074 */
2075void spi_res_add(struct spi_message *message, void *res)
2076{
2077 struct spi_res *sres = container_of(res, struct spi_res, data);
2078
2079 WARN_ON(!list_empty(&sres->entry));
2080 list_add_tail(&sres->entry, &message->resources);
2081}
2082EXPORT_SYMBOL_GPL(spi_res_add);
2083
2084/**
2085 * spi_res_release - release all spi resources for this message
2086 * @master: the @spi_master
2087 * @message: the @spi_message
2088 */
2089void spi_res_release(struct spi_master *master,
2090 struct spi_message *message)
2091{
2092 struct spi_res *res;
2093
2094 while (!list_empty(&message->resources)) {
2095 res = list_last_entry(&message->resources,
2096 struct spi_res, entry);
2097
2098 if (res->release)
2099 res->release(master, message, res->data);
2100
2101 list_del(&res->entry);
2102
2103 kfree(res);
2104 }
2105}
2106EXPORT_SYMBOL_GPL(spi_res_release);
2016 2107
2017/*-------------------------------------------------------------------------*/ 2108/*-------------------------------------------------------------------------*/
2018 2109
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 53be3a4c60cb..38204b584dc5 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -582,6 +582,37 @@ extern void spi_unregister_master(struct spi_master *master);
582 582
583extern struct spi_master *spi_busnum_to_master(u16 busnum); 583extern struct spi_master *spi_busnum_to_master(u16 busnum);
584 584
585/*
586 * SPI resource management while processing a SPI message
587 */
588
589/**
590 * struct spi_res - spi resource management structure
591 * @entry: list entry
592 * @release: release code called prior to freeing this resource
593 * @data: extra data allocated for the specific use-case
594 *
595 * this is based on ideas from devres, but focused on life-cycle
596 * management during spi_message processing
597 */
598typedef void (*spi_res_release_t)(struct spi_master *master,
599 struct spi_message *msg,
600 void *res);
601struct spi_res {
602 struct list_head entry;
603 spi_res_release_t release;
604 unsigned long long data[]; /* guarantee ull alignment */
605};
606
607extern void *spi_res_alloc(struct spi_device *spi,
608 spi_res_release_t release,
609 size_t size, gfp_t gfp);
610extern void spi_res_add(struct spi_message *message, void *res);
611extern void spi_res_free(void *res);
612
613extern void spi_res_release(struct spi_master *master,
614 struct spi_message *message);
615
585/*---------------------------------------------------------------------------*/ 616/*---------------------------------------------------------------------------*/
586 617
587/* 618/*
@@ -720,6 +751,7 @@ struct spi_transfer {
720 * @status: zero for success, else negative errno 751 * @status: zero for success, else negative errno
721 * @queue: for use by whichever driver currently owns the message 752 * @queue: for use by whichever driver currently owns the message
722 * @state: for use by whichever driver currently owns the message 753 * @state: for use by whichever driver currently owns the message
754 * @resources: for resource management when the spi message is processed
723 * 755 *
724 * A @spi_message is used to execute an atomic sequence of data transfers, 756 * A @spi_message is used to execute an atomic sequence of data transfers,
725 * each represented by a struct spi_transfer. The sequence is "atomic" 757 * each represented by a struct spi_transfer. The sequence is "atomic"
@@ -766,11 +798,15 @@ struct spi_message {
766 */ 798 */
767 struct list_head queue; 799 struct list_head queue;
768 void *state; 800 void *state;
801
802 /* list of spi_res reources when the spi message is processed */
803 struct list_head resources;
769}; 804};
770 805
771static inline void spi_message_init_no_memset(struct spi_message *m) 806static inline void spi_message_init_no_memset(struct spi_message *m)
772{ 807{
773 INIT_LIST_HEAD(&m->transfers); 808 INIT_LIST_HEAD(&m->transfers);
809 INIT_LIST_HEAD(&m->resources);
774} 810}
775 811
776static inline void spi_message_init(struct spi_message *m) 812static inline void spi_message_init(struct spi_message *m)