Hi,
this series implements detection of extended features of the AMD IOMMU.
It also implements the first feature, the INVALIDATE_ALL command to
flush the IOMMU caches right after enablement.
Regards,
Joerg
Diffstat:
arch/x86/include/asm/amd_iommu_proto.h | 8 ++++++++
arch/x86/include/asm/amd_iommu_types.h | 18 ++++++++++++++++++
arch/x86/kernel/amd_iommu.c | 26 +++++++++++++++++++++++---
arch/x86/kernel/amd_iommu_init.c | 26 +++++++++++++++++++++++---
4 files changed, 72 insertions(+), 6 deletions(-)
Shortlog:
Joerg Roedel (2):
x86/amd-iommu: Add extended feature detection
x86/amd-iommu: Add support for invalidate_all command
This patch adds support for the invalidate_all command
present in new versions of the AMD IOMMU.
Signed-off-by: Joerg Roedel <[email protected]>
---
arch/x86/include/asm/amd_iommu_types.h | 1 +
arch/x86/kernel/amd_iommu.c | 24 ++++++++++++++++++++++--
2 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h
index 5c24e46..df62d26 100644
--- a/arch/x86/include/asm/amd_iommu_types.h
+++ b/arch/x86/include/asm/amd_iommu_types.h
@@ -127,6 +127,7 @@
#define CMD_COMPL_WAIT 0x01
#define CMD_INV_DEV_ENTRY 0x02
#define CMD_INV_IOMMU_PAGES 0x03
+#define CMD_INV_ALL 0x08
#define CMD_COMPL_WAIT_STORE_MASK 0x01
#define CMD_COMPL_WAIT_INT_MASK 0x02
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index d609610..a9b5cf7 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -463,6 +463,12 @@ static void build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address,
cmd->data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK;
}
+static void build_inv_all(struct iommu_cmd *cmd)
+{
+ memset(cmd, 0, sizeof(*cmd));
+ CMD_SET_TYPE(cmd, CMD_INV_DEV_ENTRY);
+}
+
/*
* Writes the command to the IOMMUs command buffer and informs the
* hardware about the new command.
@@ -567,10 +573,24 @@ static void iommu_flush_tlb_all(struct amd_iommu *iommu)
iommu_completion_wait(iommu);
}
+static void iommu_flush_all(struct amd_iommu *iommu)
+{
+ struct iommu_cmd cmd;
+
+ build_inv_all(&cmd);
+
+ iommu_queue_command(iommu, &cmd);
+ iommu_completion_wait(iommu);
+}
+
void iommu_flush_all_caches(struct amd_iommu *iommu)
{
- iommu_flush_dte_all(iommu);
- iommu_flush_tlb_all(iommu);
+ if (iommu_feature(iommu, FEATURE_IA)) {
+ iommu_flush_all(iommu);
+ } else {
+ iommu_flush_dte_all(iommu);
+ iommu_flush_tlb_all(iommu);
+ }
}
/*
--
1.7.1
This patch adds detection of the extended features of an
AMD IOMMU. The available features are printed to dmesg on
boot.
Signed-off-by: Joerg Roedel <[email protected]>
---
arch/x86/include/asm/amd_iommu_proto.h | 8 ++++++++
arch/x86/include/asm/amd_iommu_types.h | 17 +++++++++++++++++
arch/x86/kernel/amd_iommu.c | 2 +-
arch/x86/kernel/amd_iommu_init.c | 26 +++++++++++++++++++++++---
4 files changed, 49 insertions(+), 4 deletions(-)
diff --git a/arch/x86/include/asm/amd_iommu_proto.h b/arch/x86/include/asm/amd_iommu_proto.h
index 1223c0f..30d1594 100644
--- a/arch/x86/include/asm/amd_iommu_proto.h
+++ b/arch/x86/include/asm/amd_iommu_proto.h
@@ -42,4 +42,12 @@ static inline bool is_rd890_iommu(struct pci_dev *pdev)
(pdev->device == PCI_DEVICE_ID_RD890_IOMMU);
}
+static inline bool iommu_feature(struct amd_iommu *iommu, u64 f)
+{
+ if (!(iommu->cap & (1 << IOMMU_CAP_EFR)))
+ return false;
+
+ return !!(iommu->features & f);
+}
+
#endif /* _ASM_X86_AMD_IOMMU_PROTO_H */
diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h
index 878ae00..5c24e46 100644
--- a/arch/x86/include/asm/amd_iommu_types.h
+++ b/arch/x86/include/asm/amd_iommu_types.h
@@ -68,12 +68,25 @@
#define MMIO_CONTROL_OFFSET 0x0018
#define MMIO_EXCL_BASE_OFFSET 0x0020
#define MMIO_EXCL_LIMIT_OFFSET 0x0028
+#define MMIO_EXT_FEATURES 0x0030
#define MMIO_CMD_HEAD_OFFSET 0x2000
#define MMIO_CMD_TAIL_OFFSET 0x2008
#define MMIO_EVT_HEAD_OFFSET 0x2010
#define MMIO_EVT_TAIL_OFFSET 0x2018
#define MMIO_STATUS_OFFSET 0x2020
+
+/* Extended Feature Bits */
+#define FEATURE_PREFETCH (1ULL<<0)
+#define FEATURE_PPR (1ULL<<1)
+#define FEATURE_X2APIC (1ULL<<2)
+#define FEATURE_NX (1ULL<<3)
+#define FEATURE_GT (1ULL<<4)
+#define FEATURE_IA (1ULL<<6)
+#define FEATURE_GA (1ULL<<7)
+#define FEATURE_HE (1ULL<<8)
+#define FEATURE_PC (1ULL<<9)
+
/* MMIO status bits */
#define MMIO_STATUS_COM_WAIT_INT_MASK 0x04
@@ -227,6 +240,7 @@
/* IOMMU capabilities */
#define IOMMU_CAP_IOTLB 24
#define IOMMU_CAP_NPCACHE 26
+#define IOMMU_CAP_EFR 27
#define MAX_DOMAIN_ID 65536
@@ -371,6 +385,9 @@ struct amd_iommu {
/* flags read from acpi table */
u8 acpi_flags;
+ /* Extended features */
+ u64 features;
+
/*
* Capability pointer. There could be more than one IOMMU per PCI
* device function if there are more than one AMD IOMMU capability
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index bcf58ea..d609610 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -29,8 +29,8 @@
#include <asm/proto.h>
#include <asm/iommu.h>
#include <asm/gart.h>
-#include <asm/amd_iommu_proto.h>
#include <asm/amd_iommu_types.h>
+#include <asm/amd_iommu_proto.h>
#include <asm/amd_iommu.h>
#define CMD_SET_TYPE(cmd, t) ((cmd)->data[1] |= ((t) << 28))
diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c
index 8848dda..4a78e22 100644
--- a/arch/x86/kernel/amd_iommu_init.c
+++ b/arch/x86/kernel/amd_iommu_init.c
@@ -25,8 +25,8 @@
#include <linux/interrupt.h>
#include <linux/msi.h>
#include <asm/pci-direct.h>
-#include <asm/amd_iommu_proto.h>
#include <asm/amd_iommu_types.h>
+#include <asm/amd_iommu_proto.h>
#include <asm/amd_iommu.h>
#include <asm/iommu.h>
#include <asm/gart.h>
@@ -299,9 +299,23 @@ static void iommu_feature_disable(struct amd_iommu *iommu, u8 bit)
/* Function to enable the hardware */
static void iommu_enable(struct amd_iommu *iommu)
{
- printk(KERN_INFO "AMD-Vi: Enabling IOMMU at %s cap 0x%hx\n",
+ static const char * const feat_str[] = {
+ "PreF", "PPR", "X2APIC", "NX", "GT", "[5]",
+ "IA", "GA", "HE", "PC", NULL
+ };
+ int i;
+
+ printk(KERN_INFO "AMD-Vi: Enabling IOMMU at %s cap 0x%hx",
dev_name(&iommu->dev->dev), iommu->cap_ptr);
+ if (iommu->cap & (1 << IOMMU_CAP_EFR)) {
+ printk(KERN_CONT " extended features: ");
+ for (i = 0; feat_str[i]; ++i)
+ if (iommu_feature(iommu, (1ULL << i)))
+ printk(KERN_CONT " %s", feat_str[i]);
+ }
+ printk(KERN_CONT "\n");
+
iommu_feature_enable(iommu, CONTROL_IOMMU_EN);
}
@@ -657,7 +671,7 @@ static void __init set_device_exclusion_range(u16 devid, struct ivmd_header *m)
static void __init init_iommu_from_pci(struct amd_iommu *iommu)
{
int cap_ptr = iommu->cap_ptr;
- u32 range, misc;
+ u32 range, misc, low, high;
int i, j;
pci_read_config_dword(iommu->dev, cap_ptr + MMIO_CAP_HDR_OFFSET,
@@ -673,6 +687,12 @@ static void __init init_iommu_from_pci(struct amd_iommu *iommu)
MMIO_GET_LD(range));
iommu->evt_msi_num = MMIO_MSI_NUM(misc);
+ /* read extended feature bits */
+ low = readl(iommu->mmio_base + MMIO_EXT_FEATURES);
+ high = readl(iommu->mmio_base + MMIO_EXT_FEATURES + 4);
+
+ iommu->features = ((u64)high << 32) | low;
+
if (!is_rd890_iommu(iommu->dev))
return;
--
1.7.1
On Mon, 11 Apr 2011, Joerg Roedel wrote:
> This patch adds support for the invalidate_all command
> present in new versions of the AMD IOMMU.
...
> #define CMD_COMPL_WAIT 0x01
> #define CMD_INV_DEV_ENTRY 0x02
> #define CMD_INV_IOMMU_PAGES 0x03
> +#define CMD_INV_ALL 0x08
...
> @@ -463,6 +463,12 @@ static void build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address,
> cmd->data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK;
> }
>
> +static void build_inv_all(struct iommu_cmd *cmd)
> +{
> + memset(cmd, 0, sizeof(*cmd));
> + CMD_SET_TYPE(cmd, CMD_INV_DEV_ENTRY);
Huh?
--
"One disk to rule them all, One disk to find them. One disk to bring
them all and in the darkness grind them. In the Land of Redmond
where the shadows lie." -- The Silicon Valley Tarot
Henrique Holschuh
On Mon, Apr 11, 2011 at 09:57:08AM -0400, Henrique de Moraes Holschuh wrote:
> On Mon, 11 Apr 2011, Joerg Roedel wrote:
> > This patch adds support for the invalidate_all command
> > present in new versions of the AMD IOMMU.
>
> ...
>
> > #define CMD_COMPL_WAIT 0x01
> > #define CMD_INV_DEV_ENTRY 0x02
> > #define CMD_INV_IOMMU_PAGES 0x03
> > +#define CMD_INV_ALL 0x08
>
> ...
>
> > @@ -463,6 +463,12 @@ static void build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address,
> > cmd->data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK;
> > }
> >
> > +static void build_inv_all(struct iommu_cmd *cmd)
> > +{
> > + memset(cmd, 0, sizeof(*cmd));
> > + CMD_SET_TYPE(cmd, CMD_INV_DEV_ENTRY);
>
> Huh?
Copy&Paste error :( Thanks for pointing it out.
Joerg
--
AMD Operating System Research Center
Advanced Micro Devices GmbH Einsteinring 24 85609 Dornach
General Managers: Alberto Bozzo, Andrew Bowd
Registration: Dornach, Landkr. Muenchen; Registerger. Muenchen, HRB Nr. 43632
> This patch adds detection of the extended features of an
> AMD IOMMU. The available features are printed to dmesg on
> boot.
> diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
> index bcf58ea..d609610 100644
> --- a/arch/x86/kernel/amd_iommu.c
> +++ b/arch/x86/kernel/amd_iommu.c
> @@ -29,8 +29,8 @@
> #include <asm/proto.h>
> #include <asm/iommu.h>
> #include <asm/gart.h>
> -#include <asm/amd_iommu_proto.h>
> #include <asm/amd_iommu_types.h>
> +#include <asm/amd_iommu_proto.h>
> #include <asm/amd_iommu.h>
That one (and the second place where this happens later) look suspicious.
Do you need that change? Usually those includes tend to be alphabetically
sorted (which you destroy here).
When you _need_ that change that means that you probably use some things
from amd_iommu_types.h in amd_iommu_proto.h without including that header
there (which is a bug in amd_iommu_proto.h and must be fixed there).
Otherwise this change is just noise. So either way this change should not
happen IMHO.
Eike
On Mon, Apr 11, 2011 at 11:11:44AM -0400, Rolf Eike Beer wrote:
> > This patch adds detection of the extended features of an
> > AMD IOMMU. The available features are printed to dmesg on
> > boot.
>
> > diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
> > index bcf58ea..d609610 100644
> > --- a/arch/x86/kernel/amd_iommu.c
> > +++ b/arch/x86/kernel/amd_iommu.c
> > @@ -29,8 +29,8 @@
> > #include <asm/proto.h>
> > #include <asm/iommu.h>
> > #include <asm/gart.h>
> > -#include <asm/amd_iommu_proto.h>
> > #include <asm/amd_iommu_types.h>
> > +#include <asm/amd_iommu_proto.h>
> > #include <asm/amd_iommu.h>
>
> That one (and the second place where this happens later) look suspicious.
> Do you need that change? Usually those includes tend to be alphabetically
> sorted (which you destroy here).
>
> When you _need_ that change that means that you probably use some things
> from amd_iommu_types.h in amd_iommu_proto.h without including that header
> there (which is a bug in amd_iommu_proto.h and must be fixed there).
> Otherwise this change is just noise. So either way this change should not
> happen IMHO.
Yeah, this is not very good style, I agree with that. In this case the
amd_iommu_proto.h file got a new inline function which needs the struct
amd_iommu.
I have merging of the different include files for the AMD IOMMU driver
on my cleanup list. There are currently 3 include files which seems a
bit too much. A single one will do too. Meanwhile I change this patch so
that amd_iommu_proto.h will include amd_iommu_types.h itself. This
doesn't make it nice and clean but at least less ugly meanwhile ;)
Joerg
--
AMD Operating System Research Center
Advanced Micro Devices GmbH Einsteinring 24 85609 Dornach
General Managers: Alberto Bozzo, Andrew Bowd
Registration: Dornach, Landkr. Muenchen; Registerger. Muenchen, HRB Nr. 43632