Re: [PATCH V2 2/2] mailbox: Introduce TI message manager driver

From: Nishanth Menon
Date: Mon Mar 07 2016 - 14:19:40 EST


On 03/07/2016 12:31 PM, Jassi Brar wrote:
> On Fri, Mar 4, 2016 at 8:05 PM, Nishanth Menon <nm@xxxxxx> wrote:
>> Hi Jassi,
>>
>> Thanks for reviewing the patch.
>> On 03/03/2016 11:18 PM, Jassi Brar wrote:
>>
>> [...]
>>
>>>>
>>>> drivers/mailbox/Kconfig | 11 +
>>>> drivers/mailbox/Makefile | 2 +
>>>> drivers/mailbox/ti-msgmgr.c | 657
>>
>>> Do you want to call it something more specific than 'msgmgr from TI'?
>>> Maybe its about Keystone, like mailbox-keystone.c ?
>>
>> Here is the rationale for choosing the name:
>> There are more than 1 IPC in TI SoCs and even within Keystone SoC.
>> Further, it is indeed called message manager hardware block and used
>> across multiple SoC families (even though it is originated by keystone
>> architecture). we do have a reuse of the omap-mailbox in a future
>> keystone device (in addition to message manager), so using ti-mailbox is
>> more appropriate for omap-mailbox, but anyways.. further renaming this
>> as keystone-mailbox will confuse poor users when the new SoC comes in..
>>
>> We do have a lot of cross pollination of hardware blocks across TI
>> architectures, and "keystone-" prefix does not really fit the usage.
>> hence the usage of vendor-hardwareblock name.
>>
> OK, I leave that to you to call it whatever you think is right.

thanks.

>
>>>
>>>> +#include <linux/module.h>
>>>> +#include <linux/of_device.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/of_irq.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/ti-msgmgr.h>
>>>>
>>> This seems a bit bold. I think include/linux/soc/ti/ is the right place.
>>
>> Sure, I can. Since I followed c, Would you
>> suggest all files such as include/linux/omap* be moved to
>> include/linux/soc/ti/ ? I guess that is not pertinent to this specific
>> patch, but I am curious..
>>
> include/linux/omap-mailbox.h predates mailbox api.
> But yes, I do think include/linux is not the right place for platform
> specific headers. include/linux/soc/ is.

Will fix this.

>>
>>>> + /* Do I actually have messages to read? */
>>>> + msg_count = ti_msgmgr_queue_get_num_messages(qinst);
>>>> + if (!msg_count) {
>>>> + /* Shared IRQ? */
>>>> + dev_dbg(dev, "Spurious event - 0 pending data!\n");
>>>> + return IRQ_NONE;
>>>> + }
>>>> +
>>>> + /*
>>>> + * I have no idea about the protocol being used to communicate with the
>>>> + * remote producer - 0 could be valid data, so I wont make a judgement
>>>> + * of how many bytes I should be reading. Let the client figure this
>>>> + * out.. I just read the full message and pass it on..
>>>> + */
>>> Exactly. And similarly when you send data, you should not have more
>>> than one message in transit. Now please see my note in
>>> ti_msgmgr_send_data()
>>>
>>>
>>>> +static int ti_msgmgr_send_data(struct mbox_chan *chan, void *data)
>>>> +{
>>>> + struct device *dev = chan->mbox->dev;
>>>> + struct ti_msgmgr_inst *inst = dev_get_drvdata(dev);
>>>> + const struct ti_msgmgr_desc *desc;
>>>> + struct ti_queue_inst *qinst = chan->con_priv;
>>>> + int msg_count, num_words, trail_bytes;
>>>> + struct ti_msgmgr_message *message = data;
>>>> + void __iomem *data_reg;
>>>> + u32 *word_data;
>>>> +
>>>> + if (WARN_ON(!inst)) {
>>>> + dev_err(dev, "no platform drv data??\n");
>>>> + return -EINVAL;
>>>> + }
>>>> + desc = inst->desc;
>>>> +
>>>> + if (desc->max_message_size < message->len) {
>>>> + dev_err(dev, "Queue %s message length %d > max %d\n",
>>>> + qinst->name, message->len, desc->max_message_size);
>>>> + return -EINVAL;
>>>> + }
>>>> +
>>>> + /* Are we able to send this or not? */
>>>> + msg_count = ti_msgmgr_queue_get_num_messages(qinst);
>>>> + if (msg_count >= desc->max_messages) {
>>>> + dev_warn(dev, "Queue %s is full (%d messages)\n", qinst->name,
>>>> + msg_count);
>>>> + return -EBUSY;
>>>> + }
>>> This seems fishy. mailbox api always submit 1 'complete' message to be
>>> sent and checks for completion by last_tx_done() before calling
>>> send_data() again. Controller drivers are not supposed to queue
>>> messages - mailbox core does. So you should never be unable to send a
>>> message.
>>
>>
>> OK-> to explain this, few reasons: (queue messages check and usage of
>> last_tx_done are kind of intertwined answer..
>> a) we need to remember that the message manager has a shared RAM.
>> multiple transmitter over other queues can be sharing the same.
>> unfortunately, we dont get a threshold kind of interrupt or status that
>> I am able to exploit in the current incarnation of the solution. The
>> best we can do in the full system is to constrain the number of messages
>> that are max pending simultaneously in each of the queue from various
>> transmitters in the SoC.
>> b) last_tx_done() is checked if TXDONE_BY_POLL, not if TXDONE_BY_ACK
>> right? which is how this'd work since txdone_poll is false -> that is
>> how we want this mechanism to work once the far end is ready for next
>> message, it acks. I do see your point about being tied to protocol - I
>> dont like it either.. in fact, I'd prefer that client registration
>> mention what kind of handshaking is necessary, but: a) that is not how
>> mailbox framework is constructed at the moment(we state txdone_poll at
>> mailbox registration, not at client usage) and b) I have no real need
>> for multiple clients to users of message manager who actually need
>> non-ACK usage - even for the foreseeable future (at least 1 next
>> generation of SoC) - if such a need does arise in the future, I will
>> have to rework framework and make this capability at the registration
>> time of the client - allowing each client path to use different
>> mechanisms on hardware such as these that need it.
>> c) message manager can actually queue more than one message(depending on
>> client capability). Even though, at this point, we are not really
>> capable of doing it(again from what I can see for immediate future),
>> mailbox framework by checking last_tx_done forces a single message
>> sequencing - which is not really exploiting the capability of the
>> hardware - in theory, we should be able to queue max num messages, hit
>> cpuidle and snooze away while the remote entity chomp away data at it's
>> own pace and finally give us a notification back - but again, we can
>> argue it is indeed protocol dependent, so setting txdone_poll to false
>> actually enables that to be done in user. Again - i have no immediate
>> need for any queued multiple transfer needs yet.. even if i need to, in
>> the future, it can easily be done by the client by maintaining code as
>> is - txdone_poll is false.
>>
> All I suggest is that the controller does not queue more than 1
> message at a time, which means the controller driver allows for
> maximum possible resources taken by a message.
> The buffering is already done by the core, and if for your 'batch
> dispatch' thing the client could simply flush them to remote by
> pretending it got the ack (which is no worse than simply sending all
> messages to remote without caring if the first was successful or not).

Are you suggesting to set txdone_poll is true? the controller is quite
capable of queueing more than 1 message at a time. This the reason for
letting the client choose the mode of operation - use ack mechanism for
operation. client can choose to ignore the buffering in the controller,
as you mentioned, but then, why force txdone_poll to true and deny the
usage of the queue capability of the hardware?

>>>> + /*
>>>> + * NOTE about register access involved here:
>>>> + * the hardware block is implemented with 32bit access operations and no
>>>> + * support for data splitting. We don't want the hardware to misbehave
>>>> + * with sub 32bit access - For example: if the last register write is
>>>> + * split into byte wise access, it can result in the queue getting
>>>> + * stuck or dummy messages being transmitted or indeterminate behavior.
>>>> + * The same can occur if out of order operations take place.
>>>> + * Hence, we do not use memcpy_toio or ___iowrite32_copy here, instead
>>>> + * we use writel which ensures the sequencing we need.
>>>> + */
>>> .... deja-vu ?
>>
>> Tell me about it.. but then, surprises like these do pop in once in a
>> while.. sigh..
>>
> I meant you have same para for read() , so maybe omit this one.

Aaah.. OK. i will add something trivial as "similar constraints as read"..

>>>> +
>>>> +/* Keystone K2G SoC integration details */
>>>> +static const struct ti_msgmgr_valid_queue_desc k2g_valid_queues[] = {
>>>> + {.queue_id = 0, .proxy_id = 0, .is_tx = true,},
>>>> + {.queue_id = 1, .proxy_id = 0, .is_tx = true,},
>>>> + {.queue_id = 2, .proxy_id = 0, .is_tx = true,},
>>>> + {.queue_id = 3, .proxy_id = 0, .is_tx = true,},
>>>> + {.queue_id = 5, .proxy_id = 2, .is_tx = false,},
>>>> + {.queue_id = 56, .proxy_id = 1, .is_tx = true,},
>>>> + {.queue_id = 57, .proxy_id = 2, .is_tx = false,},
>>>> + {.queue_id = 58, .proxy_id = 3, .is_tx = true,},
>>>> + {.queue_id = 59, .proxy_id = 4, .is_tx = true,},
>>>> + {.queue_id = 60, .proxy_id = 5, .is_tx = true,},
>>>> + {.queue_id = 61, .proxy_id = 6, .is_tx = true,},
>>>> +};
>>>> +
>>>> +static const struct ti_msgmgr_desc k2g_desc = {
>>>> + .queue_count = 64,
>>>> + .max_message_size = 64,
>>>> + .max_messages = 128,
>>>> + .q_slices = 1,
>>>> + .q_proxies = 1,
>>>> + .data_first_reg = 16,
>>>> + .data_last_reg = 31,
>>>> + .tx_polled = false,
>>>> + .valid_queues = k2g_valid_queues,
>>>> + .num_valid_queues = ARRAY_SIZE(k2g_valid_queues),
>>>> +};
>>> If these parameters are very configurable, maybe they should be in DT?
>>
>> These are SoC integration specific data. based on DT, we will only have
>> SoC specific compatible property in DT. Since the data is tied to SoC
>> integration, there is no benefit of keeping these in DT.
>>
> Well, yes if the numbers don't change with very often.

Hopefully not.

--
Regards,
Nishanth Menon