Merge tag 'drm-misc-fixes-2026-01-16' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-fixes

drm-misc-fixes for v6.19-rc6:

vmwgfx:
- Fix hw regression from refactoring cursor handling on v10 'hardware'
- Fix warnings in destructor by merging the 2 release functions
- kernel doc fix
- error handling in vmw_compat_shader_add()

rockchip:
- fix vop2 polling
- fix regression waiting for cfgdone without config change
- fix warning when enabling encoder

core:
- take gem lock when preallocating in gpuvm.
- add single byte read fallback to dp for broken usb-c adapters
- remove duplicate drm_sysfb declarations

gud:
- Fix oops on usb disconnect

Simple panel:
- Re-add fallback when connector is not set to fix regressions
- Set correct type in DataImage SCF0700C48GGU18

nouveau:
- locking fixes for cursor handling.

Signed-off-by: Simona Vetter <simona.vetter@ffwll.ch>
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patch.msgid.link/ce0acfe2-9c1a-42b7-8782-f1e7f34b8544@linux.intel.com
This commit is contained in:
Simona Vetter
2026-01-16 20:27:20 +01:00
16 changed files with 216 additions and 162 deletions

View File

@@ -163,6 +163,7 @@ struct dw_hdmi_qp {
unsigned long ref_clk_rate;
struct regmap *regm;
int main_irq;
unsigned long tmds_char_rate;
};
@@ -1271,6 +1272,7 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
dw_hdmi_qp_init_hw(hdmi);
hdmi->main_irq = plat_data->main_irq;
ret = devm_request_threaded_irq(dev, plat_data->main_irq,
dw_hdmi_qp_main_hardirq, NULL,
IRQF_SHARED, dev_name(dev), hdmi);
@@ -1331,9 +1333,16 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
}
EXPORT_SYMBOL_GPL(dw_hdmi_qp_bind);
void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi)
{
disable_irq(hdmi->main_irq);
}
EXPORT_SYMBOL_GPL(dw_hdmi_qp_suspend);
void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi)
{
dw_hdmi_qp_init_hw(hdmi);
enable_irq(hdmi->main_irq);
}
EXPORT_SYMBOL_GPL(dw_hdmi_qp_resume);

View File

