From: Michel Dänzer daenzer@vmware.com
Signed-off-by: Michel Dänzer daenzer@vmware.com Signed-off-by: Thomas Hellstrom thellstrom@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 3 +++ drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 11 +++++++++++ 2 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index dfe32e6..7539b56 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -567,6 +567,9 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, case 15: format = SVGA3D_A1R5G5B5; break; + case 8: + format = SVGA3D_LUMINANCE8; + break; default: DRM_ERROR("Invalid color depth: %d\n", mode_cmd->depth); return -EINVAL; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 7b8115a..c6d09a6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -83,6 +83,15 @@ static void vmw_ldu_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start, uint32_t size) { + struct vmw_private *dev_priv = vmw_priv(crtc->dev); + int i; + + for (i = 0; i < size; i++) { + DRM_DEBUG("%d r/g/b = 0x%04x / 0x%04x / 0x%04x\n", i, r[i], g[i], b[i]); + vmw_write(dev_priv, SVGA_PALETTE_BASE + i * 3 + 0, r[i] >> 8); + vmw_write(dev_priv, SVGA_PALETTE_BASE + i * 3 + 1, g[i] >> 8); + vmw_write(dev_priv, SVGA_PALETTE_BASE + i * 3 + 2, b[i] >> 8); + } }
static void vmw_ldu_crtc_destroy(struct drm_crtc *crtc) @@ -547,6 +556,8 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
drm_crtc_init(dev, crtc, &vmw_legacy_crtc_funcs);
+ drm_mode_crtc_set_gamma_size(crtc, 256); + drm_connector_attach_property(connector, dev->mode_config.dirty_info_property, 1);
From: Michel Dänzer daenzer@vmware.com
Signed-off-by: Michel Dänzer daenzer@vmware.com Signed-off-by: Thomas Hellstrom thellstrom@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 5 ----- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 14 -------------- 2 files changed, 0 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 10fc01f..d84e7a6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -195,12 +195,7 @@ struct vmw_private { struct vmw_vga_topology_state vga_save[VMWGFX_MAX_DISPLAYS]; uint32_t vga_width; uint32_t vga_height; - uint32_t vga_depth; uint32_t vga_bpp; - uint32_t vga_pseudo; - uint32_t vga_red_mask; - uint32_t vga_green_mask; - uint32_t vga_blue_mask; uint32_t vga_bpl; uint32_t vga_pitchlock;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 7539b56..9765407 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1001,10 +1001,6 @@ void vmw_kms_write_svga(struct vmw_private *vmw_priv, vmw_write(vmw_priv, SVGA_REG_WIDTH, width); vmw_write(vmw_priv, SVGA_REG_HEIGHT, height); vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, bbp); - vmw_write(vmw_priv, SVGA_REG_DEPTH, depth); - vmw_write(vmw_priv, SVGA_REG_RED_MASK, 0x00ff0000); - vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, 0x0000ff00); - vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, 0x000000ff); }
int vmw_kms_save_vga(struct vmw_private *vmw_priv) @@ -1014,12 +1010,7 @@ int vmw_kms_save_vga(struct vmw_private *vmw_priv)
vmw_priv->vga_width = vmw_read(vmw_priv, SVGA_REG_WIDTH); vmw_priv->vga_height = vmw_read(vmw_priv, SVGA_REG_HEIGHT); - vmw_priv->vga_depth = vmw_read(vmw_priv, SVGA_REG_DEPTH); vmw_priv->vga_bpp = vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL); - vmw_priv->vga_pseudo = vmw_read(vmw_priv, SVGA_REG_PSEUDOCOLOR); - vmw_priv->vga_red_mask = vmw_read(vmw_priv, SVGA_REG_RED_MASK); - vmw_priv->vga_blue_mask = vmw_read(vmw_priv, SVGA_REG_BLUE_MASK); - vmw_priv->vga_green_mask = vmw_read(vmw_priv, SVGA_REG_GREEN_MASK); if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) vmw_priv->vga_pitchlock = vmw_read(vmw_priv, SVGA_REG_PITCHLOCK); @@ -1068,12 +1059,7 @@ int vmw_kms_restore_vga(struct vmw_private *vmw_priv)
vmw_write(vmw_priv, SVGA_REG_WIDTH, vmw_priv->vga_width); vmw_write(vmw_priv, SVGA_REG_HEIGHT, vmw_priv->vga_height); - vmw_write(vmw_priv, SVGA_REG_DEPTH, vmw_priv->vga_depth); vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, vmw_priv->vga_bpp); - vmw_write(vmw_priv, SVGA_REG_PSEUDOCOLOR, vmw_priv->vga_pseudo); - vmw_write(vmw_priv, SVGA_REG_RED_MASK, vmw_priv->vga_red_mask); - vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, vmw_priv->vga_green_mask); - vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, vmw_priv->vga_blue_mask); if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) vmw_write(vmw_priv, SVGA_REG_PITCHLOCK, vmw_priv->vga_pitchlock);
From: Michel Dänzer daenzer@vmware.com
Signed-off-by: Michel Dänzer daenzer@vmware.com Signed-off-by: Thomas Hellstrom thellstrom@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 8 ++++---- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index d84e7a6..0c24347 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -505,7 +505,7 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, SVGA3dCmdHeader *header); void vmw_kms_write_svga(struct vmw_private *vmw_priv, unsigned width, unsigned height, unsigned pitch, - unsigned bbp, unsigned depth); + unsigned bpp, unsigned depth); int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); void vmw_kms_idle_workqueues(struct vmw_master *vmaster); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index bfab60c..5fb80b1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -405,14 +405,14 @@ int vmw_fb_init(struct vmw_private *vmw_priv) struct fb_info *info; unsigned initial_width, initial_height; unsigned fb_width, fb_height; - unsigned fb_bbp, fb_depth, fb_offset, fb_pitch, fb_size; + unsigned fb_bpp, fb_depth, fb_offset, fb_pitch, fb_size; int ret;
/* XXX These shouldn't be hardcoded. */ initial_width = 800; initial_height = 600;
- fb_bbp = 32; + fb_bpp = 32; fb_depth = 24;
/* XXX As shouldn't these be as well. */ @@ -422,7 +422,7 @@ int vmw_fb_init(struct vmw_private *vmw_priv) initial_width = min(fb_width, initial_width); initial_height = min(fb_height, initial_height);
- fb_pitch = fb_width * fb_bbp / 8; + fb_pitch = fb_width * fb_bpp / 8; fb_size = fb_pitch * fb_height; fb_offset = vmw_read(vmw_priv, SVGA_REG_FB_OFFSET);
@@ -437,7 +437,7 @@ int vmw_fb_init(struct vmw_private *vmw_priv) par = info->par; par->vmw_priv = vmw_priv; par->depth = fb_depth; - par->bpp = fb_bbp; + par->bpp = fb_bpp; par->vmalloc = NULL; par->max_width = fb_width; par->max_height = fb_height; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 9765407..be8163b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -992,7 +992,7 @@ out:
void vmw_kms_write_svga(struct vmw_private *vmw_priv, unsigned width, unsigned height, unsigned pitch, - unsigned bbp, unsigned depth) + unsigned bpp, unsigned depth) { if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) vmw_write(vmw_priv, SVGA_REG_PITCHLOCK, pitch); @@ -1000,7 +1000,7 @@ void vmw_kms_write_svga(struct vmw_private *vmw_priv, iowrite32(pitch, vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK); vmw_write(vmw_priv, SVGA_REG_WIDTH, width); vmw_write(vmw_priv, SVGA_REG_HEIGHT, height); - vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, bbp); + vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, bpp); }
int vmw_kms_save_vga(struct vmw_private *vmw_priv)
From: Michel Dänzer daenzer@vmware.com
Signed-off-by: Michel Dänzer daenzer@vmware.com Signed-off-by: Thomas Hellstrom thellstrom@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 6 +++--- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 10 +++++++--- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 10 +++++++++- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 14 ++++---------- 4 files changed, 23 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 0c24347..fc33f3f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -503,9 +503,9 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, struct ttm_object_file *tfile, struct ttm_buffer_object *bo, SVGA3dCmdHeader *header); -void vmw_kms_write_svga(struct vmw_private *vmw_priv, - unsigned width, unsigned height, unsigned pitch, - unsigned bpp, unsigned depth); +int vmw_kms_write_svga(struct vmw_private *vmw_priv, + unsigned width, unsigned height, unsigned pitch, + unsigned bpp, unsigned depth); int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); void vmw_kms_idle_workqueues(struct vmw_master *vmaster); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 5fb80b1..b1888e8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -158,10 +158,14 @@ static int vmw_fb_set_par(struct fb_info *info) { struct vmw_fb_par *par = info->par; struct vmw_private *vmw_priv = par->vmw_priv; + int ret; + + ret = vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres, + info->fix.line_length, + par->bpp, par->depth); + if (ret) + return ret;
- vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres, - info->fix.line_length, - par->bpp, par->depth); if (vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) { /* TODO check if pitch and offset changes */ vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index be8163b..9ea2f05 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -990,7 +990,7 @@ out: return ret; }
-void vmw_kms_write_svga(struct vmw_private *vmw_priv, +int vmw_kms_write_svga(struct vmw_private *vmw_priv, unsigned width, unsigned height, unsigned pitch, unsigned bpp, unsigned depth) { @@ -1001,6 +1001,14 @@ void vmw_kms_write_svga(struct vmw_private *vmw_priv, vmw_write(vmw_priv, SVGA_REG_WIDTH, width); vmw_write(vmw_priv, SVGA_REG_HEIGHT, height); vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, bpp); + + if (vmw_read(vmw_priv, SVGA_REG_DEPTH) != depth) { + DRM_ERROR("Invalid depth %u for %u bpp, host expects %u\n", + depth, bpp, vmw_read(vmw_priv, SVGA_REG_DEPTH)); + return -EINVAL; + } + + return 0; }
int vmw_kms_save_vga(struct vmw_private *vmw_priv) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index c6d09a6..7e1901c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -123,10 +123,8 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) return 0; fb = entry->base.crtc.fb;
- vmw_kms_write_svga(dev_priv, w, h, fb->pitch, - fb->bits_per_pixel, fb->depth); - - return 0; + return vmw_kms_write_svga(dev_priv, w, h, fb->pitch, + fb->bits_per_pixel, fb->depth); }
if (!list_empty(&lds->active)) { @@ -274,9 +272,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
vmw_ldu_del_active(dev_priv, ldu);
- vmw_ldu_commit_list(dev_priv); - - return 0; + return vmw_ldu_commit_list(dev_priv); }
@@ -301,9 +297,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
vmw_ldu_add_active(dev_priv, ldu, vfb);
- vmw_ldu_commit_list(dev_priv); - - return 0; + return vmw_ldu_commit_list(dev_priv); }
static struct drm_crtc_funcs vmw_legacy_crtc_funcs = {
Signed-off-by: Thomas Hellstrom thellstrom@vmware.com Reviewed-by: José Fonseca jfonseca@vmware.com --- drivers/gpu/drm/vmwgfx/svga_reg.h | 96 ++++++++++++++++++++++++++++++++++- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 4 ++ 2 files changed, 99 insertions(+), 1 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/svga_reg.h b/drivers/gpu/drm/vmwgfx/svga_reg.h index 1b96c2e..ec5aad9 100644 --- a/drivers/gpu/drm/vmwgfx/svga_reg.h +++ b/drivers/gpu/drm/vmwgfx/svga_reg.h @@ -39,6 +39,15 @@ #define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405
/* + * SVGA_REG_ENABLE bit definitions. + */ +#define SVGA_REG_ENABLE_DISABLE 0 +#define SVGA_REG_ENABLE_ENABLE 1 +#define SVGA_REG_ENABLE_HIDE 2 +#define SVGA_REG_ENABLE_ENABLE_HIDE (SVGA_REG_ENABLE_ENABLE |\ + SVGA_REG_ENABLE_HIDE) + +/* * Legal values for the SVGA_REG_CURSOR_ON register in old-fashioned * cursor bypass mode. This is still supported, but no new guest * drivers should use it. @@ -158,7 +167,9 @@ enum { SVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH = 44,
SVGA_REG_TRACES = 45, /* Enable trace-based updates even when FIFO is on */ - SVGA_REG_TOP = 46, /* Must be 1 more than the last register */ + SVGA_REG_GMRS_MAX_PAGES = 46, /* Maximum number of 4KB pages for all GMRs */ + SVGA_REG_MEMORY_SIZE = 47, /* Total dedicated device memory excluding FIFO */ + SVGA_REG_TOP = 48, /* Must be 1 more than the last register */
SVGA_PALETTE_BASE = 1024, /* Base of SVGA color map */ /* Next 768 (== 256*3) registers exist for colormap */ @@ -370,6 +381,15 @@ struct SVGASignedPoint { * Note the holes in the bitfield. Missing bits have been deprecated, * and must not be reused. Those capabilities will never be reported * by new versions of the SVGA device. + * + * SVGA_CAP_GMR2 -- + * Provides asynchronous commands to define and remap guest memory + * regions. Adds device registers SVGA_REG_GMRS_MAX_PAGES and + * SVGA_REG_MEMORY_SIZE. + * + * SVGA_CAP_SCREEN_OBJECT_2 -- + * Allow screen object support, and require backing stores from the + * guest for each screen object. */
#define SVGA_CAP_NONE 0x00000000 @@ -387,6 +407,8 @@ struct SVGASignedPoint { #define SVGA_CAP_DISPLAY_TOPOLOGY 0x00080000 // Legacy multi-monitor support #define SVGA_CAP_GMR 0x00100000 #define SVGA_CAP_TRACES 0x00200000 +#define SVGA_CAP_GMR2 0x00400000 +#define SVGA_CAP_SCREEN_OBJECT_2 0x00800000
/* @@ -885,6 +907,8 @@ typedef enum { SVGA_CMD_BLIT_SCREEN_TO_GMRFB = 38, SVGA_CMD_ANNOTATION_FILL = 39, SVGA_CMD_ANNOTATION_COPY = 40, + SVGA_CMD_DEFINE_GMR2 = 41, + SVGA_CMD_REMAP_GMR2 = 42, SVGA_CMD_MAX } SVGAFifoCmdId;
@@ -1343,4 +1367,74 @@ struct { uint32 srcScreenId; } SVGAFifoCmdAnnotationCopy;
+ +/* + * SVGA_CMD_DEFINE_GMR2 -- + * + * Define guest memory region v2. See the description of GMRs above. + * + * Availability: + * SVGA_CAP_GMR2 + */ + +typedef +struct { + uint32 gmrId; + uint32 numPages; +} +SVGAFifoCmdDefineGMR2; + + +/* + * SVGA_CMD_REMAP_GMR2 -- + * + * Remap guest memory region v2. See the description of GMRs above. + * + * This command allows guest to modify a portion of an existing GMR by + * invalidating it or reassigning it to different guest physical pages. + * The pages are identified by physical page number (PPN). The pages + * are assumed to be pinned and valid for DMA operations. + * + * Description of command flags: + * + * SVGA_REMAP_GMR2_VIA_GMR: If enabled, references a PPN list in a GMR. + * The PPN list must not overlap with the remap region (this can be + * handled trivially by referencing a separate GMR). If flag is + * disabled, PPN list is appended to SVGARemapGMR command. + * + * SVGA_REMAP_GMR2_PPN64: If set, PPN list is in PPN64 format, otherwise + * it is in PPN32 format. + * + * SVGA_REMAP_GMR2_SINGLE_PPN: If set, PPN list contains a single entry. + * A single PPN can be used to invalidate a portion of a GMR or + * map it to to a single guest scratch page. + * + * Availability: + * SVGA_CAP_GMR2 + */ + +typedef enum { + SVGA_REMAP_GMR2_PPN32 = 0, + SVGA_REMAP_GMR2_VIA_GMR = (1 << 0), + SVGA_REMAP_GMR2_PPN64 = (1 << 1), + SVGA_REMAP_GMR2_SINGLE_PPN = (1 << 2), +} SVGARemapGMR2Flags; + +typedef +struct { + uint32 gmrId; + SVGARemapGMR2Flags flags; + uint32 offsetPages; /* offset in pages to begin remap */ + uint32 numPages; /* number of pages to remap */ + /* + * Followed by additional data depending on SVGARemapGMR2Flags. + * + * If flag SVGA_REMAP_GMR2_VIA_GMR is set, single SVGAGuestPtr follows. + * Otherwise an array of page descriptors in PPN32 or PPN64 format + * (according to flag SVGA_REMAP_GMR2_PPN64) follows. If flag + * SVGA_REMAP_GMR2_SINGLE_PPN is set, array contains a single entry. + */ +} +SVGAFifoCmdRemapGMR2; + #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 96949b9..3a98e56 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -189,6 +189,10 @@ static void vmw_print_capabilities(uint32_t capabilities) DRM_INFO(" GMR.\n"); if (capabilities & SVGA_CAP_TRACES) DRM_INFO(" Traces.\n"); + if (capabilities & SVGA_CAP_GMR2) + DRM_INFO(" GMR2.\n"); + if (capabilities & SVGA_CAP_SCREEN_OBJECT_2) + DRM_INFO(" Screen Object 2.\n"); }
static int vmw_request_device(struct vmw_private *dev_priv)
On Wed, Aug 31, 2011 at 09:42:51AM +0200, Thomas Hellstrom wrote:
Signed-off-by: Thomas Hellstrom thellstrom@vmware.com Reviewed-by: José Fonseca jfonseca@vmware.com
drivers/gpu/drm/vmwgfx/svga_reg.h | 96 ++++++++++++++++++++++++++++++++++- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 4 ++ 2 files changed, 99 insertions(+), 1 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/svga_reg.h b/drivers/gpu/drm/vmwgfx/svga_reg.h index 1b96c2e..ec5aad9 100644 --- a/drivers/gpu/drm/vmwgfx/svga_reg.h +++ b/drivers/gpu/drm/vmwgfx/svga_reg.h @@ -39,6 +39,15 @@ #define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405
/*
- SVGA_REG_ENABLE bit definitions.
- */
+#define SVGA_REG_ENABLE_DISABLE 0 +#define SVGA_REG_ENABLE_ENABLE 1 +#define SVGA_REG_ENABLE_HIDE 2 +#define SVGA_REG_ENABLE_ENABLE_HIDE (SVGA_REG_ENABLE_ENABLE |\
SVGA_REG_ENABLE_HIDE)
That is a mouthfull. "enable enable" sounds repeative.
What if they were: SVGA_REG_ENABLE_OFF, SVGA_REG_ENABLE_ON ?
+/*
- Legal values for the SVGA_REG_CURSOR_ON register in old-fashioned
- cursor bypass mode. This is still supported, but no new guest
- drivers should use it.
@@ -158,7 +167,9 @@ enum { SVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH = 44,
SVGA_REG_TRACES = 45, /* Enable trace-based updates even when FIFO is on */
- SVGA_REG_TOP = 46, /* Must be 1 more than the last register */
SVGA_REG_GMRS_MAX_PAGES = 46, /* Maximum number of 4KB pages for all GMRs */
SVGA_REG_MEMORY_SIZE = 47, /* Total dedicated device memory excluding FIFO */
SVGA_REG_TOP = 48, /* Must be 1 more than the last register */
SVGA_PALETTE_BASE = 1024, /* Base of SVGA color map */ /* Next 768 (== 256*3) registers exist for colormap */
@@ -370,6 +381,15 @@ struct SVGASignedPoint {
- Note the holes in the bitfield. Missing bits have been deprecated,
- and must not be reused. Those capabilities will never be reported
- by new versions of the SVGA device.
- SVGA_CAP_GMR2 --
- Provides asynchronous commands to define and remap guest memory
- regions. Adds device registers SVGA_REG_GMRS_MAX_PAGES and
- SVGA_REG_MEMORY_SIZE.
- SVGA_CAP_SCREEN_OBJECT_2 --
- Allow screen object support, and require backing stores from the
*/
- guest for each screen object.
#define SVGA_CAP_NONE 0x00000000 @@ -387,6 +407,8 @@ struct SVGASignedPoint { #define SVGA_CAP_DISPLAY_TOPOLOGY 0x00080000 // Legacy multi-monitor support #define SVGA_CAP_GMR 0x00100000 #define SVGA_CAP_TRACES 0x00200000 +#define SVGA_CAP_GMR2 0x00400000 +#define SVGA_CAP_SCREEN_OBJECT_2 0x00800000
/* @@ -885,6 +907,8 @@ typedef enum { SVGA_CMD_BLIT_SCREEN_TO_GMRFB = 38, SVGA_CMD_ANNOTATION_FILL = 39, SVGA_CMD_ANNOTATION_COPY = 40,
- SVGA_CMD_DEFINE_GMR2 = 41,
- SVGA_CMD_REMAP_GMR2 = 42, SVGA_CMD_MAX
} SVGAFifoCmdId;
@@ -1343,4 +1367,74 @@ struct { uint32 srcScreenId; } SVGAFifoCmdAnnotationCopy;
+/*
- SVGA_CMD_DEFINE_GMR2 --
- Define guest memory region v2. See the description of GMRs above.
- Availability:
- SVGA_CAP_GMR2
- */
+typedef +struct {
- uint32 gmrId;
- uint32 numPages;
+} +SVGAFifoCmdDefineGMR2;
+/*
- SVGA_CMD_REMAP_GMR2 --
- Remap guest memory region v2. See the description of GMRs above.
out of curiosity - what happend to v1?
- This command allows guest to modify a portion of an existing GMR by
- invalidating it or reassigning it to different guest physical pages.
- The pages are identified by physical page number (PPN). The pages
- are assumed to be pinned and valid for DMA operations.
- Description of command flags:
- SVGA_REMAP_GMR2_VIA_GMR: If enabled, references a PPN list in a GMR.
The PPN list must not overlap with the remap region (this can be
handled trivially by referencing a separate GMR). If flag is
disabled, PPN list is appended to SVGARemapGMR command.
- SVGA_REMAP_GMR2_PPN64: If set, PPN list is in PPN64 format, otherwise
it is in PPN32 format.
- SVGA_REMAP_GMR2_SINGLE_PPN: If set, PPN list contains a single entry.
A single PPN can be used to invalidate a portion of a GMR or
map it to to a single guest scratch page.
- Availability:
- SVGA_CAP_GMR2
- */
+typedef enum {
- SVGA_REMAP_GMR2_PPN32 = 0,
- SVGA_REMAP_GMR2_VIA_GMR = (1 << 0),
- SVGA_REMAP_GMR2_PPN64 = (1 << 1),
- SVGA_REMAP_GMR2_SINGLE_PPN = (1 << 2),
+} SVGARemapGMR2Flags;
+typedef +struct {
- uint32 gmrId;
- SVGARemapGMR2Flags flags;
- uint32 offsetPages; /* offset in pages to begin remap */
- uint32 numPages; /* number of pages to remap */
That formating looks a bit wierd. Like one space and two spaces - but it might be just my editor (vim).
- /*
- Followed by additional data depending on SVGARemapGMR2Flags.
- If flag SVGA_REMAP_GMR2_VIA_GMR is set, single SVGAGuestPtr follows.
- Otherwise an array of page descriptors in PPN32 or PPN64 format
- (according to flag SVGA_REMAP_GMR2_PPN64) follows. If flag
- SVGA_REMAP_GMR2_SINGLE_PPN is set, array contains a single entry.
- */
+} +SVGAFifoCmdRemapGMR2;
#endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 96949b9..3a98e56 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -189,6 +189,10 @@ static void vmw_print_capabilities(uint32_t capabilities) DRM_INFO(" GMR.\n"); if (capabilities & SVGA_CAP_TRACES) DRM_INFO(" Traces.\n");
- if (capabilities & SVGA_CAP_GMR2)
DRM_INFO(" GMR2.\n");
- if (capabilities & SVGA_CAP_SCREEN_OBJECT_2)
DRM_INFO(" Screen Object 2.\n");
}
static int vmw_request_device(struct vmw_private *dev_priv)
1.7.4.4
dri-devel mailing list dri-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/dri-devel
Thanks for reviewing, please see inline.
On 09/01/2011 08:02 PM, Konrad Rzeszutek Wilk wrote:
On Wed, Aug 31, 2011 at 09:42:51AM +0200, Thomas Hellstrom wrote:
Signed-off-by: Thomas Hellstromthellstrom@vmware.com Reviewed-by: José Fonsecajfonseca@vmware.com
drivers/gpu/drm/vmwgfx/svga_reg.h | 96 ++++++++++++++++++++++++++++++++++- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 4 ++ 2 files changed, 99 insertions(+), 1 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/svga_reg.h b/drivers/gpu/drm/vmwgfx/svga_reg.h index 1b96c2e..ec5aad9 100644 --- a/drivers/gpu/drm/vmwgfx/svga_reg.h +++ b/drivers/gpu/drm/vmwgfx/svga_reg.h @@ -39,6 +39,15 @@ #define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405
/*
- SVGA_REG_ENABLE bit definitions.
- */
+#define SVGA_REG_ENABLE_DISABLE 0 +#define SVGA_REG_ENABLE_ENABLE 1 +#define SVGA_REG_ENABLE_HIDE 2 +#define SVGA_REG_ENABLE_ENABLE_HIDE (SVGA_REG_ENABLE_ENABLE |\
SVGA_REG_ENABLE_HIDE)
That is a mouthfull. "enable enable" sounds repeative.
What if they were: SVGA_REG_ENABLE_OFF, SVGA_REG_ENABLE_ON ?
We're trying to keep the open source version of this header as close as possible to the internal headers. Most likely VMware guys are going to be the primary maintainers this driver in the future, and having different names for the register values will be confusing, although I think you have a point.
+/*
- Legal values for the SVGA_REG_CURSOR_ON register in old-fashioned
- cursor bypass mode. This is still supported, but no new guest
- drivers should use it.
@@ -158,7 +167,9 @@ enum { SVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH = 44,
SVGA_REG_TRACES = 45, /* Enable trace-based updates even when FIFO is on */
- SVGA_REG_TOP = 46, /* Must be 1 more than the last register */
SVGA_REG_GMRS_MAX_PAGES = 46, /* Maximum number of 4KB pages for all GMRs */
SVGA_REG_MEMORY_SIZE = 47, /* Total dedicated device memory excluding FIFO */
SVGA_REG_TOP = 48, /* Must be 1 more than the last register */
SVGA_PALETTE_BASE = 1024, /* Base of SVGA color map */ /* Next 768 (== 256*3) registers exist for colormap */
@@ -370,6 +381,15 @@ struct SVGASignedPoint {
- Note the holes in the bitfield. Missing bits have been deprecated,
- and must not be reused. Those capabilities will never be reported
- by new versions of the SVGA device.
- SVGA_CAP_GMR2 --
- Provides asynchronous commands to define and remap guest memory
- regions. Adds device registers SVGA_REG_GMRS_MAX_PAGES and
- SVGA_REG_MEMORY_SIZE.
- SVGA_CAP_SCREEN_OBJECT_2 --
- Allow screen object support, and require backing stores from the
- guest for each screen object.
*/
#define SVGA_CAP_NONE 0x00000000
@@ -387,6 +407,8 @@ struct SVGASignedPoint { #define SVGA_CAP_DISPLAY_TOPOLOGY 0x00080000 // Legacy multi-monitor support #define SVGA_CAP_GMR 0x00100000 #define SVGA_CAP_TRACES 0x00200000 +#define SVGA_CAP_GMR2 0x00400000 +#define SVGA_CAP_SCREEN_OBJECT_2 0x00800000
/* @@ -885,6 +907,8 @@ typedef enum { SVGA_CMD_BLIT_SCREEN_TO_GMRFB = 38, SVGA_CMD_ANNOTATION_FILL = 39, SVGA_CMD_ANNOTATION_COPY = 40,
- SVGA_CMD_DEFINE_GMR2 = 41,
- SVGA_CMD_REMAP_GMR2 = 42, SVGA_CMD_MAX } SVGAFifoCmdId;
@@ -1343,4 +1367,74 @@ struct { uint32 srcScreenId; } SVGAFifoCmdAnnotationCopy;
+/*
- SVGA_CMD_DEFINE_GMR2 --
- Define guest memory region v2. See the description of GMRs above.
- Availability:
- SVGA_CAP_GMR2
- */
+typedef +struct {
- uint32 gmrId;
- uint32 numPages;
+} +SVGAFifoCmdDefineGMR2;
+/*
- SVGA_CMD_REMAP_GMR2 --
- Remap guest memory region v2. See the description of GMRs above.
out of curiosity - what happend to v1?
V1 is present, but is using IO registers instead of fifo commands. Please see the "Implement GMR2 patch".
- This command allows guest to modify a portion of an existing GMR by
- invalidating it or reassigning it to different guest physical pages.
- The pages are identified by physical page number (PPN). The pages
- are assumed to be pinned and valid for DMA operations.
- Description of command flags:
- SVGA_REMAP_GMR2_VIA_GMR: If enabled, references a PPN list in a GMR.
The PPN list must not overlap with the remap region (this can be
handled trivially by referencing a separate GMR). If flag is
disabled, PPN list is appended to SVGARemapGMR command.
- SVGA_REMAP_GMR2_PPN64: If set, PPN list is in PPN64 format, otherwise
it is in PPN32 format.
- SVGA_REMAP_GMR2_SINGLE_PPN: If set, PPN list contains a single entry.
A single PPN can be used to invalidate a portion of a GMR or
map it to to a single guest scratch page.
- Availability:
- SVGA_CAP_GMR2
- */
+typedef enum {
- SVGA_REMAP_GMR2_PPN32 = 0,
- SVGA_REMAP_GMR2_VIA_GMR = (1<< 0),
- SVGA_REMAP_GMR2_PPN64 = (1<< 1),
- SVGA_REMAP_GMR2_SINGLE_PPN = (1<< 2),
+} SVGARemapGMR2Flags;
+typedef +struct {
- uint32 gmrId;
- SVGARemapGMR2Flags flags;
- uint32 offsetPages; /* offset in pages to begin remap */
- uint32 numPages; /* number of pages to remap */
That formating looks a bit wierd. Like one space and two spaces - but it might be just my editor (vim).
It's probably weird, but we're trying to keep the formatting of the original file for the register definitions.
- /*
- Followed by additional data depending on SVGARemapGMR2Flags.
- If flag SVGA_REMAP_GMR2_VIA_GMR is set, single SVGAGuestPtr follows.
- Otherwise an array of page descriptors in PPN32 or PPN64 format
- (according to flag SVGA_REMAP_GMR2_PPN64) follows. If flag
- SVGA_REMAP_GMR2_SINGLE_PPN is set, array contains a single entry.
- */
+} +SVGAFifoCmdRemapGMR2;
- #endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 96949b9..3a98e56 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -189,6 +189,10 @@ static void vmw_print_capabilities(uint32_t capabilities) DRM_INFO(" GMR.\n"); if (capabilities& SVGA_CAP_TRACES) DRM_INFO(" Traces.\n");
if (capabilities& SVGA_CAP_GMR2)
DRM_INFO(" GMR2.\n");
if (capabilities& SVGA_CAP_SCREEN_OBJECT_2)
DRM_INFO(" Screen Object 2.\n");
}
static int vmw_request_device(struct vmw_private *dev_priv)
-- 1.7.4.4
dri-devel mailing list dri-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/dri-devel
Thanks for reviewing.
/Thomas
Previously this was not done when any 3D resource was active, since that meant disabling the fifo with all 3D state lost. Now, if there are still 3D resources active, we use the svga hide feature.
This fixes X server VT switching with 3D enabled.
Signed-off-by: Thomas Hellstrom thellstrom@vmware.com Reviewed-by: Jakob Bornecrantz jakob@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 54 +++++++++++++++++++++++------- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 8 ++-- 3 files changed, 48 insertions(+), 18 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 3a98e56..0f3648e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -213,7 +213,14 @@ static void vmw_release_device(struct vmw_private *dev_priv) vmw_fifo_release(dev_priv, &dev_priv->fifo); }
-int vmw_3d_resource_inc(struct vmw_private *dev_priv) +/** + * Increase the 3d resource refcount. + * If the count was prevously zero, initialize the fifo, switching to svga + * mode. Note that the master holds a ref as well, and may request an + * explicit switch to svga mode if fb is not running, using @unhide_svga. + */ +int vmw_3d_resource_inc(struct vmw_private *dev_priv, + bool unhide_svga) { int ret = 0;
@@ -222,19 +229,42 @@ int vmw_3d_resource_inc(struct vmw_private *dev_priv) ret = vmw_request_device(dev_priv); if (unlikely(ret != 0)) --dev_priv->num_3d_resources; + } else if (unhide_svga) { + mutex_lock(&dev_priv->hw_mutex); + vmw_write(dev_priv, SVGA_REG_ENABLE, + vmw_read(dev_priv, SVGA_REG_ENABLE) & + ~SVGA_REG_ENABLE_HIDE); + mutex_unlock(&dev_priv->hw_mutex); } + mutex_unlock(&dev_priv->release_mutex); return ret; }
- -void vmw_3d_resource_dec(struct vmw_private *dev_priv) +/** + * Decrease the 3d resource refcount. + * If the count reaches zero, disable the fifo, switching to vga mode. + * Note that the master holds a refcount as well, and may request an + * explicit switch to vga mode when it releases its refcount to account + * for the situation of an X server vt switch to VGA with 3d resources + * active. + */ +void vmw_3d_resource_dec(struct vmw_private *dev_priv, + bool hide_svga) { int32_t n3d;
mutex_lock(&dev_priv->release_mutex); if (unlikely(--dev_priv->num_3d_resources == 0)) vmw_release_device(dev_priv); + else if (hide_svga) { + mutex_lock(&dev_priv->hw_mutex); + vmw_write(dev_priv, SVGA_REG_ENABLE, + vmw_read(dev_priv, SVGA_REG_ENABLE) | + SVGA_REG_ENABLE_HIDE); + mutex_unlock(&dev_priv->hw_mutex); + } + n3d = (int32_t) dev_priv->num_3d_resources; mutex_unlock(&dev_priv->release_mutex);
@@ -403,7 +433,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) goto out_no_kms; vmw_overlay_init(dev_priv); if (dev_priv->enable_fb) { - ret = vmw_3d_resource_inc(dev_priv); + ret = vmw_3d_resource_inc(dev_priv, false); if (unlikely(ret != 0)) goto out_no_fifo; vmw_kms_save_vga(dev_priv); @@ -433,7 +463,7 @@ out_no_irq: if (dev_priv->enable_fb) { vmw_fb_close(dev_priv); vmw_kms_restore_vga(dev_priv); - vmw_3d_resource_dec(dev_priv); + vmw_3d_resource_dec(dev_priv, false); } out_no_fifo: vmw_overlay_close(dev_priv); @@ -476,7 +506,7 @@ static int vmw_driver_unload(struct drm_device *dev) if (dev_priv->enable_fb) { vmw_fb_close(dev_priv); vmw_kms_restore_vga(dev_priv); - vmw_3d_resource_dec(dev_priv); + vmw_3d_resource_dec(dev_priv, false); } vmw_kms_close(dev_priv); vmw_overlay_close(dev_priv); @@ -650,7 +680,7 @@ static int vmw_master_set(struct drm_device *dev, int ret = 0;
if (!dev_priv->enable_fb) { - ret = vmw_3d_resource_inc(dev_priv); + ret = vmw_3d_resource_inc(dev_priv, true); if (unlikely(ret != 0)) return ret; vmw_kms_save_vga(dev_priv); @@ -692,7 +722,7 @@ out_no_active_lock: vmw_write(dev_priv, SVGA_REG_TRACES, 1); mutex_unlock(&dev_priv->hw_mutex); vmw_kms_restore_vga(dev_priv); - vmw_3d_resource_dec(dev_priv); + vmw_3d_resource_dec(dev_priv, true); } return ret; } @@ -730,7 +760,7 @@ static void vmw_master_drop(struct drm_device *dev, vmw_write(dev_priv, SVGA_REG_TRACES, 1); mutex_unlock(&dev_priv->hw_mutex); vmw_kms_restore_vga(dev_priv); - vmw_3d_resource_dec(dev_priv); + vmw_3d_resource_dec(dev_priv, true); }
dev_priv->active_master = &dev_priv->fbdev_master; @@ -839,7 +869,7 @@ static int vmw_pm_prepare(struct device *kdev) */ dev_priv->suspended = true; if (dev_priv->enable_fb) - vmw_3d_resource_dec(dev_priv); + vmw_3d_resource_dec(dev_priv, true);
if (dev_priv->num_3d_resources != 0) {
@@ -847,7 +877,7 @@ static int vmw_pm_prepare(struct device *kdev) "while 3D resources are active.\n");
if (dev_priv->enable_fb) - vmw_3d_resource_inc(dev_priv); + vmw_3d_resource_inc(dev_priv, true); dev_priv->suspended = false; return -EBUSY; } @@ -866,7 +896,7 @@ static void vmw_pm_complete(struct device *kdev) * start fifo. */ if (dev_priv->enable_fb) - vmw_3d_resource_inc(dev_priv); + vmw_3d_resource_inc(dev_priv, false);
dev_priv->suspended = false; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index fc33f3f..a341946 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -314,8 +314,8 @@ static inline uint32_t vmw_read(struct vmw_private *dev_priv, return val; }
-int vmw_3d_resource_inc(struct vmw_private *dev_priv); -void vmw_3d_resource_dec(struct vmw_private *dev_priv); +int vmw_3d_resource_inc(struct vmw_private *dev_priv, bool unhide_svga); +void vmw_3d_resource_dec(struct vmw_private *dev_priv, bool hide_svga);
/** * GMR utilities - vmwgfx_gmr.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index bfe1bcc..87ab632 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -211,7 +211,7 @@ static void vmw_hw_context_destroy(struct vmw_resource *res) cmd->body.cid = cpu_to_le32(res->id);
vmw_fifo_commit(dev_priv, sizeof(*cmd)); - vmw_3d_resource_dec(dev_priv); + vmw_3d_resource_dec(dev_priv, false); }
static int vmw_context_init(struct vmw_private *dev_priv, @@ -248,7 +248,7 @@ static int vmw_context_init(struct vmw_private *dev_priv, cmd->body.cid = cpu_to_le32(res->id);
vmw_fifo_commit(dev_priv, sizeof(*cmd)); - (void) vmw_3d_resource_inc(dev_priv); + (void) vmw_3d_resource_inc(dev_priv, false); vmw_resource_activate(res, vmw_hw_context_destroy); return 0; } @@ -408,7 +408,7 @@ static void vmw_hw_surface_destroy(struct vmw_resource *res) cmd->body.sid = cpu_to_le32(res->id);
vmw_fifo_commit(dev_priv, sizeof(*cmd)); - vmw_3d_resource_dec(dev_priv); + vmw_3d_resource_dec(dev_priv, false); }
void vmw_surface_res_free(struct vmw_resource *res) @@ -476,7 +476,7 @@ int vmw_surface_init(struct vmw_private *dev_priv, }
vmw_fifo_commit(dev_priv, submit_size); - (void) vmw_3d_resource_inc(dev_priv); + (void) vmw_3d_resource_inc(dev_priv, false); vmw_resource_activate(res, vmw_hw_surface_destroy); return 0; }
When GMR2 is available, make sure we restrict the number of used GMR pages to the limit indicated by the device. This is done by failing a GMRID allocation if the total number of GMR pages exceeds the limit. As a result TTM will then start evicting buffers in GMR memory on a LRU basis until the allocation succeeds.
Signed-off-by: Thomas Hellstrom thellstrom@vmware.com Reviewed-by: Jakob Bornecrantz jakob@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 12 ++++++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 2 + drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c | 46 +++++++++++++++++++------ 3 files changed, 49 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 0f3648e..4ac7039 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -326,6 +326,12 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->max_gmr_ids = vmw_read(dev_priv, SVGA_REG_GMR_MAX_IDS); } + if (dev_priv->capabilities & SVGA_CAP_GMR2) { + dev_priv->max_gmr_pages = + vmw_read(dev_priv, SVGA_REG_GMRS_MAX_PAGES); + dev_priv->memory_size = + vmw_read(dev_priv, SVGA_REG_MEMORY_SIZE); + }
dev_priv->vram_size = vmw_read(dev_priv, SVGA_REG_VRAM_SIZE); dev_priv->mmio_size = vmw_read(dev_priv, SVGA_REG_MEM_SIZE); @@ -342,6 +348,12 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) DRM_INFO("Max GMR descriptors is %u\n", (unsigned)dev_priv->max_gmr_descriptors); } + if (dev_priv->capabilities & SVGA_CAP_GMR2) { + DRM_INFO("Max number of GMR pages is %u\n", + (unsigned)dev_priv->max_gmr_pages); + DRM_INFO("Max dedicated hypervisor graphics memory is %u\n", + (unsigned)dev_priv->memory_size); + } DRM_INFO("VRAM at 0x%08x size is %u kiB\n", dev_priv->vram_start, dev_priv->vram_size / 1024); DRM_INFO("MMIO at 0x%08x size is %u kiB\n", diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index a341946..d1196c8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -185,6 +185,8 @@ struct vmw_private { uint32_t capabilities; uint32_t max_gmr_descriptors; uint32_t max_gmr_ids; + uint32_t max_gmr_pages; + uint32_t memory_size; bool has_gmr; struct mutex hw_mutex;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c index ac6e0d1..5f71715 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c @@ -40,6 +40,8 @@ struct vmwgfx_gmrid_man { spinlock_t lock; struct ida gmr_ida; uint32_t max_gmr_ids; + uint32_t max_gmr_pages; + uint32_t used_gmr_pages; };
static int vmw_gmrid_man_get_node(struct ttm_mem_type_manager *man, @@ -49,33 +51,50 @@ static int vmw_gmrid_man_get_node(struct ttm_mem_type_manager *man, { struct vmwgfx_gmrid_man *gman = (struct vmwgfx_gmrid_man *)man->priv; - int ret; + int ret = 0; int id;
mem->mm_node = NULL;
- do { - if (unlikely(ida_pre_get(&gman->gmr_ida, GFP_KERNEL) == 0)) - return -ENOMEM; + spin_lock(&gman->lock); + + if (gman->max_gmr_pages > 0) { + gman->used_gmr_pages += bo->num_pages; + if (unlikely(gman->used_gmr_pages > gman->max_gmr_pages)) + goto out_err_locked; + }
+ do { + spin_unlock(&gman->lock); + if (unlikely(ida_pre_get(&gman->gmr_ida, GFP_KERNEL) == 0)) { + ret = -ENOMEM; + goto out_err; + } spin_lock(&gman->lock); - ret = ida_get_new(&gman->gmr_ida, &id);
+ ret = ida_get_new(&gman->gmr_ida, &id); if (unlikely(ret == 0 && id >= gman->max_gmr_ids)) { ida_remove(&gman->gmr_ida, id); - spin_unlock(&gman->lock); - return 0; + ret = 0; + goto out_err_locked; } - - spin_unlock(&gman->lock); - } while (ret == -EAGAIN);
if (likely(ret == 0)) { mem->mm_node = gman; mem->start = id; - } + mem->num_pages = bo->num_pages; + } else + goto out_err_locked; + + spin_unlock(&gman->lock); + return 0;
+out_err: + spin_lock(&gman->lock); +out_err_locked: + gman->used_gmr_pages -= bo->num_pages; + spin_unlock(&gman->lock); return ret; }
@@ -88,6 +107,7 @@ static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man, if (mem->mm_node) { spin_lock(&gman->lock); ida_remove(&gman->gmr_ida, mem->start); + gman->used_gmr_pages -= mem->num_pages; spin_unlock(&gman->lock); mem->mm_node = NULL; } @@ -96,6 +116,8 @@ static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man, static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man, unsigned long p_size) { + struct vmw_private *dev_priv = + container_of(man->bdev, struct vmw_private, bdev); struct vmwgfx_gmrid_man *gman = kzalloc(sizeof(*gman), GFP_KERNEL);
@@ -103,6 +125,8 @@ static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man, return -ENOMEM;
spin_lock_init(&gman->lock); + gman->max_gmr_pages = dev_priv->max_gmr_pages; + gman->used_gmr_pages = 0; ida_init(&gman->gmr_ida); gman->max_gmr_ids = p_size; man->priv = (void *) gman;
Perform all command stream validation in a bounce buffer separate from the fifo. This makes the fifo available to all validation-generated commands, which would otherwise attempt to grab the fifo recursively, causing a deadlock. This is in preparation for GMR2 and swappable surfaces.
Also maintain references to all surfaces in the command stream until the command stream has been fired in order to avoid racing with surface destruction taking place after validation but before submission.
Signed-off-by: Thomas Hellstrom thellstrom@vmware.com Reviewed-by: Jakob Bornecrantz jakob@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 + drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 14 ++- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 166 ++++++++++++++++++++++-------- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 5 +- 4 files changed, 139 insertions(+), 48 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 4ac7039..bff7932 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -513,6 +513,8 @@ static int vmw_driver_unload(struct drm_device *dev)
unregister_pm_notifier(&dev_priv->pm_nb);
+ if (dev_priv->ctx.cmd_bounce) + vfree(dev_priv->ctx.cmd_bounce); if (dev_priv->capabilities & SVGA_CAP_IRQMASK) drm_irq_uninstall(dev_priv->dev); if (dev_priv->enable_fb) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index d1196c8..323fc10 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -46,8 +46,9 @@ #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) #define VMWGFX_MAX_RELOCATIONS 2048 -#define VMWGFX_MAX_GMRS 2048 +#define VMWGFX_MAX_VALIDATIONS 2048 #define VMWGFX_MAX_DISPLAYS 16 +#define VMWGFX_CMD_BOUNCE_INIT_SIZE 32768
#define VMW_PL_GMR TTM_PL_PRIV0 #define VMW_PL_FLAG_GMR TTM_PL_FLAG_PRIV0 @@ -74,7 +75,7 @@ struct vmw_resource { bool avail; void (*hw_destroy) (struct vmw_resource *res); void (*res_free) (struct vmw_resource *res); - + bool on_validate_list; /* TODO is a generic snooper needed? */ #if 0 void (*snoop)(struct vmw_resource *res, @@ -143,8 +144,12 @@ struct vmw_sw_context{ struct list_head validate_nodes; struct vmw_relocation relocs[VMWGFX_MAX_RELOCATIONS]; uint32_t cur_reloc; - struct ttm_validate_buffer val_bufs[VMWGFX_MAX_GMRS]; + struct ttm_validate_buffer val_bufs[VMWGFX_MAX_VALIDATIONS]; uint32_t cur_val_buf; + uint32_t *cmd_bounce; + uint32_t cmd_bounce_size; + struct vmw_resource *resources[VMWGFX_MAX_VALIDATIONS]; + uint32_t num_ref_resources; };
struct vmw_legacy_display; @@ -342,7 +347,8 @@ extern int vmw_context_define_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int vmw_context_check(struct vmw_private *dev_priv, struct ttm_object_file *tfile, - int id); + int id, + struct vmw_resource **p_res); extern void vmw_surface_res_free(struct vmw_resource *res); extern int vmw_surface_init(struct vmw_private *dev_priv, struct vmw_surface *srf, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 41b95ed..3dac8ab 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -44,10 +44,36 @@ static int vmw_cmd_ok(struct vmw_private *dev_priv, return 0; }
+ +static int vmw_resource_to_validate_list(struct vmw_sw_context *sw_context, + struct vmw_resource **p_res) +{ + int ret = 0; + struct vmw_resource *res = *p_res; + + if (!res->on_validate_list) { + if (sw_context->num_ref_resources >= VMWGFX_MAX_VALIDATIONS) { + DRM_ERROR("Too many resources referenced in " + "command stream.\n"); + ret = -ENOMEM; + goto out; + } + sw_context->resources[sw_context->num_ref_resources++] = res; + res->on_validate_list = true; + return 0; + } + +out: + vmw_resource_unreference(p_res); + return ret; +} + static int vmw_cmd_cid_check(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, SVGA3dCmdHeader *header) { + struct vmw_resource *ctx; + struct vmw_cid_cmd { SVGA3dCmdHeader header; __le32 cid; @@ -58,7 +84,8 @@ static int vmw_cmd_cid_check(struct vmw_private *dev_priv, if (likely(sw_context->cid_valid && cmd->cid == sw_context->last_cid)) return 0;
- ret = vmw_context_check(dev_priv, sw_context->tfile, cmd->cid); + ret = vmw_context_check(dev_priv, sw_context->tfile, cmd->cid, + &ctx); if (unlikely(ret != 0)) { DRM_ERROR("Could not find or use context %u\n", (unsigned) cmd->cid); @@ -67,39 +94,43 @@ static int vmw_cmd_cid_check(struct vmw_private *dev_priv,
sw_context->last_cid = cmd->cid; sw_context->cid_valid = true; - - return 0; + return vmw_resource_to_validate_list(sw_context, &ctx); }
static int vmw_cmd_sid_check(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, uint32_t *sid) { + struct vmw_surface *srf; + int ret; + struct vmw_resource *res; + if (*sid == SVGA3D_INVALID_ID) return 0;
- if (unlikely((!sw_context->sid_valid || - *sid != sw_context->last_sid))) { - int real_id; - int ret = vmw_surface_check(dev_priv, sw_context->tfile, - *sid, &real_id); - - if (unlikely(ret != 0)) { - DRM_ERROR("Could ot find or use surface 0x%08x " - "address 0x%08lx\n", - (unsigned int) *sid, - (unsigned long) sid); - return ret; - } - - sw_context->last_sid = *sid; - sw_context->sid_valid = true; - *sid = real_id; - sw_context->sid_translation = real_id; - } else + if (likely((sw_context->sid_valid && + *sid == sw_context->last_sid))) { *sid = sw_context->sid_translation; + return 0; + }
- return 0; + ret = vmw_user_surface_lookup_handle(dev_priv, sw_context->tfile, + *sid, &srf); + if (unlikely(ret != 0)) { + DRM_ERROR("Could ot find or use surface 0x%08x " + "address 0x%08lx\n", + (unsigned int) *sid, + (unsigned long) sid); + return ret; + } + + sw_context->last_sid = *sid; + sw_context->sid_valid = true; + sw_context->sid_translation = srf->res.id; + *sid = sw_context->sid_translation; + + res = &srf->res; + return vmw_resource_to_validate_list(sw_context, &res); }
@@ -213,7 +244,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv, reloc->location = ptr;
cur_validate_node = vmw_dmabuf_validate_node(bo, sw_context->cur_val_buf); - if (unlikely(cur_validate_node >= VMWGFX_MAX_GMRS)) { + if (unlikely(cur_validate_node >= VMWGFX_MAX_VALIDATIONS)) { DRM_ERROR("Max number of DMA buffers per submission" " exceeded.\n"); ret = -EINVAL; @@ -302,6 +333,7 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv, SVGA3dCmdSurfaceDMA dma; } *cmd; int ret; + struct vmw_resource *res;
cmd = container_of(header, struct vmw_dma_cmd, header); ret = vmw_translate_guest_ptr(dev_priv, sw_context, @@ -318,17 +350,16 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv, goto out_no_reloc; }
- /** + /* * Patch command stream with device SID. */ - cmd->dma.host.sid = srf->res.id; vmw_kms_cursor_snoop(srf, sw_context->tfile, bo, header); - /** - * FIXME: May deadlock here when called from the - * command parsing code. - */ - vmw_surface_unreference(&srf); + + vmw_dmabuf_unreference(&vmw_bo); + + res = &srf->res; + return vmw_resource_to_validate_list(sw_context, &res);
out_no_reloc: vmw_dmabuf_unreference(&vmw_bo); @@ -500,8 +531,9 @@ out_err:
static int vmw_cmd_check_all(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, - void *buf, uint32_t size) + uint32_t size) { + void *buf = sw_context->cmd_bounce; int32_t cur_size = size; int ret;
@@ -550,7 +582,11 @@ static void vmw_apply_relocations(struct vmw_sw_context *sw_context) static void vmw_clear_validations(struct vmw_sw_context *sw_context) { struct ttm_validate_buffer *entry, *next; + uint32_t i = sw_context->num_ref_resources;
+ /* + * Drop references to DMA buffers held during command submission. + */ list_for_each_entry_safe(entry, next, &sw_context->validate_nodes, head) { list_del(&entry->head); @@ -559,6 +595,14 @@ static void vmw_clear_validations(struct vmw_sw_context *sw_context) sw_context->cur_val_buf--; } BUG_ON(sw_context->cur_val_buf != 0); + + /* + * Drop references to resources held during command submission. + */ + while (i-- > 0) { + sw_context->resources[i]->on_validate_list = false; + vmw_resource_unreference(&sw_context->resources[i]); + } }
static int vmw_validate_single_buffer(struct vmw_private *dev_priv, @@ -602,6 +646,35 @@ static int vmw_validate_buffers(struct vmw_private *dev_priv, return 0; }
+static int vmw_resize_cmd_bounce(struct vmw_sw_context *sw_context, + uint32_t size) +{ + if (likely(sw_context->cmd_bounce_size >= size)) + return 0; + + if (sw_context->cmd_bounce_size == 0) + sw_context->cmd_bounce_size = VMWGFX_CMD_BOUNCE_INIT_SIZE; + + while (sw_context->cmd_bounce_size < size) { + sw_context->cmd_bounce_size = + PAGE_ALIGN(sw_context->cmd_bounce_size + + (sw_context->cmd_bounce_size >> 1)); + } + + if (sw_context->cmd_bounce != NULL) + vfree(sw_context->cmd_bounce); + + sw_context->cmd_bounce = vmalloc(sw_context->cmd_bounce_size); + + if (sw_context->cmd_bounce == NULL) { + DRM_ERROR("Failed to allocate command bounce buffer.\n"); + sw_context->cmd_bounce_size = 0; + return -ENOMEM; + } + + return 0; +} + int vmw_execbuf_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -626,20 +699,18 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, goto out_no_cmd_mutex; }
- cmd = vmw_fifo_reserve(dev_priv, arg->command_size); - if (unlikely(cmd == NULL)) { - DRM_ERROR("Failed reserving fifo space for commands.\n"); - ret = -ENOMEM; + ret = vmw_resize_cmd_bounce(sw_context, arg->command_size); + if (unlikely(ret != 0)) goto out_unlock; - }
user_cmd = (void __user *)(unsigned long)arg->commands; - ret = copy_from_user(cmd, user_cmd, arg->command_size); + ret = copy_from_user(sw_context->cmd_bounce, + user_cmd, arg->command_size);
if (unlikely(ret != 0)) { ret = -EFAULT; DRM_ERROR("Failed copying commands.\n"); - goto out_commit; + goto out_unlock; }
sw_context->tfile = vmw_fpriv(file_priv)->tfile; @@ -647,12 +718,14 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, sw_context->sid_valid = false; sw_context->cur_reloc = 0; sw_context->cur_val_buf = 0; + sw_context->num_ref_resources = 0;
INIT_LIST_HEAD(&sw_context->validate_nodes);
- ret = vmw_cmd_check_all(dev_priv, sw_context, cmd, arg->command_size); + ret = vmw_cmd_check_all(dev_priv, sw_context, arg->command_size); if (unlikely(ret != 0)) goto out_err; + ret = ttm_eu_reserve_buffers(&sw_context->validate_nodes); if (unlikely(ret != 0)) goto out_err; @@ -668,9 +741,17 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, arg->throttle_us);
if (unlikely(ret != 0)) - goto out_err; + goto out_throttle; + } + + cmd = vmw_fifo_reserve(dev_priv, arg->command_size); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving fifo space for commands.\n"); + ret = -ENOMEM; + goto out_err; }
+ memcpy(cmd, sw_context->cmd_bounce, arg->command_size); vmw_fifo_commit(dev_priv, arg->command_size);
ret = vmw_fifo_send_fence(dev_priv, &sequence); @@ -707,10 +788,9 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, return 0; out_err: vmw_free_relocations(sw_context); +out_throttle: ttm_eu_backoff_reservation(&sw_context->validate_nodes); vmw_clear_validations(sw_context); -out_commit: - vmw_fifo_commit(dev_priv, 0); out_unlock: mutex_unlock(&dev_priv->cmdbuf_mutex); out_no_cmd_mutex: diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 87ab632..4b53803 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -364,7 +364,8 @@ out_err:
int vmw_context_check(struct vmw_private *dev_priv, struct ttm_object_file *tfile, - int id) + int id, + struct vmw_resource **p_res) { struct vmw_resource *res; int ret = 0; @@ -376,6 +377,8 @@ int vmw_context_check(struct vmw_private *dev_priv, container_of(res, struct vmw_user_context, res); if (ctx->base.tfile != tfile && !ctx->base.shareable) ret = -EPERM; + if (p_res) + *p_res = vmw_resource_reference(res); } else ret = -EINVAL; read_unlock(&dev_priv->resource_lock);
Guest Memory Regions 2 is a way to bind pages to the GPU, but using the FIFO instead of an io-submitted descriptor chain.
Signed-off-by: Thomas Hellstrom thellstrom@vmware.com Reviewed-by: Jakob Bornecantz jakob@vmware.com --- drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c | 81 ++++++++++++++++++++++++++++++++++- 1 files changed, 80 insertions(+), 1 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c index de0c594..f4e7763 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA + * Copyright © 2009-2011 VMware, Inc., Palo Alto, CA., USA * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -29,6 +29,77 @@ #include "drmP.h" #include "ttm/ttm_bo_driver.h"
+#define VMW_PPN_SIZE sizeof(unsigned long) + +static int vmw_gmr2_bind(struct vmw_private *dev_priv, + struct page *pages[], + unsigned long num_pages, + int gmr_id) +{ + SVGAFifoCmdDefineGMR2 define_cmd; + SVGAFifoCmdRemapGMR2 remap_cmd; + uint32_t define_size = sizeof(define_cmd) + 4; + uint32_t remap_size = VMW_PPN_SIZE * num_pages + sizeof(remap_cmd) + 4; + uint32_t *cmd; + uint32_t *cmd_orig; + uint32_t i; + + cmd_orig = cmd = vmw_fifo_reserve(dev_priv, define_size + remap_size); + if (unlikely(cmd == NULL)) + return -ENOMEM; + + define_cmd.gmrId = gmr_id; + define_cmd.numPages = num_pages; + + remap_cmd.gmrId = gmr_id; + remap_cmd.flags = (VMW_PPN_SIZE > sizeof(*cmd)) ? + SVGA_REMAP_GMR2_PPN64 : SVGA_REMAP_GMR2_PPN32; + remap_cmd.offsetPages = 0; + remap_cmd.numPages = num_pages; + + *cmd++ = SVGA_CMD_DEFINE_GMR2; + memcpy(cmd, &define_cmd, sizeof(define_cmd)); + cmd += sizeof(define_cmd) / sizeof(uint32); + + *cmd++ = SVGA_CMD_REMAP_GMR2; + memcpy(cmd, &remap_cmd, sizeof(remap_cmd)); + cmd += sizeof(remap_cmd) / sizeof(uint32); + + for (i = 0; i < num_pages; ++i) { + if (VMW_PPN_SIZE > 4) + *cmd = page_to_pfn(*pages++); + else + *((uint64_t *)cmd) = page_to_pfn(*pages++); + + cmd += VMW_PPN_SIZE / sizeof(*cmd); + } + + vmw_fifo_commit(dev_priv, define_size + remap_size); + + return 0; +} + +static void vmw_gmr2_unbind(struct vmw_private *dev_priv, + int gmr_id) +{ + SVGAFifoCmdDefineGMR2 define_cmd; + uint32_t define_size = sizeof(define_cmd) + 4; + uint32_t *cmd; + + cmd = vmw_fifo_reserve(dev_priv, define_size); + if (unlikely(cmd == NULL)) { + DRM_ERROR("GMR2 unbind failed.\n"); + return; + } + define_cmd.gmrId = gmr_id; + define_cmd.numPages = 0; + + *cmd++ = SVGA_CMD_DEFINE_GMR2; + memcpy(cmd, &define_cmd, sizeof(define_cmd)); + + vmw_fifo_commit(dev_priv, define_size); +} + /** * FIXME: Adjust to the ttm lowmem / highmem storage to minimize * the number of used descriptors. @@ -170,6 +241,9 @@ int vmw_gmr_bind(struct vmw_private *dev_priv, struct list_head desc_pages; int ret;
+ if (likely(dev_priv->capabilities & SVGA_CAP_GMR2)) + return vmw_gmr2_bind(dev_priv, pages, num_pages, gmr_id); + if (unlikely(!(dev_priv->capabilities & SVGA_CAP_GMR))) return -EINVAL;
@@ -192,6 +266,11 @@ int vmw_gmr_bind(struct vmw_private *dev_priv,
void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id) { + if (likely(dev_priv->capabilities & SVGA_CAP_GMR2)) { + vmw_gmr2_unbind(dev_priv, gmr_id); + return; + } + mutex_lock(&dev_priv->hw_mutex); vmw_write(dev_priv, SVGA_REG_GMR_ID, gmr_id); wmb();
On Wed, Aug 31, 2011 at 09:42:55AM +0200, Thomas Hellstrom wrote:
Guest Memory Regions 2 is a way to bind pages to the GPU, but using the FIFO instead of an io-submitted descriptor chain.
Signed-off-by: Thomas Hellstrom thellstrom@vmware.com Reviewed-by: Jakob Bornecantz jakob@vmware.com
drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c | 81 ++++++++++++++++++++++++++++++++++- 1 files changed, 80 insertions(+), 1 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c index de0c594..f4e7763 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c @@ -1,6 +1,6 @@ /**************************************************************************
- Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
- Copyright © 2009-2011 VMware, Inc., Palo Alto, CA., USA
- All Rights Reserved.
- Permission is hereby granted, free of charge, to any person obtaining a
@@ -29,6 +29,77 @@ #include "drmP.h" #include "ttm/ttm_bo_driver.h"
+#define VMW_PPN_SIZE sizeof(unsigned long)
+static int vmw_gmr2_bind(struct vmw_private *dev_priv,
struct page *pages[],
unsigned long num_pages,
int gmr_id)
+{
- SVGAFifoCmdDefineGMR2 define_cmd;
- SVGAFifoCmdRemapGMR2 remap_cmd;
- uint32_t define_size = sizeof(define_cmd) + 4;
- uint32_t remap_size = VMW_PPN_SIZE * num_pages + sizeof(remap_cmd) + 4;
Why the +4? Is it just as a precaution in case you over-ran?
- uint32_t *cmd;
- uint32_t *cmd_orig;
- uint32_t i;
- cmd_orig = cmd = vmw_fifo_reserve(dev_priv, define_size + remap_size);
- if (unlikely(cmd == NULL))
return -ENOMEM;
- define_cmd.gmrId = gmr_id;
- define_cmd.numPages = num_pages;
- remap_cmd.gmrId = gmr_id;
- remap_cmd.flags = (VMW_PPN_SIZE > sizeof(*cmd)) ?
SVGA_REMAP_GMR2_PPN64 : SVGA_REMAP_GMR2_PPN32;
- remap_cmd.offsetPages = 0;
- remap_cmd.numPages = num_pages;
- *cmd++ = SVGA_CMD_DEFINE_GMR2;
- memcpy(cmd, &define_cmd, sizeof(define_cmd));
- cmd += sizeof(define_cmd) / sizeof(uint32);
ALIGN macro? Thought I would have thought you would want: cmd += sizeof(define_cmd) - sizeof(uint32);
since you stuck a SVGA_CMD_DEFINE_GMR2 and then copied the define_cmd right afterwards?
- *cmd++ = SVGA_CMD_REMAP_GMR2;
- memcpy(cmd, &remap_cmd, sizeof(remap_cmd));
- cmd += sizeof(remap_cmd) / sizeof(uint32);
- for (i = 0; i < num_pages; ++i) {
if (VMW_PPN_SIZE > 4)
*cmd = page_to_pfn(*pages++);
else
*((uint64_t *)cmd) = page_to_pfn(*pages++);
cmd += VMW_PPN_SIZE / sizeof(*cmd);
- }
- vmw_fifo_commit(dev_priv, define_size + remap_size);
- return 0;
+}
+static void vmw_gmr2_unbind(struct vmw_private *dev_priv,
int gmr_id)
+{
- SVGAFifoCmdDefineGMR2 define_cmd;
- uint32_t define_size = sizeof(define_cmd) + 4;
- uint32_t *cmd;
- cmd = vmw_fifo_reserve(dev_priv, define_size);
- if (unlikely(cmd == NULL)) {
DRM_ERROR("GMR2 unbind failed.\n");
return;
- }
- define_cmd.gmrId = gmr_id;
- define_cmd.numPages = 0;
- *cmd++ = SVGA_CMD_DEFINE_GMR2;
Ah, that is what the +4 is for. Would it be cleaner to just do 'sizeof(SVGA_CMD_DEFINE_GMR2)' ?
- memcpy(cmd, &define_cmd, sizeof(define_cmd));
- vmw_fifo_commit(dev_priv, define_size);
+}
/**
- FIXME: Adjust to the ttm lowmem / highmem storage to minimize
- the number of used descriptors.
@@ -170,6 +241,9 @@ int vmw_gmr_bind(struct vmw_private *dev_priv, struct list_head desc_pages; int ret;
- if (likely(dev_priv->capabilities & SVGA_CAP_GMR2))
return vmw_gmr2_bind(dev_priv, pages, num_pages, gmr_id);
- if (unlikely(!(dev_priv->capabilities & SVGA_CAP_GMR))) return -EINVAL;
@@ -192,6 +266,11 @@ int vmw_gmr_bind(struct vmw_private *dev_priv,
void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id) {
- if (likely(dev_priv->capabilities & SVGA_CAP_GMR2)) {
vmw_gmr2_unbind(dev_priv, gmr_id);
return;
- }
- mutex_lock(&dev_priv->hw_mutex); vmw_write(dev_priv, SVGA_REG_GMR_ID, gmr_id); wmb();
-- 1.7.4.4
dri-devel mailing list dri-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/dri-devel
dri-devel@lists.freedesktop.org