History

firmware: arm_scmi: Add virtio transport

This transport enables communications with an SCMI platform through virtio; the SCMI platform will be represented by a virtio device. Implement an SCMI virtio driver according to the virtio SCMI device spec [1]. Virtio device id 32 has been reserved for the SCMI device [2]. The virtio transport has one Tx channel (virtio cmdq, A2P channel) and at most one Rx channel (virtio eventq, P2A channel). The following feature bit defined in [1] is not implemented: VIRTIO_SCMI_F_SHARED_MEMORY. The number of messages which can be pending simultaneously is restricted according to the virtqueue capacity negotiated at probing time. As soon as Rx channel message buffers are allocated or have been read out by the arm-scmi driver, feed them back to the virtio device. Since some virtio devices may not have the short response time exhibited by SCMI platforms using other transports, set a generous response timeout. SCMI polling mode is not supported by this virtio transport since deemed meaningless: polling mode operation is offered by the SCMI core to those transports that could not provide a completion interrupt on the TX path, which is never the case for virtio whose core callbacks can easily call into core scmi_rx_callback upon messages reception. [1] https://github.com/oasis-tcs/virtio-spec/blob/master/virtio-scmi.tex [2] https://www.oasis-open.org/committees/ballot.php?id=3496

Igor Skalkin committed 5 years ago

Commit 46abe131 parent 13fba878 files · +535 −0Browse files

Unified · Split

8 files
  1. MAINTAINERS +1 −0
  2. drivers/firmware/arm_scmi/Kconfig +11 −0
  3. drivers/firmware/arm_scmi/Makefile +1 −0
  4. drivers/firmware/arm_scmi/common.h +3 −0
  5. drivers/firmware/arm_scmi/driver.c +3 −0
  6. drivers/firmware/arm_scmi/virtio.c +491 −0
  7. include/uapi/linux/virtio_ids.h +1 −0
  8. include/uapi/linux/virtio_scmi.h +24 −0
