This adds drm_vram_helper_mode_valid(), which tests a display mode against the available video memory. It's a helper function to sort out display modes that cannot be used because of a lack of video memory.
The ast driver already implemented this test for a while. The patchset converts ast over to the helper and adds the test to the over drivers that use VRAM helpers; except mgag200. I left out mgag200 as it doesn't have atomic modesetting yet and needs adjustments to memory management first.
v2: * WARN_ON if VRAM memory manager has not been initialized (Daniel) * unexport drm_vram_helper_mode_valid_internal() (Daniel) * documentation formatting (Daniel) * remove bochs_connector_mode_valid() (Gerd)
Thomas Zimmermann (4): drm/vram: Add helpers to validate a display mode's memory requirements drm/bochs: Implement struct drm_mode_config_funcs.mode_valid drm/hibmc: Implement struct drm_mode_config_funcs.mode_valid drm/vboxvideo: Implement struct drm_mode_config_funcs.mode_valid
drivers/gpu/drm/ast/ast_main.c | 24 +------- drivers/gpu/drm/bochs/bochs_kms.c | 21 +------ drivers/gpu/drm/drm_gem_vram_helper.c | 61 +++++++++++++++++++++ drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c | 1 + drivers/gpu/drm/vboxvideo/vbox_mode.c | 1 + include/drm/drm_gem_vram_helper.h | 9 +++ 6 files changed, 74 insertions(+), 43 deletions(-)
-- 2.25.0
Devices with low amount of dedicated video memory may not be able to use all possible display modes, as the framebuffers may not fit into VRAM. The new helper function drm_vram_helper_mode_valid() implements a simple test to sort out all display modes that can not be used in any case. Drivers should call this function from struct drm_mode_config_funcs.mode_valid.
The functionality was originally implemented by the ast driver, which is being converted as well.
v2: * WARN_ON if VRAM memory manager has not been initialized * documentation fixes * unexported drm_vram_helper_mode_valid_internal()
Signed-off-by: Thomas Zimmermann tzimmermann@suse.de Reviewed-by: Daniel Vetter daniel.vetter@ffwll.ch --- drivers/gpu/drm/ast/ast_main.c | 24 +---------- drivers/gpu/drm/drm_gem_vram_helper.c | 61 +++++++++++++++++++++++++++ include/drm/drm_gem_vram_helper.h | 9 ++++ 3 files changed, 71 insertions(+), 23 deletions(-)
diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index b79f484e9bd2..18a0a4ce00f6 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -388,31 +388,9 @@ static int ast_get_dram_info(struct drm_device *dev) return 0; }
-enum drm_mode_status ast_mode_config_mode_valid(struct drm_device *dev, - const struct drm_display_mode *mode) -{ - static const unsigned long max_bpp = 4; /* DRM_FORMAT_XRGBA8888 */ - - struct ast_private *ast = dev->dev_private; - unsigned long fbsize, fbpages, max_fbpages; - - /* To support double buffering, a framebuffer may not - * consume more than half of the available VRAM. - */ - max_fbpages = (ast->vram_size / 2) >> PAGE_SHIFT; - - fbsize = mode->hdisplay * mode->vdisplay * max_bpp; - fbpages = DIV_ROUND_UP(fbsize, PAGE_SIZE); - - if (fbpages > max_fbpages) - return MODE_MEM; - - return MODE_OK; -} - static const struct drm_mode_config_funcs ast_mode_funcs = { .fb_create = drm_gem_fb_create, - .mode_valid = ast_mode_config_mode_valid, + .mode_valid = drm_vram_helper_mode_valid, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c index a4863326061a..92a11bb42365 100644 --- a/drivers/gpu/drm/drm_gem_vram_helper.c +++ b/drivers/gpu/drm/drm_gem_vram_helper.c @@ -1141,3 +1141,64 @@ void drm_vram_helper_release_mm(struct drm_device *dev) dev->vram_mm = NULL; } EXPORT_SYMBOL(drm_vram_helper_release_mm); + +/* + * Mode-config helpers + */ + +static enum drm_mode_status +drm_vram_helper_mode_valid_internal(struct drm_device *dev, + const struct drm_display_mode *mode, + unsigned long max_bpp) +{ + struct drm_vram_mm *vmm = dev->vram_mm; + unsigned long fbsize, fbpages, max_fbpages; + + if (WARN_ON(!dev->vram_mm)) + return MODE_BAD; + + max_fbpages = (vmm->vram_size / 2) >> PAGE_SHIFT; + + fbsize = mode->hdisplay * mode->vdisplay * max_bpp; + fbpages = DIV_ROUND_UP(fbsize, PAGE_SIZE); + + if (fbpages > max_fbpages) + return MODE_MEM; + + return MODE_OK; +} + +/** + * drm_vram_helper_mode_valid - Tests if a display mode's + * framebuffer fits into the available video memory. + * @dev: the DRM device + * @mode: the mode to test + * + * This function tests if enough video memory is available for using the + * specified display mode. Atomic modesetting requires importing the + * designated framebuffer into video memory before evicting the active + * one. Hence, any framebuffer may consume at most half of the available + * VRAM. Display modes that require a larger framebuffer can not be used, + * even if the CRTC does support them. Each framebuffer is assumed to + * have 32-bit color depth. + * + * Note: + * The function can only test if the display mode is supported in + * general. If there are too many framebuffers pinned to video memory, + * a display mode may still not be usable in practice. The color depth of + * 32-bit fits all current use case. A more flexible test can be added + * when necessary. + * + * Returns: + * MODE_OK if the display mode is supported, or an error code of type + * enum drm_mode_status otherwise. + */ +enum drm_mode_status +drm_vram_helper_mode_valid(struct drm_device *dev, + const struct drm_display_mode *mode) +{ + static const unsigned long max_bpp = 4; /* DRM_FORMAT_XRGB8888 */ + + return drm_vram_helper_mode_valid_internal(dev, mode, max_bpp); +} +EXPORT_SYMBOL(drm_vram_helper_mode_valid); diff --git a/include/drm/drm_gem_vram_helper.h b/include/drm/drm_gem_vram_helper.h index 573e9fd109bf..0f6e47213d8d 100644 --- a/include/drm/drm_gem_vram_helper.h +++ b/include/drm/drm_gem_vram_helper.h @@ -6,6 +6,7 @@ #include <drm/drm_file.h> #include <drm/drm_gem.h> #include <drm/drm_ioctl.h> +#include <drm/drm_modes.h> #include <drm/ttm/ttm_bo_api.h> #include <drm/ttm/ttm_bo_driver.h> #include <drm/ttm/ttm_placement.h> @@ -205,4 +206,12 @@ struct drm_vram_mm *drm_vram_helper_alloc_mm( struct drm_device *dev, uint64_t vram_base, size_t vram_size); void drm_vram_helper_release_mm(struct drm_device *dev);
+/* + * Mode-config helpers + */ + +enum drm_mode_status +drm_vram_helper_mode_valid(struct drm_device *dev, + const struct drm_display_mode *mode); + #endif
The implementation of struct drm_mode_config_funcs.mode_valid verifies that enough video memory is available for a given display mode. This replaces similar functionality in bochs_connector_mode_valid().
v2: * remove bochs_connector_mode_valid(), which now serves no purpose
Signed-off-by: Thomas Zimmermann tzimmermann@suse.de --- drivers/gpu/drm/bochs/bochs_kms.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-)
diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c index ff275faee88d..cc93ff74fbd8 100644 --- a/drivers/gpu/drm/bochs/bochs_kms.c +++ b/drivers/gpu/drm/bochs/bochs_kms.c @@ -83,28 +83,8 @@ static int bochs_connector_get_modes(struct drm_connector *connector) return count; }
-static enum drm_mode_status bochs_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - struct bochs_device *bochs = - container_of(connector, struct bochs_device, connector); - unsigned long size = mode->hdisplay * mode->vdisplay * 4; - - /* - * Make sure we can fit two framebuffers into video memory. - * This allows up to 1600x1200 with 16 MB (default size). - * If you want more try this: - * 'qemu -vga std -global VGA.vgamem_mb=32 $otherargs' - */ - if (size * 2 > bochs->fb_size) - return MODE_BAD; - - return MODE_OK; -} - static const struct drm_connector_helper_funcs bochs_connector_connector_helper_funcs = { .get_modes = bochs_connector_get_modes, - .mode_valid = bochs_connector_mode_valid, };
static const struct drm_connector_funcs bochs_connector_connector_funcs = { @@ -148,6 +128,7 @@ bochs_gem_fb_create(struct drm_device *dev, struct drm_file *file,
const struct drm_mode_config_funcs bochs_mode_funcs = { .fb_create = bochs_gem_fb_create, + .mode_valid = drm_vram_helper_mode_valid, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, };
On Mon, Feb 03, 2020 at 04:52:56PM +0100, Thomas Zimmermann wrote:
The implementation of struct drm_mode_config_funcs.mode_valid verifies that enough video memory is available for a given display mode. This replaces similar functionality in bochs_connector_mode_valid().
v2:
- remove bochs_connector_mode_valid(), which now serves no purpose
Signed-off-by: Thomas Zimmermann tzimmermann@suse.de
Reviewed-by: Gerd Hoffmann kraxel@redhat.com
drivers/gpu/drm/bochs/bochs_kms.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-)
diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c index ff275faee88d..cc93ff74fbd8 100644 --- a/drivers/gpu/drm/bochs/bochs_kms.c +++ b/drivers/gpu/drm/bochs/bochs_kms.c @@ -83,28 +83,8 @@ static int bochs_connector_get_modes(struct drm_connector *connector) return count; }
-static enum drm_mode_status bochs_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
-{
- struct bochs_device *bochs =
container_of(connector, struct bochs_device, connector);
- unsigned long size = mode->hdisplay * mode->vdisplay * 4;
- /*
* Make sure we can fit two framebuffers into video memory.
* This allows up to 1600x1200 with 16 MB (default size).
* If you want more try this:
* 'qemu -vga std -global VGA.vgamem_mb=32 $otherargs'
*/
- if (size * 2 > bochs->fb_size)
return MODE_BAD;
- return MODE_OK;
-}
static const struct drm_connector_helper_funcs bochs_connector_connector_helper_funcs = { .get_modes = bochs_connector_get_modes,
- .mode_valid = bochs_connector_mode_valid,
};
static const struct drm_connector_funcs bochs_connector_connector_funcs = { @@ -148,6 +128,7 @@ bochs_gem_fb_create(struct drm_device *dev, struct drm_file *file,
const struct drm_mode_config_funcs bochs_mode_funcs = { .fb_create = bochs_gem_fb_create,
- .mode_valid = drm_vram_helper_mode_valid, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit,
};
2.25.0
The implementation of struct drm_mode_config_funcs.mode_valid verifies that enough video memory is available for a given display mode.
Signed-off-by: Thomas Zimmermann tzimmermann@suse.de Acked-by: Daniel Vetter daniel.vetter@ffwll.ch --- drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c index 50b988fdd5cc..99397ac3b363 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c @@ -54,6 +54,7 @@ int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev, }
const struct drm_mode_config_funcs hibmc_mode_funcs = { + .mode_valid = drm_vram_helper_mode_valid, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, .fb_create = drm_gem_fb_create,
The implementation of struct drm_mode_config_funcs.mode_valid verifies that enough video memory is available for a given display mode.
Signed-off-by: Thomas Zimmermann tzimmermann@suse.de Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch --- drivers/gpu/drm/vboxvideo/vbox_mode.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/vboxvideo/vbox_mode.c b/drivers/gpu/drm/vboxvideo/vbox_mode.c index 8b7f005c4d20..0883a435e62b 100644 --- a/drivers/gpu/drm/vboxvideo/vbox_mode.c +++ b/drivers/gpu/drm/vboxvideo/vbox_mode.c @@ -826,6 +826,7 @@ static int vbox_connector_init(struct drm_device *dev,
static const struct drm_mode_config_funcs vbox_mode_funcs = { .fb_create = drm_gem_fb_create_with_dirty, + .mode_valid = drm_vram_helper_mode_valid, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, };
dri-devel@lists.freedesktop.org