@@ -1602,24 +1602,23 @@ drm_gpuvm_bo_create(struct drm_gpuvm *gpuvm,
}
EXPORT_SYMBOL_GPL(drm_gpuvm_bo_create);
/*
* drm_gpuvm_bo_destroy_not_in_lists() - final part of drm_gpuvm_bo cleanup
* @vm_bo: the &drm_gpuvm_bo to destroy
*
* It is illegal to call this method if the @vm_bo is present in the GEMs gpuva
* list, the extobj list, or the evicted list.
*
* Note that this puts a refcount on the GEM object, which may destroy the GEM
* object if the refcount reaches zero. It's illegal for this to happen if the
* caller holds the GEMs gpuva mutex because it would free the mutex.
*/
static void
drm_gpuvm_bo_destroy(struct kref *kref)
drm_gpuvm_bo_destroy_not_in_lists(struct drm_gpuvm_bo *vm_bo)
{
struct drm_gpuvm_bo *vm_bo = container_of(kref, struct drm_gpuvm_bo,
kref);
struct drm_gpuvm *gpuvm = vm_bo->vm;
const struct drm_gpuvm_ops *ops = gpuvm->ops;
struct drm_gem_object *obj = vm_bo->obj;
bool lock = !drm_gpuvm_resv_protected(gpuvm);
if (!lock)
drm_gpuvm_resv_assert_held(gpuvm);
drm_gpuvm_bo_list_del(vm_bo, extobj, lock);
drm_gpuvm_bo_list_del(vm_bo, evict, lock);
drm_gem_gpuva_assert_lock_held(gpuvm, obj);
list_del(&vm_bo->list.entry.gem);
if (ops && ops->vm_bo_free)
ops->vm_bo_free(vm_bo);
@@ -1630,6 +1629,35 @@ drm_gpuvm_bo_destroy(struct kref *kref)
drm_gem_object_put(obj);
}
static void
drm_gpuvm_bo_destroy_not_in_lists_kref(struct kref *kref)
{
struct drm_gpuvm_bo *vm_bo = container_of(kref, struct drm_gpuvm_bo,
kref);
drm_gpuvm_bo_destroy_not_in_lists(vm_bo);
}
static void
drm_gpuvm_bo_destroy(struct kref *kref)
{
struct drm_gpuvm_bo *vm_bo = container_of(kref, struct drm_gpuvm_bo,
kref);
struct drm_gpuvm *gpuvm = vm_bo->vm;
bool lock = !drm_gpuvm_resv_protected(gpuvm);
if (!lock)
drm_gpuvm_resv_assert_held(gpuvm);
drm_gpuvm_bo_list_del(vm_bo, extobj, lock);
drm_gpuvm_bo_list_del(vm_bo, evict, lock);
drm_gem_gpuva_assert_lock_held(gpuvm, vm_bo->obj);
list_del(&vm_bo->list.entry.gem);
drm_gpuvm_bo_destroy_not_in_lists(vm_bo);
}
/**
* drm_gpuvm_bo_put() - drop a struct drm_gpuvm_bo reference
* @vm_bo: the &drm_gpuvm_bo to release the reference of
@@ -1745,9 +1773,7 @@ EXPORT_SYMBOL_GPL(drm_gpuvm_bo_put_deferred);
void
drm_gpuvm_bo_deferred_cleanup(struct drm_gpuvm *gpuvm)
{
const struct drm_gpuvm_ops *ops = gpuvm->ops;
struct drm_gpuvm_bo *vm_bo;
struct drm_gem_object *obj;
struct llist_node *bo_defer;
bo_defer = llist_del_all(&gpuvm->bo_defer);
@@ -1766,14 +1792,7 @@ drm_gpuvm_bo_deferred_cleanup(struct drm_gpuvm *gpuvm)
while (bo_defer) {
vm_bo = llist_entry(bo_defer, struct drm_gpuvm_bo, list.entry.bo_defer);
bo_defer = bo_defer->next;
obj = vm_bo->obj;
if (ops && ops->vm_bo_free)
ops->vm_bo_free(vm_bo);
else
kfree(vm_bo);
drm_gpuvm_put(gpuvm);
drm_gem_object_put(obj);
drm_gpuvm_bo_destroy_not_in_lists(vm_bo);
}
}
EXPORT_SYMBOL_GPL(drm_gpuvm_bo_deferred_cleanup);
@@ -1861,6 +1880,9 @@ EXPORT_SYMBOL_GPL(drm_gpuvm_bo_obtain);
* count is decreased. If not found @__vm_bo is returned without further
* increase of the reference count.
*
* The provided @__vm_bo must not already be in the gpuva, evict, or extobj
* lists prior to calling this method.
*
* A new &drm_gpuvm_bo is added to the GEMs gpuva list.
*
* Returns: a pointer to the found &drm_gpuvm_bo or @__vm_bo if no existing
@@ -1873,14 +1895,19 @@ drm_gpuvm_bo_obtain_prealloc(struct drm_gpuvm_bo *__vm_bo)
struct drm_gem_object *obj = __vm_bo->obj;
struct drm_gpuvm_bo *vm_bo;
drm_WARN_ON(gpuvm->drm, !drm_gpuvm_immediate_mode(gpuvm));
mutex_lock(&obj->gpuva.lock);
vm_bo = drm_gpuvm_bo_find(gpuvm, obj);
if (vm_bo) {
drm_gpuvm_bo_put(__vm_bo);
mutex_unlock(&obj->gpuva.lock);
kref_put(&__vm_bo->kref, drm_gpuvm_bo_destroy_not_in_lists_kref);
return vm_bo;
}
drm_gem_gpuva_assert_lock_held(gpuvm, obj);
list_add_tail(&__vm_bo->list.entry.gem, &obj->gpuva.list);
mutex_unlock(&obj->gpuva.lock);
return __vm_bo;
}

View File

@@ -457,27 +457,20 @@ int gud_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
struct drm_crtc *crtc = new_plane_state->crtc;
struct drm_crtc_state *crtc_state;
struct drm_crtc_state *crtc_state = NULL;
const struct drm_display_mode *mode;
struct drm_framebuffer *old_fb = old_plane_state->fb;
struct drm_connector_state *connector_state = NULL;
struct drm_framebuffer *fb = new_plane_state->fb;
const struct drm_format_info *format = fb->format;
const struct drm_format_info *format;
struct drm_connector *connector;
unsigned int i, num_properties;
struct gud_state_req *req;
int idx, ret;
size_t len;
if (drm_WARN_ON_ONCE(plane->dev, !fb))
return -EINVAL;
if (drm_WARN_ON_ONCE(plane->dev, !crtc))
return -EINVAL;
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
mode = &crtc_state->mode;
if (crtc)
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
DRM_PLANE_NO_SCALING,
@@ -492,6 +485,9 @@ int gud_plane_atomic_check(struct drm_plane *plane,
if (old_plane_state->rotation != new_plane_state->rotation)
crtc_state->mode_changed = true;
mode = &crtc_state->mode;
format = fb->format;
if (old_fb && old_fb->format != format)
crtc_state->mode_changed = true;
@@ -598,7 +594,7 @@ void gud_plane_atomic_update(struct drm_plane *plane,
struct drm_atomic_helper_damage_iter iter;
int ret, idx;
if (crtc->state->mode_changed || !crtc->state->enable) {
if (!crtc || crtc->state->mode_changed || !crtc->state->enable) {
cancel_work_sync(&gdrm->work);
mutex_lock(&gdrm->damage_lock);
if (gdrm->fb) {

View File

@@ -84,6 +84,7 @@ curs507a_prepare(struct nv50_wndw *wndw, struct nv50_head_atom *asyh,
asyh->curs.handle = handle;
asyh->curs.offset = offset;
asyh->set.curs = asyh->curs.visible;
nv50_atom(asyh->state.state)->lock_core = true;
}
}

View File

@@ -43,6 +43,9 @@ nv50_head_flush_clr(struct nv50_head *head,
union nv50_head_atom_mask clr = {
.mask = asyh->clr.mask & ~(flush ? 0 : asyh->set.mask),
};
lockdep_assert_held(&head->disp->mutex);
if (clr.crc) nv50_crc_atomic_clr(head);
if (clr.olut) head->func->olut_clr(head);
if (clr.core) head->func->core_clr(head);
@@ -65,6 +68,8 @@ nv50_head_flush_set_wndw(struct nv50_head *head, struct nv50_head_atom *asyh)
void
nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh)
{
lockdep_assert_held(&head->disp->mutex);
if (asyh->set.view ) head->func->view (head, asyh);
if (asyh->set.mode ) head->func->mode (head, asyh);
if (asyh->set.core ) head->func->core_set(head, asyh);

View File

@@ -623,8 +623,61 @@ static struct panel_simple *panel_simple_probe(struct device *dev)
if (IS_ERR(desc))
return ERR_CAST(desc);
connector_type = desc->connector_type;
/* Catch common mistakes for panels. */
switch (connector_type) {
case 0:
dev_warn(dev, "Specify missing connector_type\n");
connector_type = DRM_MODE_CONNECTOR_DPI;
break;
case DRM_MODE_CONNECTOR_LVDS:
WARN_ON(desc->bus_flags &
~(DRM_BUS_FLAG_DE_LOW |
DRM_BUS_FLAG_DE_HIGH |
DRM_BUS_FLAG_DATA_MSB_TO_LSB |
DRM_BUS_FLAG_DATA_LSB_TO_MSB));
WARN_ON(desc->bus_format != MEDIA_BUS_FMT_RGB666_1X7X3_SPWG &&
desc->bus_format != MEDIA_BUS_FMT_RGB888_1X7X4_SPWG &&
desc->bus_format != MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA);
WARN_ON(desc->bus_format == MEDIA_BUS_FMT_RGB666_1X7X3_SPWG &&
desc->bpc != 6);
WARN_ON((desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_SPWG ||
desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA) &&
desc->bpc != 8);
break;
case DRM_MODE_CONNECTOR_eDP:
dev_warn(dev, "eDP panels moved to panel-edp\n");
return ERR_PTR(-EINVAL);
case DRM_MODE_CONNECTOR_DSI:
if (desc->bpc != 6 && desc->bpc != 8)
dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc);
break;
case DRM_MODE_CONNECTOR_DPI:
bus_flags = DRM_BUS_FLAG_DE_LOW |
DRM_BUS_FLAG_DE_HIGH |
DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE |
DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE |
DRM_BUS_FLAG_DATA_MSB_TO_LSB |
DRM_BUS_FLAG_DATA_LSB_TO_MSB |
DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE |
DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE;
if (desc->bus_flags & ~bus_flags)
dev_warn(dev, "Unexpected bus_flags(%d)\n", desc->bus_flags & ~bus_flags);
if (!(desc->bus_flags & bus_flags))
dev_warn(dev, "Specify missing bus_flags\n");
if (desc->bus_format == 0)
dev_warn(dev, "Specify missing bus_format\n");
if (desc->bpc != 6 && desc->bpc != 8)
dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc);
break;
default:
dev_warn(dev, "Specify a valid connector_type: %d\n", desc->connector_type);
connector_type = DRM_MODE_CONNECTOR_DPI;
break;
}
panel = devm_drm_panel_alloc(dev, struct panel_simple, base,
&panel_simple_funcs, desc->connector_type);
&panel_simple_funcs, connector_type);
if (IS_ERR(panel))
return ERR_CAST(panel);
@@ -666,60 +719,6 @@ static struct panel_simple *panel_simple_probe(struct device *dev)
goto free_ddc;
}
connector_type = desc->connector_type;
/* Catch common mistakes for panels. */
switch (connector_type) {
case 0:
dev_warn(dev, "Specify missing connector_type\n");
connector_type = DRM_MODE_CONNECTOR_DPI;
break;
case DRM_MODE_CONNECTOR_LVDS:
WARN_ON(desc->bus_flags &
~(DRM_BUS_FLAG_DE_LOW |
DRM_BUS_FLAG_DE_HIGH |
DRM_BUS_FLAG_DATA_MSB_TO_LSB |
DRM_BUS_FLAG_DATA_LSB_TO_MSB));
WARN_ON(desc->bus_format != MEDIA_BUS_FMT_RGB666_1X7X3_SPWG &&
desc->bus_format != MEDIA_BUS_FMT_RGB888_1X7X4_SPWG &&
desc->bus_format != MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA);
WARN_ON(desc->bus_format == MEDIA_BUS_FMT_RGB666_1X7X3_SPWG &&
desc->bpc != 6);
WARN_ON((desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_SPWG ||
desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA) &&
desc->bpc != 8);
break;
case DRM_MODE_CONNECTOR_eDP:
dev_warn(dev, "eDP panels moved to panel-edp\n");
err = -EINVAL;
goto free_ddc;
case DRM_MODE_CONNECTOR_DSI:
if (desc->bpc != 6 && desc->bpc != 8)
dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc);
break;
case DRM_MODE_CONNECTOR_DPI:
bus_flags = DRM_BUS_FLAG_DE_LOW |
DRM_BUS_FLAG_DE_HIGH |
DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE |
DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE |
DRM_BUS_FLAG_DATA_MSB_TO_LSB |
DRM_BUS_FLAG_DATA_LSB_TO_MSB |
DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE |
DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE;
if (desc->bus_flags & ~bus_flags)
dev_warn(dev, "Unexpected bus_flags(%d)\n", desc->bus_flags & ~bus_flags);
if (!(desc->bus_flags & bus_flags))
dev_warn(dev, "Specify missing bus_flags\n");
if (desc->bus_format == 0)
dev_warn(dev, "Specify missing bus_format\n");
if (desc->bpc != 6 && desc->bpc != 8)
dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc);
break;
default:
dev_warn(dev, "Specify a valid connector_type: %d\n", desc->connector_type);
connector_type = DRM_MODE_CONNECTOR_DPI;
break;
}
dev_set_drvdata(dev, panel);
/*
@@ -1900,6 +1899,7 @@ static const struct panel_desc dataimage_scf0700c48ggu18 = {
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
.connector_type = DRM_MODE_CONNECTOR_DPI,
};
static const struct display_timing dlc_dlc0700yzg_1_timing = {

View File

@@ -1252,17 +1252,7 @@ static int panthor_vm_prepare_map_op_ctx(struct panthor_vm_op_ctx *op_ctx,
goto err_cleanup;
}
/* drm_gpuvm_bo_obtain_prealloc() will call drm_gpuvm_bo_put() on our
* pre-allocated BO if the <BO,VM> association exists. Given we
* only have one ref on preallocated_vm_bo, drm_gpuvm_bo_destroy() will
* be called immediately, and we have to hold the VM resv lock when
* calling this function.
*/
dma_resv_lock(panthor_vm_resv(vm), NULL);
mutex_lock(&bo->base.base.gpuva.lock);
op_ctx->map.vm_bo = drm_gpuvm_bo_obtain_prealloc(preallocated_vm_bo);
mutex_unlock(&bo->base.base.gpuva.lock);
dma_resv_unlock(panthor_vm_resv(vm));
op_ctx->map.bo_offset = offset;

