From: Jani Nikula <jani.nikula@linux.intel.com>
To: intel-gfx@lists.freedesktop.org
Cc: Deepak M <m.deepak@intel.com>
Subject: Re: [MIPI SEQ PARSING v2 PATCH 05/11] drm/i915: Added support the v3 mipi sequence block
Date: Thu, 17 Sep 2015 17:38:44 +0300 [thread overview]
Message-ID: <876139t8jv.fsf@intel.com> (raw)
In-Reply-To: <1441841070-11532-6-git-send-email-m.deepak@intel.com>
On Thu, 10 Sep 2015, Deepak M <m.deepak@intel.com> wrote:
> From: vkorjani <vikas.korjani@intel.com>
>
> The Block 53 of the VBT, which is the MIPI sequence block
> has undergone a design change because of which the parsing
> logic has to be changed.
>
> The current code will handle the parsing of v3 and other
> lower versions of the MIPI sequence block.
>
> v2: rebase
>
> Signed-off-by: vkorjani <vikas.korjani@intel.com>
> Signed-off-by: Deepak M <m.deepak@intel.com>
> ---
> drivers/gpu/drm/i915/intel_bios.c | 119 +++++++++++++++++++++++-----
> drivers/gpu/drm/i915/intel_bios.h | 8 ++
> drivers/gpu/drm/i915/intel_dsi_panel_vbt.c | 7 ++
> 3 files changed, 114 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
> index 34a1042..cea641f 100644
> --- a/drivers/gpu/drm/i915/intel_bios.c
> +++ b/drivers/gpu/drm/i915/intel_bios.c
> @@ -45,6 +45,7 @@ find_section(struct drm_i915_private *dev_priv,
> int index = 0;
> u32 total, current_size;
> u8 current_id;
> + u8 version;
>
> /* skip to first section */
> index += bdb->header_size;
> @@ -56,7 +57,17 @@ find_section(struct drm_i915_private *dev_priv,
> current_id = *(base + index);
> index++;
>
> - current_size = *((const u16 *)(base + index));
> + if (current_id == BDB_MIPI_SEQUENCE) {
> + version = *(base + index + 2);
> + if (version >= 3)
> + current_size = *((const u32 *)(base +
> + index + 3));
> + else
> + current_size = *((const u16 *)(base + index));
> + } else {
> + current_size = *((const u16 *)(base + index));
> + }
> +
While reviewing I've realized the old kernels will hit this hard. I've
submitted a patch [1] to be applied to v4.3-rc and older stable kernels
so that they fail gracefully instead of starting to parse garbage. The
real parsing is too big to backport to upstream stable. Please review.
[1] http://mid.gmane.org/1442497327-27033-1-git-send-email-jani.nikula@intel.com
> index += 2;
>
> if (index + current_size > total)
> @@ -745,6 +756,55 @@ static u8 *goto_next_sequence(u8 *data, int *size)
> return data;
> }
>
> +static u8 *goto_next_sequence_v3(u8 *data, int *size)
> +{
> + int tmp = *size;
> + int op_size;
> +
> + if (--tmp < 0)
> + return NULL;
> +
> + /* Skip the panel id and the sequence size */
It's not panel id, it's the sequence byte, right?
You could also store data + 1 + size of sequence, and check whether data
ends up pointing at the same place in the end. They should.
Shouldn't you also take 4 bytes of sequence size field into account in
tmp?
> + data = data + 5;
> + while (*data != 0) {
> + u8 element_type = *data++;
> +
> + switch (element_type) {
Would be helpful to refer to operation_byte like in the spec.
> + default:
> + DRM_ERROR("Unknown element type %d\n", element_type);
> + case MIPI_SEQ_ELEM_SEND_PKT:
> + case MIPI_SEQ_ELEM_DELAY:
> + case MIPI_SEQ_ELEM_GPIO:
> + case MIPI_SEQ_ELEM_I2C:
> + case MIPI_SEQ_ELEM_SPI:
> + case MIPI_SEQ_ELEM_PMIC:
> + /*
> + * skip by this element payload size
> + * skip elem id, command flag and data type
> + */
> + op_size = *data++;
> + tmp = tmp - (op_size + 1);
> + if (tmp < 0)
> + return NULL;
Isn't each operation operation byte | size of operation | payload size,
i.e. your tmp change is one byte short?
The fact that the goto_next_sequence* functions increase data and
decrease size is getting increasingly confusing to follow. One simple
alternative would be to calculate some endp = start + size up front, and
then pass the endp around, and check if we're about to go past the end
marker.
This is not a problem with your series, it was there already. And fixing
it doesn't have to be part of your series. It just really takes ages to
review this approach of range checking. Unless I close my eyes and trust
there are no off-by-ones anywhere. But that kind of defeats the purpose
of review...
> +
> + /* skip by len */
> + data += op_size;
> + break;
> + }
> + }
> +
> + /* goto next sequence or end of block byte */
> + if (--tmp < 0)
> + return NULL;
> +
> + /* Skip the end element marker */
> + data++;
> +
> + /* update amount of data left for the sequence block to be parsed */
> + *size = tmp;
> + return data;
> +}
> +
> static void
> parse_mipi(struct drm_i915_private *dev_priv, const struct bdb_header *bdb)
> {
> @@ -754,7 +814,7 @@ parse_mipi(struct drm_i915_private *dev_priv, const struct bdb_header *bdb)
> const struct mipi_pps_data *pps;
> u8 *data;
> const u8 *seq_data;
> - int i, panel_id, seq_size;
> + int i, panel_id, panel_seq_size;
> u16 block_size;
>
> /* parse MIPI blocks only if LFP type is MIPI */
> @@ -811,29 +871,40 @@ parse_mipi(struct drm_i915_private *dev_priv, const struct bdb_header *bdb)
>
> DRM_DEBUG_DRIVER("Found MIPI sequence block\n");
>
> - block_size = get_blocksize(sequence);
> -
> /*
> * parse the sequence block for individual sequences
> */
> dev_priv->vbt.dsi.seq_version = sequence->version;
>
> seq_data = &sequence->data[0];
> + if (dev_priv->vbt.dsi.seq_version >= 3) {
> + block_size = *((unsigned int *)seq_data);
(const u32 *)
> + seq_data = seq_data + 4;
> + } else
> + block_size = get_blocksize(sequence);
block_size should be changed to u32.
>
> /*
> * sequence block is variable length and hence we need to parse and
> * get the sequence data for specific panel id
> */
> for (i = 0; i < MAX_MIPI_CONFIGURATIONS; i++) {
> - panel_id = *seq_data;
> - seq_size = *((u16 *) (seq_data + 1));
> + panel_id = *seq_data++;
> + if (dev_priv->vbt.dsi.seq_version >= 3) {
> + panel_seq_size = *((u32 *)seq_data);
> + seq_data += sizeof(u32);
> + } else {
> + panel_seq_size = *((u16 *)seq_data);
> + seq_data += sizeof(u16);
> + }
> +
> if (panel_id == panel_type)
> break;
>
> - /* skip the sequence including seq header of 3 bytes */
> - seq_data = seq_data + 3 + seq_size;
> + seq_data += panel_seq_size;
> +
> if ((seq_data - &sequence->data[0]) > block_size) {
> - DRM_ERROR("Sequence start is beyond sequence block size, corrupted sequence block\n");
> + DRM_ERROR("Sequence start is beyond seq block size\n");
> + DRM_ERROR("Corrupted sequence block\n");
Please don't add two consecutive DRM_ERRORs for the same error.
> return;
> }
> }
> @@ -845,13 +916,14 @@ parse_mipi(struct drm_i915_private *dev_priv, const struct bdb_header *bdb)
>
> /* check if found sequence is completely within the sequence block
> * just being paranoid */
> - if (seq_size > block_size) {
> + if (panel_seq_size > block_size) {
> DRM_ERROR("Corrupted sequence/size, bailing out\n");
> return;
> }
>
> - /* skip the panel id(1 byte) and seq size(2 bytes) */
> - dev_priv->vbt.dsi.data = kmemdup(seq_data + 3, seq_size, GFP_KERNEL);
> +
> + dev_priv->vbt.dsi.data = kmemdup(seq_data, panel_seq_size, GFP_KERNEL);
> +
> if (!dev_priv->vbt.dsi.data)
> return;
>
> @@ -860,29 +932,36 @@ parse_mipi(struct drm_i915_private *dev_priv, const struct bdb_header *bdb)
> * There are only 5 types of sequences as of now
> */
> data = dev_priv->vbt.dsi.data;
> - dev_priv->vbt.dsi.size = seq_size;
> + dev_priv->vbt.dsi.size = panel_seq_size;
>
> /* two consecutive 0x00 indicate end of all sequences */
> - while (1) {
> + while (*data != 0) {
> int seq_id = *data;
> + int seq_size;
u32
> +
> if (MIPI_SEQ_MAX > seq_id && seq_id > MIPI_SEQ_UNDEFINED) {
> dev_priv->vbt.dsi.sequence[seq_id] = data;
> DRM_DEBUG_DRIVER("Found mipi sequence - %d\n", seq_id);
> } else {
> - DRM_ERROR("undefined sequence\n");
> - goto err;
> + DRM_ERROR("undefined sequence - %d\n", seq_id);
> + seq_size = *(data + 1);
Needs to be *((const u32 *)(data + 1)) or you'll ignore 3 highest order
bytes.
> + if (dev_priv->vbt.dsi.seq_version >= 3) {
> + data = data + seq_size + 1;
> + continue;
> + } else
> + goto err;
> }
>
> /* partial parsing to skip elements */
> - data = goto_next_sequence(data, &seq_size);
> + if (dev_priv->vbt.dsi.seq_version >= 3)
> + data = goto_next_sequence_v3(data, &panel_seq_size);
> + else
> + data = goto_next_sequence(data, &panel_seq_size);
>
> if (data == NULL) {
> DRM_ERROR("Sequence elements going beyond block itself. Sequence block parsing failed\n");
> goto err;
> }
> -
> - if (*data == 0)
> - break; /* end of sequence reached */
> }
>
> DRM_DEBUG_DRIVER("MIPI related vbt parsing complete\n");
> diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h
> index 21a7f3f..7a4ba41 100644
> --- a/drivers/gpu/drm/i915/intel_bios.h
> +++ b/drivers/gpu/drm/i915/intel_bios.h
> @@ -948,6 +948,12 @@ enum mipi_seq {
> MIPI_SEQ_DISPLAY_ON,
> MIPI_SEQ_DISPLAY_OFF,
> MIPI_SEQ_DEASSERT_RESET,
> + MIPI_SEQ_BACKLIGHT_ON,
> + MIPI_SEQ_BACKLIGHT_OFF,
> + MIPI_SEQ_TEAR_ON,
> + MIPI_SEQ_TEAR_OFF,
> + MIPI_SEQ_POWER_ON,
> + MIPI_SEQ_POWER_OFF,
> MIPI_SEQ_MAX
> };
>
> @@ -957,6 +963,8 @@ enum mipi_seq_element {
> MIPI_SEQ_ELEM_DELAY,
> MIPI_SEQ_ELEM_GPIO,
> MIPI_SEQ_ELEM_I2C,
> + MIPI_SEQ_ELEM_SPI,
> + MIPI_SEQ_ELEM_PMIC,
> MIPI_SEQ_ELEM_STATUS,
Again, MIPI_SEQ_ELEM_STATUS is not spec.
> MIPI_SEQ_ELEM_MAX
> };
> diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
> index 9989f61..c6a6fa1 100644
> --- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
> +++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
> @@ -317,6 +317,8 @@ static const char * const seq_name[] = {
>
> static void generic_exec_sequence(struct intel_dsi *intel_dsi, const u8 *data)
> {
> + struct drm_device *dev = intel_dsi->base.base.dev;
> + struct drm_i915_private *dev_priv = dev->dev_private;
> fn_mipi_elem_exec mipi_elem_exec;
> int index;
>
> @@ -327,6 +329,8 @@ static void generic_exec_sequence(struct intel_dsi *intel_dsi, const u8 *data)
>
> /* go to the first element of the sequence */
> data++;
> + if (dev_priv->vbt.dsi.seq_version >= 3)
> + data = data + 4;
>
> /* parse each byte till we reach end of sequence byte - 0x00 */
> while (1) {
> @@ -340,6 +344,9 @@ static void generic_exec_sequence(struct intel_dsi *intel_dsi, const u8 *data)
> /* goto element payload */
> data++;
>
> + if (dev_priv->vbt.dsi.seq_version >= 3)
> + data++;
> +
> /* execute the element specific rotines */
> data = mipi_elem_exec(intel_dsi, data);
>
> --
> 1.7.9.5
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
--
Jani Nikula, Intel Open Source Technology Center
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
next prev parent reply other threads:[~2015-09-17 14:35 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-09-09 23:24 [MIPI SEQ PARSING v2 PATCH 00/11] Patches to support the version 3 of MIPI sequence in VBT Deepak M
2015-09-09 23:24 ` [MIPI SEQ PARSING v2 PATCH 01/11] drm/i915: Adding the parsing logic for the i2c element Deepak M
2015-09-17 9:18 ` Jani Nikula
2015-09-22 6:46 ` Deepak, M
2015-09-09 23:24 ` [MIPI SEQ PARSING v2 PATCH 02/11] drm/i915: Updating asle structure with new fields Deepak M
2015-09-09 23:24 ` [MIPI SEQ PARSING v2 PATCH 03/11] drm/i915: Parsing VBT if size of VBT exceeds 6KB Deepak M
2015-09-16 13:24 ` Jani Nikula
2015-09-17 12:10 ` Jani Nikula
2015-09-22 6:37 ` Deepak, M
2015-09-22 7:24 ` Jani Nikula
2015-09-09 23:24 ` [MIPI SEQ PARSING v2 PATCH 04/11] drm/i915: Using the approprite vbt size if vbt is not in mailbox4 of opregion Deepak M
2015-09-17 12:18 ` Jani Nikula
2015-09-17 13:31 ` Jani Nikula
2015-09-22 6:11 ` Deepak, M
2015-09-22 6:24 ` Deepak, M
2015-09-09 23:24 ` [MIPI SEQ PARSING v2 PATCH 05/11] drm/i915: Added support the v3 mipi sequence block Deepak M
2015-09-17 14:38 ` Jani Nikula [this message]
2015-09-22 6:23 ` Deepak, M
2015-09-09 23:24 ` [MIPI SEQ PARSING v2 PATCH 06/11] drm/i915: extending gpio read/write to other cores Deepak M
2015-09-09 23:24 ` [MIPI SEQ PARSING v2 PATCH 07/11] drm/i915: Added the generic gpio sequence support and gpio table Deepak M
2015-09-17 14:44 ` Jani Nikula
2015-09-09 23:24 ` [MIPI SEQ PARSING v2 PATCH 08/11] drm/i915: GPIO for CHT generic MIPI Deepak M
2015-09-09 23:24 ` [MIPI SEQ PARSING v2 PATCH 09/11] drm: Add few more wrapper functions for drm panel Deepak M
2015-09-09 23:24 ` [MIPI SEQ PARSING v2 PATCH 10/11] drm/i915: Add functions to execute the new sequences from VBT Deepak M
2015-09-09 23:24 ` [MIPI SEQ PARSING v2 PATCH 11/11] drm/i915: BXT GPIO support for backlight and panel control Deepak M
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=876139t8jv.fsf@intel.com \
--to=jani.nikula@linux.intel.com \
--cc=intel-gfx@lists.freedesktop.org \
--cc=m.deepak@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox