Skip to content

Commit 90b575f

Browse files
committed
drm/edid: detach debugfs EDID override from EDID property update
Having the EDID override debugfs directly update the EDID property is problematic. The update is partial only. The driver has no way of knowing it's been updated. Mode list is not updated. It's an inconsistent state. Detach debugfs EDID override from the property update completely. Only set and reset a separate override EDID copy from debugfs, and have it take effect only at detect (via EDID read). The copy is at connector->edid_override, protected by connector->edid_override_mutex. This also brings override EDID closer to firmware EDID in behaviour. Add validation of the override EDID which we completely lacked. Note that IGT already forces a detect whenever tests update the override EDID. v2: Add locking (Ville) Signed-off-by: Jani Nikula <[email protected]> Reviewed-by: Ville Syrjälä <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/4c875f8e06c4499f498fcf876e1233cbb155ec8a.1666614699.git.jani.nikula@intel.com
1 parent 6c9b3db commit 90b575f

File tree

3 files changed

+49
-41
lines changed

3 files changed

+49
-41
lines changed

drivers/gpu/drm/drm_connector.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ static int __drm_connector_init(struct drm_device *dev,
274274
INIT_LIST_HEAD(&connector->probed_modes);
275275
INIT_LIST_HEAD(&connector->modes);
276276
mutex_init(&connector->mutex);
277+
mutex_init(&connector->edid_override_mutex);
277278
connector->edid_blob_ptr = NULL;
278279
connector->epoch_counter = 0;
279280
connector->tile_blob_ptr = NULL;

drivers/gpu/drm/drm_edid.c

Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2207,8 +2207,12 @@ static struct edid *drm_get_override_edid(struct drm_connector *connector,
22072207
{
22082208
struct edid *override = NULL;
22092209

2210-
if (connector->override_edid)
2211-
override = drm_edid_duplicate(connector->edid_blob_ptr->data);
2210+
mutex_lock(&connector->edid_override_mutex);
2211+
2212+
if (connector->edid_override)
2213+
override = drm_edid_duplicate(connector->edid_override->edid);
2214+
2215+
mutex_unlock(&connector->edid_override_mutex);
22122216

22132217
if (!override)
22142218
override = drm_load_edid_firmware(connector);
@@ -2223,10 +2227,15 @@ static struct edid *drm_get_override_edid(struct drm_connector *connector,
22232227
/* For debugfs edid_override implementation */
22242228
int drm_edid_override_show(struct drm_connector *connector, struct seq_file *m)
22252229
{
2226-
struct drm_property_blob *edid = connector->edid_blob_ptr;
2230+
const struct drm_edid *drm_edid;
22272231

2228-
if (connector->override_edid && edid)
2229-
seq_write(m, edid->data, edid->length);
2232+
mutex_lock(&connector->edid_override_mutex);
2233+
2234+
drm_edid = connector->edid_override;
2235+
if (drm_edid)
2236+
seq_write(m, drm_edid->edid, drm_edid->size);
2237+
2238+
mutex_unlock(&connector->edid_override_mutex);
22302239

22312240
return 0;
22322241
}
@@ -2235,32 +2244,43 @@ int drm_edid_override_show(struct drm_connector *connector, struct seq_file *m)
22352244
int drm_edid_override_set(struct drm_connector *connector, const void *edid,
22362245
size_t size)
22372246
{
2238-
int ret;
2247+
const struct drm_edid *drm_edid;
22392248

2240-
if (size < EDID_LENGTH || edid_size(edid) > size)
2249+
drm_edid = drm_edid_alloc(edid, size);
2250+
if (!drm_edid_valid(drm_edid)) {
2251+
drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] EDID override invalid\n",
2252+
connector->base.id, connector->name);
2253+
drm_edid_free(drm_edid);
22412254
return -EINVAL;
2242-
2243-
connector->override_edid = false;
2255+
}
22442256

22452257
drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] EDID override set\n",
22462258
connector->base.id, connector->name);
22472259

2248-
ret = drm_connector_update_edid_property(connector, edid);
2249-
if (!ret)
2250-
connector->override_edid = true;
2260+
mutex_lock(&connector->edid_override_mutex);
22512261

2252-
return ret;
2262+
drm_edid_free(connector->edid_override);
2263+
connector->edid_override = drm_edid;
2264+
2265+
mutex_unlock(&connector->edid_override_mutex);
2266+
2267+
return 0;
22532268
}
22542269

22552270
/* For debugfs edid_override implementation */
22562271
int drm_edid_override_reset(struct drm_connector *connector)
22572272
{
2258-
connector->override_edid = false;
2259-
22602273
drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] EDID override reset\n",
22612274
connector->base.id, connector->name);
22622275

2263-
return drm_connector_update_edid_property(connector, NULL);
2276+
mutex_lock(&connector->edid_override_mutex);
2277+
2278+
drm_edid_free(connector->edid_override);
2279+
connector->edid_override = NULL;
2280+
2281+
mutex_unlock(&connector->edid_override_mutex);
2282+
2283+
return 0;
22642284
}
22652285

22662286
/**
@@ -6634,23 +6654,6 @@ int drm_edid_connector_update(struct drm_connector *connector,
66346654
{
66356655
int count;
66366656

6637-
/*
6638-
* FIXME: Reconcile the differences in override_edid handling between
6639-
* this and drm_connector_update_edid_property().
6640-
*
6641-
* If override_edid is set, and the EDID passed in here originates from
6642-
* drm_edid_read() and friends, it will be the override EDID, and there
6643-
* are no issues. drm_connector_update_edid_property() ignoring requests
6644-
* to set the EDID dates back to a time when override EDID was not
6645-
* handled at the low level EDID read.
6646-
*
6647-
* The only way the EDID passed in here can be different from the
6648-
* override EDID is when a driver passes in an EDID that does *not*
6649-
* originate from drm_edid_read() and friends, or passes in a stale
6650-
* cached version. This, in turn, is a question of when an override EDID
6651-
* set via debugfs should take effect.
6652-
*/
6653-
66546657
count = _drm_edid_connector_update(connector, drm_edid);
66556658

66566659
_drm_update_tile_info(connector, drm_edid);
@@ -6665,10 +6668,6 @@ EXPORT_SYMBOL(drm_edid_connector_update);
66656668
static int _drm_connector_update_edid_property(struct drm_connector *connector,
66666669
const struct drm_edid *drm_edid)
66676670
{
6668-
/* ignore requests to set edid when overridden */
6669-
if (connector->override_edid)
6670-
return 0;
6671-
66726671
/*
66736672
* Set the display info, using edid if available, otherwise resetting
66746673
* the values to defaults. This duplicates the work done in

include/drm/drm_connector.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1550,12 +1550,20 @@ struct drm_connector {
15501550
struct drm_cmdline_mode cmdline_mode;
15511551
/** @force: a DRM_FORCE_<foo> state for forced mode sets */
15521552
enum drm_connector_force force;
1553+
1554+
/**
1555+
* @edid_override: Override EDID set via debugfs.
1556+
*
1557+
* Do not modify or access outside of the drm_edid_override_* family of
1558+
* functions.
1559+
*/
1560+
const struct drm_edid *edid_override;
1561+
15531562
/**
1554-
* @override_edid: has the EDID been overwritten through debugfs for
1555-
* testing? Do not modify outside of drm_edid_override_set() and
1556-
* drm_edid_override_reset().
1563+
* @edid_override_mutex: Protect access to edid_override.
15571564
*/
1558-
bool override_edid;
1565+
struct mutex edid_override_mutex;
1566+
15591567
/** @epoch_counter: used to detect any other changes in connector, besides status */
15601568
u64 epoch_counter;
15611569

0 commit comments

Comments
 (0)