View File

@@ -121,7 +121,7 @@ static void dw_hdmi_qp_rockchip_encoder_enable(struct drm_encoder *encoder)
struct drm_crtc *crtc = encoder->crtc;
/* Unconditionally switch to TMDS as FRL is not yet supported */
gpiod_set_value(hdmi->frl_enable_gpio, 0);
gpiod_set_value_cansleep(hdmi->frl_enable_gpio, 0);
if (!crtc || !crtc->state)
return;
@@ -640,6 +640,15 @@ static void dw_hdmi_qp_rockchip_remove(struct platform_device *pdev)
component_del(&pdev->dev, &dw_hdmi_qp_rockchip_ops);
}
static int __maybe_unused dw_hdmi_qp_rockchip_suspend(struct device *dev)
{
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
dw_hdmi_qp_suspend(dev, hdmi->hdmi);
return 0;
}
static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev)
{
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
@@ -655,7 +664,8 @@ static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev)
}
static const struct dev_pm_ops dw_hdmi_qp_rockchip_pm = {
SET_SYSTEM_SLEEP_PM_OPS(NULL, dw_hdmi_qp_rockchip_resume)
SET_SYSTEM_SLEEP_PM_OPS(dw_hdmi_qp_rockchip_suspend,
dw_hdmi_qp_rockchip_resume)
};
struct platform_driver dw_hdmi_qp_rockchip_pltfm_driver = {

View File

@@ -2104,7 +2104,7 @@ static void rk3568_vop2_wait_for_port_mux_done(struct vop2 *vop2)
* Spin until the previous port_mux figuration is done.
*/
ret = readx_poll_timeout_atomic(rk3568_vop2_read_port_mux, vop2, port_mux_sel,
port_mux_sel == vop2->old_port_sel, 0, 50 * 1000);
port_mux_sel == vop2->old_port_sel, 10, 50 * 1000);
if (ret)
DRM_DEV_ERROR(vop2->dev, "wait port_mux done timeout: 0x%x--0x%x\n",
port_mux_sel, vop2->old_port_sel);
@@ -2124,7 +2124,7 @@ static void rk3568_vop2_wait_for_layer_cfg_done(struct vop2 *vop2, u32 cfg)
* Spin until the previous layer configuration is done.
*/
ret = readx_poll_timeout_atomic(rk3568_vop2_read_layer_cfg, vop2, atv_layer_cfg,
atv_layer_cfg == cfg, 0, 50 * 1000);
atv_layer_cfg == cfg, 10, 50 * 1000);
if (ret)
DRM_DEV_ERROR(vop2->dev, "wait layer cfg done timeout: 0x%x--0x%x\n",
atv_layer_cfg, cfg);
@@ -2144,6 +2144,7 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
u8 layer_sel_id;
unsigned int ofs;
u32 ovl_ctrl;
u32 cfg_done;
int i;
struct vop2_video_port *vp0 = &vop2->vps[0];
struct vop2_video_port *vp1 = &vop2->vps[1];
@@ -2298,8 +2299,16 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
rk3568_vop2_wait_for_port_mux_done(vop2);
}
if (layer_sel != old_layer_sel && atv_layer_sel != old_layer_sel)
rk3568_vop2_wait_for_layer_cfg_done(vop2, vop2->old_layer_sel);
if (layer_sel != old_layer_sel && atv_layer_sel != old_layer_sel) {
cfg_done = vop2_readl(vop2, RK3568_REG_CFG_DONE);
cfg_done &= (BIT(vop2->data->nr_vps) - 1);
cfg_done &= ~BIT(vp->id);
/*
* Changes of other VPs' overlays have not taken effect
*/
if (cfg_done)
rk3568_vop2_wait_for_layer_cfg_done(vop2, vop2->old_layer_sel);
}
vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel);
mutex_unlock(&vop2->ovl_lock);