MAINTAINERS+1−0
@@ -17940,6 +17940,7 @@ F: drivers/regulator/scmi-regulator.c · 17939 unmodified lines
17940F: drivers/reset/reset-scmi.c17940F: drivers/reset/reset-scmi.c
17941F: include/linux/sc[mp]i_protocol.h17941F: include/linux/sc[mp]i_protocol.h
17942F: include/trace/events/scmi.h17942F: include/trace/events/scmi.h
17943F: include/uapi/linux/virtio_scmi.h
17943 17944
17944SYSTEM RESET/SHUTDOWN DRIVERS17945SYSTEM RESET/SHUTDOWN DRIVERS
17945M: Sebastian Reichel <sre@kernel.org>17946M: Sebastian Reichel <sre@kernel.org>
drivers/firmware/arm_scmi/Kconfig+11−0
@@ -66,6 +66,17 @@ config ARM_SCMI_TRANSPORT_SMC · 65 unmodified lines
66 If you want the ARM SCMI PROTOCOL stack to include support for a66 If you want the ARM SCMI PROTOCOL stack to include support for a
67 transport based on SMC, answer Y.67 transport based on SMC, answer Y.
68 68
69config ARM_SCMI_TRANSPORT_VIRTIO
70 bool "SCMI transport based on VirtIO"
71 depends on VIRTIO
72 select ARM_SCMI_HAVE_TRANSPORT
73 select ARM_SCMI_HAVE_MSG
74 help
75 This enables the virtio based transport for SCMI.
76
77 If you want the ARM SCMI PROTOCOL stack to include support for a
78 transport based on VirtIO, answer Y.
79
69endif #ARM_SCMI_PROTOCOL80endif #ARM_SCMI_PROTOCOL
70 81
71config ARM_SCMI_POWER_DOMAIN82config ARM_SCMI_POWER_DOMAIN
drivers/firmware/arm_scmi/Makefile+1−0
@@ -5,6 +5,7 @@ scmi-transport-$(CONFIG_ARM_SCMI_HAVE_SHMEM) = shmem.o · 4 unmodified lines
5scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_MAILBOX) += mailbox.o5scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_MAILBOX) += mailbox.o
6scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_SMC) += smc.o6scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_SMC) += smc.o
7scmi-transport-$(CONFIG_ARM_SCMI_HAVE_MSG) += msg.o7scmi-transport-$(CONFIG_ARM_SCMI_HAVE_MSG) += msg.o
8scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO) += virtio.o
8scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.o voltage.o9scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.o voltage.o
9scmi-module-objs := $(scmi-bus-y) $(scmi-driver-y) $(scmi-protocols-y) \10scmi-module-objs := $(scmi-bus-y) $(scmi-driver-y) $(scmi-protocols-y) \
10 $(scmi-transport-y)11 $(scmi-transport-y)
drivers/firmware/arm_scmi/common.h+3−0
@@ -418,6 +418,9 @@ extern const struct scmi_desc scmi_mailbox_desc; · 417 unmodified lines
418#ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC418#ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC
419extern const struct scmi_desc scmi_smc_desc;419extern const struct scmi_desc scmi_smc_desc;
420#endif420#endif
421#ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO
422extern const struct scmi_desc scmi_virtio_desc;
423#endif
421 424
422void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv);425void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv);
423void scmi_free_channel(struct scmi_chan_info *cinfo, struct idr *idr, int id);426void scmi_free_channel(struct scmi_chan_info *cinfo, struct idr *idr, int id);
drivers/firmware/arm_scmi/driver.c+3−0
@@ -1983,6 +1983,9 @@ static const struct of_device_id scmi_of_match[] = { · 1982 unmodified lines
1983#endif1983#endif
1984#ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC1984#ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC
1985 { .compatible = "arm,scmi-smc", .data = &scmi_smc_desc},1985 { .compatible = "arm,scmi-smc", .data = &scmi_smc_desc},
1986#endif
1987#ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO
1988 { .compatible = "arm,scmi-virtio", .data = &scmi_virtio_desc},
1986#endif1989#endif
1987 { /* Sentinel */ },1990 { /* Sentinel */ },
1988};1991};
drivers/firmware/arm_scmi/virtio.c+491−0
@@ -0,0 +1,491 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Virtio Transport driver for Arm System Control and Management Interface
4 * (SCMI).
5 *
6 * Copyright (C) 2020-2021 OpenSynergy.
7 * Copyright (C) 2021 ARM Ltd.
8 */
9
10/**
11 * DOC: Theory of Operation
12 *
13 * The scmi-virtio transport implements a driver for the virtio SCMI device.
14 *
15 * There is one Tx channel (virtio cmdq, A2P channel) and at most one Rx
16 * channel (virtio eventq, P2A channel). Each channel is implemented through a
17 * virtqueue. Access to each virtqueue is protected by spinlocks.
18 */
19
20#include <linux/errno.h>
21#include <linux/slab.h>
22#include <linux/virtio.h>
23#include <linux/virtio_config.h>
24
25#include <uapi/linux/virtio_ids.h>
26#include <uapi/linux/virtio_scmi.h>
27
28#include "common.h"
29
30#define VIRTIO_SCMI_MAX_MSG_SIZE 128 /* Value may be increased. */
31#define VIRTIO_SCMI_MAX_PDU_SIZE \
32 (VIRTIO_SCMI_MAX_MSG_SIZE + SCMI_MSG_MAX_PROT_OVERHEAD)
33#define DESCRIPTORS_PER_TX_MSG 2
34
35/**
36 * struct scmi_vio_channel - Transport channel information
37 *
38 * @vqueue: Associated virtqueue
39 * @cinfo: SCMI Tx or Rx channel
40 * @free_list: List of unused scmi_vio_msg, maintained for Tx channels only
41 * @is_rx: Whether channel is an Rx channel
42 * @ready: Whether transport user is ready to hear about channel
43 * @max_msg: Maximum number of pending messages for this channel.
44 * @lock: Protects access to all members except ready.
45 * @ready_lock: Protects access to ready. If required, it must be taken before
46 * lock.
47 */
48struct scmi_vio_channel {
49 struct virtqueue *vqueue;
50 struct scmi_chan_info *cinfo;
51 struct list_head free_list;
52 bool is_rx;
53 bool ready;
54 unsigned int max_msg;
55 /* lock to protect access to all members except ready. */
56 spinlock_t lock;
57 /* lock to rotects access to ready flag. */
58 spinlock_t ready_lock;
59};
60
61/**
62 * struct scmi_vio_msg - Transport PDU information
63 *
64 * @request: SDU used for commands
65 * @input: SDU used for (delayed) responses and notifications
66 * @list: List which scmi_vio_msg may be part of
67 * @rx_len: Input SDU size in bytes, once input has been received
68 */
69struct scmi_vio_msg {
70 struct scmi_msg_payld *request;
71 struct scmi_msg_payld *input;
72 struct list_head list;
73 unsigned int rx_len;
74};
75
76/* Only one SCMI VirtIO device can possibly exist */
77static struct virtio_device *scmi_vdev;
78
79static bool scmi_vio_have_vq_rx(struct virtio_device *vdev)
80{
81 return virtio_has_feature(vdev, VIRTIO_SCMI_F_P2A_CHANNELS);
82}
83
84static int scmi_vio_feed_vq_rx(struct scmi_vio_channel *vioch,
85 struct scmi_vio_msg *msg)
86{
87 struct scatterlist sg_in;
88 int rc;
89 unsigned long flags;
90
91 sg_init_one(&sg_in, msg->input, VIRTIO_SCMI_MAX_PDU_SIZE);
92
93 spin_lock_irqsave(&vioch->lock, flags);
94
95 rc = virtqueue_add_inbuf(vioch->vqueue, &sg_in, 1, msg, GFP_ATOMIC);
96 if (rc)
97 dev_err_once(vioch->cinfo->dev,
98 "failed to add to virtqueue (%d)\n", rc);
99 else
100 virtqueue_kick(vioch->vqueue);
101
102 spin_unlock_irqrestore(&vioch->lock, flags);
103
104 return rc;
105}
106
107static void scmi_finalize_message(struct scmi_vio_channel *vioch,
108 struct scmi_vio_msg *msg)
109{
110 if (vioch->is_rx) {
111 scmi_vio_feed_vq_rx(vioch, msg);
112 } else {
113 unsigned long flags;
114
115 spin_lock_irqsave(&vioch->lock, flags);
116 list_add(&msg->list, &vioch->free_list);
117 spin_unlock_irqrestore(&vioch->lock, flags);
118 }
119}
120
121static void scmi_vio_complete_cb(struct virtqueue *vqueue)
122{
123 unsigned long ready_flags;
124 unsigned long flags;
125 unsigned int length;
126 struct scmi_vio_channel *vioch;
127 struct scmi_vio_msg *msg;
128 bool cb_enabled = true;
129
130 if (WARN_ON_ONCE(!vqueue->vdev->priv))
131 return;
132 vioch = &((struct scmi_vio_channel *)vqueue->vdev->priv)[vqueue->index];
133
134 for (;;) {
135 spin_lock_irqsave(&vioch->ready_lock, ready_flags);
136
137 if (!vioch->ready) {
138 if (!cb_enabled)
139 (void)virtqueue_enable_cb(vqueue);
140 goto unlock_ready_out;
141 }
142
143 spin_lock_irqsave(&vioch->lock, flags);
144 if (cb_enabled) {
145 virtqueue_disable_cb(vqueue);
146 cb_enabled = false;
147 }
148 msg = virtqueue_get_buf(vqueue, &length);
149 if (!msg) {
150 if (virtqueue_enable_cb(vqueue))
151 goto unlock_out;
152 cb_enabled = true;
153 }
154 spin_unlock_irqrestore(&vioch->lock, flags);
155
156 if (msg) {
157 msg->rx_len = length;
158 scmi_rx_callback(vioch->cinfo,
159 msg_read_header(msg->input), msg);
160
161 scmi_finalize_message(vioch, msg);
162 }
163
164 spin_unlock_irqrestore(&vioch->ready_lock, ready_flags);
165 }
166
167unlock_out:
168 spin_unlock_irqrestore(&vioch->lock, flags);
169unlock_ready_out:
170 spin_unlock_irqrestore(&vioch->ready_lock, ready_flags);
171}
172
173static const char *const scmi_vio_vqueue_names[] = { "tx", "rx" };
174
175static vq_callback_t *scmi_vio_complete_callbacks[] = {
176 scmi_vio_complete_cb,
177 scmi_vio_complete_cb
178};
179
180static unsigned int virtio_get_max_msg(struct scmi_chan_info *base_cinfo)
181{
182 struct scmi_vio_channel *vioch = base_cinfo->transport_info;
183
184 return vioch->max_msg;
185}
186
187static int virtio_link_supplier(struct device *dev)
188{
189 if (!scmi_vdev) {
190 dev_notice_once(dev,
191 "Deferring probe after not finding a bound scmi-virtio device\n");
192 return -EPROBE_DEFER;
193 }
194
195 if (!device_link_add(dev, &scmi_vdev->dev,
196 DL_FLAG_AUTOREMOVE_CONSUMER)) {
197 dev_err(dev, "Adding link to supplier virtio device failed\n");
198 return -ECANCELED;
199 }
200
201 return 0;
202}
203
204static bool virtio_chan_available(struct device *dev, int idx)
205{
206 struct scmi_vio_channel *channels, *vioch = NULL;
207
208 if (WARN_ON_ONCE(!scmi_vdev))
209 return false;
210
211 channels = (struct scmi_vio_channel *)scmi_vdev->priv;
212
213 switch (idx) {
214 case VIRTIO_SCMI_VQ_TX:
215 vioch = &channels[VIRTIO_SCMI_VQ_TX];
216 break;
217 case VIRTIO_SCMI_VQ_RX:
218 if (scmi_vio_have_vq_rx(scmi_vdev))
219 vioch = &channels[VIRTIO_SCMI_VQ_RX];
220 break;
221 default:
222 return false;
223 }
224
225 return vioch && !vioch->cinfo ? true : false;
226}
227
228static int virtio_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
229 bool tx)
230{
231 unsigned long flags;
232 struct scmi_vio_channel *vioch;
233 int index = tx ? VIRTIO_SCMI_VQ_TX : VIRTIO_SCMI_VQ_RX;
234 int i;
235
236 if (!scmi_vdev)
237 return -EPROBE_DEFER;
238
239 vioch = &((struct scmi_vio_channel *)scmi_vdev->priv)[index];
240
241 for (i = 0; i < vioch->max_msg; i++) {
242 struct scmi_vio_msg *msg;
243
244 msg = devm_kzalloc(cinfo->dev, sizeof(*msg), GFP_KERNEL);
245 if (!msg)
246 return -ENOMEM;
247
248 if (tx) {
249 msg->request = devm_kzalloc(cinfo->dev,
250 VIRTIO_SCMI_MAX_PDU_SIZE,
251 GFP_KERNEL);
252 if (!msg->request)
253 return -ENOMEM;
254 }
255
256 msg->input = devm_kzalloc(cinfo->dev, VIRTIO_SCMI_MAX_PDU_SIZE,
257 GFP_KERNEL);
258 if (!msg->input)
259 return -ENOMEM;
260
261 if (tx) {
262 spin_lock_irqsave(&vioch->lock, flags);
263 list_add_tail(&msg->list, &vioch->free_list);
264 spin_unlock_irqrestore(&vioch->lock, flags);
265 } else {
266 scmi_vio_feed_vq_rx(vioch, msg);
267 }
268 }
269
270 spin_lock_irqsave(&vioch->lock, flags);
271 cinfo->transport_info = vioch;
272 /* Indirectly setting channel not available any more */
273 vioch->cinfo = cinfo;
274 spin_unlock_irqrestore(&vioch->lock, flags);
275
276 spin_lock_irqsave(&vioch->ready_lock, flags);
277 vioch->ready = true;
278 spin_unlock_irqrestore(&vioch->ready_lock, flags);
279
280 return 0;
281}
282
283static int virtio_chan_free(int id, void *p, void *data)
284{
285 unsigned long flags;
286 struct scmi_chan_info *cinfo = p;
287 struct scmi_vio_channel *vioch = cinfo->transport_info;
288
289 spin_lock_irqsave(&vioch->ready_lock, flags);
290 vioch->ready = false;
291 spin_unlock_irqrestore(&vioch->ready_lock, flags);
292
293 scmi_free_channel(cinfo, data, id);
294
295 spin_lock_irqsave(&vioch->lock, flags);
296 vioch->cinfo = NULL;
297 spin_unlock_irqrestore(&vioch->lock, flags);
298
299 return 0;
300}
301
302static int virtio_send_message(struct scmi_chan_info *cinfo,
303 struct scmi_xfer *xfer)
304{
305 struct scmi_vio_channel *vioch = cinfo->transport_info;
306 struct scatterlist sg_out;
307 struct scatterlist sg_in;
308 struct scatterlist *sgs[DESCRIPTORS_PER_TX_MSG] = { &sg_out, &sg_in };
309 unsigned long flags;
310 int rc;
311 struct scmi_vio_msg *msg;
312
313 spin_lock_irqsave(&vioch->lock, flags);
314
315 if (list_empty(&vioch->free_list)) {
316 spin_unlock_irqrestore(&vioch->lock, flags);
317 return -EBUSY;
318 }
319
320 msg = list_first_entry(&vioch->free_list, typeof(*msg), list);
321 list_del(&msg->list);
322
323 msg_tx_prepare(msg->request, xfer);
324
325 sg_init_one(&sg_out, msg->request, msg_command_size(xfer));
326 sg_init_one(&sg_in, msg->input, msg_response_size(xfer));
327
328 rc = virtqueue_add_sgs(vioch->vqueue, sgs, 1, 1, msg, GFP_ATOMIC);
329 if (rc) {
330 list_add(&msg->list, &vioch->free_list);
331 dev_err_once(vioch->cinfo->dev,
332 "%s() failed to add to virtqueue (%d)\n", __func__,
333 rc);
334 } else {
335 virtqueue_kick(vioch->vqueue);
336 }
337
338 spin_unlock_irqrestore(&vioch->lock, flags);
339
340 return rc;
341}
342
343static void virtio_fetch_response(struct scmi_chan_info *cinfo,
344 struct scmi_xfer *xfer)
345{
346 struct scmi_vio_msg *msg = xfer->priv;
347
348 if (msg) {
349 msg_fetch_response(msg->input, msg->rx_len, xfer);
350 xfer->priv = NULL;
351 }
352}
353
354static void virtio_fetch_notification(struct scmi_chan_info *cinfo,
355 size_t max_len, struct scmi_xfer *xfer)
356{
357 struct scmi_vio_msg *msg = xfer->priv;
358
359 if (msg) {
360 msg_fetch_notification(msg->input, msg->rx_len, max_len, xfer);
361 xfer->priv = NULL;
362 }
363}
364
365static const struct scmi_transport_ops scmi_virtio_ops = {
366 .link_supplier = virtio_link_supplier,
367 .chan_available = virtio_chan_available,
368 .chan_setup = virtio_chan_setup,
369 .chan_free = virtio_chan_free,
370 .get_max_msg = virtio_get_max_msg,
371 .send_message = virtio_send_message,
372 .fetch_response = virtio_fetch_response,
373 .fetch_notification = virtio_fetch_notification,
374};
375
376static int scmi_vio_probe(struct virtio_device *vdev)
377{
378 struct device *dev = &vdev->dev;
379 struct scmi_vio_channel *channels;
380 bool have_vq_rx;
381 int vq_cnt;
382 int i;
383 int ret;
384 struct virtqueue *vqs[VIRTIO_SCMI_VQ_MAX_CNT];
385
386 /* Only one SCMI VirtiO device allowed */
387 if (scmi_vdev)
388 return -EINVAL;
389
390 have_vq_rx = scmi_vio_have_vq_rx(vdev);
391 vq_cnt = have_vq_rx ? VIRTIO_SCMI_VQ_MAX_CNT : 1;
392
393 channels = devm_kcalloc(dev, vq_cnt, sizeof(*channels), GFP_KERNEL);
394 if (!channels)
395 return -ENOMEM;
396
397 if (have_vq_rx)
398 channels[VIRTIO_SCMI_VQ_RX].is_rx = true;
399
400 ret = virtio_find_vqs(vdev, vq_cnt, vqs, scmi_vio_complete_callbacks,
401 scmi_vio_vqueue_names, NULL);
402 if (ret) {
403 dev_err(dev, "Failed to get %d virtqueue(s)\n", vq_cnt);
404 return ret;
405 }
406
407 for (i = 0; i < vq_cnt; i++) {
408 unsigned int sz;
409
410 spin_lock_init(&channels[i].lock);
411 spin_lock_init(&channels[i].ready_lock);
412 INIT_LIST_HEAD(&channels[i].free_list);
413 channels[i].vqueue = vqs[i];
414
415 sz = virtqueue_get_vring_size(channels[i].vqueue);
416 /* Tx messages need multiple descriptors. */
417 if (!channels[i].is_rx)
418 sz /= DESCRIPTORS_PER_TX_MSG;
419
420 if (sz > MSG_TOKEN_MAX) {
421 dev_info_once(dev,
422 "%s virtqueue could hold %d messages. Only %ld allowed to be pending.\n",
423 channels[i].is_rx ? "rx" : "tx",
424 sz, MSG_TOKEN_MAX);
425 sz = MSG_TOKEN_MAX;
426 }
427 channels[i].max_msg = sz;
428 }
429
430 vdev->priv = channels;
431 scmi_vdev = vdev;
432
433 return 0;
434}
435
436static void scmi_vio_remove(struct virtio_device *vdev)
437{
438 vdev->config->reset(vdev);
439 vdev->config->del_vqs(vdev);
440 scmi_vdev = NULL;
441}
442
443static int scmi_vio_validate(struct virtio_device *vdev)
444{
445 if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
446 dev_err(&vdev->dev,
447 "device does not comply with spec version 1.x\n");
448 return -EINVAL;
449 }
450
451 return 0;
452}
453
454static unsigned int features[] = {
455 VIRTIO_SCMI_F_P2A_CHANNELS,
456};
457
458static const struct virtio_device_id id_table[] = {
459 { VIRTIO_ID_SCMI, VIRTIO_DEV_ANY_ID },
460 { 0 }
461};
462
463static struct virtio_driver virtio_scmi_driver = {
464 .driver.name = "scmi-virtio",
465 .driver.owner = THIS_MODULE,
466 .feature_table = features,
467 .feature_table_size = ARRAY_SIZE(features),
468 .id_table = id_table,
469 .probe = scmi_vio_probe,
470 .remove = scmi_vio_remove,
471 .validate = scmi_vio_validate,
472};
473
474static int __init virtio_scmi_init(void)
475{
476 return register_virtio_driver(&virtio_scmi_driver);
477}
478
479static void __exit virtio_scmi_exit(void)
480{
481 unregister_virtio_driver(&virtio_scmi_driver);
482}
483
484const struct scmi_desc scmi_virtio_desc = {
485 .transport_init = virtio_scmi_init,
486 .transport_exit = virtio_scmi_exit,
487 .ops = &scmi_virtio_ops,
488 .max_rx_timeout_ms = 60000, /* for non-realtime virtio devices */
489 .max_msg = 0, /* overridden by virtio_get_max_msg() */
490 .max_msg_size = VIRTIO_SCMI_MAX_MSG_SIZE,
491};
include/uapi/linux/virtio_ids.h+1−0
@@ -55,6 +55,7 @@ · 54 unmodified lines
55#define VIRTIO_ID_FS 26 /* virtio filesystem */55#define VIRTIO_ID_FS 26 /* virtio filesystem */
56#define VIRTIO_ID_PMEM 27 /* virtio pmem */56#define VIRTIO_ID_PMEM 27 /* virtio pmem */
57#define VIRTIO_ID_MAC80211_HWSIM 29 /* virtio mac80211-hwsim */57#define VIRTIO_ID_MAC80211_HWSIM 29 /* virtio mac80211-hwsim */
58#define VIRTIO_ID_SCMI 32 /* virtio SCMI */
58#define VIRTIO_ID_BT 40 /* virtio bluetooth */59#define VIRTIO_ID_BT 40 /* virtio bluetooth */
59 60
60/*61/*
include/uapi/linux/virtio_scmi.h+24−0
@@ -0,0 +1,24 @@
1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2/*
3 * Copyright (C) 2020-2021 OpenSynergy GmbH
4 * Copyright (C) 2021 ARM Ltd.
5 */
6
7#ifndef _UAPI_LINUX_VIRTIO_SCMI_H
8#define _UAPI_LINUX_VIRTIO_SCMI_H
9
10#include <linux/virtio_types.h>
11
12/* Device implements some SCMI notifications, or delayed responses. */
13#define VIRTIO_SCMI_F_P2A_CHANNELS 0
14
15/* Device implements any SCMI statistics shared memory region */
16#define VIRTIO_SCMI_F_SHARED_MEMORY 1
17
18/* Virtqueues */
19
20#define VIRTIO_SCMI_VQ_TX 0 /* cmdq */
21#define VIRTIO_SCMI_VQ_RX 1 /* eventq */
22#define VIRTIO_SCMI_VQ_MAX_CNT 2
23
24#endif /* _UAPI_LINUX_VIRTIO_SCMI_H */