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

drm/bochs: new driver

DRM driver for (virtual) vga cards using the bochs dispi
interface, such as the qemu standard vga (qemu -vga std).

Don't bother supporting anything but 32bpp for now, even
though the virtual hardware is able to do that.

Known issue: mmap(/dev/fb0) doesn't work.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>

authored by

Gerd Hoffmann and committed by
Dave Airlie
0a6659bd 859ae233

+1592
+2
drivers/gpu/drm/Kconfig
··· 192 192 193 193 source "drivers/gpu/drm/qxl/Kconfig" 194 194 195 + source "drivers/gpu/drm/bochs/Kconfig" 196 + 195 197 source "drivers/gpu/drm/msm/Kconfig" 196 198 197 199 source "drivers/gpu/drm/tegra/Kconfig"
+1
drivers/gpu/drm/Makefile
··· 58 58 obj-$(CONFIG_DRM_OMAP) += omapdrm/ 59 59 obj-$(CONFIG_DRM_TILCDC) += tilcdc/ 60 60 obj-$(CONFIG_DRM_QXL) += qxl/ 61 + obj-$(CONFIG_DRM_BOCHS) += bochs/ 61 62 obj-$(CONFIG_DRM_MSM) += msm/ 62 63 obj-$(CONFIG_DRM_TEGRA) += tegra/ 63 64 obj-y += i2c/
+11
drivers/gpu/drm/bochs/Kconfig
··· 1 + config DRM_BOCHS 2 + tristate "DRM Support for bochs dispi vga interface (qemu stdvga)" 3 + depends on DRM && PCI 4 + select DRM_KMS_HELPER 5 + select FB_SYS_FILLRECT 6 + select FB_SYS_COPYAREA 7 + select FB_SYS_IMAGEBLIT 8 + select DRM_TTM 9 + help 10 + Choose this option for qemu. 11 + If M is selected the module will be called bochs-drm.
+4
drivers/gpu/drm/bochs/Makefile
··· 1 + ccflags-y := -Iinclude/drm 2 + bochs-drm-y := bochs_drv.o bochs_mm.o bochs_kms.o bochs_fbdev.o bochs_hw.o 3 + 4 + obj-$(CONFIG_DRM_BOCHS) += bochs-drm.o
+164
drivers/gpu/drm/bochs/bochs.h
··· 1 + #include <linux/io.h> 2 + #include <linux/fb.h> 3 + 4 + #include <drm/drmP.h> 5 + #include <drm/drm_crtc.h> 6 + #include <drm/drm_crtc_helper.h> 7 + #include <drm/drm_fb_helper.h> 8 + 9 + #include <ttm/ttm_bo_driver.h> 10 + #include <ttm/ttm_page_alloc.h> 11 + 12 + /* ---------------------------------------------------------------------- */ 13 + 14 + #define VBE_DISPI_IOPORT_INDEX 0x01CE 15 + #define VBE_DISPI_IOPORT_DATA 0x01CF 16 + 17 + #define VBE_DISPI_INDEX_ID 0x0 18 + #define VBE_DISPI_INDEX_XRES 0x1 19 + #define VBE_DISPI_INDEX_YRES 0x2 20 + #define VBE_DISPI_INDEX_BPP 0x3 21 + #define VBE_DISPI_INDEX_ENABLE 0x4 22 + #define VBE_DISPI_INDEX_BANK 0x5 23 + #define VBE_DISPI_INDEX_VIRT_WIDTH 0x6 24 + #define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7 25 + #define VBE_DISPI_INDEX_X_OFFSET 0x8 26 + #define VBE_DISPI_INDEX_Y_OFFSET 0x9 27 + #define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa 28 + 29 + #define VBE_DISPI_ID0 0xB0C0 30 + #define VBE_DISPI_ID1 0xB0C1 31 + #define VBE_DISPI_ID2 0xB0C2 32 + #define VBE_DISPI_ID3 0xB0C3 33 + #define VBE_DISPI_ID4 0xB0C4 34 + #define VBE_DISPI_ID5 0xB0C5 35 + 36 + #define VBE_DISPI_DISABLED 0x00 37 + #define VBE_DISPI_ENABLED 0x01 38 + #define VBE_DISPI_GETCAPS 0x02 39 + #define VBE_DISPI_8BIT_DAC 0x20 40 + #define VBE_DISPI_LFB_ENABLED 0x40 41 + #define VBE_DISPI_NOCLEARMEM 0x80 42 + 43 + /* ---------------------------------------------------------------------- */ 44 + 45 + enum bochs_types { 46 + BOCHS_QEMU_STDVGA, 47 + BOCHS_UNKNOWN, 48 + }; 49 + 50 + struct bochs_framebuffer { 51 + struct drm_framebuffer base; 52 + struct drm_gem_object *obj; 53 + }; 54 + 55 + struct bochs_device { 56 + /* hw */ 57 + void __iomem *mmio; 58 + int ioports; 59 + void __iomem *fb_map; 60 + unsigned long fb_base; 61 + unsigned long fb_size; 62 + 63 + /* mode */ 64 + u16 xres; 65 + u16 yres; 66 + u16 yres_virtual; 67 + u32 stride; 68 + u32 bpp; 69 + 70 + /* drm */ 71 + struct drm_device *dev; 72 + struct drm_crtc crtc; 73 + struct drm_encoder encoder; 74 + struct drm_connector connector; 75 + bool mode_config_initialized; 76 + 77 + /* ttm */ 78 + struct { 79 + struct drm_global_reference mem_global_ref; 80 + struct ttm_bo_global_ref bo_global_ref; 81 + struct ttm_bo_device bdev; 82 + bool initialized; 83 + } ttm; 84 + 85 + /* fbdev */ 86 + struct { 87 + struct bochs_framebuffer gfb; 88 + struct drm_fb_helper helper; 89 + int size; 90 + int x1, y1, x2, y2; /* dirty rect */ 91 + spinlock_t dirty_lock; 92 + bool initialized; 93 + } fb; 94 + }; 95 + 96 + #define to_bochs_framebuffer(x) container_of(x, struct bochs_framebuffer, base) 97 + 98 + struct bochs_bo { 99 + struct ttm_buffer_object bo; 100 + struct ttm_placement placement; 101 + struct ttm_bo_kmap_obj kmap; 102 + struct drm_gem_object gem; 103 + u32 placements[3]; 104 + int pin_count; 105 + }; 106 + 107 + static inline struct bochs_bo *bochs_bo(struct ttm_buffer_object *bo) 108 + { 109 + return container_of(bo, struct bochs_bo, bo); 110 + } 111 + 112 + static inline struct bochs_bo *gem_to_bochs_bo(struct drm_gem_object *gem) 113 + { 114 + return container_of(gem, struct bochs_bo, gem); 115 + } 116 + 117 + #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT) 118 + 119 + static inline u64 bochs_bo_mmap_offset(struct bochs_bo *bo) 120 + { 121 + return drm_vma_node_offset_addr(&bo->bo.vma_node); 122 + } 123 + 124 + /* ---------------------------------------------------------------------- */ 125 + 126 + /* bochs_hw.c */ 127 + int bochs_hw_init(struct drm_device *dev, uint32_t flags); 128 + void bochs_hw_fini(struct drm_device *dev); 129 + 130 + void bochs_hw_setmode(struct bochs_device *bochs, 131 + struct drm_display_mode *mode); 132 + void bochs_hw_setbase(struct bochs_device *bochs, 133 + int x, int y, u64 addr); 134 + 135 + /* bochs_mm.c */ 136 + int bochs_mm_init(struct bochs_device *bochs); 137 + void bochs_mm_fini(struct bochs_device *bochs); 138 + int bochs_mmap(struct file *filp, struct vm_area_struct *vma); 139 + 140 + int bochs_gem_create(struct drm_device *dev, u32 size, bool iskernel, 141 + struct drm_gem_object **obj); 142 + int bochs_gem_init_object(struct drm_gem_object *obj); 143 + void bochs_gem_free_object(struct drm_gem_object *obj); 144 + int bochs_dumb_create(struct drm_file *file, struct drm_device *dev, 145 + struct drm_mode_create_dumb *args); 146 + int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, 147 + uint32_t handle, uint64_t *offset); 148 + 149 + int bochs_framebuffer_init(struct drm_device *dev, 150 + struct bochs_framebuffer *gfb, 151 + struct drm_mode_fb_cmd2 *mode_cmd, 152 + struct drm_gem_object *obj); 153 + int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr); 154 + int bochs_bo_unpin(struct bochs_bo *bo); 155 + 156 + extern const struct drm_mode_config_funcs bochs_mode_funcs; 157 + 158 + /* bochs_kms.c */ 159 + int bochs_kms_init(struct bochs_device *bochs); 160 + void bochs_kms_fini(struct bochs_device *bochs); 161 + 162 + /* bochs_fbdev.c */ 163 + int bochs_fbdev_init(struct bochs_device *bochs); 164 + void bochs_fbdev_fini(struct bochs_device *bochs);
+178
drivers/gpu/drm/bochs/bochs_drv.c
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify 3 + * it under the terms of the GNU General Public License as published by 4 + * the Free Software Foundation; either version 2 of the License, or 5 + * (at your option) any later version. 6 + */ 7 + 8 + #include <linux/mm.h> 9 + #include <linux/module.h> 10 + #include <linux/slab.h> 11 + 12 + #include "bochs.h" 13 + 14 + static bool enable_fbdev = true; 15 + module_param_named(fbdev, enable_fbdev, bool, 0444); 16 + MODULE_PARM_DESC(fbdev, "register fbdev device"); 17 + 18 + /* ---------------------------------------------------------------------- */ 19 + /* drm interface */ 20 + 21 + static int bochs_unload(struct drm_device *dev) 22 + { 23 + struct bochs_device *bochs = dev->dev_private; 24 + 25 + bochs_fbdev_fini(bochs); 26 + bochs_kms_fini(bochs); 27 + bochs_mm_fini(bochs); 28 + bochs_hw_fini(dev); 29 + kfree(bochs); 30 + dev->dev_private = NULL; 31 + return 0; 32 + } 33 + 34 + static int bochs_load(struct drm_device *dev, unsigned long flags) 35 + { 36 + struct bochs_device *bochs; 37 + int ret; 38 + 39 + bochs = kzalloc(sizeof(*bochs), GFP_KERNEL); 40 + if (bochs == NULL) 41 + return -ENOMEM; 42 + dev->dev_private = bochs; 43 + bochs->dev = dev; 44 + 45 + ret = bochs_hw_init(dev, flags); 46 + if (ret) 47 + goto err; 48 + 49 + ret = bochs_mm_init(bochs); 50 + if (ret) 51 + goto err; 52 + 53 + ret = bochs_kms_init(bochs); 54 + if (ret) 55 + goto err; 56 + 57 + if (enable_fbdev) 58 + bochs_fbdev_init(bochs); 59 + 60 + return 0; 61 + 62 + err: 63 + bochs_unload(dev); 64 + return ret; 65 + } 66 + 67 + static const struct file_operations bochs_fops = { 68 + .owner = THIS_MODULE, 69 + .open = drm_open, 70 + .release = drm_release, 71 + .unlocked_ioctl = drm_ioctl, 72 + #ifdef CONFIG_COMPAT 73 + .compat_ioctl = drm_compat_ioctl, 74 + #endif 75 + .poll = drm_poll, 76 + .read = drm_read, 77 + .llseek = no_llseek, 78 + .mmap = bochs_mmap, 79 + }; 80 + 81 + static struct drm_driver bochs_driver = { 82 + .driver_features = DRIVER_GEM | DRIVER_MODESET, 83 + .load = bochs_load, 84 + .unload = bochs_unload, 85 + .fops = &bochs_fops, 86 + .name = "bochs-drm", 87 + .desc = "bochs dispi vga interface (qemu stdvga)", 88 + .date = "20130925", 89 + .major = 1, 90 + .minor = 0, 91 + .gem_free_object = bochs_gem_free_object, 92 + .dumb_create = bochs_dumb_create, 93 + .dumb_map_offset = bochs_dumb_mmap_offset, 94 + .dumb_destroy = drm_gem_dumb_destroy, 95 + }; 96 + 97 + /* ---------------------------------------------------------------------- */ 98 + /* pci interface */ 99 + 100 + static int bochs_kick_out_firmware_fb(struct pci_dev *pdev) 101 + { 102 + struct apertures_struct *ap; 103 + 104 + ap = alloc_apertures(1); 105 + if (!ap) 106 + return -ENOMEM; 107 + 108 + ap->ranges[0].base = pci_resource_start(pdev, 0); 109 + ap->ranges[0].size = pci_resource_len(pdev, 0); 110 + remove_conflicting_framebuffers(ap, "bochsdrmfb", false); 111 + kfree(ap); 112 + 113 + return 0; 114 + } 115 + 116 + static int bochs_pci_probe(struct pci_dev *pdev, 117 + const struct pci_device_id *ent) 118 + { 119 + int ret; 120 + 121 + ret = bochs_kick_out_firmware_fb(pdev); 122 + if (ret) 123 + return ret; 124 + 125 + return drm_get_pci_dev(pdev, ent, &bochs_driver); 126 + } 127 + 128 + static void bochs_pci_remove(struct pci_dev *pdev) 129 + { 130 + struct drm_device *dev = pci_get_drvdata(pdev); 131 + 132 + drm_put_dev(dev); 133 + } 134 + 135 + static DEFINE_PCI_DEVICE_TABLE(bochs_pci_tbl) = { 136 + { 137 + .vendor = 0x1234, 138 + .device = 0x1111, 139 + .subvendor = 0x1af4, 140 + .subdevice = 0x1100, 141 + .driver_data = BOCHS_QEMU_STDVGA, 142 + }, 143 + { 144 + .vendor = 0x1234, 145 + .device = 0x1111, 146 + .subvendor = PCI_ANY_ID, 147 + .subdevice = PCI_ANY_ID, 148 + .driver_data = BOCHS_UNKNOWN, 149 + }, 150 + { /* end of list */ } 151 + }; 152 + 153 + static struct pci_driver bochs_pci_driver = { 154 + .name = "bochs-drm", 155 + .id_table = bochs_pci_tbl, 156 + .probe = bochs_pci_probe, 157 + .remove = bochs_pci_remove, 158 + }; 159 + 160 + /* ---------------------------------------------------------------------- */ 161 + /* module init/exit */ 162 + 163 + static int __init bochs_init(void) 164 + { 165 + return drm_pci_init(&bochs_driver, &bochs_pci_driver); 166 + } 167 + 168 + static void __exit bochs_exit(void) 169 + { 170 + drm_pci_exit(&bochs_driver, &bochs_pci_driver); 171 + } 172 + 173 + module_init(bochs_init); 174 + module_exit(bochs_exit); 175 + 176 + MODULE_DEVICE_TABLE(pci, bochs_pci_tbl); 177 + MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>"); 178 + MODULE_LICENSE("GPL");
+215
drivers/gpu/drm/bochs/bochs_fbdev.c
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify 3 + * it under the terms of the GNU General Public License as published by 4 + * the Free Software Foundation; either version 2 of the License, or 5 + * (at your option) any later version. 6 + */ 7 + 8 + #include "bochs.h" 9 + 10 + /* ---------------------------------------------------------------------- */ 11 + 12 + static struct fb_ops bochsfb_ops = { 13 + .owner = THIS_MODULE, 14 + .fb_check_var = drm_fb_helper_check_var, 15 + .fb_set_par = drm_fb_helper_set_par, 16 + .fb_fillrect = sys_fillrect, 17 + .fb_copyarea = sys_copyarea, 18 + .fb_imageblit = sys_imageblit, 19 + .fb_pan_display = drm_fb_helper_pan_display, 20 + .fb_blank = drm_fb_helper_blank, 21 + .fb_setcmap = drm_fb_helper_setcmap, 22 + }; 23 + 24 + static int bochsfb_create_object(struct bochs_device *bochs, 25 + struct drm_mode_fb_cmd2 *mode_cmd, 26 + struct drm_gem_object **gobj_p) 27 + { 28 + struct drm_device *dev = bochs->dev; 29 + struct drm_gem_object *gobj; 30 + u32 size; 31 + int ret = 0; 32 + 33 + size = mode_cmd->pitches[0] * mode_cmd->height; 34 + ret = bochs_gem_create(dev, size, true, &gobj); 35 + if (ret) 36 + return ret; 37 + 38 + *gobj_p = gobj; 39 + return ret; 40 + } 41 + 42 + static int bochsfb_create(struct drm_fb_helper *helper, 43 + struct drm_fb_helper_surface_size *sizes) 44 + { 45 + struct bochs_device *bochs = 46 + container_of(helper, struct bochs_device, fb.helper); 47 + struct drm_device *dev = bochs->dev; 48 + struct fb_info *info; 49 + struct drm_framebuffer *fb; 50 + struct drm_mode_fb_cmd2 mode_cmd; 51 + struct device *device = &dev->pdev->dev; 52 + struct drm_gem_object *gobj = NULL; 53 + struct bochs_bo *bo = NULL; 54 + int size, ret; 55 + 56 + if (sizes->surface_bpp != 32) 57 + return -EINVAL; 58 + 59 + mode_cmd.width = sizes->surface_width; 60 + mode_cmd.height = sizes->surface_height; 61 + mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8); 62 + mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, 63 + sizes->surface_depth); 64 + size = mode_cmd.pitches[0] * mode_cmd.height; 65 + 66 + /* alloc, pin & map bo */ 67 + ret = bochsfb_create_object(bochs, &mode_cmd, &gobj); 68 + if (ret) { 69 + DRM_ERROR("failed to create fbcon backing object %d\n", ret); 70 + return ret; 71 + } 72 + 73 + bo = gem_to_bochs_bo(gobj); 74 + 75 + ret = ttm_bo_reserve(&bo->bo, true, false, false, 0); 76 + if (ret) 77 + return ret; 78 + 79 + ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL); 80 + if (ret) { 81 + DRM_ERROR("failed to pin fbcon\n"); 82 + ttm_bo_unreserve(&bo->bo); 83 + return ret; 84 + } 85 + 86 + ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, 87 + &bo->kmap); 88 + if (ret) { 89 + DRM_ERROR("failed to kmap fbcon\n"); 90 + ttm_bo_unreserve(&bo->bo); 91 + return ret; 92 + } 93 + 94 + ttm_bo_unreserve(&bo->bo); 95 + 96 + /* init fb device */ 97 + info = framebuffer_alloc(0, device); 98 + if (info == NULL) 99 + return -ENOMEM; 100 + 101 + info->par = &bochs->fb.helper; 102 + 103 + ret = bochs_framebuffer_init(bochs->dev, &bochs->fb.gfb, &mode_cmd, gobj); 104 + if (ret) 105 + return ret; 106 + 107 + bochs->fb.size = size; 108 + 109 + /* setup helper */ 110 + fb = &bochs->fb.gfb.base; 111 + bochs->fb.helper.fb = fb; 112 + bochs->fb.helper.fbdev = info; 113 + 114 + strcpy(info->fix.id, "bochsdrmfb"); 115 + 116 + info->flags = FBINFO_DEFAULT; 117 + info->fbops = &bochsfb_ops; 118 + 119 + drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); 120 + drm_fb_helper_fill_var(info, &bochs->fb.helper, sizes->fb_width, 121 + sizes->fb_height); 122 + 123 + info->screen_base = bo->kmap.virtual; 124 + info->screen_size = size; 125 + 126 + #if 0 127 + /* FIXME: get this right for mmap(/dev/fb0) */ 128 + info->fix.smem_start = bochs_bo_mmap_offset(bo); 129 + info->fix.smem_len = size; 130 + #endif 131 + 132 + ret = fb_alloc_cmap(&info->cmap, 256, 0); 133 + if (ret) { 134 + DRM_ERROR("%s: can't allocate color map\n", info->fix.id); 135 + return -ENOMEM; 136 + } 137 + 138 + return 0; 139 + } 140 + 141 + static int bochs_fbdev_destroy(struct bochs_device *bochs) 142 + { 143 + struct bochs_framebuffer *gfb = &bochs->fb.gfb; 144 + struct fb_info *info; 145 + 146 + DRM_DEBUG_DRIVER("\n"); 147 + 148 + if (bochs->fb.helper.fbdev) { 149 + info = bochs->fb.helper.fbdev; 150 + 151 + unregister_framebuffer(info); 152 + if (info->cmap.len) 153 + fb_dealloc_cmap(&info->cmap); 154 + framebuffer_release(info); 155 + } 156 + 157 + if (gfb->obj) { 158 + drm_gem_object_unreference_unlocked(gfb->obj); 159 + gfb->obj = NULL; 160 + } 161 + 162 + drm_fb_helper_fini(&bochs->fb.helper); 163 + drm_framebuffer_unregister_private(&gfb->base); 164 + drm_framebuffer_cleanup(&gfb->base); 165 + 166 + return 0; 167 + } 168 + 169 + void bochs_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, 170 + u16 blue, int regno) 171 + { 172 + } 173 + 174 + void bochs_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, 175 + u16 *blue, int regno) 176 + { 177 + *red = regno; 178 + *green = regno; 179 + *blue = regno; 180 + } 181 + 182 + static struct drm_fb_helper_funcs bochs_fb_helper_funcs = { 183 + .gamma_set = bochs_fb_gamma_set, 184 + .gamma_get = bochs_fb_gamma_get, 185 + .fb_probe = bochsfb_create, 186 + }; 187 + 188 + int bochs_fbdev_init(struct bochs_device *bochs) 189 + { 190 + int ret; 191 + 192 + bochs->fb.helper.funcs = &bochs_fb_helper_funcs; 193 + spin_lock_init(&bochs->fb.dirty_lock); 194 + 195 + ret = drm_fb_helper_init(bochs->dev, &bochs->fb.helper, 196 + 1, 1); 197 + if (ret) 198 + return ret; 199 + 200 + drm_fb_helper_single_add_all_connectors(&bochs->fb.helper); 201 + drm_helper_disable_unused_functions(bochs->dev); 202 + drm_fb_helper_initial_config(&bochs->fb.helper, 32); 203 + 204 + bochs->fb.initialized = true; 205 + return 0; 206 + } 207 + 208 + void bochs_fbdev_fini(struct bochs_device *bochs) 209 + { 210 + if (!bochs->fb.initialized) 211 + return; 212 + 213 + bochs_fbdev_destroy(bochs); 214 + bochs->fb.initialized = false; 215 + }
+177
drivers/gpu/drm/bochs/bochs_hw.c
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify 3 + * it under the terms of the GNU General Public License as published by 4 + * the Free Software Foundation; either version 2 of the License, or 5 + * (at your option) any later version. 6 + */ 7 + 8 + #include "bochs.h" 9 + 10 + /* ---------------------------------------------------------------------- */ 11 + 12 + static void bochs_vga_writeb(struct bochs_device *bochs, u16 ioport, u8 val) 13 + { 14 + if (WARN_ON(ioport < 0x3c0 || ioport > 0x3df)) 15 + return; 16 + 17 + if (bochs->mmio) { 18 + int offset = ioport - 0x3c0 + 0x400; 19 + writeb(val, bochs->mmio + offset); 20 + } else { 21 + outb(val, ioport); 22 + } 23 + } 24 + 25 + static u16 bochs_dispi_read(struct bochs_device *bochs, u16 reg) 26 + { 27 + u16 ret = 0; 28 + 29 + if (bochs->mmio) { 30 + int offset = 0x500 + (reg << 1); 31 + ret = readw(bochs->mmio + offset); 32 + } else { 33 + outw(reg, VBE_DISPI_IOPORT_INDEX); 34 + ret = inw(VBE_DISPI_IOPORT_DATA); 35 + } 36 + return ret; 37 + } 38 + 39 + static void bochs_dispi_write(struct bochs_device *bochs, u16 reg, u16 val) 40 + { 41 + if (bochs->mmio) { 42 + int offset = 0x500 + (reg << 1); 43 + writew(val, bochs->mmio + offset); 44 + } else { 45 + outw(reg, VBE_DISPI_IOPORT_INDEX); 46 + outw(val, VBE_DISPI_IOPORT_DATA); 47 + } 48 + } 49 + 50 + int bochs_hw_init(struct drm_device *dev, uint32_t flags) 51 + { 52 + struct bochs_device *bochs = dev->dev_private; 53 + struct pci_dev *pdev = dev->pdev; 54 + unsigned long addr, size, mem, ioaddr, iosize; 55 + u16 id; 56 + 57 + if (/* (ent->driver_data == BOCHS_QEMU_STDVGA) && */ 58 + (pdev->resource[2].flags & IORESOURCE_MEM)) { 59 + /* mmio bar with vga and bochs registers present */ 60 + if (pci_request_region(pdev, 2, "bochs-drm") != 0) { 61 + DRM_ERROR("Cannot request mmio region\n"); 62 + return -EBUSY; 63 + } 64 + ioaddr = pci_resource_start(pdev, 2); 65 + iosize = pci_resource_len(pdev, 2); 66 + bochs->mmio = ioremap(ioaddr, iosize); 67 + if (bochs->mmio == NULL) { 68 + DRM_ERROR("Cannot map mmio region\n"); 69 + return -ENOMEM; 70 + } 71 + } else { 72 + ioaddr = VBE_DISPI_IOPORT_INDEX; 73 + iosize = 2; 74 + if (!request_region(ioaddr, iosize, "bochs-drm")) { 75 + DRM_ERROR("Cannot request ioports\n"); 76 + return -EBUSY; 77 + } 78 + bochs->ioports = 1; 79 + } 80 + 81 + id = bochs_dispi_read(bochs, VBE_DISPI_INDEX_ID); 82 + mem = bochs_dispi_read(bochs, VBE_DISPI_INDEX_VIDEO_MEMORY_64K) 83 + * 64 * 1024; 84 + if ((id & 0xfff0) != VBE_DISPI_ID0) { 85 + DRM_ERROR("ID mismatch\n"); 86 + return -ENODEV; 87 + } 88 + 89 + if ((pdev->resource[0].flags & IORESOURCE_MEM) == 0) 90 + return -ENODEV; 91 + addr = pci_resource_start(pdev, 0); 92 + size = pci_resource_len(pdev, 0); 93 + if (addr == 0) 94 + return -ENODEV; 95 + if (size != mem) { 96 + DRM_ERROR("Size mismatch: pci=%ld, bochs=%ld\n", 97 + size, mem); 98 + size = min(size, mem); 99 + } 100 + 101 + if (pci_request_region(pdev, 0, "bochs-drm") != 0) { 102 + DRM_ERROR("Cannot request framebuffer\n"); 103 + return -EBUSY; 104 + } 105 + 106 + bochs->fb_map = ioremap(addr, size); 107 + if (bochs->fb_map == NULL) { 108 + DRM_ERROR("Cannot map framebuffer\n"); 109 + return -ENOMEM; 110 + } 111 + bochs->fb_base = addr; 112 + bochs->fb_size = size; 113 + 114 + DRM_INFO("Found bochs VGA, ID 0x%x.\n", id); 115 + DRM_INFO("Framebuffer size %ld kB @ 0x%lx, %s @ 0x%lx.\n", 116 + size / 1024, addr, 117 + bochs->ioports ? "ioports" : "mmio", 118 + ioaddr); 119 + return 0; 120 + } 121 + 122 + void bochs_hw_fini(struct drm_device *dev) 123 + { 124 + struct bochs_device *bochs = dev->dev_private; 125 + 126 + if (bochs->mmio) 127 + iounmap(bochs->mmio); 128 + if (bochs->ioports) 129 + release_region(VBE_DISPI_IOPORT_INDEX, 2); 130 + if (bochs->fb_map) 131 + iounmap(bochs->fb_map); 132 + pci_release_regions(dev->pdev); 133 + } 134 + 135 + void bochs_hw_setmode(struct bochs_device *bochs, 136 + struct drm_display_mode *mode) 137 + { 138 + bochs->xres = mode->hdisplay; 139 + bochs->yres = mode->vdisplay; 140 + bochs->bpp = 32; 141 + bochs->stride = mode->hdisplay * (bochs->bpp / 8); 142 + bochs->yres_virtual = bochs->fb_size / bochs->stride; 143 + 144 + DRM_DEBUG_DRIVER("%dx%d @ %d bpp, vy %d\n", 145 + bochs->xres, bochs->yres, bochs->bpp, 146 + bochs->yres_virtual); 147 + 148 + bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */ 149 + 150 + bochs_dispi_write(bochs, VBE_DISPI_INDEX_BPP, bochs->bpp); 151 + bochs_dispi_write(bochs, VBE_DISPI_INDEX_XRES, bochs->xres); 152 + bochs_dispi_write(bochs, VBE_DISPI_INDEX_YRES, bochs->yres); 153 + bochs_dispi_write(bochs, VBE_DISPI_INDEX_BANK, 0); 154 + bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_WIDTH, bochs->xres); 155 + bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_HEIGHT, 156 + bochs->yres_virtual); 157 + bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, 0); 158 + bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, 0); 159 + 160 + bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE, 161 + VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED); 162 + } 163 + 164 + void bochs_hw_setbase(struct bochs_device *bochs, 165 + int x, int y, u64 addr) 166 + { 167 + unsigned long offset = (unsigned long)addr + 168 + y * bochs->stride + 169 + x * (bochs->bpp / 8); 170 + int vy = offset / bochs->stride; 171 + int vx = (offset % bochs->stride) * 8 / bochs->bpp; 172 + 173 + DRM_DEBUG_DRIVER("x %d, y %d, addr %llx -> offset %lx, vx %d, vy %d\n", 174 + x, y, addr, offset, vx, vy); 175 + bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, vx); 176 + bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, vy); 177 + }
+294
drivers/gpu/drm/bochs/bochs_kms.c
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify 3 + * it under the terms of the GNU General Public License as published by 4 + * the Free Software Foundation; either version 2 of the License, or 5 + * (at your option) any later version. 6 + */ 7 + 8 + #include "bochs.h" 9 + 10 + static int defx = 1024; 11 + static int defy = 768; 12 + 13 + module_param(defx, int, 0444); 14 + module_param(defy, int, 0444); 15 + MODULE_PARM_DESC(defx, "default x resolution"); 16 + MODULE_PARM_DESC(defy, "default y resolution"); 17 + 18 + /* ---------------------------------------------------------------------- */ 19 + 20 + static void bochs_crtc_load_lut(struct drm_crtc *crtc) 21 + { 22 + } 23 + 24 + static void bochs_crtc_dpms(struct drm_crtc *crtc, int mode) 25 + { 26 + switch (mode) { 27 + case DRM_MODE_DPMS_ON: 28 + case DRM_MODE_DPMS_STANDBY: 29 + case DRM_MODE_DPMS_SUSPEND: 30 + case DRM_MODE_DPMS_OFF: 31 + default: 32 + return; 33 + } 34 + } 35 + 36 + static bool bochs_crtc_mode_fixup(struct drm_crtc *crtc, 37 + const struct drm_display_mode *mode, 38 + struct drm_display_mode *adjusted_mode) 39 + { 40 + return true; 41 + } 42 + 43 + static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 44 + struct drm_framebuffer *old_fb) 45 + { 46 + struct bochs_device *bochs = 47 + container_of(crtc, struct bochs_device, crtc); 48 + struct bochs_framebuffer *bochs_fb; 49 + struct bochs_bo *bo; 50 + u64 gpu_addr = 0; 51 + int ret; 52 + 53 + if (old_fb) { 54 + bochs_fb = to_bochs_framebuffer(old_fb); 55 + bo = gem_to_bochs_bo(bochs_fb->obj); 56 + ret = ttm_bo_reserve(&bo->bo, true, false, false, 0); 57 + if (ret) { 58 + DRM_ERROR("failed to reserve old_fb bo\n"); 59 + } else { 60 + bochs_bo_unpin(bo); 61 + ttm_bo_unreserve(&bo->bo); 62 + } 63 + } 64 + 65 + if (WARN_ON(crtc->fb == NULL)) 66 + return -EINVAL; 67 + 68 + bochs_fb = to_bochs_framebuffer(crtc->fb); 69 + bo = gem_to_bochs_bo(bochs_fb->obj); 70 + ret = ttm_bo_reserve(&bo->bo, true, false, false, 0); 71 + if (ret) 72 + return ret; 73 + 74 + ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr); 75 + if (ret) { 76 + ttm_bo_unreserve(&bo->bo); 77 + return ret; 78 + } 79 + 80 + ttm_bo_unreserve(&bo->bo); 81 + bochs_hw_setbase(bochs, x, y, gpu_addr); 82 + return 0; 83 + } 84 + 85 + static int bochs_crtc_mode_set(struct drm_crtc *crtc, 86 + struct drm_display_mode *mode, 87 + struct drm_display_mode *adjusted_mode, 88 + int x, int y, struct drm_framebuffer *old_fb) 89 + { 90 + struct bochs_device *bochs = 91 + container_of(crtc, struct bochs_device, crtc); 92 + 93 + bochs_hw_setmode(bochs, mode); 94 + bochs_crtc_mode_set_base(crtc, x, y, old_fb); 95 + return 0; 96 + } 97 + 98 + static void bochs_crtc_prepare(struct drm_crtc *crtc) 99 + { 100 + } 101 + 102 + static void bochs_crtc_commit(struct drm_crtc *crtc) 103 + { 104 + } 105 + 106 + static void bochs_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, 107 + u16 *blue, uint32_t start, uint32_t size) 108 + { 109 + } 110 + 111 + /* These provide the minimum set of functions required to handle a CRTC */ 112 + static const struct drm_crtc_funcs bochs_crtc_funcs = { 113 + .gamma_set = bochs_crtc_gamma_set, 114 + .set_config = drm_crtc_helper_set_config, 115 + .destroy = drm_crtc_cleanup, 116 + }; 117 + 118 + static const struct drm_crtc_helper_funcs bochs_helper_funcs = { 119 + .dpms = bochs_crtc_dpms, 120 + .mode_fixup = bochs_crtc_mode_fixup, 121 + .mode_set = bochs_crtc_mode_set, 122 + .mode_set_base = bochs_crtc_mode_set_base, 123 + .prepare = bochs_crtc_prepare, 124 + .commit = bochs_crtc_commit, 125 + .load_lut = bochs_crtc_load_lut, 126 + }; 127 + 128 + static void bochs_crtc_init(struct drm_device *dev) 129 + { 130 + struct bochs_device *bochs = dev->dev_private; 131 + struct drm_crtc *crtc = &bochs->crtc; 132 + 133 + drm_crtc_init(dev, crtc, &bochs_crtc_funcs); 134 + drm_mode_crtc_set_gamma_size(crtc, 256); 135 + drm_crtc_helper_add(crtc, &bochs_helper_funcs); 136 + } 137 + 138 + static bool bochs_encoder_mode_fixup(struct drm_encoder *encoder, 139 + const struct drm_display_mode *mode, 140 + struct drm_display_mode *adjusted_mode) 141 + { 142 + return true; 143 + } 144 + 145 + static void bochs_encoder_mode_set(struct drm_encoder *encoder, 146 + struct drm_display_mode *mode, 147 + struct drm_display_mode *adjusted_mode) 148 + { 149 + } 150 + 151 + static void bochs_encoder_dpms(struct drm_encoder *encoder, int state) 152 + { 153 + } 154 + 155 + static void bochs_encoder_prepare(struct drm_encoder *encoder) 156 + { 157 + } 158 + 159 + static void bochs_encoder_commit(struct drm_encoder *encoder) 160 + { 161 + } 162 + 163 + static const struct drm_encoder_helper_funcs bochs_encoder_helper_funcs = { 164 + .dpms = bochs_encoder_dpms, 165 + .mode_fixup = bochs_encoder_mode_fixup, 166 + .mode_set = bochs_encoder_mode_set, 167 + .prepare = bochs_encoder_prepare, 168 + .commit = bochs_encoder_commit, 169 + }; 170 + 171 + static const struct drm_encoder_funcs bochs_encoder_encoder_funcs = { 172 + .destroy = drm_encoder_cleanup, 173 + }; 174 + 175 + static void bochs_encoder_init(struct drm_device *dev) 176 + { 177 + struct bochs_device *bochs = dev->dev_private; 178 + struct drm_encoder *encoder = &bochs->encoder; 179 + 180 + encoder->possible_crtcs = 0x1; 181 + drm_encoder_init(dev, encoder, &bochs_encoder_encoder_funcs, 182 + DRM_MODE_ENCODER_DAC); 183 + drm_encoder_helper_add(encoder, &bochs_encoder_helper_funcs); 184 + } 185 + 186 + 187 + int bochs_connector_get_modes(struct drm_connector *connector) 188 + { 189 + int count; 190 + 191 + count = drm_add_modes_noedid(connector, 8192, 8192); 192 + drm_set_preferred_mode(connector, defx, defy); 193 + return count; 194 + } 195 + 196 + static int bochs_connector_mode_valid(struct drm_connector *connector, 197 + struct drm_display_mode *mode) 198 + { 199 + struct bochs_device *bochs = 200 + container_of(connector, struct bochs_device, connector); 201 + unsigned long size = mode->hdisplay * mode->vdisplay * 4; 202 + 203 + /* 204 + * Make sure we can fit two framebuffers into video memory. 205 + * This allows up to 1600x1200 with 16 MB (default size). 206 + * If you want more try this: 207 + * 'qemu -vga std -global VGA.vgamem_mb=32 $otherargs' 208 + */ 209 + if (size * 2 > bochs->fb_size) 210 + return MODE_BAD; 211 + 212 + return MODE_OK; 213 + } 214 + 215 + static struct drm_encoder * 216 + bochs_connector_best_encoder(struct drm_connector *connector) 217 + { 218 + int enc_id = connector->encoder_ids[0]; 219 + struct drm_mode_object *obj; 220 + struct drm_encoder *encoder; 221 + 222 + /* pick the encoder ids */ 223 + if (enc_id) { 224 + obj = drm_mode_object_find(connector->dev, enc_id, 225 + DRM_MODE_OBJECT_ENCODER); 226 + if (!obj) 227 + return NULL; 228 + encoder = obj_to_encoder(obj); 229 + return encoder; 230 + } 231 + return NULL; 232 + } 233 + 234 + static enum drm_connector_status bochs_connector_detect(struct drm_connector 235 + *connector, bool force) 236 + { 237 + return connector_status_connected; 238 + } 239 + 240 + struct drm_connector_helper_funcs bochs_connector_connector_helper_funcs = { 241 + .get_modes = bochs_connector_get_modes, 242 + .mode_valid = bochs_connector_mode_valid, 243 + .best_encoder = bochs_connector_best_encoder, 244 + }; 245 + 246 + struct drm_connector_funcs bochs_connector_connector_funcs = { 247 + .dpms = drm_helper_connector_dpms, 248 + .detect = bochs_connector_detect, 249 + .fill_modes = drm_helper_probe_single_connector_modes, 250 + .destroy = drm_connector_cleanup, 251 + }; 252 + 253 + static void bochs_connector_init(struct drm_device *dev) 254 + { 255 + struct bochs_device *bochs = dev->dev_private; 256 + struct drm_connector *connector = &bochs->connector; 257 + 258 + drm_connector_init(dev, connector, &bochs_connector_connector_funcs, 259 + DRM_MODE_CONNECTOR_VIRTUAL); 260 + drm_connector_helper_add(connector, 261 + &bochs_connector_connector_helper_funcs); 262 + } 263 + 264 + 265 + int bochs_kms_init(struct bochs_device *bochs) 266 + { 267 + drm_mode_config_init(bochs->dev); 268 + bochs->mode_config_initialized = true; 269 + 270 + bochs->dev->mode_config.max_width = 8192; 271 + bochs->dev->mode_config.max_height = 8192; 272 + 273 + bochs->dev->mode_config.fb_base = bochs->fb_base; 274 + bochs->dev->mode_config.preferred_depth = 24; 275 + bochs->dev->mode_config.prefer_shadow = 0; 276 + 277 + bochs->dev->mode_config.funcs = (void *)&bochs_mode_funcs; 278 + 279 + bochs_crtc_init(bochs->dev); 280 + bochs_encoder_init(bochs->dev); 281 + bochs_connector_init(bochs->dev); 282 + drm_mode_connector_attach_encoder(&bochs->connector, 283 + &bochs->encoder); 284 + 285 + return 0; 286 + } 287 + 288 + void bochs_kms_fini(struct bochs_device *bochs) 289 + { 290 + if (bochs->mode_config_initialized) { 291 + drm_mode_config_cleanup(bochs->dev); 292 + bochs->mode_config_initialized = false; 293 + } 294 + }
+546
drivers/gpu/drm/bochs/bochs_mm.c
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify 3 + * it under the terms of the GNU General Public License as published by 4 + * the Free Software Foundation; either version 2 of the License, or 5 + * (at your option) any later version. 6 + */ 7 + 8 + #include "bochs.h" 9 + 10 + static void bochs_ttm_placement(struct bochs_bo *bo, int domain); 11 + 12 + /* ---------------------------------------------------------------------- */ 13 + 14 + static inline struct bochs_device *bochs_bdev(struct ttm_bo_device *bd) 15 + { 16 + return container_of(bd, struct bochs_device, ttm.bdev); 17 + } 18 + 19 + static int bochs_ttm_mem_global_init(struct drm_global_reference *ref) 20 + { 21 + return ttm_mem_global_init(ref->object); 22 + } 23 + 24 + static void bochs_ttm_mem_global_release(struct drm_global_reference *ref) 25 + { 26 + ttm_mem_global_release(ref->object); 27 + } 28 + 29 + static int bochs_ttm_global_init(struct bochs_device *bochs) 30 + { 31 + struct drm_global_reference *global_ref; 32 + int r; 33 + 34 + global_ref = &bochs->ttm.mem_global_ref; 35 + global_ref->global_type = DRM_GLOBAL_TTM_MEM; 36 + global_ref->size = sizeof(struct ttm_mem_global); 37 + global_ref->init = &bochs_ttm_mem_global_init; 38 + global_ref->release = &bochs_ttm_mem_global_release; 39 + r = drm_global_item_ref(global_ref); 40 + if (r != 0) { 41 + DRM_ERROR("Failed setting up TTM memory accounting " 42 + "subsystem.\n"); 43 + return r; 44 + } 45 + 46 + bochs->ttm.bo_global_ref.mem_glob = 47 + bochs->ttm.mem_global_ref.object; 48 + global_ref = &bochs->ttm.bo_global_ref.ref; 49 + global_ref->global_type = DRM_GLOBAL_TTM_BO; 50 + global_ref->size = sizeof(struct ttm_bo_global); 51 + global_ref->init = &ttm_bo_global_init; 52 + global_ref->release = &ttm_bo_global_release; 53 + r = drm_global_item_ref(global_ref); 54 + if (r != 0) { 55 + DRM_ERROR("Failed setting up TTM BO subsystem.\n"); 56 + drm_global_item_unref(&bochs->ttm.mem_global_ref); 57 + return r; 58 + } 59 + 60 + return 0; 61 + } 62 + 63 + static void bochs_ttm_global_release(struct bochs_device *bochs) 64 + { 65 + if (bochs->ttm.mem_global_ref.release == NULL) 66 + return; 67 + 68 + drm_global_item_unref(&bochs->ttm.bo_global_ref.ref); 69 + drm_global_item_unref(&bochs->ttm.mem_global_ref); 70 + bochs->ttm.mem_global_ref.release = NULL; 71 + } 72 + 73 + 74 + static void bochs_bo_ttm_destroy(struct ttm_buffer_object *tbo) 75 + { 76 + struct bochs_bo *bo; 77 + 78 + bo = container_of(tbo, struct bochs_bo, bo); 79 + drm_gem_object_release(&bo->gem); 80 + kfree(bo); 81 + } 82 + 83 + static bool bochs_ttm_bo_is_bochs_bo(struct ttm_buffer_object *bo) 84 + { 85 + if (bo->destroy == &bochs_bo_ttm_destroy) 86 + return true; 87 + return false; 88 + } 89 + 90 + static int bochs_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, 91 + struct ttm_mem_type_manager *man) 92 + { 93 + switch (type) { 94 + case TTM_PL_SYSTEM: 95 + man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; 96 + man->available_caching = TTM_PL_MASK_CACHING; 97 + man->default_caching = TTM_PL_FLAG_CACHED; 98 + break; 99 + case TTM_PL_VRAM: 100 + man->func = &ttm_bo_manager_func; 101 + man->flags = TTM_MEMTYPE_FLAG_FIXED | 102 + TTM_MEMTYPE_FLAG_MAPPABLE; 103 + man->available_caching = TTM_PL_FLAG_UNCACHED | 104 + TTM_PL_FLAG_WC; 105 + man->default_caching = TTM_PL_FLAG_WC; 106 + break; 107 + default: 108 + DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); 109 + return -EINVAL; 110 + } 111 + return 0; 112 + } 113 + 114 + static void 115 + bochs_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) 116 + { 117 + struct bochs_bo *bochsbo = bochs_bo(bo); 118 + 119 + if (!bochs_ttm_bo_is_bochs_bo(bo)) 120 + return; 121 + 122 + bochs_ttm_placement(bochsbo, TTM_PL_FLAG_SYSTEM); 123 + *pl = bochsbo->placement; 124 + } 125 + 126 + static int bochs_bo_verify_access(struct ttm_buffer_object *bo, 127 + struct file *filp) 128 + { 129 + struct bochs_bo *bochsbo = bochs_bo(bo); 130 + 131 + return drm_vma_node_verify_access(&bochsbo->gem.vma_node, filp); 132 + } 133 + 134 + static int bochs_ttm_io_mem_reserve(struct ttm_bo_device *bdev, 135 + struct ttm_mem_reg *mem) 136 + { 137 + struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; 138 + struct bochs_device *bochs = bochs_bdev(bdev); 139 + 140 + mem->bus.addr = NULL; 141 + mem->bus.offset = 0; 142 + mem->bus.size = mem->num_pages << PAGE_SHIFT; 143 + mem->bus.base = 0; 144 + mem->bus.is_iomem = false; 145 + if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) 146 + return -EINVAL; 147 + switch (mem->mem_type) { 148 + case TTM_PL_SYSTEM: 149 + /* system memory */ 150 + return 0; 151 + case TTM_PL_VRAM: 152 + mem->bus.offset = mem->start << PAGE_SHIFT; 153 + mem->bus.base = bochs->fb_base; 154 + mem->bus.is_iomem = true; 155 + break; 156 + default: 157 + return -EINVAL; 158 + break; 159 + } 160 + return 0; 161 + } 162 + 163 + static void bochs_ttm_io_mem_free(struct ttm_bo_device *bdev, 164 + struct ttm_mem_reg *mem) 165 + { 166 + } 167 + 168 + static int bochs_bo_move(struct ttm_buffer_object *bo, 169 + bool evict, bool interruptible, 170 + bool no_wait_gpu, 171 + struct ttm_mem_reg *new_mem) 172 + { 173 + return ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem); 174 + } 175 + 176 + 177 + static void bochs_ttm_backend_destroy(struct ttm_tt *tt) 178 + { 179 + ttm_tt_fini(tt); 180 + kfree(tt); 181 + } 182 + 183 + static struct ttm_backend_func bochs_tt_backend_func = { 184 + .destroy = &bochs_ttm_backend_destroy, 185 + }; 186 + 187 + static struct ttm_tt *bochs_ttm_tt_create(struct ttm_bo_device *bdev, 188 + unsigned long size, 189 + uint32_t page_flags, 190 + struct page *dummy_read_page) 191 + { 192 + struct ttm_tt *tt; 193 + 194 + tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL); 195 + if (tt == NULL) 196 + return NULL; 197 + tt->func = &bochs_tt_backend_func; 198 + if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) { 199 + kfree(tt); 200 + return NULL; 201 + } 202 + return tt; 203 + } 204 + 205 + struct ttm_bo_driver bochs_bo_driver = { 206 + .ttm_tt_create = bochs_ttm_tt_create, 207 + .ttm_tt_populate = ttm_pool_populate, 208 + .ttm_tt_unpopulate = ttm_pool_unpopulate, 209 + .init_mem_type = bochs_bo_init_mem_type, 210 + .evict_flags = bochs_bo_evict_flags, 211 + .move = bochs_bo_move, 212 + .verify_access = bochs_bo_verify_access, 213 + .io_mem_reserve = &bochs_ttm_io_mem_reserve, 214 + .io_mem_free = &bochs_ttm_io_mem_free, 215 + }; 216 + 217 + int bochs_mm_init(struct bochs_device *bochs) 218 + { 219 + struct ttm_bo_device *bdev = &bochs->ttm.bdev; 220 + int ret; 221 + 222 + ret = bochs_ttm_global_init(bochs); 223 + if (ret) 224 + return ret; 225 + 226 + ret = ttm_bo_device_init(&bochs->ttm.bdev, 227 + bochs->ttm.bo_global_ref.ref.object, 228 + &bochs_bo_driver, DRM_FILE_PAGE_OFFSET, 229 + true); 230 + if (ret) { 231 + DRM_ERROR("Error initialising bo driver; %d\n", ret); 232 + return ret; 233 + } 234 + 235 + ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM, 236 + bochs->fb_size >> PAGE_SHIFT); 237 + if (ret) { 238 + DRM_ERROR("Failed ttm VRAM init: %d\n", ret); 239 + return ret; 240 + } 241 + 242 + bochs->ttm.initialized = true; 243 + return 0; 244 + } 245 + 246 + void bochs_mm_fini(struct bochs_device *bochs) 247 + { 248 + if (!bochs->ttm.initialized) 249 + return; 250 + 251 + ttm_bo_device_release(&bochs->ttm.bdev); 252 + bochs_ttm_global_release(bochs); 253 + bochs->ttm.initialized = false; 254 + } 255 + 256 + static void bochs_ttm_placement(struct bochs_bo *bo, int domain) 257 + { 258 + u32 c = 0; 259 + bo->placement.fpfn = 0; 260 + bo->placement.lpfn = 0; 261 + bo->placement.placement = bo->placements; 262 + bo->placement.busy_placement = bo->placements; 263 + if (domain & TTM_PL_FLAG_VRAM) { 264 + bo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED 265 + | TTM_PL_FLAG_VRAM; 266 + } 267 + if (domain & TTM_PL_FLAG_SYSTEM) { 268 + bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; 269 + } 270 + if (!c) { 271 + bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; 272 + } 273 + bo->placement.num_placement = c; 274 + bo->placement.num_busy_placement = c; 275 + } 276 + 277 + static inline u64 bochs_bo_gpu_offset(struct bochs_bo *bo) 278 + { 279 + return bo->bo.offset; 280 + } 281 + 282 + int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr) 283 + { 284 + int i, ret; 285 + 286 + if (bo->pin_count) { 287 + bo->pin_count++; 288 + if (gpu_addr) 289 + *gpu_addr = bochs_bo_gpu_offset(bo); 290 + return 0; 291 + } 292 + 293 + bochs_ttm_placement(bo, pl_flag); 294 + for (i = 0; i < bo->placement.num_placement; i++) 295 + bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; 296 + ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false); 297 + if (ret) 298 + return ret; 299 + 300 + bo->pin_count = 1; 301 + if (gpu_addr) 302 + *gpu_addr = bochs_bo_gpu_offset(bo); 303 + return 0; 304 + } 305 + 306 + int bochs_bo_unpin(struct bochs_bo *bo) 307 + { 308 + int i, ret; 309 + 310 + if (!bo->pin_count) { 311 + DRM_ERROR("unpin bad %p\n", bo); 312 + return 0; 313 + } 314 + bo->pin_count--; 315 + 316 + if (bo->pin_count) 317 + return 0; 318 + 319 + for (i = 0; i < bo->placement.num_placement; i++) 320 + bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT; 321 + ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false); 322 + if (ret) 323 + return ret; 324 + 325 + return 0; 326 + } 327 + 328 + int bochs_mmap(struct file *filp, struct vm_area_struct *vma) 329 + { 330 + struct drm_file *file_priv; 331 + struct bochs_device *bochs; 332 + 333 + if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) 334 + return drm_mmap(filp, vma); 335 + 336 + file_priv = filp->private_data; 337 + bochs = file_priv->minor->dev->dev_private; 338 + return ttm_bo_mmap(filp, vma, &bochs->ttm.bdev); 339 + } 340 + 341 + /* ---------------------------------------------------------------------- */ 342 + 343 + static int bochs_bo_create(struct drm_device *dev, int size, int align, 344 + uint32_t flags, struct bochs_bo **pbochsbo) 345 + { 346 + struct bochs_device *bochs = dev->dev_private; 347 + struct bochs_bo *bochsbo; 348 + size_t acc_size; 349 + int ret; 350 + 351 + bochsbo = kzalloc(sizeof(struct bochs_bo), GFP_KERNEL); 352 + if (!bochsbo) 353 + return -ENOMEM; 354 + 355 + ret = drm_gem_object_init(dev, &bochsbo->gem, size); 356 + if (ret) { 357 + kfree(bochsbo); 358 + return ret; 359 + } 360 + 361 + bochsbo->bo.bdev = &bochs->ttm.bdev; 362 + bochsbo->bo.bdev->dev_mapping = dev->dev_mapping; 363 + 364 + bochs_ttm_placement(bochsbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); 365 + 366 + acc_size = ttm_bo_dma_acc_size(&bochs->ttm.bdev, size, 367 + sizeof(struct bochs_bo)); 368 + 369 + ret = ttm_bo_init(&bochs->ttm.bdev, &bochsbo->bo, size, 370 + ttm_bo_type_device, &bochsbo->placement, 371 + align >> PAGE_SHIFT, false, NULL, acc_size, 372 + NULL, bochs_bo_ttm_destroy); 373 + if (ret) 374 + return ret; 375 + 376 + *pbochsbo = bochsbo; 377 + return 0; 378 + } 379 + 380 + int bochs_gem_create(struct drm_device *dev, u32 size, bool iskernel, 381 + struct drm_gem_object **obj) 382 + { 383 + struct bochs_bo *bochsbo; 384 + int ret; 385 + 386 + *obj = NULL; 387 + 388 + size = ALIGN(size, PAGE_SIZE); 389 + if (size == 0) 390 + return -EINVAL; 391 + 392 + ret = bochs_bo_create(dev, size, 0, 0, &bochsbo); 393 + if (ret) { 394 + if (ret != -ERESTARTSYS) 395 + DRM_ERROR("failed to allocate GEM object\n"); 396 + return ret; 397 + } 398 + *obj = &bochsbo->gem; 399 + return 0; 400 + } 401 + 402 + int bochs_dumb_create(struct drm_file *file, struct drm_device *dev, 403 + struct drm_mode_create_dumb *args) 404 + { 405 + struct drm_gem_object *gobj; 406 + u32 handle; 407 + int ret; 408 + 409 + args->pitch = args->width * ((args->bpp + 7) / 8); 410 + args->size = args->pitch * args->height; 411 + 412 + ret = bochs_gem_create(dev, args->size, false, 413 + &gobj); 414 + if (ret) 415 + return ret; 416 + 417 + ret = drm_gem_handle_create(file, gobj, &handle); 418 + drm_gem_object_unreference_unlocked(gobj); 419 + if (ret) 420 + return ret; 421 + 422 + args->handle = handle; 423 + return 0; 424 + } 425 + 426 + static void bochs_bo_unref(struct bochs_bo **bo) 427 + { 428 + struct ttm_buffer_object *tbo; 429 + 430 + if ((*bo) == NULL) 431 + return; 432 + 433 + tbo = &((*bo)->bo); 434 + ttm_bo_unref(&tbo); 435 + if (tbo == NULL) 436 + *bo = NULL; 437 + 438 + } 439 + 440 + void bochs_gem_free_object(struct drm_gem_object *obj) 441 + { 442 + struct bochs_bo *bochs_bo = gem_to_bochs_bo(obj); 443 + 444 + if (!bochs_bo) 445 + return; 446 + bochs_bo_unref(&bochs_bo); 447 + } 448 + 449 + int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, 450 + uint32_t handle, uint64_t *offset) 451 + { 452 + struct drm_gem_object *obj; 453 + int ret; 454 + struct bochs_bo *bo; 455 + 456 + mutex_lock(&dev->struct_mutex); 457 + obj = drm_gem_object_lookup(dev, file, handle); 458 + if (obj == NULL) { 459 + ret = -ENOENT; 460 + goto out_unlock; 461 + } 462 + 463 + bo = gem_to_bochs_bo(obj); 464 + *offset = bochs_bo_mmap_offset(bo); 465 + 466 + drm_gem_object_unreference(obj); 467 + ret = 0; 468 + out_unlock: 469 + mutex_unlock(&dev->struct_mutex); 470 + return ret; 471 + 472 + } 473 + 474 + /* ---------------------------------------------------------------------- */ 475 + 476 + static void bochs_user_framebuffer_destroy(struct drm_framebuffer *fb) 477 + { 478 + struct bochs_framebuffer *bochs_fb = to_bochs_framebuffer(fb); 479 + if (bochs_fb->obj) 480 + drm_gem_object_unreference_unlocked(bochs_fb->obj); 481 + drm_framebuffer_cleanup(fb); 482 + kfree(fb); 483 + } 484 + 485 + static const struct drm_framebuffer_funcs bochs_fb_funcs = { 486 + .destroy = bochs_user_framebuffer_destroy, 487 + }; 488 + 489 + int bochs_framebuffer_init(struct drm_device *dev, 490 + struct bochs_framebuffer *gfb, 491 + struct drm_mode_fb_cmd2 *mode_cmd, 492 + struct drm_gem_object *obj) 493 + { 494 + int ret; 495 + 496 + drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd); 497 + gfb->obj = obj; 498 + ret = drm_framebuffer_init(dev, &gfb->base, &bochs_fb_funcs); 499 + if (ret) { 500 + DRM_ERROR("drm_framebuffer_init failed: %d\n", ret); 501 + return ret; 502 + } 503 + return 0; 504 + } 505 + 506 + static struct drm_framebuffer * 507 + bochs_user_framebuffer_create(struct drm_device *dev, 508 + struct drm_file *filp, 509 + struct drm_mode_fb_cmd2 *mode_cmd) 510 + { 511 + struct drm_gem_object *obj; 512 + struct bochs_framebuffer *bochs_fb; 513 + int ret; 514 + 515 + DRM_DEBUG_DRIVER("%dx%d, format %c%c%c%c\n", 516 + mode_cmd->width, mode_cmd->height, 517 + (mode_cmd->pixel_format) & 0xff, 518 + (mode_cmd->pixel_format >> 8) & 0xff, 519 + (mode_cmd->pixel_format >> 16) & 0xff, 520 + (mode_cmd->pixel_format >> 24) & 0xff); 521 + 522 + if (mode_cmd->pixel_format != DRM_FORMAT_XRGB8888) 523 + return ERR_PTR(-ENOENT); 524 + 525 + obj = drm_gem_object_lookup(dev, filp, mode_cmd->handles[0]); 526 + if (obj == NULL) 527 + return ERR_PTR(-ENOENT); 528 + 529 + bochs_fb = kzalloc(sizeof(*bochs_fb), GFP_KERNEL); 530 + if (!bochs_fb) { 531 + drm_gem_object_unreference_unlocked(obj); 532 + return ERR_PTR(-ENOMEM); 533 + } 534 + 535 + ret = bochs_framebuffer_init(dev, bochs_fb, mode_cmd, obj); 536 + if (ret) { 537 + drm_gem_object_unreference_unlocked(obj); 538 + kfree(bochs_fb); 539 + return ERR_PTR(ret); 540 + } 541 + return &bochs_fb->base; 542 + } 543 + 544 + const struct drm_mode_config_funcs bochs_mode_funcs = { 545 + .fb_create = bochs_user_framebuffer_create, 546 + };