Skip to content

Commit 86ac1b1

Browse files
committed
iommu/vt-d: Add support for detecting ACPI namespace device in RMRR
zhaoxin inclusion category: feature CVE: NA ----------------- As below, ZX-200 xHCI mcu is a RMRR ANDD device in some case. [060h 0096 2] Subtable Type : 0001 [Reserved Memory Region [062h 0098 2] Length : 0020 [064h 0100 2] Reserved : 0000 [066h 0102 2] PCI Segment Number : 0000 [068h 0104 8] Base Address : 00000000B5DA5000 [070h 0112 8] End Address (limit) : 00000000B5DDDFFF [078h 0120 1] Device Scope Type : 05 [Namespace Device] [079h 0121 1] Entry Length : 08 [07Ah 0122 2] Reserved : 0000 [07Ch 0124 1] Enumeration ID : 02 [07Dh 0125 1] PCI Bus Number : 09 [07Eh 0126 2] PCI Path : 12,00 iommu driver cannot find this device and build identity map for the RMRR region, DMAR faults would occur for xHCI controller. Add func dmar_acpi_bus_add_dev to find the RMRR ANDD device. Add func acpi_rmrr_andd_probe to build identity map for the RMRR region into the domain of the correspanding xHCI controller. Add func iova_reserve_domain_addr to keep away from RMRR region when using dma iova. Signed-off-by: leoliu-oc <leoliu-oc@zhaoxin.com>
1 parent 5086b5c commit 86ac1b1

6 files changed

Lines changed: 166 additions & 2 deletions

File tree

drivers/iommu/dma-iommu.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,25 @@ static int iova_reserve_pci_windows(struct pci_dev *dev,
478478
return 0;
479479
}
480480

481+
int iova_reserve_domain_addr(struct iommu_domain *domain, dma_addr_t start, dma_addr_t end)
482+
{
483+
struct iommu_dma_cookie *cookie = domain->iova_cookie;
484+
struct iova_domain *iovad = &cookie->iovad;
485+
486+
unsigned long lo, hi;
487+
488+
lo = iova_pfn(iovad, start);
489+
hi = iova_pfn(iovad, end);
490+
491+
if (!cookie)
492+
return -EINVAL;
493+
494+
reserve_iova(iovad, lo, hi);
495+
496+
return 0;
497+
}
498+
EXPORT_SYMBOL_GPL(iova_reserve_domain_addr);
499+
481500
static int iova_reserve_iommu_regions(struct device *dev,
482501
struct iommu_domain *domain)
483502
{

drivers/iommu/intel/dmar.c

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,57 @@ static void __init dmar_acpi_insert_dev_scope(u8 device_number,
767767
device_number, dev_name(&adev->dev));
768768
}
769769

770+
/* Return: > 0 if match found, 0 if no match found */
771+
bool dmar_rmrr_acpi_insert_dev_scope(u8 device_number, struct acpi_device *adev, void *start,
772+
void *end, struct dmar_dev_scope *devices, int devices_cnt)
773+
{
774+
struct acpi_dmar_device_scope *scope;
775+
struct device *tmp;
776+
int i;
777+
struct acpi_dmar_pci_path *path;
778+
779+
for (; start < end; start += scope->length) {
780+
scope = start;
781+
if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_NAMESPACE)
782+
continue;
783+
if (scope->enumeration_id != device_number)
784+
continue;
785+
path = (void *)(scope + 1);
786+
pr_info("ACPI device \"%s\" under DMAR as %02x:%02x.%d\n", dev_name(&adev->dev),
787+
scope->bus, path->device, path->function);
788+
for_each_dev_scope(devices, devices_cnt, i, tmp)
789+
if (tmp == NULL) {
790+
devices[i].bus = scope->bus;
791+
devices[i].devfn = PCI_DEVFN(path->device, path->function);
792+
rcu_assign_pointer(devices[i].dev, get_device(&adev->dev));
793+
return true;
794+
}
795+
WARN_ON(i >= devices_cnt);
796+
}
797+
798+
return false;
799+
}
800+
801+
static int dmar_acpi_bus_add_dev(u8 device_number, struct acpi_device *adev)
802+
{
803+
struct dmar_drhd_unit *dmaru;
804+
struct acpi_dmar_hardware_unit *drhd;
805+
int ret;
806+
807+
for_each_drhd_unit(dmaru) {
808+
drhd = container_of(dmaru->hdr, struct acpi_dmar_hardware_unit, header);
809+
ret = dmar_rmrr_acpi_insert_dev_scope(device_number, adev, (void *)(drhd+1),
810+
((void *)drhd)+drhd->header.length,
811+
dmaru->devices, dmaru->devices_cnt);
812+
if (ret)
813+
break;
814+
}
815+
if (ret > 0)
816+
ret = dmar_rmrr_add_acpi_dev(device_number, adev);
817+
818+
return ret;
819+
}
820+
770821
static int __init dmar_acpi_dev_scope_init(void)
771822
{
772823
struct acpi_dmar_andd *andd;
@@ -794,7 +845,11 @@ static int __init dmar_acpi_dev_scope_init(void)
794845
andd->device_name);
795846
continue;
796847
}
797-
dmar_acpi_insert_dev_scope(andd->device_number, adev);
848+
849+
if (apply_zhaoxin_dmar_acpi_a_behavior())
850+
dmar_acpi_bus_add_dev(andd->device_number, adev);
851+
else
852+
dmar_acpi_insert_dev_scope(andd->device_number, adev);
798853
}
799854
}
800855
return 0;

