diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries/iommu.c')
-rw-r--r-- | arch/powerpc/platforms/pseries/iommu.c | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 1b2a174e7c59..86ae364900d6 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c | |||
@@ -924,6 +924,13 @@ static void restore_default_window(struct pci_dev *dev, | |||
924 | __restore_default_window(pci_dev_to_eeh_dev(dev), ddw_restore_token); | 924 | __restore_default_window(pci_dev_to_eeh_dev(dev), ddw_restore_token); |
925 | } | 925 | } |
926 | 926 | ||
927 | struct failed_ddw_pdn { | ||
928 | struct device_node *pdn; | ||
929 | struct list_head list; | ||
930 | }; | ||
931 | |||
932 | static LIST_HEAD(failed_ddw_pdn_list); | ||
933 | |||
927 | /* | 934 | /* |
928 | * If the PE supports dynamic dma windows, and there is space for a table | 935 | * If the PE supports dynamic dma windows, and there is space for a table |
929 | * that can map all pages in a linear offset, then setup such a table, | 936 | * that can map all pages in a linear offset, then setup such a table, |
@@ -951,6 +958,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) | |||
951 | struct dynamic_dma_window_prop *ddwprop; | 958 | struct dynamic_dma_window_prop *ddwprop; |
952 | const void *dma_window = NULL; | 959 | const void *dma_window = NULL; |
953 | unsigned long liobn, offset, size; | 960 | unsigned long liobn, offset, size; |
961 | struct failed_ddw_pdn *fpdn; | ||
954 | 962 | ||
955 | mutex_lock(&direct_window_init_mutex); | 963 | mutex_lock(&direct_window_init_mutex); |
956 | 964 | ||
@@ -959,6 +967,18 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) | |||
959 | goto out_unlock; | 967 | goto out_unlock; |
960 | 968 | ||
961 | /* | 969 | /* |
970 | * If we already went through this for a previous function of | ||
971 | * the same device and failed, we don't want to muck with the | ||
972 | * DMA window again, as it will race with in-flight operations | ||
973 | * and can lead to EEHs. The above mutex protects access to the | ||
974 | * list. | ||
975 | */ | ||
976 | list_for_each_entry(fpdn, &failed_ddw_pdn_list, list) { | ||
977 | if (!strcmp(fpdn->pdn->full_name, pdn->full_name)) | ||
978 | goto out_unlock; | ||
979 | } | ||
980 | |||
981 | /* | ||
962 | * the ibm,ddw-applicable property holds the tokens for: | 982 | * the ibm,ddw-applicable property holds the tokens for: |
963 | * ibm,query-pe-dma-window | 983 | * ibm,query-pe-dma-window |
964 | * ibm,create-pe-dma-window | 984 | * ibm,create-pe-dma-window |
@@ -1114,6 +1134,12 @@ out_restore_window: | |||
1114 | if (ddw_restore_token) | 1134 | if (ddw_restore_token) |
1115 | restore_default_window(dev, ddw_restore_token); | 1135 | restore_default_window(dev, ddw_restore_token); |
1116 | 1136 | ||
1137 | fpdn = kzalloc(sizeof(*fpdn), GFP_KERNEL); | ||
1138 | if (!fpdn) | ||
1139 | goto out_unlock; | ||
1140 | fpdn->pdn = pdn; | ||
1141 | list_add(&fpdn->list, &failed_ddw_pdn_list); | ||
1142 | |||
1117 | out_unlock: | 1143 | out_unlock: |
1118 | mutex_unlock(&direct_window_init_mutex); | 1144 | mutex_unlock(&direct_window_init_mutex); |
1119 | return dma_addr; | 1145 | return dma_addr; |