drm_irq.c revision 145132
1/* drm_dma.c -- DMA IOCTL and function support 2 * Created: Fri Oct 18 2003 by anholt@FreeBSD.org 3 */ 4/*- 5 * Copyright 2003 Eric Anholt 6 * All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the next 16 * paragraph) shall be included in all copies or substantial portions of the 17 * Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 23 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 * Authors: 27 * Eric Anholt <anholt@FreeBSD.org> 28 * 29 * $FreeBSD: head/sys/dev/drm/drm_irq.c 145132 2005-04-16 03:44:47Z anholt $ 30 */ 31 32#include "dev/drm/drmP.h" 33#include "dev/drm/drm.h" 34 35int drm_irq_by_busid(DRM_IOCTL_ARGS) 36{ 37 DRM_DEVICE; 38 drm_irq_busid_t irq; 39 40 DRM_COPY_FROM_USER_IOCTL(irq, (drm_irq_busid_t *)data, sizeof(irq)); 41 42 if ((irq.busnum >> 8) != dev->pci_domain || 43 (irq.busnum & 0xff) != dev->pci_bus || 44 irq.devnum != dev->pci_slot || 45 irq.funcnum != dev->pci_func) 46 return EINVAL; 47 48 irq.irq = dev->irq; 49 50 DRM_DEBUG("%d:%d:%d => IRQ %d\n", 51 irq.busnum, irq.devnum, irq.funcnum, irq.irq); 52 53 DRM_COPY_TO_USER_IOCTL( (drm_irq_busid_t *)data, irq, sizeof(irq) ); 54 55 return 0; 56} 57 58#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 59static irqreturn_t 60drm_irq_handler_wrap(DRM_IRQ_ARGS) 61{ 62 drm_device_t *dev = (drm_device_t *)arg; 63 64 DRM_SPINLOCK(&dev->irq_lock); 65 dev->irq_handler(arg); 66 DRM_SPINUNLOCK(&dev->irq_lock); 67} 68#endif 69 70int drm_irq_install(drm_device_t *dev) 71{ 72 int retcode; 73 74 if (dev->irq == 0 || dev->dev_private == NULL) 75 return DRM_ERR(EINVAL); 76 77 DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq ); 78 79 DRM_LOCK(); 80 if (dev->irq_enabled) { 81 DRM_UNLOCK(); 82 return DRM_ERR(EBUSY); 83 } 84 dev->irq_enabled = 1; 85 86 dev->context_flag = 0; 87 88 DRM_SPININIT(dev->irq_lock, "DRM IRQ lock"); 89 90 /* Before installing handler */ 91 dev->irq_preinstall(dev); 92 DRM_UNLOCK(); 93 94 /* Install handler */ 95#ifdef __FreeBSD__ 96 dev->irqrid = 0; 97 dev->irqr = bus_alloc_resource_any(dev->device, SYS_RES_IRQ, 98 &dev->irqrid, RF_SHAREABLE); 99 if (!dev->irqr) { 100 retcode = ENOENT; 101 goto err; 102 } 103#if __FreeBSD_version < 500000 104 retcode = bus_setup_intr(dev->device, dev->irqr, INTR_TYPE_TTY, 105 dev->irq_handler, dev, &dev->irqh); 106#else 107 retcode = bus_setup_intr(dev->device, dev->irqr, INTR_TYPE_TTY | INTR_MPSAFE, 108 drm_irq_handler_wrap, dev, &dev->irqh); 109#endif 110 if (retcode != 0) 111 goto err; 112#elif defined(__NetBSD__) || defined(__OpenBSD__) 113 if (pci_intr_map(&dev->pa, &dev->ih) != 0) { 114 retcode = ENOENT; 115 goto err; 116 } 117 dev->irqh = pci_intr_establish(&dev->pa.pa_pc, dev->ih, IPL_TTY, 118 (irqreturn_t (*)(DRM_IRQ_ARGS))dev->irq_handler, dev); 119 if (!dev->irqh) { 120 retcode = ENOENT; 121 goto err; 122 } 123#endif 124 125 /* After installing handler */ 126 DRM_LOCK(); 127 dev->irq_postinstall(dev); 128 DRM_UNLOCK(); 129 130 return 0; 131err: 132 DRM_LOCK(); 133 dev->irq_enabled = 0; 134#ifdef ___FreeBSD__ 135 if (dev->irqrid != 0) { 136 bus_release_resource(dev->device, SYS_RES_IRQ, dev->irqrid, 137 dev->irqr); 138 dev->irqrid = 0; 139 } 140#endif 141 DRM_SPINUNINIT(dev->irq_lock); 142 DRM_UNLOCK(); 143 return retcode; 144} 145 146int drm_irq_uninstall(drm_device_t *dev) 147{ 148 int irqrid; 149 150 if (!dev->irq_enabled) 151 return DRM_ERR(EINVAL); 152 153 dev->irq_enabled = 0; 154 irqrid = dev->irqrid; 155 dev->irqrid = 0; 156 157 DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq ); 158 159 dev->irq_uninstall(dev); 160 161#ifdef __FreeBSD__ 162 DRM_UNLOCK(); 163 bus_teardown_intr(dev->device, dev->irqr, dev->irqh); 164 bus_release_resource(dev->device, SYS_RES_IRQ, irqrid, dev->irqr); 165 DRM_LOCK(); 166#elif defined(__NetBSD__) || defined(__OpenBSD__) 167 pci_intr_disestablish(&dev->pa.pa_pc, dev->irqh); 168#endif 169 DRM_SPINUNINIT(dev->irq_lock); 170 171 return 0; 172} 173 174int drm_control(DRM_IOCTL_ARGS) 175{ 176 DRM_DEVICE; 177 drm_control_t ctl; 178 int err; 179 180 DRM_COPY_FROM_USER_IOCTL( ctl, (drm_control_t *) data, sizeof(ctl) ); 181 182 switch ( ctl.func ) { 183 case DRM_INST_HANDLER: 184 /* Handle drivers whose DRM used to require IRQ setup but the 185 * no longer does. 186 */ 187 if (!dev->use_irq) 188 return 0; 189 if (dev->if_version < DRM_IF_VERSION(1, 2) && 190 ctl.irq != dev->irq) 191 return DRM_ERR(EINVAL); 192 return drm_irq_install(dev); 193 case DRM_UNINST_HANDLER: 194 if (!dev->use_irq) 195 return 0; 196 DRM_LOCK(); 197 err = drm_irq_uninstall(dev); 198 DRM_UNLOCK(); 199 return err; 200 default: 201 return DRM_ERR(EINVAL); 202 } 203} 204 205int drm_wait_vblank(DRM_IOCTL_ARGS) 206{ 207 DRM_DEVICE; 208 drm_wait_vblank_t vblwait; 209 struct timeval now; 210 int ret; 211 212 if (!dev->irq_enabled) 213 return DRM_ERR(EINVAL); 214 215 DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data, 216 sizeof(vblwait) ); 217 218 if (vblwait.request.type & _DRM_VBLANK_RELATIVE) { 219 vblwait.request.sequence += atomic_read(&dev->vbl_received); 220 vblwait.request.type &= ~_DRM_VBLANK_RELATIVE; 221 } 222 223 flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK; 224 if (flags & _DRM_VBLANK_SIGNAL) { 225#if 0 /* disabled */ 226 drm_vbl_sig_t *vbl_sig = malloc(sizeof(drm_vbl_sig_t), M_DRM, 227 M_NOWAIT | M_ZERO); 228 if (vbl_sig == NULL) 229 return ENOMEM; 230 231 vbl_sig->sequence = vblwait.request.sequence; 232 vbl_sig->signo = vblwait.request.signal; 233 vbl_sig->pid = DRM_CURRENTPID; 234 235 vblwait.reply.sequence = atomic_read(&dev->vbl_received); 236 237 DRM_SPINLOCK(&dev->irq_lock); 238 TAILQ_INSERT_HEAD(&dev->vbl_sig_list, vbl_sig, link); 239 DRM_SPINUNLOCK(&dev->irq_lock); 240 ret = 0; 241#endif 242 ret = EINVAL; 243 } else { 244 DRM_LOCK(); 245 ret = dev->vblank_wait(dev, &vblwait.request.sequence); 246 DRM_UNLOCK(); 247 248 microtime(&now); 249 vblwait.reply.tval_sec = now.tv_sec; 250 vblwait.reply.tval_usec = now.tv_usec; 251 } 252 253 DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait, 254 sizeof(vblwait) ); 255 256 return ret; 257} 258 259void drm_vbl_send_signals(drm_device_t *dev) 260{ 261} 262 263#if 0 /* disabled */ 264void drm_vbl_send_signals( drm_device_t *dev ) 265{ 266 drm_vbl_sig_t *vbl_sig; 267 unsigned int vbl_seq = atomic_read( &dev->vbl_received ); 268 struct proc *p; 269 270 vbl_sig = TAILQ_FIRST(&dev->vbl_sig_list); 271 while (vbl_sig != NULL) { 272 drm_vbl_sig_t *next = TAILQ_NEXT(vbl_sig, link); 273 274 if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) { 275 p = pfind(vbl_sig->pid); 276 if (p != NULL) 277 psignal(p, vbl_sig->signo); 278 279 TAILQ_REMOVE(&dev->vbl_sig_list, vbl_sig, link); 280 DRM_FREE(vbl_sig,sizeof(*vbl_sig)); 281 } 282 vbl_sig = next; 283 } 284} 285#endif 286