Hi Jan, Please see the version 4. Fixed issues from last version. Build test passed on both 32 and 64 bit systems. This patch set enables ats devices on amd systems with following changes: 1) Make vendor independent ATS codes more public. 2) Add additional helper functions for ats. 3) Add amd specific enablement. Thanks, Wei _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Wei Wang
2011-Nov-03 15:48 UTC
[Xen-devel] [PATCH 1 of 5] ats: Move some ats functions to a new directory
# HG changeset patch # User Wei Wang <wei.wang2@amd.com> # Date 1320334551 -3600 # Node ID ef46c471a11f83d07e256ad2e0b868828f45ef63 # Parent 119bccb1cc5eee1364bbbd3bd1a30f22e9db703a ats: Move some ats functions to a new directory. Remove VTD prefix from debug output. passhrough/x86 holds vendor neutral codes for x86 architecture. Signed-off-by: Wei Wang <wei.wang2@amd.com> diff -r 119bccb1cc5e -r ef46c471a11f xen/drivers/passthrough/Makefile --- a/xen/drivers/passthrough/Makefile Wed Nov 02 13:53:05 2011 +0100 +++ b/xen/drivers/passthrough/Makefile Thu Nov 03 16:35:51 2011 +0100 @@ -1,6 +1,7 @@ subdir-$(x86) += vtd subdir-$(ia64) += vtd subdir-$(x86) += amd +subdir-$(x86_64) += x86 obj-y += iommu.o obj-y += io.o diff -r 119bccb1cc5e -r ef46c471a11f xen/drivers/passthrough/ats.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/drivers/passthrough/ats.h Thu Nov 03 16:35:51 2011 +0100 @@ -0,0 +1,56 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _ATS_H_ +#define _ATS_H_ + +struct pci_ats_dev { + struct list_head list; + u16 seg; + u8 bus; + u8 devfn; + u16 ats_queue_depth; /* ATS device invalidation queue depth */ +}; + +#ifdef CONFIG_X86_64 + +#define ATS_REG_CAP 4 +#define ATS_REG_CTL 6 +#define ATS_QUEUE_DEPTH_MASK 0xF +#define ATS_ENABLE (1<<15) + +extern struct list_head ats_devices; +extern bool_t ats_enabled; + +int enable_ats_device(int seg, int bus, int devfn); +void disable_ats_device(int seg, int bus, int devfn); + +#else + +#define ats_enabled 0 +static inline int enable_ats_device(int seg, int bus, int devfn) +{ + BUG(); + return -ENOSYS; +} + +static inline void disable_ats_device(int seg, int bus, int devfn) +{ + BUG(); +} +#endif + +#endif /* _ATS_H_ */ + diff -r 119bccb1cc5e -r ef46c471a11f xen/drivers/passthrough/vtd/extern.h --- a/xen/drivers/passthrough/vtd/extern.h Wed Nov 02 13:53:05 2011 +0100 +++ b/xen/drivers/passthrough/vtd/extern.h Thu Nov 03 16:35:51 2011 +0100 @@ -57,18 +57,13 @@ struct acpi_drhd_unit * iommu_to_drhd(st struct acpi_rhsa_unit * drhd_to_rhsa(struct acpi_drhd_unit *drhd); #ifdef CONFIG_X86_64 -extern bool_t ats_enabled; - struct acpi_drhd_unit * find_ats_dev_drhd(struct iommu *iommu); int ats_device(const struct pci_dev *, const struct acpi_drhd_unit *); -int enable_ats_device(int seg, int bus, int devfn); -void disable_ats_device(int seg, int bus, int devfn); int dev_invalidate_iotlb(struct iommu *iommu, u16 did, u64 addr, unsigned int size_order, u64 type); #else -#define ats_enabled 0 static inline struct acpi_drhd_unit *find_ats_dev_drhd(struct iommu *iommu) { @@ -80,15 +75,6 @@ static inline int ats_device(const struc { return 0; } -static inline int enable_ats_device(int seg, int bus, int devfn) -{ - BUG(); - return -ENOSYS; -} -static inline void disable_ats_device(int seg, int bus, int devfn) -{ - BUG(); -} static inline int dev_invalidate_iotlb(struct iommu *iommu, u16 did, u64 addr, unsigned int size_order, u64 type) diff -r 119bccb1cc5e -r ef46c471a11f xen/drivers/passthrough/vtd/iommu.c --- a/xen/drivers/passthrough/vtd/iommu.c Wed Nov 02 13:53:05 2011 +0100 +++ b/xen/drivers/passthrough/vtd/iommu.c Thu Nov 03 16:35:51 2011 +0100 @@ -40,6 +40,7 @@ #include "dmar.h" #include "extern.h" #include "vtd.h" +#include "../ats.h" #ifdef __ia64__ #define nr_ioapics iosapic_get_nr_iosapics() diff -r 119bccb1cc5e -r ef46c471a11f xen/drivers/passthrough/vtd/x86/ats.c --- a/xen/drivers/passthrough/vtd/x86/ats.c Wed Nov 02 13:53:05 2011 +0100 +++ b/xen/drivers/passthrough/vtd/x86/ats.c Thu Nov 03 16:35:51 2011 +0100 @@ -27,51 +27,10 @@ #include "../dmar.h" #include "../vtd.h" #include "../extern.h" +#include "../../ats.h" static LIST_HEAD(ats_dev_drhd_units); -#define ATS_REG_CAP 4 -#define ATS_REG_CTL 6 -#define ATS_QUEUE_DEPTH_MASK 0xF -#define ATS_ENABLE (1<<15) - -struct pci_ats_dev { - struct list_head list; - u16 seg; - u8 bus; - u8 devfn; - u16 ats_queue_depth; /* ATS device invalidation queue depth */ -}; -static LIST_HEAD(ats_devices); - -static void parse_ats_param(char *s); -custom_param("ats", parse_ats_param); - -bool_t __read_mostly ats_enabled = 1; - -static void __init parse_ats_param(char *s) -{ - char *ss; - - do { - ss = strchr(s, '',''); - if ( ss ) - *ss = ''\0''; - - switch ( parse_bool(s) ) - { - case 0: - ats_enabled = 0; - break; - case 1: - ats_enabled = 1; - break; - } - - s = ss + 1; - } while ( ss ); -} - struct acpi_drhd_unit * find_ats_dev_drhd(struct iommu *iommu) { struct acpi_drhd_unit *drhd; @@ -113,97 +72,6 @@ int ats_device(const struct pci_dev *pde return pos; } -int enable_ats_device(int seg, int bus, int devfn) -{ - struct pci_ats_dev *pdev = NULL; - u32 value; - int pos; - - pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS); - BUG_ON(!pos); - - if ( iommu_verbose ) - dprintk(XENLOG_INFO VTDPREFIX, - "%04x:%02x:%02x.%u: ATS capability found\n", - seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - - value = pci_conf_read16(seg, bus, PCI_SLOT(devfn), - PCI_FUNC(devfn), pos + ATS_REG_CTL); - if ( value & ATS_ENABLE ) - { - list_for_each_entry ( pdev, &ats_devices, list ) - { - if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn ) - { - pos = 0; - break; - } - } - } - if ( pos ) - pdev = xmalloc(struct pci_ats_dev); - if ( !pdev ) - return -ENOMEM; - - if ( !(value & ATS_ENABLE) ) - { - value |= ATS_ENABLE; - pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), - pos + ATS_REG_CTL, value); - } - - if ( pos ) - { - pdev->seg = seg; - pdev->bus = bus; - pdev->devfn = devfn; - value = pci_conf_read16(seg, bus, PCI_SLOT(devfn), - PCI_FUNC(devfn), pos + ATS_REG_CAP); - pdev->ats_queue_depth = value & ATS_QUEUE_DEPTH_MASK; - list_add(&pdev->list, &ats_devices); - } - - if ( iommu_verbose ) - dprintk(XENLOG_INFO VTDPREFIX, - "%04x:%02x:%02x.%u: ATS %s enabled\n", - seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), - pos ? "is" : "was"); - - return pos; -} - -void disable_ats_device(int seg, int bus, int devfn) -{ - struct pci_ats_dev *pdev; - u32 value; - int pos; - - pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS); - BUG_ON(!pos); - - value = pci_conf_read16(seg, bus, PCI_SLOT(devfn), - PCI_FUNC(devfn), pos + ATS_REG_CTL); - value &= ~ATS_ENABLE; - pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), - pos + ATS_REG_CTL, value); - - list_for_each_entry ( pdev, &ats_devices, list ) - { - if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn ) - { - list_del(&pdev->list); - xfree(pdev); - break; - } - } - - if ( iommu_verbose ) - dprintk(XENLOG_INFO VTDPREFIX, - "%04x:%02x:%02x.%u: ATS is disabled\n", - seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); -} - - static int device_in_domain(struct iommu *iommu, struct pci_ats_dev *pdev, u16 did) { struct root_entry *root_entry = NULL; diff -r 119bccb1cc5e -r ef46c471a11f xen/drivers/passthrough/x86/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/drivers/passthrough/x86/Makefile Thu Nov 03 16:35:51 2011 +0100 @@ -0,0 +1,1 @@ +obj-$(CONFIG_X86_64) += ats.o diff -r 119bccb1cc5e -r ef46c471a11f xen/drivers/passthrough/x86/ats.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/drivers/passthrough/x86/ats.c Thu Nov 03 16:35:51 2011 +0100 @@ -0,0 +1,136 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <xen/sched.h> +#include <xen/pci.h> +#include <xen/pci_regs.h> +#include "../ats.h" + +LIST_HEAD(ats_devices); + +static void parse_ats_param(char *s); +custom_param("ats", parse_ats_param); + +bool_t __read_mostly ats_enabled = 1; + +static void __init parse_ats_param(char *s) +{ + char *ss; + + do { + ss = strchr(s, '',''); + if ( ss ) + *ss = ''\0''; + + switch ( parse_bool(s) ) + { + case 0: + ats_enabled = 0; + break; + case 1: + ats_enabled = 1; + break; + } + + s = ss + 1; + } while ( ss ); +} + +int enable_ats_device(int seg, int bus, int devfn) +{ + struct pci_ats_dev *pdev = NULL; + u32 value; + int pos; + + pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS); + BUG_ON(!pos); + + if ( iommu_verbose ) + dprintk(XENLOG_INFO, "%04x:%02x:%02x.%u: ATS capability found\n", + seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + + value = pci_conf_read16(seg, bus, PCI_SLOT(devfn), + PCI_FUNC(devfn), pos + ATS_REG_CTL); + if ( value & ATS_ENABLE ) + { + list_for_each_entry ( pdev, &ats_devices, list ) + { + if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn ) + { + pos = 0; + break; + } + } + } + if ( pos ) + pdev = xmalloc(struct pci_ats_dev); + if ( !pdev ) + return -ENOMEM; + + if ( !(value & ATS_ENABLE) ) + { + value |= ATS_ENABLE; + pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), + pos + ATS_REG_CTL, value); + } + + if ( pos ) + { + pdev->seg = seg; + pdev->bus = bus; + pdev->devfn = devfn; + value = pci_conf_read16(seg, bus, PCI_SLOT(devfn), + PCI_FUNC(devfn), pos + ATS_REG_CAP); + pdev->ats_queue_depth = value & ATS_QUEUE_DEPTH_MASK; + list_add(&pdev->list, &ats_devices); + } + + if ( iommu_verbose ) + dprintk(XENLOG_INFO, "%04x:%02x:%02x.%u: ATS %s enabled\n", + seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), + pos ? "is" : "was"); + + return pos; +} + +void disable_ats_device(int seg, int bus, int devfn) +{ + struct pci_ats_dev *pdev; + u32 value; + int pos; + + pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS); + BUG_ON(!pos); + + value = pci_conf_read16(seg, bus, PCI_SLOT(devfn), + PCI_FUNC(devfn), pos + ATS_REG_CTL); + value &= ~ATS_ENABLE; + pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), + pos + ATS_REG_CTL, value); + + list_for_each_entry ( pdev, &ats_devices, list ) + { + if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn ) + { + list_del(&pdev->list); + xfree(pdev); + break; + } + } + + if ( iommu_verbose ) + dprintk(XENLOG_INFO, "%04x:%02x:%02x.%u: ATS is disabled\n", + seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); +} _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Wei Wang
2011-Nov-03 15:48 UTC
[Xen-devel] [PATCH 2 of 5] amd iommu: Fix iommu page size encoding when page order > 0
# HG changeset patch # User Wei Wang <wei.wang2@amd.com> # Date 1320334553 -3600 # Node ID 1bf06c8d2c70e9af610e12a7592c466a799b0de1 # Parent ef46c471a11f83d07e256ad2e0b868828f45ef63 amd iommu: Fix iommu page size encoding when page order > 0. Fix io address in invalid all pages command. Signed-off-by: Wei Wang <wei.wang2@amd.com> diff -r ef46c471a11f -r 1bf06c8d2c70 xen/drivers/passthrough/amd/iommu_map.c --- a/xen/drivers/passthrough/amd/iommu_map.c Thu Nov 03 16:35:51 2011 +0100 +++ b/xen/drivers/passthrough/amd/iommu_map.c Thu Nov 03 16:35:53 2011 +0100 @@ -77,23 +77,24 @@ static void invalidate_iommu_pages(struc { u64 addr_lo, addr_hi; u32 cmd[4], entry; - u64 mask = 0; int sflag = 0, pde = 0; + ASSERT ( order == 0 || order == 9 || order == 18 ); + + /* All pages associated with the domainID are invalidated */ + if ( order || (io_addr == INV_IOMMU_ALL_PAGES_ADDRESS ) ) + { + sflag = 1; + pde = 1; + } + /* If sflag == 1, the size of the invalidate command is determined by the first zero bit in the address starting from Address[12] */ - if ( order == 9 || order == 18 ) + if ( order ) { - mask = ((1ULL << (order - 1)) - 1) << PAGE_SHIFT; - io_addr |= mask; - sflag = 1; - } - - /* All pages associated with the domainID are invalidated */ - else if ( io_addr == 0x7FFFFFFFFFFFF000ULL ) - { - sflag = 1; - pde = 1; + u64 mask = 1ULL << (order - 1 + PAGE_SHIFT); + io_addr &= ~mask; + io_addr |= mask - 1; } addr_lo = io_addr & DMA_32BIT_MASK; @@ -917,7 +918,7 @@ static void _amd_iommu_flush_pages(struc void amd_iommu_flush_all_pages(struct domain *d) { - _amd_iommu_flush_pages(d, 0x7FFFFFFFFFFFFULL, 0); + _amd_iommu_flush_pages(d, INV_IOMMU_ALL_PAGES_ADDRESS, 0); } void amd_iommu_flush_pages(struct domain *d, diff -r ef46c471a11f -r 1bf06c8d2c70 xen/include/asm-x86/hvm/svm/amd-iommu-defs.h --- a/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h Thu Nov 03 16:35:51 2011 +0100 +++ b/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h Thu Nov 03 16:35:53 2011 +0100 @@ -407,4 +407,6 @@ #define INT_REMAP_ENTRY_VECTOR_MASK 0x00FF0000 #define INT_REMAP_ENTRY_VECTOR_SHIFT 16 +#define INV_IOMMU_ALL_PAGES_ADDRESS (1ULL << 63) - 1 + #endif /* _ASM_X86_64_AMD_IOMMU_DEFS_H */ _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Wei Wang
2011-Nov-03 15:48 UTC
[Xen-devel] [PATCH 3 of 5] ats: Add new ATS helper functions
# HG changeset patch # User Wei Wang <wei.wang2@amd.com> # Date 1320334760 -3600 # Node ID f1b4373838dd5e082755201745f87654e2eaa59f # Parent 1bf06c8d2c70e9af610e12a7592c466a799b0de1 ats: Add new ATS helper functions Signed-off-by Wei Wang <wei.wang2@amd.com> diff -r 1bf06c8d2c70 -r f1b4373838dd xen/drivers/passthrough/ats.h --- a/xen/drivers/passthrough/ats.h Thu Nov 03 16:35:53 2011 +0100 +++ b/xen/drivers/passthrough/ats.h Thu Nov 03 16:39:20 2011 +0100 @@ -16,6 +16,8 @@ #ifndef _ATS_H_ #define _ATS_H_ +#include <xen/pci_regs.h> + struct pci_ats_dev { struct list_head list; u16 seg; @@ -36,6 +38,28 @@ extern bool_t ats_enabled; int enable_ats_device(int seg, int bus, int devfn); void disable_ats_device(int seg, int bus, int devfn); +struct pci_ats_dev *get_ats_device(int seg, int bus, int devfn); + +static inline int pci_ats_enabled(int seg, int bus, int devfn) +{ + u32 value; + int pos; + + pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS); + BUG_ON(!pos); + + value = pci_conf_read16(seg, bus, PCI_SLOT(devfn), + PCI_FUNC(devfn), pos + ATS_REG_CTL); + return value & ATS_ENABLE; +} + +static inline int pci_ats_device(int seg, int bus, int devfn) +{ + if ( !ats_enabled ) + return 0; + + return pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS); +} #else @@ -50,6 +74,22 @@ static inline void disable_ats_device(in { BUG(); } + +static inline int pci_ats_enabled(int seg, int bus, int devfn) +{ + return 0; +} + +static inline int pci_ats_device(int seg, int bus, int devfn) +{ + return 0; +} + +static inline struct pci_ats_dev *get_ats_device(int seg, int bus, int devfn) +{ + return NULL; +} + #endif #endif /* _ATS_H_ */ diff -r 1bf06c8d2c70 -r f1b4373838dd xen/drivers/passthrough/x86/ats.c --- a/xen/drivers/passthrough/x86/ats.c Thu Nov 03 16:35:53 2011 +0100 +++ b/xen/drivers/passthrough/x86/ats.c Thu Nov 03 16:39:20 2011 +0100 @@ -134,3 +134,19 @@ void disable_ats_device(int seg, int bus dprintk(XENLOG_INFO, "%04x:%02x:%02x.%u: ATS is disabled\n", seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); } + +struct pci_ats_dev *get_ats_device(int seg, int bus, int devfn) +{ + struct pci_ats_dev *pdev; + + if ( !pci_ats_device(seg, bus, devfn) ) + return NULL; + + list_for_each_entry ( pdev, &ats_devices, list ) + { + if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn ) + return pdev; + } + + return NULL; +} _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Wei Wang
2011-Nov-03 15:48 UTC
[Xen-devel] [PATCH 4 of 5] amd iommu: add iotlb invalidation command
# HG changeset patch # User Wei Wang <wei.wang2@amd.com> # Date 1320334783 -3600 # Node ID acfe5b608724cb06c644a61b73599c748a81274a # Parent f1b4373838dd5e082755201745f87654e2eaa59f amd iommu: add iotlb invalidation command Signed-off-by: Wei Wang <wei.wang2@amd.com> diff -r f1b4373838dd -r acfe5b608724 xen/drivers/passthrough/amd/iommu_map.c --- a/xen/drivers/passthrough/amd/iommu_map.c Thu Nov 03 16:39:20 2011 +0100 +++ b/xen/drivers/passthrough/amd/iommu_map.c Thu Nov 03 16:39:43 2011 +0100 @@ -23,6 +23,8 @@ #include <xen/hvm/iommu.h> #include <asm/amd-iommu.h> #include <asm/hvm/svm/amd-iommu-proto.h> +#include "../ats.h" +#include <xen/pci.h> static int queue_iommu_command(struct amd_iommu *iommu, u32 cmd[]) { @@ -128,6 +130,75 @@ static void invalidate_iommu_pages(struc send_iommu_command(iommu, cmd); } +static void invalidate_iotlb_pages(struct amd_iommu *iommu, + u16 maxpend, u32 pasid, u16 queueid, + u64 io_addr, u16 dev_id, u16 order) +{ + u64 addr_lo, addr_hi; + u32 cmd[4], entry; + int sflag = 0; + + ASSERT ( order == 0 || order == 9 || order == 18 ); + + if ( order || (io_addr == INV_IOMMU_ALL_PAGES_ADDRESS ) ) + sflag = 1; + + /* If sflag == 1, the size of the invalidate command is determined + by the first zero bit in the address starting from Address[12] */ + if ( order ) + { + u64 mask = 1ULL << (order - 1 + PAGE_SHIFT); + io_addr &= ~mask; + io_addr |= mask - 1; + } + + addr_lo = io_addr & DMA_32BIT_MASK; + addr_hi = io_addr >> 32; + + set_field_in_reg_u32(dev_id, 0, + IOMMU_INV_IOTLB_PAGES_DEVICE_ID_MASK, + IOMMU_INV_IOTLB_PAGES_DEVICE_ID_SHIFT, &entry); + + set_field_in_reg_u32(maxpend, entry, + IOMMU_INV_IOTLB_PAGES_MAXPEND_MASK, + IOMMU_INV_IOTLB_PAGES_MAXPEND_SHIFT, &entry); + + set_field_in_reg_u32(pasid & 0xff, entry, + IOMMU_INV_IOTLB_PAGES_PASID1_MASK, + IOMMU_INV_IOTLB_PAGES_PASID1_SHIFT, &entry); + cmd[0] = entry; + + set_field_in_reg_u32(IOMMU_CMD_INVALIDATE_IOTLB_PAGES, 0, + IOMMU_CMD_OPCODE_MASK, IOMMU_CMD_OPCODE_SHIFT, + &entry); + + set_field_in_reg_u32(pasid >> 8, entry, + IOMMU_INV_IOTLB_PAGES_PASID2_MASK, + IOMMU_INV_IOTLB_PAGES_PASID2_SHIFT, + &entry); + + set_field_in_reg_u32(queueid, entry, + IOMMU_INV_IOTLB_PAGES_QUEUEID_MASK, + IOMMU_INV_IOTLB_PAGES_QUEUEID_SHIFT, + &entry); + cmd[1] = entry; + + set_field_in_reg_u32(sflag, 0, + IOMMU_INV_IOTLB_PAGES_S_FLAG_MASK, + IOMMU_INV_IOTLB_PAGES_S_FLAG_MASK, &entry); + + set_field_in_reg_u32((u32)addr_lo >> PAGE_SHIFT, entry, + IOMMU_INV_IOTLB_PAGES_ADDR_LOW_MASK, + IOMMU_INV_IOTLB_PAGES_ADDR_LOW_SHIFT, &entry); + cmd[2] = entry; + + set_field_in_reg_u32((u32)addr_hi, 0, + IOMMU_INV_IOTLB_PAGES_ADDR_HIGH_MASK, + IOMMU_INV_IOTLB_PAGES_ADDR_HIGH_SHIFT, &entry); + cmd[3] = entry; + + send_iommu_command(iommu, cmd); +} void flush_command_buffer(struct amd_iommu *iommu) { u32 cmd[4], status; @@ -896,6 +967,63 @@ int amd_iommu_reserve_domain_unity_map(s return 0; } +void amd_iommu_flush_iotlb(struct pci_dev *pdev, + uint64_t gaddr, unsigned int order) +{ + unsigned long flags; + struct amd_iommu *iommu; + unsigned int bdf, req_id, queueid, maxpend; + struct pci_ats_dev *ats_pdev; + + if ( !ats_enabled ) + return; + + ats_pdev = get_ats_device(pdev->seg, pdev->bus, pdev->devfn); + if ( ats_pdev == NULL ) + return; + + if ( !pci_ats_enabled(ats_pdev->seg, + ats_pdev->bus, ats_pdev->devfn) ) + return; + + bdf = PCI_BDF2(ats_pdev->bus, ats_pdev->devfn); + iommu = find_iommu_for_device(ats_pdev->seg, bdf); + + if ( !iommu ) + { + AMD_IOMMU_DEBUG("%s: Fail to find iommu for device %04x:%02x:%02x.%u\n", + __func__, ats_pdev->seg, ats_pdev->bus, + PCI_SLOT(ats_pdev->devfn), + PCI_FUNC(ats_pdev->devfn)); + return; + } + + if ( !iommu->iotlb_support ) + return; + + req_id = get_dma_requestor_id(iommu->seg, bdf); + queueid = req_id; + maxpend = (ats_pdev->ats_queue_depth + 32) & 0xff; + + /* send INVALIDATE_IOTLB_PAGES command */ + spin_lock_irqsave(&iommu->lock, flags); + invalidate_iotlb_pages(iommu, maxpend, 0, queueid, + gaddr, req_id, order); + flush_command_buffer(iommu); + spin_unlock_irqrestore(&iommu->lock, flags); +} + +static void amd_iommu_flush_all_iotlbs(struct domain *d, + uint64_t gaddr, unsigned int order) +{ + struct pci_dev *pdev; + + if ( !ats_enabled ) + return; + + for_each_pdev( d, pdev ) + amd_iommu_flush_iotlb(pdev, gaddr, order); +} /* Flush iommu cache after p2m changes. */ static void _amd_iommu_flush_pages(struct domain *d, @@ -914,6 +1042,9 @@ static void _amd_iommu_flush_pages(struc flush_command_buffer(iommu); spin_unlock_irqrestore(&iommu->lock, flags); } + + if ( ats_enabled ) + amd_iommu_flush_all_iotlbs(d, gaddr, order); } void amd_iommu_flush_all_pages(struct domain *d) diff -r f1b4373838dd -r acfe5b608724 xen/include/asm-x86/hvm/svm/amd-iommu-defs.h --- a/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h Thu Nov 03 16:39:20 2011 +0100 +++ b/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h Thu Nov 03 16:39:43 2011 +0100 @@ -233,6 +233,24 @@ #define IOMMU_INV_INT_TABLE_DEVICE_ID_MASK 0x0000FFFF #define IOMMU_INV_INT_TABLE_DEVICE_ID_SHIFT 0 +/* INVALIDATE_IOTLB_PAGES command */ +#define IOMMU_INV_IOTLB_PAGES_MAXPEND_MASK 0xff000000 +#define IOMMU_INV_IOTLB_PAGES_MAXPEND_SHIFT 24 +#define IOMMU_INV_IOTLB_PAGES_PASID1_MASK 0x00ff0000 +#define IOMMU_INV_IOTLB_PAGES_PASID1_SHIFT 16 +#define IOMMU_INV_IOTLB_PAGES_PASID2_MASK 0x0fff0000 +#define IOMMU_INV_IOTLB_PAGES_PASID2_SHIFT 16 +#define IOMMU_INV_IOTLB_PAGES_QUEUEID_MASK 0x0000ffff +#define IOMMU_INV_IOTLB_PAGES_QUEUEID_SHIFT 0 +#define IOMMU_INV_IOTLB_PAGES_DEVICE_ID_MASK 0x0000FFFF +#define IOMMU_INV_IOTLB_PAGES_DEVICE_ID_SHIFT 0 +#define IOMMU_INV_IOTLB_PAGES_ADDR_LOW_MASK 0xFFFFF000 +#define IOMMU_INV_IOTLB_PAGES_ADDR_LOW_SHIFT 12 +#define IOMMU_INV_IOTLB_PAGES_ADDR_HIGH_MASK 0xFFFFFFFF +#define IOMMU_INV_IOTLB_PAGES_ADDR_HIGH_SHIFT 0 +#define IOMMU_INV_IOTLB_PAGES_S_FLAG_MASK 0x00000001 +#define IOMMU_INV_IOTLB_PAGES_S_FLAG_SHIFT 0 + /* Event Log */ #define IOMMU_EVENT_LOG_BASE_LOW_OFFSET 0x10 #define IOMMU_EVENT_LOG_BASE_HIGH_OFFSET 0x14 diff -r f1b4373838dd -r acfe5b608724 xen/include/asm-x86/hvm/svm/amd-iommu-proto.h --- a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h Thu Nov 03 16:39:20 2011 +0100 +++ b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h Thu Nov 03 16:39:43 2011 +0100 @@ -55,6 +55,8 @@ int amd_iommu_unmap_page(struct domain * void amd_iommu_flush_pages(struct domain *d, unsigned long gfn, unsigned int order); void amd_iommu_flush_all_pages(struct domain *d); +void amd_iommu_flush_iotlb(struct pci_dev *pdev, + uint64_t gaddr, unsigned int order); u64 amd_iommu_get_next_table_from_pte(u32 *entry); int amd_iommu_reserve_domain_unity_map(struct domain *domain, _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
# HG changeset patch # User Wei Wang <wei.wang2@amd.com> # Date 1320334827 -3600 # Node ID 59b7d9f9b571d6de35e5c5dae81a3890752271fe # Parent acfe5b608724cb06c644a61b73599c748a81274a amd iommu: enable ats devices Signed-off-by: Wei Wang <wei.wang2@amd.com> diff -r acfe5b608724 -r 59b7d9f9b571 xen/drivers/passthrough/amd/iommu_map.c --- a/xen/drivers/passthrough/amd/iommu_map.c Thu Nov 03 16:39:43 2011 +0100 +++ b/xen/drivers/passthrough/amd/iommu_map.c Thu Nov 03 16:40:27 2011 +0100 @@ -370,6 +370,17 @@ void amd_iommu_set_root_page_table( dte[0] = entry; } +void iommu_dte_set_iotlb(u32 *dte, u8 i) +{ + u32 entry; + + entry = dte[3]; + set_field_in_reg_u32(!!i, entry, + IOMMU_DEV_TABLE_IOTLB_SUPPORT_MASK, + IOMMU_DEV_TABLE_IOTLB_SUPPORT_SHIFT, &entry); + dte[3] = entry; +} + void __init amd_iommu_set_intremap_table( u32 *dte, u64 intremap_ptr, u8 int_valid) { diff -r acfe5b608724 -r 59b7d9f9b571 xen/drivers/passthrough/amd/pci_amd_iommu.c --- a/xen/drivers/passthrough/amd/pci_amd_iommu.c Thu Nov 03 16:39:43 2011 +0100 +++ b/xen/drivers/passthrough/amd/pci_amd_iommu.c Thu Nov 03 16:40:27 2011 +0100 @@ -25,6 +25,7 @@ #include <asm/hvm/iommu.h> #include <asm/amd-iommu.h> #include <asm/hvm/svm/amd-iommu-proto.h> +#include "../ats.h" struct amd_iommu *find_iommu_for_device(int seg, int bdf) { @@ -86,6 +87,9 @@ static void amd_iommu_setup_domain_devic void *dte; unsigned long flags; int req_id, valid = 1; + int dte_i = 0; + u8 bus = PCI_BUS(bdf); + u8 devfn = PCI_DEVFN2(bdf); struct hvm_iommu *hd = domain_hvm_iommu(domain); @@ -94,6 +98,9 @@ static void amd_iommu_setup_domain_devic if ( iommu_passthrough && (domain->domain_id == 0) ) valid = 0; + if ( ats_enabled ) + dte_i = 1; + /* get device-table entry */ req_id = get_dma_requestor_id(iommu->seg, bdf); dte = iommu->dev_table.buffer + (req_id * IOMMU_DEV_TABLE_ENTRY_SIZE); @@ -107,6 +114,10 @@ static void amd_iommu_setup_domain_devic (u32 *)dte, page_to_maddr(hd->root_table), hd->domain_id, hd->paging_mode, valid); + if ( pci_ats_device(iommu->seg, bus, devfn) && + iommu->iotlb_support ) + iommu_dte_set_iotlb((u32 *)dte, dte_i); + invalidate_dev_table_entry(iommu, req_id); flush_command_buffer(iommu); @@ -118,11 +129,27 @@ static void amd_iommu_setup_domain_devic } spin_unlock_irqrestore(&iommu->lock, flags); + + ASSERT(spin_is_locked(&pcidevs_lock)); + + if ( pci_ats_device(iommu->seg, bus, devfn) && + !pci_ats_enabled(iommu->seg, bus, devfn) ) + { + struct pci_dev *pdev; + + enable_ats_device(iommu->seg, bus, devfn); + + ASSERT(spin_is_locked(&pcidevs_lock)); + pdev = pci_get_pdev(iommu->seg, bus, devfn); + + ASSERT( pdev != NULL ); + amd_iommu_flush_iotlb(pdev, INV_IOMMU_ALL_PAGES_ADDRESS, 0); + } } static void __init amd_iommu_setup_dom0_device(struct pci_dev *pdev) { - int bdf = (pdev->bus << 8) | pdev->devfn; + int bdf = PCI_BDF2(pdev->bus, pdev->devfn); struct amd_iommu *iommu = find_iommu_for_device(pdev->seg, bdf); if ( likely(iommu != NULL) ) @@ -261,12 +288,14 @@ static void __init amd_iommu_dom0_init(s setup_dom0_pci_devices(d, amd_iommu_setup_dom0_device); } -static void amd_iommu_disable_domain_device( - struct domain *domain, struct amd_iommu *iommu, int bdf) +void amd_iommu_disable_domain_device(struct domain *domain, + struct amd_iommu *iommu, int bdf) { void *dte; unsigned long flags; int req_id; + u8 bus = PCI_BUS(bdf); + u8 devfn = PCI_DEVFN2(bdf); BUG_ON ( iommu->dev_table.buffer == NULL ); req_id = get_dma_requestor_id(iommu->seg, bdf); @@ -276,6 +305,11 @@ static void amd_iommu_disable_domain_dev if ( is_translation_valid((u32 *)dte) ) { disable_translation((u32 *)dte); + + if ( pci_ats_device(iommu->seg, bus, devfn) && + iommu->iotlb_support ) + iommu_dte_set_iotlb((u32 *)dte, 0); + invalidate_dev_table_entry(iommu, req_id); flush_command_buffer(iommu); AMD_IOMMU_DEBUG("Disable: device id = 0x%04x, " @@ -284,6 +318,12 @@ static void amd_iommu_disable_domain_dev domain_hvm_iommu(domain)->paging_mode); } spin_unlock_irqrestore(&iommu->lock, flags); + + ASSERT(spin_is_locked(&pcidevs_lock)); + + if ( pci_ats_device(iommu->seg, bus, devfn) && + pci_ats_enabled(iommu->seg, bus, devfn) ) + disable_ats_device(iommu->seg, bus, devfn); } static int reassign_device( struct domain *source, struct domain *target, @@ -299,7 +339,7 @@ static int reassign_device( struct domai if ( !pdev ) return -ENODEV; - bdf = (bus << 8) | devfn; + bdf = PCI_BDF2(bus, devfn); iommu = find_iommu_for_device(seg, bdf); if ( !iommu ) { @@ -421,7 +461,7 @@ static int amd_iommu_add_device(struct p if ( !pdev->domain ) return -EINVAL; - bdf = (pdev->bus << 8) | pdev->devfn; + bdf = PCI_BDF2(pdev->bus, pdev->devfn); iommu = find_iommu_for_device(pdev->seg, bdf); if ( !iommu ) { @@ -443,7 +483,7 @@ static int amd_iommu_remove_device(struc if ( !pdev->domain ) return -EINVAL; - bdf = (pdev->bus << 8) | pdev->devfn; + bdf = PCI_BDF2(pdev->bus, pdev->devfn); iommu = find_iommu_for_device(pdev->seg, bdf); if ( !iommu ) { diff -r acfe5b608724 -r 59b7d9f9b571 xen/include/asm-x86/hvm/svm/amd-iommu-proto.h --- a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h Thu Nov 03 16:39:43 2011 +0100 +++ b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h Thu Nov 03 16:40:27 2011 +0100 @@ -75,6 +75,7 @@ void amd_iommu_set_intremap_table( u32 *dte, u64 intremap_ptr, u8 int_valid); void amd_iommu_set_root_page_table( u32 *dte, u64 root_ptr, u16 domain_id, u8 paging_mode, u8 valid); +void iommu_dte_set_iotlb(u32 *dte, u8 i); void invalidate_dev_table_entry(struct amd_iommu *iommu, u16 devic_id); /* send cmd to iommu */ _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Jan Beulich
2011-Nov-03 16:19 UTC
Re: [Xen-devel] [PATCH 2 of 5] amd iommu: Fix iommu page size encoding when page order > 0
>>> On 03.11.11 at 16:48, Wei Wang <wei.wang2@amd.com> wrote: > # HG changeset patch > # User Wei Wang <wei.wang2@amd.com> > # Date 1320334553 -3600 > # Node ID 1bf06c8d2c70e9af610e12a7592c466a799b0de1 > # Parent ef46c471a11f83d07e256ad2e0b868828f45ef63 > amd iommu: Fix iommu page size encoding when page order > 0. > Fix io address in invalid all pages command. > > Signed-off-by: Wei Wang <wei.wang2@amd.com> > > diff -r ef46c471a11f -r 1bf06c8d2c70 xen/drivers/passthrough/amd/iommu_map.c > --- a/xen/drivers/passthrough/amd/iommu_map.c Thu Nov 03 16:35:51 2011 +0100 > +++ b/xen/drivers/passthrough/amd/iommu_map.c Thu Nov 03 16:35:53 2011 +0100 > @@ -77,23 +77,24 @@ static void invalidate_iommu_pages(struc > { > u64 addr_lo, addr_hi; > u32 cmd[4], entry; > - u64 mask = 0; > int sflag = 0, pde = 0; > > + ASSERT ( order == 0 || order == 9 || order == 18 ); > + > + /* All pages associated with the domainID are invalidated */ > + if ( order || (io_addr == INV_IOMMU_ALL_PAGES_ADDRESS ) ) > + { > + sflag = 1; > + pde = 1; > + } > + > /* If sflag == 1, the size of the invalidate command is determined > by the first zero bit in the address starting from Address[12] */ > - if ( order == 9 || order == 18 ) > + if ( order ) > { > - mask = ((1ULL << (order - 1)) - 1) << PAGE_SHIFT; > - io_addr |= mask; > - sflag = 1; > - } > - > - /* All pages associated with the domainID are invalidated */ > - else if ( io_addr == 0x7FFFFFFFFFFFF000ULL ) > - { > - sflag = 1; > - pde = 1; > + u64 mask = 1ULL << (order - 1 + PAGE_SHIFT); > + io_addr &= ~mask; > + io_addr |= mask - 1; > } > > addr_lo = io_addr & DMA_32BIT_MASK; > @@ -917,7 +918,7 @@ static void _amd_iommu_flush_pages(struc > > void amd_iommu_flush_all_pages(struct domain *d) > { > - _amd_iommu_flush_pages(d, 0x7FFFFFFFFFFFFULL, 0); > + _amd_iommu_flush_pages(d, INV_IOMMU_ALL_PAGES_ADDRESS, 0); > } > > void amd_iommu_flush_pages(struct domain *d, > diff -r ef46c471a11f -r 1bf06c8d2c70 xen/include/asm-x86/hvm/svm/amd-iommu-defs.h > --- a/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h Thu Nov 03 16:35:51 2011 +0100 > +++ b/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h Thu Nov 03 16:35:53 2011 > +0100 > @@ -407,4 +407,6 @@ > #define INT_REMAP_ENTRY_VECTOR_MASK 0x00FF0000 > #define INT_REMAP_ENTRY_VECTOR_SHIFT 16 > > +#define INV_IOMMU_ALL_PAGES_ADDRESS (1ULL << 63) - 1Please parenthesize this properly.> + > #endif /* _ASM_X86_64_AMD_IOMMU_DEFS_H */ > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xensource.com > http://lists.xensource.com/xen-devel_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Jan Beulich
2011-Nov-03 16:21 UTC
Re: [Xen-devel] [PATCH 1 of 5] ats: Move some ats functions to a new directory
>>> On 03.11.11 at 16:48, Wei Wang <wei.wang2@amd.com> wrote: > # HG changeset patch > # User Wei Wang <wei.wang2@amd.com> > # Date 1320334551 -3600 > # Node ID ef46c471a11f83d07e256ad2e0b868828f45ef63 > # Parent 119bccb1cc5eee1364bbbd3bd1a30f22e9db703a > ats: Move some ats functions to a new directory. > Remove VTD prefix from debug output. > passhrough/x86 holds vendor neutral codes for x86 architecture. > > Signed-off-by: Wei Wang <wei.wang2@amd.com>Acked-by: Jan Beulich <jbeulich@suse.com>> > diff -r 119bccb1cc5e -r ef46c471a11f xen/drivers/passthrough/Makefile > --- a/xen/drivers/passthrough/Makefile Wed Nov 02 13:53:05 2011 +0100 > +++ b/xen/drivers/passthrough/Makefile Thu Nov 03 16:35:51 2011 +0100 > @@ -1,6 +1,7 @@ > subdir-$(x86) += vtd > subdir-$(ia64) += vtd > subdir-$(x86) += amd > +subdir-$(x86_64) += x86 > > obj-y += iommu.o > obj-y += io.o > diff -r 119bccb1cc5e -r ef46c471a11f xen/drivers/passthrough/ats.h > --- /dev/null Thu Jan 01 00:00:00 1970 +0000 > +++ b/xen/drivers/passthrough/ats.h Thu Nov 03 16:35:51 2011 +0100 > @@ -0,0 +1,56 @@ > +/* > + * This program is free software; you can redistribute it and/or modify it > + * under the terms and conditions of the GNU General Public License, > + * version 2, as published by the Free Software Foundation. > + * > + * This program is distributed in the hope it will be useful, but WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License > for > + * more details. > + * > + * You should have received a copy of the GNU General Public License along > with > + * this program; if not, write to the Free Software Foundation, Inc., 59 > Temple > + * Place - Suite 330, Boston, MA 02111-1307 USA. > + */ > + > +#ifndef _ATS_H_ > +#define _ATS_H_ > + > +struct pci_ats_dev { > + struct list_head list; > + u16 seg; > + u8 bus; > + u8 devfn; > + u16 ats_queue_depth; /* ATS device invalidation queue depth */ > +}; > + > +#ifdef CONFIG_X86_64 > + > +#define ATS_REG_CAP 4 > +#define ATS_REG_CTL 6 > +#define ATS_QUEUE_DEPTH_MASK 0xF > +#define ATS_ENABLE (1<<15) > + > +extern struct list_head ats_devices; > +extern bool_t ats_enabled; > + > +int enable_ats_device(int seg, int bus, int devfn); > +void disable_ats_device(int seg, int bus, int devfn); > + > +#else > + > +#define ats_enabled 0 > +static inline int enable_ats_device(int seg, int bus, int devfn) > +{ > + BUG(); > + return -ENOSYS; > +} > + > +static inline void disable_ats_device(int seg, int bus, int devfn) > +{ > + BUG(); > +} > +#endif > + > +#endif /* _ATS_H_ */ > + > diff -r 119bccb1cc5e -r ef46c471a11f xen/drivers/passthrough/vtd/extern.h > --- a/xen/drivers/passthrough/vtd/extern.h Wed Nov 02 13:53:05 2011 +0100 > +++ b/xen/drivers/passthrough/vtd/extern.h Thu Nov 03 16:35:51 2011 +0100 > @@ -57,18 +57,13 @@ struct acpi_drhd_unit * iommu_to_drhd(st > struct acpi_rhsa_unit * drhd_to_rhsa(struct acpi_drhd_unit *drhd); > > #ifdef CONFIG_X86_64 > -extern bool_t ats_enabled; > - > struct acpi_drhd_unit * find_ats_dev_drhd(struct iommu *iommu); > > int ats_device(const struct pci_dev *, const struct acpi_drhd_unit *); > -int enable_ats_device(int seg, int bus, int devfn); > -void disable_ats_device(int seg, int bus, int devfn); > > int dev_invalidate_iotlb(struct iommu *iommu, u16 did, > u64 addr, unsigned int size_order, u64 type); > #else > -#define ats_enabled 0 > > static inline struct acpi_drhd_unit *find_ats_dev_drhd(struct iommu *iommu) > { > @@ -80,15 +75,6 @@ static inline int ats_device(const struc > { > return 0; > } > -static inline int enable_ats_device(int seg, int bus, int devfn) > -{ > - BUG(); > - return -ENOSYS; > -} > -static inline void disable_ats_device(int seg, int bus, int devfn) > -{ > - BUG(); > -} > > static inline int dev_invalidate_iotlb(struct iommu *iommu, u16 did, u64 > addr, > unsigned int size_order, u64 type) > diff -r 119bccb1cc5e -r ef46c471a11f xen/drivers/passthrough/vtd/iommu.c > --- a/xen/drivers/passthrough/vtd/iommu.c Wed Nov 02 13:53:05 2011 +0100 > +++ b/xen/drivers/passthrough/vtd/iommu.c Thu Nov 03 16:35:51 2011 +0100 > @@ -40,6 +40,7 @@ > #include "dmar.h" > #include "extern.h" > #include "vtd.h" > +#include "../ats.h" > > #ifdef __ia64__ > #define nr_ioapics iosapic_get_nr_iosapics() > diff -r 119bccb1cc5e -r ef46c471a11f xen/drivers/passthrough/vtd/x86/ats.c > --- a/xen/drivers/passthrough/vtd/x86/ats.c Wed Nov 02 13:53:05 2011 +0100 > +++ b/xen/drivers/passthrough/vtd/x86/ats.c Thu Nov 03 16:35:51 2011 +0100 > @@ -27,51 +27,10 @@ > #include "../dmar.h" > #include "../vtd.h" > #include "../extern.h" > +#include "../../ats.h" > > static LIST_HEAD(ats_dev_drhd_units); > > -#define ATS_REG_CAP 4 > -#define ATS_REG_CTL 6 > -#define ATS_QUEUE_DEPTH_MASK 0xF > -#define ATS_ENABLE (1<<15) > - > -struct pci_ats_dev { > - struct list_head list; > - u16 seg; > - u8 bus; > - u8 devfn; > - u16 ats_queue_depth; /* ATS device invalidation queue depth */ > -}; > -static LIST_HEAD(ats_devices); > - > -static void parse_ats_param(char *s); > -custom_param("ats", parse_ats_param); > - > -bool_t __read_mostly ats_enabled = 1; > - > -static void __init parse_ats_param(char *s) > -{ > - char *ss; > - > - do { > - ss = strchr(s, '',''); > - if ( ss ) > - *ss = ''\0''; > - > - switch ( parse_bool(s) ) > - { > - case 0: > - ats_enabled = 0; > - break; > - case 1: > - ats_enabled = 1; > - break; > - } > - > - s = ss + 1; > - } while ( ss ); > -} > - > struct acpi_drhd_unit * find_ats_dev_drhd(struct iommu *iommu) > { > struct acpi_drhd_unit *drhd; > @@ -113,97 +72,6 @@ int ats_device(const struct pci_dev *pde > return pos; > } > > -int enable_ats_device(int seg, int bus, int devfn) > -{ > - struct pci_ats_dev *pdev = NULL; > - u32 value; > - int pos; > - > - pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS); > - BUG_ON(!pos); > - > - if ( iommu_verbose ) > - dprintk(XENLOG_INFO VTDPREFIX, > - "%04x:%02x:%02x.%u: ATS capability found\n", > - seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); > - > - value = pci_conf_read16(seg, bus, PCI_SLOT(devfn), > - PCI_FUNC(devfn), pos + ATS_REG_CTL); > - if ( value & ATS_ENABLE ) > - { > - list_for_each_entry ( pdev, &ats_devices, list ) > - { > - if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn ) > - { > - pos = 0; > - break; > - } > - } > - } > - if ( pos ) > - pdev = xmalloc(struct pci_ats_dev); > - if ( !pdev ) > - return -ENOMEM; > - > - if ( !(value & ATS_ENABLE) ) > - { > - value |= ATS_ENABLE; > - pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), > - pos + ATS_REG_CTL, value); > - } > - > - if ( pos ) > - { > - pdev->seg = seg; > - pdev->bus = bus; > - pdev->devfn = devfn; > - value = pci_conf_read16(seg, bus, PCI_SLOT(devfn), > - PCI_FUNC(devfn), pos + ATS_REG_CAP); > - pdev->ats_queue_depth = value & ATS_QUEUE_DEPTH_MASK; > - list_add(&pdev->list, &ats_devices); > - } > - > - if ( iommu_verbose ) > - dprintk(XENLOG_INFO VTDPREFIX, > - "%04x:%02x:%02x.%u: ATS %s enabled\n", > - seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), > - pos ? "is" : "was"); > - > - return pos; > -} > - > -void disable_ats_device(int seg, int bus, int devfn) > -{ > - struct pci_ats_dev *pdev; > - u32 value; > - int pos; > - > - pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS); > - BUG_ON(!pos); > - > - value = pci_conf_read16(seg, bus, PCI_SLOT(devfn), > - PCI_FUNC(devfn), pos + ATS_REG_CTL); > - value &= ~ATS_ENABLE; > - pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), > - pos + ATS_REG_CTL, value); > - > - list_for_each_entry ( pdev, &ats_devices, list ) > - { > - if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn ) > - { > - list_del(&pdev->list); > - xfree(pdev); > - break; > - } > - } > - > - if ( iommu_verbose ) > - dprintk(XENLOG_INFO VTDPREFIX, > - "%04x:%02x:%02x.%u: ATS is disabled\n", > - seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); > -} > - > - > static int device_in_domain(struct iommu *iommu, struct pci_ats_dev *pdev, > u16 did) > { > struct root_entry *root_entry = NULL; > diff -r 119bccb1cc5e -r ef46c471a11f xen/drivers/passthrough/x86/Makefile > --- /dev/null Thu Jan 01 00:00:00 1970 +0000 > +++ b/xen/drivers/passthrough/x86/Makefile Thu Nov 03 16:35:51 2011 +0100 > @@ -0,0 +1,1 @@ > +obj-$(CONFIG_X86_64) += ats.o > diff -r 119bccb1cc5e -r ef46c471a11f xen/drivers/passthrough/x86/ats.c > --- /dev/null Thu Jan 01 00:00:00 1970 +0000 > +++ b/xen/drivers/passthrough/x86/ats.c Thu Nov 03 16:35:51 2011 +0100 > @@ -0,0 +1,136 @@ > +/* > + * This program is free software; you can redistribute it and/or modify it > + * under the terms and conditions of the GNU General Public License, > + * version 2, as published by the Free Software Foundation. > + * > + * This program is distributed in the hope it will be useful, but WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License > for > + * more details. > + * > + * You should have received a copy of the GNU General Public License along > with > + * this program; if not, write to the Free Software Foundation, Inc., 59 > Temple > + * Place - Suite 330, Boston, MA 02111-1307 USA. > + */ > + > +#include <xen/sched.h> > +#include <xen/pci.h> > +#include <xen/pci_regs.h> > +#include "../ats.h" > + > +LIST_HEAD(ats_devices); > + > +static void parse_ats_param(char *s); > +custom_param("ats", parse_ats_param); > + > +bool_t __read_mostly ats_enabled = 1; > + > +static void __init parse_ats_param(char *s) > +{ > + char *ss; > + > + do { > + ss = strchr(s, '',''); > + if ( ss ) > + *ss = ''\0''; > + > + switch ( parse_bool(s) ) > + { > + case 0: > + ats_enabled = 0; > + break; > + case 1: > + ats_enabled = 1; > + break; > + } > + > + s = ss + 1; > + } while ( ss ); > +} > + > +int enable_ats_device(int seg, int bus, int devfn) > +{ > + struct pci_ats_dev *pdev = NULL; > + u32 value; > + int pos; > + > + pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS); > + BUG_ON(!pos); > + > + if ( iommu_verbose ) > + dprintk(XENLOG_INFO, "%04x:%02x:%02x.%u: ATS capability found\n", > + seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); > + > + value = pci_conf_read16(seg, bus, PCI_SLOT(devfn), > + PCI_FUNC(devfn), pos + ATS_REG_CTL); > + if ( value & ATS_ENABLE ) > + { > + list_for_each_entry ( pdev, &ats_devices, list ) > + { > + if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn ) > + { > + pos = 0; > + break; > + } > + } > + } > + if ( pos ) > + pdev = xmalloc(struct pci_ats_dev); > + if ( !pdev ) > + return -ENOMEM; > + > + if ( !(value & ATS_ENABLE) ) > + { > + value |= ATS_ENABLE; > + pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), > + pos + ATS_REG_CTL, value); > + } > + > + if ( pos ) > + { > + pdev->seg = seg; > + pdev->bus = bus; > + pdev->devfn = devfn; > + value = pci_conf_read16(seg, bus, PCI_SLOT(devfn), > + PCI_FUNC(devfn), pos + ATS_REG_CAP); > + pdev->ats_queue_depth = value & ATS_QUEUE_DEPTH_MASK; > + list_add(&pdev->list, &ats_devices); > + } > + > + if ( iommu_verbose ) > + dprintk(XENLOG_INFO, "%04x:%02x:%02x.%u: ATS %s enabled\n", > + seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), > + pos ? "is" : "was"); > + > + return pos; > +} > + > +void disable_ats_device(int seg, int bus, int devfn) > +{ > + struct pci_ats_dev *pdev; > + u32 value; > + int pos; > + > + pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS); > + BUG_ON(!pos); > + > + value = pci_conf_read16(seg, bus, PCI_SLOT(devfn), > + PCI_FUNC(devfn), pos + ATS_REG_CTL); > + value &= ~ATS_ENABLE; > + pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), > + pos + ATS_REG_CTL, value); > + > + list_for_each_entry ( pdev, &ats_devices, list ) > + { > + if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn ) > + { > + list_del(&pdev->list); > + xfree(pdev); > + break; > + } > + } > + > + if ( iommu_verbose ) > + dprintk(XENLOG_INFO, "%04x:%02x:%02x.%u: ATS is disabled\n", > + seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); > +} > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xensource.com > http://lists.xensource.com/xen-devel_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Jan Beulich
2011-Nov-03 16:22 UTC
Re: [Xen-devel] [PATCH 3 of 5] ats: Add new ATS helper functions
>>> On 03.11.11 at 16:48, Wei Wang <wei.wang2@amd.com> wrote: > # HG changeset patch > # User Wei Wang <wei.wang2@amd.com> > # Date 1320334760 -3600 > # Node ID f1b4373838dd5e082755201745f87654e2eaa59f > # Parent 1bf06c8d2c70e9af610e12a7592c466a799b0de1 > ats: Add new ATS helper functions > > Signed-off-by Wei Wang <wei.wang2@amd.com>Acked-by: Jan Beulich <jbeulich@suse.com>> > diff -r 1bf06c8d2c70 -r f1b4373838dd xen/drivers/passthrough/ats.h > --- a/xen/drivers/passthrough/ats.h Thu Nov 03 16:35:53 2011 +0100 > +++ b/xen/drivers/passthrough/ats.h Thu Nov 03 16:39:20 2011 +0100 > @@ -16,6 +16,8 @@ > #ifndef _ATS_H_ > #define _ATS_H_ > > +#include <xen/pci_regs.h> > + > struct pci_ats_dev { > struct list_head list; > u16 seg; > @@ -36,6 +38,28 @@ extern bool_t ats_enabled; > > int enable_ats_device(int seg, int bus, int devfn); > void disable_ats_device(int seg, int bus, int devfn); > +struct pci_ats_dev *get_ats_device(int seg, int bus, int devfn); > + > +static inline int pci_ats_enabled(int seg, int bus, int devfn) > +{ > + u32 value; > + int pos; > + > + pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS); > + BUG_ON(!pos); > + > + value = pci_conf_read16(seg, bus, PCI_SLOT(devfn), > + PCI_FUNC(devfn), pos + ATS_REG_CTL); > + return value & ATS_ENABLE; > +} > + > +static inline int pci_ats_device(int seg, int bus, int devfn) > +{ > + if ( !ats_enabled ) > + return 0; > + > + return pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS); > +} > > #else > > @@ -50,6 +74,22 @@ static inline void disable_ats_device(in > { > BUG(); > } > + > +static inline int pci_ats_enabled(int seg, int bus, int devfn) > +{ > + return 0; > +} > + > +static inline int pci_ats_device(int seg, int bus, int devfn) > +{ > + return 0; > +} > + > +static inline struct pci_ats_dev *get_ats_device(int seg, int bus, int > devfn) > +{ > + return NULL; > +} > + > #endif > > #endif /* _ATS_H_ */ > diff -r 1bf06c8d2c70 -r f1b4373838dd xen/drivers/passthrough/x86/ats.c > --- a/xen/drivers/passthrough/x86/ats.c Thu Nov 03 16:35:53 2011 +0100 > +++ b/xen/drivers/passthrough/x86/ats.c Thu Nov 03 16:39:20 2011 +0100 > @@ -134,3 +134,19 @@ void disable_ats_device(int seg, int bus > dprintk(XENLOG_INFO, "%04x:%02x:%02x.%u: ATS is disabled\n", > seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); > } > + > +struct pci_ats_dev *get_ats_device(int seg, int bus, int devfn) > +{ > + struct pci_ats_dev *pdev; > + > + if ( !pci_ats_device(seg, bus, devfn) ) > + return NULL; > + > + list_for_each_entry ( pdev, &ats_devices, list ) > + { > + if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn ) > + return pdev; > + } > + > + return NULL; > +} > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xensource.com > http://lists.xensource.com/xen-devel_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Wei Wang2
2011-Nov-03 16:54 UTC
Re: [Xen-devel] [PATCH 2 of 5] amd iommu: Fix iommu page size encoding when page order > 0
On Thursday 03 November 2011 17:19:47 Jan Beulich wrote:> >>> On 03.11.11 at 16:48, Wei Wang <wei.wang2@amd.com> wrote: > > > > # HG changeset patch > > # User Wei Wang <wei.wang2@amd.com> > > # Date 1320334553 -3600 > > # Node ID 1bf06c8d2c70e9af610e12a7592c466a799b0de1 > > # Parent ef46c471a11f83d07e256ad2e0b868828f45ef63 > > amd iommu: Fix iommu page size encoding when page order > 0. > > Fix io address in invalid all pages command. > > > > Signed-off-by: Wei Wang <wei.wang2@amd.com> > > > > diff -r ef46c471a11f -r 1bf06c8d2c70 > > xen/drivers/passthrough/amd/iommu_map.c --- > > a/xen/drivers/passthrough/amd/iommu_map.c Thu Nov 03 16:35:51 2011 +0100 > > +++ b/xen/drivers/passthrough/amd/iommu_map.c Thu Nov 03 16:35:53 2011 > > +0100 @@ -77,23 +77,24 @@ static void invalidate_iommu_pages(struc > > { > > u64 addr_lo, addr_hi; > > u32 cmd[4], entry; > > - u64 mask = 0; > > int sflag = 0, pde = 0; > > > > + ASSERT ( order == 0 || order == 9 || order == 18 ); > > + > > + /* All pages associated with the domainID are invalidated */ > > + if ( order || (io_addr == INV_IOMMU_ALL_PAGES_ADDRESS ) ) > > + { > > + sflag = 1; > > + pde = 1; > > + } > > + > > /* If sflag == 1, the size of the invalidate command is determined > > by the first zero bit in the address starting from Address[12] */ > > - if ( order == 9 || order == 18 ) > > + if ( order ) > > { > > - mask = ((1ULL << (order - 1)) - 1) << PAGE_SHIFT; > > - io_addr |= mask; > > - sflag = 1; > > - } > > - > > - /* All pages associated with the domainID are invalidated */ > > - else if ( io_addr == 0x7FFFFFFFFFFFF000ULL ) > > - { > > - sflag = 1; > > - pde = 1; > > + u64 mask = 1ULL << (order - 1 + PAGE_SHIFT); > > + io_addr &= ~mask; > > + io_addr |= mask - 1; > > } > > > > addr_lo = io_addr & DMA_32BIT_MASK; > > @@ -917,7 +918,7 @@ static void _amd_iommu_flush_pages(struc > > > > void amd_iommu_flush_all_pages(struct domain *d) > > { > > - _amd_iommu_flush_pages(d, 0x7FFFFFFFFFFFFULL, 0); > > + _amd_iommu_flush_pages(d, INV_IOMMU_ALL_PAGES_ADDRESS, 0); > > } > > > > void amd_iommu_flush_pages(struct domain *d, > > diff -r ef46c471a11f -r 1bf06c8d2c70 > > xen/include/asm-x86/hvm/svm/amd-iommu-defs.h --- > > a/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h Thu Nov 03 16:35:51 2011 > > +0100 +++ b/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h Thu Nov 03 > > 16:35:53 2011 +0100 > > @@ -407,4 +407,6 @@ > > #define INT_REMAP_ENTRY_VECTOR_MASK 0x00FF0000 > > #define INT_REMAP_ENTRY_VECTOR_SHIFT 16 > > > > +#define INV_IOMMU_ALL_PAGES_ADDRESS (1ULL << 63) - 1 > > Please parenthesize this properly.Fixed, please see attachment. Thanks, Wei> > + > > #endif /* _ASM_X86_64_AMD_IOMMU_DEFS_H */ > > > > > > _______________________________________________ > > Xen-devel mailing list > > Xen-devel@lists.xensource.com > > http://lists.xensource.com/xen-devel_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel