-
Notifications
You must be signed in to change notification settings - Fork 322
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
Better handling of module base_config_ext data #8685
Conversation
As in, I wrote up a whole commit message carefully explaining and advocating my removal of an API that never merged, heh: |
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.
This does look cleaner. I'll let others chime in. Ext-cfg is optional, but given it's more common to have it, don't see why not to handle it in common code. There are some corner cases I'd like others to chime in.
dst->init_data = ipc_module_adapter->data; | ||
dst->size = ipc_module_adapter->size; | ||
dst->avail = true; | ||
assert(dev->drv->type == SOF_COMP_MODULE_ADAPTER); |
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.
This might be ok. @jxstelter you added the if check on this in commit b570b80 , can you check?
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.
It would seem this is ok. Most modules use "DECLARE_MODULE_ADAPTER()" to register the driver (which sets the type correctly) and library_manager calls "declare_dynamic_module_adapter(drv, SOF_COMP_MODULE_ADAPTER, ..)". So I don't see any use for IPC4 where the type would not be set to adapter. It still bugs me a bit a specific branch was added to cover this case and I can't find from git history any use for this, but maybe this was some variant of loadable modules. @jxstelter @ranj063 @RanderWang @softwarecki @pjdobrowolski please do comment if I got this wrong.
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.
That was my read, yeah. The original had a check for that that then set the init_data unconditionally, which seems a little dangerous (what if it's not? what's in the data and how do we prevent treating it like pin config?". I grepped around and couldn't find any situations where it would happen, so I replaced it with an assert to be sure, figuring that CI would tell me if I missed something.
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.
Is this really fatal ?
I'm pretty sure it just can't happen. This is a method on module_adapter, it sorta strains reason that it would somehow be called on anything else. And what grepping I could do seems to confirm that. But the previous version of the code had a check for the != case where it would fall back to just assigning init_data. So the assert is here to catch any mistakes or edge cases that crept through; no reason it should stay long term.
struct processing_module *srcmod = comp_get_drvdata(source); | ||
struct processing_module *dstmod = comp_get_drvdata(sink); | ||
struct module_config *dstcfg = &dstmod->priv.cfg; | ||
struct module_config *srccfg = &srcmod->priv.cfg; |
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.
Something missing in the patch, "struct processing_module" definition is not known and there are lot of fails in CI (defined in module/base.h). Now this is supposed to be private to module implementations, which is why I think @ranj063 opted to add a new property so it can be "set from outside".
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.
@andyross I do like the idea of parsing/saving the base_cfg_ext data in the module adapter instead of doing it in the individual modules. But I think you're going to have to add a new property to retrieve the extn data just like we do for the base_cfg data today.
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.
I see the failures, presumably that's just a header ordering issue? Or if processing_module is an illegal header in some contexts, can you provide details? It would be easy enough to wrap these behind an API. That seems unlikely though, as the alternate code was already banging directly on the mod->priv.cfg.
@ranj063 you mean the COMP_ATTR_BASE_CONFIG_EXT from the version in your first PR? That's actually deliberately omitted: the only spot that would use it is using the original/kernel-derived data in the new parsed fields. The reason for making this a property would presumably be that components could then override it, but (and, OK, this is becoming a crusade of mine I guess) I think that's emphatically bad and should be avoided. If topology lied and gave us an invalid value, the job of the firmware is to fail gracefully and get the integrator to fix the topology.
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.
@andyross I think originally processing_module was intended to be private data accessible only by the module itself. But given that we are already accessing the base_cfg and base_cfg_ext from the common code, I guess it makes sense to make it shared. By the same argument maybe we should remove the COMP_ATTR_BASE_CONFIG attribute as well.
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.
Agreed, I'll look at that as a followup cleanup. The "kpb" component is the only spot I see in current code that's implementing the BASE_CONFIG attribute, and it's just echoing back the default base config anyway.
595031c
to
8331325
Compare
Cleaned up the backport from mtl-007-drop-stable (the only place I can test this) that rebases this on top of a reversion that should match main better. Hopefully will fix the build issues. |
d1e425c
to
8672299
Compare
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.
In general LGTM, just minor comment
@@ -30,6 +30,10 @@ struct module_config { | |||
const void *init_data; /**< Initial IPC configuration. */ | |||
#if CONFIG_IPC_MAJOR_4 | |||
struct ipc4_base_module_cfg base_cfg; | |||
uint8_t nb_input_pins; |
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.
now we have this twice
struct processing_module->num_of_sinks
struct processing_module->num_of_sources
(not a blocker) add please at least an assert (by now) in module_adapter_dp_queue_prepare
Target - remove it from struct processing_module (I'll do it)
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.
They're actually different values from different sources. The fields in processing_module count the number of actual comp_buffer objects connected to the module. The one here is a field set in an IPC message from the kernel based on topology input. In the case where the base_cfg_ext is provided, they surely should be the same value. But the extended config is actually not always present (some components have their own config structs here instead), so they might differ at runtime and we need to know how much memory was actually allocated behind the pointers here.
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.
CI looks good now. By directly accessing module internals is a change in convention, but we seem to have consensus this is ok in this case.
8672299
to
a17c4e1
Compare
Fixed |
a17c4e1
to
e0f068e
Compare
@@ -30,6 +30,10 @@ struct module_config { | |||
const void *init_data; /**< Initial IPC configuration. */ | |||
#if CONFIG_IPC_MAJOR_4 | |||
struct ipc4_base_module_cfg base_cfg; | |||
uint8_t nb_input_pins; | |||
uint8_t nb_output_pins; |
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.
nitpick: is "nb" an abbreviation for "number?" If so, it seems a bit non-standard to me, maybe just "n" or "num" or even "number_of..."
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.
It's the pre-existing name for the field in struct ipc4_base_module_cfg_ext from which this is derived. Personally I don't like it much either, but I'm trying to be a good citizen and not rock the boat too much. :)
The kernel-provided "base_cfg_ext" data wasn't being handled correctly by the module adapter layer. These structs (packed wire formats) only ever lived in the IPC memory. The module would set them on an "init_data" before calling into driver init, and then clear that pointer afterwards. That's a critical problem, because the values in that struct need to be used at pipeline setup time to configure buffer formats! Save the data correctly. Also pre-parse it so users don't need to do byte math on raw buffers and can just use "in/output_pins[]" arrays on the module_config struct. Signed-off-by: Andy Ross <[email protected]>
The code here never really worked right. The module base config values weren't saved by the core layers, so querying the attribute returned nothing. A few components have been modified with a whitebox workaround where they write directly to the basecfg_ext field in the module_config, but that's not really an API we should want to support. Get the values from the now-correctly-saved-and-parsed fields the module init layer has left for us, with considerable code savings and much less heap thrashing for the temporary copy. Signed-off-by: Andy Ross <[email protected]>
e0f068e
to
877ef51
Compare
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 changes can be fixed incrementally, I'd rather get this merged and tested more as priority.
if (cfgsz >= sizeof(*cfg)) { | ||
int n_in = cfg->base_cfg_ext.nb_input_pins; | ||
int n_out = cfg->base_cfg_ext.nb_output_pins; | ||
size_t pinsz = (n_in * sizeof(*dst->input_pins)) | ||
+ (n_out * sizeof(*dst->output_pins)); | ||
|
||
if (cfgsz == (sizeof(*cfg) + pinsz)) { | ||
dst->nb_input_pins = n_in; | ||
dst->nb_output_pins = n_out; | ||
dst->input_pins = rmalloc(SOF_MEM_ZONE_RUNTIME_SHARED, | ||
0, SOF_MEM_CAPS_RAM, pinsz); | ||
if (!dst->input_pins) | ||
return -ENOMEM; | ||
|
||
dst->output_pins = (void *)&dst->input_pins[n_in]; | ||
memcpy_s(dst->input_pins, pinsz, | ||
&cfg->base_cfg_ext.pin_formats[0], pinsz); | ||
} | ||
} | ||
|
||
dst->init_data = cfg; /* legacy API */ | ||
dst->avail = true; |
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.
This block could do with an inline comment describing what its doing.
dst->init_data = ipc_module_adapter->data; | ||
dst->size = ipc_module_adapter->size; | ||
dst->avail = true; | ||
assert(dev->drv->type == SOF_COMP_MODULE_ADAPTER); |
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.
Is this really fatal ?
I'm pretty sure it just can't happen. This is a method on module_adapter, it sorta strains reason that it would somehow be called on anything else. And what grepping I could do seems to confirm that. But the previous version of the code had a check for the != case where it would fall back to just assigning init_data. So the assert is here to catch any mistakes or edge cases that crept through; no reason it should stay long term.
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 changes can be fixed incrementally, I'd rather get this merged and tested more as priority.
This is a different take on a fix for #8639 than the workaround in #8575 on which it was originally coded. It removes the requirement for components to have to muck with module internals[1] and places the complicated byte-offset math into just one place (in the module code that owns the struct format). Really I think this is a lot cleaner. If you guys want to merge the first version for clarity (given it's already "shipped"[2]), I can submit this as cleanup on top of that instead (which, again, is how this was written originally anyway).
With this, the big IPC4 workaround patch at the end of the AEC work is down to just one line, hope to have that cleaned up by tomorrow. (see https://github.com/andyross/sof/commits/mtl-aec-tmp/ for the current status of my working tree).
[1] Basically, the first version: (1) requires every module to make a copy of the untyped "init_data" field of module_config, then (2) store that pointer back into a different field of module_config (because the first one points into the IPC command buffer and won't survive) where (3) it will be eventually used, not by the module code itself but by the ipc4/module layer that created it in the first place. This avoids all that by having the module_adapter init code just parse and store the data at the start.
[2] In the MTL "stable" branch, where it's already been merged. Can I just whine a bit about how frustrating it is to have to work across branches like this? I didn't realize until I was about to submit that the code I was modifying wasn't actually upstream!