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>
This commit is contained in:
@@ -582,6 +582,37 @@ extern void spi_unregister_master(struct spi_master *master);
|
||||
|
||||
extern struct spi_master *spi_busnum_to_master(u16 busnum);
|
||||
|
||||
/*
|
||||
* SPI resource management while processing a SPI message
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct spi_res - spi resource management structure
|
||||
* @entry: list entry
|
||||
* @release: release code called prior to freeing this resource
|
||||
* @data: extra data allocated for the specific use-case
|
||||
*
|
||||
* this is based on ideas from devres, but focused on life-cycle
|
||||
* management during spi_message processing
|
||||
*/
|
||||
typedef void (*spi_res_release_t)(struct spi_master *master,
|
||||
struct spi_message *msg,
|
||||
void *res);
|
||||
struct spi_res {
|
||||
struct list_head entry;
|
||||
spi_res_release_t release;
|
||||
unsigned long long data[]; /* guarantee ull alignment */
|
||||
};
|
||||
|
||||
extern void *spi_res_alloc(struct spi_device *spi,
|
||||
spi_res_release_t release,
|
||||
size_t size, gfp_t gfp);
|
||||
extern void spi_res_add(struct spi_message *message, void *res);
|
||||
extern void spi_res_free(void *res);
|
||||
|
||||
extern void spi_res_release(struct spi_master *master,
|
||||
struct spi_message *message);
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
@@ -720,6 +751,7 @@ struct spi_transfer {
|
||||
* @status: zero for success, else negative errno
|
||||
* @queue: for use by whichever driver currently owns the message
|
||||
* @state: for use by whichever driver currently owns the message
|
||||
* @resources: for resource management when the spi message is processed
|
||||
*
|
||||
* A @spi_message is used to execute an atomic sequence of data transfers,
|
||||
* each represented by a struct spi_transfer. The sequence is "atomic"
|
||||
@@ -766,11 +798,15 @@ struct spi_message {
|
||||
*/
|
||||
struct list_head queue;
|
||||
void *state;
|
||||
|
||||
/* list of spi_res reources when the spi message is processed */
|
||||
struct list_head resources;
|
||||
};
|
||||
|
||||
static inline void spi_message_init_no_memset(struct spi_message *m)
|
||||
{
|
||||
INIT_LIST_HEAD(&m->transfers);
|
||||
INIT_LIST_HEAD(&m->resources);
|
||||
}
|
||||
|
||||
static inline void spi_message_init(struct spi_message *m)
|
||||
|
Reference in New Issue
Block a user