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