Skip to content

Commit 2cd7f3d

Browse files
ffainellisudeep-holla
authored andcommitted
firmware: arm_scmi: Support 'reg-io-width' property for shared memory
Some shared memory areas might only support a certain access width, such as 32-bit, which memcpy_{from,to}_io() does not adhere to at least on ARM64 by making both 8-bit and 64-bit accesses to such memory. Update the shmem layer to support reading from and writing to such shared memory area using the specified I/O width in the Device Tree. The various transport layers making use of the shmem.c code are updated accordingly to pass the I/O accessors that they store. Signed-off-by: Florian Fainelli <[email protected]> Message-Id: <[email protected]> Signed-off-by: Sudeep Holla <[email protected]>
1 parent 14b2157 commit 2cd7f3d

File tree

5 files changed

+124
-21
lines changed

5 files changed

+124
-21
lines changed

drivers/firmware/arm_scmi/common.h

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,26 @@ enum scmi_bad_msg {
311311
MSG_MBOX_SPURIOUS = -5,
312312
};
313313

314+
/* Used for compactness and signature validation of the function pointers being
315+
* passed.
316+
*/
317+
typedef void (*shmem_copy_toio_t)(void __iomem *to, const void *from,
318+
size_t count);
319+
typedef void (*shmem_copy_fromio_t)(void *to, const void __iomem *from,
320+
size_t count);
321+
322+
/**
323+
* struct scmi_shmem_io_ops - I/O operations to read from/write to
324+
* Shared Memory
325+
*
326+
* @toio: Copy data to the shared memory area
327+
* @fromio: Copy data from the shared memory area
328+
*/
329+
struct scmi_shmem_io_ops {
330+
shmem_copy_fromio_t fromio;
331+
shmem_copy_toio_t toio;
332+
};
333+
314334
/* shmem related declarations */
315335
struct scmi_shared_mem;
316336

@@ -331,21 +351,25 @@ struct scmi_shared_mem;
331351
struct scmi_shared_mem_operations {
332352
void (*tx_prepare)(struct scmi_shared_mem __iomem *shmem,
333353
struct scmi_xfer *xfer,
334-
struct scmi_chan_info *cinfo);
354+
struct scmi_chan_info *cinfo,
355+
shmem_copy_toio_t toio);
335356
u32 (*read_header)(struct scmi_shared_mem __iomem *shmem);
336357

337358
void (*fetch_response)(struct scmi_shared_mem __iomem *shmem,
338-
struct scmi_xfer *xfer);
359+
struct scmi_xfer *xfer,
360+
shmem_copy_fromio_t fromio);
339361
void (*fetch_notification)(struct scmi_shared_mem __iomem *shmem,
340-
size_t max_len, struct scmi_xfer *xfer);
362+
size_t max_len, struct scmi_xfer *xfer,
363+
shmem_copy_fromio_t fromio);
341364
void (*clear_channel)(struct scmi_shared_mem __iomem *shmem);
342365
bool (*poll_done)(struct scmi_shared_mem __iomem *shmem,
343366
struct scmi_xfer *xfer);
344367
bool (*channel_free)(struct scmi_shared_mem __iomem *shmem);
345368
bool (*channel_intr_enabled)(struct scmi_shared_mem __iomem *shmem);
346369
void __iomem *(*setup_iomap)(struct scmi_chan_info *cinfo,
347370
struct device *dev,
348-
bool tx, struct resource *res);
371+
bool tx, struct resource *res,
372+
struct scmi_shmem_io_ops **ops);
349373
};
350374

351375
const struct scmi_shared_mem_operations *scmi_shared_mem_operations_get(void);

drivers/firmware/arm_scmi/shmem.c

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,59 @@ struct scmi_shared_mem {
3434
u8 msg_payload[];
3535
};
3636

