Skip to content

Commit ec7f496

Browse files
committed
Merge tag 'drm-fixes-2022-05-14' of git://anongit.freedesktop.org/drm/drm
Pull more drm fixes from Dave Airlie: "Turns out I was right, some fixes hadn't made it to me yet. The vmwgfx ones also popped up later, but all seem like bad enough things to fix. The dma-buf, vc4 and nouveau ones are all pretty small. The fbdev fixes are a bit more complicated: a fix to cleanup fbdev devices properly, uncovered some use-after-free bugs in existing drivers. Then the fix for those bugs wasn't correct. This reverts that fix, and puts the proper fixes in place in the drivers to avoid the use-after-frees. This has had a fair number of eyes on it at this stage, and I'm confident enough that it puts things in the right place, and is less dangerous than reverting our way out of the initial change at this stage. fbdev: - revert NULL deref fix that turned into a use-after-free - prevent use-after-free in fbdev - efifb/simplefb/vesafb: fix cleanup paths to avoid use-after-frees dma-buf: - fix panic in stats setup vc4: - fix hdmi build nouveau: - tegra iommu present fix - fix leak in backlight name vmwgfx: - Black screen due to fences using FIFO checks on SVGA3 - Random black screens on boot due to uninitialized drm_mode_fb_cmd2 - Hangs on SVGA3 due to command buffers being used with gbobjects" * tag 'drm-fixes-2022-05-14' of git://anongit.freedesktop.org/drm/drm: drm/vmwgfx: Disable command buffers on svga3 without gbobjects drm/vmwgfx: Initialize drm_mode_fb_cmd2 drm/vmwgfx: Fix fencing on SVGAv3 drm/vc4: hdmi: Fix build error for implicit function declaration dma-buf: call dma_buf_stats_setup after dmabuf is in valid list fbdev: efifb: Fix a use-after-free due early fb_info cleanup drm/nouveau: Fix a potential theorical leak in nouveau_get_backlight_name() drm/nouveau/tegra: Stop using iommu_present() fbdev: vesafb: Cleanup fb_info in .fb_destroy rather than .remove fbdev: efifb: Cleanup fb_info in .fb_destroy rather than .remove fbdev: simplefb: Cleanup fb_info in .fb_destroy rather than .remove fbdev: Prevent possible use-after-free in fb_release() Revert "fbdev: Make fb_release() return -ENODEV if fbdev was unregistered"
2 parents d928e8f + eb7bac3 commit ec7f496

File tree

15 files changed

+99
-40
lines changed

15 files changed

+99
-40
lines changed

drivers/dma-buf/dma-buf.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -543,17 +543,17 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
543543
file->f_mode |= FMODE_LSEEK;
544544
dmabuf->file = file;
545545

546-
ret = dma_buf_stats_setup(dmabuf);
547-
if (ret)
548-
goto err_sysfs;
549-
550546
mutex_init(&dmabuf->lock);
551547
INIT_LIST_HEAD(&dmabuf->attachments);
552548

553549
mutex_lock(&db_list.lock);
554550
list_add(&dmabuf->list_node, &db_list.head);
555551
mutex_unlock(&db_list.lock);
556552

553+
ret = dma_buf_stats_setup(dmabuf);
554+
if (ret)
555+
goto err_sysfs;
556+
557557
return dmabuf;
558558

559559
err_sysfs:

drivers/gpu/drm/nouveau/nouveau_backlight.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,9 @@ static bool
4646
nouveau_get_backlight_name(char backlight_name[BL_NAME_SIZE],
4747
struct nouveau_backlight *bl)
4848
{
49-
const int nb = ida_simple_get(&bl_ida, 0, 0, GFP_KERNEL);
50-
if (nb < 0 || nb >= 100)
49+
const int nb = ida_alloc_max(&bl_ida, 99, GFP_KERNEL);
50+
51+
if (nb < 0)
5152
return false;
5253
if (nb > 0)
5354
snprintf(backlight_name, BL_NAME_SIZE, "nv_backlight%d", nb);
@@ -414,7 +415,7 @@ nouveau_backlight_init(struct drm_connector *connector)
414415
nv_encoder, ops, &props);
415416
if (IS_ERR(bl->dev)) {
416417
if (bl->id >= 0)
417-
ida_simple_remove(&bl_ida, bl->id);
418+
ida_free(&bl_ida, bl->id);
418419
ret = PTR_ERR(bl->dev);
419420
goto fail_alloc;
420421
}
@@ -442,7 +443,7 @@ nouveau_backlight_fini(struct drm_connector *connector)
442443
return;
443444

