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/ktime.h> |
9 | #include <linux/io.h> |
10 | #include <linux/processor.h> |
11 | #include <linux/types.h> |
12 | |
13 | #include <linux/bug.h> |
14 | |
15 | #include "common.h" |
16 | |
17 | /* |
18 | * SCMI specification requires all parameters, message headers, return |
19 | * arguments or any protocol data to be expressed in little endian |
20 | * format only. |
21 | */ |
22 | struct scmi_shared_mem { |
23 | __le32 reserved; |
24 | __le32 channel_status; |
25 | #define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR BIT(1) |
26 | #define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE BIT(0) |
27 | __le32 reserved1[2]; |
28 | __le32 flags; |
29 | #define SCMI_SHMEM_FLAG_INTR_ENABLED BIT(0) |
30 | __le32 length; |
31 | __le32 ; |
32 | u8 msg_payload[]; |
33 | }; |
34 | |
35 | void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem, |
36 | struct scmi_xfer *xfer, struct scmi_chan_info *cinfo) |
37 | { |
38 | ktime_t stop; |
39 | |
40 | /* |
41 | * Ideally channel must be free by now unless OS timeout last |
42 | * request and platform continued to process the same, wait |
43 | * until it releases the shared memory, otherwise we may endup |
44 | * overwriting its response with new message payload or vice-versa. |
45 | * Giving up anyway after twice the expected channel timeout so as |
46 | * not to bail-out on intermittent issues where the platform is |
47 | * occasionally a bit slower to answer. |
48 | * |
49 | * Note that after a timeout is detected we bail-out and carry on but |
50 | * the transport functionality is probably permanently compromised: |
51 | * this is just to ease debugging and avoid complete hangs on boot |
52 | * due to a misbehaving SCMI firmware. |
53 | */ |
54 | stop = ktime_add_ms(kt: ktime_get(), msec: 2 * cinfo->rx_timeout_ms); |
55 | spin_until_cond((ioread32(&shmem->channel_status) & |
56 | SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE) || |
57 | ktime_after(ktime_get(), stop)); |
58 | if (!(ioread32(&shmem->channel_status) & |
59 | SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE)) { |
60 | WARN_ON_ONCE(1); |
61 | dev_err(cinfo->dev, |
62 | "Timeout waiting for a free TX channel !\n" ); |
63 | return; |
64 | } |
65 | |
66 | /* Mark channel busy + clear error */ |
67 | iowrite32(0x0, &shmem->channel_status); |
68 | iowrite32(xfer->hdr.poll_completion ? 0 : SCMI_SHMEM_FLAG_INTR_ENABLED, |
69 | &shmem->flags); |
70 | iowrite32(sizeof(shmem->msg_header) + xfer->tx.len, &shmem->length); |
71 | iowrite32(pack_scmi_header(hdr: &xfer->hdr), &shmem->msg_header); |
72 | if (xfer->tx.buf) |
73 | memcpy_toio(shmem->msg_payload, xfer->tx.buf, xfer->tx.len); |
74 | } |
75 | |
76 | u32 (struct scmi_shared_mem __iomem *shmem) |
77 | { |
78 | return ioread32(&shmem->msg_header); |
79 | } |
80 | |
81 | void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem, |
82 | struct scmi_xfer *xfer) |
83 | { |
84 | size_t len = ioread32(&shmem->length); |
85 | |
86 | xfer->hdr.status = ioread32(shmem->msg_payload); |
87 | /* Skip the length of header and status in shmem area i.e 8 bytes */ |
88 | xfer->rx.len = min_t(size_t, xfer->rx.len, len > 8 ? len - 8 : 0); |
89 | |
90 | /* Take a copy to the rx buffer.. */ |
91 | memcpy_fromio(xfer->rx.buf, shmem->msg_payload + 4, xfer->rx.len); |
92 | } |
93 | |
94 | void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem, |
95 | size_t max_len, struct scmi_xfer *xfer) |
96 | { |
97 | size_t len = ioread32(&shmem->length); |
98 | |
99 | /* Skip only the length of header in shmem area i.e 4 bytes */ |
100 | xfer->rx.len = min_t(size_t, max_len, len > 4 ? len - 4 : 0); |
101 | |
102 | /* Take a copy to the rx buffer.. */ |
103 | memcpy_fromio(xfer->rx.buf, shmem->msg_payload, xfer->rx.len); |
104 | } |
105 | |
106 | void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem) |
107 | { |
108 | iowrite32(SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE, &shmem->channel_status); |
109 | } |
110 | |
111 | bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, |
112 | struct scmi_xfer *xfer) |
113 | { |
114 | u16 xfer_id; |
115 | |
116 | xfer_id = MSG_XTRACT_TOKEN(ioread32(&shmem->msg_header)); |
117 | |
118 | if (xfer->hdr.seq != xfer_id) |
119 | return false; |
120 | |
121 | return ioread32(&shmem->channel_status) & |
122 | (SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR | |
123 | SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); |
124 | } |
125 | |
126 | bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem) |
127 | { |
128 | return (ioread32(&shmem->channel_status) & |
129 | SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); |
130 | } |
131 | |