nouveau: lock the client object tree.
[sfrench/cifs-2.6.git] / drivers / gpu / drm / nouveau / nvkm / core / client.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/client.h>
25 #include <core/device.h>
26 #include <core/option.h>
27
28 #include <nvif/class.h>
29 #include <nvif/event.h>
30 #include <nvif/if0000.h>
31 #include <nvif/unpack.h>
32
33 static int
34 nvkm_uclient_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
35                  struct nvkm_object **pobject)
36 {
37         union {
38                 struct nvif_client_v0 v0;
39         } *args = argv;
40         struct nvkm_client *client;
41         int ret = -ENOSYS;
42
43         if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))){
44                 args->v0.name[sizeof(args->v0.name) - 1] = 0;
45                 ret = nvkm_client_new(args->v0.name, args->v0.device, NULL,
46                                       NULL, oclass->client->event, &client);
47                 if (ret)
48                         return ret;
49         } else
50                 return ret;
51
52         client->object.client = oclass->client;
53         client->object.handle = oclass->handle;
54         client->object.route  = oclass->route;
55         client->object.token  = oclass->token;
56         client->object.object = oclass->object;
57         client->debug = oclass->client->debug;
58         *pobject = &client->object;
59         return 0;
60 }
61
62 static const struct nvkm_sclass
63 nvkm_uclient_sclass = {
64         .oclass = NVIF_CLASS_CLIENT,
65         .minver = 0,
66         .maxver = 0,
67         .ctor = nvkm_uclient_new,
68 };
69
70 static const struct nvkm_object_func nvkm_client;
71 struct nvkm_client *
72 nvkm_client_search(struct nvkm_client *client, u64 handle)
73 {
74         struct nvkm_object *object;
75
76         object = nvkm_object_search(client, handle, &nvkm_client);
77         if (IS_ERR(object))
78                 return (void *)object;
79
80         return nvkm_client(object);
81 }
82
83 static int
84 nvkm_client_mthd_devlist(struct nvkm_client *client, void *data, u32 size)
85 {
86         union {
87                 struct nvif_client_devlist_v0 v0;
88         } *args = data;
89         int ret = -ENOSYS;
90
91         nvif_ioctl(&client->object, "client devlist size %d\n", size);
92         if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
93                 nvif_ioctl(&client->object, "client devlist vers %d count %d\n",
94                            args->v0.version, args->v0.count);
95                 if (size == sizeof(args->v0.device[0]) * args->v0.count) {
96                         ret = nvkm_device_list(args->v0.device, args->v0.count);
97                         if (ret >= 0) {
98                                 args->v0.count = ret;
99                                 ret = 0;
100                         }
101                 } else {
102                         ret = -EINVAL;
103                 }
104         }
105
106         return ret;
107 }
108
109 static int
110 nvkm_client_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
111 {
112         struct nvkm_client *client = nvkm_client(object);
113         switch (mthd) {
114         case NVIF_CLIENT_V0_DEVLIST:
115                 return nvkm_client_mthd_devlist(client, data, size);
116         default:
117                 break;
118         }
119         return -EINVAL;
120 }
121
122 static int
123 nvkm_client_child_new(const struct nvkm_oclass *oclass,
124                       void *data, u32 size, struct nvkm_object **pobject)
125 {
126         return oclass->base.ctor(oclass, data, size, pobject);
127 }
128
129 static int
130 nvkm_client_child_get(struct nvkm_object *object, int index,
131                       struct nvkm_oclass *oclass)
132 {
133         const struct nvkm_sclass *sclass;
134
135         switch (index) {
136         case 0: sclass = &nvkm_uclient_sclass; break;
137         case 1: sclass = &nvkm_udevice_sclass; break;
138         default:
139                 return -EINVAL;
140         }
141
142         oclass->ctor = nvkm_client_child_new;
143         oclass->base = *sclass;
144         return 0;
145 }
146
147 static int
148 nvkm_client_fini(struct nvkm_object *object, bool suspend)
149 {
150         return 0;
151 }
152
153 static void *
154 nvkm_client_dtor(struct nvkm_object *object)
155 {
156         return nvkm_client(object);
157 }
158
159 static const struct nvkm_object_func
160 nvkm_client = {
161         .dtor = nvkm_client_dtor,
162         .fini = nvkm_client_fini,
163         .mthd = nvkm_client_mthd,
164         .sclass = nvkm_client_child_get,
165 };
166
167 int
168 nvkm_client_new(const char *name, u64 device, const char *cfg, const char *dbg,
169                 int (*event)(u64, void *, u32), struct nvkm_client **pclient)
170 {
171         struct nvkm_oclass oclass = { .base = nvkm_uclient_sclass };
172         struct nvkm_client *client;
173
174         if (!(client = *pclient = kzalloc(sizeof(*client), GFP_KERNEL)))
175                 return -ENOMEM;
176         oclass.client = client;
177
178         nvkm_object_ctor(&nvkm_client, &oclass, &client->object);
179         snprintf(client->name, sizeof(client->name), "%s", name);
180         client->device = device;
181         client->debug = nvkm_dbgopt(dbg, "CLIENT");
182         client->objroot = RB_ROOT;
183         spin_lock_init(&client->obj_lock);
184         client->event = event;
185         INIT_LIST_HEAD(&client->umem);
186         spin_lock_init(&client->lock);
187         return 0;
188 }