staticint update_liodn_stash(int liodn, struct fsl_dma_domain *dma_domain,
u32 val)
{ int ret = 0; unsignedlong flags;
spin_lock_irqsave(&iommu_lock, flags);
ret = pamu_update_paace_stash(liodn, val); if (ret) {
pr_debug("Failed to update SPAACE for liodn %d\n", liodn);
spin_unlock_irqrestore(&iommu_lock, flags); return ret;
}
spin_unlock_irqrestore(&iommu_lock, flags);
return ret;
}
/* Set the geometry parameters for a LIODN */ staticint pamu_set_liodn(struct fsl_dma_domain *dma_domain, struct device *dev, int liodn)
{
u32 omi_index = ~(u32)0; unsignedlong flags; int ret;
/* * Configure the omi_index at the geometry setup time. * This is a static value which depends on the type of * device and would not change thereafter.
*/
get_ome_index(&omi_index, dev);
spin_lock_irqsave(&iommu_lock, flags);
ret = pamu_disable_liodn(liodn); if (ret) goto out_unlock;
ret = pamu_config_ppaace(liodn, omi_index, dma_domain->stash_id, 0); if (ret) goto out_unlock;
ret = pamu_config_ppaace(liodn, ~(u32)0, dma_domain->stash_id,
PAACE_AP_PERMS_QUERY | PAACE_AP_PERMS_UPDATE);
out_unlock:
spin_unlock_irqrestore(&iommu_lock, flags); if (ret) {
pr_debug("PAACE configuration failed for liodn %d\n",
liodn);
} return ret;
}
spin_lock_irqsave(&device_domain_lock, flags); /* * Check here if the device is already attached to domain or not. * If the device is already attached to a domain detach it.
*/
old_domain_info = dev_iommu_priv_get(dev); if (old_domain_info && old_domain_info->domain != dma_domain) {
spin_unlock_irqrestore(&device_domain_lock, flags);
detach_device(dev, old_domain_info->domain);
spin_lock_irqsave(&device_domain_lock, flags);
}
info = kmem_cache_zalloc(iommu_devinfo_cache, GFP_ATOMIC);
list_add(&info->link, &dma_domain->devices); /* * In case of devices with multiple LIODNs just store * the info for the first LIODN as all * LIODNs share the same domain
*/ if (!dev_iommu_priv_get(dev))
dev_iommu_priv_set(dev, info);
spin_unlock_irqrestore(&device_domain_lock, flags);
}
/* * FIXME: This isn't creating an unmanaged domain since the * default_domain_ops do not have any map/unmap function it doesn't meet * the requirements for __IOMMU_DOMAIN_PAGING. The only purpose seems to * allow drivers/soc/fsl/qbman/qman_portal.c to do * fsl_pamu_configure_l1_stash()
*/ if (type != IOMMU_DOMAIN_UNMANAGED) return NULL;
dma_domain = kmem_cache_zalloc(fsl_pamu_domain_cache, GFP_KERNEL); if (!dma_domain) return NULL;
/* default geometry 64 GB i.e. maximum system address */
dma_domain->iommu_domain. geometry.aperture_start = 0;
dma_domain->iommu_domain.geometry.aperture_end = (1ULL << 36) - 1;
dma_domain->iommu_domain.geometry.force_aperture = true;
return &dma_domain->iommu_domain;
}
/* Update stash destination for all LIODNs associated with the domain */ staticint update_domain_stash(struct fsl_dma_domain *dma_domain, u32 val)
{ struct device_domain_info *info; int ret = 0;
list_for_each_entry(info, &dma_domain->devices, link) {
ret = update_liodn_stash(info->liodn, dma_domain, val); if (ret) break;
}
/* * Use LIODN of the PCI controller while attaching a * PCI device.
*/ if (dev_is_pci(dev)) {
pdev = to_pci_dev(dev);
pci_ctl = pci_bus_to_host(pdev->bus); /* * make dev point to pci controller device * so we can get the LIODN programmed by * u-boot.
*/
dev = pci_ctl->parent;
}
liodn = of_get_property(dev->of_node, "fsl,liodn", &len); if (!liodn) {
pr_debug("missing fsl,liodn property at %pOF\n", dev->of_node); return -ENODEV;
}
spin_lock_irqsave(&dma_domain->domain_lock, flags); for (i = 0; i < len / sizeof(u32); i++) { /* Ensure that LIODN value is valid */ if (liodn[i] >= PAACE_NUMBER_ENTRIES) {
pr_debug("Invalid liodn %d, attach device failed for %pOF\n",
liodn[i], dev->of_node);
ret = -ENODEV; break;
}
attach_device(dma_domain, liodn[i], dev);
ret = pamu_set_liodn(dma_domain, dev, liodn[i]); if (ret) break;
ret = pamu_enable_liodn(liodn[i]); if (ret) break;
}
spin_unlock_irqrestore(&dma_domain->domain_lock, flags); return ret;
}
/* * FIXME: fsl/pamu is completely broken in terms of how it works with the iommu * API. Immediately after probe the HW is left in an IDENTITY translation and * the driver provides a non-working UNMANAGED domain that it can switch over * to. However it cannot switch back to an IDENTITY translation, instead it * switches to what looks like BLOCKING.
*/ staticint fsl_pamu_platform_attach(struct iommu_domain *platform_domain, struct device *dev)
{ struct iommu_domain *domain = iommu_get_domain_for_dev(dev); struct fsl_dma_domain *dma_domain; const u32 *prop; int len; struct pci_dev *pdev = NULL; struct pci_controller *pci_ctl;
/* * Hack to keep things working as they always have, only leaving an * UNMANAGED domain makes it BLOCKING.
*/ if (domain == platform_domain || !domain ||
domain->type != IOMMU_DOMAIN_UNMANAGED) return 0;
dma_domain = to_fsl_dma_domain(domain);
/* * Use LIODN of the PCI controller while detaching a * PCI device.
*/ if (dev_is_pci(dev)) {
pdev = to_pci_dev(dev);
pci_ctl = pci_bus_to_host(pdev->bus); /* * make dev point to pci controller device * so we can get the LIODN programmed by * u-boot.
*/
dev = pci_ctl->parent;
}
prop = of_get_property(dev->of_node, "fsl,liodn", &len); if (prop)
detach_device(dev, dma_domain); else
pr_debug("missing fsl,liodn property at %pOF\n", dev->of_node); return 0;
}
/* Check the PCI controller version number by readding BRR1 register */
version = in_be32(pci_ctl->cfg_addr + (PCI_FSL_BRR1 >> 2));
version &= PCI_FSL_BRR1_VER; /* If PCI controller version is >= 0x204 we can partition endpoints */ return version >= 0x204;
}
/* * For platform devices we allocate a separate group for each of the * devices.
*/ if (!dev_is_pci(dev)) return generic_device_group(dev);
/* * We can partition PCIe devices so assign device group to the device
*/
pdev = to_pci_dev(dev); if (check_pci_ctl_endpt_part(pci_bus_to_host(pdev->bus))) return pci_device_group(&pdev->dev);
/* * All devices connected to the controller will share the same device * group. * * Due to ordering between fsl_pamu_init() and fsl_pci_init() it is * guaranteed that the pci_ctl->parent platform_device will have the * iommu driver bound and will already have a group set. So we just * re-use this group as the group for every device in the hose.
*/
group = iommu_group_get(pci_bus_to_host(pdev->bus)->parent); if (WARN_ON(!group)) return ERR_PTR(-EINVAL); return group;
}
staticstruct iommu_device *fsl_pamu_probe_device(struct device *dev)
{ /* * uboot must fill the fsl,liodn for platform devices to be supported by * the iommu.
*/ if (!dev_is_pci(dev) &&
!of_property_present(dev->of_node, "fsl,liodn")) return ERR_PTR(-ENODEV);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.