On Tue, Jan 7, 2014 at 5:00 PM, Jiang Liu <[email protected]> wrote:

> 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 <[email protected]>
> ---
>  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;
> +}
>

I am a little bit confused about the "alloc before check" sequence in above
function. I believe the purpose of allocating the device_domain_info before
searching the domain with spin_lock hold is to avoid the memory allocation
in the spin_lock? In this case, why can't we use mutex instead of
spin_lock? In my understanding, if we use mutex, we can first check if the
domain exists or not before we really allocate device_domain_info, right?

Another question is when is info->iommu field initialized? Looks it is not
initialized here?

-Kai

+
>  /* 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
>
> _______________________________________________
> iommu mailing list
> [email protected]
> https://lists.linuxfoundation.org/mailman/listinfo/iommu
>
_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to