1d5752b9bSBen Skeggs /*
2d5752b9bSBen Skeggs * Copyright 2013 Red Hat Inc.
3d5752b9bSBen Skeggs *
4d5752b9bSBen Skeggs * Permission is hereby granted, free of charge, to any person obtaining a
5d5752b9bSBen Skeggs * copy of this software and associated documentation files (the "Software"),
6d5752b9bSBen Skeggs * to deal in the Software without restriction, including without limitation
7d5752b9bSBen Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8d5752b9bSBen Skeggs * and/or sell copies of the Software, and to permit persons to whom the
9d5752b9bSBen Skeggs * Software is furnished to do so, subject to the following conditions:
10d5752b9bSBen Skeggs *
11d5752b9bSBen Skeggs * The above copyright notice and this permission notice shall be included in
12d5752b9bSBen Skeggs * all copies or substantial portions of the Software.
13d5752b9bSBen Skeggs *
14d5752b9bSBen Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15d5752b9bSBen Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16d5752b9bSBen Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17d5752b9bSBen Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18d5752b9bSBen Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19d5752b9bSBen Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20d5752b9bSBen Skeggs * OTHER DEALINGS IN THE SOFTWARE.
21d5752b9bSBen Skeggs *
22d5752b9bSBen Skeggs * Authors: Ben Skeggs
23d5752b9bSBen Skeggs */
244d34686eSBen Skeggs #include "priv.h"
25d5752b9bSBen Skeggs
26d5752b9bSBen Skeggs #include <core/client.h>
27d5752b9bSBen Skeggs #include <core/option.h>
284d34686eSBen Skeggs
29d5752b9bSBen Skeggs #include <nvif/class.h>
3075445a4dSBen Skeggs #include <nvif/if0002.h>
3175445a4dSBen Skeggs #include <nvif/if0003.h>
32d5752b9bSBen Skeggs #include <nvif/ioctl.h>
334d34686eSBen Skeggs #include <nvif/unpack.h>
34d5752b9bSBen Skeggs
3545f0f94dSSamuel Pitoiset static u8
nvkm_pm_count_perfdom(struct nvkm_pm * pm)368c1aeaa1SBen Skeggs nvkm_pm_count_perfdom(struct nvkm_pm *pm)
3745f0f94dSSamuel Pitoiset {
3845f0f94dSSamuel Pitoiset struct nvkm_perfdom *dom;
3945f0f94dSSamuel Pitoiset u8 domain_nr = 0;
4045f0f94dSSamuel Pitoiset
418c1aeaa1SBen Skeggs list_for_each_entry(dom, &pm->domains, head)
4245f0f94dSSamuel Pitoiset domain_nr++;
4345f0f94dSSamuel Pitoiset return domain_nr;
4445f0f94dSSamuel Pitoiset }
4545f0f94dSSamuel Pitoiset
46e4047599SSamuel Pitoiset static u16
nvkm_perfdom_count_perfsig(struct nvkm_perfdom * dom)4745f0f94dSSamuel Pitoiset nvkm_perfdom_count_perfsig(struct nvkm_perfdom *dom)
4845f0f94dSSamuel Pitoiset {
49e4047599SSamuel Pitoiset u16 signal_nr = 0;
5045f0f94dSSamuel Pitoiset int i;
5145f0f94dSSamuel Pitoiset
5245f0f94dSSamuel Pitoiset if (dom) {
5345f0f94dSSamuel Pitoiset for (i = 0; i < dom->signal_nr; i++) {
5445f0f94dSSamuel Pitoiset if (dom->signal[i].name)
5545f0f94dSSamuel Pitoiset signal_nr++;
5645f0f94dSSamuel Pitoiset }
5745f0f94dSSamuel Pitoiset }
5845f0f94dSSamuel Pitoiset return signal_nr;
5945f0f94dSSamuel Pitoiset }
6045f0f94dSSamuel Pitoiset
6145f0f94dSSamuel Pitoiset static struct nvkm_perfdom *
nvkm_perfdom_find(struct nvkm_pm * pm,int di)628c1aeaa1SBen Skeggs nvkm_perfdom_find(struct nvkm_pm *pm, int di)
6345f0f94dSSamuel Pitoiset {
6445f0f94dSSamuel Pitoiset struct nvkm_perfdom *dom;
6545f0f94dSSamuel Pitoiset int tmp = 0;
6645f0f94dSSamuel Pitoiset
678c1aeaa1SBen Skeggs list_for_each_entry(dom, &pm->domains, head) {
6845f0f94dSSamuel Pitoiset if (tmp++ == di)
6945f0f94dSSamuel Pitoiset return dom;
7045f0f94dSSamuel Pitoiset }
7145f0f94dSSamuel Pitoiset return NULL;
7245f0f94dSSamuel Pitoiset }
7345f0f94dSSamuel Pitoiset
74e08a1d97SBaoyou Xie static struct nvkm_perfsig *
nvkm_perfsig_find(struct nvkm_pm * pm,u8 di,u8 si,struct nvkm_perfdom ** pdom)758c1aeaa1SBen Skeggs nvkm_perfsig_find(struct nvkm_pm *pm, u8 di, u8 si, struct nvkm_perfdom **pdom)
76d5752b9bSBen Skeggs {
774d34686eSBen Skeggs struct nvkm_perfdom *dom = *pdom;
78d5752b9bSBen Skeggs
79d5752b9bSBen Skeggs if (dom == NULL) {
808c1aeaa1SBen Skeggs dom = nvkm_perfdom_find(pm, di);
8110a4d2b2SSamuel Pitoiset if (dom == NULL)
82d5752b9bSBen Skeggs return NULL;
8310a4d2b2SSamuel Pitoiset *pdom = dom;
84d5752b9bSBen Skeggs }
85d5752b9bSBen Skeggs
8610a4d2b2SSamuel Pitoiset if (!dom->signal[si].name)
8710a4d2b2SSamuel Pitoiset return NULL;
8810a4d2b2SSamuel Pitoiset return &dom->signal[si];
89d5752b9bSBen Skeggs }
90d5752b9bSBen Skeggs
9150d138d7SSamuel Pitoiset static u8
nvkm_perfsig_count_perfsrc(struct nvkm_perfsig * sig)9250d138d7SSamuel Pitoiset nvkm_perfsig_count_perfsrc(struct nvkm_perfsig *sig)
9350d138d7SSamuel Pitoiset {
9450d138d7SSamuel Pitoiset u8 source_nr = 0, i;
9550d138d7SSamuel Pitoiset
9650d138d7SSamuel Pitoiset for (i = 0; i < ARRAY_SIZE(sig->source); i++) {
9750d138d7SSamuel Pitoiset if (sig->source[i])
9850d138d7SSamuel Pitoiset source_nr++;
9950d138d7SSamuel Pitoiset }
10050d138d7SSamuel Pitoiset return source_nr;
10150d138d7SSamuel Pitoiset }
10250d138d7SSamuel Pitoiset
1036f99c848SSamuel Pitoiset static struct nvkm_perfsrc *
nvkm_perfsrc_find(struct nvkm_pm * pm,struct nvkm_perfsig * sig,int si)1048c1aeaa1SBen Skeggs nvkm_perfsrc_find(struct nvkm_pm *pm, struct nvkm_perfsig *sig, int si)
1056f99c848SSamuel Pitoiset {
1066f99c848SSamuel Pitoiset struct nvkm_perfsrc *src;
1076f99c848SSamuel Pitoiset bool found = false;
1086f99c848SSamuel Pitoiset int tmp = 1; /* Sources ID start from 1 */
1096f99c848SSamuel Pitoiset u8 i;
1106f99c848SSamuel Pitoiset
1116f99c848SSamuel Pitoiset for (i = 0; i < ARRAY_SIZE(sig->source) && sig->source[i]; i++) {
1126f99c848SSamuel Pitoiset if (sig->source[i] == si) {
1136f99c848SSamuel Pitoiset found = true;
1146f99c848SSamuel Pitoiset break;
1156f99c848SSamuel Pitoiset }
1166f99c848SSamuel Pitoiset }
1176f99c848SSamuel Pitoiset
1186f99c848SSamuel Pitoiset if (found) {
1198c1aeaa1SBen Skeggs list_for_each_entry(src, &pm->sources, head) {
1206f99c848SSamuel Pitoiset if (tmp++ == si)
1216f99c848SSamuel Pitoiset return src;
1226f99c848SSamuel Pitoiset }
1236f99c848SSamuel Pitoiset }
1246f99c848SSamuel Pitoiset
1256f99c848SSamuel Pitoiset return NULL;
1266f99c848SSamuel Pitoiset }
1276f99c848SSamuel Pitoiset
1286137b5a7SSamuel Pitoiset static int
nvkm_perfsrc_enable(struct nvkm_pm * pm,struct nvkm_perfctr * ctr)1298c1aeaa1SBen Skeggs nvkm_perfsrc_enable(struct nvkm_pm *pm, struct nvkm_perfctr *ctr)
1306137b5a7SSamuel Pitoiset {
131476901ffSBen Skeggs struct nvkm_subdev *subdev = &pm->engine.subdev;
132476901ffSBen Skeggs struct nvkm_device *device = subdev->device;
1336137b5a7SSamuel Pitoiset struct nvkm_perfdom *dom = NULL;
1346137b5a7SSamuel Pitoiset struct nvkm_perfsig *sig;
1356137b5a7SSamuel Pitoiset struct nvkm_perfsrc *src;
1366137b5a7SSamuel Pitoiset u32 mask, value;
1376137b5a7SSamuel Pitoiset int i, j;
1386137b5a7SSamuel Pitoiset
1397fe882ebSSamuel Pitoiset for (i = 0; i < 4; i++) {
1406137b5a7SSamuel Pitoiset for (j = 0; j < 8 && ctr->source[i][j]; j++) {
1418c1aeaa1SBen Skeggs sig = nvkm_perfsig_find(pm, ctr->domain,
1426137b5a7SSamuel Pitoiset ctr->signal[i], &dom);
1436137b5a7SSamuel Pitoiset if (!sig)
1446137b5a7SSamuel Pitoiset return -EINVAL;
1456137b5a7SSamuel Pitoiset
1468c1aeaa1SBen Skeggs src = nvkm_perfsrc_find(pm, sig, ctr->source[i][j]);
1476137b5a7SSamuel Pitoiset if (!src)
1486137b5a7SSamuel Pitoiset return -EINVAL;
1496137b5a7SSamuel Pitoiset
1506137b5a7SSamuel Pitoiset /* set enable bit if needed */
1516137b5a7SSamuel Pitoiset mask = value = 0x00000000;
1526137b5a7SSamuel Pitoiset if (src->enable)
1536137b5a7SSamuel Pitoiset mask = value = 0x80000000;
1546137b5a7SSamuel Pitoiset mask |= (src->mask << src->shift);
1556137b5a7SSamuel Pitoiset value |= ((ctr->source[i][j] >> 32) << src->shift);
1566137b5a7SSamuel Pitoiset
1576137b5a7SSamuel Pitoiset /* enable the source */
158846e831dSBen Skeggs nvkm_mask(device, src->addr, mask, value);
159476901ffSBen Skeggs nvkm_debug(subdev,
160476901ffSBen Skeggs "enabled source %08x %08x %08x\n",
161d4a312dcSSamuel Pitoiset src->addr, mask, value);
1626137b5a7SSamuel Pitoiset }
1636137b5a7SSamuel Pitoiset }
1646137b5a7SSamuel Pitoiset return 0;
1656137b5a7SSamuel Pitoiset }
1666137b5a7SSamuel Pitoiset
1676137b5a7SSamuel Pitoiset static int
nvkm_perfsrc_disable(struct nvkm_pm * pm,struct nvkm_perfctr * ctr)1688c1aeaa1SBen Skeggs nvkm_perfsrc_disable(struct nvkm_pm *pm, struct nvkm_perfctr *ctr)
1696137b5a7SSamuel Pitoiset {
170476901ffSBen Skeggs struct nvkm_subdev *subdev = &pm->engine.subdev;
171476901ffSBen Skeggs struct nvkm_device *device = subdev->device;
1726137b5a7SSamuel Pitoiset struct nvkm_perfdom *dom = NULL;
1736137b5a7SSamuel Pitoiset struct nvkm_perfsig *sig;
1746137b5a7SSamuel Pitoiset struct nvkm_perfsrc *src;
175d4a312dcSSamuel Pitoiset u32 mask;
1766137b5a7SSamuel Pitoiset int i, j;
1776137b5a7SSamuel Pitoiset
1787fe882ebSSamuel Pitoiset for (i = 0; i < 4; i++) {
1796137b5a7SSamuel Pitoiset for (j = 0; j < 8 && ctr->source[i][j]; j++) {
1808c1aeaa1SBen Skeggs sig = nvkm_perfsig_find(pm, ctr->domain,
1816137b5a7SSamuel Pitoiset ctr->signal[i], &dom);
1826137b5a7SSamuel Pitoiset if (!sig)
1836137b5a7SSamuel Pitoiset return -EINVAL;
1846137b5a7SSamuel Pitoiset
1858c1aeaa1SBen Skeggs src = nvkm_perfsrc_find(pm, sig, ctr->source[i][j]);
1866137b5a7SSamuel Pitoiset if (!src)
1876137b5a7SSamuel Pitoiset return -EINVAL;
1886137b5a7SSamuel Pitoiset
189d4a312dcSSamuel Pitoiset /* unset enable bit if needed */
190d4a312dcSSamuel Pitoiset mask = 0x00000000;
191d4a312dcSSamuel Pitoiset if (src->enable)
192d4a312dcSSamuel Pitoiset mask = 0x80000000;
193d4a312dcSSamuel Pitoiset mask |= (src->mask << src->shift);
194d4a312dcSSamuel Pitoiset
1956137b5a7SSamuel Pitoiset /* disable the source */
196846e831dSBen Skeggs nvkm_mask(device, src->addr, mask, 0);
197476901ffSBen Skeggs nvkm_debug(subdev, "disabled source %08x %08x\n",
198d4a312dcSSamuel Pitoiset src->addr, mask);
1996137b5a7SSamuel Pitoiset }
2006137b5a7SSamuel Pitoiset }
2016137b5a7SSamuel Pitoiset return 0;
2026137b5a7SSamuel Pitoiset }
2036137b5a7SSamuel Pitoiset
204d5752b9bSBen Skeggs /*******************************************************************************
2050f380436SSamuel Pitoiset * Perfdom object classes
2065a0bc4b5SSamuel Pitoiset ******************************************************************************/
2075a0bc4b5SSamuel Pitoiset static int
nvkm_perfdom_init(struct nvkm_perfdom * dom,void * data,u32 size)20897070f23SBen Skeggs nvkm_perfdom_init(struct nvkm_perfdom *dom, void *data, u32 size)
2093bfdde17SSamuel Pitoiset {
2103bfdde17SSamuel Pitoiset union {
2110f380436SSamuel Pitoiset struct nvif_perfdom_init none;
2123bfdde17SSamuel Pitoiset } *args = data;
21397070f23SBen Skeggs struct nvkm_object *object = &dom->object;
21497070f23SBen Skeggs struct nvkm_pm *pm = dom->perfmon->pm;
215f01c4e68SBen Skeggs int ret = -ENOSYS, i;
2163bfdde17SSamuel Pitoiset
21753003941SBen Skeggs nvif_ioctl(object, "perfdom init size %d\n", size);
218f01c4e68SBen Skeggs if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
21953003941SBen Skeggs nvif_ioctl(object, "perfdom init\n");
2203bfdde17SSamuel Pitoiset } else
2213bfdde17SSamuel Pitoiset return ret;
2223bfdde17SSamuel Pitoiset
2236137b5a7SSamuel Pitoiset for (i = 0; i < 4; i++) {
2246137b5a7SSamuel Pitoiset if (dom->ctr[i]) {
2258c1aeaa1SBen Skeggs dom->func->init(pm, dom, dom->ctr[i]);
2263bfdde17SSamuel Pitoiset
2276137b5a7SSamuel Pitoiset /* enable sources */
2288c1aeaa1SBen Skeggs nvkm_perfsrc_enable(pm, dom->ctr[i]);
2296137b5a7SSamuel Pitoiset }
2306137b5a7SSamuel Pitoiset }
2316137b5a7SSamuel Pitoiset
2323bfdde17SSamuel Pitoiset /* start next batch of counters for sampling */
2338c1aeaa1SBen Skeggs dom->func->next(pm, dom);
2343bfdde17SSamuel Pitoiset return 0;
2353bfdde17SSamuel Pitoiset }
2363bfdde17SSamuel Pitoiset
2373bfdde17SSamuel Pitoiset static int
nvkm_perfdom_sample(struct nvkm_perfdom * dom,void * data,u32 size)23897070f23SBen Skeggs nvkm_perfdom_sample(struct nvkm_perfdom *dom, void *data, u32 size)
239d5752b9bSBen Skeggs {
240d5752b9bSBen Skeggs union {
2410f380436SSamuel Pitoiset struct nvif_perfdom_sample none;
242d5752b9bSBen Skeggs } *args = data;
24397070f23SBen Skeggs struct nvkm_object *object = &dom->object;
24497070f23SBen Skeggs struct nvkm_pm *pm = dom->perfmon->pm;
245f01c4e68SBen Skeggs int ret = -ENOSYS;
246d5752b9bSBen Skeggs
24753003941SBen Skeggs nvif_ioctl(object, "perfdom sample size %d\n", size);
248f01c4e68SBen Skeggs if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
24953003941SBen Skeggs nvif_ioctl(object, "perfdom sample\n");
250d5752b9bSBen Skeggs } else
251d5752b9bSBen Skeggs return ret;
2528c1aeaa1SBen Skeggs pm->sequence++;
253d5752b9bSBen Skeggs
254d5752b9bSBen Skeggs /* sample previous batch of counters */
2558c1aeaa1SBen Skeggs list_for_each_entry(dom, &pm->domains, head)
2568c1aeaa1SBen Skeggs dom->func->next(pm, dom);
2573bfdde17SSamuel Pitoiset
258d5752b9bSBen Skeggs return 0;
259d5752b9bSBen Skeggs }
260d5752b9bSBen Skeggs
261d5752b9bSBen Skeggs static int
nvkm_perfdom_read(struct nvkm_perfdom * dom,void * data,u32 size)26297070f23SBen Skeggs nvkm_perfdom_read(struct nvkm_perfdom *dom, void *data, u32 size)
263d5752b9bSBen Skeggs {
264d5752b9bSBen Skeggs union {
2650f380436SSamuel Pitoiset struct nvif_perfdom_read_v0 v0;
266d5752b9bSBen Skeggs } *args = data;
26797070f23SBen Skeggs struct nvkm_object *object = &dom->object;
26897070f23SBen Skeggs struct nvkm_pm *pm = dom->perfmon->pm;
269f01c4e68SBen Skeggs int ret = -ENOSYS, i;
270d5752b9bSBen Skeggs
27153003941SBen Skeggs nvif_ioctl(object, "perfdom read size %d\n", size);
272f01c4e68SBen Skeggs if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
27353003941SBen Skeggs nvif_ioctl(object, "perfdom read vers %d\n", args->v0.version);
274d5752b9bSBen Skeggs } else
275d5752b9bSBen Skeggs return ret;
276d5752b9bSBen Skeggs
2770f380436SSamuel Pitoiset for (i = 0; i < 4; i++) {
2780f380436SSamuel Pitoiset if (dom->ctr[i])
2798c1aeaa1SBen Skeggs dom->func->read(pm, dom, dom->ctr[i]);
2800f380436SSamuel Pitoiset }
2810f380436SSamuel Pitoiset
2820f380436SSamuel Pitoiset if (!dom->clk)
283d5752b9bSBen Skeggs return -EAGAIN;
284d5752b9bSBen Skeggs
2850f380436SSamuel Pitoiset for (i = 0; i < 4; i++)
2860f380436SSamuel Pitoiset if (dom->ctr[i])
2870f380436SSamuel Pitoiset args->v0.ctr[i] = dom->ctr[i]->ctr;
2880f380436SSamuel Pitoiset args->v0.clk = dom->clk;
289d5752b9bSBen Skeggs return 0;
290d5752b9bSBen Skeggs }
291d5752b9bSBen Skeggs
292d5752b9bSBen Skeggs static int
nvkm_perfdom_mthd(struct nvkm_object * object,u32 mthd,void * data,u32 size)2930f380436SSamuel Pitoiset nvkm_perfdom_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
294d5752b9bSBen Skeggs {
29597070f23SBen Skeggs struct nvkm_perfdom *dom = nvkm_perfdom(object);
296d5752b9bSBen Skeggs switch (mthd) {
2970f380436SSamuel Pitoiset case NVIF_PERFDOM_V0_INIT:
29897070f23SBen Skeggs return nvkm_perfdom_init(dom, data, size);
2990f380436SSamuel Pitoiset case NVIF_PERFDOM_V0_SAMPLE:
30097070f23SBen Skeggs return nvkm_perfdom_sample(dom, data, size);
3010f380436SSamuel Pitoiset case NVIF_PERFDOM_V0_READ:
30297070f23SBen Skeggs return nvkm_perfdom_read(dom, data, size);
303d5752b9bSBen Skeggs default:
304d5752b9bSBen Skeggs break;
305d5752b9bSBen Skeggs }
306d5752b9bSBen Skeggs return -EINVAL;
307d5752b9bSBen Skeggs }
308d5752b9bSBen Skeggs
3095ffeb84bSBen Skeggs static void *
nvkm_perfdom_dtor(struct nvkm_object * object)31097070f23SBen Skeggs nvkm_perfdom_dtor(struct nvkm_object *object)
311d5752b9bSBen Skeggs {
31297070f23SBen Skeggs struct nvkm_perfdom *dom = nvkm_perfdom(object);
3135ffeb84bSBen Skeggs struct nvkm_pm *pm = dom->perfmon->pm;
3140f380436SSamuel Pitoiset int i;
3150f380436SSamuel Pitoiset
3160f380436SSamuel Pitoiset for (i = 0; i < 4; i++) {
3170f380436SSamuel Pitoiset struct nvkm_perfctr *ctr = dom->ctr[i];
3186137b5a7SSamuel Pitoiset if (ctr) {
3198c1aeaa1SBen Skeggs nvkm_perfsrc_disable(pm, ctr);
3206137b5a7SSamuel Pitoiset if (ctr->head.next)
321d5752b9bSBen Skeggs list_del(&ctr->head);
3226137b5a7SSamuel Pitoiset }
3230f380436SSamuel Pitoiset kfree(ctr);
3240f380436SSamuel Pitoiset }
3255ffeb84bSBen Skeggs
3265ffeb84bSBen Skeggs return dom;
327d5752b9bSBen Skeggs }
328d5752b9bSBen Skeggs
329d5752b9bSBen Skeggs static int
nvkm_perfctr_new(struct nvkm_perfdom * dom,int slot,u8 domain,struct nvkm_perfsig * signal[4],u64 source[4][8],u16 logic_op,struct nvkm_perfctr ** pctr)3308c1aeaa1SBen Skeggs nvkm_perfctr_new(struct nvkm_perfdom *dom, int slot, u8 domain,
3318c1aeaa1SBen Skeggs struct nvkm_perfsig *signal[4], u64 source[4][8],
3328c1aeaa1SBen Skeggs u16 logic_op, struct nvkm_perfctr **pctr)
333d5752b9bSBen Skeggs {
3344d34686eSBen Skeggs struct nvkm_perfctr *ctr;
3356137b5a7SSamuel Pitoiset int i, j;
336d5752b9bSBen Skeggs
33744d9de58SSamuel Pitoiset if (!dom)
33844d9de58SSamuel Pitoiset return -EINVAL;
33944d9de58SSamuel Pitoiset
3400f380436SSamuel Pitoiset ctr = *pctr = kzalloc(sizeof(*ctr), GFP_KERNEL);
3410f380436SSamuel Pitoiset if (!ctr)
3420f380436SSamuel Pitoiset return -ENOMEM;
3430f380436SSamuel Pitoiset
344d4a312dcSSamuel Pitoiset ctr->domain = domain;
3450f380436SSamuel Pitoiset ctr->logic_op = logic_op;
3460f380436SSamuel Pitoiset ctr->slot = slot;
3470f380436SSamuel Pitoiset for (i = 0; i < 4; i++) {
3486137b5a7SSamuel Pitoiset if (signal[i]) {
3490f380436SSamuel Pitoiset ctr->signal[i] = signal[i] - dom->signal;
3506137b5a7SSamuel Pitoiset for (j = 0; j < 8; j++)
3516137b5a7SSamuel Pitoiset ctr->source[i][j] = source[i][j];
3526137b5a7SSamuel Pitoiset }
3530f380436SSamuel Pitoiset }
3540f380436SSamuel Pitoiset list_add_tail(&ctr->head, &dom->list);
3550f380436SSamuel Pitoiset
3560f380436SSamuel Pitoiset return 0;
3570f380436SSamuel Pitoiset }
3580f380436SSamuel Pitoiset
3595ffeb84bSBen Skeggs static const struct nvkm_object_func
3605ffeb84bSBen Skeggs nvkm_perfdom = {
3615ffeb84bSBen Skeggs .dtor = nvkm_perfdom_dtor,
3625ffeb84bSBen Skeggs .mthd = nvkm_perfdom_mthd,
3635ffeb84bSBen Skeggs };
3645ffeb84bSBen Skeggs
3650f380436SSamuel Pitoiset static int
nvkm_perfdom_new_(struct nvkm_perfmon * perfmon,const struct nvkm_oclass * oclass,void * data,u32 size,struct nvkm_object ** pobject)3665ffeb84bSBen Skeggs nvkm_perfdom_new_(struct nvkm_perfmon *perfmon,
3675ffeb84bSBen Skeggs const struct nvkm_oclass *oclass, void *data, u32 size,
3680f380436SSamuel Pitoiset struct nvkm_object **pobject)
3690f380436SSamuel Pitoiset {
3700f380436SSamuel Pitoiset union {
3710f380436SSamuel Pitoiset struct nvif_perfdom_v0 v0;
3720f380436SSamuel Pitoiset } *args = data;
3735ffeb84bSBen Skeggs struct nvkm_pm *pm = perfmon->pm;
3745ffeb84bSBen Skeggs struct nvkm_object *parent = oclass->parent;
3750f380436SSamuel Pitoiset struct nvkm_perfdom *sdom = NULL;
3760f380436SSamuel Pitoiset struct nvkm_perfctr *ctr[4] = {};
3770f380436SSamuel Pitoiset struct nvkm_perfdom *dom;
3786137b5a7SSamuel Pitoiset int c, s, m;
379f01c4e68SBen Skeggs int ret = -ENOSYS;
3800f380436SSamuel Pitoiset
38153003941SBen Skeggs nvif_ioctl(parent, "create perfdom size %d\n", size);
382f01c4e68SBen Skeggs if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
38353003941SBen Skeggs nvif_ioctl(parent, "create perfdom vers %d dom %d mode %02x\n",
3840f380436SSamuel Pitoiset args->v0.version, args->v0.domain, args->v0.mode);
3850f380436SSamuel Pitoiset } else
3860f380436SSamuel Pitoiset return ret;
3870f380436SSamuel Pitoiset
3880f380436SSamuel Pitoiset for (c = 0; c < ARRAY_SIZE(args->v0.ctr); c++) {
3890f380436SSamuel Pitoiset struct nvkm_perfsig *sig[4] = {};
390d4a312dcSSamuel Pitoiset u64 src[4][8] = {};
3916137b5a7SSamuel Pitoiset
3920f380436SSamuel Pitoiset for (s = 0; s < ARRAY_SIZE(args->v0.ctr[c].signal); s++) {
3938c1aeaa1SBen Skeggs sig[s] = nvkm_perfsig_find(pm, args->v0.domain,
3940f380436SSamuel Pitoiset args->v0.ctr[c].signal[s],
3950f380436SSamuel Pitoiset &sdom);
3960f380436SSamuel Pitoiset if (args->v0.ctr[c].signal[s] && !sig[s])
3970f380436SSamuel Pitoiset return -EINVAL;
3986137b5a7SSamuel Pitoiset
3996137b5a7SSamuel Pitoiset for (m = 0; m < 8; m++) {
4006137b5a7SSamuel Pitoiset src[s][m] = args->v0.ctr[c].source[s][m];
4018c1aeaa1SBen Skeggs if (src[s][m] && !nvkm_perfsrc_find(pm, sig[s],
4026137b5a7SSamuel Pitoiset src[s][m]))
4036137b5a7SSamuel Pitoiset return -EINVAL;
4046137b5a7SSamuel Pitoiset }
4050f380436SSamuel Pitoiset }
4060f380436SSamuel Pitoiset
407d4a312dcSSamuel Pitoiset ret = nvkm_perfctr_new(sdom, c, args->v0.domain, sig, src,
4080f380436SSamuel Pitoiset args->v0.ctr[c].logic_op, &ctr[c]);
4090f380436SSamuel Pitoiset if (ret)
4100f380436SSamuel Pitoiset return ret;
4110f380436SSamuel Pitoiset }
4120f380436SSamuel Pitoiset
4130f380436SSamuel Pitoiset if (!sdom)
4140f380436SSamuel Pitoiset return -EINVAL;
4150f380436SSamuel Pitoiset
4165ffeb84bSBen Skeggs if (!(dom = kzalloc(sizeof(*dom), GFP_KERNEL)))
4175ffeb84bSBen Skeggs return -ENOMEM;
4185ffeb84bSBen Skeggs nvkm_object_ctor(&nvkm_perfdom, oclass, &dom->object);
4195ffeb84bSBen Skeggs dom->perfmon = perfmon;
4205ffeb84bSBen Skeggs *pobject = &dom->object;
421d5752b9bSBen Skeggs
4220f380436SSamuel Pitoiset dom->func = sdom->func;
4230f380436SSamuel Pitoiset dom->addr = sdom->addr;
4240f380436SSamuel Pitoiset dom->mode = args->v0.mode;
4250f380436SSamuel Pitoiset for (c = 0; c < ARRAY_SIZE(ctr); c++)
4260f380436SSamuel Pitoiset dom->ctr[c] = ctr[c];
427d5752b9bSBen Skeggs return 0;
428d5752b9bSBen Skeggs }
429d5752b9bSBen Skeggs
4302d4b94b9SBen Skeggs /*******************************************************************************
4312d4b94b9SBen Skeggs * Perfmon object classes
4322d4b94b9SBen Skeggs ******************************************************************************/
4332d4b94b9SBen Skeggs static int
nvkm_perfmon_mthd_query_domain(struct nvkm_perfmon * perfmon,void * data,u32 size)4345ffeb84bSBen Skeggs nvkm_perfmon_mthd_query_domain(struct nvkm_perfmon *perfmon,
4355ffeb84bSBen Skeggs void *data, u32 size)
4362d4b94b9SBen Skeggs {
4372d4b94b9SBen Skeggs union {
4382d4b94b9SBen Skeggs struct nvif_perfmon_query_domain_v0 v0;
4392d4b94b9SBen Skeggs } *args = data;
4405ffeb84bSBen Skeggs struct nvkm_object *object = &perfmon->object;
4415ffeb84bSBen Skeggs struct nvkm_pm *pm = perfmon->pm;
4422d4b94b9SBen Skeggs struct nvkm_perfdom *dom;
4432d4b94b9SBen Skeggs u8 domain_nr;
444f01c4e68SBen Skeggs int di, ret = -ENOSYS;
4452d4b94b9SBen Skeggs
44653003941SBen Skeggs nvif_ioctl(object, "perfmon query domain size %d\n", size);
447f01c4e68SBen Skeggs if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
44853003941SBen Skeggs nvif_ioctl(object, "perfmon domain vers %d iter %02x\n",
4492d4b94b9SBen Skeggs args->v0.version, args->v0.iter);
4502d4b94b9SBen Skeggs di = (args->v0.iter & 0xff) - 1;
4512d4b94b9SBen Skeggs } else
4522d4b94b9SBen Skeggs return ret;
4532d4b94b9SBen Skeggs
4548c1aeaa1SBen Skeggs domain_nr = nvkm_pm_count_perfdom(pm);
4552d4b94b9SBen Skeggs if (di >= (int)domain_nr)
4562d4b94b9SBen Skeggs return -EINVAL;
4572d4b94b9SBen Skeggs
4582d4b94b9SBen Skeggs if (di >= 0) {
4598c1aeaa1SBen Skeggs dom = nvkm_perfdom_find(pm, di);
4602d4b94b9SBen Skeggs if (dom == NULL)
4612d4b94b9SBen Skeggs return -EINVAL;
4622d4b94b9SBen Skeggs
4632d4b94b9SBen Skeggs args->v0.id = di;
4642d4b94b9SBen Skeggs args->v0.signal_nr = nvkm_perfdom_count_perfsig(dom);
465ee0d5810SArnd Bergmann strncpy(args->v0.name, dom->name, sizeof(args->v0.name) - 1);
4662d4b94b9SBen Skeggs
4672d4b94b9SBen Skeggs /* Currently only global counters (PCOUNTER) are implemented
4682d4b94b9SBen Skeggs * but this will be different for local counters (MP). */
4692d4b94b9SBen Skeggs args->v0.counter_nr = 4;
4702d4b94b9SBen Skeggs }
4712d4b94b9SBen Skeggs
4722d4b94b9SBen Skeggs if (++di < domain_nr) {
4732d4b94b9SBen Skeggs args->v0.iter = ++di;
4742d4b94b9SBen Skeggs return 0;
4752d4b94b9SBen Skeggs }
4762d4b94b9SBen Skeggs
4772d4b94b9SBen Skeggs args->v0.iter = 0xff;
4782d4b94b9SBen Skeggs return 0;
4792d4b94b9SBen Skeggs }
4802d4b94b9SBen Skeggs
4812d4b94b9SBen Skeggs static int
nvkm_perfmon_mthd_query_signal(struct nvkm_perfmon * perfmon,void * data,u32 size)4825ffeb84bSBen Skeggs nvkm_perfmon_mthd_query_signal(struct nvkm_perfmon *perfmon,
4835ffeb84bSBen Skeggs void *data, u32 size)
4842d4b94b9SBen Skeggs {
4852d4b94b9SBen Skeggs union {
4862d4b94b9SBen Skeggs struct nvif_perfmon_query_signal_v0 v0;
4872d4b94b9SBen Skeggs } *args = data;
4885ffeb84bSBen Skeggs struct nvkm_object *object = &perfmon->object;
4895ffeb84bSBen Skeggs struct nvkm_pm *pm = perfmon->pm;
4905ffeb84bSBen Skeggs struct nvkm_device *device = pm->engine.subdev.device;
4912d4b94b9SBen Skeggs struct nvkm_perfdom *dom;
4922d4b94b9SBen Skeggs struct nvkm_perfsig *sig;
4932d4b94b9SBen Skeggs const bool all = nvkm_boolopt(device->cfgopt, "NvPmShowAll", false);
4942d4b94b9SBen Skeggs const bool raw = nvkm_boolopt(device->cfgopt, "NvPmUnnamed", all);
495f01c4e68SBen Skeggs int ret = -ENOSYS, si;
4962d4b94b9SBen Skeggs
49753003941SBen Skeggs nvif_ioctl(object, "perfmon query signal size %d\n", size);
498f01c4e68SBen Skeggs if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
49953003941SBen Skeggs nvif_ioctl(object,
5002d4b94b9SBen Skeggs "perfmon query signal vers %d dom %d iter %04x\n",
5012d4b94b9SBen Skeggs args->v0.version, args->v0.domain, args->v0.iter);
5022d4b94b9SBen Skeggs si = (args->v0.iter & 0xffff) - 1;
5032d4b94b9SBen Skeggs } else
5042d4b94b9SBen Skeggs return ret;
5052d4b94b9SBen Skeggs
5068c1aeaa1SBen Skeggs dom = nvkm_perfdom_find(pm, args->v0.domain);
5072d4b94b9SBen Skeggs if (dom == NULL || si >= (int)dom->signal_nr)
5082d4b94b9SBen Skeggs return -EINVAL;
5092d4b94b9SBen Skeggs
5102d4b94b9SBen Skeggs if (si >= 0) {
5112d4b94b9SBen Skeggs sig = &dom->signal[si];
5122d4b94b9SBen Skeggs if (raw || !sig->name) {
5132d4b94b9SBen Skeggs snprintf(args->v0.name, sizeof(args->v0.name),
5142d4b94b9SBen Skeggs "/%s/%02x", dom->name, si);
5152d4b94b9SBen Skeggs } else {
5162d4b94b9SBen Skeggs strncpy(args->v0.name, sig->name,
517ee0d5810SArnd Bergmann sizeof(args->v0.name) - 1);
5182d4b94b9SBen Skeggs }
5192d4b94b9SBen Skeggs
5202d4b94b9SBen Skeggs args->v0.signal = si;
5212d4b94b9SBen Skeggs args->v0.source_nr = nvkm_perfsig_count_perfsrc(sig);
5222d4b94b9SBen Skeggs }
5232d4b94b9SBen Skeggs
5242d4b94b9SBen Skeggs while (++si < dom->signal_nr) {
5252d4b94b9SBen Skeggs if (all || dom->signal[si].name) {
5262d4b94b9SBen Skeggs args->v0.iter = ++si;
5272d4b94b9SBen Skeggs return 0;
5282d4b94b9SBen Skeggs }
5292d4b94b9SBen Skeggs }
5302d4b94b9SBen Skeggs
5312d4b94b9SBen Skeggs args->v0.iter = 0xffff;
5322d4b94b9SBen Skeggs return 0;
5332d4b94b9SBen Skeggs }
5342d4b94b9SBen Skeggs
5352d4b94b9SBen Skeggs static int
nvkm_perfmon_mthd_query_source(struct nvkm_perfmon * perfmon,void * data,u32 size)5365ffeb84bSBen Skeggs nvkm_perfmon_mthd_query_source(struct nvkm_perfmon *perfmon,
5375ffeb84bSBen Skeggs void *data, u32 size)
5382d4b94b9SBen Skeggs {
5392d4b94b9SBen Skeggs union {
5402d4b94b9SBen Skeggs struct nvif_perfmon_query_source_v0 v0;
5412d4b94b9SBen Skeggs } *args = data;
5425ffeb84bSBen Skeggs struct nvkm_object *object = &perfmon->object;
5435ffeb84bSBen Skeggs struct nvkm_pm *pm = perfmon->pm;
5442d4b94b9SBen Skeggs struct nvkm_perfdom *dom = NULL;
5452d4b94b9SBen Skeggs struct nvkm_perfsig *sig;
5462d4b94b9SBen Skeggs struct nvkm_perfsrc *src;
5472d4b94b9SBen Skeggs u8 source_nr = 0;
548f01c4e68SBen Skeggs int si, ret = -ENOSYS;
5492d4b94b9SBen Skeggs
55053003941SBen Skeggs nvif_ioctl(object, "perfmon query source size %d\n", size);
551f01c4e68SBen Skeggs if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
55253003941SBen Skeggs nvif_ioctl(object,
5532d4b94b9SBen Skeggs "perfmon source vers %d dom %d sig %02x iter %02x\n",
5542d4b94b9SBen Skeggs args->v0.version, args->v0.domain, args->v0.signal,
5552d4b94b9SBen Skeggs args->v0.iter);
5562d4b94b9SBen Skeggs si = (args->v0.iter & 0xff) - 1;
5572d4b94b9SBen Skeggs } else
5582d4b94b9SBen Skeggs return ret;
5592d4b94b9SBen Skeggs
5608c1aeaa1SBen Skeggs sig = nvkm_perfsig_find(pm, args->v0.domain, args->v0.signal, &dom);
5612d4b94b9SBen Skeggs if (!sig)
5622d4b94b9SBen Skeggs return -EINVAL;
5632d4b94b9SBen Skeggs
5642d4b94b9SBen Skeggs source_nr = nvkm_perfsig_count_perfsrc(sig);
5652d4b94b9SBen Skeggs if (si >= (int)source_nr)
5662d4b94b9SBen Skeggs return -EINVAL;
5672d4b94b9SBen Skeggs
5682d4b94b9SBen Skeggs if (si >= 0) {
5698c1aeaa1SBen Skeggs src = nvkm_perfsrc_find(pm, sig, sig->source[si]);
5702d4b94b9SBen Skeggs if (!src)
5712d4b94b9SBen Skeggs return -EINVAL;
5722d4b94b9SBen Skeggs
5732d4b94b9SBen Skeggs args->v0.source = sig->source[si];
5742d4b94b9SBen Skeggs args->v0.mask = src->mask;
575ee0d5810SArnd Bergmann strncpy(args->v0.name, src->name, sizeof(args->v0.name) - 1);
5762d4b94b9SBen Skeggs }
5772d4b94b9SBen Skeggs
5782d4b94b9SBen Skeggs if (++si < source_nr) {
5792d4b94b9SBen Skeggs args->v0.iter = ++si;
5802d4b94b9SBen Skeggs return 0;
5812d4b94b9SBen Skeggs }
5822d4b94b9SBen Skeggs
5832d4b94b9SBen Skeggs args->v0.iter = 0xff;
5842d4b94b9SBen Skeggs return 0;
5852d4b94b9SBen Skeggs }
5862d4b94b9SBen Skeggs
5872d4b94b9SBen Skeggs static int
nvkm_perfmon_mthd(struct nvkm_object * object,u32 mthd,void * data,u32 size)5882d4b94b9SBen Skeggs nvkm_perfmon_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
5892d4b94b9SBen Skeggs {
5905ffeb84bSBen Skeggs struct nvkm_perfmon *perfmon = nvkm_perfmon(object);
5912d4b94b9SBen Skeggs switch (mthd) {
5922d4b94b9SBen Skeggs case NVIF_PERFMON_V0_QUERY_DOMAIN:
5935ffeb84bSBen Skeggs return nvkm_perfmon_mthd_query_domain(perfmon, data, size);
5942d4b94b9SBen Skeggs case NVIF_PERFMON_V0_QUERY_SIGNAL:
5955ffeb84bSBen Skeggs return nvkm_perfmon_mthd_query_signal(perfmon, data, size);
5962d4b94b9SBen Skeggs case NVIF_PERFMON_V0_QUERY_SOURCE:
5975ffeb84bSBen Skeggs return nvkm_perfmon_mthd_query_source(perfmon, data, size);
5982d4b94b9SBen Skeggs default:
5992d4b94b9SBen Skeggs break;
6002d4b94b9SBen Skeggs }
6012d4b94b9SBen Skeggs return -EINVAL;
6022d4b94b9SBen Skeggs }
6032d4b94b9SBen Skeggs
604f21950eaSBen Skeggs static int
nvkm_perfmon_child_new(const struct nvkm_oclass * oclass,void * data,u32 size,struct nvkm_object ** pobject)6055ffeb84bSBen Skeggs nvkm_perfmon_child_new(const struct nvkm_oclass *oclass, void *data, u32 size,
606f21950eaSBen Skeggs struct nvkm_object **pobject)
607f21950eaSBen Skeggs {
6085ffeb84bSBen Skeggs struct nvkm_perfmon *perfmon = nvkm_perfmon(oclass->parent);
6095ffeb84bSBen Skeggs return nvkm_perfdom_new_(perfmon, oclass, data, size, pobject);
610f21950eaSBen Skeggs }
611f21950eaSBen Skeggs
6125ffeb84bSBen Skeggs static int
nvkm_perfmon_child_get(struct nvkm_object * object,int index,struct nvkm_oclass * oclass)61397070f23SBen Skeggs nvkm_perfmon_child_get(struct nvkm_object *object, int index,
6145ffeb84bSBen Skeggs struct nvkm_oclass *oclass)
6155ffeb84bSBen Skeggs {
6165ffeb84bSBen Skeggs if (index == 0) {
61708f7633cSBen Skeggs oclass->base.oclass = NVIF_CLASS_PERFDOM;
6185ffeb84bSBen Skeggs oclass->base.minver = 0;
6195ffeb84bSBen Skeggs oclass->base.maxver = 0;
6205ffeb84bSBen Skeggs oclass->ctor = nvkm_perfmon_child_new;
6215ffeb84bSBen Skeggs return 0;
6225ffeb84bSBen Skeggs }
6235ffeb84bSBen Skeggs return -EINVAL;
6245ffeb84bSBen Skeggs }
6255ffeb84bSBen Skeggs
6265ffeb84bSBen Skeggs static void *
nvkm_perfmon_dtor(struct nvkm_object * object)62797070f23SBen Skeggs nvkm_perfmon_dtor(struct nvkm_object *object)
6285ffeb84bSBen Skeggs {
62997070f23SBen Skeggs struct nvkm_perfmon *perfmon = nvkm_perfmon(object);
6305ffeb84bSBen Skeggs struct nvkm_pm *pm = perfmon->pm;
631f8106922SBen Skeggs spin_lock(&pm->client.lock);
632f8106922SBen Skeggs if (pm->client.object == &perfmon->object)
633f8106922SBen Skeggs pm->client.object = NULL;
634f8106922SBen Skeggs spin_unlock(&pm->client.lock);
6355ffeb84bSBen Skeggs return perfmon;
6365ffeb84bSBen Skeggs }
6375ffeb84bSBen Skeggs
638354a2249SJulia Lawall static const struct nvkm_object_func
6395ffeb84bSBen Skeggs nvkm_perfmon = {
6405ffeb84bSBen Skeggs .dtor = nvkm_perfmon_dtor,
6412d4b94b9SBen Skeggs .mthd = nvkm_perfmon_mthd,
6425ffeb84bSBen Skeggs .sclass = nvkm_perfmon_child_get,
6432d4b94b9SBen Skeggs };
6442d4b94b9SBen Skeggs
645d5752b9bSBen Skeggs static int
nvkm_perfmon_new(struct nvkm_pm * pm,const struct nvkm_oclass * oclass,void * data,u32 size,struct nvkm_object ** pobject)6465ffeb84bSBen Skeggs nvkm_perfmon_new(struct nvkm_pm *pm, const struct nvkm_oclass *oclass,
6475ffeb84bSBen Skeggs void *data, u32 size, struct nvkm_object **pobject)
648d5752b9bSBen Skeggs {
6495ffeb84bSBen Skeggs struct nvkm_perfmon *perfmon;
650d5752b9bSBen Skeggs
6515ffeb84bSBen Skeggs if (!(perfmon = kzalloc(sizeof(*perfmon), GFP_KERNEL)))
6525ffeb84bSBen Skeggs return -ENOMEM;
6535ffeb84bSBen Skeggs nvkm_object_ctor(&nvkm_perfmon, oclass, &perfmon->object);
6545ffeb84bSBen Skeggs perfmon->pm = pm;
6555ffeb84bSBen Skeggs *pobject = &perfmon->object;
6565ffeb84bSBen Skeggs return 0;
657f21950eaSBen Skeggs }
658f21950eaSBen Skeggs
659d5752b9bSBen Skeggs /*******************************************************************************
660d5752b9bSBen Skeggs * PPM engine/subdev functions
661d5752b9bSBen Skeggs ******************************************************************************/
6625ffeb84bSBen Skeggs
6635ffeb84bSBen Skeggs static int
nvkm_pm_oclass_new(struct nvkm_device * device,const struct nvkm_oclass * oclass,void * data,u32 size,struct nvkm_object ** pobject)6645ffeb84bSBen Skeggs nvkm_pm_oclass_new(struct nvkm_device *device, const struct nvkm_oclass *oclass,
6655ffeb84bSBen Skeggs void *data, u32 size, struct nvkm_object **pobject)
6665ffeb84bSBen Skeggs {
6675ffeb84bSBen Skeggs struct nvkm_pm *pm = nvkm_pm(oclass->engine);
6685ffeb84bSBen Skeggs int ret;
6695ffeb84bSBen Skeggs
6705ffeb84bSBen Skeggs ret = nvkm_perfmon_new(pm, oclass, data, size, pobject);
6715ffeb84bSBen Skeggs if (ret)
6725ffeb84bSBen Skeggs return ret;
6735ffeb84bSBen Skeggs
674f8106922SBen Skeggs spin_lock(&pm->client.lock);
675f8106922SBen Skeggs if (pm->client.object == NULL)
676f8106922SBen Skeggs pm->client.object = *pobject;
677f8106922SBen Skeggs ret = (pm->client.object == *pobject) ? 0 : -EBUSY;
678f8106922SBen Skeggs spin_unlock(&pm->client.lock);
6795ffeb84bSBen Skeggs return ret;
6805ffeb84bSBen Skeggs }
6815ffeb84bSBen Skeggs
6825ffeb84bSBen Skeggs static const struct nvkm_device_oclass
6835ffeb84bSBen Skeggs nvkm_pm_oclass = {
68408f7633cSBen Skeggs .base.oclass = NVIF_CLASS_PERFMON,
6855ffeb84bSBen Skeggs .base.minver = -1,
6865ffeb84bSBen Skeggs .base.maxver = -1,
6875ffeb84bSBen Skeggs .ctor = nvkm_pm_oclass_new,
6885ffeb84bSBen Skeggs };
6895ffeb84bSBen Skeggs
6905ffeb84bSBen Skeggs static int
nvkm_pm_oclass_get(struct nvkm_oclass * oclass,int index,const struct nvkm_device_oclass ** class)6915ffeb84bSBen Skeggs nvkm_pm_oclass_get(struct nvkm_oclass *oclass, int index,
6925ffeb84bSBen Skeggs const struct nvkm_device_oclass **class)
6935ffeb84bSBen Skeggs {
6945ffeb84bSBen Skeggs if (index == 0) {
6955ffeb84bSBen Skeggs oclass->base = nvkm_pm_oclass.base;
6965ffeb84bSBen Skeggs *class = &nvkm_pm_oclass;
6975ffeb84bSBen Skeggs return index;
6985ffeb84bSBen Skeggs }
6995ffeb84bSBen Skeggs return 1;
7005ffeb84bSBen Skeggs }
7015ffeb84bSBen Skeggs
702e08a1d97SBaoyou Xie static int
nvkm_perfsrc_new(struct nvkm_pm * pm,struct nvkm_perfsig * sig,const struct nvkm_specsrc * spec)7038c1aeaa1SBen Skeggs nvkm_perfsrc_new(struct nvkm_pm *pm, struct nvkm_perfsig *sig,
704e82661e2SSamuel Pitoiset const struct nvkm_specsrc *spec)
705e82661e2SSamuel Pitoiset {
706e82661e2SSamuel Pitoiset const struct nvkm_specsrc *ssrc;
707e82661e2SSamuel Pitoiset const struct nvkm_specmux *smux;
708e82661e2SSamuel Pitoiset struct nvkm_perfsrc *src;
709e82661e2SSamuel Pitoiset u8 source_nr = 0;
710e82661e2SSamuel Pitoiset
711e82661e2SSamuel Pitoiset if (!spec) {
712e82661e2SSamuel Pitoiset /* No sources are defined for this signal. */
713e82661e2SSamuel Pitoiset return 0;
714e82661e2SSamuel Pitoiset }
715e82661e2SSamuel Pitoiset
716e82661e2SSamuel Pitoiset ssrc = spec;
717e82661e2SSamuel Pitoiset while (ssrc->name) {
718e82661e2SSamuel Pitoiset smux = ssrc->mux;
719e82661e2SSamuel Pitoiset while (smux->name) {
720e82661e2SSamuel Pitoiset bool found = false;
721e82661e2SSamuel Pitoiset u8 source_id = 0;
722e82661e2SSamuel Pitoiset u32 len;
723e82661e2SSamuel Pitoiset
7248c1aeaa1SBen Skeggs list_for_each_entry(src, &pm->sources, head) {
725e82661e2SSamuel Pitoiset if (src->addr == ssrc->addr &&
726e82661e2SSamuel Pitoiset src->shift == smux->shift) {
727e82661e2SSamuel Pitoiset found = true;
728e82661e2SSamuel Pitoiset break;
729e82661e2SSamuel Pitoiset }
730e82661e2SSamuel Pitoiset source_id++;
731e82661e2SSamuel Pitoiset }
732e82661e2SSamuel Pitoiset
733e82661e2SSamuel Pitoiset if (!found) {
734e82661e2SSamuel Pitoiset src = kzalloc(sizeof(*src), GFP_KERNEL);
735e82661e2SSamuel Pitoiset if (!src)
736e82661e2SSamuel Pitoiset return -ENOMEM;
737e82661e2SSamuel Pitoiset
738e82661e2SSamuel Pitoiset src->addr = ssrc->addr;
739e82661e2SSamuel Pitoiset src->mask = smux->mask;
740e82661e2SSamuel Pitoiset src->shift = smux->shift;
741e82661e2SSamuel Pitoiset src->enable = smux->enable;
742e82661e2SSamuel Pitoiset
743e82661e2SSamuel Pitoiset len = strlen(ssrc->name) +
744e82661e2SSamuel Pitoiset strlen(smux->name) + 2;
745e82661e2SSamuel Pitoiset src->name = kzalloc(len, GFP_KERNEL);
7468c1aeaa1SBen Skeggs if (!src->name) {
7478c1aeaa1SBen Skeggs kfree(src);
748e82661e2SSamuel Pitoiset return -ENOMEM;
7498c1aeaa1SBen Skeggs }
750e82661e2SSamuel Pitoiset snprintf(src->name, len, "%s_%s", ssrc->name,
751e82661e2SSamuel Pitoiset smux->name);
752e82661e2SSamuel Pitoiset
7538c1aeaa1SBen Skeggs list_add_tail(&src->head, &pm->sources);
754e82661e2SSamuel Pitoiset }
755e82661e2SSamuel Pitoiset
756e82661e2SSamuel Pitoiset sig->source[source_nr++] = source_id + 1;
757e82661e2SSamuel Pitoiset smux++;
758e82661e2SSamuel Pitoiset }
759e82661e2SSamuel Pitoiset ssrc++;
760e82661e2SSamuel Pitoiset }
761e82661e2SSamuel Pitoiset
762e82661e2SSamuel Pitoiset return 0;
763e82661e2SSamuel Pitoiset }
764e82661e2SSamuel Pitoiset
765e82661e2SSamuel Pitoiset int
nvkm_perfdom_new(struct nvkm_pm * pm,const char * name,u32 mask,u32 base,u32 size_unit,u32 size_domain,const struct nvkm_specdom * spec)7668c1aeaa1SBen Skeggs nvkm_perfdom_new(struct nvkm_pm *pm, const char *name, u32 mask,
767d5752b9bSBen Skeggs u32 base, u32 size_unit, u32 size_domain,
7684d34686eSBen Skeggs const struct nvkm_specdom *spec)
769d5752b9bSBen Skeggs {
7704d34686eSBen Skeggs const struct nvkm_specdom *sdom;
7714d34686eSBen Skeggs const struct nvkm_specsig *ssig;
7724d34686eSBen Skeggs struct nvkm_perfdom *dom;
773e82661e2SSamuel Pitoiset int ret, i;
774d5752b9bSBen Skeggs
775d5752b9bSBen Skeggs for (i = 0; i == 0 || mask; i++) {
776d5752b9bSBen Skeggs u32 addr = base + (i * size_unit);
777d5752b9bSBen Skeggs if (i && !(mask & (1 << i)))
778d5752b9bSBen Skeggs continue;
779d5752b9bSBen Skeggs
780d5752b9bSBen Skeggs sdom = spec;
781d5752b9bSBen Skeggs while (sdom->signal_nr) {
782acafe7e3SKees Cook dom = kzalloc(struct_size(dom, signal, sdom->signal_nr),
783acafe7e3SKees Cook GFP_KERNEL);
784d5752b9bSBen Skeggs if (!dom)
785d5752b9bSBen Skeggs return -ENOMEM;
786d5752b9bSBen Skeggs
787d5752b9bSBen Skeggs if (mask) {
788d5752b9bSBen Skeggs snprintf(dom->name, sizeof(dom->name),
789d5752b9bSBen Skeggs "%s/%02x/%02x", name, i,
790d5752b9bSBen Skeggs (int)(sdom - spec));
791d5752b9bSBen Skeggs } else {
792d5752b9bSBen Skeggs snprintf(dom->name, sizeof(dom->name),
793d5752b9bSBen Skeggs "%s/%02x", name, (int)(sdom - spec));
794d5752b9bSBen Skeggs }
795d5752b9bSBen Skeggs
7968c1aeaa1SBen Skeggs list_add_tail(&dom->head, &pm->domains);
797d5752b9bSBen Skeggs INIT_LIST_HEAD(&dom->list);
798d5752b9bSBen Skeggs dom->func = sdom->func;
799d5752b9bSBen Skeggs dom->addr = addr;
800d5752b9bSBen Skeggs dom->signal_nr = sdom->signal_nr;
801d5752b9bSBen Skeggs
802d5752b9bSBen Skeggs ssig = (sdom++)->signal;
803d5752b9bSBen Skeggs while (ssig->name) {
804e82661e2SSamuel Pitoiset struct nvkm_perfsig *sig =
805e82661e2SSamuel Pitoiset &dom->signal[ssig->signal];
806e82661e2SSamuel Pitoiset sig->name = ssig->name;
8078c1aeaa1SBen Skeggs ret = nvkm_perfsrc_new(pm, sig, ssig->source);
808e82661e2SSamuel Pitoiset if (ret)
809e82661e2SSamuel Pitoiset return ret;
810d5752b9bSBen Skeggs ssig++;
811d5752b9bSBen Skeggs }
812d5752b9bSBen Skeggs
813d5752b9bSBen Skeggs addr += size_domain;
814d5752b9bSBen Skeggs }
815d5752b9bSBen Skeggs
816d5752b9bSBen Skeggs mask &= ~(1 << i);
817d5752b9bSBen Skeggs }
818d5752b9bSBen Skeggs
819d5752b9bSBen Skeggs return 0;
820d5752b9bSBen Skeggs }
821d5752b9bSBen Skeggs
82297070f23SBen Skeggs static int
nvkm_pm_fini(struct nvkm_engine * engine,bool suspend)82397070f23SBen Skeggs nvkm_pm_fini(struct nvkm_engine *engine, bool suspend)
824d5752b9bSBen Skeggs {
82597070f23SBen Skeggs struct nvkm_pm *pm = nvkm_pm(engine);
82697070f23SBen Skeggs if (pm->func->fini)
82797070f23SBen Skeggs pm->func->fini(pm);
82897070f23SBen Skeggs return 0;
829d5752b9bSBen Skeggs }
830d5752b9bSBen Skeggs
83197070f23SBen Skeggs static void *
nvkm_pm_dtor(struct nvkm_engine * engine)83297070f23SBen Skeggs nvkm_pm_dtor(struct nvkm_engine *engine)
833d5752b9bSBen Skeggs {
83497070f23SBen Skeggs struct nvkm_pm *pm = nvkm_pm(engine);
835e82661e2SSamuel Pitoiset struct nvkm_perfdom *dom, *next_dom;
836e82661e2SSamuel Pitoiset struct nvkm_perfsrc *src, *next_src;
837d5752b9bSBen Skeggs
8388c1aeaa1SBen Skeggs list_for_each_entry_safe(dom, next_dom, &pm->domains, head) {
839d5752b9bSBen Skeggs list_del(&dom->head);
840d5752b9bSBen Skeggs kfree(dom);
841d5752b9bSBen Skeggs }
842d5752b9bSBen Skeggs
8438c1aeaa1SBen Skeggs list_for_each_entry_safe(src, next_src, &pm->sources, head) {
844e82661e2SSamuel Pitoiset list_del(&src->head);
845e82661e2SSamuel Pitoiset kfree(src->name);
846e82661e2SSamuel Pitoiset kfree(src);
847e82661e2SSamuel Pitoiset }
848e82661e2SSamuel Pitoiset
84997070f23SBen Skeggs return pm;
850d5752b9bSBen Skeggs }
851d5752b9bSBen Skeggs
8525ffeb84bSBen Skeggs static const struct nvkm_engine_func
8535ffeb84bSBen Skeggs nvkm_pm = {
85497070f23SBen Skeggs .dtor = nvkm_pm_dtor,
85597070f23SBen Skeggs .fini = nvkm_pm_fini,
8565ffeb84bSBen Skeggs .base.sclass = nvkm_pm_oclass_get,
8575ffeb84bSBen Skeggs };
8585ffeb84bSBen Skeggs
859d5752b9bSBen Skeggs int
nvkm_pm_ctor(const struct nvkm_pm_func * func,struct nvkm_device * device,enum nvkm_subdev_type type,int inst,struct nvkm_pm * pm)86097070f23SBen Skeggs nvkm_pm_ctor(const struct nvkm_pm_func *func, struct nvkm_device *device,
861*e73d371aSBen Skeggs enum nvkm_subdev_type type, int inst, struct nvkm_pm *pm)
862d5752b9bSBen Skeggs {
86397070f23SBen Skeggs pm->func = func;
8648c1aeaa1SBen Skeggs INIT_LIST_HEAD(&pm->domains);
8658c1aeaa1SBen Skeggs INIT_LIST_HEAD(&pm->sources);
866f8106922SBen Skeggs spin_lock_init(&pm->client.lock);
867*e73d371aSBen Skeggs return nvkm_engine_ctor(&nvkm_pm, device, type, inst, true, &pm->engine);
868d5752b9bSBen Skeggs }
869