blob: 90a7d89cc019b81ab93f6a3f38d663864e173297 [file] [log] [blame]
Ben Skeggsaa4d7a42013-02-13 15:29:11 +10001/*
2 * Copyright 2013 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 */
Ben Skeggs4d346862015-01-14 15:31:13 +100024#include "priv.h"
Ben Skeggsaa4d7a42013-02-13 15:29:11 +100025
Ben Skeggs96af8222014-08-10 04:10:24 +100026#include <core/client.h>
Ben Skeggsaa4d7a42013-02-13 15:29:11 +100027#include <core/option.h>
Ben Skeggs24bd0932015-08-20 14:54:18 +100028#include <core/parent.h>
Ben Skeggs4d346862015-01-14 15:31:13 +100029
Ben Skeggs96af8222014-08-10 04:10:24 +100030#include <nvif/class.h>
31#include <nvif/ioctl.h>
Ben Skeggs4d346862015-01-14 15:31:13 +100032#include <nvif/unpack.h>
Ben Skeggsaa4d7a42013-02-13 15:29:11 +100033
Samuel Pitoiset45f0f942015-06-07 22:40:17 +020034static u8
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +100035nvkm_pm_count_perfdom(struct nvkm_pm *pm)
Samuel Pitoiset45f0f942015-06-07 22:40:17 +020036{
37 struct nvkm_perfdom *dom;
38 u8 domain_nr = 0;
39
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +100040 list_for_each_entry(dom, &pm->domains, head)
Samuel Pitoiset45f0f942015-06-07 22:40:17 +020041 domain_nr++;
42 return domain_nr;
43}
44
Samuel Pitoisete4047592015-06-07 22:40:19 +020045static u16
Samuel Pitoiset45f0f942015-06-07 22:40:17 +020046nvkm_perfdom_count_perfsig(struct nvkm_perfdom *dom)
47{
Samuel Pitoisete4047592015-06-07 22:40:19 +020048 u16 signal_nr = 0;
Samuel Pitoiset45f0f942015-06-07 22:40:17 +020049 int i;
50
51 if (dom) {
52 for (i = 0; i < dom->signal_nr; i++) {
53 if (dom->signal[i].name)
54 signal_nr++;
55 }
56 }
57 return signal_nr;
58}
59
60static struct nvkm_perfdom *
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +100061nvkm_perfdom_find(struct nvkm_pm *pm, int di)
Samuel Pitoiset45f0f942015-06-07 22:40:17 +020062{
63 struct nvkm_perfdom *dom;
64 int tmp = 0;
65
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +100066 list_for_each_entry(dom, &pm->domains, head) {
Samuel Pitoiset45f0f942015-06-07 22:40:17 +020067 if (tmp++ == di)
68 return dom;
69 }
70 return NULL;
71}
72
Ben Skeggs4d346862015-01-14 15:31:13 +100073struct nvkm_perfsig *
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +100074nvkm_perfsig_find(struct nvkm_pm *pm, u8 di, u8 si, struct nvkm_perfdom **pdom)
Ben Skeggsaa4d7a42013-02-13 15:29:11 +100075{
Ben Skeggs4d346862015-01-14 15:31:13 +100076 struct nvkm_perfdom *dom = *pdom;
Ben Skeggsaa4d7a42013-02-13 15:29:11 +100077
78 if (dom == NULL) {
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +100079 dom = nvkm_perfdom_find(pm, di);
Samuel Pitoiset10a4d2b2015-06-07 22:40:20 +020080 if (dom == NULL)
81 return NULL;
82 *pdom = dom;
Ben Skeggsaa4d7a42013-02-13 15:29:11 +100083 }
84
Samuel Pitoiset10a4d2b2015-06-07 22:40:20 +020085 if (!dom->signal[si].name)
86 return NULL;
87 return &dom->signal[si];
Ben Skeggsaa4d7a42013-02-13 15:29:11 +100088}
89
Samuel Pitoiset50d138d2015-06-07 22:40:23 +020090static u8
91nvkm_perfsig_count_perfsrc(struct nvkm_perfsig *sig)
92{
93 u8 source_nr = 0, i;
94
95 for (i = 0; i < ARRAY_SIZE(sig->source); i++) {
96 if (sig->source[i])
97 source_nr++;
98 }
99 return source_nr;
100}
101
Samuel Pitoiset6f99c842015-06-07 22:40:24 +0200102static struct nvkm_perfsrc *
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000103nvkm_perfsrc_find(struct nvkm_pm *pm, struct nvkm_perfsig *sig, int si)
Samuel Pitoiset6f99c842015-06-07 22:40:24 +0200104{
105 struct nvkm_perfsrc *src;
106 bool found = false;
107 int tmp = 1; /* Sources ID start from 1 */
108 u8 i;
109
110 for (i = 0; i < ARRAY_SIZE(sig->source) && sig->source[i]; i++) {
111 if (sig->source[i] == si) {
112 found = true;
113 break;
114 }
115 }
116
117 if (found) {
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000118 list_for_each_entry(src, &pm->sources, head) {
Samuel Pitoiset6f99c842015-06-07 22:40:24 +0200119 if (tmp++ == si)
120 return src;
121 }
122 }
123
124 return NULL;
125}
126
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200127static int
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000128nvkm_perfsrc_enable(struct nvkm_pm *pm, struct nvkm_perfctr *ctr)
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200129{
Ben Skeggs476901f2015-08-20 14:54:13 +1000130 struct nvkm_subdev *subdev = &pm->engine.subdev;
131 struct nvkm_device *device = subdev->device;
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200132 struct nvkm_perfdom *dom = NULL;
133 struct nvkm_perfsig *sig;
134 struct nvkm_perfsrc *src;
135 u32 mask, value;
136 int i, j;
137
Samuel Pitoiset7fe882e2015-08-04 23:58:12 +0200138 for (i = 0; i < 4; i++) {
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200139 for (j = 0; j < 8 && ctr->source[i][j]; j++) {
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000140 sig = nvkm_perfsig_find(pm, ctr->domain,
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200141 ctr->signal[i], &dom);
142 if (!sig)
143 return -EINVAL;
144
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000145 src = nvkm_perfsrc_find(pm, sig, ctr->source[i][j]);
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200146 if (!src)
147 return -EINVAL;
148
149 /* set enable bit if needed */
150 mask = value = 0x00000000;
151 if (src->enable)
152 mask = value = 0x80000000;
153 mask |= (src->mask << src->shift);
154 value |= ((ctr->source[i][j] >> 32) << src->shift);
155
156 /* enable the source */
Ben Skeggs846e8312015-08-20 14:54:10 +1000157 nvkm_mask(device, src->addr, mask, value);
Ben Skeggs476901f2015-08-20 14:54:13 +1000158 nvkm_debug(subdev,
159 "enabled source %08x %08x %08x\n",
160 src->addr, mask, value);
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200161 }
162 }
163 return 0;
164}
165
166static int
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000167nvkm_perfsrc_disable(struct nvkm_pm *pm, struct nvkm_perfctr *ctr)
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200168{
Ben Skeggs476901f2015-08-20 14:54:13 +1000169 struct nvkm_subdev *subdev = &pm->engine.subdev;
170 struct nvkm_device *device = subdev->device;
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200171 struct nvkm_perfdom *dom = NULL;
172 struct nvkm_perfsig *sig;
173 struct nvkm_perfsrc *src;
Samuel Pitoisetd4a312d2015-06-14 13:50:06 +0200174 u32 mask;
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200175 int i, j;
176
Samuel Pitoiset7fe882e2015-08-04 23:58:12 +0200177 for (i = 0; i < 4; i++) {
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200178 for (j = 0; j < 8 && ctr->source[i][j]; j++) {
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000179 sig = nvkm_perfsig_find(pm, ctr->domain,
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200180 ctr->signal[i], &dom);
181 if (!sig)
182 return -EINVAL;
183
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000184 src = nvkm_perfsrc_find(pm, sig, ctr->source[i][j]);
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200185 if (!src)
186 return -EINVAL;
187
Samuel Pitoisetd4a312d2015-06-14 13:50:06 +0200188 /* unset enable bit if needed */
189 mask = 0x00000000;
190 if (src->enable)
191 mask = 0x80000000;
192 mask |= (src->mask << src->shift);
193
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200194 /* disable the source */
Ben Skeggs846e8312015-08-20 14:54:10 +1000195 nvkm_mask(device, src->addr, mask, 0);
Ben Skeggs476901f2015-08-20 14:54:13 +1000196 nvkm_debug(subdev, "disabled source %08x %08x\n",
197 src->addr, mask);
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200198 }
199 }
200 return 0;
201}
202
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000203/*******************************************************************************
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200204 * Perfdom object classes
Samuel Pitoiset5a0bc4b2015-06-07 22:40:15 +0200205 ******************************************************************************/
206static int
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200207nvkm_perfdom_init(struct nvkm_object *object, void *data, u32 size)
Samuel Pitoiset3bfdde12015-06-07 22:40:25 +0200208{
209 union {
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200210 struct nvif_perfdom_init none;
Samuel Pitoiset3bfdde12015-06-07 22:40:25 +0200211 } *args = data;
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000212 struct nvkm_pm *pm = (void *)object->engine;
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200213 struct nvkm_perfdom *dom = (void *)object;
214 int ret, i;
Samuel Pitoiset3bfdde12015-06-07 22:40:25 +0200215
Ben Skeggs53003942015-08-20 14:54:13 +1000216 nvif_ioctl(object, "perfdom init size %d\n", size);
Samuel Pitoiset3bfdde12015-06-07 22:40:25 +0200217 if (nvif_unvers(args->none)) {
Ben Skeggs53003942015-08-20 14:54:13 +1000218 nvif_ioctl(object, "perfdom init\n");
Samuel Pitoiset3bfdde12015-06-07 22:40:25 +0200219 } else
220 return ret;
221
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200222 for (i = 0; i < 4; i++) {
223 if (dom->ctr[i]) {
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000224 dom->func->init(pm, dom, dom->ctr[i]);
Samuel Pitoiset3bfdde12015-06-07 22:40:25 +0200225
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200226 /* enable sources */
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000227 nvkm_perfsrc_enable(pm, dom->ctr[i]);
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200228 }
229 }
230
Samuel Pitoiset3bfdde12015-06-07 22:40:25 +0200231 /* start next batch of counters for sampling */
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000232 dom->func->next(pm, dom);
Samuel Pitoiset3bfdde12015-06-07 22:40:25 +0200233 return 0;
234}
235
236static int
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200237nvkm_perfdom_sample(struct nvkm_object *object, void *data, u32 size)
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000238{
Ben Skeggs96af8222014-08-10 04:10:24 +1000239 union {
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200240 struct nvif_perfdom_sample none;
Ben Skeggs96af8222014-08-10 04:10:24 +1000241 } *args = data;
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000242 struct nvkm_pm *pm = (void *)object->engine;
Ben Skeggs4d346862015-01-14 15:31:13 +1000243 struct nvkm_perfdom *dom;
Ben Skeggs96af8222014-08-10 04:10:24 +1000244 int ret;
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000245
Ben Skeggs53003942015-08-20 14:54:13 +1000246 nvif_ioctl(object, "perfdom sample size %d\n", size);
Ben Skeggs96af8222014-08-10 04:10:24 +1000247 if (nvif_unvers(args->none)) {
Ben Skeggs53003942015-08-20 14:54:13 +1000248 nvif_ioctl(object, "perfdom sample\n");
Ben Skeggs96af8222014-08-10 04:10:24 +1000249 } else
250 return ret;
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000251 pm->sequence++;
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000252
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200253 /* sample previous batch of counters */
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000254 list_for_each_entry(dom, &pm->domains, head)
255 dom->func->next(pm, dom);
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000256
257 return 0;
258}
259
260static int
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200261nvkm_perfdom_read(struct nvkm_object *object, void *data, u32 size)
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000262{
Ben Skeggs96af8222014-08-10 04:10:24 +1000263 union {
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200264 struct nvif_perfdom_read_v0 v0;
Ben Skeggs96af8222014-08-10 04:10:24 +1000265 } *args = data;
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000266 struct nvkm_pm *pm = (void *)object->engine;
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200267 struct nvkm_perfdom *dom = (void *)object;
268 int ret, i;
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000269
Ben Skeggs53003942015-08-20 14:54:13 +1000270 nvif_ioctl(object, "perfdom read size %d\n", size);
Ben Skeggs96af8222014-08-10 04:10:24 +1000271 if (nvif_unpack(args->v0, 0, 0, false)) {
Ben Skeggs53003942015-08-20 14:54:13 +1000272 nvif_ioctl(object, "perfdom read vers %d\n", args->v0.version);
Ben Skeggs96af8222014-08-10 04:10:24 +1000273 } else
274 return ret;
275
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200276 for (i = 0; i < 4; i++) {
277 if (dom->ctr[i])
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000278 dom->func->read(pm, dom, dom->ctr[i]);
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200279 }
280
281 if (!dom->clk)
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000282 return -EAGAIN;
283
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200284 for (i = 0; i < 4; i++)
285 if (dom->ctr[i])
286 args->v0.ctr[i] = dom->ctr[i]->ctr;
287 args->v0.clk = dom->clk;
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000288 return 0;
289}
290
Ben Skeggs96af8222014-08-10 04:10:24 +1000291static int
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200292nvkm_perfdom_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
Ben Skeggs96af8222014-08-10 04:10:24 +1000293{
294 switch (mthd) {
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200295 case NVIF_PERFDOM_V0_INIT:
296 return nvkm_perfdom_init(object, data, size);
297 case NVIF_PERFDOM_V0_SAMPLE:
298 return nvkm_perfdom_sample(object, data, size);
299 case NVIF_PERFDOM_V0_READ:
300 return nvkm_perfdom_read(object, data, size);
Ben Skeggs96af8222014-08-10 04:10:24 +1000301 default:
302 break;
303 }
304 return -EINVAL;
305}
306
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000307static void
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200308nvkm_perfdom_dtor(struct nvkm_object *object)
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000309{
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000310 struct nvkm_pm *pm = (void *)object->engine;
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200311 struct nvkm_perfdom *dom = (void *)object;
312 int i;
313
314 for (i = 0; i < 4; i++) {
315 struct nvkm_perfctr *ctr = dom->ctr[i];
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200316 if (ctr) {
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000317 nvkm_perfsrc_disable(pm, ctr);
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200318 if (ctr->head.next)
319 list_del(&ctr->head);
320 }
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200321 kfree(ctr);
322 }
323 nvkm_object_destroy(&dom->base);
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000324}
325
326static int
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000327nvkm_perfctr_new(struct nvkm_perfdom *dom, int slot, u8 domain,
328 struct nvkm_perfsig *signal[4], u64 source[4][8],
329 u16 logic_op, struct nvkm_perfctr **pctr)
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000330{
Ben Skeggs4d346862015-01-14 15:31:13 +1000331 struct nvkm_perfctr *ctr;
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200332 int i, j;
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000333
Samuel Pitoiset44d9de52015-06-07 22:40:16 +0200334 if (!dom)
335 return -EINVAL;
336
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200337 ctr = *pctr = kzalloc(sizeof(*ctr), GFP_KERNEL);
338 if (!ctr)
339 return -ENOMEM;
340
Samuel Pitoisetd4a312d2015-06-14 13:50:06 +0200341 ctr->domain = domain;
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200342 ctr->logic_op = logic_op;
343 ctr->slot = slot;
344 for (i = 0; i < 4; i++) {
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200345 if (signal[i]) {
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200346 ctr->signal[i] = signal[i] - dom->signal;
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200347 for (j = 0; j < 8; j++)
348 ctr->source[i][j] = source[i][j];
349 }
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200350 }
351 list_add_tail(&ctr->head, &dom->list);
352
353 return 0;
354}
355
356static int
357nvkm_perfdom_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
358 struct nvkm_oclass *oclass, void *data, u32 size,
359 struct nvkm_object **pobject)
360{
361 union {
362 struct nvif_perfdom_v0 v0;
363 } *args = data;
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000364 struct nvkm_pm *pm = (void *)engine;
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200365 struct nvkm_perfdom *sdom = NULL;
366 struct nvkm_perfctr *ctr[4] = {};
367 struct nvkm_perfdom *dom;
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200368 int c, s, m;
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200369 int ret;
370
Ben Skeggs53003942015-08-20 14:54:13 +1000371 nvif_ioctl(parent, "create perfdom size %d\n", size);
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200372 if (nvif_unpack(args->v0, 0, 0, false)) {
Ben Skeggs53003942015-08-20 14:54:13 +1000373 nvif_ioctl(parent, "create perfdom vers %d dom %d mode %02x\n",
374 args->v0.version, args->v0.domain, args->v0.mode);
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200375 } else
376 return ret;
377
378 for (c = 0; c < ARRAY_SIZE(args->v0.ctr); c++) {
379 struct nvkm_perfsig *sig[4] = {};
Samuel Pitoisetd4a312d2015-06-14 13:50:06 +0200380 u64 src[4][8] = {};
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200381
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200382 for (s = 0; s < ARRAY_SIZE(args->v0.ctr[c].signal); s++) {
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000383 sig[s] = nvkm_perfsig_find(pm, args->v0.domain,
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200384 args->v0.ctr[c].signal[s],
385 &sdom);
386 if (args->v0.ctr[c].signal[s] && !sig[s])
387 return -EINVAL;
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200388
389 for (m = 0; m < 8; m++) {
390 src[s][m] = args->v0.ctr[c].source[s][m];
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000391 if (src[s][m] && !nvkm_perfsrc_find(pm, sig[s],
Samuel Pitoiset6137b5a2015-06-07 22:40:27 +0200392 src[s][m]))
393 return -EINVAL;
394 }
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200395 }
396
Samuel Pitoisetd4a312d2015-06-14 13:50:06 +0200397 ret = nvkm_perfctr_new(sdom, c, args->v0.domain, sig, src,
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200398 args->v0.ctr[c].logic_op, &ctr[c]);
399 if (ret)
400 return ret;
401 }
402
403 if (!sdom)
404 return -EINVAL;
405
406 ret = nvkm_object_create(parent, engine, oclass, 0, &dom);
407 *pobject = nv_object(dom);
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000408 if (ret)
409 return ret;
410
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200411 dom->func = sdom->func;
412 dom->addr = sdom->addr;
413 dom->mode = args->v0.mode;
414 for (c = 0; c < ARRAY_SIZE(ctr); c++)
415 dom->ctr[c] = ctr[c];
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000416 return 0;
417}
418
Ben Skeggs4d346862015-01-14 15:31:13 +1000419static struct nvkm_ofuncs
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200420nvkm_perfdom_ofuncs = {
421 .ctor = nvkm_perfdom_ctor,
422 .dtor = nvkm_perfdom_dtor,
Ben Skeggsaa358882015-08-20 14:54:16 +1000423 .init = _nvkm_object_init,
424 .fini = _nvkm_object_fini,
Samuel Pitoiset0f380432015-06-07 22:40:26 +0200425 .mthd = nvkm_perfdom_mthd,
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000426};
427
Ben Skeggs2d4b94b2015-06-14 12:10:59 +1000428/*******************************************************************************
429 * Perfmon object classes
430 ******************************************************************************/
431static int
432nvkm_perfmon_mthd_query_domain(struct nvkm_object *object, void *data, u32 size)
433{
434 union {
435 struct nvif_perfmon_query_domain_v0 v0;
436 } *args = data;
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000437 struct nvkm_pm *pm = (void *)object->engine;
Ben Skeggs2d4b94b2015-06-14 12:10:59 +1000438 struct nvkm_perfdom *dom;
439 u8 domain_nr;
440 int di, ret;
441
Ben Skeggs53003942015-08-20 14:54:13 +1000442 nvif_ioctl(object, "perfmon query domain size %d\n", size);
Ben Skeggs2d4b94b2015-06-14 12:10:59 +1000443 if (nvif_unpack(args->v0, 0, 0, false)) {
Ben Skeggs53003942015-08-20 14:54:13 +1000444 nvif_ioctl(object, "perfmon domain vers %d iter %02x\n",
445 args->v0.version, args->v0.iter);
Ben Skeggs2d4b94b2015-06-14 12:10:59 +1000446 di = (args->v0.iter & 0xff) - 1;
447 } else
448 return ret;
449
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000450 domain_nr = nvkm_pm_count_perfdom(pm);
Ben Skeggs2d4b94b2015-06-14 12:10:59 +1000451 if (di >= (int)domain_nr)
452 return -EINVAL;
453
454 if (di >= 0) {
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000455 dom = nvkm_perfdom_find(pm, di);
Ben Skeggs2d4b94b2015-06-14 12:10:59 +1000456 if (dom == NULL)
457 return -EINVAL;
458
459 args->v0.id = di;
460 args->v0.signal_nr = nvkm_perfdom_count_perfsig(dom);
Samuel Pitoisetdf0b37e2015-06-19 17:36:37 +0200461 strncpy(args->v0.name, dom->name, sizeof(args->v0.name));
Ben Skeggs2d4b94b2015-06-14 12:10:59 +1000462
463 /* Currently only global counters (PCOUNTER) are implemented
464 * but this will be different for local counters (MP). */
465 args->v0.counter_nr = 4;
466 }
467
468 if (++di < domain_nr) {
469 args->v0.iter = ++di;
470 return 0;
471 }
472
473 args->v0.iter = 0xff;
474 return 0;
475}
476
477static int
478nvkm_perfmon_mthd_query_signal(struct nvkm_object *object, void *data, u32 size)
479{
480 union {
481 struct nvif_perfmon_query_signal_v0 v0;
482 } *args = data;
483 struct nvkm_device *device = nv_device(object);
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000484 struct nvkm_pm *pm = (void *)object->engine;
Ben Skeggs2d4b94b2015-06-14 12:10:59 +1000485 struct nvkm_perfdom *dom;
486 struct nvkm_perfsig *sig;
487 const bool all = nvkm_boolopt(device->cfgopt, "NvPmShowAll", false);
488 const bool raw = nvkm_boolopt(device->cfgopt, "NvPmUnnamed", all);
489 int ret, si;
490
Ben Skeggs53003942015-08-20 14:54:13 +1000491 nvif_ioctl(object, "perfmon query signal size %d\n", size);
Ben Skeggs2d4b94b2015-06-14 12:10:59 +1000492 if (nvif_unpack(args->v0, 0, 0, false)) {
Ben Skeggs53003942015-08-20 14:54:13 +1000493 nvif_ioctl(object,
494 "perfmon query signal vers %d dom %d iter %04x\n",
495 args->v0.version, args->v0.domain, args->v0.iter);
Ben Skeggs2d4b94b2015-06-14 12:10:59 +1000496 si = (args->v0.iter & 0xffff) - 1;
497 } else
498 return ret;
499
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000500 dom = nvkm_perfdom_find(pm, args->v0.domain);
Ben Skeggs2d4b94b2015-06-14 12:10:59 +1000501 if (dom == NULL || si >= (int)dom->signal_nr)
502 return -EINVAL;
503
504 if (si >= 0) {
505 sig = &dom->signal[si];
506 if (raw || !sig->name) {
507 snprintf(args->v0.name, sizeof(args->v0.name),
508 "/%s/%02x", dom->name, si);
509 } else {
510 strncpy(args->v0.name, sig->name,
511 sizeof(args->v0.name));
512 }
513
514 args->v0.signal = si;
515 args->v0.source_nr = nvkm_perfsig_count_perfsrc(sig);
516 }
517
518 while (++si < dom->signal_nr) {
519 if (all || dom->signal[si].name) {
520 args->v0.iter = ++si;
521 return 0;
522 }
523 }
524
525 args->v0.iter = 0xffff;
526 return 0;
527}
528
529static int
530nvkm_perfmon_mthd_query_source(struct nvkm_object *object, void *data, u32 size)
531{
532 union {
533 struct nvif_perfmon_query_source_v0 v0;
534 } *args = data;
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000535 struct nvkm_pm *pm = (void *)object->engine;
Ben Skeggs2d4b94b2015-06-14 12:10:59 +1000536 struct nvkm_perfdom *dom = NULL;
537 struct nvkm_perfsig *sig;
538 struct nvkm_perfsrc *src;
539 u8 source_nr = 0;
540 int si, ret;
541
Ben Skeggs53003942015-08-20 14:54:13 +1000542 nvif_ioctl(object, "perfmon query source size %d\n", size);
Ben Skeggs2d4b94b2015-06-14 12:10:59 +1000543 if (nvif_unpack(args->v0, 0, 0, false)) {
Ben Skeggs53003942015-08-20 14:54:13 +1000544 nvif_ioctl(object,
545 "perfmon source vers %d dom %d sig %02x iter %02x\n",
546 args->v0.version, args->v0.domain, args->v0.signal,
547 args->v0.iter);
Ben Skeggs2d4b94b2015-06-14 12:10:59 +1000548 si = (args->v0.iter & 0xff) - 1;
549 } else
550 return ret;
551
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000552 sig = nvkm_perfsig_find(pm, args->v0.domain, args->v0.signal, &dom);
Ben Skeggs2d4b94b2015-06-14 12:10:59 +1000553 if (!sig)
554 return -EINVAL;
555
556 source_nr = nvkm_perfsig_count_perfsrc(sig);
557 if (si >= (int)source_nr)
558 return -EINVAL;
559
560 if (si >= 0) {
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000561 src = nvkm_perfsrc_find(pm, sig, sig->source[si]);
Ben Skeggs2d4b94b2015-06-14 12:10:59 +1000562 if (!src)
563 return -EINVAL;
564
565 args->v0.source = sig->source[si];
566 args->v0.mask = src->mask;
567 strncpy(args->v0.name, src->name, sizeof(args->v0.name));
568 }
569
570 if (++si < source_nr) {
571 args->v0.iter = ++si;
572 return 0;
573 }
574
575 args->v0.iter = 0xff;
576 return 0;
577}
578
579static int
580nvkm_perfmon_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
581{
582 switch (mthd) {
583 case NVIF_PERFMON_V0_QUERY_DOMAIN:
584 return nvkm_perfmon_mthd_query_domain(object, data, size);
585 case NVIF_PERFMON_V0_QUERY_SIGNAL:
586 return nvkm_perfmon_mthd_query_signal(object, data, size);
587 case NVIF_PERFMON_V0_QUERY_SOURCE:
588 return nvkm_perfmon_mthd_query_source(object, data, size);
589 default:
590 break;
591 }
592 return -EINVAL;
593}
594
Ben Skeggsf21950e2015-06-14 12:20:37 +1000595static struct nvkm_oclass
596nvkm_perfmon_sclass[] = {
597 { .handle = NVIF_IOCTL_NEW_V0_PERFDOM,
598 .ofuncs = &nvkm_perfdom_ofuncs,
599 },
600 {}
601};
602
603static int
604nvkm_perfmon_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
605 struct nvkm_oclass *oclass, void *data, u32 size,
606 struct nvkm_object **pobject)
607{
608 struct nvkm_parent *perfmon;
609 int ret = nvkm_parent_create(parent, engine, oclass, 0,
610 nvkm_perfmon_sclass, 0, &perfmon);
611 *pobject = perfmon ? &perfmon->object : NULL;
612 return ret;
613}
614
Ben Skeggs2d4b94b2015-06-14 12:10:59 +1000615static struct nvkm_ofuncs
616nvkm_perfmon_ofuncs = {
Ben Skeggsf21950e2015-06-14 12:20:37 +1000617 .ctor = nvkm_perfmon_ctor,
618 .dtor = _nvkm_parent_dtor,
619 .init = _nvkm_parent_init,
620 .fini = _nvkm_parent_fini,
Ben Skeggs2d4b94b2015-06-14 12:10:59 +1000621 .mthd = nvkm_perfmon_mthd,
622};
623
Ben Skeggs4d346862015-01-14 15:31:13 +1000624struct nvkm_oclass
625nvkm_pm_sclass[] = {
Samuel Pitoiset5a0bc4b2015-06-07 22:40:15 +0200626 {
627 .handle = NVIF_IOCTL_NEW_V0_PERFMON,
628 .ofuncs = &nvkm_perfmon_ofuncs,
629 },
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000630 {},
631};
632
633/*******************************************************************************
634 * PPM context
635 ******************************************************************************/
636static void
Ben Skeggs4d346862015-01-14 15:31:13 +1000637nvkm_perfctx_dtor(struct nvkm_object *object)
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000638{
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000639 struct nvkm_pm *pm = (void *)object->engine;
Samuel Pitoiset3693d542015-06-07 22:40:11 +0200640 struct nvkm_perfctx *ctx = (void *)object;
641
Ben Skeggsa1e88732015-08-20 14:54:15 +1000642 nvkm_gpuobj_destroy(&ctx->base);
Ben Skeggs6cf813f2015-08-20 14:54:17 +1000643 mutex_lock(&nv_subdev(pm)->mutex);
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000644 if (pm->context == ctx)
645 pm->context = NULL;
646 mutex_unlock(&nv_subdev(pm)->mutex);
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000647}
648
649static int
Ben Skeggs4d346862015-01-14 15:31:13 +1000650nvkm_perfctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
651 struct nvkm_oclass *oclass, void *data, u32 size,
652 struct nvkm_object **pobject)
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000653{
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000654 struct nvkm_pm *pm = (void *)engine;
Ben Skeggs4d346862015-01-14 15:31:13 +1000655 struct nvkm_perfctx *ctx;
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000656 int ret;
657
Ben Skeggsf21950e2015-06-14 12:20:37 +1000658 /* no context needed for perfdom objects... */
Ben Skeggs2a9f8472015-08-20 14:54:18 +1000659 if (parent->parent != &nvkm_client(parent)->object) {
Ben Skeggsf21950e2015-06-14 12:20:37 +1000660 atomic_inc(&parent->refcount);
661 *pobject = parent;
662 return 1;
663 }
664
Ben Skeggsa1e88732015-08-20 14:54:15 +1000665 ret = nvkm_gpuobj_create(parent, engine, oclass, 0, NULL, 0, 0, 0, &ctx);
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000666 *pobject = nv_object(ctx);
667 if (ret)
668 return ret;
669
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000670 mutex_lock(&nv_subdev(pm)->mutex);
671 if (pm->context == NULL)
672 pm->context = ctx;
673 if (ctx != pm->context)
Samuel Pitoiset305c1952015-06-07 22:40:12 +0200674 ret = -EBUSY;
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000675 mutex_unlock(&nv_subdev(pm)->mutex);
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000676
Samuel Pitoiset305c1952015-06-07 22:40:12 +0200677 return ret;
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000678}
679
Ben Skeggs4d346862015-01-14 15:31:13 +1000680struct nvkm_oclass
681nvkm_pm_cclass = {
Ben Skeggs4d346862015-01-14 15:31:13 +1000682 .ofuncs = &(struct nvkm_ofuncs) {
683 .ctor = nvkm_perfctx_ctor,
684 .dtor = nvkm_perfctx_dtor,
Ben Skeggsa1e88732015-08-20 14:54:15 +1000685 .init = _nvkm_gpuobj_init,
686 .fini = _nvkm_gpuobj_fini,
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000687 },
688};
689
690/*******************************************************************************
691 * PPM engine/subdev functions
692 ******************************************************************************/
693int
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000694nvkm_perfsrc_new(struct nvkm_pm *pm, struct nvkm_perfsig *sig,
Samuel Pitoisete82661e2015-06-07 22:40:22 +0200695 const struct nvkm_specsrc *spec)
696{
697 const struct nvkm_specsrc *ssrc;
698 const struct nvkm_specmux *smux;
699 struct nvkm_perfsrc *src;
700 u8 source_nr = 0;
701
702 if (!spec) {
703 /* No sources are defined for this signal. */
704 return 0;
705 }
706
707 ssrc = spec;
708 while (ssrc->name) {
709 smux = ssrc->mux;
710 while (smux->name) {
711 bool found = false;
712 u8 source_id = 0;
713 u32 len;
714
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000715 list_for_each_entry(src, &pm->sources, head) {
Samuel Pitoisete82661e2015-06-07 22:40:22 +0200716 if (src->addr == ssrc->addr &&
717 src->shift == smux->shift) {
718 found = true;
719 break;
720 }
721 source_id++;
722 }
723
724 if (!found) {
725 src = kzalloc(sizeof(*src), GFP_KERNEL);
726 if (!src)
727 return -ENOMEM;
728
729 src->addr = ssrc->addr;
730 src->mask = smux->mask;
731 src->shift = smux->shift;
732 src->enable = smux->enable;
733
734 len = strlen(ssrc->name) +
735 strlen(smux->name) + 2;
736 src->name = kzalloc(len, GFP_KERNEL);
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000737 if (!src->name) {
738 kfree(src);
Samuel Pitoisete82661e2015-06-07 22:40:22 +0200739 return -ENOMEM;
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000740 }
Samuel Pitoisete82661e2015-06-07 22:40:22 +0200741 snprintf(src->name, len, "%s_%s", ssrc->name,
742 smux->name);
743
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000744 list_add_tail(&src->head, &pm->sources);
Samuel Pitoisete82661e2015-06-07 22:40:22 +0200745 }
746
747 sig->source[source_nr++] = source_id + 1;
748 smux++;
749 }
750 ssrc++;
751 }
752
753 return 0;
754}
755
756int
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000757nvkm_perfdom_new(struct nvkm_pm *pm, const char *name, u32 mask,
Ben Skeggs4d346862015-01-14 15:31:13 +1000758 u32 base, u32 size_unit, u32 size_domain,
759 const struct nvkm_specdom *spec)
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000760{
Ben Skeggs4d346862015-01-14 15:31:13 +1000761 const struct nvkm_specdom *sdom;
762 const struct nvkm_specsig *ssig;
763 struct nvkm_perfdom *dom;
Samuel Pitoisete82661e2015-06-07 22:40:22 +0200764 int ret, i;
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000765
766 for (i = 0; i == 0 || mask; i++) {
767 u32 addr = base + (i * size_unit);
768 if (i && !(mask & (1 << i)))
769 continue;
770
771 sdom = spec;
772 while (sdom->signal_nr) {
773 dom = kzalloc(sizeof(*dom) + sdom->signal_nr *
774 sizeof(*dom->signal), GFP_KERNEL);
775 if (!dom)
776 return -ENOMEM;
777
778 if (mask) {
779 snprintf(dom->name, sizeof(dom->name),
780 "%s/%02x/%02x", name, i,
781 (int)(sdom - spec));
782 } else {
783 snprintf(dom->name, sizeof(dom->name),
784 "%s/%02x", name, (int)(sdom - spec));
785 }
786
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000787 list_add_tail(&dom->head, &pm->domains);
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000788 INIT_LIST_HEAD(&dom->list);
789 dom->func = sdom->func;
790 dom->addr = addr;
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000791 dom->signal_nr = sdom->signal_nr;
792
793 ssig = (sdom++)->signal;
794 while (ssig->name) {
Samuel Pitoisete82661e2015-06-07 22:40:22 +0200795 struct nvkm_perfsig *sig =
796 &dom->signal[ssig->signal];
797 sig->name = ssig->name;
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000798 ret = nvkm_perfsrc_new(pm, sig, ssig->source);
Samuel Pitoisete82661e2015-06-07 22:40:22 +0200799 if (ret)
800 return ret;
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000801 ssig++;
802 }
803
804 addr += size_domain;
805 }
806
807 mask &= ~(1 << i);
808 }
809
810 return 0;
811}
812
813int
Ben Skeggs4d346862015-01-14 15:31:13 +1000814_nvkm_pm_fini(struct nvkm_object *object, bool suspend)
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000815{
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000816 struct nvkm_pm *pm = (void *)object;
Ben Skeggs89c651e2015-08-20 14:54:16 +1000817 return nvkm_engine_fini_old(&pm->engine, suspend);
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000818}
819
820int
Ben Skeggs4d346862015-01-14 15:31:13 +1000821_nvkm_pm_init(struct nvkm_object *object)
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000822{
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000823 struct nvkm_pm *pm = (void *)object;
Ben Skeggs89c651e2015-08-20 14:54:16 +1000824 return nvkm_engine_init_old(&pm->engine);
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000825}
826
827void
Ben Skeggs4d346862015-01-14 15:31:13 +1000828_nvkm_pm_dtor(struct nvkm_object *object)
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000829{
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000830 struct nvkm_pm *pm = (void *)object;
Samuel Pitoisete82661e2015-06-07 22:40:22 +0200831 struct nvkm_perfdom *dom, *next_dom;
832 struct nvkm_perfsrc *src, *next_src;
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000833
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000834 list_for_each_entry_safe(dom, next_dom, &pm->domains, head) {
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000835 list_del(&dom->head);
836 kfree(dom);
837 }
838
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000839 list_for_each_entry_safe(src, next_src, &pm->sources, head) {
Samuel Pitoisete82661e2015-06-07 22:40:22 +0200840 list_del(&src->head);
841 kfree(src->name);
842 kfree(src);
843 }
844
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000845 nvkm_engine_destroy(&pm->engine);
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000846}
847
848int
Ben Skeggs4d346862015-01-14 15:31:13 +1000849nvkm_pm_create_(struct nvkm_object *parent, struct nvkm_object *engine,
850 struct nvkm_oclass *oclass, int length, void **pobject)
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000851{
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000852 struct nvkm_pm *pm;
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000853 int ret;
854
Ben Skeggs4d346862015-01-14 15:31:13 +1000855 ret = nvkm_engine_create_(parent, engine, oclass, true, "PPM",
856 "pm", length, pobject);
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000857 pm = *pobject;
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000858 if (ret)
859 return ret;
860
Ben Skeggs8c1aeaa2015-08-20 14:54:08 +1000861 INIT_LIST_HEAD(&pm->domains);
862 INIT_LIST_HEAD(&pm->sources);
Ben Skeggsaa4d7a42013-02-13 15:29:11 +1000863 return 0;
864}