Commit 5fa88138 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm-misc-fixes-2022-11-17' of git://anongit.freedesktop.org/drm/drm-misc into drm-fixes

drm-misc-fixes for v6.1-rc6:
- Fix error handling in vc4_atomic_commit_tail()
- Set bpc for logictechno panels.
- Fix potential memory leak in drm_dev_init()
- Fix potential null-ptr-deref in drm_vblank_destroy_worker()
- Set lima's clkname corrrectly when regulator is missing.
- Small amdgpu fix to gang submission.
- Revert hiding unregistered connectors from userspace, as it breaks on DP-MST.
- Add workaround for DP++ dual mode adaptors that don't support
  i2c subaddressing.
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/c7d02936-c550-199b-6cb7-cbf6cf104e4a@linux.intel.com
parents 094226ad 5954acba
...@@ -109,6 +109,7 @@ static int amdgpu_cs_p1_ib(struct amdgpu_cs_parser *p, ...@@ -109,6 +109,7 @@ static int amdgpu_cs_p1_ib(struct amdgpu_cs_parser *p,
return r; return r;
++(num_ibs[r]); ++(num_ibs[r]);
p->gang_leader_idx = r;
return 0; return 0;
} }
...@@ -300,7 +301,7 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p, ...@@ -300,7 +301,7 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p,
if (ret) if (ret)
goto free_all_kdata; goto free_all_kdata;
} }
p->gang_leader = p->jobs[p->gang_size - 1]; p->gang_leader = p->jobs[p->gang_leader_idx];
if (p->ctx->vram_lost_counter != p->gang_leader->vram_lost_counter) { if (p->ctx->vram_lost_counter != p->gang_leader->vram_lost_counter) {
ret = -ECANCELED; ret = -ECANCELED;
...@@ -1195,16 +1196,18 @@ static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p) ...@@ -1195,16 +1196,18 @@ static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p)
return r; return r;
} }
for (i = 0; i < p->gang_size - 1; ++i) { for (i = 0; i < p->gang_size; ++i) {
if (p->jobs[i] == leader)
continue;
r = amdgpu_sync_clone(&leader->sync, &p->jobs[i]->sync); r = amdgpu_sync_clone(&leader->sync, &p->jobs[i]->sync);
if (r) if (r)
return r; return r;
} }
r = amdgpu_ctx_wait_prev_fence(p->ctx, p->entities[p->gang_size - 1]); r = amdgpu_ctx_wait_prev_fence(p->ctx, p->entities[p->gang_leader_idx]);
if (r && r != -ERESTARTSYS) if (r && r != -ERESTARTSYS)
DRM_ERROR("amdgpu_ctx_wait_prev_fence failed.\n"); DRM_ERROR("amdgpu_ctx_wait_prev_fence failed.\n");
return r; return r;
} }
...@@ -1238,9 +1241,12 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, ...@@ -1238,9 +1241,12 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
for (i = 0; i < p->gang_size; ++i) for (i = 0; i < p->gang_size; ++i)
drm_sched_job_arm(&p->jobs[i]->base); drm_sched_job_arm(&p->jobs[i]->base);
for (i = 0; i < (p->gang_size - 1); ++i) { for (i = 0; i < p->gang_size; ++i) {
struct dma_fence *fence; struct dma_fence *fence;
if (p->jobs[i] == leader)
continue;
fence = &p->jobs[i]->base.s_fence->scheduled; fence = &p->jobs[i]->base.s_fence->scheduled;
r = amdgpu_sync_fence(&leader->sync, fence); r = amdgpu_sync_fence(&leader->sync, fence);
if (r) if (r)
...@@ -1276,7 +1282,10 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, ...@@ -1276,7 +1282,10 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
list_for_each_entry(e, &p->validated, tv.head) { list_for_each_entry(e, &p->validated, tv.head) {
/* Everybody except for the gang leader uses READ */ /* Everybody except for the gang leader uses READ */
for (i = 0; i < (p->gang_size - 1); ++i) { for (i = 0; i < p->gang_size; ++i) {
if (p->jobs[i] == leader)
continue;
dma_resv_add_fence(e->tv.bo->base.resv, dma_resv_add_fence(e->tv.bo->base.resv,
&p->jobs[i]->base.s_fence->finished, &p->jobs[i]->base.s_fence->finished,
DMA_RESV_USAGE_READ); DMA_RESV_USAGE_READ);
...@@ -1286,7 +1295,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, ...@@ -1286,7 +1295,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
e->tv.num_shared = 0; e->tv.num_shared = 0;
} }
seq = amdgpu_ctx_add_fence(p->ctx, p->entities[p->gang_size - 1], seq = amdgpu_ctx_add_fence(p->ctx, p->entities[p->gang_leader_idx],
p->fence); p->fence);
amdgpu_cs_post_dependencies(p); amdgpu_cs_post_dependencies(p);
......
...@@ -54,6 +54,7 @@ struct amdgpu_cs_parser { ...@@ -54,6 +54,7 @@ struct amdgpu_cs_parser {
/* scheduler job objects */ /* scheduler job objects */
unsigned int gang_size; unsigned int gang_size;
unsigned int gang_leader_idx;
struct drm_sched_entity *entities[AMDGPU_CS_GANG_SIZE]; struct drm_sched_entity *entities[AMDGPU_CS_GANG_SIZE];
struct amdgpu_job *jobs[AMDGPU_CS_GANG_SIZE]; struct amdgpu_job *jobs[AMDGPU_CS_GANG_SIZE];
struct amdgpu_job *gang_leader; struct amdgpu_job *gang_leader;
......
...@@ -63,23 +63,45 @@ ...@@ -63,23 +63,45 @@
ssize_t drm_dp_dual_mode_read(struct i2c_adapter *adapter, ssize_t drm_dp_dual_mode_read(struct i2c_adapter *adapter,
u8 offset, void *buffer, size_t size) u8 offset, void *buffer, size_t size)
{ {
u8 zero = 0;
char *tmpbuf = NULL;
/*
* As sub-addressing is not supported by all adaptors,
* always explicitly read from the start and discard
* any bytes that come before the requested offset.
* This way, no matter whether the adaptor supports it
* or not, we'll end up reading the proper data.
*/
struct i2c_msg msgs[] = { struct i2c_msg msgs[] = {
{ {
.addr = DP_DUAL_MODE_SLAVE_ADDRESS, .addr = DP_DUAL_MODE_SLAVE_ADDRESS,
.flags = 0, .flags = 0,
.len = 1, .len = 1,
.buf = &offset, .buf = &zero,
}, },
{ {
.addr = DP_DUAL_MODE_SLAVE_ADDRESS, .addr = DP_DUAL_MODE_SLAVE_ADDRESS,
.flags = I2C_M_RD, .flags = I2C_M_RD,
.len = size, .len = size + offset,
.buf = buffer, .buf = buffer,
}, },
}; };
int ret; int ret;
if (offset) {
tmpbuf = kmalloc(size + offset, GFP_KERNEL);
if (!tmpbuf)
return -ENOMEM;
msgs[1].buf = tmpbuf;
}
ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs)); ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs));
if (tmpbuf)
memcpy(buffer, tmpbuf + offset, size);
kfree(tmpbuf);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (ret != ARRAY_SIZE(msgs)) if (ret != ARRAY_SIZE(msgs))
...@@ -208,18 +230,6 @@ enum drm_dp_dual_mode_type drm_dp_dual_mode_detect(const struct drm_device *dev, ...@@ -208,18 +230,6 @@ enum drm_dp_dual_mode_type drm_dp_dual_mode_detect(const struct drm_device *dev,
if (ret) if (ret)
return DRM_DP_DUAL_MODE_UNKNOWN; return DRM_DP_DUAL_MODE_UNKNOWN;
/*
* Sigh. Some (maybe all?) type 1 adaptors are broken and ack
* the offset but ignore it, and instead they just always return
* data from the start of the HDMI ID buffer. So for a broken
* type 1 HDMI adaptor a single byte read will always give us
* 0x44, and for a type 1 DVI adaptor it should give 0x00
* (assuming it implements any registers). Fortunately neither
* of those values will match the type 2 signature of the
* DP_DUAL_MODE_ADAPTOR_ID register so we can proceed with
* the type 2 adaptor detection safely even in the presence
* of broken type 1 adaptors.
*/
ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_ADAPTOR_ID, ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_ADAPTOR_ID,
&adaptor_id, sizeof(adaptor_id)); &adaptor_id, sizeof(adaptor_id));
drm_dbg_kms(dev, "DP dual mode adaptor ID: %02x (err %zd)\n", adaptor_id, ret); drm_dbg_kms(dev, "DP dual mode adaptor ID: %02x (err %zd)\n", adaptor_id, ret);
...@@ -233,11 +243,10 @@ enum drm_dp_dual_mode_type drm_dp_dual_mode_detect(const struct drm_device *dev, ...@@ -233,11 +243,10 @@ enum drm_dp_dual_mode_type drm_dp_dual_mode_detect(const struct drm_device *dev,
return DRM_DP_DUAL_MODE_TYPE2_DVI; return DRM_DP_DUAL_MODE_TYPE2_DVI;
} }
/* /*
* If neither a proper type 1 ID nor a broken type 1 adaptor * If not a proper type 1 ID, still assume type 1, but let
* as described above, assume type 1, but let the user know * the user know that we may have misdetected the type.
* that we may have misdetected the type.
*/ */
if (!is_type1_adaptor(adaptor_id) && adaptor_id != hdmi_id[0]) if (!is_type1_adaptor(adaptor_id))
drm_err(dev, "Unexpected DP dual mode adaptor ID %02x\n", adaptor_id); drm_err(dev, "Unexpected DP dual mode adaptor ID %02x\n", adaptor_id);
} }
...@@ -343,10 +352,8 @@ EXPORT_SYMBOL(drm_dp_dual_mode_get_tmds_output); ...@@ -343,10 +352,8 @@ EXPORT_SYMBOL(drm_dp_dual_mode_get_tmds_output);
* @enable: enable (as opposed to disable) the TMDS output buffers * @enable: enable (as opposed to disable) the TMDS output buffers
* *
* Set the state of the TMDS output buffers in the adaptor. For * Set the state of the TMDS output buffers in the adaptor. For
* type2 this is set via the DP_DUAL_MODE_TMDS_OEN register. As * type2 this is set via the DP_DUAL_MODE_TMDS_OEN register.
* some type 1 adaptors have problems with registers (see comments * Type1 adaptors do not support any register writes.
* in drm_dp_dual_mode_detect()) we avoid touching the register,
* making this function a no-op on type 1 adaptors.
* *
* Returns: * Returns:
* 0 on success, negative error code on failure * 0 on success, negative error code on failure
......
...@@ -615,7 +615,7 @@ static int drm_dev_init(struct drm_device *dev, ...@@ -615,7 +615,7 @@ static int drm_dev_init(struct drm_device *dev,
mutex_init(&dev->clientlist_mutex); mutex_init(&dev->clientlist_mutex);
mutex_init(&dev->master_mutex); mutex_init(&dev->master_mutex);
ret = drmm_add_action(dev, drm_dev_init_release, NULL); ret = drmm_add_action_or_reset(dev, drm_dev_init_release, NULL);
if (ret) if (ret)
return ret; return ret;
......
...@@ -104,6 +104,7 @@ static inline void drm_vblank_flush_worker(struct drm_vblank_crtc *vblank) ...@@ -104,6 +104,7 @@ static inline void drm_vblank_flush_worker(struct drm_vblank_crtc *vblank)
static inline void drm_vblank_destroy_worker(struct drm_vblank_crtc *vblank) static inline void drm_vblank_destroy_worker(struct drm_vblank_crtc *vblank)
{ {
if (vblank->worker)
kthread_destroy_worker(vblank->worker); kthread_destroy_worker(vblank->worker);
} }
......
...@@ -151,9 +151,6 @@ int drm_mode_getresources(struct drm_device *dev, void *data, ...@@ -151,9 +151,6 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
count = 0; count = 0;
connector_id = u64_to_user_ptr(card_res->connector_id_ptr); connector_id = u64_to_user_ptr(card_res->connector_id_ptr);
drm_for_each_connector_iter(connector, &conn_iter) { drm_for_each_connector_iter(connector, &conn_iter) {
if (connector->registration_state != DRM_CONNECTOR_REGISTERED)
continue;
/* only expose writeback connectors if userspace understands them */ /* only expose writeback connectors if userspace understands them */
if (!file_priv->writeback_connectors && if (!file_priv->writeback_connectors &&
(connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)) (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK))
......
...@@ -112,11 +112,6 @@ int lima_devfreq_init(struct lima_device *ldev) ...@@ -112,11 +112,6 @@ int lima_devfreq_init(struct lima_device *ldev)
unsigned long cur_freq; unsigned long cur_freq;
int ret; int ret;
const char *regulator_names[] = { "mali", NULL }; const char *regulator_names[] = { "mali", NULL };
const char *clk_names[] = { "core", NULL };
struct dev_pm_opp_config config = {
.regulator_names = regulator_names,
.clk_names = clk_names,
};
if (!device_property_present(dev, "operating-points-v2")) if (!device_property_present(dev, "operating-points-v2"))
/* Optional, continue without devfreq */ /* Optional, continue without devfreq */
...@@ -124,7 +119,15 @@ int lima_devfreq_init(struct lima_device *ldev) ...@@ -124,7 +119,15 @@ int lima_devfreq_init(struct lima_device *ldev)
spin_lock_init(&ldevfreq->lock); spin_lock_init(&ldevfreq->lock);
ret = devm_pm_opp_set_config(dev, &config); /*
* clkname is set separately so it is not affected by the optional
* regulator setting which may return error.
*/
ret = devm_pm_opp_set_clkname(dev, "core");
if (ret)
return ret;
ret = devm_pm_opp_set_regulators(dev, regulator_names);
if (ret) { if (ret) {
/* Continue if the optional regulator is missing */ /* Continue if the optional regulator is missing */
if (ret != -ENODEV) if (ret != -ENODEV)
......
...@@ -2500,6 +2500,7 @@ static const struct display_timing logictechno_lt161010_2nh_timing = { ...@@ -2500,6 +2500,7 @@ static const struct display_timing logictechno_lt161010_2nh_timing = {
static const struct panel_desc logictechno_lt161010_2nh = { static const struct panel_desc logictechno_lt161010_2nh = {
.timings = &logictechno_lt161010_2nh_timing, .timings = &logictechno_lt161010_2nh_timing,
.num_timings = 1, .num_timings = 1,
.bpc = 6,
.size = { .size = {
.width = 154, .width = 154,
.height = 86, .height = 86,
...@@ -2529,6 +2530,7 @@ static const struct display_timing logictechno_lt170410_2whc_timing = { ...@@ -2529,6 +2530,7 @@ static const struct display_timing logictechno_lt170410_2whc_timing = {
static const struct panel_desc logictechno_lt170410_2whc = { static const struct panel_desc logictechno_lt170410_2whc = {
.timings = &logictechno_lt170410_2whc_timing, .timings = &logictechno_lt170410_2whc_timing,
.num_timings = 1, .num_timings = 1,
.bpc = 8,
.size = { .size = {
.width = 217, .width = 217,
.height = 136, .height = 136,
......
...@@ -197,8 +197,8 @@ vc4_hvs_get_new_global_state(struct drm_atomic_state *state) ...@@ -197,8 +197,8 @@ vc4_hvs_get_new_global_state(struct drm_atomic_state *state)
struct drm_private_state *priv_state; struct drm_private_state *priv_state;
priv_state = drm_atomic_get_new_private_obj_state(state, &vc4->hvs_channels); priv_state = drm_atomic_get_new_private_obj_state(state, &vc4->hvs_channels);
if (IS_ERR(priv_state)) if (!priv_state)
return ERR_CAST(priv_state); return ERR_PTR(-EINVAL);
return to_vc4_hvs_state(priv_state); return to_vc4_hvs_state(priv_state);
} }
...@@ -210,8 +210,8 @@ vc4_hvs_get_old_global_state(struct drm_atomic_state *state) ...@@ -210,8 +210,8 @@ vc4_hvs_get_old_global_state(struct drm_atomic_state *state)
struct drm_private_state *priv_state; struct drm_private_state *priv_state;
priv_state = drm_atomic_get_old_private_obj_state(state, &vc4->hvs_channels); priv_state = drm_atomic_get_old_private_obj_state(state, &vc4->hvs_channels);
if (IS_ERR(priv_state)) if (!priv_state)
return ERR_CAST(priv_state); return ERR_PTR(-EINVAL);
return to_vc4_hvs_state(priv_state); return to_vc4_hvs_state(priv_state);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment