diff options
Diffstat (limited to 'drivers/iommu/amd_iommu_init.c')
-rw-r--r-- | drivers/iommu/amd_iommu_init.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index eb104c719629..4413aa67000e 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c | |||
@@ -23,6 +23,8 @@ | |||
23 | #include <linux/mem_encrypt.h> | 23 | #include <linux/mem_encrypt.h> |
24 | #include <asm/pci-direct.h> | 24 | #include <asm/pci-direct.h> |
25 | #include <asm/iommu.h> | 25 | #include <asm/iommu.h> |
26 | #include <asm/apic.h> | ||
27 | #include <asm/msidef.h> | ||
26 | #include <asm/gart.h> | 28 | #include <asm/gart.h> |
27 | #include <asm/x86_init.h> | 29 | #include <asm/x86_init.h> |
28 | #include <asm/iommu_table.h> | 30 | #include <asm/iommu_table.h> |
@@ -1920,6 +1922,90 @@ static int iommu_setup_msi(struct amd_iommu *iommu) | |||
1920 | return 0; | 1922 | return 0; |
1921 | } | 1923 | } |
1922 | 1924 | ||
1925 | #define XT_INT_DEST_MODE(x) (((x) & 0x1ULL) << 2) | ||
1926 | #define XT_INT_DEST_LO(x) (((x) & 0xFFFFFFULL) << 8) | ||
1927 | #define XT_INT_VEC(x) (((x) & 0xFFULL) << 32) | ||
1928 | #define XT_INT_DEST_HI(x) ((((x) >> 24) & 0xFFULL) << 56) | ||
1929 | |||
1930 | /** | ||
1931 | * Setup the IntCapXT registers with interrupt routing information | ||
1932 | * based on the PCI MSI capability block registers, accessed via | ||
1933 | * MMIO MSI address low/hi and MSI data registers. | ||
1934 | */ | ||
1935 | static void iommu_update_intcapxt(struct amd_iommu *iommu) | ||
1936 | { | ||
1937 | u64 val; | ||
1938 | u32 addr_lo = readl(iommu->mmio_base + MMIO_MSI_ADDR_LO_OFFSET); | ||
1939 | u32 addr_hi = readl(iommu->mmio_base + MMIO_MSI_ADDR_HI_OFFSET); | ||
1940 | u32 data = readl(iommu->mmio_base + MMIO_MSI_DATA_OFFSET); | ||
1941 | bool dm = (addr_lo >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1; | ||
1942 | u32 dest = ((addr_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xFF); | ||
1943 | |||
1944 | if (x2apic_enabled()) | ||
1945 | dest |= MSI_ADDR_EXT_DEST_ID(addr_hi); | ||
1946 | |||
1947 | val = XT_INT_VEC(data & 0xFF) | | ||
1948 | XT_INT_DEST_MODE(dm) | | ||
1949 | XT_INT_DEST_LO(dest) | | ||
1950 | XT_INT_DEST_HI(dest); | ||
1951 | |||
1952 | /** | ||
1953 | * Current IOMMU implemtation uses the same IRQ for all | ||
1954 | * 3 IOMMU interrupts. | ||
1955 | */ | ||
1956 | writeq(val, iommu->mmio_base + MMIO_INTCAPXT_EVT_OFFSET); | ||
1957 | writeq(val, iommu->mmio_base + MMIO_INTCAPXT_PPR_OFFSET); | ||
1958 | writeq(val, iommu->mmio_base + MMIO_INTCAPXT_GALOG_OFFSET); | ||
1959 | } | ||
1960 | |||
1961 | static void _irq_notifier_notify(struct irq_affinity_notify *notify, | ||
1962 | const cpumask_t *mask) | ||
1963 | { | ||
1964 | struct amd_iommu *iommu; | ||
1965 | |||
1966 | for_each_iommu(iommu) { | ||
1967 | if (iommu->dev->irq == notify->irq) { | ||
1968 | iommu_update_intcapxt(iommu); | ||
1969 | break; | ||
1970 | } | ||
1971 | } | ||
1972 | } | ||
1973 | |||
1974 | static void _irq_notifier_release(struct kref *ref) | ||
1975 | { | ||
1976 | } | ||
1977 | |||
1978 | static int iommu_init_intcapxt(struct amd_iommu *iommu) | ||
1979 | { | ||
1980 | int ret; | ||
1981 | struct irq_affinity_notify *notify = &iommu->intcapxt_notify; | ||
1982 | |||
1983 | /** | ||
1984 | * IntCapXT requires XTSup=1, which can be inferred | ||
1985 | * amd_iommu_xt_mode. | ||
1986 | */ | ||
1987 | if (amd_iommu_xt_mode != IRQ_REMAP_X2APIC_MODE) | ||
1988 | return 0; | ||
1989 | |||
1990 | /** | ||
1991 | * Also, we need to setup notifier to update the IntCapXT registers | ||
1992 | * whenever the irq affinity is changed from user-space. | ||
1993 | */ | ||
1994 | notify->irq = iommu->dev->irq; | ||
1995 | notify->notify = _irq_notifier_notify, | ||
1996 | notify->release = _irq_notifier_release, | ||
1997 | ret = irq_set_affinity_notifier(iommu->dev->irq, notify); | ||
1998 | if (ret) { | ||
1999 | pr_err("Failed to register irq affinity notifier (devid=%#x, irq %d)\n", | ||
2000 | iommu->devid, iommu->dev->irq); | ||
2001 | return ret; | ||
2002 | } | ||
2003 | |||
2004 | iommu_update_intcapxt(iommu); | ||
2005 | iommu_feature_enable(iommu, CONTROL_INTCAPXT_EN); | ||
2006 | return ret; | ||
2007 | } | ||
2008 | |||
1923 | static int iommu_init_msi(struct amd_iommu *iommu) | 2009 | static int iommu_init_msi(struct amd_iommu *iommu) |
1924 | { | 2010 | { |
1925 | int ret; | 2011 | int ret; |
@@ -1936,6 +2022,10 @@ static int iommu_init_msi(struct amd_iommu *iommu) | |||
1936 | return ret; | 2022 | return ret; |
1937 | 2023 | ||
1938 | enable_faults: | 2024 | enable_faults: |
2025 | ret = iommu_init_intcapxt(iommu); | ||
2026 | if (ret) | ||
2027 | return ret; | ||
2028 | |||
1939 | iommu_feature_enable(iommu, CONTROL_EVT_INT_EN); | 2029 | iommu_feature_enable(iommu, CONTROL_EVT_INT_EN); |
1940 | 2030 | ||
1941 | if (iommu->ppr_log != NULL) | 2031 | if (iommu->ppr_log != NULL) |