|
@@ -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);
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|