diff options
Diffstat (limited to 'drivers/gpu/drm/virtio/virtgpu_drv.c')
-rw-r--r-- | drivers/gpu/drm/virtio/virtgpu_drv.c | 79 |
1 files changed, 75 insertions, 4 deletions
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index 7df50920c1e0..af92964b6889 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c | |||
@@ -40,8 +40,60 @@ static int virtio_gpu_modeset = -1; | |||
40 | MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); | 40 | MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); |
41 | module_param_named(modeset, virtio_gpu_modeset, int, 0400); | 41 | module_param_named(modeset, virtio_gpu_modeset, int, 0400); |
42 | 42 | ||
43 | static int virtio_gpu_pci_quirk(struct drm_device *dev, struct virtio_device *vdev) | ||
44 | { | ||
45 | struct pci_dev *pdev = to_pci_dev(vdev->dev.parent); | ||
46 | const char *pname = dev_name(&pdev->dev); | ||
47 | bool vga = (pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA; | ||
48 | char unique[20]; | ||
49 | |||
50 | DRM_INFO("pci: %s detected at %s\n", | ||
51 | vga ? "virtio-vga" : "virtio-gpu-pci", | ||
52 | pname); | ||
53 | dev->pdev = pdev; | ||
54 | if (vga) | ||
55 | drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, | ||
56 | 0, | ||
57 | "virtiodrmfb"); | ||
58 | |||
59 | /* | ||
60 | * Normally the drm_dev_set_unique() call is done by core DRM. | ||
61 | * The following comment covers, why virtio cannot rely on it. | ||
62 | * | ||
63 | * Unlike the other virtual GPU drivers, virtio abstracts the | ||
64 | * underlying bus type by using struct virtio_device. | ||
65 | * | ||
66 | * Hence the dev_is_pci() check, used in core DRM, will fail | ||
67 | * and the unique returned will be the virtio_device "virtio0", | ||
68 | * while a "pci:..." one is required. | ||
69 | * | ||
70 | * A few other ideas were considered: | ||
71 | * - Extend the dev_is_pci() check [in drm_set_busid] to | ||
72 | * consider virtio. | ||
73 | * Seems like a bigger hack than what we have already. | ||
74 | * | ||
75 | * - Point drm_device::dev to the parent of the virtio_device | ||
76 | * Semantic changes: | ||
77 | * * Using the wrong device for i2c, framebuffer_alloc and | ||
78 | * prime import. | ||
79 | * Visual changes: | ||
80 | * * Helpers such as DRM_DEV_ERROR, dev_info, drm_printer, | ||
81 | * will print the wrong information. | ||
82 | * | ||
83 | * We could address the latter issues, by introducing | ||
84 | * drm_device::bus_dev, ... which would be used solely for this. | ||
85 | * | ||
86 | * So for the moment keep things as-is, with a bulky comment | ||
87 | * for the next person who feels like removing this | ||
88 | * drm_dev_set_unique() quirk. | ||
89 | */ | ||
90 | snprintf(unique, sizeof(unique), "pci:%s", pname); | ||
91 | return drm_dev_set_unique(dev, unique); | ||
92 | } | ||
93 | |||
43 | static int virtio_gpu_probe(struct virtio_device *vdev) | 94 | static int virtio_gpu_probe(struct virtio_device *vdev) |
44 | { | 95 | { |
96 | struct drm_device *dev; | ||
45 | int ret; | 97 | int ret; |
46 | 98 | ||
47 | if (vgacon_text_force() && virtio_gpu_modeset == -1) | 99 | if (vgacon_text_force() && virtio_gpu_modeset == -1) |
@@ -50,18 +102,39 @@ static int virtio_gpu_probe(struct virtio_device *vdev) | |||
50 | if (virtio_gpu_modeset == 0) | 102 | if (virtio_gpu_modeset == 0) |
51 | return -EINVAL; | 103 | return -EINVAL; |
52 | 104 | ||
53 | ret = drm_virtio_init(&driver, vdev); | 105 | dev = drm_dev_alloc(&driver, &vdev->dev); |
106 | if (IS_ERR(dev)) | ||
107 | return PTR_ERR(dev); | ||
108 | vdev->priv = dev; | ||
109 | |||
110 | if (!strcmp(vdev->dev.parent->bus->name, "pci")) { | ||
111 | ret = virtio_gpu_pci_quirk(dev, vdev); | ||
112 | if (ret) | ||
113 | goto err_free; | ||
114 | } | ||
115 | |||
116 | ret = virtio_gpu_init(dev); | ||
54 | if (ret) | 117 | if (ret) |
55 | return ret; | 118 | goto err_free; |
119 | |||
120 | ret = drm_dev_register(dev, 0); | ||
121 | if (ret) | ||
122 | goto err_free; | ||
56 | 123 | ||
57 | drm_fbdev_generic_setup(vdev->priv, 32); | 124 | drm_fbdev_generic_setup(vdev->priv, 32); |
58 | return 0; | 125 | return 0; |
126 | |||
127 | err_free: | ||
128 | drm_dev_put(dev); | ||
129 | return ret; | ||
59 | } | 130 | } |
60 | 131 | ||
61 | static void virtio_gpu_remove(struct virtio_device *vdev) | 132 | static void virtio_gpu_remove(struct virtio_device *vdev) |
62 | { | 133 | { |
63 | struct drm_device *dev = vdev->priv; | 134 | struct drm_device *dev = vdev->priv; |
64 | 135 | ||
136 | drm_dev_unregister(dev); | ||
137 | virtio_gpu_deinit(dev); | ||
65 | drm_put_dev(dev); | 138 | drm_put_dev(dev); |
66 | } | 139 | } |
67 | 140 | ||
@@ -123,8 +196,6 @@ static const struct file_operations virtio_gpu_driver_fops = { | |||
123 | 196 | ||
124 | static struct drm_driver driver = { | 197 | static struct drm_driver driver = { |
125 | .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER | DRIVER_ATOMIC, | 198 | .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER | DRIVER_ATOMIC, |
126 | .load = virtio_gpu_driver_load, | ||
127 | .unload = virtio_gpu_driver_unload, | ||
128 | .open = virtio_gpu_driver_open, | 199 | .open = virtio_gpu_driver_open, |
129 | .postclose = virtio_gpu_driver_postclose, | 200 | .postclose = virtio_gpu_driver_postclose, |
130 | 201 | ||