Loading arch/x86/include/asm/amd_iommu.h +1 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #ifdef CONFIG_AMD_IOMMU extern int amd_iommu_init(void); extern int amd_iommu_init_dma_ops(void); extern int amd_iommu_init_passthrough(void); extern void amd_iommu_detect(void); extern irqreturn_t amd_iommu_int_handler(int irq, void *data); extern void amd_iommu_flush_all_domains(void); Loading arch/x86/include/asm/amd_iommu_types.h +4 −0 Original line number Diff line number Diff line Loading @@ -143,6 +143,7 @@ #define EVT_BUFFER_SIZE 8192 /* 512 entries */ #define EVT_LEN_MASK (0x9ULL << 56) #define PAGE_MODE_NONE 0x00 #define PAGE_MODE_1_LEVEL 0x01 #define PAGE_MODE_2_LEVEL 0x02 #define PAGE_MODE_3_LEVEL 0x03 Loading Loading @@ -194,6 +195,9 @@ #define PD_DMA_OPS_MASK (1UL << 0) /* domain used for dma_ops */ #define PD_DEFAULT_MASK (1UL << 1) /* domain is a default dma_ops domain for an IOMMU */ #define PD_PASSTHROUGH_MASK (1UL << 2) /* domain has no page translation */ extern bool amd_iommu_dump; #define DUMP_printk(format, arg...) \ do { \ Loading arch/x86/kernel/amd_iommu.c +123 −18 Original line number Diff line number Diff line Loading @@ -41,6 +41,13 @@ static DEFINE_RWLOCK(amd_iommu_devtable_lock); static LIST_HEAD(iommu_pd_list); static DEFINE_SPINLOCK(iommu_pd_list_lock); /* * Domain for untranslated devices - only allocated * if iommu=pt passed on kernel cmd line. */ static struct protection_domain *pt_domain; #ifdef CONFIG_IOMMU_API static struct iommu_ops amd_iommu_ops; /* Loading Loading @@ -1130,25 +1137,41 @@ static struct protection_domain *domain_for_device(u16 devid) * If a device is not yet associated with a domain, this function does * assigns it visible for the hardware */ static void attach_device(struct amd_iommu *iommu, static void __attach_device(struct amd_iommu *iommu, struct protection_domain *domain, u16 devid) { unsigned long flags; u64 pte_root = virt_to_phys(domain->pt_root); u64 pte_root; domain->dev_cnt += 1; /* lock domain */ spin_lock(&domain->lock); pte_root = virt_to_phys(domain->pt_root); pte_root |= (domain->mode & DEV_ENTRY_MODE_MASK) << DEV_ENTRY_MODE_SHIFT; pte_root |= IOMMU_PTE_IR | IOMMU_PTE_IW | IOMMU_PTE_P | IOMMU_PTE_TV; write_lock_irqsave(&amd_iommu_devtable_lock, flags); amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root); amd_iommu_dev_table[devid].data[1] = upper_32_bits(pte_root); amd_iommu_dev_table[devid].data[2] = domain->id; amd_iommu_dev_table[devid].data[1] = upper_32_bits(pte_root); amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root); amd_iommu_pd_table[devid] = domain; domain->dev_cnt += 1; /* ready */ spin_unlock(&domain->lock); } static void attach_device(struct amd_iommu *iommu, struct protection_domain *domain, u16 devid) { unsigned long flags; write_lock_irqsave(&amd_iommu_devtable_lock, flags); __attach_device(iommu, domain, devid); write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); /* Loading Loading @@ -1182,6 +1205,15 @@ static void __detach_device(struct protection_domain *domain, u16 devid) /* ready */ spin_unlock(&domain->lock); /* * If we run in passthrough mode the device must be assigned to the * passthrough domain if it is detached from any other domain */ if (iommu_pass_through) { struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; __attach_device(iommu, pt_domain, devid); } } /* Loading Loading @@ -1227,6 +1259,8 @@ static int device_change_notifier(struct notifier_block *nb, case BUS_NOTIFY_UNBOUND_DRIVER: if (!domain) goto out; if (iommu_pass_through) break; detach_device(domain, devid); break; case BUS_NOTIFY_ADD_DEVICE: Loading Loading @@ -2051,19 +2085,47 @@ static void cleanup_domain(struct protection_domain *domain) write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); } static int amd_iommu_domain_init(struct iommu_domain *dom) static void protection_domain_free(struct protection_domain *domain) { if (!domain) return; if (domain->id) domain_id_free(domain->id); kfree(domain); } static struct protection_domain *protection_domain_alloc(void) { struct protection_domain *domain; domain = kzalloc(sizeof(*domain), GFP_KERNEL); if (!domain) return -ENOMEM; return NULL; spin_lock_init(&domain->lock); domain->mode = PAGE_MODE_3_LEVEL; domain->id = domain_id_alloc(); if (!domain->id) goto out_err; return domain; out_err: kfree(domain); return NULL; } static int amd_iommu_domain_init(struct iommu_domain *dom) { struct protection_domain *domain; domain = protection_domain_alloc(); if (!domain) goto out_free; domain->mode = PAGE_MODE_3_LEVEL; domain->pt_root = (void *)get_zeroed_page(GFP_KERNEL); if (!domain->pt_root) goto out_free; Loading @@ -2073,7 +2135,7 @@ static int amd_iommu_domain_init(struct iommu_domain *dom) return 0; out_free: kfree(domain); protection_domain_free(domain); return -ENOMEM; } Loading Loading @@ -2254,3 +2316,46 @@ static struct iommu_ops amd_iommu_ops = { .domain_has_cap = amd_iommu_domain_has_cap, }; /***************************************************************************** * * The next functions do a basic initialization of IOMMU for pass through * mode * * In passthrough mode the IOMMU is initialized and enabled but not used for * DMA-API translation. * *****************************************************************************/ int __init amd_iommu_init_passthrough(void) { struct pci_dev *dev = NULL; u16 devid, devid2; /* allocate passthroug domain */ pt_domain = protection_domain_alloc(); if (!pt_domain) return -ENOMEM; pt_domain->mode |= PAGE_MODE_NONE; while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { struct amd_iommu *iommu; devid = calc_devid(dev->bus->number, dev->devfn); if (devid > amd_iommu_last_bdf) continue; devid2 = amd_iommu_alias_table[devid]; iommu = amd_iommu_rlookup_table[devid2]; if (!iommu) continue; __attach_device(iommu, pt_domain, devid); __attach_device(iommu, pt_domain, devid2); } pr_info("AMD-Vi: Initialized for Passthrough Mode\n"); return 0; } arch/x86/kernel/amd_iommu_init.c +7 −1 Original line number Diff line number Diff line Loading @@ -1252,12 +1252,18 @@ int __init amd_iommu_init(void) if (ret) goto free; if (iommu_pass_through) ret = amd_iommu_init_passthrough(); else ret = amd_iommu_init_dma_ops(); if (ret) goto free; enable_iommus(); if (iommu_pass_through) goto out; printk(KERN_INFO "AMD-Vi: device isolation "); if (amd_iommu_isolate) printk("enabled\n"); Loading arch/x86/kernel/pci-dma.c +8 −1 Original line number Diff line number Diff line Loading @@ -32,7 +32,14 @@ int no_iommu __read_mostly; /* Set this to 1 if there is a HW IOMMU in the system */ int iommu_detected __read_mostly = 0; int iommu_pass_through; /* * This variable becomes 1 if iommu=pt is passed on the kernel command line. * If this variable is 1, IOMMU implementations do no DMA ranslation for * devices and allow every device to access to whole physical memory. This is * useful if a user want to use an IOMMU only for KVM device assignment to * guests and not for driver dma translation. */ int iommu_pass_through __read_mostly; dma_addr_t bad_dma_address __read_mostly = 0; EXPORT_SYMBOL(bad_dma_address); Loading Loading
arch/x86/include/asm/amd_iommu.h +1 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #ifdef CONFIG_AMD_IOMMU extern int amd_iommu_init(void); extern int amd_iommu_init_dma_ops(void); extern int amd_iommu_init_passthrough(void); extern void amd_iommu_detect(void); extern irqreturn_t amd_iommu_int_handler(int irq, void *data); extern void amd_iommu_flush_all_domains(void); Loading
arch/x86/include/asm/amd_iommu_types.h +4 −0 Original line number Diff line number Diff line Loading @@ -143,6 +143,7 @@ #define EVT_BUFFER_SIZE 8192 /* 512 entries */ #define EVT_LEN_MASK (0x9ULL << 56) #define PAGE_MODE_NONE 0x00 #define PAGE_MODE_1_LEVEL 0x01 #define PAGE_MODE_2_LEVEL 0x02 #define PAGE_MODE_3_LEVEL 0x03 Loading Loading @@ -194,6 +195,9 @@ #define PD_DMA_OPS_MASK (1UL << 0) /* domain used for dma_ops */ #define PD_DEFAULT_MASK (1UL << 1) /* domain is a default dma_ops domain for an IOMMU */ #define PD_PASSTHROUGH_MASK (1UL << 2) /* domain has no page translation */ extern bool amd_iommu_dump; #define DUMP_printk(format, arg...) \ do { \ Loading
arch/x86/kernel/amd_iommu.c +123 −18 Original line number Diff line number Diff line Loading @@ -41,6 +41,13 @@ static DEFINE_RWLOCK(amd_iommu_devtable_lock); static LIST_HEAD(iommu_pd_list); static DEFINE_SPINLOCK(iommu_pd_list_lock); /* * Domain for untranslated devices - only allocated * if iommu=pt passed on kernel cmd line. */ static struct protection_domain *pt_domain; #ifdef CONFIG_IOMMU_API static struct iommu_ops amd_iommu_ops; /* Loading Loading @@ -1130,25 +1137,41 @@ static struct protection_domain *domain_for_device(u16 devid) * If a device is not yet associated with a domain, this function does * assigns it visible for the hardware */ static void attach_device(struct amd_iommu *iommu, static void __attach_device(struct amd_iommu *iommu, struct protection_domain *domain, u16 devid) { unsigned long flags; u64 pte_root = virt_to_phys(domain->pt_root); u64 pte_root; domain->dev_cnt += 1; /* lock domain */ spin_lock(&domain->lock); pte_root = virt_to_phys(domain->pt_root); pte_root |= (domain->mode & DEV_ENTRY_MODE_MASK) << DEV_ENTRY_MODE_SHIFT; pte_root |= IOMMU_PTE_IR | IOMMU_PTE_IW | IOMMU_PTE_P | IOMMU_PTE_TV; write_lock_irqsave(&amd_iommu_devtable_lock, flags); amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root); amd_iommu_dev_table[devid].data[1] = upper_32_bits(pte_root); amd_iommu_dev_table[devid].data[2] = domain->id; amd_iommu_dev_table[devid].data[1] = upper_32_bits(pte_root); amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root); amd_iommu_pd_table[devid] = domain; domain->dev_cnt += 1; /* ready */ spin_unlock(&domain->lock); } static void attach_device(struct amd_iommu *iommu, struct protection_domain *domain, u16 devid) { unsigned long flags; write_lock_irqsave(&amd_iommu_devtable_lock, flags); __attach_device(iommu, domain, devid); write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); /* Loading Loading @@ -1182,6 +1205,15 @@ static void __detach_device(struct protection_domain *domain, u16 devid) /* ready */ spin_unlock(&domain->lock); /* * If we run in passthrough mode the device must be assigned to the * passthrough domain if it is detached from any other domain */ if (iommu_pass_through) { struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; __attach_device(iommu, pt_domain, devid); } } /* Loading Loading @@ -1227,6 +1259,8 @@ static int device_change_notifier(struct notifier_block *nb, case BUS_NOTIFY_UNBOUND_DRIVER: if (!domain) goto out; if (iommu_pass_through) break; detach_device(domain, devid); break; case BUS_NOTIFY_ADD_DEVICE: Loading Loading @@ -2051,19 +2085,47 @@ static void cleanup_domain(struct protection_domain *domain) write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); } static int amd_iommu_domain_init(struct iommu_domain *dom) static void protection_domain_free(struct protection_domain *domain) { if (!domain) return; if (domain->id) domain_id_free(domain->id); kfree(domain); } static struct protection_domain *protection_domain_alloc(void) { struct protection_domain *domain; domain = kzalloc(sizeof(*domain), GFP_KERNEL); if (!domain) return -ENOMEM; return NULL; spin_lock_init(&domain->lock); domain->mode = PAGE_MODE_3_LEVEL; domain->id = domain_id_alloc(); if (!domain->id) goto out_err; return domain; out_err: kfree(domain); return NULL; } static int amd_iommu_domain_init(struct iommu_domain *dom) { struct protection_domain *domain; domain = protection_domain_alloc(); if (!domain) goto out_free; domain->mode = PAGE_MODE_3_LEVEL; domain->pt_root = (void *)get_zeroed_page(GFP_KERNEL); if (!domain->pt_root) goto out_free; Loading @@ -2073,7 +2135,7 @@ static int amd_iommu_domain_init(struct iommu_domain *dom) return 0; out_free: kfree(domain); protection_domain_free(domain); return -ENOMEM; } Loading Loading @@ -2254,3 +2316,46 @@ static struct iommu_ops amd_iommu_ops = { .domain_has_cap = amd_iommu_domain_has_cap, }; /***************************************************************************** * * The next functions do a basic initialization of IOMMU for pass through * mode * * In passthrough mode the IOMMU is initialized and enabled but not used for * DMA-API translation. * *****************************************************************************/ int __init amd_iommu_init_passthrough(void) { struct pci_dev *dev = NULL; u16 devid, devid2; /* allocate passthroug domain */ pt_domain = protection_domain_alloc(); if (!pt_domain) return -ENOMEM; pt_domain->mode |= PAGE_MODE_NONE; while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { struct amd_iommu *iommu; devid = calc_devid(dev->bus->number, dev->devfn); if (devid > amd_iommu_last_bdf) continue; devid2 = amd_iommu_alias_table[devid]; iommu = amd_iommu_rlookup_table[devid2]; if (!iommu) continue; __attach_device(iommu, pt_domain, devid); __attach_device(iommu, pt_domain, devid2); } pr_info("AMD-Vi: Initialized for Passthrough Mode\n"); return 0; }
arch/x86/kernel/amd_iommu_init.c +7 −1 Original line number Diff line number Diff line Loading @@ -1252,12 +1252,18 @@ int __init amd_iommu_init(void) if (ret) goto free; if (iommu_pass_through) ret = amd_iommu_init_passthrough(); else ret = amd_iommu_init_dma_ops(); if (ret) goto free; enable_iommus(); if (iommu_pass_through) goto out; printk(KERN_INFO "AMD-Vi: device isolation "); if (amd_iommu_isolate) printk("enabled\n"); Loading
arch/x86/kernel/pci-dma.c +8 −1 Original line number Diff line number Diff line Loading @@ -32,7 +32,14 @@ int no_iommu __read_mostly; /* Set this to 1 if there is a HW IOMMU in the system */ int iommu_detected __read_mostly = 0; int iommu_pass_through; /* * This variable becomes 1 if iommu=pt is passed on the kernel command line. * If this variable is 1, IOMMU implementations do no DMA ranslation for * devices and allow every device to access to whole physical memory. This is * useful if a user want to use an IOMMU only for KVM device assignment to * guests and not for driver dma translation. */ int iommu_pass_through __read_mostly; dma_addr_t bad_dma_address __read_mostly = 0; EXPORT_SYMBOL(bad_dma_address); Loading