Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2012 Red Hat Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: Ben Skeggs
0023  */
0024 #include <core/client.h>
0025 #include <core/device.h>
0026 #include <core/notify.h>
0027 #include <core/option.h>
0028 
0029 #include <nvif/class.h>
0030 #include <nvif/event.h>
0031 #include <nvif/if0000.h>
0032 #include <nvif/unpack.h>
0033 
0034 static int
0035 nvkm_uclient_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
0036          struct nvkm_object **pobject)
0037 {
0038     union {
0039         struct nvif_client_v0 v0;
0040     } *args = argv;
0041     struct nvkm_client *client;
0042     int ret = -ENOSYS;
0043 
0044     if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))){
0045         args->v0.name[sizeof(args->v0.name) - 1] = 0;
0046         ret = nvkm_client_new(args->v0.name, args->v0.device, NULL,
0047                       NULL, oclass->client->ntfy, &client);
0048         if (ret)
0049             return ret;
0050     } else
0051         return ret;
0052 
0053     client->object.client = oclass->client;
0054     client->object.handle = oclass->handle;
0055     client->object.route  = oclass->route;
0056     client->object.token  = oclass->token;
0057     client->object.object = oclass->object;
0058     client->debug = oclass->client->debug;
0059     *pobject = &client->object;
0060     return 0;
0061 }
0062 
0063 static const struct nvkm_sclass
0064 nvkm_uclient_sclass = {
0065     .oclass = NVIF_CLASS_CLIENT,
0066     .minver = 0,
0067     .maxver = 0,
0068     .ctor = nvkm_uclient_new,
0069 };
0070 
0071 struct nvkm_client_notify {
0072     struct nvkm_client *client;
0073     struct nvkm_notify n;
0074     u8 version;
0075     u8 size;
0076     union {
0077         struct nvif_notify_rep_v0 v0;
0078     } rep;
0079 };
0080 
0081 static int
0082 nvkm_client_notify(struct nvkm_notify *n)
0083 {
0084     struct nvkm_client_notify *notify = container_of(n, typeof(*notify), n);
0085     struct nvkm_client *client = notify->client;
0086     return client->ntfy(&notify->rep, notify->size, n->data, n->size);
0087 }
0088 
0089 int
0090 nvkm_client_notify_put(struct nvkm_client *client, int index)
0091 {
0092     if (index < ARRAY_SIZE(client->notify)) {
0093         if (client->notify[index]) {
0094             nvkm_notify_put(&client->notify[index]->n);
0095             return 0;
0096         }
0097     }
0098     return -ENOENT;
0099 }
0100 
0101 int
0102 nvkm_client_notify_get(struct nvkm_client *client, int index)
0103 {
0104     if (index < ARRAY_SIZE(client->notify)) {
0105         if (client->notify[index]) {
0106             nvkm_notify_get(&client->notify[index]->n);
0107             return 0;
0108         }
0109     }
0110     return -ENOENT;
0111 }
0112 
0113 int
0114 nvkm_client_notify_del(struct nvkm_client *client, int index)
0115 {
0116     if (index < ARRAY_SIZE(client->notify)) {
0117         if (client->notify[index]) {
0118             nvkm_notify_fini(&client->notify[index]->n);
0119             kfree(client->notify[index]);
0120             client->notify[index] = NULL;
0121             return 0;
0122         }
0123     }
0124     return -ENOENT;
0125 }
0126 
0127 int
0128 nvkm_client_notify_new(struct nvkm_object *object,
0129                struct nvkm_event *event, void *data, u32 size)
0130 {
0131     struct nvkm_client *client = object->client;
0132     struct nvkm_client_notify *notify;
0133     union {
0134         struct nvif_notify_req_v0 v0;
0135     } *req = data;
0136     u8  index, reply;
0137     int ret = -ENOSYS;
0138 
0139     for (index = 0; index < ARRAY_SIZE(client->notify); index++) {
0140         if (!client->notify[index])
0141             break;
0142     }
0143 
0144     if (index == ARRAY_SIZE(client->notify))
0145         return -ENOSPC;
0146 
0147     notify = kzalloc(sizeof(*notify), GFP_KERNEL);
0148     if (!notify)
0149         return -ENOMEM;
0150 
0151     nvif_ioctl(object, "notify new size %d\n", size);
0152     if (!(ret = nvif_unpack(ret, &data, &size, req->v0, 0, 0, true))) {
0153         nvif_ioctl(object, "notify new vers %d reply %d route %02x "
0154                    "token %llx\n", req->v0.version,
0155                req->v0.reply, req->v0.route, req->v0.token);
0156         notify->version = req->v0.version;
0157         notify->size = sizeof(notify->rep.v0);
0158         notify->rep.v0.version = req->v0.version;
0159         notify->rep.v0.route = req->v0.route;
0160         notify->rep.v0.token = req->v0.token;
0161         reply = req->v0.reply;
0162     }
0163 
0164     if (ret == 0) {
0165         ret = nvkm_notify_init(object, event, nvkm_client_notify,
0166                        false, data, size, reply, &notify->n);
0167         if (ret == 0) {
0168             client->notify[index] = notify;
0169             notify->client = client;
0170             return index;
0171         }
0172     }
0173 
0174     kfree(notify);
0175     return ret;
0176 }
0177 
0178 static const struct nvkm_object_func nvkm_client;
0179 struct nvkm_client *
0180 nvkm_client_search(struct nvkm_client *client, u64 handle)
0181 {
0182     struct nvkm_object *object;
0183 
0184     object = nvkm_object_search(client, handle, &nvkm_client);
0185     if (IS_ERR(object))
0186         return (void *)object;
0187 
0188     return nvkm_client(object);
0189 }
0190 
0191 static int
0192 nvkm_client_mthd_devlist(struct nvkm_client *client, void *data, u32 size)
0193 {
0194     union {
0195         struct nvif_client_devlist_v0 v0;
0196     } *args = data;
0197     int ret = -ENOSYS;
0198 
0199     nvif_ioctl(&client->object, "client devlist size %d\n", size);
0200     if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
0201         nvif_ioctl(&client->object, "client devlist vers %d count %d\n",
0202                args->v0.version, args->v0.count);
0203         if (size == sizeof(args->v0.device[0]) * args->v0.count) {
0204             ret = nvkm_device_list(args->v0.device, args->v0.count);
0205             if (ret >= 0) {
0206                 args->v0.count = ret;
0207                 ret = 0;
0208             }
0209         } else {
0210             ret = -EINVAL;
0211         }
0212     }
0213 
0214     return ret;
0215 }
0216 
0217 static int
0218 nvkm_client_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
0219 {
0220     struct nvkm_client *client = nvkm_client(object);
0221     switch (mthd) {
0222     case NVIF_CLIENT_V0_DEVLIST:
0223         return nvkm_client_mthd_devlist(client, data, size);
0224     default:
0225         break;
0226     }
0227     return -EINVAL;
0228 }
0229 
0230 static int
0231 nvkm_client_child_new(const struct nvkm_oclass *oclass,
0232               void *data, u32 size, struct nvkm_object **pobject)
0233 {
0234     return oclass->base.ctor(oclass, data, size, pobject);
0235 }
0236 
0237 static int
0238 nvkm_client_child_get(struct nvkm_object *object, int index,
0239               struct nvkm_oclass *oclass)
0240 {
0241     const struct nvkm_sclass *sclass;
0242 
0243     switch (index) {
0244     case 0: sclass = &nvkm_uclient_sclass; break;
0245     case 1: sclass = &nvkm_udevice_sclass; break;
0246     default:
0247         return -EINVAL;
0248     }
0249 
0250     oclass->ctor = nvkm_client_child_new;
0251     oclass->base = *sclass;
0252     return 0;
0253 }
0254 
0255 static int
0256 nvkm_client_fini(struct nvkm_object *object, bool suspend)
0257 {
0258     struct nvkm_client *client = nvkm_client(object);
0259     const char *name[2] = { "fini", "suspend" };
0260     int i;
0261     nvif_debug(object, "%s notify\n", name[suspend]);
0262     for (i = 0; i < ARRAY_SIZE(client->notify); i++)
0263         nvkm_client_notify_put(client, i);
0264     return 0;
0265 }
0266 
0267 static void *
0268 nvkm_client_dtor(struct nvkm_object *object)
0269 {
0270     struct nvkm_client *client = nvkm_client(object);
0271     int i;
0272     for (i = 0; i < ARRAY_SIZE(client->notify); i++)
0273         nvkm_client_notify_del(client, i);
0274     return client;
0275 }
0276 
0277 static const struct nvkm_object_func
0278 nvkm_client = {
0279     .dtor = nvkm_client_dtor,
0280     .fini = nvkm_client_fini,
0281     .mthd = nvkm_client_mthd,
0282     .sclass = nvkm_client_child_get,
0283 };
0284 
0285 int
0286 nvkm_client_new(const char *name, u64 device, const char *cfg,
0287         const char *dbg,
0288         int (*ntfy)(const void *, u32, const void *, u32),
0289         struct nvkm_client **pclient)
0290 {
0291     struct nvkm_oclass oclass = { .base = nvkm_uclient_sclass };
0292     struct nvkm_client *client;
0293 
0294     if (!(client = *pclient = kzalloc(sizeof(*client), GFP_KERNEL)))
0295         return -ENOMEM;
0296     oclass.client = client;
0297 
0298     nvkm_object_ctor(&nvkm_client, &oclass, &client->object);
0299     snprintf(client->name, sizeof(client->name), "%s", name);
0300     client->device = device;
0301     client->debug = nvkm_dbgopt(dbg, "CLIENT");
0302     client->objroot = RB_ROOT;
0303     client->ntfy = ntfy;
0304     INIT_LIST_HEAD(&client->umem);
0305     spin_lock_init(&client->lock);
0306     return 0;
0307 }