-
Notifications
You must be signed in to change notification settings - Fork 7.6k
drivers: flash: stm32: add "generic read/write" ex op to QSPI driver #91186
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a reference here is the link to the discussion where one of the
reviewers asked for using ex ops instead of custom code in a board.c file.
Link: 90264
this can be removed from commit message
af9312d
to
c94ecb2
Compare
c94ecb2
to
f06d093
Compare
f06d093
to
8756532
Compare
drivers/flash/flash_stm32_qspi.c
Outdated
cmd = &cmd_copy; | ||
|
||
if (cmd->NbData <= CONFIG_FLASH_STM32_QSPI_GENERIC_STACK_BUFFER_MAX_SIZE) { | ||
out_copy = alloca(CONFIG_FLASH_STM32_QSPI_GENERIC_STACK_BUFFER_MAX_SIZE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dynamic allocation should be avoided. Allocating things on stack is risky.
I think driver should use either slab or statically pre allocated number of buffers; the number of buffers would be no more then number of parallel running threads, as not all threads will access flash at the same time.
What should software when driver returns -ENOMEM?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using 64 bytes of stack seems quite reasonable.
If it's the typical buffer size expected for theses extended ops, maybe simpler to hard code it in the driver rather than adding a config switch:
#ifdef CONFIG_USERSPACE
QSPI_CommandTypeDef cmd_copy;
uint8_t out_copy_def[64];
bool syscall_trap = z_syscall_trap();
if (syscall_trap) {
K_OOPS(k_usermode_from_copy(&cmd_copy, cmd, sizeof(cmd_copy)));
cmd = &cmd_copy;
if (cmd->NbData <= sizeof(out_copy_def) ) {
buffer = out_copy_def;
} else {
buffer = k_malloc(cmd->NbData);
if (buffer == NULL) {
return -ENOMEM;
}
}
}
#endif
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using 64 bytes of stack seems quite reasonable.
This sentence is not true, as the value is configurable.
And https://docs.zephyrproject.org/latest/contribute/coding_guidelines/index.html rule 14
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If dynamic allocation should not be used at all, would it be OK to keep the Kconfig option and just return ENOMEM
if cmd->NbData
is greater than the static allocation. After all, the user is asking for a specific operation and knows exactly how much memory it is supposed to read/write.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using 64 bytes of stack seems quite reasonable.
This sentence is not true, as the value is configurable.
I was referring to the config default value proposed in the Kconfig file.
I could seem nice to have a config for this but what will prevent one from setting a value that would overflow the stack enough to have side effect and not enough to make those effects not visible?
If this feature is to be used on "reasonably-sized" buffer, I agree the dynamic allocation could be removed. Is alloca()
considered a dynamic allocation since its handle by the toolchain? Is alloca()
better than a raw variable-in-stack definition (like uint8_t loc_buf[CONFIG_xxx];
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If dynamic allocation should not be used at all, would it be OK to keep the Kconfig option and just return ENOMEM if cmd->NbData is greater than the static allocation. After all, the user is asking for a specific operation and knows exactly how much memory it is supposed to read/write.
I agree with your proposal.
e72a3e1
to
332e446
Compare
I just pushed a new version that removes the dynamic allocation while allowing the user to specify how much stack should be used via a Kconfig variable. I also implemented all other requested changes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the update. The implementation looks good to me.
drivers/flash/Kconfig.stm32_qspi
Outdated
If the buffer is less than the value configured in this options | ||
the copy will be allocated on the stack, else it will be | ||
allocated dyanmically from the caller’s resource pool via | ||
z_thread_malloc(). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Few things to update. s/less/less or equal/, s/options/option/, remove the dynamic allocation info.
I suggest either:
If the data buffer size is less than or equal to this value, the buffer
is allocated in the stack, otherwise operation will fail.
or
This option defines the max supported size of data being read/written
with the generic read and write extended operation. Be warned that
the related buffer is allocated in the stack and this value should be reasonable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we even need this? Per https://docs.zephyrproject.org/latest/kernel/usermode/syscalls.html#verification-memory-access-policies:
There is one exception in place, with respect to large data buffers which are only used to provide a memory area that is either only written to, or whose contents are never used for any validation or control flow. Further discussion of this later in this section.
...
Finally, we must consider large data buffers. These represent areas of user memory which either have data copied out of, or copied into. It is permitted to pass these pointers to the implementation function directly. The caller’s access to the buffer still must be validated with K_SYSCALL_MEMORY APIs. The following constraints need to be met:<...refer to page....>
int z_vrfy_get_data_from_kernel(void *buf, size_t size) { K_OOPS(K_SYSCALL_MEMORY_WRITE(buf, size)); return z_impl_get_data_from_kernel(buf, size); }
I think this is exactly the situation we are in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean using k_usermode_alloc_from_copy()
and k_usermode_from_copy()
/k_usermode_to_copy()
?
Sounds good,
There is no k_usermode_alloc_to_copy()
helper function. Since k_usermode_alloc_from_copy()
relies on z_thread_malloc()
, maybe the write operation could use z_thread_malloc()
and k_usermode_to_copy()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My fault, I forgot about the Kconfig description. I'll update it after the other changes if we still need it.
I don't think z_thread_malloc()
is accessible outside the kernel proper but I'll investigate how to use the K_SYSCALL_MEMORY
API and provide a new patch if that's the right way to go.
Some external flash modules have extra commands to support, for example, reading/writing an OTP zone. Given that the commands are highly specific and difficult to generalize, we add two ex ops that can be used to transmit a custom command (in the form of a full QSPI_CommandTypeDef) and then read or write a user-provided buffer. Signed-off-by: Federico Di Gregorio <[email protected]>
332e446
to
64156b7
Compare
I just pushed a new version that does not copy the "variable length" buffers (but does copy the Also, I removed the Kconfig variable |
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LAGTM
Some external flash modules have extra commands to support, for example, reading/writing an OTP zone. Given that the commands are highly specific and difficult to generalize, we add two ex ops that can be used to transmit a custom command (in the form of a full QSPI_CommandTypeDef) and then read or write a user-provided buffer.
As a reference here is the link to the discussion where one of the reviewers asked for using ex ops instead of custom code in a board.c file.
Link: #90264