On Tue, Mar 15, 2022 at 03:21:05PM +0000, Lee, Shawn C wrote: > On Tuesday, March 15, 2022 8:33 PM, Nikula, Jani <jani.nik...@intel.com> > wrote: > >On Mon, 14 Mar 2022, Drew Davenport <ddavenp...@chromium.org> wrote: > >> On Mon, Mar 14, 2022 at 10:40:47AM +0200, Jani Nikula wrote: > >>> On Sun, 13 Mar 2022, Lee Shawn C <shawn.c....@intel.com> wrote: > >>> > drm_find_cea_extension() always look for a top level CEA block. > >>> > Pass ext_index from caller then this function to search next > >>> > available CEA ext block from a specific EDID block pointer. > >>> > > >>> > v2: save proper extension block index if CTA data information > >>> > was found in DispalyID block. > >>> > v3: using different parameters to store CEA and DisplayID block index. > >>> > configure DisplayID extansion block index before search available > >>> > DisplayID block. > >>> > > >>> > Cc: Jani Nikula <jani.nik...@linux.intel.com> > >>> > Cc: Ville Syrjala <ville.syrj...@linux.intel.com> > >>> > Cc: Ankit Nautiyal <ankit.k.nauti...@intel.com> > >>> > Cc: Drew Davenport <ddavenp...@chromium.org> > >>> > Cc: intel-gfx <intel-...@lists.freedesktop.org> > >>> > Signed-off-by: Lee Shawn C <shawn.c....@intel.com> > >>> > --- > >>> > drivers/gpu/drm/drm_displayid.c | 10 +++++-- > >>> > drivers/gpu/drm/drm_edid.c | 53 ++++++++++++++++++--------------- > >>> > include/drm/drm_displayid.h | 4 +-- > >>> > 3 files changed, 39 insertions(+), 28 deletions(-) > >>> > > >>> > diff --git a/drivers/gpu/drm/drm_displayid.c > >>> > b/drivers/gpu/drm/drm_displayid.c index 32da557b960f..31c3e6d7d549 > >>> > 100644 > >>> > --- a/drivers/gpu/drm/drm_displayid.c > >>> > +++ b/drivers/gpu/drm/drm_displayid.c > >>> > @@ -59,11 +59,14 @@ static const u8 > >>> > *drm_find_displayid_extension(const struct edid *edid, } > >>> > > >>> > void displayid_iter_edid_begin(const struct edid *edid, > >>> > - struct displayid_iter *iter) > >>> > + struct displayid_iter *iter, int > >>> > *ext_index) > >>> > >>> Please don't do this. This just ruins the clean approach displayid > >>> iterator added. > >>> > >>> Instead of making the displayid iterator ugly, and leaking its > >>> abstractions, I'll repeat what I said should be done in reply to the > >>> very first version of this patch series [1]: > >>> > >>> "I think we're going to need abstracted EDID iteration similar to > >>> what I've done for DisplayID iteration. We can't have all places > >>> reimplementing the iteration like we have now." > >>> > >>> This isn't a problem that should be solved by having all the callers > >>> hold a bunch of local variables and pass them around to all the > >>> functions. Nobody's going to be able to keep track of this anymore. > >>> And this series, as it is, makes it harder to fix this properly later on. > >> > >> I missed your original review comment, so apologies for repeating what > >> you said there already. > >> > >> I'd agree that passing a starting index to the displayid_iter_* > >> functions is probably not the right direction here. More thoughts below. > >> > >>> > >>> > >>> BR, > >>> Jani. > >>> > >>> > >>> [1] https://lore.kernel.org/r/87czjf8dik....@intel.com > >>> > >>> > >>> > >>> > { > >>> > memset(iter, 0, sizeof(*iter)); > >>> > > >>> > iter->edid = edid; > >>> > + > >>> > + if (ext_index) > >>> > + iter->ext_index = *ext_index; > >>> > } > >>> > > >>> > static const struct displayid_block * @@ -126,7 +129,10 @@ > >>> > __displayid_iter_next(struct displayid_iter *iter) > >>> > } > >>> > } > >>> > > >>> > -void displayid_iter_end(struct displayid_iter *iter) > >>> > +void displayid_iter_end(struct displayid_iter *iter, int > >>> > +*ext_index) > >>> > { > >>> > + if (ext_index) > >>> > + *ext_index = iter->ext_index; > >>> > + > >>> > memset(iter, 0, sizeof(*iter)); > >>> > } > >>> > diff --git a/drivers/gpu/drm/drm_edid.c > >>> > b/drivers/gpu/drm/drm_edid.c index 561f53831e29..78c415aa6889 > >>> > 100644 > >>> > --- a/drivers/gpu/drm/drm_edid.c > >>> > +++ b/drivers/gpu/drm/drm_edid.c > >>> > @@ -3353,28 +3353,27 @@ const u8 *drm_find_edid_extension(const struct > >>> > edid *edid, > >>> > return edid_ext; > >>> > } > >>> > > >>> > -static const u8 *drm_find_cea_extension(const struct edid *edid) > >>> > +static const u8 *drm_find_cea_extension(const struct edid *edid, > >>> > + int *cea_ext_index, int > >>> > *displayid_ext_index) > >> > >> As discussed above, passing both indices into this function may not be > >> the best approach here. But I think we need to keep track of some kind > >> of state in order to know which was the last CEA block that was > >> returned, and thus this function can return the next one after that, > >> whether it's in the CEA extension block or DisplayID block. > > > >Per DisplayID v1.3 Appendix B: DisplayID as an EDID Extension, it's > >recommended that DisplayID extensions are exposed after all of the CEA > >extensions. > > > >I think it should be fine to first iterate over all CEA extensions across > >the EDID, followed by iterating over all the DisplayID extensions. No need > >to keep track of the order between CEA and DisplayID, as the former should > >precede the latter. > > > > Refer to "DisplayID extensions are exposed after all of the CEA extensions". > It looks to me patch v5 is able to support this. And did not touch DisplayID > iterator. > https://patchwork.freedesktop.org/series/100690/#rev5
Patch v5 does not iterate over all the DisplayID extensions, and it has the previously mentioned problem about resulting in a possible infinite loop when depending on ext_index to iterate over the CEA extensions. > > >> What do you think of using the pointer returned from this function as > >> that state? The caller could pass in a u8* that was returned from a > >> previous call. This function would iterate through the extension > >> blocks and skip the CEA blocks it finds until it finds the passed in > >> pointer, and then return the next one after (or NULL). > >> > >> An alternative might be to create a linked list of ptrs to the edid > >> extension blocks, and allow a caller to iterate over them in whatever > >> way they need, but I'm not sure how useful that is elsewhere. > > > >I think the main problem here is trying to hack a for loop around > >drm_find_cea_extension() and drm_find_edid_extension(), and duplicating that > >all over the place, without adding more structure or abstractions. > > > >Contrast with displayid_iter_edid_begin(), displayid_iter_for_each(), and > >displayid_iter_end() and their usage. They hide all the complexity of > >looping across DisplayID data blocks inside EDID extensions, and none of the > >users need to be aware of that complexity. All the state is hidden in struct > >displayid_iter, and the users don't need to look inside. No allocations, no > >linked lists. > > > >I think it's particularly bad to have the changes here break the > >abstractions in displayid_iter_*, especially because they should be usable > >for pure DisplayID 2.0 *without* an EDID block structure. They'll just need > >a displayid_iter_begin() for pure DisplayID and some internal changes. > > > >Looking at the usage, the iteration should probably be done at the CEA data > >block level, something like this: > > > > struct cea_iter iter; > > const struct cea_block *block; > > > > cea_iter_edid_begin(edid, &iter); > > cea_iter_for_each(block, &iter) { > > /* ... */ > > } > > cea_iter_end(&iter); > > > >This would replace cea_db_offsets() and for_each_cea_db(), and would iterate > >across the all CEA and DisplayID extensions in the entire EDID. > > > >This looks usable, and then you'd start figuring out how to implement that, > >instead of trying to retrofit all the existing usages to abstractions that > >don't cut it. You'll probably need an EDID extension iterator too, and then > >use that and __displayid_iter_next() within > >cea_iter_for_each() i.e. you'd embed the edid_iter and displayid_iter within > >struct cea_iter. Exhaust the former first, and then the latter. > > > > > >BR, > >Jani. > > > > Hi Jani, Drew, thank you all for your comment! Agree that edid driver may need > abstracted EDID iteration similar to what you did for DisplayID iteration. > It will need a lot of code changes in drm driver. > > But, we have a tight schedule and have to meet HDMI 2.1 compliance test > requirement. > Do you think this series can be a short term solution to pass HDMI CTS test? > And we can have another long term plan to work on your opinion to modify > the iterator and make edid driver more efficient and easier to maintain. > > Best regards, > Shawn > > > > >> > >>> > { > >>> > const struct displayid_block *block; > >>> > struct displayid_iter iter; > >>> > const u8 *cea; > >>> > - int ext_index = 0; > >>> > > >>> > - /* Look for a top level CEA extension block */ > >>> > - /* FIXME: make callers iterate through multiple CEA ext blocks? > >>> > */ > >>> > - cea = drm_find_edid_extension(edid, CEA_EXT, &ext_index); > >>> > + /* Look for a CEA extension block from ext_index */ > >>> > + cea = drm_find_edid_extension(edid, CEA_EXT, cea_ext_index); > >>> > if (cea) > >>> > return cea; > >>> > > >>> > /* CEA blocks can also be found embedded in a DisplayID block */ > >>> > - displayid_iter_edid_begin(edid, &iter); > >>> > + displayid_iter_edid_begin(edid, &iter, displayid_ext_index); > >>> > displayid_iter_for_each(block, &iter) { > >>> > if (block->tag == DATA_BLOCK_CTA) { > >>> > cea = (const u8 *)block; > >>> > break; > >>> > } > >>> > } > >>> > - displayid_iter_end(&iter); > >>> > + displayid_iter_end(&iter, displayid_ext_index); > >>> > > >>> > return cea; > >>> > } > >>> > @@ -3643,10 +3642,10 @@ add_alternate_cea_modes(struct drm_connector > >>> > *connector, struct edid *edid) > >>> > struct drm_device *dev = connector->dev; > >>> > struct drm_display_mode *mode, *tmp; > >>> > LIST_HEAD(list); > >>> > - int modes = 0; > >>> > + int modes = 0, cea_ext_index = 0, displayid_ext_index = 0; > >>> > > >>> > /* Don't add CEA modes if the CEA extension block is missing */ > >>> > - if (!drm_find_cea_extension(edid)) > >>> > + if (!drm_find_cea_extension(edid, &cea_ext_index, > >>> > +&displayid_ext_index)) > >>> > return 0; > >>> > > >>> > /* > >>> > @@ -4321,11 +4320,11 @@ static void > >>> > drm_parse_y420cmdb_bitmap(struct drm_connector *connector, static > >>> > int add_cea_modes(struct drm_connector *connector, struct edid > >>> > *edid) { > >>> > - const u8 *cea = drm_find_cea_extension(edid); > >>> > - const u8 *db, *hdmi = NULL, *video = NULL; > >>> > + const u8 *cea, *db, *hdmi = NULL, *video = NULL; > >>> > u8 dbl, hdmi_len, video_len = 0; > >>> > - int modes = 0; > >>> > + int modes = 0, cea_ext_index = 0, displayid_ext_index = 0; > >>> > > >>> > + cea = drm_find_cea_extension(edid, &cea_ext_index, > >>> > +&displayid_ext_index); > >>> > if (cea && cea_revision(cea) >= 3) { > >>> > int i, start, end; > >>> > > >>> > @@ -4563,6 +4562,7 @@ static void drm_edid_to_eld(struct drm_connector > >>> > *connector, struct edid *edid) > >>> > const u8 *cea; > >>> > const u8 *db; > >>> > int total_sad_count = 0; > >>> > + int cea_ext_index = 0, displayid_ext_index = 0; > >>> > int mnl; > >>> > int dbl; > >>> > > >>> > @@ -4571,7 +4571,7 @@ static void drm_edid_to_eld(struct drm_connector > >>> > *connector, struct edid *edid) > >>> > if (!edid) > >>> > return; > >>> > > >>> > - cea = drm_find_cea_extension(edid); > >>> > + cea = drm_find_cea_extension(edid, &cea_ext_index, > >>> > +&displayid_ext_index); > >>> > if (!cea) { > >>> > DRM_DEBUG_KMS("ELD: no CEA Extension found\n"); > >>> > return; > >>> > @@ -4657,9 +4657,10 @@ int drm_edid_to_sad(struct edid *edid, > >>> > struct cea_sad **sads) { > >>> > int count = 0; > >>> > int i, start, end, dbl; > >>> > + int cea_ext_index = 0, displayid_ext_index = 0; > >>> > const u8 *cea; > >>> > > >>> > - cea = drm_find_cea_extension(edid); > >>> > + cea = drm_find_cea_extension(edid, &cea_ext_index, > >>> > +&displayid_ext_index); > >>> > if (!cea) { > >>> > DRM_DEBUG_KMS("SAD: no CEA Extension found\n"); > >>> > return 0; > >>> > @@ -4719,9 +4720,10 @@ int drm_edid_to_speaker_allocation(struct > >>> > edid *edid, u8 **sadb) { > >>> > int count = 0; > >>> > int i, start, end, dbl; > >>> > + int cea_ext_index = 0, displayid_ext_index = 0; > >>> > const u8 *cea; > >>> > > >>> > - cea = drm_find_cea_extension(edid); > >>> > + cea = drm_find_cea_extension(edid, &cea_ext_index, > >>> > +&displayid_ext_index); > >>> > if (!cea) { > >>> > DRM_DEBUG_KMS("SAD: no CEA Extension found\n"); > >>> > return 0; > >>> > @@ -4815,8 +4817,9 @@ bool drm_detect_hdmi_monitor(struct edid *edid) > >>> > const u8 *edid_ext; > >>> > int i; > >>> > int start_offset, end_offset; > >>> > + int cea_ext_index = 0, displayid_ext_index = 0; > >>> > > >>> > - edid_ext = drm_find_cea_extension(edid); > >>> > + edid_ext = drm_find_cea_extension(edid, &cea_ext_index, > >>> > +&displayid_ext_index); > >>> > if (!edid_ext) > >>> > return false; > >>> > > >>> > @@ -4854,8 +4857,9 @@ bool drm_detect_monitor_audio(struct edid *edid) > >>> > int i, j; > >>> > bool has_audio = false; > >>> > int start_offset, end_offset; > >>> > + int cea_ext_index = 0, displayid_ext_index = 0; > >>> > > >>> > - edid_ext = drm_find_cea_extension(edid); > >>> > + edid_ext = drm_find_cea_extension(edid, &cea_ext_index, > >>> > +&displayid_ext_index); > >>> > if (!edid_ext) > >>> > goto end; > >>> > > >>> > @@ -5178,8 +5182,9 @@ static void drm_parse_cea_ext(struct > >>> > drm_connector *connector, > >>> > struct drm_display_info *info = &connector->display_info; > >>> > const u8 *edid_ext; > >>> > int i, start, end; > >>> > + int cea_ext_index = 0, displayid_ext_index = 0; > >>> > > >>> > - edid_ext = drm_find_cea_extension(edid); > >>> > + edid_ext = drm_find_cea_extension(edid, &cea_ext_index, > >>> > +&displayid_ext_index); > >>> > if (!edid_ext) > >>> > return; > >>> > > >>> > @@ -5311,12 +5316,12 @@ static void drm_update_mso(struct drm_connector > >>> > *connector, const struct edid *e > >>> > const struct displayid_block *block; > >>> > struct displayid_iter iter; > >>> > > >>> > - displayid_iter_edid_begin(edid, &iter); > >>> > + displayid_iter_edid_begin(edid, &iter, NULL); > >>> > displayid_iter_for_each(block, &iter) { > >>> > if (block->tag == DATA_BLOCK_2_VENDOR_SPECIFIC) > >>> > drm_parse_vesa_mso_data(connector, block); > >>> > } > >>> > - displayid_iter_end(&iter); > >>> > + displayid_iter_end(&iter, NULL); > >>> > } > >>> > > >>> > /* A connector has no EDID information, so we've got no EDID to > >>> > compute quirks from. Reset @@ -5516,13 +5521,13 @@ static int > >>> > add_displayid_detailed_modes(struct drm_connector *connector, > >>> > struct displayid_iter iter; > >>> > int num_modes = 0; > >>> > > >>> > - displayid_iter_edid_begin(edid, &iter); > >>> > + displayid_iter_edid_begin(edid, &iter, NULL); > >>> > displayid_iter_for_each(block, &iter) { > >>> > if (block->tag == DATA_BLOCK_TYPE_1_DETAILED_TIMING || > >>> > block->tag == DATA_BLOCK_2_TYPE_7_DETAILED_TIMING) > >>> > num_modes += > >>> > add_displayid_detailed_1_modes(connector, block); > >>> > } > >>> > - displayid_iter_end(&iter); > >>> > + displayid_iter_end(&iter, NULL); > >>> > > >>> > return num_modes; > >>> > } > >>> > @@ -6164,12 +6169,12 @@ void drm_update_tile_info(struct > >>> > drm_connector *connector, > >>> > > >>> > connector->has_tile = false; > >>> > > >>> > - displayid_iter_edid_begin(edid, &iter); > >>> > + displayid_iter_edid_begin(edid, &iter, NULL); > >>> > displayid_iter_for_each(block, &iter) { > >>> > if (block->tag == DATA_BLOCK_TILED_DISPLAY) > >>> > drm_parse_tiled_block(connector, block); > >>> > } > >>> > - displayid_iter_end(&iter); > >>> > + displayid_iter_end(&iter, NULL); > >>> > > >>> > if (!connector->has_tile && connector->tile_group) { > >>> > drm_mode_put_tile_group(connector->dev, > >>> > connector->tile_group); > >>> > diff --git a/include/drm/drm_displayid.h > >>> > b/include/drm/drm_displayid.h index 7ffbd9f7bfc7..15442a161c11 > >>> > 100644 > >>> > --- a/include/drm/drm_displayid.h > >>> > +++ b/include/drm/drm_displayid.h > >>> > @@ -150,11 +150,11 @@ struct displayid_iter { }; > >>> > > >>> > void displayid_iter_edid_begin(const struct edid *edid, > >>> > - struct displayid_iter *iter); > >>> > + struct displayid_iter *iter, int > >>> > *ext_index); > >>> > const struct displayid_block * > >>> > __displayid_iter_next(struct displayid_iter *iter); #define > >>> > displayid_iter_for_each(__block, __iter) \ > >>> > while (((__block) = __displayid_iter_next(__iter))) -void > >>> > displayid_iter_end(struct displayid_iter *iter); > >>> > +void displayid_iter_end(struct displayid_iter *iter, int > >>> > +*ext_index); > >>> > > >>> > #endif > >>> > >>> -- > >>> Jani Nikula, Intel Open Source Graphics Center > > > >-- > >Jani Nikula, Intel Open Source Graphics Center