Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 79fec2c5 authored by Ingo Molnar's avatar Ingo Molnar
Browse files

Merge tag 'intr-remapping-ops-for-ingo' of...

Merge tag 'intr-remapping-ops-for-ingo' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu

 into core/iommu

- This patchset introduces a generic ops-interface for
  accessing interrupt remapping hardware on x86. It factors
  out the VT-d specific code from io_apic.c and moves it to
  drivers/iommu. These changes will be used to add support for
  AMD interrupt remapping hardware.

Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents febb72a6 8a8f422d
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
#ifndef __IA64_INTR_REMAPPING_H
#define __IA64_INTR_REMAPPING_H
#define irq_remapping_enabled 0
#endif
+89 −31
Original line number Diff line number Diff line
#ifndef _ASM_X86_IRQ_REMAPPING_H
#define _ASM_X86_IRQ_REMAPPING_H
/*
 * Copyright (C) 2012 Advanced Micro Devices, Inc.
 * Author: Joerg Roedel <joerg.roedel@amd.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 * This header file contains the interface of the interrupt remapping code to
 * the x86 interrupt management code.
 */

#define IRTE_DEST(dest) ((x2apic_mode) ? dest : dest << 8)
#ifndef __X86_IRQ_REMAPPING_H
#define __X86_IRQ_REMAPPING_H

#ifdef CONFIG_IRQ_REMAP
static void irq_remap_modify_chip_defaults(struct irq_chip *chip);
static inline void prepare_irte(struct irte *irte, int vector,
			        unsigned int dest)
{
	memset(irte, 0, sizeof(*irte));

	irte->present = 1;
	irte->dst_mode = apic->irq_dest_mode;
	/*
	 * Trigger mode in the IRTE will always be edge, and for IO-APIC, the
	 * actual level or edge trigger will be setup in the IO-APIC
	 * RTE. This will help simplify level triggered irq migration.
	 * For more details, see the comments (in io_apic.c) explainig IO-APIC
	 * irq migration in the presence of interrupt-remapping.
	*/
	irte->trigger_mode = 0;
	irte->dlvry_mode = apic->irq_delivery_mode;
	irte->vector = vector;
	irte->dest_id = IRTE_DEST(dest);
	irte->redir_hint = 1;
struct IO_APIC_route_entry;
struct io_apic_irq_attr;
struct pci_dev;

extern int irq_remapping_enabled;

extern void setup_irq_remapping_ops(void);
extern int irq_remapping_supported(void);
extern int irq_remapping_prepare(void);
extern int irq_remapping_enable(void);
extern void irq_remapping_disable(void);
extern int irq_remapping_reenable(int);
extern int irq_remap_enable_fault_handling(void);
extern int setup_ioapic_remapped_entry(int irq,
				       struct IO_APIC_route_entry *entry,
				       unsigned int destination,
				       int vector,
				       struct io_apic_irq_attr *attr);
extern int set_remapped_irq_affinity(struct irq_data *data,
				     const struct cpumask *mask,
				     bool force);
extern void free_remapped_irq(int irq);
extern void compose_remapped_msi_msg(struct pci_dev *pdev,
				     unsigned int irq, unsigned int dest,
				     struct msi_msg *msg, u8 hpet_id);
extern int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec);
extern int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
				  int index, int sub_handle);
extern int setup_hpet_msi_remapped(unsigned int irq, unsigned int id);

#else  /* CONFIG_IRQ_REMAP */

#define irq_remapping_enabled	0

static inline void setup_irq_remapping_ops(void) { }
static inline int irq_remapping_supported(void) { return 0; }
static inline int irq_remapping_prepare(void) { return -ENODEV; }
static inline int irq_remapping_enable(void) { return -ENODEV; }
static inline void irq_remapping_disable(void) { }
static inline int irq_remapping_reenable(int eim) { return -ENODEV; }
static inline int irq_remap_enable_fault_handling(void) { return -ENODEV; }
static inline int setup_ioapic_remapped_entry(int irq,
					      struct IO_APIC_route_entry *entry,
					      unsigned int destination,
					      int vector,
					      struct io_apic_irq_attr *attr)
{
	return -ENODEV;
}
static inline int set_remapped_irq_affinity(struct irq_data *data,
					    const struct cpumask *mask,
					    bool force)
{
	return 0;
}
static inline bool irq_remapped(struct irq_cfg *cfg)
static inline void free_remapped_irq(int irq) { }
static inline void compose_remapped_msi_msg(struct pci_dev *pdev,
					    unsigned int irq, unsigned int dest,
					    struct msi_msg *msg, u8 hpet_id)
{
	return cfg->irq_2_iommu.iommu != NULL;
}
#else
static void prepare_irte(struct irte *irte, int vector, unsigned int dest)
static inline int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
{
	return -ENODEV;
}
static inline bool irq_remapped(struct irq_cfg *cfg)
static inline int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
					 int index, int sub_handle)
{
	return false;
	return -ENODEV;
}
static inline void irq_remap_modify_chip_defaults(struct irq_chip *chip)
static inline int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
{
	return -ENODEV;
}
#endif
#endif /* CONFIG_IRQ_REMAP */

#endif	/* _ASM_X86_IRQ_REMAPPING_H */
#endif /* __X86_IRQ_REMAPPING_H */
+17 −13
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
#include <linux/smp.h>
#include <linux/mm.h>

#include <asm/irq_remapping.h>
#include <asm/perf_event.h>
#include <asm/x86_init.h>
#include <asm/pgalloc.h>
@@ -1441,8 +1442,8 @@ void __init bsp_end_local_APIC_setup(void)
	 * Now that local APIC setup is completed for BP, configure the fault
	 * handling for interrupt remapping.
	 */
	if (intr_remapping_enabled)
		enable_drhd_fault_handling();
	if (irq_remapping_enabled)
		irq_remap_enable_fault_handling();

}

@@ -1517,7 +1518,7 @@ void enable_x2apic(void)
int __init enable_IR(void)
{
#ifdef CONFIG_IRQ_REMAP
	if (!intr_remapping_supported()) {
	if (!irq_remapping_supported()) {
		pr_debug("intr-remapping not supported\n");
		return -1;
	}
@@ -1528,7 +1529,7 @@ int __init enable_IR(void)
		return -1;
	}

	return enable_intr_remapping();
	return irq_remapping_enable();
#endif
	return -1;
}
@@ -1537,10 +1538,13 @@ void __init enable_IR_x2apic(void)
{
	unsigned long flags;
	int ret, x2apic_enabled = 0;
	int dmar_table_init_ret;
	int hardware_init_ret;

	dmar_table_init_ret = dmar_table_init();
	if (dmar_table_init_ret && !x2apic_supported())
	/* Make sure irq_remap_ops are initialized */
	setup_irq_remapping_ops();

	hardware_init_ret = irq_remapping_prepare();
	if (hardware_init_ret && !x2apic_supported())
		return;

	ret = save_ioapic_entries();
@@ -1556,7 +1560,7 @@ void __init enable_IR_x2apic(void)
	if (x2apic_preenabled && nox2apic)
		disable_x2apic();

	if (dmar_table_init_ret)
	if (hardware_init_ret)
		ret = -1;
	else
		ret = enable_IR();
@@ -2176,8 +2180,8 @@ static int lapic_suspend(void)
	local_irq_save(flags);
	disable_local_APIC();

	if (intr_remapping_enabled)
		disable_intr_remapping();
	if (irq_remapping_enabled)
		irq_remapping_disable();

	local_irq_restore(flags);
	return 0;
@@ -2193,7 +2197,7 @@ static void lapic_resume(void)
		return;

	local_irq_save(flags);
	if (intr_remapping_enabled) {
	if (irq_remapping_enabled) {
		/*
		 * IO-APIC and PIC have their own resume routines.
		 * We just mask them here to make sure the interrupt
@@ -2245,8 +2249,8 @@ static void lapic_resume(void)
	apic_write(APIC_ESR, 0);
	apic_read(APIC_ESR);

	if (intr_remapping_enabled)
		reenable_intr_remapping(x2apic_mode);
	if (irq_remapping_enabled)
		irq_remapping_reenable(x2apic_mode);

	local_irq_restore(flags);
}
+61 −236
Original line number Diff line number Diff line
@@ -86,6 +86,22 @@ void __init set_io_apic_ops(const struct io_apic_ops *ops)
	io_apic_ops = *ops;
}

#ifdef CONFIG_IRQ_REMAP
static void irq_remap_modify_chip_defaults(struct irq_chip *chip);
static inline bool irq_remapped(struct irq_cfg *cfg)
{
	return cfg->irq_2_iommu.iommu != NULL;
}
#else
static inline bool irq_remapped(struct irq_cfg *cfg)
{
	return false;
}
static inline void irq_remap_modify_chip_defaults(struct irq_chip *chip)
{
}
#endif

/*
 *      Is the SiS APIC rmw bug present ?
 *      -1 = don't know, 0 = no, 1 = yes
@@ -1361,77 +1377,13 @@ static void ioapic_register_intr(unsigned int irq, struct irq_cfg *cfg,
				      fasteoi ? "fasteoi" : "edge");
}


static int setup_ir_ioapic_entry(int irq,
			      struct IR_IO_APIC_route_entry *entry,
			      unsigned int destination, int vector,
			      struct io_apic_irq_attr *attr)
{
	int index;
	struct irte irte;
	int ioapic_id = mpc_ioapic_id(attr->ioapic);
	struct intel_iommu *iommu = map_ioapic_to_ir(ioapic_id);

	if (!iommu) {
		pr_warn("No mapping iommu for ioapic %d\n", ioapic_id);
		return -ENODEV;
	}

	index = alloc_irte(iommu, irq, 1);
	if (index < 0) {
		pr_warn("Failed to allocate IRTE for ioapic %d\n", ioapic_id);
		return -ENOMEM;
	}

	prepare_irte(&irte, vector, destination);

	/* Set source-id of interrupt request */
	set_ioapic_sid(&irte, ioapic_id);

	modify_irte(irq, &irte);

	apic_printk(APIC_VERBOSE, KERN_DEBUG "IOAPIC[%d]: "
		"Set IRTE entry (P:%d FPD:%d Dst_Mode:%d "
		"Redir_hint:%d Trig_Mode:%d Dlvry_Mode:%X "
		"Avail:%X Vector:%02X Dest:%08X "
		"SID:%04X SQ:%X SVT:%X)\n",
		attr->ioapic, irte.present, irte.fpd, irte.dst_mode,
		irte.redir_hint, irte.trigger_mode, irte.dlvry_mode,
		irte.avail, irte.vector, irte.dest_id,
		irte.sid, irte.sq, irte.svt);

	memset(entry, 0, sizeof(*entry));

	entry->index2	= (index >> 15) & 0x1;
	entry->zero	= 0;
	entry->format	= 1;
	entry->index	= (index & 0x7fff);
	/*
	 * IO-APIC RTE will be configured with virtual vector.
	 * irq handler will do the explicit EOI to the io-apic.
	 */
	entry->vector	= attr->ioapic_pin;
	entry->mask	= 0;			/* enable IRQ */
	entry->trigger	= attr->trigger;
	entry->polarity	= attr->polarity;

	/* Mask level triggered irqs.
	 * Use IRQ_DELAYED_DISABLE for edge triggered irqs.
	 */
	if (attr->trigger)
		entry->mask = 1;

	return 0;
}

static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
			       unsigned int destination, int vector,
			       struct io_apic_irq_attr *attr)
{
	if (intr_remapping_enabled)
		return setup_ir_ioapic_entry(irq,
			 (struct IR_IO_APIC_route_entry *)entry,
			 destination, vector, attr);
	if (irq_remapping_enabled)
		return setup_ioapic_remapped_entry(irq, entry, destination,
						   vector, attr);

	memset(entry, 0, sizeof(*entry));

@@ -1588,7 +1540,7 @@ static void __init setup_timer_IRQ0_pin(unsigned int ioapic_idx,
{
	struct IO_APIC_route_entry entry;

	if (intr_remapping_enabled)
	if (irq_remapping_enabled)
		return;

	memset(&entry, 0, sizeof(entry));
@@ -1674,7 +1626,7 @@ __apicdebuginit(void) print_IO_APIC(int ioapic_idx)

	printk(KERN_DEBUG ".... IRQ redirection table:\n");

	if (intr_remapping_enabled) {
	if (irq_remapping_enabled) {
		printk(KERN_DEBUG " NR Indx Fmt Mask Trig IRR"
			" Pol Stat Indx2 Zero Vect:\n");
	} else {
@@ -1683,7 +1635,7 @@ __apicdebuginit(void) print_IO_APIC(int ioapic_idx)
	}

	for (i = 0; i <= reg_01.bits.entries; i++) {
		if (intr_remapping_enabled) {
		if (irq_remapping_enabled) {
			struct IO_APIC_route_entry entry;
			struct IR_IO_APIC_route_entry *ir_entry;

@@ -2050,7 +2002,7 @@ void disable_IO_APIC(void)
	 * IOAPIC RTE as well as interrupt-remapping table entry).
	 * As this gets called during crash dump, keep this simple for now.
	 */
	if (ioapic_i8259.pin != -1 && !intr_remapping_enabled) {
	if (ioapic_i8259.pin != -1 && !irq_remapping_enabled) {
		struct IO_APIC_route_entry entry;

		memset(&entry, 0, sizeof(entry));
@@ -2074,7 +2026,7 @@ void disable_IO_APIC(void)
	 * Use virtual wire A mode when interrupt remapping is enabled.
	 */
	if (cpu_has_apic || apic_from_smp_config())
		disconnect_bsp_APIC(!intr_remapping_enabled &&
		disconnect_bsp_APIC(!irq_remapping_enabled &&
				ioapic_i8259.pin != -1);
}

@@ -2390,71 +2342,6 @@ ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
	return ret;
}

#ifdef CONFIG_IRQ_REMAP

/*
 * Migrate the IO-APIC irq in the presence of intr-remapping.
 *
 * For both level and edge triggered, irq migration is a simple atomic
 * update(of vector and cpu destination) of IRTE and flush the hardware cache.
 *
 * For level triggered, we eliminate the io-apic RTE modification (with the
 * updated vector information), by using a virtual vector (io-apic pin number).
 * Real vector that is used for interrupting cpu will be coming from
 * the interrupt-remapping table entry.
 *
 * As the migration is a simple atomic update of IRTE, the same mechanism
 * is used to migrate MSI irq's in the presence of interrupt-remapping.
 */
static int
ir_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
		       bool force)
{
	struct irq_cfg *cfg = data->chip_data;
	unsigned int dest, irq = data->irq;
	struct irte irte;

	if (!cpumask_intersects(mask, cpu_online_mask))
		return -EINVAL;

	if (get_irte(irq, &irte))
		return -EBUSY;

	if (assign_irq_vector(irq, cfg, mask))
		return -EBUSY;

	dest = apic->cpu_mask_to_apicid_and(cfg->domain, mask);

	irte.vector = cfg->vector;
	irte.dest_id = IRTE_DEST(dest);

	/*
	 * Atomically updates the IRTE with the new destination, vector
	 * and flushes the interrupt entry cache.
	 */
	modify_irte(irq, &irte);

	/*
	 * After this point, all the interrupts will start arriving
	 * at the new destination. So, time to cleanup the previous
	 * vector allocation.
	 */
	if (cfg->move_in_progress)
		send_cleanup_vector(cfg);

	cpumask_copy(data->affinity, mask);
	return 0;
}

#else
static inline int
ir_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
		       bool force)
{
	return 0;
}
#endif

asmlinkage void smp_irq_move_cleanup_interrupt(void)
{
	unsigned vector, me;
@@ -2699,7 +2586,7 @@ static void irq_remap_modify_chip_defaults(struct irq_chip *chip)
	chip->irq_eoi = ir_ack_apic_level;

#ifdef CONFIG_SMP
	chip->irq_set_affinity = ir_ioapic_set_affinity;
	chip->irq_set_affinity = set_remapped_irq_affinity;
#endif
}
#endif /* CONFIG_IRQ_REMAP */
@@ -2912,7 +2799,7 @@ static inline void __init check_timer(void)
	 * 8259A.
	 */
	if (pin1 == -1) {
		if (intr_remapping_enabled)
		if (irq_remapping_enabled)
			panic("BIOS bug: timer not connected to IO-APIC");
		pin1 = pin2;
		apic1 = apic2;
@@ -2945,7 +2832,7 @@ static inline void __init check_timer(void)
				clear_IO_APIC_pin(0, pin1);
			goto out;
		}
		if (intr_remapping_enabled)
		if (irq_remapping_enabled)
			panic("timer doesn't work through Interrupt-remapped IO-APIC");
		local_irq_disable();
		clear_IO_APIC_pin(apic1, pin1);
@@ -3169,7 +3056,7 @@ void destroy_irq(unsigned int irq)
	irq_set_status_flags(irq, IRQ_NOREQUEST|IRQ_NOPROBE);

	if (irq_remapped(cfg))
		free_irte(irq);
		free_remapped_irq(irq);
	raw_spin_lock_irqsave(&vector_lock, flags);
	__clear_irq_vector(irq, cfg);
	raw_spin_unlock_irqrestore(&vector_lock, flags);
@@ -3198,30 +3085,10 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
	dest = apic->cpu_mask_to_apicid_and(cfg->domain, apic->target_cpus());

	if (irq_remapped(cfg)) {
		struct irte irte;
		int ir_index;
		u16 sub_handle;

		ir_index = map_irq_to_irte_handle(irq, &sub_handle);
		BUG_ON(ir_index == -1);

		prepare_irte(&irte, cfg->vector, dest);

		/* Set source-id of interrupt request */
		if (pdev)
			set_msi_sid(&irte, pdev);
		else
			set_hpet_sid(&irte, hpet_id);

		modify_irte(irq, &irte);
		compose_remapped_msi_msg(pdev, irq, dest, msg, hpet_id);
		return err;
	}

		msg->address_hi = MSI_ADDR_BASE_HI;
		msg->data = sub_handle;
		msg->address_lo = MSI_ADDR_BASE_LO | MSI_ADDR_IR_EXT_INT |
				  MSI_ADDR_IR_SHV |
				  MSI_ADDR_IR_INDEX1(ir_index) |
				  MSI_ADDR_IR_INDEX2(ir_index);
	} else {
	if (x2apic_enabled())
		msg->address_hi = MSI_ADDR_BASE_HI |
				  MSI_ADDR_EXT_DEST_ID(dest);
@@ -3245,7 +3112,7 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
			MSI_DATA_DELIVERY_FIXED:
			MSI_DATA_DELIVERY_LOWPRI) |
		MSI_DATA_VECTOR(cfg->vector);
	}

	return err;
}

@@ -3288,33 +3155,6 @@ static struct irq_chip msi_chip = {
	.irq_retrigger		= ioapic_retrigger_irq,
};

/*
 * Map the PCI dev to the corresponding remapping hardware unit
 * and allocate 'nvec' consecutive interrupt-remapping table entries
 * in it.
 */
static int msi_alloc_irte(struct pci_dev *dev, int irq, int nvec)
{
	struct intel_iommu *iommu;
	int index;

	iommu = map_dev_to_ir(dev);
	if (!iommu) {
		printk(KERN_ERR
		       "Unable to map PCI %s to iommu\n", pci_name(dev));
		return -ENOENT;
	}

	index = alloc_irte(iommu, irq, nvec);
	if (index < 0) {
		printk(KERN_ERR
		       "Unable to allocate %d IRTE for PCI %s\n", nvec,
		       pci_name(dev));
		return -ENOSPC;
	}
	return index;
}

static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
{
	struct irq_chip *chip = &msi_chip;
@@ -3345,7 +3185,6 @@ int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
	int node, ret, sub_handle, index = 0;
	unsigned int irq, irq_want;
	struct msi_desc *msidesc;
	struct intel_iommu *iommu = NULL;

	/* x86 doesn't support multiple MSI yet */
	if (type == PCI_CAP_ID_MSI && nvec > 1)
@@ -3359,7 +3198,7 @@ int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
		if (irq == 0)
			return -1;
		irq_want = irq + 1;
		if (!intr_remapping_enabled)
		if (!irq_remapping_enabled)
			goto no_ir;

		if (!sub_handle) {
@@ -3367,24 +3206,17 @@ int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
			 * allocate the consecutive block of IRTE's
			 * for 'nvec'
			 */
			index = msi_alloc_irte(dev, irq, nvec);
			index = msi_alloc_remapped_irq(dev, irq, nvec);
			if (index < 0) {
				ret = index;
				goto error;
			}
		} else {
			iommu = map_dev_to_ir(dev);
			if (!iommu) {
				ret = -ENOENT;
			ret = msi_setup_remapped_irq(dev, irq, index,
						     sub_handle);
			if (ret < 0)
				goto error;
		}
			/*
			 * setup the mapping between the irq and the IRTE
			 * base index, the sub_handle pointing to the
			 * appropriate interrupt remap table entry.
			 */
			set_irte_irq(irq, iommu, index, sub_handle);
		}
no_ir:
		ret = setup_msi_irq(dev, msidesc, irq);
		if (ret < 0)
@@ -3501,15 +3333,8 @@ int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
	struct msi_msg msg;
	int ret;

	if (intr_remapping_enabled) {
		struct intel_iommu *iommu = map_hpet_to_ir(id);
		int index;

		if (!iommu)
			return -1;

		index = alloc_irte(iommu, irq, 1);
		if (index < 0)
	if (irq_remapping_enabled) {
		if (!setup_hpet_msi_remapped(irq, id))
			return -1;
	}

@@ -3888,8 +3713,8 @@ void __init setup_ioapic_dest(void)
		else
			mask = apic->target_cpus();

		if (intr_remapping_enabled)
			ir_ioapic_set_affinity(idata, mask, false);
		if (irq_remapping_enabled)
			set_remapped_irq_affinity(idata, mask, false);
		else
			ioapic_set_affinity(idata, mask, false);
	}
+1 −1
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@ obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
obj-$(CONFIG_DMAR_TABLE) += dmar.o
obj-$(CONFIG_INTEL_IOMMU) += iova.o intel-iommu.o
obj-$(CONFIG_IRQ_REMAP) += intr_remapping.o
obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o
obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
obj-$(CONFIG_OMAP_IOVMM) += omap-iovmm.o
obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
Loading