[Intel-gfx] [MIPI SEQ PARSING v2 PATCH 05/11] drm/i915: Added support the v3 mipi sequence block
Deepak, M
m.deepak at intel.com
Mon Sep 21 23:23:10 PDT 2015
>-----Original Message-----
>From: Jani Nikula [mailto:jani.nikula at linux.intel.com]
>Sent: Thursday, September 17, 2015 8:09 PM
>To: Deepak, M; intel-gfx at lists.freedesktop.org
>Cc: Deepak, M
>Subject: Re: [Intel-gfx] [MIPI SEQ PARSING v2 PATCH 05/11] drm/i915: Added
>support the v3 mipi sequence block
>
>On Thu, 10 Sep 2015, Deepak M <m.deepak at intel.com> wrote:
>> From: vkorjani <vikas.korjani at 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 at intel.com>
>> Signed-off-by: Deepak M <m.deepak at 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 at 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...
>
[Deepak M] Okay will try to simplify the logic.
>> +
>> + /* 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 at lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>
>--
>Jani Nikula, Intel Open Source Technology Center
More information about the Intel-gfx
mailing list