444445
if (bl->id >= 0)
445-
ida_simple_remove(&bl_ida, bl->id);
446+
ida_free(&bl_ida, bl->id);
446447

447448
backlight_device_unregister(bl->dev);
448449
nv_conn->backlight = NULL;

drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ nvkm_device_tegra_probe_iommu(struct nvkm_device_tegra *tdev)
123123

124124
mutex_init(&tdev->iommu.mutex);
125125

126-
if (iommu_present(&platform_bus_type)) {
126+
if (device_iommu_mapped(dev)) {
127127
tdev->iommu.domain = iommu_domain_alloc(&platform_bus_type);
128128
if (!tdev->iommu.domain)
129129
goto error;

drivers/gpu/drm/vc4/vc4_hdmi.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <drm/drm_scdc_helper.h>
3939
#include <linux/clk.h>
4040
#include <linux/component.h>
41+
#include <linux/gpio/consumer.h>
4142
#include <linux/i2c.h>
4243
#include <linux/of_address.h>
4344
#include <linux/of_gpio.h>

drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ int vmw_cmd_send_fence(struct vmw_private *dev_priv, uint32_t *seqno)
528528
*seqno = atomic_add_return(1, &dev_priv->marker_seq);
529529
} while (*seqno == 0);
530530

531-
if (!(vmw_fifo_caps(dev_priv) & SVGA_FIFO_CAP_FENCE)) {
531+
if (!vmw_has_fences(dev_priv)) {
532532

533533
/*
534534
* Don't request hardware to send a fence. The
@@ -675,11 +675,14 @@ int vmw_cmd_emit_dummy_query(struct vmw_private *dev_priv,
675675
*/
676676
bool vmw_cmd_supported(struct vmw_private *vmw)
677677
{
678-
if ((vmw->capabilities & (SVGA_CAP_COMMAND_BUFFERS |
679-
SVGA_CAP_CMD_BUFFERS_2)) != 0)
680-
return true;
678+
bool has_cmdbufs =
679+
(vmw->capabilities & (SVGA_CAP_COMMAND_BUFFERS |
680+
SVGA_CAP_CMD_BUFFERS_2)) != 0;
681+
if (vmw_is_svga_v3(vmw))
682+
return (has_cmdbufs &&
683+
(vmw->capabilities & SVGA_CAP_GBOBJECTS) != 0);
681684
/*
682685
* We have FIFO cmd's
683686
*/
684-
return vmw->fifo_mem != NULL;
687+
return has_cmdbufs || vmw->fifo_mem != NULL;
685688
}

drivers/gpu/drm/vmwgfx/vmwgfx_drv.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1679,4 +1679,12 @@ static inline void vmw_irq_status_write(struct vmw_private *vmw,
16791679
outl(status, vmw->io_start + SVGA_IRQSTATUS_PORT);
16801680
}
16811681

1682+
static inline bool vmw_has_fences(struct vmw_private *vmw)
1683+
{
1684+
if ((vmw->capabilities & (SVGA_CAP_COMMAND_BUFFERS |
1685+
SVGA_CAP_CMD_BUFFERS_2)) != 0)
1686+
return true;
1687+
return (vmw_fifo_caps(vmw) & SVGA_FIFO_CAP_FENCE) != 0;
1688+
}
1689+
16821690
#endif

drivers/gpu/drm/vmwgfx/vmwgfx_fb.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ static int vmw_fb_kms_detach(struct vmw_fb_par *par,
483483

484484
static int vmw_fb_kms_framebuffer(struct fb_info *info)
485485
{
486-
struct drm_mode_fb_cmd2 mode_cmd;
486+
struct drm_mode_fb_cmd2 mode_cmd = {0};
487487
struct vmw_fb_par *par = info->par;
488488
struct fb_var_screeninfo *var = &info->var;
489489
struct drm_framebuffer *cur_fb;

drivers/gpu/drm/vmwgfx/vmwgfx_fence.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,22 @@ fman_from_fence(struct vmw_fence_obj *fence)
8282
return container_of(fence->base.lock, struct vmw_fence_manager, lock);
8383
}
8484

85+
static u32 vmw_fence_goal_read(struct vmw_private *vmw)
86+
{
87+
if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0)
88+
return vmw_read(vmw, SVGA_REG_FENCE_GOAL);
89+
else
90+
return vmw_fifo_mem_read(vmw, SVGA_FIFO_FENCE_GOAL);
91+
}
92+
93+
static void vmw_fence_goal_write(struct vmw_private *vmw, u32 value)
94+
{
95+
if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0)
96+
vmw_write(vmw, SVGA_REG_FENCE_GOAL, value);
97+
else
98+
vmw_fifo_mem_write(vmw, SVGA_FIFO_FENCE_GOAL, value);
99+
}
100+
85101
/*
86102
* Note on fencing subsystem usage of irqs:
87103
* Typically the vmw_fences_update function is called
@@ -392,17 +408,16 @@ static bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman,
392408
if (likely(!fman->seqno_valid))
393409
return false;
394410

395-
goal_seqno = vmw_fifo_mem_read(fman->dev_priv, SVGA_FIFO_FENCE_GOAL);
411+
goal_seqno = vmw_fence_goal_read(fman->dev_priv);
396412
if (likely(passed_seqno - goal_seqno >= VMW_FENCE_WRAP))
397413
return false;
398414

399415
fman->seqno_valid = false;
400416
list_for_each_entry(fence, &fman->fence_list, head) {
401417
if (!list_empty(&fence->seq_passed_actions)) {
402418
fman->seqno_valid = true;
403-
vmw_fifo_mem_write(fman->dev_priv,
404-
SVGA_FIFO_FENCE_GOAL,
405-
fence->base.seqno);
419+
vmw_fence_goal_write(fman->dev_priv,
420+
fence->base.seqno);
406421
break;
407422
}
408423
}
@@ -434,13 +449,12 @@ static bool vmw_fence_goal_check_locked(struct vmw_fence_obj *fence)
434449
if (dma_fence_is_signaled_locked(&fence->base))
435450
return false;
436451

437-
goal_seqno = vmw_fifo_mem_read(fman->dev_priv, SVGA_FIFO_FENCE_GOAL);
452+
goal_seqno = vmw_fence_goal_read(fman->dev_priv);
438453
if (likely(fman->seqno_valid &&
439454
goal_seqno - fence->base.seqno < VMW_FENCE_WRAP))
440455
return false;
441456

442-
vmw_fifo_mem_write(fman->dev_priv, SVGA_FIFO_FENCE_GOAL,
443-
fence->base.seqno);
457+
vmw_fence_goal_write(fman->dev_priv, fence->base.seqno);
444458
fman->seqno_valid = true;
445459

446460
return true;

drivers/gpu/drm/vmwgfx/vmwgfx_irq.c

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@
3232

3333
#define VMW_FENCE_WRAP (1 << 24)
3434

35+
static u32 vmw_irqflag_fence_goal(struct vmw_private *vmw)
36+
{
37+
if ((vmw->capabilities2 & SVGA_CAP2_EXTRA_REGS) != 0)
38+
return SVGA_IRQFLAG_REG_FENCE_GOAL;
39+
else
40+
return SVGA_IRQFLAG_FENCE_GOAL;
41+
}
42+
3543
/**
3644
* vmw_thread_fn - Deferred (process context) irq handler
3745
*
@@ -96,7 +104,7 @@ static irqreturn_t vmw_irq_handler(int irq, void *arg)
96104
wake_up_all(&dev_priv->fifo_queue);
97105

98106
if ((masked_status & (SVGA_IRQFLAG_ANY_FENCE |
99-
SVGA_IRQFLAG_FENCE_GOAL)) &&
107+
vmw_irqflag_fence_goal(dev_priv))) &&
100108
!test_and_set_bit(VMW_IRQTHREAD_FENCE, dev_priv->irqthread_pending))
101109
ret = IRQ_WAKE_THREAD;
102110

@@ -137,8 +145,7 @@ bool vmw_seqno_passed(struct vmw_private *dev_priv,
137145
if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP))
138146
return true;
139147

140-
if (!(vmw_fifo_caps(dev_priv) & SVGA_FIFO_CAP_FENCE) &&
141-
vmw_fifo_idle(dev_priv, seqno))
148+
if (!vmw_has_fences(dev_priv) && vmw_fifo_idle(dev_priv, seqno))
142149
return true;
143150

144151
/**
@@ -160,6 +167,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
160167
unsigned long timeout)
161168
{
162169
struct vmw_fifo_state *fifo_state = dev_priv->fifo;
170+
bool fifo_down = false;
163171

164172
uint32_t count = 0;
165173
uint32_t signal_seq;
@@ -176,12 +184,14 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
176184
*/
177185

178186
if (fifo_idle) {
179-
down_read(&fifo_state->rwsem);
180187
if (dev_priv->cman) {
181188
ret = vmw_cmdbuf_idle(dev_priv->cman, interruptible,
182189
10*HZ);
183190
if (ret)
184191
goto out_err;
192+
} else if (fifo_state) {
193+
down_read(&fifo_state->rwsem);
194+
fifo_down = true;
185195
}
186196
}
187197

@@ -218,12 +228,12 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
218228
}
219229
}
220230
finish_wait(&dev_priv->fence_queue, &__wait);
221-
if (ret == 0 && fifo_idle)
231+
if (ret == 0 && fifo_idle && fifo_state)
222232
vmw_fence_write(dev_priv, signal_seq);
223233

224234
wake_up_all(&dev_priv->fence_queue);
225235
out_err:
226-
if (fifo_idle)
236+
if (fifo_down)
227237
up_read(&fifo_state->rwsem);
228238

229239
return ret;
@@ -266,13 +276,13 @@ void vmw_seqno_waiter_remove(struct vmw_private *dev_priv)
266276

267277
void vmw_goal_waiter_add(struct vmw_private *dev_priv)
268278
{
269-
vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_FENCE_GOAL,
279+
vmw_generic_waiter_add(dev_priv, vmw_irqflag_fence_goal(dev_priv),
270280
&dev_priv->goal_queue_waiters);
271281
}
272282

273283
void vmw_goal_waiter_remove(struct vmw_private *dev_priv)
274284
{
275-
vmw_generic_waiter_remove(dev_priv, SVGA_IRQFLAG_FENCE_GOAL,
285+
vmw_generic_waiter_remove(dev_priv, vmw_irqflag_fence_goal(dev_priv),
276286
&dev_priv->goal_queue_waiters);
277287
}
278288

drivers/gpu/drm/vmwgfx/vmwgfx_kms.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,7 +1344,6 @@ vmw_kms_new_framebuffer(struct vmw_private *dev_priv,
13441344
ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb,
13451345
mode_cmd,
13461346
is_bo_proxy);
1347-
13481347
/*
13491348
* vmw_create_bo_proxy() adds a reference that is no longer
13501349
* needed
@@ -1385,13 +1384,16 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
13851384
ret = vmw_user_lookup_handle(dev_priv, file_priv,
13861385
mode_cmd->handles[0],
13871386
&surface, &bo);
1388-
if (ret)
1387+
if (ret) {
1388+
DRM_ERROR("Invalid buffer object handle %u (0x%x).\n",
1389+
mode_cmd->handles[0], mode_cmd->handles[0]);
13891390
goto err_out;
1391+
}
13901392

13911393

13921394
if (!bo &&
13931395
!vmw_kms_srf_ok(dev_priv, mode_cmd->width, mode_cmd->height)) {
1394-
DRM_ERROR("Surface size cannot exceed %dx%d",
1396+
DRM_ERROR("Surface size cannot exceed %dx%d\n",
13951397
dev_priv->texture_max_width,
13961398
dev_priv->texture_max_height);
13971399
goto err_out;

0 commit comments

Comments
 (0)