xref: /netbsd-src/sys/external/bsd/drm2/drm/drm_agp_hook.c (revision 5fc7130c35d07225254a1b1b44b836dcd2dc4f9d)
1*5fc7130cSriastradh /*	$NetBSD: drm_agp_hook.c,v 1.7 2022/07/19 22:24:34 riastradh Exp $	*/
2d46aeca2Sriastradh 
3d46aeca2Sriastradh /*-
4d46aeca2Sriastradh  * Copyright (c) 2018 The NetBSD Foundation, Inc.
5d46aeca2Sriastradh  * All rights reserved.
6d46aeca2Sriastradh  *
7d46aeca2Sriastradh  * This code is derived from software contributed to The NetBSD Foundation
8d46aeca2Sriastradh  * by Taylor R. Campbell.
9d46aeca2Sriastradh  *
10d46aeca2Sriastradh  * Redistribution and use in source and binary forms, with or without
11d46aeca2Sriastradh  * modification, are permitted provided that the following conditions
12d46aeca2Sriastradh  * are met:
13d46aeca2Sriastradh  * 1. Redistributions of source code must retain the above copyright
14d46aeca2Sriastradh  *    notice, this list of conditions and the following disclaimer.
15d46aeca2Sriastradh  * 2. Redistributions in binary form must reproduce the above copyright
16d46aeca2Sriastradh  *    notice, this list of conditions and the following disclaimer in the
17d46aeca2Sriastradh  *    documentation and/or other materials provided with the distribution.
18d46aeca2Sriastradh  *
19d46aeca2Sriastradh  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20d46aeca2Sriastradh  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21d46aeca2Sriastradh  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22d46aeca2Sriastradh  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23d46aeca2Sriastradh  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24d46aeca2Sriastradh  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25d46aeca2Sriastradh  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26d46aeca2Sriastradh  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27d46aeca2Sriastradh  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28d46aeca2Sriastradh  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29d46aeca2Sriastradh  * POSSIBILITY OF SUCH DAMAGE.
30d46aeca2Sriastradh  */
31d46aeca2Sriastradh 
32d46aeca2Sriastradh #include <sys/cdefs.h>
33*5fc7130cSriastradh __KERNEL_RCSID(0, "$NetBSD: drm_agp_hook.c,v 1.7 2022/07/19 22:24:34 riastradh Exp $");
34d46aeca2Sriastradh 
35d46aeca2Sriastradh #include <sys/types.h>
36d46aeca2Sriastradh #include <sys/condvar.h>
37d46aeca2Sriastradh #include <sys/errno.h>
38d46aeca2Sriastradh #include <sys/mutex.h>
39d46aeca2Sriastradh #include <sys/once.h>
40d46aeca2Sriastradh 
418fe3f4a7Sriastradh #include <drm/drm_agpsupport.h>
428fe3f4a7Sriastradh #include <drm/drm_drv.h>
433f26b5c5Sriastradh #include "../dist/drm/drm_internal.h"
44d46aeca2Sriastradh 
45d46aeca2Sriastradh static struct {
46d46aeca2Sriastradh 	kmutex_t			lock;
47d46aeca2Sriastradh 	kcondvar_t			cv;
48d46aeca2Sriastradh 	unsigned			refcnt; /* at most one per device */
49d46aeca2Sriastradh 	const struct drm_agp_hooks	*hooks;
50d46aeca2Sriastradh } agp_hooks __cacheline_aligned;
51d46aeca2Sriastradh 
52d46aeca2Sriastradh void
drm_agp_hooks_init(void)53d46aeca2Sriastradh drm_agp_hooks_init(void)
54d46aeca2Sriastradh {
55d46aeca2Sriastradh 
56d46aeca2Sriastradh 	mutex_init(&agp_hooks.lock, MUTEX_DEFAULT, IPL_NONE);
57d46aeca2Sriastradh 	cv_init(&agp_hooks.cv, "agphooks");
58d46aeca2Sriastradh 	agp_hooks.refcnt = 0;
59d46aeca2Sriastradh 	agp_hooks.hooks = NULL;
60d46aeca2Sriastradh }
61d46aeca2Sriastradh 
62d46aeca2Sriastradh void
drm_agp_hooks_fini(void)63d46aeca2Sriastradh drm_agp_hooks_fini(void)
64d46aeca2Sriastradh {
65d46aeca2Sriastradh 
66d46aeca2Sriastradh 	KASSERT(agp_hooks.hooks == NULL);
67d46aeca2Sriastradh 	KASSERT(agp_hooks.refcnt == 0);
68d46aeca2Sriastradh 	cv_destroy(&agp_hooks.cv);
69d46aeca2Sriastradh 	mutex_destroy(&agp_hooks.lock);
70d46aeca2Sriastradh }
71d46aeca2Sriastradh 
72d46aeca2Sriastradh int
drm_agp_register(const struct drm_agp_hooks * hooks)73d46aeca2Sriastradh drm_agp_register(const struct drm_agp_hooks *hooks)
74d46aeca2Sriastradh {
75d46aeca2Sriastradh 	int error = 0;
76d46aeca2Sriastradh 
77d46aeca2Sriastradh 	mutex_enter(&agp_hooks.lock);
78d46aeca2Sriastradh 	if (agp_hooks.refcnt) {
79d46aeca2Sriastradh 		KASSERT(agp_hooks.hooks);
80d46aeca2Sriastradh 		error = EBUSY;
81d46aeca2Sriastradh 	} else {
82d46aeca2Sriastradh 		agp_hooks.refcnt++;
83d46aeca2Sriastradh 		agp_hooks.hooks = hooks;
84d46aeca2Sriastradh 	}
85d46aeca2Sriastradh 	mutex_exit(&agp_hooks.lock);
86d46aeca2Sriastradh 
87d46aeca2Sriastradh 	return error;
88d46aeca2Sriastradh }
89d46aeca2Sriastradh 
90d46aeca2Sriastradh int
drm_agp_deregister(const struct drm_agp_hooks * hooks)91d46aeca2Sriastradh drm_agp_deregister(const struct drm_agp_hooks *hooks)
92d46aeca2Sriastradh {
93c1e8fdacStnn 	int error = 0;
94d46aeca2Sriastradh 
95d46aeca2Sriastradh 	mutex_enter(&agp_hooks.lock);
96d46aeca2Sriastradh 	KASSERT(agp_hooks.hooks == hooks);
97d46aeca2Sriastradh 	if (agp_hooks.refcnt > 1) {
98d46aeca2Sriastradh 		error = EBUSY;
99d46aeca2Sriastradh 	} else {
100d46aeca2Sriastradh 		agp_hooks.refcnt = 0;
101d46aeca2Sriastradh 		agp_hooks.hooks = NULL;
102d46aeca2Sriastradh 	}
103d46aeca2Sriastradh 	mutex_exit(&agp_hooks.lock);
104d46aeca2Sriastradh 
105d46aeca2Sriastradh 	return error;
106d46aeca2Sriastradh }
107d46aeca2Sriastradh 
108d46aeca2Sriastradh static const struct drm_agp_hooks *
drm_agp_hooks_acquire(void)109d46aeca2Sriastradh drm_agp_hooks_acquire(void)
110d46aeca2Sriastradh {
111d46aeca2Sriastradh 	const struct drm_agp_hooks *hooks;
112d46aeca2Sriastradh 
113d46aeca2Sriastradh 	mutex_enter(&agp_hooks.lock);
114d46aeca2Sriastradh 	if (agp_hooks.refcnt == 0) {
115d46aeca2Sriastradh 		hooks = NULL;
116d46aeca2Sriastradh 	} else {
117d46aeca2Sriastradh 		KASSERT(agp_hooks.refcnt < UINT_MAX);
118d46aeca2Sriastradh 		agp_hooks.refcnt++;
119d46aeca2Sriastradh 		hooks = agp_hooks.hooks;
120d46aeca2Sriastradh 	}
121d46aeca2Sriastradh 	mutex_exit(&agp_hooks.lock);
122d46aeca2Sriastradh 
123d46aeca2Sriastradh 	return hooks;
124d46aeca2Sriastradh }
125d46aeca2Sriastradh 
126d46aeca2Sriastradh static void
drm_agp_hooks_release(const struct drm_agp_hooks * hooks)127d46aeca2Sriastradh drm_agp_hooks_release(const struct drm_agp_hooks *hooks)
128d46aeca2Sriastradh {
129d46aeca2Sriastradh 
130d46aeca2Sriastradh 	mutex_enter(&agp_hooks.lock);
131d46aeca2Sriastradh 	KASSERT(agp_hooks.hooks == hooks);
132d46aeca2Sriastradh 	KASSERT(agp_hooks.refcnt);
133d46aeca2Sriastradh 	if (--agp_hooks.refcnt == 0)
134d46aeca2Sriastradh 		cv_broadcast(&agp_hooks.cv);
135d46aeca2Sriastradh 	mutex_exit(&agp_hooks.lock);
136d46aeca2Sriastradh }
137d46aeca2Sriastradh 
138d46aeca2Sriastradh struct drm_agp_head *
drm_agp_init(struct drm_device * dev)139d46aeca2Sriastradh drm_agp_init(struct drm_device *dev)
140d46aeca2Sriastradh {
141d46aeca2Sriastradh 	const struct drm_agp_hooks *hooks;
142d46aeca2Sriastradh 	struct drm_agp_head *agp;
143d46aeca2Sriastradh 
144d46aeca2Sriastradh 	if ((hooks = drm_agp_hooks_acquire()) == NULL)
145d46aeca2Sriastradh 		return NULL;
146d46aeca2Sriastradh 	agp = hooks->agph_init(dev);
147d46aeca2Sriastradh 	if (agp == NULL)
148d46aeca2Sriastradh 		drm_agp_hooks_release(hooks);
1492958c943Smrg 	else
1502958c943Smrg 		agp->hooks = hooks;
151d46aeca2Sriastradh 
152d46aeca2Sriastradh 	return agp;
153d46aeca2Sriastradh }
154d46aeca2Sriastradh 
155d46aeca2Sriastradh void
drm_agp_fini(struct drm_device * dev)156d46aeca2Sriastradh drm_agp_fini(struct drm_device *dev)
157d46aeca2Sriastradh {
158d46aeca2Sriastradh 
159d46aeca2Sriastradh 	if (dev->agp == NULL)
160d46aeca2Sriastradh 		return;
161d46aeca2Sriastradh 	dev->agp->hooks->agph_clear(dev);
162d46aeca2Sriastradh 	drm_agp_hooks_release(dev->agp->hooks);
163d46aeca2Sriastradh 	kfree(dev->agp);
164d46aeca2Sriastradh 	dev->agp = NULL;
165d46aeca2Sriastradh }
166d46aeca2Sriastradh 
167d46aeca2Sriastradh void
drm_legacy_agp_clear(struct drm_device * dev)1689f36f594Sriastradh drm_legacy_agp_clear(struct drm_device *dev)
169d46aeca2Sriastradh {
170d46aeca2Sriastradh 
171d46aeca2Sriastradh 	if (dev->agp == NULL)
172d46aeca2Sriastradh 		return;
173d46aeca2Sriastradh 	dev->agp->hooks->agph_clear(dev);
174d46aeca2Sriastradh }
175d46aeca2Sriastradh 
176d46aeca2Sriastradh int
drm_agp_acquire(struct drm_device * dev)177d46aeca2Sriastradh drm_agp_acquire(struct drm_device *dev)
178d46aeca2Sriastradh {
179d46aeca2Sriastradh 
180d46aeca2Sriastradh 	if (dev->agp == NULL)
181d46aeca2Sriastradh 		return -ENODEV;
182d46aeca2Sriastradh 	return dev->agp->hooks->agph_acquire(dev);
183d46aeca2Sriastradh }
184d46aeca2Sriastradh 
185d46aeca2Sriastradh int
drm_agp_release(struct drm_device * dev)186d46aeca2Sriastradh drm_agp_release(struct drm_device *dev)
187d46aeca2Sriastradh {
188d46aeca2Sriastradh 
189d46aeca2Sriastradh 	if (dev->agp == NULL)
190d46aeca2Sriastradh 		return -EINVAL;
191d46aeca2Sriastradh 	return dev->agp->hooks->agph_release(dev);
192d46aeca2Sriastradh }
193d46aeca2Sriastradh 
194d46aeca2Sriastradh int
drm_agp_enable(struct drm_device * dev,struct drm_agp_mode mode)195d46aeca2Sriastradh drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode)
196d46aeca2Sriastradh {
197d46aeca2Sriastradh 
198d46aeca2Sriastradh 	if (dev->agp == NULL)
199d46aeca2Sriastradh 		return -EINVAL;
200d46aeca2Sriastradh 	return dev->agp->hooks->agph_enable(dev, mode);
201d46aeca2Sriastradh }
202d46aeca2Sriastradh 
203d46aeca2Sriastradh int
drm_agp_info(struct drm_device * dev,struct drm_agp_info * info)204d46aeca2Sriastradh drm_agp_info(struct drm_device *dev, struct drm_agp_info *info)
205d46aeca2Sriastradh {
206d46aeca2Sriastradh 
207d46aeca2Sriastradh 	if (dev->agp == NULL)
208d46aeca2Sriastradh 		return -EINVAL;
209d46aeca2Sriastradh 	return dev->agp->hooks->agph_info(dev, info);
210d46aeca2Sriastradh }
211d46aeca2Sriastradh 
212d46aeca2Sriastradh int
drm_agp_alloc(struct drm_device * dev,struct drm_agp_buffer * request)213d46aeca2Sriastradh drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
214d46aeca2Sriastradh {
215d46aeca2Sriastradh 
216d46aeca2Sriastradh 	if (dev->agp == NULL)
217d46aeca2Sriastradh 		return -EINVAL;
218d46aeca2Sriastradh 	return dev->agp->hooks->agph_alloc(dev, request);
219d46aeca2Sriastradh }
220d46aeca2Sriastradh 
221d46aeca2Sriastradh int
drm_agp_free(struct drm_device * dev,struct drm_agp_buffer * request)222d46aeca2Sriastradh drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request)
223d46aeca2Sriastradh {
224d46aeca2Sriastradh 
225d46aeca2Sriastradh 	if (dev->agp == NULL)
226d46aeca2Sriastradh 		return -EINVAL;
227d46aeca2Sriastradh 	return dev->agp->hooks->agph_free(dev, request);
228d46aeca2Sriastradh }
229d46aeca2Sriastradh 
230d46aeca2Sriastradh int
drm_agp_bind(struct drm_device * dev,struct drm_agp_binding * request)231d46aeca2Sriastradh drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request)
232d46aeca2Sriastradh {
233d46aeca2Sriastradh 
234d46aeca2Sriastradh 	if (dev->agp == NULL)
235d46aeca2Sriastradh 		return -EINVAL;
236d46aeca2Sriastradh 	return dev->agp->hooks->agph_bind(dev, request);
237d46aeca2Sriastradh }
238d46aeca2Sriastradh 
239d46aeca2Sriastradh int
drm_agp_unbind(struct drm_device * dev,struct drm_agp_binding * request)240d46aeca2Sriastradh drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request)
241d46aeca2Sriastradh {
242d46aeca2Sriastradh 
243d46aeca2Sriastradh 	if (dev->agp == NULL)
244d46aeca2Sriastradh 		return -EINVAL;
245d46aeca2Sriastradh 	return dev->agp->hooks->agph_unbind(dev, request);
246d46aeca2Sriastradh }
247d46aeca2Sriastradh 
248d46aeca2Sriastradh #define	DEFINE_AGP_HOOK_IOCTL(NAME, FIELD)				      \
249d46aeca2Sriastradh int									      \
250d46aeca2Sriastradh NAME(struct drm_device *dev, void *data, struct drm_file *file)		      \
251d46aeca2Sriastradh {									      \
252d46aeca2Sriastradh 									      \
253d46aeca2Sriastradh 	if (dev->agp == NULL)						      \
254d46aeca2Sriastradh 		return -ENODEV;						      \
255d46aeca2Sriastradh 	return dev->agp->hooks->FIELD(dev, data, file);			      \
256d46aeca2Sriastradh }
257d46aeca2Sriastradh 
DEFINE_AGP_HOOK_IOCTL(drm_agp_acquire_ioctl,agph_acquire_ioctl)258d46aeca2Sriastradh DEFINE_AGP_HOOK_IOCTL(drm_agp_acquire_ioctl, agph_acquire_ioctl)
259d46aeca2Sriastradh DEFINE_AGP_HOOK_IOCTL(drm_agp_release_ioctl, agph_release_ioctl)
260d46aeca2Sriastradh DEFINE_AGP_HOOK_IOCTL(drm_agp_enable_ioctl, agph_enable_ioctl)
261d46aeca2Sriastradh DEFINE_AGP_HOOK_IOCTL(drm_agp_info_ioctl, agph_info_ioctl)
262d46aeca2Sriastradh DEFINE_AGP_HOOK_IOCTL(drm_agp_alloc_ioctl, agph_alloc_ioctl)
263d46aeca2Sriastradh DEFINE_AGP_HOOK_IOCTL(drm_agp_free_ioctl, agph_free_ioctl)
264d46aeca2Sriastradh DEFINE_AGP_HOOK_IOCTL(drm_agp_bind_ioctl, agph_bind_ioctl)
265d46aeca2Sriastradh DEFINE_AGP_HOOK_IOCTL(drm_agp_unbind_ioctl, agph_unbind_ioctl)
266d46aeca2Sriastradh 
267d46aeca2Sriastradh void
268d46aeca2Sriastradh drm_agp_flush(void)
269d46aeca2Sriastradh {
270d46aeca2Sriastradh 	const struct drm_agp_hooks *hooks;
271d46aeca2Sriastradh 
272d46aeca2Sriastradh 	if ((hooks = drm_agp_hooks_acquire()) == NULL)
273d46aeca2Sriastradh 		return;
274d46aeca2Sriastradh 	hooks->agph_flush();
275d46aeca2Sriastradh 	drm_agp_hooks_release(hooks);
276d46aeca2Sriastradh }
277