[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