diff options
author | Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> | 2016-08-23 14:52:34 -0400 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2016-09-05 06:41:46 -0400 |
commit | 880ac60e2538337f84d9f76ab7b3c13ee7787804 (patch) | |
tree | 8785d7a8c6fde2d636b69a8f905058d7b214f8dc | |
parent | a38180bd366f9912a08f52dd6f9a843bf0107d5f (diff) |
iommu/amd: Introduce interrupt remapping ops structure
Currently, IOMMU support two interrupt remapping table entry formats,
32-bit (legacy) and 128-bit (GA). The spec also implies that it might
support additional modes/formats in the future.
So, this patch introduces the new struct amd_irte_ops, which allows
the same code to work with different irte formats by providing hooks
for various operations on an interrupt remapping table entry.
Suggested-by: Joerg Roedel <joro@8bytes.org>
Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r-- | drivers/iommu/amd_iommu.c | 190 | ||||
-rw-r--r-- | drivers/iommu/amd_iommu_types.h | 20 |
2 files changed, 205 insertions, 5 deletions
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index c262a82971e4..baf2c2cf119f 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c | |||
@@ -3644,11 +3644,12 @@ out: | |||
3644 | return index; | 3644 | return index; |
3645 | } | 3645 | } |
3646 | 3646 | ||
3647 | static int modify_irte(u16 devid, int index, union irte irte) | 3647 | static int modify_irte_ga(u16 devid, int index, struct irte_ga *irte) |
3648 | { | 3648 | { |
3649 | struct irq_remap_table *table; | 3649 | struct irq_remap_table *table; |
3650 | struct amd_iommu *iommu; | 3650 | struct amd_iommu *iommu; |
3651 | unsigned long flags; | 3651 | unsigned long flags; |
3652 | struct irte_ga *entry; | ||
3652 | 3653 | ||
3653 | iommu = amd_iommu_rlookup_table[devid]; | 3654 | iommu = amd_iommu_rlookup_table[devid]; |
3654 | if (iommu == NULL) | 3655 | if (iommu == NULL) |
@@ -3659,7 +3660,38 @@ static int modify_irte(u16 devid, int index, union irte irte) | |||
3659 | return -ENOMEM; | 3660 | return -ENOMEM; |
3660 | 3661 | ||
3661 | spin_lock_irqsave(&table->lock, flags); | 3662 | spin_lock_irqsave(&table->lock, flags); |
3662 | table->table[index] = irte.val; | 3663 | |
3664 | entry = (struct irte_ga *)table->table; | ||
3665 | entry = &entry[index]; | ||
3666 | entry->lo.fields_remap.valid = 0; | ||
3667 | entry->hi.val = irte->hi.val; | ||
3668 | entry->lo.val = irte->lo.val; | ||
3669 | entry->lo.fields_remap.valid = 1; | ||
3670 | |||
3671 | spin_unlock_irqrestore(&table->lock, flags); | ||
3672 | |||
3673 | iommu_flush_irt(iommu, devid); | ||
3674 | iommu_completion_wait(iommu); | ||
3675 | |||
3676 | return 0; | ||
3677 | } | ||
3678 | |||
3679 | static int modify_irte(u16 devid, int index, union irte *irte) | ||
3680 | { | ||
3681 | struct irq_remap_table *table; | ||
3682 | struct amd_iommu *iommu; | ||
3683 | unsigned long flags; | ||
3684 | |||
3685 | iommu = amd_iommu_rlookup_table[devid]; | ||
3686 | if (iommu == NULL) | ||
3687 | return -EINVAL; | ||
3688 | |||
3689 | table = get_irq_table(devid, false); | ||
3690 | if (!table) | ||
3691 | return -ENOMEM; | ||
3692 | |||
3693 | spin_lock_irqsave(&table->lock, flags); | ||
3694 | table->table[index] = irte->val; | ||
3663 | spin_unlock_irqrestore(&table->lock, flags); | 3695 | spin_unlock_irqrestore(&table->lock, flags); |
3664 | 3696 | ||
3665 | iommu_flush_irt(iommu, devid); | 3697 | iommu_flush_irt(iommu, devid); |
@@ -3690,6 +3722,134 @@ static void free_irte(u16 devid, int index) | |||
3690 | iommu_completion_wait(iommu); | 3722 | iommu_completion_wait(iommu); |
3691 | } | 3723 | } |
3692 | 3724 | ||
3725 | static void irte_prepare(void *entry, | ||
3726 | u32 delivery_mode, u32 dest_mode, | ||
3727 | u8 vector, u32 dest_apicid) | ||
3728 | { | ||
3729 | union irte *irte = (union irte *) entry; | ||
3730 | |||
3731 | irte->val = 0; | ||
3732 | irte->fields.vector = vector; | ||
3733 | irte->fields.int_type = delivery_mode; | ||
3734 | irte->fields.destination = dest_apicid; | ||
3735 | irte->fields.dm = dest_mode; | ||
3736 | irte->fields.valid = 1; | ||
3737 | } | ||
3738 | |||
3739 | static void irte_ga_prepare(void *entry, | ||
3740 | u32 delivery_mode, u32 dest_mode, | ||
3741 | u8 vector, u32 dest_apicid) | ||
3742 | { | ||
3743 | struct irte_ga *irte = (struct irte_ga *) entry; | ||
3744 | |||
3745 | irte->lo.val = 0; | ||
3746 | irte->hi.val = 0; | ||
3747 | irte->lo.fields_remap.guest_mode = 0; | ||
3748 | irte->lo.fields_remap.int_type = delivery_mode; | ||
3749 | irte->lo.fields_remap.dm = dest_mode; | ||
3750 | irte->hi.fields.vector = vector; | ||
3751 | irte->lo.fields_remap.destination = dest_apicid; | ||
3752 | irte->lo.fields_remap.valid = 1; | ||
3753 | } | ||
3754 | |||
3755 | static void irte_activate(void *entry, u16 devid, u16 index) | ||
3756 | { | ||
3757 | union irte *irte = (union irte *) entry; | ||
3758 | |||
3759 | irte->fields.valid = 1; | ||
3760 | modify_irte(devid, index, irte); | ||
3761 | } | ||
3762 | |||
3763 | static void irte_ga_activate(void *entry, u16 devid, u16 index) | ||
3764 | { | ||
3765 | struct irte_ga *irte = (struct irte_ga *) entry; | ||
3766 | |||
3767 | irte->lo.fields_remap.valid = 1; | ||
3768 | modify_irte_ga(devid, index, irte); | ||
3769 | } | ||
3770 | |||
3771 | static void irte_deactivate(void *entry, u16 devid, u16 index) | ||
3772 | { | ||
3773 | union irte *irte = (union irte *) entry; | ||
3774 | |||
3775 | irte->fields.valid = 0; | ||
3776 | modify_irte(devid, index, irte); | ||
3777 | } | ||
3778 | |||
3779 | static void irte_ga_deactivate(void *entry, u16 devid, u16 index) | ||
3780 | { | ||
3781 | struct irte_ga *irte = (struct irte_ga *) entry; | ||
3782 | |||
3783 | irte->lo.fields_remap.valid = 0; | ||
3784 | modify_irte_ga(devid, index, irte); | ||
3785 | } | ||
3786 | |||
3787 | static void irte_set_affinity(void *entry, u16 devid, u16 index, | ||
3788 | u8 vector, u32 dest_apicid) | ||
3789 | { | ||
3790 | union irte *irte = (union irte *) entry; | ||
3791 | |||
3792 | irte->fields.vector = vector; | ||
3793 | irte->fields.destination = dest_apicid; | ||
3794 | modify_irte(devid, index, irte); | ||
3795 | } | ||
3796 | |||
3797 | static void irte_ga_set_affinity(void *entry, u16 devid, u16 index, | ||
3798 | u8 vector, u32 dest_apicid) | ||
3799 | { | ||
3800 | struct irte_ga *irte = (struct irte_ga *) entry; | ||
3801 | |||
3802 | irte->hi.fields.vector = vector; | ||
3803 | irte->lo.fields_remap.destination = dest_apicid; | ||
3804 | irte->lo.fields_remap.guest_mode = 0; | ||
3805 | modify_irte_ga(devid, index, irte); | ||
3806 | } | ||
3807 | |||
3808 | static void irte_set_allocated(struct irq_remap_table *table, int index) | ||
3809 | { | ||
3810 | table->table[index] = IRTE_ALLOCATED; | ||
3811 | } | ||
3812 | |||
3813 | static void irte_ga_set_allocated(struct irq_remap_table *table, int index) | ||
3814 | { | ||
3815 | struct irte_ga *ptr = (struct irte_ga *)table->table; | ||
3816 | struct irte_ga *irte = &ptr[index]; | ||
3817 | |||
3818 | memset(&irte->lo.val, 0, sizeof(u64)); | ||
3819 | memset(&irte->hi.val, 0, sizeof(u64)); | ||
3820 | irte->hi.fields.vector = 0xff; | ||
3821 | } | ||
3822 | |||
3823 | static bool irte_is_allocated(struct irq_remap_table *table, int index) | ||
3824 | { | ||
3825 | union irte *ptr = (union irte *)table->table; | ||
3826 | union irte *irte = &ptr[index]; | ||
3827 | |||
3828 | return irte->val != 0; | ||
3829 | } | ||
3830 | |||
3831 | static bool irte_ga_is_allocated(struct irq_remap_table *table, int index) | ||
3832 | { | ||
3833 | struct irte_ga *ptr = (struct irte_ga *)table->table; | ||
3834 | struct irte_ga *irte = &ptr[index]; | ||
3835 | |||
3836 | return irte->hi.fields.vector != 0; | ||
3837 | } | ||
3838 | |||
3839 | static void irte_clear_allocated(struct irq_remap_table *table, int index) | ||
3840 | { | ||
3841 | table->table[index] = 0; | ||
3842 | } | ||
3843 | |||
3844 | static void irte_ga_clear_allocated(struct irq_remap_table *table, int index) | ||
3845 | { | ||
3846 | struct irte_ga *ptr = (struct irte_ga *)table->table; | ||
3847 | struct irte_ga *irte = &ptr[index]; | ||
3848 | |||
3849 | memset(&irte->lo.val, 0, sizeof(u64)); | ||
3850 | memset(&irte->hi.val, 0, sizeof(u64)); | ||
3851 | } | ||
3852 | |||
3693 | static int get_devid(struct irq_alloc_info *info) | 3853 | static int get_devid(struct irq_alloc_info *info) |
3694 | { | 3854 | { |
3695 | int devid = -1; | 3855 | int devid = -1; |
@@ -3817,6 +3977,26 @@ static void irq_remapping_prepare_irte(struct amd_ir_data *data, | |||
3817 | } | 3977 | } |
3818 | } | 3978 | } |
3819 | 3979 | ||
3980 | struct amd_irte_ops irte_32_ops = { | ||
3981 | .prepare = irte_prepare, | ||
3982 | .activate = irte_activate, | ||
3983 | .deactivate = irte_deactivate, | ||
3984 | .set_affinity = irte_set_affinity, | ||
3985 | .set_allocated = irte_set_allocated, | ||
3986 | .is_allocated = irte_is_allocated, | ||
3987 | .clear_allocated = irte_clear_allocated, | ||
3988 | }; | ||
3989 | |||
3990 | struct amd_irte_ops irte_128_ops = { | ||
3991 | .prepare = irte_ga_prepare, | ||
3992 | .activate = irte_ga_activate, | ||
3993 | .deactivate = irte_ga_deactivate, | ||
3994 | .set_affinity = irte_ga_set_affinity, | ||
3995 | .set_allocated = irte_ga_set_allocated, | ||
3996 | .is_allocated = irte_ga_is_allocated, | ||
3997 | .clear_allocated = irte_ga_clear_allocated, | ||
3998 | }; | ||
3999 | |||
3820 | static int irq_remapping_alloc(struct irq_domain *domain, unsigned int virq, | 4000 | static int irq_remapping_alloc(struct irq_domain *domain, unsigned int virq, |
3821 | unsigned int nr_irqs, void *arg) | 4001 | unsigned int nr_irqs, void *arg) |
3822 | { | 4002 | { |
@@ -3922,7 +4102,7 @@ static void irq_remapping_activate(struct irq_domain *domain, | |||
3922 | struct amd_ir_data *data = irq_data->chip_data; | 4102 | struct amd_ir_data *data = irq_data->chip_data; |
3923 | struct irq_2_irte *irte_info = &data->irq_2_irte; | 4103 | struct irq_2_irte *irte_info = &data->irq_2_irte; |
3924 | 4104 | ||
3925 | modify_irte(irte_info->devid, irte_info->index, data->irte_entry); | 4105 | modify_irte(irte_info->devid, irte_info->index, &data->irte_entry); |
3926 | } | 4106 | } |
3927 | 4107 | ||
3928 | static void irq_remapping_deactivate(struct irq_domain *domain, | 4108 | static void irq_remapping_deactivate(struct irq_domain *domain, |
@@ -3933,7 +4113,7 @@ static void irq_remapping_deactivate(struct irq_domain *domain, | |||
3933 | union irte entry; | 4113 | union irte entry; |
3934 | 4114 | ||
3935 | entry.val = 0; | 4115 | entry.val = 0; |
3936 | modify_irte(irte_info->devid, irte_info->index, data->irte_entry); | 4116 | modify_irte(irte_info->devid, irte_info->index, &data->irte_entry); |
3937 | } | 4117 | } |
3938 | 4118 | ||
3939 | static struct irq_domain_ops amd_ir_domain_ops = { | 4119 | static struct irq_domain_ops amd_ir_domain_ops = { |
@@ -3962,7 +4142,7 @@ static int amd_ir_set_affinity(struct irq_data *data, | |||
3962 | */ | 4142 | */ |
3963 | ir_data->irte_entry.fields.vector = cfg->vector; | 4143 | ir_data->irte_entry.fields.vector = cfg->vector; |
3964 | ir_data->irte_entry.fields.destination = cfg->dest_apicid; | 4144 | ir_data->irte_entry.fields.destination = cfg->dest_apicid; |
3965 | modify_irte(irte_info->devid, irte_info->index, ir_data->irte_entry); | 4145 | modify_irte(irte_info->devid, irte_info->index, &ir_data->irte_entry); |
3966 | 4146 | ||
3967 | /* | 4147 | /* |
3968 | * After this point, all the interrupts will start arriving | 4148 | * After this point, all the interrupts will start arriving |
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index 8b61289cd5b7..6b93ebcbc181 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h | |||
@@ -410,6 +410,7 @@ struct amd_iommu_fault { | |||
410 | 410 | ||
411 | struct iommu_domain; | 411 | struct iommu_domain; |
412 | struct irq_domain; | 412 | struct irq_domain; |
413 | struct amd_irte_ops; | ||
413 | 414 | ||
414 | /* | 415 | /* |
415 | * This structure contains generic data for IOMMU protection domains | 416 | * This structure contains generic data for IOMMU protection domains |
@@ -533,6 +534,8 @@ struct amd_iommu { | |||
533 | #ifdef CONFIG_IRQ_REMAP | 534 | #ifdef CONFIG_IRQ_REMAP |
534 | struct irq_domain *ir_domain; | 535 | struct irq_domain *ir_domain; |
535 | struct irq_domain *msi_domain; | 536 | struct irq_domain *msi_domain; |
537 | |||
538 | struct amd_irte_ops *irte_ops; | ||
536 | #endif | 539 | #endif |
537 | }; | 540 | }; |
538 | 541 | ||
@@ -779,6 +782,23 @@ struct amd_ir_data { | |||
779 | struct irq_2_irte irq_2_irte; | 782 | struct irq_2_irte irq_2_irte; |
780 | union irte irte_entry; | 783 | union irte irte_entry; |
781 | struct msi_msg msi_entry; | 784 | struct msi_msg msi_entry; |
785 | void *entry; /* Pointer to union irte or struct irte_ga */ | ||
786 | }; | ||
787 | |||
788 | struct amd_irte_ops { | ||
789 | void (*prepare)(void *, u32, u32, u8, u32); | ||
790 | void (*activate)(void *, u16, u16); | ||
791 | void (*deactivate)(void *, u16, u16); | ||
792 | void (*set_affinity)(void *, u16, u16, u8, u32); | ||
793 | void *(*get)(struct irq_remap_table *, int); | ||
794 | void (*set_allocated)(struct irq_remap_table *, int); | ||
795 | bool (*is_allocated)(struct irq_remap_table *, int); | ||
796 | void (*clear_allocated)(struct irq_remap_table *, int); | ||
782 | }; | 797 | }; |
783 | 798 | ||
799 | #ifdef CONFIG_IRQ_REMAP | ||
800 | extern struct amd_irte_ops irte_32_ops; | ||
801 | extern struct amd_irte_ops irte_128_ops; | ||
802 | #endif | ||
803 | |||
784 | #endif /* _ASM_X86_AMD_IOMMU_TYPES_H */ | 804 | #endif /* _ASM_X86_AMD_IOMMU_TYPES_H */ |