Skip to content

Commit 8a86bb8

Browse files
hersen wugregkh
authored andcommitted
drm/amd/display: phase2 enable mst hdcp multiple displays
[ Upstream commit aa9fdd5d5add50305d2022fa072fe6f189283415 ] [why] For MST topology with 1 physical link and multiple connectors (>=2), e.g. daisy cahined MST + SST, or 1-to-multi MST hub, if userspace set to enable the HDCP simultaneously on all connected outputs, the commit tail iteratively call the hdcp_update_display() for each display (connector). However, the hdcp workqueue data structure for each link has only one DM connector and encryption status members, which means the work queue of property_validate/update() would only be triggered for the last connector within this physical link, and therefore the HDCP property value of other connectors would stay on DESIRED instead of switching to ENABLED, which is NOT as expected. [how] Use array of AMDGPU_DM_MAX_DISPLAY_INDEX for both aconnector and encryption status in hdcp workqueue data structure for each physical link. For property validate/update work queue, we iterates over the array and do similar operation/check for each connected display. Tested-by: Daniel Wheeler <[email protected]> Signed-off-by: hersen wu <[email protected]> Signed-off-by: Alex Deucher <[email protected]> Stable-dep-of: be593d9d91c5 ("drm/amd/display: Fix slab-use-after-free in hdcp") Signed-off-by: Sasha Levin <[email protected]>
1 parent 8316820 commit 8a86bb8

File tree

2 files changed

+122
-43
lines changed

2 files changed

+122
-43
lines changed

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c

Lines changed: 120 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,10 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
170170
struct mod_hdcp_display *display = &hdcp_work[link_index].display;
171171
struct mod_hdcp_link *link = &hdcp_work[link_index].link;
172172
struct mod_hdcp_display_query query;
173+
unsigned int conn_index = aconnector->base.index;
173174

174175
mutex_lock(&hdcp_w->mutex);
175-
hdcp_w->aconnector = aconnector;
176+
hdcp_w->aconnector[conn_index] = aconnector;
176177

177178
query.display = NULL;
178179
mod_hdcp_query_display(&hdcp_w->hdcp, aconnector->base.index, &query);
@@ -204,7 +205,7 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
204205
msecs_to_jiffies(DRM_HDCP_CHECK_PERIOD_MS));
205206
} else {
206207
display->adjust.disable = MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION;
207-
hdcp_w->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
208+
hdcp_w->encryption_status[conn_index] = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
208209
cancel_delayed_work(&hdcp_w->property_validate_dwork);
209210
}
210211

@@ -223,9 +224,10 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
223224
{
224225
struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
225226
struct drm_connector_state *conn_state = aconnector->base.state;
227+
unsigned int conn_index = aconnector->base.index;
226228

227229
mutex_lock(&hdcp_w->mutex);
228-
hdcp_w->aconnector = aconnector;
230+
hdcp_w->aconnector[conn_index] = aconnector;
229231

230232
/* the removal of display will invoke auth reset -> hdcp destroy and
231233
* we'd expect the Content Protection (CP) property changed back to
@@ -247,13 +249,18 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
247249
void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index)
248250
{
249251
struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
252+
unsigned int conn_index;
250253

251254
mutex_lock(&hdcp_w->mutex);
252255

253256
mod_hdcp_reset_connection(&hdcp_w->hdcp, &hdcp_w->output);
254257

255258
cancel_delayed_work(&hdcp_w->property_validate_dwork);
256-
hdcp_w->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
259+
260+
for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX; conn_index++) {
261+
hdcp_w->encryption_status[conn_index] =
262+
MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
263+
}
257264

258265
process_output(hdcp_w);
259266

@@ -290,69 +297,135 @@ static void event_callback(struct work_struct *work)
290297

291298

292299
}
300+
293301
static void event_property_update(struct work_struct *work)
294302
{
295-
296303
struct hdcp_workqueue *hdcp_work = container_of(work, struct hdcp_workqueue, property_update_work);
297-
struct amdgpu_dm_connector *aconnector = hdcp_work->aconnector;
298-
struct drm_device *dev = hdcp_work->aconnector->base.dev;
304+
struct amdgpu_dm_connector *aconnector = NULL;
305+
struct drm_device *dev;
299306
long ret;
307+
unsigned int conn_index;
308+
struct drm_connector *connector;
309+
struct drm_connector_state *conn_state;
300310

301-
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
302-
mutex_lock(&hdcp_work->mutex);
311+
for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX; conn_index++) {
312+
aconnector = hdcp_work->aconnector[conn_index];
303313

314+
if (!aconnector)
315+
continue;
304316

305-
if (aconnector->base.state && aconnector->base.state->commit) {
306-
ret = wait_for_completion_interruptible_timeout(&aconnector->base.state->commit->hw_done, 10 * HZ);
317+
if (!aconnector->base.index)
318+
continue;
307319

308-
if (ret == 0) {
309-
DRM_ERROR("HDCP state unknown! Setting it to DESIRED");
310-
hdcp_work->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
311-
}
312-
}
320+
connector = &aconnector->base;
321+
322+
/* check if display connected */
323+
if (connector->status != connector_status_connected)
324+
continue;
313325

314-
if (aconnector->base.state) {
315-
if (hdcp_work->encryption_status != MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF) {
316-
if (aconnector->base.state->hdcp_content_type ==
326+
conn_state = aconnector->base.state;
327+
328+
if (!conn_state)
329+
continue;
330+
331+
dev = connector->dev;
332+
333+
if (!dev)
334+
continue;
335+
336+
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
337+
mutex_lock(&hdcp_work->mutex);
338+
339+
if (conn_state->commit) {
340+
ret = wait_for_completion_interruptible_timeout(
341+
&conn_state->commit->hw_done, 10 * HZ);
342+
if (ret == 0) {
343+
DRM_ERROR(
344+
"HDCP state unknown! Setting it to DESIRED");
345+
hdcp_work->encryption_status[conn_index] =
346+
MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
347+
}
348+
}
349+
if (hdcp_work->encryption_status[conn_index] !=
350+
MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF) {
351+
if (conn_state->hdcp_content_type ==
317352
DRM_MODE_HDCP_CONTENT_TYPE0 &&
318-
hdcp_work->encryption_status <=
319-
MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON)
320-
drm_hdcp_update_content_protection(&aconnector->base,
353+
hdcp_work->encryption_status[conn_index] <=
354+
MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON) {
355+
356+
DRM_DEBUG_DRIVER("[HDCP_DM] DRM_MODE_CONTENT_PROTECTION_ENABLED\n");
357+
drm_hdcp_update_content_protection(
358+
connector,
321359
DRM_MODE_CONTENT_PROTECTION_ENABLED);
322-
else if (aconnector->base.state->hdcp_content_type ==
360+
} else if (conn_state->hdcp_content_type ==
323361
DRM_MODE_HDCP_CONTENT_TYPE1 &&
324-
hdcp_work->encryption_status ==
325-
MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON)
326-
drm_hdcp_update_content_protection(&aconnector->base,
362+
hdcp_work->encryption_status[conn_index] ==
363+
MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON) {
364+
drm_hdcp_update_content_protection(
365+
connector,
327366
DRM_MODE_CONTENT_PROTECTION_ENABLED);
367+
}
328368
} else {
329-
drm_hdcp_update_content_protection(&aconnector->base,
330-
DRM_MODE_CONTENT_PROTECTION_DESIRED);
369+
DRM_DEBUG_DRIVER("[HDCP_DM] DRM_MODE_CONTENT_PROTECTION_DESIRED\n");
370+
drm_hdcp_update_content_protection(
371+
connector, DRM_MODE_CONTENT_PROTECTION_DESIRED);
372+
331373
}
374+
mutex_unlock(&hdcp_work->mutex);
375+
drm_modeset_unlock(&dev->mode_config.connection_mutex);
332376
}
333-
334-
mutex_unlock(&hdcp_work->mutex);
335-
drm_modeset_unlock(&dev->mode_config.connection_mutex);
336377
}
337378

338379
static void event_property_validate(struct work_struct *work)
339380
{
340381
struct hdcp_workqueue *hdcp_work =
341382
container_of(to_delayed_work(work), struct hdcp_workqueue, property_validate_dwork);
342383
struct mod_hdcp_display_query query;
343-
struct amdgpu_dm_connector *aconnector = hdcp_work->aconnector;
344-
345-
if (!aconnector)
346-
return;
384+
struct amdgpu_dm_connector *aconnector;
385+
unsigned int conn_index;
347386

348387
mutex_lock(&hdcp_work->mutex);
349388

350-
query.encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
351-
mod_hdcp_query_display(&hdcp_work->hdcp, aconnector->base.index, &query);
389+
for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX;
390+
conn_index++) {
391+
aconnector = hdcp_work->aconnector[conn_index];
392+
393+
394+
if (!aconnector)
395+
continue;
396+
397+
if (!aconnector->base.index)
398+
continue;
399+
400+
/* check if display connected */
401+
if (aconnector->base.status != connector_status_connected)
402+
continue;
352403

353-
if (query.encryption_status != hdcp_work->encryption_status) {
354-
hdcp_work->encryption_status = query.encryption_status;
355-
schedule_work(&hdcp_work->property_update_work);
404+
if (!aconnector->base.state)
405+
continue;
406+
407+
query.encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
408+
mod_hdcp_query_display(&hdcp_work->hdcp, aconnector->base.index,
409+
&query);
410+
411+
DRM_DEBUG_DRIVER("[HDCP_DM] disp %d, connector->CP %u, (query, work): (%d, %d)\n",
412+
aconnector->base.index,
413+
aconnector->base.state->content_protection,
414+
query.encryption_status,
415+
hdcp_work->encryption_status[conn_index]);
416+
417+
if (query.encryption_status !=
418+
hdcp_work->encryption_status[conn_index]) {
419+
DRM_DEBUG_DRIVER("[HDCP_DM] encryption_status change from %x to %x\n",
420+
hdcp_work->encryption_status[conn_index], query.encryption_status);
421+
422+
hdcp_work->encryption_status[conn_index] =
423+
query.encryption_status;
424+
425+
DRM_DEBUG_DRIVER("[HDCP_DM] trigger property_update_work\n");
426+
427+
schedule_work(&hdcp_work->property_update_work);
428+
}
356429
}
357430

358431
mutex_unlock(&hdcp_work->mutex);
@@ -687,6 +760,13 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct
687760
hdcp_work[i].hdcp.config.ddc.funcs.read_i2c = lp_read_i2c;
688761
hdcp_work[i].hdcp.config.ddc.funcs.write_dpcd = lp_write_dpcd;
689762
hdcp_work[i].hdcp.config.ddc.funcs.read_dpcd = lp_read_dpcd;
763+
764+
memset(hdcp_work[i].aconnector, 0,
765+
sizeof(struct amdgpu_dm_connector *) *
766+
AMDGPU_DM_MAX_DISPLAY_INDEX);
767+
memset(hdcp_work[i].encryption_status, 0,
768+
sizeof(enum mod_hdcp_encryption_status) *
769+
AMDGPU_DM_MAX_DISPLAY_INDEX);
690770
}
691771

692772
cp_psp->funcs.update_stream_config = update_config;

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,15 @@ struct hdcp_workqueue {
4343
struct delayed_work callback_dwork;
4444
struct delayed_work watchdog_timer_dwork;
4545
struct delayed_work property_validate_dwork;
46-
struct amdgpu_dm_connector *aconnector;
46+
struct amdgpu_dm_connector *aconnector[AMDGPU_DM_MAX_DISPLAY_INDEX];
4747
struct mutex mutex;
4848

4949
struct mod_hdcp hdcp;
5050
struct mod_hdcp_output output;
5151
struct mod_hdcp_display display;
5252
struct mod_hdcp_link link;
5353

54-
enum mod_hdcp_encryption_status encryption_status;
55-
54+
enum mod_hdcp_encryption_status encryption_status[AMDGPU_DM_MAX_DISPLAY_INDEX];
5655
/* when display is unplugged from mst hub, connctor will be
5756
* destroyed within dm_dp_mst_connector_destroy. connector
5857
* hdcp perperties, like type, undesired, desired, enabled,

0 commit comments

Comments
 (0)