Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions drivers/iommu/dma-iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,25 @@ static int iova_reserve_pci_windows(struct pci_dev *dev,
return 0;
}

int iova_reserve_domain_addr(struct iommu_domain *domain, dma_addr_t start, dma_addr_t end)
{
struct iommu_dma_cookie *cookie = domain->iova_cookie;
struct iova_domain *iovad = &cookie->iovad;

unsigned long lo, hi;

lo = iova_pfn(iovad, start);
hi = iova_pfn(iovad, end);

if (!cookie)
return -EINVAL;

reserve_iova(iovad, lo, hi);

return 0;
}
EXPORT_SYMBOL_GPL(iova_reserve_domain_addr);

static int iova_reserve_iommu_regions(struct device *dev,
struct iommu_domain *domain)
{
Expand Down
57 changes: 56 additions & 1 deletion drivers/iommu/intel/dmar.c
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,57 @@ static void __init dmar_acpi_insert_dev_scope(u8 device_number,
device_number, dev_name(&adev->dev));
}

/* Return: > 0 if match found, 0 if no match found */
bool dmar_rmrr_acpi_insert_dev_scope(u8 device_number, struct acpi_device *adev, void *start,
void *end, struct dmar_dev_scope *devices, int devices_cnt)
{
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);
pr_info("ACPI device \"%s\" under DMAR as %02x:%02x.%d\n", dev_name(&adev->dev),
scope->bus, path->device, path->function);
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);
ret = dmar_rmrr_acpi_insert_dev_scope(device_number, adev, (void *)(drhd+1),
((void *)drhd)+drhd->header.length,
dmaru->devices, dmaru->devices_cnt);
if (ret)
break;
}
if (ret > 0)
ret = dmar_rmrr_add_acpi_dev(device_number, adev);

return ret;
}

static int __init dmar_acpi_dev_scope_init(void)
{
struct acpi_dmar_andd *andd;
Expand Down Expand Up @@ -794,7 +845,11 @@ static int __init dmar_acpi_dev_scope_init(void)
andd->device_name);
continue;
}
dmar_acpi_insert_dev_scope(andd->device_number, adev);

if (apply_zhaoxin_dmar_acpi_a_behavior())
dmar_acpi_bus_add_dev(andd->device_number, adev);
else
dmar_acpi_insert_dev_scope(andd->device_number, adev);
}
}
return 0;
Expand Down
59 changes: 59 additions & 0 deletions drivers/iommu/intel/iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -3467,6 +3467,24 @@ static int dmar_ats_supported(struct pci_dev *dev, struct intel_iommu *iommu)
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_rmrr_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;
Expand Down Expand Up @@ -3725,6 +3743,43 @@ static int __init platform_optin_force_iommu(void)
return 1;
}

static inline int acpi_rmrr_device_create_direct_mappings(struct iommu_domain *domain,
struct device *dev)
{
int ret;

pr_info("rmrr andd dev:%s enter to %s\n", dev_name(dev), __func__);
ret = __acpi_rmrr_device_create_direct_mappings(domain, dev);

return ret;
}

static inline int acpi_rmrr_andd_probe(struct device *dev)
{
struct intel_iommu *iommu = NULL;
struct pci_dev *pci_device = NULL;
u8 bus, devfn;
int ret = 0;

ret = iommu_probe_device(dev);

iommu = device_to_iommu(dev, &bus, &devfn);
if (!iommu) {
pr_info("dpoint-- cannot get acpi device corresponding iommu\n");
return -EINVAL;
}

pci_device = pci_get_domain_bus_and_slot(iommu->segment, bus, devfn);
if (!pci_device) {
pr_info("dpoint-- cannot get acpi devie corresponding pci_device\n");
return -EINVAL;
}
ret = acpi_rmrr_device_create_direct_mappings(iommu_get_domain_for_dev(&pci_device->dev),
dev);

return ret;
}

static int __init probe_acpi_namespace_devices(void)
{
struct dmar_drhd_unit *drhd;
Expand All @@ -3747,6 +3802,10 @@ static int __init probe_acpi_namespace_devices(void)
list_for_each_entry(pn,
&adev->physical_node_list, node) {
ret = iommu_probe_device(pn->dev);

if (apply_zhaoxin_dmar_acpi_a_behavior())
ret = acpi_rmrr_andd_probe(dev);

if (ret)
break;
}
Expand Down
9 changes: 8 additions & 1 deletion drivers/iommu/iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1103,7 +1103,8 @@ static int iommu_create_device_direct_mappings(struct iommu_domain *domain,
map_size = 0;
}
}

if (apply_zhaoxin_dmar_acpi_a_behavior())
iova_reserve_domain_addr(domain, start, end);
}

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

int __acpi_rmrr_device_create_direct_mappings(struct iommu_domain *domain, struct device *dev)
{
return iommu_create_device_direct_mappings(domain, dev);
}
EXPORT_SYMBOL_GPL(__acpi_rmrr_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)
Expand Down
9 changes: 9 additions & 0 deletions include/linux/dmar.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ extern int dmar_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_rmrr_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);
Expand Down Expand Up @@ -144,6 +147,7 @@ extern int dmar_check_one_atsr(struct acpi_dmar_header *hdr, void *arg);
extern int dmar_parse_one_satc(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; }
Expand All @@ -155,6 +159,11 @@ static inline void intel_iommu_shutdown(void) { }
#define dmar_release_one_atsr dmar_res_noop
#define dmar_parse_one_satc 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;
Expand Down
15 changes: 15 additions & 0 deletions include/linux/iommu.h
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,21 @@ void iommu_set_dma_strict(void);
extern int report_iommu_fault(struct iommu_domain *domain, struct device *dev,
unsigned long iova, int flags);

static inline bool apply_zhaoxin_dmar_acpi_a_behavior(void)
{
#if defined(CONFIG_CPU_SUP_ZHAOXIN) || defined(CONFIG_CPU_SUP_CENTAUR)
if (((boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR) ||
(boot_cpu_data.x86_vendor == X86_VENDOR_ZHAOXIN)) &&
((boot_cpu_data.x86 == 7) && (boot_cpu_data.x86_model == 0x3b)))
return true;
#endif
return false;
}

extern int iova_reserve_domain_addr(struct iommu_domain *domain, dma_addr_t start, dma_addr_t end);

int __acpi_rmrr_device_create_direct_mappings(struct iommu_domain *domain, struct device *dev);

static inline void iommu_flush_iotlb_all(struct iommu_domain *domain)
{
if (domain->ops->flush_iotlb_all)
Expand Down