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.

Signed-off-by: Jakob Bornecrantz <jakob@vmware.com>
Reviewed-by: Biran Paul <brianp@vmware.com>
Reviewed-by: Zack Rusin <zackr@vmware.com>
Cc: stable@vger.kernel.org
Signed-off-by: Dave Airlie <airlied@gmail.com>

authored by Jakob Bornecrantz and committed by Dave Airlie 6e4dcff3 1dcff832

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