Loading drivers/gpu/msm/adreno_a5xx.c +13 −206 Original line number Diff line number Diff line Loading @@ -728,187 +728,17 @@ static int _gpmu_create_load_cmds(struct adreno_device *adreno_dev, return 0; } static int _gpmu_verify_header(struct adreno_device *adreno_dev, uint32_t *header, uint32_t fw_size) { unsigned int i; const struct adreno_gpu_core *gpucore = adreno_dev->gpucore; unsigned int gpmu_major_offset = 0, gpmu_minor_offset = 0; unsigned int gpmu_major, gpmu_minor; uint32_t header_size; header_size = header[0]; /* * The minimum firmware binary size is eight dwords, one for each of * the following fields: GPMU header block length, header block ID, * major tag, major vlaue, minor tag, minor value, ucode block length, * and ucode block ID. */ if (fw_size < 8) { KGSL_CORE_ERR("GPMU firmware size is less than 8 dwords, actual size %d\n", fw_size); return -EIO; } /* * The minimum firmware header size is five dwords, one for each of * the following fields: GPMU header block ID, major tag, major value, * minor tag, minor value. */ if (header_size < 5) { KGSL_CORE_ERR("GPMU firmware header size is less than 5 dwords, actual size %d\n", header_size); return -EIO; } if (header_size >= fw_size) { KGSL_CORE_ERR("GPMU firmware header size (%d) is larger than firmware size (%d)\n", header_size, fw_size); return -EIO; } if (header[1] != GPMU_HEADER_ID) { KGSL_CORE_ERR("GPMU firmware header ID mis-match: expected 0x%X, actual 0x%X\n", GPMU_HEADER_ID, header[1]); return -EIO; } if ((header_size - 1) % 2 != 0) { KGSL_CORE_ERR("GPMU firmware header contains incompete (tag, value) pair\n"); return -EIO; } for (i = 2; i < header_size; i += 2) { switch (header[i]) { case HEADER_MAJOR: gpmu_major_offset = i; gpmu_major = header[i + 1]; break; case HEADER_MINOR: gpmu_minor_offset = i; gpmu_minor = header[i + 1]; break; case HEADER_DATE: case HEADER_TIME: break; default: KGSL_CORE_ERR("GPMU unknown header ID %d\n", header[i]); break; } } if (gpmu_major_offset == 0) { KGSL_CORE_ERR("GPMU major version number is missing\n"); return -EIO; } if (gpmu_minor_offset == 0) { KGSL_CORE_ERR("GPMU minor version number is missing\n"); return -EIO; } /* * A value of 0 for both the Major and Minor version fields indicates * the code is un-versioned, and should be allowed to pass all * versioning checks. */ if ((gpmu_major != 0) || (gpmu_minor != 0)) { if (gpucore->gpmu_major != gpmu_major) { KGSL_CORE_ERR( "GPMU major version mis-match: expected %d, actual %d\n", gpucore->gpmu_major, gpmu_major); return -EIO; } /* * Driver should be compatible for firmware with * smaller minor version number. */ if (gpucore->gpmu_minor < gpmu_minor) { KGSL_CORE_ERR( "GPMU minor version mis-match: expected %d, actual %d\n", gpucore->gpmu_minor, gpmu_minor); return -EIO; } } return 0; } static int _gpmu_verify_ucode(struct adreno_device *adreno_dev, uint32_t *data, uint32_t fw_size) { uint32_t header_size = data[0]; uint32_t *block = &data[header_size + 1]; uint32_t block_size = block[0]; uint32_t block_id = block[1]; if (block_size == 0) { KGSL_CORE_ERR("GPMU firmware block size is zero\n"); return -EIO; } /* * Deduct one (block length field) from the firmware block size to * get the microcode size. */ block_size -= 1; if (block_size > GPMU_INST_RAM_SIZE) { KGSL_CORE_ERR( "GPMU firmware block size is larger than RAM size\n"); return -EIO; } /* * The actual microcode size is fw_size - header_size - 2, with * the two block length dword fields deducted. */ if (block_size > fw_size - header_size - 2) { KGSL_CORE_ERR("GPMU firmware microcode size (%d) larger than actual (%d)\n", block_size, fw_size - header_size - 2); return -EIO; } if (block_id != GPMU_FIRMWARE_ID) { KGSL_CORE_ERR("GPMU firmware id not mis-match: expected 0x%X, actual 0x%X\n", GPMU_FIRMWARE_ID, block_id); return -EIO; } return 0; } /* * _load_gpmu_firmware() - Load the ucode into the GPMU RAM * @adreno_dev: Pointer to adreno device * GPMU firmare format (one dword per field): * Header block length (length dword field not inclusive) * Header block ID * Header Field 1 tag * Header Field 1 data * Header Field 2 tag * Header Field 2 data (two tag/data pairs minimum for major and minor) * . . . * Header Field M tag * Header Field M data * Microcode block length (length dword field not inclusive) * Microcode block ID * Microcode data Dword 1 * Microcode data Dword 2 * . . . * Microcode data Dword N */ static int _load_gpmu_firmware(struct adreno_device *adreno_dev) { uint32_t *data, *header; uint32_t *data; const struct firmware *fw = NULL; struct kgsl_device *device = &adreno_dev->dev; const struct adreno_gpu_core *gpucore = adreno_dev->gpucore; uint32_t fw_size, header_size; uint32_t *cmds, cmd_size; int ret = -EINVAL; Loading @@ -930,30 +760,8 @@ static int _load_gpmu_firmware(struct adreno_device *adreno_dev) } data = (uint32_t *)fw->data; fw_size = fw->size / sizeof(uint32_t); if (data[0] == 9) { /* Legacy file header */ /* Read header block and verify versioning first */ ret = _gpmu_verify_header(adreno_dev, data, fw_size); if (ret) goto err; /* Now verify the block data */ ret = _gpmu_verify_ucode(adreno_dev, data, fw_size); if (ret) goto err; header = &data[0]; header_size = header[0]; cmds = data + header_size + 1 + 2; cmd_size = data[header_size + 1] - 1; } else { /* New file header */ if (data[0] >= fw_size || data[0] < 2) if (data[0] >= (fw->size / sizeof(uint32_t)) || data[0] < 2) goto err; if (data[1] != GPMU_FIRMWARE_ID) Loading @@ -967,7 +775,6 @@ static int _load_gpmu_firmware(struct adreno_device *adreno_dev) cmds = data + data[2] + 3; cmd_size = data[0] - data[2] - 2; } if (cmd_size > GPMU_INST_RAM_SIZE) { KGSL_CORE_ERR( Loading Loading
drivers/gpu/msm/adreno_a5xx.c +13 −206 Original line number Diff line number Diff line Loading @@ -728,187 +728,17 @@ static int _gpmu_create_load_cmds(struct adreno_device *adreno_dev, return 0; } static int _gpmu_verify_header(struct adreno_device *adreno_dev, uint32_t *header, uint32_t fw_size) { unsigned int i; const struct adreno_gpu_core *gpucore = adreno_dev->gpucore; unsigned int gpmu_major_offset = 0, gpmu_minor_offset = 0; unsigned int gpmu_major, gpmu_minor; uint32_t header_size; header_size = header[0]; /* * The minimum firmware binary size is eight dwords, one for each of * the following fields: GPMU header block length, header block ID, * major tag, major vlaue, minor tag, minor value, ucode block length, * and ucode block ID. */ if (fw_size < 8) { KGSL_CORE_ERR("GPMU firmware size is less than 8 dwords, actual size %d\n", fw_size); return -EIO; } /* * The minimum firmware header size is five dwords, one for each of * the following fields: GPMU header block ID, major tag, major value, * minor tag, minor value. */ if (header_size < 5) { KGSL_CORE_ERR("GPMU firmware header size is less than 5 dwords, actual size %d\n", header_size); return -EIO; } if (header_size >= fw_size) { KGSL_CORE_ERR("GPMU firmware header size (%d) is larger than firmware size (%d)\n", header_size, fw_size); return -EIO; } if (header[1] != GPMU_HEADER_ID) { KGSL_CORE_ERR("GPMU firmware header ID mis-match: expected 0x%X, actual 0x%X\n", GPMU_HEADER_ID, header[1]); return -EIO; } if ((header_size - 1) % 2 != 0) { KGSL_CORE_ERR("GPMU firmware header contains incompete (tag, value) pair\n"); return -EIO; } for (i = 2; i < header_size; i += 2) { switch (header[i]) { case HEADER_MAJOR: gpmu_major_offset = i; gpmu_major = header[i + 1]; break; case HEADER_MINOR: gpmu_minor_offset = i; gpmu_minor = header[i + 1]; break; case HEADER_DATE: case HEADER_TIME: break; default: KGSL_CORE_ERR("GPMU unknown header ID %d\n", header[i]); break; } } if (gpmu_major_offset == 0) { KGSL_CORE_ERR("GPMU major version number is missing\n"); return -EIO; } if (gpmu_minor_offset == 0) { KGSL_CORE_ERR("GPMU minor version number is missing\n"); return -EIO; } /* * A value of 0 for both the Major and Minor version fields indicates * the code is un-versioned, and should be allowed to pass all * versioning checks. */ if ((gpmu_major != 0) || (gpmu_minor != 0)) { if (gpucore->gpmu_major != gpmu_major) { KGSL_CORE_ERR( "GPMU major version mis-match: expected %d, actual %d\n", gpucore->gpmu_major, gpmu_major); return -EIO; } /* * Driver should be compatible for firmware with * smaller minor version number. */ if (gpucore->gpmu_minor < gpmu_minor) { KGSL_CORE_ERR( "GPMU minor version mis-match: expected %d, actual %d\n", gpucore->gpmu_minor, gpmu_minor); return -EIO; } } return 0; } static int _gpmu_verify_ucode(struct adreno_device *adreno_dev, uint32_t *data, uint32_t fw_size) { uint32_t header_size = data[0]; uint32_t *block = &data[header_size + 1]; uint32_t block_size = block[0]; uint32_t block_id = block[1]; if (block_size == 0) { KGSL_CORE_ERR("GPMU firmware block size is zero\n"); return -EIO; } /* * Deduct one (block length field) from the firmware block size to * get the microcode size. */ block_size -= 1; if (block_size > GPMU_INST_RAM_SIZE) { KGSL_CORE_ERR( "GPMU firmware block size is larger than RAM size\n"); return -EIO; } /* * The actual microcode size is fw_size - header_size - 2, with * the two block length dword fields deducted. */ if (block_size > fw_size - header_size - 2) { KGSL_CORE_ERR("GPMU firmware microcode size (%d) larger than actual (%d)\n", block_size, fw_size - header_size - 2); return -EIO; } if (block_id != GPMU_FIRMWARE_ID) { KGSL_CORE_ERR("GPMU firmware id not mis-match: expected 0x%X, actual 0x%X\n", GPMU_FIRMWARE_ID, block_id); return -EIO; } return 0; } /* * _load_gpmu_firmware() - Load the ucode into the GPMU RAM * @adreno_dev: Pointer to adreno device * GPMU firmare format (one dword per field): * Header block length (length dword field not inclusive) * Header block ID * Header Field 1 tag * Header Field 1 data * Header Field 2 tag * Header Field 2 data (two tag/data pairs minimum for major and minor) * . . . * Header Field M tag * Header Field M data * Microcode block length (length dword field not inclusive) * Microcode block ID * Microcode data Dword 1 * Microcode data Dword 2 * . . . * Microcode data Dword N */ static int _load_gpmu_firmware(struct adreno_device *adreno_dev) { uint32_t *data, *header; uint32_t *data; const struct firmware *fw = NULL; struct kgsl_device *device = &adreno_dev->dev; const struct adreno_gpu_core *gpucore = adreno_dev->gpucore; uint32_t fw_size, header_size; uint32_t *cmds, cmd_size; int ret = -EINVAL; Loading @@ -930,30 +760,8 @@ static int _load_gpmu_firmware(struct adreno_device *adreno_dev) } data = (uint32_t *)fw->data; fw_size = fw->size / sizeof(uint32_t); if (data[0] == 9) { /* Legacy file header */ /* Read header block and verify versioning first */ ret = _gpmu_verify_header(adreno_dev, data, fw_size); if (ret) goto err; /* Now verify the block data */ ret = _gpmu_verify_ucode(adreno_dev, data, fw_size); if (ret) goto err; header = &data[0]; header_size = header[0]; cmds = data + header_size + 1 + 2; cmd_size = data[header_size + 1] - 1; } else { /* New file header */ if (data[0] >= fw_size || data[0] < 2) if (data[0] >= (fw->size / sizeof(uint32_t)) || data[0] < 2) goto err; if (data[1] != GPMU_FIRMWARE_ID) Loading @@ -967,7 +775,6 @@ static int _load_gpmu_firmware(struct adreno_device *adreno_dev) cmds = data + data[2] + 3; cmd_size = data[0] - data[2] - 2; } if (cmd_size > GPMU_INST_RAM_SIZE) { KGSL_CORE_ERR( Loading