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

mem_attr: Introduce library to query memory attributes #60916

Closed
wants to merge 4 commits into from

Conversation

carlocaione
Copy link
Collaborator

The introduction on the zephyr,memory-attr property for memory nodes in #60049 has been very useful to mark attributes and capabilities of the memory regions defined in the DT. What's still missing is an abstracted and unified way to deal and manage this kind of information.

In this PR we introduce a small and extensible library / subsystem that can be used by application, drivers or other subsystems to query this kind of information.

One very common use-case of this library is for example to check whether a buffer has certain kind of capabilities (i.e. it is cacheable / non-cacheable). Right now there is no common and generalized why to achieve that, so each platform has to resort to custom platform-specific code, like in #57786

Add a dt-bindings header file to be able to easily match in C code the
YAML / DT enum.

Signed-off-by: Carlo Caione <[email protected]>
Instead of relying on numerical values only.

Signed-off-by: Carlo Caione <[email protected]>
…_NODE

Introduce a new DT_MEMORY_ATTR_FOREACH_STATUS_OKAY_NODE() macro and make
the DT_MEMORY_ATTR_FOREACH_NODE() macro visiting disabled nodes as well.

Signed-off-by: Carlo Caione <[email protected]>
@carlocaione carlocaione changed the title Mem attr mem_attr: Introduce library to query memory attributes Jul 28, 2023
The introduction on the `zephyr,memory-attr` property for memory nodes
has been very useful to mark attributes and capabilities of the memory
regions defined into the DT. What's still missing is an abstracted and
unified way to deal and manage this kind of information.

In this PR we introduce a small and extensible library / subsystem that
can be used by application, drivers or other subsystems to query this
kind of information.

One very common use-case of this library is for example to check whether
a buffer has certain kind of capabilities (i.e. it is cacheable /
non-cacheable).

Signed-off-by: Carlo Caione <[email protected]>
Copy link
Collaborator

@teburd teburd left a comment

Choose a reason for hiding this comment

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

This mostly looks great.

I do think a few of the names are a bit misleading though.

mem_mgmt makes me think oh, this thing will have something like allocation and other such things to manage memory. But its more like memory introspection abilities to query what some memory is capable. mem_caps, mem_info, mem_introspect, etc seem more apt than mem_mgmt to me.

The other oddity is the memory attributes themselves. I had, wrongly, assumed there could be more than one attribute applied to a memory region. E.g. this memory is uncached and has buswide access, such that it's useful to dma and not just tcm attached to core(s). Maybe that means RAM_NOCACHE | BUS_ACCESSIBLE for example. Point being there are multiple attributes associated.

It seems like instead each region more or less gets a type tag enum and calls that mem_attr which is a bit misleading.

The actual API seems plenty fine to me and does as advertised I believe.

@carlocaione
Copy link
Collaborator Author

carlocaione commented Jul 28, 2023

This mostly looks great.

Aaargh, this is in draft, I feel violated now 😄 (joking, I'm just waiting for the other PRs this is depending on to be merged before marking this as ready)

I do think a few of the names are a bit misleading though.

mem_mgmt makes me think oh, this thing will have something like allocation and other such things to manage memory. But its more like memory introspection abilities to query what some memory is capable. mem_caps, mem_info, mem_introspect, etc seem more apt than mem_mgmt to me.

Yes, you actually got the point here. But this PR is part of a long game that will add a couple of more memory management bits and the biggest player will be indeed a memory allocator based on memory properties (think about a malloc where you can specify the kind / attribute of memory you want to get from it). In prospective I thought that calling this mem_mgmt was ok.

The other oddity is the memory attributes themselves. I had, wrongly, assumed there could be more than one attribute applied to a memory region. E.g. this memory is uncached and has buswide access, such that it's useful to dma and not just tcm attached to core(s). Maybe that means RAM_NOCACHE | BUS_ACCESSIBLE for example. Point being there are multiple attributes associated.

It seems like instead each region more or less gets a type tag enum and calls that mem_attr which is a bit misleading.

Fully agree here and you are spot on. I thought hard about that but this is extremely hard to achieve if we want to achieve everything only using the zephyr,memory-attr property. This is due to the fact that this property is used also to create at build time the MPU / MMU regions, see:

/**
* @brief Invokes @p fn for MPU/MMU regions generation from the device tree
* nodes with `zephyr,memory-attr` property.
*
* Helper macro to invoke a @p fn macro on all the memory regions declared
* using the `zephyr,memory-attr` property
*
* The macro @p fn must take the form:
*
* @code{.c}
* #define MPU_FN(name, base, size, attr) ...
* @endcode
*
* The @p name, @p base and @p size parameters are retrieved from the DT node.
* When the `zephyr,memory-region` property is present in the node, the @p name
* parameter is retrived from there, otherwise the full node name is used.
*
* The `zephyr,memory-attr` enum property is passed as an extended token
* to the @p fn macro using the @p attr parameter in the form of a macro
* REGION_{attr}_ATTR.
*
* The following enums are supported for the `zephyr,memory-attr` property (see
* `zephyr,memory-attr.yaml` for a complete list):
*
* - RAM
* - RAM_NOCACHE
* - FLASH
* - PPB
* - IO
* - EXTMEM
*
* This means that usually the user code would provide some macros or defines
* with the same name of the extended property, that is:
*
* - REGION_RAM_ATTR
* - REGION_RAM_NOCACHE_ATTR
* - REGION_FLASH_ATTR
* - REGION_PPB_ATTR
* - REGION_IO_ATTR
* - REGION_EXTMEM_ATTR
*
* Example devicetree fragment:
*
* @code{.dts}
* / {
* soc {
* res0: memory@20000000 {
* reg = <0x20000000 0x4000>;
* zephyr,memory-region = "MY_NAME";
* zephyr,memory-attr = "RAM_NOCACHE";
* };
*
* res1: memory@30000000 {
* reg = <0x30000000 0x2000>;
* zephyr,memory-attr = "RAM";
* };
* };
* };
* @endcode
*
* Example usage:
*
* @code{.c}
* #define REGION_RAM_NOCACHE_ATTR 0xAAAA
* #define REGION_RAM_ATTR 0xBBBB
* #define REGION_FLASH_ATTR 0xCCCC
*
* #define MPU_FN(p_name, p_base, p_size, p_attr) \
* { \
* .name = p_name, \
* .base = p_base, \
* .size = p_size, \
* .attr = p_attr, \
* }
*
* static const struct arm_mpu_region mpu_regions[] = {
* DT_MEMORY_ATTR_APPLY(MPU_FN)
* };
* @endcode
*
* This expands to:
*
* @code{.c}
* static const struct arm_mpu_region mpu_regions[] = {
* { "MY_NAME", 0x20000000, 0x4000, 0xAAAA },
* { "memory@30000000", 0x30000000, 0x2000, 0xBBBB },
* };
* @endcode
*
* @param fn macro to invoke
*/
#define DT_MEMORY_ATTR_APPLY(fn) \
DT_FOREACH_STATUS_OKAY_NODE_VARGS(_APPLY, fn)

Used for example in:

DT_MEMORY_ATTR_APPLY(MPU_REGION_ENTRY_FROM_DTS)

So we have two ways forward here:

  1. We keep having only the zephyr,memory-attr as is, but for each set of memory capabilities we have a different type tag enum, so for example instead of having RAM_NOCACHE | BUS_ACCESSIBLE you will have a RAM_NOCACHE_BUS_ACCESSIBLE enum:
zephyr,memory-attr = "RAM_NOCACHE_BUS_ACCESSIBLE";
  1. We add one more zephyr, ... property and we split the MPU / MMU region generation from the actual definition of the capabilities for the memory region, so we will have something like:
zephyr,memory-attr = "RAM";  // For MPU generation
zephyr,memory-cap = <( RAM_NOCACHE | BUS_ACCESSIBLE )>; // For memory characterization

I was going with (1) because is objectively easier but if we want to steer towards (2) this is something that I need to know ASAP because that will be quite a bit of work :)

@carlocaione
Copy link
Collaborator Author

@teburd I actually got an idea, let me prepare an RFC.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants