]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/suse-2.6.27.39/patches.drivers/via-unichrome-drm-bugfixes.patch
Fix oinkmaster patch.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.drivers / via-unichrome-drm-bugfixes.patch
1 From: Bruce Chang <BruceChang@via.com.tw>
2 Subject: via: Unichrome DRM bugfixes
3
4 1. Patch the system hang issue caused by multi X support when doing
5 switch user.
6 2. Patch system hang issue caused by 3D scaling+ACPI
7 3. Patch segmentation fault issue caused by playing video with AGP after
8 resume from suspend.
9 4. Reverse the wrong modification we did on the in-line source for
10 coding style only. So ther should no typedef structure...
11 5. Move private AGP structure into public.
12 6. Remove the modification we did for bypassing DMA check to improve
13 performance.
14
15
16 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
17
18 ---
19 drivers/gpu/drm/via/via_dma.c | 341 +++++++++++++++++++++++++++++++++++++++++-
20 drivers/gpu/drm/via/via_drv.c | 12 +
21 drivers/gpu/drm/via/via_drv.h | 12 +
22 drivers/gpu/drm/via/via_map.c | 45 +++++
23 drivers/gpu/drm/via/via_mm.c | 137 +++++++++++++++-
24 include/drm/via_drm.h | 43 +++++
25 6 files changed, 576 insertions(+), 14 deletions(-)
26
27 --- a/drivers/gpu/drm/via/via_dma.c
28 +++ b/drivers/gpu/drm/via/via_dma.c
29 @@ -68,6 +68,15 @@
30 *vb++ = (w2); \
31 dev_priv->dma_low += 8;
32
33 +#define VIA_OUT_VIDEO_AGP_BUFFER(cmd1, cmd2) \
34 + do { \
35 + *cur_virtual++ = cmd1; \
36 + *cur_virtual++ = cmd2; \
37 + cmdbuf_info.cmd_size += 8; \
38 + } while (0);
39 +
40 +static void via_cmdbuf_flush(struct drm_via_private *dev_priv,
41 + uint32_t cmd_type);
42 static void via_cmdbuf_start(drm_via_private_t * dev_priv);
43 static void via_cmdbuf_pause(drm_via_private_t * dev_priv);
44 static void via_cmdbuf_reset(drm_via_private_t * dev_priv);
45 @@ -75,6 +84,7 @@ static void via_cmdbuf_rewind(drm_via_pr
46 static int via_wait_idle(drm_via_private_t * dev_priv);
47 static void via_pad_cache(drm_via_private_t * dev_priv, int qwords);
48
49 +
50 /*
51 * Free space in command buffer.
52 */
53 @@ -155,17 +165,35 @@ static inline uint32_t *via_check_dma(dr
54
55 int via_dma_cleanup(struct drm_device * dev)
56 {
57 + struct drm_via_video_save_head *pnode;
58 + int i;
59 +
60 +
61 + for (pnode = via_video_save_head; pnode; pnode =
62 + (struct drm_via_video_save_head *)pnode->next)
63 + memcpy(pnode->psystemmem, pnode->pvideomem, pnode->size);
64 if (dev->dev_private) {
65 drm_via_private_t *dev_priv =
66 (drm_via_private_t *) dev->dev_private;
67
68 if (dev_priv->ring.virtual_start) {
69 - via_cmdbuf_reset(dev_priv);
70 + if (dev_priv->cr_status == CR_FOR_RINGBUFFER)
71 + via_cmdbuf_flush(dev_priv, HC_HAGPBpID_STOP);
72 +
73 + via_wait_idle(dev_priv);
74
75 drm_core_ioremapfree(&dev_priv->ring.map, dev);
76 dev_priv->ring.virtual_start = NULL;
77 }
78
79 + for (i = 0; i < 3; i++) {
80 + if (dev_priv->video_agp_address_map[i].handle &&
81 + dev_priv->video_agp_address_map[i].size)
82 + drm_core_ioremapfree(dev_priv->
83 + video_agp_address_map+i, dev);
84 + /*Fix for suspend reuse video buf*/
85 + dev_priv->video_agp_address_map[i].handle = NULL;
86 + }
87 }
88
89 return 0;
90 @@ -175,6 +203,7 @@ static int via_initialize(struct drm_dev
91 drm_via_private_t * dev_priv,
92 drm_via_dma_init_t * init)
93 {
94 + struct drm_via_video_save_head *pnode;
95 if (!dev_priv || !dev_priv->mmio) {
96 DRM_ERROR("via_dma_init called before via_map_init\n");
97 return -EFAULT;
98 @@ -194,6 +223,9 @@ static int via_initialize(struct drm_dev
99 DRM_ERROR("AGP DMA is not supported on this chip\n");
100 return -EINVAL;
101 }
102 +
103 + for (pnode = via_video_save_head; pnode; pnode = pnode->next)
104 + memcpy(pnode->pvideomem, pnode->psystemmem, pnode->size);
105
106 dev_priv->ring.map.offset = dev->agp->base + init->offset;
107 dev_priv->ring.map.size = init->size;
108 @@ -224,6 +256,7 @@ static int via_initialize(struct drm_dev
109
110 via_cmdbuf_start(dev_priv);
111
112 + dev_priv->cr_status = CR_FOR_RINGBUFFER;
113 return 0;
114 }
115
116 @@ -332,12 +365,42 @@ static int via_flush_ioctl(struct drm_de
117 static int via_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv)
118 {
119 drm_via_cmdbuffer_t *cmdbuf = data;
120 - int ret;
121 + drm_via_private_t *dev_priv = dev->dev_private;
122 + int ret = 0, count;
123
124 LOCK_TEST_WITH_RETURN(dev, file_priv);
125
126 DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size);
127
128 + if (dev_priv->cr_status == CR_FOR_VIDEO) {
129 + /* Because our driver will hook CR stop cmd behind video cmd,
130 + * all we need to do here is to wait for CR idle,
131 + * and initialize ring buffer.
132 + */
133 + count = 10000000;
134 + while (count-- && (VIA_READ(VIA_REG_STATUS) &
135 + VIA_CMD_RGTR_BUSY))
136 + cpu_relax();
137 + /* Seldom happen */
138 + if (count < 0) {
139 + DRM_INFO("The CR can't be idle from video agp cmd \
140 + dispatch when it is needed by ring buffer \n");
141 + return -1;
142 + }
143 + /* CR has been idle so that we need to initialize ring buffer */
144 + dev_priv->dma_ptr = dev_priv->ring.virtual_start;
145 + dev_priv->dma_low = 0;
146 + dev_priv->dma_high = 0x1000000;
147 + dev_priv->dma_wrap = 0x1000000;
148 + dev_priv->dma_offset = 0x0;
149 + dev_priv->last_pause_ptr = NULL;
150 + dev_priv->hw_addr_ptr = dev_priv->mmio->handle + 0x418;
151 +
152 + via_cmdbuf_start(dev_priv);
153 +
154 + dev_priv->cr_status = CR_FOR_RINGBUFFER;
155 +
156 + }
157 ret = via_dispatch_cmdbuffer(dev, cmdbuf);
158 if (ret) {
159 return ret;
160 @@ -346,6 +409,134 @@ static int via_cmdbuffer(struct drm_devi
161 return 0;
162 }
163
164 +int via_cmdbuffer_video_agp(struct drm_device *dev, void *data,
165 + struct drm_file *file_priv)
166 +{
167 + drm_via_private_t *dev_priv = dev->dev_private;
168 + struct drm_via_video_agp_cmd cmdbuf_info;
169 + int count;
170 + u32 start_addr, start_addr_lo;
171 + u32 end_addr, end_addr_lo;
172 + u32 pause_addr, pause_addr_hi, pause_addr_lo;
173 + u32 *cur_virtual;
174 + u32 command;
175 + int i = 0;
176 + struct drm_map map;
177 +
178 + LOCK_TEST_WITH_RETURN(dev, file_priv);
179 +
180 + /* Check whether CR services for ring buffer or for video engine. */
181 + if (dev_priv->cr_status == CR_FOR_RINGBUFFER) {
182 + /* Here we need to hook stop cmd in tail of ringbuffer
183 + * in order to stop CR, for we will reset start/end/pause
184 + * address for fetch cmd from video AGP buffer
185 + */
186 + via_cmdbuf_flush(dev_priv, HC_HAGPBpID_STOP);
187 + }
188 +
189 + /* Set CR status here to avoid ring buffer crush in case we
190 + * can't initialize CR for video properly
191 + */
192 + dev_priv->cr_status = CR_FOR_VIDEO;
193 +
194 + /* Wait idle since we will reset CR relevant registers. */
195 + count = 10000000;
196 + while (count-- && (VIA_READ(VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY))
197 + cpu_relax();
198 +
199 + /* Seldom happen */
200 + if (count < 0) {
201 + DRM_INFO("The CR can't be idle from video agp cmd dispatch \
202 + when it is needed by ring buffer \n");
203 + return -1;
204 + }
205 +
206 + /* Till here, the CR has been idle, all need to here is to initialize
207 + * CR START/END/PAUSE address registers according to video AGP buffer
208 + * location and size. BE LUCKY!!!
209 + */
210 + cmdbuf_info = *(struct drm_via_video_agp_cmd *)data;
211 +
212 + start_addr = cmdbuf_info.offset + dev->agp->base;
213 + end_addr = cmdbuf_info.buffer_size + start_addr;
214 +
215 + if ((cmdbuf_info.buffer_size & 0xFF) ||
216 + (start_addr + 2 * 0xFF > end_addr) ||
217 + start_addr & 0xFF) {
218 + DRM_INFO("The video cmd is too large or you didn't set the \
219 + video cmd 2 DWORD alignment. \n");
220 + return -1;
221 + }
222 +
223 + map.offset = start_addr;
224 + map.size = cmdbuf_info.buffer_size;
225 + map.type = map.flags = map.mtrr = 0;
226 + map.handle = 0;
227 +
228 + for (i = 0; i < 3; i++) {
229 + if ((dev_priv->video_agp_address_map[i].offset == map.offset) &&
230 + (dev_priv->video_agp_address_map[i].size == map.size) &&
231 + dev_priv->video_agp_address_map[i].handle) {
232 + map.handle = dev_priv->video_agp_address_map[i].handle;
233 + break;
234 + }
235 + if (!dev_priv->video_agp_address_map[i].handle)
236 + break;
237 + }
238 +
239 + /* Check whether this agp cmd buffer has already been remaped before */
240 + /* case: Never be remaped before */
241 + if (!map.handle) {
242 + drm_core_ioremap(&map, dev);
243 + if (!map.handle)
244 + return -1;
245 + /* there is a free hole for filling in this address map */
246 + if (i < 3)
247 + dev_priv->video_agp_address_map[i] = map;
248 + else {
249 + drm_core_ioremapfree(dev_priv->video_agp_address_map,
250 + dev);
251 + dev_priv->video_agp_address_map[0] = map;
252 + }
253 + }
254 +
255 + cur_virtual = map.handle + cmdbuf_info.cmd_size;
256 +
257 + VIA_OUT_VIDEO_AGP_BUFFER(HC_HEADER2 | ((VIA_REG_TRANSET >> 2) << 12) |
258 + (VIA_REG_TRANSPACE >> 2), HC_ParaType_PreCR << 16);
259 +
260 + /* pause register need 0xFF alignment */
261 + do {
262 + VIA_OUT_VIDEO_AGP_BUFFER(HC_DUMMY, HC_DUMMY);
263 + } while (cmdbuf_info.cmd_size & 0xFF);
264 + pause_addr = cmdbuf_info.cmd_size + start_addr - 8;
265 +
266 + pause_addr_lo = ((HC_SubA_HAGPBpL << 24) | HC_HAGPBpID_STOP |
267 + (pause_addr & HC_HAGPBpL_MASK));
268 + pause_addr_hi = ((HC_SubA_HAGPBpH << 24) | (pause_addr >> 24));
269 + start_addr_lo = ((HC_SubA_HAGPBstL << 24) | (start_addr & 0xFFFFFF));
270 + end_addr_lo = ((HC_SubA_HAGPBendL << 24) | (end_addr & 0xFFFFFF));
271 + command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) |
272 + ((end_addr & 0xff000000) >> 16));
273 + *(cur_virtual-2) = pause_addr_hi;
274 + *(cur_virtual-1) = pause_addr_lo;
275 +
276 + via_flush_write_combine();
277 +
278 + VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
279 + VIA_WRITE(VIA_REG_TRANSPACE, command);
280 + VIA_WRITE(VIA_REG_TRANSPACE, start_addr_lo);
281 + VIA_WRITE(VIA_REG_TRANSPACE, end_addr_lo);
282 +
283 + VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
284 + VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
285 + DRM_WRITEMEMORYBARRIER();
286 + /* fire */
287 + VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
288 +
289 + return 0;
290 +}
291 +
292 static int via_dispatch_pci_cmdbuffer(struct drm_device * dev,
293 drm_via_cmdbuffer_t * cmd)
294 {
295 @@ -735,6 +926,146 @@ static int via_cmdbuf_size(struct drm_de
296 return ret;
297 }
298
299 +/*The following functions are for ACPI*/
300 +
301 +static void initialize3Dengine(drm_via_private_t *dev_priv)
302 +{
303 + int i = 0;
304 +
305 + VIA_WRITE(0x43C, 0x00010000);
306 +
307 + for (i = 0; i <= 0x7D; i++)
308 + VIA_WRITE(0x440, (unsigned long) i << 24);
309 +
310 + VIA_WRITE(0x43C, 0x00020000);
311 +
312 + for (i = 0; i <= 0x94; i++)
313 + VIA_WRITE(0x440, (unsigned long) i << 24);
314 +
315 + VIA_WRITE(0x440, 0x82400000);
316 + VIA_WRITE(0x43C, 0x01020000);
317 +
318 + for (i = 0; i <= 0x94; i++)
319 + VIA_WRITE(0x440, (unsigned long) i << 24);
320 +
321 + VIA_WRITE(0x440, 0x82400000);
322 + VIA_WRITE(0x43C, 0xfe020000);
323 +
324 + for (i = 0; i <= 0x03; i++)
325 + VIA_WRITE(0x440, (unsigned long) i << 24);
326 +
327 + VIA_WRITE(0x43C, 0x00030000);
328 +
329 + for (i = 0; i <= 0xff; i++)
330 + VIA_WRITE(0x440, 0);
331 +
332 + VIA_WRITE(0x43C, 0x00100000);
333 + VIA_WRITE(0x440, 0x00333004);
334 + VIA_WRITE(0x440, 0x10000002);
335 + VIA_WRITE(0x440, 0x60000000);
336 + VIA_WRITE(0x440, 0x61000000);
337 + VIA_WRITE(0x440, 0x62000000);
338 + VIA_WRITE(0x440, 0x63000000);
339 + VIA_WRITE(0x440, 0x64000000);
340 +
341 + VIA_WRITE(0x43C, 0x00fe0000);
342 + VIA_WRITE(0x440, 0x40008c0f);
343 + VIA_WRITE(0x440, 0x44000000);
344 + VIA_WRITE(0x440, 0x45080C04);
345 + VIA_WRITE(0x440, 0x46800408);
346 + VIA_WRITE(0x440, 0x50000000);
347 + VIA_WRITE(0x440, 0x51000000);
348 + VIA_WRITE(0x440, 0x52000000);
349 + VIA_WRITE(0x440, 0x53000000);
350 +
351 +
352 + VIA_WRITE(0x43C, 0x00fe0000);
353 + VIA_WRITE(0x440, 0x08000001);
354 + VIA_WRITE(0x440, 0x0A000183);
355 + VIA_WRITE(0x440, 0x0B00019F);
356 + VIA_WRITE(0x440, 0x0C00018B);
357 + VIA_WRITE(0x440, 0x0D00019B);
358 + VIA_WRITE(0x440, 0x0E000000);
359 + VIA_WRITE(0x440, 0x0F000000);
360 + VIA_WRITE(0x440, 0x10000000);
361 + VIA_WRITE(0x440, 0x11000000);
362 + VIA_WRITE(0x440, 0x20000000);
363 +}
364 +/* For acpi case, when system resume from suspend or hibernate,
365 + * need to re-initialize dma info into HW
366 + */
367 +int via_drm_resume(struct pci_dev *pci)
368 +{
369 + struct drm_device *dev = (struct drm_device *)pci_get_drvdata(pci);
370 + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
371 + struct drm_via_video_save_head *pnode = 0;
372 +
373 + if (!dev_priv->initialize)
374 + return 0;
375 + /* when resume, initialize 3d registers */
376 + initialize3Dengine(dev_priv);
377 +
378 + /* here we need to restore some video memory content */
379 + for (pnode = via_video_save_head; pnode; pnode = pnode->next)
380 + memcpy(pnode->pvideomem, pnode->psystemmem, pnode->size);
381 +
382 + /* if pci path, return */
383 + if (!dev_priv->ring.virtual_start)
384 + return 0;
385 +
386 + dev_priv->dma_ptr = dev_priv->ring.virtual_start;
387 + dev_priv->dma_low = 0;
388 + dev_priv->dma_high = 0x1000000;
389 + dev_priv->dma_wrap = 0x1000000;
390 + dev_priv->dma_offset = 0x0;
391 + dev_priv->last_pause_ptr = NULL;
392 + dev_priv->hw_addr_ptr = dev_priv->mmio->handle + 0x418;
393 +
394 + via_cmdbuf_start(dev_priv);
395 +
396 + return 0;
397 +}
398 +
399 +int via_drm_suspend(struct pci_dev *pci, pm_message_t state)
400 +{
401 + struct drm_device *dev = (struct drm_device *)pci_get_drvdata(pci);
402 + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
403 +
404 + struct drm_via_video_save_head *pnode = 0;
405 +
406 + if (!dev_priv->initialize)
407 + return 0;
408 + /*here we need to save some video mem information into system memory,
409 + to keep the system consistent between suspend *before* and *after*
410 + 1.save only necessary */
411 + for (pnode = via_video_save_head; pnode;
412 + pnode = (struct drm_via_video_save_head *)pnode->next)
413 + memcpy(pnode->psystemmem, pnode->pvideomem, pnode->size);
414 +
415 + /* Only agp path need to flush the cmd */
416 + if (dev_priv->ring.virtual_start)
417 + via_cmdbuf_reset(dev_priv);
418 +
419 + return 0;
420 +}
421 +int via_drm_authmagic(struct drm_device *dev, void *data,
422 + struct drm_file *file_priv)
423 +{
424 + return 0;
425 +}
426 +
427 +int via_drm_init_judge(struct drm_device *dev, void *data,
428 + struct drm_file *file_priv)
429 +{
430 + struct drm_via_private *dev_priv = dev->dev_private;
431 +
432 + if (dev_priv->initialize)
433 + *(int *)data = 1;
434 + else
435 + *(int *)data = -1;
436 + return 0;
437 +}
438 +
439 struct drm_ioctl_desc via_ioctls[] = {
440 DRM_IOCTL_DEF(DRM_VIA_ALLOCMEM, via_mem_alloc, DRM_AUTH),
441 DRM_IOCTL_DEF(DRM_VIA_FREEMEM, via_mem_free, DRM_AUTH),
442 @@ -742,6 +1073,7 @@ struct drm_ioctl_desc via_ioctls[] = {
443 DRM_IOCTL_DEF(DRM_VIA_FB_INIT, via_fb_init, DRM_AUTH|DRM_MASTER),
444 DRM_IOCTL_DEF(DRM_VIA_MAP_INIT, via_map_init, DRM_AUTH|DRM_MASTER),
445 DRM_IOCTL_DEF(DRM_VIA_DEC_FUTEX, via_decoder_futex, DRM_AUTH),
446 + DRM_IOCTL_DEF(DRM_VIA_GET_INFO, via_get_drm_info, DRM_AUTH),
447 DRM_IOCTL_DEF(DRM_VIA_DMA_INIT, via_dma_init, DRM_AUTH),
448 DRM_IOCTL_DEF(DRM_VIA_CMDBUFFER, via_cmdbuffer, DRM_AUTH),
449 DRM_IOCTL_DEF(DRM_VIA_FLUSH, via_flush_ioctl, DRM_AUTH),
450 @@ -749,7 +1081,10 @@ struct drm_ioctl_desc via_ioctls[] = {
451 DRM_IOCTL_DEF(DRM_VIA_CMDBUF_SIZE, via_cmdbuf_size, DRM_AUTH),
452 DRM_IOCTL_DEF(DRM_VIA_WAIT_IRQ, via_wait_irq, DRM_AUTH),
453 DRM_IOCTL_DEF(DRM_VIA_DMA_BLIT, via_dma_blit, DRM_AUTH),
454 - DRM_IOCTL_DEF(DRM_VIA_BLIT_SYNC, via_dma_blit_sync, DRM_AUTH)
455 + DRM_IOCTL_DEF(DRM_VIA_BLIT_SYNC, via_dma_blit_sync, DRM_AUTH),
456 + DRM_IOCTL_DEF(DRM_VIA_AUTH_MAGIC, via_drm_authmagic, 0),
457 + DRM_IOCTL_DEF(DRM_VIA_FLUSH_VIDEO, via_cmdbuffer_video_agp, 0),
458 + DRM_IOCTL_DEF(DRM_VIA_INIT_JUDGE, via_drm_init_judge, 0)
459 };
460
461 int via_max_ioctl = DRM_ARRAY_SIZE(via_ioctls);
462 --- a/drivers/gpu/drm/via/via_drv.c
463 +++ b/drivers/gpu/drm/via/via_drv.c
464 @@ -37,10 +37,16 @@ static struct pci_device_id pciidlist[]
465 viadrv_PCI_IDS
466 };
467
468 +int via_driver_open(struct drm_device *dev, struct drm_file *priv)
469 +{
470 + priv->authenticated = 1;
471 + return 0;
472 +}
473 static struct drm_driver driver = {
474 .driver_features =
475 DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ |
476 DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
477 + .open = via_driver_open,
478 .load = via_driver_load,
479 .unload = via_driver_unload,
480 .context_dtor = via_final_context,
481 @@ -68,8 +74,10 @@ static struct drm_driver driver = {
482 .fasync = drm_fasync,
483 },
484 .pci_driver = {
485 - .name = DRIVER_NAME,
486 - .id_table = pciidlist,
487 + .name = DRIVER_NAME,
488 + .id_table = pciidlist,
489 + .suspend = via_drm_suspend,
490 + .resume = via_drm_resume,
491 },
492
493 .name = DRIVER_NAME,
494 --- a/drivers/gpu/drm/via/via_drv.h
495 +++ b/drivers/gpu/drm/via/via_drv.h
496 @@ -62,6 +62,7 @@ typedef struct drm_via_private {
497 drm_local_map_t *sarea;
498 drm_local_map_t *fb;
499 drm_local_map_t *mmio;
500 + enum drm_agp_type agptype;
501 unsigned long agpAddr;
502 wait_queue_head_t decoder_queue[VIA_NR_XVMC_LOCKS];
503 char *dma_ptr;
504 @@ -93,7 +94,13 @@ typedef struct drm_via_private {
505 unsigned long vram_offset;
506 unsigned long agp_offset;
507 drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES];
508 + struct drm_map video_agp_address_map[3];
509 + enum {
510 + CR_FOR_RINGBUFFER,
511 + CR_FOR_VIDEO
512 + } cr_status;
513 uint32_t dma_diff;
514 + int initialize;
515 } drm_via_private_t;
516
517 enum via_family {
518 @@ -119,6 +126,8 @@ extern int via_mem_free(struct drm_devic
519 extern int via_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
520 extern int via_map_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
521 extern int via_decoder_futex(struct drm_device *dev, void *data, struct drm_file *file_priv);
522 +extern int via_get_drm_info(struct drm_device *dev, void *data,
523 + struct drm_file *file_priv);
524 extern int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv);
525 extern int via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file *file_priv );
526 extern int via_dma_blit( struct drm_device *dev, void *data, struct drm_file *file_priv );
527 @@ -150,4 +159,7 @@ extern void via_lastclose(struct drm_dev
528 extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq);
529 extern void via_init_dmablit(struct drm_device *dev);
530
531 +extern int via_drm_resume(struct pci_dev *dev);
532 +extern int via_drm_suspend(struct pci_dev *dev, pm_message_t state);
533 +
534 #endif
535 --- a/drivers/gpu/drm/via/via_map.c
536 +++ b/drivers/gpu/drm/via/via_map.c
537 @@ -25,6 +25,7 @@
538 #include "via_drm.h"
539 #include "via_drv.h"
540
541 +static int associate;
542 static int via_do_init_map(struct drm_device * dev, drm_via_init_t * init)
543 {
544 drm_via_private_t *dev_priv = dev->dev_private;
545 @@ -65,12 +66,35 @@ static int via_do_init_map(struct drm_de
546 via_init_dmablit(dev);
547
548 dev->dev_private = (void *)dev_priv;
549 +
550 + /* from doing this, we has the stuff in prev data
551 + * structure to manage agp
552 + */
553 + if (init->agp_type != DISABLED) {
554 + dev->agp_buffer_map = drm_core_findmap(dev, init->agp_offset);
555 + if (!dev->agp_buffer_map) {
556 + DRM_ERROR("failed to find dma buffer region!\n");
557 + return -EINVAL;
558 + }
559 + if (init->agp_type == AGP_DOUBLE_BUFFER)
560 + dev_priv->agptype = AGP_DOUBLE_BUFFER;
561 + if (init->agp_type == AGP_RING_BUFFER)
562 + dev_priv->agptype = AGP_RING_BUFFER;
563 + } else {
564 + dev_priv->agptype = DISABLED;
565 + dev->agp_buffer_map = 0;
566 + }
567 + /* end */
568 + dev_priv->initialize = 1;
569 +
570 return 0;
571 }
572
573 int via_do_cleanup_map(struct drm_device * dev)
574 {
575 + drm_via_private_t *dev_priv = dev->dev_private;
576 via_dma_cleanup(dev);
577 + dev_priv->initialize = 0;
578
579 return 0;
580 }
581 @@ -95,6 +119,11 @@ int via_driver_load(struct drm_device *d
582 {
583 drm_via_private_t *dev_priv;
584 int ret = 0;
585 + if (!associate) {
586 + pci_set_drvdata(dev->pdev, dev);
587 + dev->pdev->driver = &dev->driver->pci_driver;
588 + associate = 1;
589 + }
590
591 dev_priv = drm_calloc(1, sizeof(drm_via_private_t), DRM_MEM_DRIVER);
592 if (dev_priv == NULL)
593 @@ -121,3 +150,19 @@ int via_driver_unload(struct drm_device
594
595 return 0;
596 }
597 +int via_get_drm_info(struct drm_device *dev, void *data,
598 + struct drm_file *file_priv)
599 +{
600 + drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
601 + struct drm_via_info *info = data;
602 +
603 + if (!dev_priv->initialize)
604 + return -EINVAL;
605 +
606 + info->RegSize = dev_priv->mmio->size;
607 + info->AgpSize = dev->agp_buffer_map->size;
608 + info->RegHandle = dev_priv->mmio->offset;
609 + info->AgpHandle = dev->agp_buffer_map->offset;
610 +
611 + return 0;
612 +}
613 --- a/drivers/gpu/drm/via/via_mm.c
614 +++ b/drivers/gpu/drm/via/via_mm.c
615 @@ -30,6 +30,7 @@
616 #include "via_drv.h"
617 #include "drm_sman.h"
618
619 +struct drm_via_video_save_head *via_video_save_head;
620 #define VIA_MM_ALIGN_SHIFT 4
621 #define VIA_MM_ALIGN_MASK ( (1 << VIA_MM_ALIGN_SHIFT) - 1)
622
623 @@ -56,6 +57,8 @@ int via_agp_init(struct drm_device *dev,
624 DRM_DEBUG("offset = %u, size = %u\n", agp->offset, agp->size);
625 return 0;
626 }
627 +static void *global_dev;
628 +static void *global_file_priv;
629
630 int via_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
631 {
632 @@ -78,6 +81,8 @@ int via_fb_init(struct drm_device *dev,
633
634 mutex_unlock(&dev->struct_mutex);
635 DRM_DEBUG("offset = %u, size = %u\n", fb->offset, fb->size);
636 + global_dev = dev;
637 + global_file_priv = file_priv;
638
639 return 0;
640
641 @@ -115,6 +120,84 @@ void via_lastclose(struct drm_device *de
642 mutex_unlock(&dev->struct_mutex);
643 }
644
645 +static int via_videomem_presave_ok(drm_via_private_t *dev_priv,
646 + drm_via_mem_t *mem)
647 +{
648 + void *pvideomem = 0, *psystemmem = 0;
649 + struct drm_via_video_save_head *pnode = 0;
650 +
651 + if (!mem || !mem->size || (mem->type != VIA_MEM_VIDEO_SAVE))
652 + return 0;
653 +
654 + /* here the mem->offset is the absolute address,
655 + * not the offset within videomem
656 + */
657 + pvideomem = (void *)ioremap(dev_priv->fb->offset + mem->offset,
658 + mem->size);
659 + if (!pvideomem)
660 + return 0;
661 +
662 + psystemmem = kmalloc(mem->size, GFP_KERNEL);
663 + if (!psystemmem) {
664 + iounmap(pvideomem);
665 + return 0;
666 + }
667 +
668 + /* map success, then save this information into
669 + * a data structure for later saving usage
670 + */
671 + pnode = kmalloc(
672 + sizeof(struct drm_via_video_save_head), GFP_KERNEL);
673 + if (!pnode) {
674 + iounmap(pvideomem);
675 + kfree(psystemmem);
676 + return 0;
677 + }
678 +
679 + pnode->next = 0;
680 + pnode->psystemmem = psystemmem;
681 + pnode->pvideomem = pvideomem;
682 + pnode->size = mem->size;
683 + pnode->token = mem->offset;
684 +
685 + /* insert this node into list */
686 + if (!via_video_save_head) {
687 + via_video_save_head = pnode;
688 + } else {
689 + pnode->next = via_video_save_head;
690 + via_video_save_head = pnode;
691 + }
692 +
693 + return 1;
694 +}
695 +
696 +static int via_videomem_housekeep_ok(drm_via_mem_t *mem)
697 +{
698 + struct drm_via_video_save_head **ppnode = 0;
699 + struct drm_via_video_save_head *tmpnode = 0;
700 + /* if this mem's token match with one node of the list */
701 + for (ppnode = &via_video_save_head; *ppnode;
702 + ppnode = (struct drm_via_video_save_head **)(&((*ppnode)->next))) {
703 + if ((*ppnode)->token == mem->offset)
704 + break;
705 + }
706 +
707 + if (*ppnode == 0) {
708 + /* not found, the user may specify the wrong mem node to free */
709 + return 0;
710 + }
711 +
712 + /* delete this node from the list and then
713 + *free all the mem to avoid memory leak
714 + */
715 + tmpnode = *ppnode;
716 + *ppnode = (*ppnode)->next;
717 + iounmap(tmpnode->pvideomem);
718 + kfree(tmpnode->psystemmem);
719 + kfree(tmpnode);
720 +
721 + return 1;
722 +}
723 int via_mem_alloc(struct drm_device *dev, void *data,
724 struct drm_file *file_priv)
725 {
726 @@ -124,12 +207,13 @@ int via_mem_alloc(struct drm_device *dev
727 drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
728 unsigned long tmpSize;
729
730 - if (mem->type > VIA_MEM_AGP) {
731 + if (mem->type > VIA_MEM_VIDEO_SAVE) {
732 DRM_ERROR("Unknown memory type allocation\n");
733 return -EINVAL;
734 }
735 mutex_lock(&dev->struct_mutex);
736 - if (0 == ((mem->type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized :
737 + if (0 == ((mem->type == VIA_MEM_VIDEO ||
738 + mem->type == VIA_MEM_VIDEO_SAVE) ? dev_priv->vram_initialized :
739 dev_priv->agp_initialized)) {
740 DRM_ERROR
741 ("Attempt to allocate from uninitialized memory manager.\n");
742 @@ -138,15 +222,25 @@ int via_mem_alloc(struct drm_device *dev
743 }
744
745 tmpSize = (mem->size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT;
746 - item = drm_sman_alloc(&dev_priv->sman, mem->type, tmpSize, 0,
747 - (unsigned long)file_priv);
748 + item = drm_sman_alloc(&dev_priv->sman,
749 + (mem->type == VIA_MEM_VIDEO_SAVE ? VIA_MEM_VIDEO : mem->type),
750 + tmpSize, 0, (unsigned long)file_priv);
751 mutex_unlock(&dev->struct_mutex);
752 if (item) {
753 - mem->offset = ((mem->type == VIA_MEM_VIDEO) ?
754 - dev_priv->vram_offset : dev_priv->agp_offset) +
755 - (item->mm->
756 - offset(item->mm, item->mm_info) << VIA_MM_ALIGN_SHIFT);
757 + mem->offset = ((mem->type == VIA_MEM_VIDEO ||
758 + mem->type == VIA_MEM_VIDEO_SAVE) ?
759 + dev_priv->vram_offset : dev_priv->agp_offset) +
760 + (item->mm->offset(item->mm, item->mm_info) <<
761 + VIA_MM_ALIGN_SHIFT);
762 mem->index = item->user_hash.key;
763 + if (mem->type == VIA_MEM_VIDEO_SAVE) {
764 + if (!via_videomem_presave_ok(dev_priv, mem)) {
765 + mutex_lock(&dev->struct_mutex);
766 + drm_sman_free_key(&dev_priv->sman, mem->index);
767 + mutex_unlock(&dev->struct_mutex);
768 + retval = -ENOMEM;
769 + }
770 + }
771 } else {
772 mem->offset = 0;
773 mem->size = 0;
774 @@ -166,6 +260,10 @@ int via_mem_free(struct drm_device *dev,
775
776 mutex_lock(&dev->struct_mutex);
777 ret = drm_sman_free_key(&dev_priv->sman, mem->index);
778 + if (mem->type == VIA_MEM_VIDEO_SAVE) {
779 + if (!via_videomem_housekeep_ok(mem))
780 + ret = -EINVAL;
781 + }
782 mutex_unlock(&dev->struct_mutex);
783 DRM_DEBUG("free = 0x%lx\n", mem->index);
784
785 @@ -192,3 +290,26 @@ void via_reclaim_buffers_locked(struct d
786 mutex_unlock(&dev->struct_mutex);
787 return;
788 }
789 +static int via_fb_alloc(drm_via_mem_t *mem)
790 +{
791 + struct drm_device *dev = global_dev;
792 + struct drm_file *file_priv = global_file_priv;
793 +
794 + if (dev && file_priv)
795 + return via_mem_alloc(dev, mem, file_priv);
796 + else
797 + return -EINVAL;
798 +}
799 +EXPORT_SYMBOL(via_fb_alloc);
800 +
801 +static int via_fb_free(drm_via_mem_t *mem)
802 +{
803 + struct drm_device *dev = global_dev;
804 + struct drm_file *file_priv = global_file_priv;
805 +
806 + if (dev && file_priv)
807 + return via_mem_free(dev, mem, file_priv);
808 + else
809 + return -EINVAL;
810 +}
811 +EXPORT_SYMBOL(via_fb_free);
812 --- a/include/drm/via_drm.h
813 +++ b/include/drm/via_drm.h
814 @@ -51,6 +51,12 @@
815 #define VIA_LOG_MIN_TEX_REGION_SIZE 16
816 #endif
817
818 +struct drm_via_info {
819 + unsigned long AgpHandle;
820 + unsigned long AgpSize;
821 + unsigned long RegHandle;
822 + unsigned long RegSize;
823 +} ;
824 #define VIA_UPLOAD_TEX0IMAGE 0x1 /* handled clientside */
825 #define VIA_UPLOAD_TEX1IMAGE 0x2 /* handled clientside */
826 #define VIA_UPLOAD_CTX 0x4
827 @@ -67,7 +73,7 @@
828 #define DRM_VIA_FB_INIT 0x03
829 #define DRM_VIA_MAP_INIT 0x04
830 #define DRM_VIA_DEC_FUTEX 0x05
831 -#define NOT_USED
832 +#define DRM_VIA_GET_INFO 0x06
833 #define DRM_VIA_DMA_INIT 0x07
834 #define DRM_VIA_CMDBUFFER 0x08
835 #define DRM_VIA_FLUSH 0x09
836 @@ -77,6 +83,9 @@
837 #define DRM_VIA_WAIT_IRQ 0x0d
838 #define DRM_VIA_DMA_BLIT 0x0e
839 #define DRM_VIA_BLIT_SYNC 0x0f
840 +#define DRM_VIA_AUTH_MAGIC 0x11
841 +#define DRM_VIA_FLUSH_VIDEO 0x12
842 +#define DRM_VIA_INIT_JUDGE 0x16
843
844 #define DRM_IOCTL_VIA_ALLOCMEM DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_ALLOCMEM, drm_via_mem_t)
845 #define DRM_IOCTL_VIA_FREEMEM DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_FREEMEM, drm_via_mem_t)
846 @@ -84,6 +93,8 @@
847 #define DRM_IOCTL_VIA_FB_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_FB_INIT, drm_via_fb_t)
848 #define DRM_IOCTL_VIA_MAP_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_MAP_INIT, drm_via_init_t)
849 #define DRM_IOCTL_VIA_DEC_FUTEX DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_DEC_FUTEX, drm_via_futex_t)
850 +#define DRM_IOCTL_VIA_GET_INFO DRM_IOR(DRM_COMMAND_BASE + \
851 + DRM_VIA_GET_INFO, struct drm_via_info)
852 #define DRM_IOCTL_VIA_DMA_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_DMA_INIT, drm_via_dma_init_t)
853 #define DRM_IOCTL_VIA_CMDBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_CMDBUFFER, drm_via_cmdbuffer_t)
854 #define DRM_IOCTL_VIA_FLUSH DRM_IO( DRM_COMMAND_BASE + DRM_VIA_FLUSH)
855 @@ -91,8 +102,14 @@
856 #define DRM_IOCTL_VIA_CMDBUF_SIZE DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_CMDBUF_SIZE, \
857 drm_via_cmdbuf_size_t)
858 #define DRM_IOCTL_VIA_WAIT_IRQ DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_WAIT_IRQ, drm_via_irqwait_t)
859 +#define DRM_IOCTL_VIA_FLUSH_VIDEO DRM_IOW(DRM_COMMAND_BASE + \
860 + DRM_VIA_FLUSH_VIDEO, struct drm_via_video_agp_cmd)
861 #define DRM_IOCTL_VIA_DMA_BLIT DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_DMA_BLIT, drm_via_dmablit_t)
862 #define DRM_IOCTL_VIA_BLIT_SYNC DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_BLIT_SYNC, drm_via_blitsync_t)
863 +#define DRM_IOCTL_VIA_AUTH_MAGIC DRM_IOW(DRM_COMMAND_BASE + \
864 + DRM_VIA_AUTH_MAGIC, drm_auth_t)
865 +#define DRM_IOCTL_VIA_INIT_JUDGE DRM_IOR(DRM_COMMAND_BASE + \
866 + DRM_VIA_INIT_JUDGE, int)
867
868 /* Indices into buf.Setup where various bits of state are mirrored per
869 * context and per buffer. These can be fired at the card as a unit,
870 @@ -112,6 +129,13 @@
871 #define VIA_MEM_SYSTEM 2
872 #define VIA_MEM_MIXED 3
873 #define VIA_MEM_UNKNOWN 4
874 +#define VIA_MEM_VIDEO_SAVE 2 /*For video memory need to be saved in ACPI */
875 +
876 +enum drm_agp_type {
877 + AGP_RING_BUFFER,
878 + AGP_DOUBLE_BUFFER,
879 + DISABLED
880 +};
881
882 typedef struct {
883 uint32_t offset;
884 @@ -141,6 +165,8 @@ typedef struct _drm_via_init {
885 unsigned long fb_offset;
886 unsigned long mmio_offset;
887 unsigned long agpAddr;
888 + unsigned long agp_offset;
889 + enum drm_agp_type agp_type;
890 } drm_via_init_t;
891
892 typedef struct _drm_via_futex {
893 @@ -245,6 +271,12 @@ typedef union drm_via_irqwait {
894 struct drm_wait_vblank_reply reply;
895 } drm_via_irqwait_t;
896
897 +struct drm_via_video_agp_cmd {
898 + u32 offset;
899 + u32 cmd_size;
900 + u32 buffer_size;
901 +} ;
902 +
903 typedef struct drm_via_blitsync {
904 uint32_t sync_handle;
905 unsigned engine;
906 @@ -272,4 +304,13 @@ typedef struct drm_via_dmablit {
907 drm_via_blitsync_t sync;
908 } drm_via_dmablit_t;
909
910 +struct drm_via_video_save_head {
911 + void *pvideomem;
912 + void *psystemmem;
913 + int size;
914 + /* token used to identify this video memory */
915 + unsigned long token;
916 + void *next;
917 +} ;
918 +extern struct drm_via_video_save_head *via_video_save_head;
919 #endif /* _VIA_DRM_H_ */