37+
static inline void shmem_memcpy_fromio32(void *to,
38+
const void __iomem *from,
39+
size_t count)
40+
{
41+
WARN_ON(!IS_ALIGNED((unsigned long)from, 4) ||
42+
!IS_ALIGNED((unsigned long)to, 4) ||
43+
count % 4);
44+
45+
__ioread32_copy(to, from, count / 4);
46+
}
47+
48+
static inline void shmem_memcpy_toio32(void __iomem *to,
49+
const void *from,
50+
size_t count)
51+
{
52+
WARN_ON(!IS_ALIGNED((unsigned long)to, 4) ||
53+
!IS_ALIGNED((unsigned long)from, 4) ||
54+
count % 4);
55+
56+
__iowrite32_copy(to, from, count / 4);
57+
}
58+
59+
static struct scmi_shmem_io_ops shmem_io_ops32 = {
60+
.fromio = shmem_memcpy_fromio32,
61+
.toio = shmem_memcpy_toio32,
62+
};
63+
64+
/* Wrappers are needed for proper memcpy_{from,to}_io expansion by the
65+
* pre-processor.
66+
*/
67+
static inline void shmem_memcpy_fromio(void *to,
68+
const void __iomem *from,
69+
size_t count)
70+
{
71+
memcpy_fromio(to, from, count);
72+
}
73+
74+
static inline void shmem_memcpy_toio(void __iomem *to,
75+
const void *from,
76+
size_t count)
77+
{
78+
memcpy_toio(to, from, count);
79+
}
80+
81+
static struct scmi_shmem_io_ops shmem_io_ops_default = {
82+
.fromio = shmem_memcpy_fromio,
83+
.toio = shmem_memcpy_toio,
84+
};
85+
3786
static void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem,
3887
struct scmi_xfer *xfer,
39-
struct scmi_chan_info *cinfo)
88+
struct scmi_chan_info *cinfo,
89+
shmem_copy_toio_t copy_toio)
4090
{
4191
ktime_t stop;
4292

@@ -73,7 +123,7 @@ static void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem,
73123
iowrite32(sizeof(shmem->msg_header) + xfer->tx.len, &shmem->length);
74124
iowrite32(pack_scmi_header(&xfer->hdr), &shmem->msg_header);
75125
if (xfer->tx.buf)
76-
memcpy_toio(shmem->msg_payload, xfer->tx.buf, xfer->tx.len);
126+
copy_toio(shmem->msg_payload, xfer->tx.buf, xfer->tx.len);
77127
}
78128

79129
static u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem)
@@ -82,7 +132,8 @@ static u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem)
82132
}
83133

84134
static void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem,
85-
struct scmi_xfer *xfer)
135+
struct scmi_xfer *xfer,
136+
shmem_copy_fromio_t copy_fromio)
86137
{
87138
size_t len = ioread32(&shmem->length);
88139

@@ -91,19 +142,20 @@ static void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem,
91142
xfer->rx.len = min_t(size_t, xfer->rx.len, len > 8 ? len - 8 : 0);
92143

93144
/* Take a copy to the rx buffer.. */
94-
memcpy_fromio(xfer->rx.buf, shmem->msg_payload + 4, xfer->rx.len);
145+
copy_fromio(xfer->rx.buf, shmem->msg_payload + 4, xfer->rx.len);
95146
}
96147

97148
static void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem,
98-
size_t max_len, struct scmi_xfer *xfer)
149+
size_t max_len, struct scmi_xfer *xfer,
150+
shmem_copy_fromio_t copy_fromio)
99151
{
100152
size_t len = ioread32(&shmem->length);
101153

102154
/* Skip only the length of header in shmem area i.e 4 bytes */
103155
xfer->rx.len = min_t(size_t, max_len, len > 4 ? len - 4 : 0);
104156

105157
/* Take a copy to the rx buffer.. */
106-
memcpy_fromio(xfer->rx.buf, shmem->msg_payload, xfer->rx.len);
158+
copy_fromio(xfer->rx.buf, shmem->msg_payload, xfer->rx.len);
107159
}
108160

109161
static void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem)
@@ -139,7 +191,8 @@ static bool shmem_channel_intr_enabled(struct scmi_shared_mem __iomem *shmem)
139191

140192
static void __iomem *shmem_setup_iomap(struct scmi_chan_info *cinfo,
141193
struct device *dev, bool tx,
142-
struct resource *res)
194+
struct resource *res,
195+
struct scmi_shmem_io_ops **ops)
143196
{
144197
struct device_node *shmem __free(device_node);
145198
const char *desc = tx ? "Tx" : "Rx";
@@ -148,6 +201,7 @@ static void __iomem *shmem_setup_iomap(struct scmi_chan_info *cinfo,
148201
struct resource lres = {};
149202
resource_size_t size;
150203
void __iomem *addr;
204+
u32 reg_io_width;
151205

152206
shmem = of_parse_phandle(cdev->of_node, "shmem", idx);
153207
if (!shmem)
@@ -173,6 +227,16 @@ static void __iomem *shmem_setup_iomap(struct scmi_chan_info *cinfo,
173227
return IOMEM_ERR_PTR(-EADDRNOTAVAIL);
174228
}
175229

230+
of_property_read_u32(shmem, "reg-io-width", &reg_io_width);
231+
switch (reg_io_width) {
232+
case 4:
233+
*ops = &shmem_io_ops32;
234+
break;
235+
default:
236+
*ops = &shmem_io_ops_default;
237+
break;
238+
}
239+
176240
return addr;
177241
}
178242

drivers/firmware/arm_scmi/transports/mailbox.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
* @cinfo: SCMI channel info
2727
* @shmem: Transmit/Receive shared memory area
2828
* @chan_lock: Lock that prevents multiple xfers from being queued
29+
* @io_ops: Transport specific I/O operations
2930
*/
3031
struct scmi_mailbox {
3132
struct mbox_client cl;
@@ -35,6 +36,7 @@ struct scmi_mailbox {
3536
struct scmi_chan_info *cinfo;
3637
struct scmi_shared_mem __iomem *shmem;
3738
struct mutex chan_lock;
39+
struct scmi_shmem_io_ops *io_ops;
3840
};
3941

4042
#define client_to_scmi_mailbox(c) container_of(c, struct scmi_mailbox, cl)
@@ -45,7 +47,8 @@ static void tx_prepare(struct mbox_client *cl, void *m)
4547
{
4648
struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl);
4749

48-
core->shmem->tx_prepare(smbox->shmem, m, smbox->cinfo);
50+
core->shmem->tx_prepare(smbox->shmem, m, smbox->cinfo,
51+
smbox->io_ops->toio);
4952
}
5053

5154
static void rx_callback(struct mbox_client *cl, void *m)
@@ -197,7 +200,8 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
197200
if (!smbox)
198201
return -ENOMEM;
199202

200-
smbox->shmem = core->shmem->setup_iomap(cinfo, dev, tx, NULL);
203+
smbox->shmem = core->shmem->setup_iomap(cinfo, dev, tx, NULL,
204+
&smbox->io_ops);
201205
if (IS_ERR(smbox->shmem))
202206
return PTR_ERR(smbox->shmem);
203207

@@ -305,15 +309,16 @@ static void mailbox_fetch_response(struct scmi_chan_info *cinfo,
305309
{
306310
struct scmi_mailbox *smbox = cinfo->transport_info;
307311

308-
core->shmem->fetch_response(smbox->shmem, xfer);
312+
core->shmem->fetch_response(smbox->shmem, xfer, smbox->io_ops->fromio);
309313
}
310314

311315
static void mailbox_fetch_notification(struct scmi_chan_info *cinfo,
312316
size_t max_len, struct scmi_xfer *xfer)
313317
{
314318
struct scmi_mailbox *smbox = cinfo->transport_info;
315319

316-
core->shmem->fetch_notification(smbox->shmem, max_len, xfer);
320+
core->shmem->fetch_notification(smbox->shmem, max_len, xfer,
321+
smbox->io_ops->fromio);
317322
}
318323

319324
static void mailbox_clear_channel(struct scmi_chan_info *cinfo)

drivers/firmware/arm_scmi/transports/optee.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ enum scmi_optee_pta_cmd {
114114
* @req.shmem: Virtual base address of the shared memory
115115
* @req.msg: Shared memory protocol handle for SCMI request and
116116
* synchronous response
117+
* @io_ops: Transport specific I/O operations
117118
* @tee_shm: TEE shared memory handle @req or NULL if using IOMEM shmem
118119
* @link: Reference in agent's channel list
119120
*/
@@ -128,6 +129,7 @@ struct scmi_optee_channel {
128129
struct scmi_shared_mem __iomem *shmem;
129130
struct scmi_msg_payld *msg;
130131
} req;
132+
struct scmi_shmem_io_ops *io_ops;
131133
struct tee_shm *tee_shm;
132134
struct list_head link;
133135
};
@@ -350,7 +352,8 @@ static int setup_dynamic_shmem(struct device *dev, struct scmi_optee_channel *ch
350352
static int setup_static_shmem(struct device *dev, struct scmi_chan_info *cinfo,
351353
struct scmi_optee_channel *channel)
352354
{
353-
channel->req.shmem = core->shmem->setup_iomap(cinfo, dev, true, NULL);
355+
channel->req.shmem = core->shmem->setup_iomap(cinfo, dev, true, NULL,
356+
&channel->io_ops);
354357
if (IS_ERR(channel->req.shmem))
355358
return PTR_ERR(channel->req.shmem);
356359

@@ -465,7 +468,8 @@ static int scmi_optee_send_message(struct scmi_chan_info *cinfo,
465468
ret = invoke_process_msg_channel(channel,
466469
core->msg->command_size(xfer));
467470
} else {
468-
core->shmem->tx_prepare(channel->req.shmem, xfer, cinfo);
471+
core->shmem->tx_prepare(channel->req.shmem, xfer, cinfo,
472+
channel->io_ops->toio);
469473
ret = invoke_process_smt_channel(channel);
470474
}
471475

@@ -484,7 +488,8 @@ static void scmi_optee_fetch_response(struct scmi_chan_info *cinfo,
484488
core->msg->fetch_response(channel->req.msg,
485489
channel->rx_len, xfer);
486490
else
487-
core->shmem->fetch_response(channel->req.shmem, xfer);
491+
core->shmem->fetch_response(channel->req.shmem, xfer,
492+
channel->io_ops->fromio);
488493
}
489494

490495
static void scmi_optee_mark_txdone(struct scmi_chan_info *cinfo, int ret,

drivers/firmware/arm_scmi/transports/smc.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
* @irq: An optional IRQ for completion
4646
* @cinfo: SCMI channel info
4747
* @shmem: Transmit/Receive shared memory area
48+
* @io_ops: Transport specific I/O operations
4849
* @shmem_lock: Lock to protect access to Tx/Rx shared memory area.
4950
* Used when NOT operating in atomic mode.
5051
* @inflight: Atomic flag to protect access to Tx/Rx shared memory area.
@@ -60,6 +61,7 @@ struct scmi_smc {
6061
int irq;
6162
struct scmi_chan_info *cinfo;
6263
struct scmi_shared_mem __iomem *shmem;
64+
struct scmi_shmem_io_ops *io_ops;
6365
/* Protect access to shmem area */
6466
struct mutex shmem_lock;
6567
#define INFLIGHT_NONE MSG_TOKEN_MAX
@@ -144,7 +146,8 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
144146
if (!scmi_info)
145147
return -ENOMEM;
146148

147-
scmi_info->shmem = core->shmem->setup_iomap(cinfo, dev, tx, &res);
149+
scmi_info->shmem = core->shmem->setup_iomap(cinfo, dev, tx, &res,
150+
&scmi_info->io_ops);
148151
if (IS_ERR(scmi_info->shmem))
149152
return PTR_ERR(scmi_info->shmem);
150153

@@ -229,7 +232,8 @@ static int smc_send_message(struct scmi_chan_info *cinfo,
229232
*/
230233
smc_channel_lock_acquire(scmi_info, xfer);
231234

232-
core->shmem->tx_prepare(scmi_info->shmem, xfer, cinfo);
235+
core->shmem->tx_prepare(scmi_info->shmem, xfer, cinfo,
236+
scmi_info->io_ops->toio);
233237

234238
if (scmi_info->cap_id != ULONG_MAX)
235239
arm_smccc_1_1_invoke(scmi_info->func_id, scmi_info->cap_id, 0,
@@ -253,7 +257,8 @@ static void smc_fetch_response(struct scmi_chan_info *cinfo,
253257
{
254258
struct scmi_smc *scmi_info = cinfo->transport_info;
255259

256-
core->shmem->fetch_response(scmi_info->shmem, xfer);
260+
core->shmem->fetch_response(scmi_info->shmem, xfer,
261+
scmi_info->io_ops->fromio);
257262
}
258263

259264
static void smc_mark_txdone(struct scmi_chan_info *cinfo, int ret,

0 commit comments

Comments
 (0)