Home | History | Annotate | Line # | Download | only in drm
      1  1.18  riastrad /*	$NetBSD: drm_irq.c,v 1.18 2021/12/19 12:05:08 riastradh Exp $	*/
      2   1.9  riastrad 
      3   1.9  riastrad /*
      4   1.9  riastrad  * drm_irq.c IRQ and vblank support
      5   1.1  riastrad  *
      6   1.1  riastrad  * \author Rickard E. (Rik) Faith <faith (at) valinux.com>
      7   1.1  riastrad  * \author Gareth Hughes <gareth (at) valinux.com>
      8  1.17  riastrad  *
      9  1.17  riastrad  * Permission is hereby granted, free of charge, to any person obtaining a
     10  1.17  riastrad  * copy of this software and associated documentation files (the "Software"),
     11  1.17  riastrad  * to deal in the Software without restriction, including without limitation
     12  1.17  riastrad  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     13  1.17  riastrad  * and/or sell copies of the Software, and to permit persons to whom the
     14  1.17  riastrad  * Software is furnished to do so, subject to the following conditions:
     15  1.17  riastrad  *
     16  1.17  riastrad  * The above copyright notice and this permission notice (including the next
     17  1.17  riastrad  * paragraph) shall be included in all copies or substantial portions of the
     18  1.17  riastrad  * Software.
     19  1.17  riastrad  *
     20  1.17  riastrad  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     21  1.17  riastrad  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     22  1.17  riastrad  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     23  1.17  riastrad  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     24  1.17  riastrad  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     25  1.17  riastrad  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     26  1.17  riastrad  * OTHER DEALINGS IN THE SOFTWARE.
     27   1.1  riastrad  */
     28   1.1  riastrad 
     29   1.1  riastrad /*
     30   1.1  riastrad  * Created: Fri Mar 19 14:30:16 1999 by faith (at) valinux.com
     31   1.1  riastrad  *
     32   1.1  riastrad  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
     33   1.1  riastrad  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
     34   1.1  riastrad  * All Rights Reserved.
     35   1.1  riastrad  *
     36   1.1  riastrad  * Permission is hereby granted, free of charge, to any person obtaining a
     37   1.1  riastrad  * copy of this software and associated documentation files (the "Software"),
     38   1.1  riastrad  * to deal in the Software without restriction, including without limitation
     39   1.1  riastrad  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     40   1.1  riastrad  * and/or sell copies of the Software, and to permit persons to whom the
     41   1.1  riastrad  * Software is furnished to do so, subject to the following conditions:
     42   1.1  riastrad  *
     43   1.1  riastrad  * The above copyright notice and this permission notice (including the next
     44   1.1  riastrad  * paragraph) shall be included in all copies or substantial portions of the
     45   1.1  riastrad  * Software.
     46   1.1  riastrad  *
     47   1.1  riastrad  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     48   1.1  riastrad  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     49   1.1  riastrad  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     50   1.1  riastrad  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     51   1.1  riastrad  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     52   1.1  riastrad  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     53   1.1  riastrad  * OTHER DEALINGS IN THE SOFTWARE.
     54   1.1  riastrad  */
     55   1.1  riastrad 
     56  1.17  riastrad 
     57   1.9  riastrad #include <sys/cdefs.h>
     58  1.18  riastrad __KERNEL_RCSID(0, "$NetBSD: drm_irq.c,v 1.18 2021/12/19 12:05:08 riastradh Exp $");
     59   1.9  riastrad 
     60  1.17  riastrad #include <linux/export.h>
     61  1.17  riastrad #include <linux/interrupt.h>	/* For task queue support */
     62  1.17  riastrad #include <linux/pci.h>
     63  1.17  riastrad #include <linux/vgaarb.h>
     64   1.1  riastrad 
     65  1.17  riastrad #include <drm/drm.h>
     66  1.17  riastrad #include <drm/drm_device.h>
     67  1.17  riastrad #include <drm/drm_drv.h>
     68  1.17  riastrad #include <drm/drm_irq.h>
     69  1.17  riastrad #include <drm/drm_print.h>
     70  1.17  riastrad #include <drm/drm_vblank.h>
     71   1.1  riastrad 
     72  1.17  riastrad #include "drm_internal.h"
     73   1.2  riastrad 
     74   1.2  riastrad #ifdef __NetBSD__		/* XXX hurk -- selnotify &c. */
     75   1.2  riastrad #include <sys/poll.h>
     76   1.2  riastrad #include <sys/select.h>
     77   1.2  riastrad #endif
     78   1.2  riastrad 
     79   1.1  riastrad 
     80   1.9  riastrad /**
     81  1.17  riastrad  * DOC: irq helpers
     82   1.9  riastrad  *
     83  1.17  riastrad  * The DRM core provides very simple support helpers to enable IRQ handling on a
     84  1.17  riastrad  * device through the drm_irq_install() and drm_irq_uninstall() functions. This
     85  1.17  riastrad  * only supports devices with a single interrupt on the main device stored in
     86  1.17  riastrad  * &drm_device.dev and set as the device paramter in drm_dev_alloc().
     87  1.17  riastrad  *
     88  1.17  riastrad  * These IRQ helpers are strictly optional. Drivers which roll their own only
     89  1.17  riastrad  * need to set &drm_device.irq_enabled to signal the DRM core that vblank
     90  1.17  riastrad  * interrupts are working. Since these helpers don't automatically clean up the
     91  1.17  riastrad  * requested interrupt like e.g. devm_request_irq() they're not really
     92  1.17  riastrad  * recommended.
     93   1.9  riastrad  */
     94   1.1  riastrad 
     95   1.1  riastrad /**
     96   1.9  riastrad  * drm_irq_install - install IRQ handler
     97   1.9  riastrad  * @dev: DRM device
     98   1.9  riastrad  * @irq: IRQ number to install the handler for
     99   1.9  riastrad  *
    100   1.9  riastrad  * Initializes the IRQ related data. Installs the handler, calling the driver
    101  1.17  riastrad  * &drm_driver.irq_preinstall and &drm_driver.irq_postinstall functions before
    102  1.17  riastrad  * and after the installation.
    103   1.1  riastrad  *
    104   1.9  riastrad  * This is the simplified helper interface provided for drivers with no special
    105   1.9  riastrad  * needs. Drivers which need to install interrupt handlers for multiple
    106  1.17  riastrad  * interrupts must instead set &drm_device.irq_enabled to signal the DRM core
    107   1.9  riastrad  * that vblank interrupts are available.
    108   1.1  riastrad  *
    109  1.17  riastrad  * @irq must match the interrupt number that would be passed to request_irq(),
    110  1.17  riastrad  * if called directly instead of using this helper function.
    111  1.17  riastrad  *
    112  1.17  riastrad  * &drm_driver.irq_handler is called to handle the registered interrupt.
    113  1.17  riastrad  *
    114   1.9  riastrad  * Returns:
    115   1.9  riastrad  * Zero on success or a negative error code on failure.
    116   1.1  riastrad  */
    117  1.11  riastrad #ifdef __NetBSD__
    118  1.11  riastrad int drm_irq_install(struct drm_device *dev)
    119  1.11  riastrad #else
    120   1.9  riastrad int drm_irq_install(struct drm_device *dev, int irq)
    121  1.11  riastrad #endif
    122   1.1  riastrad {
    123   1.1  riastrad 	int ret;
    124   1.1  riastrad 	unsigned long sh_flags = 0;
    125   1.1  riastrad 
    126  1.11  riastrad #ifndef __NetBSD__
    127   1.9  riastrad 	if (irq == 0)
    128   1.1  riastrad 		return -EINVAL;
    129  1.11  riastrad #endif
    130   1.1  riastrad 
    131   1.1  riastrad 	/* Driver must have been initialized */
    132   1.9  riastrad 	if (!dev->dev_private)
    133   1.1  riastrad 		return -EINVAL;
    134   1.1  riastrad 
    135   1.9  riastrad 	if (dev->irq_enabled)
    136   1.1  riastrad 		return -EBUSY;
    137   1.4  riastrad 	dev->irq_enabled = true;
    138   1.1  riastrad 
    139  1.11  riastrad #ifndef __NetBSD__
    140   1.9  riastrad 	DRM_DEBUG("irq=%d\n", irq);
    141  1.11  riastrad #endif
    142   1.1  riastrad 
    143   1.1  riastrad 	/* Before installing handler */
    144   1.1  riastrad 	if (dev->driver->irq_preinstall)
    145   1.1  riastrad 		dev->driver->irq_preinstall(dev);
    146   1.1  riastrad 
    147  1.17  riastrad 	/* PCI devices require shared interrupts. */
    148  1.17  riastrad 	if (dev->pdev)
    149   1.1  riastrad 		sh_flags = IRQF_SHARED;
    150   1.1  riastrad 
    151   1.2  riastrad #ifdef __NetBSD__
    152  1.11  riastrad 	ret = (*dev->driver->request_irq)(dev, sh_flags);
    153   1.2  riastrad #else
    154   1.9  riastrad 	ret = request_irq(irq, dev->driver->irq_handler,
    155   1.9  riastrad 			  sh_flags, dev->driver->name, dev);
    156   1.2  riastrad #endif
    157   1.1  riastrad 
    158   1.1  riastrad 	if (ret < 0) {
    159   1.4  riastrad 		dev->irq_enabled = false;
    160   1.1  riastrad 		return ret;
    161   1.1  riastrad 	}
    162   1.1  riastrad 
    163   1.1  riastrad 	/* After installing handler */
    164   1.1  riastrad 	if (dev->driver->irq_postinstall)
    165   1.1  riastrad 		ret = dev->driver->irq_postinstall(dev);
    166   1.1  riastrad 
    167   1.1  riastrad 	if (ret < 0) {
    168   1.4  riastrad 		dev->irq_enabled = false;
    169  1.17  riastrad 		if (drm_core_check_feature(dev, DRIVER_LEGACY))
    170   1.1  riastrad 			vga_client_register(dev->pdev, NULL, NULL, NULL);
    171   1.2  riastrad #ifdef __NetBSD__
    172  1.11  riastrad 		(*dev->driver->free_irq)(dev);
    173   1.2  riastrad #else
    174   1.9  riastrad 		free_irq(irq, dev);
    175   1.2  riastrad #endif
    176   1.9  riastrad 	} else {
    177  1.11  riastrad #ifndef __NetBSD__
    178   1.9  riastrad 		dev->irq = irq;
    179  1.11  riastrad #endif
    180   1.1  riastrad 	}
    181   1.1  riastrad 
    182   1.1  riastrad 	return ret;
    183   1.1  riastrad }
    184   1.1  riastrad EXPORT_SYMBOL(drm_irq_install);
    185   1.1  riastrad 
    186   1.1  riastrad /**
    187   1.9  riastrad  * drm_irq_uninstall - uninstall the IRQ handler
    188   1.9  riastrad  * @dev: DRM device
    189   1.1  riastrad  *
    190  1.17  riastrad  * Calls the driver's &drm_driver.irq_uninstall function and unregisters the IRQ
    191  1.17  riastrad  * handler.  This should only be called by drivers which used drm_irq_install()
    192  1.17  riastrad  * to set up their interrupt handler. Other drivers must only reset
    193  1.17  riastrad  * &drm_device.irq_enabled to false.
    194   1.9  riastrad  *
    195   1.9  riastrad  * Note that for kernel modesetting drivers it is a bug if this function fails.
    196   1.9  riastrad  * The sanity checks are only to catch buggy user modesetting drivers which call
    197   1.9  riastrad  * the same function through an ioctl.
    198   1.1  riastrad  *
    199   1.9  riastrad  * Returns:
    200   1.9  riastrad  * Zero on success or a negative error code on failure.
    201   1.1  riastrad  */
    202   1.1  riastrad int drm_irq_uninstall(struct drm_device *dev)
    203   1.1  riastrad {
    204   1.1  riastrad 	unsigned long irqflags;
    205   1.4  riastrad 	bool irq_enabled;
    206   1.4  riastrad 	int i;
    207   1.1  riastrad 
    208   1.1  riastrad 	irq_enabled = dev->irq_enabled;
    209   1.4  riastrad 	dev->irq_enabled = false;
    210   1.1  riastrad 
    211   1.1  riastrad 	/*
    212   1.9  riastrad 	 * Wake up any waiters so they don't hang. This is just to paper over
    213  1.17  riastrad 	 * issues for UMS drivers which aren't in full control of their
    214   1.9  riastrad 	 * vblank/irq handling. KMS drivers must ensure that vblanks are all
    215   1.9  riastrad 	 * disabled when uninstalling the irq handler.
    216   1.1  riastrad 	 */
    217   1.1  riastrad 	if (dev->num_crtcs) {
    218  1.18  riastrad 		spin_lock_irqsave(&dev->event_lock, irqflags);
    219   1.1  riastrad 		for (i = 0; i < dev->num_crtcs; i++) {
    220   1.9  riastrad 			struct drm_vblank_crtc *vblank = &dev->vblank[i];
    221   1.9  riastrad 
    222   1.9  riastrad 			if (!vblank->enabled)
    223   1.9  riastrad 				continue;
    224   1.9  riastrad 
    225   1.9  riastrad 			WARN_ON(drm_core_check_feature(dev, DRIVER_MODESET));
    226   1.9  riastrad 
    227  1.17  riastrad 			drm_vblank_disable_and_save(dev, i);
    228   1.2  riastrad #ifdef __NetBSD__
    229  1.18  riastrad 			DRM_SPIN_WAKEUP_ONE(&vblank->queue,
    230  1.18  riastrad 			    &dev->event_lock);
    231   1.2  riastrad #else
    232   1.9  riastrad 			wake_up(&vblank->queue);
    233   1.2  riastrad #endif
    234   1.1  riastrad 		}
    235  1.18  riastrad 		spin_unlock_irqrestore(&dev->event_lock, irqflags);
    236   1.1  riastrad 	}
    237   1.1  riastrad 
    238   1.1  riastrad 	if (!irq_enabled)
    239   1.1  riastrad 		return -EINVAL;
    240   1.1  riastrad 
    241   1.9  riastrad 	DRM_DEBUG("irq=%d\n", dev->irq);
    242   1.1  riastrad 
    243  1.17  riastrad 	if (drm_core_check_feature(dev, DRIVER_LEGACY))
    244   1.1  riastrad 		vga_client_register(dev->pdev, NULL, NULL, NULL);
    245   1.1  riastrad 
    246   1.1  riastrad 	if (dev->driver->irq_uninstall)
    247   1.1  riastrad 		dev->driver->irq_uninstall(dev);
    248   1.1  riastrad 
    249   1.2  riastrad #ifdef __NetBSD__
    250  1.11  riastrad 	(*dev->driver->free_irq)(dev);
    251   1.2  riastrad #else
    252   1.9  riastrad 	free_irq(dev->irq, dev);
    253   1.2  riastrad #endif
    254   1.1  riastrad 
    255   1.1  riastrad 	return 0;
    256   1.1  riastrad }
    257   1.1  riastrad EXPORT_SYMBOL(drm_irq_uninstall);
    258   1.1  riastrad 
    259  1.17  riastrad #if IS_ENABLED(CONFIG_DRM_LEGACY)
    260  1.17  riastrad int drm_legacy_irq_control(struct drm_device *dev, void *data,
    261  1.17  riastrad 			   struct drm_file *file_priv)
    262   1.1  riastrad {
    263   1.1  riastrad 	struct drm_control *ctl = data;
    264   1.9  riastrad 	int ret = 0, irq;
    265   1.1  riastrad 
    266   1.1  riastrad 	/* if we haven't irq we fallback for compatibility reasons -
    267   1.1  riastrad 	 * this used to be a separate function in drm_dma.h
    268   1.1  riastrad 	 */
    269   1.1  riastrad 
    270   1.9  riastrad 	if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
    271   1.9  riastrad 		return 0;
    272  1.17  riastrad 	if (!drm_core_check_feature(dev, DRIVER_LEGACY))
    273   1.9  riastrad 		return 0;
    274  1.17  riastrad 	/* UMS was only ever supported on pci devices. */
    275   1.9  riastrad 	if (WARN_ON(!dev->pdev))
    276   1.9  riastrad 		return -EINVAL;
    277   1.1  riastrad 
    278   1.1  riastrad 	switch (ctl->func) {
    279   1.1  riastrad 	case DRM_INST_HANDLER:
    280  1.11  riastrad #ifdef __NetBSD__
    281  1.11  riastrad 		irq = ctl->irq;
    282  1.11  riastrad #else
    283   1.9  riastrad 		irq = dev->pdev->irq;
    284  1.11  riastrad #endif
    285   1.9  riastrad 
    286   1.1  riastrad 		if (dev->if_version < DRM_IF_VERSION(1, 2) &&
    287   1.9  riastrad 		    ctl->irq != irq)
    288   1.1  riastrad 			return -EINVAL;
    289   1.9  riastrad 		mutex_lock(&dev->struct_mutex);
    290  1.11  riastrad #ifdef __NetBSD__
    291  1.11  riastrad 		ret = drm_irq_install(dev);
    292  1.11  riastrad #else
    293   1.9  riastrad 		ret = drm_irq_install(dev, irq);
    294  1.11  riastrad #endif
    295   1.9  riastrad 		mutex_unlock(&dev->struct_mutex);
    296   1.9  riastrad 
    297   1.9  riastrad 		return ret;
    298   1.1  riastrad 	case DRM_UNINST_HANDLER:
    299   1.9  riastrad 		mutex_lock(&dev->struct_mutex);
    300   1.9  riastrad 		ret = drm_irq_uninstall(dev);
    301   1.9  riastrad 		mutex_unlock(&dev->struct_mutex);
    302   1.9  riastrad 
    303   1.9  riastrad 		return ret;
    304   1.1  riastrad 	default:
    305   1.1  riastrad 		return -EINVAL;
    306   1.1  riastrad 	}
    307   1.1  riastrad }
    308  1.17  riastrad #endif
    309