Intel IOMMU Support.
Subsystems (4)
PATCH 2/8 Some generic search functions required to lookup device relationships.
In reply to Ashok RajPCI support functions for DMAR, to find parent bridge.
When devices are under a p2p bridge, upstream
transactions get replaced by the device id of the bridge as it owns the PCIE transaction. Hence its necessary to setup translations on behalf of the bridge as well. Due to this limitation all devices under a p2p share the same domain in a DMAR.
We just cache the type of device, if its a native PCIe device or not for later use.
-------------------------------------------------
drivers/pci/pci.h +1 -0
@@ -90,3 +90,4 @@ pci_match_one_device(const struct pci_dereturn NULL ; } +struct pci_dev *pci_find_upstream_pcie_bridge (struct pci_dev *pdev);
drivers/pci/probe.c +14 -0
@@ -822,6 +822,19 @@ static void pci_release_dev(struct devickfree (pci_dev); } +static void set_pcie_port_type (struct pci_dev *pdev) +{ +int pos; +u16 reg16; + + pos =pci_find_capability (pdev,PCI_CAP_ID_EXP ); +if (!pos) +return ; + pdev->is_pcie =1 ; +pci_read_config_word (pdev, pos +PCI_EXP_FLAGS , ®16); + pdev->pcie_type = (reg16 &PCI_EXP_FLAGS_TYPE ) >>4 ; +} +/** * pci_cfg_space_size - get the configuration space size of the PCI device. * @dev: PCI device
@@ -919,6 +932,7 @@ pci_scan_device(struct pci_bus *bus, int dev->device = (l >>16 ) &0xffff ; dev->cfg_size =pci_cfg_space_size (dev); dev->error_state = pci_channel_io_normal; +set_pcie_port_type (dev);/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer) set this higher, assuming the system even supports it. */
drivers/pci/search.c +30 -0
@@ -14,6 +14,36 @@#include "pci.h" DECLARE_RWSEM (pci_bus_sem); +/* +* find the upstream PCIE-to-PCI bridge of a PCI device +* if the device is PCIE, return NULL +* if the device isn't connected to a PCIE bridge (that is its parent is a +* legacy PCI bridge and the bridge is directly connected to bus 0), return its +* parent +*/ +struct pci_dev * +pci_find_upstream_pcie_bridge (struct pci_dev *pdev) +{ +struct pci_dev *tmp =NULL ; + +if (pdev->is_pcie) +return NULL ; +while (1 ) { +if (!pdev->bus->self) +break ; + pdev = pdev->bus->self; +/* a p2p bridge */ +if (!pdev->is_pcie) { + tmp = pdev; +continue ; + } +/* PCI device should connect to a PCIE bridge */ +BUG_ON (pdev->pcie_type !=PCI_EXP_TYPE_PCI_BRIDGE ); +return pdev; + } + +return tmp; +}static struct pci_bus *pci_do_find_bus (struct pci_bus * bus,unsigned char busnr)
include/linux/pci.h +2 -0
@@ -126,6 +126,7 @@ struct pci_dev {unsigned short subsystem_device;unsigned int class;/* 3 bytes: (base,sub,prog-if) */ u8 hdr_type;/* PCI header type (`multi' flag masked out) */ +u8 pcie_type;/* PCI-E device/port type */ u8 rom_base_reg;/* which config register controls the ROM */ u8 pin;/* which interrupt pin this device uses */
@@ -168,6 +169,7 @@ struct pci_dev { unsigned int msi_enabled:1; unsigned int msix_enabled:1; unsigned int is_managed:1; + unsigned int is_pcie:1;atomic_t enable_cnt;/* pci_enable_device has been called */ u32 saved_config_space[16 ];/* config space saved at suspend time */
PATCH 7/8 Support for legacy ISA devices
In reply to Ashok RajFloppy disk drivers dont work well with DMA remapping. Its possible to extend the current use for x86_64, but the gain is very little. If someone feels compelled to clean this up, its up for grabs. Since these use 16M, we just provide a unity map for the ISA bridge device.
------------------------------------
Documentation/kernel-parameters.txt +5 -0
@@ -730,6 +730,11 @@ the IOMMU driver to set a unity map for all OS visible memory. Hence the driver can continue to use physical addresses for DMA. + noisamap + This option is required to setup identify map for + first 16M. The floppy disk could be modified to use + the DMA api's but thats a lot of pain for very small + gain. This option is turned on by default. io7= [HW] IO7 for Marvel based alpha systems See comment before marvel_specify_io7 in arch/alpha/kernel/core_marvel.c.
drivers/pci/intel-iommu.c +26 -0
@@ -37,6 +37,8 @@#include "pci.h" #define IS_GFX_DEVICE (pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) +#define IS_ISA_DEVICE (pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) +#define IOAPIC_RANGE_START (0xfee00000)#define IOAPIC_RANGE_END (0xfeefffff)#define IOAPIC_RANGE_SIZE (IOAPIC_RANGE_END - IOAPIC_RANGE_START + 1)
@@ -87,6 +89,7 @@static int dmar_disabled, dmar_force_rw;static int dmar_map_gfx =1 , dmar_no_gfx_identity_map =1 ; +static int dmar_fix_isa =1 ;static char *get_fault_reason (u8 fault_reason) {
@@ -113,6 +116,9 @@ }else if (!strncmp (str,"gfx_workaround" ,14 )) { dmar_no_gfx_identity_map =0 ;printk (KERN_INFO "Intel-IOMMU: do 1-1 mapping whole physical memory for GFX device\n" ); + }else if (!strncmp (str,"noisamap" ,8 )) { + dmar_fix_isa =0 ; +printk (KERN_INFO "Intel-IOMMU: Turning off 16M unity map for LPC\n" ); } str +=strcspn (str,"," );
@@ -1582,6 +1588,25 @@ } } +static void iommu_prepare_isa (void ) +{ +struct pci_dev *pdev =NULL ; +int ret; + +if (!dmar_fix_isa) +return ; + + pdev =pci_get_class (PCI_CLASS_BRIDGE_ISA <<8 ,NULL ); +if (!pdev) +return ; + +printk (KERN_INFO "IOMMU: Prepare 0-16M unity mapping for LPC\n" ); + ret =iommu_prepare_identity_map (pdev,0 ,16 *1024 *1024 ); + +if (ret) +printk ("IOMMU: Failed to create 0-64M identity map, Floppy might not work\n" ); + +}int __init init_dmars (void ) {struct dmar_drhd_unit *drhd;
@@ -1638,6 +1663,7 @@end_for_each_rmrr_device (rmrr, pdev)iommu_prepare_gfx_mapping (); +iommu_prepare_isa ();/* * for each drhd
PATCH 6/8 Doc updates for Intel Virtualization Technology for Directed I/O.
In reply to Ashok RajDocument Intel IOMMU driver boot option.
Documentation/Intel-IOMMU.txt new file +119 -0
@@ -0,0 +1,119 @@ +Linux IOMMU Support +=================== + +The architecture spec can be obtained from the below location. + +http://www.intel.com/technology/virtualization/ + +This guide gives a quick cheat sheet for some basic understanding. + +Some Keywords + +DMAR - DMA remapping +DRHD - DMA Engine Reporting Structure +RMRR - Reserved memory Region Reporting Structure +ZLR - Zero length reads from PCI devices +IOVA - IO Virtual address. + +Basic stuff +----------- + +ACPI enumerates and lists the different DMA engines in the platform, and +device scope relationships between PCI devices and which DMA engine controls +them. + +What is RMRR? +------------- + +There are some devices the BIOS controls, for e.g USB devices to perform +PS2 emulation. The regions of memory used for these devices are marked +reserved in the e820 map. When we turn on DMA translation, DMA to those +regions will fail. Hence BIOS uses RMRR to specify these regions along with +devices that need to access these regions. OS is expected to setup +unity mappings for these regions for these devices to access these regions. + +How is IOVA generated? +--------------------- + +Well behaved drivers call pci_map_*() calls before sending command to device +that needs to perform DMA. Once DMA is completed and mapping is no longer +required, device performs a pci_unmap_*() calls to unmap the region. + +The Intel IOMMU driver allocates a virtual address per domain. Each PCIE +device has its own domain (hence protection). Devices under p2p bridges +share the virtual address with all devices under the p2p bridge due to +transaction id aliasing for p2p bridges. + +IOVA generation is pretty generic. We used the same technique as vmalloc() +but these are not global address spaces, but separate for each domain. +Different DMA engines may support different number of domains. + +We also allocate gaurd pages with each mapping, so we can attempt to catch +any overflow that might happen. + + +Graphics Problems? +------------------ +If you encounter issues with graphics devices, you can try adding +option intel_iommu=igfx_off to turn off the integrated graphics engine. + +If it happens to be a PCI device included in the INCLUDE_ALL Engine, +then try the intel_iommu=gfx_workaround to setup a 1-1 map. We hear +graphics drivers may be in process of using DMA api's in the near +future.... + +Some exceptions to IOVA +----------------------- +Interrupt ranges are not address translated, (0xfee00000 - 0xfeefffff). +The same is true for peer to peer transactions. Hence we reserve the +address from PCI MMIO ranges so they are not allocated for IOVA addresses. + + +Fault reporting +--------------- +When errors are reported, the DMA engine signals via an interrupt. The fault +reason and device that caused it with fault reason is printed on console. + +See below for sample. + + +Boot Message Sample +------------------- + +Something like this gets printed indicating presence of DMAR tables +in ACPI. + +ACPI: DMAR (v001 A M I OEMDMAR 0x00000001 MSFT 0x00000097) @ 0x000000007f5b5ef0 + +When DMAR is being processed and initialized by ACPI, prints DMAR locations +and any RMRR's processed. + +ACPI DMAR:Host address width 36 +ACPI DMAR:DRHD (flags: 0x00000000)base: 0x00000000fed90000 +ACPI DMAR:DRHD (flags: 0x00000000)base: 0x00000000fed91000 +ACPI DMAR:DRHD (flags: 0x00000001)base: 0x00000000fed93000 +ACPI DMAR:RMRR base: 0x00000000000ed000 end: 0x00000000000effff +ACPI DMAR:RMRR base: 0x000000007f600000 end: 0x000000007fffffff + +When DMAR is enabled for use, you will notice.. + +PCI-DMA: Using DMAR IOMMU + +Fault reporting +--------------- + +DMAR:[DMA Write] Request device [00:02.0] fault addr 6df084000 +DMAR:[fault reason 05] PTE Write access is not set +DMAR:[DMA Write] Request device [00:02.0] fault addr 6df084000 +DMAR:[fault reason 05] PTE Write access is not set + +TBD +---- + +- No Performance tuning / analysis yet. +- sysfs needs useful data to be populated. + DMAR info, device scope, stats could be exposed to some extent. +- Add support to Firmware Developer Kit to test ACPI tables for DMAR. +- For compatibility testing, could use unity map domain for all devices, just + provide a 1-1 for all useful memory under a single domain for all devices. +- API for paravirt ops for abstracting functionlity for VMM folks.
Documentation/kernel-parameters.txt +20 -0
@@ -710,6 +710,26 @@ inttest= [IA64] + intel_iommu= [DMAR] Intel IOMMU driver (DMAR) option + off + Disable intel iommu driver. + forcerw + Some drivers might incorrectly map DMA buffers as + write-only even when the device, requires read/write + mapping. This option works around the issue in IOMMU + driver by making all write-only map as read/write. + Default is off. + igfx_off [Default Off] + By default, gfx is mapped as normal device. If a gfx + device has a dedicated DMAR unit, the DMAR unit is + bypassed with this option. In this case, gfx device + will use physical address for DMA. + gfx_workaround [Default Off] + gfx devices tend to use physical address for DMA and + avoid using DMA api's. Setting this option permits + the IOMMU driver to set a unity map for all OS + visible memory. Hence the driver can continue to use + physical addresses for DMA. io7= [HW] IO7 for Marvel based alpha systems See comment before marvel_specify_io7 in arch/alpha/kernel/core_marvel.c.
PATCH 3/8 Generic hardware support for Intel IOMMU.
In reply to Ashok RajActual intel IOMMU driver. Hardware spec can be found at:
http://www.intel.com/technology/virtualization
The current version of spec is slightly outdated, but an updated version of spec is in works and comming very soon. I will send a note to the list when new updated spec is available. For the most part existing spec should be good for basic understanding of the mechanics of the IOMMU.
This driver sets X86_64 'dma_ops', so hook into standard DMA APIs. In this way, PCI driver will get virtual DMA address. This change is transparent to PCI drivers.
arch/x86_64/kernel/io_apic.c +58 -1
@@ -32,6 +32,7 @@#include <linux/sysdev.h> #include <linux/msi.h> #include <linux/htirq.h> +#include <linux/intel-iommu.h> #ifdef CONFIG_ACPI #include <acpi/acpi_bus.h> #endif
@@ -2002,8 +2003,64 @@ void arch_teardown_msi_irq(unsigned intdestroy_irq (irq); } -#endif /* CONFIG_PCI_MSI */ +#ifdef CONFIG_DMAR +#ifdef CONFIG_SMP +static void dmar_msi_set_affinity (unsigned int irq,cpumask_t mask) +{ +struct irq_cfg *cfg = irq_cfg + irq; +struct msi_msg msg; +unsigned int dest; +cpumask_t tmp; + +cpus_and (tmp, mask, cpu_online_map); +if (cpus_empty (tmp)) +return ; + +if (assign_irq_vector (irq, mask)) +return ; + +cpus_and (tmp, cfg->domain, mask); + dest =cpu_mask_to_apicid (tmp); + +dmar_msi_read (irq, &msg); + + msg.data &= ~MSI_DATA_VECTOR_MASK ; + msg.data |=MSI_DATA_VECTOR (cfg->vector); + msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK ; + msg.address_lo |=MSI_ADDR_DEST_ID (dest); + +dmar_msi_write (irq, &msg); + irq_desc[irq].affinity = mask; +} +#endif /* CONFIG_SMP */ + +struct irq_chip dmar_msi_type = { + .name ="DMAR_MSI" , + .unmask = dmar_msi_unmask, + .mask = dmar_msi_mask, + .ack = ack_apic_edge, +#ifdef CONFIG_SMP + .set_affinity = dmar_msi_set_affinity, +#endif + .retrigger = ioapic_retrigger_irq, +}; + +int arch_setup_dmar_msi (unsigned int irq) +{ +int ret; +struct msi_msg msg; + + ret =msi_compose_msg (NULL , irq, &msg); +if (ret <0 ) +return ret; +dmar_msi_write (irq, &msg); +set_irq_chip_and_handler_name (irq, &dmar_msi_type, handle_edge_irq, +"edge" ); +return 0 ; +} +#endif +#endif /* CONFIG_PCI_MSI */ /* * Hypertransport interrupt support */
arch/x86_64/kernel/pci-dma.c +9 -0
@@ -7,6 +7,7 @@#include <linux/string.h> #include <linux/pci.h> #include <linux/module.h> +#include <linux/intel-iommu.h> #include <asm/io.h> #include <asm/proto.h> #include <asm/calgary.h>
@@ -303,6 +304,10 @@ void __init pci_iommu_alloc(void)detect_calgary ();#endif +#ifdef CONFIG_DMAR +detect_intel_iommu (); +#endif +#ifdef CONFIG_SWIOTLB pci_swiotlb_init ();#endif
@@ -314,6 +319,10 @@ static int __init pci_iommu_init(void)calgary_iommu_init ();#endif +#ifdef CONFIG_DMAR +intel_iommu_init (); +#endif +#ifdef CONFIG_IOMMU gart_iommu_init ();#endif
arch/x86_64/mm/pageattr.c +3 -3
@@ -61,10 +61,10 @@ static struct page *split_large_page(unsreturn base; } -static void cache_flush_page (void *adr) +void clflush_cache_range (void *adr,int size) {int i; -for (i =0 ; i <PAGE_SIZE ; i += boot_cpu_data.x86_clflush_size) +for (i =0 ; i < size; i += boot_cpu_data.x86_clflush_size) asmvolatile ("clflush (%0)" ::"r" (adr + i)); }
@@ -80,7 +80,7 @@ static void flush_kernel_map(void *arg)list_for_each_entry (pg, l, lru) {void *adr =page_address (pg);if (cpu_has_clflush) -cache_flush_page (adr); +clflush_cache_range (adr,PAGE_SIZE );__flush_tlb_one (adr); } }
drivers/pci/Kconfig +8 -0
@@ -60,3 +60,11 @@ config HT_IRQ This allows native hypertransport devices to use interrupts. If unsure say Y. + +config IOVA_GUARD_PAGE + bool "Enables gaurd page when allocating IO Virtual Address for IOMMU" + depends on DMAR + +config IOVA_NEXT_CONTIG + bool "Keeps IOVA allocations consequent between allocations" + depends on DMAR && EXPERIMENTAL
drivers/pci/Makefile +3 -0
@@ -20,6 +20,9 @@ obj-$(CONFIG_PCI_MSI) += msi.o # Build the Hypertransport interrupt support obj-$(CONFIG_HT_IRQ) += htirq.o +# Build DMAR if configured +obj-$(CONFIG_DMAR) += intel-iommu.o iova.o + # # Some architectures use the generic PCI setup functions #
drivers/pci/intel-iommu.c new file +2070 -0
2,070 lines not on this page · raw message
drivers/pci/iova.c new file +274 -0
274 lines not on this page · raw message
drivers/pci/iova.h new file +56 -0
56 lines not on this page · raw message
include/asm-x86_64/cacheflush.h +1 -0
@@ -27,6 +27,7 @@void global_flush_tlb (void );int change_page_attr (struct page *page,int numpages,pgprot_t prot);int change_page_attr_addr (unsigned long addr,int numpages,pgprot_t prot); +void clflush_cache_range (void *addr,int size);#ifdef CONFIG_DEBUG_RODATA void mark_rodata_ro (void );
include/linux/intel-iommu.h new file +269 -0
269 lines not on this page · raw message
PATCH 5/8 Graphics driver workarounds to provide unity map
In reply to Ashok RajMost GFX drivers don't call standard PCI DMA APIs to allocate DMA buffer, Such drivers will be broken with IOMMU enabled. To workaround this issue, we added two options.
Once graphics devices are converted over to use the DMA-API's this entire patch can be removed...
a. intel_iommu=igfx_off. With this option, DMAR who has just gfx devices
under it will be ignored. This mostly affect intergated gfx devices. If the DMAR is ignored, gfx device under it will get physical address for DMA.
b. intel_iommu=gfx_workaround. With this option, we will setup 1:1 mapping
for whole memory for gfx devices, that is physical address equals to virtual address.In this way, gfx will use physical address for DMA, this is primarily for add-in card GFX device.
arch/x86_64/kernel/e820.c +19 -0
@@ -730,3 +730,22 @@ __init void e820_setup_gap(void)printk (KERN_INFO "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n" , pci_mem_start, gapstart, gapsize); } + +int __init arch_get_ram_range (int slot,u64 *addr,u64 *size) +{ +int i; + +if (slot <0 || slot >= e820.nr_map) +return -1 ; +for (i = slot; i < e820.nr_map; i++) { +if (e820.map[i].type !=E820_RAM ) +continue ; +break ; + } +if (i == e820.nr_map || e820.map[i].addr > (max_pfn <<PAGE_SHIFT )) +return -1 ; + *addr = e820.map[i].addr; + *size =min_t (u64, e820.map[i].size + e820.map[i].addr, + max_pfn <<PAGE_SHIFT ) - *addr; +return i +1 ; +}
drivers/pci/dmar.h +1 -0
@@ -35,6 +35,7 @@ struct dmar_drhd_unit {int devices_cnt; u8 include_all:1;struct iommu *iommu; + int ignored:1; /* the drhd should be ignored */ };struct dmar_rmrr_unit {
drivers/pci/intel-iommu.c +119 -0
226 lines not on this page · raw message
include/linux/intel-iommu.h +2 -0
@@ -263,6 +263,8 @@ extern void dmar_msi_read(int irq, strucextern void dmar_msi_write (int irq,struct msi_msg *msg);extern int arch_setup_dmar_msi (unsigned int irq); +extern int arch_get_ram_range (int slot,u64 *addr,u64 *size); +extern int init_dmars (void );extern void detect_intel_iommu (void );extern int early_dmar_detect (void );
PATCH 8/8 Preserve some Virtual Address when devices cannot address entire range.
In reply to Ashok RajSome devices may not support entire 64bit DMA. In a situation where such devices are co-located in a shared domain, we need to ensure there is some address space reserved for such devices without the low addresses getting depleted by other devices capable of handling high dma addresses.
Documentation/kernel-parameters.txt +5 -0
@@ -735,6 +735,11 @@ first 16M. The floppy disk could be modified to use the DMA api's but thats a lot of pain for very small gain. This option is turned on by default. + preserve_{1g/2g/4g/512m/256m/16m} + If a device is sharing a domain with other devices + and the device mask doesnt cover the 64bit range, + use this option to let the iommu code preserve some + virtual addr for such devices. io7= [HW] IO7 for Marvel based alpha systems See comment before marvel_specify_io7 in arch/alpha/kernel/core_marvel.c.
drivers/pci/intel-iommu.c +32 -5
@@ -90,6 +90,7 @@static int dmar_disabled, dmar_force_rw;static int dmar_map_gfx =1 , dmar_no_gfx_identity_map =1 ;static int dmar_fix_isa =1 ; +static u64 dmar_preserve_iova_mask;static char *get_fault_reason (u8 fault_reason) {
@@ -119,6 +120,32 @@ }else if (!strncmp (str,"noisamap" ,8 )) { dmar_fix_isa =0 ;printk (KERN_INFO "Intel-IOMMU: Turning off 16M unity map for LPC\n" ); + }else if (!strncmp (str,"preserve_" ,9 )) { +if (!strncmp (str +9 ,"4g" ,2 ) || + !strncmp (str +9 ,"4G" ,2 )) + dmar_preserve_iova_mask =DMA_32BIT_MASK ; +else if (!strncmp (str +9 ,"2g" ,2 ) || + !strncmp (str +9 ,"2G" ,2 )) + dmar_preserve_iova_mask =DMA_31BIT_MASK ; +else if (!strncmp (str +9 ,"1g" ,2 ) || + !strncmp (str +9 ,"1G" ,2 )) + dmar_preserve_iova_mask =DMA_30BIT_MASK ; +else if (!strncmp (str +9 ,"512m" ,2 ) || + !strncmp (str +9 ,"512M" ,2 )) + dmar_preserve_iova_mask =DMA_29BIT_MASK ; +else if (!strncmp (str +9 ,"256m" ,4 ) || + !strncmp (str +9 ,"256M" ,4 )) + dmar_preserve_iova_mask =DMA_28BIT_MASK ; +else if (!strncmp (str +9 ,"16m" ,3 ) || + !strncmp (str +9 ,"16M" ,3 )) + dmar_preserve_iova_mask =DMA_24BIT_MASK ; +if (dmar_preserve_iova_mask) +printk (KERN_INFO +"DMAR: Preserved IOVA mask 0x%Lx for devices " +"sharing domain\n" , dmar_preserve_iova_mask); +else +printk (KERN_ERR "DMAR: Unsuppored preserve mask" +" provided" ); } str +=strcspn (str,"," );
@@ -1723,7 +1750,6 @@ last_addr : IOVA_START_ADDR); }return last_addr; - }#endif
@@ -1751,13 +1777,14 @@/* * If the device shares a domain with other devices and the device can -* handle > 4G DMA, let the device use DMA address started from 4G, so to -* leave rooms for other devices +* can handle higher address, leave rooms for devices that cant +* address high address ranges. */ if ((domain->flags &DOMAIN_FLAG_MULTIPLE_DEVICES ) && - pdev->dma_mask >DMA_32BIT_MASK ) + dmar_preserve_iova_mask && + (pdev->dma_mask > dmar_preserve_iova_mask)) iova =alloc_iova (domain, addr, size, -DMA_32BIT_MASK +1 , pdev->dma_mask); + dmar_preserve_iova_mask +1 , pdev->dma_mask);else {#ifndef CONFIG_IOVA_NEXT_CONTIG iova = alloc_iova(domain, addr, size,
cover Intel IOMMU Support.
Hello again!
Andrew: Could you help include in -mm to give it more exposure preparing for mainline inclusion with more testing?
This is a resend of the patches after addressing some feedback we received.
1. As len requested, we moved most of the acpi parts to drivers/pci instead of leaving them in drivers/acpi, including some renaming of functions, using just acpi_get_table() only.
2. Made the guard page support configurable.
3. Added new CONFIG option to allocate consecutive address instead of re-using free addresses as an experimental option, Not validated extensively. Its expected to improve in certain cases...
4. Fixed a couple minor bugs that got exposed in testing.
Other feedback:
- Some suggested depend on ACPI, but thats not doable for several reasons.
- Graphics 1-1 maps exist only for compatibility until graphics drivers start calling pci map functions, including user space X that might be using /dev/mem.
Some more interesting possibilities. -- enhancements to work on.
- In order to ensure we dont break any driver that may not be using dma api's here are some suggestions to work on.
- Create a single 1-1 map, and make sure any pci device gets this map when they do a pci_set_master() to enable bus mastering automatically.
- When the device driver does a first call to do a dma mapping, then dissociate the device from the unity map domain, to its own. This gives limited protection but doesnt break drivers that do not use dma mapping.
- Creating context entries only 1 per segment.. today we create one per IOMMU which is not required.
This way we can avoid doing some of the workarounds we do for some devices today, and will function as a default container for compatibility.
On one hand, this will provide more compatibility, but we will lose oppertunity to identify broken device drivers that dont use dma api's and fix them.... Depending on who you talk to.. some like it.. some just hate it! and would like to fix the broken ones instead.
Cheers,
Ashok Raj
PATCH 4/8 Supporting Zero Length Reads in Intel IOMMU.
PCI specs permit zero length reads (ZLR) even if the mapping for that region is write only. Support for this feature is indicated by the presence of a bit in the DMAR capability. If a particular DMAR does not support this capability we map write-only regions as read-write.
This option can also provides a workaround for some drivers that request a write-only mapping when they really should request a read-write. (We ran into one such case in eepro100.c in handling rx_ring_dma)
----------------------------------
drivers/pci/intel-iommu.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/pci/intel-iommu.c +10 -2
@@ -84,7 +84,7 @@ struct iommu {struct sys_device sysdev; }; -static int dmar_disabled; +static int dmar_disabled, dmar_force_rw;static char *get_fault_reason (u8 fault_reason) {
@@ -102,6 +102,9 @@ static int __init intel_iommu_setup(charif (!strncmp (str,"off" ,3 )) { dmar_disabled =1 ;printk (KERN_INFO "Intel-IOMMU: disabled\n" ); + }else if (!strncmp (str,"forcerw" ,7 )) { + dmar_force_rw =1 ; +printk (KERN_INFO "Intel-IOMMU: force R/W for W/O mapping\n" ); } str +=strcspn (str,"," );while (*str ==',' )
@@ -1720,7 +1723,12 @@ static dma_addr_t __intel_map_single(str goto error; } -if (dir ==DMA_TO_DEVICE || dir ==DMA_BIDIRECTIONAL ) +/* +* Check if DMAR supports zero-length reads on write only +* mappings.. +*/ +if (dir ==DMA_TO_DEVICE || dir ==DMA_BIDIRECTIONAL || \ + !cap_zlr (domain->iommu->cap) || dmar_force_rw) prot |=DMA_PTE_READ ;if (dir ==DMA_FROM_DEVICE || dir ==DMA_BIDIRECTIONAL ) prot |=DMA_PTE_WRITE ;
include/linux/intel-iommu.h +1 -0
@@ -79,6 +79,7 @@#define cap_max_fault_reg_offset (c) \ (cap_fault_reg_offset(c) + cap_num_fault_regs(c) * 16) +#define cap_zlr (c) (((c) >> 22) & 1)#define cap_isoch (c) (((c) >> 23) & 1)#define cap_mgaw (c) ((((c) >> 16) & 0x3f) + 1)#define cap_sagaw (c) (((c) >> 8) & 0x1f)
PATCH 1/8 ACPI support for Intel Virtualization Technology for Directed I/O
In reply to Ashok RajThis patch contains basic ACPI parsing and enumeration support.
arch/x86_64/Kconfig +8 -0
@@ -687,6 +687,14 @@ bool "Support mmconfig PCI config space access" depends on PCI && ACPI +config DMAR + bool "Support for DMA Remapping Devices (EXPERIMENTAL)" + depends on PCI_MSI && ACPI && EXPERIMENTAL + help + Support DMA Remapping Devices. The devices are reported via + ACPI tables and includes pci device scope under each DMA + remapping device. + source "drivers/pci/pcie/Kconfig" source "drivers/pci/Kconfig"
drivers/pci/Makefile +1 -0
@@ -38,6 +38,7 @@ # obj-$(CONFIG_ACPI) += pci-acpi.o +obj-$(CONFIG_DMAR) += dmar.o # Cardbus & CompactPCI use setup-bus obj-$(CONFIG_HOTPLUG) += setup-bus.o
drivers/pci/dmar.c new file +350 -0
350 lines not on this page · raw message
drivers/pci/dmar.h new file +65 -0
65 lines not on this page · raw message
include/acpi/actbl1.h +20 -7
@@ -257,7 +257,8 @@struct acpi_table_dmar {struct acpi_table_header header;/* Common ACPI table header */ u8 width;/* Host Address Width */ -u8 reserved[11 ]; +u8 flags; +u8 reserved[10 ]; };/* DMAR subtable header */
@@ -265,8 +266,6 @@struct acpi_dmar_header {u16 type;u16 length; -u8 flags; -u8 reserved[3 ]; };/* Values for subtable type in struct acpi_dmar_header */
@@ -274,13 +273,15 @@enum acpi_dmar_type {ACPI_DMAR_TYPE_HARDWARE_UNIT =0 ,ACPI_DMAR_TYPE_RESERVED_MEMORY =1 , -ACPI_DMAR_TYPE_RESERVED =2 /* 2 and greater are reserved */ +ACPI_DMAR_TYPE_ATSR =2 , +ACPI_DMAR_TYPE_RESERVED =3 /* 3 and greater are reserved */ };struct acpi_dmar_device_scope {u8 entry_type;u8 length; -u8 segment; +u16 reserved; +u8 enumeration_id;u8 bus; };
@@ -290,7 +291,14 @@ACPI_DMAR_SCOPE_TYPE_NOT_USED =0 ,ACPI_DMAR_SCOPE_TYPE_ENDPOINT =1 ,ACPI_DMAR_SCOPE_TYPE_BRIDGE =2 , - ACPI_DMAR_SCOPE_TYPE_RESERVED = 3 /* 3 and greater are reserved */ +ACPI_DMAR_SCOPE_TYPE_IOAPIC =3 , +ACPI_DMAR_SCOPE_TYPE_HPET =4 , + ACPI_DMAR_SCOPE_TYPE_RESERVED = 5 /* 5 and greater are reserved */ +}; + +struct acpi_dmar_pci_path { +u8 dev; +u8 fn; };/*
@@ -301,6 +309,9 @@struct acpi_dmar_hardware_unit {struct acpi_dmar_header header; +u8 flags; +u8 reserved; +u16 segment;u64 address;/* Register Base Address */ };
@@ -312,7 +323,9 @@struct acpi_dmar_reserved_memory {struct acpi_dmar_header header; -u64 address;/* 4_k aligned base address */ +u16 reserved; +u16 segment; +u64 base_address;/* 4_k aligned base address */ u64 end_address;/* 4_k aligned limit address */ };
Re: [Intel IOMMU][patch 3/8] Generic hardware support for Intel IOMMU.
In reply to Ashok Rajarch/x86_64/kernel/io_apic.c void arch_teardown_msi_irq(unsigned int · line 2008
Quoted 4 lines · On Tuesday 24 April 2007 08:03:02 Ashok Raj wrote:
arch/x86_64/kernel/io_apic.c +3
-0+#ifdef CONFIG_DMAR +#ifdef CONFIG_SMP +static void dmar_msi_set_affinity (unsigned int irq,cpumask_t mask)
Why does it need an own interrupt type?
drivers/pci/Kconfig config HT_IRQ · line 70
Quoted 8 lines
drivers/pci/Kconfig +8
-0+ +config IOVA_GUARD_PAGE + bool "Enables gaurd page when allocating IO Virtual Address for IOMMU" + depends on DMAR + +config IOVA_NEXT_CONTIG + bool "Keeps IOVA allocations consequent between allocations" + depends on DMAR && EXPERIMENTAL
Needs reference to Intel and better description
The file should have a high level description what it is good for etc.
Need high level overview over what locks protects what and if there is a locking order.
It doesn't seem to enable sg merging? Since you have enough space that should work.
Quoted 9 lines
drivers/pci/intel-iommu.c new file +9
-0+static char *fault_reason_strings[] = +{ +"Software" , +"Present bit in root entry is clear" , +"Present bit in context entry is clear" , +"Invalid context entry" , +"Access beyond MGAW" , +"PTE Write access is not set" , +"PTE Read access is not set" ,
drivers/pci/intel-iommu.c line 66
Quoted 10 lines
drivers/pci/intel-iommu.c new file +10
-0+"Next page table ptr is invalid" , +"Root table address invalid" , +"Context table ptr is invalid" , +"non-zero reserved fields in RTP" , +"non-zero reserved fields in CTP" , +"non-zero reserved fields in PTE" , + "Unknown" +}; + +#define MAX_FAULT_REASON_IDX (12)
You got 14 of them. better use ARRAY_SIZE
drivers/pci/intel-iommu.c line 69
Quoted 3 lines
drivers/pci/intel-iommu.c new file +3
-0+#define IOMMU_NAME_LEN (7) + +struct iommu {
call it intel_iommu or somesuch even when it's private.
Quoted 6 lines
drivers/pci/intel-iommu.c new file +6
-0+static int __init intel_iommu_setup (char *str) +{ +if (!str) +return -EINVAL ; +while (*str) { +if (!strncmp (str,"off" ,3 )) {
drivers/pci/intel-iommu.c line 112
Quoted 10 lines
drivers/pci/intel-iommu.c new file +10
-0+ dmar_disabled =1 ; +printk (KERN_INFO "Intel-IOMMU: disabled\n" ); + } + str +=strcspn (str,"," ); +while (*str ==',' ) + str++; + } +return 0 ; +} +__setup ("intel_iommu=" , intel_iommu_setup);
Why can't you just use the normal iommu=off for this?
drivers/pci/intel-iommu.c line 119
Quoted 7 lines
drivers/pci/intel-iommu.c new file +7
-0+ +#define MIN_PGTABLE_PAGES (10) +static mempool_t *pgtable_mempool; +#define MIN_DOMAIN_REQ (20) +static mempool_t *domain_mempool; +#define MIN_DEVINFO_REQ (20) +static mempool_t *devinfo_mempool;
Lots of mempools. How much memory does this pin?
drivers/pci/intel-iommu.c line 126
Quoted 7 lines
drivers/pci/intel-iommu.c new file +7
-0+ +#define alloc_pgtable_page () mempool_alloc(pgtable_mempool, GFP_ATOMIC) +#define free_pgtable_page (vaddr) mempool_free(vaddr, pgtable_mempool) +#define alloc_domain_mem () mempool_alloc(domain_mempool, GFP_ATOMIC) +#define free_domain_mem (vaddr) mempool_free(vaddr, domain_mempool) +#define alloc_devinfo_mem () mempool_alloc(devinfo_mempool, GFP_ATOMIC) +#define free_devinfo_mem (vaddr) mempool_free(vaddr, devinfo_mempool)
Do we need the macros? Better expand them in the caller.
drivers/pci/intel-iommu.c line 137
Quoted 10 lines
drivers/pci/intel-iommu.c new file +10
-0+static void __iommu_flush_cache (struct iommu *iommu,void *addr,int size) +{ +if (!ecap_coherent (iommu->ecap)) +clflush_cache_range (addr, size); +} + +#define iommu_flush_cache_entry (iommu, addr) \ + __iommu_flush_cache(iommu, addr, 8) +#define iommu_flush_cache_page (iommu, addr) \ + __iommu_flush_cache(iommu, addr, PAGE_SIZE_4K)
Similar.
And the 8 should be probably something more descriptive (sizeof?)
drivers/pci/intel-iommu.c line 151
Quoted 13 lines
drivers/pci/intel-iommu.c new file +13
-0+/* context entry handling */ +static struct context_entry *device_to_context_entry (struct iommu *iommu, +u8 bus,u8 devfn) +{ +struct root_entry *root; +struct context_entry *context; +unsigned long phy_addr; +unsigned long flags; + +spin_lock_irqsave (&iommu->lock, flags); + root = &iommu->root_entry[bus]; +if (!root_present (*root)) { + phy_addr = (unsigned long )alloc_pgtable_page ();
A GFP_ATOMIC mempool is rather useless. mempool only works if it can block for someone else freeing memory and if it can't do that it's not failsafe. I'm afraid you need to revise the allocation strategy -- best would be to somehow move the memory allocations outside the spinlock paths and preallocate if possible.
Same problem in other code.
drivers/pci/intel-iommu.c line 269
Quoted 2 lines
drivers/pci/intel-iommu.c new file +2
-0+if (!dma_pte_present (*pte)) { + tmp =alloc_pgtable_page ();
Please don't name variable tmp. I know some other code does it, but it's just bad style imho.
drivers/pci/intel-iommu.c line 431
Quoted 10 lines
drivers/pci/intel-iommu.c new file +10
-0+/* Make sure hardware complete it */ + start_time = jiffies; +while (1 ) { + sts =dmar_readl (iommu->reg,DMAR_GSTS_REG ); +if (sts &DMA_GSTS_RTPS ) +break ; +if (time_after (jiffies, start_time +DMAR_OPERATION_TIMEOUT )) +panic ("DMAR hardware is malfunctional, please disable IOMMU\n" ); +cpu_relax (); + }
Could MWAIT/MONITOR be used for this?
Quoted 17 lines
drivers/pci/intel-iommu.c new file +17
-0+spin_unlock_irqrestore (&iommu->register_lock, flag); +} + +static void iommu_flush_write_buffer (struct iommu *iommu) +{ +u32 val; +unsigned long flag; +unsigned long start_time; + +if (!cap_rwbf (iommu->cap)) +return ; + val = iommu->gcmd |DMA_GCMD_WBF ; + +spin_lock_irqsave (&iommu->register_lock, flag); +dmar_writel (iommu->reg,DMAR_GCMD_REG , val); + +/* Make sure hardware complete it */
drivers/pci/intel-iommu.c line 458
Quoted 10 lines
drivers/pci/intel-iommu.c new file +10
-0+ start_time = jiffies; +while (1 ) { + val =dmar_readl (iommu->reg,DMAR_GSTS_REG ); +if (!(val &DMA_GSTS_WBFS )) +break ; +if (time_after (jiffies, start_time +DMAR_OPERATION_TIMEOUT )) +panic ("DMAR hardware is malfunctional, please disable IOMMU\n" ); +cpu_relax (); + } +spin_unlock_irqrestore (&iommu->register_lock, flag);
Surely some code sharing with the previous function is possible? This code seems to be cut'n'pasted a lot
Quoted 1 line
+/* iommu interrupt handling. Most staffs are MSI-like. */
staffs?
drivers/pci/iova.c line 53
Quoted 4 lines
drivers/pci/iova.c new file +4
-0+static struct iova *alloc_iova_from_pool (void ) +{ +struct iova *iova; + iova =mempool_alloc (iova_mempool,GFP_ATOMIC );
Similar comment as earlier. Non blocking mempool doesn't make sense
-Andi
Re: [Intel IOMMU][patch 1/8] ACPI support for Intel Virtualization Technology for Directed I/O
In reply to Ashok Rajarch/x86_64/Kconfig line 696
Quoted 8 lines
arch/x86_64/Kconfig +7
-0+config DMAR + bool "Support for DMA Remapping Devices (EXPERIMENTAL)" + depends on PCI_MSI && ACPI && EXPERIMENTAL + help + Support DMA Remapping Devices. The devices are reported via + ACPI tables and includes pci device scope under each DMA + remapping device.
The description needs to explain what a dma remapping device is.
And some high level comment here what this file does.
drivers/pci/dmar.c line 34
Quoted 3 lines
drivers/pci/dmar.c new file +3
-0+ +LIST_HEAD (dmar_drhd_units); +LIST_HEAD (dmar_rmrr_units);
Comment describing what lock protects those lists? In fact there seems to be no locking. What about hotplug?
drivers/pci/dmar.c line 296
Quoted 7 lines
drivers/pci/dmar.c new file +6
-0+ + dmar = (struct acpi_table_dmar *)table; +if (!dmar) { + printk (KERN_WARNING PREFIX "Unable to map DMAR\n"); +return -ENODEV ; + }
Shouldn't that be wherever the table is mapped. Or is it not needed?
-Andi
Re: [Intel IOMMU][patch 4/8] Supporting Zero Length Reads in Intel IOMMU.
In reply to Ashok RajQuoted 8 lines · On Tuesday 24 April 2007 08:03:03 Ashok Raj wrote:
PCI specs permit zero length reads (ZLR) even if the mapping for that region is write only. Support for this feature is indicated by the presence of a bit in the DMAR capability. If a particular DMAR does not support this capability we map write-only regions as read-write.
This option can also provides a workaround for some drivers that request a write-only mapping when they really should request a read-write. (We ran into one such case in
eepro100.cin handlingrx_ring_dma)
Better just fix the drivers instead of adding such hacks
-Andi
Re: [Intel IOMMU][patch 7/8] Support for legacy ISA devices
In reply to Ashok RajQuoted 1 line · On Tuesday 24 April 2007 08:03:06 Ashok Raj wrote:
Floppy disk drivers dont work well with DMA remapping.
What is the problem? You can't allocate mappings <16MB?
Quoted 5 lines
Its possible to
extend the current use forx86_64, but the gain is very little. If someone feels compelled to clean this up, its up for grabs. Since these use 16M, we just provide a unity map for the ISA bridge device.
While it's probably not worth for the floppy there are other devices with similar weird addressing limitations. Some generic handling of it would be nice.
-Andi
Re: [Intel IOMMU][patch 8/8] Preserve some Virtual Address when devices cannot address entire range.
In reply to Ashok RajQuoted 4 lines · On Tuesday 24 April 2007 08:03:07 Ashok Raj wrote:
Some devices may not support entire 64bit DMA. In a situation where such devices are co-located in a shared domain, we need to ensure there is some address space reserved for such devices without the low addresses getting depleted by other devices capable of handling high dma addresses.
Sorry, but you need to find some way to make this usually work without special options. Otherwise users will be unhappy.
An possible way would be to allocate space upside down from the limit of the device. Then the lower areas should be usually free.
-Andi
Re: [Intel IOMMU][patch 1/8] ACPI support for Intel Virtualization Technology for Directed I/O
In reply to Andi KleenQuoted 8 lines · Andi Kleen
drivers/pci/dmar.c line 34
Quoted 4 lines
drivers/pci/dmar.c new file +3
-0+ +LIST_HEAD (dmar_drhd_units); +LIST_HEAD (dmar_rmrr_units);Comment describing what lock protects those lists? In fact there seems to be no locking. What about hotplug?
There is no support to handle an IOMMU hotplug at this time. IOMMU hotplug requires additional support via ACPI that needs to be extended to handle this.
These definitions are scanned at boot time from BIOS tables. They are pretty much static data that we process during boot. Hence no locking is required. We pretty much tread this as read only, and the information never gets changed after initial parsing.
Re: [Intel IOMMU][patch 7/8] Support for legacy ISA devices
In reply to Andi KleenQuoted 5 lines · Andi Kleen
Quoted 1 line · On Tuesday 24 April 2007 08:03:06 Ashok Raj wrote:
Floppy disk drivers dont work well with DMA remapping.
What is the problem? You can't allocate mappings <16MB?
floppy doesn't use the DMA mapping API :)
that's the problem
Re: [Intel IOMMU][patch 8/8] Preserve some Virtual Address when devices cannot address entire range.
In reply to Andi KleenQuoted 6 lines · Andi Kleen
Quoted 4 lines · On Tuesday 24 April 2007 08:03:07 Ashok Raj wrote:
Some devices may not support entire 64bit DMA. In a situation where such devices are co-located in a shared domain, we need to ensure there is some address space reserved for such devices without the low addresses getting depleted by other devices capable of handling high dma addresses.
Quoted 6 lines
Sorry, but you need to find some way to make this usually work without special options. Otherwise users will be unhappy.
An possible way would be to allocate space upside down from the limit of the device. Then the lower areas should be usually free.
With PCIE there is some benefit to keep dma addr low for performance reasons,
since it will use 32bit Transaction level packets instead of 64bit.
This reservation is only required if we have some legacy device under a p2p where its required to share its addr space with other devices. We could implement a default when one is not specified to keep things simple.
Re: [Intel IOMMU][patch 7/8] Support for legacy ISA devices
In reply to Andi KleenQuoted 4 lines · Andi Kleen
Quoted 1 line · On Tuesday 24 April 2007 08:03:06 Ashok Raj wrote:
Floppy disk drivers dont work well with DMA remapping.
What is the problem? You can't allocate mappings <16MB?
No.. these drivers dont call DMA mapping api's.. thats the problem.
Quoted 11 lines
Quoted 6 lines
Its possible to
extend the current use forx86_64, but the gain is very little. If someone feels compelled to clean this up, its up for grabs. Since these use 16M, we just provide a unity map for the ISA bridge device.While it's probably not worth for the floppy there are other devices with similar weird addressing limitations. Some generic handling of it would be nice.
In the intro we had outlined a way to handle this via a generic unity map for all devices, we could do that, i.e
- implement a generic 1-1 map if the device is not calling dma api's and dynamically dissociate it if the device does start using dma apis.
For some of the addr reservation as well, we could use set_dma_mask() to ensure there is some dma space. Problem is some drivers may not use dma apis. Also it might be difficult to address device hotplugged that has a weird requirement.
Re: [Intel IOMMU][patch 4/8] Supporting Zero Length Reads in Intel IOMMU.
In reply to Andi KleenQuoted 11 lines · Andi Kleen
Quoted 8 lines · On Tuesday 24 April 2007 08:03:03 Ashok Raj wrote:
PCI specs permit zero length reads (ZLR) even if the mapping for that region is write only. Support for this feature is indicated by the presence of a bit in the DMAR capability. If a particular DMAR does not support this capability we map write-only regions as read-write.
This option can also provides a workaround for some drivers that request a write-only mapping when they really should request a read-write. (We ran into one such case in
eepro100.cin handlingrx_ring_dma)Better just fix the drivers instead of adding such hacks
Some of the early DMAR's dont handle zero-length-reads as required. hardware that supports it correctly will advertise via its capabilities.
We could remove the cmdline option since it should not be really required.
Re: [Intel IOMMU][patch 4/8] Supporting Zero Length Reads in Intel IOMMU.
In reply to Andi KleenFrom: Andi Kleen <[email protected]>
Date: Tue, 24 Apr 2007 21:28:11 +0200
Quoted 11 lines · On Tuesday 24 April 2007 08:03:03 Ashok Raj wrote:
Quoted 8 lines
PCI specs permit zero length reads (ZLR) even if the mapping for that region is write only. Support for this feature is indicated by the presence of a bit in the DMAR capability. If a particular DMAR does not support this capability we map write-only regions as read-write.
This option can also provides a workaround for some drivers that request a write-only mapping when they really should request a read-write. (We ran into one such case in
eepro100.cin handlingrx_ring_dma)Better just fix the drivers instead of adding such hacks
I totally agree.
It is a feature when we have a device which can enforce such permissions correctly and thus trap such bad uses. If you paper around it, these things will never get fixed.
Re: [Intel IOMMU][patch 3/8] Generic hardware support for Intel IOMMU.
In reply to Andi KleenQuoted 8 lines · Andi Kleen
arch/x86_64/kernel/io_apic.c void arch_teardown_msi_irq(unsigned int · line 2008
Quoted 4 lines · On Tuesday 24 April 2007 08:03:02 Ashok Raj wrote:
arch/x86_64/kernel/io_apic.c +3
-0+#ifdef CONFIG_DMAR +#ifdef CONFIG_SMP +static void dmar_msi_set_affinity (unsigned int irq,cpumask_t mask)Why does it need an own interrupt type?
Problem is its MSI type interrupt, but we cannot use pci_dev since its not a PCI device, hence requires its own way of setup etc.
Quoted 12 lines
drivers/pci/Kconfig config HT_IRQ · line 70
Quoted 9 lines
drivers/pci/Kconfig +8
-0+ +config IOVA_GUARD_PAGE + bool "Enables gaurd page when allocating IO Virtual Address for IOMMU" + depends on DMAR + +config IOVA_NEXT_CONTIG + bool "Keeps IOVA allocations consequent between allocations" + depends on DMAR && EXPERIMENTALNeeds reference to Intel and better description
Quoted 7 lines
The file should have a high level description what it is good for etc.
Need high level overview over what locks protects what and if there is a locking order.
It doesn't seem to enable sg merging? Since you have enough space that should work.
Most of the IOVA stuff is really generic, and could be used outside of the Intel code with probably some rework. Since today only DMAR requires it we have depends on DMAR, but we could make it more generic and let the IOMMU driver just turn it on as required.
Quoted 15 lines
Quoted 15 lines
drivers/pci/intel-iommu.c new file +14
-0+static char *fault_reason_strings[] = +{ +"Software" , +"Present bit in root entry is clear" , +"Present bit in context entry is clear" , +"Invalid context entry" , +"Access beyond MGAW" , +"PTE Write access is not set" , +"PTE Read access is not set" , +"Next page table ptr is invalid" , +"Root table address invalid" , +"Context table ptr is invalid" , +"non-zero reserved fields in RTP" , +"non-zero reserved fields in CTP" ,
Quoted 8 lines
drivers/pci/intel-iommu.c line 66
Quoted 5 lines
drivers/pci/intel-iommu.c new file +5
-0+"non-zero reserved fields in PTE" , + "Unknown" +}; + +#define MAX_FAULT_REASON_IDX (12)You got 14 of them. better use
ARRAY_SIZE
Its the last index(zero based) of the useful entry returned by the fault record.
Only used to find out if index from fault record is out of bounds.
We will work on the remaining comments and repost.
Re: [Intel IOMMU][patch 8/8] Preserve some Virtual Address when devices cannot address entire range.
In reply to Ashok RajQuoted 6 lines · On Tuesday 24 April 2007 22:33:04 Ashok Raj wrote:
With PCIE there is some benefit to keep dma addr low for performance reasons,
since it will use 32bit Transaction level packets instead of 64bit.This reservation is only required if we have some legacy device under a p2p where its required to share its addr space with other devices. We could implement a default when one is not specified to keep things simple.
We already have a couple of other IOMMU architectures who essentially have the same problem. Have you checked how they solve this?
-Andi
Re: [Intel IOMMU][patch 8/8] Preserve some Virtual Address when devices cannot address entire range.
From: Andi Kleen <[email protected]>
Date: Tue, 24 Apr 2007 23:12:54 +0200
Quoted 2 lines
We already have a couple of other IOMMU architectures who essentially have the same problem. Have you checked how they solve this?
Sparc64, for one, only uses 32-bit IOMMU addresses. And we simply don't try to handle the funny devices at all, in fact we can't handle the ones that want mappings only in the low 16MB for example since the hardware IOMMU window usually starts in the middle of the 32-bit PCI address space.
We do it both because that's faster due to Single Address Cycles, as mentioned, and also because that's simply is where the hardware's IOMMU window is. You can't use 64-bit IOMMU addresses even if you wanted to on sparc64.
My suggestion would be to allocate top-down in the 32-bit IOMMU space.
That might work, but my gut feeling is that this won't be sufficient and we'll need some kind of device driver initiated reservation mechanism for the <16MB et al. weird stuff.
Re: [Intel IOMMU][patch 8/8] Preserve some Virtual Address when devices cannot address entire range.
Quoted 1 line
My suggestion would be to allocate top-down in the 32-bit IOMMU space.
I think that's good for normal things, but it's not unreasonable to want to map > 4 GB of memory at once for an Infiniband device.
So maybe we would want some heuristics about the size of the mapping being requested or the amount of 32-bit space left to decide whether a mapping should be below 4 GB.
- R.
Re: [Intel IOMMU][patch 8/8] Preserve some Virtual Address when devices cannot address entire range.
In reply to David MillerQuoted 17 lines · David Miller
From: Andi Kleen <[email protected]>
Date: Tue, 24 Apr 2007 23:12:54 +0200Quoted 2 lines
We already have a couple of other IOMMU architectures who essentially have the same problem. Have you checked how they solve this?
Sparc64, for one, only uses 32-bit IOMMU addresses. And we simply don't try to handle the funny devices at all, in fact we can't handle the ones that want mappings only in the low 16MB for example since the hardware IOMMU window usually starts in the middle of the 32-bit PCI address space.
We do it both because that's faster due to Single Address Cycles, as mentioned, and also because that's simply is where the hardware's IOMMU window is. You can't use 64-bit IOMMU addresses even if you wanted to on sparc64.
Quoted 5 lines
My suggestion would be to allocate top-down in the 32-bit IOMMU space.
That might work, but my gut feeling is that this won't be sufficient and we'll need some kind of device driver initiated reservation mechanism for the <16MB et al. weird stuff.
Its not clear if we have a very generic device breakage.. most devices on these platforms are going to be more recent, (except maybe some legacy fd)...
Maybe we should wait to fix unless we are certain if there are more of them that breaks in these platforms.
We could choose to use the generic 1-1 for those weird cases, since the driver does ensure today that physical mem is low 16M, then we could just turn on 1-1 domain for such devices without breaking any.
Re: [Intel IOMMU][patch 8/8] Preserve some Virtual Address when devices cannot address entire range.
In reply to Roland DreierFrom: Roland Dreier <[email protected]>
Date: Tue, 24 Apr 2007 14:32:42 -0700
Quoted 4 lines
Quoted 1 line
My suggestion would be to allocate top-down in the 32-bit IOMMU space.
I think that's good for normal things, but it's not unreasonable to want to map > 4 GB of memory at once for an Infiniband device.
That's what the DAC interfaces were for, but people wanted to remoe that since no in-tree users existed.
Devices like that want to essentially map the entire address space, via pass-thru, not IOMMU mappings.
Clustering cards, such as those made by Dolphin, are another example.
I realize that this doesn't work when we absolutely must use an IOMMU such as for virtualization which is the whole impetus of the Intel IOMMU. :-)
Quoted 3 lines
So maybe we would want some heuristics about the size of the mapping being requested or the amount of 32-bit space left to decide whether a mapping should be below 4 GB.
Perhaps, but as I said heuristics might not be enough here.
Re: [Intel IOMMU][patch 8/8] Preserve some Virtual Address when devices cannot address entire range.
In reply to Ashok RajFrom: Ashok Raj <[email protected]>
Date: Tue, 24 Apr 2007 14:38:35 -0700
Quoted 3 lines
Its not clear if we have a very generic device breakage.. most devices on these platforms are going to be more recent, (except maybe some legacy fd)...
I'm not so sure, there are some "modern" sound cards that have a 31-bit DMA addressing limitation because they use the 31st bit as a status bit in their DMA descriptors :-)
Re: [Intel IOMMU][patch 8/8] Preserve some Virtual Address when devices cannot address entire range.
Quoted 10 lines · On Tuesday 24 April 2007 23:50:26 David Miller wrote:
From: Ashok Raj <[email protected]>
Date: Tue, 24 Apr 2007 14:38:35 -0700Quoted 3 lines
Its not clear if we have a very generic device breakage.. most devices on these platforms are going to be more recent, (except maybe some legacy fd)...
I'm not so sure, there are some "modern" sound cards that have a 31-bit DMA addressing limitation because they use the 31st bit as a status bit in their DMA descriptors :-)
There's also a 2GB only megaraid RAID controller that's pretty popular because Dell shipped it for a long time.
-Andi
Re: [Intel IOMMU][patch 8/8] Preserve some Virtual Address when devices cannot address entire range.
Quoted 8 lines · Andi Kleen
Quoted 7 lines · On Tuesday 24 April 2007 23:50:26 David Miller wrote:
From: Ashok Raj <[email protected]>
Date: Tue, 24 Apr 2007 14:38:35 -0700Quoted 3 lines
Its not clear if we have a very generic device breakage.. most devices on these platforms are going to be more recent, (except maybe some legacy fd)...
Quoted 6 lines
Quoted 3 lines
I'm not so sure, there are some "modern" sound cards that have a 31-bit DMA addressing limitation because they use the 31st bit as a status bit in their DMA descriptors :-)
There's also a 2GB only megaraid RAID controller that's pretty popular because Dell shipped it for a long time.
Sounds like we have quite a few of those weird ones!
The real question is whats the working set for mapped dma handles for such a controller. They would typically allocate only a few to what the controller could handle, and would submit when the io completes right.. So typically we shouldnt have any trouble since they would be able to reclaim what they freed before submission (for iova).
Having a IOVA requirement in 2g etc is not a problem, except how many devices on the same pci bus and what the total working set for iova is for that config.
The only way to gaurantee would be for the device to ask for a gauranteed set maybe during pci_set_dma_mask() or some such time, and pre-reserve some IOVA to gaurantee we never run out. BUt this is again driver changes and wont be fair if some driver is greedy.
Re: [Intel IOMMU][patch 8/8] Preserve some Virtual Address when devices cannot address entire range.
In reply to David MillerQuoted 10 lines · On Tue, 24 Apr 2007 14:50:26 -0700 (PDT) David Miller <[email protected]>…
From: Ashok Raj <[email protected]>
Date: Tue, 24 Apr 2007 14:38:35 -0700Quoted 3 lines
Its not clear if we have a very generic device breakage.. most devices on these platforms are going to be more recent, (except maybe some legacy fd)...
I'm not so sure, there are some "modern" sound cards that have a 31-bit DMA addressing limitation because they use the 31st bit as a status bit in their DMA descriptors :-)
The sound stuff is going away bit by bit thankfully, but the 30bit DMA limit is present on some more demented wireless chips still.
Alan
Re: [Intel IOMMU][patch 8/8] Preserve some Virtual Address when devices cannot address entire range.
In reply to Andi KleenQuoted 4 lines · Andi Kleen
Quoted 3 lines · On Tuesday 24 April 2007 23:50:26 David Miller wrote:
From: Ashok Raj <[email protected]>
Date: Tue, 24 Apr 2007 14:38:35 -0700
Quoted 9 lines
Quoted 6 lines
Quoted 3 lines
Its not clear if we have a very generic device breakage.. most devices on these platforms are going to be more recent, (except maybe some legacy fd)...
I'm not so sure, there are some "modern" sound cards that have a 31-bit DMA addressing limitation because they use the 31st bit as a status bit in their DMA descriptors :-)
There's also a 2GB only megaraid RAID controller that's pretty popular because Dell shipped it for a long time.
You can probably find almost any possible bitmask if you look long enough. Hardware vendors are notorious for this kind of "optimizations".
-hpa
Re: [Intel IOMMU][patch 3/8] Generic hardware support for Intel IOMMU.
In reply to Andi KleenQuoted 20 lines · Andi Kleen
arch/x86_64/kernel/io_apic.c void arch_teardown_msi_irq(unsigned int · line 2008
Quoted 4 lines · On Tuesday 24 April 2007 08:03:02 Ashok Raj wrote:
arch/x86_64/kernel/io_apic.c +3
-0+#ifdef CONFIG_DMAR +#ifdef CONFIG_SMP +static void dmar_msi_set_affinity (unsigned int irq,cpumask_t mask)Why does it need an own interrupt type?
drivers/pci/Kconfig config HT_IRQ · line 70
Quoted 8 lines
drivers/pci/Kconfig +8
-0+ +config IOVA_GUARD_PAGE + bool "Enables gaurd page when allocating IO Virtual Address for IOMMU" + depends on DMAR + +config IOVA_NEXT_CONTIG + bool "Keeps IOVA allocations consequent between allocations" + depends on DMAR && EXPERIMENTALNeeds reference to Intel and better description
Quoted 7 lines
The file should have a high level description what it is good for etc.
Need high level overview over what locks protects what and if there is a locking order.
It doesn't seem to enable sg merging? Since you have enough space that should work.
We actually have a patch to do sg merge. In my test, it doesn't have any performance gain.
Quoted 39 lines
Quoted 9 lines
drivers/pci/intel-iommu.c new file +9
-0+static char *fault_reason_strings[] = +{ +"Software" , +"Present bit in root entry is clear" , +"Present bit in context entry is clear" , +"Invalid context entry" , +"Access beyond MGAW" , +"PTE Write access is not set" , +"PTE Read access is not set" ,drivers/pci/intel-iommu.c line 66
Quoted 10 lines
drivers/pci/intel-iommu.c new file +10
-0+"Next page table ptr is invalid" , +"Root table address invalid" , +"Context table ptr is invalid" , +"non-zero reserved fields in RTP" , +"non-zero reserved fields in CTP" , +"non-zero reserved fields in PTE" , + "Unknown" +}; + +#define MAX_FAULT_REASON_IDX (12)You got 14 of them. better use
ARRAY_SIZEdrivers/pci/intel-iommu.c line 69
Quoted 3 lines
drivers/pci/intel-iommu.c new file +3
-0+#define IOMMU_NAME_LEN (7) + +struct iommu {call it
intel_iommuor somesuch even when it's private.Quoted 10 lines
drivers/pci/intel-iommu.c new file +10
-0+static int __init intel_iommu_setup (char *str) +{ +if (!str) +return -EINVAL ; +while (*str) { +if (!strncmp (str,"off" ,3 )) { + dmar_disabled =1 ; +printk (KERN_INFO "Intel-IOMMU: disabled\n" ); + } + str +=strcspn (str,"," );
Quoted 8 lines
drivers/pci/intel-iommu.c line 112
Quoted 6 lines
drivers/pci/intel-iommu.c new file +6
-0+while (*str ==',' ) + str++; + } +return 0 ; +} +__setup ("intel_iommu=" , intel_iommu_setup);Why can't you just use the normal iommu=off for this?
iommu=off disable all iommu, intel_iommu=off just disables intel_iommu. Isn't possible people want to use other iommu like swiotlb?
Quoted 46 lines
drivers/pci/intel-iommu.c line 119
Quoted 7 lines
drivers/pci/intel-iommu.c new file +7
-0+ +#define MIN_PGTABLE_PAGES (10) +static mempool_t *pgtable_mempool; +#define MIN_DOMAIN_REQ (20) +static mempool_t *domain_mempool; +#define MIN_DEVINFO_REQ (20) +static mempool_t *devinfo_mempool;Lots of mempools. How much memory does this pin?
drivers/pci/intel-iommu.c line 126
Quoted 7 lines
drivers/pci/intel-iommu.c new file +7
-0+ +#define alloc_pgtable_page () mempool_alloc(pgtable_mempool, GFP_ATOMIC) +#define free_pgtable_page (vaddr) mempool_free(vaddr, pgtable_mempool) +#define alloc_domain_mem () mempool_alloc(domain_mempool, GFP_ATOMIC) +#define free_domain_mem (vaddr) mempool_free(vaddr, domain_mempool) +#define alloc_devinfo_mem () mempool_alloc(devinfo_mempool, GFP_ATOMIC) +#define free_devinfo_mem (vaddr) mempool_free(vaddr, devinfo_mempool)Do we need the macros? Better expand them in the caller.
drivers/pci/intel-iommu.c line 137
Quoted 10 lines
drivers/pci/intel-iommu.c new file +10
-0+static void __iommu_flush_cache (struct iommu *iommu,void *addr,int size) +{ +if (!ecap_coherent (iommu->ecap)) +clflush_cache_range (addr, size); +} + +#define iommu_flush_cache_entry (iommu, addr) \ + __iommu_flush_cache(iommu, addr, 8) +#define iommu_flush_cache_page (iommu, addr) \ + __iommu_flush_cache(iommu, addr, PAGE_SIZE_4K)Similar.
And the 8 should be probably something more descriptive (sizeof?)
Quoted 11 lines
drivers/pci/intel-iommu.c new file +11
-0+/* context entry handling */ +static struct context_entry *device_to_context_entry (struct iommu *iommu, +u8 bus,u8 devfn) +{ +struct root_entry *root; +struct context_entry *context; +unsigned long phy_addr; +unsigned long flags; + +spin_lock_irqsave (&iommu->lock, flags); + root = &iommu->root_entry[bus];
Quoted 8 lines
drivers/pci/intel-iommu.c line 151
Quoted 2 lines
drivers/pci/intel-iommu.c new file +2
-0+if (!root_present (*root)) { + phy_addr = (unsigned long )alloc_pgtable_page ();A
GFP_ATOMICmempool is rather useless. mempool only works if it can block for someone else freeing memory and if it can't do that it's not failsafe. I'm afraid you need to revise the allocation strategy -- best would be to somehow move the memory allocations outside the spinlock paths and preallocate if possible.
The problem is pci_map_single and friends usually called with interrupt disabled or spin locked, so we must use GFP_ATOMIC.
Quoted 9 lines
Same problem in other code.
drivers/pci/intel-iommu.c line 269
Quoted 2 lines
drivers/pci/intel-iommu.c new file +2
-0+if (!dma_pte_present (*pte)) { + tmp =alloc_pgtable_page ();Please don't name variable tmp. I know some other code does it, but it's just bad style imho.
Quoted 12 lines
drivers/pci/intel-iommu.c line 431
Quoted 10 lines
drivers/pci/intel-iommu.c new file +10
-0+/* Make sure hardware complete it */ + start_time = jiffies; +while (1 ) { + sts =dmar_readl (iommu->reg,DMAR_GSTS_REG ); +if (sts &DMA_GSTS_RTPS ) +break ; +if (time_after (jiffies, start_time +DMAR_OPERATION_TIMEOUT )) +panic ("DMAR hardware is malfunctional, please disable IOMMU\n" ); +cpu_relax (); + }Could MWAIT/MONITOR be used for this?
MWAIT/MONITOR just works for cached memory. And this is memory mapped io.
Thanks,
Shaohua
Re: [Intel IOMMU][patch 3/8] Generic hardware support for Intel IOMMU.
On Wednesday 25 A
Quoted 4 lines
Quoted 2 lines
It doesn't seem to enable sg merging? Since you have enough space that should work.
We actually have a patch to do sg merge. In my test, it doesn't have any performance gain.
It probably depends on the IO device and how slow or fast it is at walking sg lists. I saw a small win (few percent gain) some years ago with MPT Fusion chips
Quoted 7 lines
Quoted 5 lines
A
GFP_ATOMICmempool is rather useless. mempool only works if it can block for someone else freeing memory and if it can't do that it's not failsafe. I'm afraid you need to revise the allocation strategy -- best would be to somehow move the memory allocations outside the spinlock paths and preallocate if possible.The problem is
pci_map_singleand friends usually called with interrupt disabled or spin locked, so we must useGFP_ATOMIC.
Yes I know, but the mempool still won't work. The design is b0rken.
-Andi
Re: [Intel IOMMU][patch 8/8] Preserve some Virtual Address when devices cannot address entire range.
In reply to H. Peter AnvinQuoted 2 lines · On Wednesday 25 April 2007 03:12:51 H. Peter Anvin wrote:
You can probably find almost any possible bitmask if you look long enough. Hardware vendors are notorious for this kind of "optimizations".
The nice thing is if this was solved in the IOMMU code then we could drop (or not initialize) GFP_DMA on systems with that hardware. I guess GFP_DMA32 would still need to stay for the graphics devices though.
Not sure how much difference it would make though, but at least Christoph Lameter seems to think it would.
-Andi