aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuravee Suthikulpanit <suravee.suthikulpanit@amd.com>2016-08-23 14:52:34 -0400
committerJoerg Roedel <jroedel@suse.de>2016-09-05 06:41:46 -0400
commit880ac60e2538337f84d9f76ab7b3c13ee7787804 (patch)
tree8785d7a8c6fde2d636b69a8f905058d7b214f8dc
parenta38180bd366f9912a08f52dd6f9a843bf0107d5f (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.c190
-rw-r--r--drivers/iommu/amd_iommu_types.h20
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
3647static int modify_irte(u16 devid, int index, union irte irte) 3647static 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
3679static 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
3725static 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
3739static 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
3755static 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
3763static 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
3771static 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
3779static 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
3787static 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
3797static 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
3808static void irte_set_allocated(struct irq_remap_table *table, int index)
3809{
3810 table->table[index] = IRTE_ALLOCATED;
3811}
3812
3813static 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
3823static 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
3831static 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
3839static void irte_clear_allocated(struct irq_remap_table *table, int index)
3840{
3841 table->table[index] = 0;
3842}
3843
3844static 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
3693static int get_devid(struct irq_alloc_info *info) 3853static 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
3980struct 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
3990struct 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
3820static int irq_remapping_alloc(struct irq_domain *domain, unsigned int virq, 4000static 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
3928static void irq_remapping_deactivate(struct irq_domain *domain, 4108static 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
3939static struct irq_domain_ops amd_ir_domain_ops = { 4119static 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
411struct iommu_domain; 411struct iommu_domain;
412struct irq_domain; 412struct irq_domain;
413struct 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
788struct 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
800extern struct amd_irte_ops irte_32_ops;
801extern 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 */