Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/edid: use struct drm_edid for override/firmware EDID

There's a lot going on here, but the main thing is switching the
firmware EDID loader to use struct drm_edid. Unfortunately, it's
difficult to reasonably split to smaller pieces.

Convert the EDID loader to struct drm_edid. There's a functional change
in validation; it no longer tries to fix errors or filter invalid
blocks. It's stricter in this sense. Hopefully this will not be an
issue.

As a by-product, this change also allows HF-EEODB extended EDIDs to be
passed via override/firmware EDID.

Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/e64267c28eca483e83c802bc06ddd149bdcdfc66.1666614699.git.jani.nikula@intel.com

+37 -87
+17 -15
drivers/gpu/drm/drm_edid.c
··· 2202 2202 } 2203 2203 2204 2204 /* Get override or firmware EDID */ 2205 - static struct edid *drm_get_override_edid(struct drm_connector *connector, 2206 - size_t *alloc_size) 2205 + static const struct drm_edid *drm_edid_override_get(struct drm_connector *connector) 2207 2206 { 2208 - struct edid *override = NULL; 2207 + const struct drm_edid *override = NULL; 2209 2208 2210 2209 mutex_lock(&connector->edid_override_mutex); 2211 2210 2212 2211 if (connector->edid_override) 2213 - override = drm_edid_duplicate(connector->edid_override->edid); 2212 + override = drm_edid_dup(connector->edid_override); 2214 2213 2215 2214 mutex_unlock(&connector->edid_override_mutex); 2216 2215 2217 2216 if (!override) 2218 2217 override = drm_edid_load_firmware(connector); 2219 - 2220 - /* FIXME: Get alloc size from deeper down the stack */ 2221 - if (!IS_ERR_OR_NULL(override) && alloc_size) 2222 - *alloc_size = edid_size(override); 2223 2218 2224 2219 return IS_ERR(override) ? NULL : override; 2225 2220 } ··· 2291 2296 */ 2292 2297 int drm_edid_override_connector_update(struct drm_connector *connector) 2293 2298 { 2294 - struct edid *override; 2299 + const struct drm_edid *override; 2295 2300 int num_modes = 0; 2296 2301 2297 - override = drm_get_override_edid(connector, NULL); 2302 + override = drm_edid_override_get(connector); 2298 2303 if (override) { 2299 - drm_connector_update_edid_property(connector, override); 2300 - num_modes = drm_add_edid_modes(connector, override); 2301 - kfree(override); 2304 + num_modes = drm_edid_connector_update(connector, override); 2305 + 2306 + drm_edid_free(override); 2302 2307 2303 2308 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] adding %d modes via fallback override/firmware EDID\n", 2304 2309 connector->base.id, connector->name, num_modes); ··· 2349 2354 { 2350 2355 enum edid_block_status status; 2351 2356 int i, num_blocks, invalid_blocks = 0; 2357 + const struct drm_edid *override; 2352 2358 struct edid *edid, *new; 2353 2359 size_t alloc_size = EDID_LENGTH; 2354 2360 2355 - edid = drm_get_override_edid(connector, &alloc_size); 2356 - if (edid) 2361 + override = drm_edid_override_get(connector); 2362 + if (override) { 2363 + alloc_size = override->size; 2364 + edid = kmemdup(override->edid, alloc_size, GFP_KERNEL); 2365 + drm_edid_free(override); 2366 + if (!edid) 2367 + return NULL; 2357 2368 goto ok; 2369 + } 2358 2370 2359 2371 edid = kmalloc(alloc_size, GFP_KERNEL); 2360 2372 if (!edid)
+18 -70
drivers/gpu/drm/drm_edid_load.c
··· 159 159 }, 160 160 }; 161 161 162 - static int edid_size(const u8 *edid, int data_size) 163 - { 164 - if (data_size < EDID_LENGTH) 165 - return 0; 166 - 167 - return (edid[0x7e] + 1) * EDID_LENGTH; 168 - } 169 - 170 - static void *edid_load(struct drm_connector *connector, const char *name) 162 + static const struct drm_edid *edid_load(struct drm_connector *connector, const char *name) 171 163 { 172 164 const struct firmware *fw = NULL; 173 165 const u8 *fwdata; 174 - u8 *edid; 166 + const struct drm_edid *drm_edid; 175 167 int fwsize, builtin; 176 - int i, valid_extensions = 0; 177 - bool print_bad_edid = !connector->bad_edid_counter || drm_debug_enabled(DRM_UT_KMS); 178 168 179 169 builtin = match_string(generic_edid_name, GENERIC_EDIDS, name); 180 170 if (builtin >= 0) { ··· 193 203 fwsize = fw->size; 194 204 } 195 205 196 - if (edid_size(fwdata, fwsize) != fwsize) { 197 - DRM_ERROR("Size of EDID firmware \"%s\" is invalid " 198 - "(expected %d, got %d\n", name, 199 - edid_size(fwdata, fwsize), (int)fwsize); 200 - edid = ERR_PTR(-EINVAL); 201 - goto out; 206 + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Loaded %s firmware EDID \"%s\"\n", 207 + connector->base.id, connector->name, 208 + builtin >= 0 ? "built-in" : "external", name); 209 + 210 + drm_edid = drm_edid_alloc(fwdata, fwsize); 211 + if (!drm_edid_valid(drm_edid)) { 212 + drm_err(connector->dev, "Invalid firmware EDID \"%s\"\n", name); 213 + drm_edid_free(drm_edid); 214 + drm_edid = ERR_PTR(-EINVAL); 202 215 } 203 216 204 - edid = kmemdup(fwdata, fwsize, GFP_KERNEL); 205 - if (edid == NULL) { 206 - edid = ERR_PTR(-ENOMEM); 207 - goto out; 208 - } 209 - 210 - if (!drm_edid_block_valid(edid, 0, print_bad_edid, 211 - &connector->edid_corrupt)) { 212 - connector->bad_edid_counter++; 213 - DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ", 214 - name); 215 - kfree(edid); 216 - edid = ERR_PTR(-EINVAL); 217 - goto out; 218 - } 219 - 220 - for (i = 1; i <= edid[0x7e]; i++) { 221 - if (i != valid_extensions + 1) 222 - memcpy(edid + (valid_extensions + 1) * EDID_LENGTH, 223 - edid + i * EDID_LENGTH, EDID_LENGTH); 224 - if (drm_edid_block_valid(edid + i * EDID_LENGTH, i, 225 - print_bad_edid, 226 - NULL)) 227 - valid_extensions++; 228 - } 229 - 230 - if (valid_extensions != edid[0x7e]) { 231 - u8 *new_edid; 232 - 233 - edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions; 234 - DRM_INFO("Found %d valid extensions instead of %d in EDID data " 235 - "\"%s\" for connector \"%s\"\n", valid_extensions, 236 - edid[0x7e], name, connector->name); 237 - edid[0x7e] = valid_extensions; 238 - 239 - new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH, 240 - GFP_KERNEL); 241 - if (new_edid) 242 - edid = new_edid; 243 - } 244 - 245 - DRM_INFO("Got %s EDID base block and %d extension%s from " 246 - "\"%s\" for connector \"%s\"\n", (builtin >= 0) ? "built-in" : 247 - "external", valid_extensions, valid_extensions == 1 ? "" : "s", 248 - name, connector->name); 249 - 250 - out: 251 217 release_firmware(fw); 252 - return edid; 218 + 219 + return drm_edid; 253 220 } 254 221 255 - struct edid *drm_edid_load_firmware(struct drm_connector *connector) 222 + const struct drm_edid *drm_edid_load_firmware(struct drm_connector *connector) 256 223 { 257 224 char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL; 258 - struct edid *edid; 225 + const struct drm_edid *drm_edid; 259 226 260 227 if (edid_firmware[0] == '\0') 261 228 return ERR_PTR(-ENOENT); ··· 255 308 if (*last == '\n') 256 309 *last = '\0'; 257 310 258 - edid = edid_load(connector, edidname); 311 + drm_edid = edid_load(connector, edidname); 312 + 259 313 kfree(fwstr); 260 314 261 - return edid; 315 + return drm_edid; 262 316 }
+2 -2
include/drm/drm_edid.h
··· 388 388 const struct drm_display_mode *mode); 389 389 390 390 #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE 391 - struct edid *drm_edid_load_firmware(struct drm_connector *connector); 391 + const struct drm_edid *drm_edid_load_firmware(struct drm_connector *connector); 392 392 int __drm_set_edid_firmware_path(const char *path); 393 393 int __drm_get_edid_firmware_path(char *buf, size_t bufsize); 394 394 #else 395 - static inline struct edid * 395 + static inline const struct drm_edid * 396 396 drm_edid_load_firmware(struct drm_connector *connector) 397 397 { 398 398 return ERR_PTR(-ENOENT);