Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iommu/omap: add support for late attachment of iommu devices

Current implementation of OMAP IOMMU enforces strict ordering of device
probe, initiated by iommu and followed by remoteproc later. This doesn't
work too well with the new setup done with ti-sysc changes which may
have the devices probed at pretty much any order. To overcome this limitation,
if iommu has not been probed yet when a consumer tries to attach to it,
add the device to orphan device list which will be parsed during iommu
probe to see if any orphan devices should be attached.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>

authored by

Tero Kristo and committed by
Joerg Roedel
604629bc d9c4d8a6

+56 -4
+53 -3
drivers/iommu/omap-iommu.c
··· 35 35 36 36 static const struct iommu_ops omap_iommu_ops; 37 37 38 + struct orphan_dev { 39 + struct device *dev; 40 + struct list_head node; 41 + }; 42 + 43 + static LIST_HEAD(orphan_dev_list); 44 + 45 + static DEFINE_SPINLOCK(orphan_lock); 46 + 38 47 #define to_iommu(dev) ((struct omap_iommu *)dev_get_drvdata(dev)) 39 48 40 49 /* bitmap of the page sizes currently supported */ ··· 61 52 62 53 static struct platform_driver omap_iommu_driver; 63 54 static struct kmem_cache *iopte_cachep; 55 + 56 + static int _omap_iommu_add_device(struct device *dev); 64 57 65 58 /** 66 59 * to_omap_domain - Get struct omap_iommu_domain from generic iommu_domain ··· 1177 1166 struct omap_iommu *obj; 1178 1167 struct resource *res; 1179 1168 struct device_node *of = pdev->dev.of_node; 1169 + struct orphan_dev *orphan_dev, *tmp; 1180 1170 1181 1171 if (!of) { 1182 1172 pr_err("%s: only DT-based devices are supported\n", __func__); ··· 1260 1248 omap_iommu_debugfs_add(obj); 1261 1249 1262 1250 dev_info(&pdev->dev, "%s registered\n", obj->name); 1251 + 1252 + list_for_each_entry_safe(orphan_dev, tmp, &orphan_dev_list, node) { 1253 + err = _omap_iommu_add_device(orphan_dev->dev); 1254 + if (!err) { 1255 + list_del(&orphan_dev->node); 1256 + kfree(orphan_dev); 1257 + } 1258 + } 1263 1259 1264 1260 return 0; 1265 1261 ··· 1658 1638 return ret; 1659 1639 } 1660 1640 1661 - static int omap_iommu_add_device(struct device *dev) 1641 + static int _omap_iommu_add_device(struct device *dev) 1662 1642 { 1663 1643 struct omap_iommu_arch_data *arch_data, *tmp; 1664 1644 struct omap_iommu *oiommu; ··· 1667 1647 struct platform_device *pdev; 1668 1648 int num_iommus, i; 1669 1649 int ret; 1650 + struct orphan_dev *orphan_dev; 1651 + unsigned long flags; 1670 1652 1671 1653 /* 1672 1654 * Allocate the archdata iommu structure for DT-based devices. ··· 1700 1678 } 1701 1679 1702 1680 pdev = of_find_device_by_node(np); 1703 - if (WARN_ON(!pdev)) { 1681 + if (!pdev) { 1704 1682 of_node_put(np); 1705 1683 kfree(arch_data); 1706 - return -EINVAL; 1684 + spin_lock_irqsave(&orphan_lock, flags); 1685 + list_for_each_entry(orphan_dev, &orphan_dev_list, 1686 + node) { 1687 + if (orphan_dev->dev == dev) 1688 + break; 1689 + } 1690 + spin_unlock_irqrestore(&orphan_lock, flags); 1691 + 1692 + if (orphan_dev && orphan_dev->dev == dev) 1693 + return -EPROBE_DEFER; 1694 + 1695 + orphan_dev = kzalloc(sizeof(*orphan_dev), GFP_KERNEL); 1696 + orphan_dev->dev = dev; 1697 + spin_lock_irqsave(&orphan_lock, flags); 1698 + list_add(&orphan_dev->node, &orphan_dev_list); 1699 + spin_unlock_irqrestore(&orphan_lock, flags); 1700 + return -EPROBE_DEFER; 1707 1701 } 1708 1702 1709 1703 oiommu = platform_get_drvdata(pdev); ··· 1730 1692 } 1731 1693 1732 1694 tmp->iommu_dev = oiommu; 1695 + tmp->dev = &pdev->dev; 1733 1696 1734 1697 of_node_put(np); 1735 1698 } ··· 1763 1724 iommu_group_put(group); 1764 1725 1765 1726 return 0; 1727 + } 1728 + 1729 + static int omap_iommu_add_device(struct device *dev) 1730 + { 1731 + int ret; 1732 + 1733 + ret = _omap_iommu_add_device(dev); 1734 + if (ret == -EPROBE_DEFER) 1735 + return 0; 1736 + 1737 + return ret; 1766 1738 } 1767 1739 1768 1740 static void omap_iommu_remove_device(struct device *dev)
+3 -1
drivers/iommu/omap-iommu.h
··· 87 87 88 88 /** 89 89 * struct omap_iommu_arch_data - omap iommu private data 90 - * @iommu_dev: handle of the iommu device 90 + * @iommu_dev: handle of the OMAP iommu device 91 + * @dev: handle of the iommu device 91 92 * 92 93 * This is an omap iommu private data object, which binds an iommu user 93 94 * to its iommu device. This object should be placed at the iommu user's ··· 97 96 */ 98 97 struct omap_iommu_arch_data { 99 98 struct omap_iommu *iommu_dev; 99 + struct device *dev; 100 100 }; 101 101 102 102 struct cr_regs {