intel-iommu: fix for IOMMU early crash

pci_dev's->sysdata is highly overloaded and currently IOMMU is broken due
to IOMMU code depending on this field.

This patch introduces new field in pci_dev's dev.archdata struct to hold
IOMMU specific per device IOMMU private data.

Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Greg KH <greg@kroah.com>
Cc: Jeff Garzik <jeff@garzik.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Keshavamurthy, Anil S 2007-10-21 16:41:59 -07:00 committed by Linus Torvalds
parent f76aec76ec
commit 358dd8ac53
2 changed files with 14 additions and 11 deletions

View File

@ -1348,7 +1348,7 @@ static void domain_remove_dev_info(struct dmar_domain *domain)
list_del(&info->link); list_del(&info->link);
list_del(&info->global); list_del(&info->global);
if (info->dev) if (info->dev)
info->dev->sysdata = NULL; info->dev->dev.archdata.iommu = NULL;
spin_unlock_irqrestore(&device_domain_lock, flags); spin_unlock_irqrestore(&device_domain_lock, flags);
detach_domain_for_dev(info->domain, info->bus, info->devfn); detach_domain_for_dev(info->domain, info->bus, info->devfn);
@ -1361,7 +1361,7 @@ static void domain_remove_dev_info(struct dmar_domain *domain)
/* /*
* find_domain * find_domain
* Note: we use struct pci_dev->sysdata stores the info * Note: we use struct pci_dev->dev.archdata.iommu stores the info
*/ */
struct dmar_domain * struct dmar_domain *
find_domain(struct pci_dev *pdev) find_domain(struct pci_dev *pdev)
@ -1369,7 +1369,7 @@ find_domain(struct pci_dev *pdev)
struct device_domain_info *info; struct device_domain_info *info;
/* No lock here, assumes no domain exit in normal case */ /* No lock here, assumes no domain exit in normal case */
info = pdev->sysdata; info = pdev->dev.archdata.iommu;
if (info) if (info)
return info->domain; return info->domain;
return NULL; return NULL;
@ -1519,7 +1519,7 @@ found_domain:
} }
list_add(&info->link, &domain->devices); list_add(&info->link, &domain->devices);
list_add(&info->global, &device_domain_list); list_add(&info->global, &device_domain_list);
pdev->sysdata = info; pdev->dev.archdata.iommu = info;
spin_unlock_irqrestore(&device_domain_lock, flags); spin_unlock_irqrestore(&device_domain_lock, flags);
return domain; return domain;
error: error:
@ -1579,7 +1579,7 @@ error:
static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr, static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
struct pci_dev *pdev) struct pci_dev *pdev)
{ {
if (pdev->sysdata == DUMMY_DEVICE_DOMAIN_INFO) if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
return 0; return 0;
return iommu_prepare_identity_map(pdev, rmrr->base_address, return iommu_prepare_identity_map(pdev, rmrr->base_address,
rmrr->end_address + 1); rmrr->end_address + 1);
@ -1595,7 +1595,7 @@ static void __init iommu_prepare_gfx_mapping(void)
int ret; int ret;
for_each_pci_dev(pdev) { for_each_pci_dev(pdev) {
if (pdev->sysdata == DUMMY_DEVICE_DOMAIN_INFO || if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO ||
!IS_GFX_DEVICE(pdev)) !IS_GFX_DEVICE(pdev))
continue; continue;
printk(KERN_INFO "IOMMU: gfx device %s 1-1 mapping\n", printk(KERN_INFO "IOMMU: gfx device %s 1-1 mapping\n",
@ -1836,7 +1836,7 @@ static dma_addr_t intel_map_single(struct device *hwdev, void *addr,
int prot = 0; int prot = 0;
BUG_ON(dir == DMA_NONE); BUG_ON(dir == DMA_NONE);
if (pdev->sysdata == DUMMY_DEVICE_DOMAIN_INFO) if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
return virt_to_bus(addr); return virt_to_bus(addr);
domain = get_valid_domain_for_dev(pdev); domain = get_valid_domain_for_dev(pdev);
@ -1900,7 +1900,7 @@ static void intel_unmap_single(struct device *dev, dma_addr_t dev_addr,
unsigned long start_addr; unsigned long start_addr;
struct iova *iova; struct iova *iova;
if (pdev->sysdata == DUMMY_DEVICE_DOMAIN_INFO) if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
return; return;
domain = find_domain(pdev); domain = find_domain(pdev);
BUG_ON(!domain); BUG_ON(!domain);
@ -1974,7 +1974,7 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sg,
size_t size = 0; size_t size = 0;
void *addr; void *addr;
if (pdev->sysdata == DUMMY_DEVICE_DOMAIN_INFO) if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
return; return;
domain = find_domain(pdev); domain = find_domain(pdev);
@ -2032,7 +2032,7 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sg,
unsigned long start_addr; unsigned long start_addr;
BUG_ON(dir == DMA_NONE); BUG_ON(dir == DMA_NONE);
if (pdev->sysdata == DUMMY_DEVICE_DOMAIN_INFO) if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
return intel_nontranslate_map_sg(hwdev, sg, nelems, dir); return intel_nontranslate_map_sg(hwdev, sg, nelems, dir);
domain = get_valid_domain_for_dev(pdev); domain = get_valid_domain_for_dev(pdev);
@ -2234,7 +2234,7 @@ static void __init init_no_remapping_devices(void)
for (i = 0; i < drhd->devices_cnt; i++) { for (i = 0; i < drhd->devices_cnt; i++) {
if (!drhd->devices[i]) if (!drhd->devices[i])
continue; continue;
drhd->devices[i]->sysdata = DUMMY_DEVICE_DOMAIN_INFO; drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
} }
} }
} }

View File

@ -5,6 +5,9 @@ struct dev_archdata {
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
void *acpi_handle; void *acpi_handle;
#endif #endif
#ifdef CONFIG_DMAR
void *iommu; /* hook for IOMMU specific extension */
#endif
}; };
#endif /* _ASM_X86_DEVICE_H */ #endif /* _ASM_X86_DEVICE_H */