mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +03:00
platform: tegra: bwmgr: support error handling
When BWMGR is unavailable, BWMGR could be either unsupported and disabled in BPMP firmware. For unsupported state, MRQ_BWMGR_INT is not available to use. For disabled state, MRQ_BWMGR_INT is available but sending any MRQ_BWMGR_INT request will just get -BPMP_NODEV error code. Add error handling logic to make min_freq and max_freq devfreq sysfs nodes as read-only but still expose devfreq nodes, such as available_frequencies, min_freq, and max_freq, to allow user space apps to read information from. Bug 5555075 Change-Id: Id7c2695765d3dfee148a0d1bc1f7b0552fe4b343 Signed-off-by: Johnny Liu <johnliu@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3467128 Reviewed-by: svcacv <svcacv@nvidia.com> Reviewed-by: Rajkumar Kasirajan <rkasirajan@nvidia.com> GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
bf60517305
commit
d7466525c8
@@ -10,11 +10,13 @@
|
||||
#include <linux/devfreq.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/types.h>
|
||||
#if defined(NV_TEGRA264_BWMGR_DEBUG_MACRO_PRESENT)
|
||||
#include <linux/tegra264-bwmgr.h>
|
||||
@@ -32,6 +34,8 @@ struct tegra_bpmp_bwmgr {
|
||||
struct devfreq_dev_profile *devfreq_profile;
|
||||
struct notifier_block max_freq_nb;
|
||||
struct tegra_bpmp *bpmp;
|
||||
bool mrq_valid;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
#if defined(NV_TEGRA264_BWMGR_DEBUG_MACRO_PRESENT)
|
||||
@@ -63,13 +67,13 @@ static int tegra_bpmp_bwmgr_max_freq_notifier(struct notifier_block *nb, unsigne
|
||||
return err;
|
||||
}
|
||||
|
||||
if (msg.rx.ret < 0) {
|
||||
if (msg.rx.ret == 0) {
|
||||
dev_info(bwmgr->dev, "cap EMC frequency to %luHz\n", rate);
|
||||
} else {
|
||||
dev_err(bwmgr->dev, "failed to cap EMC frequency with %luHz: %d\n", rate, msg.rx.ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_info(bwmgr->dev, "cap EMC frequency to %luHz\n", rate);
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
@@ -111,6 +115,11 @@ static int tegra_bpmp_bwmgr_devfreq_target(struct device *dev, unsigned long *fr
|
||||
u32 khz;
|
||||
int err;
|
||||
|
||||
// This will be called once when calling devfreq_add_device. Need to
|
||||
// check early return if bwmgr is not supported.
|
||||
if (!bwmgr->mrq_valid || !bwmgr->enabled)
|
||||
return 0;
|
||||
|
||||
khz = *freq / 1000;
|
||||
bwmgr_req.cmd = CMD_BWMGR_INT_CALC_AND_SET;
|
||||
bwmgr_req.bwmgr_calc_set_req.mc_floor = khz;
|
||||
@@ -129,21 +138,36 @@ static int tegra_bpmp_bwmgr_devfreq_target(struct device *dev, unsigned long *fr
|
||||
return err;
|
||||
}
|
||||
|
||||
if (msg.rx.ret < 0) {
|
||||
dev_err(dev, "fail to set floor frequency with %uKHz\n", khz);
|
||||
if (msg.rx.ret == 0) {
|
||||
dev_info(dev, "set EMC floor frequency to %uKHz\n", khz);
|
||||
} else {
|
||||
dev_err(dev, "failed to set floor frequency with %uKHz: %d\n", khz, msg.rx.ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_bpmp_bwmgr_devfreq_cur_freq(struct device *dev, unsigned long *freq)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct tegra_bpmp_bwmgr *bwmgr = platform_get_drvdata(pdev);
|
||||
|
||||
*freq = clk_get_rate(bwmgr->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int tegra_bpmp_bwmgr_devfreq_register(struct tegra_bpmp_bwmgr *bwmgr)
|
||||
{
|
||||
#if defined(NV_TEGRA264_BWMGR_DEBUG_MACRO_PRESENT)
|
||||
static const struct attribute min_attr = { .name = "min_freq" };
|
||||
static const struct attribute max_attr = { .name = "max_freq" };
|
||||
unsigned long max_rate = clk_round_rate(bwmgr->clk, ULONG_MAX);
|
||||
unsigned long min_rate = clk_round_rate(bwmgr->clk, 0);
|
||||
unsigned long rate = min_rate;
|
||||
struct kobject *kobj = NULL;
|
||||
int ret = 0;
|
||||
|
||||
bwmgr->devfreq_profile = devm_kzalloc(bwmgr->dev, sizeof(*bwmgr->devfreq_profile), GFP_KERNEL);
|
||||
@@ -160,6 +184,7 @@ static int tegra_bpmp_bwmgr_devfreq_register(struct tegra_bpmp_bwmgr *bwmgr)
|
||||
|
||||
bwmgr->devfreq_profile->target = tegra_bpmp_bwmgr_devfreq_target;
|
||||
bwmgr->devfreq_profile->initial_freq = clk_get_rate(bwmgr->clk);
|
||||
bwmgr->devfreq_profile->get_cur_freq = tegra_bpmp_bwmgr_devfreq_cur_freq;
|
||||
bwmgr->devfreq = devm_devfreq_add_device(bwmgr->dev,
|
||||
bwmgr->devfreq_profile,
|
||||
DEVFREQ_GOV_BWMGR, NULL);
|
||||
@@ -168,6 +193,18 @@ static int tegra_bpmp_bwmgr_devfreq_register(struct tegra_bpmp_bwmgr *bwmgr)
|
||||
return PTR_ERR(bwmgr->devfreq);
|
||||
}
|
||||
|
||||
if (!bwmgr->mrq_valid || !bwmgr->enabled) {
|
||||
kobj = &bwmgr->devfreq->dev.kobj;
|
||||
|
||||
ret = sysfs_chmod_file(kobj, &min_attr, 0444);
|
||||
if (ret)
|
||||
dev_warn(bwmgr->dev, "fail to update min_freq as read-only\n");
|
||||
|
||||
ret = sysfs_chmod_file(kobj, &max_attr, 0444);
|
||||
if (ret)
|
||||
dev_warn(bwmgr->dev, "fail to update max_freq as read-only\n");
|
||||
}
|
||||
|
||||
bwmgr->max_freq_nb.notifier_call = tegra_bpmp_bwmgr_max_freq_notifier;
|
||||
ret = dev_pm_qos_add_notifier(bwmgr->dev,
|
||||
&bwmgr->max_freq_nb,
|
||||
@@ -197,6 +234,9 @@ static void tegra_bpmp_bwmgr_devfreq_unregister(struct tegra_bpmp_bwmgr *bwmgr)
|
||||
|
||||
static int tegra_bpmp_bwmgr_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mrq_bwmgr_int_request bwmgr_req = { 0 };
|
||||
struct mrq_bwmgr_int_request bwmgr_resp = { 0 };
|
||||
struct tegra_bpmp_message msg = { 0 };
|
||||
struct tegra_bpmp_bwmgr *bwmgr;
|
||||
int err;
|
||||
|
||||
@@ -212,6 +252,31 @@ static int tegra_bpmp_bwmgr_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(bwmgr->bpmp))
|
||||
return PTR_ERR(bwmgr->bpmp);
|
||||
|
||||
bwmgr->mrq_valid = tegra_bpmp_mrq_is_supported(bwmgr->bpmp, MRQ_BWMGR_INT);
|
||||
if (bwmgr->mrq_valid) {
|
||||
bwmgr_req.cmd = CMD_BWMGR_INT_CALC_AND_SET;
|
||||
bwmgr_req.bwmgr_calc_set_req.mc_floor = 0;
|
||||
bwmgr_req.bwmgr_calc_set_req.floor_unit = BWMGR_INT_UNIT_KHZ;
|
||||
#if defined(NV_TEGRA264_BWMGR_DEBUG_MACRO_PRESENT)
|
||||
bwmgr_req.bwmgr_calc_set_req.client_id = TEGRA264_BWMGR_DEBUG;
|
||||
#endif
|
||||
|
||||
msg.mrq = MRQ_BWMGR_INT;
|
||||
msg.tx.data = &bwmgr_req;
|
||||
msg.tx.size = sizeof(bwmgr_req);
|
||||
msg.rx.data = &bwmgr_resp;
|
||||
msg.rx.size = sizeof(bwmgr_resp);
|
||||
|
||||
err = tegra_bpmp_transfer(bwmgr->bpmp, &msg);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "BPMP transfer failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (msg.rx.ret == 0)
|
||||
bwmgr->enabled = true;
|
||||
}
|
||||
|
||||
bwmgr->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, bwmgr);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user