diff options
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_irq.c | 203 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_state.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv04_fifo.c | 206 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv10_fifo.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv40_fifo.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_fifo.c | 4 |
7 files changed, 219 insertions, 208 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index c0fad126eaa4..e174479ab675 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h | |||
@@ -1053,6 +1053,7 @@ extern void nvc0_fb_takedown(struct drm_device *); | |||
1053 | 1053 | ||
1054 | /* nv04_fifo.c */ | 1054 | /* nv04_fifo.c */ |
1055 | extern int nv04_fifo_init(struct drm_device *); | 1055 | extern int nv04_fifo_init(struct drm_device *); |
1056 | extern void nv04_fifo_fini(struct drm_device *); | ||
1056 | extern void nv04_fifo_disable(struct drm_device *); | 1057 | extern void nv04_fifo_disable(struct drm_device *); |
1057 | extern void nv04_fifo_enable(struct drm_device *); | 1058 | extern void nv04_fifo_enable(struct drm_device *); |
1058 | extern bool nv04_fifo_reassign(struct drm_device *, bool); | 1059 | extern bool nv04_fifo_reassign(struct drm_device *, bool); |
@@ -1062,6 +1063,7 @@ extern int nv04_fifo_create_context(struct nouveau_channel *); | |||
1062 | extern void nv04_fifo_destroy_context(struct nouveau_channel *); | 1063 | extern void nv04_fifo_destroy_context(struct nouveau_channel *); |
1063 | extern int nv04_fifo_load_context(struct nouveau_channel *); | 1064 | extern int nv04_fifo_load_context(struct nouveau_channel *); |
1064 | extern int nv04_fifo_unload_context(struct drm_device *); | 1065 | extern int nv04_fifo_unload_context(struct drm_device *); |
1066 | extern void nv04_fifo_isr(struct drm_device *); | ||
1065 | 1067 | ||
1066 | /* nv10_fifo.c */ | 1068 | /* nv10_fifo.c */ |
1067 | extern int nv10_fifo_init(struct drm_device *); | 1069 | extern int nv10_fifo_init(struct drm_device *); |
diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 6c30669ac0b6..16f42f774a9e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c | |||
@@ -69,204 +69,6 @@ nouveau_irq_uninstall(struct drm_device *dev) | |||
69 | nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); | 69 | nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); |
70 | } | 70 | } |
71 | 71 | ||
72 | static bool | ||
73 | nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data) | ||
74 | { | ||
75 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
76 | struct nouveau_channel *chan = NULL; | ||
77 | struct nouveau_gpuobj *obj; | ||
78 | unsigned long flags; | ||
79 | const int subc = (addr >> 13) & 0x7; | ||
80 | const int mthd = addr & 0x1ffc; | ||
81 | bool handled = false; | ||
82 | u32 engine; | ||
83 | |||
84 | spin_lock_irqsave(&dev_priv->channels.lock, flags); | ||
85 | if (likely(chid >= 0 && chid < dev_priv->engine.fifo.channels)) | ||
86 | chan = dev_priv->channels.ptr[chid]; | ||
87 | if (unlikely(!chan)) | ||
88 | goto out; | ||
89 | |||
90 | switch (mthd) { | ||
91 | case 0x0000: /* bind object to subchannel */ | ||
92 | obj = nouveau_ramht_find(chan, data); | ||
93 | if (unlikely(!obj || obj->engine != NVOBJ_ENGINE_SW)) | ||
94 | break; | ||
95 | |||
96 | chan->sw_subchannel[subc] = obj->class; | ||
97 | engine = 0x0000000f << (subc * 4); | ||
98 | |||
99 | nv_mask(dev, NV04_PFIFO_CACHE1_ENGINE, engine, 0x00000000); | ||
100 | handled = true; | ||
101 | break; | ||
102 | default: | ||
103 | engine = nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE); | ||
104 | if (unlikely(((engine >> (subc * 4)) & 0xf) != 0)) | ||
105 | break; | ||
106 | |||
107 | if (!nouveau_gpuobj_mthd_call(chan, chan->sw_subchannel[subc], | ||
108 | mthd, data)) | ||
109 | handled = true; | ||
110 | break; | ||
111 | } | ||
112 | |||
113 | out: | ||
114 | spin_unlock_irqrestore(&dev_priv->channels.lock, flags); | ||
115 | return handled; | ||
116 | } | ||
117 | |||
118 | static void | ||
119 | nouveau_fifo_irq_handler(struct drm_device *dev) | ||
120 | { | ||
121 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
122 | struct nouveau_engine *engine = &dev_priv->engine; | ||
123 | uint32_t status, reassign; | ||
124 | int cnt = 0; | ||
125 | |||
126 | reassign = nv_rd32(dev, NV03_PFIFO_CACHES) & 1; | ||
127 | while ((status = nv_rd32(dev, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) { | ||
128 | uint32_t chid, get; | ||
129 | |||
130 | nv_wr32(dev, NV03_PFIFO_CACHES, 0); | ||
131 | |||
132 | chid = engine->fifo.channel_id(dev); | ||
133 | get = nv_rd32(dev, NV03_PFIFO_CACHE1_GET); | ||
134 | |||
135 | if (status & NV_PFIFO_INTR_CACHE_ERROR) { | ||
136 | uint32_t mthd, data; | ||
137 | int ptr; | ||
138 | |||
139 | /* NV_PFIFO_CACHE1_GET actually goes to 0xffc before | ||
140 | * wrapping on my G80 chips, but CACHE1 isn't big | ||
141 | * enough for this much data.. Tests show that it | ||
142 | * wraps around to the start at GET=0x800.. No clue | ||
143 | * as to why.. | ||
144 | */ | ||
145 | ptr = (get & 0x7ff) >> 2; | ||
146 | |||
147 | if (dev_priv->card_type < NV_40) { | ||
148 | mthd = nv_rd32(dev, | ||
149 | NV04_PFIFO_CACHE1_METHOD(ptr)); | ||
150 | data = nv_rd32(dev, | ||
151 | NV04_PFIFO_CACHE1_DATA(ptr)); | ||
152 | } else { | ||
153 | mthd = nv_rd32(dev, | ||
154 | NV40_PFIFO_CACHE1_METHOD(ptr)); | ||
155 | data = nv_rd32(dev, | ||
156 | NV40_PFIFO_CACHE1_DATA(ptr)); | ||
157 | } | ||
158 | |||
159 | if (!nouveau_fifo_swmthd(dev, chid, mthd, data)) { | ||
160 | NV_INFO(dev, "PFIFO_CACHE_ERROR - Ch %d/%d " | ||
161 | "Mthd 0x%04x Data 0x%08x\n", | ||
162 | chid, (mthd >> 13) & 7, mthd & 0x1ffc, | ||
163 | data); | ||
164 | } | ||
165 | |||
166 | nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0); | ||
167 | nv_wr32(dev, NV03_PFIFO_INTR_0, | ||
168 | NV_PFIFO_INTR_CACHE_ERROR); | ||
169 | |||
170 | nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, | ||
171 | nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) & ~1); | ||
172 | nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4); | ||
173 | nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, | ||
174 | nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) | 1); | ||
175 | nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0); | ||
176 | |||
177 | nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, | ||
178 | nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUSH) | 1); | ||
179 | nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); | ||
180 | |||
181 | status &= ~NV_PFIFO_INTR_CACHE_ERROR; | ||
182 | } | ||
183 | |||
184 | if (status & NV_PFIFO_INTR_DMA_PUSHER) { | ||
185 | u32 dma_get = nv_rd32(dev, 0x003244); | ||
186 | u32 dma_put = nv_rd32(dev, 0x003240); | ||
187 | u32 push = nv_rd32(dev, 0x003220); | ||
188 | u32 state = nv_rd32(dev, 0x003228); | ||
189 | |||
190 | if (dev_priv->card_type == NV_50) { | ||
191 | u32 ho_get = nv_rd32(dev, 0x003328); | ||
192 | u32 ho_put = nv_rd32(dev, 0x003320); | ||
193 | u32 ib_get = nv_rd32(dev, 0x003334); | ||
194 | u32 ib_put = nv_rd32(dev, 0x003330); | ||
195 | |||
196 | if (nouveau_ratelimit()) | ||
197 | NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x " | ||
198 | "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x " | ||
199 | "State 0x%08x Push 0x%08x\n", | ||
200 | chid, ho_get, dma_get, ho_put, | ||
201 | dma_put, ib_get, ib_put, state, | ||
202 | push); | ||
203 | |||
204 | /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ | ||
205 | nv_wr32(dev, 0x003364, 0x00000000); | ||
206 | if (dma_get != dma_put || ho_get != ho_put) { | ||
207 | nv_wr32(dev, 0x003244, dma_put); | ||
208 | nv_wr32(dev, 0x003328, ho_put); | ||
209 | } else | ||
210 | if (ib_get != ib_put) { | ||
211 | nv_wr32(dev, 0x003334, ib_put); | ||
212 | } | ||
213 | } else { | ||
214 | NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x " | ||
215 | "Put 0x%08x State 0x%08x Push 0x%08x\n", | ||
216 | chid, dma_get, dma_put, state, push); | ||
217 | |||
218 | if (dma_get != dma_put) | ||
219 | nv_wr32(dev, 0x003244, dma_put); | ||
220 | } | ||
221 | |||
222 | nv_wr32(dev, 0x003228, 0x00000000); | ||
223 | nv_wr32(dev, 0x003220, 0x00000001); | ||
224 | nv_wr32(dev, 0x002100, NV_PFIFO_INTR_DMA_PUSHER); | ||
225 | status &= ~NV_PFIFO_INTR_DMA_PUSHER; | ||
226 | } | ||
227 | |||
228 | if (status & NV_PFIFO_INTR_SEMAPHORE) { | ||
229 | uint32_t sem; | ||
230 | |||
231 | status &= ~NV_PFIFO_INTR_SEMAPHORE; | ||
232 | nv_wr32(dev, NV03_PFIFO_INTR_0, | ||
233 | NV_PFIFO_INTR_SEMAPHORE); | ||
234 | |||
235 | sem = nv_rd32(dev, NV10_PFIFO_CACHE1_SEMAPHORE); | ||
236 | nv_wr32(dev, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1); | ||
237 | |||
238 | nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4); | ||
239 | nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); | ||
240 | } | ||
241 | |||
242 | if (dev_priv->card_type == NV_50) { | ||
243 | if (status & 0x00000010) { | ||
244 | nv50_fb_vm_trap(dev, 1, "PFIFO_BAR_FAULT"); | ||
245 | status &= ~0x00000010; | ||
246 | nv_wr32(dev, 0x002100, 0x00000010); | ||
247 | } | ||
248 | } | ||
249 | |||
250 | if (status) { | ||
251 | if (nouveau_ratelimit()) | ||
252 | NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n", | ||
253 | status, chid); | ||
254 | nv_wr32(dev, NV03_PFIFO_INTR_0, status); | ||
255 | status = 0; | ||
256 | } | ||
257 | |||
258 | nv_wr32(dev, NV03_PFIFO_CACHES, reassign); | ||
259 | } | ||
260 | |||
261 | if (status) { | ||
262 | NV_INFO(dev, "PFIFO still angry after %d spins, halt\n", cnt); | ||
263 | nv_wr32(dev, 0x2140, 0); | ||
264 | nv_wr32(dev, 0x140, 0); | ||
265 | } | ||
266 | |||
267 | nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PFIFO_PENDING); | ||
268 | } | ||
269 | |||
270 | static struct nouveau_bitfield nstatus_names[] = | 72 | static struct nouveau_bitfield nstatus_names[] = |
271 | { | 73 | { |
272 | { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" }, | 74 | { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" }, |
@@ -1146,11 +948,6 @@ nouveau_irq_handler(DRM_IRQ_ARGS) | |||
1146 | 948 | ||
1147 | spin_lock_irqsave(&dev_priv->context_switch_lock, flags); | 949 | spin_lock_irqsave(&dev_priv->context_switch_lock, flags); |
1148 | 950 | ||
1149 | if (status & NV_PMC_INTR_0_PFIFO_PENDING) { | ||
1150 | nouveau_fifo_irq_handler(dev); | ||
1151 | status &= ~NV_PMC_INTR_0_PFIFO_PENDING; | ||
1152 | } | ||
1153 | |||
1154 | if (status & NV_PMC_INTR_0_PGRAPH_PENDING) { | 951 | if (status & NV_PMC_INTR_0_PGRAPH_PENDING) { |
1155 | if (dev_priv->card_type >= NV_50) | 952 | if (dev_priv->card_type >= NV_50) |
1156 | nv50_pgraph_irq_handler(dev); | 953 | nv50_pgraph_irq_handler(dev); |
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 84bff459491e..262545b58d96 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c | |||
@@ -75,7 +75,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) | |||
75 | engine->graph.unload_context = nv04_graph_unload_context; | 75 | engine->graph.unload_context = nv04_graph_unload_context; |
76 | engine->fifo.channels = 16; | 76 | engine->fifo.channels = 16; |
77 | engine->fifo.init = nv04_fifo_init; | 77 | engine->fifo.init = nv04_fifo_init; |
78 | engine->fifo.takedown = nouveau_stub_takedown; | 78 | engine->fifo.takedown = nv04_fifo_fini; |
79 | engine->fifo.disable = nv04_fifo_disable; | 79 | engine->fifo.disable = nv04_fifo_disable; |
80 | engine->fifo.enable = nv04_fifo_enable; | 80 | engine->fifo.enable = nv04_fifo_enable; |
81 | engine->fifo.reassign = nv04_fifo_reassign; | 81 | engine->fifo.reassign = nv04_fifo_reassign; |
@@ -132,7 +132,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) | |||
132 | engine->graph.set_tile_region = nv10_graph_set_tile_region; | 132 | engine->graph.set_tile_region = nv10_graph_set_tile_region; |
133 | engine->fifo.channels = 32; | 133 | engine->fifo.channels = 32; |
134 | engine->fifo.init = nv10_fifo_init; | 134 | engine->fifo.init = nv10_fifo_init; |
135 | engine->fifo.takedown = nouveau_stub_takedown; | 135 | engine->fifo.takedown = nv04_fifo_fini; |
136 | engine->fifo.disable = nv04_fifo_disable; | 136 | engine->fifo.disable = nv04_fifo_disable; |
137 | engine->fifo.enable = nv04_fifo_enable; | 137 | engine->fifo.enable = nv04_fifo_enable; |
138 | engine->fifo.reassign = nv04_fifo_reassign; | 138 | engine->fifo.reassign = nv04_fifo_reassign; |
@@ -189,7 +189,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) | |||
189 | engine->graph.set_tile_region = nv20_graph_set_tile_region; | 189 | engine->graph.set_tile_region = nv20_graph_set_tile_region; |
190 | engine->fifo.channels = 32; | 190 | engine->fifo.channels = 32; |
191 | engine->fifo.init = nv10_fifo_init; | 191 | engine->fifo.init = nv10_fifo_init; |
192 | engine->fifo.takedown = nouveau_stub_takedown; | 192 | engine->fifo.takedown = nv04_fifo_fini; |
193 | engine->fifo.disable = nv04_fifo_disable; | 193 | engine->fifo.disable = nv04_fifo_disable; |
194 | engine->fifo.enable = nv04_fifo_enable; | 194 | engine->fifo.enable = nv04_fifo_enable; |
195 | engine->fifo.reassign = nv04_fifo_reassign; | 195 | engine->fifo.reassign = nv04_fifo_reassign; |
@@ -246,7 +246,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) | |||
246 | engine->graph.set_tile_region = nv20_graph_set_tile_region; | 246 | engine->graph.set_tile_region = nv20_graph_set_tile_region; |
247 | engine->fifo.channels = 32; | 247 | engine->fifo.channels = 32; |
248 | engine->fifo.init = nv10_fifo_init; | 248 | engine->fifo.init = nv10_fifo_init; |
249 | engine->fifo.takedown = nouveau_stub_takedown; | 249 | engine->fifo.takedown = nv04_fifo_fini; |
250 | engine->fifo.disable = nv04_fifo_disable; | 250 | engine->fifo.disable = nv04_fifo_disable; |
251 | engine->fifo.enable = nv04_fifo_enable; | 251 | engine->fifo.enable = nv04_fifo_enable; |
252 | engine->fifo.reassign = nv04_fifo_reassign; | 252 | engine->fifo.reassign = nv04_fifo_reassign; |
@@ -306,7 +306,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) | |||
306 | engine->graph.set_tile_region = nv40_graph_set_tile_region; | 306 | engine->graph.set_tile_region = nv40_graph_set_tile_region; |
307 | engine->fifo.channels = 32; | 307 | engine->fifo.channels = 32; |
308 | engine->fifo.init = nv40_fifo_init; | 308 | engine->fifo.init = nv40_fifo_init; |
309 | engine->fifo.takedown = nouveau_stub_takedown; | 309 | engine->fifo.takedown = nv04_fifo_fini; |
310 | engine->fifo.disable = nv04_fifo_disable; | 310 | engine->fifo.disable = nv04_fifo_disable; |
311 | engine->fifo.enable = nv04_fifo_enable; | 311 | engine->fifo.enable = nv04_fifo_enable; |
312 | engine->fifo.reassign = nv04_fifo_reassign; | 312 | engine->fifo.reassign = nv04_fifo_reassign; |
diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c index 4c0d3a8fca68..a32ba8ccaae6 100644 --- a/drivers/gpu/drm/nouveau/nv04_fifo.c +++ b/drivers/gpu/drm/nouveau/nv04_fifo.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "drm.h" | 28 | #include "drm.h" |
29 | #include "nouveau_drv.h" | 29 | #include "nouveau_drv.h" |
30 | #include "nouveau_ramht.h" | 30 | #include "nouveau_ramht.h" |
31 | #include "nouveau_util.h" | ||
31 | 32 | ||
32 | #define NV04_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV04_RAMFC__SIZE)) | 33 | #define NV04_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV04_RAMFC__SIZE)) |
33 | #define NV04_RAMFC__SIZE 32 | 34 | #define NV04_RAMFC__SIZE 32 |
@@ -284,6 +285,7 @@ nv04_fifo_init_ramxx(struct drm_device *dev) | |||
284 | static void | 285 | static void |
285 | nv04_fifo_init_intr(struct drm_device *dev) | 286 | nv04_fifo_init_intr(struct drm_device *dev) |
286 | { | 287 | { |
288 | nouveau_irq_register(dev, 8, nv04_fifo_isr); | ||
287 | nv_wr32(dev, 0x002100, 0xffffffff); | 289 | nv_wr32(dev, 0x002100, 0xffffffff); |
288 | nv_wr32(dev, 0x002140, 0xffffffff); | 290 | nv_wr32(dev, 0x002140, 0xffffffff); |
289 | } | 291 | } |
@@ -315,3 +317,207 @@ nv04_fifo_init(struct drm_device *dev) | |||
315 | return 0; | 317 | return 0; |
316 | } | 318 | } |
317 | 319 | ||
320 | void | ||
321 | nv04_fifo_fini(struct drm_device *dev) | ||
322 | { | ||
323 | nv_wr32(dev, 0x2140, 0x00000000); | ||
324 | nouveau_irq_unregister(dev, 8); | ||
325 | } | ||
326 | |||
327 | static bool | ||
328 | nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data) | ||
329 | { | ||
330 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
331 | struct nouveau_channel *chan = NULL; | ||
332 | struct nouveau_gpuobj *obj; | ||
333 | unsigned long flags; | ||
334 | const int subc = (addr >> 13) & 0x7; | ||
335 | const int mthd = addr & 0x1ffc; | ||
336 | bool handled = false; | ||
337 | u32 engine; | ||
338 | |||
339 | spin_lock_irqsave(&dev_priv->channels.lock, flags); | ||
340 | if (likely(chid >= 0 && chid < dev_priv->engine.fifo.channels)) | ||
341 | chan = dev_priv->channels.ptr[chid]; | ||
342 | if (unlikely(!chan)) | ||
343 | goto out; | ||
344 | |||
345 | switch (mthd) { | ||
346 | case 0x0000: /* bind object to subchannel */ | ||
347 | obj = nouveau_ramht_find(chan, data); | ||
348 | if (unlikely(!obj || obj->engine != NVOBJ_ENGINE_SW)) | ||
349 | break; | ||
350 | |||
351 | chan->sw_subchannel[subc] = obj->class; | ||
352 | engine = 0x0000000f << (subc * 4); | ||
353 | |||
354 | nv_mask(dev, NV04_PFIFO_CACHE1_ENGINE, engine, 0x00000000); | ||
355 | handled = true; | ||
356 | break; | ||
357 | default: | ||
358 | engine = nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE); | ||
359 | if (unlikely(((engine >> (subc * 4)) & 0xf) != 0)) | ||
360 | break; | ||
361 | |||
362 | if (!nouveau_gpuobj_mthd_call(chan, chan->sw_subchannel[subc], | ||
363 | mthd, data)) | ||
364 | handled = true; | ||
365 | break; | ||
366 | } | ||
367 | |||
368 | out: | ||
369 | spin_unlock_irqrestore(&dev_priv->channels.lock, flags); | ||
370 | return handled; | ||
371 | } | ||
372 | |||
373 | void | ||
374 | nv04_fifo_isr(struct drm_device *dev) | ||
375 | { | ||
376 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
377 | struct nouveau_engine *engine = &dev_priv->engine; | ||
378 | uint32_t status, reassign; | ||
379 | int cnt = 0; | ||
380 | |||
381 | reassign = nv_rd32(dev, NV03_PFIFO_CACHES) & 1; | ||
382 | while ((status = nv_rd32(dev, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) { | ||
383 | uint32_t chid, get; | ||
384 | |||
385 | nv_wr32(dev, NV03_PFIFO_CACHES, 0); | ||
386 | |||
387 | chid = engine->fifo.channel_id(dev); | ||
388 | get = nv_rd32(dev, NV03_PFIFO_CACHE1_GET); | ||
389 | |||
390 | if (status & NV_PFIFO_INTR_CACHE_ERROR) { | ||
391 | uint32_t mthd, data; | ||
392 | int ptr; | ||
393 | |||
394 | /* NV_PFIFO_CACHE1_GET actually goes to 0xffc before | ||
395 | * wrapping on my G80 chips, but CACHE1 isn't big | ||
396 | * enough for this much data.. Tests show that it | ||
397 | * wraps around to the start at GET=0x800.. No clue | ||
398 | * as to why.. | ||
399 | */ | ||
400 | ptr = (get & 0x7ff) >> 2; | ||
401 | |||
402 | if (dev_priv->card_type < NV_40) { | ||
403 | mthd = nv_rd32(dev, | ||
404 | NV04_PFIFO_CACHE1_METHOD(ptr)); | ||
405 | data = nv_rd32(dev, | ||
406 | NV04_PFIFO_CACHE1_DATA(ptr)); | ||
407 | } else { | ||
408 | mthd = nv_rd32(dev, | ||
409 | NV40_PFIFO_CACHE1_METHOD(ptr)); | ||
410 | data = nv_rd32(dev, | ||
411 | NV40_PFIFO_CACHE1_DATA(ptr)); | ||
412 | } | ||
413 | |||
414 | if (!nouveau_fifo_swmthd(dev, chid, mthd, data)) { | ||
415 | NV_INFO(dev, "PFIFO_CACHE_ERROR - Ch %d/%d " | ||
416 | "Mthd 0x%04x Data 0x%08x\n", | ||
417 | chid, (mthd >> 13) & 7, mthd & 0x1ffc, | ||
418 | data); | ||
419 | } | ||
420 | |||
421 | nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0); | ||
422 | nv_wr32(dev, NV03_PFIFO_INTR_0, | ||
423 | NV_PFIFO_INTR_CACHE_ERROR); | ||
424 | |||
425 | nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, | ||
426 | nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) & ~1); | ||
427 | nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4); | ||
428 | nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, | ||
429 | nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) | 1); | ||
430 | nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0); | ||
431 | |||
432 | nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, | ||
433 | nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUSH) | 1); | ||
434 | nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); | ||
435 | |||
436 | status &= ~NV_PFIFO_INTR_CACHE_ERROR; | ||
437 | } | ||
438 | |||
439 | if (status & NV_PFIFO_INTR_DMA_PUSHER) { | ||
440 | u32 dma_get = nv_rd32(dev, 0x003244); | ||
441 | u32 dma_put = nv_rd32(dev, 0x003240); | ||
442 | u32 push = nv_rd32(dev, 0x003220); | ||
443 | u32 state = nv_rd32(dev, 0x003228); | ||
444 | |||
445 | if (dev_priv->card_type == NV_50) { | ||
446 | u32 ho_get = nv_rd32(dev, 0x003328); | ||
447 | u32 ho_put = nv_rd32(dev, 0x003320); | ||
448 | u32 ib_get = nv_rd32(dev, 0x003334); | ||
449 | u32 ib_put = nv_rd32(dev, 0x003330); | ||
450 | |||
451 | if (nouveau_ratelimit()) | ||
452 | NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x " | ||
453 | "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x " | ||
454 | "State 0x%08x Push 0x%08x\n", | ||
455 | chid, ho_get, dma_get, ho_put, | ||
456 | dma_put, ib_get, ib_put, state, | ||
457 | push); | ||
458 | |||
459 | /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ | ||
460 | nv_wr32(dev, 0x003364, 0x00000000); | ||
461 | if (dma_get != dma_put || ho_get != ho_put) { | ||
462 | nv_wr32(dev, 0x003244, dma_put); | ||
463 | nv_wr32(dev, 0x003328, ho_put); | ||
464 | } else | ||
465 | if (ib_get != ib_put) { | ||
466 | nv_wr32(dev, 0x003334, ib_put); | ||
467 | } | ||
468 | } else { | ||
469 | NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x " | ||
470 | "Put 0x%08x State 0x%08x Push 0x%08x\n", | ||
471 | chid, dma_get, dma_put, state, push); | ||
472 | |||
473 | if (dma_get != dma_put) | ||
474 | nv_wr32(dev, 0x003244, dma_put); | ||
475 | } | ||
476 | |||
477 | nv_wr32(dev, 0x003228, 0x00000000); | ||
478 | nv_wr32(dev, 0x003220, 0x00000001); | ||
479 | nv_wr32(dev, 0x002100, NV_PFIFO_INTR_DMA_PUSHER); | ||
480 | status &= ~NV_PFIFO_INTR_DMA_PUSHER; | ||
481 | } | ||
482 | |||
483 | if (status & NV_PFIFO_INTR_SEMAPHORE) { | ||
484 | uint32_t sem; | ||
485 | |||
486 | status &= ~NV_PFIFO_INTR_SEMAPHORE; | ||
487 | nv_wr32(dev, NV03_PFIFO_INTR_0, | ||
488 | NV_PFIFO_INTR_SEMAPHORE); | ||
489 | |||
490 | sem = nv_rd32(dev, NV10_PFIFO_CACHE1_SEMAPHORE); | ||
491 | nv_wr32(dev, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1); | ||
492 | |||
493 | nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4); | ||
494 | nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); | ||
495 | } | ||
496 | |||
497 | if (dev_priv->card_type == NV_50) { | ||
498 | if (status & 0x00000010) { | ||
499 | nv50_fb_vm_trap(dev, 1, "PFIFO_BAR_FAULT"); | ||
500 | status &= ~0x00000010; | ||
501 | nv_wr32(dev, 0x002100, 0x00000010); | ||
502 | } | ||
503 | } | ||
504 | |||
505 | if (status) { | ||
506 | if (nouveau_ratelimit()) | ||
507 | NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n", | ||
508 | status, chid); | ||
509 | nv_wr32(dev, NV03_PFIFO_INTR_0, status); | ||
510 | status = 0; | ||
511 | } | ||
512 | |||
513 | nv_wr32(dev, NV03_PFIFO_CACHES, reassign); | ||
514 | } | ||
515 | |||
516 | if (status) { | ||
517 | NV_INFO(dev, "PFIFO still angry after %d spins, halt\n", cnt); | ||
518 | nv_wr32(dev, 0x2140, 0); | ||
519 | nv_wr32(dev, 0x140, 0); | ||
520 | } | ||
521 | |||
522 | nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PFIFO_PENDING); | ||
523 | } | ||
diff --git a/drivers/gpu/drm/nouveau/nv10_fifo.c b/drivers/gpu/drm/nouveau/nv10_fifo.c index 912556f2e33c..acb9216e6d0a 100644 --- a/drivers/gpu/drm/nouveau/nv10_fifo.c +++ b/drivers/gpu/drm/nouveau/nv10_fifo.c | |||
@@ -208,6 +208,7 @@ nv10_fifo_init_ramxx(struct drm_device *dev) | |||
208 | static void | 208 | static void |
209 | nv10_fifo_init_intr(struct drm_device *dev) | 209 | nv10_fifo_init_intr(struct drm_device *dev) |
210 | { | 210 | { |
211 | nouveau_irq_register(dev, 8, nv04_fifo_isr); | ||
211 | nv_wr32(dev, 0x002100, 0xffffffff); | 212 | nv_wr32(dev, 0x002100, 0xffffffff); |
212 | nv_wr32(dev, 0x002140, 0xffffffff); | 213 | nv_wr32(dev, 0x002140, 0xffffffff); |
213 | } | 214 | } |
diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c index 311ac9ea5d53..f6b3580c685a 100644 --- a/drivers/gpu/drm/nouveau/nv40_fifo.c +++ b/drivers/gpu/drm/nouveau/nv40_fifo.c | |||
@@ -268,6 +268,7 @@ nv40_fifo_init_ramxx(struct drm_device *dev) | |||
268 | static void | 268 | static void |
269 | nv40_fifo_init_intr(struct drm_device *dev) | 269 | nv40_fifo_init_intr(struct drm_device *dev) |
270 | { | 270 | { |
271 | nouveau_irq_register(dev, 8, nv04_fifo_isr); | ||
271 | nv_wr32(dev, 0x002100, 0xffffffff); | 272 | nv_wr32(dev, 0x002100, 0xffffffff); |
272 | nv_wr32(dev, 0x002140, 0xffffffff); | 273 | nv_wr32(dev, 0x002140, 0xffffffff); |
273 | } | 274 | } |
diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c index d3295aae0c4e..ed18952ae7f4 100644 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c +++ b/drivers/gpu/drm/nouveau/nv50_fifo.c | |||
@@ -106,6 +106,7 @@ nv50_fifo_init_intr(struct drm_device *dev) | |||
106 | { | 106 | { |
107 | NV_DEBUG(dev, "\n"); | 107 | NV_DEBUG(dev, "\n"); |
108 | 108 | ||
109 | nouveau_irq_register(dev, 8, nv04_fifo_isr); | ||
109 | nv_wr32(dev, NV03_PFIFO_INTR_0, 0xFFFFFFFF); | 110 | nv_wr32(dev, NV03_PFIFO_INTR_0, 0xFFFFFFFF); |
110 | nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xFFFFFFFF); | 111 | nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xFFFFFFFF); |
111 | } | 112 | } |
@@ -207,6 +208,9 @@ nv50_fifo_takedown(struct drm_device *dev) | |||
207 | if (!pfifo->playlist[0]) | 208 | if (!pfifo->playlist[0]) |
208 | return; | 209 | return; |
209 | 210 | ||
211 | nv_wr32(dev, 0x2140, 0x00000000); | ||
212 | nouveau_irq_unregister(dev, 8); | ||
213 | |||
210 | nouveau_gpuobj_ref(NULL, &pfifo->playlist[0]); | 214 | nouveau_gpuobj_ref(NULL, &pfifo->playlist[0]); |
211 | nouveau_gpuobj_ref(NULL, &pfifo->playlist[1]); | 215 | nouveau_gpuobj_ref(NULL, &pfifo->playlist[1]); |
212 | } | 216 | } |