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/namedb.h>
25#include <core/gpuobj.h>
26#include <core/handle.h>
27
28static struct nvkm_handle *
29nvkm_namedb_lookup(struct nvkm_namedb *namedb, u32 name)
30{
31	struct nvkm_handle *handle;
32
33	list_for_each_entry(handle, &namedb->list, node) {
34		if (handle->name == name)
35			return handle;
36	}
37
38	return NULL;
39}
40
41static struct nvkm_handle *
42nvkm_namedb_lookup_class(struct nvkm_namedb *namedb, u16 oclass)
43{
44	struct nvkm_handle *handle;
45
46	list_for_each_entry(handle, &namedb->list, node) {
47		if (nv_mclass(handle->object) == oclass)
48			return handle;
49	}
50
51	return NULL;
52}
53
54static struct nvkm_handle *
55nvkm_namedb_lookup_vinst(struct nvkm_namedb *namedb, u64 vinst)
56{
57	struct nvkm_handle *handle;
58
59	list_for_each_entry(handle, &namedb->list, node) {
60		if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
61			if (nv_gpuobj(handle->object)->addr == vinst)
62				return handle;
63		}
64	}
65
66	return NULL;
67}
68
69static struct nvkm_handle *
70nvkm_namedb_lookup_cinst(struct nvkm_namedb *namedb, u32 cinst)
71{
72	struct nvkm_handle *handle;
73
74	list_for_each_entry(handle, &namedb->list, node) {
75		if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
76			if (nv_gpuobj(handle->object)->node &&
77			    nv_gpuobj(handle->object)->node->offset == cinst)
78				return handle;
79		}
80	}
81
82	return NULL;
83}
84
85int
86nvkm_namedb_insert(struct nvkm_namedb *namedb, u32 name,
87		   struct nvkm_object *object,
88		   struct nvkm_handle *handle)
89{
90	int ret = -EEXIST;
91	write_lock_irq(&namedb->lock);
92	if (!nvkm_namedb_lookup(namedb, name)) {
93		nvkm_object_ref(object, &handle->object);
94		handle->namedb = namedb;
95		list_add(&handle->node, &namedb->list);
96		ret = 0;
97	}
98	write_unlock_irq(&namedb->lock);
99	return ret;
100}
101
102void
103nvkm_namedb_remove(struct nvkm_handle *handle)
104{
105	struct nvkm_namedb *namedb = handle->namedb;
106	struct nvkm_object *object = handle->object;
107	write_lock_irq(&namedb->lock);
108	list_del(&handle->node);
109	write_unlock_irq(&namedb->lock);
110	nvkm_object_ref(NULL, &object);
111}
112
113struct nvkm_handle *
114nvkm_namedb_get(struct nvkm_namedb *namedb, u32 name)
115{
116	struct nvkm_handle *handle;
117	read_lock(&namedb->lock);
118	handle = nvkm_namedb_lookup(namedb, name);
119	if (handle == NULL)
120		read_unlock(&namedb->lock);
121	return handle;
122}
123
124struct nvkm_handle *
125nvkm_namedb_get_class(struct nvkm_namedb *namedb, u16 oclass)
126{
127	struct nvkm_handle *handle;
128	read_lock(&namedb->lock);
129	handle = nvkm_namedb_lookup_class(namedb, oclass);
130	if (handle == NULL)
131		read_unlock(&namedb->lock);
132	return handle;
133}
134
135struct nvkm_handle *
136nvkm_namedb_get_vinst(struct nvkm_namedb *namedb, u64 vinst)
137{
138	struct nvkm_handle *handle;
139	read_lock(&namedb->lock);
140	handle = nvkm_namedb_lookup_vinst(namedb, vinst);
141	if (handle == NULL)
142		read_unlock(&namedb->lock);
143	return handle;
144}
145
146struct nvkm_handle *
147nvkm_namedb_get_cinst(struct nvkm_namedb *namedb, u32 cinst)
148{
149	struct nvkm_handle *handle;
150	read_lock(&namedb->lock);
151	handle = nvkm_namedb_lookup_cinst(namedb, cinst);
152	if (handle == NULL)
153		read_unlock(&namedb->lock);
154	return handle;
155}
156
157void
158nvkm_namedb_put(struct nvkm_handle *handle)
159{
160	if (handle)
161		read_unlock(&handle->namedb->lock);
162}
163
164int
165nvkm_namedb_create_(struct nvkm_object *parent, struct nvkm_object *engine,
166		    struct nvkm_oclass *oclass, u32 pclass,
167		    struct nvkm_oclass *sclass, u64 engcls,
168		    int length, void **pobject)
169{
170	struct nvkm_namedb *namedb;
171	int ret;
172
173	ret = nvkm_parent_create_(parent, engine, oclass, pclass |
174				  NV_NAMEDB_CLASS, sclass, engcls,
175				  length, pobject);
176	namedb = *pobject;
177	if (ret)
178		return ret;
179
180	rwlock_init(&namedb->lock);
181	INIT_LIST_HEAD(&namedb->list);
182	return 0;
183}
184
185int
186_nvkm_namedb_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
187		  struct nvkm_oclass *oclass, void *data, u32 size,
188		  struct nvkm_object **pobject)
189{
190	struct nvkm_namedb *object;
191	int ret;
192
193	ret = nvkm_namedb_create(parent, engine, oclass, 0, NULL, 0, &object);
194	*pobject = nv_object(object);
195	if (ret)
196		return ret;
197
198	return 0;
199}
200