View File

@@ -54,15 +54,6 @@ const struct drm_format_info *drm_sysfb_get_format_si(struct drm_device *dev,
const struct screen_info *si);
#endif
/*
* Input parsing
*/
int drm_sysfb_get_validated_int(struct drm_device *dev, const char *name,
u64 value, u32 max);
int drm_sysfb_get_validated_int0(struct drm_device *dev, const char *name,
u64 value, u32 max);
/*
* Display modes
*/

View File

@@ -32,9 +32,15 @@
#include <drm/ttm/ttm_placement.h>
static void vmw_bo_release(struct vmw_bo *vbo)
/**
* vmw_bo_free - vmw_bo destructor
*
* @bo: Pointer to the embedded struct ttm_buffer_object
*/
static void vmw_bo_free(struct ttm_buffer_object *bo)
{
struct vmw_resource *res;
struct vmw_bo *vbo = to_vmw_bo(&bo->base);
WARN_ON(kref_read(&vbo->tbo.base.refcount) != 0);
vmw_bo_unmap(vbo);
@@ -62,20 +68,8 @@ static void vmw_bo_release(struct vmw_bo *vbo)
}
vmw_surface_unreference(&vbo->dumb_surface);
}
drm_gem_object_release(&vbo->tbo.base);
}
/**
* vmw_bo_free - vmw_bo destructor
*
* @bo: Pointer to the embedded struct ttm_buffer_object
*/
static void vmw_bo_free(struct ttm_buffer_object *bo)
{
struct vmw_bo *vbo = to_vmw_bo(&bo->base);
WARN_ON(!RB_EMPTY_ROOT(&vbo->res_tree));
vmw_bo_release(vbo);
drm_gem_object_release(&vbo->tbo.base);
WARN_ON(vbo->dirty);
kfree(vbo);
}

