firmware: arm_scmi: Add per-channel raw injection support
On a system configured with multiple transport channels, expose a few additional debugfs per-channel entries to allow a user to explicitly select which transport channel to use for the SCMI message injection. Signed-off-by: Cristian Marussi <cristian.marussi@arm.com> Tested-by: Florian Fainelli <f.fainelli@gmail.com> Tested-by: Vincent Guittot <vincent.guittot@linaro.org> Link: https://lore.kernel.org/r/20230118121426.492864-18-cristian.marussi@arm.com Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
This commit is contained in:
parent
9c54633e4e
commit
7860701d1e
@ -64,3 +64,46 @@ Description: SCMI Raw stack reset facility; writing a value to this entry
|
||||
Can be used to reset and clean the SCMI Raw stack between to
|
||||
different test-run.
|
||||
Users: Debugging, any userspace test suite
|
||||
|
||||
What: /sys/kernel/debug/scmi/<n>/raw/channels/<m>/message
|
||||
Date: March 2023
|
||||
KernelVersion: 6.3
|
||||
Contact: cristian.marussi@arm.com
|
||||
Description: SCMI Raw synchronous message injection/snooping facility; write
|
||||
a complete SCMI synchronous command message (header included)
|
||||
in little-endian binary format to have it sent to the configured
|
||||
backend SCMI server for instance <n> through the <m> transport
|
||||
channel.
|
||||
Any subsequently received response can be read from this same
|
||||
entry if it arrived on channel <m> within the configured
|
||||
timeout.
|
||||
Each write to the entry causes one command request to be built
|
||||
and sent while the replies are read back one message at time
|
||||
(receiving an EOF at each message boundary).
|
||||
Note that these per-channel entries rooted at <..>/channels
|
||||
exist only if the transport is configured to have more than
|
||||
one channel.
|
||||
Users: Debugging, any userspace test suite
|
||||
|
||||
What: /sys/kernel/debug/scmi/<n>/raw/channels/<m>/message_async
|
||||
Date: March 2023
|
||||
KernelVersion: 6.3
|
||||
Contact: cristian.marussi@arm.com
|
||||
Description: SCMI Raw asynchronous message injection/snooping facility; write
|
||||
a complete SCMI asynchronous command message (header included)
|
||||
in little-endian binary format to have it sent to the configured
|
||||
backend SCMI server for instance <n> through the <m> transport
|
||||
channel.
|
||||
Any subsequently received response can be read from this same
|
||||
entry if it arrived on channel <m> within the configured
|
||||
timeout.
|
||||
Any additional delayed response received afterwards can be read
|
||||
from this same entry too if it arrived within the configured
|
||||
timeout.
|
||||
Each write to the entry causes one command request to be built
|
||||
and sent while the replies are read back one message at time
|
||||
(receiving an EOF at each message boundary).
|
||||
Note that these per-channel entries rooted at <..>/channels
|
||||
exist only if the transport is configured to have more than
|
||||
one channel.
|
||||
Users: Debugging, any userspace test suite
|
||||
|
@ -27,6 +27,8 @@
|
||||
#include "protocols.h"
|
||||
#include "notify.h"
|
||||
|
||||
#define SCMI_MAX_CHANNELS 256
|
||||
|
||||
#define SCMI_MAX_RESPONSE_TIMEOUT (2 * MSEC_PER_SEC)
|
||||
|
||||
enum scmi_error_codes {
|
||||
|
@ -660,6 +660,7 @@ void scmi_xfer_raw_put(const struct scmi_handle *handle, struct scmi_xfer *xfer)
|
||||
struct scmi_info *info = handle_to_scmi_info(handle);
|
||||
|
||||
xfer->flags &= ~SCMI_XFER_FLAG_IS_RAW;
|
||||
xfer->flags &= ~SCMI_XFER_FLAG_CHAN_SET;
|
||||
return __scmi_xfer_put(&info->tx_minfo, xfer);
|
||||
}
|
||||
|
||||
@ -896,7 +897,8 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo,
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) {
|
||||
xfer->hdr.seq = MSG_XTRACT_TOKEN(msg_hdr);
|
||||
scmi_raw_message_report(info->raw, xfer, SCMI_RAW_NOTIF_QUEUE);
|
||||
scmi_raw_message_report(info->raw, xfer, SCMI_RAW_NOTIF_QUEUE,
|
||||
cinfo->id);
|
||||
}
|
||||
|
||||
__scmi_xfer_put(minfo, xfer);
|
||||
@ -955,7 +957,9 @@ static void scmi_handle_response(struct scmi_chan_info *cinfo,
|
||||
* poll loop.
|
||||
*/
|
||||
if (!xfer->hdr.poll_completion)
|
||||
scmi_raw_message_report(info->raw, xfer, SCMI_RAW_REPLY_QUEUE);
|
||||
scmi_raw_message_report(info->raw, xfer,
|
||||
SCMI_RAW_REPLY_QUEUE,
|
||||
cinfo->id);
|
||||
}
|
||||
|
||||
scmi_xfer_command_release(info, xfer);
|
||||
@ -1078,7 +1082,8 @@ static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc,
|
||||
handle_to_scmi_info(cinfo->handle);
|
||||
|
||||
scmi_raw_message_report(info->raw, xfer,
|
||||
SCMI_RAW_REPLY_QUEUE);
|
||||
SCMI_RAW_REPLY_QUEUE,
|
||||
cinfo->id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -2608,14 +2613,35 @@ static struct scmi_debug_info *scmi_debugfs_common_setup(struct scmi_info *info)
|
||||
|
||||
static int scmi_debugfs_raw_mode_setup(struct scmi_info *info)
|
||||
{
|
||||
int ret = 0;
|
||||
int id, num_chans = 0, ret = 0;
|
||||
struct scmi_chan_info *cinfo;
|
||||
u8 channels[SCMI_MAX_CHANNELS] = {};
|
||||
DECLARE_BITMAP(protos, SCMI_MAX_CHANNELS) = {};
|
||||
|
||||
if (!info->dbg)
|
||||
return -EINVAL;
|
||||
|
||||
/* Enumerate all channels to collect their ids */
|
||||
idr_for_each_entry(&info->tx_idr, cinfo, id) {
|
||||
/*
|
||||
* Cannot happen, but be defensive.
|
||||
* Zero as num_chans is ok, warn and carry on.
|
||||
*/
|
||||
if (num_chans >= SCMI_MAX_CHANNELS || !cinfo) {
|
||||
dev_warn(info->dev,
|
||||
"SCMI RAW - Error enumerating channels\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!test_bit(cinfo->id, protos)) {
|
||||
channels[num_chans++] = cinfo->id;
|
||||
set_bit(cinfo->id, protos);
|
||||
}
|
||||
}
|
||||
|
||||
info->raw = scmi_raw_mode_init(&info->handle, info->dbg->top_dentry,
|
||||
info->id, info->desc,
|
||||
info->tx_minfo.max_msg);
|
||||
info->id, channels, num_chans,
|
||||
info->desc, info->tx_minfo.max_msg);
|
||||
if (IS_ERR(info->raw)) {
|
||||
dev_err(info->dev, "Failed to initialize SCMI RAW Mode !\n");
|
||||
ret = PTR_ERR(info->raw);
|
||||
|
@ -138,6 +138,9 @@ struct scmi_xfer {
|
||||
int state;
|
||||
#define SCMI_XFER_FLAG_IS_RAW BIT(0)
|
||||
#define SCMI_XFER_IS_RAW(x) ((x)->flags & SCMI_XFER_FLAG_IS_RAW)
|
||||
#define SCMI_XFER_FLAG_CHAN_SET BIT(1)
|
||||
#define SCMI_XFER_IS_CHAN_SET(x) \
|
||||
((x)->flags & SCMI_XFER_FLAG_CHAN_SET)
|
||||
int flags;
|
||||
/* A lock to protect state and busy fields */
|
||||
spinlock_t lock;
|
||||
|
@ -37,10 +37,17 @@
|
||||
* which in turn is rooted under the corresponding underlying SCMI instance.
|
||||
*
|
||||
* /sys/kernel/debug/scmi/
|
||||
* |-- 0
|
||||
* `-- 0
|
||||
* |-- atomic_threshold_us
|
||||
* |-- instance_name
|
||||
* |-- raw
|
||||
* | |-- channels
|
||||
* | | |-- 0x10
|
||||
* | | | |-- message
|
||||
* | | | `-- message_async
|
||||
* | | `-- 0x13
|
||||
* | | |-- message
|
||||
* | | `-- message_async
|
||||
* | |-- errors
|
||||
* | |-- message
|
||||
* | |-- message_async
|
||||
@ -65,6 +72,15 @@
|
||||
* 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.
|
||||
@ -95,7 +111,6 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
@ -104,6 +119,7 @@
|
||||
#include <linux/poll.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/xarray.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
@ -140,6 +156,7 @@ struct scmi_raw_queue {
|
||||
* @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
|
||||
@ -159,6 +176,7 @@ struct scmi_raw_mode_info {
|
||||
const struct scmi_desc *desc;
|
||||
int tx_max_msg;
|
||||
struct scmi_raw_queue *q[SCMI_RAW_MAX_QUEUE];
|
||||
struct xarray chans_q;
|
||||
struct list_head free_waiters;
|
||||
/* Protect free_waiters list */
|
||||
struct mutex free_mtx;
|
||||
@ -208,6 +226,8 @@ struct scmi_raw_buffer {
|
||||
* 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.
|
||||
@ -216,6 +236,7 @@ struct scmi_raw_buffer {
|
||||
* @rx_size: The effective size of the RX message.
|
||||
*/
|
||||
struct scmi_dbg_raw_data {
|
||||
u8 chan_id;
|
||||
struct scmi_raw_mode_info *raw;
|
||||
struct scmi_msg tx;
|
||||
size_t tx_size;
|
||||
@ -224,6 +245,16 @@ struct scmi_dbg_raw_data {
|
||||
size_t rx_size;
|
||||
};
|
||||
|
||||
static struct scmi_raw_queue *
|
||||
scmi_raw_queue_select(struct scmi_raw_mode_info *raw, unsigned int idx,
|
||||
unsigned int chan_id)
|
||||
{
|
||||
if (!chan_id)
|
||||
return raw->q[idx];
|
||||
|
||||
return xa_load(&raw->chans_q, chan_id);
|
||||
}
|
||||
|
||||
static struct scmi_raw_buffer *scmi_raw_buffer_get(struct scmi_raw_queue *q)
|
||||
{
|
||||
unsigned long flags;
|
||||
@ -563,6 +594,8 @@ static int scmi_xfer_raw_get_init(struct scmi_raw_mode_info *raw, void *buf,
|
||||
*
|
||||
* @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
|
||||
@ -576,14 +609,20 @@ static int scmi_xfer_raw_get_init(struct scmi_raw_mode_info *raw, void *buf,
|
||||
* Return: 0 on Success
|
||||
*/
|
||||
static int scmi_do_xfer_raw_start(struct scmi_raw_mode_info *raw,
|
||||
struct scmi_xfer *xfer, bool async)
|
||||
struct scmi_xfer *xfer, u8 chan_id,
|
||||
bool async)
|
||||
{
|
||||
int ret;
|
||||
struct scmi_chan_info *cinfo;
|
||||
struct scmi_xfer_raw_waiter *rw;
|
||||
struct device *dev = raw->handle->dev;
|
||||
|
||||
cinfo = scmi_xfer_raw_channel_get(raw->handle, xfer->hdr.protocol_id);
|
||||
if (!chan_id)
|
||||
chan_id = xfer->hdr.protocol_id;
|
||||
else
|
||||
xfer->flags |= SCMI_XFER_FLAG_CHAN_SET;
|
||||
|
||||
cinfo = scmi_xfer_raw_channel_get(raw->handle, chan_id);
|
||||
if (IS_ERR(cinfo))
|
||||
return PTR_ERR(cinfo);
|
||||
|
||||
@ -630,12 +669,13 @@ static int scmi_do_xfer_raw_start(struct scmi_raw_mode_info *raw,
|
||||
* @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.
|
||||
*
|
||||
* Return: 0 on Success
|
||||
*/
|
||||
static int scmi_raw_message_send(struct scmi_raw_mode_info *raw,
|
||||
void *buf, size_t len, bool async)
|
||||
void *buf, size_t len, u8 chan_id, bool async)
|
||||
{
|
||||
int ret;
|
||||
struct scmi_xfer *xfer;
|
||||
@ -644,7 +684,7 @@ static int scmi_raw_message_send(struct scmi_raw_mode_info *raw,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = scmi_do_xfer_raw_start(raw, xfer, async);
|
||||
ret = scmi_do_xfer_raw_start(raw, xfer, chan_id, async);
|
||||
if (ret)
|
||||
scmi_xfer_raw_put(raw->handle, xfer);
|
||||
|
||||
@ -687,18 +727,23 @@ scmi_raw_message_dequeue(struct scmi_raw_queue *q, bool o_nonblock)
|
||||
* @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
|
||||
*/
|
||||
static int scmi_raw_message_receive(struct scmi_raw_mode_info *raw,
|
||||
void *buf, size_t len, size_t *size,
|
||||
unsigned int idx,
|
||||
unsigned int idx, unsigned int chan_id,
|
||||
bool o_nonblock)
|
||||
{
|
||||
int ret = 0;
|
||||
struct scmi_raw_buffer *rb;
|
||||
struct scmi_raw_queue *q = raw->q[idx];
|
||||
struct scmi_raw_queue *q;
|
||||
|
||||
q = scmi_raw_queue_select(raw, idx, chan_id);
|
||||
if (!q)
|
||||
return -ENODEV;
|
||||
|
||||
rb = scmi_raw_message_dequeue(q, o_nonblock);
|
||||
if (IS_ERR(rb)) {
|
||||
@ -732,7 +777,7 @@ static ssize_t scmi_dbg_raw_mode_common_read(struct file *filp,
|
||||
int ret;
|
||||
|
||||
ret = scmi_raw_message_receive(rd->raw, rd->rx.buf, rd->rx.len,
|
||||
&rd->rx_size, idx,
|
||||
&rd->rx_size, idx, rd->chan_id,
|
||||
filp->f_flags & O_NONBLOCK);
|
||||
if (ret) {
|
||||
rd->rx_size = 0;
|
||||
@ -782,7 +827,8 @@ static ssize_t scmi_dbg_raw_mode_common_write(struct file *filp,
|
||||
return cnt;
|
||||
}
|
||||
|
||||
ret = scmi_raw_message_send(rd->raw, rd->tx.buf, rd->tx_size, async);
|
||||
ret = scmi_raw_message_send(rd->raw, rd->tx.buf, rd->tx_size,
|
||||
rd->chan_id, async);
|
||||
|
||||
/* Reset ppos for next message ... */
|
||||
rd->tx_size = 0;
|
||||
@ -797,9 +843,13 @@ static __poll_t scmi_test_dbg_raw_common_poll(struct file *filp,
|
||||
{
|
||||
unsigned long flags;
|
||||
struct scmi_dbg_raw_data *rd = filp->private_data;
|
||||
struct scmi_raw_queue *q = rd->raw->q[idx];
|
||||
struct scmi_raw_queue *q;
|
||||
__poll_t mask = 0;
|
||||
|
||||
q = scmi_raw_queue_select(rd->raw, idx, rd->chan_id);
|
||||
if (!q)
|
||||
return mask;
|
||||
|
||||
poll_wait(filp, &q->wq, wait);
|
||||
|
||||
spin_lock_irqsave(&q->msg_q_lock, flags);
|
||||
@ -833,8 +883,10 @@ static __poll_t scmi_dbg_raw_mode_message_poll(struct file *filp,
|
||||
|
||||
static int scmi_dbg_raw_mode_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
u8 id;
|
||||
struct scmi_raw_mode_info *raw;
|
||||
struct scmi_dbg_raw_data *rd;
|
||||
const char *id_str = filp->f_path.dentry->d_parent->d_name.name;
|
||||
|
||||
if (!inode->i_private)
|
||||
return -ENODEV;
|
||||
@ -859,6 +911,10 @@ static int scmi_dbg_raw_mode_open(struct inode *inode, struct file *filp)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Grab channel ID from debugfs entry naming if any */
|
||||
if (!kstrtou8(id_str, 16, &id))
|
||||
rd->chan_id = id;
|
||||
|
||||
rd->raw = raw;
|
||||
filp->private_data = rd;
|
||||
|
||||
@ -1028,7 +1084,8 @@ static int scmi_xfer_raw_worker_init(struct scmi_raw_mode_info *raw)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw)
|
||||
static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw,
|
||||
u8 *channels, int num_chans)
|
||||
{
|
||||
int ret, idx;
|
||||
void *gid;
|
||||
@ -1046,15 +1103,43 @@ static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw)
|
||||
}
|
||||
}
|
||||
|
||||
xa_init(&raw->chans_q);
|
||||
if (num_chans > 1) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_chans; i++) {
|
||||
void *xret;
|
||||
struct scmi_raw_queue *q;
|
||||
|
||||
q = scmi_raw_queue_init(raw);
|
||||
if (IS_ERR(q)) {
|
||||
ret = PTR_ERR(q);
|
||||
goto err_xa;
|
||||
}
|
||||
|
||||
xret = xa_store(&raw->chans_q, channels[i], q,
|
||||
GFP_KERNEL);
|
||||
if (xa_err(xret)) {
|
||||
dev_err(dev,
|
||||
"Fail to allocate Raw queue 0x%02X\n",
|
||||
channels[i]);
|
||||
ret = xa_err(xret);
|
||||
goto err_xa;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = scmi_xfer_raw_worker_init(raw);
|
||||
if (ret)
|
||||
goto err;
|
||||
goto err_xa;
|
||||
|
||||
devres_close_group(dev, gid);
|
||||
raw->gid = gid;
|
||||
|
||||
return 0;
|
||||
|
||||
err_xa:
|
||||
xa_destroy(&raw->chans_q);
|
||||
err:
|
||||
devres_release_group(dev, gid);
|
||||
return ret;
|
||||
@ -1067,6 +1152,8 @@ err:
|
||||
* @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
|
||||
*
|
||||
@ -1076,6 +1163,7 @@ err:
|
||||
*/
|
||||
void *scmi_raw_mode_init(const struct scmi_handle *handle,
|
||||
struct dentry *top_dentry, int instance_id,
|
||||
u8 *channels, int num_chans,
|
||||
const struct scmi_desc *desc, int tx_max_msg)
|
||||
{
|
||||
int ret;
|
||||
@ -1095,7 +1183,7 @@ void *scmi_raw_mode_init(const struct scmi_handle *handle,
|
||||
raw->tx_max_msg = tx_max_msg;
|
||||
raw->id = instance_id;
|
||||
|
||||
ret = scmi_raw_mode_setup(raw);
|
||||
ret = scmi_raw_mode_setup(raw, channels, num_chans);
|
||||
if (ret) {
|
||||
devm_kfree(dev, raw);
|
||||
return ERR_PTR(ret);
|
||||
@ -1118,6 +1206,32 @@ void *scmi_raw_mode_init(const struct scmi_handle *handle,
|
||||
debugfs_create_file("errors", 0400, raw->dentry, raw,
|
||||
&scmi_dbg_raw_mode_errors_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("channels", raw->dentry);
|
||||
|
||||
for (i = 0; i < num_chans; i++) {
|
||||
char cdir[8];
|
||||
struct dentry *chd;
|
||||
|
||||
snprintf(cdir, 8, "0x%02X", channels[i]);
|
||||
chd = debugfs_create_dir(cdir, top_chans);
|
||||
|
||||
debugfs_create_file("message", 0600, chd, raw,
|
||||
&scmi_dbg_raw_mode_message_fops);
|
||||
|
||||
debugfs_create_file("message_async", 0600, chd, raw,
|
||||
&scmi_dbg_raw_mode_message_async_fops);
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(dev, "SCMI RAW Mode initialized for instance %d\n", raw->id);
|
||||
|
||||
return raw;
|
||||
@ -1139,6 +1253,7 @@ void scmi_raw_mode_cleanup(void *r)
|
||||
|
||||
cancel_work_sync(&raw->waiters_work);
|
||||
destroy_workqueue(raw->wait_wq);
|
||||
xa_destroy(&raw->chans_q);
|
||||
}
|
||||
|
||||
static int scmi_xfer_raw_collect(void *msg, size_t *msg_len,
|
||||
@ -1178,6 +1293,7 @@ static int scmi_xfer_raw_collect(void *msg, size_t *msg_len,
|
||||
* @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
|
||||
@ -1187,7 +1303,8 @@ static int scmi_xfer_raw_collect(void *msg, size_t *msg_len,
|
||||
* user can read back the raw message payload at its own pace (if ever) without
|
||||
* holding an xfer for too long.
|
||||
*/
|
||||
void scmi_raw_message_report(void *r, struct scmi_xfer *xfer, unsigned int idx)
|
||||
void scmi_raw_message_report(void *r, struct scmi_xfer *xfer,
|
||||
unsigned int idx, unsigned int chan_id)
|
||||
{
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
@ -1200,7 +1317,8 @@ void scmi_raw_message_report(void *r, struct scmi_xfer *xfer, unsigned int idx)
|
||||
return;
|
||||
|
||||
dev = raw->handle->dev;
|
||||
q = raw->q[idx];
|
||||
q = scmi_raw_queue_select(raw, idx,
|
||||
SCMI_XFER_IS_CHAN_SET(xfer) ? chan_id : 0);
|
||||
|
||||
/*
|
||||
* Grab the msg_q_lock upfront to avoid a possible race between
|
||||
@ -1319,7 +1437,7 @@ void scmi_raw_error_report(void *r, struct scmi_chan_info *cinfo,
|
||||
smp_store_mb(xfer.priv, priv);
|
||||
|
||||
scmi_xfer_raw_fill(raw, cinfo, &xfer, msg_hdr);
|
||||
scmi_raw_message_report(raw, &xfer, SCMI_RAW_ERRS_QUEUE);
|
||||
scmi_raw_message_report(raw, &xfer, SCMI_RAW_ERRS_QUEUE, 0);
|
||||
|
||||
kfree(xfer.rx.buf);
|
||||
}
|
||||
|
@ -19,11 +19,12 @@ enum {
|
||||
|
||||
void *scmi_raw_mode_init(const struct scmi_handle *handle,
|
||||
struct dentry *top_dentry, int instance_id,
|
||||
u8 *channels, int num_chans,
|
||||
const struct scmi_desc *desc, int tx_max_msg);
|
||||
void scmi_raw_mode_cleanup(void *raw);
|
||||
|
||||
void scmi_raw_message_report(void *raw, struct scmi_xfer *xfer,
|
||||
unsigned int idx);
|
||||
unsigned int idx, unsigned int chan_id);
|
||||
void scmi_raw_error_report(void *raw, struct scmi_chan_info *cinfo,
|
||||
u32 msg_hdr, void *priv);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user