Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/mgag200: Replace VRAM helpers with SHMEM helpers

The VRAM helpers managed the framebuffer memory for mgag200. This came
with several problems, as some MGA device require the scanout address
to be located at VRAM offset 0. It's incompatible with the page-flip
semantics of DRM's atomic modesettting. With atomic modesetting, old and
new framebuffers have to be located in VRAM at the same time. So at least
one of them has to reside at a non-0 offset.

This patch replaces VRAM helpers with SHMEM helpers. GEM SHMEM buffers
reside in system memory, and are shadow-copied into VRAM during page
flips. The shadow copy always starts at VRAM offset 0.

v2:
* revert dev->pdev changes

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: John Donnelly <John.p.donnelly@oracle.com>
Acked-by: Emil Velikov <emil.velikov@collabora.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200515083233.32036-16-tzimmermann@suse.de

+56 -88
+1 -3
drivers/gpu/drm/mgag200/Kconfig
··· 2 2 config DRM_MGAG200 3 3 tristate "Kernel modesetting driver for MGA G200 server engines" 4 4 depends on DRM && PCI && MMU 5 + select DRM_GEM_SHMEM_HELPER 5 6 select DRM_KMS_HELPER 6 - select DRM_VRAM_HELPER 7 - select DRM_TTM 8 - select DRM_TTM_HELPER 9 7 help 10 8 This is a KMS driver for the MGA G200 server chips, it 11 9 does not support the original MGA G200 or any of the desktop
+2 -47
drivers/gpu/drm/mgag200/mgag200_drv.c
··· 22 22 * which then performs further device association and calls our graphics init 23 23 * functions 24 24 */ 25 - int mgag200_modeset = -1; 26 25 26 + int mgag200_modeset = -1; 27 27 MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); 28 28 module_param_named(modeset, mgag200_modeset, int, 0400); 29 - 30 - int mgag200_hw_bug_no_startadd = -1; 31 - MODULE_PARM_DESC(modeset, "HW does not interpret scanout-buffer start address correctly"); 32 - module_param_named(hw_bug_no_startadd, mgag200_hw_bug_no_startadd, int, 0400); 33 29 34 30 static struct drm_driver driver; 35 31 ··· 97 101 98 102 DEFINE_DRM_GEM_FOPS(mgag200_driver_fops); 99 103 100 - static bool mgag200_pin_bo_at_0(const struct mga_device *mdev) 101 - { 102 - if (mgag200_hw_bug_no_startadd > 0) { 103 - DRM_WARN_ONCE("Option hw_bug_no_startradd is enabled. Please " 104 - "report the output of 'lspci -vvnn' to " 105 - "<dri-devel@lists.freedesktop.org> if this " 106 - "option is required to make mgag200 work " 107 - "correctly on your system.\n"); 108 - return true; 109 - } else if (!mgag200_hw_bug_no_startadd) { 110 - return false; 111 - } 112 - return mdev->flags & MGAG200_FLAG_HW_BUG_NO_STARTADD; 113 - } 114 - 115 - int mgag200_driver_dumb_create(struct drm_file *file, 116 - struct drm_device *dev, 117 - struct drm_mode_create_dumb *args) 118 - { 119 - struct mga_device *mdev = to_mga_device(dev); 120 - unsigned long pg_align; 121 - 122 - if (WARN_ONCE(!dev->vram_mm, "VRAM MM not initialized")) 123 - return -EINVAL; 124 - 125 - pg_align = 0ul; 126 - 127 - /* 128 - * Aligning scanout buffers to the size of the video ram forces 129 - * placement at offset 0. Works around a bug where HW does not 130 - * respect 'startadd' field. 131 - */ 132 - if (mgag200_pin_bo_at_0(mdev)) 133 - pg_align = PFN_UP(mdev->mc.vram_size); 134 - 135 - return drm_gem_vram_fill_create_dumb(file, dev, pg_align, 0, args); 136 - } 137 - 138 104 static struct drm_driver driver = { 139 105 .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET, 140 106 .fops = &mgag200_driver_fops, ··· 106 148 .major = DRIVER_MAJOR, 107 149 .minor = DRIVER_MINOR, 108 150 .patchlevel = DRIVER_PATCHLEVEL, 109 - .debugfs_init = drm_vram_mm_debugfs_init, 110 - .dumb_create = mgag200_driver_dumb_create, 111 - .dumb_map_offset = drm_gem_vram_driver_dumb_mmap_offset, 112 - .gem_prime_mmap = drm_gem_prime_mmap, 151 + DRM_GEM_SHMEM_DRIVER_OPS, 113 152 }; 114 153 115 154 static struct pci_driver mgag200_pci_driver = {
+3 -2
drivers/gpu/drm/mgag200/mgag200_drv.h
··· 18 18 #include <drm/drm_encoder.h> 19 19 #include <drm/drm_fb_helper.h> 20 20 #include <drm/drm_gem.h> 21 - #include <drm/drm_gem_vram_helper.h> 21 + #include <drm/drm_gem_shmem_helper.h> 22 22 #include <drm/drm_simple_kms_helper.h> 23 23 24 24 #include "mgag200_reg.h" ··· 151 151 152 152 struct mga_mc mc; 153 153 154 - size_t vram_fb_available; 154 + void __iomem *vram; 155 + size_t vram_fb_available; 155 156 156 157 enum mga_type type; 157 158 int has_sdram;
+35 -23
drivers/gpu/drm/mgag200/mgag200_mode.c
··· 14 14 #include <drm/drm_atomic_helper.h> 15 15 #include <drm/drm_atomic_state_helper.h> 16 16 #include <drm/drm_crtc_helper.h> 17 + #include <drm/drm_damage_helper.h> 18 + #include <drm/drm_format_helper.h> 17 19 #include <drm/drm_fourcc.h> 18 20 #include <drm/drm_gem_framebuffer_helper.h> 19 21 #include <drm/drm_plane_helper.h> ··· 1576 1574 } 1577 1575 1578 1576 static void 1577 + mgag200_handle_damage(struct mga_device *mdev, struct drm_framebuffer *fb, 1578 + struct drm_rect *clip) 1579 + { 1580 + struct drm_device *dev = mdev->dev; 1581 + void *vmap; 1582 + 1583 + vmap = drm_gem_shmem_vmap(fb->obj[0]); 1584 + if (drm_WARN_ON(dev, !vmap)) 1585 + return; /* BUG: SHMEM BO should always be vmapped */ 1586 + 1587 + drm_fb_memcpy_dstclip(mdev->vram, vmap, fb, clip); 1588 + 1589 + drm_gem_shmem_vunmap(fb->obj[0], vmap); 1590 + 1591 + /* Always scanout image at VRAM offset 0 */ 1592 + mgag200_set_startadd(mdev, (u32)0); 1593 + mgag200_set_offset(mdev, fb); 1594 + } 1595 + 1596 + static void 1579 1597 mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, 1580 1598 struct drm_crtc_state *crtc_state, 1581 1599 struct drm_plane_state *plane_state) ··· 1605 1583 struct mga_device *mdev = to_mga_device(dev); 1606 1584 struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; 1607 1585 struct drm_framebuffer *fb = plane_state->fb; 1608 - struct drm_gem_vram_object *gbo; 1609 - s64 gpu_addr; 1610 - 1611 - gbo = drm_gem_vram_of_gem(fb->obj[0]); 1612 - 1613 - gpu_addr = drm_gem_vram_offset(gbo); 1614 - if (drm_WARN_ON_ONCE(dev, gpu_addr < 0)) 1615 - return; /* BUG: BO should have been pinned to VRAM. */ 1586 + struct drm_rect fullscreen = { 1587 + .x1 = 0, 1588 + .x2 = fb->width, 1589 + .y1 = 0, 1590 + .y2 = fb->height, 1591 + }; 1616 1592 1617 1593 mga_crtc_prepare(crtc); 1618 1594 ··· 1626 1606 mgag200_g200ev_set_hiprilvl(mdev); 1627 1607 1628 1608 mga_crtc_commit(crtc); 1609 + 1610 + mgag200_handle_damage(mdev, fb, &fullscreen); 1629 1611 } 1630 1612 1631 1613 static void ··· 1668 1646 struct mga_device *mdev = to_mga_device(dev); 1669 1647 struct drm_plane_state *state = plane->state; 1670 1648 struct drm_framebuffer *fb = state->fb; 1671 - struct drm_gem_vram_object *gbo; 1672 - s64 gpu_addr; 1649 + struct drm_rect damage; 1673 1650 1674 1651 if (!fb) 1675 1652 return; 1676 1653 1677 - gbo = drm_gem_vram_of_gem(fb->obj[0]); 1678 - 1679 - gpu_addr = drm_gem_vram_offset(gbo); 1680 - if (drm_WARN_ON_ONCE(dev, gpu_addr < 0)) 1681 - return; /* BUG: BO should have been pinned to VRAM. */ 1682 - 1683 - mgag200_set_startadd(mdev, (unsigned long)gpu_addr); 1684 - mgag200_set_offset(mdev, fb); 1654 + if (drm_atomic_helper_damage_merged(old_state, state, &damage)) 1655 + mgag200_handle_damage(mdev, fb, &damage); 1685 1656 } 1686 1657 1687 1658 static const struct drm_simple_display_pipe_funcs ··· 1684 1669 .disable = mgag200_simple_display_pipe_disable, 1685 1670 .check = mgag200_simple_display_pipe_check, 1686 1671 .update = mgag200_simple_display_pipe_update, 1687 - .prepare_fb = drm_gem_vram_simple_display_pipe_prepare_fb, 1688 - .cleanup_fb = drm_gem_vram_simple_display_pipe_cleanup_fb, 1672 + .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb, 1689 1673 }; 1690 1674 1691 1675 static const uint32_t mgag200_simple_display_pipe_formats[] = { ··· 1703 1689 */ 1704 1690 1705 1691 static const struct drm_mode_config_funcs mgag200_mode_config_funcs = { 1706 - .fb_create = drm_gem_fb_create, 1707 - .mode_valid = drm_vram_helper_mode_valid, 1692 + .fb_create = drm_gem_fb_create_with_dirty, 1708 1693 .atomic_check = drm_atomic_helper_check, 1709 1694 .atomic_commit = drm_atomic_helper_commit, 1710 1695 }; ··· 1742 1729 dev->mode_config.max_height = MGAG200_MAX_FB_HEIGHT; 1743 1730 1744 1731 dev->mode_config.preferred_depth = mgag200_preferred_depth(mdev); 1745 - dev->mode_config.prefer_shadow = 1; 1746 1732 1747 1733 dev->mode_config.fb_base = mdev->mc.vram_base; 1748 1734
+15 -13
drivers/gpu/drm/mgag200/mgag200_ttm.c
··· 32 32 33 33 int mgag200_mm_init(struct mga_device *mdev) 34 34 { 35 - struct drm_vram_mm *vmm; 36 - int ret; 37 35 struct drm_device *dev = mdev->dev; 38 - 39 - vmm = drm_vram_helper_alloc_mm(dev, pci_resource_start(dev->pdev, 0), 40 - mdev->mc.vram_size); 41 - if (IS_ERR(vmm)) { 42 - ret = PTR_ERR(vmm); 43 - DRM_ERROR("Error initializing VRAM MM; %d\n", ret); 44 - return ret; 45 - } 36 + int ret; 46 37 47 38 arch_io_reserve_memtype_wc(pci_resource_start(dev->pdev, 0), 48 39 pci_resource_len(dev->pdev, 0)); ··· 41 50 mdev->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0), 42 51 pci_resource_len(dev->pdev, 0)); 43 52 53 + mdev->vram = ioremap(pci_resource_start(dev->pdev, 0), 54 + pci_resource_len(dev->pdev, 0)); 55 + if (!mdev->vram) { 56 + ret = -ENOMEM; 57 + goto err_arch_phys_wc_del; 58 + } 59 + 44 60 mdev->vram_fb_available = mdev->mc.vram_size; 45 61 46 62 return 0; 63 + 64 + err_arch_phys_wc_del: 65 + arch_phys_wc_del(mdev->fb_mtrr); 66 + arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0), 67 + pci_resource_len(dev->pdev, 0)); 68 + return ret; 47 69 } 48 70 49 71 void mgag200_mm_fini(struct mga_device *mdev) ··· 64 60 struct drm_device *dev = mdev->dev; 65 61 66 62 mdev->vram_fb_available = 0; 67 - 68 - drm_vram_helper_release_mm(dev); 69 - 63 + iounmap(mdev->vram); 70 64 arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0), 71 65 pci_resource_len(dev->pdev, 0)); 72 66 arch_phys_wc_del(mdev->fb_mtrr);