Skip to content

Add architectural support for shared interrupts #61331

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

Closed

Conversation

LaurentiuM1234
Copy link
Collaborator

@LaurentiuM1234 LaurentiuM1234 commented Aug 9, 2023

This series of patches introduces architectural support for shared interrupts.

This works by keeping track of all of the ISR/arg pairs passed to z_isr_install() and calling
them in our own "dummy" ISR.

In theory, this patch series shouldn't affect the current architecture as this is an opt-in option and the series only contains additions and no modifications of current code.

Currently, there's a weird dependency on the ARM64 architecture. This is because I was only able to test this change on said architecture.

For the associated issue please see: #61278.

This commit adds the "__weak" adnotation to the z_isr_install function.
The reason for this is because the z_isr_install symbol needs to be
overwritten when enabling support for shared interrupts.

Signed-off-by: Laurentiu Mihalcea <[email protected]>
@LaurentiuM1234 LaurentiuM1234 force-pushed the shared_irqs branch 2 times, most recently from fe40c6c to 921d4be Compare August 9, 2023 11:28
This commit introduces the support for shared interrupts.
This works by "hijacking" the ISR passed to z_isr_install()
and installing our own "dummy" ISR, which, in turn, calls all
of the ISRs registered by the clients.
Since the support is based on overwriting z_isr_install(), this
means we'll have a dependency on CONFIG_DYNAMIC_INTERRUPTS.

Signed-off-by: Laurentiu Mihalcea <[email protected]>
With the support for shared interrupts, we need a way to
unregister pairs of ISR/arg. This is because we don't want
to keep piling up new clients as this will lead to reaching the
limit of clients.

This feature is only needed and supported in the case of
shared interrupts.

Signed-off-by: Laurentiu Mihalcea <[email protected]>
@LaurentiuM1234
Copy link
Collaborator Author

CI is green, removing this from draft.

CC: @dbaluta @iuliana-prodan

@LaurentiuM1234 LaurentiuM1234 marked this pull request as ready for review August 9, 2023 12:12
@zephyrbot zephyrbot added area: Base OS Base OS Library (lib/os) area: Architectures labels Aug 9, 2023
Copy link
Collaborator

@andyross andyross left a comment

Choose a reason for hiding this comment

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

Some notes. Seems pretty reasonable on the whole, though IIRC there was another PR supporting IRQ sharing kicking around a few months back that never merged. Would be good to dig it up and figure out which bits we want from both. IIRC it was attempting the somewhat more complicated case of handling shared handlers for static interrupts too. One thing I do like about this variant is that it doesn't involve an API change; you use the same irq_connect API to register shared interrupts as you do for normal ones.

Regarding the IRQ_CONNECT() interaction: I guess I'm personally fine with this API being limited to runtime, as dynamic IRQs are a commonly supported feature and relatively lightweight. It's not a hardship. But you do have to be really clear in the docs (which are a little thin) that IRQ_CONNECT() gives you exactly one interrupt, but that you can come along later and register more.

Also needs a test case for sure.

zephyr_library_sources_ifdef(
CONFIG_SHARED_INTERRUPTS
shared_irq.c
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

There's some ambiguity, but this belongs in kernel/ not arch/common/ I'd say. The arch layer is responsible for handling interrupts and dispatching to a _sw_isr_table[] entry, but everything downstream is OS behavior and belongs in the kernel.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ACK. I'm assuming the same rationale is applicable to sw_isr_common.c, right?

struct k_spinlock lock;
};

static struct shared_irq_data shared_irq_table[CONFIG_NUM_IRQS];
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is an awfully big table! 8 bytes per record, 16 (default) records per IRQ, and most platforms have a few dozen IRQ slots. At the very least I'd say 16 is way too generous for a MAX_NUM_CLIENTS default. The much more typical number of drivers forced to share an interrupt is "two". :)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Actually, you'd pay for it with a little code size, but one clever way to do this would be to put a dlist node into the structs and keep them in lists, "allocating" them pool-style (i.e. walk the array linearly to start, keep deleted records in a free list, and allocate from there when the original N have been exhausted). Then you'd only need one record (albeit one of 16 bytes instead of 8) for each shared handler of any IRQ in the system.

_sw_isr_table[table_idx].arg = irq_data;
_sw_isr_table[table_idx].isr = shared_irq_isr;

irq_data->enabled = true;
Copy link
Collaborator

@andyross andyross Aug 9, 2023

Choose a reason for hiding this comment

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

(Never mind: this is me being confused as mentioned in the comment below, I just forgot to delete the comment)

This seems wrong? If you call this function on a disabled IRQ it'll silently drop the new function you registered and continue using whatever it was already there? Dynamic interrupts are dynamic, the whole point of the API is that you might want to change handlers at runtime.


key = k_spin_lock(&irq_data->lock);

if (!irq_data->enabled) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just test if(_sw_isr_table[table_idx].isr == shared_irq_isr) instead and save the space in the irq_data struct. Actually IMHO having it present and calling it "enabled" is a net loss, because I read that as "interrupt line is enabled" and not "shared interrupts are enabled on this line" and was really confused about what was happening here.

*/
for (i = client_idx; i <= (int)irq_data->client_num - 2; i++)
swap_client_data(&irq_data->clients[i],
&irq_data->clients[i + 1]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Might be worth expanding this handling a bit to detect the case where there's only one handler registered and "unshare" the IRQ.

static inline int
irq_disconnect_dynamic(unsigned int irq, unsigned int priority,
void (*routine)(const void *parameter),
const void *parameter, uint32_t flags)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: would be cleaner to put the implementation for arch_irq_disconnect_dynamic() into this patch. Right now all the important stuff is added in a generic patch, but the patch that says it's adding irq_disconnect is actually only adding a wrapper.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good point, will fix. Thanks!

@LaurentiuM1234
Copy link
Collaborator Author

LaurentiuM1234 commented Aug 10, 2023

@andyross TYVM for all of your input !

Currently, I'm taking a look at #57146. I'm going to try to find a way to allow us to make use of the shared interrupts feature using IRQ_CONNECT() as well. I'm thinking a combination of this patch (which handles the shared interrupts "dynamically" ) and the one I've mentioned above (which handles the shared interrupts "statically"). When I have something somewhat decent I will submit a PR as an alternative to this one.

If that doesn't work, I'll come back to this PR and address all of your suggestions.

As I'm going to be away starting from next week, this might take a while :( (ETA 2 weeks or so).

EDIT: submitted alternative to this at #61422

@LaurentiuM1234
Copy link
Collaborator Author

Feature implemented in #61422.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: Architectures area: Base OS Base OS Library (lib/os)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants