diff options
Diffstat (limited to 'arch/powerpc/kernel/iommu.c')
-rw-r--r-- | arch/powerpc/kernel/iommu.c | 69 |
1 files changed, 11 insertions, 58 deletions
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index f0dc680e659a..9d5d109f15c0 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <asm/fadump.h> | 47 | #include <asm/fadump.h> |
48 | #include <asm/vio.h> | 48 | #include <asm/vio.h> |
49 | #include <asm/tce.h> | 49 | #include <asm/tce.h> |
50 | #include <asm/mmu_context.h> | ||
50 | 51 | ||
51 | #define DBG(...) | 52 | #define DBG(...) |
52 | 53 | ||
@@ -993,15 +994,19 @@ int iommu_tce_check_gpa(unsigned long page_shift, unsigned long gpa) | |||
993 | } | 994 | } |
994 | EXPORT_SYMBOL_GPL(iommu_tce_check_gpa); | 995 | EXPORT_SYMBOL_GPL(iommu_tce_check_gpa); |
995 | 996 | ||
996 | long iommu_tce_xchg(struct iommu_table *tbl, unsigned long entry, | 997 | long iommu_tce_xchg(struct mm_struct *mm, struct iommu_table *tbl, |
997 | unsigned long *hpa, enum dma_data_direction *direction) | 998 | unsigned long entry, unsigned long *hpa, |
999 | enum dma_data_direction *direction) | ||
998 | { | 1000 | { |
999 | long ret; | 1001 | long ret; |
1002 | unsigned long size = 0; | ||
1000 | 1003 | ||
1001 | ret = tbl->it_ops->exchange(tbl, entry, hpa, direction); | 1004 | ret = tbl->it_ops->exchange(tbl, entry, hpa, direction); |
1002 | 1005 | ||
1003 | if (!ret && ((*direction == DMA_FROM_DEVICE) || | 1006 | if (!ret && ((*direction == DMA_FROM_DEVICE) || |
1004 | (*direction == DMA_BIDIRECTIONAL))) | 1007 | (*direction == DMA_BIDIRECTIONAL)) && |
1008 | !mm_iommu_is_devmem(mm, *hpa, tbl->it_page_shift, | ||
1009 | &size)) | ||
1005 | SetPageDirty(pfn_to_page(*hpa >> PAGE_SHIFT)); | 1010 | SetPageDirty(pfn_to_page(*hpa >> PAGE_SHIFT)); |
1006 | 1011 | ||
1007 | /* if (unlikely(ret)) | 1012 | /* if (unlikely(ret)) |
@@ -1073,11 +1078,8 @@ void iommu_release_ownership(struct iommu_table *tbl) | |||
1073 | } | 1078 | } |
1074 | EXPORT_SYMBOL_GPL(iommu_release_ownership); | 1079 | EXPORT_SYMBOL_GPL(iommu_release_ownership); |
1075 | 1080 | ||
1076 | int iommu_add_device(struct device *dev) | 1081 | int iommu_add_device(struct iommu_table_group *table_group, struct device *dev) |
1077 | { | 1082 | { |
1078 | struct iommu_table *tbl; | ||
1079 | struct iommu_table_group_link *tgl; | ||
1080 | |||
1081 | /* | 1083 | /* |
1082 | * The sysfs entries should be populated before | 1084 | * The sysfs entries should be populated before |
1083 | * binding IOMMU group. If sysfs entries isn't | 1085 | * binding IOMMU group. If sysfs entries isn't |
@@ -1093,32 +1095,10 @@ int iommu_add_device(struct device *dev) | |||
1093 | return -EBUSY; | 1095 | return -EBUSY; |
1094 | } | 1096 | } |
1095 | 1097 | ||
1096 | tbl = get_iommu_table_base(dev); | ||
1097 | if (!tbl) { | ||
1098 | pr_debug("%s: Skipping device %s with no tbl\n", | ||
1099 | __func__, dev_name(dev)); | ||
1100 | return 0; | ||
1101 | } | ||
1102 | |||
1103 | tgl = list_first_entry_or_null(&tbl->it_group_list, | ||
1104 | struct iommu_table_group_link, next); | ||
1105 | if (!tgl) { | ||
1106 | pr_debug("%s: Skipping device %s with no group\n", | ||
1107 | __func__, dev_name(dev)); | ||
1108 | return 0; | ||
1109 | } | ||
1110 | pr_debug("%s: Adding %s to iommu group %d\n", | 1098 | pr_debug("%s: Adding %s to iommu group %d\n", |
1111 | __func__, dev_name(dev), | 1099 | __func__, dev_name(dev), iommu_group_id(table_group->group)); |
1112 | iommu_group_id(tgl->table_group->group)); | ||
1113 | |||
1114 | if (PAGE_SIZE < IOMMU_PAGE_SIZE(tbl)) { | ||
1115 | pr_err("%s: Invalid IOMMU page size %lx (%lx) on %s\n", | ||
1116 | __func__, IOMMU_PAGE_SIZE(tbl), | ||
1117 | PAGE_SIZE, dev_name(dev)); | ||
1118 | return -EINVAL; | ||
1119 | } | ||
1120 | 1100 | ||
1121 | return iommu_group_add_device(tgl->table_group->group, dev); | 1101 | return iommu_group_add_device(table_group->group, dev); |
1122 | } | 1102 | } |
1123 | EXPORT_SYMBOL_GPL(iommu_add_device); | 1103 | EXPORT_SYMBOL_GPL(iommu_add_device); |
1124 | 1104 | ||
@@ -1138,31 +1118,4 @@ void iommu_del_device(struct device *dev) | |||
1138 | iommu_group_remove_device(dev); | 1118 | iommu_group_remove_device(dev); |
1139 | } | 1119 | } |
1140 | EXPORT_SYMBOL_GPL(iommu_del_device); | 1120 | EXPORT_SYMBOL_GPL(iommu_del_device); |
1141 | |||
1142 | static int tce_iommu_bus_notifier(struct notifier_block *nb, | ||
1143 | unsigned long action, void *data) | ||
1144 | { | ||
1145 | struct device *dev = data; | ||
1146 | |||
1147 | switch (action) { | ||
1148 | case BUS_NOTIFY_ADD_DEVICE: | ||
1149 | return iommu_add_device(dev); | ||
1150 | case BUS_NOTIFY_DEL_DEVICE: | ||
1151 | if (dev->iommu_group) | ||
1152 | iommu_del_device(dev); | ||
1153 | return 0; | ||
1154 | default: | ||
1155 | return 0; | ||
1156 | } | ||
1157 | } | ||
1158 | |||
1159 | static struct notifier_block tce_iommu_bus_nb = { | ||
1160 | .notifier_call = tce_iommu_bus_notifier, | ||
1161 | }; | ||
1162 | |||
1163 | int __init tce_iommu_bus_notifier_init(void) | ||
1164 | { | ||
1165 | bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb); | ||
1166 | return 0; | ||
1167 | } | ||
1168 | #endif /* CONFIG_IOMMU_API */ | 1121 | #endif /* CONFIG_IOMMU_API */ |