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

Cleanup cache initialization #66524

Merged

Conversation

benediktibk
Copy link
Collaborator

@benediktibk benediktibk commented Dec 14, 2023

Data and instruction cache initialization is currently a little bit messy. This PR aims at unifying the available config options and providing a more consistent approach on cache activation.

This is a follow up to #66443.

Open is to check where the caches were automatically enabled previously (SystemInit, Hal, ...) and disabling them directly after.

  • soc_rt10xx.c
  • soc_rt11xx.c
  • kv5x/soc.c
  • same70/soc.c
  • samv71/soc.c

Copy link
Collaborator

@carlocaione carlocaione left a comment

Choose a reason for hiding this comment

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

This is fixing the wrong way a pre-existing issue.

The issue is that the cache APIs must be used and not rely on architecture-specific operations like SCB_*. The guards are already included in the APIs, see https://github.com/zephyrproject-rtos/zephyr/blob/main/include/zephyr/cache.h

Comment on lines 221 to 223
if (IS_ENABLED(CONFIG_DCACHE)) {
arch_dcache_enable();
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

The problem here is that the architecture must not use arch_dcache_enable directly, but instead they have to rely on sys_cache_data_enable.

sys_cache_data_enable collapse to a NOP when !CONFIG_CACHE_MANAGEMENT or !CONFIG_DCACHE.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

fine for me, will change it

Copy link
Collaborator

@pillo79 pillo79 Dec 14, 2023

Choose a reason for hiding this comment

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

Forgive me if I'm wrong, but that would never turn on caches unless both of these settings were enabled, and it makes sense to be able to use the CPU cache but not the Cache API interface.
If using arch_ functions is wrong in this context, perhaps the suggestion should be to use a guarded cache_data_enable() instead?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Forgive me if I'm wrong, but that would never turn on caches unless both of these settings were enabled

Correct, and that is explained in https://docs.zephyrproject.org/latest/hardware/cache/index.html indeed.

CONFIG_DCACHE is telling you that a DCACHE is present but whether that is actually used or not it is up to CONFIG_CACHE_MANAGEMENT option.

it makes sense to be able to use the CPU cache but not the Cache API interface.

Does it though? Before the cache API was introduced every single architecture was doing something different and custom, the cache API was introduced exactly to put order in the cache management chaos. So the path forward here is just to move to the new cache API, not adding workarounds.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I agree with @pillo79, CONFIG_CACHE_MANAGEMENT might be disabled manually, but still CONFIG_DCACHE enabled. In such a case I would expect not to be able to enable or disable the caches from the application, but still the data cache to be active.

static ALWAYS_INLINE void sys_cache_data_enable(void)
{
#if defined(CONFIG_CACHE_MANAGEMENT) && defined(CONFIG_DCACHE)
    cache_data_enable();
#endif
}

I'm rather thinking towards calling cache_data_enable, with IS_ENABLED(CONFIG_DCACHE) around it.

Copy link
Collaborator

Choose a reason for hiding this comment

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

when the cache API was introduced we could not move all the cache implementation over right away, it was just too much work. So where possible we simply used CONFIG_DCACHE around the legacy cache operation code and we added CONFIG_DCACHE to be set at SoC / platform level to say: "the SoC has a functional DCACHE that is being used by some code".

For legacy code we moved from:

  custom_cache_op();

to:

#ifdef CONFIG_DCACHE
  custom_cache_op();
#endif

So, a quick recap is:

  • CONFIG_CPU_HAS_DCACHE: the CPU has a DCACHE, it can be used or not
  • CONFIG_DCACHE: the CPU has a DCACHE that is being used somehow (this was done to support legacy cache operations)
  • CONFIG_CACHE_MANAGEMENT: the CPU has a DCACHE that is being used using the cache API

So, back to this PR. Is this PR correct? It is, but it is simply fixing a legacy usage that it should (and it is) deprecated.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks for the clarification, but I think one version in between is missing.

  • CONFIG_CPU_HAS_DCACHE: the CPU has a DCACHE, it can be used or not
  • CONFIG_DCACHE: the CPU has a DCACHE that is being used somehow (this was done to support legacy cache operations)
  • ???: the CPU as DCACHE which is active, but it is not accessible using the cache API
  • CONFIG_CACHE_MANAGEMENT: the CPU has a DCACHE that is being used using the cache API

I will in the meantime go ahead with moving forward to sys_cache_data_enable as CONFIG_DCACHE seems to be somewhat deprecated.

Copy link
Collaborator

Choose a reason for hiding this comment

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

the CPU as DCACHE which is active, but it is not accessible using the cache API

Well, that would be CONFIG_DCACHE=y and CONFIG_CACHE_MANAGEMENT=n.

That is: you have something managing the DCACHE using some kind of custom API that it is not the zephyr cache API. In this case your code should use the custom / HAL API to manage the cache and now you see why we needed a formal, shared API for that, because we needed to abstract the cache operations away from the actual implementation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

But with CONFIG_DCACHE=y and CONFIG_CACHE_MANAGEMENT=n sys_cache_data_enable will turn into NOP. Therefore I won't be able to use the cache management API.
I totally agree with you that having an abstract cache operations API is a good thing to have. I'm just saying that having this API available doesn't necessarily mean that one wants to automatically enable the cache. These are two separate things for me.

Copy link
Collaborator

Choose a reason for hiding this comment

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

But with CONFIG_DCACHE=y and CONFIG_CACHE_MANAGEMENT=n sys_cache_data_enable will turn into NOP

Yes, exactly.

You can have CONFIG_DCACHE=y and CONFIG_CACHE_MANAGEMENT=n in two cases:

  1. Your SoC has sys_cache_data_enabled implemented but you do not want to use it, this is why you are setting CONFIG_CACHE_MANAGEMENT=n, so sys_cache_data_enable() is returning -ENOTSUP.
  2. Your SoC doesn't have sys_cache_data_enabled implemented, but to enable the DCACHE it is relying on some custom API, so sys_cache_data_enable() is returning -ENOTSUP because the API that you want to use is different (custom).

@nandojve
Copy link
Member

Hi @benediktibk ,

In the case of SAM only:

The initial discussion around SAM cache started here #60425. Later the #61005 solve the issues and let user setup cache as it pleases. The default value is cache disabled and the below examples are for SAMV71 which have both I/D Cache available. User should add below lines on their own board.

I Cache only:
CONFIG_CACHE_MANAGEMENT=y
CONFIG_DCACHE=n

D Cache only:
CONFIG_CACHE_MANAGEMENT=y
CONFIG_ICACHE=n

I/D Cache disabled:
CONFIG_ICACHE=n
CONFIG_DCACHE=n

I/D Cache Enabled:
CONFIG_CACHE_MANAGEMENT=y

IMHO, cache should be user defined since user may want to use ITCM/DTCM for other purposes. So, I'm interested in know how this PR changes the above behavior?

@benediktibk
Copy link
Collaborator Author

Hi @benediktibk ,

In the case of SAM only:

The initial discussion around SAM cache started here #60425. Later the #61005 solve the issues and let user setup cache as it pleases. The default value is cache disabled and the below examples are for SAMV71 which have both I/D Cache available. User should add below lines on their own board.

I Cache only: CONFIG_CACHE_MANAGEMENT=y CONFIG_DCACHE=n

D Cache only: CONFIG_CACHE_MANAGEMENT=y CONFIG_ICACHE=n

I/D Cache disabled: CONFIG_ICACHE=n CONFIG_DCACHE=n

I/D Cache Enabled: CONFIG_CACHE_MANAGEMENT=y

IMHO, cache should be user defined since user may want to use ITCM/DTCM for other purposes. So, I'm interested in know how this PR changes the above behavior?

This seems to contradict what I got told in this PR earlier on by @carlocaione. If I understood it correctly SoCs should use in their init code sys_cache_data/instr_enable to enable the caches. Therefore, configuring CONFIG_CACHE_MANAGEMENT=n will result in disabled caches in anyway, and CONFIG_DCACHE and CONFIG_ICACHE will only indicate if the SoC has a cache or not.

Btw, I saw that in the of the PRs you explictly added a disable-call for the caches during initialization. Are the caches enabled using something else earlier on for these SoCs?

@carlocaione
Copy link
Collaborator

This seems to contradict what I got told in this PR earlier on by @carlocaione. If I understood it correctly SoCs should use in their init code sys_cache_data/instr_enable to enable the caches. Therefore, configuring CONFIG_CACHE_MANAGEMENT=n will result in disabled caches in anyway, and CONFIG_DCACHE and CONFIG_ICACHE will only indicate if the SoC has a cache or not.

yes, this is correct. @nandojve you should never toggle CONFIG_DCACHE yourself if you are using the Zephyr cache APIs.

I'll try to better explain what is the rationale here (when using the proper cache APIs):

  1. All the zephyr code should use the sys_cache_* API to do cache operations so that the code is agnostic about the actual hardware it is running on.
  2. The only switch that the user could use to disable / enable the cache operations is CONFIG_CACHE_MANAGEMENT and nothing else. If the hardware does not support cache ops that option is doing nothing from the beginning (see following point), otherwise we are simply converting all the cache operations to -ENOTSUP when setting that to =n.
  3. At SoC level the SoC is defining CONFIG_{D,I}CACHE whether we support cache operations at SoC level. If the SoC does not support caches, it simply do not define those and the sys_cache_* ops are falling to -ENOTSUP.

@benediktibk
Copy link
Collaborator Author

  1. All the zephyr code should use the sys_cache_* API to do cache operations so that the code is agnostic about the actual hardware it is running on.

One small caveat: If external code (for instance HAL) is used for the initalization, which automatically activates caches, the caches have to be deactivated directly after such a call using a low level function call, not sys_cache_. Then during the SoC initialization later on sys_cache_ can be used to activate the caches.

@carlocaione Correct?

@zephyrbot zephyrbot added the area: X86 x86 Architecture (32-bit) label Dec 28, 2023
@benediktibk
Copy link
Collaborator Author

@carlocaione There are, of now, some spots where I have to disable caches, although CONFIG_CACHE_MANAGEMENT might be disabled. I decided to use arch_dcache_disable for this, as I did not want to spread calls to SCB_DisableDCache all over the place. Unfortunately, these functions are only built and linked if CONFIG_CACHE_MANAGEMENT is enabled. To work around this I introduced CONFIG_ANY_CACHE, which is basically the same as CONFIG_CACHE_MANAGEMENT but without a prompt.

Which version would you prefer, CONFIG_ANY_CACHE or calling SCB_DisableDCache directly? Or something completely different?

The problematic spots are:

  • arch/arm/core/cortex_m/scb.c
  • soc/arm/atmel_sam/same70/soc.c
  • soc/arm/atmel_sam/samv71/soc.c

nandojve
nandojve previously approved these changes Dec 28, 2023
Copy link
Member

@nandojve nandojve left a comment

Choose a reason for hiding this comment

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

atmel_sam

@carlocaione
Copy link
Collaborator

Which version would you prefer, CONFIG_ANY_CACHE or calling SCB_DisableDCache directly? Or something completely different?

I'm honestly really lost about what is the problem here and why only ARM is so messed up in this regard while the other architectures are implementing this nicely (@microbuilder). That said I really want to avoid adding one more cache related Kconfig symbol, so if this could not be solved cleanly just use SCB_DisableDCache directly.

@benediktibk
Copy link
Collaborator Author

Removed ANY_CACHE again and used direct calls to SCB_* wherever it was necessary.

1 similar comment
@benediktibk
Copy link
Collaborator Author

Removed ANY_CACHE again and used direct calls to SCB_* wherever it was necessary.

Copy link
Collaborator

@carlocaione carlocaione left a comment

Choose a reason for hiding this comment

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

Way better IMO

@benediktibk benediktibk removed the DNM This PR should not be merged (Do Not Merge) label Jan 9, 2024
Use sys_cache* for enabling the caches in nxp_s32. This automatically
considers CONFIG_CACHE_MANAGEMENT and will activate the
cases only if this is active.

Signed-off-by: Benedikt Schmidt <benedikt.schmidt@embedded-solutions.at>
Replace the redundant cache config options for the nxp_imx and
use sys_cache* functions to enable the caches. These will automatically
consider CONFIG_CACHE_MANAGEMENT.

Signed-off-by: Benedikt Schmidt <benedikt.schmidt@embedded-solutions.at>
Remove the redundant cache config options for kv5x and use
the sys_cache* functions to enable the caches. This will automatically
consider CONFIG_CACHE_MANAGEMENT.

Signed-off-by: Benedikt Schmidt <benedikt.schmidt@embedded-solutions.at>
Use sys_cache_data_enable instead of arch_dcache_enable to enable
the cache. This will ensure that CONFIG_CACHE_MANAGEMENT
is considered correctly.

Signed-off-by: Benedikt Schmidt <benedikt.schmidt@embedded-solutions.at>
Use the sys_cache* functions to enable the caches on same70 and
samv71. This will ensure that CONFIG_CACHE_MANAGEMENT is
considered correctly.

Signed-off-by: Benedikt Schmidt <benedikt.schmidt@embedded-solutions.at>
Use sys_cache* functions to enable the caches for stm32f7 and
stm32h7. This ensures that CONFIG_CACHE_MANAGEMENT is
considered correctly.

Signed-off-by: Benedikt Schmidt <benedikt.schmidt@embedded-solutions.at>
Use the arch-cache functions instead of the sys-cache-functions
in z_arm_init_arch_hw_at_boot to ensure that the caches are
disabled even when CONFIG_CACHE_MANAGEMENT is disabled.

Signed-off-by: Benedikt Schmidt <benedikt.schmidt@embedded-solutions.at>
@benediktibk
Copy link
Collaborator Author

Rebased to trigger CI as the github incident has been resolved.

@carlescufi carlescufi merged commit 70c8df7 into zephyrproject-rtos:main Jan 10, 2024
25 checks passed
@benediktibk benediktibk deleted the cleanup_cache_initialization branch January 16, 2024 09:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: ARC ARC Architecture area: ARM ARM (32-bit) Architecture area: X86 x86 Architecture (32-bit) platform: Microchip SAM Microchip SAM Platform (formerly Atmel SAM) platform: NXP NXP platform: STM32 ST Micro STM32
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants