Merge "msm: kgsl: Set up the adreno device at runtime"

This commit is contained in:
qctecmdr 2019-12-09 09:05:22 -08:00 • committed by Gerrit - the friendly Code Review server
commit a0aff6fc73
10 changed files with 175 additions and 197 deletions

View file

@ -32,43 +32,7 @@ static void adreno_input_work(struct work_struct *work);
static unsigned int counter_delta(struct kgsl_device *device,
unsigned int reg, unsigned int *counter);
static struct devfreq_msm_adreno_tz_data adreno_tz_data = {
.bus = {
.max = 350,
.floating = true,
},
.device_id = 0,
};
static const struct kgsl_functable adreno_functable;
static struct adreno_device device_3d0 = {
.dev = {
KGSL_DEVICE_COMMON_INIT(device_3d0.dev),
.pwrscale = KGSL_PWRSCALE_INIT(&adreno_tz_data),
.name = DEVICE_3D0_NAME,
.id = 0,
.iomemname = "kgsl_3d0_reg_memory",
.ftbl = &adreno_functable,
},
.ft_policy = KGSL_FT_DEFAULT_POLICY,
.ft_pf_policy = KGSL_FT_PAGEFAULT_DEFAULT_POLICY,
.long_ib_detect = 1,
.input_work = __WORK_INITIALIZER(device_3d0.input_work,
adreno_input_work),
.pwrctrl_flag = BIT(ADRENO_SPTP_PC_CTRL) |
BIT(ADRENO_THROTTLING_CTRL) | BIT(ADRENO_HWCG_CTRL),
.profile.enabled = false,
.active_list = LIST_HEAD_INIT(device_3d0.active_list),
.active_list_lock = __SPIN_LOCK_UNLOCKED(device_3d0.active_list_lock),
.gpu_llc_slice_enable = true,
.gpuhtw_llc_slice_enable = true,
.preempt = {
.preempt_level = 1,
.skipsaverestore = 1,
.usesgmem = 1,
},
};
static struct adreno_device device_3d0;
/* Ptr to array for the current set of fault detect registers */
unsigned int *adreno_ft_regs;
@ -858,7 +822,7 @@ static int adreno_identify_gpu(struct adreno_device *adreno_dev)
}
static const struct platform_device_id adreno_id_table[] = {
{ DEVICE_3D0_NAME, (unsigned long) &device_3d0, },
{ "kgsl-3d0", (unsigned long) &device_3d0, },
{},
};
@ -1140,7 +1104,8 @@ static int adreno_of_get_power(struct adreno_device *adreno_dev,
/* Get starting physical address of device registers */
res = platform_get_resource_byname(device->pdev, IORESOURCE_MEM,
device->iomemname);
"kgsl_3d0_reg_memory");
if (res == NULL) {
dev_err(device->dev,
"platform_get_resource_byname failed\n");
@ -1356,6 +1321,47 @@ static int adreno_probe_efuse(struct platform_device *pdev,
return 0;
}
static const struct kgsl_functable adreno_functable;
static void adreno_setup_device(struct adreno_device *adreno_dev)
{
memset(adreno_dev, 0, sizeof(*adreno_dev));
adreno_dev->dev.name = "kgsl-3d0";
adreno_dev->dev.ftbl = &adreno_functable;
init_completion(&adreno_dev->dev.hwaccess_gate);
init_completion(&adreno_dev->dev.halt_gate);
idr_init(&adreno_dev->dev.context_idr);
mutex_init(&adreno_dev->dev.mutex);
INIT_LIST_HEAD(&adreno_dev->dev.globals);
/* Set the fault tolerance policy to replay, skip, throttle */
adreno_dev->ft_policy = BIT(KGSL_FT_REPLAY) |
BIT(KGSL_FT_SKIPCMD) | BIT(KGSL_FT_THROTTLE);
/* Enable command timeouts by default */
adreno_dev->long_ib_detect = true;
INIT_WORK(&adreno_dev->input_work, adreno_input_work);
/*
* Enable SPTP power collapse, throttling and hardware clock gating by
* default where applicable
*/
adreno_dev->pwrctrl_flag = BIT(ADRENO_SPTP_PC_CTRL) |
BIT(ADRENO_THROTTLING_CTRL) | BIT(ADRENO_HWCG_CTRL);
INIT_LIST_HEAD(&adreno_dev->active_list);
spin_lock_init(&adreno_dev->active_list_lock);
/* Enable use of the LLC slices where applicable */
adreno_dev->gpu_llc_slice_enable = true;
adreno_dev->gpuhtw_llc_slice_enable = true;
}
static int adreno_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id;
@ -1370,6 +1376,10 @@ static int adreno_probe(struct platform_device *pdev)
return -EINVAL;
adreno_dev = (struct adreno_device *) of_id->data;
/* Initialize the adreno device structure */
adreno_setup_device(adreno_dev);
device = KGSL_DEVICE(adreno_dev);
device->pdev = pdev;
@ -3750,35 +3760,6 @@ static struct platform_driver adreno_platform_driver = {
}
};
static const struct of_device_id busmon_match_table[] = {
{ .compatible = "qcom,kgsl-busmon", .data = &device_3d0 },
{}
};
static int adreno_busmon_probe(struct platform_device *pdev)
{
struct kgsl_device *device;
const struct of_device_id *pdid =
of_match_device(busmon_match_table, &pdev->dev);
if (pdid == NULL)
return -ENXIO;
device = (struct kgsl_device *)pdid->data;
device->busmondev = &pdev->dev;
dev_set_drvdata(device->busmondev, device);
return 0;
}
static struct platform_driver kgsl_bus_platform_driver = {
.probe = adreno_busmon_probe,
.driver = {
.name = "kgsl-busmon",
.of_match_table = busmon_match_table,
}
};
static int __init kgsl_3d_init(void)
{
int ret;
@ -3787,17 +3768,9 @@ static int __init kgsl_3d_init(void)
if (ret)
return ret;
ret = platform_driver_register(&kgsl_bus_platform_driver);
if (ret) {
kgsl_core_exit();
return ret;
}
ret = platform_driver_register(&adreno_platform_driver);
if (ret) {
platform_driver_unregister(&kgsl_bus_platform_driver);
if (ret)
kgsl_core_exit();
}
return ret;
}
@ -3805,8 +3778,6 @@ static int __init kgsl_3d_init(void)
static void __exit kgsl_3d_exit(void)
{
platform_driver_unregister(&adreno_platform_driver);
platform_driver_unregister(&kgsl_bus_platform_driver);
kgsl_core_exit();
}

View file

@ -13,8 +13,6 @@
#include "adreno_ringbuffer.h"
#include "kgsl_sharedmem.h"
#define DEVICE_3D0_NAME "kgsl-3d0"
/* ADRENO_DEVICE - Given a kgsl_device return the adreno device struct */
#define ADRENO_DEVICE(device) \
container_of(device, struct adreno_device, dev)
@ -476,7 +474,7 @@ struct adreno_device {
struct adreno_ringbuffer *prev_rb;
unsigned int fast_hang_detect;
unsigned long ft_policy;
unsigned int long_ib_detect;
bool long_ib_detect;
unsigned long ft_pf_policy;
bool cooperative_reset;
struct adreno_profile profile;
@ -839,13 +837,13 @@ struct adreno_gpudev {
*/
enum kgsl_ft_policy_bits {
KGSL_FT_OFF = 0,
KGSL_FT_REPLAY = 1,
KGSL_FT_SKIPIB = 2,
KGSL_FT_SKIPFRAME = 3,
KGSL_FT_DISABLE = 4,
KGSL_FT_TEMP_DISABLE = 5,
KGSL_FT_THROTTLE = 6,
KGSL_FT_SKIPCMD = 7,
KGSL_FT_REPLAY,
KGSL_FT_SKIPIB,
KGSL_FT_SKIPFRAME,
KGSL_FT_DISABLE,
KGSL_FT_TEMP_DISABLE,
KGSL_FT_THROTTLE,
KGSL_FT_SKIPCMD,
/* KGSL_FT_MAX_BITS is used to calculate the mask */
KGSL_FT_MAX_BITS,
/* Internal bits - set during GFT */
@ -855,11 +853,6 @@ enum kgsl_ft_policy_bits {
#define KGSL_FT_POLICY_MASK GENMASK(KGSL_FT_MAX_BITS - 1, 0)
#define KGSL_FT_DEFAULT_POLICY \
(BIT(KGSL_FT_REPLAY) | \
BIT(KGSL_FT_SKIPCMD) | \
BIT(KGSL_FT_THROTTLE))
/**
* enum kgsl_ft_pagefault_policy_bits - KGSL pagefault policy bits
* @KGSL_FT_PAGEFAULT_INT_ENABLE: No longer used, but retained for compatibility

View file

@ -2205,6 +2205,10 @@ static void a6xx_platform_setup(struct adreno_device *adreno_dev)
{
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
adreno_dev->preempt.preempt_level = 1;
adreno_dev->preempt.skipsaverestore = true;
adreno_dev->preempt.usesgmem = true;
if (adreno_has_gbif(adreno_dev)) {
a6xx_perfcounter_groups[KGSL_PERFCOUNTER_GROUP_VBIF].regs =
a6xx_perfcounters_gbif;

View file

@ -210,10 +210,6 @@ void a6xx_preemption_trigger(struct adreno_device *adreno_dev)
unsigned long flags;
struct adreno_preemption *preempt = &adreno_dev->preempt;
cntl = (((preempt->preempt_level << 6) & 0xC0) |
((preempt->skipsaverestore << 9) & 0x200) |
((preempt->usesgmem << 8) & 0x100) | 0x1);
/* Put ourselves into a possible trigger state */
if (!adreno_move_preempt_state(adreno_dev,
ADRENO_PREEMPT_NONE, ADRENO_PREEMPT_START))
@ -352,6 +348,16 @@ void a6xx_preemption_trigger(struct adreno_device *adreno_dev)
mod_timer(&adreno_dev->preempt.timer,
jiffies + msecs_to_jiffies(ADRENO_PREEMPT_TIMEOUT));
cntl = (preempt->preempt_level << 6) | 0x01;
/* Skip save/restore during L1 preemption */
if (preempt->skipsaverestore)
cntl |= (1 << 9);
/* Enable GMEM save/restore across preemption */
if (preempt->usesgmem)
cntl |= (1 << 8);
trace_adreno_preempt_trigger(adreno_dev->cur_rb, adreno_dev->next_rb,
cntl);

View file

@ -50,7 +50,7 @@ static int _usesgmem_store(struct adreno_device *adreno_dev, bool val)
{
struct adreno_preemption *preempt = &adreno_dev->preempt;
preempt->usesgmem = val ? 1 : 0;
preempt->usesgmem = val ? true : false;
return 0;
}
@ -63,7 +63,7 @@ static int _skipsaverestore_store(struct adreno_device *adreno_dev, bool val)
{
struct adreno_preemption *preempt = &adreno_dev->preempt;
preempt->skipsaverestore = val ? 1 : 0;
preempt->skipsaverestore = val ? true : false;
return 0;
}
@ -124,7 +124,7 @@ static bool _gpuhtw_llc_slice_enable_show(struct adreno_device *adreno_dev)
static int _ft_long_ib_detect_store(struct adreno_device *adreno_dev, bool val)
{
adreno_dev->long_ib_detect = val;
adreno_dev->long_ib_detect = val ? true : false;
return 0;
}

View file

@ -263,7 +263,6 @@ struct kgsl_device {
atomic_t active_cnt;
wait_queue_head_t wait_queue;
wait_queue_head_t active_cnt_wq;
struct platform_device *pdev;
struct dentry *d_debugfs;
@ -297,8 +296,6 @@ struct kgsl_device {
int reset_counter; /* Track how many GPU core resets have occurred */
struct workqueue_struct *events_wq;
struct device *busmondev; /* pseudo dev for GPU BW voting governor */
/* Number of active contexts seen globally for this device */
int active_context_count;
struct kobject *gpu_sysfs_kobj;
@ -322,19 +319,6 @@ struct kgsl_device {
#define KGSL_MMU_DEVICE(_mmu) \
container_of((_mmu), struct kgsl_device, mmu)
#define KGSL_DEVICE_COMMON_INIT(_dev) \
.hwaccess_gate = COMPLETION_INITIALIZER((_dev).hwaccess_gate),\
.halt_gate = COMPLETION_INITIALIZER((_dev).halt_gate),\
.idle_check_ws = __WORK_INITIALIZER((_dev).idle_check_ws,\
kgsl_idle_check),\
.context_idr = IDR_INIT((_dev).context_idr),\
.wait_queue = __WAIT_QUEUE_HEAD_INITIALIZER((_dev).wait_queue),\
.active_cnt_wq = __WAIT_QUEUE_HEAD_INITIALIZER((_dev).active_cnt_wq),\
.mutex = __MUTEX_INITIALIZER((_dev).mutex),\
.state = KGSL_STATE_NONE, \
.globals = LIST_HEAD_INIT((_dev).globals)
/**
* enum bits for struct kgsl_context.priv
* @KGSL_CONTEXT_PRIV_SUBMITTED - The context has submitted commands to gpu.

View file

@ -1643,6 +1643,8 @@ static u32 *kgsl_bus_get_table(struct platform_device *pdev, int *count)
return levels;
}
static void kgsl_idle_check(struct work_struct *work);
int kgsl_pwrctrl_init(struct kgsl_device *device)
{
int i, result, freq, levels_count;
@ -1679,6 +1681,9 @@ int kgsl_pwrctrl_init(struct kgsl_device *device)
return -EINVAL;
}
INIT_WORK(&device->idle_check_ws, kgsl_idle_check);
init_waitqueue_head(&device->active_cnt_wq);
/* Initialize the user and thermal clock constraints */
pwr->max_pwrlevel = 0;
@ -1786,15 +1791,12 @@ void kgsl_pwrctrl_close(struct kgsl_device *device)
pm_runtime_disable(&device->pdev->dev);
}
/**
* kgsl_idle_check() - Work function for GPU interrupts and idle timeouts.
* @device: The device
*
/*
* This function is called for work that is queued by the interrupt
* handler or the idle timer. It attempts to transition to a clocks
* off state if the active_cnt is 0 and the hardware is idle.
*/
void kgsl_idle_check(struct work_struct *work)
static void kgsl_idle_check(struct work_struct *work)
{
struct kgsl_device *device = container_of(work, struct kgsl_device,
idle_check_ws);

View file

@ -158,7 +158,6 @@ struct kgsl_pwrctrl {
int kgsl_pwrctrl_init(struct kgsl_device *device);
void kgsl_pwrctrl_close(struct kgsl_device *device);
void kgsl_timer(struct timer_list *t);
void kgsl_idle_check(struct work_struct *work);
void kgsl_pre_hwaccess(struct kgsl_device *device);
void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
unsigned int level);

View file

@ -10,6 +10,13 @@
#include "kgsl_pwrscale.h"
#include "kgsl_trace.h"
static struct devfreq_msm_adreno_tz_data adreno_tz_data = {
.bus = {
.max = 350,
.floating = true,
},
};
/**
* struct kgsl_midframe_info - midframe power stats sampling info
* @timer - midframe sampling timer
@ -654,22 +661,74 @@ static int opp_notify(struct notifier_block *nb,
return 0;
}
static void pwrscale_busmon_create(struct kgsl_device *device,
struct platform_device *pdev, unsigned long *table)
{
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
struct kgsl_pwrscale *pwrscale = &device->pwrscale;
struct device *dev = &pwrscale->busmondev;
struct msm_busmon_extended_profile *bus_profile;
struct devfreq *bus_devfreq;
int i;
bus_profile = &pwrscale->bus_profile;
bus_profile->private_data = &adreno_tz_data;
bus_profile->profile.target = kgsl_busmon_target;
bus_profile->profile.get_dev_status = kgsl_busmon_get_dev_status;
bus_profile->profile.get_cur_freq = kgsl_busmon_get_cur_freq;
bus_profile->profile.max_state = pwr->num_pwrlevels - 1;
bus_profile->profile.freq_table = table;
dev->parent = &pdev->dev;
dev_set_name(dev, "kgsl-busmon");
if (device_register(dev))
return;
/* Build out the OPP table for the busmon device */
for (i = 0; i < pwr->num_pwrlevels; i++) {
if (!pwr->pwrlevels[i].gpu_freq)
continue;
dev_pm_opp_add(dev, pwr->pwrlevels[i].gpu_freq, 0);
}
bus_devfreq = devfreq_add_device(dev, &pwrscale->bus_profile.profile,
"gpubw_mon", NULL);
if (IS_ERR_OR_NULL(bus_devfreq)) {
dev_err(&pdev->dev, "Bus scaling not enabled\n");
put_device(dev);
return;
}
pwrscale->gpu_profile.bus_devfreq = bus_devfreq;
}
int kgsl_pwrscale_init(struct kgsl_device *device, struct platform_device *pdev,
const char *governor)
{
struct kgsl_pwrscale *pwrscale;
struct kgsl_pwrctrl *pwr;
struct kgsl_pwrscale *pwrscale = &device->pwrscale;
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
struct devfreq *devfreq;
struct devfreq *bus_devfreq = NULL;
struct msm_adreno_extended_profile *gpu_profile;
struct devfreq_dev_profile *profile;
struct devfreq_msm_adreno_tz_data *data;
int i, ret;
pwrscale = &device->pwrscale;
pwr = &device->pwrctrl;
pwrscale->enabled = true;
gpu_profile = &pwrscale->gpu_profile;
profile = &pwrscale->gpu_profile.profile;
gpu_profile->private_data = &adreno_tz_data;
gpu_profile->profile.target = kgsl_devfreq_target;
gpu_profile->profile.get_dev_status = kgsl_devfreq_get_dev_status;
gpu_profile->profile.get_cur_freq = kgsl_devfreq_get_cur_freq;
gpu_profile->profile.initial_freq =
pwr->pwrlevels[pwr->default_pwrlevel].gpu_freq;
gpu_profile->profile.polling_ms = 10;
pwr->nb.notifier_call = opp_notify;
@ -677,39 +736,33 @@ int kgsl_pwrscale_init(struct kgsl_device *device, struct platform_device *pdev,
srcu_init_notifier_head(&pwrscale->nh);
profile->initial_freq =
pwr->pwrlevels[pwr->default_pwrlevel].gpu_freq;
/* Let's start with 10 ms and tune in later */
profile->polling_ms = 10;
/* do not include the 'off' level or duplicate freq. levels */
for (i = 0; i < (pwr->num_pwrlevels - 1); i++)
pwrscale->freq_table[out++] = pwr->pwrlevels[i].gpu_freq;
pwrscale->freq_table[i] = pwr->pwrlevels[i].gpu_freq;
/*
* Max_state is the number of valid power levels.
* The valid power levels range from 0 - (max_state - 1)
*/
profile->max_state = pwr->num_pwrlevels - 1;
gpu_profile->profile.max_state = pwr->num_pwrlevels - 1;
/* link storage array to the devfreq profile pointer */
profile->freq_table = pwrscale->freq_table;
gpu_profile->profile.freq_table = pwrscale->freq_table;
/* if there is only 1 freq, no point in running a governor */
if (profile->max_state == 1)
if (gpu_profile->profile.max_state == 1)
governor = "performance";
/* initialize msm-adreno-tz governor specific data here */
data = gpu_profile->private_data;
data->disable_busy_time_burst =
adreno_tz_data.disable_busy_time_burst =
of_property_read_bool(pdev->dev.of_node,
"qcom,disable-busy-time-burst");
if (pwrscale->ctxt_aware_enable) {
data->ctxt_aware_enable = pwrscale->ctxt_aware_enable;
data->bin.ctxt_aware_target_pwrlevel =
adreno_tz_data.ctxt_aware_enable = pwrscale->ctxt_aware_enable;
adreno_tz_data.bin.ctxt_aware_target_pwrlevel =
pwrscale->ctxt_aware_target_pwrlevel;
data->bin.ctxt_aware_busy_penalty =
adreno_tz_data.bin.ctxt_aware_busy_penalty =
pwrscale->ctxt_aware_busy_penalty;
}
@ -734,18 +787,17 @@ int kgsl_pwrscale_init(struct kgsl_device *device, struct platform_device *pdev,
* the bus bandwidth vote.
*/
if (pwr->bus_control) {
data->bus.num = pwr->bus_ibs_count;
data->bus.ib_mbps = pwr->bus_ibs;
data->bus.width = pwr->bus_width;
adreno_tz_data.bus.num = pwr->bus_ibs_count;
adreno_tz_data.bus.ib_mbps = pwr->bus_ibs;
adreno_tz_data.bus.width = pwr->bus_width;
if (!kgsl_of_property_read_ddrtype(device->pdev->dev.of_node,
"qcom,bus-accesses", &data->bus.max))
data->bus.floating = false;
} else
data->bus.num = 0;
"qcom,bus-accesses", &adreno_tz_data.bus.max))
adreno_tz_data.bus.floating = false;
}
devfreq = devfreq_add_device(&pdev->dev, &pwrscale->gpu_profile.profile,
governor, pwrscale->gpu_profile.private_data);
devfreq = devfreq_add_device(&pdev->dev, &gpu_profile->profile,
governor, &adreno_tz_data);
if (IS_ERR(devfreq)) {
device->pwrscale.enabled = false;
return PTR_ERR(devfreq);
@ -758,34 +810,9 @@ int kgsl_pwrscale_init(struct kgsl_device *device, struct platform_device *pdev,
pwrscale->cooling_dev = NULL;
pwrscale->gpu_profile.bus_devfreq = NULL;
if (data->bus.num) {
pwrscale->bus_profile.profile.max_state
= pwr->num_pwrlevels - 1;
pwrscale->bus_profile.profile.freq_table
= pwrscale->freq_table;
/*
* This is needed because devfreq expects the device
* to have an opp table handle to calculate the min/max
* frequency.
*/
ret = dev_pm_opp_of_add_table(device->busmondev);
/*
* Disable OPP which are not supported as per GPU freq plan.
* This is need to ensure freq_table specified in bus_profile
* above matches OPP table.
*/
kgsl_pwrctrl_disable_unused_opp(device, device->busmondev);
if (!ret)
bus_devfreq = devfreq_add_device(device->busmondev,
&pwrscale->bus_profile.profile, "gpubw_mon",
NULL);
if (IS_ERR_OR_NULL(bus_devfreq))
dev_err(device->dev, "Bus scaling not enabled\n");
else
pwrscale->gpu_profile.bus_devfreq = bus_devfreq;
}
if (adreno_tz_data.bus.num)
pwrscale_busmon_create(device, pdev, pwrscale->freq_table);
ret = sysfs_create_link(&device->dev->kobj,
&devfreq->dev.kobj, "devfreq");
@ -825,6 +852,12 @@ void kgsl_pwrscale_close(struct kgsl_device *device)
pwr = &device->pwrctrl;
pwrscale = &device->pwrscale;
if (pwrscale->gpu_profile.bus_devfreq) {
devfreq_remove_device(pwrscale->gpu_profile.bus_devfreq);
put_device(&pwrscale->busmondev);
}
if (!pwrscale->devfreqptr)
return;
if (pwrscale->cooling_dev)

View file

@ -63,6 +63,8 @@ struct kgsl_pwrscale {
bool ctxt_aware_enable;
unsigned int ctxt_aware_target_pwrlevel;
unsigned int ctxt_aware_busy_penalty;
/** @busmondev: A child device for the busmon governor */
struct device busmondev;
};
/**
@ -99,20 +101,4 @@ int kgsl_busmon_get_dev_status(struct device *dev,
struct devfreq_dev_status *stat);
int kgsl_busmon_get_cur_freq(struct device *dev, unsigned long *freq);
#define KGSL_PWRSCALE_INIT(_priv_data) { \
.enabled = true, \
.gpu_profile = { \
.private_data = _priv_data, \
.profile = { \
.target = kgsl_devfreq_target, \
.get_dev_status = kgsl_devfreq_get_dev_status, \
.get_cur_freq = kgsl_devfreq_get_cur_freq, \
} }, \
.bus_profile = { \
.private_data = _priv_data, \
.profile = { \
.target = kgsl_busmon_target, \
.get_dev_status = kgsl_busmon_get_dev_status, \
.get_cur_freq = kgsl_busmon_get_cur_freq, \
} } }
#endif