mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-16 13:34:30 +00:00
IOMMU Fixes for Linux v4.5-rc6
Including 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 -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJW2D+vAAoJECvwRC2XARrj3m8QAL8oDvVQp12r6MeT/Mre4JPb 5Y572a7kaA1Sp6b1ymnrMKsOATdxEJ7+P4OCkHDWjEZTGWvyDS/+latvPMTI0djf fzof5eB+OeGc1nI3z050Y2hKcC17gNs+cy6RoEDmWA8WRCYOh2FV8pgAFAqz/RNt qOA/8tdzbFyGk/A7GQV4N2ox30eGZwNHfMZDTNYkcAtf5BiKObyUDnkLk98hig5o bv2oEGckMDv35rOlpe6ToVPKe8hwy+uJLxBSvQKn3+d0Bu/4ZNVq2FVmcn1+DWbY sSqM6fFfEGyKK1moEOD2tuPJD5cr5qsqpN0GIbk8CRldSG6xYekJxUjY85aFeziS pARSu9LB+lOdi7yYbZu8zpfvN/G+gbRByqWaXBI1SHvmrx2ZS1VGHvHPel8aBQBz PLIF+z3ij3sCJwZnim4Tg2pyCAccz2sEiR7O0xBx5kDQKB8ZSeNKVhTz2d9cH5AZ gP4I7BmlSWaYXXi5FX6BMin3dYzHYuE/wcprQ98v1MIAk4AcqZGtOgX7CeQWABuC pBpdCYUiSIDQg+pDA6SSx7IJOxwVLhbQg/cxmJB5SWAMsNwnWqy7G2HWNvIJLrwT Bq++MmOYEwGH7g5xd8Q+rXszmaoVjzMhGojaAZg3gRmIe9AsaFSb9umoLvO1lNy0 u3aOUVDZM3eIrhTHtmB7 =uPsu -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
19eab220e7
@ -114,6 +114,7 @@ struct kmem_cache *amd_iommu_irq_cache;
|
||||
|
||||
static void update_domain(struct protection_domain *domain);
|
||||
static int protection_domain_init(struct protection_domain *domain);
|
||||
static void detach_device(struct device *dev);
|
||||
|
||||
/*
|
||||
* 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)
|
||||
if (!dev_data)
|
||||
return;
|
||||
|
||||
if (dev_data->domain)
|
||||
detach_device(dev);
|
||||
|
||||
iommu_device_unlink(amd_iommu_rlookup_table[dev_data->devid]->iommu_dev,
|
||||
dev);
|
||||
|
||||
|
@ -228,6 +228,10 @@ static int amd_iommu_enable_interrupts(void);
|
||||
static int __init iommu_go_to_state(enum iommu_init_state state);
|
||||
static void init_device_table_dma(void);
|
||||
|
||||
static int iommu_pc_get_set_reg_val(struct amd_iommu *iommu,
|
||||
u8 bank, u8 cntr, u8 fxn,
|
||||
u64 *value, bool is_write);
|
||||
|
||||
static inline void update_last_devid(u16 devid)
|
||||
{
|
||||
if (devid > amd_iommu_last_bdf)
|
||||
@ -1015,6 +1019,34 @@ static void amd_iommu_erratum_746_workaround(struct amd_iommu *iommu)
|
||||
pci_write_config_dword(iommu->dev, 0xf0, 0x90);
|
||||
}
|
||||
|
||||
/*
|
||||
* Family15h Model 30h-3fh (IOMMU Mishandles ATS Write Permission)
|
||||
* Workaround:
|
||||
* BIOS should enable ATS write permission check by setting
|
||||
* L2_DEBUG_3[AtsIgnoreIWDis](D0F2xF4_x47[0]) = 1b
|
||||
*/
|
||||
static void amd_iommu_ats_write_check_workaround(struct amd_iommu *iommu)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
if ((boot_cpu_data.x86 != 0x15) ||
|
||||
(boot_cpu_data.x86_model < 0x30) ||
|
||||
(boot_cpu_data.x86_model > 0x3f))
|
||||
return;
|
||||
|
||||
/* Test L2_DEBUG_3[AtsIgnoreIWDis] == 1 */
|
||||
value = iommu_read_l2(iommu, 0x47);
|
||||
|
||||
if (value & BIT(0))
|
||||
return;
|
||||
|
||||
/* Set L2_DEBUG_3[AtsIgnoreIWDis] = 1 */
|
||||
iommu_write_l2(iommu, 0x47, value | BIT(0));
|
||||
|
||||
pr_info("AMD-Vi: Applying ATS write check workaround for IOMMU at %s\n",
|
||||
dev_name(&iommu->dev->dev));
|
||||
}
|
||||
|
||||
/*
|
||||
* This function clues the initialization function for one IOMMU
|
||||
* together and also allocates the command buffer and programs the
|
||||
@ -1142,8 +1174,8 @@ static void init_iommu_perf_ctr(struct amd_iommu *iommu)
|
||||
amd_iommu_pc_present = true;
|
||||
|
||||
/* Check if the performance counters can be written to */
|
||||
if ((0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val, true)) ||
|
||||
(0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val2, false)) ||
|
||||
if ((0 != iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val, true)) ||
|
||||
(0 != iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val2, false)) ||
|
||||
(val != val2)) {
|
||||
pr_err("AMD-Vi: Unable to write to IOMMU perf counter.\n");
|
||||
amd_iommu_pc_present = false;
|
||||
@ -1284,6 +1316,7 @@ static int iommu_init_pci(struct amd_iommu *iommu)
|
||||
}
|
||||
|
||||
amd_iommu_erratum_746_workaround(iommu);
|
||||
amd_iommu_ats_write_check_workaround(iommu);
|
||||
|
||||
iommu->iommu_dev = iommu_device_create(&iommu->dev->dev, iommu,
|
||||
amd_iommu_groups, "ivhd%d",
|
||||
@ -2283,22 +2316,15 @@ u8 amd_iommu_pc_get_max_counters(u16 devid)
|
||||
}
|
||||
EXPORT_SYMBOL(amd_iommu_pc_get_max_counters);
|
||||
|
||||
int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn,
|
||||
static int iommu_pc_get_set_reg_val(struct amd_iommu *iommu,
|
||||
u8 bank, u8 cntr, u8 fxn,
|
||||
u64 *value, bool is_write)
|
||||
{
|
||||
struct amd_iommu *iommu;
|
||||
u32 offset;
|
||||
u32 max_offset_lim;
|
||||
|
||||
/* Make sure the IOMMU PC resource is available */
|
||||
if (!amd_iommu_pc_present)
|
||||
return -ENODEV;
|
||||
|
||||
/* Locate the iommu associated with the device ID */
|
||||
iommu = amd_iommu_rlookup_table[devid];
|
||||
|
||||
/* Check for valid iommu and pc register indexing */
|
||||
if (WARN_ON((iommu == NULL) || (fxn > 0x28) || (fxn & 7)))
|
||||
if (WARN_ON((fxn > 0x28) || (fxn & 7)))
|
||||
return -ENODEV;
|
||||
|
||||
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,
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(amd_iommu_pc_get_set_reg_val);
|
||||
|
||||
int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn,
|
||||
u64 *value, bool is_write)
|
||||
{
|
||||
struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
|
||||
|
||||
/* Make sure the IOMMU PC resource is available */
|
||||
if (!amd_iommu_pc_present || iommu == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
return iommu_pc_get_set_reg_val(iommu, bank, cntr, fxn,
|
||||
value, is_write);
|
||||
}
|
||||
|
@ -329,7 +329,8 @@ static int dmar_pci_bus_notifier(struct notifier_block *nb,
|
||||
/* Only care about add/remove events for physical functions */
|
||||
if (pdev->is_virtfn)
|
||||
return NOTIFY_DONE;
|
||||
if (action != BUS_NOTIFY_ADD_DEVICE && action != BUS_NOTIFY_DEL_DEVICE)
|
||||
if (action != BUS_NOTIFY_ADD_DEVICE &&
|
||||
action != BUS_NOTIFY_REMOVED_DEVICE)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
info = dmar_alloc_pci_notify_info(pdev, action);
|
||||
@ -339,7 +340,7 @@ static int dmar_pci_bus_notifier(struct notifier_block *nb,
|
||||
down_write(&dmar_global_lock);
|
||||
if (action == BUS_NOTIFY_ADD_DEVICE)
|
||||
dmar_pci_bus_add_dev(info);
|
||||
else if (action == BUS_NOTIFY_DEL_DEVICE)
|
||||
else if (action == BUS_NOTIFY_REMOVED_DEVICE)
|
||||
dmar_pci_bus_del_dev(info);
|
||||
up_write(&dmar_global_lock);
|
||||
|
||||
|
@ -4367,7 +4367,7 @@ int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
|
||||
rmrru->devices_cnt);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
} else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
|
||||
} else if (info->event == BUS_NOTIFY_REMOVED_DEVICE) {
|
||||
dmar_remove_dev_scope(info, rmrr->segment,
|
||||
rmrru->devices, rmrru->devices_cnt);
|
||||
}
|
||||
@ -4387,7 +4387,7 @@ int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
|
||||
break;
|
||||
else if(ret < 0)
|
||||
return ret;
|
||||
} else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
|
||||
} else if (info->event == BUS_NOTIFY_REMOVED_DEVICE) {
|
||||
if (dmar_remove_dev_scope(info, atsr->segment,
|
||||
atsru->devices, atsru->devices_cnt))
|
||||
break;
|
||||
|
Loading…
x
Reference in New Issue
Block a user