15f76f294SBen Skeggs /*
25f76f294SBen Skeggs * Copyright 2016 Red Hat Inc.
35f76f294SBen Skeggs *
45f76f294SBen Skeggs * Permission is hereby granted, free of charge, to any person obtaining a
55f76f294SBen Skeggs * copy of this software and associated documentation files (the "Software"),
65f76f294SBen Skeggs * to deal in the Software without restriction, including without limitation
75f76f294SBen Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense,
85f76f294SBen Skeggs * and/or sell copies of the Software, and to permit persons to whom the
95f76f294SBen Skeggs * Software is furnished to do so, subject to the following conditions:
105f76f294SBen Skeggs *
115f76f294SBen Skeggs * The above copyright notice and this permission notice shall be included in
125f76f294SBen Skeggs * all copies or substantial portions of the Software.
135f76f294SBen Skeggs *
145f76f294SBen Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
155f76f294SBen Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
165f76f294SBen Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
175f76f294SBen Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
185f76f294SBen Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
195f76f294SBen Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
205f76f294SBen Skeggs * OTHER DEALINGS IN THE SOFTWARE.
215f76f294SBen Skeggs *
225f76f294SBen Skeggs * Authors: Ben Skeggs <bskeggs@redhat.com>
235f76f294SBen Skeggs */
245f76f294SBen Skeggs #include "priv.h"
255f76f294SBen Skeggs
265f76f294SBen Skeggs struct nvkm_top_device *
nvkm_top_device_new(struct nvkm_top * top)275f76f294SBen Skeggs nvkm_top_device_new(struct nvkm_top *top)
285f76f294SBen Skeggs {
295f76f294SBen Skeggs struct nvkm_top_device *info = kmalloc(sizeof(*info), GFP_KERNEL);
305f76f294SBen Skeggs if (info) {
315e0d3dbcSBen Skeggs info->type = NVKM_SUBDEV_NR;
325e0d3dbcSBen Skeggs info->inst = -1;
335f76f294SBen Skeggs info->addr = 0;
345f76f294SBen Skeggs info->fault = -1;
355f76f294SBen Skeggs info->engine = -1;
365f76f294SBen Skeggs info->runlist = -1;
375f76f294SBen Skeggs info->reset = -1;
385f76f294SBen Skeggs info->intr = -1;
395f76f294SBen Skeggs list_add_tail(&info->head, &top->device);
405f76f294SBen Skeggs }
415f76f294SBen Skeggs return info;
425f76f294SBen Skeggs }
435f76f294SBen Skeggs
445f76f294SBen Skeggs u32
nvkm_top_addr(struct nvkm_device * device,enum nvkm_subdev_type type,int inst)45b7da823aSBen Skeggs nvkm_top_addr(struct nvkm_device *device, enum nvkm_subdev_type type, int inst)
46eec9ffe4SBen Skeggs {
47eec9ffe4SBen Skeggs struct nvkm_top *top = device->top;
48eec9ffe4SBen Skeggs struct nvkm_top_device *info;
49eec9ffe4SBen Skeggs
50eec9ffe4SBen Skeggs if (top) {
51eec9ffe4SBen Skeggs list_for_each_entry(info, &top->device, head) {
52b7da823aSBen Skeggs if (info->type == type && info->inst == inst)
53eec9ffe4SBen Skeggs return info->addr;
54eec9ffe4SBen Skeggs }
55eec9ffe4SBen Skeggs }
56eec9ffe4SBen Skeggs
57eec9ffe4SBen Skeggs return 0;
58eec9ffe4SBen Skeggs }
59eec9ffe4SBen Skeggs
60eec9ffe4SBen Skeggs u32
nvkm_top_reset(struct nvkm_device * device,enum nvkm_subdev_type type,int inst)616997ea13SBen Skeggs nvkm_top_reset(struct nvkm_device *device, enum nvkm_subdev_type type, int inst)
625f76f294SBen Skeggs {
63952eb819SBen Skeggs struct nvkm_top *top = device->top;
645f76f294SBen Skeggs struct nvkm_top_device *info;
655f76f294SBen Skeggs
665f76f294SBen Skeggs if (top) {
675f76f294SBen Skeggs list_for_each_entry(info, &top->device, head) {
686997ea13SBen Skeggs if (info->type == type && info->inst == inst && info->reset >= 0)
695f76f294SBen Skeggs return BIT(info->reset);
705f76f294SBen Skeggs }
715f76f294SBen Skeggs }
725f76f294SBen Skeggs
735f76f294SBen Skeggs return 0;
745f76f294SBen Skeggs }
755f76f294SBen Skeggs
765f76f294SBen Skeggs u32
nvkm_top_intr_mask(struct nvkm_device * device,enum nvkm_subdev_type type,int inst)77a35047baSBen Skeggs nvkm_top_intr_mask(struct nvkm_device *device, enum nvkm_subdev_type type, int inst)
783560e170SBen Skeggs {
793560e170SBen Skeggs struct nvkm_top *top = device->top;
803560e170SBen Skeggs struct nvkm_top_device *info;
813560e170SBen Skeggs
823560e170SBen Skeggs if (top) {
833560e170SBen Skeggs list_for_each_entry(info, &top->device, head) {
84a35047baSBen Skeggs if (info->type == type && info->inst == inst && info->intr >= 0)
853560e170SBen Skeggs return BIT(info->intr);
863560e170SBen Skeggs }
873560e170SBen Skeggs }
883560e170SBen Skeggs
893560e170SBen Skeggs return 0;
903560e170SBen Skeggs }
913560e170SBen Skeggs
9213416077SBen Skeggs int
nvkm_top_fault_id(struct nvkm_device * device,enum nvkm_subdev_type type,int inst)93088bfe43SBen Skeggs nvkm_top_fault_id(struct nvkm_device *device, enum nvkm_subdev_type type, int inst)
9413416077SBen Skeggs {
9513416077SBen Skeggs struct nvkm_top *top = device->top;
9613416077SBen Skeggs struct nvkm_top_device *info;
9713416077SBen Skeggs
9813416077SBen Skeggs list_for_each_entry(info, &top->device, head) {
99088bfe43SBen Skeggs if (info->type == type && info->inst == inst && info->fault >= 0)
10013416077SBen Skeggs return info->fault;
10113416077SBen Skeggs }
10213416077SBen Skeggs
10313416077SBen Skeggs return -ENOENT;
10413416077SBen Skeggs }
10513416077SBen Skeggs
106ba083ec7SBen Skeggs struct nvkm_subdev *
nvkm_top_fault(struct nvkm_device * device,int fault)107952eb819SBen Skeggs nvkm_top_fault(struct nvkm_device *device, int fault)
1085f76f294SBen Skeggs {
109952eb819SBen Skeggs struct nvkm_top *top = device->top;
1105f76f294SBen Skeggs struct nvkm_top_device *info;
1115f76f294SBen Skeggs
1125f76f294SBen Skeggs list_for_each_entry(info, &top->device, head) {
1135f76f294SBen Skeggs if (info->fault == fault)
114ba083ec7SBen Skeggs return nvkm_device_subdev(device, info->type, info->inst);
1155f76f294SBen Skeggs }
1165f76f294SBen Skeggs
117ba083ec7SBen Skeggs return NULL;
1185f76f294SBen Skeggs }
1195f76f294SBen Skeggs
120*eec3f6dfSBen Skeggs int
nvkm_top_parse(struct nvkm_device * device)121*eec3f6dfSBen Skeggs nvkm_top_parse(struct nvkm_device *device)
1225f76f294SBen Skeggs {
123*eec3f6dfSBen Skeggs struct nvkm_top *top = device->top;
124*eec3f6dfSBen Skeggs
125*eec3f6dfSBen Skeggs if (!top || !list_empty(&top->device))
126*eec3f6dfSBen Skeggs return 0;
127*eec3f6dfSBen Skeggs
128*eec3f6dfSBen Skeggs return top->func->parse(top);
1295f76f294SBen Skeggs }
1305f76f294SBen Skeggs
1315f76f294SBen Skeggs static void *
nvkm_top_dtor(struct nvkm_subdev * subdev)1325f76f294SBen Skeggs nvkm_top_dtor(struct nvkm_subdev *subdev)
1335f76f294SBen Skeggs {
1345f76f294SBen Skeggs struct nvkm_top *top = nvkm_top(subdev);
1355f76f294SBen Skeggs struct nvkm_top_device *info, *temp;
1365f76f294SBen Skeggs
1375f76f294SBen Skeggs list_for_each_entry_safe(info, temp, &top->device, head) {
1385f76f294SBen Skeggs list_del(&info->head);
1395f76f294SBen Skeggs kfree(info);
1405f76f294SBen Skeggs }
1415f76f294SBen Skeggs
1425f76f294SBen Skeggs return top;
1435f76f294SBen Skeggs }
1445f76f294SBen Skeggs
1455f76f294SBen Skeggs static const struct nvkm_subdev_func
1465f76f294SBen Skeggs nvkm_top = {
1475f76f294SBen Skeggs .dtor = nvkm_top_dtor,
1485f76f294SBen Skeggs };
1495f76f294SBen Skeggs
1505f76f294SBen Skeggs int
nvkm_top_new_(const struct nvkm_top_func * func,struct nvkm_device * device,enum nvkm_subdev_type type,int inst,struct nvkm_top ** ptop)1515f76f294SBen Skeggs nvkm_top_new_(const struct nvkm_top_func *func, struct nvkm_device *device,
152601c2a06SBen Skeggs enum nvkm_subdev_type type, int inst, struct nvkm_top **ptop)
1535f76f294SBen Skeggs {
1545f76f294SBen Skeggs struct nvkm_top *top;
1555f76f294SBen Skeggs if (!(top = *ptop = kzalloc(sizeof(*top), GFP_KERNEL)))
1565f76f294SBen Skeggs return -ENOMEM;
157601c2a06SBen Skeggs nvkm_subdev_ctor(&nvkm_top, device, type, inst, &top->subdev);
1585f76f294SBen Skeggs top->func = func;
1595f76f294SBen Skeggs INIT_LIST_HEAD(&top->device);
1605f76f294SBen Skeggs return 0;
1615f76f294SBen Skeggs }
162