Re: [PATCH v5 16/16] iommu/hyperv: setup an IO-APIC IRQ remapping domain for root partition
On Thu, Feb 04, 2021 at 04:41:47PM +, Michael Kelley wrote: > From: Wei Liu Sent: Wednesday, February 3, 2021 4:47 AM [...] > > > > + > > > > + if (level) > > > > + intr_desc->trigger_mode = > > > > HV_INTERRUPT_TRIGGER_MODE_LEVEL; > > > > + else > > > > + intr_desc->trigger_mode = > > > > HV_INTERRUPT_TRIGGER_MODE_EDGE; > > > > + > > > > + __set_bit(vcpu, (unsigned long *)_desc->target.vp_mask); > > > > + > > > > + status = hv_do_rep_hypercall(HVCALL_MAP_DEVICE_INTERRUPT, 0, 0, > > > > input, > > output) & > > > > +HV_HYPERCALL_RESULT_MASK; > > > > + local_irq_restore(flags); > > > > + > > > > + *entry = output->interrupt_entry; > > > > + > > > > + return status; > > > > > > As a cross-check, I was comparing this code against > > > hv_map_msi_interrupt(). They are > > > mostly parallel, though some of the assignments are done in a different > > > order. It's a nit, > > > but making them as parallel as possible would be nice. :-) > > > > > > > Indeed. I will see about factoring out a function. > > If factoring out a separate helper function is clumsy, just having the > parallel code > in the two functions be as similar as possible makes it easier to see what's > the > same and what's different. > No. It is not clumsy at all. I've done it in the newly posted v6. I was baffled why I wrote hv_unmap_interrupt helper to be used by both hv_unmap_ioapic_interrupt and hv_unmap_msi_interrupt in the previous patch, but didn't write a hv_map_interrupt. Maybe I didn't have enough coffee that day. :-/ Thanks for pointing out that issue. It definitely helped improve the quality of this series. Wei. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
RE: [PATCH v5 16/16] iommu/hyperv: setup an IO-APIC IRQ remapping domain for root partition
From: Wei Liu Sent: Wednesday, February 3, 2021 4:47 AM > > On Wed, Jan 27, 2021 at 05:47:08AM +, Michael Kelley wrote: > > From: Wei Liu Sent: Wednesday, January 20, 2021 4:01 AM > > > > > > Just like MSI/MSI-X, IO-APIC interrupts are remapped by Microsoft > > > Hypervisor when Linux runs as the root partition. Implement an IRQ > > > domain to handle mapping and unmapping of IO-APIC interrupts. > > > > > > Signed-off-by: Wei Liu > > > --- > > > arch/x86/hyperv/irqdomain.c | 54 ++ > > > arch/x86/include/asm/mshyperv.h | 4 + > > > drivers/iommu/hyperv-iommu.c| 179 +++- > > > 3 files changed, 233 insertions(+), 4 deletions(-) > > > > > > diff --git a/arch/x86/hyperv/irqdomain.c b/arch/x86/hyperv/irqdomain.c > > > index 19637cd60231..8e2b4e478b70 100644 > > > --- a/arch/x86/hyperv/irqdomain.c > > > +++ b/arch/x86/hyperv/irqdomain.c > > > @@ -330,3 +330,57 @@ struct irq_domain * __init > > > hv_create_pci_msi_domain(void) > > > } > > > > > > #endif /* CONFIG_PCI_MSI */ > > > + > > > +int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry > > > *entry) > > > +{ > > > + union hv_device_id device_id; > > > + > > > + device_id.as_uint64 = 0; > > > + device_id.device_type = HV_DEVICE_TYPE_IOAPIC; > > > + device_id.ioapic.ioapic_id = (u8)ioapic_id; > > > + > > > + return hv_unmap_interrupt(device_id.as_uint64, entry) & > HV_HYPERCALL_RESULT_MASK; > > > > The masking is already done in hv_unmap_interrupt. > > Fixed. > > > > > > +} > > > +EXPORT_SYMBOL_GPL(hv_unmap_ioapic_interrupt); > > > + > > > +int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int > > > vector, > > > + struct hv_interrupt_entry *entry) > > > +{ > > > + unsigned long flags; > > > + struct hv_input_map_device_interrupt *input; > > > + struct hv_output_map_device_interrupt *output; > > > + union hv_device_id device_id; > > > + struct hv_device_interrupt_descriptor *intr_desc; > > > + u16 status; > > > + > > > + device_id.as_uint64 = 0; > > > + device_id.device_type = HV_DEVICE_TYPE_IOAPIC; > > > + device_id.ioapic.ioapic_id = (u8)ioapic_id; > > > + > > > + local_irq_save(flags); > > > + input = *this_cpu_ptr(hyperv_pcpu_input_arg); > > > + output = *this_cpu_ptr(hyperv_pcpu_output_arg); > > > + memset(input, 0, sizeof(*input)); > > > + intr_desc = >interrupt_descriptor; > > > + input->partition_id = hv_current_partition_id; > > > + input->device_id = device_id.as_uint64; > > > + intr_desc->interrupt_type = HV_X64_INTERRUPT_TYPE_FIXED; > > > + intr_desc->target.vector = vector; > > > + intr_desc->vector_count = 1; > > > + > > > + if (level) > > > + intr_desc->trigger_mode = HV_INTERRUPT_TRIGGER_MODE_LEVEL; > > > + else > > > + intr_desc->trigger_mode = HV_INTERRUPT_TRIGGER_MODE_EDGE; > > > + > > > + __set_bit(vcpu, (unsigned long *)_desc->target.vp_mask); > > > + > > > + status = hv_do_rep_hypercall(HVCALL_MAP_DEVICE_INTERRUPT, 0, 0, input, > output) & > > > + HV_HYPERCALL_RESULT_MASK; > > > + local_irq_restore(flags); > > > + > > > + *entry = output->interrupt_entry; > > > + > > > + return status; > > > > As a cross-check, I was comparing this code against hv_map_msi_interrupt(). > > They are > > mostly parallel, though some of the assignments are done in a different > > order. It's a nit, > > but making them as parallel as possible would be nice. :-) > > > > Indeed. I will see about factoring out a function. If factoring out a separate helper function is clumsy, just having the parallel code in the two functions be as similar as possible makes it easier to see what's the same and what's different. > > > Same 64 vCPU comment applies here as well. > > > > This is changed to use vpset instead. Took me a bit of time to get it > working because document is a bit lacking. > > > > > > +} > > > +EXPORT_SYMBOL_GPL(hv_map_ioapic_interrupt); > > > diff --git a/arch/x86/include/asm/mshyperv.h > > > b/arch/x86/include/asm/mshyperv.h > > > index ccc849e25d5e..345d7c6f8c37 100644 > > > --- a/arch/x86/include/asm/mshyperv.h > > > +++ b/arch/x86/include/asm/mshyperv.h > > > @@ -263,6 +263,10 @@ static inline void hv_set_msi_entry_from_desc(union > > > hv_msi_entry *msi_entry, > > > > > > struct irq_domain *hv_create_pci_msi_domain(void); > > > > > > +int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int > > > vector, > > > + struct hv_interrupt_entry *entry); > > > +int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry > > > *entry); > > > + > > > #else /* CONFIG_HYPERV */ > > > static inline void hyperv_init(void) {} > > > static inline void hyperv_setup_mmu_ops(void) {} > > > diff --git a/drivers/iommu/hyperv-iommu.c b/drivers/iommu/hyperv-iommu.c > > > index b7db6024e65c..6d35e4c303c6 100644 > > > --- a/drivers/iommu/hyperv-iommu.c > > > +++ b/drivers/iommu/hyperv-iommu.c > > > @@ -116,30 +116,43 @@ static const struct irq_domain_ops > > > hyperv_ir_domain_ops = { > >
Re: [PATCH v5 16/16] iommu/hyperv: setup an IO-APIC IRQ remapping domain for root partition
On Wed, Jan 27, 2021 at 05:47:08AM +, Michael Kelley wrote: > From: Wei Liu Sent: Wednesday, January 20, 2021 4:01 AM > > > > Just like MSI/MSI-X, IO-APIC interrupts are remapped by Microsoft > > Hypervisor when Linux runs as the root partition. Implement an IRQ > > domain to handle mapping and unmapping of IO-APIC interrupts. > > > > Signed-off-by: Wei Liu > > --- > > arch/x86/hyperv/irqdomain.c | 54 ++ > > arch/x86/include/asm/mshyperv.h | 4 + > > drivers/iommu/hyperv-iommu.c| 179 +++- > > 3 files changed, 233 insertions(+), 4 deletions(-) > > > > diff --git a/arch/x86/hyperv/irqdomain.c b/arch/x86/hyperv/irqdomain.c > > index 19637cd60231..8e2b4e478b70 100644 > > --- a/arch/x86/hyperv/irqdomain.c > > +++ b/arch/x86/hyperv/irqdomain.c > > @@ -330,3 +330,57 @@ struct irq_domain * __init > > hv_create_pci_msi_domain(void) > > } > > > > #endif /* CONFIG_PCI_MSI */ > > + > > +int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry > > *entry) > > +{ > > + union hv_device_id device_id; > > + > > + device_id.as_uint64 = 0; > > + device_id.device_type = HV_DEVICE_TYPE_IOAPIC; > > + device_id.ioapic.ioapic_id = (u8)ioapic_id; > > + > > + return hv_unmap_interrupt(device_id.as_uint64, entry) & > > HV_HYPERCALL_RESULT_MASK; > > The masking is already done in hv_unmap_interrupt. Fixed. > > > +} > > +EXPORT_SYMBOL_GPL(hv_unmap_ioapic_interrupt); > > + > > +int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int > > vector, > > + struct hv_interrupt_entry *entry) > > +{ > > + unsigned long flags; > > + struct hv_input_map_device_interrupt *input; > > + struct hv_output_map_device_interrupt *output; > > + union hv_device_id device_id; > > + struct hv_device_interrupt_descriptor *intr_desc; > > + u16 status; > > + > > + device_id.as_uint64 = 0; > > + device_id.device_type = HV_DEVICE_TYPE_IOAPIC; > > + device_id.ioapic.ioapic_id = (u8)ioapic_id; > > + > > + local_irq_save(flags); > > + input = *this_cpu_ptr(hyperv_pcpu_input_arg); > > + output = *this_cpu_ptr(hyperv_pcpu_output_arg); > > + memset(input, 0, sizeof(*input)); > > + intr_desc = >interrupt_descriptor; > > + input->partition_id = hv_current_partition_id; > > + input->device_id = device_id.as_uint64; > > + intr_desc->interrupt_type = HV_X64_INTERRUPT_TYPE_FIXED; > > + intr_desc->target.vector = vector; > > + intr_desc->vector_count = 1; > > + > > + if (level) > > + intr_desc->trigger_mode = HV_INTERRUPT_TRIGGER_MODE_LEVEL; > > + else > > + intr_desc->trigger_mode = HV_INTERRUPT_TRIGGER_MODE_EDGE; > > + > > + __set_bit(vcpu, (unsigned long *)_desc->target.vp_mask); > > + > > + status = hv_do_rep_hypercall(HVCALL_MAP_DEVICE_INTERRUPT, 0, 0, input, > > output) & > > +HV_HYPERCALL_RESULT_MASK; > > + local_irq_restore(flags); > > + > > + *entry = output->interrupt_entry; > > + > > + return status; > > As a cross-check, I was comparing this code against hv_map_msi_interrupt(). > They are > mostly parallel, though some of the assignments are done in a different > order. It's a nit, > but making them as parallel as possible would be nice. :-) > Indeed. I will see about factoring out a function. > Same 64 vCPU comment applies here as well. > This is changed to use vpset instead. Took me a bit of time to get it working because document is a bit lacking. > > > +} > > +EXPORT_SYMBOL_GPL(hv_map_ioapic_interrupt); > > diff --git a/arch/x86/include/asm/mshyperv.h > > b/arch/x86/include/asm/mshyperv.h > > index ccc849e25d5e..345d7c6f8c37 100644 > > --- a/arch/x86/include/asm/mshyperv.h > > +++ b/arch/x86/include/asm/mshyperv.h > > @@ -263,6 +263,10 @@ static inline void hv_set_msi_entry_from_desc(union > > hv_msi_entry *msi_entry, > > > > struct irq_domain *hv_create_pci_msi_domain(void); > > > > +int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int > > vector, > > + struct hv_interrupt_entry *entry); > > +int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry > > *entry); > > + > > #else /* CONFIG_HYPERV */ > > static inline void hyperv_init(void) {} > > static inline void hyperv_setup_mmu_ops(void) {} > > diff --git a/drivers/iommu/hyperv-iommu.c b/drivers/iommu/hyperv-iommu.c > > index b7db6024e65c..6d35e4c303c6 100644 > > --- a/drivers/iommu/hyperv-iommu.c > > +++ b/drivers/iommu/hyperv-iommu.c > > @@ -116,30 +116,43 @@ static const struct irq_domain_ops > > hyperv_ir_domain_ops = { > > .free = hyperv_irq_remapping_free, > > }; > > > > +static const struct irq_domain_ops hyperv_root_ir_domain_ops; > > static int __init hyperv_prepare_irq_remapping(void) > > { > > struct fwnode_handle *fn; > > int i; > > + const char *name; > > + const struct irq_domain_ops *ops; > > > > if (!hypervisor_is_type(X86_HYPER_MS_HYPERV) || > > x86_init.hyper.msi_ext_dest_id() || > > -
RE: [PATCH v5 16/16] iommu/hyperv: setup an IO-APIC IRQ remapping domain for root partition
From: Wei Liu Sent: Wednesday, January 20, 2021 4:01 AM > > Just like MSI/MSI-X, IO-APIC interrupts are remapped by Microsoft > Hypervisor when Linux runs as the root partition. Implement an IRQ > domain to handle mapping and unmapping of IO-APIC interrupts. > > Signed-off-by: Wei Liu > --- > arch/x86/hyperv/irqdomain.c | 54 ++ > arch/x86/include/asm/mshyperv.h | 4 + > drivers/iommu/hyperv-iommu.c| 179 +++- > 3 files changed, 233 insertions(+), 4 deletions(-) > > diff --git a/arch/x86/hyperv/irqdomain.c b/arch/x86/hyperv/irqdomain.c > index 19637cd60231..8e2b4e478b70 100644 > --- a/arch/x86/hyperv/irqdomain.c > +++ b/arch/x86/hyperv/irqdomain.c > @@ -330,3 +330,57 @@ struct irq_domain * __init hv_create_pci_msi_domain(void) > } > > #endif /* CONFIG_PCI_MSI */ > + > +int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry > *entry) > +{ > + union hv_device_id device_id; > + > + device_id.as_uint64 = 0; > + device_id.device_type = HV_DEVICE_TYPE_IOAPIC; > + device_id.ioapic.ioapic_id = (u8)ioapic_id; > + > + return hv_unmap_interrupt(device_id.as_uint64, entry) & > HV_HYPERCALL_RESULT_MASK; The masking is already done in hv_unmap_interrupt. > +} > +EXPORT_SYMBOL_GPL(hv_unmap_ioapic_interrupt); > + > +int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int vector, > + struct hv_interrupt_entry *entry) > +{ > + unsigned long flags; > + struct hv_input_map_device_interrupt *input; > + struct hv_output_map_device_interrupt *output; > + union hv_device_id device_id; > + struct hv_device_interrupt_descriptor *intr_desc; > + u16 status; > + > + device_id.as_uint64 = 0; > + device_id.device_type = HV_DEVICE_TYPE_IOAPIC; > + device_id.ioapic.ioapic_id = (u8)ioapic_id; > + > + local_irq_save(flags); > + input = *this_cpu_ptr(hyperv_pcpu_input_arg); > + output = *this_cpu_ptr(hyperv_pcpu_output_arg); > + memset(input, 0, sizeof(*input)); > + intr_desc = >interrupt_descriptor; > + input->partition_id = hv_current_partition_id; > + input->device_id = device_id.as_uint64; > + intr_desc->interrupt_type = HV_X64_INTERRUPT_TYPE_FIXED; > + intr_desc->target.vector = vector; > + intr_desc->vector_count = 1; > + > + if (level) > + intr_desc->trigger_mode = HV_INTERRUPT_TRIGGER_MODE_LEVEL; > + else > + intr_desc->trigger_mode = HV_INTERRUPT_TRIGGER_MODE_EDGE; > + > + __set_bit(vcpu, (unsigned long *)_desc->target.vp_mask); > + > + status = hv_do_rep_hypercall(HVCALL_MAP_DEVICE_INTERRUPT, 0, 0, input, > output) & > + HV_HYPERCALL_RESULT_MASK; > + local_irq_restore(flags); > + > + *entry = output->interrupt_entry; > + > + return status; As a cross-check, I was comparing this code against hv_map_msi_interrupt(). They are mostly parallel, though some of the assignments are done in a different order. It's a nit, but making them as parallel as possible would be nice. :-) Same 64 vCPU comment applies here as well. > +} > +EXPORT_SYMBOL_GPL(hv_map_ioapic_interrupt); > diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h > index ccc849e25d5e..345d7c6f8c37 100644 > --- a/arch/x86/include/asm/mshyperv.h > +++ b/arch/x86/include/asm/mshyperv.h > @@ -263,6 +263,10 @@ static inline void hv_set_msi_entry_from_desc(union > hv_msi_entry *msi_entry, > > struct irq_domain *hv_create_pci_msi_domain(void); > > +int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int vector, > + struct hv_interrupt_entry *entry); > +int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry > *entry); > + > #else /* CONFIG_HYPERV */ > static inline void hyperv_init(void) {} > static inline void hyperv_setup_mmu_ops(void) {} > diff --git a/drivers/iommu/hyperv-iommu.c b/drivers/iommu/hyperv-iommu.c > index b7db6024e65c..6d35e4c303c6 100644 > --- a/drivers/iommu/hyperv-iommu.c > +++ b/drivers/iommu/hyperv-iommu.c > @@ -116,30 +116,43 @@ static const struct irq_domain_ops hyperv_ir_domain_ops > = { > .free = hyperv_irq_remapping_free, > }; > > +static const struct irq_domain_ops hyperv_root_ir_domain_ops; > static int __init hyperv_prepare_irq_remapping(void) > { > struct fwnode_handle *fn; > int i; > + const char *name; > + const struct irq_domain_ops *ops; > > if (!hypervisor_is_type(X86_HYPER_MS_HYPERV) || > x86_init.hyper.msi_ext_dest_id() || > - !x2apic_supported() || hv_root_partition) > + !x2apic_supported()) Any reason that the check for hv_root_partition was added in patch #4 of this series, and then removed here? Could patch #4 just be dropped? > return -ENODEV; > > - fn = irq_domain_alloc_named_id_fwnode("HYPERV-IR", 0); > + if (hv_root_partition) { > + name = "HYPERV-ROOT-IR"; > + ops =
[PATCH v5 16/16] iommu/hyperv: setup an IO-APIC IRQ remapping domain for root partition
Just like MSI/MSI-X, IO-APIC interrupts are remapped by Microsoft Hypervisor when Linux runs as the root partition. Implement an IRQ domain to handle mapping and unmapping of IO-APIC interrupts. Signed-off-by: Wei Liu --- arch/x86/hyperv/irqdomain.c | 54 ++ arch/x86/include/asm/mshyperv.h | 4 + drivers/iommu/hyperv-iommu.c| 179 +++- 3 files changed, 233 insertions(+), 4 deletions(-) diff --git a/arch/x86/hyperv/irqdomain.c b/arch/x86/hyperv/irqdomain.c index 19637cd60231..8e2b4e478b70 100644 --- a/arch/x86/hyperv/irqdomain.c +++ b/arch/x86/hyperv/irqdomain.c @@ -330,3 +330,57 @@ struct irq_domain * __init hv_create_pci_msi_domain(void) } #endif /* CONFIG_PCI_MSI */ + +int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry *entry) +{ + union hv_device_id device_id; + + device_id.as_uint64 = 0; + device_id.device_type = HV_DEVICE_TYPE_IOAPIC; + device_id.ioapic.ioapic_id = (u8)ioapic_id; + + return hv_unmap_interrupt(device_id.as_uint64, entry) & HV_HYPERCALL_RESULT_MASK; +} +EXPORT_SYMBOL_GPL(hv_unmap_ioapic_interrupt); + +int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int vector, + struct hv_interrupt_entry *entry) +{ + unsigned long flags; + struct hv_input_map_device_interrupt *input; + struct hv_output_map_device_interrupt *output; + union hv_device_id device_id; + struct hv_device_interrupt_descriptor *intr_desc; + u16 status; + + device_id.as_uint64 = 0; + device_id.device_type = HV_DEVICE_TYPE_IOAPIC; + device_id.ioapic.ioapic_id = (u8)ioapic_id; + + local_irq_save(flags); + input = *this_cpu_ptr(hyperv_pcpu_input_arg); + output = *this_cpu_ptr(hyperv_pcpu_output_arg); + memset(input, 0, sizeof(*input)); + intr_desc = >interrupt_descriptor; + input->partition_id = hv_current_partition_id; + input->device_id = device_id.as_uint64; + intr_desc->interrupt_type = HV_X64_INTERRUPT_TYPE_FIXED; + intr_desc->target.vector = vector; + intr_desc->vector_count = 1; + + if (level) + intr_desc->trigger_mode = HV_INTERRUPT_TRIGGER_MODE_LEVEL; + else + intr_desc->trigger_mode = HV_INTERRUPT_TRIGGER_MODE_EDGE; + + __set_bit(vcpu, (unsigned long *)_desc->target.vp_mask); + + status = hv_do_rep_hypercall(HVCALL_MAP_DEVICE_INTERRUPT, 0, 0, input, output) & +HV_HYPERCALL_RESULT_MASK; + local_irq_restore(flags); + + *entry = output->interrupt_entry; + + return status; +} +EXPORT_SYMBOL_GPL(hv_map_ioapic_interrupt); diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index ccc849e25d5e..345d7c6f8c37 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h @@ -263,6 +263,10 @@ static inline void hv_set_msi_entry_from_desc(union hv_msi_entry *msi_entry, struct irq_domain *hv_create_pci_msi_domain(void); +int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int vector, + struct hv_interrupt_entry *entry); +int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry *entry); + #else /* CONFIG_HYPERV */ static inline void hyperv_init(void) {} static inline void hyperv_setup_mmu_ops(void) {} diff --git a/drivers/iommu/hyperv-iommu.c b/drivers/iommu/hyperv-iommu.c index b7db6024e65c..6d35e4c303c6 100644 --- a/drivers/iommu/hyperv-iommu.c +++ b/drivers/iommu/hyperv-iommu.c @@ -116,30 +116,43 @@ static const struct irq_domain_ops hyperv_ir_domain_ops = { .free = hyperv_irq_remapping_free, }; +static const struct irq_domain_ops hyperv_root_ir_domain_ops; static int __init hyperv_prepare_irq_remapping(void) { struct fwnode_handle *fn; int i; + const char *name; + const struct irq_domain_ops *ops; if (!hypervisor_is_type(X86_HYPER_MS_HYPERV) || x86_init.hyper.msi_ext_dest_id() || - !x2apic_supported() || hv_root_partition) + !x2apic_supported()) return -ENODEV; - fn = irq_domain_alloc_named_id_fwnode("HYPERV-IR", 0); + if (hv_root_partition) { + name = "HYPERV-ROOT-IR"; + ops = _root_ir_domain_ops; + } else { + name = "HYPERV-IR"; + ops = _ir_domain_ops; + } + + fn = irq_domain_alloc_named_id_fwnode(name, 0); if (!fn) return -ENOMEM; ioapic_ir_domain = irq_domain_create_hierarchy(arch_get_ir_parent_domain(), - 0, IOAPIC_REMAPPING_ENTRY, fn, - _ir_domain_ops, NULL); + 0, IOAPIC_REMAPPING_ENTRY, fn, ops, NULL); if (!ioapic_ir_domain) { irq_domain_free_fwnode(fn); return -ENOMEM; } + if (hv_root_partition) +