diff options
Diffstat (limited to 'drivers/iommu/amd_iommu_init.c')
-rw-r--r-- | drivers/iommu/amd_iommu_init.c | 63 |
1 files changed, 51 insertions, 12 deletions
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 013bdfff2d4d..bf4959f4225b 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c | |||
@@ -228,6 +228,10 @@ static int amd_iommu_enable_interrupts(void); | |||
228 | static int __init iommu_go_to_state(enum iommu_init_state state); | 228 | static int __init iommu_go_to_state(enum iommu_init_state state); |
229 | static void init_device_table_dma(void); | 229 | static void init_device_table_dma(void); |
230 | 230 | ||
231 | static int iommu_pc_get_set_reg_val(struct amd_iommu *iommu, | ||
232 | u8 bank, u8 cntr, u8 fxn, | ||
233 | u64 *value, bool is_write); | ||
234 | |||
231 | static inline void update_last_devid(u16 devid) | 235 | static inline void update_last_devid(u16 devid) |
232 | { | 236 | { |
233 | if (devid > amd_iommu_last_bdf) | 237 | if (devid > amd_iommu_last_bdf) |
@@ -1016,6 +1020,34 @@ static void amd_iommu_erratum_746_workaround(struct amd_iommu *iommu) | |||
1016 | } | 1020 | } |
1017 | 1021 | ||
1018 | /* | 1022 | /* |
1023 | * Family15h Model 30h-3fh (IOMMU Mishandles ATS Write Permission) | ||
1024 | * Workaround: | ||
1025 | * BIOS should enable ATS write permission check by setting | ||
1026 | * L2_DEBUG_3[AtsIgnoreIWDis](D0F2xF4_x47[0]) = 1b | ||
1027 | */ | ||
1028 | static void amd_iommu_ats_write_check_workaround(struct amd_iommu *iommu) | ||
1029 | { | ||
1030 | u32 value; | ||
1031 | |||
1032 | if ((boot_cpu_data.x86 != 0x15) || | ||
1033 | (boot_cpu_data.x86_model < 0x30) || | ||
1034 | (boot_cpu_data.x86_model > 0x3f)) | ||
1035 | return; | ||
1036 | |||
1037 | /* Test L2_DEBUG_3[AtsIgnoreIWDis] == 1 */ | ||
1038 | value = iommu_read_l2(iommu, 0x47); | ||
1039 | |||
1040 | if (value & BIT(0)) | ||
1041 | return; | ||
1042 | |||
1043 | /* Set L2_DEBUG_3[AtsIgnoreIWDis] = 1 */ | ||
1044 | iommu_write_l2(iommu, 0x47, value | BIT(0)); | ||
1045 | |||
1046 | pr_info("AMD-Vi: Applying ATS write check workaround for IOMMU at %s\n", | ||
1047 | dev_name(&iommu->dev->dev)); | ||
1048 | } | ||
1049 | |||
1050 | /* | ||
1019 | * This function clues the initialization function for one IOMMU | 1051 | * This function clues the initialization function for one IOMMU |
1020 | * together and also allocates the command buffer and programs the | 1052 | * together and also allocates the command buffer and programs the |
1021 | * hardware. It does NOT enable the IOMMU. This is done afterwards. | 1053 | * hardware. It does NOT enable the IOMMU. This is done afterwards. |
@@ -1142,8 +1174,8 @@ static void init_iommu_perf_ctr(struct amd_iommu *iommu) | |||
1142 | amd_iommu_pc_present = true; | 1174 | amd_iommu_pc_present = true; |
1143 | 1175 | ||
1144 | /* Check if the performance counters can be written to */ | 1176 | /* Check if the performance counters can be written to */ |
1145 | if ((0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val, true)) || | 1177 | if ((0 != iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val, true)) || |
1146 | (0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val2, false)) || | 1178 | (0 != iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val2, false)) || |
1147 | (val != val2)) { | 1179 | (val != val2)) { |
1148 | pr_err("AMD-Vi: Unable to write to IOMMU perf counter.\n"); | 1180 | pr_err("AMD-Vi: Unable to write to IOMMU perf counter.\n"); |
1149 | amd_iommu_pc_present = false; | 1181 | amd_iommu_pc_present = false; |
@@ -1284,6 +1316,7 @@ static int iommu_init_pci(struct amd_iommu *iommu) | |||
1284 | } | 1316 | } |
1285 | 1317 | ||
1286 | amd_iommu_erratum_746_workaround(iommu); | 1318 | amd_iommu_erratum_746_workaround(iommu); |
1319 | amd_iommu_ats_write_check_workaround(iommu); | ||
1287 | 1320 | ||
1288 | iommu->iommu_dev = iommu_device_create(&iommu->dev->dev, iommu, | 1321 | iommu->iommu_dev = iommu_device_create(&iommu->dev->dev, iommu, |
1289 | amd_iommu_groups, "ivhd%d", | 1322 | amd_iommu_groups, "ivhd%d", |
@@ -2283,22 +2316,15 @@ u8 amd_iommu_pc_get_max_counters(u16 devid) | |||
2283 | } | 2316 | } |
2284 | EXPORT_SYMBOL(amd_iommu_pc_get_max_counters); | 2317 | EXPORT_SYMBOL(amd_iommu_pc_get_max_counters); |
2285 | 2318 | ||
2286 | int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn, | 2319 | static int iommu_pc_get_set_reg_val(struct amd_iommu *iommu, |
2320 | u8 bank, u8 cntr, u8 fxn, | ||
2287 | u64 *value, bool is_write) | 2321 | u64 *value, bool is_write) |
2288 | { | 2322 | { |
2289 | struct amd_iommu *iommu; | ||
2290 | u32 offset; | 2323 | u32 offset; |
2291 | u32 max_offset_lim; | 2324 | u32 max_offset_lim; |
2292 | 2325 | ||
2293 | /* Make sure the IOMMU PC resource is available */ | ||
2294 | if (!amd_iommu_pc_present) | ||
2295 | return -ENODEV; | ||
2296 | |||
2297 | /* Locate the iommu associated with the device ID */ | ||
2298 | iommu = amd_iommu_rlookup_table[devid]; | ||
2299 | |||
2300 | /* Check for valid iommu and pc register indexing */ | 2326 | /* Check for valid iommu and pc register indexing */ |
2301 | if (WARN_ON((iommu == NULL) || (fxn > 0x28) || (fxn & 7))) | 2327 | if (WARN_ON((fxn > 0x28) || (fxn & 7))) |
2302 | return -ENODEV; | 2328 | return -ENODEV; |
2303 | 2329 | ||
2304 | offset = (u32)(((0x40|bank) << 12) | (cntr << 8) | fxn); | 2330 | offset = (u32)(((0x40|bank) << 12) | (cntr << 8) | fxn); |
@@ -2322,3 +2348,16 @@ int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn, | |||
2322 | return 0; | 2348 | return 0; |
2323 | } | 2349 | } |
2324 | EXPORT_SYMBOL(amd_iommu_pc_get_set_reg_val); | 2350 | EXPORT_SYMBOL(amd_iommu_pc_get_set_reg_val); |
2351 | |||
2352 | int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn, | ||
2353 | u64 *value, bool is_write) | ||
2354 | { | ||
2355 | struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; | ||
2356 | |||
2357 | /* Make sure the IOMMU PC resource is available */ | ||
2358 | if (!amd_iommu_pc_present || iommu == NULL) | ||
2359 | return -ENODEV; | ||
2360 | |||
2361 | return iommu_pc_get_set_reg_val(iommu, bank, cntr, fxn, | ||
2362 | value, is_write); | ||
2363 | } | ||