[Nouveau] [RFC PATCH 2/3] dvfs: add support for GK20A
Vince Hsu
vinceh at nvidia.com
Thu Dec 18 17:25:07 PST 2014
On 12/19/2014 03:33 AM, Samuel Pitoiset wrote:
> On 12/18/2014 11:25 AM, Ben Skeggs wrote:
>> On Thu, Dec 18, 2014 at 8:13 PM, Vince Hsu <vinceh at nvidia.com> wrote:
>>> Hello Ben,
>>>
>>> On 12/18/2014 05:34 PM, Ben Skeggs wrote:
>>>> On Thu, Dec 18, 2014 at 4:28 PM, Vince Hsu <vinceh at nvidia.com> wrote:
>>>>> This patch creates a subdev for DVFS (Dynamic Voltage and Frequency
>>>>> Scaling)
>>>>> support in Nouveau. This subdev refers to the status information
>>>>> provided
>>>>> by
>>>>> the NVIDIA hardware and tries to adjust the performance level
>>>>> based on
>>>>> the
>>>>> calculated target. Only the GK20A is supported right now.
>>>> Hey Vince,
>>>>
>>>> I'd not make a new subdev, but implement this in the PMU (PWR
>>>> currently) subdev. The ucode that's supposed to be running there can
>>>> do the performance monitoring in a more complex implementation, and
>>>> it's PMU counters you're touching to get the usage stats :) But the
>>>> simpler on-host implementation is totally fine.
>>> Yeah, I know we have the counters defined in daemon.c. Martin
>>> reminded me
>>> that Roy had a patch to remove that, sorry that I could not find the
>>> link
>>> now. Another reason I did not use the nouveau_specsig is because I
>>> had to
>>> create some nvif structures to access the counters and that's not
>>> straightforward. I'm happy to hear you're fine with the on-host
>>> implementation. :)
>
> Hey Vince,
>
> It's not Roy but me who had submitted a patch which removes PDAEMON
> signals. :-)
Oops. Sorry for the wrong name, my bad.
>
> However, the patch is not ready to be upstream because we don't have
> any other ways to expose these performance counters.
>
> Currently, I'm working on perfmon and nvif to expose hardware events
> to the userspace for NV50. I hope to submit the bunch of patches as
> soon as possible but unfortunately,
> I don't have my full time on this, so it takes more time than expected.
>
>>>
>>> I will move all to PWR subdev in the next version.
>>>>
>>>> The current base PMU implementation tries to do a lot of stuff that
>>>> you don't need, just override the implementation entirely for GK20A
>>>> for now if that's easier than reworking it.
>>> So currently there is no dGPU using the PMU? I just don't want to
>>> break any
>>> dGPU functions. ;)
>> We upload a custom firmware to it, which we (currently) only use as a
>> script interpreter for memory clock changes. But for your needs right
>> now, it'd be fine to ignore all the common code there for GK20A.
>>
>>>>
>>>> Aside from the subdev move, it looks good so far to me. Glad to see
>>>> the CLK stuff isn't totally useless, despite it needing a *lot* of
>>>> work.
>>> BTW, can we add some execution time information for pstate? I mean
>>> something
>>> like "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state". I
>>> know we
>>> don't want to change the user space ABI though.
>>>
>>> Thanks,
>>> Vince
>>>
>>>
>>>> Thanks,
>>>> Ben.
>>>>
>>>>> Signed-off-by: Vince Hsu <vinceh at nvidia.com>
>>>>> ---
>>>>> drm/Kbuild | 2 +
>>>>> drm/core/include/subdev/dvfs.h | 1 +
>>>>> drm/core/subdev/dvfs/base.c | 1 +
>>>>> drm/core/subdev/dvfs/gk20a.c | 1 +
>>>>> drm/core/subdev/dvfs/priv.h | 1 +
>>>>> nvkm/engine/device/nve0.c | 2 +
>>>>> nvkm/include/core/device.h | 1 +
>>>>> nvkm/include/subdev/dvfs.h | 30 ++++++++
>>>>> nvkm/subdev/Makefile.am | 5 +-
>>>>> nvkm/subdev/dvfs/Makefile.am | 6 ++
>>>>> nvkm/subdev/dvfs/base.c | 129
>>>>> ++++++++++++++++++++++++++++++++++
>>>>> nvkm/subdev/dvfs/gk20a.c | 156
>>>>> +++++++++++++++++++++++++++++++++++++++++
>>>>> nvkm/subdev/dvfs/priv.h | 43 ++++++++++++
>>>>> 13 files changed, 376 insertions(+), 2 deletions(-)
>>>>> create mode 120000 drm/core/include/subdev/dvfs.h
>>>>> create mode 120000 drm/core/subdev/dvfs/base.c
>>>>> create mode 120000 drm/core/subdev/dvfs/gk20a.c
>>>>> create mode 120000 drm/core/subdev/dvfs/priv.h
>>>>> create mode 100644 nvkm/include/subdev/dvfs.h
>>>>> create mode 100644 nvkm/subdev/dvfs/Makefile.am
>>>>> create mode 100644 nvkm/subdev/dvfs/base.c
>>>>> create mode 100644 nvkm/subdev/dvfs/gk20a.c
>>>>> create mode 100644 nvkm/subdev/dvfs/priv.h
>>>>>
>>>>> diff --git a/drm/Kbuild b/drm/Kbuild
>>>>> index 061d9faef836..e7eb05e666a0 100644
>>>>> --- a/drm/Kbuild
>>>>> +++ b/drm/Kbuild
>>>>> @@ -227,6 +227,8 @@ nouveau-y += core/subdev/volt/base.o
>>>>> nouveau-y += core/subdev/volt/gpio.o
>>>>> nouveau-y += core/subdev/volt/nv40.o
>>>>> nouveau-y += core/subdev/volt/gk20a.o
>>>>> +nouveau-y += core/subdev/dvfs/base.o
>>>>> +nouveau-y += core/subdev/dvfs/gk20a.o
>>>>>
>>>>> nouveau-y += core/engine/falcon.o
>>>>> nouveau-y += core/engine/xtensa.o
>>>>> diff --git a/drm/core/include/subdev/dvfs.h
>>>>> b/drm/core/include/subdev/dvfs.h
>>>>> new file mode 120000
>>>>> index 000000000000..553a6968350b
>>>>> --- /dev/null
>>>>> +++ b/drm/core/include/subdev/dvfs.h
>>>>> @@ -0,0 +1 @@
>>>>> +../../../../nvkm/include/subdev/dvfs.h
>>>>> \ No newline at end of file
>>>>> diff --git a/drm/core/subdev/dvfs/base.c
>>>>> b/drm/core/subdev/dvfs/base.c
>>>>> new file mode 120000
>>>>> index 000000000000..296334ee52d1
>>>>> --- /dev/null
>>>>> +++ b/drm/core/subdev/dvfs/base.c
>>>>> @@ -0,0 +1 @@
>>>>> +../../../../nvkm/subdev/dvfs/base.c
>>>>> \ No newline at end of file
>>>>> diff --git a/drm/core/subdev/dvfs/gk20a.c
>>>>> b/drm/core/subdev/dvfs/gk20a.c
>>>>> new file mode 120000
>>>>> index 000000000000..d05d493e3fc9
>>>>> --- /dev/null
>>>>> +++ b/drm/core/subdev/dvfs/gk20a.c
>>>>> @@ -0,0 +1 @@
>>>>> +../../../../nvkm/subdev/dvfs/gk20a.c
>>>>> \ No newline at end of file
>>>>> diff --git a/drm/core/subdev/dvfs/priv.h
>>>>> b/drm/core/subdev/dvfs/priv.h
>>>>> new file mode 120000
>>>>> index 000000000000..9b471dc44f48
>>>>> --- /dev/null
>>>>> +++ b/drm/core/subdev/dvfs/priv.h
>>>>> @@ -0,0 +1 @@
>>>>> +../../../../nvkm/subdev/dvfs/priv.h
>>>>> \ No newline at end of file
>>>>> diff --git a/nvkm/engine/device/nve0.c b/nvkm/engine/device/nve0.c
>>>>> index ba7922d31351..5a830a37a15d 100644
>>>>> --- a/nvkm/engine/device/nve0.c
>>>>> +++ b/nvkm/engine/device/nve0.c
>>>>> @@ -41,6 +41,7 @@
>>>>> #include <subdev/bar.h>
>>>>> #include <subdev/pwr.h>
>>>>> #include <subdev/volt.h>
>>>>> +#include <subdev/dvfs.h>
>>>>>
>>>>> #include <engine/device.h>
>>>>> #include <engine/dmaobj.h>
>>>>> @@ -180,6 +181,7 @@ nve0_identify(struct nouveau_device *device)
>>>>> device->oclass[NVDEV_ENGINE_COPY2 ] =
>>>>> &nve0_copy2_oclass;
>>>>> device->oclass[NVDEV_ENGINE_PERFMON] =
>>>>> &gk20a_perfmon_oclass;
>>>>> device->oclass[NVDEV_SUBDEV_VOLT ] =
>>>>> &gk20a_volt_oclass;
>>>>> + device->oclass[NVDEV_SUBDEV_DVFS ] =
>>>>> gk20a_dvfs_oclass;
>>>>> break;
>>>>> case 0xf0:
>>>>> device->cname = "GK110";
>>>>> diff --git a/nvkm/include/core/device.h b/nvkm/include/core/device.h
>>>>> index 2ec2e50d3676..162fa6a3cfcc 100644
>>>>> --- a/nvkm/include/core/device.h
>>>>> +++ b/nvkm/include/core/device.h
>>>>> @@ -39,6 +39,7 @@ enum nv_subdev_type {
>>>>> NVDEV_SUBDEV_VOLT,
>>>>> NVDEV_SUBDEV_THERM,
>>>>> NVDEV_SUBDEV_CLOCK,
>>>>> + NVDEV_SUBDEV_DVFS,
>>>>>
>>>>> NVDEV_ENGINE_FIRST,
>>>>> NVDEV_ENGINE_DMAOBJ = NVDEV_ENGINE_FIRST,
>>>>> diff --git a/nvkm/include/subdev/dvfs.h b/nvkm/include/subdev/dvfs.h
>>>>> new file mode 100644
>>>>> index 000000000000..3851629a0de4
>>>>> --- /dev/null
>>>>> +++ b/nvkm/include/subdev/dvfs.h
>>>>> @@ -0,0 +1,30 @@
>>>>> +#ifndef __NOUVEAU_DVFS_H__
>>>>> +#define __NOUVEAU_DVFS_H__
>>>>> +
>>>>> +#include <core/subdev.h>
>>>>> +#include <core/device.h>
>>>>> +
>>>>> +#include <subdev/timer.h>
>>>>> +
>>>>> +struct nouveau_dvfs_data {
>>>>> + int p_load_target;
>>>>> + int p_load_max;
>>>>> + int p_smooth;
>>>>> + unsigned int avg_load;
>>>>> +};
>>>>> +
>>>>> +struct nouveau_dvfs {
>>>>> + struct nouveau_subdev base;
>>>>> + struct nouveau_alarm alarm;
>>>>> + struct nouveau_dvfs_data *data;
>>>>> +};
>>>>> +
>>>>> +static inline struct nouveau_dvfs *
>>>>> +nouveau_dvfs(void *obj)
>>>>> +{
>>>>> + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_DVFS];
>>>>> +}
>>>>> +
>>>>> +extern struct nouveau_oclass *gk20a_dvfs_oclass;
>>>>> +
>>>>> +#endif
>>>>> diff --git a/nvkm/subdev/Makefile.am b/nvkm/subdev/Makefile.am
>>>>> index 5a48ddb87981..3d11e0833032 100644
>>>>> --- a/nvkm/subdev/Makefile.am
>>>>> +++ b/nvkm/subdev/Makefile.am
>>>>> @@ -1,5 +1,5 @@
>>>>> SUBDIRS = bar bus bios clock devinit fb fuse gpio i2c ibus
>>>>> instmem \
>>>>> - ltc mc mxm pwr therm timer vm volt
>>>>> + ltc mc mxm pwr therm timer vm volt dvfs
>>>>>
>>>>> noinst_LTLIBRARIES = libsubdev.la
>>>>>
>>>>> @@ -22,4 +22,5 @@ libsubdev_la_LIBADD = bar/libbar.la \
>>>>> therm/libtherm.la \
>>>>> timer/libtimer.la \
>>>>> vm/libvm.la \
>>>>> - volt/libvolt.la
>>>>> + volt/libvolt.la \
>>>>> + dvfs/dvfs.la
>>>>> diff --git a/nvkm/subdev/dvfs/Makefile.am
>>>>> b/nvkm/subdev/dvfs/Makefile.am
>>>>> new file mode 100644
>>>>> index 000000000000..c09d4ec4124d
>>>>> --- /dev/null
>>>>> +++ b/nvkm/subdev/dvfs/Makefile.am
>>>>> @@ -0,0 +1,6 @@
>>>>> +noinst_LTLIBRARIES = libdvfs.la
>>>>> +
>>>>> +libdvfs_la_SOURCES = base.c \
>>>>> + gk20a.c
>>>>> +
>>>>> +include $(srcdir)/../Makefile.subdev
>>>>> diff --git a/nvkm/subdev/dvfs/base.c b/nvkm/subdev/dvfs/base.c
>>>>> new file mode 100644
>>>>> index 000000000000..88ae201840a8
>>>>> --- /dev/null
>>>>> +++ b/nvkm/subdev/dvfs/base.c
>>>>> @@ -0,0 +1,129 @@
>>>>> +/*
>>>>> + * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
>>>>> + *
>>>>> + * Permission is hereby granted, free of charge, to any person
>>>>> obtaining
>>>>> a
>>>>> + * copy of this software and associated documentation files (the
>>>>> "Software"),
>>>>> + * to deal in the Software without restriction, including without
>>>>> limitation
>>>>> + * the rights to use, copy, modify, merge, publish, distribute,
>>>>> sublicense,
>>>>> + * and/or sell copies of the Software, and to permit persons to
>>>>> whom the
>>>>> + * Software is furnished to do so, subject to the following
>>>>> conditions:
>>>>> + *
>>>>> + * The above copyright notice and this permission notice shall be
>>>>> included in
>>>>> + * all copies or substantial portions of the Software.
>>>>> + *
>>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>>>> EXPRESS OR
>>>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>>>>> MERCHANTABILITY,
>>>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
>>>>> SHALL
>>>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
>>>>> DAMAGES OR
>>>>> OTHER
>>>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>>>>> ARISING
>>>>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>>>>> OTHER
>>>>> + * DEALINGS IN THE SOFTWARE.
>>>>> + */
>>>>> +
>>>>> +#include <core/option.h>
>>>>> +
>>>>> +#include <subdev/clock.h>
>>>>> +#include <subdev/dvfs.h>
>>>>> +#include <subdev/volt.h>
>>>>> +
>>>>> +#include "priv.h"
>>>>> +
>>>>> +static void
>>>>> +_nouveau_dvfs_work(struct nouveau_alarm *alarm)
>>>>> +{
>>>>> + struct nouveau_dvfs *dvfs = container_of(alarm, struct
>>>>> nouveau_dvfs,
>>>>> + alarm);
>>>>> + struct nouveau_dvfs_data *data = dvfs->data;
>>>>> + struct nouveau_object *object = nv_object(dvfs);
>>>>> + struct nouveau_dvfs_impl *impl = (void *)object->oclass;
>>>>> + struct nouveau_dvfs_dev_status status;
>>>>> + u32 utilization = 0;
>>>>> + int state, ret;
>>>>> +
>>>>> + ret = impl->get_dev_status(dvfs, &status);
>>>>> + if (ret) {
>>>>> + nv_warn(dvfs, "failed to get device status\n");
>>>>> + goto resched;
>>>>> + }
>>>>> +
>>>>> + if (status.total)
>>>>> + utilization = div_u64((u64)status.busy * 100,
>>>>> status.total);
>>>>> +
>>>>> + data->avg_load = (data->p_smooth * data->avg_load) +
>>>>> utilization;
>>>>> + data->avg_load /= data->p_smooth + 1;
>>>>> + nv_trace(dvfs, "utilization = %d %%, avg_load = %d %%\n",
>>>>> + utilization, data->avg_load);
>>>>> +
>>>>> + ret = impl->get_cur_state(dvfs, &state);
>>>>> + if (ret) {
>>>>> + nv_warn(dvfs, "failed to get current state\n");
>>>>> + goto resched;
>>>>> + }
>>>>> +
>>>>> + if (impl->get_target_state(dvfs, &state, data->avg_load)) {
>>>>> + nv_trace(dvfs, "set new state to %d\n", state);
>>>>> + impl->target(dvfs, &state);
>>>>> + }
>>>>> +
>>>>> +resched:
>>>>> + impl->reset_dev_status(dvfs);
>>>>> + nouveau_timer_alarm(dvfs, 100000000, alarm);
>>>>> +}
>>>>> +
>>>>> +int
>>>>> +_nouveau_dvfs_fini(struct nouveau_object *object, bool suspend)
>>>>> +{
>>>>> + struct nouveau_dvfs *dvfs = (void *)object;
>>>>> +
>>>>> + nouveau_timer_alarm_cancel(dvfs, &dvfs->alarm);
>>>>> +
>>>>> + return nouveau_subdev_fini(&dvfs->base, suspend);
>>>>> +}
>>>>> +
>>>>> +int
>>>>> +_nouveau_dvfs_init(struct nouveau_object *object)
>>>>> +{
>>>>> + struct nouveau_dvfs *dvfs = (void *)object;
>>>>> + struct nouveau_clock *clk = nouveau_clock(object);
>>>>> + struct nouveau_volt *volt = nouveau_volt(object);
>>>>> + int ret;
>>>>> +
>>>>> + ret = nouveau_subdev_init(&dvfs->base);
>>>>> + if (ret)
>>>>> + return ret;
>>>>> +
>>>>> + if (!clk || !volt)
>>>>> + return -EINVAL;
>>>>> +
>>>>> + nouveau_timer_alarm(dvfs, 2000000000, &dvfs->alarm);
>>>>> +
>>>>> + return 0;
>>>>> +}
>>>>> +
>>>>> +void
>>>>> +_nouveau_dvfs_dtor(struct nouveau_object *object)
>>>>> +{
>>>>> + struct nouveau_dvfs *dvfs = (void *)object;
>>>>> +
>>>>> + nouveau_subdev_destroy(&dvfs->base);
>>>>> +}
>>>>> +
>>>>> +int
>>>>> +nouveau_dvfs_create_(struct nouveau_object *parent,
>>>>> + struct nouveau_object *engine,
>>>>> + struct nouveau_oclass *oclass,
>>>>> + int size, void **pobject)
>>>>> +{
>>>>> + struct nouveau_dvfs *dvfs;
>>>>> + int ret;
>>>>> +
>>>>> + ret = nouveau_subdev_create_(parent, engine, oclass, 0,
>>>>> "DVFS",
>>>>> + "dvfs", size, pobject);
>>>>> + dvfs = *pobject;
>>>>> + if (ret)
>>>>> + return ret;
>>>>> +
>>>>> + nouveau_alarm_init(&dvfs->alarm, _nouveau_dvfs_work);
>>>>> +
>>>>> + return 0;
>>>>> +}
>>>>> diff --git a/nvkm/subdev/dvfs/gk20a.c b/nvkm/subdev/dvfs/gk20a.c
>>>>> new file mode 100644
>>>>> index 000000000000..efebd2c10f99
>>>>> --- /dev/null
>>>>> +++ b/nvkm/subdev/dvfs/gk20a.c
>>>>> @@ -0,0 +1,156 @@
>>>>> +/*
>>>>> + * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
>>>>> + *
>>>>> + * Permission is hereby granted, free of charge, to any person
>>>>> obtaining
>>>>> a
>>>>> + * copy of this software and associated documentation files (the
>>>>> "Software"),
>>>>> + * to deal in the Software without restriction, including without
>>>>> limitation
>>>>> + * the rights to use, copy, modify, merge, publish, distribute,
>>>>> sublicense,
>>>>> + * and/or sell copies of the Software, and to permit persons to
>>>>> whom the
>>>>> + * Software is furnished to do so, subject to the following
>>>>> conditions:
>>>>> + *
>>>>> + * The above copyright notice and this permission notice shall be
>>>>> included in
>>>>> + * all copies or substantial portions of the Software.
>>>>> + *
>>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>>>> EXPRESS OR
>>>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>>>>> MERCHANTABILITY,
>>>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
>>>>> SHALL
>>>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
>>>>> DAMAGES OR
>>>>> OTHER
>>>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>>>>> ARISING
>>>>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>>>>> OTHER
>>>>> + * DEALINGS IN THE SOFTWARE.
>>>>> + */
>>>>> +
>>>>> +#include <subdev/clock.h>
>>>>> +#include <subdev/dvfs.h>
>>>>> +#include <subdev/volt.h>
>>>>> +
>>>>> +#include "priv.h"
>>>>> +
>>>>> +#define BUSY_SLOT 0
>>>>> +#define CLK_SLOT 7
>>>>> +
>>>>> +struct gk20a_dvfs_priv {
>>>>> + struct nouveau_dvfs base;
>>>>> +};
>>>>> +
>>>>> +static int
>>>>> +gk20a_dvfs_target(struct nouveau_dvfs *dvfs, int *state)
>>>>> +{
>>>>> + struct nouveau_clock *clk = nouveau_clock(dvfs);
>>>>> +
>>>>> + return nouveau_clock_astate(clk, *state, 0, false);
>>>>> +}
>>>>> +
>>>>> +static int
>>>>> +gk20a_dvfs_get_cur_state(struct nouveau_dvfs *dvfs, int *state)
>>>>> +{
>>>>> + struct nouveau_clock *clk = nouveau_clock(dvfs);
>>>>> +
>>>>> + *state = clk->pstate;
>>>>> + return 0;
>>>>> +}
>>>>> +
>>>>> +static int
>>>>> +gk20a_dvfs_get_target_state(struct nouveau_dvfs *dvfs, int
>>>>> *state, int
>>>>> load)
>>>>> +{
>>>>> + struct nouveau_dvfs_data *data = dvfs->data;
>>>>> + struct nouveau_clock *clk = nouveau_clock(dvfs);
>>>>> + int cur_level, level;
>>>>> +
>>>>> + /* For GK20A, the performance level is directly mapped to
>>>>> pstate
>>>>> */
>>>>> + level = cur_level = clk->pstate;
>>>>> +
>>>>> + if (load > data->p_load_max) {
>>>>> + level = min(clk->state_nr - 1, level +
>>>>> (clk->state_nr /
>>>>> 3));
>>>>> + } else {
>>>>> + level += ((load - data->p_load_target) * 10 /
>>>>> + data->p_load_target) / 2;
>>>>> + level = max(0, level);
>>>>> + level = min(clk->state_nr - 1, level);
>>>>> + }
>>>>> +
>>>>> + nv_trace(dvfs, "cur level = %d, new level = %d\n", cur_level,
>>>>> level);
>>>>> +
>>>>> + *state = level;
>>>>> +
>>>>> + if (level == cur_level)
>>>>> + return 0;
>>>>> + else
>>>>> + return 1;
>>>>> +}
>>>>> +
>>>>> +static int
>>>>> +gk20a_dvfs_get_dev_status(struct nouveau_dvfs *dvfs,
>>>>> + struct nouveau_dvfs_dev_status *status)
>>>>> +{
>>>>> + status->busy = nv_rd32(dvfs, 0x10a508 + (BUSY_SLOT * 0x10));
>>>>> + status->total= nv_rd32(dvfs, 0x10a508 + (CLK_SLOT * 0x10));
>>>>> + return 0;
>>>>> +}
>>>>> +
>>>>> +static void
>>>>> +gk20a_dvfs_reset_dev_status(struct nouveau_dvfs *dvfs)
>>>>> +{
>>>>> + nv_wr32(dvfs, 0x10a508 + (BUSY_SLOT * 0x10), 0x80000000);
>>>>> + nv_wr32(dvfs, 0x10a508 + (CLK_SLOT * 0x10), 0x80000000);
>>>>> +}
>>>>> +
>>>>> +static int
>>>>> +gk20a_dvfs_init(struct nouveau_object *object)
>>>>> +{
>>>>> + struct gk20a_dvfs_priv *priv = (void *)object;
>>>>> + int ret;
>>>>> +
>>>>> + /* init pwr perf counter */
>>>>> + nv_wr32(priv, 0x10a504 + (BUSY_SLOT * 0x10), 0x00200001);
>>>>> + nv_wr32(priv, 0x10a50c + (BUSY_SLOT * 0x10), 0x00000002);
>>>>> + nv_wr32(priv, 0x10a50c + (CLK_SLOT * 0x10), 0x00000003);
>>>>> +
>>>>> + ret = nouveau_dvfs_init(&priv->base);
>>>>> + if (ret)
>>>>> + return ret;
>>>>> +
>>>>> + return 0;
>>>>> +}
>>>>> +
>>>>> +struct nouveau_dvfs_data gk20a_dvfs_data = {
>>>>> + .p_load_target = 70,
>>>>> + .p_load_max = 90,
>>>>> + .p_smooth = 1,
>>>>> +};
>>>>> +
>>>>> +static int
>>>>> +gk20a_dvfs_ctor(struct nouveau_object *parent, struct nouveau_object
>>>>> *engine,
>>>>> + struct nouveau_oclass *oclass, void *data, u32 size,
>>>>> + struct nouveau_object **pobject)
>>>>> +{
>>>>> + struct gk20a_dvfs_priv *priv;
>>>>> + struct nouveau_dvfs *dvfs;
>>>>> + int ret;
>>>>> +
>>>>> + ret = nouveau_dvfs_create(parent, engine, oclass, &priv);
>>>>> + *pobject = nv_object(priv);
>>>>> + if (ret)
>>>>> + return ret;
>>>>> +
>>>>> + dvfs = &priv->base;
>>>>> + dvfs->data = &gk20a_dvfs_data;
>>>>> +
>>>>> + return 0;
>>>>> +}
>>>>> +
>>>>> +struct nouveau_oclass *
>>>>> +gk20a_dvfs_oclass = &(struct nouveau_dvfs_impl) {
>>>>> + .base.handle = NV_SUBDEV(DVFS, 0xea),
>>>>> + .base.ofuncs = &(struct nouveau_ofuncs) {
>>>>> + .ctor = gk20a_dvfs_ctor,
>>>>> + .dtor = _nouveau_dvfs_dtor,
>>>>> + .init = gk20a_dvfs_init,
>>>>> + .fini = _nouveau_dvfs_fini,
>>>>> + },
>>>>> + .get_dev_status = gk20a_dvfs_get_dev_status,
>>>>> + .reset_dev_status = gk20a_dvfs_reset_dev_status,
>>>>> + .target = gk20a_dvfs_target,
>>>>> + .get_cur_state = gk20a_dvfs_get_cur_state,
>>>>> + .get_target_state = gk20a_dvfs_get_target_state,
>>>>> +}.base;
>>>>> diff --git a/nvkm/subdev/dvfs/priv.h b/nvkm/subdev/dvfs/priv.h
>>>>> new file mode 100644
>>>>> index 000000000000..95c8a00a01c1
>>>>> --- /dev/null
>>>>> +++ b/nvkm/subdev/dvfs/priv.h
>>>>> @@ -0,0 +1,43 @@
>>>>> +#ifndef __NVKM_DVFS_PRIV_H__
>>>>> +#define __NVKM_DVFS_PRIV_H__
>>>>> +
>>>>> +#include <subdev/dvfs.h>
>>>>> +
>>>>> +struct nouveau_dvfs_dev_status {
>>>>> + unsigned long total;
>>>>> + unsigned long busy;
>>>>> + int cur_state;
>>>>> +};
>>>>> +
>>>>> +struct nouveau_dvfs_impl {
>>>>> + struct nouveau_oclass base;
>>>>> + int (*get_dev_status)(struct nouveau_dvfs *,
>>>>> + struct nouveau_dvfs_dev_status *);
>>>>> + void (*reset_dev_status)(struct nouveau_dvfs *);
>>>>> + int (*target)(struct nouveau_dvfs *, int *state);
>>>>> + int (*get_cur_state)(struct nouveau_dvfs *, int *state);
>>>>> + int (*get_target_state)(struct nouveau_dvfs *, int *state,
>>>>> int
>>>>> load);
>>>>> +};
>>>>> +
>>>>> +#define nouveau_dvfs_create(p,e,o,d)
>>>>> \
>>>>> + nouveau_dvfs_create_((p), (e), (o), sizeof(**d), (void **)d)
>>>>> +#define nouveau_dvfs_destroy(p) ({
>>>>> \
>>>>> + struct nouveau_dvfs *d = (p);
>>>>> \
>>>>> + _nouveau_dvfs_dtor(nv_object(d));
>>>>> \
>>>>> +})
>>>>> +#define nouveau_dvfs_init(p) ({
>>>>> \
>>>>> + struct nouveau_dvfs *d = (p);
>>>>> \
>>>>> + _nouveau_dvfs_init(nv_object(d));
>>>>> \
>>>>> +})
>>>>> +#define nouveau_dvfs_fini(p,s) ({
>>>>> \
>>>>> + struct nouveau_dvfs *d = (p);
>>>>> \
>>>>> + _nouveau_dvfs_fini(nv_object(d), (s));
>>>>> \
>>>>> +})
>>>>> +
>>>>> +int nouveau_dvfs_create_(struct nouveau_object *, struct
>>>>> nouveau_object
>>>>> *,
>>>>> + struct nouveau_oclass *, int, void **);
>>>>> +void _nouveau_dvfs_dtor(struct nouveau_object *);
>>>>> +int _nouveau_dvfs_init(struct nouveau_object *);
>>>>> +int _nouveau_dvfs_fini(struct nouveau_object *, bool suspend);
>>>>> +
>>>>> +#endif
>>>>> --
>>>>> 1.9.1
>>>>>
>>>>> _______________________________________________
>>>>> Nouveau mailing list
>>>>> Nouveau at lists.freedesktop.org
>>>>> http://lists.freedesktop.org/mailman/listinfo/nouveau
>>>
>>>
>>> -----------------------------------------------------------------------------------
>>>
>>> This email message is for the sole use of the intended recipient(s)
>>> and may
>>> contain
>>> confidential information. Any unauthorized review, use, disclosure or
>>> distribution
>>> is prohibited. If you are not the intended recipient, please
>>> contact the
>>> sender by
>>> reply email and destroy all copies of the original message.
>>> -----------------------------------------------------------------------------------
>>>
>> _______________________________________________
>> Nouveau mailing list
>> Nouveau at lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/nouveau
>
More information about the Nouveau
mailing list