1/* 2 * Copyright (C) 2006 Ben Skeggs. 3 * 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining 7 * a copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sublicense, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial 16 * portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 */ 27 28/* 29 * Authors: 30 * Ben Skeggs <darktama@iinet.net.au> 31 */ 32 33#include "drmP.h" 34#include "drm.h" 35#include "nouveau_drm.h" 36#include "nouveau_drv.h" 37#include "nouveau_reg.h" 38#include "nouveau_ramht.h" 39#include "nouveau_util.h" 40 41void 42nouveau_irq_preinstall(struct drm_device *dev) 43{ 44 struct drm_nouveau_private *dev_priv = dev->dev_private; 45 46 /* Master disable */ 47 nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); 48 49 INIT_LIST_HEAD(&dev_priv->vbl_waiting); 50} 51 52int 53nouveau_irq_postinstall(struct drm_device *dev) 54{ 55 struct drm_nouveau_private *dev_priv = dev->dev_private; 56 57 /* Master enable */ 58 nv_wr32(dev, NV03_PMC_INTR_EN_0, NV_PMC_INTR_EN_0_MASTER_ENABLE); 59 if (dev_priv->msi_enabled) 60 nv_wr08(dev, 0x00088068, 0xff); 61 62 return 0; 63} 64 65void 66nouveau_irq_uninstall(struct drm_device *dev) 67{ 68 /* Master disable */ 69 nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); 70} 71 72irqreturn_t 73nouveau_irq_handler(DRM_IRQ_ARGS) 74{ 75 struct drm_device *dev = (struct drm_device *)arg; 76 struct drm_nouveau_private *dev_priv = dev->dev_private; 77 unsigned long flags; 78 u32 stat; 79 int i; 80 81 stat = nv_rd32(dev, NV03_PMC_INTR_0); 82 if (stat == 0 || stat == ~0) 83 return IRQ_NONE; 84 85 spin_lock_irqsave(&dev_priv->context_switch_lock, flags); 86 for (i = 0; i < 32 && stat; i++) { 87 if (!(stat & (1 << i)) || !dev_priv->irq_handler[i]) 88 continue; 89 90 dev_priv->irq_handler[i](dev); 91 stat &= ~(1 << i); 92 } 93 94 if (dev_priv->msi_enabled) 95 nv_wr08(dev, 0x00088068, 0xff); 96 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); 97 98 if (stat && nouveau_ratelimit()) 99 NV_ERROR(dev, "PMC - unhandled INTR 0x%08x\n", stat); 100 return IRQ_HANDLED; 101} 102 103int 104nouveau_irq_init(struct drm_device *dev) 105{ 106 struct drm_nouveau_private *dev_priv = dev->dev_private; 107 int ret; 108 109 if (nouveau_msi != 0 && dev_priv->card_type >= NV_50) { 110 ret = pci_enable_msi(dev->pdev); 111 if (ret == 0) { 112 NV_INFO(dev, "enabled MSI\n"); 113 dev_priv->msi_enabled = true; 114 } 115 } 116 117 return drm_irq_install(dev); 118} 119 120void 121nouveau_irq_fini(struct drm_device *dev) 122{ 123 struct drm_nouveau_private *dev_priv = dev->dev_private; 124 125 drm_irq_uninstall(dev); 126 if (dev_priv->msi_enabled) 127 pci_disable_msi(dev->pdev); 128} 129 130void 131nouveau_irq_register(struct drm_device *dev, int status_bit, 132 void (*handler)(struct drm_device *)) 133{ 134 struct drm_nouveau_private *dev_priv = dev->dev_private; 135 unsigned long flags; 136 137 spin_lock_irqsave(&dev_priv->context_switch_lock, flags); 138 dev_priv->irq_handler[status_bit] = handler; 139 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); 140} 141 142void 143nouveau_irq_unregister(struct drm_device *dev, int status_bit) 144{ 145 struct drm_nouveau_private *dev_priv = dev->dev_private; 146 unsigned long flags; 147 148 spin_lock_irqsave(&dev_priv->context_switch_lock, flags); 149 dev_priv->irq_handler[status_bit] = NULL; 150 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); 151} 152