At Mon, 19 Nov 2012 15:23:11 -0500, "Egbert Eich " <"eich@xxxxxxxxxx> wrote: > > According the the VESA specs there can be up to 254 EEDID extension blocks. > Since we may read the EDID (including extensions) in 10 second intervals to > probe for display hotplugging (at least in cases where no hardware hotplug > detection exists) and I2C transfer is rather slow we may end up consuming > a considerable amount on CPU time for just that. > This patch caches the EDID block if it contains at least one extension. > To determine if the blocks match we only tranfer the base block, on a match > we use the cached data. > > Signed-off-by: Egbert Eich <eich@xxxxxxx> > --- > drivers/gpu/drm/drm_crtc.c | 1 + > drivers/gpu/drm/drm_edid.c | 43 ++++++++++++++++++++++++++++++++++++++++++- > include/drm/drm_crtc.h | 1 + > include/drm/drm_edid.h | 1 + > 4 files changed, 45 insertions(+), 1 deletions(-) > > diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c > index 3533609..e283355 100644 > --- a/drivers/gpu/drm/drm_crtc.c > +++ b/drivers/gpu/drm/drm_crtc.c > @@ -598,6 +598,7 @@ void drm_connector_cleanup(struct drm_connector *connector) > drm_mode_remove(connector, mode); > > mutex_lock(&dev->mode_config.mutex); > + drm_cache_edid(connector, NULL); > drm_mode_object_put(dev, &connector->base); > list_del(&connector->head); > dev->mode_config.num_connector--; > diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c > index 3e7df61..410a54d 100644 > --- a/drivers/gpu/drm/drm_edid.c > +++ b/drivers/gpu/drm/drm_edid.c > @@ -431,6 +431,41 @@ fixup_edid(u8 **blockp, int valid_extensions) > return (new ? valid_extensions : -ENOMEM); > } > > +static bool > +compare_get_edid_from_cache(struct drm_connector *connector, struct edid **edidp) > +{ > + if (connector->edid_cache && > + connector->edid_cache->prod_code[0] == (*edidp)->prod_code[0] && > + connector->edid_cache->prod_code[1] == (*edidp)->prod_code[1] && > + connector->edid_cache->serial == (*edidp)->serial && > + connector->edid_cache->input == (*edidp)->input) { > + int size = (connector->edid_cache->extensions + 1) * EDID_LENGTH; > + struct edid *new = kmalloc(size, GFP_KERNEL); > + if (!new) > + return false; > + DRM_DEBUG_KMS("Got EDID for %s from cache.\n",drm_get_connector_name(connector)); > + memcpy(new, connector->edid_cache, size); > + kfree(*edidp); You can use kmemdup(). > + *edidp = new; > + return true; > + } > + return false; > +} > + > +void > +drm_cache_edid(struct drm_connector *connector, struct edid *edid) > +{ > + struct edid *new = NULL; > + kfree(connector->edid_cache); > + if (edid) { > + int size = (edid->extensions + 1) * EDID_LENGTH; > + new = kmalloc(size, GFP_KERNEL); > + if (new) > + memcpy(new, edid, size); Ditto. Takashi > + } > + connector->edid_cache = new; > +} > + > static u8 * > drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) > { > @@ -462,10 +497,14 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) > if (i == 4) > goto carp; > > - /* if there's no extensions, we're done */ > + /* if there are no extensions, we're done - don't bother caching */ > if (block[EDID_EXTENSION_FLAG_OFFSET] == 0) > return block; > > + /* see if EDID is in the cache - no need to read all extension blocks */ > + if (compare_get_edid_from_cache(connector, (struct edid **)&block)) > + return block; > + > new = krealloc(block, (block[EDID_EXTENSION_FLAG_OFFSET] + 1) * EDID_LENGTH, GFP_KERNEL); > if (!new) > goto out; > @@ -505,6 +544,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) > > no_more: > fixup_edid(&block, valid_extensions); > + drm_cache_edid(connector, (struct edid *)block); > > return block; > > @@ -513,6 +553,7 @@ carp: > dev_warn(connector->dev->dev, "%s: EDID block %d invalid.\n", > drm_get_connector_name(connector), j); > } > + drm_cache_edid(connector, NULL); > connector->bad_edid_counter++; > > out: > diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h > index 49dd8c2..6a1054c 100644 > --- a/include/drm/drm_crtc.h > +++ b/include/drm/drm_crtc.h > @@ -601,6 +601,7 @@ struct drm_connector { > struct drm_encoder *encoder; /* currently active encoder */ > > /* EDID bits */ > + struct edid *edid_cache; > uint8_t eld[MAX_ELD_BYTES]; > bool dvi_dual; > int max_tmds_clock; /* in MHz */ > diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h > index 53c619c..c880510 100644 > --- a/include/drm/drm_edid.h > +++ b/include/drm/drm_edid.h > @@ -256,5 +256,6 @@ struct drm_connector *drm_select_eld(struct drm_encoder *encoder, > struct edid *drm_load_edid_firmware(struct drm_connector *connector); > #endif > int drm_validate_edid_blob(struct drm_connector *connector, u8 **blockp, int len); > +void drm_cache_edid(struct drm_connector *connector, struct edid *edid); > > #endif /* __DRM_EDID_H__ */ > -- > 1.7.7 > _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel