1c39f472eSBen Skeggs /*
2c39f472eSBen Skeggs  * Copyright 2012 Red Hat Inc.
3c39f472eSBen Skeggs  *
4c39f472eSBen Skeggs  * Permission is hereby granted, free of charge, to any person obtaining a
5c39f472eSBen Skeggs  * copy of this software and associated documentation files (the "Software"),
6c39f472eSBen Skeggs  * to deal in the Software without restriction, including without limitation
7c39f472eSBen Skeggs  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8c39f472eSBen Skeggs  * and/or sell copies of the Software, and to permit persons to whom the
9c39f472eSBen Skeggs  * Software is furnished to do so, subject to the following conditions:
10c39f472eSBen Skeggs  *
11c39f472eSBen Skeggs  * The above copyright notice and this permission notice shall be included in
12c39f472eSBen Skeggs  * all copies or substantial portions of the Software.
13c39f472eSBen Skeggs  *
14c39f472eSBen Skeggs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15c39f472eSBen Skeggs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16c39f472eSBen Skeggs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17c39f472eSBen Skeggs  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18c39f472eSBen Skeggs  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19c39f472eSBen Skeggs  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20c39f472eSBen Skeggs  * OTHER DEALINGS IN THE SOFTWARE.
21c39f472eSBen Skeggs  *
22c39f472eSBen Skeggs  * Authors: Ben Skeggs
23c39f472eSBen Skeggs  */
24c39f472eSBen Skeggs #include <core/client.h>
255025407bSBen Skeggs #include <core/device.h>
26c39f472eSBen Skeggs #include <core/option.h>
275025407bSBen Skeggs 
28c39f472eSBen Skeggs #include <nvif/class.h>
29c39f472eSBen Skeggs #include <nvif/event.h>
3013db6d6eSBen Skeggs #include <nvif/if0000.h>
315025407bSBen Skeggs #include <nvif/unpack.h>
32c39f472eSBen Skeggs 
3304b88677SBen Skeggs static int
nvkm_uclient_new(const struct nvkm_oclass * oclass,void * argv,u32 argc,struct nvkm_object ** pobject)3404b88677SBen Skeggs nvkm_uclient_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
3504b88677SBen Skeggs 		 struct nvkm_object **pobject)
3604b88677SBen Skeggs {
3704b88677SBen Skeggs 	union {
3804b88677SBen Skeggs 		struct nvif_client_v0 v0;
3904b88677SBen Skeggs 	} *args = argv;
4004b88677SBen Skeggs 	struct nvkm_client *client;
4104b88677SBen Skeggs 	int ret = -ENOSYS;
4204b88677SBen Skeggs 
4304b88677SBen Skeggs 	if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))){
4404b88677SBen Skeggs 		args->v0.name[sizeof(args->v0.name) - 1] = 0;
4504b88677SBen Skeggs 		ret = nvkm_client_new(args->v0.name, args->v0.device, NULL,
4699d0701aSBen Skeggs 				      NULL, oclass->client->event, &client);
4704b88677SBen Skeggs 		if (ret)
4804b88677SBen Skeggs 			return ret;
4904b88677SBen Skeggs 	} else
5004b88677SBen Skeggs 		return ret;
5104b88677SBen Skeggs 
5204b88677SBen Skeggs 	client->object.client = oclass->client;
5304b88677SBen Skeggs 	client->object.handle = oclass->handle;
5404b88677SBen Skeggs 	client->object.route  = oclass->route;
5504b88677SBen Skeggs 	client->object.token  = oclass->token;
5604b88677SBen Skeggs 	client->object.object = oclass->object;
5704b88677SBen Skeggs 	client->debug = oclass->client->debug;
5804b88677SBen Skeggs 	*pobject = &client->object;
5904b88677SBen Skeggs 	return 0;
6004b88677SBen Skeggs }
6104b88677SBen Skeggs 
625e18b973SZou Wei static const struct nvkm_sclass
6303295eabSBen Skeggs nvkm_uclient_sclass = {
6403295eabSBen Skeggs 	.oclass = NVIF_CLASS_CLIENT,
6504b88677SBen Skeggs 	.minver = 0,
6604b88677SBen Skeggs 	.maxver = 0,
6704b88677SBen Skeggs 	.ctor = nvkm_uclient_new,
6803295eabSBen Skeggs };
6903295eabSBen Skeggs 
7004b88677SBen Skeggs static const struct nvkm_object_func nvkm_client;
7104b88677SBen Skeggs struct nvkm_client *
nvkm_client_search(struct nvkm_client * client,u64 handle)7204b88677SBen Skeggs nvkm_client_search(struct nvkm_client *client, u64 handle)
7304b88677SBen Skeggs {
7404b88677SBen Skeggs 	struct nvkm_object *object;
7504b88677SBen Skeggs 
7604b88677SBen Skeggs 	object = nvkm_object_search(client, handle, &nvkm_client);
7704b88677SBen Skeggs 	if (IS_ERR(object))
7804b88677SBen Skeggs 		return (void *)object;
7904b88677SBen Skeggs 
8004b88677SBen Skeggs 	return nvkm_client(object);
8104b88677SBen Skeggs }
8204b88677SBen Skeggs 
83c39f472eSBen Skeggs static int
nvkm_client_mthd_devlist(struct nvkm_client * client,void * data,u32 size)8403295eabSBen Skeggs nvkm_client_mthd_devlist(struct nvkm_client *client, void *data, u32 size)
85c39f472eSBen Skeggs {
86c39f472eSBen Skeggs 	union {
8703295eabSBen Skeggs 		struct nvif_client_devlist_v0 v0;
88c39f472eSBen Skeggs 	} *args = data;
89f01c4e68SBen Skeggs 	int ret = -ENOSYS;
90c39f472eSBen Skeggs 
9103295eabSBen Skeggs 	nvif_ioctl(&client->object, "client devlist size %d\n", size);
92f01c4e68SBen Skeggs 	if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
9303295eabSBen Skeggs 		nvif_ioctl(&client->object, "client devlist vers %d count %d\n",
94c39f472eSBen Skeggs 			   args->v0.version, args->v0.count);
95c39f472eSBen Skeggs 		if (size == sizeof(args->v0.device[0]) * args->v0.count) {
965025407bSBen Skeggs 			ret = nvkm_device_list(args->v0.device, args->v0.count);
97c39f472eSBen Skeggs 			if (ret >= 0) {
98c39f472eSBen Skeggs 				args->v0.count = ret;
99c39f472eSBen Skeggs 				ret = 0;
100c39f472eSBen Skeggs 			}
101c39f472eSBen Skeggs 		} else {
102c39f472eSBen Skeggs 			ret = -EINVAL;
103c39f472eSBen Skeggs 		}
104c39f472eSBen Skeggs 	}
105c39f472eSBen Skeggs 
106c39f472eSBen Skeggs 	return ret;
107c39f472eSBen Skeggs }
108c39f472eSBen Skeggs 
109c39f472eSBen Skeggs static int
nvkm_client_mthd(struct nvkm_object * object,u32 mthd,void * data,u32 size)1105025407bSBen Skeggs nvkm_client_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
111c39f472eSBen Skeggs {
11203295eabSBen Skeggs 	struct nvkm_client *client = nvkm_client(object);
113c39f472eSBen Skeggs 	switch (mthd) {
11403295eabSBen Skeggs 	case NVIF_CLIENT_V0_DEVLIST:
11503295eabSBen Skeggs 		return nvkm_client_mthd_devlist(client, data, size);
116c39f472eSBen Skeggs 	default:
117c39f472eSBen Skeggs 		break;
118c39f472eSBen Skeggs 	}
119c39f472eSBen Skeggs 	return -EINVAL;
120c39f472eSBen Skeggs }
121c39f472eSBen Skeggs 
12224bd0930SBen Skeggs static int
nvkm_client_child_new(const struct nvkm_oclass * oclass,void * data,u32 size,struct nvkm_object ** pobject)12324bd0930SBen Skeggs nvkm_client_child_new(const struct nvkm_oclass *oclass,
12424bd0930SBen Skeggs 		      void *data, u32 size, struct nvkm_object **pobject)
12524bd0930SBen Skeggs {
1262a9f847fSBen Skeggs 	return oclass->base.ctor(oclass, data, size, pobject);
12724bd0930SBen Skeggs }
12824bd0930SBen Skeggs 
12924bd0930SBen Skeggs static int
nvkm_client_child_get(struct nvkm_object * object,int index,struct nvkm_oclass * oclass)13024bd0930SBen Skeggs nvkm_client_child_get(struct nvkm_object *object, int index,
13124bd0930SBen Skeggs 		      struct nvkm_oclass *oclass)
13224bd0930SBen Skeggs {
1332a9f847fSBen Skeggs 	const struct nvkm_sclass *sclass;
1342a9f847fSBen Skeggs 
1352a9f847fSBen Skeggs 	switch (index) {
13604b88677SBen Skeggs 	case 0: sclass = &nvkm_uclient_sclass; break;
13704b88677SBen Skeggs 	case 1: sclass = &nvkm_udevice_sclass; break;
1382a9f847fSBen Skeggs 	default:
13924bd0930SBen Skeggs 		return -EINVAL;
14024bd0930SBen Skeggs 	}
14124bd0930SBen Skeggs 
1422a9f847fSBen Skeggs 	oclass->ctor = nvkm_client_child_new;
1432a9f847fSBen Skeggs 	oclass->base = *sclass;
1442a9f847fSBen Skeggs 	return 0;
1452a9f847fSBen Skeggs }
1462a9f847fSBen Skeggs 
1472c3af924SBen Skeggs static int
nvkm_client_fini(struct nvkm_object * object,bool suspend)1482c3af924SBen Skeggs nvkm_client_fini(struct nvkm_object *object, bool suspend)
149c39f472eSBen Skeggs {
1502c3af924SBen Skeggs 	return 0;
151c39f472eSBen Skeggs }
152c39f472eSBen Skeggs 
1532c3af924SBen Skeggs static void *
nvkm_client_dtor(struct nvkm_object * object)1542c3af924SBen Skeggs nvkm_client_dtor(struct nvkm_object *object)
15576ecea5bSBen Skeggs {
15699d0701aSBen Skeggs 	return nvkm_client(object);
15776ecea5bSBen Skeggs }
1582c3af924SBen Skeggs 
1592c3af924SBen Skeggs static const struct nvkm_object_func
1602c3af924SBen Skeggs nvkm_client = {
1612c3af924SBen Skeggs 	.dtor = nvkm_client_dtor,
1622c3af924SBen Skeggs 	.fini = nvkm_client_fini,
1632c3af924SBen Skeggs 	.mthd = nvkm_client_mthd,
1642c3af924SBen Skeggs 	.sclass = nvkm_client_child_get,
1652c3af924SBen Skeggs };
16676ecea5bSBen Skeggs 
16776ecea5bSBen Skeggs int
nvkm_client_new(const char * name,u64 device,const char * cfg,const char * dbg,int (* event)(u64,void *,u32),struct nvkm_client ** pclient)16899d0701aSBen Skeggs nvkm_client_new(const char *name, u64 device, const char *cfg, const char *dbg,
169f43e47c0SBen Skeggs 		int (*event)(u64, void *, u32), struct nvkm_client **pclient)
17076ecea5bSBen Skeggs {
17103295eabSBen Skeggs 	struct nvkm_oclass oclass = { .base = nvkm_uclient_sclass };
17276ecea5bSBen Skeggs 	struct nvkm_client *client;
17376ecea5bSBen Skeggs 
17424bd0930SBen Skeggs 	if (!(client = *pclient = kzalloc(sizeof(*client), GFP_KERNEL)))
17524bd0930SBen Skeggs 		return -ENOMEM;
17624bd0930SBen Skeggs 	oclass.client = client;
17776ecea5bSBen Skeggs 
1782c3af924SBen Skeggs 	nvkm_object_ctor(&nvkm_client, &oclass, &client->object);
17976ecea5bSBen Skeggs 	snprintf(client->name, sizeof(client->name), "%s", name);
18024bd0930SBen Skeggs 	client->device = device;
18176ecea5bSBen Skeggs 	client->debug = nvkm_dbgopt(dbg, "CLIENT");
182bf81df9bSBen Skeggs 	client->objroot = RB_ROOT;
1836887314fSDave Airlie 	spin_lock_init(&client->obj_lock);
184f43e47c0SBen Skeggs 	client->event = event;
185c83c4097SBen Skeggs 	INIT_LIST_HEAD(&client->umem);
186c83c4097SBen Skeggs 	spin_lock_init(&client->lock);
187fbd58ebdSBen Skeggs 	return 0;
18876ecea5bSBen Skeggs }
189