lkml.org 
[lkml]   [2014]   [Jan]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[Patch Part2 V1 03/14] iommu/vt-d: simplify function get_domain_for_dev()
    Date
    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>
    ---
    drivers/iommu/intel-iommu.c | 161 ++++++++++++++++++++-----------------------
    1 file changed, 75 insertions(+), 86 deletions(-)

    diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
    index 1704e97..da65884 100644
    --- a/drivers/iommu/intel-iommu.c
    +++ b/drivers/iommu/intel-iommu.c
    @@ -1957,18 +1957,70 @@ find_domain(struct pci_dev *pdev)
    return NULL;
    }

    +static inline struct dmar_domain *
    +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 &&
    + info->devfn == devfn)
    + return info->domain;
    +
    + return NULL;
    +}
    +
    +static int dmar_insert_dev_info(int segment, int bus, int devfn,
    + struct pci_dev *dev, struct dmar_domain **domp)
    +{
    + struct dmar_domain *found, *domain = *domp;
    + struct device_domain_info *info;
    + unsigned long flags;
    +
    + info = alloc_devinfo_mem();
    + if (!info)
    + return -ENOMEM;
    +
    + info->segment = segment;
    + info->bus = bus;
    + info->devfn = devfn;
    + info->dev = dev;
    + info->domain = domain;
    + 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);
    + 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->dev.archdata.iommu = info;
    + spin_unlock_irqrestore(&device_domain_lock, flags);
    + }
    +
    + return 0;
    +}
    +
    /* domain is initialized */
    static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
    {
    - struct dmar_domain *domain, *found = NULL;
    + struct dmar_domain *domain;
    struct intel_iommu *iommu;
    struct dmar_drhd_unit *drhd;
    - struct device_domain_info *info, *tmp;
    - struct pci_dev *dev_tmp;
    + struct pci_dev *bridge;
    unsigned long flags;
    - int bus = 0, devfn = 0;
    - int segment;
    - int ret;
    + int segment, bus, devfn;

    domain = find_domain(pdev);
    if (domain)
    @@ -1976,119 +2028,56 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)

    segment = pci_domain_nr(pdev->bus);

    - dev_tmp = pci_find_upstream_pcie_bridge(pdev);
    - if (dev_tmp) {
    - if (pci_is_pcie(dev_tmp)) {
    - bus = dev_tmp->subordinate->number;
    + bridge = pci_find_upstream_pcie_bridge(pdev);
    + if (bridge) {
    + if (pci_is_pcie(bridge)) {
    + bus = bridge->subordinate->number;
    devfn = 0;
    } else {
    - bus = dev_tmp->bus->number;
    - devfn = dev_tmp->devfn;
    + bus = bridge->bus->number;
    + devfn = bridge->devfn;
    }
    spin_lock_irqsave(&device_domain_lock, flags);
    - list_for_each_entry(info, &device_domain_list, global) {
    - if (info->segment == segment &&
    - info->bus == bus && info->devfn == devfn) {
    - found = info->domain;
    - break;
    - }
    - }
    + domain = dmar_search_domain_by_dev_info(segment, bus, devfn);
    spin_unlock_irqrestore(&device_domain_lock, flags);
    /* pcie-pci bridge already has a domain, uses it */
    - if (found) {
    - domain = found;
    + if (domain)
    goto found_domain;
    - }
    }

    - domain = alloc_domain();
    - if (!domain)
    - goto error;
    -
    - /* Allocate new domain for the device */
    drhd = dmar_find_matched_drhd_unit(pdev);
    if (!drhd) {
    printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
    pci_name(pdev));
    - free_domain_mem(domain);
    return NULL;
    }
    iommu = drhd->iommu;

    - ret = iommu_attach_domain(domain, iommu);
    - if (ret) {
    + /* Allocate new domain for the device */
    + domain = alloc_domain();
    + if (!domain)
    + goto error;
    + if (iommu_attach_domain(domain, iommu)) {
    free_domain_mem(domain);
    goto error;
    }
    -
    if (domain_init(domain, gaw)) {
    domain_exit(domain);
    goto error;
    }

    /* register pcie-to-pci device */
    - if (dev_tmp) {
    - info = alloc_devinfo_mem();
    - if (!info) {
    + if (bridge) {
    + if (dmar_insert_dev_info(segment, bus, devfn, NULL, &domain)) {
    domain_exit(domain);
    goto error;
    }
    - info->segment = segment;
    - info->bus = bus;
    - info->devfn = devfn;
    - info->dev = NULL;
    - info->domain = domain;
    - /* This domain is shared by devices under p2p bridge */
    - domain->flags |= DOMAIN_FLAG_P2P_MULTIPLE_DEVICES;
    -
    - /* pcie-to-pci bridge already has a domain, uses it */
    - found = NULL;
    - spin_lock_irqsave(&device_domain_lock, flags);
    - list_for_each_entry(tmp, &device_domain_list, global) {
    - if (tmp->segment == segment &&
    - tmp->bus == bus && tmp->devfn == devfn) {
    - found = tmp->domain;
    - break;
    - }
    - }
    - if (found) {
    - spin_unlock_irqrestore(&device_domain_lock, flags);
    - free_devinfo_mem(info);
    - domain_exit(domain);
    - domain = found;
    - } else {
    - list_add(&info->link, &domain->devices);
    - list_add(&info->global, &device_domain_list);
    - spin_unlock_irqrestore(&device_domain_lock, flags);
    - }
    }

    found_domain:
    - info = alloc_devinfo_mem();
    - if (!info)
    - goto error;
    - info->segment = segment;
    - info->bus = pdev->bus->number;
    - info->devfn = pdev->devfn;
    - info->dev = pdev;
    - info->domain = domain;
    - spin_lock_irqsave(&device_domain_lock, flags);
    - /* somebody is fast */
    - found = find_domain(pdev);
    - if (found != NULL) {
    - spin_unlock_irqrestore(&device_domain_lock, flags);
    - if (found != domain) {
    - domain_exit(domain);
    - domain = found;
    - }
    - free_devinfo_mem(info);
    + if (dmar_insert_dev_info(segment, pdev->bus->number, pdev->devfn,
    + pdev, &domain) == 0)
    return domain;
    - }
    - 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);
    - return domain;
    error:
    /* recheck it here, maybe others set it */
    return find_domain(pdev);
    --
    1.7.10.4


    \
     
     \ /
      Last update: 2014-01-07 10:41    [W:4.185 / U:3.436 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site