From: Joerg Roedel Date: Mon, 9 May 2016 17:39:17 +0000 (+0200) Subject: Merge branches 'arm/io-pgtable', 'arm/rockchip', 'arm/omap', 'x86/vt-d', 'ppc/pamu... X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=6c0b43df74f900e7f31a49d1844f166df0f8afc6;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git Merge branches 'arm/io-pgtable', 'arm/rockchip', 'arm/omap', 'x86/vt-d', 'ppc/pamu', 'core' and 'x86/amd' into next --- 6c0b43df74f900e7f31a49d1844f166df0f8afc6 diff --cc drivers/iommu/amd_iommu.c index 374c129219ef,374c129219ef,374c129219ef,374c129219ef,374c129219ef,5efadad4615b,de9f028be79e..c9ccc74e0b9e --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@@@@@@@ -161,11 -161,11 -161,11 -161,11 -161,11 -162,18 -164,65 +165,65 @@@@@@@@ struct dma_ops_domain * ****************************************************************************/ - static struct protection_domain *to_pdomain(struct iommu_domain *dom) ++++++ static inline int match_hid_uid(struct device *dev, ++++++ struct acpihid_map_entry *entry) +++++ { - return container_of(dom, struct protection_domain, domain); ++++++ const char *hid, *uid; ++++++ ++++++ hid = acpi_device_hid(ACPI_COMPANION(dev)); ++++++ uid = acpi_device_uid(ACPI_COMPANION(dev)); ++++++ ++++++ if (!hid || !(*hid)) ++++++ return -ENODEV; ++++++ ++++++ if (!uid || !(*uid)) ++++++ return strcmp(hid, entry->hid); ++++++ ++++++ if (!(*entry->uid)) ++++++ return strcmp(hid, entry->hid); ++++++ ++++++ return (strcmp(hid, entry->hid) || strcmp(uid, entry->uid)); +++++ } +++++ - static inline u16 get_device_id(struct device *dev) ++++++ static inline u16 get_pci_device_id(struct device *dev) +++++ { +++++ struct pci_dev *pdev = to_pci_dev(dev); +++++ +++++ return PCI_DEVID(pdev->bus->number, pdev->devfn); +++++ } +++++ ++++++ static inline int get_acpihid_device_id(struct device *dev, ++++++ struct acpihid_map_entry **entry) ++++++ { ++++++ struct acpihid_map_entry *p; ++++++ ++++++ list_for_each_entry(p, &acpihid_map, list) { ++++++ if (!match_hid_uid(dev, p)) { ++++++ if (entry) ++++++ *entry = p; ++++++ return p->devid; ++++++ } ++++++ } ++++++ return -EINVAL; ++++++ } ++++++ ++++++ static inline int get_device_id(struct device *dev) ++++++ { ++++++ int devid; ++++++ ++++++ if (dev_is_pci(dev)) ++++++ devid = get_pci_device_id(dev); ++++++ else ++++++ devid = get_acpihid_device_id(dev, NULL); ++++++ ++++++ return devid; ++++++ } ++++++ + static struct protection_domain *to_pdomain(struct iommu_domain *dom) + { + return container_of(dom, struct protection_domain, domain); + } + static struct iommu_dev_data *alloc_dev_data(u16 devid) { struct iommu_dev_data *dev_data; @@@@@@@@ -203,6 -203,6 -203,6 -203,6 -203,6 -211,68 -260,6 +261,69 @@@@@@@@ out_unlock return dev_data; } +++++ +static int __last_alias(struct pci_dev *pdev, u16 alias, void *data) +++++ +{ +++++ + *(u16 *)data = alias; +++++ + return 0; +++++ +} +++++ + +++++ +static u16 get_alias(struct device *dev) +++++ +{ +++++ + struct pci_dev *pdev = to_pci_dev(dev); +++++ + u16 devid, ivrs_alias, pci_alias; +++++ + +++++++ /* The callers make sure that get_device_id() does not fail here */ +++++ + devid = get_device_id(dev); +++++ + ivrs_alias = amd_iommu_alias_table[devid]; +++++ + pci_for_each_dma_alias(pdev, __last_alias, &pci_alias); +++++ + +++++ + if (ivrs_alias == pci_alias) +++++ + return ivrs_alias; +++++ + +++++ + /* +++++ + * DMA alias showdown +++++ + * +++++ + * The IVRS is fairly reliable in telling us about aliases, but it +++++ + * can't know about every screwy device. If we don't have an IVRS +++++ + * reported alias, use the PCI reported alias. In that case we may +++++ + * still need to initialize the rlookup and dev_table entries if the +++++ + * alias is to a non-existent device. +++++ + */ +++++ + if (ivrs_alias == devid) { +++++ + if (!amd_iommu_rlookup_table[pci_alias]) { +++++ + amd_iommu_rlookup_table[pci_alias] = +++++ + amd_iommu_rlookup_table[devid]; +++++ + memcpy(amd_iommu_dev_table[pci_alias].data, +++++ + amd_iommu_dev_table[devid].data, +++++ + sizeof(amd_iommu_dev_table[pci_alias].data)); +++++ + } +++++ + +++++ + return pci_alias; +++++ + } +++++ + +++++ + pr_info("AMD-Vi: Using IVRS reported alias %02x:%02x.%d " +++++ + "for device %s[%04x:%04x], kernel reported alias " +++++ + "%02x:%02x.%d\n", PCI_BUS_NUM(ivrs_alias), PCI_SLOT(ivrs_alias), +++++ + PCI_FUNC(ivrs_alias), dev_name(dev), pdev->vendor, pdev->device, +++++ + PCI_BUS_NUM(pci_alias), PCI_SLOT(pci_alias), +++++ + PCI_FUNC(pci_alias)); +++++ + +++++ + /* +++++ + * If we don't have a PCI DMA alias and the IVRS alias is on the same +++++ + * bus, then the IVRS table may know about a quirk that we don't. +++++ + */ +++++ + if (pci_alias == devid && +++++ + PCI_BUS_NUM(ivrs_alias) == pdev->bus->number) { +++++ + pdev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; +++++ + pdev->dma_alias_devfn = ivrs_alias & 0xff; +++++ + pr_info("AMD-Vi: Added PCI DMA alias %02x.%d for %s\n", +++++ + PCI_SLOT(ivrs_alias), PCI_FUNC(ivrs_alias), +++++ + dev_name(dev)); +++++ + } +++++ + +++++ + return ivrs_alias; +++++ +} +++++ + static struct iommu_dev_data *find_dev_data(u16 devid) { struct iommu_dev_data *dev_data; @@@@@@@@ -215,18 -215,18 -215,18 -215,18 -215,18 -285,11 -272,34 +336,34 @@@@@@@@ return dev_data; } ----- static inline u16 get_device_id(struct device *dev) +++++ static struct iommu_dev_data *get_dev_data(struct device *dev) { ----- struct pci_dev *pdev = to_pci_dev(dev); ----- ----- return PCI_DEVID(pdev->bus->number, pdev->devfn); +++++ return dev->archdata.iommu; } ----- static struct iommu_dev_data *get_dev_data(struct device *dev) ++++++ /* ++++++ * Find or create an IOMMU group for a acpihid device. ++++++ */ ++++++ static struct iommu_group *acpihid_device_group(struct device *dev) + { ----- return dev->archdata.iommu; ++++++ struct acpihid_map_entry *p, *entry = NULL; ++++++ int devid; ++++++ ++++++ devid = get_acpihid_device_id(dev, &entry); ++++++ if (devid < 0) ++++++ return ERR_PTR(devid); ++++++ ++++++ list_for_each_entry(p, &acpihid_map, list) { ++++++ if ((devid == p->devid) && p->group) ++++++ entry->group = p->group; ++++++ } ++++++ ++++++ if (!entry->group) ++++++ entry->group = generic_device_group(dev); ++++++ ++++++ return entry->group; + } + static bool pci_iommuv2_capable(struct pci_dev *pdev) { static const int caps[] = { @@@@@@@@ -349,10 -349,10 -349,10 -349,10 -349,10 -412,12 -426,10 +490,12 @@@@@@@@ static int iommu_init_device(struct dev if (!dev_data) return -ENOMEM; ----- if (pci_iommuv2_capable(pdev)) { +++++ + dev_data->alias = get_alias(dev); +++++ + - if (pci_iommuv2_capable(pdev)) { ++++++ if (dev_is_pci(dev) && pci_iommuv2_capable(to_pci_dev(dev))) { struct amd_iommu *iommu; ------ iommu = amd_iommu_rlookup_table[dev_data->devid]; ++++++ iommu = amd_iommu_rlookup_table[dev_data->devid]; dev_data->iommu_v2 = iommu->is_iommu_v2; } @@@@@@@@ -366,10 -366,10 -366,10 -366,10 -366,10 -431,10 -443,14 +509,14 @@@@@@@@ static void iommu_ignore_device(struct device *dev) { ------ u16 devid, alias; ++++++ u16 alias; ++++++ int devid; devid = get_device_id(dev); ----- alias = amd_iommu_alias_table[devid]; ++++++ if (devid < 0) ++++++ return; ++++++ - alias = amd_iommu_alias_table[devid]; +++++ + alias = get_alias(dev); memset(&amd_iommu_dev_table[devid], 0, sizeof(struct dev_table_entry)); memset(&amd_iommu_dev_table[alias], 0, sizeof(struct dev_table_entry));