Skip to content

Commit df227dc

Browse files
dgerlachJassiBrar
authored andcommitted
mailbox: ti-msgmgr: Operate mailbox in polled mode during system suspend
During the system suspend path we must set all queues to operate in polled mode as it is possible for any protocol built using this mailbox, such as TISCI, to require communication during the no irq phase of suspend, and we cannot rely on interrupts there. Polled mode is implemented by allowing the mailbox user to define an RX channel as part of the message that is sent which is what gets polled for a response. If polled mode is enabled, this will immediately be polled for a response at the end of the mailbox send_data op before returning success for the data send or timing out if no response is received. Finally, to ensure polled mode is always enabled during system suspend, iterate through all queues to set RX queues to polled mode during system suspend and disable polled mode for all in the resume handler. Signed-off-by: Dave Gerlach <d-gerlach@ti.com> Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
1 parent cb62b8f commit df227dc

File tree

2 files changed

+98
-3
lines changed

2 files changed

+98
-3
lines changed

drivers/mailbox/ti-msgmgr.c

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/*
33
* Texas Instruments' Message Manager Driver
44
*
5-
* Copyright (C) 2015-2017 Texas Instruments Incorporated - https://www.ti.com/
5+
* Copyright (C) 2015-2022 Texas Instruments Incorporated - https://www.ti.com/
66
* Nishanth Menon
77
*/
88

@@ -11,6 +11,7 @@
1111
#include <linux/device.h>
1212
#include <linux/interrupt.h>
1313
#include <linux/io.h>
14+
#include <linux/iopoll.h>
1415
#include <linux/kernel.h>
1516
#include <linux/mailbox_controller.h>
1617
#include <linux/module.h>
@@ -100,6 +101,7 @@ struct ti_msgmgr_desc {
100101
* @queue_ctrl: Queue Control register
101102
* @chan: Mailbox channel
102103
* @rx_buff: Receive buffer pointer allocated at probe, max_message_size
104+
* @polled_rx_mode: Use polling for rx instead of interrupts
103105
*/
104106
struct ti_queue_inst {
105107
char name[30];
@@ -113,6 +115,7 @@ struct ti_queue_inst {
113115
void __iomem *queue_ctrl;
114116
struct mbox_chan *chan;
115117
u32 *rx_buff;
118+
bool polled_rx_mode;
116119
};
117120

118121
/**
@@ -237,6 +240,26 @@ static int ti_msgmgr_queue_rx_data(struct mbox_chan *chan, struct ti_queue_inst
237240
return 0;
238241
}
239242

243+
static int ti_msgmgr_queue_rx_poll_timeout(struct mbox_chan *chan, int timeout_us)
244+
{
245+
struct device *dev = chan->mbox->dev;
246+
struct ti_msgmgr_inst *inst = dev_get_drvdata(dev);
247+
struct ti_queue_inst *qinst = chan->con_priv;
248+
const struct ti_msgmgr_desc *desc = inst->desc;
249+
int msg_count;
250+
int ret;
251+
252+
ret = readl_poll_timeout_atomic(qinst->queue_state, msg_count,
253+
(msg_count & desc->status_cnt_mask),
254+
10, timeout_us);
255+
if (ret != 0)
256+
return ret;
257+
258+
ti_msgmgr_queue_rx_data(chan, qinst, desc);
259+
260+
return 0;
261+
}
262+
240263
/**
241264
* ti_msgmgr_queue_rx_interrupt() - Interrupt handler for receive Queue
242265
* @irq: Interrupt number
@@ -346,6 +369,17 @@ static bool ti_msgmgr_last_tx_done(struct mbox_chan *chan)
346369
return msg_count ? false : true;
347370
}
348371

372+
static bool ti_msgmgr_chan_has_polled_queue_rx(struct mbox_chan *chan)
373+
{
374+
struct ti_queue_inst *qinst;
375+
376+
if (!chan)
377+
return false;
378+
379+
qinst = chan->con_priv;
380+
return qinst->polled_rx_mode;
381+
}
382+
349383
/**
350384
* ti_msgmgr_send_data() - Send data
351385
* @chan: Channel Pointer
@@ -363,6 +397,7 @@ static int ti_msgmgr_send_data(struct mbox_chan *chan, void *data)
363397
struct ti_msgmgr_message *message = data;
364398
void __iomem *data_reg;
365399
u32 *word_data;
400+
int ret = 0;
366401

367402
if (WARN_ON(!inst)) {
368403
dev_err(dev, "no platform drv data??\n");
@@ -404,7 +439,12 @@ static int ti_msgmgr_send_data(struct mbox_chan *chan, void *data)
404439
if (data_reg <= qinst->queue_buff_end)
405440
writel(0, qinst->queue_buff_end);
406441

407-
return 0;
442+
/* If we are in polled mode, wait for a response before proceeding */
443+
if (ti_msgmgr_chan_has_polled_queue_rx(message->chan_rx))
444+
ret = ti_msgmgr_queue_rx_poll_timeout(message->chan_rx,
445+
message->timeout_rx_ms * 1000);
446+
447+
return ret;
408448
}
409449

410450
/**
@@ -652,6 +692,54 @@ static int ti_msgmgr_queue_setup(int idx, struct device *dev,
652692
return 0;
653693
}
654694

695+
static int ti_msgmgr_queue_rx_set_polled_mode(struct ti_queue_inst *qinst, bool enable)
696+
{
697+
if (enable) {
698+
disable_irq(qinst->irq);
699+
qinst->polled_rx_mode = true;
700+
} else {
701+
enable_irq(qinst->irq);
702+
qinst->polled_rx_mode = false;
703+
}
704+
705+
return 0;
706+
}
707+
708+
static int ti_msgmgr_suspend(struct device *dev)
709+
{
710+
struct ti_msgmgr_inst *inst = dev_get_drvdata(dev);
711+
struct ti_queue_inst *qinst;
712+
int i;
713+
714+
/*
715+
* We must switch operation to polled mode now as drivers and the genpd
716+
* layer may make late TI SCI calls to change clock and device states
717+
* from the noirq phase of suspend.
718+
*/
719+
for (qinst = inst->qinsts, i = 0; i < inst->num_valid_queues; qinst++, i++) {
720+
if (!qinst->is_tx)
721+
ti_msgmgr_queue_rx_set_polled_mode(qinst, true);
722+
}
723+
724+
return 0;
725+
}
726+
727+
static int ti_msgmgr_resume(struct device *dev)
728+
{
729+
struct ti_msgmgr_inst *inst = dev_get_drvdata(dev);
730+
struct ti_queue_inst *qinst;
731+
int i;
732+
733+
for (qinst = inst->qinsts, i = 0; i < inst->num_valid_queues; qinst++, i++) {
734+
if (!qinst->is_tx)
735+
ti_msgmgr_queue_rx_set_polled_mode(qinst, false);
736+
}
737+
738+
return 0;
739+
}
740+
741+
static DEFINE_SIMPLE_DEV_PM_OPS(ti_msgmgr_pm_ops, ti_msgmgr_suspend, ti_msgmgr_resume);
742+
655743
/* Queue operations */
656744
static const struct mbox_chan_ops ti_msgmgr_chan_ops = {
657745
.startup = ti_msgmgr_queue_startup,
@@ -839,6 +927,7 @@ static struct platform_driver ti_msgmgr_driver = {
839927
.driver = {
840928
.name = "ti-msgmgr",
841929
.of_match_table = of_match_ptr(ti_msgmgr_of_match),
930+
.pm = &ti_msgmgr_pm_ops,
842931
},
843932
};
844933
module_platform_driver(ti_msgmgr_driver);

include/linux/soc/ti/ti-msgmgr.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* Texas Instruments' Message Manager
33
*
4-
* Copyright (C) 2015-2016 Texas Instruments Incorporated - https://www.ti.com/
4+
* Copyright (C) 2015-2022 Texas Instruments Incorporated - https://www.ti.com/
55
* Nishanth Menon
66
*
77
* This program is free software; you can redistribute it and/or modify
@@ -17,10 +17,14 @@
1717
#ifndef TI_MSGMGR_H
1818
#define TI_MSGMGR_H
1919

20+
struct mbox_chan;
21+
2022
/**
2123
* struct ti_msgmgr_message - Message Manager structure
2224
* @len: Length of data in the Buffer
2325
* @buf: Buffer pointer
26+
* @chan_rx: Expected channel for response, must be provided to use polled rx
27+
* @timeout_rx_ms: Timeout value to use if polling for response
2428
*
2529
* This is the structure for data used in mbox_send_message
2630
* the length of data buffer used depends on the SoC integration
@@ -30,6 +34,8 @@
3034
struct ti_msgmgr_message {
3135
size_t len;
3236
u8 *buf;
37+
struct mbox_chan *chan_rx;
38+
int timeout_rx_ms;
3339
};
3440

3541
#endif /* TI_MSGMGR_H */

0 commit comments

Comments
 (0)