Skip to content

Commit 3223fa1

Browse files
leoliu-ocopsiff
authored andcommitted
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> Link: deepin-community#261 (cherry picked from commit 8b9161e) Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
1 parent 29f5371 commit 3223fa1

File tree

6 files changed

+166
-2
lines changed

6 files changed

+166
-2
lines changed

drivers/iommu/dma-iommu.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,25 @@ static int iova_reserve_pci_windows(struct pci_dev *dev,
549549
return 0;
550550
}
551551

552+
int iova_reserve_domain_addr(struct iommu_domain *domain, dma_addr_t start, dma_addr_t end)
553+
{
554+
struct iommu_dma_cookie *cookie = domain->iova_cookie;
555+
struct iova_domain *iovad = &cookie->iovad;
556+
557+
unsigned long lo, hi;
558+
559+
lo = iova_pfn(iovad, start);
560+
hi = iova_pfn(iovad, end);
561+
562+
if (!cookie)
563+
return -EINVAL;
564+
565+
reserve_iova(iovad, lo, hi);
566+
567+
return 0;
568+
}
569+
EXPORT_SYMBOL_GPL(iova_reserve_domain_addr);
570+
552571
static int iova_reserve_iommu_regions(struct device *dev,
553572
struct iommu_domain *domain)
554573
{

drivers/iommu/intel/dmar.c

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

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

drivers/iommu/intel/iommu.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2755,6 +2755,24 @@ static bool dmar_ats_supported(struct pci_dev *dev, struct intel_iommu *iommu)
27552755
return supported;
27562756
}
27572757

2758+
int dmar_rmrr_add_acpi_dev(u8 device_number, struct acpi_device *adev)
2759+
{
2760+
int ret;
2761+
struct dmar_rmrr_unit *rmrru;
2762+
struct acpi_dmar_reserved_memory *rmrr;
2763+
2764+
list_for_each_entry(rmrru, &dmar_rmrr_units, list) {
2765+
rmrr = container_of(rmrru->hdr, struct acpi_dmar_reserved_memory, header);
2766+
ret = dmar_rmrr_acpi_insert_dev_scope(device_number, adev, (void *)(rmrr + 1),
2767+
((void *)rmrr) + rmrr->header.length,
2768+
rmrru->devices, rmrru->devices_cnt);
2769+
if (ret)
2770+
break;
2771+
}
2772+
2773+
return 0;
2774+
}
2775+
27582776
int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
27592777
{
27602778
int ret;
@@ -2975,6 +2993,43 @@ static int __init platform_optin_force_iommu(void)
29752993
return 1;
29762994
}
29772995

2996+
static inline int acpi_rmrr_device_create_direct_mappings(struct iommu_domain *domain,
2997+
struct device *dev)
2998+
{
2999+
int ret;
3000+
3001+
pr_info("rmrr andd dev:%s enter to %s\n", dev_name(dev), __func__);
3002+
ret = __acpi_rmrr_device_create_direct_mappings(domain, dev);
3003+
3004+
return ret;
3005+
}
3006+
3007+
static inline int acpi_rmrr_andd_probe(struct device *dev)
3008+
{
3009+
struct intel_iommu *iommu = NULL;
3010+
struct pci_dev *pci_device = NULL;
3011+
u8 bus, devfn;
3012+
int ret = 0;
3013+
3014+
ret = iommu_probe_device(dev);
3015+
3016+
iommu = device_to_iommu(dev, &bus, &devfn);
3017+
if (!iommu) {
3018+
pr_info("dpoint-- cannot get acpi device corresponding iommu\n");
3019+
return -EINVAL;
3020+
}
3021+
3022+
pci_device = pci_get_domain_bus_and_slot(iommu->segment, bus, devfn);
3023+
if (!pci_device) {
3024+
pr_info("dpoint-- cannot get acpi devie corresponding pci_device\n");
3025+
return -EINVAL;
3026+
}
3027+
ret = acpi_rmrr_device_create_direct_mappings(iommu_get_domain_for_dev(&pci_device->dev),
3028+
dev);
3029+
3030+
return ret;
3031+
}
3032+
29783033
static int __init probe_acpi_namespace_devices(void)
29793034
{
29803035
struct dmar_drhd_unit *drhd;
@@ -2998,6 +3053,10 @@ static int __init probe_acpi_namespace_devices(void)
29983053
list_for_each_entry(pn,
29993054
&adev->physical_node_list, node) {
30003055
ret = iommu_probe_device(pn->dev);
3056+
3057+
if (apply_zhaoxin_dmar_acpi_a_behavior())
3058+
ret = acpi_rmrr_andd_probe(dev);
3059+
30013060
if (ret)
30023061
break;
30033062
}

drivers/iommu/iommu.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1208,7 +1208,8 @@ static int iommu_create_device_direct_mappings(struct iommu_domain *domain,
12081208
map_size = 0;
12091209
}
12101210
}
1211-
1211+
if (apply_zhaoxin_dmar_acpi_a_behavior())
1212+
iova_reserve_domain_addr(domain, start, end);
12121213
}
12131214
out:
12141215
iommu_put_resv_regions(dev, &mappings);
@@ -1272,6 +1273,12 @@ static struct group_device *iommu_group_alloc_device(struct iommu_group *group,
12721273
return ERR_PTR(ret);
12731274
}
12741275

1276+
int __acpi_rmrr_device_create_direct_mappings(struct iommu_domain *domain, struct device *dev)
1277+
{
1278+
return iommu_create_device_direct_mappings(domain, dev);
1279+
}
1280+
EXPORT_SYMBOL_GPL(__acpi_rmrr_device_create_direct_mappings);
1281+
12751282
/**
12761283
* iommu_group_add_device - add a device to an iommu group
12771284
* @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
@@ -969,6 +969,21 @@ void iommu_set_dma_strict(void);
969969
extern int report_iommu_fault(struct iommu_domain *domain, struct device *dev,
970970
unsigned long iova, int flags);
971971

972+
static inline bool apply_zhaoxin_dmar_acpi_a_behavior(void)
973+
{
974+
#if defined(CONFIG_CPU_SUP_ZHAOXIN) || defined(CONFIG_CPU_SUP_CENTAUR)
975+
if (((boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR) ||
976+
(boot_cpu_data.x86_vendor == X86_VENDOR_ZHAOXIN)) &&
977+
((boot_cpu_data.x86 == 7) && (boot_cpu_data.x86_model == 0x3b)))
978+
return true;
979+
#endif
980+
return false;
981+
}
982+
983+
extern int iova_reserve_domain_addr(struct iommu_domain *domain, dma_addr_t start, dma_addr_t end);
984+
985+
int __acpi_rmrr_device_create_direct_mappings(struct iommu_domain *domain, struct device *dev);
986+
972987
static inline void iommu_flush_iotlb_all(struct iommu_domain *domain)
973988
{
974989
if (domain->ops->flush_iotlb_all)

0 commit comments

Comments
 (0)