@@ -1201,6 +1201,23 @@ void spi_finalize_current_transfer(struct spi_controller *ctlr)
EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
/**
+ * __spi_res_unprepare_message - resource management function which
+ * calls unprepare_message
+ * @ctlr: controller for
+ * @msg: the message to unprepare
+ * @res: extra data - ignored
+ */
+static void __spi_res_unprepare_message(struct spi_controller *ctlr,
+ struct spi_message *msg,
+ void *res)
+{
+ int ret = ctlr->unprepare_message(ctlr, msg);
+
+ if (ret)
+ dev_err(&ctlr->dev, "failed to unprepare message: %d\n", ret);
+}
+
+/**
* __spi_pump_messages - function which processes spi message queue
* @ctlr: controller to process queue for
* @in_kthread: true if we are in the context of the message pump thread
@@ -1318,6 +1335,19 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
if (ctlr->prepare_message) {
struct list_head *tail = ctlr->cur_msg->resources.prev;
+ void *res = NULL;
+
+ if (ctlr->unprepare_message) {
+ res = spi_res_alloc(ctlr->cur_msg->spi,
+ __spi_res_unprepare_message, 0,
+ GFP_KERNEL);
+ if (!res) {
+ ret = -ENOMEM;
+ ctlr->cur_msg->status = ret;
+ spi_finalize_current_message(ctlr);
+ goto out;
+ }
+ }
ret = ctlr->prepare_message(ctlr, ctlr->cur_msg);
if (ret) {
dev_err(&ctlr->dev, "failed to prepare message: %d\n",
@@ -1331,6 +1361,10 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
tail != ctlr->cur_msg->resources.prev)
dev_warn_once(&ctlr->dev,
"spi_message.resource is modified and unprepare_message is defined - this can give unexpected results during finalize\n");
+ /* we only add the resource late to keep the expected order */
+ if (res)
+ spi_res_add(ctlr->cur_msg, res);
+
ctlr->cur_msg_prepared = true;
}
@@ -1436,29 +1470,12 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
{
struct spi_message *mesg;
unsigned long flags;
- int ret;
spin_lock_irqsave(&ctlr->queue_lock, flags);
mesg = ctlr->cur_msg;
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
spi_unmap_msg(ctlr, mesg);
-
- if (ctlr->cur_msg_prepared && ctlr->unprepare_message) {
- ret = ctlr->unprepare_message(ctlr, mesg);
- if (ret) {
- dev_err(&ctlr->dev, "failed to unprepare message: %d\n",
- ret);
- }
- }
-
- /* where to put the release is a slight nightmare because
- * ctlr->prepare_message may add to resources as well.
- * so the question is: call it before unprepare or after?
- * for now leave it after - the asumption here is that
- * if prepare_message is using spi_res for callbacks,
- * then no unprepare_message is used
- */
spi_res_release(ctlr, mesg);
spin_lock_irqsave(&ctlr->queue_lock, flags);
@@ -3770,4 +3787,3 @@ static int __init spi_init(void)
* include needing to have boardinfo data structures be much more public.
*/
postcore_initcall(spi_init);
-