History

drm/vmwgfx: Split GMR2_REMAP commands if they are to large

This fixes the piglit test texturing/max-texture-size causing the VM to die due to a too large SVGA command.

Jakob Bornecrantz committed 13 years ago

Commit 6e4dcff1 parent 1dcff831 file · +39 −19Browse files

Unified · Split

drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c+39−19
@@ -29,7 +29,9 @@ · 28 unmodified lines
29#include <drm/drmP.h>29#include <drm/drmP.h>
30#include <drm/ttm/ttm_bo_driver.h>30#include <drm/ttm/ttm_bo_driver.h>
31 31
32#define VMW_PPN_SIZE sizeof(unsigned long)32#define VMW_PPN_SIZE (sizeof(unsigned long))
33/* A future safe maximum remap size. */
34#define VMW_PPN_PER_REMAP ((31 * 1024) / VMW_PPN_SIZE)
33 35
34static int vmw_gmr2_bind(struct vmw_private *dev_priv,36static int vmw_gmr2_bind(struct vmw_private *dev_priv,
35 struct page *pages[],37 struct page *pages[],
@@ -38,43 +40,61 @@ static int vmw_gmr2_bind(struct vmw_private *dev_priv, · 2 unmodified lines
38{40{
39 SVGAFifoCmdDefineGMR2 define_cmd;41 SVGAFifoCmdDefineGMR2 define_cmd;
40 SVGAFifoCmdRemapGMR2 remap_cmd;42 SVGAFifoCmdRemapGMR2 remap_cmd;
41 uint32_t define_size = sizeof(define_cmd) + 4;
42 uint32_t remap_size = VMW_PPN_SIZE * num_pages + sizeof(remap_cmd) + 4;
43 uint32_t *cmd;43 uint32_t *cmd;
44 uint32_t *cmd_orig;44 uint32_t *cmd_orig;
45 uint32_t define_size = sizeof(define_cmd) + sizeof(*cmd);
46 uint32_t remap_num = num_pages / VMW_PPN_PER_REMAP + ((num_pages % VMW_PPN_PER_REMAP) > 0);
47 uint32_t remap_size = VMW_PPN_SIZE * num_pages + (sizeof(remap_cmd) + sizeof(*cmd)) * remap_num;
48 uint32_t remap_pos = 0;
49 uint32_t cmd_size = define_size + remap_size;
45 uint32_t i;50 uint32_t i;
46 51
47 cmd_orig = cmd = vmw_fifo_reserve(dev_priv, define_size + remap_size);52 cmd_orig = cmd = vmw_fifo_reserve(dev_priv, cmd_size);
48 if (unlikely(cmd == NULL))53 if (unlikely(cmd == NULL))
49 return -ENOMEM;54 return -ENOMEM;
50 55
51 define_cmd.gmrId = gmr_id;56 define_cmd.gmrId = gmr_id;
52 define_cmd.numPages = num_pages;57 define_cmd.numPages = num_pages;
53 58
59 *cmd++ = SVGA_CMD_DEFINE_GMR2;
60 memcpy(cmd, &define_cmd, sizeof(define_cmd));
61 cmd += sizeof(define_cmd) / sizeof(*cmd);
62
63 /*
64 * Need to split the command if there are too many
65 * pages that goes into the gmr.
66 */
67
54 remap_cmd.gmrId = gmr_id;68 remap_cmd.gmrId = gmr_id;
55 remap_cmd.flags = (VMW_PPN_SIZE > sizeof(*cmd)) ?69 remap_cmd.flags = (VMW_PPN_SIZE > sizeof(*cmd)) ?
56 SVGA_REMAP_GMR2_PPN64 : SVGA_REMAP_GMR2_PPN32;70 SVGA_REMAP_GMR2_PPN64 : SVGA_REMAP_GMR2_PPN32;
57 remap_cmd.offsetPages = 0;
58 remap_cmd.numPages = num_pages;
59 71
60 *cmd++ = SVGA_CMD_DEFINE_GMR2;72 while (num_pages > 0) {
61 memcpy(cmd, &define_cmd, sizeof(define_cmd));73 unsigned long nr = min(num_pages, (unsigned long)VMW_PPN_PER_REMAP);
62 cmd += sizeof(define_cmd) / sizeof(uint32);74
75 remap_cmd.offsetPages = remap_pos;
76 remap_cmd.numPages = nr;
63 77
64 *cmd++ = SVGA_CMD_REMAP_GMR2;78 *cmd++ = SVGA_CMD_REMAP_GMR2;
65 memcpy(cmd, &remap_cmd, sizeof(remap_cmd));79 memcpy(cmd, &remap_cmd, sizeof(remap_cmd));
66 cmd += sizeof(remap_cmd) / sizeof(uint32);80 cmd += sizeof(remap_cmd) / sizeof(*cmd);
67 81
68 for (i = 0; i < num_pages; ++i) {82 for (i = 0; i < nr; ++i) {
69 if (VMW_PPN_SIZE <= 4)83 if (VMW_PPN_SIZE <= 4)
70 *cmd = page_to_pfn(*pages++);84 *cmd = page_to_pfn(*pages++);
71 else85 else
72 *((uint64_t *)cmd) = page_to_pfn(*pages++);86 *((uint64_t *)cmd) = page_to_pfn(*pages++);
73 87
74 cmd += VMW_PPN_SIZE / sizeof(*cmd);88 cmd += VMW_PPN_SIZE / sizeof(*cmd);
89 }
90
91 num_pages -= nr;
92 remap_pos += nr;
75 }93 }
76 94
77 vmw_fifo_commit(dev_priv, define_size + remap_size);95 BUG_ON(cmd != cmd_orig + cmd_size / sizeof(*cmd));
96
97 vmw_fifo_commit(dev_priv, cmd_size);
78 98
79 return 0;99 return 0;
80}100}