Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

flash: fix flash_read API for NXP LPC55S36 #80351

Merged

Conversation

pillo79
Copy link
Collaborator

@pillo79 pillo79 commented Oct 24, 2024

This PR reworks the LPC55S36 implementation of the flash_mcux_read() function to work around issue #80325. Feedback welcome!

This is achieved on the CONFIG_CHECK_BEFORE_READING path (the default) by using the FLASH_Read() HAL API call, which is resilient to errors, and map the error codes to properly emulate an erased page read.

When CONFIG_CHECK_BEFORE_READING is disabled, the code reverts to the previous memcpy() operation, which is faster but unsafe on erased or otherwise unreadable pages.

#ifdef guards kept in the style of the file, though some may be changed to if (IS_ENABLED(...)) if desired.

Fixes #80325

@pillo79 pillo79 marked this pull request as ready for review October 24, 2024 08:48
@zephyrbot zephyrbot added the platform: NXP Drivers NXP Semiconductors, drivers label Oct 24, 2024
@pillo79 pillo79 added the bug The issue is a bug, or the PR is fixing a bug label Oct 25, 2024
@pillo79
Copy link
Collaborator Author

pillo79 commented Oct 31, 2024

Friendly ping for any feedback after a week of silence 🙂
I know Zephyr is in freeze right now, but since this is a bugfix I think this would be useful in 4.0.

} else {
/* Check whether the flash is erased ("len" and "addr" must be word-aligned). */
rc = FLASH_VerifyErase(&priv->config, ((addr + 0x3) & ~0x3), ((len + 0x3) & ~0x3));
#if defined(CONFIG_CHECK_BEFORE_READING) && !defined(CONFIG_SOC_LPC55S36)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A suggestion here for readability- could we do something like this:

if (IS_ENABLED(CONFIG_CHECK_BEFORE_READING)) {
    if (IS_ENABLED(CONFIG_SOC_LPC55S36) {
        /* LPC55S36 specific logic */
    } else {
       rc = is_area_readable(addr, len)
    }
}

if (!rc) {
   memcpy(data, (void *)addr, len);
} else if ((rc == -ENODATA) && IS_ENABLED(CONFIG_CHECK_BEFORE_READING)) {
  /* Erased area, return dummy data as an erased page. */
  memset(data, 0xFF, len);
  rc = 0;
}
return rc;

Apologies if formatting there is confusing. At least IMO, the current function implementation in main is hard to follow, and I figure if we are fixing the bug cleaning up the readability wouldn't hurt either

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completely agree, but it's really a thorny situation. The FLASH_Read does a "copy before verify" which doesn't neatly fit in the previous model:

CHECK is set? on 55S36? Check stage Copy stage 0xff fill
no - no memcpy no
yes no is_area_readable memcpy yes
yes yes FLASH_Read + VerifyErased (already done) yes

My first proposal avoided any duplicate code, but ended up creating awkward logical groupings.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the explanation here, this makes more sense (and I really like the rework in the latest push, it is a lot easier to follow)

@pillo79 pillo79 force-pushed the pr-lpc55s36-fix-flash_read branch from 2766e22 to ec14af1 Compare November 3, 2024 12:04
@zephyrbot zephyrbot requested a review from rghaddab November 3, 2024 12:05
@pillo79 pillo79 force-pushed the pr-lpc55s36-fix-flash_read branch from ec14af1 to 292a0e5 Compare November 3, 2024 12:05
@pillo79
Copy link
Collaborator Author

pillo79 commented Nov 3, 2024

v2:

  • converted #ifdef ... to if (IS_ENABLED(...))
  • spelled out all cases to make it way easier to read

* Ensure the area is readable, since a direct access may cause faults on erased
* or otherwise unreadable pages. Emulate erased pages, return other errors.
*/
if (IS_ENABLED(CONFIG_SOC_LPC55S36)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pillo79 it looks like we may need more "#ifdefery", because some older NXP platforms don't define the FLASH_Read API at all. I think we probably need to use #ifdef here. Sorry for the poor guidance

@danieldegrasse
Copy link
Collaborator

On the next push can you reference the github issue within the commit message? IE add

Fixes #80325 to the commit message (at the end, before the signed-off-by-line)

As other targets in the LPC55xxx series, the LPC55S36 has a Flash
controller that raises ECC errors when reading erased pages directly.
To avoid this, there is special code for this platform that calls the
HAL FLASH_IsFlashAreaReadable() function. However, this in turn calls a
function at an hardcoded address in ROM that _always_ causes an
instruction fault, making the situation worse.

This patch reworks the read operation to use the FLASH_Read() HAL
function for this target to gracefully handle error conditions and
properly emulate accesses to erased pages. The preprocessor is required
since some targets do not define the FLASH_Read() function.

Fixes: zephyrproject-rtos#80325

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
@pillo79 pillo79 force-pushed the pr-lpc55s36-fix-flash_read branch from 292a0e5 to 9d78c65 Compare November 5, 2024 08:40
@pillo79
Copy link
Collaborator Author

pillo79 commented Nov 5, 2024

v3:

  • use preprocessor like in the original version
  • added PR reference to the commit message

OT: not sure why Twister decided to run 5000+ tests this time? 😅 🤷‍♂️

The current alignment logic does not work as expected if given unaligned
values, resulting in a skip of the first word. The length also has to
take into account the starting address: for example, asking for 2 bytes
at offset 3 should actually check 8 bytes.

This patch adjusts the logic so that it always includes the first and
the last word of the input area.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
@pillo79
Copy link
Collaborator Author

pillo79 commented Nov 5, 2024

Minor addition I spotted only now - fixed the alignment logic for FLASH_VerifyErase, which was too simple and did not properly enlarge the area.

@danieldegrasse danieldegrasse added this to the v4.0.0 milestone Nov 6, 2024
@danieldegrasse
Copy link
Collaborator

@de-nordic can you take a look?

/* Check id the ECC issue is due to the Flash being erased
* ("addr" and "len" must be word-aligned for this call).
*/
rc = FLASH_VerifyErase(&priv->config,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: wouldn't it be better to just ifdef the is_area_readable internally to use this method of verification, whether memory is readable, for CONFIG_SOC_LPC55S36, and then follow it with the memcopy or memset depending on result? Instead of reading first and then checking why it failed, and have streamlined code fall all devices supported?

As far as I understand the description for FLASH_VerifyErase in fsl_iap.h, it is able to tell whether there is ECC problem in range (btw NXP, the function no longer takes margin as parameter, yet you still mention it in description).

Additional note: IMHO making read check configurable makes no sense, because there is always a chance that ECC error will topple device instead of returning with error, unless of course you disable ECC,

Copy link
Collaborator

@de-nordic de-nordic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks OK, as far as I can tell.
Left a comment on potential place for streamlining execution here https://github.com/zephyrproject-rtos/zephyr/pull/80351/files#r1831641313, but that is up to the vendor here.

@mmahadevan108 mmahadevan108 merged commit 33def30 into zephyrproject-rtos:main Nov 7, 2024
23 checks passed
@pillo79 pillo79 deleted the pr-lpc55s36-fix-flash_read branch November 19, 2024 11:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: Flash bug The issue is a bug, or the PR is fixing a bug platform: NXP Drivers NXP Semiconductors, drivers platform: NXP NXP
Projects
None yet
Development

Successfully merging this pull request may close these issues.

nxp/lpc55s36: failure reading from internal Flash via flash_read()
5 participants