Re: [PATCH v2 03/18] firmware: arm_scmi: add basic driver infrastructure for SCMI

From: Sudeep Holla
Date: Tue Sep 05 2017 - 06:25:46 EST


Hi Julien,

Thanks for reviewing this.

On 05/09/17 11:03, Julien Thierry wrote:
> Hi Sudeep,
>
> I am not sure what the patch does is correct when having a big endian
> kernel dealing with scmi_shared_mem. Unless there is a reason not to
> have SCMI with big endian kernel, please see remarks below.
>

No the intention at least is to have it working even with big endian
kernel. I found couple of issues when testing after this was posted.
They are already fixed in [1]


[...]

>> +/**
>> + * scmi_rx_callback() - mailbox client callback for receive messages
>> + *
>> + * @cl: client pointer
>> + * @m: mailbox message
>> + *
>> + * Processes one received message to appropriate transfer information
>> and
>> + * signals completion of the transfer.
>> + *
>> + * NOTE: This function will be invoked in IRQ context, hence should be
>> + * as optimal as possible.
>> + */
>> +static void scmi_rx_callback(struct mbox_client *cl, void *m)
>> +{
>> + u16 xfer_id;
>> + struct scmi_xfer *xfer;
>> + struct scmi_info *info = client_to_scmi_info(cl);
>> + struct scmi_xfers_info *minfo = &info->minfo;
>> + struct device *dev = info->dev;
>> + struct scmi_shared_mem *mem = info->tx_payload;
>> +
>> + xfer_id = MSG_XTRACT_TOKEN(mem->msg_header);
>> +
>
> Don't we need to convert msg_header to cpu endian?
>

Indeed, already fixed as mentioned above.

>> + /*
>> + * Are we even expecting this?
>> + */
>> + if (!test_bit(xfer_id, minfo->xfer_alloc_table)) {
>> + dev_err(dev, "message for %d is not expected!\n", xfer_id);
>> + return;
>> + }
>> +
>> + xfer = &minfo->xfer_block[xfer_id];
>> +
>> + scmi_dump_header_dbg(dev, &xfer->hdr);
>> + /* Is the message of valid length? */
>> + if (xfer->rx.len > info->desc->max_msg_size) {
>> + dev_err(dev, "unable to handle %zu xfer(max %d)\n",
>> + xfer->rx.len, info->desc->max_msg_size);
>> + return;
>> + }
>> +
>> + scmi_fetch_response(xfer, mem);
>> + complete(&xfer->done);
>> +}
>> +
>> +/**
>> + * pack_scmi_header() - packs and returns 32-bit header
>> + *
>> + * @hdr: pointer to header containing all the information on message id,
>> + * protocol id and sequence id.
>> + */
>> +static inline u32 pack_scmi_header(struct scmi_msg_hdr *hdr)
>> +{
>> + return ((hdr->id & MSG_ID_MASK) << MSG_ID_SHIFT) |
>> + ((hdr->seq & MSG_TOKEN_ID_MASK) << MSG_TOKEN_ID_SHIFT) |
>> + ((hdr->protocol_id & MSG_PROTOCOL_ID_MASK) <<
>> MSG_PROTOCOL_ID_SHIFT);
>> +}
>> +
>> +/**
>> + * scmi_tx_prepare() - mailbox client callback to prepare for the
>> transfer
>> + *
>> + * @cl: client pointer
>> + * @m: mailbox message
>> + *
>> + * This function prepares the shared memory which contains the header
>> and the
>> + * payload.
>> + */
>> +static void scmi_tx_prepare(struct mbox_client *cl, void *m)
>> +{
>> + struct scmi_xfer *t = m;
>> + struct scmi_info *info = client_to_scmi_info(cl);
>> + struct scmi_shared_mem *mem = info->tx_payload;
>> +
>> + mem->channel_status = 0x0; /* Mark channel busy + clear error */
>> + mem->flags = t->hdr.poll_completion ? 0 :
>> SCMI_SHMEM_FLAG_INTR_ENABLED;
>> + mem->length = sizeof(mem->msg_header) + t->tx.len;
>> + mem->msg_header = cpu_to_le32(pack_scmi_header(&t->hdr));
>> + if (t->tx.buf)
>> + memcpy_toio(mem->msg_payload, t->tx.buf, t->tx.len);
>> +}
>
> I thought every member of scmi_shared_mem should be in le, not just the
> header.
> If that is the case, why do mem->length and mem->flags not get converted
> to le?
> If it is not the case, should they be of type __le32?
>
> (same remark applies in scmi_fetch_response for mem->length)
>

Agreed and already fixed, sorry for that. I am planning to repost after
4.14-rc1. and hence waiting with fixes.

>> +
>> +/**
>> + * scmi_one_xfer_get() - Allocate one message
>> + *
>> + * @handle: SCMI entity handle
>> + *
>> + * Helper function which is used by various command functions that are
>> + * exposed to clients of this driver for allocating a message traffic
>> event.
>> + *
>> + * This function can sleep depending on pending requests already in
>> the system
>> + * for the SCMI entity. Further, this also holds a spinlock to maintain
>> + * integrity of internal data structures.
>> + *
>> + * Return: 0 if all went fine, else corresponding error.
>> + */
>> +static struct scmi_xfer *scmi_one_xfer_get(const struct scmi_handle
>> *handle)
>> +{
>> + u16 xfer_id;
>> + int ret, timeout;
>> + struct scmi_xfer *xfer;
>> + unsigned long flags, bit_pos;
>> + struct scmi_info *info = handle_to_scmi_info(handle);
>> + struct scmi_xfers_info *minfo = &info->minfo;
>> +
>> + /*
>> + * Ensure we have only controlled number of pending messages.
>> + * Ideally, we might just have to wait a single message, be
>> + * conservative and wait 5 times that..
>> + */
>> + timeout = msecs_to_jiffies(info->desc->max_rx_timeout_ms) * 5;
>> + ret = down_timeout(&minfo->sem_xfer_count, timeout);
>> + if (ret < 0)
>> + return ERR_PTR(ret);
>> +
>> + /* Keep the locked section as small as possible */
>> + spin_lock_irqsave(&minfo->xfer_lock, flags);
>> + bit_pos = find_first_zero_bit(minfo->xfer_alloc_table,
>> + info->desc->max_msg);
>> + if (bit_pos == info->desc->max_msg) {
>> + spin_unlock_irqrestore(&minfo->xfer_lock, flags);
>> + return ERR_PTR(-ENOMEM);
>> + }
>> + set_bit(bit_pos, minfo->xfer_alloc_table);
>> + spin_unlock_irqrestore(&minfo->xfer_lock, flags);
>> +
>
> Is it needed to disable IRQs here? Since the callback called in IRQ
> context only reads the xfer_alloc_table without modification nor taking
> locks, can't we just do spin_lock/spin_unlock?
>

Yes we can for now. I started adding notification support where we may
need to allocate(i.e. assign from the pre-allocated buffer) in IRQ
context. I left it as is though I removed notifications as I haven't
tested it.

--
Regards,
Sudeep

[1] https://git.kernel.org/sudeep.holla/linux/h/for-list/arm_scmi