diff options
author | Jiang Liu <jiang.liu@linux.intel.com> | 2014-02-19 01:07:26 -0500 |
---|---|---|
committer | Joerg Roedel <joro@8bytes.org> | 2014-03-04 11:51:01 -0500 |
commit | 745f2586e78efc5c226a60cfc8e7fbd735b1c856 (patch) | |
tree | bc4cb38cbf06f6df84d9e353bbed4a4f12c5b46d | |
parent | b94e4117f8c4ffb591b1e462364d725e3a1c63c4 (diff) |
iommu/vt-d: Simplify function get_domain_for_dev()
Function get_domain_for_dev() is a little complex, simplify it
by factoring out dmar_search_domain_by_dev_info() and
dmar_insert_dev_info().
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
Signed-off-by: Joerg Roedel <joro@8bytes.org>
-rw-r--r-- | drivers/iommu/intel-iommu.c | 142 |
1 files changed, 66 insertions, 76 deletions
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index fffe3d166662..67b114e784bc 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c | |||
@@ -1957,18 +1957,71 @@ find_domain(struct pci_dev *pdev) | |||
1957 | return NULL; | 1957 | return NULL; |
1958 | } | 1958 | } |
1959 | 1959 | ||
1960 | static inline struct dmar_domain * | ||
1961 | dmar_search_domain_by_dev_info(int segment, int bus, int devfn) | ||
1962 | { | ||
1963 | struct device_domain_info *info; | ||
1964 | |||
1965 | list_for_each_entry(info, &device_domain_list, global) | ||
1966 | if (info->segment == segment && info->bus == bus && | ||
1967 | info->devfn == devfn) | ||
1968 | return info->domain; | ||
1969 | |||
1970 | return NULL; | ||
1971 | } | ||
1972 | |||
1973 | static int dmar_insert_dev_info(int segment, int bus, int devfn, | ||
1974 | struct pci_dev *dev, struct dmar_domain **domp) | ||
1975 | { | ||
1976 | struct dmar_domain *found, *domain = *domp; | ||
1977 | struct device_domain_info *info; | ||
1978 | unsigned long flags; | ||
1979 | |||
1980 | info = alloc_devinfo_mem(); | ||
1981 | if (!info) | ||
1982 | return -ENOMEM; | ||
1983 | |||
1984 | info->segment = segment; | ||
1985 | info->bus = bus; | ||
1986 | info->devfn = devfn; | ||
1987 | info->dev = dev; | ||
1988 | info->domain = domain; | ||
1989 | if (!dev) | ||
1990 | domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES; | ||
1991 | |||
1992 | spin_lock_irqsave(&device_domain_lock, flags); | ||
1993 | if (dev) | ||
1994 | found = find_domain(dev); | ||
1995 | else | ||
1996 | found = dmar_search_domain_by_dev_info(segment, bus, devfn); | ||
1997 | if (found) { | ||
1998 | spin_unlock_irqrestore(&device_domain_lock, flags); | ||
1999 | free_devinfo_mem(info); | ||
2000 | if (found != domain) { | ||
2001 | domain_exit(domain); | ||
2002 | *domp = found; | ||
2003 | } | ||
2004 | } else { | ||
2005 | list_add(&info->link, &domain->devices); | ||
2006 | list_add(&info->global, &device_domain_list); | ||
2007 | if (dev) | ||
2008 | dev->dev.archdata.iommu = info; | ||
2009 | spin_unlock_irqrestore(&device_domain_lock, flags); | ||
2010 | } | ||
2011 | |||
2012 | return 0; | ||
2013 | } | ||
2014 | |||
1960 | /* domain is initialized */ | 2015 | /* domain is initialized */ |
1961 | static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) | 2016 | static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) |
1962 | { | 2017 | { |
1963 | struct dmar_domain *domain, *found = NULL; | 2018 | struct dmar_domain *domain; |
1964 | struct intel_iommu *iommu; | 2019 | struct intel_iommu *iommu; |
1965 | struct dmar_drhd_unit *drhd; | 2020 | struct dmar_drhd_unit *drhd; |
1966 | struct device_domain_info *info, *tmp; | ||
1967 | struct pci_dev *dev_tmp; | 2021 | struct pci_dev *dev_tmp; |
1968 | unsigned long flags; | 2022 | unsigned long flags; |
1969 | int bus = 0, devfn = 0; | 2023 | int bus = 0, devfn = 0; |
1970 | int segment; | 2024 | int segment; |
1971 | int ret; | ||
1972 | 2025 | ||
1973 | domain = find_domain(pdev); | 2026 | domain = find_domain(pdev); |
1974 | if (domain) | 2027 | if (domain) |
@@ -1986,41 +2039,29 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) | |||
1986 | devfn = dev_tmp->devfn; | 2039 | devfn = dev_tmp->devfn; |
1987 | } | 2040 | } |
1988 | spin_lock_irqsave(&device_domain_lock, flags); | 2041 | spin_lock_irqsave(&device_domain_lock, flags); |
1989 | list_for_each_entry(info, &device_domain_list, global) { | 2042 | domain = dmar_search_domain_by_dev_info(segment, bus, devfn); |
1990 | if (info->segment == segment && | ||
1991 | info->bus == bus && info->devfn == devfn) { | ||
1992 | found = info->domain; | ||
1993 | break; | ||
1994 | } | ||
1995 | } | ||
1996 | spin_unlock_irqrestore(&device_domain_lock, flags); | 2043 | spin_unlock_irqrestore(&device_domain_lock, flags); |
1997 | /* pcie-pci bridge already has a domain, uses it */ | 2044 | /* pcie-pci bridge already has a domain, uses it */ |
1998 | if (found) { | 2045 | if (domain) |
1999 | domain = found; | ||
2000 | goto found_domain; | 2046 | goto found_domain; |
2001 | } | ||
2002 | } | 2047 | } |
2003 | 2048 | ||
2004 | domain = alloc_domain(); | ||
2005 | if (!domain) | ||
2006 | goto error; | ||
2007 | |||
2008 | /* Allocate new domain for the device */ | ||
2009 | drhd = dmar_find_matched_drhd_unit(pdev); | 2049 | drhd = dmar_find_matched_drhd_unit(pdev); |
2010 | if (!drhd) { | 2050 | if (!drhd) { |
2011 | printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n", | 2051 | printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n", |
2012 | pci_name(pdev)); | 2052 | pci_name(pdev)); |
2013 | free_domain_mem(domain); | ||
2014 | return NULL; | 2053 | return NULL; |
2015 | } | 2054 | } |
2016 | iommu = drhd->iommu; | 2055 | iommu = drhd->iommu; |
2017 | 2056 | ||
2018 | ret = iommu_attach_domain(domain, iommu); | 2057 | /* Allocate and intialize new domain for the device */ |
2019 | if (ret) { | 2058 | domain = alloc_domain(); |
2059 | if (!domain) | ||
2060 | goto error; | ||
2061 | if (iommu_attach_domain(domain, iommu)) { | ||
2020 | free_domain_mem(domain); | 2062 | free_domain_mem(domain); |
2021 | goto error; | 2063 | goto error; |
2022 | } | 2064 | } |
2023 | |||
2024 | if (domain_init(domain, gaw)) { | 2065 | if (domain_init(domain, gaw)) { |
2025 | domain_exit(domain); | 2066 | domain_exit(domain); |
2026 | goto error; | 2067 | goto error; |
@@ -2028,67 +2069,16 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) | |||
2028 | 2069 | ||
2029 | /* register pcie-to-pci device */ | 2070 | /* register pcie-to-pci device */ |
2030 | if (dev_tmp) { | 2071 | if (dev_tmp) { |
2031 | info = alloc_devinfo_mem(); | 2072 | if (dmar_insert_dev_info(segment, bus, devfn, NULL, &domain)) { |
2032 | if (!info) { | ||
2033 | domain_exit(domain); | 2073 | domain_exit(domain); |
2034 | goto error; | 2074 | goto error; |
2035 | } | 2075 | } |
2036 | info->segment = segment; | ||
2037 | info->bus = bus; | ||
2038 | info->devfn = devfn; | ||
2039 | info->dev = NULL; | ||
2040 | info->domain = domain; | ||
2041 | /* This domain is shared by devices under p2p bridge */ | ||
2042 | domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES; | ||
2043 | |||
2044 | /* pcie-to-pci bridge already has a domain, uses it */ | ||
2045 | found = NULL; | ||
2046 | spin_lock_irqsave(&device_domain_lock, flags); | ||
2047 | list_for_each_entry(tmp, &device_domain_list, global) { | ||
2048 | if (tmp->segment == segment && | ||
2049 | tmp->bus == bus && tmp->devfn == devfn) { | ||
2050 | found = tmp->domain; | ||
2051 | break; | ||
2052 | } | ||
2053 | } | ||
2054 | if (found) { | ||
2055 | spin_unlock_irqrestore(&device_domain_lock, flags); | ||
2056 | free_devinfo_mem(info); | ||
2057 | domain_exit(domain); | ||
2058 | domain = found; | ||
2059 | } else { | ||
2060 | list_add(&info->link, &domain->devices); | ||
2061 | list_add(&info->global, &device_domain_list); | ||
2062 | spin_unlock_irqrestore(&device_domain_lock, flags); | ||
2063 | } | ||
2064 | } | 2076 | } |
2065 | 2077 | ||
2066 | found_domain: | 2078 | found_domain: |
2067 | info = alloc_devinfo_mem(); | 2079 | if (dmar_insert_dev_info(segment, pdev->bus->number, pdev->devfn, |
2068 | if (!info) | 2080 | pdev, &domain) == 0) |
2069 | goto error; | ||
2070 | info->segment = segment; | ||
2071 | info->bus = pdev->bus->number; | ||
2072 | info->devfn = pdev->devfn; | ||
2073 | info->dev = pdev; | ||
2074 | info->domain = domain; | ||
2075 | spin_lock_irqsave(&device_domain_lock, flags); | ||
2076 | /* somebody is fast */ | ||
2077 | found = find_domain(pdev); | ||
2078 | if (found != NULL) { | ||
2079 | spin_unlock_irqrestore(&device_domain_lock, flags); | ||
2080 | if (found != domain) { | ||
2081 | domain_exit(domain); | ||
2082 | domain = found; | ||
2083 | } | ||
2084 | free_devinfo_mem(info); | ||
2085 | return domain; | 2081 | return domain; |
2086 | } | ||
2087 | list_add(&info->link, &domain->devices); | ||
2088 | list_add(&info->global, &device_domain_list); | ||
2089 | pdev->dev.archdata.iommu = info; | ||
2090 | spin_unlock_irqrestore(&device_domain_lock, flags); | ||
2091 | return domain; | ||
2092 | error: | 2082 | error: |
2093 | /* recheck it here, maybe others set it */ | 2083 | /* recheck it here, maybe others set it */ |
2094 | return find_domain(pdev); | 2084 | return find_domain(pdev); |