1 /* 2 * drm_irq.c -- IRQ IOCTL and function support 3 * Created: Fri Oct 18 2003 by anholt@FreeBSD.org 4 */ 5 /* 6 * Copyright 2003 Eric Anholt 7 * All Rights Reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice (including the next 17 * paragraph) shall be included in all copies or substantial portions of the 18 * Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 * ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 24 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 * Authors: 28 * Eric Anholt <anholt@FreeBSD.org> 29 * 30 */ 31 32 /* 33 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 34 * Use is subject to license terms. 35 */ 36 37 #pragma ident "%Z%%M% %I% %E% SMI" 38 39 #include "drmP.h" 40 #include "drm.h" 41 42 /*ARGSUSED*/ 43 int 44 drm_irq_by_busid(DRM_IOCTL_ARGS) 45 { 46 DRM_DEVICE; 47 drm_irq_busid_t irq; 48 49 DRM_COPY_FROM_USER_IOCTL(irq, (drm_irq_busid_t *)data, sizeof (irq)); 50 51 if ((irq.busnum >> 8) != dev->pci_domain || 52 (irq.busnum & 0xff) != dev->pci_bus || 53 irq.devnum != dev->pci_slot || 54 irq.funcnum != dev->pci_func) 55 return (DRM_ERR(EINVAL)); 56 57 irq.irq = dev->irq; 58 59 DRM_DEBUG("%x:%x:%x => IRQ %x\n", 60 irq.busnum, irq.devnum, irq.funcnum, irq.irq); 61 62 DRM_COPY_TO_USER_IOCTL((drm_irq_busid_t *)data, irq, sizeof (irq)); 63 64 return (0); 65 } 66 67 /*ARGSUSED*/ 68 static int 69 drm_install_irq_handle(drm_softstate_t *dev) 70 { 71 dev_info_t *dip = NULL; 72 73 dip = dev->dip; 74 if (dip == NULL) { 75 DRM_ERROR("drm_install_irq_handle: cannot get vgatext's dip"); 76 return (DDI_FAILURE); 77 } 78 79 if (ddi_intr_hilevel(dip, 0) != 0) { 80 DRM_ERROR("drm_install_irq_handle: " 81 "high-level interrupts are not supported"); 82 return (DDI_FAILURE); 83 } 84 85 if (ddi_get_iblock_cookie(dip, (uint_t)0, 86 &dev->intr_block) != DDI_SUCCESS) { 87 DRM_ERROR("drm_install_irq_handle: cannot get iblock cookie"); 88 return (DDI_FAILURE); 89 } 90 91 mutex_init(&dev->irq_lock, NULL, MUTEX_DRIVER, (void *)dev->intr_block); 92 93 /* setup the interrupt handler */ 94 95 if (ddi_add_intr(dip, 0, &dev->intr_block, 96 (ddi_idevice_cookie_t *)NULL, dev->irq_handler, 97 (caddr_t)dev) != DDI_SUCCESS) { 98 DRM_ERROR("drm_install_irq_handle: ddi_add_intr failed"); 99 return (DDI_FAILURE); 100 } 101 DRM_DEBUG("drm_install_irq_handle: add the intr handle successful"); 102 103 104 return (DDI_SUCCESS); 105 } 106 107 /*ARGSUSED*/ 108 int 109 drm_irq_install(drm_softstate_t *dev) 110 { 111 int ret; 112 113 if (dev->dev_private == NULL) { 114 DRM_ERROR("drm_irq_install: dev_private is NULL"); 115 return (DRM_ERR(EINVAL)); 116 } 117 118 if (dev->irq_enabled) { 119 DRM_ERROR("drm_irq_install: irq already enabled"); 120 return (DRM_ERR(EBUSY)); 121 } 122 123 dev->context_flag = 0; 124 125 mutex_init(&dev->tasklet_lock, NULL, MUTEX_DRIVER, NULL); 126 127 /* before installing handler */ 128 dev->irq_preinstall(dev); 129 130 /* install handler */ 131 ret = drm_install_irq_handle(dev); 132 if (ret != DDI_SUCCESS) { 133 DRM_ERROR("drm_irq_install: drm_install_irq_handle failed"); 134 return (ret); 135 } 136 137 /* after installing handler */ 138 dev->irq_postinstall(dev); 139 140 dev->irq_enabled = 1; 141 142 return (DDI_SUCCESS); 143 } 144 145 static void 146 drm_uninstall_irq_handle(drm_device_t *dev) 147 { 148 ASSERT(dev->dip); 149 ddi_remove_intr(dev->dip, 0, dev->intr_block); 150 } 151 152 153 /*ARGSUSED*/ 154 int 155 drm_irq_uninstall(drm_softstate_t *dev) 156 { 157 if (!dev->irq_enabled) { 158 return (DRM_ERR(EINVAL)); 159 } 160 161 dev->irq_enabled = 0; 162 163 dev->irq_uninstall(dev); 164 165 drm_uninstall_irq_handle(dev); 166 167 dev->locked_tasklet_func = NULL; 168 169 mutex_destroy(&dev->tasklet_lock); 170 return (DDI_SUCCESS); 171 } 172 173 /*ARGSUSED*/ 174 int 175 drm_control(DRM_IOCTL_ARGS) 176 { 177 DRM_DEVICE; 178 drm_control_t ctl; 179 int err; 180 181 DRM_DEBUG("drm_control: install irq = %x\n", dev->irq); 182 DRM_COPY_FROM_USER_IOCTL(ctl, (drm_control_t *)data, sizeof (ctl)); 183 184 switch (ctl.func) { 185 case DRM_INST_HANDLER: 186 /* 187 * Handle drivers whose DRM used to require IRQ setup but the 188 * no longer does. 189 */ 190 return (drm_irq_install(dev)); 191 case DRM_UNINST_HANDLER: 192 err = drm_irq_uninstall(dev); 193 return (err); 194 default: 195 return (DRM_ERR(EINVAL)); 196 } 197 } 198 199 /*ARGSUSED*/ 200 int 201 drm_wait_vblank(DRM_IOCTL_ARGS) 202 { 203 return (0); 204 } 205 206 /*ARGSUSED*/ 207 void 208 drm_vbl_send_signals(drm_device_t *dev) 209 { 210 } 211 212 void 213 drm_locked_tasklet(drm_device_t *dev, void (*func)(drm_device_t *)) 214 { 215 mutex_enter(&dev->tasklet_lock); 216 217 if (dev->locked_tasklet_func) { 218 mutex_exit(&dev->tasklet_lock); 219 return; 220 } 221 222 dev->locked_tasklet_func = func; 223 224 mutex_exit(&dev->tasklet_lock); 225 } 226