View File

@@ -515,12 +515,12 @@ int vmw_fence_obj_unref_ioctl(struct drm_device *dev, void *data,
/**
* vmw_event_fence_action_seq_passed
*
* @action: The struct vmw_fence_action embedded in a struct
* vmw_event_fence_action.
* @f: The struct dma_fence which provides timestamp for the action event
* @cb: The struct dma_fence_cb callback for the action event.
*
* This function is called when the seqno of the fence where @action is
* attached has passed. It queues the event on the submitter's event list.
* This function is always called from atomic context.
* This function is called when the seqno of the fence has passed
* and it is always called from atomic context.
* It queues the event on the submitter's event list.
*/
static void vmw_event_fence_action_seq_passed(struct dma_fence *f,
struct dma_fence_cb *cb)

View File

@@ -766,13 +766,15 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
return ERR_PTR(ret);
}
ttm_bo_reserve(&bo->tbo, false, false, NULL);
ret = vmw_bo_dirty_add(bo);
if (!ret && surface && surface->res.func->dirty_alloc) {
surface->res.coherent = true;
ret = surface->res.func->dirty_alloc(&surface->res);
if (bo) {
ttm_bo_reserve(&bo->tbo, false, false, NULL);
ret = vmw_bo_dirty_add(bo);
if (!ret && surface && surface->res.func->dirty_alloc) {
surface->res.coherent = true;
ret = surface->res.func->dirty_alloc(&surface->res);
}
ttm_bo_unreserve(&bo->tbo);
}
ttm_bo_unreserve(&bo->tbo);
return &vfb->base;
}

