From 2e4da2653a970b7c66a5e608bcc4005e81d516a3 Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Mon, 10 Oct 2022 18:28:37 -0700 Subject: [PATCH] soc: qcom: llcc: Introduce APIs to support staling mode Staling mode (Capacity-based or notification-based) is a new feature that allows for clients to influence cache replacement for their sub-cache in real time. Introducing two new APIs: - llcc_configure_staling_mode() allows for clients to configure the staling mode and specify mode-specific parameters such as the staling distance for the notification-based mode. - llcc_notif_staling_inc_counter() increments the frame staling counter that ultimately marks previously cached memory at a user-configurable frame distance for eviction. Change-Id: Ied032cd0bead377e294b568a73a713e61159ac2c Signed-off-by: Guru Das Srinagesh --- drivers/soc/qcom/llcc-qcom.c | 122 +++++++++++++++++++++++++++++ include/linux/soc/qcom/llcc-qcom.h | 57 +++++++++++++- 2 files changed, 178 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index c0c350747849..26513773b1c3 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -47,6 +47,14 @@ #define LLCC_TRP_ACT_CTRLn(n) (n * SZ_4K) #define LLCC_TRP_ACT_CLEARn(n) (8 + n * SZ_4K) #define LLCC_TRP_STATUSn(n) (4 + n * SZ_4K) + +#define LLCC_TRP_STAL_ATTR0_CFGn(n) (0xC + SZ_4K * n) +#define STALING_TRIGGER_MASK 0x1 + +#define LLCC_TRP_STAL_ATTR1_CFGn(n) (0x10 + SZ_4K * n) +#define STALING_ENABLE_MASK 0x1 +#define STALING_NUM_FRAMES_MASK GENMASK(6, 4) + #define LLCC_TRP_ATTR0_CFGn(n) (0x21000 + SZ_8 * n) #define LLCC_TRP_ATTR1_CFGn(n) (0x21004 + SZ_8 * n) #define LLCC_TRP_ATTR2_CFGn(n) (0x21100 + SZ_4 * n) @@ -678,6 +686,120 @@ size_t llcc_get_slice_size(struct llcc_slice_desc *desc) } EXPORT_SYMBOL_GPL(llcc_get_slice_size); +static int llcc_staling_conf_capacity(u32 sid, struct llcc_staling_mode_params *p) +{ + u32 notif_staling_reg; + + notif_staling_reg = LLCC_TRP_STAL_ATTR1_CFGn(sid); + + return regmap_update_bits(drv_data->bcast_regmap, notif_staling_reg, + STALING_ENABLE_MASK, + LLCC_STALING_MODE_CAPACITY); +} + +static int llcc_staling_conf_notify(u32 sid, struct llcc_staling_mode_params *p) +{ + u32 notif_staling_reg, staling_distance; + int ret; + + if (p->notify_params.op != LLCC_NOTIFY_STALING_WRITEBACK) + return -EINVAL; + + notif_staling_reg = LLCC_TRP_STAL_ATTR1_CFGn(sid); + + ret = regmap_update_bits(drv_data->bcast_regmap, notif_staling_reg, + STALING_ENABLE_MASK, + LLCC_STALING_MODE_NOTIFY); + if (ret) + return ret; + + staling_distance = p->notify_params.staling_distance; + + return regmap_update_bits(drv_data->bcast_regmap, notif_staling_reg, + STALING_NUM_FRAMES_MASK, staling_distance); +} + +static int (*staling_mode_ops[LLCC_STALING_MODE_MAX])(u32, struct llcc_staling_mode_params *) = { + [LLCC_STALING_MODE_CAPACITY] = llcc_staling_conf_capacity, + [LLCC_STALING_MODE_NOTIFY] = llcc_staling_conf_notify, +}; + +/** + * llcc_configure_staling_mode - Configure cache staling mode by setting the + * staling_mode and corresponding + * mode-specific params + * + * @desc: Pointer to llcc slice descriptor + * @p: Staling mode-specific params + * + * Returns: zero on success or negative errno. + */ +int llcc_configure_staling_mode(struct llcc_slice_desc *desc, + struct llcc_staling_mode_params *p) + +{ + u32 sid; + enum llcc_staling_mode m; + + if (IS_ERR(drv_data)) + return PTR_ERR(drv_data); + + if (drv_data->llcc_ver < 50) + return -EOPNOTSUPP; + + if (IS_ERR_OR_NULL(desc) || !p) + return -EINVAL; + + sid = desc->slice_id; + m = p->staling_mode; + + /* + * Look up op corresponding to staling mode and call it + * with the params passed + */ + return (*staling_mode_ops[m])(sid, p); + +} +EXPORT_SYMBOL(llcc_configure_staling_mode); + +/** + * llcc_notif_staling_inc_counter - Trigger the staling of the sub-cache frame. + * + * @desc: Pointer to llcc slice descriptor + * + * Returns: zero on success or negative errno. + */ +int llcc_notif_staling_inc_counter(struct llcc_slice_desc *desc) +{ + u32 sid, stale_trigger_reg, discard; + int ret; + + if (IS_ERR(drv_data)) + return PTR_ERR(drv_data); + + if (drv_data->llcc_ver < 50) + return -EOPNOTSUPP; + + if (IS_ERR_OR_NULL(desc)) + return -EINVAL; + + sid = desc->slice_id; + stale_trigger_reg = LLCC_TRP_STAL_ATTR0_CFGn(sid); + + ret = regmap_update_bits(drv_data->bcast_regmap, stale_trigger_reg, + STALING_TRIGGER_MASK, STALING_TRIGGER_MASK); + if (ret) + return ret; + + /* + * stale_trigger_reg is a self-clearing reg. Read it anyway to ensure + * that the write went through. We don't care about the value being + * read, so discard it. + */ + return regmap_read(drv_data->bcast_regmap, stale_trigger_reg, &discard); +} +EXPORT_SYMBOL(llcc_notif_staling_inc_counter); + static int qcom_llcc_cfg_program(struct platform_device *pdev) { int i; diff --git a/include/linux/soc/qcom/llcc-qcom.h b/include/linux/soc/qcom/llcc-qcom.h index 8eab6006c3bc..30d282b7bd55 100644 --- a/include/linux/soc/qcom/llcc-qcom.h +++ b/include/linux/soc/qcom/llcc-qcom.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. - * + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -124,6 +124,32 @@ struct llcc_drv_data { struct llcc_slice_desc *desc; }; +/** + * Enum describing the various staling modes available for clients to use. + */ +enum llcc_staling_mode { + LLCC_STALING_MODE_CAPACITY, /* Default option on reset */ + LLCC_STALING_MODE_NOTIFY, + LLCC_STALING_MODE_MAX +}; + +enum llcc_staling_notify_op { + LLCC_NOTIFY_STALING_WRITEBACK, + /* LLCC_NOTIFY_STALING_NO_WRITEBACK, */ + LLCC_NOTIFY_STALING_OPS_MAX +}; + +struct llcc_staling_mode_params { + enum llcc_staling_mode staling_mode; + union { + /* STALING_MODE_CAPACITY needs no params */ + struct staling_mode_notify_params { + u8 staling_distance; + enum llcc_staling_notify_op op; + } notify_params; + }; +}; + #if IS_ENABLED(CONFIG_QCOM_LLCC) /** * llcc_slice_getd - get llcc slice descriptor @@ -161,6 +187,26 @@ int llcc_slice_activate(struct llcc_slice_desc *desc); */ int llcc_slice_deactivate(struct llcc_slice_desc *desc); +/** + * llcc_configure_staling_mode - Configure cache staling mode by setting the + * staling_mode and corresponding + * mode-specific params + * + * @desc: Pointer to llcc slice descriptor + * @p: Staling mode-specific params + * + * Returns: zero on success or negative errno. + */ +int llcc_configure_staling_mode(struct llcc_slice_desc *desc, + struct llcc_staling_mode_params *p); +/** + * llcc_notif_staling_inc_counter - Trigger the staling of the sub-cache frame. + * + * @desc: Pointer to llcc slice descriptor + * + * Returns: zero on success or negative errno. + */ +int llcc_notif_staling_inc_counter(struct llcc_slice_desc *desc); #else static inline struct llcc_slice_desc *llcc_slice_getd(u32 uid) { @@ -190,6 +236,15 @@ static inline int llcc_slice_deactivate(struct llcc_slice_desc *desc) { return -EINVAL; } +static int llcc_configure_staling_mode(struct llcc_slice_desc *desc, + struct llcc_staling_mode_params *p) +{ + return -EINVAL; +} +static inline int llcc_notif_staling_inc_counter(struct llcc_slice_desc *desc) +{ + return -EINVAL; +} #endif #endif