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