@@ -77,12 +77,14 @@ struct rpmh_request {
* @cache: the list of cached requests
* @cache_lock: synchronize access to the cache data
* @dirty: was the cache updated since flush
+ * @in_solver_mode: Controller is busy in solver mode
* @batch_cache: Cache sleep and wake requests sent as batch
*/
struct rpmh_ctrlr {
struct list_head cache;
spinlock_t cache_lock;
bool dirty;
+ bool in_solver_mode;
struct list_head batch_cache;
};
@@ -94,6 +96,7 @@ struct rpmh_ctrlr {
* @tcs_base: Start address of the TCS registers in this controller.
* @id: Instance id in the controller (Direct Resource Voter).
* @num_tcs: Number of TCSes in this DRV.
+ * @in_solver_mode: Controller is busy in solver mode
* @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.
@@ -116,6 +119,7 @@ struct rsc_drv {
void __iomem *tcs_base;
int id;
int num_tcs;
+ bool in_solver_mode;
struct notifier_block rsc_pm;
atomic_t cpus_in_pm;
struct tcs_group tcs[TCS_TYPE_NR];
@@ -129,6 +133,7 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg);
int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv,
const struct tcs_request *msg);
void rpmh_rsc_invalidate(struct rsc_drv *drv);
+int rpmh_rsc_mode_solver_set(struct rsc_drv *drv, bool enable);
void rpmh_tx_done(const struct tcs_request *msg, int r);
int rpmh_flush(struct rpmh_ctrlr *ctrlr);
@@ -638,6 +638,12 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
spin_lock_irqsave(&drv->lock, flags);
+ if (drv->in_solver_mode) {
+ /* Controller is busy in 'solver' mode */
+ spin_unlock_irqrestore(&drv->lock, flags);
+ return -EBUSY;
+ }
+
/* Wait forever for a free tcs. It better be there eventually! */
wait_event_lock_irq(drv->tcs_wait,
(tcs_id = claim_tcs_for_req(drv, tcs, msg)) >= 0,
@@ -859,6 +865,31 @@ static int rpmh_rsc_cpu_pm_callback(struct notifier_block *nfb,
return ret;
}
+/**
+ * rpmh_rsc_mode_solver_set() - Enable/disable solver mode.
+ * @drv: The controller.
+ * @enable: Boolean state to be set - true/false
+ *
+ * Return:
+ * * 0 - success
+ * * -EBUSY - AMCs are busy
+ */
+int rpmh_rsc_mode_solver_set(struct rsc_drv *drv, bool enable)
+{
+ int ret = -EBUSY;
+
+ if (spin_trylock(&drv->lock)) {
+ if (!enable || !rpmh_rsc_ctrlr_is_busy(drv)) {
+ drv->in_solver_mode = enable;
+ trace_rpmh_solver_set(drv, enable);
+ ret = 0;
+ }
+ spin_unlock(&drv->lock);
+ }
+
+ return ret;
+}
+
static int rpmh_probe_tcs_config(struct platform_device *pdev,
struct rsc_drv *drv, void __iomem *base)
{
@@ -76,6 +76,22 @@ static struct rpmh_ctrlr *get_rpmh_ctrlr(const struct device *dev)
return &drv->client;
}
+static int check_ctrlr_state(struct rpmh_ctrlr *ctrlr, enum rpmh_state state)
+{
+ int ret = 0;
+
+ if (state != RPMH_ACTIVE_ONLY_STATE)
+ return ret;
+
+ /* Do not allow sending active votes when in solver mode */
+ spin_lock(&ctrlr->cache_lock);
+ if (ctrlr->in_solver_mode)
+ ret = -EBUSY;
+ spin_unlock(&ctrlr->cache_lock);
+
+ return ret;
+}
+
void rpmh_tx_done(const struct tcs_request *msg, int r)
{
struct rpmh_request *rpm_msg = container_of(msg, struct rpmh_request,
@@ -229,9 +245,14 @@ static int __fill_rpmh_msg(struct rpmh_request *req, enum rpmh_state state,
int rpmh_write_async(const struct device *dev, enum rpmh_state state,
const struct tcs_cmd *cmd, u32 n)
{
+ struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
struct rpmh_request *rpm_msg;
int ret;
+ ret = check_ctrlr_state(ctrlr, state);
+ if (ret)
+ return ret;
+
rpm_msg = kzalloc(sizeof(*rpm_msg), GFP_ATOMIC);
if (!rpm_msg)
return -ENOMEM;
@@ -262,8 +283,13 @@ int rpmh_write(const struct device *dev, enum rpmh_state state,
{
DECLARE_COMPLETION_ONSTACK(compl);
DEFINE_RPMH_MSG_ONSTACK(dev, state, &compl, rpm_msg);
+ struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
int ret;
+ ret = check_ctrlr_state(ctrlr, state);
+ if (ret)
+ return ret;
+
ret = __fill_rpmh_msg(&rpm_msg, state, cmd, n);
if (ret)
return ret;
@@ -338,6 +364,10 @@ int rpmh_write_batch(const struct device *dev, enum rpmh_state state,
int ret, i;
void *ptr;
+ ret = check_ctrlr_state(ctrlr, state);
+ if (ret)
+ return ret;
+
if (!cmd || !n)
return -EINVAL;
@@ -505,3 +535,29 @@ void rpmh_invalidate(const struct device *dev)
spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
}
EXPORT_SYMBOL(rpmh_invalidate);
+
+/**
+ * rpmh_mode_solver_set() - Indicate that the RSC controller hardware has
+ * been configured to be in solver mode
+ *
+ * @dev: The device making the request
+ * @enable: Boolean value indicating if the controller is in solver mode.
+ *
+ * Return:
+ * * 0 - Success
+ * * Error code - Otherwise
+ */
+int rpmh_mode_solver_set(const struct device *dev, bool enable)
+{
+ int ret;
+ struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
+
+ spin_lock(&ctrlr->cache_lock);
+ ret = rpmh_rsc_mode_solver_set(ctrlr_to_drv(ctrlr), enable);
+ if (!ret)
+ ctrlr->in_solver_mode = enable;
+ spin_unlock(&ctrlr->cache_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(rpmh_mode_solver_set);
@@ -71,6 +71,26 @@ TRACE_EVENT(rpmh_send_msg,
__entry->addr, __entry->data, __entry->wait)
);
+TRACE_EVENT(rpmh_solver_set,
+
+ TP_PROTO(struct rsc_drv *d, bool set),
+
+ TP_ARGS(d, set),
+
+ TP_STRUCT__entry(
+ __string(name, d->name)
+ __field(bool, set)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, d->name);
+ __entry->set = set;
+ ),
+
+ TP_printk("%s: solver mode set: %d",
+ __get_str(name), __entry->set)
+);
+
#endif /* _TRACE_RPMH_H */
#undef TRACE_INCLUDE_PATH
@@ -20,6 +20,8 @@ int rpmh_write_async(const struct device *dev, enum rpmh_state state,
int rpmh_write_batch(const struct device *dev, enum rpmh_state state,
const struct tcs_cmd *cmd, u32 *n);
+int rpmh_mode_solver_set(const struct device *dev, bool enable);
+
void rpmh_invalidate(const struct device *dev);
#else
@@ -38,6 +40,9 @@ static inline int rpmh_write_batch(const struct device *dev,
const struct tcs_cmd *cmd, u32 *n)
{ return -ENODEV; }
+static int rpmh_mode_solver_set(const struct device *dev, bool enable)
+{ return -ENODEV; }
+
static inline void rpmh_invalidate(const struct device *dev)
{
}