Commit | Line | Data |
---|---|---|
6ee73861 BS |
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 | ||
760285e7 DH |
33 | #include <drm/drmP.h> |
34 | #include <drm/nouveau_drm.h> | |
6ee73861 BS |
35 | #include "nouveau_drv.h" |
36 | #include "nouveau_reg.h" | |
a8eaebc6 | 37 | #include "nouveau_ramht.h" |
d7facf9d | 38 | #include "nouveau_util.h" |
6ee73861 | 39 | |
6ee73861 BS |
40 | void |
41 | nouveau_irq_preinstall(struct drm_device *dev) | |
42 | { | |
6ee73861 BS |
43 | /* Master disable */ |
44 | nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); | |
6ee73861 BS |
45 | } |
46 | ||
47 | int | |
48 | nouveau_irq_postinstall(struct drm_device *dev) | |
49 | { | |
35fa2f2a BS |
50 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
51 | ||
6ee73861 BS |
52 | /* Master enable */ |
53 | nv_wr32(dev, NV03_PMC_INTR_EN_0, NV_PMC_INTR_EN_0_MASTER_ENABLE); | |
35fa2f2a BS |
54 | if (dev_priv->msi_enabled) |
55 | nv_wr08(dev, 0x00088068, 0xff); | |
56 | ||
6ee73861 BS |
57 | return 0; |
58 | } | |
59 | ||
60 | void | |
61 | nouveau_irq_uninstall(struct drm_device *dev) | |
62 | { | |
63 | /* Master disable */ | |
64 | nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); | |
65 | } | |
66 | ||
6ee73861 BS |
67 | irqreturn_t |
68 | nouveau_irq_handler(DRM_IRQ_ARGS) | |
69 | { | |
70 | struct drm_device *dev = (struct drm_device *)arg; | |
71 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
ff9e5279 | 72 | unsigned long flags; |
274fec93 | 73 | u32 stat; |
8f8a5448 | 74 | int i; |
6ee73861 | 75 | |
274fec93 | 76 | stat = nv_rd32(dev, NV03_PMC_INTR_0); |
9717f3d9 | 77 | if (stat == 0 || stat == ~0) |
6ee73861 BS |
78 | return IRQ_NONE; |
79 | ||
ff9e5279 | 80 | spin_lock_irqsave(&dev_priv->context_switch_lock, flags); |
274fec93 BS |
81 | for (i = 0; i < 32 && stat; i++) { |
82 | if (!(stat & (1 << i)) || !dev_priv->irq_handler[i]) | |
8f8a5448 BS |
83 | continue; |
84 | ||
85 | dev_priv->irq_handler[i](dev); | |
274fec93 | 86 | stat &= ~(1 << i); |
8f8a5448 BS |
87 | } |
88 | ||
35fa2f2a BS |
89 | if (dev_priv->msi_enabled) |
90 | nv_wr08(dev, 0x00088068, 0xff); | |
274fec93 | 91 | spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); |
35fa2f2a | 92 | |
274fec93 BS |
93 | if (stat && nouveau_ratelimit()) |
94 | NV_ERROR(dev, "PMC - unhandled INTR 0x%08x\n", stat); | |
6ee73861 BS |
95 | return IRQ_HANDLED; |
96 | } | |
35fa2f2a BS |
97 | |
98 | int | |
99 | nouveau_irq_init(struct drm_device *dev) | |
100 | { | |
101 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
102 | int ret; | |
103 | ||
104 | if (nouveau_msi != 0 && dev_priv->card_type >= NV_50) { | |
105 | ret = pci_enable_msi(dev->pdev); | |
106 | if (ret == 0) { | |
107 | NV_INFO(dev, "enabled MSI\n"); | |
108 | dev_priv->msi_enabled = true; | |
109 | } | |
110 | } | |
111 | ||
112 | return drm_irq_install(dev); | |
113 | } | |
114 | ||
115 | void | |
116 | nouveau_irq_fini(struct drm_device *dev) | |
117 | { | |
118 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
119 | ||
120 | drm_irq_uninstall(dev); | |
121 | if (dev_priv->msi_enabled) | |
122 | pci_disable_msi(dev->pdev); | |
123 | } | |
8f8a5448 BS |
124 | |
125 | void | |
126 | nouveau_irq_register(struct drm_device *dev, int status_bit, | |
127 | void (*handler)(struct drm_device *)) | |
128 | { | |
129 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
130 | unsigned long flags; | |
131 | ||
132 | spin_lock_irqsave(&dev_priv->context_switch_lock, flags); | |
133 | dev_priv->irq_handler[status_bit] = handler; | |
134 | spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); | |
135 | } | |
136 | ||
137 | void | |
138 | nouveau_irq_unregister(struct drm_device *dev, int status_bit) | |
139 | { | |
140 | struct drm_nouveau_private *dev_priv = dev->dev_private; | |
141 | unsigned long flags; | |
142 | ||
143 | spin_lock_irqsave(&dev_priv->context_switch_lock, flags); | |
144 | dev_priv->irq_handler[status_bit] = NULL; | |
145 | spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); | |
146 | } |