[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v10 1/5] xen/riscv: implement IRQ routing for device passthrough





On 9/30/26 1:56 PM, Jan Beulich wrote:
On 23.09.2026 12:26, Oleksii Kurochko wrote:
dom0less device passthrough requires granting guest domains access to
device interrupts.  Introduce map_device_irqs_to_domain() to enumerate
a DT node's interrupt properties, skipping those not owned by
the primary interrupt controller (as at the moment I haven't seen usages
of it), and map_irq_to_domain() to grant domain access and configure
Xen's interrupt descriptor accordingly. Sharing IRQ between domains is
rejected.

Both map_irq_to_domain() and map_device_irqs_to_domain() are marked
__overlay_init, mirroring Arm: without CONFIG_OVERLAY_DTB this expands to
__init, so the functions are init-only and need no XSM check; with
CONFIG_OVERLAY_DTB they become runtime-callable, but the only runtime
entry point is dt_overlay_domctl(), which performs the XSM checks at the
domctl layer.  RISC-V does not wire up DT overlay yet, so today these are
strictly __init; if/when overlay support is added, the domctl-level XSM
gating must be added together with it, as on Arm.

route_irq_to_guest() and release_guest_irq() manage irq_desc ownership
for guest-assigned interrupts.  Each assignment carries a small irq_guest
structure as irqaction::dev_id, recording the owning domain and virtual
IRQ number which is 1:1 mapped to physical IRQ number.  A per-domain
vIRQ allocation bitmap (used_irqs in struct vintc), managed by
vintc_reserve_virq(), prevents the same vIRQ being claimed twice.

Host and guest interrupts may differ in some operations, EOI timing in
particular: a host IRQ is completed once Xen's handler runs, whereas a
passthrough IRQ must defer the physical completion until the guest issues
its own EOI, otherwise a still-asserted level line would immediately
retrigger and storm.  Hence a separate guest hw_irq_controller instance,
aplic_guest_irq_type, rather than an alias of the host one.

Its callbacks are BUG_ON("unimplemented") for now.  The only interrupt
controller configuration supported so far is APLIC in MSI mode together
with IMSIC, where guest interrupts are delivered by hardware straight to
the guest's interrupt file, bypassing do_IRQ() and thereby Xen entirely.
The _IRQ_GUEST branch in do_IRQ() is left as BUG() for the same reason.
Real callbacks, .end() in particular, become necessary once a platform
without direct IMSIC delivery has to be supported, where Xen traps the
interrupt and injects it into the guest itself.

Signed-off-by: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx>

Acked-by: Jan Beulich <jbeulich@xxxxxxxx>

Thanks.


One nit:

Changes in v8:
  - vintc_reserve_virq(): return an error code instead of a bool: 0 on
    success, -EEXIST when the vIRQ has already been reserved (which
    legitimately happens for an IRQ shared between devices) and -ERANGE
    when the vIRQ is outside the range the vINTC provides. Document the
    function and its return values.
  - vintc_reserve_virq(): mark it __overlay_init, as its only caller
    map_irq_to_domain() is __overlay_init too. Add the <xen/dt-overlay.h>
    and <xen/errno.h> includes this needs.
  - map_irq_to_domain(): check the return value of vintc_reserve_virq()
    and propagate anything but -EEXIST. Otherwise the IRQ would end up
    routed to the domain without domain_vintc_deinit() ever releasing it
    again. Update the stale comment accordingly.
  - domain_vintc_deinit(): only walk used_irqs and free it if it has
    actually been allocated. domain_vintc_init() can fail after the vINTC
    itself has been allocated, leaving used_irqs NULL.
  - irq.c: split the body of release_irq() into two helpers:
    irq_detach_action(), which removes the action matching dev_id from
    desc->action with desc->lock held, and irq_release_action(), which
    waits for a handler still running on another CPU and frees the action
    with desc->lock dropped. Both document the locking rules they rely on.
    release_irq() is now just a wrapper around the two.
  - release_guest_irq(): use irq_detach_action()/irq_release_action()
    instead of open-coding __clear_bit(_IRQ_GUEST, ...) followed by
    release_irq(), which looked the action up by dev_id a second time.
  - release_guest_irq(): drop the -EBUSY restriction that only allowed
    unrouting from a dying domain. Detaching the action under desc->lock
    now closes the window this was working around.
  - route_irq_to_guest(): on the intc_route_irq_to_guest() failure path,
    detach the action while desc->lock is still held and only release it
    after the lock has been dropped, instead of dropping the lock first
    and calling release_irq().
  - route_irq_to_guest(): initialise desc at its declaration.
  - irq_get_guest_info(): use ASSERT(desc->action) instead of
    ASSERT(desc->action != NULL).

Along the lines of this, and in line with ...

+/* Route an IRQ to a specific guest */
+int route_irq_to_guest(struct domain *d, unsigned int virq,
+                       unsigned int irq, const char *devname)
+{
+    struct irq_guest *info;
+    struct irq_desc *desc = irq_to_desc(irq);
+    unsigned long flags;
+    int retval = 0;
+
+    if ( d->is_dying )
+        return -EINVAL;
+
+    info = xvzalloc(struct irq_guest);
+    if ( !info )

... e.g. this, ...

+        return -ENOMEM;
+
+    info->d = d;
+    info->virq = virq;
+
+    info->action.dev_id = info;
+    info->action.name = devname;
+
+    spin_lock_irqsave(&desc->lock, flags);
+
+    /*
+     * If the IRQ is already used by someone
+     *  - If it's the same domain -> Xen doesn't need to update the IRQ desc.
+     *  For safety check if we are not trying to assign the IRQ to a
+     *  different vIRQ.
+     *  - Otherwise -> For now, don't allow the IRQ to be shared between
+     *  Xen and domains.
+     */
+    if ( desc->action != NULL )

... this would more consistently be "if ( desc->action )". I think I'll take
the liberty to adjust this while committing.

I will be happy with that.

Thanks.

~ Oleksii



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.