diff options
author | Martin Sperl <kernel@martin.sperl.org> | 2015-12-14 10:20:18 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-02-09 14:25:43 -0500 |
commit | d780c3711d9df9bacd56b71cf23443b895a331ca (patch) | |
tree | 4c6cf9ae8b0cd70fd6128a9bc2cec1ba1676dc47 | |
parent | 92e963f50fc74041b5e9e744c330dca48e04f08d (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.c | 91 | ||||
-rw-r--r-- | include/linux/spi/spi.h | 36 |
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 | } |
2014 | EXPORT_SYMBOL_GPL(spi_busnum_to_master); | 2016 | EXPORT_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 | */ | ||
2036 | void *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 | } | ||
2051 | EXPORT_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 | */ | ||
2058 | void 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 | } | ||
2068 | EXPORT_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 | */ | ||
2075 | void 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 | } | ||
2082 | EXPORT_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 | */ | ||
2089 | void 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 | } | ||
2106 | EXPORT_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 | ||
583 | extern struct spi_master *spi_busnum_to_master(u16 busnum); | 583 | extern 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 | */ | ||
598 | typedef void (*spi_res_release_t)(struct spi_master *master, | ||
599 | struct spi_message *msg, | ||
600 | void *res); | ||
601 | struct spi_res { | ||
602 | struct list_head entry; | ||
603 | spi_res_release_t release; | ||
604 | unsigned long long data[]; /* guarantee ull alignment */ | ||
605 | }; | ||
606 | |||
607 | extern void *spi_res_alloc(struct spi_device *spi, | ||
608 | spi_res_release_t release, | ||
609 | size_t size, gfp_t gfp); | ||
610 | extern void spi_res_add(struct spi_message *message, void *res); | ||
611 | extern void spi_res_free(void *res); | ||
612 | |||
613 | extern 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 | ||
771 | static inline void spi_message_init_no_memset(struct spi_message *m) | 806 | static 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 | ||
776 | static inline void spi_message_init(struct spi_message *m) | 812 | static inline void spi_message_init(struct spi_message *m) |