Skip to content

Commit 9a62657

Browse files
rfs613gregkh
authored andcommitted
nvmem: eeprom: at25: fix FRAM byte_len
Commit fd307a4 ("nvmem: prepare basics for FRAM support") added support for FRAM devices such as the Cypress FM25V. During testing, it was found that the FRAM detects properly, however reads and writes fail. Upon further investigation, two problem were found in at25_probe() routine. 1) In the case of an FRAM device without platform data, eg. fram == true && spi->dev.platform_data == NULL the stack local variable "struct spi_eeprom chip" is not initialized fully, prior to being copied into at25->chip. The chip.flags field in particular can cause problems. 2) The byte_len of FRAM is computed from its ID register, and is stored into the stack local "struct spi_eeprom chip" structure. This happens after the same structure has been copied into at25->chip. As a result, at25->chip.byte_len does not contain the correct length of the device. In turn this can cause checks at beginning of at25_ee_read() to fail (or equally, it could allow reads beyond the end of the device length). Fix both of these issues by eliminating the on-stack struct spi_eeprom. Instead use the one inside at25_data structure, which starts of zeroed. Fixes: fd307a4 ("nvmem: prepare basics for FRAM support") Cc: stable <[email protected]> Reviewed-by: Arnd Bergmann <[email protected]> Signed-off-by: Ralph Siemsen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 3a1bf59 commit 9a62657

File tree

1 file changed

+18
-20
lines changed

1 file changed

+18
-20
lines changed

drivers/misc/eeprom/at25.c

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,6 @@ MODULE_DEVICE_TABLE(spi, at25_spi_ids);
376376
static int at25_probe(struct spi_device *spi)
377377
{
378378
struct at25_data *at25 = NULL;
379-
struct spi_eeprom chip;
380379
int err;
381380
int sr;
382381
u8 id[FM25_ID_LEN];
@@ -389,15 +388,18 @@ static int at25_probe(struct spi_device *spi)
389388
if (match && !strcmp(match->compatible, "cypress,fm25"))
390389
is_fram = 1;
391390

391+
at25 = devm_kzalloc(&spi->dev, sizeof(struct at25_data), GFP_KERNEL);
392+
if (!at25)
393+
return -ENOMEM;
394+
392395
/* Chip description */
393-
if (!spi->dev.platform_data) {
394-
if (!is_fram) {
395-
err = at25_fw_to_chip(&spi->dev, &chip);
396-
if (err)
397-
return err;
398-
}
399-
} else
400-
chip = *(struct spi_eeprom *)spi->dev.platform_data;
396+
if (spi->dev.platform_data) {
397+
memcpy(&at25->chip, spi->dev.platform_data, sizeof(at25->chip));
398+
} else if (!is_fram) {
399+
err = at25_fw_to_chip(&spi->dev, &at25->chip);
400+
if (err)
401+
return err;
402+
}
401403

402404
/* Ping the chip ... the status register is pretty portable,
403405
* unlike probing manufacturer IDs. We do expect that system
@@ -409,12 +411,7 @@ static int at25_probe(struct spi_device *spi)
409411
return -ENXIO;
410412
}
411413

412-
at25 = devm_kzalloc(&spi->dev, sizeof(struct at25_data), GFP_KERNEL);
413-
if (!at25)
414-
return -ENOMEM;
415-
416414
mutex_init(&at25->lock);
417-
at25->chip = chip;
418415
at25->spi = spi;
419416
spi_set_drvdata(spi, at25);
420417

@@ -431,7 +428,7 @@ static int at25_probe(struct spi_device *spi)
431428
dev_err(&spi->dev, "Error: unsupported size (id %02x)\n", id[7]);
432429
return -ENODEV;
433430
}
434-
chip.byte_len = int_pow(2, id[7] - 0x21 + 4) * 1024;
431+
at25->chip.byte_len = int_pow(2, id[7] - 0x21 + 4) * 1024;
435432

436433
if (at25->chip.byte_len > 64 * 1024)
437434
at25->chip.flags |= EE_ADDR3;
@@ -464,7 +461,7 @@ static int at25_probe(struct spi_device *spi)
464461
at25->nvmem_config.type = is_fram ? NVMEM_TYPE_FRAM : NVMEM_TYPE_EEPROM;
465462
at25->nvmem_config.name = dev_name(&spi->dev);
466463
at25->nvmem_config.dev = &spi->dev;
467-
at25->nvmem_config.read_only = chip.flags & EE_READONLY;
464+
at25->nvmem_config.read_only = at25->chip.flags & EE_READONLY;
468465
at25->nvmem_config.root_only = true;
469466
at25->nvmem_config.owner = THIS_MODULE;
470467
at25->nvmem_config.compat = true;
@@ -474,17 +471,18 @@ static int at25_probe(struct spi_device *spi)
474471
at25->nvmem_config.priv = at25;
475472
at25->nvmem_config.stride = 1;
476473
at25->nvmem_config.word_size = 1;
477-
at25->nvmem_config.size = chip.byte_len;
474+
at25->nvmem_config.size = at25->chip.byte_len;
478475

479476
at25->nvmem = devm_nvmem_register(&spi->dev, &at25->nvmem_config);
480477
if (IS_ERR(at25->nvmem))
481478
return PTR_ERR(at25->nvmem);
482479

483480
dev_info(&spi->dev, "%d %s %s %s%s, pagesize %u\n",
484-
(chip.byte_len < 1024) ? chip.byte_len : (chip.byte_len / 1024),
485-
(chip.byte_len < 1024) ? "Byte" : "KByte",
481+
(at25->chip.byte_len < 1024) ?
482+
at25->chip.byte_len : (at25->chip.byte_len / 1024),
483+
(at25->chip.byte_len < 1024) ? "Byte" : "KByte",
486484
at25->chip.name, is_fram ? "fram" : "eeprom",
487-
(chip.flags & EE_READONLY) ? " (readonly)" : "",
485+
(at25->chip.flags & EE_READONLY) ? " (readonly)" : "",
488486
at25->chip.page_size);
489487
return 0;
490488
}

0 commit comments

Comments
 (0)