|
[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 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>
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.
Jan
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |