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

kern: let drivers disable double-interrupt behavior #1948

Merged
merged 1 commit into from
Dec 13, 2024

Conversation

cbiffle
Copy link
Collaborator

@cbiffle cbiffle commented Dec 13, 2024

Currently drivers tend to get a spurious interrupt notification just after handling a real one. This is because the interrupt controller notices the kernel generic ISR exit while the interrupt condition is still asserted, because it doesn't expect us to be handling it in task code. So, it sets the pending bit so the 'new' interrupt condition isn't forgotten.

This causes an interrupt to occur immediately when we re-enable.

This adds an additional bit for IRQ_CONTROL that drivers can use to request any pending interrupt status be cleared.

Fixes #536.

@cbiffle cbiffle requested review from hawkw and mkeeter December 13, 2024 02:27
Comment on lines +503 to +504
The concept of a "pending" interrupt is inherently specific to a particular
architecture and interrupt controller. On an architecture without a concept of
Copy link
Member

Choose a reason for hiding this comment

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

this might just be one of my pet hobby-horses but i might cite some examples of such architectures here?

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 can't, sorry. I'd take suggestions, but, all the architectures where I'm deeply familiar with the interrupt controller have this bit. I think maybe AVRs don't, but they also don't have a Rust port.

Copy link
Member

Choose a reason for hiding this comment

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

hm, honestly, maybe we should just say "such as all the architectures Hubris currently targets"...but we would have to go and change that if hubris gets ported to some weird thing someday...

sys/userlib/src/lib.rs Show resolved Hide resolved
@@ -753,15 +753,16 @@ fn irq_control(
) -> Result<NextTask, UserError> {
let args = tasks[caller].save().as_irq_args();

let operation = match args.control {
let operation = match args.control & 1 {
Copy link
Member

Choose a reason for hiding this comment

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

feel free to ignore me, but i would personally prefer to write these masks as

Suggested change
let operation = match args.control & 1 {
let operation = match args.control & 0b01 {

as it feels a bit more obvious which bit we are picking out

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added a bitflags type and removed the constants.

Comment on lines 760 to 761
let also_clear_pending = args.control & 2 != 0;
if args.control & !3 != 0 {
Copy link
Member

Choose a reason for hiding this comment

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

similarly, this is just a personal style preference and you're welcome to tell me i'm wrong, but i'd have done

Suggested change
let also_clear_pending = args.control & 2 != 0;
if args.control & !3 != 0 {
let also_clear_pending = args.control & 0b10 != 0;
if args.control & !0b11 != 0 {

#[inline(always)]
pub fn sys_irq_control_clear_pending(mask: u32, enable: bool) {
unsafe {
sys_irq_control_stub(mask, enable as u32 | 0b10);
Copy link
Member

Choose a reason for hiding this comment

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

it seems like it could be nicer if the bitflags for this argument were defined in sys/abi so that the kernel and userlib could depend on the same definition, instead of having magic numbers. this isn't a huge deal, and if it's too annoying, we're probably not going to go and mess with them any time soon, so it's fine-as is. but, it would make me a little happier.

Copy link
Member

@hawkw hawkw left a comment

Choose a reason for hiding this comment

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

all of my comments are just obnoxious style nitpicks, so feel free to merge whenever you're happy with it!

@cbiffle
Copy link
Collaborator Author

cbiffle commented Dec 13, 2024

all of my comments are just obnoxious style nitpicks, so feel free to merge whenever you're happy with it!

You are too hard on yourself, these are good comments. :-)

@cbiffle
Copy link
Collaborator Author

cbiffle commented Dec 13, 2024

Alright, addressed, PTAL.

@cbiffle cbiffle requested review from hawkw and mkeeter December 13, 2024 21:47
Comment on lines +553 to +562
bitflags::bitflags! {
/// Bitflags that can be passed into the `IRQ_CONTROL` syscall.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct IrqControlArg: u32 {
/// Enables the interrupt if present, disables if not present.
const ENABLED = 1 << 0;
/// If present, requests that any pending instance of this interrupt be
// cleared.
const CLEAR_PENDING = 1 << 1;
}
Copy link
Member

Choose a reason for hiding this comment

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

you love to see it!

UsageError::NoIrq,
)));
}
let also_clear_pending = control.contains(IrqControlArg::CLEAR_PENDING);
Copy link
Member

Choose a reason for hiding this comment

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

this looks lovely!

Currently drivers tend to get a spurious interrupt notification just
after handling a real one. This is because the interrupt controller
notices the kernel generic ISR exit while the interrupt condition is
still asserted, because it doesn't expect us to be handling it in task
code. So, it sets the pending bit so the 'new' interrupt condition isn't
forgotten.

This causes an interrupt to occur immediately when we re-enable.

This adds an additional bit for IRQ_CONTROL that drivers can use to
request any pending interrupt status be cleared.

Fixes oxidecomputer#536.
@cbiffle cbiffle force-pushed the cbiffle/clear-pending-irq branch from 74af38d to 3be9463 Compare December 13, 2024 22:31
@cbiffle cbiffle enabled auto-merge (rebase) December 13, 2024 22:32
@cbiffle cbiffle merged commit a443ac5 into oxidecomputer:master Dec 13, 2024
125 checks passed
@cbiffle cbiffle deleted the cbiffle/clear-pending-irq branch December 14, 2024 00:13
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.

IRQ double-fires, but only when handled by Hubris
3 participants