Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/linux-2.6-iommu
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/linux-2.6-iommu: (89 commits) AMD IOMMU: remove now unnecessary #ifdefs AMD IOMMU: prealloc_protection_domains should be static kvm/iommu: fix compile warning AMD IOMMU: add statistics about total number of map requests AMD IOMMU: add statistics about allocated io memory AMD IOMMU: add stats counter for domain tlb flushes AMD IOMMU: add stats counter for single iommu domain tlb flushes AMD IOMMU: add stats counter for cross-page request AMD IOMMU: add stats counter for free_coherent requests AMD IOMMU: add stats counter for alloc_coherent requests AMD IOMMU: add stats counter for unmap_sg requests AMD IOMMU: add stats counter for map_sg requests AMD IOMMU: add stats counter for unmap_single requests AMD IOMMU: add stats counter for map_single requests AMD IOMMU: add stats counter for completion wait events AMD IOMMU: add init code for statistic collection AMD IOMMU: add necessary header defines for stats counting AMD IOMMU: add Kconfig entry for statistic collection code AMD IOMMU: use dev_name in iommu_enable function AMD IOMMU: use calc_devid in prealloc_protection_domains ...
This commit is contained in:
@@ -9,148 +9,16 @@
|
||||
#define VTD_PAGE_MASK (((u64)-1) << VTD_PAGE_SHIFT)
|
||||
#define VTD_PAGE_ALIGN(addr) (((addr) + VTD_PAGE_SIZE - 1) & VTD_PAGE_MASK)
|
||||
|
||||
#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
|
||||
#define DMA_32BIT_PFN IOVA_PFN(DMA_32BIT_MASK)
|
||||
#define DMA_64BIT_PFN IOVA_PFN(DMA_64BIT_MASK)
|
||||
|
||||
|
||||
/*
|
||||
* 0: Present
|
||||
* 1-11: Reserved
|
||||
* 12-63: Context Ptr (12 - (haw-1))
|
||||
* 64-127: Reserved
|
||||
*/
|
||||
struct root_entry {
|
||||
u64 val;
|
||||
u64 rsvd1;
|
||||
};
|
||||
#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
|
||||
static inline bool root_present(struct root_entry *root)
|
||||
{
|
||||
return (root->val & 1);
|
||||
}
|
||||
static inline void set_root_present(struct root_entry *root)
|
||||
{
|
||||
root->val |= 1;
|
||||
}
|
||||
static inline void set_root_value(struct root_entry *root, unsigned long value)
|
||||
{
|
||||
root->val |= value & VTD_PAGE_MASK;
|
||||
}
|
||||
|
||||
struct context_entry;
|
||||
static inline struct context_entry *
|
||||
get_context_addr_from_root(struct root_entry *root)
|
||||
{
|
||||
return (struct context_entry *)
|
||||
(root_present(root)?phys_to_virt(
|
||||
root->val & VTD_PAGE_MASK) :
|
||||
NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* low 64 bits:
|
||||
* 0: present
|
||||
* 1: fault processing disable
|
||||
* 2-3: translation type
|
||||
* 12-63: address space root
|
||||
* high 64 bits:
|
||||
* 0-2: address width
|
||||
* 3-6: aval
|
||||
* 8-23: domain id
|
||||
*/
|
||||
struct context_entry {
|
||||
u64 lo;
|
||||
u64 hi;
|
||||
};
|
||||
#define context_present(c) ((c).lo & 1)
|
||||
#define context_fault_disable(c) (((c).lo >> 1) & 1)
|
||||
#define context_translation_type(c) (((c).lo >> 2) & 3)
|
||||
#define context_address_root(c) ((c).lo & VTD_PAGE_MASK)
|
||||
#define context_address_width(c) ((c).hi & 7)
|
||||
#define context_domain_id(c) (((c).hi >> 8) & ((1 << 16) - 1))
|
||||
|
||||
#define context_set_present(c) do {(c).lo |= 1;} while (0)
|
||||
#define context_set_fault_enable(c) \
|
||||
do {(c).lo &= (((u64)-1) << 2) | 1;} while (0)
|
||||
#define context_set_translation_type(c, val) \
|
||||
do { \
|
||||
(c).lo &= (((u64)-1) << 4) | 3; \
|
||||
(c).lo |= ((val) & 3) << 2; \
|
||||
} while (0)
|
||||
#define CONTEXT_TT_MULTI_LEVEL 0
|
||||
#define context_set_address_root(c, val) \
|
||||
do {(c).lo |= (val) & VTD_PAGE_MASK; } while (0)
|
||||
#define context_set_address_width(c, val) do {(c).hi |= (val) & 7;} while (0)
|
||||
#define context_set_domain_id(c, val) \
|
||||
do {(c).hi |= ((val) & ((1 << 16) - 1)) << 8;} while (0)
|
||||
#define context_clear_entry(c) do {(c).lo = 0; (c).hi = 0;} while (0)
|
||||
|
||||
/*
|
||||
* 0: readable
|
||||
* 1: writable
|
||||
* 2-6: reserved
|
||||
* 7: super page
|
||||
* 8-11: available
|
||||
* 12-63: Host physcial address
|
||||
*/
|
||||
struct dma_pte {
|
||||
u64 val;
|
||||
};
|
||||
#define dma_clear_pte(p) do {(p).val = 0;} while (0)
|
||||
|
||||
#define DMA_PTE_READ (1)
|
||||
#define DMA_PTE_WRITE (2)
|
||||
|
||||
#define dma_set_pte_readable(p) do {(p).val |= DMA_PTE_READ;} while (0)
|
||||
#define dma_set_pte_writable(p) do {(p).val |= DMA_PTE_WRITE;} while (0)
|
||||
#define dma_set_pte_prot(p, prot) \
|
||||
do {(p).val = ((p).val & ~3) | ((prot) & 3); } while (0)
|
||||
#define dma_pte_addr(p) ((p).val & VTD_PAGE_MASK)
|
||||
#define dma_set_pte_addr(p, addr) do {\
|
||||
(p).val |= ((addr) & VTD_PAGE_MASK); } while (0)
|
||||
#define dma_pte_present(p) (((p).val & 3) != 0)
|
||||
|
||||
struct intel_iommu;
|
||||
struct dmar_domain;
|
||||
struct root_entry;
|
||||
|
||||
struct dmar_domain {
|
||||
int id; /* domain id */
|
||||
struct intel_iommu *iommu; /* back pointer to owning iommu */
|
||||
|
||||
struct list_head devices; /* all devices' list */
|
||||
struct iova_domain iovad; /* iova's that belong to this domain */
|
||||
|
||||
struct dma_pte *pgd; /* virtual address */
|
||||
spinlock_t mapping_lock; /* page table lock */
|
||||
int gaw; /* max guest address width */
|
||||
|
||||
/* adjusted guest address width, 0 is level 2 30-bit */
|
||||
int agaw;
|
||||
|
||||
#define DOMAIN_FLAG_MULTIPLE_DEVICES 1
|
||||
int flags;
|
||||
};
|
||||
|
||||
/* PCI domain-device relationship */
|
||||
struct device_domain_info {
|
||||
struct list_head link; /* link to domain siblings */
|
||||
struct list_head global; /* link to global list */
|
||||
u8 bus; /* PCI bus numer */
|
||||
u8 devfn; /* PCI devfn number */
|
||||
struct pci_dev *dev; /* it's NULL for PCIE-to-PCI bridge */
|
||||
struct dmar_domain *domain; /* pointer to domain */
|
||||
};
|
||||
|
||||
extern int init_dmars(void);
|
||||
extern void free_dmar_iommu(struct intel_iommu *iommu);
|
||||
extern int iommu_calculate_agaw(struct intel_iommu *iommu);
|
||||
|
||||
extern int dmar_disabled;
|
||||
|
||||
#ifndef CONFIG_DMAR_GFX_WA
|
||||
static inline void iommu_prepare_gfx_mapping(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif /* !CONFIG_DMAR_GFX_WA */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -144,7 +144,6 @@ struct dmar_rmrr_unit {
|
||||
list_for_each_entry(rmrr, &dmar_rmrr_units, list)
|
||||
/* Intel DMAR initialization functions */
|
||||
extern int intel_iommu_init(void);
|
||||
extern int dmar_disabled;
|
||||
#else
|
||||
static inline int intel_iommu_init(void)
|
||||
{
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
#define _INTEL_IOMMU_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/sysdev.h>
|
||||
#include <linux/iova.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/dma_remapping.h>
|
||||
@@ -289,10 +287,10 @@ struct intel_iommu {
|
||||
void __iomem *reg; /* Pointer to hardware regs, virtual addr */
|
||||
u64 cap;
|
||||
u64 ecap;
|
||||
int seg;
|
||||
u32 gcmd; /* Holds TE, EAFL. Don't need SRTP, SFL, WBF */
|
||||
spinlock_t register_lock; /* protect register handling */
|
||||
int seq_id; /* sequence id of the iommu */
|
||||
int agaw; /* agaw of this iommu */
|
||||
|
||||
#ifdef CONFIG_DMAR
|
||||
unsigned long *domain_ids; /* bitmap of domains */
|
||||
@@ -302,8 +300,6 @@ struct intel_iommu {
|
||||
|
||||
unsigned int irq;
|
||||
unsigned char name[7]; /* Device Name */
|
||||
struct msi_msg saved_msg;
|
||||
struct sys_device sysdev;
|
||||
struct iommu_flush flush;
|
||||
#endif
|
||||
struct q_inval *qi; /* Queued invalidation info */
|
||||
@@ -334,25 +330,6 @@ extern int qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr,
|
||||
|
||||
extern void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu);
|
||||
|
||||
void intel_iommu_domain_exit(struct dmar_domain *domain);
|
||||
struct dmar_domain *intel_iommu_domain_alloc(struct pci_dev *pdev);
|
||||
int intel_iommu_context_mapping(struct dmar_domain *domain,
|
||||
struct pci_dev *pdev);
|
||||
int intel_iommu_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
|
||||
u64 hpa, size_t size, int prot);
|
||||
void intel_iommu_detach_dev(struct dmar_domain *domain, u8 bus, u8 devfn);
|
||||
struct dmar_domain *intel_iommu_find_domain(struct pci_dev *pdev);
|
||||
u64 intel_iommu_iova_to_pfn(struct dmar_domain *domain, u64 iova);
|
||||
|
||||
#ifdef CONFIG_DMAR
|
||||
int intel_iommu_found(void);
|
||||
#else /* CONFIG_DMAR */
|
||||
static inline int intel_iommu_found(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_DMAR */
|
||||
|
||||
extern void *intel_alloc_coherent(struct device *, size_t, dma_addr_t *, gfp_t);
|
||||
extern void intel_free_coherent(struct device *, size_t, void *, dma_addr_t);
|
||||
extern dma_addr_t intel_map_single(struct device *, phys_addr_t, size_t, int);
|
||||
|
||||
112
include/linux/iommu.h
Normal file
112
include/linux/iommu.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
|
||||
* Author: Joerg Roedel <joerg.roedel@amd.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that 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 __LINUX_IOMMU_H
|
||||
#define __LINUX_IOMMU_H
|
||||
|
||||
#define IOMMU_READ (1)
|
||||
#define IOMMU_WRITE (2)
|
||||
|
||||
struct device;
|
||||
|
||||
struct iommu_domain {
|
||||
void *priv;
|
||||
};
|
||||
|
||||
struct iommu_ops {
|
||||
int (*domain_init)(struct iommu_domain *domain);
|
||||
void (*domain_destroy)(struct iommu_domain *domain);
|
||||
int (*attach_dev)(struct iommu_domain *domain, struct device *dev);
|
||||
void (*detach_dev)(struct iommu_domain *domain, struct device *dev);
|
||||
int (*map)(struct iommu_domain *domain, unsigned long iova,
|
||||
phys_addr_t paddr, size_t size, int prot);
|
||||
void (*unmap)(struct iommu_domain *domain, unsigned long iova,
|
||||
size_t size);
|
||||
phys_addr_t (*iova_to_phys)(struct iommu_domain *domain,
|
||||
unsigned long iova);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IOMMU_API
|
||||
|
||||
extern void register_iommu(struct iommu_ops *ops);
|
||||
extern bool iommu_found(void);
|
||||
extern struct iommu_domain *iommu_domain_alloc(void);
|
||||
extern void iommu_domain_free(struct iommu_domain *domain);
|
||||
extern int iommu_attach_device(struct iommu_domain *domain,
|
||||
struct device *dev);
|
||||
extern void iommu_detach_device(struct iommu_domain *domain,
|
||||
struct device *dev);
|
||||
extern int iommu_map_range(struct iommu_domain *domain, unsigned long iova,
|
||||
phys_addr_t paddr, size_t size, int prot);
|
||||
extern void iommu_unmap_range(struct iommu_domain *domain, unsigned long iova,
|
||||
size_t size);
|
||||
extern phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain,
|
||||
unsigned long iova);
|
||||
|
||||
#else /* CONFIG_IOMMU_API */
|
||||
|
||||
static inline void register_iommu(struct iommu_ops *ops)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool iommu_found(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline struct iommu_domain *iommu_domain_alloc(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void iommu_domain_free(struct iommu_domain *domain)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int iommu_attach_device(struct iommu_domain *domain,
|
||||
struct device *dev)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline void iommu_detach_device(struct iommu_domain *domain,
|
||||
struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int iommu_map_range(struct iommu_domain *domain,
|
||||
unsigned long iova, phys_addr_t paddr,
|
||||
size_t size, int prot)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline void iommu_unmap_range(struct iommu_domain *domain,
|
||||
unsigned long iova, size_t size)
|
||||
{
|
||||
}
|
||||
|
||||
static inline phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain,
|
||||
unsigned long iova)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IOMMU_API */
|
||||
|
||||
#endif /* __LINUX_IOMMU_H */
|
||||
@@ -316,6 +316,7 @@ struct kvm_assigned_dev_kernel {
|
||||
#define KVM_ASSIGNED_DEV_HOST_MSI (1 << 9)
|
||||
unsigned long irq_requested_type;
|
||||
int irq_source_id;
|
||||
int flags;
|
||||
struct pci_dev *dev;
|
||||
struct kvm *kvm;
|
||||
};
|
||||
@@ -327,13 +328,16 @@ void kvm_unregister_irq_ack_notifier(struct kvm_irq_ack_notifier *kian);
|
||||
int kvm_request_irq_source_id(struct kvm *kvm);
|
||||
void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id);
|
||||
|
||||
#ifdef CONFIG_DMAR
|
||||
#ifdef CONFIG_IOMMU_API
|
||||
int kvm_iommu_map_pages(struct kvm *kvm, gfn_t base_gfn,
|
||||
unsigned long npages);
|
||||
int kvm_iommu_map_guest(struct kvm *kvm,
|
||||
struct kvm_assigned_dev_kernel *assigned_dev);
|
||||
int kvm_iommu_map_guest(struct kvm *kvm);
|
||||
int kvm_iommu_unmap_guest(struct kvm *kvm);
|
||||
#else /* CONFIG_DMAR */
|
||||
int kvm_assign_device(struct kvm *kvm,
|
||||
struct kvm_assigned_dev_kernel *assigned_dev);
|
||||
int kvm_deassign_device(struct kvm *kvm,
|
||||
struct kvm_assigned_dev_kernel *assigned_dev);
|
||||
#else /* CONFIG_IOMMU_API */
|
||||
static inline int kvm_iommu_map_pages(struct kvm *kvm,
|
||||
gfn_t base_gfn,
|
||||
unsigned long npages)
|
||||
@@ -341,9 +345,7 @@ static inline int kvm_iommu_map_pages(struct kvm *kvm,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int kvm_iommu_map_guest(struct kvm *kvm,
|
||||
struct kvm_assigned_dev_kernel
|
||||
*assigned_dev)
|
||||
static inline int kvm_iommu_map_guest(struct kvm *kvm)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -352,7 +354,19 @@ static inline int kvm_iommu_unmap_guest(struct kvm *kvm)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_DMAR */
|
||||
|
||||
static inline int kvm_assign_device(struct kvm *kvm,
|
||||
struct kvm_assigned_dev_kernel *assigned_dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int kvm_deassign_device(struct kvm *kvm,
|
||||
struct kvm_assigned_dev_kernel *assigned_dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_IOMMU_API */
|
||||
|
||||
static inline void kvm_guest_enter(void)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user