shmem.c (2882B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * For transport using shared mem structure. 4 * 5 * Copyright (C) 2019 ARM Ltd. 6 */ 7 8#include <linux/io.h> 9#include <linux/processor.h> 10#include <linux/types.h> 11 12#include "common.h" 13 14/* 15 * SCMI specification requires all parameters, message headers, return 16 * arguments or any protocol data to be expressed in little endian 17 * format only. 18 */ 19struct scmi_shared_mem { 20 __le32 reserved; 21 __le32 channel_status; 22#define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR BIT(1) 23#define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE BIT(0) 24 __le32 reserved1[2]; 25 __le32 flags; 26#define SCMI_SHMEM_FLAG_INTR_ENABLED BIT(0) 27 __le32 length; 28 __le32 msg_header; 29 u8 msg_payload[]; 30}; 31 32void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem, 33 struct scmi_xfer *xfer) 34{ 35 /* 36 * Ideally channel must be free by now unless OS timeout last 37 * request and platform continued to process the same, wait 38 * until it releases the shared memory, otherwise we may endup 39 * overwriting its response with new message payload or vice-versa 40 */ 41 spin_until_cond(ioread32(&shmem->channel_status) & 42 SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); 43 /* Mark channel busy + clear error */ 44 iowrite32(0x0, &shmem->channel_status); 45 iowrite32(xfer->hdr.poll_completion ? 0 : SCMI_SHMEM_FLAG_INTR_ENABLED, 46 &shmem->flags); 47 iowrite32(sizeof(shmem->msg_header) + xfer->tx.len, &shmem->length); 48 iowrite32(pack_scmi_header(&xfer->hdr), &shmem->msg_header); 49 if (xfer->tx.buf) 50 memcpy_toio(shmem->msg_payload, xfer->tx.buf, xfer->tx.len); 51} 52 53u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem) 54{ 55 return ioread32(&shmem->msg_header); 56} 57 58void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem, 59 struct scmi_xfer *xfer) 60{ 61 xfer->hdr.status = ioread32(shmem->msg_payload); 62 /* Skip the length of header and status in shmem area i.e 8 bytes */ 63 xfer->rx.len = min_t(size_t, xfer->rx.len, 64 ioread32(&shmem->length) - 8); 65 66 /* Take a copy to the rx buffer.. */ 67 memcpy_fromio(xfer->rx.buf, shmem->msg_payload + 4, xfer->rx.len); 68} 69 70void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem, 71 size_t max_len, struct scmi_xfer *xfer) 72{ 73 /* Skip only the length of header in shmem area i.e 4 bytes */ 74 xfer->rx.len = min_t(size_t, max_len, ioread32(&shmem->length) - 4); 75 76 /* Take a copy to the rx buffer.. */ 77 memcpy_fromio(xfer->rx.buf, shmem->msg_payload, xfer->rx.len); 78} 79 80void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem) 81{ 82 iowrite32(SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE, &shmem->channel_status); 83} 84 85bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, 86 struct scmi_xfer *xfer) 87{ 88 u16 xfer_id; 89 90 xfer_id = MSG_XTRACT_TOKEN(ioread32(&shmem->msg_header)); 91 92 if (xfer->hdr.seq != xfer_id) 93 return false; 94 95 return ioread32(&shmem->channel_status) & 96 (SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR | 97 SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); 98}