View File

@@ -923,8 +923,10 @@ int vmw_compat_shader_add(struct vmw_private *dev_priv,
ttm_bo_unreserve(&buf->tbo);
res = vmw_shader_alloc(dev_priv, buf, size, 0, shader_type);
if (unlikely(ret != 0))
if (IS_ERR(res)) {
ret = PTR_ERR(res);
goto no_reserve;
}
ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader,
vmw_shader_key(user_key, shader_type),

View File

@@ -34,5 +34,6 @@ struct dw_hdmi_qp_plat_data {
struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
struct drm_encoder *encoder,
const struct dw_hdmi_qp_plat_data *plat_data);
void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi);
void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi);
#endif /* __DW_HDMI_QP__ */

View File

@@ -551,6 +551,22 @@ ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset,
void *buffer, size_t size);
/**
* drm_dp_dpcd_readb() - read a single byte from the DPCD
* @aux: DisplayPort AUX channel
* @offset: address of the register to read
* @valuep: location where the value of the register will be stored
*
* Returns the number of bytes transferred (1) on success, or a negative
* error code on failure. In most of the cases you should be using
* drm_dp_dpcd_read_byte() instead.
*/
static inline ssize_t drm_dp_dpcd_readb(struct drm_dp_aux *aux,
unsigned int offset, u8 *valuep)
{
return drm_dp_dpcd_read(aux, offset, valuep, 1);
}
/**
* drm_dp_dpcd_read_data() - read a series of bytes from the DPCD
* @aux: DisplayPort AUX channel (SST or MST)
@@ -570,12 +586,29 @@ static inline int drm_dp_dpcd_read_data(struct drm_dp_aux *aux,
void *buffer, size_t size)
{
int ret;
size_t i;
u8 *buf = buffer;
ret = drm_dp_dpcd_read(aux, offset, buffer, size);
if (ret < 0)
return ret;
if (ret < size)
return -EPROTO;
if (ret >= 0) {
if (ret < size)
return -EPROTO;
return 0;
}
/*
* Workaround for USB-C hubs/adapters with buggy firmware that fail
* multi-byte AUX reads but work with single-byte reads.
* Known affected devices:
* - Lenovo USB-C to VGA adapter (VIA VL817, idVendor=17ef, idProduct=7217)
* - Dell DA310 USB-C hub (idVendor=413c, idProduct=c010)
* Attempt byte-by-byte reading as a fallback.
*/
for (i = 0; i < size; i++) {
ret = drm_dp_dpcd_readb(aux, offset + i, &buf[i]);
if (ret < 0)
return ret;
}
return 0;
}
@@ -609,22 +642,6 @@ static inline int drm_dp_dpcd_write_data(struct drm_dp_aux *aux,
return 0;
}
/**
* drm_dp_dpcd_readb() - read a single byte from the DPCD
* @aux: DisplayPort AUX channel
* @offset: address of the register to read
* @valuep: location where the value of the register will be stored
*
* Returns the number of bytes transferred (1) on success, or a negative
* error code on failure. In most of the cases you should be using
* drm_dp_dpcd_read_byte() instead.
*/
static inline ssize_t drm_dp_dpcd_readb(struct drm_dp_aux *aux,
unsigned int offset, u8 *valuep)
{
return drm_dp_dpcd_read(aux, offset, valuep, 1);
}
/**
* drm_dp_dpcd_writeb() - write a single byte to the DPCD
* @aux: DisplayPort AUX channel