Commit 2cd63e48 authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab

[media] drx-j: Split firmware size check from the main routine

The firmware upload routine is already complex enough. Split the
first loop that verifies the firmware size into a separate routine,
making the code more readable.
Acked-by: default avatarDevin Heitmueller <dheitmueller@kernellabs.com>
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
parent b48293db
...@@ -933,6 +933,86 @@ static u16 u_code_compute_crc(u8 *block_data, u16 nr_words) ...@@ -933,6 +933,86 @@ static u16 u_code_compute_crc(u8 *block_data, u16 nr_words)
/*============================================================================*/ /*============================================================================*/
static int check_firmware(struct drx_demod_instance *demod, u8 *mc_data,
unsigned size)
{
struct drxu_code_block_hdr block_hdr;
int i;
unsigned count = 2 * sizeof(u16);
u32 mc_dev_type, mc_version, mc_base_version;
u16 mc_nr_of_blks = u_code_read16(mc_data + sizeof(u16));
/*
* Scan microcode blocks first for version info
* and firmware check
*/
/* Clear version block */
DRX_ATTR_MCRECORD(demod).aux_type = 0;
DRX_ATTR_MCRECORD(demod).mc_dev_type = 0;
DRX_ATTR_MCRECORD(demod).mc_version = 0;
DRX_ATTR_MCRECORD(demod).mc_base_version = 0;
for (i = 0; i < mc_nr_of_blks; i++) {
if (count + 3 * sizeof(u16) + sizeof(u32) > size)
goto eof;
/* Process block header */
block_hdr.addr = u_code_read32(mc_data + count);
count += sizeof(u32);
block_hdr.size = u_code_read16(mc_data + count);
count += sizeof(u16);
block_hdr.flags = u_code_read16(mc_data + count);
count += sizeof(u16);
block_hdr.CRC = u_code_read16(mc_data + count);
count += sizeof(u16);
pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n",
count, block_hdr.addr, block_hdr.size, block_hdr.flags,
block_hdr.CRC);
if (block_hdr.flags & 0x8) {
u8 *auxblk = ((void *)mc_data) + block_hdr.addr;
u16 auxtype;
if (block_hdr.addr + sizeof(u16) > size)
goto eof;
auxtype = u_code_read16(auxblk);
/* Aux block. Check type */
if (DRX_ISMCVERTYPE(auxtype)) {
if (block_hdr.addr + 2 * sizeof(u16) + 2 * sizeof (u32) > size)
goto eof;
auxblk += sizeof(u16);
mc_dev_type = u_code_read32(auxblk);
auxblk += sizeof(u32);
mc_version = u_code_read32(auxblk);
auxblk += sizeof(u32);
mc_base_version = u_code_read32(auxblk);
DRX_ATTR_MCRECORD(demod).aux_type = auxtype;
DRX_ATTR_MCRECORD(demod).mc_dev_type = mc_dev_type;
DRX_ATTR_MCRECORD(demod).mc_version = mc_version;
DRX_ATTR_MCRECORD(demod).mc_base_version = mc_base_version;
pr_info("Firmware dev %x, ver %x, base ver %x\n",
mc_dev_type, mc_version, mc_base_version);
}
} else if (count + block_hdr.size * sizeof(u16) > size)
goto eof;
count += block_hdr.size * sizeof(u16);
}
return 0;
eof:
pr_err("Firmware is truncated at pos %u/%u\n", count, size);
return -EINVAL;
}
/** /**
* \brief Handle microcode upload or verify. * \brief Handle microcode upload or verify.
* \param dev_addr: Address of device. * \param dev_addr: Address of device.
...@@ -962,24 +1042,15 @@ ctrl_u_code(struct drx_demod_instance *demod, ...@@ -962,24 +1042,15 @@ ctrl_u_code(struct drx_demod_instance *demod,
u16 mc_magic_word = 0; u16 mc_magic_word = 0;
const u8 *mc_data_init = NULL; const u8 *mc_data_init = NULL;
u8 *mc_data = NULL; u8 *mc_data = NULL;
unsigned size;
char *mc_file = mc_info->mc_file; char *mc_file = mc_info->mc_file;
/* Check arguments */ /* Check arguments */
if (!mc_info || !mc_file) if (!mc_info || !mc_file)
return -EINVAL; return -EINVAL;
if (demod->firmware) { if (!demod->firmware) {
mc_data_init = demod->firmware->data;
mc_data = (void *)mc_data_init;
/* Check data */
mc_magic_word = u_code_read16(mc_data);
mc_data += sizeof(u16);
mc_nr_of_blks = u_code_read16(mc_data);
mc_data += sizeof(u16);
} else {
const struct firmware *fw = NULL; const struct firmware *fw = NULL;
unsigned size = 0;
rc = request_firmware(&fw, mc_file, demod->i2c->dev.parent); rc = request_firmware(&fw, mc_file, demod->i2c->dev.parent);
if (rc < 0) { if (rc < 0) {
...@@ -987,95 +1058,49 @@ ctrl_u_code(struct drx_demod_instance *demod, ...@@ -987,95 +1058,49 @@ ctrl_u_code(struct drx_demod_instance *demod,
return -ENOENT; return -ENOENT;
} }
demod->firmware = fw; demod->firmware = fw;
if (demod->firmware->size < 2 * sizeof(u16)) {
rc = -EINVAL;
pr_err("Firmware is too short!\n");
goto release;
}
pr_info("Firmware %s, size %zu\n",
mc_file, demod->firmware->size);
}
mc_data_init = demod->firmware->data; mc_data_init = demod->firmware->data;
size = demod->firmware->size; size = demod->firmware->size;
pr_info("Firmware %s, size %u\n", mc_file, size);
mc_data = (void *)mc_data_init; mc_data = (void *)mc_data_init;
/* Check data */ /* Check data */
if (mc_data - mc_data_init + 2 * sizeof(u16) > size)
goto eof;
mc_magic_word = u_code_read16(mc_data); mc_magic_word = u_code_read16(mc_data);
mc_data += sizeof(u16); mc_data += sizeof(u16);
mc_nr_of_blks = u_code_read16(mc_data); mc_nr_of_blks = u_code_read16(mc_data);
mc_data += sizeof(u16); mc_data += sizeof(u16);
if ((mc_magic_word != DRX_UCODE_MAGIC_WORD) || (mc_nr_of_blks == 0)) { if ((mc_magic_word != DRX_UCODE_MAGIC_WORD) || (mc_nr_of_blks == 0)) {
rc = -EINVAL; /* wrong endianess or wrong data ? */ rc = -EINVAL;
pr_err("Firmware magic word doesn't match\n"); pr_err("Firmware magic word doesn't match\n");
goto release; goto release;
} }
/*
* Scan microcode blocks first for version info
* and firmware check
*/
/* Clear version block */
DRX_ATTR_MCRECORD(demod).aux_type = 0;
DRX_ATTR_MCRECORD(demod).mc_dev_type = 0;
DRX_ATTR_MCRECORD(demod).mc_version = 0;
DRX_ATTR_MCRECORD(demod).mc_base_version = 0;
for (i = 0; i < mc_nr_of_blks; i++) {
struct drxu_code_block_hdr block_hdr;
if (mc_data - mc_data_init +
3 * sizeof(u16) + sizeof(u32) > size)
goto eof;
/* Process block header */
block_hdr.addr = u_code_read32(mc_data);
mc_data += sizeof(u32);
block_hdr.size = u_code_read16(mc_data);
mc_data += sizeof(u16);
block_hdr.flags = u_code_read16(mc_data);
mc_data += sizeof(u16);
block_hdr.CRC = u_code_read16(mc_data);
mc_data += sizeof(u16);
if (block_hdr.flags & 0x8) {
u8 *auxblk = ((void *)mc_data_init) + block_hdr.addr;
u16 auxtype;
if (mc_data - mc_data_init + sizeof(u16) +
2 * sizeof(u32) > size)
goto eof;
/* Aux block. Check type */
auxtype = u_code_read16(auxblk);
if (DRX_ISMCVERTYPE(auxtype)) {
DRX_ATTR_MCRECORD(demod).aux_type = u_code_read16(auxblk);
auxblk += sizeof(u16);
DRX_ATTR_MCRECORD(demod).mc_dev_type = u_code_read32(auxblk);
auxblk += sizeof(u32);
DRX_ATTR_MCRECORD(demod).mc_version = u_code_read32(auxblk);
auxblk += sizeof(u32);
DRX_ATTR_MCRECORD(demod).mc_base_version = u_code_read32(auxblk);
}
}
if (mc_data - mc_data_init +
block_hdr.size * sizeof(u16) > size)
goto eof;
/* Next block */
mc_data += block_hdr.size * sizeof(u16);
}
/* Restore data pointer */
mc_data = ((void *)mc_data_init) + 2 * sizeof(u16);
}
if (action == UCODE_UPLOAD) { if (action == UCODE_UPLOAD) {
rc = check_firmware(demod, (u8 *)mc_data_init, size);
if (rc)
goto release;
/* After scanning, validate the microcode. /* After scanning, validate the microcode.
It is also valid if no validation control exists. It is also valid if no validation control exists.
*/ */
rc = drx_ctrl(demod, DRX_CTRL_VALIDATE_UCODE, NULL); rc = drx_ctrl(demod, DRX_CTRL_VALIDATE_UCODE, NULL);
if (rc != 0 && rc != -ENOTSUPP) { if (rc != 0 && rc != -ENOTSUPP) {
pr_err("Validate ucode not supported\n"); pr_err("Validate ucode not supported\n");
goto release; return rc;
} }
pr_info("Uploading firmware %s\n", mc_file); pr_info("Uploading firmware %s\n", mc_file);
} else if (action == UCODE_VERIFY) {
pr_info("Verifying if firmware upload was ok.\n");
} }
/* Process microcode blocks */ /* Process microcode blocks */
...@@ -1093,6 +1118,10 @@ ctrl_u_code(struct drx_demod_instance *demod, ...@@ -1093,6 +1118,10 @@ ctrl_u_code(struct drx_demod_instance *demod,
block_hdr.CRC = u_code_read16(mc_data); block_hdr.CRC = u_code_read16(mc_data);
mc_data += sizeof(u16); mc_data += sizeof(u16);
pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n",
(unsigned)(mc_data - mc_data_init), block_hdr.addr,
block_hdr.size, block_hdr.flags, block_hdr.CRC);
/* Check block header on: /* Check block header on:
- data larger than 64Kb - data larger than 64Kb
- if CRC enabled check CRC - if CRC enabled check CRC
...@@ -1114,17 +1143,18 @@ ctrl_u_code(struct drx_demod_instance *demod, ...@@ -1114,17 +1143,18 @@ ctrl_u_code(struct drx_demod_instance *demod,
/* Perform the desired action */ /* Perform the desired action */
switch (action) { switch (action) {
case UCODE_UPLOAD: case UCODE_UPLOAD: /* Upload microcode */
/* Upload microcode */
if (demod->my_access_funct->write_block_func(dev_addr, if (demod->my_access_funct->write_block_func(dev_addr,
block_hdr.addr, block_hdr.addr,
mc_block_nr_bytes, mc_block_nr_bytes,
mc_data, 0x0000)) { mc_data, 0x0000)) {
pr_err("error writing firmware\n"); rc = -EIO;
pr_err("error writing firmware at pos %u\n",
(unsigned)(mc_data - mc_data_init));
goto release; goto release;
} }
break; break;
case UCODE_VERIFY: { case UCODE_VERIFY: { /* Verify uploaded microcode */
int result = 0; int result = 0;
u8 mc_data_buffer[DRX_UCODE_MAX_BUF_SIZE]; u8 mc_data_buffer[DRX_UCODE_MAX_BUF_SIZE];
u32 bytes_to_comp = 0; u32 bytes_to_comp = 0;
...@@ -1144,8 +1174,9 @@ ctrl_u_code(struct drx_demod_instance *demod, ...@@ -1144,8 +1174,9 @@ ctrl_u_code(struct drx_demod_instance *demod,
(u16)bytes_to_comp, (u16)bytes_to_comp,
(u8 *)mc_data_buffer, (u8 *)mc_data_buffer,
0x0000)) { 0x0000)) {
pr_err("error reading firmware\n"); pr_err("error reading firmware at pos %u\n",
goto release; (unsigned)(mc_data - mc_data_init));
return -EIO;
} }
result =drxbsp_hst_memcmp(curr_ptr, result =drxbsp_hst_memcmp(curr_ptr,
...@@ -1153,7 +1184,8 @@ ctrl_u_code(struct drx_demod_instance *demod, ...@@ -1153,7 +1184,8 @@ ctrl_u_code(struct drx_demod_instance *demod,
bytes_to_comp); bytes_to_comp);
if (result) { if (result) {
pr_err("error verifying firmware\n"); pr_err("error verifying firmware at pos %u\n",
(unsigned)(mc_data - mc_data_init));
return -EIO; return -EIO;
} }
...@@ -1172,10 +1204,7 @@ ctrl_u_code(struct drx_demod_instance *demod, ...@@ -1172,10 +1204,7 @@ ctrl_u_code(struct drx_demod_instance *demod,
} }
return 0; return 0;
eof:
rc = -ENOENT;
pr_err("Firmware file %s is truncated at pos %lu\n",
mc_file, (unsigned long)(mc_data - mc_data_init));
release: release:
release_firmware(demod->firmware); release_firmware(demod->firmware);
demod->firmware = NULL; demod->firmware = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment