dff42fe7a12a13f7c4441fd329495d25da043f98
[linux-2.6-microblaze.git] / drivers / gpu / drm / nouveau / nvkm / core / subdev.c
1 /*
2  * Copyright 2012 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  */
24 #include <core/subdev.h>
25 #include <core/device.h>
26 #include <core/option.h>
27 #include <subdev/mc.h>
28
29 const char *
30 nvkm_subdev_type[NVKM_SUBDEV_NR] = {
31 #define NVKM_LAYOUT_ONCE(type,data,ptr,...) [type] = #ptr,
32 #define NVKM_LAYOUT_INST(A...) NVKM_LAYOUT_ONCE(A)
33 #include <core/layout.h>
34 #undef NVKM_LAYOUT_ONCE
35 #undef NVKM_LAYOUT_INST
36         [NVKM_ENGINE_MSVLD   ] = "msvld",
37         [NVKM_ENGINE_NVENC0  ] = "nvenc0",
38         [NVKM_ENGINE_NVENC1  ] = "nvenc1",
39         [NVKM_ENGINE_NVENC2  ] = "nvenc2",
40         [NVKM_ENGINE_NVDEC0  ] = "nvdec0",
41         [NVKM_ENGINE_NVDEC1  ] = "nvdec1",
42         [NVKM_ENGINE_NVDEC2  ] = "nvdec2",
43         [NVKM_ENGINE_PM      ] = "pm",
44         [NVKM_ENGINE_SEC     ] = "sec",
45         [NVKM_ENGINE_SEC2    ] = "sec2",
46         [NVKM_ENGINE_SW      ] = "sw",
47         [NVKM_ENGINE_VIC     ] = "vic",
48 };
49
50 void
51 nvkm_subdev_intr(struct nvkm_subdev *subdev)
52 {
53         if (subdev->func->intr)
54                 subdev->func->intr(subdev);
55 }
56
57 int
58 nvkm_subdev_info(struct nvkm_subdev *subdev, u64 mthd, u64 *data)
59 {
60         if (subdev->func->info)
61                 return subdev->func->info(subdev, mthd, data);
62         return -ENOSYS;
63 }
64
65 int
66 nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend)
67 {
68         struct nvkm_device *device = subdev->device;
69         const char *action = suspend ? "suspend" : "fini";
70         s64 time;
71
72         nvkm_trace(subdev, "%s running...\n", action);
73         time = ktime_to_us(ktime_get());
74
75         if (subdev->func->fini) {
76                 int ret = subdev->func->fini(subdev, suspend);
77                 if (ret) {
78                         nvkm_error(subdev, "%s failed, %d\n", action, ret);
79                         if (suspend)
80                                 return ret;
81                 }
82         }
83
84         nvkm_mc_reset(device, subdev->type, subdev->inst);
85
86         time = ktime_to_us(ktime_get()) - time;
87         nvkm_trace(subdev, "%s completed in %lldus\n", action, time);
88         return 0;
89 }
90
91 int
92 nvkm_subdev_preinit(struct nvkm_subdev *subdev)
93 {
94         s64 time;
95
96         nvkm_trace(subdev, "preinit running...\n");
97         time = ktime_to_us(ktime_get());
98
99         if (subdev->func->preinit) {
100                 int ret = subdev->func->preinit(subdev);
101                 if (ret) {
102                         nvkm_error(subdev, "preinit failed, %d\n", ret);
103                         return ret;
104                 }
105         }
106
107         time = ktime_to_us(ktime_get()) - time;
108         nvkm_trace(subdev, "preinit completed in %lldus\n", time);
109         return 0;
110 }
111
112 int
113 nvkm_subdev_init(struct nvkm_subdev *subdev)
114 {
115         s64 time;
116         int ret;
117
118         nvkm_trace(subdev, "init running...\n");
119         time = ktime_to_us(ktime_get());
120
121         if (subdev->func->oneinit && !subdev->oneinit) {
122                 s64 time;
123                 nvkm_trace(subdev, "one-time init running...\n");
124                 time = ktime_to_us(ktime_get());
125                 ret = subdev->func->oneinit(subdev);
126                 if (ret) {
127                         nvkm_error(subdev, "one-time init failed, %d\n", ret);
128                         return ret;
129                 }
130
131                 subdev->oneinit = true;
132                 time = ktime_to_us(ktime_get()) - time;
133                 nvkm_trace(subdev, "one-time init completed in %lldus\n", time);
134         }
135
136         if (subdev->func->init) {
137                 ret = subdev->func->init(subdev);
138                 if (ret) {
139                         nvkm_error(subdev, "init failed, %d\n", ret);
140                         return ret;
141                 }
142         }
143
144         time = ktime_to_us(ktime_get()) - time;
145         nvkm_trace(subdev, "init completed in %lldus\n", time);
146         return 0;
147 }
148
149 void
150 nvkm_subdev_del(struct nvkm_subdev **psubdev)
151 {
152         struct nvkm_subdev *subdev = *psubdev;
153         s64 time;
154
155         if (subdev && !WARN_ON(!subdev->func)) {
156                 nvkm_trace(subdev, "destroy running...\n");
157                 time = ktime_to_us(ktime_get());
158                 list_del(&subdev->head);
159                 if (subdev->func->dtor)
160                         *psubdev = subdev->func->dtor(subdev);
161                 time = ktime_to_us(ktime_get()) - time;
162                 nvkm_trace(subdev, "destroy completed in %lldus\n", time);
163                 kfree(*psubdev);
164                 *psubdev = NULL;
165         }
166 }
167
168 void
169 nvkm_subdev_disable(struct nvkm_device *device, enum nvkm_subdev_type type, int inst)
170 {
171         struct nvkm_subdev *subdev;
172         list_for_each_entry(subdev, &device->subdev, head) {
173                 if (subdev->type == type && subdev->inst == inst) {
174                         *subdev->pself = NULL;
175                         nvkm_subdev_del(&subdev);
176                         break;
177                 }
178         }
179 }
180
181 void
182 nvkm_subdev_ctor_(const struct nvkm_subdev_func *func, bool old,
183                  struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
184                  struct nvkm_subdev *subdev)
185 {
186         subdev->func = func;
187         subdev->device = device;
188         subdev->type = type;
189         subdev->inst = inst < 0 ? 0 : inst;
190         subdev->index = type + subdev->inst;
191
192         if (old) {
193                 switch (subdev->type) {
194                 case NVKM_ENGINE_NVENC0 ... NVKM_ENGINE_NVENC_LAST:
195                         subdev->type = NVKM_ENGINE_NVENC;
196                         subdev->inst = subdev->index - NVKM_ENGINE_NVENC0;
197                         break;
198                 case NVKM_ENGINE_NVDEC0 ... NVKM_ENGINE_NVDEC_LAST:
199                         subdev->type = NVKM_ENGINE_NVDEC;
200                         subdev->inst = subdev->index - NVKM_ENGINE_NVDEC0;
201                         break;
202                 default:
203                         break;
204                 }
205                 inst = -1;
206         }
207
208         if (inst >= 0)
209                 snprintf(subdev->name, sizeof(subdev->name), "%s%d", nvkm_subdev_type[type], inst);
210         else
211                 strscpy(subdev->name, nvkm_subdev_type[type], sizeof(subdev->name));
212         subdev->debug = nvkm_dbgopt(device->dbgopt, subdev->name);
213         list_add_tail(&subdev->head, &device->subdev);
214 }
215
216 int
217 nvkm_subdev_new_(const struct nvkm_subdev_func *func, struct nvkm_device *device,
218                  enum nvkm_subdev_type type, int inst, struct nvkm_subdev **psubdev)
219 {
220         if (!(*psubdev = kzalloc(sizeof(**psubdev), GFP_KERNEL)))
221                 return -ENOMEM;
222         nvkm_subdev_ctor(func, device, type, inst, *psubdev);
223         return 0;
224 }