iommu/vt-d: Add support for DMA mapping of ACPI-enumerated devices
Subsystems (3)
cover iommu/vt-d: Add support for DMA mapping of ACPI-enumerated devices
Version 2.2 of the VT-d specification adds support for DMA mapping of ACPI devices, by adding fields to the DMAR table which indicate the ACPI path
of each DMA-capable device and the PCI bus/dev/fn from which its DMA will
*appear* to come.
The bulk of this patch series is going through the code and changing all
the hardcoded assumptions about 'struct pci_dev' to use 'struct device'
instead. The rest is fairly boring; just storing the bus/devfn in the scope arrays and using them accordingly.
I've pushed this out to git://git.infradead.org/iommu-2.6.git along with the previous 4-patch series to clean up and fix the page table unmapping.
A message that is not in the archive (sent off-list or not yet received): 1395422354-19762-1-git-send-email-David.Woodhouse-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org
PATCH 1/33 iommu/vt-d: Add ACPI namespace device reporting structures
--- include/acpi/actbl2.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
include/acpi/actbl2.h +13 -2
@@ -424,7 +424,8 @@ enum acpi_dmar_type {ACPI_DMAR_TYPE_RESERVED_MEMORY =1 ,ACPI_DMAR_TYPE_ATSR =2 ,ACPI_DMAR_HARDWARE_AFFINITY =3 , - ACPI_DMAR_TYPE_RESERVED = 4 /* 4 and greater are reserved */ +ACPI_DMAR_TYPE_ANDD =4 , + ACPI_DMAR_TYPE_RESERVED = 5 /* 5 and greater are reserved */ };/* DMAR Device Scope structure */
@@ -445,7 +446,8 @@ enum acpi_dmar_scope_type {ACPI_DMAR_SCOPE_TYPE_BRIDGE =2 ,ACPI_DMAR_SCOPE_TYPE_IOAPIC =3 ,ACPI_DMAR_SCOPE_TYPE_HPET =4 , -ACPI_DMAR_SCOPE_TYPE_RESERVED =5 /* 5 and greater are reserved */ +ACPI_DMAR_SCOPE_TYPE_ACPI =5 , +ACPI_DMAR_SCOPE_TYPE_RESERVED =6 /* 6 and greater are reserved */ }; struct acpi_dmar_pci_path {
@@ -507,6 +509,15 @@ struct acpi_dmar_rhsa {u32 proximity_domain; }; +/* 4: ACPI Namespace Device Declaration Structure */ + +struct acpi_dmar_andd { +struct acpi_dmar_header header; +u8 reserved[3 ]; +u8 device_number; +u8 object_name[]; +}; +/******************************************************************************* * * HPET - High Precision Event Timer table
Signature · 1 line
1.8.5.3
PATCH 2/33 iommu/vt-d: Parse ANDD records
In reply to a message not in the archive--- drivers/iommu/dmar.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
drivers/iommu/dmar.c +27 -0
@@ -373,6 +373,26 @@ static void dmar_free_drhd(struct dmar_drhd_unit *dmaru)kfree (dmaru); } +static int __init dmar_parse_one_andd (struct acpi_dmar_header *header) +{ +struct acpi_dmar_andd *andd = (void *)header; + +/* Check for NUL termination within the designated length */ +if (strnlen (andd->object_name, header->length -8 ) == header->length -8 ) { +WARN_TAINT (1 ,TAINT_FIRMWARE_WORKAROUND , +"Your BIOS is broken; ANDD object name is not NUL-terminated\n" +"BIOS vendor: %s; Ver: %s; Product Version: %s\n" , +dmi_get_system_info (DMI_BIOS_VENDOR ), +dmi_get_system_info (DMI_BIOS_VERSION ), +dmi_get_system_info (DMI_PRODUCT_VERSION )); +return -EINVAL ; + } +pr_info ("ANDD device: %x name: %s\n" , andd->device_number, + andd->object_name); + +return 0 ; +} +#ifdef CONFIG_ACPI_NUMA static int __init dmar_parse_one_rhsa (struct acpi_dmar_header *header)
@@ -436,6 +456,10 @@ dmar_table_print_dmar_entry(struct acpi_dmar_header *header) (unsigned long long )rhsa->base_address, rhsa->proximity_domain);break ; +case ACPI_DMAR_TYPE_ANDD : +/* We don't print this here because we need to sanity-check +it first. So print it in dmar_parse_one_andd() instead. */ +break ; } }
@@ -521,6 +545,9 @@ parse_dmar_table(void) ret =dmar_parse_one_rhsa (entry_header);#endif break ; +case ACPI_DMAR_TYPE_ANDD : + ret =dmar_parse_one_andd (entry_header); +break ;default :pr_warn ("Unknown DMAR structure type %d\n" , entry_header->type);
Signature · 1 line
1.8.5.3
PATCH 3/33 iommu/vt-d: Allocate space for ACPI devices
In reply to a message not in the archive--- drivers/iommu/dmar.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-)
drivers/iommu/dmar.c +10 -12
@@ -84,7 +84,8 @@ void *dmar_alloc_dev_scope(void *start, void *end, int *cnt) *cnt =0 ;while (start < end) { scope = start; -if (scope->entry_type ==ACPI_DMAR_SCOPE_TYPE_ENDPOINT || +if (scope->entry_type ==ACPI_DMAR_SCOPE_TYPE_ACPI || + scope->entry_type ==ACPI_DMAR_SCOPE_TYPE_ENDPOINT || scope->entry_type ==ACPI_DMAR_SCOPE_TYPE_BRIDGE ) (*cnt)++; else if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_IOAPIC &&
@@ -342,21 +343,18 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header) dmaru->reg_base_addr = drhd->address; dmaru->segment = drhd->segment; dmaru->include_all = drhd->flags &0x1 ;/* BIT0: INCLUDE_ALL */ -if (!dmaru->include_all) { - dmaru->devices =dmar_alloc_dev_scope ((void *)(drhd +1 ), - ((void *)drhd) + drhd->header.length, - &dmaru->devices_cnt); -if (dmaru->devices_cnt && dmaru->devices ==NULL ) { -kfree (dmaru); -return -ENOMEM ; - } + dmaru->devices =dmar_alloc_dev_scope ((void *)(drhd +1 ), + ((void *)drhd) + drhd->header.length, + &dmaru->devices_cnt); +if (dmaru->devices_cnt && dmaru->devices ==NULL ) { +kfree (dmaru); +return -ENOMEM ; } ret =alloc_iommu (dmaru);if (ret) { -if (!dmaru->include_all) -dmar_free_dev_scope (&dmaru->devices, - &dmaru->devices_cnt); +dmar_free_dev_scope (&dmaru->devices, + &dmaru->devices_cnt);kfree (dmaru);return ret; }
Signature · 1 line
1.8.5.3
PATCH 4/33 iommu/vt-d: Change scope lists to struct device, bus, devfn
In reply to a message not in the archiveIt's not only for PCI devices any more, and the scope information for an ACPI device provides the bus and devfn so that has to be stored here too.
--- drivers/iommu/dmar.c | 41 ++++++++++++++++++++++------------------- drivers/iommu/intel-iommu.c | 43 +++++++++++++++++++++++++------------------ include/linux/dmar.h | 18 ++++++++++++------ 3 files changed, 59 insertions(+), 43 deletions(-)
drivers/iommu/dmar.c +22 -19
@@ -97,17 +97,17 @@ void *dmar_alloc_dev_scope(void *start, void *end, int *cnt)if (*cnt ==0 )return NULL ; -return kcalloc (*cnt,sizeof (struct pci_dev *),GFP_KERNEL ); +return kcalloc (*cnt,sizeof (struct dmar_dev_scope ),GFP_KERNEL ); } -void dmar_free_dev_scope (struct pci_dev __rcu ***devices,int *cnt) +void dmar_free_dev_scope (struct dmar_dev_scope __rcu **devices,int *cnt) {int i; -struct pci_dev *tmp_dev; +struct device *tmp_dev;if (*devices && *cnt) {for_each_active_dev_scope (*devices, *cnt, i, tmp_dev) -pci_dev_put (tmp_dev); +put_device (tmp_dev);kfree (*devices); }
@@ -191,10 +191,11 @@ static bool dmar_match_pci_path(struct dmar_pci_notify_info *info, int bus,/* Return: > 0 if match found, 0 if no match found, < 0 if error happens */ int dmar_insert_dev_scope (struct dmar_pci_notify_info *info,void *start,void *end,u16 segment, -struct pci_dev __rcu **devices,int devices_cnt) +struct dmar_dev_scope __rcu *devices, +int devices_cnt) {int i, level; -struct pci_dev *tmp, *dev = info->dev; +struct device *tmp, *dev = &info->dev->dev;struct acpi_dmar_device_scope *scope;struct acpi_dmar_pci_path *path;
@@ -213,16 +214,18 @@ int dmar_insert_dev_scope(struct dmar_pci_notify_info *info,continue ;if ((scope->entry_type ==ACPI_DMAR_SCOPE_TYPE_ENDPOINT ) ^ - (dev->hdr_type ==PCI_HEADER_TYPE_NORMAL )) { + (info->dev->hdr_type ==PCI_HEADER_TYPE_NORMAL )) {pr_warn ("Device scope type does not match for %s\n" , -pci_name (dev)); +pci_name (info->dev));return -EINVAL ; }for_each_dev_scope (devices, devices_cnt, i, tmp)if (tmp ==NULL ) { -rcu_assign_pointer (devices[i], -pci_dev_get (dev)); + devices[i].bus = info->dev->bus->number; + devices[i].devfn = info->dev->devfn; +rcu_assign_pointer (devices[i].dev, +get_device (dev));return 1 ; }BUG_ON (i >= devices_cnt);
@@ -232,19 +235,19 @@ int dmar_insert_dev_scope(struct dmar_pci_notify_info *info, }int dmar_remove_dev_scope (struct dmar_pci_notify_info *info,u16 segment, -struct pci_dev __rcu **devices,int count) +struct dmar_dev_scope __rcu *devices,int count) {int index; -struct pci_dev *tmp; +struct device *tmp;if (info->seg != segment)return 0 ;for_each_active_dev_scope (devices, count, index, tmp) -if (tmp == info->dev) { -rcu_assign_pointer (devices[index],NULL ); +if (tmp == &info->dev->dev) { +rcu_assign_pointer (devices[index].dev,NULL );synchronize_rcu (); -pci_dev_put (tmp); +put_device (tmp);return 1 ; }
@@ -562,15 +565,15 @@ parse_dmar_table(void)return ret; } -static int dmar_pci_device_match (struct pci_dev __rcu *devices[],int cnt, -struct pci_dev *dev) +static int dmar_pci_device_match (struct dmar_dev_scope __rcu devices[], +int cnt,struct pci_dev *dev) {int index; -struct pci_dev *tmp; +struct device *tmp;while (dev) {for_each_active_dev_scope (devices, cnt, index, tmp) -if (dev == tmp) +if (dev_is_pci (tmp) && dev ==to_pci_dev (tmp))return 1 ;/* Check our parent */
drivers/iommu/intel-iommu.c +25 -18
128 lines not on this page · raw message
include/linux/dmar.h +12 -6
@@ -36,13 +36,19 @@ struct acpi_dmar_header;struct intel_iommu ; +struct dmar_dev_scope { +struct device *dev; +u8 bus; +u8 devfn; +}; + #ifdef CONFIG_DMAR_TABLE extern struct acpi_table_header *dmar_tbl; struct dmar_drhd_unit { struct list_head list; /* list of drhd units */ struct acpi_dmar_header *hdr; /* ACPI header */ u64 reg_base_addr; /* register base address*/ - struct pci_dev __rcu **devices;/* target device array */ + struct dmar_dev_scope __rcu *devices;/* target device array */ int devices_cnt; /* target device count */ u16 segment; /* PCI domain */ u8 ignored:1; /* ignore drhd */
@@ -86,7 +92,7 @@ static inline bool dmar_rcu_check(void)#define dmar_rcu_dereference (p) rcu_dereference_check((p), dmar_rcu_check())#define for_each_dev_scope (a, c, p, d) \ - for ((p) = 0; ((d) = (p) < (c) ? dmar_rcu_dereference((a)[(p)]) : \ + for ((p) = 0; ((d) = (p) < (c) ? dmar_rcu_dereference((a)[(p)].dev) : \ NULL, (p) < (c)); (p)++)#define for_each_active_dev_scope (a, c, p, d) \
@@ -95,15 +101,15 @@ static inline bool dmar_rcu_check(void)extern int dmar_table_init (void );extern int dmar_dev_scope_init (void );extern int dmar_parse_dev_scope (void *start,void *end,int *cnt, -struct pci_dev ***devices,u16 segment); +struct dmar_dev_scope **devices,u16 segment);extern void *dmar_alloc_dev_scope (void *start,void *end,int *cnt); -extern void dmar_free_dev_scope (struct pci_dev __rcu ***devices,int *cnt); +extern void dmar_free_dev_scope (struct dmar_dev_scope __rcu **devices,int *cnt);extern int dmar_insert_dev_scope (struct dmar_pci_notify_info *info,void *start,void *end,u16 segment, -struct pci_dev __rcu **devices, +struct dmar_dev_scope __rcu *devices,int devices_cnt);extern int dmar_remove_dev_scope (struct dmar_pci_notify_info *info, -u16 segment,struct pci_dev __rcu **devices, +u16 segment,struct dmar_dev_scope __rcu *devices,int count);/* Intel IOMMU detection */ extern int detect_intel_iommu (void );
Signature · 1 line
1.8.5.3
PATCH 5/33 iommu/vt-d: Add ACPI devices into dmaru->devices[] array
In reply to a message not in the archive--- drivers/iommu/dmar.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+)
drivers/iommu/dmar.c +75 -0
@@ -612,6 +612,79 @@ out:return dmaru; } +static void __init dmar_acpi_insert_dev_scope (u8 device_number, +struct acpi_device *adev) +{ +struct dmar_drhd_unit *dmaru; +struct acpi_dmar_hardware_unit *drhd; +struct acpi_dmar_device_scope *scope; +struct device *tmp; +int i; +struct acpi_dmar_pci_path *path; + +for_each_drhd_unit (dmaru) { + drhd =container_of (dmaru->hdr, + struct acpi_dmar_hardware_unit, + header); + +for (scope = (void *)(drhd +1 ); + (unsigned long )scope < ((unsigned long )drhd) + drhd->header.length; + scope = ((void *)scope) + scope->length) { +if (scope->entry_type !=ACPI_DMAR_SCOPE_TYPE_ACPI ) +continue ; +if (scope->enumeration_id != device_number) +continue ; + + path = (void *)(scope +1 ); +pr_info ("ACPI device \"%s\" under DMAR at %llx as %02x:%02x.%d\n" , +dev_name (&adev->dev), dmaru->reg_base_addr, + scope->bus, path->device, path->function); +for_each_dev_scope (dmaru->devices, dmaru->devices_cnt, i, tmp) +if (tmp ==NULL ) { + dmaru->devices[i].bus = scope->bus; + dmaru->devices[i].devfn =PCI_DEVFN (path->device, + path->function); +rcu_assign_pointer (dmaru->devices[i].dev, +get_device (&adev->dev)); +return ; + } +BUG_ON (i >= dmaru->devices_cnt); + } + } +pr_warn ("No IOMMU scope found for ANDD enumeration ID %d (%s)\n" , + device_number,dev_name (&adev->dev)); +} + +static int __init dmar_acpi_dev_scope_init (void ) +{ +struct acpi_dmar_andd *andd = (void *)dmar_tbl +sizeof (struct acpi_table_dmar ); + +while (((unsigned long )andd) < + ((unsigned long )dmar_tbl) + dmar_tbl->length) { +if (andd->header.type ==ACPI_DMAR_TYPE_ANDD ) { +acpi_handle h; +struct acpi_device *adev; + +if (!ACPI_SUCCESS (acpi_get_handle (ACPI_ROOT_OBJECT , + andd->object_name, + &h))) { +pr_err ("Failed to find handle for ACPI object %s\n" , + andd->object_name); +continue ; + } +acpi_bus_get_device (h, &adev); +if (!adev) { +pr_err ("Failed to get device for ACPI object %s\n" , + andd->object_name); +continue ; + } +dmar_acpi_insert_dev_scope (andd->device_number, adev); + } + andd = ((void *)andd) + andd->header.length; + } +return 0 ; +} +int __init dmar_dev_scope_init (void ) {struct pci_dev *dev =NULL ;
@@ -620,6 +693,8 @@ int __init dmar_dev_scope_init(void)if (dmar_dev_scope_status !=1 )return dmar_dev_scope_status; +dmar_acpi_dev_scope_init (); +if (list_empty (&dmar_drhd_units)) { dmar_dev_scope_status = -ENODEV ; }else {
Signature · 1 line
1.8.5.3
A message that is not in the archive (sent off-list or not yet received): 1395422354-19762-6-git-send-email-David.Woodhouse-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org
PATCH 1/1 iommu/vt-d: Check for NULL pointer in dmar_acpi_dev_scope_init() array
Hi David,
Review
Quoted 6 lines · David Woodhouse
(quoted diff) +6
-0+static int __init dmar_acpi_dev_scope_init(void) +{ + struct acpi_dmar_andd *andd = (void *)dmar_tbl + sizeof(struct acpi_table_dmar); + + while (((unsigned long)andd) < + ((unsigned long)dmar_tbl) + dmar_tbl->length) {
This is causing a kernel crash on AMD IOMMU systems. I will queue attached patch on the x86/vt-d to fix the issue. A better solution would be to not call ir_dev_scope_init() by a rootfs-initcall, but this is more complicated and better not done that close to the merge-window. Do you have objections?
Joerg
Quoted 1 line
From
0e1ad789087ea3b142ee4a169662db0ec77425ffMon Sep 17 00:00:00 2001
From: Joerg Roedel <[email protected]>
Date: Tue, 25 Mar 2014 20:16:40 +0100
Subject: [PATCH] iommu/vt-d: Check for NULL pointer in dmar_acpi_dev_scope_init()
When ir_dev_scope_init() is called via a rootfs initcall it will check for irq_remapping_enabled before it calls (indirectly) into dmar_acpi_dev_scope_init() which uses the dmar_tbl pointer without any checks.
The AMD IOMMU driver also sets the irq_remapping_enabled flag which causes the dmar_acpi_dev_scope_init() function to be called on systems with AMD IOMMU hardware too, causing a boot-time kernel crash.
--- drivers/iommu/dmar.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/iommu/dmar.c +6 -1
@@ -657,7 +657,12 @@ static void __init dmar_acpi_insert_dev_scope(u8 device_number,static int __init dmar_acpi_dev_scope_init (void ) { -struct acpi_dmar_andd *andd = (void *)dmar_tbl +sizeof (struct acpi_table_dmar ); +struct acpi_dmar_andd *andd; + +if (dmar_tbl ==NULL ) +return -ENODEV ; + + andd = (void *)dmar_tbl +sizeof (struct acpi_table_dmar );while (((unsigned long )andd) < ((unsigned long )dmar_tbl) + dmar_tbl->length) {
Signature · 1 line
1.7.9.5
A message that is not in the archive (sent off-list or not yet received): [email protected]
Woodhouse, David
Acked-byRe: [PATCH] iommu/vt-d: Check for NULL pointer in dmar_acpi_dev_scope_init() array
Quoted 5 lines · Joerg Roedel
When
ir_dev_scope_init()is called via a rootfs initcall it will check forirq_remapping_enabledbefore it calls (indirectly) intodmar_acpi_dev_scope_init()which uses thedmar_tblpointer without any checks.
Ew. If irq_remapping_enabled is not (any more?) Intel-specific, then ir_dev_scope_init() ought to be checking something more appropriate.
But defensively fixing dmar_dev_scope_init() as you have done certainly seems reasonable. On a slow path, it doesn't hurt to check for NULL.
However, I note that dmar_dev_scope_init() already *does* effectively check for the existence of Intel IOMMU hardware, because it checks the dmar_drhd_units list. So the patch below would also make sense, and should be sufficient to fix the problem on its own...
From: David Woodhouse <[email protected]>
Subject: iommu/vt-d: Only call dmar_acpi_dev_scope_init() if there are DRHD units
For arcane reasons, this code path gets exercised even on AMD systems when IRQ remapping is enabled.
drivers/iommu/dmar.c +2 -2
@@ -693,13 +693,13 @@ int __init dmar_dev_scope_init(void)if (dmar_dev_scope_status !=1 )return dmar_dev_scope_status; -dmar_acpi_dev_scope_init (); -if (list_empty (&dmar_drhd_units)) { dmar_dev_scope_status = -ENODEV ; }else { dmar_dev_scope_status =0 ; +dmar_acpi_dev_scope_init (); +for_each_pci_dev (dev) {if (dev->is_virtfn)continue ;
Signature · 2 lines
David Woodhouse Open Source Technology Centre [email protected] Intel Corporation
PATCH 6/33 iommu/vt-d: Make iommu_dummy() take struct device instead of struct pci_dev
In reply to a message not in the archive--- drivers/iommu/intel-iommu.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/iommu/intel-iommu.c +5 -5
@@ -2882,9 +2882,9 @@ static inline struct dmar_domain *get_valid_domain_for_dev(struct pci_dev *dev)return __get_valid_domain_for_dev (dev); } -static int iommu_dummy (struct pci_dev *pdev) +static int iommu_dummy (struct device *dev) { -return pdev->dev.archdata.iommu ==DUMMY_DEVICE_DOMAIN_INFO ; +return dev->archdata.iommu ==DUMMY_DEVICE_DOMAIN_INFO ; }/* Check if the pdev needs to go through non-identity map and unmap process.*/
@@ -2896,13 +2896,13 @@ static int iommu_no_mapping(struct device *dev)if (unlikely (!dev_is_pci (dev)))return 1 ; - pdev =to_pci_dev (dev); -if (iommu_dummy (pdev)) +if (iommu_dummy (dev))return 1 ;if (!iommu_identity_mapping)return 0 ; + pdev =to_pci_dev (dev); found =identity_mapping (pdev);if (found) {if (iommu_should_identity_map (pdev,0 ))
@@ -3801,7 +3801,7 @@ static int device_notifier(struct notifier_block *nb,struct pci_dev *pdev =to_pci_dev (dev);struct dmar_domain *domain; -if (iommu_dummy (pdev)) +if (iommu_dummy (dev))return 0 ; if (action != BUS_NOTIFY_UNBOUND_DRIVER &&
Signature · 1 line
1.8.5.3
PATCH 7/33 iommu/vt-d: Make dmar_insert_dev_info() take struct device instead of struct pci_dev
In reply to a message not in the archive--- drivers/iommu/intel-iommu.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-)
drivers/iommu/intel-iommu.c +10 -11
@@ -2113,15 +2113,14 @@ static void domain_remove_dev_info(struct dmar_domain *domain)/* * find_domain -* Note: we use struct pci_dev->dev.archdata.iommu stores the info +* Note: we use struct device->archdata.iommu stores the info */ -static struct dmar_domain * -find_domain (struct pci_dev *pdev) +static struct dmar_domain *find_domain (struct device *dev) {struct device_domain_info *info;/* No lock here, assumes no domain exit in normal case */ - info = pdev->dev.archdata.iommu; + info = dev->archdata.iommu;if (info)return info->domain;return NULL ;
@@ -2161,7 +2160,7 @@ static int dmar_insert_dev_info(int segment, int bus, int devfn,spin_lock_irqsave (&device_domain_lock, flags);if (dev) - found =find_domain (dev); + found =find_domain (&dev->dev);else found =dmar_search_domain_by_dev_info (segment, bus, devfn);if (found) {
@@ -2193,7 +2192,7 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)int bus =0 , devfn =0 ;int segment; - domain =find_domain (pdev); + domain =find_domain (&pdev->dev);if (domain)return domain;
@@ -2252,7 +2251,7 @@ error:if (free)domain_exit (free);/* recheck it here, maybe others set it */ -return find_domain (pdev); +return find_domain (&pdev->dev); }static int iommu_identity_mapping;
@@ -3108,7 +3107,7 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,if (iommu_no_mapping (dev))return ; - domain =find_domain (pdev); + domain =find_domain (dev);BUG_ON (!domain); iommu =domain_get_iommu (domain);
@@ -3200,7 +3199,7 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,if (iommu_no_mapping (hwdev))return ; - domain =find_domain (pdev); + domain =find_domain (hwdev);BUG_ON (!domain); iommu =domain_get_iommu (domain);
@@ -3808,7 +3807,7 @@ static int device_notifier(struct notifier_block *nb, action != BUS_NOTIFY_DEL_DEVICE)return 0 ; - domain =find_domain (pdev); + domain =find_domain (dev);if (!domain)return 0 ;
@@ -4147,7 +4146,7 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,if (unlikely (domain_context_mapped (pdev))) {struct dmar_domain *old_domain; - old_domain =find_domain (pdev); + old_domain =find_domain (dev);if (old_domain) {if (dmar_domain->flags &DOMAIN_FLAG_VIRTUAL_MACHINE || dmar_domain->flags &DOMAIN_FLAG_STATIC_IDENTITY )
Signature · 1 line
1.8.5.3
PATCH 8/33 iommu/vt-d: Use struct device in device_domain_info, not struct pci_dev
In reply to a message not in the archive--- drivers/iommu/intel-iommu.c | 54 +++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 22 deletions(-)
drivers/iommu/intel-iommu.c +32 -22
@@ -372,7 +372,7 @@ struct device_domain_info {int segment;/* PCI domain */ u8 bus;/* PCI bus number */ u8 devfn;/* PCI devfn number */ -struct pci_dev *dev;/* it's NULL for PCIe-to-PCI bridge */ +struct device *dev;/* it's NULL for PCIe-to-PCI bridge */ struct intel_iommu *iommu;/* IOMMU used by this device */ struct dmar_domain *domain;/* pointer to domain */ };
@@ -428,7 +428,7 @@ static void domain_remove_dev_info(struct dmar_domain *domain);static void domain_remove_one_dev_info (struct dmar_domain *domain,struct pci_dev *pdev);static void iommu_detach_dependent_devices (struct intel_iommu *iommu, -struct pci_dev *pdev); +struct device *dev);#ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON int dmar_disabled =0 ;
@@ -1247,6 +1247,7 @@ static struct device_domain_info *iommu_support_dev_iotlb(unsigned long flags;struct device_domain_info *info;struct intel_iommu *iommu =device_to_iommu (segment, bus, devfn); +struct pci_dev *pdev;if (!ecap_dev_iotlb_support (iommu->ecap))return NULL ;
@@ -1262,13 +1263,15 @@ static struct device_domain_info *iommu_support_dev_iotlb( }spin_unlock_irqrestore (&device_domain_lock, flags); -if (!found || !info->dev) +if (!found || !info->dev || !dev_is_pci (info->dev))return NULL ; -if (!pci_find_ext_capability (info->dev,PCI_EXT_CAP_ID_ATS )) + pdev =to_pci_dev (info->dev); + +if (!pci_find_ext_capability (pdev,PCI_EXT_CAP_ID_ATS ))return NULL ; -if (!dmar_find_matched_atsr_unit (info->dev)) +if (!dmar_find_matched_atsr_unit (pdev))return NULL ; info->iommu = iommu;
@@ -1278,18 +1281,19 @@ static struct device_domain_info *iommu_support_dev_iotlb(static void iommu_enable_dev_iotlb (struct device_domain_info *info) { -if (!info) +if (!info || !dev_is_pci (info->dev))return ; -pci_enable_ats (info->dev,VTD_PAGE_SHIFT ); +pci_enable_ats (to_pci_dev (info->dev),VTD_PAGE_SHIFT ); }static void iommu_disable_dev_iotlb (struct device_domain_info *info) { -if (!info->dev || !pci_ats_enabled (info->dev)) +if (!info->dev || !dev_is_pci (info->dev) || + !pci_ats_enabled (to_pci_dev (info->dev)))return ; -pci_disable_ats (info->dev); +pci_disable_ats (to_pci_dev (info->dev)); } static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
@@ -1301,11 +1305,16 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain,spin_lock_irqsave (&device_domain_lock, flags);list_for_each_entry (info, &domain->devices, link) { -if (!info->dev || !pci_ats_enabled (info->dev)) +struct pci_dev *pdev; +if (!info->dev || !dev_is_pci (info->dev)) +continue ; + + pdev =to_pci_dev (info->dev); +if (!pci_ats_enabled (pdev))continue ; sid = info->bus <<8 | info->devfn; - qdep =pci_ats_queue_depth (info->dev); + qdep =pci_ats_queue_depth (pdev);qi_flush_dev_iotlb (info->iommu, sid, qdep, addr, mask); }spin_unlock_irqrestore (&device_domain_lock, flags);
@@ -2071,7 +2080,7 @@ static inline void unlink_domain_info(struct device_domain_info *info)list_del (&info->link);list_del (&info->global);if (info->dev) - info->dev->dev.archdata.iommu =NULL ; + info->dev->archdata.iommu =NULL ; }static void domain_remove_dev_info (struct dmar_domain *domain)
@@ -2140,7 +2149,7 @@ dmar_search_domain_by_dev_info(int segment, int bus, int devfn) }static int dmar_insert_dev_info (int segment,int bus,int devfn, -struct pci_dev *dev,struct dmar_domain **domp) +struct device *dev,struct dmar_domain **domp) {struct dmar_domain *found, *domain = *domp;struct device_domain_info *info;
@@ -2160,7 +2169,7 @@ static int dmar_insert_dev_info(int segment, int bus, int devfn,spin_lock_irqsave (&device_domain_lock, flags);if (dev) - found =find_domain (&dev->dev); + found =find_domain (dev);else found =dmar_search_domain_by_dev_info (segment, bus, devfn);if (found) {
@@ -2174,7 +2183,7 @@ static int dmar_insert_dev_info(int segment, int bus, int devfn,list_add (&info->link, &domain->devices);list_add (&info->global, &device_domain_list);if (dev) - dev->dev.archdata.iommu = info; + dev->archdata.iommu = info;spin_unlock_irqrestore (&device_domain_lock, flags); }
@@ -2245,7 +2254,7 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) found_domain:if (dmar_insert_dev_info (segment, pdev->bus->number, pdev->devfn, - pdev, &domain) ==0 ) + &pdev->dev, &domain) ==0 )return domain; error:if (free)
@@ -2458,7 +2467,7 @@ static int domain_add_dev_info(struct dmar_domain *domain, info->segment =pci_domain_nr (pdev->bus); info->bus = pdev->bus->number; info->devfn = pdev->devfn; - info->dev = pdev; + info->dev = &pdev->dev; info->domain = domain;spin_lock_irqsave (&device_domain_lock, flags);
@@ -3189,7 +3198,6 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist, int nelems, enum dma_data_direction dir, struct dma_attrs *attrs) { - struct pci_dev *pdev = to_pci_dev(hwdev); struct dmar_domain *domain;unsigned long start_pfn, last_pfn;struct iova *iova;
@@ -3985,13 +3993,15 @@ out_free_dmar: }static void iommu_detach_dependent_devices (struct intel_iommu *iommu, -struct pci_dev *pdev) +struct device *dev) { -struct pci_dev *tmp, *parent; +struct pci_dev *tmp, *parent, *pdev; -if (!iommu || !pdev) +if (!iommu || !dev || !dev_is_pci (dev))return ; + pdev =to_pci_dev (dev); +/* dependent device detach */ tmp =pci_find_upstream_pcie_bridge (pdev);/* Secondary interface's bus number and devfn 0 */
@@ -4034,7 +4044,7 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain,iommu_disable_dev_iotlb (info);iommu_detach_dev (iommu, info->bus, info->devfn); -iommu_detach_dependent_devices (iommu, pdev); +iommu_detach_dependent_devices (iommu, &pdev->dev);free_devinfo_mem (info);spin_lock_irqsave (&device_domain_lock, flags);
Signature · 1 line
1.8.5.3
PATCH 9/33 iommu/vt-d: Pass iommu to domain_context_mapping_one() and iommu_support_dev_iotlb()
In reply to a message not in the archive--- drivers/iommu/intel-iommu.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-)
drivers/iommu/intel-iommu.c +17 -18
@@ -1240,13 +1240,13 @@ static void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did, (unsigned long long)DMA_TLB_IAIG(val)); } -static struct device_domain_info *iommu_support_dev_iotlb ( -struct dmar_domain *domain,int segment,u8 bus,u8 devfn) +static struct device_domain_info * +iommu_support_dev_iotlb (struct dmar_domain *domain,struct intel_iommu *iommu, +u8 bus,u8 devfn) {int found =0 ;unsigned long flags;struct device_domain_info *info; -struct intel_iommu *iommu =device_to_iommu (segment, bus, devfn);struct pci_dev *pdev;if (!ecap_dev_iotlb_support (iommu->ecap))
@@ -1700,12 +1700,12 @@ static void domain_exit(struct dmar_domain *domain)free_domain_mem (domain); } -static int domain_context_mapping_one (struct dmar_domain *domain,int segment, -u8 bus,u8 devfn,int translation) +static int domain_context_mapping_one (struct dmar_domain *domain, +struct intel_iommu *iommu, +u8 bus,u8 devfn,int translation) {struct context_entry *context;unsigned long flags; -struct intel_iommu *iommu;struct dma_pte *pgd;unsigned long num;unsigned long ndomains;
@@ -1720,10 +1720,6 @@ static int domain_context_mapping_one(struct dmar_domain *domain, int segment,BUG_ON (translation !=CONTEXT_TT_PASS_THROUGH && translation !=CONTEXT_TT_MULTI_LEVEL ); - iommu =device_to_iommu (segment, bus, devfn); -if (!iommu) -return -ENODEV ; - context =device_to_context_entry (iommu, bus, devfn);if (!context)return -ENOMEM ;
@@ -1781,7 +1777,7 @@ static int domain_context_mapping_one(struct dmar_domain *domain, int segment,context_set_domain_id (context, id);if (translation !=CONTEXT_TT_PASS_THROUGH ) { - info =iommu_support_dev_iotlb (domain, segment, bus, devfn); + info =iommu_support_dev_iotlb (domain, iommu, bus, devfn); translation = info ?CONTEXT_TT_DEV_IOTLB :CONTEXT_TT_MULTI_LEVEL ; }
@@ -1836,8 +1832,14 @@ domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev, {int ret;struct pci_dev *tmp, *parent; +struct intel_iommu *iommu; + + iommu =device_to_iommu (pci_domain_nr (pdev->bus), pdev->bus->number, + pdev->devfn); +if (!iommu) +return -ENODEV ; - ret =domain_context_mapping_one (domain,pci_domain_nr (pdev->bus), + ret =domain_context_mapping_one (domain, iommu, pdev->bus->number, pdev->devfn, translation);if (ret)
@@ -1850,8 +1852,7 @@ domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev,/* Secondary interface's bus number and devfn 0 */ parent = pdev->bus->self;while (parent != tmp) { - ret =domain_context_mapping_one (domain, -pci_domain_nr (parent->bus), + ret =domain_context_mapping_one (domain, iommu, parent->bus->number, parent->devfn, translation);if (ret)
@@ -1859,13 +1860,11 @@ domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev, parent = parent->bus->self; }if (pci_is_pcie (tmp))/* this is a PCIe-to-PCI bridge */ -return domain_context_mapping_one (domain, -pci_domain_nr (tmp->subordinate), +return domain_context_mapping_one (domain, iommu, tmp->subordinate->number,0 , translation);else /* this is a legacy PCI bridge */ -return domain_context_mapping_one (domain, -pci_domain_nr (tmp->bus), +return domain_context_mapping_one (domain, iommu, tmp->bus->number, tmp->devfn, translation);
Signature · 1 line
1.8.5.3
PATCH 10/33 iommu/vt-d: Stop dmar_insert_dev_info() freeing domains on losing race
In reply to a message not in the archiveBy moving this into get_domain_for_dev() we can make dmar_insert_dev_info() suitable for use with "special" domains such as the si_domain, which currently use domain_add_dev_info().
--- drivers/iommu/intel-iommu.c | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-)
drivers/iommu/intel-iommu.c +21 -24
@@ -2147,16 +2147,17 @@ dmar_search_domain_by_dev_info(int segment, int bus, int devfn)return NULL ; } -static int dmar_insert_dev_info (int segment,int bus,int devfn, -struct device *dev,struct dmar_domain **domp) +static struct dmar_domain *dmar_insert_dev_info (int segment,int bus,int devfn, +struct device *dev, +struct dmar_domain *domain) { -struct dmar_domain *found, *domain = *domp; +struct dmar_domain *found;struct device_domain_info *info;unsigned long flags; info =alloc_devinfo_mem ();if (!info) -return -ENOMEM ; +return NULL ; info->segment = segment; info->bus = bus;
@@ -2174,19 +2175,17 @@ static int dmar_insert_dev_info(int segment, int bus, int devfn,if (found) {spin_unlock_irqrestore (&device_domain_lock, flags);free_devinfo_mem (info); -if (found != domain) { -domain_exit (domain); - *domp = found; - } - }else { -list_add (&info->link, &domain->devices); -list_add (&info->global, &device_domain_list); -if (dev) - dev->archdata.iommu = info; -spin_unlock_irqrestore (&device_domain_lock, flags); +/* Caller must free the original domain */ +return found; } -return 0 ; +list_add (&info->link, &domain->devices); +list_add (&info->global, &device_domain_list); +if (dev) + dev->archdata.iommu = info; +spin_unlock_irqrestore (&device_domain_lock, flags); + +return domain; }/* domain is initialized */
@@ -2245,21 +2244,19 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)/* register pcie-to-pci device */ if (dev_tmp) { -if (dmar_insert_dev_info (segment, bus, devfn,NULL , &domain)) + domain =dmar_insert_dev_info (segment, bus, devfn,NULL , domain); +if (!domain) goto error; -else - free =NULL ; } found_domain: -if (dmar_insert_dev_info (segment, pdev->bus->number, pdev->devfn, - &pdev->dev, &domain) ==0 ) -return domain; + domain =dmar_insert_dev_info (segment, pdev->bus->number, pdev->devfn, + &pdev->dev, domain); error: -if (free) +if (free != domain)domain_exit (free); -/* recheck it here, maybe others set it */ -return find_domain (&pdev->dev); + +return domain; }static int iommu_identity_mapping;
Signature · 1 line
1.8.5.3
PATCH 11/33 iommu/vt-d: use dmar_insert_dev_info() from dma_add_dev_info()
In reply to a message not in the archive--- drivers/iommu/intel-iommu.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-)
drivers/iommu/intel-iommu.c +7 -15
@@ -2452,29 +2452,21 @@ static int domain_add_dev_info(struct dmar_domain *domain, struct pci_dev *pdev, int translation) { +struct dmar_domain *ndomain;struct device_domain_info *info;unsigned long flags;int ret; - info =alloc_devinfo_mem (); -if (!info) -return -ENOMEM ; - - info->segment =pci_domain_nr (pdev->bus); - info->bus = pdev->bus->number; - info->devfn = pdev->devfn; - info->dev = &pdev->dev; - info->domain = domain; - -spin_lock_irqsave (&device_domain_lock, flags); -list_add (&info->link, &domain->devices); -list_add (&info->global, &device_domain_list); - pdev->dev.archdata.iommu = info; -spin_unlock_irqrestore (&device_domain_lock, flags); + ndomain =dmar_insert_dev_info (pci_domain_nr (pdev->bus), + pdev->bus->number, pdev->devfn, + &pdev->dev, domain); +if (ndomain != domain) +return -EBUSY ; ret =domain_context_mapping (domain, pdev, translation);if (ret) {spin_lock_irqsave (&device_domain_lock, flags); + info = pdev->dev.archdata.iommu;unlink_domain_info (info);spin_unlock_irqrestore (&device_domain_lock, flags);free_devinfo_mem (info);
Signature · 1 line
1.8.5.3
PATCH 12/33 iommu/vt-d: Use domain_remove_one_dev_info() in domain_add_dev_info() error path
In reply to a message not in the archive--- drivers/iommu/intel-iommu.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-)
drivers/iommu/intel-iommu.c +1 -7
@@ -2453,8 +2453,6 @@ static int domain_add_dev_info(struct dmar_domain *domain, int translation) {struct dmar_domain *ndomain; -struct device_domain_info *info; -unsigned long flags;int ret; ndomain = dmar_insert_dev_info(pci_domain_nr(pdev->bus),
@@ -2465,11 +2463,7 @@ static int domain_add_dev_info(struct dmar_domain *domain, ret =domain_context_mapping (domain, pdev, translation);if (ret) { -spin_lock_irqsave (&device_domain_lock, flags); - info = pdev->dev.archdata.iommu; -unlink_domain_info (info); -spin_unlock_irqrestore (&device_domain_lock, flags); -free_devinfo_mem (info); +domain_remove_one_dev_info (domain, pdev);return ret; }
Signature · 1 line
1.8.5.3
PATCH 13/33 iommu/vt-d: Always store iommu in device_domain_info
In reply to a message not in the archive--- drivers/iommu/intel-iommu.c | 47 ++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 16 deletions(-)
drivers/iommu/intel-iommu.c +31 -16
@@ -1274,8 +1274,6 @@ iommu_support_dev_iotlb (struct dmar_domain *domain, struct intel_iommu *iommu,if (!dmar_find_matched_atsr_unit (pdev))return NULL ; - info->iommu = iommu; -return info; }
@@ -2134,7 +2132,7 @@ static struct dmar_domain *find_domain(struct device *dev)return NULL ; } -static inline struct dmar_domain * +static inline struct device_domain_info *dmar_search_domain_by_dev_info (int segment,int bus,int devfn) {struct device_domain_info *info;
@@ -2142,16 +2140,17 @@ dmar_search_domain_by_dev_info(int segment, int bus, int devfn)list_for_each_entry (info, &device_domain_list, global)if (info->segment == segment && info->bus == bus && info->devfn == devfn) -return info->domain; +return info;return NULL ; } -static struct dmar_domain *dmar_insert_dev_info (int segment,int bus,int devfn, +static struct dmar_domain *dmar_insert_dev_info (struct intel_iommu *iommu, +int segment,int bus,int devfn,struct device *dev,struct dmar_domain *domain) { -struct dmar_domain *found; +struct dmar_domain *found =NULL ;struct device_domain_info *info;unsigned long flags;
@@ -2164,14 +2163,19 @@ static struct dmar_domain *dmar_insert_dev_info(int segment, int bus, int devfn, info->devfn = devfn; info->dev = dev; info->domain = domain; + info->iommu = iommu;if (!dev) domain->flags |=DOMAIN_FLAG_P2P_MULTIPLE_DEVICES ;spin_lock_irqsave (&device_domain_lock, flags);if (dev) found =find_domain (dev); -else - found =dmar_search_domain_by_dev_info (segment, bus, devfn); +else { +struct device_domain_info *info2; + info2 =dmar_search_domain_by_dev_info (segment, bus, devfn); +if (info2) + found = info2->domain; + }if (found) {spin_unlock_irqrestore (&device_domain_lock, flags);free_devinfo_mem (info);
@@ -2192,7 +2196,8 @@ static struct dmar_domain *dmar_insert_dev_info(int segment, int bus, int devfn,static struct dmar_domain *get_domain_for_dev (struct pci_dev *pdev,int gaw) {struct dmar_domain *domain, *free =NULL ; -struct intel_iommu *iommu; +struct intel_iommu *iommu =NULL ; +struct device_domain_info *info;struct dmar_drhd_unit *drhd;struct pci_dev *dev_tmp;unsigned long flags;
@@ -2215,10 +2220,13 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) devfn = dev_tmp->devfn; }spin_lock_irqsave (&device_domain_lock, flags); - domain =dmar_search_domain_by_dev_info (segment, bus, devfn); + info =dmar_search_domain_by_dev_info (segment, bus, devfn); +if (info) { + iommu = info->iommu; + domain = info->domain; + }spin_unlock_irqrestore (&device_domain_lock, flags); -/* pcie-pci bridge already has a domain, uses it */ -if (domain) +if (info) goto found_domain; }
@@ -2244,14 +2252,15 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)/* register pcie-to-pci device */ if (dev_tmp) { - domain =dmar_insert_dev_info (segment, bus, devfn,NULL , domain); + domain =dmar_insert_dev_info (iommu, segment, bus, devfn,NULL , + domain);if (!domain) goto error; } found_domain: - domain =dmar_insert_dev_info (segment, pdev->bus->number, pdev->devfn, - &pdev->dev, domain); + domain =dmar_insert_dev_info (iommu, segment, pdev->bus->number, + pdev->devfn, &pdev->dev, domain); error:if (free != domain)domain_exit (free);
@@ -2453,9 +2462,15 @@ static int domain_add_dev_info(struct dmar_domain *domain, int translation) {struct dmar_domain *ndomain; +struct intel_iommu *iommu;int ret; - ndomain =dmar_insert_dev_info (pci_domain_nr (pdev->bus), + iommu =device_to_iommu (pci_domain_nr (pdev->bus), + pdev->bus->number, pdev->devfn); +if (!iommu) +return -ENODEV ; + + ndomain =dmar_insert_dev_info (iommu,pci_domain_nr (pdev->bus), pdev->bus->number, pdev->devfn, &pdev->dev, domain);if (ndomain != domain)
Signature · 1 line
1.8.5.3
PATCH 14/33 iommu/vt-d: Simplify iommu check in domain_remove_one_dev_info()
In reply to a message not in the archiveNow we store the iommu in the device_domain_info, we don't need to do a lookup.
--- drivers/iommu/intel-iommu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/iommu/intel-iommu.c +1 -2
@@ -4056,8 +4056,7 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain,* owned by this domain, clear this iommu in iommu_bmp * update iommu count and coherency */ -if (iommu ==device_to_iommu (info->segment, info->bus, - info->devfn)) +if (info->iommu == iommu) found =1 ; }
Signature · 1 line
1.8.5.3
PATCH 15/33 iommu/vt-d: Remove device_to_iommu() call from domain_remove_dev_info()
In reply to a message not in the archiveThis was problematic because it works by domain/bus/devfn and we want to make device_to_iommu() use only a struct device * (for handling non-PCI devices). Now that the iommu pointer is reliably stored in the device_domain_info, we don't need to look it up.
--- drivers/iommu/intel-iommu.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
drivers/iommu/intel-iommu.c +3 -5
@@ -2084,7 +2084,6 @@ static void domain_remove_dev_info(struct dmar_domain *domain) {struct device_domain_info *info;unsigned long flags, flags2; -struct intel_iommu *iommu;spin_lock_irqsave (&device_domain_lock, flags);while (!list_empty (&domain->devices)) {
@@ -2094,16 +2093,15 @@ static void domain_remove_dev_info(struct dmar_domain *domain)spin_unlock_irqrestore (&device_domain_lock, flags);iommu_disable_dev_iotlb (info); - iommu =device_to_iommu (info->segment, info->bus, info->devfn); -iommu_detach_dev (iommu, info->bus, info->devfn); +iommu_detach_dev (info->iommu, info->bus, info->devfn);if (domain->flags &DOMAIN_FLAG_VIRTUAL_MACHINE ) { -iommu_detach_dependent_devices (iommu, info->dev); +iommu_detach_dependent_devices (info->iommu, info->dev);/* clear this iommu in iommu_bmp, update iommu count * and capabilities */ spin_lock_irqsave (&domain->iommu_lock, flags2); -if (test_and_clear_bit (iommu->seq_id, +if (test_and_clear_bit (info->iommu->seq_id, domain->iommu_bmp)) { domain->iommu_count--;domain_update_iommu_cap (domain);
Signature · 1 line
1.8.5.3
PATCH 16/33 iommu/vt-d: Store PCI segment number in struct intel_iommu
In reply to a message not in the archive--- drivers/iommu/dmar.c | 1 + include/linux/intel-iommu.h | 1 + 2 files changed, 2 insertions(+)
drivers/iommu/dmar.c +1 -0
@@ -952,6 +952,7 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd) } iommu->agaw = agaw; iommu->msagaw = msagaw; + iommu->segment = drhd->segment; iommu->node =-1 ;
include/linux/intel-iommu.h +1 -0
@@ -322,6 +322,7 @@ struct intel_iommu {unsigned char name[13 ];/* Device Name */ #ifdef CONFIG_INTEL_IOMMU +u16 segment;/* PCI segment# */ unsigned long *domain_ids;/* bitmap of domains */ struct dmar_domain **domains;/* ptr to domains */ spinlock_t lock;/* protect context, domain ids */
Signature · 1 line
1.8.5.3
PATCH 17/33 iommu/vt-d: Remove segment from struct device_domain_info()
In reply to a message not in the archiveIt's accessible via info->iommu->segment so this is redundant.
--- drivers/iommu/intel-iommu.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-)
drivers/iommu/intel-iommu.c +7 -10
@@ -369,7 +369,6 @@ struct dmar_domain {struct device_domain_info {struct list_head link;/* link to domain siblings */ struct list_head global;/* link to global list */ -int segment;/* PCI domain */ u8 bus;/* PCI bus number */ u8 devfn;/* PCI devfn number */ struct device *dev;/* it's NULL for PCIe-to-PCI bridge */
@@ -2136,7 +2135,7 @@ dmar_search_domain_by_dev_info(int segment, int bus, int devfn)struct device_domain_info *info;list_for_each_entry (info, &device_domain_list, global) -if (info->segment == segment && info->bus == bus && +if (info->iommu->segment == segment && info->bus == bus && info->devfn == devfn)return info;
@@ -2144,7 +2143,7 @@ dmar_search_domain_by_dev_info(int segment, int bus, int devfn) }static struct dmar_domain *dmar_insert_dev_info (struct intel_iommu *iommu, -int segment,int bus,int devfn, +int bus,int devfn,struct device *dev,struct dmar_domain *domain) {
@@ -2156,7 +2155,6 @@ static struct dmar_domain *dmar_insert_dev_info(struct intel_iommu *iommu,if (!info)return NULL ; - info->segment = segment; info->bus = bus; info->devfn = devfn; info->dev = dev;
@@ -2170,7 +2168,7 @@ static struct dmar_domain *dmar_insert_dev_info(struct intel_iommu *iommu, found =find_domain (dev); else {struct device_domain_info *info2; - info2 =dmar_search_domain_by_dev_info (segment, bus, devfn); + info2 =dmar_search_domain_by_dev_info (iommu->segment, bus, devfn);if (info2) found = info2->domain; }
@@ -2250,14 +2248,14 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)/* register pcie-to-pci device */ if (dev_tmp) { - domain =dmar_insert_dev_info (iommu, segment, bus, devfn,NULL , + domain =dmar_insert_dev_info (iommu, bus, devfn,NULL , domain);if (!domain) goto error; } found_domain: - domain =dmar_insert_dev_info (iommu, segment, pdev->bus->number, + domain =dmar_insert_dev_info (iommu, pdev->bus->number, pdev->devfn, &pdev->dev, domain); error:if (free != domain)
@@ -2468,8 +2466,7 @@ static int domain_add_dev_info(struct dmar_domain *domain,if (!iommu)return -ENODEV ; - ndomain =dmar_insert_dev_info (iommu,pci_domain_nr (pdev->bus), - pdev->bus->number, pdev->devfn, + ndomain =dmar_insert_dev_info (iommu, pdev->bus->number, pdev->devfn, &pdev->dev, domain);if (ndomain != domain)return -EBUSY ;
@@ -4031,7 +4028,7 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain,spin_lock_irqsave (&device_domain_lock, flags);list_for_each_entry_safe (info, tmp, &domain->devices, link) { -if (info->segment ==pci_domain_nr (pdev->bus) && +if (info->iommu->segment ==pci_domain_nr (pdev->bus) && info->bus == pdev->bus->number && info->devfn == pdev->devfn) {unlink_domain_info (info);
Signature · 1 line
1.8.5.3
PATCH 18/33 iommu/vt-d: Make identity_mapping() take struct device not struct pci_dev
In reply to a message not in the archive--- drivers/iommu/intel-iommu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/iommu/intel-iommu.c +3 -3
@@ -2439,14 +2439,14 @@ static int __init si_domain_init(int hw)return 0 ; } -static int identity_mapping (struct pci_dev *pdev) +static int identity_mapping (struct device *dev) {struct device_domain_info *info;if (likely (!iommu_identity_mapping))return 0 ; - info = pdev->dev.archdata.iommu; + info = dev->archdata.iommu;if (info && info !=DUMMY_DEVICE_DOMAIN_INFO )return (info->domain == si_domain);
@@ -2903,7 +2903,7 @@ static int iommu_no_mapping(struct device *dev)return 0 ; pdev =to_pci_dev (dev); - found =identity_mapping (pdev); + found =identity_mapping (dev);if (found) {if (iommu_should_identity_map (pdev,0 ))return 1 ;
Signature · 1 line
1.8.5.3
PATCH 19/33 iommu/vt-d: Make device_to_iommu() cope with non-PCI devices
In reply to a message not in the archivePass the struct device to it, and also make it return the bus/devfn to use, since that is also stored in the DMAR table.
--- drivers/iommu/intel-iommu.c | 78 ++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 32 deletions(-)
drivers/iommu/intel-iommu.c +46 -32
@@ -664,37 +664,53 @@ static void domain_update_iommu_cap(struct dmar_domain *domain)domain_update_iommu_superpage (domain); } -static struct intel_iommu *device_to_iommu (int segment,u8 bus,u8 devfn) +static struct intel_iommu *device_to_iommu (struct device *dev,u8 *bus,u8 *devfn) {struct dmar_drhd_unit *drhd =NULL ;struct intel_iommu *iommu; -struct device *dev; -struct pci_dev *pdev; +struct device *tmp; +struct pci_dev *ptmp, *pdev =NULL ; +u16 segment;int i; +if (dev_is_pci (dev)) { + pdev =to_pci_dev (dev); + segment =pci_domain_nr (pdev->bus); + }else if (ACPI_COMPANION (dev)) + dev = &ACPI_COMPANION (dev)->dev; +rcu_read_lock ();for_each_active_iommu (iommu, drhd) { -if (segment != drhd->segment) +if (pdev && segment != drhd->segment)continue ;for_each_active_dev_scope (drhd->devices, - drhd->devices_cnt, i, dev) { -if (!dev_is_pci (dev)) -continue ; - pdev =to_pci_dev (dev); -if (pdev->bus->number == bus && pdev->devfn == devfn) - goto out; -if (pdev->subordinate && - pdev->subordinate->number <= bus && - pdev->subordinate->busn_res.end >= bus) + drhd->devices_cnt, i, tmp) { +if (tmp == dev) { + *bus = drhd->devices[i].bus; + *devfn = drhd->devices[i].devfn; goto out; + } + +if (!pdev || !dev_is_pci (tmp)) +continue ; + + ptmp =to_pci_dev (tmp); +if (ptmp->subordinate && + ptmp->subordinate->number <= pdev->bus->number && + ptmp->subordinate->busn_res.end >= pdev->bus->number) + goto got_pdev; } -if (drhd->include_all) +if (pdev && drhd->include_all) { + got_pdev: + *bus = pdev->bus->number; + *devfn = pdev->devfn; goto out; + } } iommu =NULL ; -out: + out:rcu_read_unlock ();return iommu;
@@ -1830,14 +1846,13 @@ domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev,int ret;struct pci_dev *tmp, *parent;struct intel_iommu *iommu; +u8 bus, devfn; - iommu =device_to_iommu (pci_domain_nr (pdev->bus), pdev->bus->number, - pdev->devfn); + iommu =device_to_iommu (&pdev->dev, &bus, &devfn);if (!iommu)return -ENODEV ; - ret =domain_context_mapping_one (domain, iommu, - pdev->bus->number, pdev->devfn, + ret =domain_context_mapping_one (domain, iommu, bus, devfn, translation);if (ret)return ret;
@@ -1872,13 +1887,13 @@ static int domain_context_mapped(struct pci_dev *pdev)int ret;struct pci_dev *tmp, *parent;struct intel_iommu *iommu; +u8 bus, devfn; - iommu =device_to_iommu (pci_domain_nr (pdev->bus), pdev->bus->number, - pdev->devfn); + iommu =device_to_iommu (&pdev->dev, &bus, &devfn);if (!iommu)return -ENODEV ; - ret =device_context_mapped (iommu, pdev->bus->number, pdev->devfn); + ret =device_context_mapped (iommu, bus, devfn);if (!ret)return ret;/* dependent device mapping */
@@ -2459,15 +2474,14 @@ static int domain_add_dev_info(struct dmar_domain *domain, {struct dmar_domain *ndomain;struct intel_iommu *iommu; +u8 bus, devfn;int ret; - iommu =device_to_iommu (pci_domain_nr (pdev->bus), - pdev->bus->number, pdev->devfn); + iommu =device_to_iommu (&pdev->dev, &bus, &devfn);if (!iommu)return -ENODEV ; - ndomain =dmar_insert_dev_info (iommu, pdev->bus->number, pdev->devfn, - &pdev->dev, domain); + ndomain =dmar_insert_dev_info (iommu, bus, devfn, &pdev->dev, domain);if (ndomain != domain)return -EBUSY ;
@@ -4020,9 +4034,9 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain,struct intel_iommu *iommu;unsigned long flags;int found =0 ; +u8 bus, devfn; - iommu =device_to_iommu (pci_domain_nr (pdev->bus), pdev->bus->number, - pdev->devfn); + iommu =device_to_iommu (&pdev->dev, &bus, &devfn);if (!iommu)return ;
@@ -4142,6 +4156,7 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,struct pci_dev *pdev =to_pci_dev (dev);struct intel_iommu *iommu;int addr_width; +u8 bus, devfn;/* normally pdev is not mapped */ if (unlikely (domain_context_mapped (pdev))) {
@@ -4157,8 +4172,7 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, } } - iommu =device_to_iommu (pci_domain_nr (pdev->bus), pdev->bus->number, - pdev->devfn); + iommu =device_to_iommu (dev, &bus, &devfn);if (!iommu)return -ENODEV ;
@@ -4324,9 +4338,9 @@ static int intel_iommu_add_device(struct device *dev)struct pci_dev *bridge, *dma_pdev =NULL ;struct iommu_group *group;int ret; +u8 bus, devfn; -if (!device_to_iommu (pci_domain_nr (pdev->bus), - pdev->bus->number, pdev->devfn)) +if (!device_to_iommu (dev, &bus, &devfn))return -ENODEV ; bridge =pci_find_upstream_pcie_bridge (pdev);
Signature · 1 line
1.8.5.3
PATCH 20/33 iommu/vt-d: Make domain_context_mapp{ed, ing}() take struct device
In reply to a message not in the archive--- drivers/iommu/intel-iommu.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-)
drivers/iommu/intel-iommu.c +17 -14
@@ -1840,24 +1840,25 @@ static int domain_context_mapping_one(struct dmar_domain *domain, }static int -domain_context_mapping (struct dmar_domain *domain,struct pci_dev *pdev, -int translation) +domain_context_mapping (struct dmar_domain *domain,struct device *dev, +int translation) {int ret; -struct pci_dev *tmp, *parent; +struct pci_dev *pdev, *tmp, *parent;struct intel_iommu *iommu;u8 bus, devfn; - iommu =device_to_iommu (&pdev->dev, &bus, &devfn); + iommu =device_to_iommu (dev, &bus, &devfn);if (!iommu)return -ENODEV ; ret =domain_context_mapping_one (domain, iommu, bus, devfn, translation); -if (ret) +if (ret || !dev_is_pci (dev))return ret;/* dependent device mapping */ + pdev =to_pci_dev (dev); tmp =pci_find_upstream_pcie_bridge (pdev);if (!tmp)return 0 ;
@@ -1882,21 +1883,23 @@ domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev, translation); } -static int domain_context_mapped (struct pci_dev *pdev) +static int domain_context_mapped (struct device *dev) {int ret; -struct pci_dev *tmp, *parent; +struct pci_dev *pdev, *tmp, *parent;struct intel_iommu *iommu;u8 bus, devfn; - iommu =device_to_iommu (&pdev->dev, &bus, &devfn); + iommu =device_to_iommu (dev, &bus, &devfn);if (!iommu)return -ENODEV ; ret =device_context_mapped (iommu, bus, devfn); -if (!ret) +if (!ret || !dev_is_pci (dev))return ret; +/* dependent device mapping */ + pdev =to_pci_dev (dev); tmp =pci_find_upstream_pcie_bridge (pdev);if (!tmp)return ret;
@@ -2361,7 +2364,7 @@ static int iommu_prepare_identity_map(struct pci_dev *pdev, goto error;/* context entry init */ - ret =domain_context_mapping (domain, pdev,CONTEXT_TT_MULTI_LEVEL ); + ret =domain_context_mapping (domain, &pdev->dev,CONTEXT_TT_MULTI_LEVEL );if (ret) goto error;
@@ -2485,7 +2488,7 @@ static int domain_add_dev_info(struct dmar_domain *domain,if (ndomain != domain)return -EBUSY ; - ret =domain_context_mapping (domain, pdev, translation); + ret =domain_context_mapping (domain, &pdev->dev, translation);if (ret) {domain_remove_one_dev_info (domain, pdev);return ret;
@@ -2870,8 +2873,8 @@ static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev) }/* make sure context mapping is ok */ -if (unlikely (!domain_context_mapped (pdev))) { - ret =domain_context_mapping (domain, pdev, +if (unlikely (!domain_context_mapped (&pdev->dev))) { + ret =domain_context_mapping (domain, &pdev->dev,CONTEXT_TT_MULTI_LEVEL );if (ret) { printk(KERN_ERR
@@ -4159,7 +4162,7 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,u8 bus, devfn;/* normally pdev is not mapped */ -if (unlikely (domain_context_mapped (pdev))) { +if (unlikely (domain_context_mapped (&pdev->dev))) {struct dmar_domain *old_domain; old_domain =find_domain (dev);
Signature · 1 line
1.8.5.3
PATCH 21/33 iommu/vt-d: Make get_domain_for_dev() take struct device
In reply to a message not in the archive--- drivers/iommu/intel-iommu.c | 75 ++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 39 deletions(-)
drivers/iommu/intel-iommu.c +36 -39
@@ -2207,52 +2207,51 @@ static struct dmar_domain *dmar_insert_dev_info(struct intel_iommu *iommu, }/* domain is initialized */ -static struct dmar_domain *get_domain_for_dev (struct pci_dev *pdev,int gaw) +static struct dmar_domain *get_domain_for_dev (struct device *dev,int gaw) {struct dmar_domain *domain, *free =NULL ;struct intel_iommu *iommu =NULL ;struct device_domain_info *info; -struct dmar_drhd_unit *drhd; -struct pci_dev *dev_tmp; +struct pci_dev *dev_tmp =NULL ;unsigned long flags; -int bus =0 , devfn =0 ; -int segment; +u8 bus, devfn, bridge_bus, bridge_devfn; - domain =find_domain (&pdev->dev); + domain =find_domain (dev);if (domain)return domain; - segment =pci_domain_nr (pdev->bus); +if (dev_is_pci (dev)) { +struct pci_dev *pdev =to_pci_dev (dev); +u16 segment; - dev_tmp =pci_find_upstream_pcie_bridge (pdev); -if (dev_tmp) { -if (pci_is_pcie (dev_tmp)) { - bus = dev_tmp->subordinate->number; - devfn =0 ; - }else { - bus = dev_tmp->bus->number; - devfn = dev_tmp->devfn; - } -spin_lock_irqsave (&device_domain_lock, flags); - info =dmar_search_domain_by_dev_info (segment, bus, devfn); -if (info) { - iommu = info->iommu; - domain = info->domain; + segment =pci_domain_nr (pdev->bus); + dev_tmp =pci_find_upstream_pcie_bridge (pdev); +if (dev_tmp) { +if (pci_is_pcie (dev_tmp)) { + bridge_bus = dev_tmp->subordinate->number; + bridge_devfn =0 ; + }else { + bridge_bus = dev_tmp->bus->number; + bridge_devfn = dev_tmp->devfn; + } +spin_lock_irqsave (&device_domain_lock, flags); + info =dmar_search_domain_by_dev_info (segment, bus, devfn); +if (info) { + iommu = info->iommu; + domain = info->domain; + } +spin_unlock_irqrestore (&device_domain_lock, flags); +/* pcie-pci bridge already has a domain, uses it */ +if (info) + goto found_domain; } -spin_unlock_irqrestore (&device_domain_lock, flags); -if (info) - goto found_domain; } - drhd =dmar_find_matched_drhd_unit (pdev); -if (!drhd) { -printk (KERN_ERR "IOMMU: can't find DMAR for device %s\n" , -pci_name (pdev)); -return NULL ; - } - iommu = drhd->iommu; + iommu =device_to_iommu (dev, &bus, &devfn); +if (!iommu) + goto error; -/* Allocate and intialize new domain for the device */ +/* Allocate and initialize new domain for the device */ domain =alloc_domain (false);if (!domain) goto error;
@@ -2266,15 +2265,14 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)/* register pcie-to-pci device */ if (dev_tmp) { - domain =dmar_insert_dev_info (iommu, bus, devfn,NULL , - domain); + domain =dmar_insert_dev_info (iommu, bridge_bus, bridge_devfn, +NULL , domain);if (!domain) goto error; } found_domain: - domain =dmar_insert_dev_info (iommu, pdev->bus->number, - pdev->devfn, &pdev->dev, domain); + domain =dmar_insert_dev_info (iommu, bus, devfn, dev, domain); error:if (free != domain)domain_exit (free);
@@ -2320,7 +2318,7 @@ static int iommu_prepare_identity_map(struct pci_dev *pdev,struct dmar_domain *domain;int ret; - domain =get_domain_for_dev (pdev,DEFAULT_DOMAIN_ADDRESS_WIDTH ); + domain =get_domain_for_dev (&pdev->dev,DEFAULT_DOMAIN_ADDRESS_WIDTH );if (!domain)return -ENOMEM ;
@@ -2864,8 +2862,7 @@ static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev)struct dmar_domain *domain;int ret; - domain =get_domain_for_dev (pdev, -DEFAULT_DOMAIN_ADDRESS_WIDTH ); + domain =get_domain_for_dev (&pdev->dev,DEFAULT_DOMAIN_ADDRESS_WIDTH );if (!domain) {printk (KERN_ERR "Allocating domain for %s failed" ,pci_name (pdev));
Signature · 1 line
1.8.5.3
A message that is not in the archive (sent off-list or not yet received): 1395422354-19762-22-git-send-email-David.Woodhouse-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org
Re: [PATCH 21/33] iommu/vt-d: Make get_domain_for_dev() take struct device
Quoted 53 lines · David Woodhouse
Signed-off-by David Woodhouse <[email protected]>--- drivers/iommu/intel-iommu.c | 75 ++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 39 deletions(-)drivers/iommu/intel-iommu.c +9
-21@@ -2207,52 +2207,51 @@ static struct dmar_domain *dmar_insert_dev_info(struct intel_iommu *iommu, }/* domain is initialized */ -static struct dmar_domain *get_domain_for_dev (struct pci_dev *pdev,int gaw) +static struct dmar_domain *get_domain_for_dev (struct device *dev,int gaw) {struct dmar_domain *domain, *free =NULL ;struct intel_iommu *iommu =NULL ;struct device_domain_info *info; -struct dmar_drhd_unit *drhd; -struct pci_dev *dev_tmp; +struct pci_dev *dev_tmp =NULL ;unsigned long flags; -int bus =0 , devfn =0 ; -int segment; +u8 bus, devfn, bridge_bus, bridge_devfn; - domain =find_domain (&pdev->dev); + domain =find_domain (dev);if (domain)return domain; - segment =pci_domain_nr (pdev->bus); +if (dev_is_pci (dev)) { +struct pci_dev *pdev =to_pci_dev (dev); +u16 segment; - dev_tmp =pci_find_upstream_pcie_bridge (pdev); -if (dev_tmp) { -if (pci_is_pcie (dev_tmp)) { - bus = dev_tmp->subordinate->number; - devfn =0 ; - }else { - bus = dev_tmp->bus->number; - devfn = dev_tmp->devfn; - } -spin_lock_irqsave (&device_domain_lock, flags); - info =dmar_search_domain_by_dev_info (segment, bus, devfn); -if (info) { - iommu = info->iommu; - domain = info->domain; + segment =pci_domain_nr (pdev->bus); + dev_tmp =pci_find_upstream_pcie_bridge (pdev);
drivers/iommu/intel-iommu.c static struct dmar_domain *dmar_insert_dev_info(struct intel_iommu *iommu, · line 2238
Quoted 10 lines
drivers/iommu/intel-iommu.c +10
-0+if (dev_tmp) { +if (pci_is_pcie (dev_tmp)) { + bridge_bus = dev_tmp->subordinate->number; + bridge_devfn =0 ; + }else { + bridge_bus = dev_tmp->bus->number; + bridge_devfn = dev_tmp->devfn; + } +spin_lock_irqsave (&device_domain_lock, flags); + info =dmar_search_domain_by_dev_info (segment, bus, devfn);
bus and devfn are uninitialized here, CID 1197747 & 1197746. Thanks,
Alex
Quoted 68 lines
drivers/iommu/intel-iommu.c +17
-18+if (info) { + iommu = info->iommu; + domain = info->domain; + } +spin_unlock_irqrestore (&device_domain_lock, flags); +/* pcie-pci bridge already has a domain, uses it */ +if (info) + goto found_domain; } -spin_unlock_irqrestore (&device_domain_lock, flags); -if (info) - goto found_domain; } - drhd =dmar_find_matched_drhd_unit (pdev); -if (!drhd) { -printk (KERN_ERR "IOMMU: can't find DMAR for device %s\n" , -pci_name (pdev)); -return NULL ; - } - iommu = drhd->iommu; + iommu =device_to_iommu (dev, &bus, &devfn); +if (!iommu) + goto error; -/* Allocate and intialize new domain for the device */ +/* Allocate and initialize new domain for the device */ domain =alloc_domain (false);if (!domain) goto error;@@ -2266,15 +2265,14 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)/* register pcie-to-pci device */ if (dev_tmp) { - domain =dmar_insert_dev_info (iommu, bus, devfn,NULL , - domain); + domain =dmar_insert_dev_info (iommu, bridge_bus, bridge_devfn, +NULL , domain);if (!domain) goto error; } found_domain: - domain =dmar_insert_dev_info (iommu, pdev->bus->number, - pdev->devfn, &pdev->dev, domain); + domain =dmar_insert_dev_info (iommu, bus, devfn, dev, domain); error:if (free != domain)domain_exit (free);@@ -2320,7 +2318,7 @@ static int iommu_prepare_identity_map(struct pci_dev *pdev,struct dmar_domain *domain;int ret; - domain =get_domain_for_dev (pdev,DEFAULT_DOMAIN_ADDRESS_WIDTH ); + domain =get_domain_for_dev (&pdev->dev,DEFAULT_DOMAIN_ADDRESS_WIDTH );if (!domain)return -ENOMEM ;@@ -2864,8 +2862,7 @@ static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev)struct dmar_domain *domain;int ret; - domain =get_domain_for_dev (pdev, -DEFAULT_DOMAIN_ADDRESS_WIDTH ); + domain =get_domain_for_dev (&pdev->dev,DEFAULT_DOMAIN_ADDRESS_WIDTH );if (!domain) {printk (KERN_ERR "Allocating domain for %s failed" ,pci_name (pdev));
A message that is not in the archive (sent off-list or not yet received): 1397510541.3060.15.camel-85EaTFmN5p//[email protected]
Re: [PATCH 21/33] iommu/vt-d: Make get_domain_for_dev() take struct device
Quoted 13 lines · Alex Williamson
drivers/iommu/intel-iommu.c static struct dmar_domain *dmar_insert_dev_info(struct intel_iommu *iommu, · line 2238
Quoted 11 lines
drivers/iommu/intel-iommu.c +10
-0+if (dev_tmp) { +if (pci_is_pcie (dev_tmp)) { + bridge_bus = dev_tmp->subordinate->number; + bridge_devfn =0 ; + }else { + bridge_bus = dev_tmp->bus->number; + bridge_devfn = dev_tmp->devfn; + } +spin_lock_irqsave (&device_domain_lock, flags); + info =dmar_search_domain_by_dev_info (segment, bus, devfn);
Quoted 1 line
bus and devfn are uninitialized here, CID 1197747 & 1197746. Thanks,
Oops. That should be using bridge_bus and bridge_devfn, shouldn't it?
Will fix; thanks.
Signature · 2 lines
David Woodhouse Open Source Technology Centre [email protected] Intel Corporation
A message that is not in the archive (sent off-list or not yet received): 1397511643.19944.217.camel-Fexsq3y4057IgHVZqg5X0TlWvGAXklZc@public.gmane.org
Re: [PATCH 21/33] iommu/vt-d: Make get_domain_for_dev() take struct device
Quoted 14 lines · David
Quoted 13 lines · Alex Williamson
Quoted 11 lines
drivers/iommu/intel-iommu.c +10
-0+if (dev_tmp) { +if (pci_is_pcie (dev_tmp)) { + bridge_bus = dev_tmp->subordinate->number; + bridge_devfn =0 ; + }else { + bridge_bus = dev_tmp->bus->number; + bridge_devfn = dev_tmp->devfn; + } +spin_lock_irqsave (&device_domain_lock, flags); + info =dmar_search_domain_by_dev_info (segment, bus, devfn);
Quoted 6 lines
Quoted 1 line
bus and devfn are uninitialized here, CID 1197747 & 1197746. Thanks,
Oops. That should be using
bridge_busandbridge_devfn, shouldn't it?Will fix; thanks.
Yep, I think it was supposed to be bridge_*. Thanks,
Alex
PATCH 22/33 iommu/vt-d: Handle RMRRs for non-PCI devices
In reply to a message not in the archiveShould hopefully never happen (RMRRs are an abomination) but while we're busy eliminating all the PCI assumptions, we might as well do it.
--- drivers/iommu/intel-iommu.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-)
drivers/iommu/intel-iommu.c +14 -16
@@ -2311,14 +2311,14 @@ static int iommu_domain_identity_map(struct dmar_domain *domain, DMA_PTE_READ|DMA_PTE_WRITE); } -static int iommu_prepare_identity_map (struct pci_dev *pdev, +static int iommu_prepare_identity_map (struct device *dev,unsigned long long start,unsigned long long end) {struct dmar_domain *domain;int ret; - domain =get_domain_for_dev (&pdev->dev,DEFAULT_DOMAIN_ADDRESS_WIDTH ); + domain =get_domain_for_dev (dev,DEFAULT_DOMAIN_ADDRESS_WIDTH );if (!domain)return -ENOMEM ;
@@ -2328,13 +2328,13 @@ static int iommu_prepare_identity_map(struct pci_dev *pdev,up to start with in si_domain */ if (domain == si_domain && hw_pass_through) {printk ("Ignoring identity map for HW passthrough device %s [0x%Lx - 0x%Lx]\n" , -pci_name (pdev), start, end); +dev_name (dev), start, end);return 0 ; }printk (KERN_INFO "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n" , -pci_name (pdev), start, end); +dev_name (dev), start, end);if (end < start) { WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n"
@@ -2362,7 +2362,7 @@ static int iommu_prepare_identity_map(struct pci_dev *pdev, goto error;/* context entry init */ - ret =domain_context_mapping (domain, &pdev->dev,CONTEXT_TT_MULTI_LEVEL ); + ret =domain_context_mapping (domain, dev,CONTEXT_TT_MULTI_LEVEL );if (ret) goto error;
@@ -2374,12 +2374,12 @@ static int iommu_prepare_identity_map(struct pci_dev *pdev, }static inline int iommu_prepare_rmrr_dev (struct dmar_rmrr_unit *rmrr, -struct pci_dev *pdev) +struct device *dev) { -if (pdev->dev.archdata.iommu ==DUMMY_DEVICE_DOMAIN_INFO ) +if (dev->archdata.iommu ==DUMMY_DEVICE_DOMAIN_INFO )return 0 ; -return iommu_prepare_identity_map (pdev, rmrr->base_address, - rmrr->end_address); +return iommu_prepare_identity_map (dev, rmrr->base_address, + rmrr->end_address); }#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA
@@ -2393,7 +2393,7 @@ static inline void iommu_prepare_isa(void)return ;printk (KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n" ); - ret =iommu_prepare_identity_map (pdev,0 ,16 *1024 *1024 -1 ); + ret =iommu_prepare_identity_map (&pdev->dev,0 ,16 *1024 *1024 -1 );if (ret) printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
@@ -2495,7 +2495,7 @@ static int domain_add_dev_info(struct dmar_domain *domain,return 0 ; } -static bool device_has_rmrr (struct pci_dev *dev) +static bool device_has_rmrr (struct device *dev) {struct dmar_rmrr_unit *rmrr;struct device *tmp;
@@ -2509,7 +2509,7 @@ static bool device_has_rmrr(struct pci_dev *dev)*/ for_each_active_dev_scope (rmrr->devices, rmrr->devices_cnt, i, tmp) -if (tmp == &dev->dev) { +if (tmp == dev) {rcu_read_unlock ();return true; }
@@ -2529,7 +2529,7 @@ static int iommu_should_identity_map(struct pci_dev *pdev, int startup)* from this process due to their usage of RMRRs that are known * to not be needed after BIOS hand-off to OS. */ -if (device_has_rmrr (pdev) && +if (device_has_rmrr (&pdev->dev) && (pdev->class >>8 ) !=PCI_CLASS_SERIAL_USB )return 0 ;
@@ -2766,9 +2766,7 @@ static int __init init_dmars(void)/* some BIOS lists non-exist devices in DMAR table. */ for_each_active_dev_scope (rmrr->devices, rmrr->devices_cnt, i, dev) { -if (!dev_is_pci (dev)) -continue ; - ret =iommu_prepare_rmrr_dev (rmrr,to_pci_dev (dev)); + ret =iommu_prepare_rmrr_dev (rmrr, dev);if (ret)printk (KERN_ERR "IOMMU: mapping reserved region failed\n" );
Signature · 1 line
1.8.5.3
PATCH 23/33 iommu/vt-d: Make iommu_should_identity_map() take struct device
In reply to a message not in the archive--- drivers/iommu/intel-iommu.c | 107 +++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 50 deletions(-)
drivers/iommu/intel-iommu.c +57 -50
@@ -2518,58 +2518,65 @@ static bool device_has_rmrr(struct device *dev)return false; } -static int iommu_should_identity_map (struct pci_dev *pdev,int startup) +static int iommu_should_identity_map (struct device *dev,int startup) { -/* -* We want to prevent any device associated with an RMRR from -* getting placed into the SI Domain. This is done because -* problems exist when devices are moved in and out of domains -* and their respective RMRR info is lost. We exempt USB devices -* from this process due to their usage of RMRRs that are known -* to not be needed after BIOS hand-off to OS. -*/ -if (device_has_rmrr (&pdev->dev) && - (pdev->class >>8 ) !=PCI_CLASS_SERIAL_USB ) -return 0 ; +if (dev_is_pci (dev)) { +struct pci_dev *pdev =to_pci_dev (dev); -if ((iommu_identity_mapping &IDENTMAP_AZALIA ) &&IS_AZALIA (pdev)) -return 1 ; +/* +* We want to prevent any device associated with an RMRR from +* getting placed into the SI Domain. This is done because +* problems exist when devices are moved in and out of domains +* and their respective RMRR info is lost. We exempt USB devices +* from this process due to their usage of RMRRs that are known +* to not be needed after BIOS hand-off to OS. +*/ +if (device_has_rmrr (dev) && + (pdev->class >>8 ) !=PCI_CLASS_SERIAL_USB ) +return 0 ; -if ((iommu_identity_mapping &IDENTMAP_GFX ) &&IS_GFX_DEVICE (pdev)) -return 1 ; +if ((iommu_identity_mapping &IDENTMAP_AZALIA ) &&IS_AZALIA (pdev)) +return 1 ; -if (!(iommu_identity_mapping &IDENTMAP_ALL )) -return 0 ; +if ((iommu_identity_mapping &IDENTMAP_GFX ) &&IS_GFX_DEVICE (pdev)) +return 1 ; -/* -* We want to start off with all devices in the 1:1 domain, and -* take them out later if we find they can't access all of memory. -* -* However, we can't do this for PCI devices behind bridges, -* because all PCI devices behind the same bridge will end up -* with the same source-id on their transactions. -* -* Practically speaking, we can't change things around for these -* devices at run-time, because we can't be sure there'll be no -* DMA transactions in flight for any of their siblings. -* -* So PCI devices (unless they're on the root bus) as well as -* their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of -* the 1:1 domain, just in _case_ one of their siblings turns out -* not to be able to map all of memory. -*/ -if (!pci_is_pcie (pdev)) { -if (!pci_is_root_bus (pdev->bus)) +if (!(iommu_identity_mapping &IDENTMAP_ALL ))return 0 ; -if (pdev->class >>8 ==PCI_CLASS_BRIDGE_PCI ) + +/* +* We want to start off with all devices in the 1:1 domain, and +* take them out later if we find they can't access all of memory. +* +* However, we can't do this for PCI devices behind bridges, +* because all PCI devices behind the same bridge will end up +* with the same source-id on their transactions. +* +* Practically speaking, we can't change things around for these +* devices at run-time, because we can't be sure there'll be no +* DMA transactions in flight for any of their siblings. +* +* So PCI devices (unless they're on the root bus) as well as +* their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of +* the 1:1 domain, just in _case_ one of their siblings turns out +* not to be able to map all of memory. +*/ +if (!pci_is_pcie (pdev)) { +if (!pci_is_root_bus (pdev->bus)) +return 0 ; +if (pdev->class >>8 ==PCI_CLASS_BRIDGE_PCI ) +return 0 ; + }else if (pci_pcie_type (pdev) ==PCI_EXP_TYPE_PCI_BRIDGE )return 0 ; - }else if (pci_pcie_type (pdev) ==PCI_EXP_TYPE_PCI_BRIDGE ) -return 0 ; + }else { +if (device_has_rmrr (dev)) +return 0 ; + } -/* +/* * At boot time, we don't yet know if devices will be 64-bit capable. -* Assume that they will -- if they turn out not to be, then we can +* Assume that they will — if they turn out not to be, then we can * take them out of the 1:1 domain later. */ if (!startup) {
@@ -2577,13 +2584,13 @@ static int iommu_should_identity_map(struct pci_dev *pdev, int startup)* If the device's dma_mask is less than the system's memory * size then this is not a candidate for identity mapping. */ -u64 dma_mask = pdev->dma_mask; +u64 dma_mask = *dev->dma_mask; -if (pdev->dev.coherent_dma_mask && - pdev->dev.coherent_dma_mask < dma_mask) - dma_mask = pdev->dev.coherent_dma_mask; +if (dev->coherent_dma_mask && + dev->coherent_dma_mask < dma_mask) + dma_mask = dev->coherent_dma_mask; -return dma_mask >=dma_get_required_mask (&pdev->dev); +return dma_mask >=dma_get_required_mask (dev); }return 1 ;
@@ -2599,7 +2606,7 @@ static int __init iommu_prepare_static_identity_mapping(int hw)return -EFAULT ;for_each_pci_dev (pdev) { -if (iommu_should_identity_map (pdev,1 )) { +if (iommu_should_identity_map (&pdev->dev,1 )) { ret =domain_add_dev_info (si_domain, pdev, hw ?CONTEXT_TT_PASS_THROUGH :CONTEXT_TT_MULTI_LEVEL );
@@ -2917,7 +2924,7 @@ static int iommu_no_mapping(struct device *dev) pdev =to_pci_dev (dev); found =identity_mapping (dev);if (found) { -if (iommu_should_identity_map (pdev,0 )) +if (iommu_should_identity_map (&pdev->dev,0 ))return 1 ;else {/*
@@ -2934,7 +2941,7 @@ static int iommu_no_mapping(struct device *dev)* In case of a detached 64 bit DMA device from vm, the device * is put into si_domain for identity mapping. */ -if (iommu_should_identity_map (pdev,0 )) { +if (iommu_should_identity_map (&pdev->dev,0 )) {int ret; ret = domain_add_dev_info(si_domain, pdev, hw_pass_through ?
Signature · 6 lines
1.8.5.3 _______________________________________________ iommu mailing list [email protected] https://lists.linuxfoundation.org/mailman/listinfo/iommu
PATCH 24/33 iommu/vt-d: Make get_valid_domain_for_dev() take struct device
In reply to a message not in the archive--- drivers/iommu/intel-iommu.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-)
drivers/iommu/intel-iommu.c +12 -14
@@ -2862,26 +2862,24 @@ static struct iova *intel_alloc_iova(struct device *dev,return iova; } -static struct dmar_domain *__get_valid_domain_for_dev (struct pci_dev *pdev) +static struct dmar_domain *__get_valid_domain_for_dev (struct device *dev) {struct dmar_domain *domain;int ret; - domain =get_domain_for_dev (&pdev->dev,DEFAULT_DOMAIN_ADDRESS_WIDTH ); + domain =get_domain_for_dev (dev,DEFAULT_DOMAIN_ADDRESS_WIDTH );if (!domain) { -printk (KERN_ERR -"Allocating domain for %s failed" ,pci_name (pdev)); +printk (KERN_ERR "Allocating domain for %s failed" , +dev_name (dev));return NULL ; }/* make sure context mapping is ok */ -if (unlikely (!domain_context_mapped (&pdev->dev))) { - ret =domain_context_mapping (domain, &pdev->dev, -CONTEXT_TT_MULTI_LEVEL ); +if (unlikely (!domain_context_mapped (dev))) { + ret =domain_context_mapping (domain, dev,CONTEXT_TT_MULTI_LEVEL );if (ret) { -printk (KERN_ERR -"Domain context map for %s failed" , -pci_name (pdev)); +printk (KERN_ERR "Domain context map for %s failed" , +dev_name (dev));return NULL ; } }
@@ -2889,12 +2887,12 @@ static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev)return domain; } -static inline struct dmar_domain *get_valid_domain_for_dev (struct pci_dev *dev) +static inline struct dmar_domain *get_valid_domain_for_dev (struct device *dev) {struct device_domain_info *info;/* No lock here, assumes no domain exit in normal case */ - info = dev->dev.archdata.iommu; + info = dev->archdata.iommu;if (likely (info))return info->domain;
@@ -2975,7 +2973,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,if (iommu_no_mapping (hwdev))return paddr; - domain =get_valid_domain_for_dev (pdev); + domain =get_valid_domain_for_dev (hwdev);if (!domain)return 0 ;
@@ -3280,7 +3278,7 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int neif (iommu_no_mapping (hwdev))return intel_nontranslate_map_sg (hwdev, sglist, nelems, dir); - domain =get_valid_domain_for_dev (pdev); + domain =get_valid_domain_for_dev (hwdev);if (!domain)return 0 ;
Signature · 1 line
1.8.5.3
PATCH 25/33 iommu/vt-d: Remove some pointless to_pci_dev() calls
In reply to a message not in the archiveMostly made redundant by using dev_name() instead of pci_name(), and one instance of using *dev->dma_mask instead of pdev->dma_mask.
--- drivers/iommu/intel-iommu.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-)
drivers/iommu/intel-iommu.c +4 -8
@@ -2835,7 +2835,6 @@ static struct iova *intel_alloc_iova(struct device *dev,struct dmar_domain *domain, unsigned long nrpages, uint64_t dma_mask) { - struct pci_dev *pdev = to_pci_dev(dev); struct iova *iova = NULL;/* Restrict dma_mask to the width that the iommu can handle */
@@ -2855,7 +2854,7 @@ static struct iova *intel_alloc_iova(struct device *dev, iova =alloc_iova (&domain->iovad, nrpages,IOVA_PFN (dma_mask),1 );if (unlikely (!iova)) {printk (KERN_ERR "Allocating %ld-page iova for %s failed" , - nrpages,pci_name (pdev)); + nrpages,dev_name (dev));return NULL ; }
@@ -2959,7 +2958,6 @@ static int iommu_no_mapping(struct device *dev)static dma_addr_t __intel_map_single (struct device *hwdev,phys_addr_t paddr,size_t size,int dir,u64 dma_mask) { -struct pci_dev *pdev =to_pci_dev (hwdev);struct dmar_domain *domain;phys_addr_t start_paddr;struct iova *iova;
@@ -3018,7 +3016,7 @@ error:if (iova)__free_iova (&domain->iovad, iova);printk (KERN_ERR "Device %s request: %zx@%llx dir %d --- failed\n" , -pci_name (pdev), size, (unsigned long long )paddr, dir); +dev_name (hwdev), size, (unsigned long long )paddr, dir);return 0 ; }
@@ -3115,7 +3113,6 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr, size_t size, enum dma_data_direction dir, struct dma_attrs *attrs) { - struct pci_dev *pdev = to_pci_dev(dev); struct dmar_domain *domain;unsigned long start_pfn, last_pfn;struct iova *iova;
@@ -3139,7 +3136,7 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr, last_pfn =mm_to_dma_pfn (iova->pfn_hi +1 ) -1 ;pr_debug ("Device %s unmapping: pfn %lx-%lx\n" , -pci_name (pdev), start_pfn, last_pfn); +dev_name (dev), start_pfn, last_pfn); freelist =domain_unmap (domain, start_pfn, last_pfn);
@@ -3264,7 +3261,6 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne enum dma_data_direction dir, struct dma_attrs *attrs) { int i; -struct pci_dev *pdev =to_pci_dev (hwdev);struct dmar_domain *domain;size_t size =0 ;int prot =0 ;
@@ -3288,7 +3284,7 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne size +=aligned_nrpages (sg->offset, sg->length); iova =intel_alloc_iova (hwdev, domain,dma_to_mm_pfn (size), - pdev->dma_mask); + *hwdev->dma_mask);if (!iova) { sglist->dma_length =0 ;return 0 ;
Signature · 1 line
1.8.5.3
PATCH 26/33 iommu/vt-d: Rename 'hwdev' variables to 'dev' now that that's the norm
In reply to a message not in the archive--- drivers/iommu/intel-iommu.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-)
drivers/iommu/intel-iommu.c +22 -22
@@ -2955,7 +2955,7 @@ static int iommu_no_mapping(struct device *dev)return 0 ; } -static dma_addr_t __intel_map_single (struct device *hwdev,phys_addr_t paddr, +static dma_addr_t __intel_map_single (struct device *dev,phys_addr_t paddr,size_t size,int dir,u64 dma_mask) {struct dmar_domain *domain;
@@ -2968,17 +2968,17 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,BUG_ON (dir ==DMA_NONE ); -if (iommu_no_mapping (hwdev)) +if (iommu_no_mapping (dev))return paddr; - domain =get_valid_domain_for_dev (hwdev); + domain =get_valid_domain_for_dev (dev);if (!domain)return 0 ; iommu =domain_get_iommu (domain); size =aligned_nrpages (paddr, size); - iova =intel_alloc_iova (hwdev, domain,dma_to_mm_pfn (size), dma_mask); + iova =intel_alloc_iova (dev, domain,dma_to_mm_pfn (size), dma_mask);if (!iova) goto error;
@@ -3016,7 +3016,7 @@ error:if (iova)__free_iova (&domain->iovad, iova);printk (KERN_ERR "Device %s request: %zx@%llx dir %d --- failed\n" , -dev_name (hwdev), size, (unsigned long long )paddr, dir); +dev_name (dev), size, (unsigned long long )paddr, dir);return 0 ; }
@@ -3155,7 +3155,7 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr, } } -static void *intel_alloc_coherent (struct device *hwdev,size_t size, +static void *intel_alloc_coherent (struct device *dev,size_t size,dma_addr_t *dma_handle,gfp_t flags,struct dma_attrs *attrs) {
@@ -3165,10 +3165,10 @@ static void *intel_alloc_coherent(struct device *hwdev, size_t size, size =PAGE_ALIGN (size); order =get_order (size); -if (!iommu_no_mapping (hwdev)) +if (!iommu_no_mapping (dev)) flags &= ~(GFP_DMA |GFP_DMA32 ); -else if (hwdev->coherent_dma_mask <dma_get_required_mask (hwdev)) { -if (hwdev->coherent_dma_mask <DMA_BIT_MASK (32 )) +else if (dev->coherent_dma_mask <dma_get_required_mask (dev)) { +if (dev->coherent_dma_mask <DMA_BIT_MASK (32 )) flags |=GFP_DMA ;else flags |=GFP_DMA32 ;
@@ -3179,16 +3179,16 @@ static void *intel_alloc_coherent(struct device *hwdev, size_t size,return NULL ;memset (vaddr,0 , size); - *dma_handle =__intel_map_single (hwdev,virt_to_bus (vaddr), size, + *dma_handle =__intel_map_single (dev,virt_to_bus (vaddr), size,DMA_BIDIRECTIONAL , - hwdev->coherent_dma_mask); + dev->coherent_dma_mask);if (*dma_handle)return vaddr;free_pages ((unsigned long )vaddr, order);return NULL ; } -static void intel_free_coherent (struct device *hwdev,size_t size,void *vaddr, +static void intel_free_coherent (struct device *dev,size_t size,void *vaddr,dma_addr_t dma_handle,struct dma_attrs *attrs) {int order;
@@ -3196,11 +3196,11 @@ static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr, size =PAGE_ALIGN (size); order =get_order (size); -intel_unmap_page (hwdev, dma_handle, size,DMA_BIDIRECTIONAL ,NULL ); +intel_unmap_page (dev, dma_handle, size,DMA_BIDIRECTIONAL ,NULL );free_pages ((unsigned long )vaddr, order); } -static void intel_unmap_sg (struct device *hwdev,struct scatterlist *sglist, +static void intel_unmap_sg (struct device *dev,struct scatterlist *sglist,int nelems,enum dma_data_direction dir,struct dma_attrs *attrs) {
@@ -3210,10 +3210,10 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,struct intel_iommu *iommu;struct page *freelist; -if (iommu_no_mapping (hwdev)) +if (iommu_no_mapping (dev))return ; - domain =find_domain (hwdev); + domain =find_domain (dev);BUG_ON (!domain); iommu =domain_get_iommu (domain);
@@ -3257,7 +3257,7 @@ static int intel_nontranslate_map_sg(struct device *hddev,return nelems; } -static int intel_map_sg (struct device *hwdev,struct scatterlist *sglist,int nelems, +static int intel_map_sg (struct device *dev,struct scatterlist *sglist,int nelems,enum dma_data_direction dir,struct dma_attrs *attrs) {int i;
@@ -3271,10 +3271,10 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nestruct intel_iommu *iommu;BUG_ON (dir ==DMA_NONE ); -if (iommu_no_mapping (hwdev)) -return intel_nontranslate_map_sg (hwdev, sglist, nelems, dir); +if (iommu_no_mapping (dev)) +return intel_nontranslate_map_sg (dev, sglist, nelems, dir); - domain =get_valid_domain_for_dev (hwdev); + domain =get_valid_domain_for_dev (dev);if (!domain)return 0 ;
@@ -3283,8 +3283,8 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nefor_each_sg (sglist, sg, nelems, i) size +=aligned_nrpages (sg->offset, sg->length); - iova =intel_alloc_iova (hwdev, domain,dma_to_mm_pfn (size), - *hwdev->dma_mask); + iova =intel_alloc_iova (dev, domain,dma_to_mm_pfn (size), + *dev->dma_mask);if (!iova) { sglist->dma_length =0 ;return 0 ;
Signature · 1 line
1.8.5.3
PATCH 27/33 iommu/vt-d: Make domain_remove_one_dev_info() take struct device
In reply to a message not in the archive--- drivers/iommu/intel-iommu.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-)
drivers/iommu/intel-iommu.c +11 -14
@@ -425,7 +425,7 @@ static long list_size;static void domain_exit (struct dmar_domain *domain);static void domain_remove_dev_info (struct dmar_domain *domain);static void domain_remove_one_dev_info (struct dmar_domain *domain, -struct pci_dev *pdev); +struct device *dev);static void iommu_detach_dependent_devices (struct intel_iommu *iommu,struct device *dev);
@@ -2488,7 +2488,7 @@ static int domain_add_dev_info(struct dmar_domain *domain, ret =domain_context_mapping (domain, &pdev->dev, translation);if (ret) { -domain_remove_one_dev_info (domain, pdev); +domain_remove_one_dev_info (domain, &pdev->dev);return ret; }
@@ -2928,7 +2928,7 @@ static int iommu_no_mapping(struct device *dev)* 32 bit DMA is removed from si_domain and fall back * to non-identity mapping. */ -domain_remove_one_dev_info (si_domain, pdev); +domain_remove_one_dev_info (si_domain, dev);printk (KERN_INFO "32bit %s uses non-identity mapping\n" ,pci_name (pdev));return 0 ;
@@ -3810,7 +3810,6 @@ static int device_notifier(struct notifier_block *nb, unsigned long action, void *data) { struct device *dev = data; -struct pci_dev *pdev =to_pci_dev (dev);struct dmar_domain *domain;if (iommu_dummy (dev))
@@ -3825,7 +3824,7 @@ static int device_notifier(struct notifier_block *nb,return 0 ;down_read (&dmar_global_lock); -domain_remove_one_dev_info (domain, pdev); +domain_remove_one_dev_info (domain, dev);if (!(domain->flags &DOMAIN_FLAG_VIRTUAL_MACHINE ) && !(domain->flags &DOMAIN_FLAG_STATIC_IDENTITY ) &&list_empty (&domain->devices))
@@ -4027,7 +4026,7 @@ static void iommu_detach_dependent_devices(struct intel_iommu *iommu, }static void domain_remove_one_dev_info (struct dmar_domain *domain, -struct pci_dev *pdev) +struct device *dev) {struct device_domain_info *info, *tmp;struct intel_iommu *iommu;
@@ -4035,21 +4034,20 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain,int found =0 ;u8 bus, devfn; - iommu =device_to_iommu (&pdev->dev, &bus, &devfn); + iommu =device_to_iommu (dev, &bus, &devfn);if (!iommu)return ;spin_lock_irqsave (&device_domain_lock, flags);list_for_each_entry_safe (info, tmp, &domain->devices, link) { -if (info->iommu->segment ==pci_domain_nr (pdev->bus) && - info->bus == pdev->bus->number && - info->devfn == pdev->devfn) { +if (info->iommu == iommu && info->bus == bus && + info->devfn == devfn) {unlink_domain_info (info);spin_unlock_irqrestore (&device_domain_lock, flags);iommu_disable_dev_iotlb (info);iommu_detach_dev (iommu, info->bus, info->devfn); -iommu_detach_dependent_devices (iommu, &pdev->dev); +iommu_detach_dependent_devices (iommu, dev);free_devinfo_mem (info);spin_lock_irqsave (&device_domain_lock, flags);
@@ -4165,7 +4163,7 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,if (old_domain) {if (dmar_domain->flags &DOMAIN_FLAG_VIRTUAL_MACHINE || dmar_domain->flags &DOMAIN_FLAG_STATIC_IDENTITY ) -domain_remove_one_dev_info (old_domain, pdev); +domain_remove_one_dev_info (old_domain, dev);else domain_remove_dev_info (old_domain); }
@@ -4210,9 +4208,8 @@ static void intel_iommu_detach_device(struct iommu_domain *domain, struct device *dev) {struct dmar_domain *dmar_domain = domain->priv; -struct pci_dev *pdev =to_pci_dev (dev); -domain_remove_one_dev_info (dmar_domain, pdev); +domain_remove_one_dev_info (dmar_domain, dev); } static int intel_iommu_map(struct iommu_domain *domain,
Signature · 1 line
1.8.5.3
PATCH 28/33 iommu/vt-d: Make domain_add_dev_info() take struct device
In reply to a message not in the archive--- drivers/iommu/intel-iommu.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-)
drivers/iommu/intel-iommu.c +8 -9
@@ -2470,25 +2470,24 @@ static int identity_mapping(struct device *dev) }static int domain_add_dev_info (struct dmar_domain *domain, -struct pci_dev *pdev, -int translation) +struct device *dev,int translation) {struct dmar_domain *ndomain;struct intel_iommu *iommu;u8 bus, devfn;int ret; - iommu =device_to_iommu (&pdev->dev, &bus, &devfn); + iommu =device_to_iommu (dev, &bus, &devfn);if (!iommu)return -ENODEV ; - ndomain =dmar_insert_dev_info (iommu, bus, devfn, &pdev->dev, domain); + ndomain =dmar_insert_dev_info (iommu, bus, devfn, dev, domain);if (ndomain != domain)return -EBUSY ; - ret =domain_context_mapping (domain, &pdev->dev, translation); + ret =domain_context_mapping (domain, dev, translation);if (ret) { -domain_remove_one_dev_info (domain, &pdev->dev); +domain_remove_one_dev_info (domain, dev);return ret; }
@@ -2607,7 +2606,7 @@ static int __init iommu_prepare_static_identity_mapping(int hw)for_each_pci_dev (pdev) {if (iommu_should_identity_map (&pdev->dev,1 )) { - ret =domain_add_dev_info (si_domain, pdev, + ret =domain_add_dev_info (si_domain, &pdev->dev, hw ?CONTEXT_TT_PASS_THROUGH :CONTEXT_TT_MULTI_LEVEL );if (ret) {
@@ -2940,7 +2939,7 @@ static int iommu_no_mapping(struct device *dev)*/ if (iommu_should_identity_map (&pdev->dev,0 )) {int ret; - ret =domain_add_dev_info (si_domain, pdev, + ret =domain_add_dev_info (si_domain, dev, hw_pass_through ?CONTEXT_TT_PASS_THROUGH :CONTEXT_TT_MULTI_LEVEL );
@@ -4201,7 +4200,7 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, dmar_domain->agaw--; } -return domain_add_dev_info (dmar_domain, pdev,CONTEXT_TT_MULTI_LEVEL ); +return domain_add_dev_info (dmar_domain, dev,CONTEXT_TT_MULTI_LEVEL ); } static void intel_iommu_detach_device(struct iommu_domain *domain,
Signature · 1 line
1.8.5.3
PATCH 29/33 iommu/vt-d: Remove pdev from iommu_no_mapping()
In reply to a message not in the archive--- drivers/iommu/intel-iommu.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-)
drivers/iommu/intel-iommu.c +5 -7
@@ -2902,10 +2902,9 @@ static int iommu_dummy(struct device *dev)return dev->archdata.iommu ==DUMMY_DEVICE_DOMAIN_INFO ; } -/* Check if the pdev needs to go through non-identity map and unmap process.*/ +/* Check if the dev needs to go through non-identity map and unmap process.*/ static int iommu_no_mapping (struct device *dev) { -struct pci_dev *pdev;int found;if (unlikely (!dev_is_pci (dev)))
@@ -2917,10 +2916,9 @@ static int iommu_no_mapping(struct device *dev)if (!iommu_identity_mapping)return 0 ; - pdev =to_pci_dev (dev); found =identity_mapping (dev);if (found) { -if (iommu_should_identity_map (&pdev->dev,0 )) +if (iommu_should_identity_map (dev,0 ))return 1 ;else {/*
@@ -2929,7 +2927,7 @@ static int iommu_no_mapping(struct device *dev)*/ domain_remove_one_dev_info (si_domain, dev);printk (KERN_INFO "32bit %s uses non-identity mapping\n" , -pci_name (pdev)); +dev_name (dev));return 0 ; } }else {
@@ -2937,7 +2935,7 @@ static int iommu_no_mapping(struct device *dev)* In case of a detached 64 bit DMA device from vm, the device * is put into si_domain for identity mapping. */ -if (iommu_should_identity_map (&pdev->dev,0 )) { +if (iommu_should_identity_map (dev,0 )) {int ret; ret = domain_add_dev_info(si_domain, dev, hw_pass_through ?
@@ -2945,7 +2943,7 @@ static int iommu_no_mapping(struct device *dev) CONTEXT_TT_MULTI_LEVEL);if (!ret) {printk (KERN_INFO "64bit %s uses identity mapping\n" , -pci_name (pdev)); +dev_name (dev));return 1 ; } }
Signature · 1 line
1.8.5.3
PATCH 30/33 iommu/vt-d: Remove pdev from intel_iommu_attach_device()
In reply to a message not in the archive--- drivers/iommu/intel-iommu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/iommu/intel-iommu.c +2 -3
@@ -4147,13 +4147,12 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, struct device *dev) {struct dmar_domain *dmar_domain = domain->priv; -struct pci_dev *pdev =to_pci_dev (dev);struct intel_iommu *iommu;int addr_width;u8 bus, devfn; -/* normally pdev is not mapped */ -if (unlikely (domain_context_mapped (&pdev->dev))) { +/* normally dev is not mapped */ +if (unlikely (domain_context_mapped (dev))) {struct dmar_domain *old_domain; old_domain =find_domain (dev);
Signature · 1 line
1.8.5.3
PATCH 31/33 iommu/vt-d: Remove to_pci_dev() in intel_map_page()
In reply to a message not in the archiveIt might not be...
--- drivers/iommu/intel-iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iommu/intel-iommu.c +1 -1
@@ -3023,7 +3023,7 @@ static dma_addr_t intel_map_page(struct device *dev, struct page *page, struct dma_attrs *attrs) {return __intel_map_single (dev,page_to_phys (page) + offset, size, - dir,to_pci_dev (dev)->dma_mask); + dir, *dev->dma_mask); }static void flush_unmaps (void )
Signature · 1 line
1.8.5.3
PATCH 32/33 iommu/vt-d: Finally enable translation for non-PCI devices
In reply to a message not in the archive--- drivers/iommu/intel-iommu.c | 3 --- 1 file changed, 3 deletions(-)
drivers/iommu/intel-iommu.c +0 -3
@@ -2907,9 +2907,6 @@ static int iommu_no_mapping(struct device *dev) {int found; -if (unlikely (!dev_is_pci (dev))) -return 1 ; -if (iommu_dummy (dev))return 1 ;
Signature · 1 line
1.8.5.3
PATCH 33/33 iommu/vt-d: Include ACPI devices in iommu=pt
In reply to a message not in the archive--- drivers/iommu/intel-iommu.c | 61 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 13 deletions(-)
drivers/iommu/intel-iommu.c +48 -13
@@ -2595,30 +2595,65 @@ static int iommu_should_identity_map(struct device *dev, int startup)return 1 ; } +static int __init dev_prepare_static_identity_mapping (struct device *dev,int hw) +{ +int ret; + +if (!iommu_should_identity_map (dev,1 )) +return 0 ; + + ret =domain_add_dev_info (si_domain, dev, + hw ?CONTEXT_TT_PASS_THROUGH : +CONTEXT_TT_MULTI_LEVEL ); +if (!ret) +pr_info ("IOMMU: %s identity mapping for device %s\n" , + hw ?"hardware" :"software" ,dev_name (dev)); +else if (ret == -ENODEV ) +/* device not associated with an iommu */ + ret =0 ; + +return ret; +} + +static int __init iommu_prepare_static_identity_mapping (int hw) {struct pci_dev *pdev =NULL ; -int ret; +struct dmar_drhd_unit *drhd; +struct intel_iommu *iommu; +struct device *dev; +int i; +int ret =0 ; ret =si_domain_init (hw);if (ret)return -EFAULT ;for_each_pci_dev (pdev) { -if (iommu_should_identity_map (&pdev->dev,1 )) { - ret =domain_add_dev_info (si_domain, &pdev->dev, - hw ?CONTEXT_TT_PASS_THROUGH : -CONTEXT_TT_MULTI_LEVEL ); -if (ret) { -/* device not associated with an iommu */ -if (ret == -ENODEV ) -continue ; -return ret; + ret =dev_prepare_static_identity_mapping (&pdev->dev, hw); +if (ret) +return ret; + } + +for_each_active_iommu (iommu, drhd) +for_each_active_dev_scope (drhd->devices, drhd->devices_cnt, i, dev) { +struct acpi_device_physical_node *pn; +struct acpi_device *adev; + +if (dev->bus != &acpi_bus_type) +continue ; + + adev=to_acpi_device (dev); +mutex_lock (&adev->physical_node_lock); +list_for_each_entry (pn, &adev->physical_node_list, node) { + ret =dev_prepare_static_identity_mapping (pn->dev, hw); +if (ret) +break ; } -pr_info ("IOMMU: %s identity mapping for device %s\n" , - hw ?"hardware" :"software" ,pci_name (pdev)); +mutex_unlock (&adev->physical_node_lock); +if (ret) +return ret; } - }return 0 ; }
Signature · 1 line
1.8.5.3
[PATCH 34/33] iommu/vt-d: Fix RCU annotations on device scope lists
In reply to a message not in the archiveIn commit d78e0ac577 ("iommu/vt-d: Change scope lists to struct device, bus, devfn") I converted the 'struct device *' arrays into an array of 'struct dmar_dev_scope', where:
struct dmar_dev_scope {
struct device *dev;
u8 bus;
u8 devfn;
};That commit contained changes such as this:
-extern void dmar_free_dev_scope(struct pci_dev __rcu ***devices, int *cnt); +extern void dmar_free_dev_scope(struct dmar_dev_scope __rcu **devices, int *cnt);
This was wrong; it is the device pointer which needs to be protected with RCU, and the above-cited change was moving the __rcu annotation so that it actually referred to the enclosing structure, not the device pointer itself.
Reported by the Intel 0-day build testing infrastructure. Thanks, Fengguang.
--- drivers/iommu/dmar.c | 8 ++++---- drivers/iommu/intel-iommu.c | 4 ++-- include/linux/dmar.h | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-)
drivers/iommu/dmar.c +4 -4
@@ -100,7 +100,7 @@ void *dmar_alloc_dev_scope(void *start, void *end, int *cnt)return kcalloc (*cnt,sizeof (struct dmar_dev_scope ),GFP_KERNEL ); } -void dmar_free_dev_scope (struct dmar_dev_scope __rcu **devices,int *cnt) +void dmar_free_dev_scope (struct dmar_dev_scope **devices,int *cnt) {int i;struct device *tmp_dev;
@@ -191,7 +191,7 @@ static bool dmar_match_pci_path(struct dmar_pci_notify_info *info, int bus,/* Return: > 0 if match found, 0 if no match found, < 0 if error happens */ int dmar_insert_dev_scope (struct dmar_pci_notify_info *info,void *start,void *end,u16 segment, -struct dmar_dev_scope __rcu *devices, +struct dmar_dev_scope *devices,int devices_cnt) {int i, level;
@@ -235,7 +235,7 @@ int dmar_insert_dev_scope(struct dmar_pci_notify_info *info, }int dmar_remove_dev_scope (struct dmar_pci_notify_info *info,u16 segment, -struct dmar_dev_scope __rcu *devices,int count) +struct dmar_dev_scope *devices,int count) {int index;struct device *tmp;
@@ -565,7 +565,7 @@ parse_dmar_table(void)return ret; } -static int dmar_pci_device_match (struct dmar_dev_scope __rcu devices[], +static int dmar_pci_device_match (struct dmar_dev_scope devices[],int cnt,struct pci_dev *dev) {int index;
drivers/iommu/intel-iommu.c +2 -2
@@ -381,14 +381,14 @@ struct dmar_rmrr_unit {struct acpi_dmar_header *hdr;/* ACPI header */ u64 base_address;/* reserved base address*/ u64 end_address;/* reserved end address */ -struct dmar_dev_scope __rcu *devices;/* target devices */ +struct dmar_dev_scope *devices;/* target devices */ int devices_cnt;/* target device count */ };struct dmar_atsr_unit {struct list_head list;/* list of ATSR units */ struct acpi_dmar_header *hdr;/* ACPI header */ -struct dmar_dev_scope __rcu *devices;/* target devices */ +struct dmar_dev_scope *devices;/* target devices */ int devices_cnt;/* target device count */ u8 include_all:1 ;/* include all ports */ };
include/linux/dmar.h +5 -5
@@ -37,7 +37,7 @@ struct acpi_dmar_header;struct intel_iommu ;struct dmar_dev_scope { -struct device *dev; +struct device __rcu *dev;u8 bus;u8 devfn; };
@@ -48,7 +48,7 @@ struct dmar_drhd_unit {struct list_head list;/* list of drhd units */ struct acpi_dmar_header *hdr;/* ACPI header */ u64 reg_base_addr;/* register base address*/ -struct dmar_dev_scope __rcu *devices;/* target device array */ +struct dmar_dev_scope *devices;/* target device array */ int devices_cnt;/* target device count */ u16 segment;/* PCI domain */ u8 ignored:1; /* ignore drhd */
@@ -103,13 +103,13 @@ extern int dmar_dev_scope_init(void);extern int dmar_parse_dev_scope (void *start,void *end,int *cnt,struct dmar_dev_scope **devices,u16 segment);extern void *dmar_alloc_dev_scope (void *start,void *end,int *cnt); -extern void dmar_free_dev_scope (struct dmar_dev_scope __rcu **devices,int *cnt); +extern void dmar_free_dev_scope (struct dmar_dev_scope **devices,int *cnt);extern int dmar_insert_dev_scope (struct dmar_pci_notify_info *info,void *start,void *end,u16 segment, -struct dmar_dev_scope __rcu *devices, +struct dmar_dev_scope *devices,int devices_cnt);extern int dmar_remove_dev_scope (struct dmar_pci_notify_info *info, -u16 segment,struct dmar_dev_scope __rcu *devices, +u16 segment,struct dmar_dev_scope *devices,int count);/* Intel IOMMU detection */ extern int detect_intel_iommu (void );
Signature · 6 lines
1.8.5.3 -- David Woodhouse Open Source Technology Centre [email protected] Intel Corporation