drivers/iommu/intel/iommu.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3467,6 +3467,24 @@ static int dmar_ats_supported(struct pci_dev *dev, struct intel_iommu *iommu)
34673467
return ret;
34683468
}
34693469

3470+
int dmar_rmrr_add_acpi_dev(u8 device_number, struct acpi_device *adev)
3471+
{
3472+
int ret;
3473+
struct dmar_rmrr_unit *rmrru;
3474+
struct acpi_dmar_reserved_memory *rmrr;
3475+
3476+
list_for_each_entry(rmrru, &dmar_rmrr_units, list) {
3477+
rmrr = container_of(rmrru->hdr, struct acpi_dmar_reserved_memory, header);
3478+
ret = dmar_rmrr_acpi_insert_dev_scope(device_number, adev, (void *)(rmrr + 1),
3479+
((void *)rmrr) + rmrr->header.length,
3480+
rmrru->devices, rmrru->devices_cnt);
3481+
if (ret)
3482+
break;
3483+
}
3484+
3485+
return 0;
3486+
}
3487+
34703488
int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
34713489
{
34723490
int ret;
@@ -3725,6 +3743,43 @@ static int __init platform_optin_force_iommu(void)
37253743
return 1;
37263744
}
37273745

3746+
static inline int acpi_rmrr_device_create_direct_mappings(struct iommu_domain *domain,
3747+
struct device *dev)
3748+
{
3749+
int ret;
3750+
3751+
pr_info("rmrr andd dev:%s enter to %s\n", dev_name(dev), __func__);
3752+
ret = __acpi_rmrr_device_create_direct_mappings(domain, dev);
3753+
3754+
return ret;
3755+
}
3756+
3757+
static inline int acpi_rmrr_andd_probe(struct device *dev)
3758+
{
3759+
struct intel_iommu *iommu = NULL;
3760+
struct pci_dev *pci_device = NULL;
3761+
u8 bus, devfn;
3762+
int ret = 0;
3763+
3764+
ret = iommu_probe_device(dev);
3765+
3766+
iommu = device_lookup_iommu(dev, &bus, &devfn);
3767+
if (!iommu) {
3768+
pr_info("dpoint-- cannot get acpi device corresponding iommu\n");
3769+
return -EINVAL;
3770+
}
3771+
3772+
pci_device = pci_get_domain_bus_and_slot(iommu->segment, bus, devfn);
3773+
if (!pci_device) {
3774+
pr_info("dpoint-- cannot get acpi devie corresponding pci_device\n");
3775+
return -EINVAL;
3776+
}
3777+
ret = acpi_rmrr_device_create_direct_mappings(iommu_get_domain_for_dev(&pci_device->dev),
3778+
dev);
3779+
3780+
return ret;
3781+
}
3782+
37283783
static int __init probe_acpi_namespace_devices(void)
37293784
{
37303785
struct dmar_drhd_unit *drhd;
@@ -3747,6 +3802,10 @@ static int __init probe_acpi_namespace_devices(void)
37473802
list_for_each_entry(pn,
37483803
&adev->physical_node_list, node) {
37493804
ret = iommu_probe_device(pn->dev);
3805+
3806+
if (apply_zhaoxin_dmar_acpi_a_behavior())
3807+
ret = acpi_rmrr_andd_probe(dev);
3808+
37503809
if (ret)
37513810
break;
37523811
}

drivers/iommu/iommu.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1103,7 +1103,8 @@ static int iommu_create_device_direct_mappings(struct iommu_domain *domain,
11031103
map_size = 0;
11041104
}
11051105
}
1106-
1106+
if (apply_zhaoxin_dmar_acpi_a_behavior())
1107+
iova_reserve_domain_addr(domain, start, end);
11071108
}
11081109

11091110
if (!list_empty(&mappings) && iommu_is_dma_domain(domain))
@@ -1171,6 +1172,12 @@ static struct group_device *iommu_group_alloc_device(struct iommu_group *group,
11711172
return ERR_PTR(ret);
11721173
}
11731174

1175+
int __acpi_rmrr_device_create_direct_mappings(struct iommu_domain *domain, struct device *dev)
1176+
{
1177+
return iommu_create_device_direct_mappings(domain, dev);
1178+
}
1179+
EXPORT_SYMBOL_GPL(__acpi_rmrr_device_create_direct_mappings);
1180+
11741181
/**
11751182
* iommu_group_add_device - add a device to an iommu group
11761183
* @group: the group into which to add the device (reference should be held)

include/linux/dmar.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ extern int dmar_insert_dev_scope(struct dmar_pci_notify_info *info,
112112
void *start, void*end, u16 segment,
113113
struct dmar_dev_scope *devices,
114114
int devices_cnt);
115+
extern bool dmar_rmrr_acpi_insert_dev_scope(u8 device_number,
116+
struct acpi_device *adev, void *start, void *end,
117+
struct dmar_dev_scope *devices, int devices_cnt);
115118
extern int dmar_remove_dev_scope(struct dmar_pci_notify_info *info,
116119
u16 segment, struct dmar_dev_scope *devices,
117120
int count);
@@ -144,6 +147,7 @@ extern int dmar_check_one_atsr(struct acpi_dmar_header *hdr, void *arg);
144147
extern int dmar_parse_one_satc(struct acpi_dmar_header *hdr, void *arg);
145148
extern int dmar_release_one_atsr(struct acpi_dmar_header *hdr, void *arg);
146149
extern int dmar_iommu_hotplug(struct dmar_drhd_unit *dmaru, bool insert);
150+
extern int dmar_rmrr_add_acpi_dev(u8 device_number, struct acpi_device *adev);
147151
extern int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info);
148152
#else /* !CONFIG_INTEL_IOMMU: */
149153
static inline int intel_iommu_init(void) { return -ENODEV; }
@@ -155,6 +159,11 @@ static inline void intel_iommu_shutdown(void) { }
155159
#define dmar_release_one_atsr dmar_res_noop
156160
#define dmar_parse_one_satc dmar_res_noop
157161

162+
static inline int dmar_rmrr_add_acpi_dev(u8 device_number, struct acpi_device *adev)
163+
{
164+
return 0;
165+
}
166+
158167
static inline int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
159168
{
160169
return 0;

include/linux/iommu.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,21 @@ void iommu_set_dma_strict(void);
541541
extern int report_iommu_fault(struct iommu_domain *domain, struct device *dev,
542542
unsigned long iova, int flags);
543543

544+
static inline bool apply_zhaoxin_dmar_acpi_a_behavior(void)
545+
{
546+
#if defined(CONFIG_CPU_SUP_ZHAOXIN) || defined(CONFIG_CPU_SUP_CENTAUR)
547+
if (((boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR) ||
548+
(boot_cpu_data.x86_vendor == X86_VENDOR_ZHAOXIN)) &&
549+
((boot_cpu_data.x86 == 7) && (boot_cpu_data.x86_model == 0x3b)))
550+
return true;
551+
#endif
552+
return false;
553+
}
554+
555+
extern int iova_reserve_domain_addr(struct iommu_domain *domain, dma_addr_t start, dma_addr_t end);
556+
557+
int __acpi_rmrr_device_create_direct_mappings(struct iommu_domain *domain, struct device *dev);
558+
544559
static inline void iommu_flush_iotlb_all(struct iommu_domain *domain)
545560
{
546561
if (domain->ops->flush_iotlb_all)

0 commit comments

Comments
 (0)