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

Ben Skeggs skeggsb at gmail.com
Thu Dec 18 02:25:52 PST 2014


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.

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