[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