All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Ville Syrjälä" <ville.syrjala@linux.intel.com>
To: Jani Nikula <jani.nikula@intel.com>
Cc: intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org
Subject: Re: [Intel-gfx] [PATCH v3 05/13] drm/edid: add drm_edid_connector_update()
Date: Wed, 22 Jun 2022 18:17:37 +0300	[thread overview]
Message-ID: <YrMykdSOXCGVbFMd@intel.com> (raw)
In-Reply-To: <bcdc925d3a50a40714637c9bf7c71e4c534bd223.1655895388.git.jani.nikula@intel.com>

On Wed, Jun 22, 2022 at 01:59:19PM +0300, Jani Nikula wrote:
> Add a new function drm_edid_connector_update() to replace the
> combination of calls drm_connector_update_edid_property() and
> drm_add_edid_modes(). Usually they are called in the drivers in this
> order, however the former needs information from the latter.
> 
> Since the new drm_edid_read*() functions no longer call the connector
> updates directly, and the read and update are separated, we'll need this
> new function for the connector update.
> 
> This is all in drm_edid.c simply to keep struct drm_edid opaque.
> 
> v2:
> - Share code with drm_connector_update_edid_property() (Ville)
> - Add comment about override EDID handling
> 
> Signed-off-by: Jani Nikula <jani.nikula@intel.com>

Had to take notes to figure who did/does what. But it does look
like non-static stuff should end up doing the same thing before
and after this patch, apart from the new function that is.

Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

> ---
>  drivers/gpu/drm/drm_edid.c | 103 ++++++++++++++++++++++++++++---------
>  include/drm/drm_edid.h     |   2 +
>  2 files changed, 81 insertions(+), 24 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index c3f0f0a5a8a9..41b3de52b8f1 100644
> --- a/drivers/gpu/drm/drm_edid.c
> +++ b/drivers/gpu/drm/drm_edid.c
> @@ -6160,8 +6160,8 @@ static int add_displayid_detailed_modes(struct drm_connector *connector,
>  	return num_modes;
>  }
>  
> -static int drm_edid_connector_update(struct drm_connector *connector,
> -				     const struct drm_edid *drm_edid)
> +static int _drm_edid_connector_update(struct drm_connector *connector,
> +				      const struct drm_edid *drm_edid)
>  {
>  	int num_modes = 0;
>  	u32 quirks;
> @@ -6227,31 +6227,12 @@ static int drm_edid_connector_update(struct drm_connector *connector,
>  static void _drm_update_tile_info(struct drm_connector *connector,
>  				  const struct drm_edid *drm_edid);
>  
> -static int _drm_connector_update_edid_property(struct drm_connector *connector,
> +static int _drm_edid_connector_property_update(struct drm_connector *connector,
>  					       const struct drm_edid *drm_edid)
>  {
>  	struct drm_device *dev = connector->dev;
>  	int ret;
>  
> -	/* ignore requests to set edid when overridden */
> -	if (connector->override_edid)
> -		return 0;
> -
> -	/*
> -	 * Set the display info, using edid if available, otherwise resetting
> -	 * the values to defaults. This duplicates the work done in
> -	 * drm_add_edid_modes, but that function is not consistently called
> -	 * before this one in all drivers and the computation is cheap enough
> -	 * that it seems better to duplicate it rather than attempt to ensure
> -	 * some arbitrary ordering of calls.
> -	 */
> -	if (drm_edid)
> -		update_display_info(connector, drm_edid);
> -	else
> -		drm_reset_display_info(connector);
> -
> -	_drm_update_tile_info(connector, drm_edid);
> -
>  	if (connector->edid_blob_ptr) {
>  		const struct edid *old_edid = connector->edid_blob_ptr->data;
>  
> @@ -6297,6 +6278,76 @@ static int _drm_connector_update_edid_property(struct drm_connector *connector,
>  	return ret;
>  }
>  
> +/**
> + * drm_edid_connector_update - Update connector information from EDID
> + * @connector: Connector
> + * @drm_edid: EDID
> + *
> + * Update the connector mode list, display info, ELD, HDR metadata, relevant
> + * properties, etc. from the passed in EDID.
> + *
> + * If EDID is NULL, reset the information.
> + *
> + * Return: The number of modes added or 0 if we couldn't find any.
> + */
> +int drm_edid_connector_update(struct drm_connector *connector,
> +			      const struct drm_edid *drm_edid)
> +{
> +	int count;
> +
> +	/*
> +	 * FIXME: Reconcile the differences in override_edid handling between
> +	 * this and drm_connector_update_edid_property().
> +	 *
> +	 * If override_edid is set, and the EDID passed in here originates from
> +	 * drm_edid_read() and friends, it will be the override EDID, and there
> +	 * are no issues. drm_connector_update_edid_property() ignoring requests
> +	 * to set the EDID dates back to a time when override EDID was not
> +	 * handled at the low level EDID read.
> +	 *
> +	 * The only way the EDID passed in here can be different from the
> +	 * override EDID is when a driver passes in an EDID that does *not*
> +	 * originate from drm_edid_read() and friends, or passes in a stale
> +	 * cached version. This, in turn, is a question of when an override EDID
> +	 * set via debugfs should take effect.
> +	 */
> +
> +	count = _drm_edid_connector_update(connector, drm_edid);
> +
> +	_drm_update_tile_info(connector, drm_edid);
> +
> +	/* Note: Ignore errors for now. */
> +	_drm_edid_connector_property_update(connector, drm_edid);
> +
> +	return count;
> +}
> +EXPORT_SYMBOL(drm_edid_connector_update);
> +
> +static int _drm_connector_update_edid_property(struct drm_connector *connector,
> +					       const struct drm_edid *drm_edid)
> +{
> +	/* ignore requests to set edid when overridden */
> +	if (connector->override_edid)
> +		return 0;
> +
> +	/*
> +	 * Set the display info, using edid if available, otherwise resetting
> +	 * the values to defaults. This duplicates the work done in
> +	 * drm_add_edid_modes, but that function is not consistently called
> +	 * before this one in all drivers and the computation is cheap enough
> +	 * that it seems better to duplicate it rather than attempt to ensure
> +	 * some arbitrary ordering of calls.
> +	 */
> +	if (drm_edid)
> +		update_display_info(connector, drm_edid);
> +	else
> +		drm_reset_display_info(connector);
> +
> +	_drm_update_tile_info(connector, drm_edid);
> +
> +	return _drm_edid_connector_property_update(connector, drm_edid);
> +}
> +
>  /**
>   * drm_connector_update_edid_property - update the edid property of a connector
>   * @connector: drm connector
> @@ -6308,6 +6359,8 @@ static int _drm_connector_update_edid_property(struct drm_connector *connector,
>   * set the connector's tile property here. See drm_connector_set_tile_property()
>   * for more details.
>   *
> + * This function is deprecated. Use drm_edid_connector_update() instead.
> + *
>   * Returns:
>   * Zero on success, negative errno on failure.
>   */
> @@ -6330,6 +6383,8 @@ EXPORT_SYMBOL(drm_connector_update_edid_property);
>   * &drm_display_info structure and ELD in @connector with any information which
>   * can be derived from the edid.
>   *
> + * This function is deprecated. Use drm_edid_connector_update() instead.
> + *
>   * Return: The number of modes added or 0 if we couldn't find any.
>   */
>  int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
> @@ -6342,8 +6397,8 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
>  		edid = NULL;
>  	}
>  
> -	return drm_edid_connector_update(connector,
> -					 drm_edid_legacy_init(&drm_edid, edid));
> +	return _drm_edid_connector_update(connector,
> +					  drm_edid_legacy_init(&drm_edid, edid));
>  }
>  EXPORT_SYMBOL(drm_add_edid_modes);
>  
> diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
> index 9d2d78135dee..aeb2fa95bc04 100644
> --- a/include/drm/drm_edid.h
> +++ b/include/drm/drm_edid.h
> @@ -603,6 +603,8 @@ const struct drm_edid *drm_edid_read_ddc(struct drm_connector *connector,
>  const struct drm_edid *drm_edid_read_custom(struct drm_connector *connector,
>  					    int (*read_block)(void *context, u8 *buf, unsigned int block, size_t len),
>  					    void *context);
> +int drm_edid_connector_update(struct drm_connector *connector,
> +			      const struct drm_edid *edid);
>  const u8 *drm_find_edid_extension(const struct drm_edid *drm_edid,
>  				  int ext_id, int *ext_index);
>  
> -- 
> 2.30.2

-- 
Ville Syrjälä
Intel

WARNING: multiple messages have this Message-ID (diff)
From: "Ville Syrjälä" <ville.syrjala@linux.intel.com>
To: Jani Nikula <jani.nikula@intel.com>
Cc: intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v3 05/13] drm/edid: add drm_edid_connector_update()
Date: Wed, 22 Jun 2022 18:17:37 +0300	[thread overview]
Message-ID: <YrMykdSOXCGVbFMd@intel.com> (raw)
In-Reply-To: <bcdc925d3a50a40714637c9bf7c71e4c534bd223.1655895388.git.jani.nikula@intel.com>

On Wed, Jun 22, 2022 at 01:59:19PM +0300, Jani Nikula wrote:
> Add a new function drm_edid_connector_update() to replace the
> combination of calls drm_connector_update_edid_property() and
> drm_add_edid_modes(). Usually they are called in the drivers in this
> order, however the former needs information from the latter.
> 
> Since the new drm_edid_read*() functions no longer call the connector
> updates directly, and the read and update are separated, we'll need this
> new function for the connector update.
> 
> This is all in drm_edid.c simply to keep struct drm_edid opaque.
> 
> v2:
> - Share code with drm_connector_update_edid_property() (Ville)
> - Add comment about override EDID handling
> 
> Signed-off-by: Jani Nikula <jani.nikula@intel.com>

Had to take notes to figure who did/does what. But it does look
like non-static stuff should end up doing the same thing before
and after this patch, apart from the new function that is.

Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

> ---
>  drivers/gpu/drm/drm_edid.c | 103 ++++++++++++++++++++++++++++---------
>  include/drm/drm_edid.h     |   2 +
>  2 files changed, 81 insertions(+), 24 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index c3f0f0a5a8a9..41b3de52b8f1 100644
> --- a/drivers/gpu/drm/drm_edid.c
> +++ b/drivers/gpu/drm/drm_edid.c
> @@ -6160,8 +6160,8 @@ static int add_displayid_detailed_modes(struct drm_connector *connector,
>  	return num_modes;
>  }
>  
> -static int drm_edid_connector_update(struct drm_connector *connector,
> -				     const struct drm_edid *drm_edid)
> +static int _drm_edid_connector_update(struct drm_connector *connector,
> +				      const struct drm_edid *drm_edid)
>  {
>  	int num_modes = 0;
>  	u32 quirks;
> @@ -6227,31 +6227,12 @@ static int drm_edid_connector_update(struct drm_connector *connector,
>  static void _drm_update_tile_info(struct drm_connector *connector,
>  				  const struct drm_edid *drm_edid);
>  
> -static int _drm_connector_update_edid_property(struct drm_connector *connector,
> +static int _drm_edid_connector_property_update(struct drm_connector *connector,
>  					       const struct drm_edid *drm_edid)
>  {
>  	struct drm_device *dev = connector->dev;
>  	int ret;
>  
> -	/* ignore requests to set edid when overridden */
> -	if (connector->override_edid)
> -		return 0;
> -
> -	/*
> -	 * Set the display info, using edid if available, otherwise resetting
> -	 * the values to defaults. This duplicates the work done in
> -	 * drm_add_edid_modes, but that function is not consistently called
> -	 * before this one in all drivers and the computation is cheap enough
> -	 * that it seems better to duplicate it rather than attempt to ensure
> -	 * some arbitrary ordering of calls.
> -	 */
> -	if (drm_edid)
> -		update_display_info(connector, drm_edid);
> -	else
> -		drm_reset_display_info(connector);
> -
> -	_drm_update_tile_info(connector, drm_edid);
> -
>  	if (connector->edid_blob_ptr) {
>  		const struct edid *old_edid = connector->edid_blob_ptr->data;
>  
> @@ -6297,6 +6278,76 @@ static int _drm_connector_update_edid_property(struct drm_connector *connector,
>  	return ret;
>  }
>  
> +/**
> + * drm_edid_connector_update - Update connector information from EDID
> + * @connector: Connector
> + * @drm_edid: EDID
> + *
> + * Update the connector mode list, display info, ELD, HDR metadata, relevant
> + * properties, etc. from the passed in EDID.
> + *
> + * If EDID is NULL, reset the information.
> + *
> + * Return: The number of modes added or 0 if we couldn't find any.
> + */
> +int drm_edid_connector_update(struct drm_connector *connector,
> +			      const struct drm_edid *drm_edid)
> +{
> +	int count;
> +
> +	/*
> +	 * FIXME: Reconcile the differences in override_edid handling between
> +	 * this and drm_connector_update_edid_property().
> +	 *
> +	 * If override_edid is set, and the EDID passed in here originates from
> +	 * drm_edid_read() and friends, it will be the override EDID, and there
> +	 * are no issues. drm_connector_update_edid_property() ignoring requests
> +	 * to set the EDID dates back to a time when override EDID was not
> +	 * handled at the low level EDID read.
> +	 *
> +	 * The only way the EDID passed in here can be different from the
> +	 * override EDID is when a driver passes in an EDID that does *not*
> +	 * originate from drm_edid_read() and friends, or passes in a stale
> +	 * cached version. This, in turn, is a question of when an override EDID
> +	 * set via debugfs should take effect.
> +	 */
> +
> +	count = _drm_edid_connector_update(connector, drm_edid);
> +
> +	_drm_update_tile_info(connector, drm_edid);
> +
> +	/* Note: Ignore errors for now. */
> +	_drm_edid_connector_property_update(connector, drm_edid);
> +
> +	return count;
> +}
> +EXPORT_SYMBOL(drm_edid_connector_update);
> +
> +static int _drm_connector_update_edid_property(struct drm_connector *connector,
> +					       const struct drm_edid *drm_edid)
> +{
> +	/* ignore requests to set edid when overridden */
> +	if (connector->override_edid)
> +		return 0;
> +
> +	/*
> +	 * Set the display info, using edid if available, otherwise resetting
> +	 * the values to defaults. This duplicates the work done in
> +	 * drm_add_edid_modes, but that function is not consistently called
> +	 * before this one in all drivers and the computation is cheap enough
> +	 * that it seems better to duplicate it rather than attempt to ensure
> +	 * some arbitrary ordering of calls.
> +	 */
> +	if (drm_edid)
> +		update_display_info(connector, drm_edid);
> +	else
> +		drm_reset_display_info(connector);
> +
> +	_drm_update_tile_info(connector, drm_edid);
> +
> +	return _drm_edid_connector_property_update(connector, drm_edid);
> +}
> +
>  /**
>   * drm_connector_update_edid_property - update the edid property of a connector
>   * @connector: drm connector
> @@ -6308,6 +6359,8 @@ static int _drm_connector_update_edid_property(struct drm_connector *connector,
>   * set the connector's tile property here. See drm_connector_set_tile_property()
>   * for more details.
>   *
> + * This function is deprecated. Use drm_edid_connector_update() instead.
> + *
>   * Returns:
>   * Zero on success, negative errno on failure.
>   */
> @@ -6330,6 +6383,8 @@ EXPORT_SYMBOL(drm_connector_update_edid_property);
>   * &drm_display_info structure and ELD in @connector with any information which
>   * can be derived from the edid.
>   *
> + * This function is deprecated. Use drm_edid_connector_update() instead.
> + *
>   * Return: The number of modes added or 0 if we couldn't find any.
>   */
>  int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
> @@ -6342,8 +6397,8 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
>  		edid = NULL;
>  	}
>  
> -	return drm_edid_connector_update(connector,
> -					 drm_edid_legacy_init(&drm_edid, edid));
> +	return _drm_edid_connector_update(connector,
> +					  drm_edid_legacy_init(&drm_edid, edid));
>  }
>  EXPORT_SYMBOL(drm_add_edid_modes);
>  
> diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
> index 9d2d78135dee..aeb2fa95bc04 100644
> --- a/include/drm/drm_edid.h
> +++ b/include/drm/drm_edid.h
> @@ -603,6 +603,8 @@ const struct drm_edid *drm_edid_read_ddc(struct drm_connector *connector,
>  const struct drm_edid *drm_edid_read_custom(struct drm_connector *connector,
>  					    int (*read_block)(void *context, u8 *buf, unsigned int block, size_t len),
>  					    void *context);
> +int drm_edid_connector_update(struct drm_connector *connector,
> +			      const struct drm_edid *edid);
>  const u8 *drm_find_edid_extension(const struct drm_edid *drm_edid,
>  				  int ext_id, int *ext_index);
>  
> -- 
> 2.30.2

-- 
Ville Syrjälä
Intel

  reply	other threads:[~2022-06-22 15:17 UTC|newest]

Thread overview: 59+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-22 10:59 [Intel-gfx] [PATCH v3 00/13] drm/edid: expand on struct drm_edid usage Jani Nikula
2022-06-22 10:59 ` Jani Nikula
2022-06-22 10:59 ` [Intel-gfx] [PATCH v3 01/13] drm/edid: move drm_connector_update_edid_property() to drm_edid.c Jani Nikula
2022-06-22 10:59   ` Jani Nikula
2022-06-22 14:37   ` [Intel-gfx] " Ville Syrjälä
2022-06-22 14:37     ` Ville Syrjälä
2022-06-22 10:59 ` [Intel-gfx] [PATCH v3 02/13] drm/edid: convert drm_connector_update_edid_property() to struct drm_edid Jani Nikula
2022-06-22 10:59   ` Jani Nikula
2022-06-22 14:38   ` [Intel-gfx] " Ville Syrjälä
2022-06-22 14:38     ` Ville Syrjälä
2022-06-22 10:59 ` [Intel-gfx] [PATCH v3 03/13] drm/edid: clean up connector update error handling and debug logging Jani Nikula
2022-06-22 10:59   ` Jani Nikula
2022-06-22 14:40   ` [Intel-gfx] " Ville Syrjälä
2022-06-22 14:40     ` Ville Syrjälä
2022-06-22 10:59 ` [Intel-gfx] [PATCH v3 04/13] drm/edid: abstract debugfs override EDID set/reset Jani Nikula
2022-06-22 10:59   ` Jani Nikula
2022-06-22 14:41   ` [Intel-gfx] " Ville Syrjälä
2022-06-22 14:41     ` Ville Syrjälä
2022-06-22 10:59 ` [Intel-gfx] [PATCH v3 05/13] drm/edid: add drm_edid_connector_update() Jani Nikula
2022-06-22 10:59   ` Jani Nikula
2022-06-22 15:17   ` Ville Syrjälä [this message]
2022-06-22 15:17     ` Ville Syrjälä
2022-06-22 10:59 ` [Intel-gfx] [PATCH v3 06/13] drm/probe-helper: add drm_connector_helper_get_modes() Jani Nikula
2022-06-22 10:59   ` Jani Nikula
2022-06-22 10:59 ` [Intel-gfx] [PATCH v3 07/13] drm/edid: add drm_edid_raw() to access the raw EDID data Jani Nikula
2022-06-22 10:59   ` Jani Nikula
2022-06-22 10:59 ` [Intel-gfx] [PATCH v3 08/13] drm/i915/edid: convert DP, HDMI and LVDS to drm_edid Jani Nikula
2022-06-22 10:59   ` Jani Nikula
2022-06-22 15:05   ` [Intel-gfx] " Ville Syrjälä
2022-06-22 15:05     ` Ville Syrjälä
2022-06-23  7:29     ` [Intel-gfx] " Jani Nikula
2022-06-23  7:29       ` Jani Nikula
2022-06-23  7:27   ` [Intel-gfx] [PATCH] " Jani Nikula
2022-06-23  7:27     ` Jani Nikula
2022-06-23  9:20     ` [Intel-gfx] " Ville Syrjälä
2022-06-23  9:20       ` Ville Syrjälä
2022-06-22 10:59 ` [Intel-gfx] [PATCH v3 09/13] drm/i915/bios: convert intel_bios_init_panel() " Jani Nikula
2022-06-22 10:59   ` Jani Nikula
2022-06-22 10:59 ` [Intel-gfx] [PATCH v3 10/13] drm/edid: do invalid block filtering in-place Jani Nikula
2022-06-22 10:59   ` Jani Nikula
2022-06-22 10:59 ` [Intel-gfx] [PATCH v3 11/13] drm/edid: add HF-EEODB support to EDID read and allocation Jani Nikula
2022-06-22 10:59   ` Jani Nikula
2022-06-22 10:59 ` [Intel-gfx] [PATCH v3 12/13] drm/edid: take HF-EEODB extension count into account Jani Nikula
2022-06-22 10:59   ` Jani Nikula
2022-06-22 10:59 ` [Intel-gfx] [PATCH v3 13/13] drm/todo: add entry for converting the subsystem to struct drm_edid Jani Nikula
2022-06-22 10:59   ` Jani Nikula
2022-06-22 21:38 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for drm/edid: expand on struct drm_edid usage (rev4) Patchwork
2022-06-22 21:38 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
2022-06-22 21:59 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
2022-06-23  7:56 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for drm/edid: expand on struct drm_edid usage (rev5) Patchwork
2022-06-23  8:18 ` [Intel-gfx] ✗ Fi.CI.BAT: failure " Patchwork
2022-06-23  8:59 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for drm/edid: expand on struct drm_edid usage (rev6) Patchwork
2022-06-23  9:26 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
2022-06-27 10:41 ` [Intel-gfx] ✗ Fi.CI.IGT: failure for drm/edid: expand on struct drm_edid usage (rev4) Patchwork
2022-06-27 13:15 ` [Intel-gfx] ✗ Fi.CI.IGT: failure for drm/edid: expand on struct drm_edid usage (rev6) Patchwork
2022-06-28 20:49 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for drm/edid: expand on struct drm_edid usage (rev7) Patchwork
2022-06-28 20:49 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
2022-06-28 21:09 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
2022-06-29 13:28 ` [Intel-gfx] ✗ Fi.CI.IGT: failure " Patchwork

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=YrMykdSOXCGVbFMd@intel.com \
    --to=ville.syrjala@linux.intel.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=jani.nikula@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.