Merge "soc: qcom: rpmh-rsc: Add support for multiple DRVs"

This commit is contained in:
qctecmdr 2022-05-10 11:43:35 -07:00 committed by Gerrit - the friendly Code Review server
commit fb8eb48d75
5 changed files with 628 additions and 294 deletions

View File

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016-2018, 2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2016-2018, 2020-2021, The Linux Foundation. All rights reserved.
*/
@ -11,6 +11,12 @@
#include <linux/wait.h>
#include <soc/qcom/tcs.h>
#define MAX_NAME_LENGTH 20
#define CH0 0
#define CH1 1
#define MAX_CHANNEL 2
#define TCS_TYPE_NR 5
#define MAX_CMDS_PER_TCS 16
#define MAX_TCS_PER_TYPE 3
@ -62,7 +68,6 @@ struct tcs_group {
* @cmd: the payload that will be part of the @msg
* @completion: triggered when request is done
* @dev: the device making the request
* @err: err return from the controller
* @needs_free: check to free dynamically allocated request object
*/
struct rpmh_request {
@ -70,7 +75,6 @@ struct rpmh_request {
struct tcs_cmd cmd[MAX_RPMH_PAYLOAD];
struct completion *completion;
const struct device *dev;
int err;
bool needs_free;
};
@ -93,21 +97,38 @@ struct rpmh_ctrlr {
struct list_head batch_cache;
};
/**
* struct drv_channel: our representation of the drv channels
*
* @tcs: TCS groups.
* @drv: DRV containing the channel
* @initialized: Whether channel is initialized
*/
struct drv_channel {
struct tcs_group tcs[TCS_TYPE_NR];
struct rsc_drv *drv;
bool initialized;
};
/**
* struct rsc_drv: the Direct Resource Voter (DRV) of the
* Resource State Coordinator controller (RSC)
*
* @name: Controller identifier.
* @base: Base address of the RSC controller.
* @tcs_base: Start address of the TCS registers in this controller.
* @reg: Register offsets for RSC controller.
* @id: Instance id in the controller (Direct Resource Voter).
* @num_tcs: Number of TCSes in this DRV.
* @num_channels: Number of channels in this DRV.
* @irq: IRQ at gic.
* @in_solver_mode: Controller is busy in solver mode
* @initialized: Whether DRV is initialized
* @rsc_pm: CPU PM notifier for controller.
* Used when solver mode is not present.
* @cpus_in_pm: Number of CPUs not in idle power collapse.
* Used when solver mode is not present.
* @tcs: TCS groups.
* @ch: DRV channels.
* @tcs_in_use: S/W state of the TCS; only set for ACTIVE_ONLY
* transfers, but might show a sleep/wake TCS in use if
* it was borrowed for an active_only transfer. You
@ -121,41 +142,51 @@ struct rpmh_ctrlr {
* @client: Handle to the DRV's client.
* @genpd_nb: PM Domain notifier
* @dev: RSC device
* @ipc_log_ctx: IPC logger handle
* @pdev: platform device
*/
struct rsc_drv {
const char *name;
char name[MAX_NAME_LENGTH];
void __iomem *base;
void __iomem *tcs_base;
u32 *regs;
int id;
int num_tcs;
int num_channels;
int irq;
bool in_solver_mode;
bool initialized;
struct notifier_block rsc_pm;
atomic_t cpus_in_pm;
struct tcs_group tcs[TCS_TYPE_NR];
struct drv_channel ch[MAX_CHANNEL];
DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR);
spinlock_t lock;
wait_queue_head_t tcs_wait;
struct rpmh_ctrlr client;
struct notifier_block genpd_nb;
struct device *dev;
void *ipc_log_ctx;
struct platform_device *pdev;
};
extern bool rpmh_standalone;
int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg);
int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg, int ch);
int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv,
const struct tcs_request *msg);
void rpmh_rsc_invalidate(struct rsc_drv *drv);
const struct tcs_request *msg,
int ch);
void rpmh_rsc_invalidate(struct rsc_drv *drv, int ch);
void rpmh_rsc_debug(struct rsc_drv *drv, struct completion *compl);
int rpmh_rsc_mode_solver_set(struct rsc_drv *drv, bool enable);
int rpmh_rsc_get_channel(struct rsc_drv *drv);
void rpmh_tx_done(const struct tcs_request *msg, int r);
int rpmh_flush(struct rpmh_ctrlr *ctrlr);
int _rpmh_flush(struct rpmh_ctrlr *ctrlr);
void rpmh_tx_done(const struct tcs_request *msg);
int rpmh_flush(struct rpmh_ctrlr *ctrlr, int ch);
int _rpmh_flush(struct rpmh_ctrlr *ctrlr, int ch);
int rpmh_rsc_init_fast_path(struct rsc_drv *drv, const struct tcs_request *msg);
int rpmh_rsc_init_fast_path(struct rsc_drv *drv, const struct tcs_request *msg, int ch);
int rpmh_rsc_update_fast_path(struct rsc_drv *drv,
const struct tcs_request *msg,
u32 update_mask);
u32 update_mask, int ch);
#endif /* __RPM_INTERNAL_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016-2018, 2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2016-2018, 2020-2021, The Linux Foundation. All rights reserved.
*/
#include <linux/atomic.h>
@ -66,7 +66,7 @@ struct cache_req {
struct batch_cache_req {
struct list_head list;
int count;
struct rpmh_request rpm_msgs[];
struct rpmh_request *rpm_msgs;
};
static struct rpmh_ctrlr *get_rpmh_ctrlr(const struct device *dev)
@ -95,19 +95,13 @@ static int check_ctrlr_state(struct rpmh_ctrlr *ctrlr, enum rpmh_state state)
return ret;
}
void rpmh_tx_done(const struct tcs_request *msg, int r)
void rpmh_tx_done(const struct tcs_request *msg)
{
struct rpmh_request *rpm_msg = container_of(msg, struct rpmh_request,
msg);
struct completion *compl = rpm_msg->completion;
bool free = rpm_msg->needs_free;
rpm_msg->err = r;
if (r)
dev_err(rpm_msg->dev, "RPMH TX fail in msg addr=%#x, err=%d\n",
rpm_msg->msg.cmds[0].addr, r);
if (!compl)
goto exit;
@ -198,7 +192,7 @@ static int __rpmh_write(const struct device *dev, enum rpmh_state state,
struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
int ret = -EINVAL;
struct cache_req *req;
int i;
int i, ch;
/* Cache the request in our store and link the payload */
for (i = 0; i < rpm_msg->msg.num_cmds; i++) {
@ -209,11 +203,16 @@ static int __rpmh_write(const struct device *dev, enum rpmh_state state,
if (state == RPMH_ACTIVE_ONLY_STATE) {
WARN_ON(irqs_disabled());
ret = rpmh_rsc_send_data(ctrlr_to_drv(ctrlr), &rpm_msg->msg);
ch = rpmh_rsc_get_channel(ctrlr_to_drv(ctrlr));
if (ch < 0)
return ch;
ret = rpmh_rsc_send_data(ctrlr_to_drv(ctrlr), &rpm_msg->msg, ch);
} else {
/* Clean up our call by spoofing tx_done */
ret = 0;
rpmh_tx_done(&rpm_msg->msg, ret);
rpmh_tx_done(&rpm_msg->msg);
}
return ret;
@ -327,7 +326,7 @@ static void cache_batch(struct rpmh_ctrlr *ctrlr, struct batch_cache_req *req)
spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
}
static int flush_batch(struct rpmh_ctrlr *ctrlr)
static int flush_batch(struct rpmh_ctrlr *ctrlr, int ch)
{
struct batch_cache_req *req;
const struct rpmh_request *rpm_msg;
@ -339,7 +338,7 @@ static int flush_batch(struct rpmh_ctrlr *ctrlr)
for (i = 0; i < req->count; i++) {
rpm_msg = req->rpm_msgs + i;
ret = rpmh_rsc_write_ctrl_data(ctrlr_to_drv(ctrlr),
&rpm_msg->msg);
&rpm_msg->msg, ch);
if (ret)
break;
}
@ -374,7 +373,7 @@ int rpmh_write_batch(const struct device *dev, enum rpmh_state state,
struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
unsigned long time_left;
int count = 0;
int ret, i;
int ret, i, ch;
void *ptr;
if (rpmh_standalone)
@ -399,10 +398,11 @@ int rpmh_write_batch(const struct device *dev, enum rpmh_state state,
return -ENOMEM;
req = ptr;
rpm_msgs = ptr + sizeof(*req);
compls = ptr + sizeof(*req) + count * sizeof(*rpm_msgs);
req->count = count;
rpm_msgs = req->rpm_msgs;
req->rpm_msgs = rpm_msgs;
for (i = 0; i < count; i++) {
__fill_rpmh_msg(rpm_msgs + i, state, cmd, n[i]);
@ -414,12 +414,18 @@ int rpmh_write_batch(const struct device *dev, enum rpmh_state state,
return 0;
}
ch = rpmh_rsc_get_channel(ctrlr_to_drv(ctrlr));
if (ch < 0) {
kfree(ptr);
return ch;
}
for (i = 0; i < count; i++) {
struct completion *compl = &compls[i];
init_completion(compl);
rpm_msgs[i].completion = compl;
ret = rpmh_rsc_send_data(ctrlr_to_drv(ctrlr), &rpm_msgs[i].msg);
ret = rpmh_rsc_send_data(ctrlr_to_drv(ctrlr), &rpm_msgs[i].msg, ch);
if (ret) {
pr_err("Error(%d) sending RPMH message addr=%#x\n",
ret, rpm_msgs[i].msg.cmds[0].addr);
@ -437,12 +443,10 @@ int rpmh_write_batch(const struct device *dev, enum rpmh_state state,
* we've returned from this function.
*/
rpmh_rsc_debug(ctrlr_to_drv(ctrlr), &compls[i]);
ret = -ETIMEDOUT;
goto exit;
BUG_ON(1);
}
}
exit:
kfree(ptr);
return ret;
@ -457,7 +461,7 @@ static int is_req_valid(struct cache_req *req)
}
static int send_single(struct rpmh_ctrlr *ctrlr, enum rpmh_state state,
u32 addr, u32 data)
u32 addr, u32 data, int ch)
{
DEFINE_RPMH_MSG_ONSTACK(NULL, state, NULL, rpm_msg);
@ -467,10 +471,10 @@ static int send_single(struct rpmh_ctrlr *ctrlr, enum rpmh_state state,
rpm_msg.cmd[0].data = data;
rpm_msg.msg.num_cmds = 1;
return rpmh_rsc_write_ctrl_data(ctrlr_to_drv(ctrlr), &rpm_msg.msg);
return rpmh_rsc_write_ctrl_data(ctrlr_to_drv(ctrlr), &rpm_msg.msg, ch);
}
int _rpmh_flush(struct rpmh_ctrlr *ctrlr)
int _rpmh_flush(struct rpmh_ctrlr *ctrlr, int ch)
{
struct cache_req *p;
int ret = 0;
@ -481,10 +485,10 @@ int _rpmh_flush(struct rpmh_ctrlr *ctrlr)
}
/* Invalidate the TCSes first to avoid stale data */
rpmh_rsc_invalidate(ctrlr_to_drv(ctrlr));
rpmh_rsc_invalidate(ctrlr_to_drv(ctrlr), ch);
/* First flush the cached batch requests */
ret = flush_batch(ctrlr);
ret = flush_batch(ctrlr, ch);
if (ret)
return ret;
@ -495,11 +499,11 @@ int _rpmh_flush(struct rpmh_ctrlr *ctrlr)
continue;
}
ret = send_single(ctrlr, RPMH_SLEEP_STATE, p->addr,
p->sleep_val);
p->sleep_val, ch);
if (ret)
return ret;
ret = send_single(ctrlr, RPMH_WAKE_ONLY_STATE, p->addr,
p->wake_val);
p->wake_val, ch);
if (ret)
return ret;
}
@ -513,12 +517,13 @@ int _rpmh_flush(struct rpmh_ctrlr *ctrlr)
* rpmh_flush() - Flushes the buffered sleep and wake sets to TCSes
*
* @ctrlr: Controller making request to flush cached data
* @ch: Channel number
*
* Return:
* * 0 - Success
* * Error code - Otherwise
*/
int rpmh_flush(struct rpmh_ctrlr *ctrlr)
int rpmh_flush(struct rpmh_ctrlr *ctrlr, int ch)
{
int ret;
@ -545,7 +550,7 @@ int rpmh_flush(struct rpmh_ctrlr *ctrlr)
*/
if (!spin_trylock(&ctrlr->cache_lock))
return -EBUSY;
ret = _rpmh_flush(ctrlr);
ret = _rpmh_flush(ctrlr, ch);
spin_unlock(&ctrlr->cache_lock);
return ret;
@ -562,7 +567,14 @@ int rpmh_flush(struct rpmh_ctrlr *ctrlr)
*/
int rpmh_write_sleep_and_wake(const struct device *dev)
{
return rpmh_flush(get_rpmh_ctrlr(dev));
struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
int ch;
ch = rpmh_rsc_get_channel(ctrlr_to_drv(ctrlr));
if (ch < 0)
return ch;
return rpmh_flush(ctrlr, ch);
}
EXPORT_SYMBOL(rpmh_write_sleep_and_wake);
@ -583,8 +595,11 @@ void rpmh_invalidate(const struct device *dev)
return;
spin_lock_irqsave(&ctrlr->cache_lock, flags);
list_for_each_entry_safe(req, tmp, &ctrlr->batch_cache, list)
list_for_each_entry_safe(req, tmp, &ctrlr->batch_cache, list) {
list_del(&req->list);
kfree(req);
}
INIT_LIST_HEAD(&ctrlr->batch_cache);
ctrlr->dirty = true;
spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
@ -621,3 +636,90 @@ int rpmh_mode_solver_set(const struct device *dev, bool enable)
return ret;
}
EXPORT_SYMBOL(rpmh_mode_solver_set);
/**
* RPMH Fast Path mode
*
* - Fast path mode is a lock-less request transmission to AOSS.
* - Requests may be sent from interrupt/scheduler context.
* - Dedicated fast-path TCS must be available in the RSC.
* - Error returned, when dedicated TCS is not available.
* - Only one client is expected to call RPMH fast path.
* - Serialization of requests is a responsibility of the client.
* - Only active state requests may be made through this mode.
* - Sleep/Wake requests for the nodes must be made through
* the standard RPMH APIs (locking modes).
* - Fast path requests are not cached and sent immediately.
* - Fast path requests are all blocking requests.
* - Fast path requests do not use AMC completion interrupts,
* therefore will not receive a tx_done callback.
*/
/**
* rpmh_init_fast_path: Initialize TCS request in fast-path TCS
*
* @dev: The device making the request
* @cmd: The {addr, data} to be initialized with.
* @n: The number of @cmd
*
* Return:
* * 0 - Success
* * Error code - Otherwise
*/
int rpmh_init_fast_path(const struct device *dev,
struct tcs_cmd *cmd, int n)
{
struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
struct tcs_request req;
int ch;
if (rpmh_standalone)
return 0;
ch = rpmh_rsc_get_channel(ctrlr_to_drv(ctrlr));
if (ch < 0)
return ch;
req.cmds = cmd;
req.num_cmds = n;
req.wait_for_compl = 0;
return rpmh_rsc_init_fast_path(ctrlr_to_drv(ctrlr), &req, ch);
}
EXPORT_SYMBOL(rpmh_init_fast_path);
/**
* rpmh_update_fast_path: Initialize TCS request in fast-path TCS
*
* @dev: The device making the request
* @cmd: The data to be updated.
* @n: The number of @cmd
* @update_mask: The elements in @cmd that only need to be updated
*
* Return:
* * 0 - Success
* * Error code - Otherwise
*/
int rpmh_update_fast_path(const struct device *dev,
struct tcs_cmd *cmd, int n, u32 update_mask)
{
struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
struct tcs_request req;
int ch;
if (rpmh_standalone)
return 0;
ch = rpmh_rsc_get_channel(ctrlr_to_drv(ctrlr));
if (ch < 0)
return ch;
req.cmds = cmd;
req.num_cmds = n;
req.wait_for_compl = 0;
return rpmh_rsc_update_fast_path(ctrlr_to_drv(ctrlr), &req,
update_mask, ch);
}
EXPORT_SYMBOL(rpmh_update_fast_path);

View File

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2016-2019, 2021, The Linux Foundation. All rights reserved.
*/
#if !defined(_TRACE_RPMH_H) || defined(TRACE_HEADER_MULTI_READ)
@ -14,16 +14,15 @@
TRACE_EVENT(rpmh_tx_done,
TP_PROTO(struct rsc_drv *d, int m, const struct tcs_request *r, int e),
TP_PROTO(struct rsc_drv *d, int m, const struct tcs_request *r),
TP_ARGS(d, m, r, e),
TP_ARGS(d, m, r),
TP_STRUCT__entry(
__string(name, d->name)
__field(int, m)
__field(u32, addr)
__field(u32, data)
__field(int, err)
),
TP_fast_assign(
@ -31,12 +30,10 @@ TRACE_EVENT(rpmh_tx_done,
__entry->m = m;
__entry->addr = r->cmds[0].addr;
__entry->data = r->cmds[0].data;
__entry->err = e;
),
TP_printk("%s: ack: tcs-m: %d addr: %#x data: %#x errno: %d",
__get_str(name), __entry->m, __entry->addr, __entry->data,
__entry->err)
TP_printk("%s: ack: tcs-m: %d addr: %#x data: %#x",
__get_str(name), __entry->m, __entry->addr, __entry->data)
);
TRACE_EVENT(rpmh_send_msg,

View File

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*/
#ifndef __SOC_QCOM_RPMH_H__
@ -26,6 +26,11 @@ int rpmh_write_sleep_and_wake(const struct device *dev);
void rpmh_invalidate(const struct device *dev);
int rpmh_init_fast_path(const struct device *dev,
struct tcs_cmd *cmd, int n);
int rpmh_update_fast_path(const struct device *dev,
struct tcs_cmd *cmd, int n, u32 update_mask);
#else
static inline int rpmh_write(const struct device *dev, enum rpmh_state state,
@ -52,6 +57,15 @@ static inline void rpmh_invalidate(const struct device *dev)
{
}
static inline int rpmh_init_fast_path(const struct device *dev,
struct tcs_cmd *msg, int n)
{ return -ENODEV; }
static inline int rpmh_update_fast_path(const struct device *dev,
struct tcs_cmd *msg, int n,
u32 update_mask)
{ return -ENODEV; }
#endif /* CONFIG_QCOM_RPMH */
#endif /* __SOC_QCOM_RPMH_H__ */