Commit 832bd858 authored by David Woodhouse's avatar David Woodhouse

iommu/vt-d: Change scope lists to struct device, bus, devfn

It's not only for PCI devices any more, and the scope information for an
ACPI device provides the bus and devfn so that has to be stored here too.

It is the device pointer itself which needs to be protected with RCU,
so the __rcu annotation follows it into the definition of struct
dmar_dev_scope, since we're no longer just passing arrays of device
pointers around.
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 07cb52ff
...@@ -97,17 +97,17 @@ void *dmar_alloc_dev_scope(void *start, void *end, int *cnt) ...@@ -97,17 +97,17 @@ void *dmar_alloc_dev_scope(void *start, void *end, int *cnt)
if (*cnt == 0) if (*cnt == 0)
return NULL; return NULL;
return kcalloc(*cnt, sizeof(struct pci_dev *), GFP_KERNEL); return kcalloc(*cnt, sizeof(struct dmar_dev_scope), GFP_KERNEL);
} }
void dmar_free_dev_scope(struct pci_dev __rcu ***devices, int *cnt) void dmar_free_dev_scope(struct dmar_dev_scope **devices, int *cnt)
{ {
int i; int i;
struct pci_dev *tmp_dev; struct device *tmp_dev;
if (*devices && *cnt) { if (*devices && *cnt) {
for_each_active_dev_scope(*devices, *cnt, i, tmp_dev) for_each_active_dev_scope(*devices, *cnt, i, tmp_dev)
pci_dev_put(tmp_dev); put_device(tmp_dev);
kfree(*devices); kfree(*devices);
} }
...@@ -191,10 +191,11 @@ static bool dmar_match_pci_path(struct dmar_pci_notify_info *info, int bus, ...@@ -191,10 +191,11 @@ 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 */ /* 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_insert_dev_scope(struct dmar_pci_notify_info *info,
void *start, void*end, u16 segment, void *start, void*end, u16 segment,
struct pci_dev __rcu **devices, int devices_cnt) struct dmar_dev_scope *devices,
int devices_cnt)
{ {
int i, level; int i, level;
struct pci_dev *tmp, *dev = info->dev; struct device *tmp, *dev = &info->dev->dev;
struct acpi_dmar_device_scope *scope; struct acpi_dmar_device_scope *scope;
struct acpi_dmar_pci_path *path; struct acpi_dmar_pci_path *path;
...@@ -213,16 +214,18 @@ int dmar_insert_dev_scope(struct dmar_pci_notify_info *info, ...@@ -213,16 +214,18 @@ int dmar_insert_dev_scope(struct dmar_pci_notify_info *info,
continue; continue;
if ((scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT) ^ if ((scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT) ^
(dev->hdr_type == PCI_HEADER_TYPE_NORMAL)) { (info->dev->hdr_type == PCI_HEADER_TYPE_NORMAL)) {
pr_warn("Device scope type does not match for %s\n", pr_warn("Device scope type does not match for %s\n",
pci_name(dev)); pci_name(info->dev));
return -EINVAL; return -EINVAL;
} }
for_each_dev_scope(devices, devices_cnt, i, tmp) for_each_dev_scope(devices, devices_cnt, i, tmp)
if (tmp == NULL) { if (tmp == NULL) {
rcu_assign_pointer(devices[i], devices[i].bus = info->dev->bus->number;
pci_dev_get(dev)); devices[i].devfn = info->dev->devfn;
rcu_assign_pointer(devices[i].dev,
get_device(dev));
return 1; return 1;
} }
BUG_ON(i >= devices_cnt); BUG_ON(i >= devices_cnt);
...@@ -232,19 +235,19 @@ int dmar_insert_dev_scope(struct dmar_pci_notify_info *info, ...@@ -232,19 +235,19 @@ int dmar_insert_dev_scope(struct dmar_pci_notify_info *info,
} }
int dmar_remove_dev_scope(struct dmar_pci_notify_info *info, u16 segment, int dmar_remove_dev_scope(struct dmar_pci_notify_info *info, u16 segment,
struct pci_dev __rcu **devices, int count) struct dmar_dev_scope *devices, int count)
{ {
int index; int index;
struct pci_dev *tmp; struct device *tmp;
if (info->seg != segment) if (info->seg != segment)
return 0; return 0;
for_each_active_dev_scope(devices, count, index, tmp) for_each_active_dev_scope(devices, count, index, tmp)
if (tmp == info->dev) { if (tmp == &info->dev->dev) {
rcu_assign_pointer(devices[index], NULL); rcu_assign_pointer(devices[index].dev, NULL);
synchronize_rcu(); synchronize_rcu();
pci_dev_put(tmp); put_device(tmp);
return 1; return 1;
} }
...@@ -562,15 +565,15 @@ parse_dmar_table(void) ...@@ -562,15 +565,15 @@ parse_dmar_table(void)
return ret; return ret;
} }
static int dmar_pci_device_match(struct pci_dev __rcu *devices[], int cnt, static int dmar_pci_device_match(struct dmar_dev_scope devices[],
struct pci_dev *dev) int cnt, struct pci_dev *dev)
{ {
int index; int index;
struct pci_dev *tmp; struct device *tmp;
while (dev) { while (dev) {
for_each_active_dev_scope(devices, cnt, index, tmp) for_each_active_dev_scope(devices, cnt, index, tmp)
if (dev == tmp) if (dev_is_pci(tmp) && dev == to_pci_dev(tmp))
return 1; return 1;
/* Check our parent */ /* Check our parent */
......
...@@ -382,14 +382,14 @@ struct dmar_rmrr_unit { ...@@ -382,14 +382,14 @@ struct dmar_rmrr_unit {
struct acpi_dmar_header *hdr; /* ACPI header */ struct acpi_dmar_header *hdr; /* ACPI header */
u64 base_address; /* reserved base address*/ u64 base_address; /* reserved base address*/
u64 end_address; /* reserved end address */ u64 end_address; /* reserved end address */
struct pci_dev __rcu **devices; /* target devices */ struct dmar_dev_scope *devices; /* target devices */
int devices_cnt; /* target device count */ int devices_cnt; /* target device count */
}; };
struct dmar_atsr_unit { struct dmar_atsr_unit {
struct list_head list; /* list of ATSR units */ struct list_head list; /* list of ATSR units */
struct acpi_dmar_header *hdr; /* ACPI header */ struct acpi_dmar_header *hdr; /* ACPI header */
struct pci_dev __rcu **devices; /* target devices */ struct dmar_dev_scope *devices; /* target devices */
int devices_cnt; /* target device count */ int devices_cnt; /* target device count */
u8 include_all:1; /* include all ports */ u8 include_all:1; /* include all ports */
}; };
...@@ -669,7 +669,8 @@ static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn) ...@@ -669,7 +669,8 @@ static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
{ {
struct dmar_drhd_unit *drhd = NULL; struct dmar_drhd_unit *drhd = NULL;
struct intel_iommu *iommu; struct intel_iommu *iommu;
struct pci_dev *dev; struct device *dev;
struct pci_dev *pdev;
int i; int i;
rcu_read_lock(); rcu_read_lock();
...@@ -679,11 +680,14 @@ static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn) ...@@ -679,11 +680,14 @@ static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
for_each_active_dev_scope(drhd->devices, for_each_active_dev_scope(drhd->devices,
drhd->devices_cnt, i, dev) { drhd->devices_cnt, i, dev) {
if (dev->bus->number == bus && dev->devfn == devfn) if (!dev_is_pci(dev))
continue;
pdev = to_pci_dev(dev);
if (pdev->bus->number == bus && pdev->devfn == devfn)
goto out; goto out;
if (dev->subordinate && if (pdev->subordinate &&
dev->subordinate->number <= bus && pdev->subordinate->number <= bus &&
dev->subordinate->busn_res.end >= bus) pdev->subordinate->busn_res.end >= bus)
goto out; goto out;
} }
...@@ -2479,7 +2483,7 @@ static int domain_add_dev_info(struct dmar_domain *domain, ...@@ -2479,7 +2483,7 @@ static int domain_add_dev_info(struct dmar_domain *domain,
static bool device_has_rmrr(struct pci_dev *dev) static bool device_has_rmrr(struct pci_dev *dev)
{ {
struct dmar_rmrr_unit *rmrr; struct dmar_rmrr_unit *rmrr;
struct pci_dev *tmp; struct device *tmp;
int i; int i;
rcu_read_lock(); rcu_read_lock();
...@@ -2490,7 +2494,7 @@ static bool device_has_rmrr(struct pci_dev *dev) ...@@ -2490,7 +2494,7 @@ static bool device_has_rmrr(struct pci_dev *dev)
*/ */
for_each_active_dev_scope(rmrr->devices, for_each_active_dev_scope(rmrr->devices,
rmrr->devices_cnt, i, tmp) rmrr->devices_cnt, i, tmp)
if (tmp == dev) { if (tmp == &dev->dev) {
rcu_read_unlock(); rcu_read_unlock();
return true; return true;
} }
...@@ -2602,7 +2606,7 @@ static int __init init_dmars(void) ...@@ -2602,7 +2606,7 @@ static int __init init_dmars(void)
{ {
struct dmar_drhd_unit *drhd; struct dmar_drhd_unit *drhd;
struct dmar_rmrr_unit *rmrr; struct dmar_rmrr_unit *rmrr;
struct pci_dev *pdev; struct device *dev;
struct intel_iommu *iommu; struct intel_iommu *iommu;
int i, ret; int i, ret;
...@@ -2746,8 +2750,10 @@ static int __init init_dmars(void) ...@@ -2746,8 +2750,10 @@ static int __init init_dmars(void)
for_each_rmrr_units(rmrr) { for_each_rmrr_units(rmrr) {
/* some BIOS lists non-exist devices in DMAR table. */ /* some BIOS lists non-exist devices in DMAR table. */
for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt, for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt,
i, pdev) { i, dev) {
ret = iommu_prepare_rmrr_dev(rmrr, pdev); if (!dev_is_pci(dev))
continue;
ret = iommu_prepare_rmrr_dev(rmrr, to_pci_dev(dev));
if (ret) if (ret)
printk(KERN_ERR printk(KERN_ERR
"IOMMU: mapping reserved region failed\n"); "IOMMU: mapping reserved region failed\n");
...@@ -3434,7 +3440,7 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quir ...@@ -3434,7 +3440,7 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quir
static void __init init_no_remapping_devices(void) static void __init init_no_remapping_devices(void)
{ {
struct dmar_drhd_unit *drhd; struct dmar_drhd_unit *drhd;
struct pci_dev *dev; struct device *dev;
int i; int i;
for_each_drhd_unit(drhd) { for_each_drhd_unit(drhd) {
...@@ -3442,7 +3448,7 @@ static void __init init_no_remapping_devices(void) ...@@ -3442,7 +3448,7 @@ static void __init init_no_remapping_devices(void)
for_each_active_dev_scope(drhd->devices, for_each_active_dev_scope(drhd->devices,
drhd->devices_cnt, i, dev) drhd->devices_cnt, i, dev)
break; break;
/* ignore DMAR unit if no pci devices exist */ /* ignore DMAR unit if no devices exist */
if (i == drhd->devices_cnt) if (i == drhd->devices_cnt)
drhd->ignored = 1; drhd->ignored = 1;
} }
...@@ -3454,7 +3460,7 @@ static void __init init_no_remapping_devices(void) ...@@ -3454,7 +3460,7 @@ static void __init init_no_remapping_devices(void)
for_each_active_dev_scope(drhd->devices, for_each_active_dev_scope(drhd->devices,
drhd->devices_cnt, i, dev) drhd->devices_cnt, i, dev)
if (!IS_GFX_DEVICE(dev)) if (!dev_is_pci(dev) || !IS_GFX_DEVICE(to_pci_dev(dev)))
break; break;
if (i < drhd->devices_cnt) if (i < drhd->devices_cnt)
continue; continue;
...@@ -3467,7 +3473,7 @@ static void __init init_no_remapping_devices(void) ...@@ -3467,7 +3473,7 @@ static void __init init_no_remapping_devices(void)
drhd->ignored = 1; drhd->ignored = 1;
for_each_active_dev_scope(drhd->devices, for_each_active_dev_scope(drhd->devices,
drhd->devices_cnt, i, dev) drhd->devices_cnt, i, dev)
dev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO; dev->archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
} }
} }
} }
...@@ -3691,7 +3697,8 @@ int dmar_find_matched_atsr_unit(struct pci_dev *dev) ...@@ -3691,7 +3697,8 @@ int dmar_find_matched_atsr_unit(struct pci_dev *dev)
{ {
int i, ret = 1; int i, ret = 1;
struct pci_bus *bus; struct pci_bus *bus;
struct pci_dev *bridge = NULL, *tmp; struct pci_dev *bridge = NULL;
struct device *tmp;
struct acpi_dmar_atsr *atsr; struct acpi_dmar_atsr *atsr;
struct dmar_atsr_unit *atsru; struct dmar_atsr_unit *atsru;
...@@ -3714,7 +3721,7 @@ int dmar_find_matched_atsr_unit(struct pci_dev *dev) ...@@ -3714,7 +3721,7 @@ int dmar_find_matched_atsr_unit(struct pci_dev *dev)
continue; continue;
for_each_dev_scope(atsru->devices, atsru->devices_cnt, i, tmp) for_each_dev_scope(atsru->devices, atsru->devices_cnt, i, tmp)
if (tmp == bridge) if (tmp == &bridge->dev)
goto out; goto out;
if (atsru->include_all) if (atsru->include_all)
......
...@@ -36,13 +36,19 @@ struct acpi_dmar_header; ...@@ -36,13 +36,19 @@ struct acpi_dmar_header;
struct intel_iommu; struct intel_iommu;
struct dmar_dev_scope {
struct device __rcu *dev;
u8 bus;
u8 devfn;
};
#ifdef CONFIG_DMAR_TABLE #ifdef CONFIG_DMAR_TABLE
extern struct acpi_table_header *dmar_tbl; extern struct acpi_table_header *dmar_tbl;
struct dmar_drhd_unit { struct dmar_drhd_unit {
struct list_head list; /* list of drhd units */ struct list_head list; /* list of drhd units */
struct acpi_dmar_header *hdr; /* ACPI header */ struct acpi_dmar_header *hdr; /* ACPI header */
u64 reg_base_addr; /* register base address*/ u64 reg_base_addr; /* register base address*/
struct pci_dev __rcu **devices;/* target device array */ struct dmar_dev_scope *devices;/* target device array */
int devices_cnt; /* target device count */ int devices_cnt; /* target device count */
u16 segment; /* PCI domain */ u16 segment; /* PCI domain */
u8 ignored:1; /* ignore drhd */ u8 ignored:1; /* ignore drhd */
...@@ -86,7 +92,7 @@ static inline bool dmar_rcu_check(void) ...@@ -86,7 +92,7 @@ static inline bool dmar_rcu_check(void)
#define dmar_rcu_dereference(p) rcu_dereference_check((p), dmar_rcu_check()) #define dmar_rcu_dereference(p) rcu_dereference_check((p), dmar_rcu_check())
#define for_each_dev_scope(a, c, p, d) \ #define for_each_dev_scope(a, c, p, d) \
for ((p) = 0; ((d) = (p) < (c) ? dmar_rcu_dereference((a)[(p)]) : \ for ((p) = 0; ((d) = (p) < (c) ? dmar_rcu_dereference((a)[(p)].dev) : \
NULL, (p) < (c)); (p)++) NULL, (p) < (c)); (p)++)
#define for_each_active_dev_scope(a, c, p, d) \ #define for_each_active_dev_scope(a, c, p, d) \
...@@ -95,15 +101,15 @@ static inline bool dmar_rcu_check(void) ...@@ -95,15 +101,15 @@ static inline bool dmar_rcu_check(void)
extern int dmar_table_init(void); extern int dmar_table_init(void);
extern int dmar_dev_scope_init(void); extern int dmar_dev_scope_init(void);
extern int dmar_parse_dev_scope(void *start, void *end, int *cnt, extern int dmar_parse_dev_scope(void *start, void *end, int *cnt,
struct pci_dev ***devices, u16 segment); struct dmar_dev_scope **devices, u16 segment);
extern void *dmar_alloc_dev_scope(void *start, void *end, int *cnt); extern void *dmar_alloc_dev_scope(void *start, void *end, int *cnt);
extern void dmar_free_dev_scope(struct pci_dev __rcu ***devices, 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_insert_dev_scope(struct dmar_pci_notify_info *info,
void *start, void*end, u16 segment, void *start, void*end, u16 segment,
struct pci_dev __rcu **devices, struct dmar_dev_scope *devices,
int devices_cnt); int devices_cnt);
extern int dmar_remove_dev_scope(struct dmar_pci_notify_info *info, extern int dmar_remove_dev_scope(struct dmar_pci_notify_info *info,
u16 segment, struct pci_dev __rcu **devices, u16 segment, struct dmar_dev_scope *devices,
int count); int count);
/* Intel IOMMU detection */ /* Intel IOMMU detection */
extern int detect_intel_iommu(void); extern int detect_intel_iommu(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment