All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ander Conselvan De Oliveira <conselvan2@gmail.com>
To: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
	intel-gfx@lists.freedesktop.org
Subject: Re: [PATCH 08/13] drm/i915: Refactor platform specifics out of intel_get_shared_dpll()
Date: Fri, 04 Mar 2016 08:36:17 +0200	[thread overview]
Message-ID: <1457073377.2668.1.camel@gmail.com> (raw)
In-Reply-To: <56D84564.5050807@linux.intel.com>

On Thu, 2016-03-03 at 15:08 +0100, Maarten Lankhorst wrote:
> Op 26-02-16 om 14:54 schreef Ander Conselvan de Oliveira:
> > The function intel_get_shared_dpll() had a more or less generic
> > implementation with some platform specific checks to handle smaller
> > differences between platforms. However, the minimalist approach forces
> > bigger differences between platforms to be implemented outside of the
> > shared dpll code (see the *_ddi_pll_select() functions in intel_ddi.c,
> > for instance).
> > 
> > This patch changes the implementation of intel_get_share_dpll() so that
> > a completely platform specific version can be used, providing helpers to
> > reduce code duplication. This should allow the code from the ddi pll
> > select functions to be moved, and also make room for making more dplls
> > managed by the shared dpll infrastructure.
> > 
> > Signed-off-by: Ander Conselvan de Oliveira <
> > ander.conselvan.de.oliveira@intel.com>
> > ---
> >  drivers/gpu/drm/i915/i915_drv.h       |   1 +
> >  drivers/gpu/drm/i915/intel_dpll_mgr.c | 226 +++++++++++++++++++++----------
> > ---
> >  drivers/gpu/drm/i915/intel_dpll_mgr.h |   2 +
> >  3 files changed, 145 insertions(+), 84 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/i915_drv.h
> > b/drivers/gpu/drm/i915/i915_drv.h
> > index 6de93dc..b858801 100644
> > --- a/drivers/gpu/drm/i915/i915_drv.h
> > +++ b/drivers/gpu/drm/i915/i915_drv.h
> > @@ -1802,6 +1802,7 @@ struct drm_i915_private {
> >  	/* dpll and cdclk state is protected by connection_mutex */
> >  	int num_shared_dpll;
> >  	struct intel_shared_dpll shared_dplls[I915_NUM_PLLS];
> > +	const struct intel_dpll_mgr *dpll_mgr;
> >  
> >  	unsigned int active_crtcs;
> >  	unsigned int min_pixclk[I915_MAX_PIPES];
> > diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c
> > b/drivers/gpu/drm/i915/intel_dpll_mgr.c
> > index e88dc46..3553324 100644
> > --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
> > +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
> > @@ -174,66 +174,20 @@ void intel_disable_shared_dpll(struct intel_crtc
> > *crtc)
> >  	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
> >  }
> >  
> > -static enum intel_dpll_id
> > -ibx_get_fixed_dpll(struct intel_crtc *crtc,
> > -		   struct intel_crtc_state *crtc_state)
> > -{
> > -	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> > -	struct intel_shared_dpll *pll;
> > -	enum intel_dpll_id i;
> > -
> > -	/* Ironlake PCH has a fixed PLL->PCH pipe mapping. */
> > -	i = (enum intel_dpll_id) crtc->pipe;
> > -	pll = &dev_priv->shared_dplls[i];
> > -
> > -	DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
> > -		      crtc->base.base.id, pll->name);
> > -
> > -	return i;
> > -}
> > -
> > -static enum intel_dpll_id
> > -bxt_get_fixed_dpll(struct intel_crtc *crtc,
> > -		   struct intel_crtc_state *crtc_state)
> > -{
> > -	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> > -	struct intel_encoder *encoder;
> > -	struct intel_digital_port *intel_dig_port;
> > -	struct intel_shared_dpll *pll;
> > -	enum intel_dpll_id i;
> > -
> > -	/* PLL is attached to port in bxt */
> > -	encoder = intel_ddi_get_crtc_new_encoder(crtc_state);
> > -	if (WARN_ON(!encoder))
> > -		return DPLL_ID_PRIVATE;
> > -
> > -	intel_dig_port = enc_to_dig_port(&encoder->base);
> > -	/* 1:1 mapping between ports and PLLs */
> > -	i = (enum intel_dpll_id)intel_dig_port->port;
> > -	pll = &dev_priv->shared_dplls[i];
> > -	DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
> > -		crtc->base.base.id, pll->name);
> > -
> > -	return i;
> > -}
> > -
> > -static enum intel_dpll_id
> > +static struct intel_shared_dpll *
> >  intel_find_shared_dpll(struct intel_crtc *crtc,
> > -		       struct intel_crtc_state *crtc_state)
> > +		       struct intel_crtc_state *crtc_state,
> > +		       enum intel_dpll_id range_min,
> > +		       enum intel_dpll_id range_max)
> >  {
> >  	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> >  	struct intel_shared_dpll *pll;
> >  	struct intel_shared_dpll_config *shared_dpll;
> >  	enum intel_dpll_id i;
> > -	int max = dev_priv->num_shared_dpll;
> > -
> > -	if (INTEL_INFO(dev_priv)->gen < 9 && HAS_DDI(dev_priv))
> > -		/* Do not consider SPLL */
> > -		max = 2;
> >  
> >  	shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state
> > ->base.state);
> >  
> > -	for (i = 0; i < max; i++) {
> > +	for (i = range_min; i <= range_max; i++) {
> >  		pll = &dev_priv->shared_dplls[i];
> >  
> >  		/* Only want to check enabled timings first */
> > @@ -247,49 +201,33 @@ intel_find_shared_dpll(struct intel_crtc *crtc,
> >  				      crtc->base.base.id, pll->name,
> >  				      shared_dpll[i].crtc_mask,
> >  				      pll->active);
> > -			return i;
> > +			return pll;
> >  		}
> >  	}
> >  
> >  	/* Ok no matching timings, maybe there's a free one? */
> > -	for (i = 0; i < dev_priv->num_shared_dpll; i++) {
> > +	for (i = range_min; i <= range_max; i++) {
> >  		pll = &dev_priv->shared_dplls[i];
> >  		if (shared_dpll[i].crtc_mask == 0) {
> >  			DRM_DEBUG_KMS("CRTC:%d allocated %s\n",
> >  				      crtc->base.base.id, pll->name);
> > -			return i;
> > +			return pll;
> >  		}
> >  	}
> >  
> > -	return DPLL_ID_PRIVATE;
> > +	return NULL;
> >  }
> >  
> > -struct intel_shared_dpll *
> > -intel_get_shared_dpll(struct intel_crtc *crtc,
> > -		      struct intel_crtc_state *crtc_state)
> > +static void
> > +intel_reference_shared_dpll(struct intel_shared_dpll *pll,
> > +			    struct intel_crtc_state *crtc_state)
> >  {
> > -	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> > -	struct intel_shared_dpll *pll;
> >  	struct intel_shared_dpll_config *shared_dpll;
> > -	enum intel_dpll_id i;
> > +	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
> > +	enum intel_dpll_id i = pll->id;
> >  
> >  	shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state
> > ->base.state);
> >  
> > -	if (HAS_PCH_IBX(dev_priv->dev)) {
> > -		i = ibx_get_fixed_dpll(crtc, crtc_state);
> > -		WARN_ON(shared_dpll[i].crtc_mask);
> > -	} else if (IS_BROXTON(dev_priv->dev)) {
> > -		i = bxt_get_fixed_dpll(crtc, crtc_state);
> > -		WARN_ON(shared_dpll[i].crtc_mask);
> > -	} else {
> > -		i = intel_find_shared_dpll(crtc, crtc_state);
> > -	}
> > -
> > -	if (i < 0)
> > -		return NULL;
> > -
> > -	pll = &dev_priv->shared_dplls[i];
> > -
> >  	if (shared_dpll[i].crtc_mask == 0)
> >  		shared_dpll[i].hw_state =
> >  			crtc_state->dpll_hw_state;
> > @@ -299,8 +237,6 @@ intel_get_shared_dpll(struct intel_crtc *crtc,
> >  			 pipe_name(crtc->pipe));
> >  
> >  	intel_shared_dpll_config_get(shared_dpll, pll, crtc);
> > -
> > -	return pll;
> >  }
> >  
> >  void intel_shared_dpll_commit(struct drm_atomic_state *state)
> > @@ -398,6 +334,32 @@ static void ibx_pch_dpll_disable(struct
> > drm_i915_private *dev_priv,
> >  	udelay(200);
> >  }
> >  
> > +static struct intel_shared_dpll *
> > +ibx_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state)
> > +{
> > +	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> > +	struct intel_shared_dpll *pll;
> > +	enum intel_dpll_id i;
> > +
> > +	if (HAS_PCH_IBX(dev_priv)) {
> > +		/* Ironlake PCH has a fixed PLL->PCH pipe mapping. */
> > +		i = (enum intel_dpll_id) crtc->pipe;
> > +		pll = &dev_priv->shared_dplls[i];
> > +
> > +		DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
> > +			      crtc->base.base.id, pll->name);
> > +	} else {
> > +		pll = intel_find_shared_dpll(crtc, crtc_state,
> > +					     DPLL_ID_PCH_PLL_A,
> > +					     DPLL_ID_PCH_PLL_B);
> > +	}
> > +
> > +	/* reference the pll */
> > +	intel_reference_shared_dpll(pll, crtc_state);
> > +
> > +	return pll;
> > +}
> > +
> >  static const struct intel_shared_dpll_funcs ibx_pch_dpll_funcs = {
> >  	.mode_set = ibx_pch_dpll_mode_set,
> >  	.enable = ibx_pch_dpll_enable,
> > @@ -475,6 +437,19 @@ static bool hsw_ddi_spll_get_hw_state(struct
> > drm_i915_private *dev_priv,
> >  	return val & SPLL_PLL_ENABLE;
> >  }
> >  
> > +static struct intel_shared_dpll *
> > +hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state)
> > +{
> > +	struct intel_shared_dpll *pll;
> > +
> > +	pll = intel_find_shared_dpll(crtc, crtc_state,
> > +				     DPLL_ID_WRPLL1, DPLL_ID_WRPLL2);
> > +	if (pll)
> > +		intel_reference_shared_dpll(pll, crtc_state);
> > +
> > +	return pll;
> > +}
> > +
> >  
> >  static const struct intel_shared_dpll_funcs hsw_ddi_wrpll_funcs = {
> >  	.enable = hsw_ddi_wrpll_enable,
> > @@ -594,6 +569,19 @@ out:
> >  	return ret;
> >  }
> >  
> > +static struct intel_shared_dpll *
> > +skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state)
> > +{
> > +	struct intel_shared_dpll *pll;
> > +
> > +	pll = intel_find_shared_dpll(crtc, crtc_state,
> > +				     DPLL_ID_SKL_DPLL1, DPLL_ID_SKL_DPLL3);
> > +	if (pll)
> > +		intel_reference_shared_dpll(pll, crtc_state);
> > +
> > +	return pll;
> > +}
> > +
> >  static const struct intel_shared_dpll_funcs skl_ddi_pll_funcs = {
> >  	.enable = skl_ddi_pll_enable,
> >  	.disable = skl_ddi_pll_disable,
> > @@ -782,6 +770,32 @@ out:
> >  	return ret;
> >  }
> >  
> > +static struct intel_shared_dpll *
> > +bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state)
> > +{
> > +	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> > +	struct intel_encoder *encoder;
> > +	struct intel_digital_port *intel_dig_port;
> > +	struct intel_shared_dpll *pll;
> > +	enum intel_dpll_id i;
> > +
> > +	/* PLL is attached to port in bxt */
> > +	encoder = intel_ddi_get_crtc_new_encoder(crtc_state);
> > +	if (WARN_ON(!encoder))
> > +		return NULL;
> > +
> > +	intel_dig_port = enc_to_dig_port(&encoder->base);
> > +	/* 1:1 mapping between ports and PLLs */
> > +	i = (enum intel_dpll_id)intel_dig_port->port;
> > +	pll = &dev_priv->shared_dplls[i];
> > +	DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
> > +		crtc->base.base.id, pll->name);
> > +
> > +	intel_reference_shared_dpll(pll, crtc_state);
> > +
> > +	return pll;
> > +}
> > +
> >  static const struct intel_shared_dpll_funcs bxt_ddi_pll_funcs = {
> >  	.enable = bxt_ddi_pll_enable,
> >  	.disable = bxt_ddi_pll_disable,
> > @@ -826,12 +840,24 @@ struct dpll_info {
> >  	const struct intel_shared_dpll_funcs *funcs;
> >  };
> >  
> > +struct intel_dpll_mgr {
> > +	const struct dpll_info *dpll_info;
> > +
> > +	struct intel_shared_dpll *(*get_dpll)(struct intel_crtc *crtc,
> > +					      struct intel_crtc_state
> > *crtc_state);
> > +};
> > +
> >  static const struct dpll_info pch_plls[] = {
> >  	{ "PCH DPLL A", DPLL_ID_PCH_PLL_A, &ibx_pch_dpll_funcs },
> >  	{ "PCH DPLL B", DPLL_ID_PCH_PLL_B, &ibx_pch_dpll_funcs },
> >  	{ NULL, -1, NULL },
> >  };
> >  
> > +static const struct intel_dpll_mgr pch_pll_mgr = {
> > +	.dpll_info = pch_plls,
> > +	.get_dpll = ibx_get_dpll,
> > +};
> > +
> >  static const struct dpll_info hsw_plls[] = {
> >  	{ "WRPLL 1", DPLL_ID_WRPLL1, &hsw_ddi_wrpll_funcs },
> >  	{ "WRPLL 2", DPLL_ID_WRPLL2, &hsw_ddi_wrpll_funcs },
> > @@ -839,6 +865,11 @@ static const struct dpll_info hsw_plls[] = {
> >  	{ NULL, -1, NULL, },
> >  };
> >  
> > +static const struct intel_dpll_mgr hsw_pll_mgr = {
> > +	.dpll_info = hsw_plls,
> > +	.get_dpll = hsw_get_dpll,
> > +};
> > +
> >  static const struct dpll_info skl_plls[] = {
> >  	{ "DPPL 1", DPLL_ID_SKL_DPLL1, &skl_ddi_pll_funcs },
> >  	{ "DPPL 2", DPLL_ID_SKL_DPLL2, &skl_ddi_pll_funcs },
> > @@ -846,6 +877,11 @@ static const struct dpll_info skl_plls[] = {
> >  	{ NULL, -1, NULL, },
> >  };
> >  
> > +static const struct intel_dpll_mgr skl_pll_mgr = {
> > +	.dpll_info = skl_plls,
> > +	.get_dpll = skl_get_dpll,
> > +};
> > +
> >  static const struct dpll_info bxt_plls[] = {
> >  	{ "PORT PLL A", 0, &bxt_ddi_pll_funcs },
> >  	{ "PORT PLL B", 1, &bxt_ddi_pll_funcs },
> > @@ -853,26 +889,34 @@ static const struct dpll_info bxt_plls[] = {
> >  	{ NULL, -1, NULL, },
> >  };
> >  
> > +static const struct intel_dpll_mgr bxt_pll_mgr = {
> > +	.dpll_info = bxt_plls,
> > +	.get_dpll = bxt_get_dpll,
> > +};
> > +
> >  void intel_shared_dpll_init(struct drm_device *dev)
> >  {
> >  	struct drm_i915_private *dev_priv = dev->dev_private;
> > -	const struct dpll_info *dpll_info = NULL;
> > +	const struct intel_dpll_mgr *dpll_mgr = NULL;
> > +	const struct dpll_info *dpll_info;
> >  	int i;
> >  
> >  	if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
> > -		dpll_info = skl_plls;
> > +		dpll_mgr = &skl_pll_mgr;
> >  	else if IS_BROXTON(dev)
> > -		dpll_info = bxt_plls;
> > +		dpll_mgr = &bxt_pll_mgr;
> >  	else if (HAS_DDI(dev))
> > -		dpll_info = hsw_plls;
> > +		dpll_mgr = &hsw_pll_mgr;
> >  	else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
> > -		dpll_info = pch_plls;
> > +		dpll_mgr = &pch_pll_mgr;
> >  
> > -	if (!dpll_info) {
> > +	if (!dpll_mgr) {
> >  		dev_priv->num_shared_dpll = 0;
> >  		return;
> >  	}
> >  
> > +	dpll_info = dpll_mgr->dpll_info;
> > +
> >  	for (i = 0; dpll_info[i].id >= 0; i++) {
> >  		WARN_ON(i != dpll_info[i].id);
> >  
> > @@ -881,6 +925,7 @@ void intel_shared_dpll_init(struct drm_device *dev)
> >  		dev_priv->shared_dplls[i].funcs = *dpll_info[i].funcs;
> >  	}
> >  
> > +	dev_priv->dpll_mgr = dpll_mgr;
> >  	dev_priv->num_shared_dpll = i;
> >  
> >  	BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
> > @@ -889,3 +934,16 @@ void intel_shared_dpll_init(struct drm_device *dev)
> >  	if (HAS_DDI(dev))
> >  		intel_ddi_pll_init(dev);
> >  }
> > +
> > +struct intel_shared_dpll *
> > +intel_get_shared_dpll(struct intel_crtc *crtc,
> > +		      struct intel_crtc_state *crtc_state)
> > +{
> > +	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> > +	const struct intel_dpll_mgr *dpll_mgr = dev_priv->dpll_mgr;
> > +
> > +	if (dpll_mgr)
> > +		return dpll_mgr->get_dpll(crtc, crtc_state);
> > +	else
> > +		return NULL;
> > +}
> should there be a WARN_ON here?
> 

Makes sense. I'll send v2.

Thanks,
Ander

> Rest looks good, so for patch 8...11/13:
> 
> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

  reply	other threads:[~2016-03-04  6:36 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-02-26 13:54 [PATCH 00/13] Shared pll improvements Ander Conselvan de Oliveira
2016-02-26 13:54 ` [PATCH 01/13] drm/i915: Move shared dpll code to a new file Ander Conselvan de Oliveira
2016-02-26 13:54 ` [PATCH 02/13] drm/i915: Move ddi shared dpll code to intel_dpll_mgr.c Ander Conselvan de Oliveira
2016-02-26 13:54 ` [PATCH 03/13] drm/i915: Split intel_get_shared_dpll() into smaller functions Ander Conselvan de Oliveira
2016-02-26 13:54 ` [PATCH 04/13] drm/i915: Store a direct pointer to shared dpll in intel_crtc_state Ander Conselvan de Oliveira
2016-02-26 13:54 ` [PATCH 05/13] drm/i915: Move shared dpll struct definitions to separate header file Ander Conselvan de Oliveira
2016-02-26 13:54 ` [PATCH 06/13] drm/i915: Move shared dpll function prototypes to intel_dpll_mgr.h Ander Conselvan de Oliveira
2016-03-02 14:56   ` Maarten Lankhorst
2016-02-26 13:54 ` [PATCH 07/13] drm/i915: Use a table to initilize shared dplls Ander Conselvan de Oliveira
2016-03-02 15:30   ` Maarten Lankhorst
2016-03-03 11:32     ` Ander Conselvan De Oliveira
2016-03-03 13:35       ` Maarten Lankhorst
2016-02-26 13:54 ` [PATCH 08/13] drm/i915: Refactor platform specifics out of intel_get_shared_dpll() Ander Conselvan de Oliveira
2016-03-03 14:08   ` Maarten Lankhorst
2016-03-04  6:36     ` Ander Conselvan De Oliveira [this message]
2016-03-04  6:49     ` Ander Conselvan De Oliveira
2016-03-07  9:59       ` Maarten Lankhorst
2016-02-26 13:54 ` [PATCH 09/13] drm/i915: Move HSW/BDW pll selection logic to intel_dpll_mgr.c Ander Conselvan de Oliveira
2016-02-26 13:54 ` [PATCH 10/13] drm/i915: Move SKL/KLB " Ander Conselvan de Oliveira
2016-02-26 13:54 ` [PATCH 11/13] drm/i915: Move BXT pll configuration " Ander Conselvan de Oliveira
2016-02-26 13:54 ` [PATCH 12/13] drm/i915: Manage HSW/BDW LCPLLs with the shared dpll interface Ander Conselvan de Oliveira
2016-02-29  9:08   ` [PATCH v2 " Ander Conselvan de Oliveira
2016-03-08 11:05   ` [PATCH " Maarten Lankhorst
2016-03-08 11:11     ` Conselvan De Oliveira, Ander
2016-03-08 11:16       ` Ander Conselvan De Oliveira
2016-02-26 13:54 ` [PATCH 13/13] drm/i915: Make SKL/KBL DPLL0 managed by the shared dpll code Ander Conselvan de Oliveira
2016-02-29  9:08   ` [PATCH v3 " Ander Conselvan de Oliveira
2016-03-03 13:33     ` Maarten Lankhorst
2016-03-03 13:40       ` Ander Conselvan De Oliveira
2016-03-03 13:51         ` Maarten Lankhorst
2016-02-26 14:27 ` ✗ Fi.CI.BAT: failure for Shared pll improvements Patchwork
2016-03-08 15:46 [PATCH 00/13] " Ander Conselvan de Oliveira
2016-03-08 15:46 ` [PATCH 08/13] drm/i915: Refactor platform specifics out of intel_get_shared_dpll() Ander Conselvan de Oliveira

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1457073377.2668.1.camel@gmail.com \
    --to=conselvan2@gmail.com \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=maarten.lankhorst@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.