IOMMU Fixes for Linux v4.17-rc4

Fixes come with:
 
 	* Fix for compile warning in AMD IOMMU driver with irq remapping
 	  disabled
 
 	* Fix for VT-d interrupt remapping and invalidation size (caused
 	  a BUG_ON when trying to invalidate more than 4GB)
 
 	* Build fix and a regression fix for broken graphics with old
 	  DTS for the rockchip iommu driver
 
 	* A revert in PCI window reservation code which fixes a
 	  regression with VFIO.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABAgAGBQJa7s0XAAoJECvwRC2XARrj5bAP/RuP5Y+R67+pT4HfWb2gthJN
 pHwzZL90EG4DU1b5rdzaElWHXtJglqYHaH4QUnuwh/JwLhrOV2goN3EfzYKNfcHF
 voEzuM5OCP8OX+j6hLvg+Lroq6PktrnKpKlVpQ6CMK4pPTxv/ig72BdQ3iaAsg4y
 DUtDCJeG0pGSOuK9HBjRhvQtk77tT26Y0nkyDTev1Zk+1kW0yxeEvWPEXOo+rbVQ
 ZvDUksAiK7iLRTejm+tR/xC8lSs8Tj2o05HTEhfCMTMcChpKeSOunq4TyVMzWDVv
 xss9dB+7SNxZtKp6Ek+ORMgBpGlP4kKTgeWVLUVHW/3NkQGMeKzrYX8d7rXHcn1m
 aPNTB2xNcjTV0x8zEsuBCht2aMW4vnxhx0WwqnXxBVGs9X0hwFNeMAXIuzKdZJjo
 FuCzYpdBooYKyBbL8j7lxBBVGHKwh7DMVw1LDAgCwq14qTXcGA0hL41uCpjsB1Z+
 PJHsso5d+7NqXzqQ/h4Hp4gEgIGluKcXtR7M3toriXUW7b4BatdU62CvFL93Wu4S
 qYV/ShnTVrvEBMGEoM2QHvqnD0zDIsMhVLK5u386nmQRmfv3yj8gN/f/QxecLW3v
 r5UOMSjIGLv655g4RaVQtG44hTXz7HHuUJIxFKxU7ExufAGkkZLG3k+seokQdeex
 3I3I2xnmRwrdSeWcR5tv
 =RGxK
 -----END PGP SIGNATURE-----

Merge tag 'iommu-fixes-v4.17-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu

Pull iommu fixes from Joerg Roedel:

 - fix a compile warning in the AMD IOMMU driver with irq remapping
   disabled

 - fix for VT-d interrupt remapping and invalidation size (caused a
   BUG_ON when trying to invalidate more than 4GB)

 - build fix and a regression fix for broken graphics with old DTS for
   the rockchip iommu driver

 - a revert in the PCI window reservation code which fixes a regression
   with VFIO.

* tag 'iommu-fixes-v4.17-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu:
  iommu: rockchip: fix building without CONFIG_OF
  iommu/vt-d: Use WARN_ON_ONCE instead of BUG_ON in qi_flush_dev_iotlb()
  iommu/vt-d: fix shift-out-of-bounds in bug checking
  iommu/dma: Move PCI window region reservation back into dma specific path.
  iommu/rockchip: Make clock handling optional
  iommu/amd: Hide unused iommu_table_lock
  iommu/vt-d: Fix usage of force parameter in intel_ir_reconfigure_irte()
This commit is contained in:
Linus Torvalds 2018-05-06 05:42:24 -10:00
commit 772d4f84c6
5 changed files with 37 additions and 34 deletions

View File

@ -83,7 +83,6 @@
static DEFINE_SPINLOCK(amd_iommu_devtable_lock); static DEFINE_SPINLOCK(amd_iommu_devtable_lock);
static DEFINE_SPINLOCK(pd_bitmap_lock); static DEFINE_SPINLOCK(pd_bitmap_lock);
static DEFINE_SPINLOCK(iommu_table_lock);
/* List of all available dev_data structures */ /* List of all available dev_data structures */
static LLIST_HEAD(dev_data_list); static LLIST_HEAD(dev_data_list);
@ -3562,6 +3561,7 @@ EXPORT_SYMBOL(amd_iommu_device_info);
*****************************************************************************/ *****************************************************************************/
static struct irq_chip amd_ir_chip; static struct irq_chip amd_ir_chip;
static DEFINE_SPINLOCK(iommu_table_lock);
static void set_dte_irq_entry(u16 devid, struct irq_remap_table *table) static void set_dte_irq_entry(u16 devid, struct irq_remap_table *table)
{ {

View File

@ -167,40 +167,16 @@ EXPORT_SYMBOL(iommu_put_dma_cookie);
* @list: Reserved region list from iommu_get_resv_regions() * @list: Reserved region list from iommu_get_resv_regions()
* *
* IOMMU drivers can use this to implement their .get_resv_regions callback * IOMMU drivers can use this to implement their .get_resv_regions callback
* for general non-IOMMU-specific reservations. Currently, this covers host * for general non-IOMMU-specific reservations. Currently, this covers GICv3
* bridge windows for PCI devices and GICv3 ITS region reservation on ACPI * ITS region reservation on ACPI based ARM platforms that may require HW MSI
* based ARM platforms that may require HW MSI reservation. * reservation.
*/ */
void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list) void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list)
{ {
struct pci_host_bridge *bridge;
struct resource_entry *window;
if (!is_of_node(dev->iommu_fwspec->iommu_fwnode) && if (!is_of_node(dev->iommu_fwspec->iommu_fwnode))
iort_iommu_msi_get_resv_regions(dev, list) < 0) iort_iommu_msi_get_resv_regions(dev, list);
return;
if (!dev_is_pci(dev))
return;
bridge = pci_find_host_bridge(to_pci_dev(dev)->bus);
resource_list_for_each_entry(window, &bridge->windows) {
struct iommu_resv_region *region;
phys_addr_t start;
size_t length;
if (resource_type(window->res) != IORESOURCE_MEM)
continue;
start = window->res->start - window->offset;
length = window->res->end - window->res->start + 1;
region = iommu_alloc_resv_region(start, length, 0,
IOMMU_RESV_RESERVED);
if (!region)
return;
list_add_tail(&region->list, list);
}
} }
EXPORT_SYMBOL(iommu_dma_get_resv_regions); EXPORT_SYMBOL(iommu_dma_get_resv_regions);
@ -229,6 +205,23 @@ static int cookie_init_hw_msi_region(struct iommu_dma_cookie *cookie,
return 0; return 0;
} }
static void iova_reserve_pci_windows(struct pci_dev *dev,
struct iova_domain *iovad)
{
struct pci_host_bridge *bridge = pci_find_host_bridge(dev->bus);
struct resource_entry *window;
unsigned long lo, hi;
resource_list_for_each_entry(window, &bridge->windows) {
if (resource_type(window->res) != IORESOURCE_MEM)
continue;
lo = iova_pfn(iovad, window->res->start - window->offset);
hi = iova_pfn(iovad, window->res->end - window->offset);
reserve_iova(iovad, lo, hi);
}
}
static int iova_reserve_iommu_regions(struct device *dev, static int iova_reserve_iommu_regions(struct device *dev,
struct iommu_domain *domain) struct iommu_domain *domain)
{ {
@ -238,6 +231,9 @@ static int iova_reserve_iommu_regions(struct device *dev,
LIST_HEAD(resv_regions); LIST_HEAD(resv_regions);
int ret = 0; int ret = 0;
if (dev_is_pci(dev))
iova_reserve_pci_windows(to_pci_dev(dev), iovad);
iommu_get_resv_regions(dev, &resv_regions); iommu_get_resv_regions(dev, &resv_regions);
list_for_each_entry(region, &resv_regions, list) { list_for_each_entry(region, &resv_regions, list) {
unsigned long lo, hi; unsigned long lo, hi;

View File

@ -1345,7 +1345,7 @@ void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 qdep,
struct qi_desc desc; struct qi_desc desc;
if (mask) { if (mask) {
BUG_ON(addr & ((1 << (VTD_PAGE_SHIFT + mask)) - 1)); WARN_ON_ONCE(addr & ((1ULL << (VTD_PAGE_SHIFT + mask)) - 1));
addr |= (1ULL << (VTD_PAGE_SHIFT + mask - 1)) - 1; addr |= (1ULL << (VTD_PAGE_SHIFT + mask - 1)) - 1;
desc.high = QI_DEV_IOTLB_ADDR(addr) | QI_DEV_IOTLB_SIZE; desc.high = QI_DEV_IOTLB_ADDR(addr) | QI_DEV_IOTLB_SIZE;
} else } else

View File

@ -1136,7 +1136,7 @@ static void intel_ir_reconfigure_irte(struct irq_data *irqd, bool force)
irte->dest_id = IRTE_DEST(cfg->dest_apicid); irte->dest_id = IRTE_DEST(cfg->dest_apicid);
/* Update the hardware only if the interrupt is in remapped mode. */ /* Update the hardware only if the interrupt is in remapped mode. */
if (!force || ir_data->irq_2_iommu.mode == IRQ_REMAPPING) if (force || ir_data->irq_2_iommu.mode == IRQ_REMAPPING)
modify_irte(&ir_data->irq_2_iommu, irte); modify_irte(&ir_data->irq_2_iommu, irte);
} }

View File

@ -1098,7 +1098,7 @@ static int rk_iommu_of_xlate(struct device *dev,
data->iommu = platform_get_drvdata(iommu_dev); data->iommu = platform_get_drvdata(iommu_dev);
dev->archdata.iommu = data; dev->archdata.iommu = data;
of_dev_put(iommu_dev); platform_device_put(iommu_dev);
return 0; return 0;
} }
@ -1175,8 +1175,15 @@ static int rk_iommu_probe(struct platform_device *pdev)
for (i = 0; i < iommu->num_clocks; ++i) for (i = 0; i < iommu->num_clocks; ++i)
iommu->clocks[i].id = rk_iommu_clocks[i]; iommu->clocks[i].id = rk_iommu_clocks[i];
/*
* iommu clocks should be present for all new devices and devicetrees
* but there are older devicetrees without clocks out in the wild.
* So clocks as optional for the time being.
*/
err = devm_clk_bulk_get(iommu->dev, iommu->num_clocks, iommu->clocks); err = devm_clk_bulk_get(iommu->dev, iommu->num_clocks, iommu->clocks);
if (err) if (err == -ENOENT)
iommu->num_clocks = 0;
else if (err)
return err; return err;
err = clk_bulk_prepare(iommu->num_clocks, iommu->clocks); err = clk_bulk_prepare(iommu->num_clocks, iommu->clocks);