Skip to content

Commit a7d5eea

Browse files
Sean Andersontomba
authored andcommitted
drm: zynqmp_dp: Add locking
Add some locking to prevent the IRQ/workers/bridge API calls from stepping on each other's toes. This lock protects: - Non-atomic registers configuring the link. That is, everything but the IRQ registers (since these are accessed in an atomic fashion), and the DP AUX registers (since these don't affect the link). We also access AUX while holding this lock, so it would be very tricky to support. - Link configuration. This is effectively everything in zynqmp_dp which isn't read-only after probe time. So from next_bridge onward. This lock is designed to protect configuration changes so we don't have to do anything tricky. Configuration should never be in the hot path, so I'm not worried about performance. Signed-off-by: Sean Anderson <sean.anderson@linux.dev> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240809193600.3360015-3-sean.anderson@linux.dev
1 parent 2e07c88 commit a7d5eea

1 file changed

Lines changed: 18 additions & 0 deletions

File tree

drivers/gpu/drm/xlnx/zynqmp_dp.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ struct zynqmp_dp_config {
280280
* @dpsub: Display subsystem
281281
* @iomem: device I/O memory for register access
282282
* @reset: reset controller
283+
* @lock: Mutex protecting this struct and register access (but not AUX)
283284
* @irq: irq
284285
* @bridge: DRM bridge for the DP encoder
285286
* @next_bridge: The downstream bridge
@@ -294,11 +295,16 @@ struct zynqmp_dp_config {
294295
* @link_config: common link configuration between IP core and sink device
295296
* @mode: current mode between IP core and sink device
296297
* @train_set: set of training data
298+
*
299+
* @lock covers the link configuration in this struct and the device's
300+
* registers. It does not cover @aux. It is not strictly required for any of
301+
* the members which are only modified at probe/remove time (e.g. @dev).
297302
*/
298303
struct zynqmp_dp {
299304
struct drm_dp_aux aux;
300305
struct drm_bridge bridge;
301306
struct work_struct hpd_work;
307+
struct mutex lock;
302308

303309
struct drm_bridge *next_bridge;
304310
struct device *dev;
@@ -1386,8 +1392,10 @@ zynqmp_dp_bridge_mode_valid(struct drm_bridge *bridge,
13861392
}
13871393

13881394
/* Check with link rate and lane count */
1395+
mutex_lock(&dp->lock);
13891396
rate = zynqmp_dp_max_rate(dp->link_config.max_rate,
13901397
dp->link_config.max_lanes, dp->config.bpp);
1398+
mutex_unlock(&dp->lock);
13911399
if (mode->clock > rate) {
13921400
dev_dbg(dp->dev, "filtered mode %s for high pixel rate\n",
13931401
mode->name);
@@ -1414,6 +1422,7 @@ static void zynqmp_dp_bridge_atomic_enable(struct drm_bridge *bridge,
14141422

14151423
pm_runtime_get_sync(dp->dev);
14161424

1425+
mutex_lock(&dp->lock);
14171426
zynqmp_dp_disp_enable(dp, old_bridge_state);
14181427

14191428
/*
@@ -1474,13 +1483,15 @@ static void zynqmp_dp_bridge_atomic_enable(struct drm_bridge *bridge,
14741483
zynqmp_dp_write(dp, ZYNQMP_DP_SOFTWARE_RESET,
14751484
ZYNQMP_DP_SOFTWARE_RESET_ALL);
14761485
zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_ENABLE, 1);
1486+
mutex_unlock(&dp->lock);
14771487
}
14781488

14791489
static void zynqmp_dp_bridge_atomic_disable(struct drm_bridge *bridge,
14801490
struct drm_bridge_state *old_bridge_state)
14811491
{
14821492
struct zynqmp_dp *dp = bridge_to_dp(bridge);
14831493

1494+
mutex_lock(&dp->lock);
14841495
dp->enabled = false;
14851496
cancel_work(&dp->hpd_work);
14861497
zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_ENABLE, 0);
@@ -1491,6 +1502,7 @@ static void zynqmp_dp_bridge_atomic_disable(struct drm_bridge *bridge,
14911502
zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 0);
14921503

14931504
zynqmp_dp_disp_disable(dp, old_bridge_state);
1505+
mutex_unlock(&dp->lock);
14941506

14951507
pm_runtime_put_sync(dp->dev);
14961508
}
@@ -1533,6 +1545,8 @@ static enum drm_connector_status zynqmp_dp_bridge_detect(struct drm_bridge *brid
15331545
u32 state, i;
15341546
int ret;
15351547

1548+
mutex_lock(&dp->lock);
1549+
15361550
/*
15371551
* This is from heuristic. It takes some delay (ex, 100 ~ 500 msec) to
15381552
* get the HPD signal with some monitors.
@@ -1560,11 +1574,13 @@ static enum drm_connector_status zynqmp_dp_bridge_detect(struct drm_bridge *brid
15601574
dp->num_lanes);
15611575

15621576
dp->status = connector_status_connected;
1577+
mutex_unlock(&dp->lock);
15631578
return connector_status_connected;
15641579
}
15651580

15661581
disconnected:
15671582
dp->status = connector_status_disconnected;
1583+
mutex_unlock(&dp->lock);
15681584
return connector_status_disconnected;
15691585
}
15701586

@@ -1725,6 +1741,7 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub)
17251741
dp->dev = &pdev->dev;
17261742
dp->dpsub = dpsub;
17271743
dp->status = connector_status_disconnected;
1744+
mutex_init(&dp->lock);
17281745

17291746
INIT_WORK(&dp->hpd_work, zynqmp_dp_hpd_work_func);
17301747

@@ -1838,4 +1855,5 @@ void zynqmp_dp_remove(struct zynqmp_dpsub *dpsub)
18381855

18391856
zynqmp_dp_phy_exit(dp);
18401857
zynqmp_dp_reset(dp, true);
1858+
mutex_destroy(&dp->lock);
18411859
}

0 commit comments

Comments
 (0)