[Nouveau] [RFC PATCH 2/3] dvfs: add support for GK20A

Vince Hsu vinceh at nvidia.com
Thu Dec 18 02:37:40 PST 2014


On 12/18/2014 06:25 PM, 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. :)
>>
>> 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.
Understand. Thanks!

Vince
>
>>>
>>> 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.
>> -----------------------------------------------------------------------------------



More information about the Nouveau mailing list