--- zzzz-none-000/linux-4.4.271/drivers/mtd/bcm47xxpart.c 2021-06-03 06:22:09.000000000 +0000 +++ hawkeye-5590-750/linux-4.4.271/drivers/mtd/bcm47xxpart.c 2023-04-19 10:22:29.000000000 +0000 @@ -38,6 +38,7 @@ #define NVRAM_HEADER 0x48534C46 /* FLSH */ #define POT_MAGIC1 0x54544f50 /* POTT */ #define POT_MAGIC2 0x504f /* OP */ +#define T_METER_MAGIC 0x4D540000 /* MT */ #define ML_MAGIC1 0x39685a42 #define ML_MAGIC2 0x26594131 #define TRX_MAGIC 0x30524448 @@ -61,6 +62,34 @@ part->mask_flags = mask_flags; } +/* + * Calculate real end offset (address) for a given amount of data. It checks + * all blocks skipping bad ones. + */ +static size_t bcm47xxpart_real_offset(struct mtd_info *master, size_t offset, + size_t bytes) +{ + size_t real_offset = offset; + + if (mtd_block_isbad(master, real_offset)) + pr_warn("Base offset shouldn't be at bad block"); + + while (bytes >= master->erasesize) { + bytes -= master->erasesize; + real_offset += master->erasesize; + while (mtd_block_isbad(master, real_offset)) { + real_offset += master->erasesize; + + if (real_offset >= master->size) + return real_offset - master->erasesize; + } + } + + real_offset += bytes; + + return real_offset; +} + static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master, size_t offset) { @@ -180,8 +209,19 @@ continue; } + /* T_Meter */ + if ((le32_to_cpu(buf[0x000 / 4]) & 0xFFFF0000) == T_METER_MAGIC && + (le32_to_cpu(buf[0x030 / 4]) & 0xFFFF0000) == T_METER_MAGIC && + (le32_to_cpu(buf[0x060 / 4]) & 0xFFFF0000) == T_METER_MAGIC) { + bcm47xxpart_add_part(&parts[curr_part++], "T_Meter", offset, + MTD_WRITEABLE); + continue; + } + /* TRX */ if (buf[0x000 / 4] == TRX_MAGIC) { + uint32_t tmp; + if (BCM47XXPART_MAX_PARTS - curr_part < 4) { pr_warn("Not enough partitions left to register trx, scanning stopped!\n"); break; @@ -196,18 +236,18 @@ i = 0; /* We have LZMA loader if offset[2] points to sth */ if (trx->offset[2]) { + tmp = bcm47xxpart_real_offset(master, offset, + trx->offset[i]); bcm47xxpart_add_part(&parts[curr_part++], - "loader", - offset + trx->offset[i], - 0); + "loader", tmp, 0); i++; } if (trx->offset[i]) { + tmp = bcm47xxpart_real_offset(master, offset, + trx->offset[i]); bcm47xxpart_add_part(&parts[curr_part++], - "linux", - offset + trx->offset[i], - 0); + "linux", tmp, 0); i++; } @@ -219,11 +259,11 @@ if (trx->offset[i]) { const char *name; - name = bcm47xxpart_trx_data_part_name(master, offset + trx->offset[i]); + tmp = bcm47xxpart_real_offset(master, offset, + trx->offset[i]); + name = bcm47xxpart_trx_data_part_name(master, tmp); bcm47xxpart_add_part(&parts[curr_part++], - name, - offset + trx->offset[i], - 0); + name, tmp, 0); i++; }