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

drm/vc4: Disable V3D interactions if the v3d component didn't probe.

One might want to use the VC4 display stack without using Mesa.
Similar to the debugfs fixes for not having all of the possible
display bits enabled, make sure you can't oops in vc4 if v3d isn't
enabled.

v2: Fix matching against other v3d variants (review by Paul), don't
forget to set irq_enabled so that the vblank uapi works
v3: Use -ENODEV instead of -EINVAL on Paul's suggestion.

Signed-off-by: Eric Anholt <eric@anholt.net>
Link: https://patchwork.freedesktop.org/patch/msgid/20190401183559.3823-2-eric@anholt.net
Reviewed-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

+50 -1
+10
drivers/gpu/drm/vc4/vc4_drv.c
··· 72 72 if (args->pad != 0) 73 73 return -EINVAL; 74 74 75 + if (!vc4->v3d) 76 + return -ENODEV; 77 + 75 78 switch (args->param) { 76 79 case DRM_VC4_PARAM_V3D_IDENT0: 77 80 ret = vc4_v3d_pm_get(vc4); ··· 251 248 struct platform_device *pdev = to_platform_device(dev); 252 249 struct drm_device *drm; 253 250 struct vc4_dev *vc4; 251 + struct device_node *node; 254 252 int ret = 0; 255 253 256 254 dev->coherent_dma_mask = DMA_BIT_MASK(32); ··· 259 255 vc4 = devm_kzalloc(dev, sizeof(*vc4), GFP_KERNEL); 260 256 if (!vc4) 261 257 return -ENOMEM; 258 + 259 + /* If VC4 V3D is missing, don't advertise render nodes. */ 260 + node = of_find_matching_node_and_match(NULL, vc4_v3d_dt_match, NULL); 261 + if (!node || !of_device_is_available(node)) 262 + vc4_drm_driver.driver_features &= ~DRIVER_RENDER; 263 + of_node_put(node); 262 264 263 265 drm = drm_dev_alloc(&vc4_drm_driver, dev); 264 266 if (IS_ERR(drm))
+1
drivers/gpu/drm/vc4/vc4_drv.h
··· 831 831 832 832 /* vc4_v3d.c */ 833 833 extern struct platform_driver vc4_v3d_driver; 834 + extern const struct of_device_id vc4_v3d_dt_match[]; 834 835 int vc4_v3d_get_bin_slot(struct vc4_dev *vc4); 835 836 int vc4_v3d_pm_get(struct vc4_dev *vc4); 836 837 void vc4_v3d_pm_put(struct vc4_dev *vc4);
+10
drivers/gpu/drm/vc4/vc4_gem.c
··· 74 74 u32 i; 75 75 int ret = 0; 76 76 77 + if (!vc4->v3d) { 78 + DRM_DEBUG("VC4_GET_HANG_STATE with no VC4 V3D probed\n"); 79 + return -ENODEV; 80 + } 81 + 77 82 spin_lock_irqsave(&vc4->job_lock, irqflags); 78 83 kernel_state = vc4->hang_state; 79 84 if (!kernel_state) { ··· 1123 1118 struct ww_acquire_ctx acquire_ctx; 1124 1119 struct dma_fence *in_fence; 1125 1120 int ret = 0; 1121 + 1122 + if (!vc4->v3d) { 1123 + DRM_DEBUG("VC4_SUBMIT_CL with no VC4 V3D probed\n"); 1124 + return -ENODEV; 1125 + } 1126 1126 1127 1127 if ((args->flags & ~(VC4_SUBMIT_CL_USE_CLEAR_COLOR | 1128 1128 VC4_SUBMIT_CL_FIXED_RCL_ORDER |
+9
drivers/gpu/drm/vc4/vc4_irq.c
··· 229 229 { 230 230 struct vc4_dev *vc4 = to_vc4_dev(dev); 231 231 232 + if (!vc4->v3d) 233 + return; 234 + 232 235 init_waitqueue_head(&vc4->job_wait_queue); 233 236 INIT_WORK(&vc4->overflow_mem_work, vc4_overflow_mem_work); 234 237 ··· 246 243 { 247 244 struct vc4_dev *vc4 = to_vc4_dev(dev); 248 245 246 + if (!vc4->v3d) 247 + return 0; 248 + 249 249 /* Enable both the render done and out of memory interrupts. */ 250 250 V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS); 251 251 ··· 259 253 vc4_irq_uninstall(struct drm_device *dev) 260 254 { 261 255 struct vc4_dev *vc4 = to_vc4_dev(dev); 256 + 257 + if (!vc4->v3d) 258 + return; 262 259 263 260 /* Disable sending interrupts for our driver's IRQs. */ 264 261 V3D_WRITE(V3D_INTDIS, V3D_DRIVER_IRQS);
+1
drivers/gpu/drm/vc4/vc4_kms.c
··· 525 525 /* Set support for vblank irq fast disable, before drm_vblank_init() */ 526 526 dev->vblank_disable_immediate = true; 527 527 528 + dev->irq_enabled = true; 528 529 ret = drm_vblank_init(dev, dev->mode_config.num_crtc); 529 530 if (ret < 0) { 530 531 dev_err(dev->dev, "failed to initialize vblank\n");
+18
drivers/gpu/drm/vc4/vc4_perfmon.c
··· 100 100 int vc4_perfmon_create_ioctl(struct drm_device *dev, void *data, 101 101 struct drm_file *file_priv) 102 102 { 103 + struct vc4_dev *vc4 = to_vc4_dev(dev); 103 104 struct vc4_file *vc4file = file_priv->driver_priv; 104 105 struct drm_vc4_perfmon_create *req = data; 105 106 struct vc4_perfmon *perfmon; 106 107 unsigned int i; 107 108 int ret; 109 + 110 + if (!vc4->v3d) { 111 + DRM_DEBUG("Creating perfmon no VC4 V3D probed\n"); 112 + return -ENODEV; 113 + } 108 114 109 115 /* Number of monitored counters cannot exceed HW limits. */ 110 116 if (req->ncounters > DRM_VC4_MAX_PERF_COUNTERS || ··· 152 146 int vc4_perfmon_destroy_ioctl(struct drm_device *dev, void *data, 153 147 struct drm_file *file_priv) 154 148 { 149 + struct vc4_dev *vc4 = to_vc4_dev(dev); 155 150 struct vc4_file *vc4file = file_priv->driver_priv; 156 151 struct drm_vc4_perfmon_destroy *req = data; 157 152 struct vc4_perfmon *perfmon; 153 + 154 + if (!vc4->v3d) { 155 + DRM_DEBUG("Destroying perfmon no VC4 V3D probed\n"); 156 + return -ENODEV; 157 + } 158 158 159 159 mutex_lock(&vc4file->perfmon.lock); 160 160 perfmon = idr_remove(&vc4file->perfmon.idr, req->id); ··· 176 164 int vc4_perfmon_get_values_ioctl(struct drm_device *dev, void *data, 177 165 struct drm_file *file_priv) 178 166 { 167 + struct vc4_dev *vc4 = to_vc4_dev(dev); 179 168 struct vc4_file *vc4file = file_priv->driver_priv; 180 169 struct drm_vc4_perfmon_get_values *req = data; 181 170 struct vc4_perfmon *perfmon; 182 171 int ret; 172 + 173 + if (!vc4->v3d) { 174 + DRM_DEBUG("Getting perfmon no VC4 V3D probed\n"); 175 + return -ENODEV; 176 + } 183 177 184 178 mutex_lock(&vc4file->perfmon.lock); 185 179 perfmon = idr_find(&vc4file->perfmon.idr, req->id);
+1 -1
drivers/gpu/drm/vc4/vc4_v3d.c
··· 474 474 return 0; 475 475 } 476 476 477 - static const struct of_device_id vc4_v3d_dt_match[] = { 477 + const struct of_device_id vc4_v3d_dt_match[] = { 478 478 { .compatible = "brcm,bcm2835-v3d" }, 479 479 { .compatible = "brcm,cygnus-v3d" }, 480 480 { .compatible = "brcm,vc4-v3d" },