diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2008-12-10 12:27:25 -0500 |
---|---|---|
committer | Joerg Roedel <joerg.roedel@amd.com> | 2009-01-03 08:11:55 -0500 |
commit | e275a2a0fc9e2168b15f6c7814e30b7ad58b1c7c (patch) | |
tree | d9cb9771b53c0d631497eb248667c56e1a6a6deb /arch/x86/kernel/amd_iommu.c | |
parent | 355bf553edb7fe21ada51f62c849180bec6da877 (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/kernel/amd_iommu.c')
-rw-r--r-- | arch/x86/kernel/amd_iommu.c | 62 |
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 | ||
48 | static int dma_ops_unity_map(struct dma_ops_domain *dma_dom, | 48 | static int dma_ops_unity_map(struct dma_ops_domain *dma_dom, |
49 | struct unity_map_entry *e); | 49 | struct unity_map_entry *e); |
50 | static 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 */ |
52 | static int iommu_has_npcache(struct amd_iommu *iommu) | 54 | static 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 | |
886 | static 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 | |||
934 | out: | ||
935 | return 0; | ||
936 | } | ||
937 | |||
938 | struct 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 | ||
1515 | free_domains: | 1573 | free_domains: |