diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2011-06-09 11:48:39 -0400 |
---|---|---|
committer | Joerg Roedel <joerg.roedel@amd.com> | 2011-06-14 06:49:58 -0400 |
commit | 2b02b091ab3d1685926bfc76486bf7a22d92979a (patch) | |
tree | 0f4279ee639695f4e4934f32b46fccf495819acf | |
parent | ec9e79ef062272a119994c4fdd5e434f3e1bf352 (diff) |
x86/amd-iommu: Allow dev_data->alias to be NULL
Let dev_data->alias be just NULL if the device has no alias.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
-rw-r--r-- | arch/x86/kernel/amd_iommu.c | 77 |
1 files changed, 41 insertions, 36 deletions
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index a15a1723190..2d914a49b19 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c | |||
@@ -183,12 +183,14 @@ static int iommu_init_device(struct device *dev) | |||
183 | return -ENOMEM; | 183 | return -ENOMEM; |
184 | 184 | ||
185 | alias = amd_iommu_alias_table[dev_data->devid]; | 185 | alias = amd_iommu_alias_table[dev_data->devid]; |
186 | pdev = pci_get_bus_and_slot(PCI_BUS(alias), alias & 0xff); | 186 | if (alias != dev_data->devid) { |
187 | if (pdev) | 187 | pdev = pci_get_bus_and_slot(PCI_BUS(alias), alias & 0xff); |
188 | dev_data->alias = &pdev->dev; | 188 | if (pdev) |
189 | else { | 189 | dev_data->alias = &pdev->dev; |
190 | free_dev_data(dev_data); | 190 | else { |
191 | return -ENOTSUPP; | 191 | free_dev_data(dev_data); |
192 | return -ENOTSUPP; | ||
193 | } | ||
192 | } | 194 | } |
193 | 195 | ||
194 | dev->archdata.iommu = dev_data; | 196 | dev->archdata.iommu = dev_data; |
@@ -1604,29 +1606,31 @@ static void do_detach(struct iommu_dev_data *dev_data) | |||
1604 | static int __attach_device(struct iommu_dev_data *dev_data, | 1606 | static int __attach_device(struct iommu_dev_data *dev_data, |
1605 | struct protection_domain *domain) | 1607 | struct protection_domain *domain) |
1606 | { | 1608 | { |
1607 | struct iommu_dev_data *alias_data; | ||
1608 | int ret; | 1609 | int ret; |
1609 | 1610 | ||
1610 | alias_data = get_dev_data(dev_data->alias); | ||
1611 | |||
1612 | if (!alias_data) | ||
1613 | return -EINVAL; | ||
1614 | |||
1615 | /* lock domain */ | 1611 | /* lock domain */ |
1616 | spin_lock(&domain->lock); | 1612 | spin_lock(&domain->lock); |
1617 | 1613 | ||
1618 | /* Some sanity checks */ | 1614 | if (dev_data->alias != NULL) { |
1619 | ret = -EBUSY; | 1615 | struct iommu_dev_data *alias_data; |
1620 | if (alias_data->domain != NULL && | 1616 | |
1621 | alias_data->domain != domain) | 1617 | alias_data = get_dev_data(dev_data->alias); |
1622 | goto out_unlock; | 1618 | |
1619 | ret = -EINVAL; | ||
1620 | if (!alias_data) | ||
1621 | goto out_unlock; | ||
1623 | 1622 | ||
1624 | if (dev_data->domain != NULL && | 1623 | /* Some sanity checks */ |
1625 | dev_data->domain != domain) | 1624 | ret = -EBUSY; |
1626 | goto out_unlock; | 1625 | if (alias_data->domain != NULL && |
1626 | alias_data->domain != domain) | ||
1627 | goto out_unlock; | ||
1627 | 1628 | ||
1628 | /* Do real assignment */ | 1629 | if (dev_data->domain != NULL && |
1629 | if (dev_data->devid != alias_data->devid) { | 1630 | dev_data->domain != domain) |
1631 | goto out_unlock; | ||
1632 | |||
1633 | /* Do real assignment */ | ||
1630 | if (alias_data->domain == NULL) | 1634 | if (alias_data->domain == NULL) |
1631 | do_attach(alias_data, domain); | 1635 | do_attach(alias_data, domain); |
1632 | 1636 | ||
@@ -1696,8 +1700,8 @@ static void __detach_device(struct iommu_dev_data *dev_data) | |||
1696 | 1700 | ||
1697 | spin_lock_irqsave(&domain->lock, flags); | 1701 | spin_lock_irqsave(&domain->lock, flags); |
1698 | 1702 | ||
1699 | alias_data = get_dev_data(dev_data->alias); | 1703 | if (dev_data->alias) { |
1700 | if (dev_data->devid != alias_data->devid) { | 1704 | alias_data = get_dev_data(dev_data->alias); |
1701 | if (atomic_dec_and_test(&alias_data->bind)) | 1705 | if (atomic_dec_and_test(&alias_data->bind)) |
1702 | do_detach(alias_data); | 1706 | do_detach(alias_data); |
1703 | } | 1707 | } |
@@ -1744,24 +1748,25 @@ static void detach_device(struct device *dev) | |||
1744 | */ | 1748 | */ |
1745 | static struct protection_domain *domain_for_device(struct device *dev) | 1749 | static struct protection_domain *domain_for_device(struct device *dev) |
1746 | { | 1750 | { |
1747 | struct protection_domain *dom; | ||
1748 | struct iommu_dev_data *dev_data, *alias_data; | 1751 | struct iommu_dev_data *dev_data, *alias_data; |
1752 | struct protection_domain *dom = NULL; | ||
1749 | unsigned long flags; | 1753 | unsigned long flags; |
1750 | 1754 | ||
1751 | dev_data = get_dev_data(dev); | 1755 | dev_data = get_dev_data(dev); |
1752 | alias_data = get_dev_data(dev_data->alias); | ||
1753 | if (!alias_data) | ||
1754 | return NULL; | ||
1755 | 1756 | ||
1756 | read_lock_irqsave(&amd_iommu_devtable_lock, flags); | 1757 | if (dev_data->domain) |
1757 | dom = dev_data->domain; | 1758 | return dev_data->domain; |
1758 | if (dom == NULL && | ||
1759 | alias_data->domain != NULL) { | ||
1760 | __attach_device(dev_data, alias_data->domain); | ||
1761 | dom = alias_data->domain; | ||
1762 | } | ||
1763 | 1759 | ||
1764 | read_unlock_irqrestore(&amd_iommu_devtable_lock, flags); | 1760 | if (dev_data->alias != NULL) { |
1761 | alias_data = get_dev_data(dev_data->alias); | ||
1762 | |||
1763 | read_lock_irqsave(&amd_iommu_devtable_lock, flags); | ||
1764 | if (alias_data->domain != NULL) { | ||
1765 | __attach_device(dev_data, alias_data->domain); | ||
1766 | dom = alias_data->domain; | ||
1767 | } | ||
1768 | read_unlock_irqrestore(&amd_iommu_devtable_lock, flags); | ||
1769 | } | ||
1765 | 1770 | ||
1766 | return dom; | 1771 | return dom; |
1767 | } | 1772 | } |