提交 d6602228 编写于 作者: L LeoLiu-oc 提交者: Zheng Zengkai

iommu/vt-d:Add support for detecting ACPI device, in RMRR

zhaoxin inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I40QDN
CVE: NA

----------------------------------------------------------------

Some ACPI devices need to issue dma requests to access
the reserved memory area.BIOS uses the device scope type
ACPI_NAMESPACE_DEVICE in RMRR to report these ACPI devices.
This patch add support for detecting ACPI devices in RMRR and in
order to distinguish it from PCI device, some interface functions
are modified.
Signed-off-by: NLeoLiu-oc <LeoLiu-oc@zhaoxin.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
Reviewed-by: NHanjun Guo <guohanjun@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 71fb2651
......@@ -215,7 +215,7 @@ static bool dmar_match_pci_path(struct dmar_pci_notify_info *info, int bus,
}
/* Return: > 0 if match found, 0 if no match found, < 0 if error happens */
int dmar_insert_dev_scope(struct dmar_pci_notify_info *info,
int dmar_pci_insert_dev_scope(struct dmar_pci_notify_info *info,
void *start, void*end, u16 segment,
struct dmar_dev_scope *devices,
int devices_cnt)
......@@ -304,7 +304,7 @@ static int dmar_pci_bus_add_dev(struct dmar_pci_notify_info *info)
drhd = container_of(dmaru->hdr,
struct acpi_dmar_hardware_unit, header);
ret = dmar_insert_dev_scope(info, (void *)(drhd + 1),
ret = dmar_pci_insert_dev_scope(info, (void *)(drhd + 1),
((void *)drhd) + drhd->header.length,
dmaru->segment,
dmaru->devices, dmaru->devices_cnt);
......@@ -719,47 +719,58 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev)
return dmaru;
}
static void __init dmar_acpi_insert_dev_scope(u8 device_number,
struct acpi_device *adev)
/* Return: > 0 if match found, 0 if no match found */
bool dmar_acpi_insert_dev_scope(u8 device_number,
struct acpi_device *adev,
void *start, void *end,
struct dmar_dev_scope *devices,
int devices_cnt)
{
struct dmar_drhd_unit *dmaru;
struct acpi_dmar_hardware_unit *drhd;
struct acpi_dmar_device_scope *scope;
struct device *tmp;
int i;
struct acpi_dmar_pci_path *path;
for (; start < end; start += scope->length) {
scope = start;
if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_NAMESPACE)
continue;
if (scope->enumeration_id != device_number)
continue;
path = (void *)(scope + 1);
for_each_dev_scope(devices, devices_cnt, i, tmp)
if (tmp == NULL) {
devices[i].bus = scope->bus;
devices[i].devfn = PCI_DEVFN(path->device, path->function);
rcu_assign_pointer(devices[i].dev,
get_device(&adev->dev));
return true;
}
WARN_ON(i >= devices_cnt);
}
return false;
}
static int dmar_acpi_bus_add_dev(u8 device_number, struct acpi_device *adev)
{
struct dmar_drhd_unit *dmaru;
struct acpi_dmar_hardware_unit *drhd;
int ret;
for_each_drhd_unit(dmaru) {
drhd = container_of(dmaru->hdr,
struct acpi_dmar_hardware_unit,
header);
for (scope = (void *)(drhd + 1);
(unsigned long)scope < ((unsigned long)drhd) + drhd->header.length;
scope = ((void *)scope) + scope->length) {
if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_NAMESPACE)
continue;
if (scope->enumeration_id != device_number)
continue;
path = (void *)(scope + 1);
pr_info("ACPI device \"%s\" under DMAR at %llx as %02x:%02x.%d\n",
dev_name(&adev->dev), dmaru->reg_base_addr,
scope->bus, path->device, path->function);
for_each_dev_scope(dmaru->devices, dmaru->devices_cnt, i, tmp)
if (tmp == NULL) {
dmaru->devices[i].bus = scope->bus;
dmaru->devices[i].devfn = PCI_DEVFN(path->device,
path->function);
rcu_assign_pointer(dmaru->devices[i].dev,
get_device(&adev->dev));
return;
}
BUG_ON(i >= dmaru->devices_cnt);
}
ret = dmar_acpi_insert_dev_scope(device_number, adev, (void *)(drhd+1),
((void *)drhd)+drhd->header.length,
dmaru->devices, dmaru->devices_cnt);
if (ret)
break;
}
pr_warn("No IOMMU scope found for ANDD enumeration ID %d (%s)\n",
device_number, dev_name(&adev->dev));
if (ret > 0)
ret = dmar_rmrr_add_acpi_dev(device_number, adev);
return ret;
}
static int __init dmar_acpi_dev_scope_init(void)
......@@ -788,7 +799,7 @@ static int __init dmar_acpi_dev_scope_init(void)
andd->device_name);
continue;
}
dmar_acpi_insert_dev_scope(andd->device_number, adev);
dmar_acpi_bus_add_dev(andd->device_number, adev);
}
}
return 0;
......
......@@ -4622,6 +4622,25 @@ int dmar_find_matched_atsr_unit(struct pci_dev *dev)
return ret;
}
int dmar_rmrr_add_acpi_dev(u8 device_number, struct acpi_device *adev)
{
int ret;
struct dmar_rmrr_unit *rmrru;
struct acpi_dmar_reserved_memory *rmrr;
list_for_each_entry(rmrru, &dmar_rmrr_units, list) {
rmrr = container_of(rmrru->hdr,
struct acpi_dmar_reserved_memory,
header);
ret = dmar_acpi_insert_dev_scope(device_number, adev, (void *)(rmrr + 1),
((void *)rmrr) + rmrr->header.length,
rmrru->devices, rmrru->devices_cnt);
if (ret)
break;
}
return 0;
}
int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
{
int ret;
......@@ -4637,7 +4656,7 @@ int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
rmrr = container_of(rmrru->hdr,
struct acpi_dmar_reserved_memory, header);
if (info->event == BUS_NOTIFY_ADD_DEVICE) {
ret = dmar_insert_dev_scope(info, (void *)(rmrr + 1),
ret = dmar_pci_insert_dev_scope(info, (void *)(rmrr + 1),
((void *)rmrr) + rmrr->header.length,
rmrr->segment, rmrru->devices,
rmrru->devices_cnt);
......@@ -4655,7 +4674,7 @@ int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
if (info->event == BUS_NOTIFY_ADD_DEVICE) {
ret = dmar_insert_dev_scope(info, (void *)(atsr + 1),
ret = dmar_pci_insert_dev_scope(info, (void *)(atsr + 1),
(void *)atsr + atsr->header.length,
atsr->segment, atsru->devices,
atsru->devices_cnt);
......@@ -4894,6 +4913,22 @@ static int __init platform_optin_force_iommu(void)
return 1;
}
static int acpi_device_create_direct_mappings(struct device *pn_dev, struct device *acpi_device)
{
struct iommu_group *group;
acpi_device->bus->iommu_ops = &intel_iommu_ops;
group = iommu_group_get(pn_dev);
if (!group) {
pr_warn("ACPI name space devices create direct mappings wrong!\n");
return -EINVAL;
}
printk(KERN_INFO "pn_dev:%s enter to %s\n", dev_name(pn_dev), __func__);
__acpi_device_create_direct_mappings(group, acpi_device);
return 0;
}
static int __init probe_acpi_namespace_devices(void)
{
struct dmar_drhd_unit *drhd;
......@@ -4901,6 +4936,7 @@ static int __init probe_acpi_namespace_devices(void)
struct intel_iommu *iommu __maybe_unused;
struct device *dev;
int i, ret = 0;
u8 bus, devfn;
for_each_active_iommu(iommu, drhd) {
for_each_active_dev_scope(drhd->devices,
......@@ -4909,6 +4945,8 @@ static int __init probe_acpi_namespace_devices(void)
struct iommu_group *group;
struct acpi_device *adev;
struct device *pn_dev = NULL;
struct device_domain_info *info = NULL;
if (dev->bus != &acpi_bus_type)
continue;
......@@ -4918,19 +4956,53 @@ static int __init probe_acpi_namespace_devices(void)
&adev->physical_node_list, node) {
group = iommu_group_get(pn->dev);
if (group) {
pn_dev = pn->dev;
iommu_group_put(group);
continue;
}
pn->dev->bus->iommu_ops = &intel_iommu_ops;
ret = iommu_probe_device(pn->dev);
if (ret)
break;
iommu = device_to_iommu(dev, &bus, &devfn);
if (!iommu)
return -ENODEV;
info = dmar_search_domain_by_dev_info(iommu->segment, bus, devfn);
if (!info) {
pn->dev->bus->iommu_ops = &intel_iommu_ops;
ret = iommu_probe_device(pn->dev);
if (ret) {
pr_err("pn->dev:%s probe fail! ret:%d\n",
dev_name(pn->dev), ret);
goto unlock;
}
}
pn_dev = pn->dev;
}
if (!pn_dev) {
iommu = device_to_iommu(dev, &bus, &devfn);
if (!iommu)
return -ENODEV;
info = dmar_search_domain_by_dev_info(iommu->segment, bus, devfn);
if (!info) {
dev->bus->iommu_ops = &intel_iommu_ops;
ret = iommu_probe_device(dev);
if (ret) {
pr_err("dev:%s probe fail! ret:%d\n",
dev_name(dev), ret);
goto unlock;
}
goto unlock;
}
}
if (!info)
ret = acpi_device_create_direct_mappings(pn_dev, dev);
else
ret = acpi_device_create_direct_mappings(info->dev, dev);
unlock:
mutex_unlock(&adev->physical_node_lock);
if (ret)
if (ret) {
pr_err("%s fail! ret:%d\n", __func__, ret);
return ret;
}
}
}
......
......@@ -814,6 +814,12 @@ static bool iommu_is_attach_deferred(struct iommu_domain *domain,
return false;
}
void __acpi_device_create_direct_mappings(struct iommu_group *group, struct device *acpi_device)
{
iommu_create_device_direct_mappings(group, acpi_device);
}
EXPORT_SYMBOL_GPL(__acpi_device_create_direct_mappings);
/**
* iommu_group_add_device - add a device to an iommu group
* @group: the group into which to add the device (reference should be held)
......
......@@ -113,10 +113,13 @@ extern int dmar_parse_dev_scope(void *start, void *end, int *cnt,
struct dmar_dev_scope **devices, u16 segment);
extern void *dmar_alloc_dev_scope(void *start, void *end, int *cnt);
extern void dmar_free_dev_scope(struct dmar_dev_scope **devices, int *cnt);
extern int dmar_insert_dev_scope(struct dmar_pci_notify_info *info,
extern int dmar_pci_insert_dev_scope(struct dmar_pci_notify_info *info,
void *start, void*end, u16 segment,
struct dmar_dev_scope *devices,
int devices_cnt);
extern bool dmar_acpi_insert_dev_scope(u8 device_number,
struct acpi_device *adev, void *start, void *end,
struct dmar_dev_scope *devices, int devices_cnt);
extern int dmar_remove_dev_scope(struct dmar_pci_notify_info *info,
u16 segment, struct dmar_dev_scope *devices,
int count);
......@@ -140,6 +143,7 @@ extern int dmar_parse_one_atsr(struct acpi_dmar_header *header, void *arg);
extern int dmar_check_one_atsr(struct acpi_dmar_header *hdr, void *arg);
extern int dmar_release_one_atsr(struct acpi_dmar_header *hdr, void *arg);
extern int dmar_iommu_hotplug(struct dmar_drhd_unit *dmaru, bool insert);
extern int dmar_rmrr_add_acpi_dev(u8 device_number, struct acpi_device *adev);
extern int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info);
#else /* !CONFIG_INTEL_IOMMU: */
static inline int intel_iommu_init(void) { return -ENODEV; }
......@@ -150,6 +154,11 @@ static inline void intel_iommu_shutdown(void) { }
#define dmar_check_one_atsr dmar_res_noop
#define dmar_release_one_atsr dmar_res_noop
static inline int dmar_rmrr_add_acpi_dev(u8 device_number, struct acpi_device *adev)
{
return 0;
}
static inline int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
{
return 0;
......
......@@ -593,6 +593,9 @@ extern void iommu_domain_window_disable(struct iommu_domain *domain, u32 wnd_nr)
extern int report_iommu_fault(struct iommu_domain *domain, struct device *dev,
unsigned long iova, int flags);
extern void __acpi_device_create_direct_mappings(struct iommu_group *group,
struct device *acpi_device);
static inline void iommu_flush_iotlb_all(struct iommu_domain *domain)
{
if (domain->ops->flush_iotlb_all)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册