1 From: Bruce Chang <BruceChang@via.com.tw>
2 Subject: via: Unichrome DRM bugfixes
4 1. Patch the system hang issue caused by multi X support when doing
6 2. Patch system hang issue caused by 3D scaling+ACPI
7 3. Patch segmentation fault issue caused by playing video with AGP after
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
16 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
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(-)
27 --- a/drivers/gpu/drm/via/via_dma.c
28 +++ b/drivers/gpu/drm/via/via_dma.c
31 dev_priv->dma_low += 8;
33 +#define VIA_OUT_VIDEO_AGP_BUFFER(cmd1, cmd2) \
35 + *cur_virtual++ = cmd1; \
36 + *cur_virtual++ = cmd2; \
37 + cmdbuf_info.cmd_size += 8; \
40 +static void via_cmdbuf_flush(struct drm_via_private *dev_priv,
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);
51 * Free space in command buffer.
53 @@ -155,17 +165,35 @@ static inline uint32_t *via_check_dma(dr
55 int via_dma_cleanup(struct drm_device * dev)
57 + struct drm_via_video_save_head *pnode;
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;
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);
73 + via_wait_idle(dev_priv);
75 drm_core_ioremapfree(&dev_priv->ring.map, dev);
76 dev_priv->ring.virtual_start = NULL;
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;
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)
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");
98 @@ -194,6 +223,9 @@ static int via_initialize(struct drm_dev
99 DRM_ERROR("AGP DMA is not supported on this chip\n");
103 + for (pnode = via_video_save_head; pnode; pnode = pnode->next)
104 + memcpy(pnode->pvideomem, pnode->psystemmem, pnode->size);
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
110 via_cmdbuf_start(dev_priv);
112 + dev_priv->cr_status = CR_FOR_RINGBUFFER;
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)
119 drm_via_cmdbuffer_t *cmdbuf = data;
121 + drm_via_private_t *dev_priv = dev->dev_private;
122 + int ret = 0, count;
124 LOCK_TEST_WITH_RETURN(dev, file_priv);
126 DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size);
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.
134 + while (count-- && (VIA_READ(VIA_REG_STATUS) &
135 + VIA_CMD_RGTR_BUSY))
137 + /* Seldom happen */
139 + DRM_INFO("The CR can't be idle from video agp cmd \
140 + dispatch when it is needed by ring buffer \n");
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;
152 + via_cmdbuf_start(dev_priv);
154 + dev_priv->cr_status = CR_FOR_RINGBUFFER;
157 ret = via_dispatch_cmdbuffer(dev, cmdbuf);
160 @@ -346,6 +409,134 @@ static int via_cmdbuffer(struct drm_devi
164 +int via_cmdbuffer_video_agp(struct drm_device *dev, void *data,
165 + struct drm_file *file_priv)
167 + drm_via_private_t *dev_priv = dev->dev_private;
168 + struct drm_via_video_agp_cmd cmdbuf_info;
170 + u32 start_addr, start_addr_lo;
171 + u32 end_addr, end_addr_lo;
172 + u32 pause_addr, pause_addr_hi, pause_addr_lo;
176 + struct drm_map map;
178 + LOCK_TEST_WITH_RETURN(dev, file_priv);
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
186 + via_cmdbuf_flush(dev_priv, HC_HAGPBpID_STOP);
189 + /* Set CR status here to avoid ring buffer crush in case we
190 + * can't initialize CR for video properly
192 + dev_priv->cr_status = CR_FOR_VIDEO;
194 + /* Wait idle since we will reset CR relevant registers. */
196 + while (count-- && (VIA_READ(VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY))
199 + /* Seldom happen */
201 + DRM_INFO("The CR can't be idle from video agp cmd dispatch \
202 + when it is needed by ring buffer \n");
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!!!
210 + cmdbuf_info = *(struct drm_via_video_agp_cmd *)data;
212 + start_addr = cmdbuf_info.offset + dev->agp->base;
213 + end_addr = cmdbuf_info.buffer_size + start_addr;
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");
223 + map.offset = start_addr;
224 + map.size = cmdbuf_info.buffer_size;
225 + map.type = map.flags = map.mtrr = 0;
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;
235 + if (!dev_priv->video_agp_address_map[i].handle)
239 + /* Check whether this agp cmd buffer has already been remaped before */
240 + /* case: Never be remaped before */
242 + drm_core_ioremap(&map, dev);
245 + /* there is a free hole for filling in this address map */
247 + dev_priv->video_agp_address_map[i] = map;
249 + drm_core_ioremapfree(dev_priv->video_agp_address_map,
251 + dev_priv->video_agp_address_map[0] = map;
255 + cur_virtual = map.handle + cmdbuf_info.cmd_size;
257 + VIA_OUT_VIDEO_AGP_BUFFER(HC_HEADER2 | ((VIA_REG_TRANSET >> 2) << 12) |
258 + (VIA_REG_TRANSPACE >> 2), HC_ParaType_PreCR << 16);
260 + /* pause register need 0xFF alignment */
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;
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;
276 + via_flush_write_combine();
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);
283 + VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
284 + VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
285 + DRM_WRITEMEMORYBARRIER();
287 + VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
292 static int via_dispatch_pci_cmdbuffer(struct drm_device * dev,
293 drm_via_cmdbuffer_t * cmd)
295 @@ -735,6 +926,146 @@ static int via_cmdbuf_size(struct drm_de
299 +/*The following functions are for ACPI*/
301 +static void initialize3Dengine(drm_via_private_t *dev_priv)
305 + VIA_WRITE(0x43C, 0x00010000);
307 + for (i = 0; i <= 0x7D; i++)
308 + VIA_WRITE(0x440, (unsigned long) i << 24);
310 + VIA_WRITE(0x43C, 0x00020000);
312 + for (i = 0; i <= 0x94; i++)
313 + VIA_WRITE(0x440, (unsigned long) i << 24);
315 + VIA_WRITE(0x440, 0x82400000);
316 + VIA_WRITE(0x43C, 0x01020000);
318 + for (i = 0; i <= 0x94; i++)
319 + VIA_WRITE(0x440, (unsigned long) i << 24);
321 + VIA_WRITE(0x440, 0x82400000);
322 + VIA_WRITE(0x43C, 0xfe020000);
324 + for (i = 0; i <= 0x03; i++)
325 + VIA_WRITE(0x440, (unsigned long) i << 24);
327 + VIA_WRITE(0x43C, 0x00030000);
329 + for (i = 0; i <= 0xff; i++)
330 + VIA_WRITE(0x440, 0);
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);
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);
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);
364 +/* For acpi case, when system resume from suspend or hibernate,
365 + * need to re-initialize dma info into HW
367 +int via_drm_resume(struct pci_dev *pci)
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;
373 + if (!dev_priv->initialize)
375 + /* when resume, initialize 3d registers */
376 + initialize3Dengine(dev_priv);
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);
382 + /* if pci path, return */
383 + if (!dev_priv->ring.virtual_start)
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;
394 + via_cmdbuf_start(dev_priv);
399 +int via_drm_suspend(struct pci_dev *pci, pm_message_t state)
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;
404 + struct drm_via_video_save_head *pnode = 0;
406 + if (!dev_priv->initialize)
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);
415 + /* Only agp path need to flush the cmd */
416 + if (dev_priv->ring.virtual_start)
417 + via_cmdbuf_reset(dev_priv);
421 +int via_drm_authmagic(struct drm_device *dev, void *data,
422 + struct drm_file *file_priv)
427 +int via_drm_init_judge(struct drm_device *dev, void *data,
428 + struct drm_file *file_priv)
430 + struct drm_via_private *dev_priv = dev->dev_private;
432 + if (dev_priv->initialize)
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)
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[]
468 +int via_driver_open(struct drm_device *dev, struct drm_file *priv)
470 + priv->authenticated = 1;
473 static struct drm_driver driver = {
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,
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,
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;
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];
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];
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);
531 +extern int via_drm_resume(struct pci_dev *dev);
532 +extern int via_drm_suspend(struct pci_dev *dev, pm_message_t state);
535 --- a/drivers/gpu/drm/via/via_map.c
536 +++ b/drivers/gpu/drm/via/via_map.c
541 +static int associate;
542 static int via_do_init_map(struct drm_device * dev, drm_via_init_t * init)
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);
548 dev->dev_private = (void *)dev_priv;
550 + /* from doing this, we has the stuff in prev data
551 + * structure to manage agp
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");
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;
564 + dev_priv->agptype = DISABLED;
565 + dev->agp_buffer_map = 0;
568 + dev_priv->initialize = 1;
573 int via_do_cleanup_map(struct drm_device * dev)
575 + drm_via_private_t *dev_priv = dev->dev_private;
576 via_dma_cleanup(dev);
577 + dev_priv->initialize = 0;
581 @@ -95,6 +119,11 @@ int via_driver_load(struct drm_device *d
583 drm_via_private_t *dev_priv;
586 + pci_set_drvdata(dev->pdev, dev);
587 + dev->pdev->driver = &dev->driver->pci_driver;
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
597 +int via_get_drm_info(struct drm_device *dev, void *data,
598 + struct drm_file *file_priv)
600 + drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
601 + struct drm_via_info *info = data;
603 + if (!dev_priv->initialize)
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;
613 --- a/drivers/gpu/drm/via/via_mm.c
614 +++ b/drivers/gpu/drm/via/via_mm.c
617 #include "drm_sman.h"
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)
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);
627 +static void *global_dev;
628 +static void *global_file_priv;
630 int via_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
632 @@ -78,6 +81,8 @@ int via_fb_init(struct drm_device *dev,
634 mutex_unlock(&dev->struct_mutex);
635 DRM_DEBUG("offset = %u, size = %u\n", fb->offset, fb->size);
637 + global_file_priv = file_priv;
641 @@ -115,6 +120,84 @@ void via_lastclose(struct drm_device *de
642 mutex_unlock(&dev->struct_mutex);
645 +static int via_videomem_presave_ok(drm_via_private_t *dev_priv,
646 + drm_via_mem_t *mem)
648 + void *pvideomem = 0, *psystemmem = 0;
649 + struct drm_via_video_save_head *pnode = 0;
651 + if (!mem || !mem->size || (mem->type != VIA_MEM_VIDEO_SAVE))
654 + /* here the mem->offset is the absolute address,
655 + * not the offset within videomem
657 + pvideomem = (void *)ioremap(dev_priv->fb->offset + mem->offset,
662 + psystemmem = kmalloc(mem->size, GFP_KERNEL);
664 + iounmap(pvideomem);
668 + /* map success, then save this information into
669 + * a data structure for later saving usage
672 + sizeof(struct drm_via_video_save_head), GFP_KERNEL);
674 + iounmap(pvideomem);
680 + pnode->psystemmem = psystemmem;
681 + pnode->pvideomem = pvideomem;
682 + pnode->size = mem->size;
683 + pnode->token = mem->offset;
685 + /* insert this node into list */
686 + if (!via_video_save_head) {
687 + via_video_save_head = pnode;
689 + pnode->next = via_video_save_head;
690 + via_video_save_head = pnode;
696 +static int via_videomem_housekeep_ok(drm_via_mem_t *mem)
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)
707 + if (*ppnode == 0) {
708 + /* not found, the user may specify the wrong mem node to free */
712 + /* delete this node from the list and then
713 + *free all the mem to avoid memory leak
716 + *ppnode = (*ppnode)->next;
717 + iounmap(tmpnode->pvideomem);
718 + kfree(tmpnode->psystemmem);
723 int via_mem_alloc(struct drm_device *dev, void *data,
724 struct drm_file *file_priv)
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;
730 - if (mem->type > VIA_MEM_AGP) {
731 + if (mem->type > VIA_MEM_VIDEO_SAVE) {
732 DRM_ERROR("Unknown memory type allocation\n");
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)) {
741 ("Attempt to allocate from uninitialized memory manager.\n");
742 @@ -138,15 +222,25 @@ int via_mem_alloc(struct drm_device *dev
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);
753 - mem->offset = ((mem->type == VIA_MEM_VIDEO) ?
754 - dev_priv->vram_offset : dev_priv->agp_offset) +
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);
774 @@ -166,6 +260,10 @@ int via_mem_free(struct drm_device *dev,
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))
782 mutex_unlock(&dev->struct_mutex);
783 DRM_DEBUG("free = 0x%lx\n", mem->index);
785 @@ -192,3 +290,26 @@ void via_reclaim_buffers_locked(struct d
786 mutex_unlock(&dev->struct_mutex);
789 +static int via_fb_alloc(drm_via_mem_t *mem)
791 + struct drm_device *dev = global_dev;
792 + struct drm_file *file_priv = global_file_priv;
794 + if (dev && file_priv)
795 + return via_mem_alloc(dev, mem, file_priv);
799 +EXPORT_SYMBOL(via_fb_alloc);
801 +static int via_fb_free(drm_via_mem_t *mem)
803 + struct drm_device *dev = global_dev;
804 + struct drm_file *file_priv = global_file_priv;
806 + if (dev && file_priv)
807 + return via_mem_free(dev, mem, file_priv);
811 +EXPORT_SYMBOL(via_fb_free);
812 --- a/include/drm/via_drm.h
813 +++ b/include/drm/via_drm.h
815 #define VIA_LOG_MIN_TEX_REGION_SIZE 16
818 +struct drm_via_info {
819 + unsigned long AgpHandle;
820 + unsigned long AgpSize;
821 + unsigned long RegHandle;
822 + unsigned long RegSize;
824 #define VIA_UPLOAD_TEX0IMAGE 0x1 /* handled clientside */
825 #define VIA_UPLOAD_TEX1IMAGE 0x2 /* handled clientside */
826 #define VIA_UPLOAD_CTX 0x4
828 #define DRM_VIA_FB_INIT 0x03
829 #define DRM_VIA_MAP_INIT 0x04
830 #define DRM_VIA_DEC_FUTEX 0x05
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
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
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)
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)
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)
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,
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 */
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;
892 typedef struct _drm_via_futex {
893 @@ -245,6 +271,12 @@ typedef union drm_via_irqwait {
894 struct drm_wait_vblank_reply reply;
897 +struct drm_via_video_agp_cmd {
903 typedef struct drm_via_blitsync {
904 uint32_t sync_handle;
906 @@ -272,4 +304,13 @@ typedef struct drm_via_dmablit {
907 drm_via_blitsync_t sync;
910 +struct drm_via_video_save_head {
914 + /* token used to identify this video memory */
915 + unsigned long token;
918 +extern struct drm_via_video_save_head *via_video_save_head;
919 #endif /* _VIA_DRM_H_ */