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

Interrupt v3: Add interrupt traits and a KVM based implementation #21

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

jiangliu
Copy link
Member

This PR is the successor of PR #11. The #11 has too many discussions so we reopen a new PR for clear review history, it also rebases to the latest vm-device code base.

The adds consts/structs/traits to manage interrupt sources for backend devices.
It also provides a KVM hypervisor based implementation for x86 legacy interrupts, PCI MSI/MSI-x interrupts.

There are also two planned PR based on this one:

  1. Refine the InterruptSourceGroup trait based on Cloud Hypervisor's implementation.
  2. Add support for VFIO devices, which has dependency on the vfio-ioctls crate(which is still under review), so not included in this PR.

Ok(())
}

#[cfg(any(target_arch = "aarch", target_arch = "aarch64"))]

Choose a reason for hiding this comment

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

It should be "arm" for the architecture before aarch64.

Copy link
Member

@bonzini bonzini left a comment

Choose a reason for hiding this comment

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

My remarks from sameo#3 still apply; I don't think that having the interrupt type as an enum is future proof, since it prevents you from using the interrupt traits internally (for example for buses that are internal to device emulation). I'm not a contributor to vm-device so I'm not making this a reject, but anyway that's my opinion.

src/interrupt/kvm/mod.rs Outdated Show resolved Hide resolved
Introduce traits InterruptManager and InterruptSourceGroup to manage
interrupt sources for virtual devices.

Signed-off-by: Liu Jiang <gerry@linux.alibaba.com>
Signed-off-by: Bin Zha <zhabin@linux.alibaba.com>
@jiangliu jiangliu force-pushed the irq_v3 branch 2 times, most recently from 497c92d to 9e5bc2b Compare February 28, 2020 17:13
Copy link
Member

@bonzini bonzini left a comment

Choose a reason for hiding this comment

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

Asking for a rework of the features, leaving them to later commits that implement the KVM integrations.

Copy link
Member

@bonzini bonzini left a comment

Choose a reason for hiding this comment

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

Sorry, now including the comments. I just cannot get this GitHub thing. :D

#[cfg(feature = "msi-irq")]
/// Configuration data for PciMsi, PciMsix and generic MSI interrupts.
MsiIrq(MsiIrqSourceConfig),
}
Copy link
Member

Choose a reason for hiding this comment

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

I would go a step further if possible:

  • make this enum an associated type of InterruptSourceGroup

  • move InterruptSourceConfig to the implementation of the KVM manager, removing the two features.

@jiangliu
Copy link
Member Author

Hi, @bonzini @sameo @sboeuf @alexandruag
I have updated the PR to only include the interface definition of InterruptSourceGroup, and leave InterruptManager and InterruptSourceGroup concrete implementations to VMMs.

I have merged most changed from Cloud Hypervisor into the new InterruptSourceGroup trait, with two main changes:

  1. enable() takes a parameter configs and enforce that enable should be called before calling other methods of InterruptSourceGroup.
  2. add get_pending_state() method, to company mask/unmask.

@andreeaflorescu
Copy link
Member

Asking for a rework of the features, leaving them to later commits that implement the KVM integrations.

I would actually prefer the KVM implementations to live in a separate crate or in the VMM specific code. In the future, I would love to see vm-device independent of KVM and extend this code to support other hypervisors as well. Right now it feels a bit targeted at x86_64 and KVM.

@bonzini
Copy link
Member

bonzini commented Feb 28, 2020

To me it's okay as long as it's hidden behind a feature, just like we have an mmap backend in vm-memory that isn't strictly speaking needed for all VMMs. Making a separate crate for KVM things makes sense too, we could have also an integration with GuestMemory in the same crate, or a dispatcher for MMIO vmexits. But the most important part is that it should certainly be customizable (it's also easier to move stuff in the future out if it's a separate feature).

@jiangliu jiangliu force-pushed the irq_v3 branch 2 times, most recently from 75f73a9 to b33c69e Compare February 28, 2020 17:32
@jiangliu
Copy link
Member Author

To me it's okay as long as it's hidden behind a feature, just like we have an mmap backend in vm-memory that isn't strictly speaking needed for all VMMs. Making a separate crate for KVM things makes sense too, we could have also an integration with GuestMemory in the same crate, or a dispatcher for MMIO vmexits. But the most important part is that it should certainly be customizable (it's also easier to move stuff in the future out if it's a separate feature).

I agree it would be better to make the interface trait as common as possible, and use feature to gate platform/hypervisor specific implementation. I also prefer including such a reference implementation in the same crate, it helps to verify that the interfaces really work.

It's challenge to design interface by rust without a reference implementation:(

@jiangliu
Copy link
Member Author

How does the caller know the number of interrupts? Should the trait include a len() method and a constructor that takes size: u32?

Sorry, interrupt_type() getter should be removed, but the len() method should be kept. Will recover it .

@jiangliu
Copy link
Member Author

This only makes sense for level-triggered interrupts. Should this return a Result, so that it can fail in the edge-triggered case?

pardon, which method?

@bonzini
Copy link
Member

bonzini commented Feb 28, 2020

pardon, which method?

get_pending_state. See b33c69e, I have no idea why the relevant contenxt is not showing up in the pull request web page.

@jiangliu
Copy link
Member Author

pardon, which method?

get_pending_state. See b33c69e, I have no idea why the relevant contenxt is not showing up in the pull request web page.

The main use case of mask/unmask/get_pending_state() is to support PCI MSI/MSIx. PCI MSI/MSIx is edge triggered and supports pending state bit. So used bool instead of Result<bool>. Any requirement to distinguish between "No pending interrupt" and "no support of querying pending state"?

It's really challenge to support PCI bus, much more complex than MMIO. We have used MSI with MMIO devices without support of mask/unmask for a long time.

@bonzini
Copy link
Member

bonzini commented Feb 28, 2020

Looking more at the cloud-hypervisor code, a lot of the MsiInterruptGroup group seems to be a very boring wrapper around Vec. I wonder if the best solution is to have InterruptSourceGroup be a struct that implements Index, and instead making VMMs implement an Interrupt trait. So you would write:

grp[i].trigger();

Something like this:

pub trait Interrupt {
    type Config;
    fn enable(&self) -> Result<()>;
    fn disable(&self) -> Result<()>;
    fn notifier(&self) -> Option<&EventFd> { None }
    fn trigger(&self) -> Result<()> { self.notifier().write(1) }
}
pub trait MSIInterrupt: Interrupt {
    fn mask(&self) -> Result<()>;
    fn unmask(&self) -> Result<()>;
    fn get_state(&self) -> bool;
}

pub struct InterruptSourceGroup<'a, I: Interrupt> {
    vec: Vec<I>
}

impl InterruptSourceGroup {
    fn enable(&self) -> Result<()> {
        for (_, route) in self.vec.iter() {
            route.enable()?;
        }

        Ok(())
    }
    // etc. possibly implement a get() method that returns an Option<I>
    // to not panic on out-of-bounds accesses
}

impl<I: Interrupt> Index<u32> for InterruptSourceGroup<'_, I> {
    type Output = I;
    fn index(&self, index: u32) -> &Self::Output { self.vec[index] }
}

create_group then can just return an Arc<InterruptSourceGroup<Self::Interrupt>> where Interrupt is an associated type of InterruptManager (and the config type then is Self::Interrupt::Config>).

@bonzini
Copy link
Member

bonzini commented Mar 2, 2020

See bonzini@388a575 for an example (also including unit tests).

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.

5 participants