Skip to content

Commit 19eab22

Browse files
committed
Merge tag 'iommu-fixes-v4.5-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu
Pull IOMMU fixes from Joerg Roedel: "One fix for Intel VT-d: - Use BUS_NOTIFY_REMOVED_DEVICE notifier to unbind a device from its domain _after_ it has been unbound from its driver. This fixes a BUG_ON being triggered in the PCI hotplug path. And three for AMD IOMMU: - Add a workaround for a hardware issue with ATS in use - Fix ATS enable/disable balance when a device is removed - Fix a boot warning being triggered when the system has IOMMU performance counters and PCI device 00:00.0 is not covered by the IOMMU" * tag 'iommu-fixes-v4.5-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu: iommu/vt-d: Use BUS_NOTIFY_REMOVED_DEVICE in hotplug path iommu/amd: Detach device from domain before removal iommu/amd: Apply workaround for ATS write permission check iommu/amd: Fix boot warning when device 00:00.0 is not iommu covered
2 parents f4bd982 + e6a8c9b commit 19eab22

File tree

4 files changed

+60
-16
lines changed

4 files changed

+60
-16
lines changed

drivers/iommu/amd_iommu.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ struct kmem_cache *amd_iommu_irq_cache;
114114

115115
static void update_domain(struct protection_domain *domain);
116116
static int protection_domain_init(struct protection_domain *domain);
117+
static void detach_device(struct device *dev);
117118

118119
/*
119120
* For dynamic growth the aperture size is split into ranges of 128MB of
@@ -384,6 +385,9 @@ static void iommu_uninit_device(struct device *dev)
384385
if (!dev_data)
385386
return;
386387

388+
if (dev_data->domain)
389+
detach_device(dev);
390+
387391
iommu_device_unlink(amd_iommu_rlookup_table[dev_data->devid]->iommu_dev,
388392
dev);
389393

drivers/iommu/amd_iommu_init.c

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,10 @@ static int amd_iommu_enable_interrupts(void);
228228
static int __init iommu_go_to_state(enum iommu_init_state state);
229229
static void init_device_table_dma(void);
230230

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+
231235
static inline void update_last_devid(u16 devid)
232236
{
233237
if (devid > amd_iommu_last_bdf)
@@ -1015,6 +1019,34 @@ static void amd_iommu_erratum_746_workaround(struct amd_iommu *iommu)
10151019
pci_write_config_dword(iommu->dev, 0xf0, 0x90);
10161020
}
10171021

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+
10181050
/*
10191051
* This function clues the initialization function for one IOMMU
10201052
* together and also allocates the command buffer and programs the
@@ -1142,8 +1174,8 @@ static void init_iommu_perf_ctr(struct amd_iommu *iommu)
11421174
amd_iommu_pc_present = true;
11431175

11441176
/* 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)) ||
1146-
(0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val2, false)) ||
1177+
if ((0 != iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val, true)) ||
1178+
(0 != iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val2, false)) ||
11471179
(val != val2)) {
11481180
pr_err("AMD-Vi: Unable to write to IOMMU perf counter.\n");
11491181
amd_iommu_pc_present = false;
@@ -1284,6 +1316,7 @@ static int iommu_init_pci(struct amd_iommu *iommu)
12841316
}
12851317

12861318
amd_iommu_erratum_746_workaround(iommu);
1319+
amd_iommu_ats_write_check_workaround(iommu);
12871320

12881321
iommu->iommu_dev = iommu_device_create(&iommu->dev->dev, iommu,
12891322
amd_iommu_groups, "ivhd%d",
@@ -2283,22 +2316,15 @@ u8 amd_iommu_pc_get_max_counters(u16 devid)
22832316
}
22842317
EXPORT_SYMBOL(amd_iommu_pc_get_max_counters);
22852318

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,
22872321
u64 *value, bool is_write)
22882322
{
2289-
struct amd_iommu *iommu;
22902323
u32 offset;
22912324
u32 max_offset_lim;
22922325

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-
23002326
/* 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)))
23022328
return -ENODEV;
23032329

23042330
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,
23222348
return 0;
23232349
}
23242350
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+
}

drivers/iommu/dmar.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,8 @@ static int dmar_pci_bus_notifier(struct notifier_block *nb,
329329
/* Only care about add/remove events for physical functions */
330330
if (pdev->is_virtfn)
331331
return NOTIFY_DONE;
332-
if (action != BUS_NOTIFY_ADD_DEVICE && action != BUS_NOTIFY_DEL_DEVICE)
332+
if (action != BUS_NOTIFY_ADD_DEVICE &&
333+
action != BUS_NOTIFY_REMOVED_DEVICE)
333334
return NOTIFY_DONE;
334335

335336
info = dmar_alloc_pci_notify_info(pdev, action);
@@ -339,7 +340,7 @@ static int dmar_pci_bus_notifier(struct notifier_block *nb,
339340
down_write(&dmar_global_lock);
340341
if (action == BUS_NOTIFY_ADD_DEVICE)
341342
dmar_pci_bus_add_dev(info);
342-
else if (action == BUS_NOTIFY_DEL_DEVICE)
343+
else if (action == BUS_NOTIFY_REMOVED_DEVICE)
343344
dmar_pci_bus_del_dev(info);
344345
up_write(&dmar_global_lock);
345346

drivers/iommu/intel-iommu.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4367,7 +4367,7 @@ int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
43674367
rmrru->devices_cnt);
43684368
if(ret < 0)
43694369
return ret;
4370-
} else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
4370+
} else if (info->event == BUS_NOTIFY_REMOVED_DEVICE) {
43714371
dmar_remove_dev_scope(info, rmrr->segment,
43724372
rmrru->devices, rmrru->devices_cnt);
43734373
}
@@ -4387,7 +4387,7 @@ int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
43874387
break;
43884388
else if(ret < 0)
43894389
return ret;
4390-
} else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
4390+
} else if (info->event == BUS_NOTIFY_REMOVED_DEVICE) {
43914391
if (dmar_remove_dev_scope(info, atsr->segment,
43924392
atsru->devices, atsru->devices_cnt))
43934393
break;

0 commit comments

Comments
 (0)