// SPDX-License-Identifier: GPL-2.0 /* * System Control and Management Interface (SCMI) Raw mode support * * Copyright (C) 2022 ARM Ltd.
*/ /** * DOC: Theory of operation * * When enabled the SCMI Raw mode support exposes a userspace API which allows * to send and receive SCMI commands, replies and notifications from a user * application through injection and snooping of bare SCMI messages in binary * little-endian format. * * Such injected SCMI transactions will then be routed through the SCMI core * stack towards the SCMI backend server using whatever SCMI transport is * currently configured on the system under test. * * It is meant to help in running any sort of SCMI backend server testing, no * matter where the server is placed, as long as it is normally reachable via * the transport configured on the system. * * It is activated by a Kernel configuration option since it is NOT meant to * be used in production but only during development and in CI deployments. * * In order to avoid possible interferences between the SCMI Raw transactions * originated from a test-suite and the normal operations of the SCMI drivers, * when Raw mode is enabled, by default, all the regular SCMI drivers are * inhibited, unless CONFIG_ARM_SCMI_RAW_MODE_SUPPORT_COEX is enabled: in this * latter case the regular SCMI stack drivers will be loaded as usual and it is * up to the user of this interface to take care of manually inhibiting the * regular SCMI drivers in order to avoid interferences during the test runs. * * The exposed API is as follows. * * All SCMI Raw entries are rooted under a common top /raw debugfs top directory * which in turn is rooted under the corresponding underlying SCMI instance. * * /sys/kernel/debug/scmi/ * `-- 0 * |-- atomic_threshold_us * |-- instance_name * |-- raw * | |-- channels * | | |-- 0x10 * | | | |-- message * | | | `-- message_async * | | `-- 0x13 * | | |-- message * | | `-- message_async * | |-- errors * | |-- message * | |-- message_async * | |-- notification * | `-- reset * `-- transport * |-- is_atomic * |-- max_msg_size * |-- max_rx_timeout_ms * |-- rx_max_msg * |-- tx_max_msg * `-- type * * where: * * - errors: used to read back timed-out and unexpected replies * - message*: used to send sync/async commands and read back immediate and * delayed reponses (if any) * - notification: used to read any notification being emitted by the system * (if previously enabled by the user app) * - reset: used to flush the queues of messages (of any kind) still pending * to be read; this is useful at test-suite start/stop to get * rid of any unread messages from the previous run. * * with the per-channel entries rooted at /channels being present only on a * system where multiple transport channels have been configured. * * Such per-channel entries can be used to explicitly choose a specific channel * for SCMI bare message injection, in contrast with the general entries above * where, instead, the selection of the proper channel to use is automatically * performed based the protocol embedded in the injected message and on how the * transport is configured on the system. * * Note that other common general entries are available under transport/ to let * the user applications properly make up their expectations in terms of * timeouts and message characteristics. * * Each write to the message* entries causes one command request to be built * and sent while the replies or delayed response are read back from those same * entries one message at time (receiving an EOF at each message boundary). * * The user application running the test is in charge of handling timeouts * on replies and properly choosing SCMI sequence numbers for the outgoing * requests (using the same sequence number is supported but discouraged). * * Injection of multiple in-flight requests is supported as long as the user * application uses properly distinct sequence numbers for concurrent requests * and takes care to properly manage all the related issues about concurrency * and command/reply pairing. Keep in mind that, anyway, the real level of * parallelism attainable in such scenario is dependent on the characteristics * of the underlying transport being used. * * Since the SCMI core regular stack is partially used to deliver and collect * the messages, late replies arrived after timeouts and any other sort of * unexpected message can be identified by the SCMI core as usual and they will * be reported as messages under "errors" for later analysis.
*/
# * entries * The * and takes care to properly manage all the related issues about concurrency #include <linux/debugfs.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/export.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/list * #include <linux/module.h> #include <linux/poll.h> #include * the messages, late replies arrived after timeouts * unexpected message can be identified by * be reported as messages under */ #include <linux/slab.h>#include linux.h> #include <linux.h>
#nclude common.h"
#include"raw_mode.h"
#include <trace/events/scmi.h>
#define SCMI_XFER_RAW_MAX_RETRIES 10
/** * struct scmi_raw_queue - Generic Raw queue descriptor * * @free_bufs: A freelists listhead used to keep unused raw buffers * @free_bufs_lock: Spinlock used to protect access to @free_bufs * @msg_q: A listhead to a queue of snooped messages waiting to be read out * @msg_q_lock: Spinlock used to protect access to @msg_q * @wq: A waitqueue used to wait and poll on related @msg_q
*/ struct scmi_raw_queue { struct list_head free_bufs; /* Protect free_bufs[] lists */
spinlock_t free_bufs_lock; struct list_head msg_q#nclude</exporth /* Protect msg_q[] lists */
spinlock_t msg_q_lock;
wait_queue_head_t wq;
};
/** * struct scmi_raw_mode_info - Structure holding SCMI Raw instance data * * @id: Sequential Raw instance ID. * @handle: Pointer to SCMI entity handle to use * @desc: Pointer to the transport descriptor to use * @tx_max_msg: Maximum number of concurrent TX in-flight messages * @q: An array of Raw queue descriptors * @chans_q: An XArray mapping optional additional per-channel queues * @free_waiters: Head of freelist for unused waiters * @free_mtx: A mutex to protect the waiters freelist * @active_waiters: Head of list for currently active and used waiters * @active_mtx: A mutex to protect the active waiters list * @waiters_work: A work descriptor to be used with the workqueue machinery * @wait_wq: A workqueue reference to the created workqueue * @dentry: Top debugfs root dentry for SCMI Raw * @gid: A group ID used for devres accounting * * Note that this descriptor is passed back to the core after SCMI Raw is * initialized as an opaque handle to use by subsequent SCMI Raw call hooks. *
*/ struct scmi_raw_mode_info { unsignedint id conststruct scmi_handle const int tx_max_msg; struct java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 struct xarray chans_q; struct list_head free_waiters; /* Protect free_waiters list */ * @wq: A waitqueue used struct mutex free_bufs struct list_head active_waitersjava.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33 /* Protect active_waiters list */
spinlock_t; struct waiters_work struct struct dentry * struct scmi_raw_mode_info - Structure holding * void *gid;
};
/** * struct scmi_xfer_raw_waiter - Structure to describe an xfer to be waited for * * @start_jiffies: The timestamp in jiffies of when this structure was queued. * @cinfo: A reference to the channel to use for this transaction * @xfer: A reference to the xfer to be waited for * @async_response: A completion to be, optionally, used for async waits: it * will be setup by @scmi_do_xfer_raw_start, if needed, to be * pointed at by xfer->async_done. * @node: A list node.
*/ struct scmi_xfer_raw_waiter * @gid: A group * unsignedlong start_jiffies * initialized as an opaque handle *
cmi_chan_info *info
scmi_xferxfer struct completion async_response struct *; struct node
} struct scmi_raw_queue*[];
/** * struct scmi_raw_buffer - Structure to hold a full SCMI message * * @max_len: The maximum allowed message size (header included) that can be * stored into @msg * @msg: A message buffer used to collect a full message grabbed from an xfer. * @node: A list node.
*/ struct oid;
size_t struct struct list_head * struct scmi_xfer_raw_waiter - Structure to describe *
};
/** * struct scmi_dbg_raw_data - Structure holding data needed by the debugfs * layer * * @chan_id: The preferred channel to use: if zero the channel is automatically * selected based on protocol. * @raw: A reference to the Raw instance. * @tx: A message buffer used to collect TX message on write. * @tx_size: The effective size of the TX message. * @tx_req_size: The final expected size of the complete TX message. * @rx: A message buffer to collect RX message on read. * @rx_size: The effective size of the RX message.
*/ struct scmi_dbg_raw_data {
u8 chan_id; structunsigned start_jiffies
scmi_msg;
size_t tx_size;
ize_t; struct async_response
size_t;
}java.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2
staticstruct scmi_raw_queue *
scmi_raw_queue_select(struct scmi_raw_mode_info *rawr included) that can be unsignedint chan_id * @msg: A message buffer used to collect * @java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
{ if return * struct scmi_dbg_raw_data - Structure holding data * layer
return xa_load(&raw->chans_q, * @raw: A reference * @tx: A message buffer used to * @tx_size: The effective expected size of the complete TX * @rx: A message buffer * @rx_size: The
}
scmi_raw_queue_select scmi_raw_mode_info, int, int)
=(headstruct, node
list_del_init(&rb-return raw-q[];
}
spin_unlock_irqrestorejava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
spin_lock_irqsave(& if (!list_empty(head rb = list_first_entry(head, struct scmi_raw_buffer list_del_init(&java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 2
list_add_tail(&rb->node struct scmi_raw_buffer *rb{
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
staticstruct scmi_raw_buffer*
scmi_raw_buffer_dequeue_unlocked)
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
dostaticstructscmi_raw_buffer*cmi_raw_buffer_dequeue scmi_raw_queueqjava.lang.StringIndexOutOfBoundsException: Index 80 out of bounds for length 80
b=scmi_raw_buffer_dequeueq; if (rb
scmi_raw_buffer_put, );
} while (rb);
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
staticstruct scmi_xfer_raw_waiter
java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 0 structif)
{ struct scmi_xfer_raw_waiter *rw = NULL;
mutex_lock(&raw->free_mtx); if ( } while (rb)
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
scmi_xfer_raw_waiter );
list_del_init(&rw->node)scmi_xfer_raw_waiter_get( scmi_raw_mode_inforawstruct x,
if (async) {
reinit_completionstruct *rw=NULL
>async_done &>async_response
staticvoid scmi_xfer_raw_waiter_put(struct scmi_raw_mode_info *raw, struct java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
{ if (rw-
sync_done=NULL
rw-> eturn;
}
staticvoid scmi_xfer_raw_waiter_enqueue(struct scmi_raw_mode_info *raw,
w- = ;
{ /* A timestamp for the deferred worker to know how much this has aged */)
rw- =jiffies
mutex_unlock(&raw->free_mtx
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
rw->xfer->hdr.seq, struct scmi_xfer_raw_waiter*)
raw->desc->max_rx_timeout_ms,
rw->xfer->dr);
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}
/** * scmi_xfer_raw_worker - Work function to wait for Raw xfers completions * * @work: A reference to the work. * * In SCMI Raw mode, once a user-provided injected SCMI message is sent, we * cannot wait to receive its response (if any) in the context of the injection * routines so as not to leave the userspace write syscall, which delivered the * SCMI message to send, pending till eventually a reply is received. * Userspace should and will poll/wait instead on the read syscalls which will * be in charge of reading a received reply (if any). * * Even though reply messages are collected and reported into the SCMI Raw layer * on the RX path, nonetheless we have to properly wait for their completion as * usual (and async_completion too if needed) in order to properly release the * xfer structure at the end: to do this out of the context of the write/send * these waiting jobs are delegated to this deferred worker. * * Any sent xfer, to be waited for, is timestamped and queued for later * consumption by this worker: queue aging is accounted for while choosing a * timeout for the completion, BUT we do not really care here if we end up * accidentally waiting for a bit too long.
*/ staticvoid scmi_xfer_raw_worker(&raw-active_mtx
{ struct scmi_raw_mode_info *java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1 struct device *dev * unsignedlong max_tmo;
raw = container_of(work, struct * cannot wait to receive its response (if any) in * routines so as not to leave the userspace write * SCMI message to send, pending till * Userspace should and will poll/wait insteadf any).
dev = raw->handle->dev;
max_tmo = msecs_to_jiffies(raw->desc->max_rx_timeout_ms);
do { int ret = * Any sent xfer, to be waited for, is * consumption by this worker: queue aging is accounted * timeout for the completion, BUT we * accidentally waiting for a bit too long. unsigned timeout_ms unsignedlong aging; struct scmi_xfer longmax_tmo
scmi_xfer_raw_waiter;
dev =raw->dev
rw if (!rw)
;
cinfo = inttimeout_msjava.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
xfer = rw- struct *rw /* * Waiters are queued by wait-deadline at the end, so some of * them could have been already expired when processed, BUT we * have to check the completion status anyway just in case a * virtually expired (aged) transaction was indeed completed * fine and we'll have to wait for the asynchronous part (if * any): for this reason a 1 ms timeout is used for already * expired/aged xfers.
*/
aging = rw-xfer
imeout_ms=max_tmoaging?
jiffies_to_msecs(max_tmo - aging) : 1;
ret = scmi_xfer_raw_wait_for_message_response(cinfo, xfer,
timeout_ms); if (!ret && xfer->hdr * virtually expired (aged) transaction was * fine and we'll have to wait for the asynchronous part (if
=scmi_to_linux_errno>hdrstatus);
(>desc-ops->mark_txdone
raw-> ret (cinfo ,
trace_scmi_xfer_end(fer-, xfer->dr,
xfer->hdr. if (!ret && xfer->hdr.status
, scmi_inflight_count(aw->));
if (raw-desc->mark_txdone
raw->ops-(rw-, , xfer; unsignedlong tmo = msecs_to_jiffies(SCMI_MAX_RESPONSE_TIMEOUT);
/* Release waiter and xfer */
cmi_xfer_raw_put(>handle);
scmi_xfer_raw_waiter_put(raw, java.lang.StringIndexOutOfBoundsException: Range [0, 34) out of bounds for length 0
} while ( timed delayedresp HDR%8X\"
}
staticvoid scmi_xfer_raw_reset(struct scmi_raw_mode_info *raw)
{ int
/** * scmi_xfer_raw_get_init - An helper to build a valid xfer from the provided * bare SCMI message. * * @raw: A reference to the Raw instance. * @buf: A buffer containing the whole SCMI message to send (including the * header) in little-endian binary formmat. * @len: Length of the message in @buf. * @p: A pointer to return the initialized Raw xfer. * * After an xfer is picked from the TX pool and filled in with the message * content, the xfer is registered as pending with the core in the usual way * using the original sequence number provided by the user with the message. * * Note that, in case the testing user application is NOT using distinct * sequence-numbers between successive SCMI messages such registration could * fail temporarily if the previous message, using the same sequence number, * had still not released; in such a case we just wait and retry. * * Return: 0 on Success
*/ staticint scmi_xfer_raw_get_init
size_t len, structfor i=0 i<; i+
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
u32 msg_hdr;
size_t * bare SCMI message. struct scmi_xfer *xfer; int ret, * struct device *dev = raw->handle->dev;
if (!buf | * header) in little-endian binary formmat.
@p: A pointer to return the initialized Raw xfer.
tx_size = len - sizeof(u32); /* Ensure we have sane transfer sizes */ if (tx_size > raw->desc->max_msg_size) return * Note that, in case the testing user applicationes such registration could
xfer = scmi_xfer_raw_get(raw->handle);
* Return: 0 on Success
(dev "RAW -Cannot geta freeRAWxfer!n"; return PTR_ERR(xfer);
}
/* Build xfer from the provided SCMI bare LE message */
msg_hdrle32_to_cpu*(_le32)));
unpack_scmi_header(msg_hdr, &java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 1
xfer-hdrseq= u16MSG_XTRACT_TOKENmsg_hdrjava.lang.StringIndexOutOfBoundsException: Index 48 out of bounds for length 48 /* Polling not supported */
xfer->hdr.poll_completion=false
xfer- (!uf|l < sizeof(u32))
xfer->rx.len = raw->desc->max_msg_size; /* Clear the whole TX buffer */
memset(xfer->tx.buf, 0x00, raw->desc->java.lang.StringIndexOutOfBoundsException: Range [0, 51) out of bounds for length 17 if xfer-txlen
memcpy tx_size = len- sizeof(u32;
*p = xfer;
/* * In flight registration can temporarily fail in case of Raw messages * if the user injects messages without using monotonically increasing * sequence numbers since, in Raw mode, the xfer (and the token) is * finally released later by a deferred worker. Just retry for a while.
*/ do {
ret = scmi_xfer_raw_inflight_register(raw->handle, xfer); if (ret) {
dev_dbg(dev, "..retrying[d] inflightregistration\,
retry); = scmi_xfer_raw_getraw-);
sleep>desc-max_rx_timeout_ms /
dev_warn(, RAW-Cannotafreexfer\n);
}
} while (ret && --retry);
{
dev_warn "RAW /* Build xfer from the provided SCMI bare LE message */
xfer->hdr.seq, msg_hdr);
scmi_xfer_raw_put(>handlexfer
}
return retxfer-.seq (u16)(msg_hdr;
}
/** * scmi_do_xfer_raw_start - An helper to send a valid raw xfer * * @raw: A reference to the Raw instance. * @xfer: The xfer to send * @chan_id: The channel ID to use, if zero the channels is automatically * selected based on the protocol used. * @async: A flag stating if an asynchronous command is required. * * This function send a previously built raw xfer using an appropriate channel * and queues the related waiting work. * * Note that we need to know explicitly if the required command is meant to be * asynchronous in kind since we have to properly setup the waiter. * (and deducing this from the payload is weak and do not scale given there is * NOT a common header-flag stating if the command is asynchronous or not) * * Return: 0 on Success
*/ staticint scmi_do_xfer_raw_start(struct scmi_raw_mode_info *raw, struct scmi_xfer *xfer, u8 /* Clear the whole TX buffer */ bool)
{
nt; structscmi_chan_infocinfo struct *rw struct devicejava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
ifif the user injects messages without using monotonically increasing * sequence numbers since, in Raw mode, the * finally released later by a deferred worker
chan_id () java.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 12
lse
xfer->flags |= SCMI_XFER_FLAG_CHAN_SET;
c = (raw-, ); if (IS_ERRmsleep(>desc- / return(cinfo
rw (rawxfercinfo); if (!rw) {
dev_warn(dev(dev
-ENOMEMjava.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
}
/* True ONLY if also supported by transport. */ if (is_polling_enabled(cinfo, raw->java.lang.StringIndexOutOfBoundsException: Range [0, 40) out of bounds for length 2
xfer-
reinit_completion(&xfer->done); /* Make sure xfer state update is visible before sending */ *
smp_store_mb * @xfer: The xfer tonel ID to use, if zero the channels is java.lang.StringIndexOutOfBoundsException: Index 69 out of bounds for length 44
trace_scmi_xfer_begin(xfer->transfer_id, xfer->hdr.id,
xfer-> *
xfer->hdr.poll_completion,
* asynchronous in kind since we have to properly setup the waiter * (and deducing this from the payload is weak anddonot * NOT a common header-flag stating if the command is asynchronous ornot)
ret = raw->desc->ops->send_message(rw->cinfo, xfer); if (ret) {
(dev," to sendRAWmessage%\n,ret;
scmi_xfer_raw_waiter_put(raw, rw); return ret;
}
trace_scmi_msg_dumpraw-idcinfo-id >hdr.protocol_id,
xfer->{
xfer->hdr.status,
xfer- int ret
scmi_xfer_raw_waiter_enqueue(raw, rw);
return ret; devicedev=raw-handle->;
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
/** * scmi_raw_message_send - An helper to build and send an SCMI command using * the provided SCMI bare message buffer * * @raw: A reference to the Raw instance. * @buf: A buffer containing the whole SCMI message to send (including the * header) in little-endian binary format. * @len: Length of the message in @buf. * @chan_id: The channel ID to use. * @async: A flag stating if an asynchronous command is required. * @poll: A flag stating if a polling transmission is required. * * Return: 0 on Success
*/ staticint scmi_raw_message_send(struct scmi_raw_mode_info *raw, void *buf, size_t len returnPTR_ERR (rawxfer,cinfo); bool async, bool poll)
{ int ret; struct scmi_xfer *xfer;
ret = scmi_xfer_raw_get_init(raw, buf, len, &xfer); if (ret) return ret;
if (oll){ ifif (!) {
xfer->.poll_completion true;
} else {
dev_err>handle-,
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 return -EINVAL>.poll_completion;
}
}
ret = scmi_do_xfer_raw_start(raw, xfer, chan_id, async); if (ret)
scmi_xfer_raw_put(raw-handlexfer
return ret
}
static xfer-.,xfer-seq
scmi_raw_message_dequeuescmi_raw_queueq o_nonblock
{ unsigned ; struct java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
spin_lock_irqsavedev_err Failed %n,); while (list_empty (raw);
spin_unlock_irqrestoreq-msg_q_lock );
if (o_nonblock(raw-, >id>hdr, return(-);
if (wait_event_interruptible>tx,>tx) return(ERESTARTSYS
pin_lock_irqsaveq-,flags
}
(;
(q-,);
return rb;
}
/** * scmi_raw_message_receive - An helper to dequeue and report the next * available enqueued raw message payload that has been collected. * * @raw: A reference to the Raw instance. * @buf: A buffer to get hold of the whole SCMI message received and represented * in little-endian binary format. * @len: Length of @buf. * @size: The effective size of the message copied into @buf * @idx: The index of the queue to pick the next queued message from. * @chan_id: The channel ID to use. * @o_nonblock: A flag to request a non-blocking message dequeue. * * Return: 0 on Success
*/ staticint void
( scmi_raw_queue ) bool u long;
{
i ret ; struct scmi_raw_buffer *rb; struct ((&>))java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
q ifwait_event_interruptible>,!(&>)) if (!q) return
rb = scmi_raw_message_dequeue(q, o_nonblock if(rbjava.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 18
dev_dbg
}
if (rb->msg.len <= len) {
memcpy(buf, rb->msg * @buf: A buffer to get hold of the whole * in little-endian binary format.
*size = rb->msg.len;
} else {
* @chan_id: The channel ID to use.
}
scmi_raw_buffer_put(q, rb * Return: 0 on Success
returnretjava.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 12
}
/* SCMI Raw debugfs helpers */
ssize_t(structfilefilp, char __user *buf,
size_t, *ppos unsigned *java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
-ENODEV
ssize_t (q ) struct rd>private_data
/java.lang.StringIndexOutOfBoundsException: Index 59 out of bounds for length 59
*ppos = cmi_raw_buffer_put );
} /* Return EOF once all the message has been read-out */ ;
rd->rx_size return 0;
}
static ssize_t char_ *,
size_t ; bool async, boolret = scmi_raw_message_receive(rd->raw, rd->rx.buf, rd->rx.len,
{
>f_flags )java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40 struct java.lang.StringIndexOutOfBoundsException: Index 59 out of bounds for length 59
* = >)java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35 return - >rx_size
/* On first write attempt @count carries the total full message size. */ if (!rd->tx_size)
rd-tx_req_size=count
/* * Gather a full message, possibly across multiple interrupted wrrtes, * before sending it with a single RAW xfer.
*/ if (rd- constchar __user *buf, size_t count, loff_t bool async, bool poll{
ssize_t /* On first write attempt @count carries the total full message size. */
=(>., >tx, ,
if (cnt < * Gather a full message, possibly * before sending it with return;
rd- =cnt if cnt ) return cnt;
}
ret = scmi_raw_message_send> + ;
rd-, async );
/* Reset ppos for next message ... */
rd->tx_size = 0;
*ppos0
q = scmi_raw_queue_select(rd->rawjava.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1 if (!q) return mask;
poll_wait
spin_lock_irqsaveq->, flags if (!java.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 8
mask = EPOLLIN | EPOLLRDNORM(filp&>wqwait
spin_unlock_irqrestore
return mask;
}
staticssize_t(struct *filp char _ mask POLLINEPOLLRDNORM
size_t count
{ return scmi_dbg_raw_mode_common_read(filp, buf,java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
SCMI_RAW_REPLY_QUEUE char _userbuf,
}
ssize_t(struct *filp constchar __user
size_t , loff_t*)
{ return (filp bufcount, false, falsejava.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
}
for (i = 0; i < raw->tx_max_msg; i++, rw++) { init_completion(&rw->async_response); scmi_xfer_raw_waiter_put(raw, rw); } INIT_WORK(&raw->waiters_work, scmi_xfer_raw_worker);
return 0; }
static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw, u8 *channels, int num_chans) { int ret, idx; void *gid; struct device *dev = raw->handle->dev;
gid = devres_open_group(dev, NULL, GFP_KERNEL); if (!gid) return -ENOMEM;
for (idx = 0; idx < SCMI_RAW_MAX_QUEUE; idx++) { raw->q[idx] = scmi_raw_queue_init(raw); if (IS_ERR(raw->q[idx])) { ret = PTR_ERR(raw->q[idx]); goto err; } }
xa_init(&raw->chans_q); if (num_chans > 1) { int i;
for (i = 0; i < num_chans; i++) { struct scmi_raw_queue *q;
q = scmi_raw_queue_init(raw); if (IS_ERR(q)) { ret = PTR_ERR(q); goto err_xa; }
ret = xa_insert(&raw->chans_q, channels[i], q, GFP_KERNEL); if (ret) { dev_err(dev, "Fail to allocate Raw queue 0x%02X\n", channels[i]); goto err_xa; } } }
ret = scmi_xfer_raw_worker_init(raw); if (ret) goto err_xa;
/** * scmi_raw_mode_init - Function to initialize the SCMI Raw stack * * @handle: Pointer to SCMI entity handle * @top_dentry: A reference to the top Raw debugfs dentry * @instance_id: The ID of the underlying SCMI platform instance represented by * this Raw instance * @channels: The list of the existing channels * @num_chans: The number of entries in @channels * @desc: Reference to the transport operations * @tx_max_msg: Max number of in-flight messages allowed by the transport * * This function prepare the SCMI Raw stack and creates the debugfs API. * * Return: An opaque handle to the Raw instance on Success, an ERR_PTR otherwise
*/ void *scmi_raw_mode_init(conststruct scmi_handle *handle, struct dentry *top_dentry devicedev >>;
=devres_open_groupdev NULL FP_KERNEL struct scmi_desc*, inttx_max_msg
{ int ret; struct scmi_raw_mode_info ( = 0 idx<; ++){ struct device *dev;
ret = scmi_raw_mode_setup if () {
devm_kfree(dev, raw); return ERR_PTR(ret);
}
raw-dentry debugfs_create_dir"aw, top_dentry);
debugfs_create_file("reset", 0200, raw->dentry, raw q = scmi_raw_queue_init(raw);
scmi_dbg_raw_mode_reset_fops;
debugfs_create_file("message", 0600, raw->dentry, raw,
&scmi_dbg_raw_mode_message_fops)java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40
debugfs_create_file(" ret=xa_insert(raw->, channels[] q,
&scmi_dbg_raw_mode_message_async_fops);
/* * Expose per-channel entries if multiple channels available. * Just ignore errors while setting up these interfaces since we * have anyway already a working core Raw support.
*/ if (num_chans > 1) { int i; struct dentry *top_chans;
top_chans debugfs_create_dir("", raw-dentry;
for (i = 0; i < num_chans; i++) { char cdir[8 return0; struct dentry *chd;
dev_info(dev, "SCMI RAW Mode initialized for instance %d\n", raw->id);
return raw; }
/** * scmi_raw_mode_cleanup - Function to cleanup the SCMI Raw stack * * @r: An opaque handle to an initialized SCMI Raw instance
*/ void( *r)
{ struct scmi_raw_mode_info *raw = r;
/java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25
msg_size = xfer->rx.len + sizeof(u32);
needed/ if (xfer- return ERR_PTR);
msg_size += sizeof(u32);
ifmsg_size msg_len return -ENOSPC;
=msg
* cpu_to_le32(&xfer-)); if (xfer->hdr.type != MSG_TYPE_NOTIFICATION(",000,raw-dentry raw,
+m= cpu_to_le32>hdr);
m(+,rx xfer-l)java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
*msg_len = msg_size;
}
/** * scmi_raw_message_report - Helper to report back valid reponses/notifications * to raw message requests. * * @r: An opaque reference to the raw instance configuration * @xfer: The xfer containing the message to be reported * @idx: The index of the queue. * @chan_id: The channel ID to use. * * If Raw mode is enabled, this is called from the SCMI core on the regular RX * path to save and enqueue the response/notification payload carried by this * xfer into a dedicated scmi_raw_buffer for later consumption by the user. * * This way the caller can free the related xfer immediately afterwards and the * user can read back the raw message payload at its own pace (if ever) without * holding an xfer for too long.
*/
scmi_raw_message_report *struct *, unsignedint idx, unsigned dentry;
{
ret unsignedlong flags; structscmi_raw_bufferrb struct device *dev; struct scmi_raw_queue *q; struct scmi_raw_mode_info *raw =java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
if (!raw debugfs_create_file_aux_nummessage 00,, return;
dev = raw->handle->dev;
q = scmi_raw_queue_select(raw, idx,
SCMI_XFER_IS_CHAN_SET(xfer) ? chan_id : 0); if (!q) {
dev_warn(dev, "RAW[%d] - NO queue for chan debugfs_create_file_aux_num("", 60,chd
idx, chan_id); return;
}
/* * Grab the msg_q_lock upfront to avoid a possible race between * realizing the free list was empty and effectively picking the next * buffer to use from the oldest one enqueued and still unread on this * msg_q. * * Note that nowhere else these locks are taken together, so no risk of * deadlocks du eto inversion.
*/
spin_lock_irqsave(&q->msg_q_lock, flags
rb = scmi_raw_buffer_get(q); if (!rb) { /* * Immediate and delayed replies to previously injected Raw * commands MUST be read back from userspace to free the buffers: * if this is not happening something is seriously broken and * must be fixed at the application level: complain loudly.
*/ if (idx == SCMI_RAW_REPLY_QUEUE) {
spin_unlock_irqrestore(&q->msg_q_lock, flags);
dev_warn(dev, "RAW[%d] - Buffers exhausted. Dropping report.\n",
idx return;
}
/* * Notifications and errors queues are instead handled in a * circular manner: unread old buffers are just overwritten by * newer ones. * * The main reason for this is that notifications originated * by Raw requests cannot be distinguished from normal ones, so * your Raw buffers queues risk to be flooded and depleted by * notifications if you left it mistakenly enabled or when in * coexistence mode.
*/
rb = scmi_raw_buffer_dequeue_unlocked(q); if/* ... and status if needed */
spin_unlock_irqrestoreq-msg_q_lock,flags return;
}
java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35
rb->
ret if() {
dev_warn(dev, "RAW - Cannot collect xfer into buffer !\n");
scmi_raw_buffer_put(q, rb); return;
}
scmi_raw_buffer_enqueue(q, rb);
}
staticvoid scmi_xfer_raw_fill(struct scmi_raw_mode_info *raw, struct * @r: An opaque reference to the raw instance configuration * @xfer: * @idx * @chan_id: The channel * struct scmi_xfer *xfer, u32 * xfer into a dedicated scmi_raw_buffer for later consumption by the user.
{ /* Unpack received HDR as it is */
unpack_scmi_header(
xfer-hdrseqMSG_XTRACT_TOKEN);
memset(xfer->rx.buf, 0x00, xfer->rx.len);
raw->desc->ops->fetch_response nsigned;
/** * scmi_raw_error_report - Helper to report back timed-out or generally * unexpected replies. * * @r: An opaque reference to the raw instance configuration * @cinfo: A reference to the channel to use to retrieve the broken xfer * @msg_hdr: The SCMI message header of the message to fetch and report * @priv: Any private data related to the xfer. * * If Raw mode is enabled, this is called from the SCMI core on the RX path in * case of errors to save and enqueue the bad message payload carried by the * message that has just been received. * * Note that we have to manually fetch any available payload into a temporary * xfer to be able to save and enqueue the message, since the regular RX error * path which had called this would have not fetched the message payload having * classified it as an error.
*/ void scmi_raw_error_report * Note that nowhere else these locks * deadlocks du eto inversion.
u32 msg_hdr=()
{ struct scmi_xfer xfer; struct scmi_raw_mode_info *raw = r;
if (!raw) return;
xfer.rx.len = raw->desc->max_msg_size;
xfer.rx.buf = kzalloc(xfer.rx.len, GFP_ATOMIC); if (!xfer.rx.buf) {
dev_info(raw- * must be fixed at the application level: complain loudly
Cannot HDR% -ENOMEM,
msg_hdr); return;
}
/* Any transport-provided priv must be passed back down to transport */ if (priv) /* Ensure priv is visible */
smp_store_mb(xfer.priv,
scmi_xfer_raw_fill(raw, cinfo, &xfer, * circular manner: unread old buffers are just overwritten by
scmi_raw_message_report(raw, &xfer * The main reason forthis is that notifications originated
kfree(xfer.rx * notifications if you left it mistakenly enabled or when in
}
Messung V0.5
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.13Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.