aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorJoerg Roedel <joerg.roedel@amd.com>2008-12-10 12:27:25 -0500
committerJoerg Roedel <joerg.roedel@amd.com>2009-01-03 08:11:55 -0500
commite275a2a0fc9e2168b15f6c7814e30b7ad58b1c7c (patch)
treed9cb9771b53c0d631497eb248667c56e1a6a6deb /arch/x86
parent355bf553edb7fe21ada51f62c849180bec6da877 (diff)
AMD IOMMU: add device notifier callback
Impact: inform IOMMU about state change of a device in the driver core Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/kernel/amd_iommu.c62
1 files changed, 60 insertions, 2 deletions
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index 15456a3a18c8..140875b3f6ef 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -47,6 +47,8 @@ struct iommu_cmd {
47 47
48static int dma_ops_unity_map(struct dma_ops_domain *dma_dom, 48static int dma_ops_unity_map(struct dma_ops_domain *dma_dom,
49 struct unity_map_entry *e); 49 struct unity_map_entry *e);
50static struct dma_ops_domain *find_protection_domain(u16 devid);
51
50 52
51/* returns !0 if the IOMMU is caching non-present entries in its TLB */ 53/* returns !0 if the IOMMU is caching non-present entries in its TLB */
52static int iommu_has_npcache(struct amd_iommu *iommu) 54static int iommu_has_npcache(struct amd_iommu *iommu)
@@ -844,7 +846,6 @@ static void attach_device(struct amd_iommu *iommu,
844 iommu_queue_inv_dev_entry(iommu, devid); 846 iommu_queue_inv_dev_entry(iommu, devid);
845} 847}
846 848
847#ifdef CONFIG_IOMMU_API
848/* 849/*
849 * Removes a device from a protection domain (unlocked) 850 * Removes a device from a protection domain (unlocked)
850 */ 851 */
@@ -881,7 +882,62 @@ static void detach_device(struct protection_domain *domain, u16 devid)
881 __detach_device(domain, devid); 882 __detach_device(domain, devid);
882 write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); 883 write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
883} 884}
884#endif 885
886static int device_change_notifier(struct notifier_block *nb,
887 unsigned long action, void *data)
888{
889 struct device *dev = data;
890 struct pci_dev *pdev = to_pci_dev(dev);
891 u16 devid = calc_devid(pdev->bus->number, pdev->devfn);
892 struct protection_domain *domain;
893 struct dma_ops_domain *dma_domain;
894 struct amd_iommu *iommu;
895
896 if (devid > amd_iommu_last_bdf)
897 goto out;
898
899 devid = amd_iommu_alias_table[devid];
900
901 iommu = amd_iommu_rlookup_table[devid];
902 if (iommu == NULL)
903 goto out;
904
905 domain = domain_for_device(devid);
906
907 if (domain && !dma_ops_domain(domain))
908 WARN_ONCE(1, "AMD IOMMU WARNING: device %s already bound "
909 "to a non-dma-ops domain\n", dev_name(dev));
910
911 switch (action) {
912 case BUS_NOTIFY_BOUND_DRIVER:
913 if (domain)
914 goto out;
915 dma_domain = find_protection_domain(devid);
916 if (!dma_domain)
917 dma_domain = iommu->default_dom;
918 attach_device(iommu, &dma_domain->domain, devid);
919 printk(KERN_INFO "AMD IOMMU: Using protection domain %d for "
920 "device %s\n", dma_domain->domain.id, dev_name(dev));
921 break;
922 case BUS_NOTIFY_UNBIND_DRIVER:
923 if (!domain)
924 goto out;
925 detach_device(domain, devid);
926 break;
927 default:
928 goto out;
929 }
930
931 iommu_queue_inv_dev_entry(iommu, devid);
932 iommu_completion_wait(iommu);
933
934out:
935 return 0;
936}
937
938struct notifier_block device_nb = {
939 .notifier_call = device_change_notifier,
940};
885 941
886/***************************************************************************** 942/*****************************************************************************
887 * 943 *
@@ -1510,6 +1566,8 @@ int __init amd_iommu_init_dma_ops(void)
1510 /* Make the driver finally visible to the drivers */ 1566 /* Make the driver finally visible to the drivers */
1511 dma_ops = &amd_iommu_dma_ops; 1567 dma_ops = &amd_iommu_dma_ops;
1512 1568
1569 bus_register_notifier(&pci_bus_type, &device_nb);
1570
1513 return 0; 1571 return 0;
1514 1572
1515free_domains: 1573free_domains: