Message ID | 1306267639.3100.102.camel@x201 (mailing list archive) |
---|---|
State | Not Applicable, archived |
Headers | show |
On 05/24/2011 01:07 PM, Alex Williamson wrote: > On Tue, 2011-05-24 at 12:34 -0700, Yinghai Lu wrote: >> On 05/24/2011 10:42 AM, Alex Williamson wrote: >>> On Tue, 2011-05-24 at 11:58 +0100, David Woodhouse wrote: >>>> On Thu, 2011-05-19 at 16:15 -0600, Alex Williamson wrote: >>>>> I think I'd vote for saving some kind of representation of the bus >>>>> hierarchy, we probably don't need to list every possible individual >>>>> device. Leaving a broken pointer around to be matched up and restored >>>>> later just seems like a continuation of an idea that was bad to begin >>>>> with. Thanks, >>>> >>>> I agree. We should just process the original ATSR information in >>>> dmar_find_matched_drhd_unit(), rather than comparing with a list of >>>> possibly stale pointers. >>>> >>>> I don't quite understand why the list of PCI devices was *ever* done >>>> like that. >>> >>> Yinghai, >>> >>> I thought I might be running into something similar so spent some time >>> taking a different slant coding up the bug you found. Turns out I >>> should have tested your patch first because I wasn't hitting that bug at >>> all. The patch below is a work-in-progress that I think fixes the bug >>> by providing a quick means of re-parsing the scope as needed to match >>> current struct pci_devs. It needs testing and cleanup, but feel free to >>> run with it (or ignore). Just figured its better to post than waste the >>> code if you end up doing something similar. Thanks, >>> >>> Alex >>> >> >> it does not apply to current linus tree cleanly. > > Sorry, for some reason I started hacking on this against a rhel kernel. > Here's the compile tested-only forward port to 2.6.39 (plus the > domain_exit flush patch). Thanks, can not find anywhere to call flush_unmaps_timeout(0). so what do you mean flush patch? > > Alex > > > Not for commit > > Signed-off-by: Alex Williamson <alex.williamson@redhat.com> > --- > > drivers/pci/dmar.c | 162 ++++++++++++++++++++++++--------------------- > drivers/pci/intel-iommu.c | 94 ++++++++++++++++---------- > include/linux/dmar.h | 29 ++++++-- > 3 files changed, 166 insertions(+), 119 deletions(-) > > > diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c > index 12e02bf..47e4f09 100644 > --- a/drivers/pci/dmar.c > +++ b/drivers/pci/dmar.c > @@ -61,8 +61,8 @@ static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd) > list_add(&drhd->list, &dmar_drhd_units); > } > > -static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, > - struct pci_dev **dev, u16 segment) > +struct pci_dev *dmar_get_scope_dev(struct acpi_dmar_device_scope *scope, > + u16 segment) > { > struct pci_bus *bus; > struct pci_dev *pdev = NULL; > @@ -74,7 +74,7 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, > count = (scope->length - sizeof(struct acpi_dmar_device_scope)) > / sizeof(struct acpi_dmar_pci_path); > > - while (count) { > + for (; count; path++, count--, bus = pdev->subordinate) { > if (pdev) > pci_dev_put(pdev); > /* > @@ -82,53 +82,77 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, > * ignore it > */ > if (!bus) { > - printk(KERN_WARNING > - PREFIX "Device scope bus [%d] not found\n", > - scope->bus); > - break; > + printk(KERN_WARNING PREFIX > + "Device scope bus [%d] not found\n", scope->bus); > + return NULL; > } > pdev = pci_get_slot(bus, PCI_DEVFN(path->dev, path->fn)); > if (!pdev) { > printk(KERN_WARNING PREFIX > - "Device scope device [%04x:%02x:%02x.%02x] not found\n", > - segment, bus->number, path->dev, path->fn); > - break; > + "Device scope device [%04x:%02x:%02x.%02x] not found\n", > + segment, bus->number, path->dev, path->fn); > + return NULL; > } > - path ++; > - count --; > - bus = pdev->subordinate; > } > - if (!pdev) { > - printk(KERN_WARNING PREFIX > - "Device scope device [%04x:%02x:%02x.%02x] not found\n", > - segment, scope->bus, path->dev, path->fn); > - *dev = NULL; > + > + return pdev; > +} > + > +static int dmar_match_scope_one(struct acpi_dmar_device_scope *scope, > + struct pci_dev *dev, u16 segment) > +{ > + struct pci_dev *pdev; > + int ret = 0; > + > + if (segment != pci_domain_nr(dev->bus)) > + return 0; > + > + pdev = dmar_get_scope_dev(scope, segment); > + if (!pdev) > return 0; > + > + if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT) { > + if (dev == pdev) > + ret = 1; > + } else { > + while (dev) { > + if (dev == pdev) { > + ret = 1; > + break; > + } > + dev = dev->bus->self; > + } > } > - if ((scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT && \ > - pdev->subordinate) || (scope->entry_type == \ > - ACPI_DMAR_SCOPE_TYPE_BRIDGE && !pdev->subordinate)) { > - pci_dev_put(pdev); > - printk(KERN_WARNING PREFIX > - "Device scope type does not match for %s\n", > - pci_name(pdev)); > - return -EINVAL; > + > + pci_dev_put(pdev); > + > + return ret; > +} > + > +int dmar_match_scope(struct acpi_dmar_device_scope **scopes, int cnt, > + struct pci_dev *dev, u16 segment) > +{ > + int i; > + > + for (i = 0; i < cnt; i++) { > + if (dmar_match_scope_one(scopes[i], dev, segment)) > + return 1; > } > - *dev = pdev; > return 0; > } > > static int __init dmar_parse_dev_scope(void *start, void *end, int *cnt, > - struct pci_dev ***devices, u16 segment) > + struct acpi_dmar_device_scope ***scopes) > { > struct acpi_dmar_device_scope *scope; > - void * tmp = start; > - int index; > - int ret; > + void *tmp = start; > + int index = 0; > > *cnt = 0; > + > while (start < end) { > scope = start; > + > if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT || > scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE) > (*cnt)++; > @@ -138,27 +162,23 @@ static int __init dmar_parse_dev_scope(void *start, void *end, int *cnt, > } > start += scope->length; > } > + > if (*cnt == 0) > return 0; > > - *devices = kcalloc(*cnt, sizeof(struct pci_dev *), GFP_KERNEL); > - if (!*devices) > + *scopes = kcalloc(*cnt, sizeof(struct acpi_dmar_device_scope *), > + GFP_KERNEL); > + if (!*scopes) > return -ENOMEM; > > start = tmp; > - index = 0; > while (start < end) { > scope = start; > + > if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT || > - scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE) { > - ret = dmar_parse_one_dev_scope(scope, > - &(*devices)[index], segment); > - if (ret) { > - kfree(*devices); > - return ret; > - } > - index ++; > - } > + scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE) > + (*scopes)[index++] = scope; > + > start += scope->length; > } > > @@ -207,9 +227,8 @@ static int __init dmar_parse_dev(struct dmar_drhd_unit *dmaru) > return 0; > > ret = dmar_parse_dev_scope((void *)(drhd + 1), > - ((void *)drhd) + drhd->header.length, > - &dmaru->devices_cnt, &dmaru->devices, > - drhd->segment); > + ((void *)drhd) + drhd->header.length, > + &dmaru->scopes_cnt, &dmaru->scopes); > if (ret) { > list_del(&dmaru->list); > kfree(dmaru); > @@ -253,10 +272,10 @@ rmrr_parse_dev(struct dmar_rmrr_unit *rmrru) > > rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr; > ret = dmar_parse_dev_scope((void *)(rmrr + 1), > - ((void *)rmrr) + rmrr->header.length, > - &rmrru->devices_cnt, &rmrru->devices, rmrr->segment); > + ((void *)rmrr) + rmrr->header.length, > + &rmrru->scopes_cnt, &rmrru->scopes); > > - if (ret || (rmrru->devices_cnt == 0)) { > + if (ret || (rmrru->scopes_cnt == 0)) { > list_del(&rmrru->list); > kfree(rmrru); > } > @@ -293,10 +312,9 @@ static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru) > > atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header); > rc = dmar_parse_dev_scope((void *)(atsr + 1), > - (void *)atsr + atsr->header.length, > - &atsru->devices_cnt, &atsru->devices, > - atsr->segment); > - if (rc || !atsru->devices_cnt) { > + (void *)atsr + atsr->header.length, > + &atsru->scopes_cnt, &atsru->scopes); > + if (rc || !atsru->scopes_cnt) { > list_del(&atsru->list); > kfree(atsru); > } > @@ -310,6 +328,7 @@ int dmar_find_matched_atsr_unit(struct pci_dev *dev) > struct pci_bus *bus; > struct acpi_dmar_atsr *atsr; > struct dmar_atsr_unit *atsru; > + struct pci_dev *pdev; > > dev = pci_physfn(dev); > > @@ -330,10 +349,18 @@ found: > return 0; > > if (bridge->pcie_type == PCI_EXP_TYPE_ROOT_PORT) { > - for (i = 0; i < atsru->devices_cnt; i++) > - if (atsru->devices[i] == bridge) > + for (i = 0; i < atsru->scopes_cnt; i++) { > + pdev = dmar_get_scope_dev(atsru->scopes[i], > + atsr->segment); > + if (!pdev) > + continue; > + > + if (pdev == bridge) { > + pci_dev_put(pdev); > return 1; > - break; > + } > + pci_dev_put(pdev); > + } > } > } > > @@ -513,23 +540,6 @@ parse_dmar_table(void) > return ret; > } > > -static int dmar_pci_device_match(struct pci_dev *devices[], int cnt, > - struct pci_dev *dev) > -{ > - int index; > - > - while (dev) { > - for (index = 0; index < cnt; index++) > - if (dev == devices[index]) > - return 1; > - > - /* Check our parent */ > - dev = dev->bus->self; > - } > - > - return 0; > -} > - > struct dmar_drhd_unit * > dmar_find_matched_drhd_unit(struct pci_dev *dev) > { > @@ -544,11 +554,11 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev) > header); > > if (dmaru->include_all && > - drhd->segment == pci_domain_nr(dev->bus)) > + dmaru->segment == pci_domain_nr(dev->bus)) > return dmaru; > > - if (dmar_pci_device_match(dmaru->devices, > - dmaru->devices_cnt, dev)) > + if (dmar_match_scope(dmaru->scopes, dmaru->scopes_cnt, > + dev, dmaru->segment)) > return dmaru; > } > > diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c > index b04f84e..d1d542a 100644 > --- a/drivers/pci/intel-iommu.c > +++ b/drivers/pci/intel-iommu.c > @@ -563,32 +563,34 @@ static void domain_update_iommu_cap(struct dmar_domain *domain) > > static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn) > { > - struct dmar_drhd_unit *drhd = NULL; > - int i; > + struct dmar_drhd_unit *dmaru = NULL; > + struct pci_dev *pdev; > + struct intel_iommu *found = NULL; > > - for_each_drhd_unit(drhd) { > - if (drhd->ignored) > + pdev = pci_get_domain_bus_and_slot(segment, bus, devfn); > + > + for_each_drhd_unit(dmaru) { > + if (dmaru->ignored) > continue; > - if (segment != drhd->segment) > + if (segment != dmaru->segment) > continue; > > - for (i = 0; i < drhd->devices_cnt; i++) { > - if (drhd->devices[i] && > - drhd->devices[i]->bus->number == bus && > - drhd->devices[i]->devfn == devfn) > - return drhd->iommu; > - if (drhd->devices[i] && > - drhd->devices[i]->subordinate && > - drhd->devices[i]->subordinate->number <= bus && > - drhd->devices[i]->subordinate->subordinate >= bus) > - return drhd->iommu; > + if (dmaru->include_all) { > + found = dmaru->iommu; > + break; > + } > + > + if (dmar_match_scope(dmaru->scopes, dmaru->scopes_cnt, > + pdev, dmaru->segment)) { > + found = dmaru->iommu; > + break; > } > > - if (drhd->include_all) > - return drhd->iommu; > } > > - return NULL; > + pci_dev_put(pdev); > + > + return found; > } > > static void domain_flush_cache(struct dmar_domain *domain, > @@ -2227,7 +2229,7 @@ static int __init init_dmars(int force_on) > struct dmar_rmrr_unit *rmrr; > struct pci_dev *pdev; > struct intel_iommu *iommu; > - int i, ret; > + int ret; > > /* > * for each drhd > @@ -2376,18 +2378,22 @@ static int __init init_dmars(int force_on) > */ > printk(KERN_INFO "IOMMU: Setting RMRR:\n"); > for_each_rmrr_units(rmrr) { > - for (i = 0; i < rmrr->devices_cnt; i++) { > - pdev = rmrr->devices[i]; > - /* > - * some BIOS lists non-exist devices in DMAR > - * table. > - */ > + struct acpi_dmar_reserved_memory *rmrrh; > + int i; > + > + rmrrh = container_of(rmrr->hdr, > + struct acpi_dmar_reserved_memory, header); > + > + for (i = 0; i < rmrr->scopes_cnt; i++) { > + pdev = dmar_get_scope_dev(rmrr->scopes[i], > + rmrrh->segment); > if (!pdev) > continue; > - ret = iommu_prepare_rmrr_dev(rmrr, pdev); > - if (ret) > + > + if (iommu_prepare_rmrr_dev(rmrr, pdev)) > printk(KERN_ERR > "IOMMU: mapping reserved region failed\n"); > + pci_dev_put(pdev); > } > } > > @@ -3072,15 +3078,21 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quir > static void __init init_no_remapping_devices(void) > { > struct dmar_drhd_unit *drhd; > + struct pci_dev *pdev; > > for_each_drhd_unit(drhd) { > if (!drhd->include_all) { > int i; > - for (i = 0; i < drhd->devices_cnt; i++) > - if (drhd->devices[i] != NULL) > + for (i = 0; i < drhd->scopes_cnt; i++) { > + pdev = dmar_get_scope_dev(drhd->scopes[i], > + drhd->segment); > + if (pdev) { > + pci_dev_put(pdev); > break; > + } > + } > /* ignore DMAR unit if no pci devices exist */ > - if (i == drhd->devices_cnt) > + if (i == drhd->scopes_cnt) > drhd->ignored = 1; > } > } > @@ -3093,20 +3105,28 @@ static void __init init_no_remapping_devices(void) > if (drhd->ignored || drhd->include_all) > continue; > > - for (i = 0; i < drhd->devices_cnt; i++) > - if (drhd->devices[i] && > - !IS_GFX_DEVICE(drhd->devices[i])) > + for (i = 0; i < drhd->scopes_cnt; i++) { > + pdev = dmar_get_scope_dev(drhd->scopes[i], > + drhd->segment); > + if (pdev && !IS_GFX_DEVICE(pdev)) { > + pci_dev_put(pdev); > break; > + } > + pci_dev_put(pdev); > + } > > - if (i < drhd->devices_cnt) > + if (i < drhd->scopes_cnt) > continue; > > /* bypass IOMMU if it is just for gfx devices */ > drhd->ignored = 1; > - for (i = 0; i < drhd->devices_cnt; i++) { > - if (!drhd->devices[i]) > + for (i = 0; i < drhd->scopes_cnt; i++) { > + pdev = dmar_get_scope_dev(drhd->scopes[i], > + drhd->segment); > + if (!pdev) > continue; > - drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO; > + pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO; > + pci_dev_put(pdev); > } > } > } > diff --git a/include/linux/dmar.h b/include/linux/dmar.h > index 7b776d7..cf071f9 100644 > --- a/include/linux/dmar.h > +++ b/include/linux/dmar.h > @@ -32,8 +32,8 @@ struct dmar_drhd_unit { > struct list_head list; /* list of drhd units */ > struct acpi_dmar_header *hdr; /* ACPI header */ > u64 reg_base_addr; /* register base address*/ > - struct pci_dev **devices; /* target device array */ > - int devices_cnt; /* target device count */ > + struct acpi_dmar_device_scope **scopes; /* target scope array */ > + int scopes_cnt; /* target scope count */ > u16 segment; /* PCI domain */ > u8 ignored:1; /* ignore drhd */ > u8 include_all:1; > @@ -55,6 +55,9 @@ extern struct list_head dmar_drhd_units; > > extern int dmar_table_init(void); > extern int dmar_dev_scope_init(void); > +extern int dmar_match_scope(struct acpi_dmar_device_scope **, int, > + struct pci_dev *, u16); > +extern struct pci_dev *dmar_get_scope_dev(struct acpi_dmar_device_scope *, u16); > > /* Intel IOMMU detection */ > extern int detect_intel_iommu(void); > @@ -72,6 +75,20 @@ static inline int dmar_table_init(void) > { > return -ENODEV; > } > + > +static inline int dmar_match_scope(struct acpi_dmar_device_scope **scopes, > + int cnt, struct pci_dev *dev, u16 segment) > +{ > + return 0; > +} > + > +static inline struct pci_dev *dmar_get_scope_dev( > + struct acpi_dmar_device_scope *scope, > + u16 segment) > +{ > + return NULL; > +} > + > static inline int enable_drhd_fault_handling(void) > { > return -1; > @@ -212,8 +229,8 @@ struct dmar_rmrr_unit { > struct acpi_dmar_header *hdr; /* ACPI header */ > u64 base_address; /* reserved base address*/ > u64 end_address; /* reserved end address */ > - struct pci_dev **devices; /* target devices */ > - int devices_cnt; /* target device count */ > + struct acpi_dmar_device_scope **scopes; /* target scope array */ > + int scopes_cnt; /* target scope count */ > }; > > #define for_each_rmrr_units(rmrr) \ > @@ -222,8 +239,8 @@ struct dmar_rmrr_unit { > struct dmar_atsr_unit { > struct list_head list; /* list of ATSR units */ > struct acpi_dmar_header *hdr; /* ACPI header */ > - struct pci_dev **devices; /* target devices */ > - int devices_cnt; /* target device count */ > + struct acpi_dmar_device_scope **scopes; /* target scope array */ > + int scopes_cnt; /* target scope count */ > u8 include_all:1; /* include all ports */ > }; > > -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, 2011-05-24 at 13:24 -0700, Yinghai Lu wrote: > On 05/24/2011 01:07 PM, Alex Williamson wrote: > > On Tue, 2011-05-24 at 12:34 -0700, Yinghai Lu wrote: > >> On 05/24/2011 10:42 AM, Alex Williamson wrote: > >>> On Tue, 2011-05-24 at 11:58 +0100, David Woodhouse wrote: > >>>> On Thu, 2011-05-19 at 16:15 -0600, Alex Williamson wrote: > >>>>> I think I'd vote for saving some kind of representation of the bus > >>>>> hierarchy, we probably don't need to list every possible individual > >>>>> device. Leaving a broken pointer around to be matched up and restored > >>>>> later just seems like a continuation of an idea that was bad to begin > >>>>> with. Thanks, > >>>> > >>>> I agree. We should just process the original ATSR information in > >>>> dmar_find_matched_drhd_unit(), rather than comparing with a list of > >>>> possibly stale pointers. > >>>> > >>>> I don't quite understand why the list of PCI devices was *ever* done > >>>> like that. > >>> > >>> Yinghai, > >>> > >>> I thought I might be running into something similar so spent some time > >>> taking a different slant coding up the bug you found. Turns out I > >>> should have tested your patch first because I wasn't hitting that bug at > >>> all. The patch below is a work-in-progress that I think fixes the bug > >>> by providing a quick means of re-parsing the scope as needed to match > >>> current struct pci_devs. It needs testing and cleanup, but feel free to > >>> run with it (or ignore). Just figured its better to post than waste the > >>> code if you end up doing something similar. Thanks, > >>> > >>> Alex > >>> > >> > >> it does not apply to current linus tree cleanly. > > > > Sorry, for some reason I started hacking on this against a rhel kernel. > > Here's the compile tested-only forward port to 2.6.39 (plus the > > domain_exit flush patch). Thanks, > > can not find anywhere to call flush_unmaps_timeout(0). > > so what do you mean flush patch? Take v2.6.39, add http://git.infradead.org/iommu-2.6.git/commitdiff/7b668357810ecb5fdda4418689d50f5d95aea6a8 and the patch below should apply cleanly. IIRC, it doesn't touch anything near domain_exit, so it should apply with some fuzz to stock 2.6.39 too. Thanks, Alex -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 05/24/2011 01:07 PM, Alex Williamson wrote: > On Tue, 2011-05-24 at 12:34 -0700, Yinghai Lu wrote: >> On 05/24/2011 10:42 AM, Alex Williamson wrote: >>> On Tue, 2011-05-24 at 11:58 +0100, David Woodhouse wrote: >>>> On Thu, 2011-05-19 at 16:15 -0600, Alex Williamson wrote: >>>>> I think I'd vote for saving some kind of representation of the bus >>>>> hierarchy, we probably don't need to list every possible individual >>>>> device. Leaving a broken pointer around to be matched up and restored >>>>> later just seems like a continuation of an idea that was bad to begin >>>>> with. Thanks, >>>> >>>> I agree. We should just process the original ATSR information in >>>> dmar_find_matched_drhd_unit(), rather than comparing with a list of >>>> possibly stale pointers. >>>> >>>> I don't quite understand why the list of PCI devices was *ever* done >>>> like that. >>> >>> Yinghai, >>> >>> I thought I might be running into something similar so spent some time >>> taking a different slant coding up the bug you found. Turns out I >>> should have tested your patch first because I wasn't hitting that bug at >>> all. The patch below is a work-in-progress that I think fixes the bug >>> by providing a quick means of re-parsing the scope as needed to match >>> current struct pci_devs. It needs testing and cleanup, but feel free to >>> run with it (or ignore). Just figured its better to post than waste the >>> code if you end up doing something similar. Thanks, >>> >>> Alex >>> >> >> it does not apply to current linus tree cleanly. > > Sorry, for some reason I started hacking on this against a rhel kernel. > Here's the compile tested-only forward port to 2.6.39 (plus the > domain_exit flush patch). Thanks, > > Alex > > > Not for commit > > Signed-off-by: Alex Williamson <alex.williamson@redhat.com> > --- > > drivers/pci/dmar.c | 162 ++++++++++++++++++++++++--------------------- > drivers/pci/intel-iommu.c | 94 ++++++++++++++++---------- > include/linux/dmar.h | 29 ++++++-- > 3 files changed, 166 insertions(+), 119 deletions(-) > > > diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c > index 12e02bf..47e4f09 100644 > --- a/drivers/pci/dmar.c > +++ b/drivers/pci/dmar.c > @@ -61,8 +61,8 @@ static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd) > list_add(&drhd->list, &dmar_drhd_units); > } > > -static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, > - struct pci_dev **dev, u16 segment) > +struct pci_dev *dmar_get_scope_dev(struct acpi_dmar_device_scope *scope, > + u16 segment) > { > struct pci_bus *bus; > struct pci_dev *pdev = NULL; > @@ -74,7 +74,7 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, > count = (scope->length - sizeof(struct acpi_dmar_device_scope)) > / sizeof(struct acpi_dmar_pci_path); > > - while (count) { > + for (; count; path++, count--, bus = pdev->subordinate) { > if (pdev) > pci_dev_put(pdev); > /* > @@ -82,53 +82,77 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, > * ignore it > */ > if (!bus) { > - printk(KERN_WARNING > - PREFIX "Device scope bus [%d] not found\n", > - scope->bus); > - break; > + printk(KERN_WARNING PREFIX > + "Device scope bus [%d] not found\n", scope->bus); > + return NULL; > } > pdev = pci_get_slot(bus, PCI_DEVFN(path->dev, path->fn)); > if (!pdev) { > printk(KERN_WARNING PREFIX > - "Device scope device [%04x:%02x:%02x.%02x] not found\n", > - segment, bus->number, path->dev, path->fn); > - break; > + "Device scope device [%04x:%02x:%02x.%02x] not found\n", > + segment, bus->number, path->dev, path->fn); > + return NULL; > } > - path ++; > - count --; > - bus = pdev->subordinate; > } > - if (!pdev) { > - printk(KERN_WARNING PREFIX > - "Device scope device [%04x:%02x:%02x.%02x] not found\n", > - segment, scope->bus, path->dev, path->fn); > - *dev = NULL; > + > + return pdev; > +} > + > +static int dmar_match_scope_one(struct acpi_dmar_device_scope *scope, > + struct pci_dev *dev, u16 segment) > +{ > + struct pci_dev *pdev; > + int ret = 0; > + > + if (segment != pci_domain_nr(dev->bus)) > + return 0; > + > + pdev = dmar_get_scope_dev(scope, segment); > + if (!pdev) > return 0; > + > + if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT) { > + if (dev == pdev) > + ret = 1; > + } else { > + while (dev) { > + if (dev == pdev) { > + ret = 1; > + break; > + } > + dev = dev->bus->self; > + } > } > - if ((scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT && \ > - pdev->subordinate) || (scope->entry_type == \ > - ACPI_DMAR_SCOPE_TYPE_BRIDGE && !pdev->subordinate)) { > - pci_dev_put(pdev); > - printk(KERN_WARNING PREFIX > - "Device scope type does not match for %s\n", > - pci_name(pdev)); > - return -EINVAL; > + > + pci_dev_put(pdev); > + > + return ret; > +} > + > +int dmar_match_scope(struct acpi_dmar_device_scope **scopes, int cnt, > + struct pci_dev *dev, u16 segment) > +{ > + int i; > + > + for (i = 0; i < cnt; i++) { > + if (dmar_match_scope_one(scopes[i], dev, segment)) > + return 1; > } > - *dev = pdev; > return 0; > } > > static int __init dmar_parse_dev_scope(void *start, void *end, int *cnt, > - struct pci_dev ***devices, u16 segment) > + struct acpi_dmar_device_scope ***scopes) > { > struct acpi_dmar_device_scope *scope; > - void * tmp = start; > - int index; > - int ret; > + void *tmp = start; > + int index = 0; > > *cnt = 0; > + > while (start < end) { > scope = start; > + > if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT || > scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE) > (*cnt)++; > @@ -138,27 +162,23 @@ static int __init dmar_parse_dev_scope(void *start, void *end, int *cnt, > } > start += scope->length; > } > + > if (*cnt == 0) > return 0; > > - *devices = kcalloc(*cnt, sizeof(struct pci_dev *), GFP_KERNEL); > - if (!*devices) > + *scopes = kcalloc(*cnt, sizeof(struct acpi_dmar_device_scope *), > + GFP_KERNEL); > + if (!*scopes) > return -ENOMEM; > > start = tmp; > - index = 0; > while (start < end) { > scope = start; > + > if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT || > - scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE) { > - ret = dmar_parse_one_dev_scope(scope, > - &(*devices)[index], segment); > - if (ret) { > - kfree(*devices); > - return ret; > - } > - index ++; > - } > + scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE) > + (*scopes)[index++] = scope; > + > start += scope->length; > } > > @@ -207,9 +227,8 @@ static int __init dmar_parse_dev(struct dmar_drhd_unit *dmaru) > return 0; > > ret = dmar_parse_dev_scope((void *)(drhd + 1), > - ((void *)drhd) + drhd->header.length, > - &dmaru->devices_cnt, &dmaru->devices, > - drhd->segment); > + ((void *)drhd) + drhd->header.length, > + &dmaru->scopes_cnt, &dmaru->scopes); > if (ret) { > list_del(&dmaru->list); > kfree(dmaru); > @@ -253,10 +272,10 @@ rmrr_parse_dev(struct dmar_rmrr_unit *rmrru) > > rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr; > ret = dmar_parse_dev_scope((void *)(rmrr + 1), > - ((void *)rmrr) + rmrr->header.length, > - &rmrru->devices_cnt, &rmrru->devices, rmrr->segment); > + ((void *)rmrr) + rmrr->header.length, > + &rmrru->scopes_cnt, &rmrru->scopes); > > - if (ret || (rmrru->devices_cnt == 0)) { > + if (ret || (rmrru->scopes_cnt == 0)) { > list_del(&rmrru->list); > kfree(rmrru); > } > @@ -293,10 +312,9 @@ static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru) > > atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header); > rc = dmar_parse_dev_scope((void *)(atsr + 1), > - (void *)atsr + atsr->header.length, > - &atsru->devices_cnt, &atsru->devices, > - atsr->segment); > - if (rc || !atsru->devices_cnt) { > + (void *)atsr + atsr->header.length, > + &atsru->scopes_cnt, &atsru->scopes); > + if (rc || !atsru->scopes_cnt) { > list_del(&atsru->list); > kfree(atsru); > } > @@ -310,6 +328,7 @@ int dmar_find_matched_atsr_unit(struct pci_dev *dev) > struct pci_bus *bus; > struct acpi_dmar_atsr *atsr; > struct dmar_atsr_unit *atsru; > + struct pci_dev *pdev; > > dev = pci_physfn(dev); > > @@ -330,10 +349,18 @@ found: > return 0; > > if (bridge->pcie_type == PCI_EXP_TYPE_ROOT_PORT) { > - for (i = 0; i < atsru->devices_cnt; i++) > - if (atsru->devices[i] == bridge) > + for (i = 0; i < atsru->scopes_cnt; i++) { > + pdev = dmar_get_scope_dev(atsru->scopes[i], > + atsr->segment); > + if (!pdev) > + continue; > + > + if (pdev == bridge) { > + pci_dev_put(pdev); > return 1; > - break; > + } > + pci_dev_put(pdev); > + } > } > } > > @@ -513,23 +540,6 @@ parse_dmar_table(void) > return ret; > } > > -static int dmar_pci_device_match(struct pci_dev *devices[], int cnt, > - struct pci_dev *dev) > -{ > - int index; > - > - while (dev) { > - for (index = 0; index < cnt; index++) > - if (dev == devices[index]) > - return 1; > - > - /* Check our parent */ > - dev = dev->bus->self; > - } > - > - return 0; > -} > - > struct dmar_drhd_unit * > dmar_find_matched_drhd_unit(struct pci_dev *dev) > { > @@ -544,11 +554,11 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev) > header); > > if (dmaru->include_all && > - drhd->segment == pci_domain_nr(dev->bus)) > + dmaru->segment == pci_domain_nr(dev->bus)) > return dmaru; > > - if (dmar_pci_device_match(dmaru->devices, > - dmaru->devices_cnt, dev)) > + if (dmar_match_scope(dmaru->scopes, dmaru->scopes_cnt, > + dev, dmaru->segment)) > return dmaru; > } > > diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c > index b04f84e..d1d542a 100644 > --- a/drivers/pci/intel-iommu.c > +++ b/drivers/pci/intel-iommu.c > @@ -563,32 +563,34 @@ static void domain_update_iommu_cap(struct dmar_domain *domain) > > static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn) > { > - struct dmar_drhd_unit *drhd = NULL; > - int i; > + struct dmar_drhd_unit *dmaru = NULL; > + struct pci_dev *pdev; > + struct intel_iommu *found = NULL; > > - for_each_drhd_unit(drhd) { > - if (drhd->ignored) > + pdev = pci_get_domain_bus_and_slot(segment, bus, devfn); > + > + for_each_drhd_unit(dmaru) { > + if (dmaru->ignored) > continue; > - if (segment != drhd->segment) > + if (segment != dmaru->segment) > continue; > > - for (i = 0; i < drhd->devices_cnt; i++) { > - if (drhd->devices[i] && > - drhd->devices[i]->bus->number == bus && > - drhd->devices[i]->devfn == devfn) > - return drhd->iommu; > - if (drhd->devices[i] && > - drhd->devices[i]->subordinate && > - drhd->devices[i]->subordinate->number <= bus && > - drhd->devices[i]->subordinate->subordinate >= bus) > - return drhd->iommu; > + if (dmaru->include_all) { > + found = dmaru->iommu; > + break; > + } > + > + if (dmar_match_scope(dmaru->scopes, dmaru->scopes_cnt, > + pdev, dmaru->segment)) { > + found = dmaru->iommu; > + break; > } > > - if (drhd->include_all) > - return drhd->iommu; > } > > - return NULL; > + pci_dev_put(pdev); > + > + return found; > } > > static void domain_flush_cache(struct dmar_domain *domain, > @@ -2227,7 +2229,7 @@ static int __init init_dmars(int force_on) > struct dmar_rmrr_unit *rmrr; > struct pci_dev *pdev; > struct intel_iommu *iommu; > - int i, ret; > + int ret; > > /* > * for each drhd > @@ -2376,18 +2378,22 @@ static int __init init_dmars(int force_on) > */ > printk(KERN_INFO "IOMMU: Setting RMRR:\n"); > for_each_rmrr_units(rmrr) { > - for (i = 0; i < rmrr->devices_cnt; i++) { > - pdev = rmrr->devices[i]; > - /* > - * some BIOS lists non-exist devices in DMAR > - * table. > - */ > + struct acpi_dmar_reserved_memory *rmrrh; > + int i; > + > + rmrrh = container_of(rmrr->hdr, > + struct acpi_dmar_reserved_memory, header); > + > + for (i = 0; i < rmrr->scopes_cnt; i++) { > + pdev = dmar_get_scope_dev(rmrr->scopes[i], > + rmrrh->segment); > if (!pdev) > continue; > - ret = iommu_prepare_rmrr_dev(rmrr, pdev); > - if (ret) > + > + if (iommu_prepare_rmrr_dev(rmrr, pdev)) > printk(KERN_ERR > "IOMMU: mapping reserved region failed\n"); > + pci_dev_put(pdev); > } > } > > @@ -3072,15 +3078,21 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quir > static void __init init_no_remapping_devices(void) > { > struct dmar_drhd_unit *drhd; > + struct pci_dev *pdev; > > for_each_drhd_unit(drhd) { > if (!drhd->include_all) { > int i; > - for (i = 0; i < drhd->devices_cnt; i++) > - if (drhd->devices[i] != NULL) > + for (i = 0; i < drhd->scopes_cnt; i++) { > + pdev = dmar_get_scope_dev(drhd->scopes[i], > + drhd->segment); > + if (pdev) { > + pci_dev_put(pdev); > break; > + } > + } > /* ignore DMAR unit if no pci devices exist */ > - if (i == drhd->devices_cnt) > + if (i == drhd->scopes_cnt) > drhd->ignored = 1; > } > } > @@ -3093,20 +3105,28 @@ static void __init init_no_remapping_devices(void) > if (drhd->ignored || drhd->include_all) > continue; > > - for (i = 0; i < drhd->devices_cnt; i++) > - if (drhd->devices[i] && > - !IS_GFX_DEVICE(drhd->devices[i])) > + for (i = 0; i < drhd->scopes_cnt; i++) { > + pdev = dmar_get_scope_dev(drhd->scopes[i], > + drhd->segment); > + if (pdev && !IS_GFX_DEVICE(pdev)) { > + pci_dev_put(pdev); > break; > + } > + pci_dev_put(pdev); > + } > > - if (i < drhd->devices_cnt) > + if (i < drhd->scopes_cnt) > continue; > > /* bypass IOMMU if it is just for gfx devices */ > drhd->ignored = 1; > - for (i = 0; i < drhd->devices_cnt; i++) { > - if (!drhd->devices[i]) > + for (i = 0; i < drhd->scopes_cnt; i++) { > + pdev = dmar_get_scope_dev(drhd->scopes[i], > + drhd->segment); > + if (!pdev) > continue; > - drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO; > + pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO; > + pci_dev_put(pdev); > } > } > } > diff --git a/include/linux/dmar.h b/include/linux/dmar.h > index 7b776d7..cf071f9 100644 > --- a/include/linux/dmar.h > +++ b/include/linux/dmar.h > @@ -32,8 +32,8 @@ struct dmar_drhd_unit { > struct list_head list; /* list of drhd units */ > struct acpi_dmar_header *hdr; /* ACPI header */ > u64 reg_base_addr; /* register base address*/ > - struct pci_dev **devices; /* target device array */ > - int devices_cnt; /* target device count */ > + struct acpi_dmar_device_scope **scopes; /* target scope array */ > + int scopes_cnt; /* target scope count */ > u16 segment; /* PCI domain */ > u8 ignored:1; /* ignore drhd */ > u8 include_all:1; > @@ -55,6 +55,9 @@ extern struct list_head dmar_drhd_units; > > extern int dmar_table_init(void); > extern int dmar_dev_scope_init(void); > +extern int dmar_match_scope(struct acpi_dmar_device_scope **, int, > + struct pci_dev *, u16); > +extern struct pci_dev *dmar_get_scope_dev(struct acpi_dmar_device_scope *, u16); > > /* Intel IOMMU detection */ > extern int detect_intel_iommu(void); > @@ -72,6 +75,20 @@ static inline int dmar_table_init(void) > { > return -ENODEV; > } > + > +static inline int dmar_match_scope(struct acpi_dmar_device_scope **scopes, > + int cnt, struct pci_dev *dev, u16 segment) > +{ > + return 0; > +} > + > +static inline struct pci_dev *dmar_get_scope_dev( > + struct acpi_dmar_device_scope *scope, > + u16 segment) > +{ > + return NULL; > +} > + > static inline int enable_drhd_fault_handling(void) > { > return -1; > @@ -212,8 +229,8 @@ struct dmar_rmrr_unit { > struct acpi_dmar_header *hdr; /* ACPI header */ > u64 base_address; /* reserved base address*/ > u64 end_address; /* reserved end address */ > - struct pci_dev **devices; /* target devices */ > - int devices_cnt; /* target device count */ > + struct acpi_dmar_device_scope **scopes; /* target scope array */ > + int scopes_cnt; /* target scope count */ > }; > > #define for_each_rmrr_units(rmrr) \ > @@ -222,8 +239,8 @@ struct dmar_rmrr_unit { > struct dmar_atsr_unit { > struct list_head list; /* list of ATSR units */ > struct acpi_dmar_header *hdr; /* ACPI header */ > - struct pci_dev **devices; /* target devices */ > - int devices_cnt; /* target device count */ > + struct acpi_dmar_device_scope **scopes; /* target scope array */ > + int scopes_cnt; /* target scope count */ > u8 include_all:1; /* include all ports */ > }; > > No, it does not work. [ 592.792864] BUG: unable to handle kernel NULL pointer dereference at 0000000000000010 [ 592.793279] IP: [<ffffffff8136271a>] dmar_match_scope+0x27/0xb6 [ 592.804488] PGD 0 [ 592.804629] Oops: 0000 [#1] SMP [ 592.804849] CPU 1 [ 592.804947] Modules linked in: [ 592.824426] [ 592.824521] Pid: 14498, comm: kworker/u:7 Tainted: G W 2.6.39-tip-yh-06738-g5d55a15-dirty #1043 Oracle Corporation Sun Fire X4800 M2 / [ 592.844637] RIP: 0010:[<ffffffff8136271a>] [<ffffffff8136271a>] dmar_match_scope+0x27/0xb6 [ 592.864410] RSP: 0018:ffff881ffce45a70 EFLAGS: 00010293 [ 592.864673] RAX: 0000000000000000 RBX: 0000000000000008 RCX: 0000000000000000 [ 592.884403] RDX: 0000000000000000 RSI: 0000000000000008 RDI: ffff88fffeef6000 [ 592.904205] RBP: ffff881ffce45ab0 R08: 0000000000000000 R09: 0000000000000000 [ 592.904535] R10: 0000000000000000 R11: ffff88dffedda320 R12: 0000000000000000 [ 592.924419] R13: 0000000000000000 R14: ffff88fffeef6000 R15: 0000000000000000 [ 592.924748] FS: 0000000000000000(0000) GS:ffff88207d800000(0000) knlGS:0000000000000000 [ 592.944447] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 592.964196] CR2: 0000000000000010 CR3: 00000000023cb000 CR4: 00000000000006e0 [ 592.964541] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 592.984308] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 593.004091] Process kworker/u:7 (pid: 14498, threadinfo ffff881ffce44000, task ffff881ffce3c560) [ 593.004492] Stack: [ 593.024051] ffff881ffce45a80 ffffffff8134bf6a ffff881ffce45ab0 ffff88407d002640 [ 593.024479] 0000000000000000 0000000000000000 0000000000000000 0000000000000000 [ 593.044272] ffff881ffce45ae0 ffffffff81363e4a ffff881ffce45b00 ffff88dffe1c1d00 [ 593.064027] Call Trace: [ 593.064156] [<ffffffff8134bf6a>] ? pci_get_device+0x16/0x18 [ 593.064441] [<ffffffff81363e4a>] device_to_iommu+0x4c/0x77 [ 593.084054] [<ffffffff81364163>] domain_remove_one_dev_info+0x39/0x1fc [ 593.084361] [<ffffffff8136637f>] device_notifier+0x52/0x78 [ 593.104093] [<ffffffff81c24cc3>] notifier_call_chain+0x68/0x9f [ 593.123814] [<ffffffff81193710>] ? sysfs_schedule_callback+0x1df/0x1df [ 593.124125] [<ffffffff8109f209>] __blocking_notifier_call_chain+0x4c/0x61 [ 593.143899] [<ffffffff8109f232>] blocking_notifier_call_chain+0x14/0x16 [ 593.144207] [<ffffffff81414909>] __device_release_driver+0xcd/0xd2 [ 593.163934] [<ffffffff81414933>] device_release_driver+0x25/0x32 [ 593.164222] [<ffffffff814144bd>] bus_remove_device+0x8e/0x9f [ 593.183934] [<ffffffff8141255e>] device_del+0x130/0x17f [ 593.184186] [<ffffffff814125c3>] device_unregister+0x16/0x23 [ 593.203888] [<ffffffff813473e5>] pci_stop_bus_device+0x61/0x83 [ 593.223661] [<ffffffff8134c88a>] ? remove_callback+0x1f/0x3c [ 593.223932] [<ffffffff813473b4>] pci_stop_bus_device+0x30/0x83 [ 593.243652] [<ffffffff81347470>] pci_remove_bus_device+0x1a/0xba [ 593.243955] [<ffffffff8134c896>] remove_callback+0x2b/0x3c [ 593.263631] [<ffffffff8119372c>] sysfs_schedule_callback_work+0x1c/0x5f [ 593.263962] [<ffffffff8109433b>] process_one_work+0x231/0x3e6 [ 593.283667] [<ffffffff810942ac>] ? process_one_work+0x1a2/0x3e6 [ 593.283958] [<ffffffff81094829>] worker_thread+0x17c/0x240 [ 593.303651] [<ffffffff810add32>] ? trace_hardirqs_on+0xd/0xf [ 593.303927] [<ffffffff810946ad>] ? manage_workers+0xab/0xab [ 593.323617] [<ffffffff81099ea5>] kthread+0xa0/0xa8 [ 593.323845] [<ffffffff810adbcc>] ? trace_hardirqs_on_caller+0x1f/0x178 [ 593.343620] [<ffffffff81c29614>] kernel_thread_helper+0x4/0x10 [ 593.343888] [<ffffffff81c218c4>] ? _raw_spin_unlock_irq+0x30/0x36 [ 593.363642] [<ffffffff810add32>] ? trace_hardirqs_on+0xd/0xf [ 593.383357] [<ffffffff81c21bc0>] ? retint_restore_args+0xe/0xe [ 593.383624] [<ffffffff81099e05>] ? __init_kthread_worker+0x5b/0x5b [ 593.403441] [<ffffffff81c29610>] ? gs_change+0xb/0xb [ 593.403667] Code: 41 5f c9 c3 55 48 89 e5 41 57 41 56 41 55 41 54 53 48 83 ec 18 66 66 66 66 90 45 31 ed 89 f3 49 89 d4 49 89 fe 44 0f b7 f9 eb 72 [ 593.424146] 8b 44 24 10 49 8b 16 48 8b 80 88 00 00 00 44 3b 38 75 57 48 [ 593.443684] RIP [<ffffffff8136271a>] dmar_match_scope+0x27/0xb6 [ 593.443968] RSP <ffff881ffce45a70> [ 593.463319] CR2: 0000000000000010 [ 593.463510] ---[ end trace 75ddbb3d94414ea9 ]--- [ 593.465841] BUG: unable to handle kernel -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, 2011-05-24 at 14:45 -0700, Yinghai Lu wrote: > No, it does not work. I didn't say this wasn't without some effort, just thought it might give you a jump start. Alex > [ 592.792864] BUG: unable to handle kernel NULL pointer dereference at 0000000000000010 > [ 592.793279] IP: [<ffffffff8136271a>] dmar_match_scope+0x27/0xb6 > [ 592.804488] PGD 0 > [ 592.804629] Oops: 0000 [#1] SMP > [ 592.804849] CPU 1 > [ 592.804947] Modules linked in: > [ 592.824426] > [ 592.824521] Pid: 14498, comm: kworker/u:7 Tainted: G W 2.6.39-tip-yh-06738-g5d55a15-dirty #1043 Oracle Corporation Sun Fire X4800 M2 / > [ 592.844637] RIP: 0010:[<ffffffff8136271a>] [<ffffffff8136271a>] dmar_match_scope+0x27/0xb6 > [ 592.864410] RSP: 0018:ffff881ffce45a70 EFLAGS: 00010293 > [ 592.864673] RAX: 0000000000000000 RBX: 0000000000000008 RCX: 0000000000000000 > [ 592.884403] RDX: 0000000000000000 RSI: 0000000000000008 RDI: ffff88fffeef6000 > [ 592.904205] RBP: ffff881ffce45ab0 R08: 0000000000000000 R09: 0000000000000000 > [ 592.904535] R10: 0000000000000000 R11: ffff88dffedda320 R12: 0000000000000000 > [ 592.924419] R13: 0000000000000000 R14: ffff88fffeef6000 R15: 0000000000000000 > [ 592.924748] FS: 0000000000000000(0000) GS:ffff88207d800000(0000) knlGS:0000000000000000 > [ 592.944447] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b > [ 592.964196] CR2: 0000000000000010 CR3: 00000000023cb000 CR4: 00000000000006e0 > [ 592.964541] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 > [ 592.984308] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 > [ 593.004091] Process kworker/u:7 (pid: 14498, threadinfo ffff881ffce44000, task ffff881ffce3c560) > [ 593.004492] Stack: > [ 593.024051] ffff881ffce45a80 ffffffff8134bf6a ffff881ffce45ab0 ffff88407d002640 > [ 593.024479] 0000000000000000 0000000000000000 0000000000000000 0000000000000000 > [ 593.044272] ffff881ffce45ae0 ffffffff81363e4a ffff881ffce45b00 ffff88dffe1c1d00 > [ 593.064027] Call Trace: > [ 593.064156] [<ffffffff8134bf6a>] ? pci_get_device+0x16/0x18 > [ 593.064441] [<ffffffff81363e4a>] device_to_iommu+0x4c/0x77 > [ 593.084054] [<ffffffff81364163>] domain_remove_one_dev_info+0x39/0x1fc > [ 593.084361] [<ffffffff8136637f>] device_notifier+0x52/0x78 > [ 593.104093] [<ffffffff81c24cc3>] notifier_call_chain+0x68/0x9f > [ 593.123814] [<ffffffff81193710>] ? sysfs_schedule_callback+0x1df/0x1df > [ 593.124125] [<ffffffff8109f209>] __blocking_notifier_call_chain+0x4c/0x61 > [ 593.143899] [<ffffffff8109f232>] blocking_notifier_call_chain+0x14/0x16 > [ 593.144207] [<ffffffff81414909>] __device_release_driver+0xcd/0xd2 > [ 593.163934] [<ffffffff81414933>] device_release_driver+0x25/0x32 > [ 593.164222] [<ffffffff814144bd>] bus_remove_device+0x8e/0x9f > [ 593.183934] [<ffffffff8141255e>] device_del+0x130/0x17f > [ 593.184186] [<ffffffff814125c3>] device_unregister+0x16/0x23 > [ 593.203888] [<ffffffff813473e5>] pci_stop_bus_device+0x61/0x83 > [ 593.223661] [<ffffffff8134c88a>] ? remove_callback+0x1f/0x3c > [ 593.223932] [<ffffffff813473b4>] pci_stop_bus_device+0x30/0x83 > [ 593.243652] [<ffffffff81347470>] pci_remove_bus_device+0x1a/0xba > [ 593.243955] [<ffffffff8134c896>] remove_callback+0x2b/0x3c > [ 593.263631] [<ffffffff8119372c>] sysfs_schedule_callback_work+0x1c/0x5f > [ 593.263962] [<ffffffff8109433b>] process_one_work+0x231/0x3e6 > [ 593.283667] [<ffffffff810942ac>] ? process_one_work+0x1a2/0x3e6 > [ 593.283958] [<ffffffff81094829>] worker_thread+0x17c/0x240 > [ 593.303651] [<ffffffff810add32>] ? trace_hardirqs_on+0xd/0xf > [ 593.303927] [<ffffffff810946ad>] ? manage_workers+0xab/0xab > [ 593.323617] [<ffffffff81099ea5>] kthread+0xa0/0xa8 > [ 593.323845] [<ffffffff810adbcc>] ? trace_hardirqs_on_caller+0x1f/0x178 > [ 593.343620] [<ffffffff81c29614>] kernel_thread_helper+0x4/0x10 > [ 593.343888] [<ffffffff81c218c4>] ? _raw_spin_unlock_irq+0x30/0x36 > [ 593.363642] [<ffffffff810add32>] ? trace_hardirqs_on+0xd/0xf > [ 593.383357] [<ffffffff81c21bc0>] ? retint_restore_args+0xe/0xe > [ 593.383624] [<ffffffff81099e05>] ? __init_kthread_worker+0x5b/0x5b > [ 593.403441] [<ffffffff81c29610>] ? gs_change+0xb/0xb > [ 593.403667] Code: 41 5f c9 c3 55 48 89 e5 41 57 41 56 41 55 41 54 53 48 83 ec 18 66 66 66 66 90 45 31 ed 89 f3 49 89 d4 49 89 fe 44 0f b7 f9 eb 72 > [ 593.424146] 8b 44 24 10 49 8b 16 48 8b 80 88 00 00 00 44 3b 38 75 57 48 > [ 593.443684] RIP [<ffffffff8136271a>] dmar_match_scope+0x27/0xb6 > [ 593.443968] RSP <ffff881ffce45a70> > [ 593.463319] CR2: 0000000000000010 > [ 593.463510] ---[ end trace 75ddbb3d94414ea9 ]--- > [ 593.465841] BUG: unable to handle kernel > -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 05/24/2011 03:38 PM, Alex Williamson wrote: > On Tue, 2011-05-24 at 14:45 -0700, Yinghai Lu wrote: >> No, it does not work. > > I didn't say this wasn't without some effort, just thought it might give > you a jump start. ok, let me debug it tonight. looks like that pdev is not freed, but already get removed from the device tree. may need to pass pci_dev pointer directly. > > Alex > >> [ 592.792864] BUG: unable to handle kernel NULL pointer dereference at 0000000000000010 >> [ 592.793279] IP: [<ffffffff8136271a>] dmar_match_scope+0x27/0xb6 >> [ 592.804488] PGD 0 >> [ 592.804629] Oops: 0000 [#1] SMP >> [ 592.804849] CPU 1 >> [ 592.804947] Modules linked in: >> [ 592.824426] >> [ 592.824521] Pid: 14498, comm: kworker/u:7 Tainted: G W 2.6.39-tip-yh-06738-g5d55a15-dirty #1043 Oracle Corporation Sun Fire X4800 M2 / >> [ 592.844637] RIP: 0010:[<ffffffff8136271a>] [<ffffffff8136271a>] dmar_match_scope+0x27/0xb6 >> [ 592.864410] RSP: 0018:ffff881ffce45a70 EFLAGS: 00010293 >> [ 592.864673] RAX: 0000000000000000 RBX: 0000000000000008 RCX: 0000000000000000 >> [ 592.884403] RDX: 0000000000000000 RSI: 0000000000000008 RDI: ffff88fffeef6000 >> [ 592.904205] RBP: ffff881ffce45ab0 R08: 0000000000000000 R09: 0000000000000000 >> [ 592.904535] R10: 0000000000000000 R11: ffff88dffedda320 R12: 0000000000000000 >> [ 592.924419] R13: 0000000000000000 R14: ffff88fffeef6000 R15: 0000000000000000 >> [ 592.924748] FS: 0000000000000000(0000) GS:ffff88207d800000(0000) knlGS:0000000000000000 >> [ 592.944447] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b >> [ 592.964196] CR2: 0000000000000010 CR3: 00000000023cb000 CR4: 00000000000006e0 >> [ 592.964541] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 >> [ 592.984308] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 >> [ 593.004091] Process kworker/u:7 (pid: 14498, threadinfo ffff881ffce44000, task ffff881ffce3c560) >> [ 593.004492] Stack: >> [ 593.024051] ffff881ffce45a80 ffffffff8134bf6a ffff881ffce45ab0 ffff88407d002640 >> [ 593.024479] 0000000000000000 0000000000000000 0000000000000000 0000000000000000 >> [ 593.044272] ffff881ffce45ae0 ffffffff81363e4a ffff881ffce45b00 ffff88dffe1c1d00 >> [ 593.064027] Call Trace: >> [ 593.064156] [<ffffffff8134bf6a>] ? pci_get_device+0x16/0x18 >> [ 593.064441] [<ffffffff81363e4a>] device_to_iommu+0x4c/0x77 >> [ 593.084054] [<ffffffff81364163>] domain_remove_one_dev_info+0x39/0x1fc >> [ 593.084361] [<ffffffff8136637f>] device_notifier+0x52/0x78 >> [ 593.104093] [<ffffffff81c24cc3>] notifier_call_chain+0x68/0x9f >> [ 593.123814] [<ffffffff81193710>] ? sysfs_schedule_callback+0x1df/0x1df >> [ 593.124125] [<ffffffff8109f209>] __blocking_notifier_call_chain+0x4c/0x61 >> [ 593.143899] [<ffffffff8109f232>] blocking_notifier_call_chain+0x14/0x16 >> [ 593.144207] [<ffffffff81414909>] __device_release_driver+0xcd/0xd2 >> [ 593.163934] [<ffffffff81414933>] device_release_driver+0x25/0x32 >> [ 593.164222] [<ffffffff814144bd>] bus_remove_device+0x8e/0x9f >> [ 593.183934] [<ffffffff8141255e>] device_del+0x130/0x17f >> [ 593.184186] [<ffffffff814125c3>] device_unregister+0x16/0x23 >> [ 593.203888] [<ffffffff813473e5>] pci_stop_bus_device+0x61/0x83 >> [ 593.223661] [<ffffffff8134c88a>] ? remove_callback+0x1f/0x3c >> [ 593.223932] [<ffffffff813473b4>] pci_stop_bus_device+0x30/0x83 >> [ 593.243652] [<ffffffff81347470>] pci_remove_bus_device+0x1a/0xba >> [ 593.243955] [<ffffffff8134c896>] remove_callback+0x2b/0x3c >> [ 593.263631] [<ffffffff8119372c>] sysfs_schedule_callback_work+0x1c/0x5f >> [ 593.263962] [<ffffffff8109433b>] process_one_work+0x231/0x3e6 >> [ 593.283667] [<ffffffff810942ac>] ? process_one_work+0x1a2/0x3e6 >> [ 593.283958] [<ffffffff81094829>] worker_thread+0x17c/0x240 >> [ 593.303651] [<ffffffff810add32>] ? trace_hardirqs_on+0xd/0xf >> [ 593.303927] [<ffffffff810946ad>] ? manage_workers+0xab/0xab >> [ 593.323617] [<ffffffff81099ea5>] kthread+0xa0/0xa8 >> [ 593.323845] [<ffffffff810adbcc>] ? trace_hardirqs_on_caller+0x1f/0x178 >> [ 593.343620] [<ffffffff81c29614>] kernel_thread_helper+0x4/0x10 >> [ 593.343888] [<ffffffff81c218c4>] ? _raw_spin_unlock_irq+0x30/0x36 >> [ 593.363642] [<ffffffff810add32>] ? trace_hardirqs_on+0xd/0xf >> [ 593.383357] [<ffffffff81c21bc0>] ? retint_restore_args+0xe/0xe >> [ 593.383624] [<ffffffff81099e05>] ? __init_kthread_worker+0x5b/0x5b >> [ 593.403441] [<ffffffff81c29610>] ? gs_change+0xb/0xb >> [ 593.403667] Code: 41 5f c9 c3 55 48 89 e5 41 57 41 56 41 55 41 54 53 48 83 ec 18 66 66 66 66 90 45 31 ed 89 f3 49 89 d4 49 89 fe 44 0f b7 f9 eb 72 >> [ 593.424146] 8b 44 24 10 49 8b 16 48 8b 80 88 00 00 00 44 3b 38 75 57 48 >> [ 593.443684] RIP [<ffffffff8136271a>] dmar_match_scope+0x27/0xb6 >> [ 593.443968] RSP <ffff881ffce45a70> >> [ 593.463319] CR2: 0000000000000010 >> [ 593.463510] ---[ end trace 75ddbb3d94414ea9 ]--- >> [ 593.465841] BUG: unable to handle kernel >> > > -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, May 24, 2011 at 4:02 PM, Yinghai Lu <yinghai@kernel.org> wrote: > On 05/24/2011 03:38 PM, Alex Williamson wrote: >> On Tue, 2011-05-24 at 14:45 -0700, Yinghai Lu wrote: >>> No, it does not work. >> >> I didn't say this wasn't without some effort, just thought it might give >> you a jump start. > > ok, let me debug it tonight. > > looks like that pdev is not freed, but already get removed from the device tree. > > may need to pass pci_dev pointer directly. keep getting: [ 784.364244] BUG: sleeping function called from invalid context at kernel/rwsem.c:21 [ 784.364253] in_atomic(): 0, irqs_disabled(): 1, pid: 29398, name: work_for_cpu [ 784.364259] INFO: lockdep is turned off. [ 784.364265] irq event stamp: 0 [ 784.364271] hardirqs last enabled at (0): [< (null)>] (null) [ 784.364282] hardirqs last disabled at (0): [<ffffffff8107ba5e>] copy_process+0x43b/0xd95 [ 784.364305] softirqs last enabled at (0): [<ffffffff8107ba5e>] copy_process+0x43b/0xd95 [ 784.364318] softirqs last disabled at (0): [< (null)>] (null) [ 784.364332] Pid: 29398, comm: work_for_cpu Not tainted 2.6.39-tip-yh-06791-gb282579-dirty #1047 [ 784.364339] Call Trace: [ 784.364375] [<ffffffff810ad12a>] ? print_irqtrace_events+0xd0/0xd4 [ 784.364392] [<ffffffff81071572>] __might_sleep+0xf2/0xf6 [ 784.364410] [<ffffffff81c20fc0>] down_read+0x26/0x91 [ 784.364429] [<ffffffff8134c089>] pci_find_next_bus+0x45/0x75 [ 784.364442] [<ffffffff8134c0fa>] pci_find_bus+0x41/0x54 [ 784.364457] [<ffffffff8136263f>] dmar_get_scope_dev+0x2f/0xe3 [ 784.364474] [<ffffffff813353ad>] ? random32+0x19/0x1b [ 784.364488] [<ffffffff8136273d>] dmar_match_scope+0x4a/0xb6 [ 784.364502] [<ffffffff813628d4>] dmar_find_matched_drhd_unit+0x55/0x6f [ 784.364519] [<ffffffff81367018>] get_domain_for_dev.clone.2+0x103/0x392 [ 784.364533] [<ffffffff81367459>] __get_valid_domain_for_dev+0x14/0x88 [ 784.364546] [<ffffffff813676c5>] __intel_map_single+0x58/0x174 [ 784.364559] [<ffffffff813678eb>] intel_alloc_coherent+0xc7/0xee [ 784.364575] [<ffffffff811281dc>] pool_alloc_page.clone.0+0xc9/0x140 [ 784.364588] [<ffffffff811282d8>] dma_pool_alloc+0x85/0x131 [ 784.364603] [<ffffffff81134b8c>] ? should_failslab+0x44/0x48 [ 784.364618] [<ffffffff81132d62>] ? kmem_cache_alloc_trace+0x5e/0x123 [ 784.364635] [<ffffffff818429aa>] ehci_qh_alloc+0x59/0xd2 [ 784.364649] [<ffffffff81844451>] ehci_mem_init.clone.1+0x84/0x25c [ 784.364660] [<ffffffff8184471b>] ehci_init+0xf2/0x245 [ 784.364671] [<ffffffff81844999>] ehci_pci_setup+0x12b/0x564 [ 784.364687] [<ffffffff818323d5>] usb_add_hcd+0x10f/0x318 [ 784.364703] [<ffffffff8183e31e>] usb_hcd_pci_probe+0x1e4/0x312 [ 784.364722] [<ffffffff8134ae25>] local_pci_probe+0x4d/0x96 [ 784.364739] [<ffffffff81093c4b>] ? cwq_dec_nr_in_flight+0x81/0x81 [ 784.364754] [<ffffffff81093c63>] do_work_for_cpu+0x18/0x2b [ 784.364770] [<ffffffff81093c4b>] ? cwq_dec_nr_in_flight+0x81/0x81 [ 784.364787] [<ffffffff81099ea5>] kthread+0xa0/0xa8 [ 784.364801] [<ffffffff810adbcc>] ? trace_hardirqs_on_caller+0x1f/0x178 [ 784.364818] [<ffffffff81c2a214>] kernel_thread_helper+0x4/0x10 [ 784.364832] [<ffffffff81c224cc>] ? _raw_spin_unlock_irq+0x30/0x36 [ 784.364846] [<ffffffff810add32>] ? trace_hardirqs_on+0xd/0xf [ 784.364861] [<ffffffff81c227c0>] ? retint_restore_args+0xe/0xe [ 784.364880] [<ffffffff81099e05>] ? __init_kthread_worker+0x5b/0x5b [ 784.364893] [<ffffffff81c2a210>] ? gs_change+0xb/0xb [ 784.364902] DMAR: Device scope device [0000:40:00.00] not found [ 784.364910] DMAR: Device scope device [0000:40:01.00] not found [ 784.364931] DMAR: Device scope device [0000:40:03.00] not found [ 784.364948] DMAR: Device scope device [0000:40:05.00] not found [ 784.364961] DMAR: Device scope device [0000:40:07.00] not found [ 784.364978] DMAR: Device scope device [0000:40:09.00] not found [ 784.365019] DMAR: Device scope device [0000:80:00.00] not found [ 784.365034] DMAR: Device scope device [0000:80:01.00] not found [ 784.365053] DMAR: Device scope device [0000:80:03.00] not found [ 784.365075] DMAR: Device scope device [0000:80:05.00] not found [ 784.365094] DMAR: Device scope device [0000:80:07.00] not found [ 784.365116] DMAR: Device scope device [0000:80:09.00] not found [ 784.365166] DMAR: Device scope device [0000:c0:00.00] not found [ 784.365193] DMAR: Device scope device [0000:c0:01.00] not found [ 784.365216] DMAR: Device scope device [0000:c0:03.00] not found [ 784.365243] DMAR: Device scope device [0000:c0:05.00] not found [ 784.365266] DMAR: Device scope device [0000:c0:07.00] not found [ 784.365284] DMAR: Device scope device [0000:c0:09.00] not found -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 12e02bf..47e4f09 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -61,8 +61,8 @@ static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd) list_add(&drhd->list, &dmar_drhd_units); } -static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, - struct pci_dev **dev, u16 segment) +struct pci_dev *dmar_get_scope_dev(struct acpi_dmar_device_scope *scope, + u16 segment) { struct pci_bus *bus; struct pci_dev *pdev = NULL; @@ -74,7 +74,7 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, count = (scope->length - sizeof(struct acpi_dmar_device_scope)) / sizeof(struct acpi_dmar_pci_path); - while (count) { + for (; count; path++, count--, bus = pdev->subordinate) { if (pdev) pci_dev_put(pdev); /* @@ -82,53 +82,77 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, * ignore it */ if (!bus) { - printk(KERN_WARNING - PREFIX "Device scope bus [%d] not found\n", - scope->bus); - break; + printk(KERN_WARNING PREFIX + "Device scope bus [%d] not found\n", scope->bus); + return NULL; } pdev = pci_get_slot(bus, PCI_DEVFN(path->dev, path->fn)); if (!pdev) { printk(KERN_WARNING PREFIX - "Device scope device [%04x:%02x:%02x.%02x] not found\n", - segment, bus->number, path->dev, path->fn); - break; + "Device scope device [%04x:%02x:%02x.%02x] not found\n", + segment, bus->number, path->dev, path->fn); + return NULL; } - path ++; - count --; - bus = pdev->subordinate; } - if (!pdev) { - printk(KERN_WARNING PREFIX - "Device scope device [%04x:%02x:%02x.%02x] not found\n", - segment, scope->bus, path->dev, path->fn); - *dev = NULL; + + return pdev; +} + +static int dmar_match_scope_one(struct acpi_dmar_device_scope *scope, + struct pci_dev *dev, u16 segment) +{ + struct pci_dev *pdev; + int ret = 0; + + if (segment != pci_domain_nr(dev->bus)) + return 0; + + pdev = dmar_get_scope_dev(scope, segment); + if (!pdev) return 0; + + if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT) { + if (dev == pdev) + ret = 1; + } else { + while (dev) { + if (dev == pdev) { + ret = 1; + break; + } + dev = dev->bus->self; + } } - if ((scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT && \ - pdev->subordinate) || (scope->entry_type == \ - ACPI_DMAR_SCOPE_TYPE_BRIDGE && !pdev->subordinate)) { - pci_dev_put(pdev); - printk(KERN_WARNING PREFIX - "Device scope type does not match for %s\n", - pci_name(pdev)); - return -EINVAL; + + pci_dev_put(pdev); + + return ret; +} + +int dmar_match_scope(struct acpi_dmar_device_scope **scopes, int cnt, + struct pci_dev *dev, u16 segment) +{ + int i; + + for (i = 0; i < cnt; i++) { + if (dmar_match_scope_one(scopes[i], dev, segment)) + return 1; } - *dev = pdev; return 0; } static int __init dmar_parse_dev_scope(void *start, void *end, int *cnt, - struct pci_dev ***devices, u16 segment) + struct acpi_dmar_device_scope ***scopes) { struct acpi_dmar_device_scope *scope; - void * tmp = start; - int index; - int ret; + void *tmp = start; + int index = 0; *cnt = 0; + while (start < end) { scope = start; + if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT || scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE) (*cnt)++; @@ -138,27 +162,23 @@ static int __init dmar_parse_dev_scope(void *start, void *end, int *cnt, } start += scope->length; } + if (*cnt == 0) return 0; - *devices = kcalloc(*cnt, sizeof(struct pci_dev *), GFP_KERNEL); - if (!*devices) + *scopes = kcalloc(*cnt, sizeof(struct acpi_dmar_device_scope *), + GFP_KERNEL); + if (!*scopes) return -ENOMEM; start = tmp; - index = 0; while (start < end) { scope = start; + if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT || - scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE) { - ret = dmar_parse_one_dev_scope(scope, - &(*devices)[index], segment); - if (ret) { - kfree(*devices); - return ret; - } - index ++; - } + scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE) + (*scopes)[index++] = scope; + start += scope->length; } @@ -207,9 +227,8 @@ static int __init dmar_parse_dev(struct dmar_drhd_unit *dmaru) return 0; ret = dmar_parse_dev_scope((void *)(drhd + 1), - ((void *)drhd) + drhd->header.length, - &dmaru->devices_cnt, &dmaru->devices, - drhd->segment); + ((void *)drhd) + drhd->header.length, + &dmaru->scopes_cnt, &dmaru->scopes); if (ret) { list_del(&dmaru->list); kfree(dmaru); @@ -253,10 +272,10 @@ rmrr_parse_dev(struct dmar_rmrr_unit *rmrru) rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr; ret = dmar_parse_dev_scope((void *)(rmrr + 1), - ((void *)rmrr) + rmrr->header.length, - &rmrru->devices_cnt, &rmrru->devices, rmrr->segment); + ((void *)rmrr) + rmrr->header.length, + &rmrru->scopes_cnt, &rmrru->scopes); - if (ret || (rmrru->devices_cnt == 0)) { + if (ret || (rmrru->scopes_cnt == 0)) { list_del(&rmrru->list); kfree(rmrru); } @@ -293,10 +312,9 @@ static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru) atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header); rc = dmar_parse_dev_scope((void *)(atsr + 1), - (void *)atsr + atsr->header.length, - &atsru->devices_cnt, &atsru->devices, - atsr->segment); - if (rc || !atsru->devices_cnt) { + (void *)atsr + atsr->header.length, + &atsru->scopes_cnt, &atsru->scopes); + if (rc || !atsru->scopes_cnt) { list_del(&atsru->list); kfree(atsru); } @@ -310,6 +328,7 @@ int dmar_find_matched_atsr_unit(struct pci_dev *dev) struct pci_bus *bus; struct acpi_dmar_atsr *atsr; struct dmar_atsr_unit *atsru; + struct pci_dev *pdev; dev = pci_physfn(dev); @@ -330,10 +349,18 @@ found: return 0; if (bridge->pcie_type == PCI_EXP_TYPE_ROOT_PORT) { - for (i = 0; i < atsru->devices_cnt; i++) - if (atsru->devices[i] == bridge) + for (i = 0; i < atsru->scopes_cnt; i++) { + pdev = dmar_get_scope_dev(atsru->scopes[i], + atsr->segment); + if (!pdev) + continue; + + if (pdev == bridge) { + pci_dev_put(pdev); return 1; - break; + } + pci_dev_put(pdev); + } } } @@ -513,23 +540,6 @@ parse_dmar_table(void) return ret; } -static int dmar_pci_device_match(struct pci_dev *devices[], int cnt, - struct pci_dev *dev) -{ - int index; - - while (dev) { - for (index = 0; index < cnt; index++) - if (dev == devices[index]) - return 1; - - /* Check our parent */ - dev = dev->bus->self; - } - - return 0; -} - struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev) { @@ -544,11 +554,11 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev) header); if (dmaru->include_all && - drhd->segment == pci_domain_nr(dev->bus)) + dmaru->segment == pci_domain_nr(dev->bus)) return dmaru; - if (dmar_pci_device_match(dmaru->devices, - dmaru->devices_cnt, dev)) + if (dmar_match_scope(dmaru->scopes, dmaru->scopes_cnt, + dev, dmaru->segment)) return dmaru; } diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index b04f84e..d1d542a 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -563,32 +563,34 @@ static void domain_update_iommu_cap(struct dmar_domain *domain) static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn) { - struct dmar_drhd_unit *drhd = NULL; - int i; + struct dmar_drhd_unit *dmaru = NULL; + struct pci_dev *pdev; + struct intel_iommu *found = NULL; - for_each_drhd_unit(drhd) { - if (drhd->ignored) + pdev = pci_get_domain_bus_and_slot(segment, bus, devfn); + + for_each_drhd_unit(dmaru) { + if (dmaru->ignored) continue; - if (segment != drhd->segment) + if (segment != dmaru->segment) continue; - for (i = 0; i < drhd->devices_cnt; i++) { - if (drhd->devices[i] && - drhd->devices[i]->bus->number == bus && - drhd->devices[i]->devfn == devfn) - return drhd->iommu; - if (drhd->devices[i] && - drhd->devices[i]->subordinate && - drhd->devices[i]->subordinate->number <= bus && - drhd->devices[i]->subordinate->subordinate >= bus) - return drhd->iommu; + if (dmaru->include_all) { + found = dmaru->iommu; + break; + } + + if (dmar_match_scope(dmaru->scopes, dmaru->scopes_cnt, + pdev, dmaru->segment)) { + found = dmaru->iommu; + break; } - if (drhd->include_all) - return drhd->iommu; } - return NULL; + pci_dev_put(pdev); + + return found; } static void domain_flush_cache(struct dmar_domain *domain, @@ -2227,7 +2229,7 @@ static int __init init_dmars(int force_on) struct dmar_rmrr_unit *rmrr; struct pci_dev *pdev; struct intel_iommu *iommu; - int i, ret; + int ret; /* * for each drhd @@ -2376,18 +2378,22 @@ static int __init init_dmars(int force_on) */ printk(KERN_INFO "IOMMU: Setting RMRR:\n"); for_each_rmrr_units(rmrr) { - for (i = 0; i < rmrr->devices_cnt; i++) { - pdev = rmrr->devices[i]; - /* - * some BIOS lists non-exist devices in DMAR - * table. - */ + struct acpi_dmar_reserved_memory *rmrrh; + int i; + + rmrrh = container_of(rmrr->hdr, + struct acpi_dmar_reserved_memory, header); + + for (i = 0; i < rmrr->scopes_cnt; i++) { + pdev = dmar_get_scope_dev(rmrr->scopes[i], + rmrrh->segment); if (!pdev) continue; - ret = iommu_prepare_rmrr_dev(rmrr, pdev); - if (ret) + + if (iommu_prepare_rmrr_dev(rmrr, pdev)) printk(KERN_ERR "IOMMU: mapping reserved region failed\n"); + pci_dev_put(pdev); } } @@ -3072,15 +3078,21 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quir static void __init init_no_remapping_devices(void) { struct dmar_drhd_unit *drhd; + struct pci_dev *pdev; for_each_drhd_unit(drhd) { if (!drhd->include_all) { int i; - for (i = 0; i < drhd->devices_cnt; i++) - if (drhd->devices[i] != NULL) + for (i = 0; i < drhd->scopes_cnt; i++) { + pdev = dmar_get_scope_dev(drhd->scopes[i], + drhd->segment); + if (pdev) { + pci_dev_put(pdev); break; + } + } /* ignore DMAR unit if no pci devices exist */ - if (i == drhd->devices_cnt) + if (i == drhd->scopes_cnt) drhd->ignored = 1; } } @@ -3093,20 +3105,28 @@ static void __init init_no_remapping_devices(void) if (drhd->ignored || drhd->include_all) continue; - for (i = 0; i < drhd->devices_cnt; i++) - if (drhd->devices[i] && - !IS_GFX_DEVICE(drhd->devices[i])) + for (i = 0; i < drhd->scopes_cnt; i++) { + pdev = dmar_get_scope_dev(drhd->scopes[i], + drhd->segment); + if (pdev && !IS_GFX_DEVICE(pdev)) { + pci_dev_put(pdev); break; + } + pci_dev_put(pdev); + } - if (i < drhd->devices_cnt) + if (i < drhd->scopes_cnt) continue; /* bypass IOMMU if it is just for gfx devices */ drhd->ignored = 1; - for (i = 0; i < drhd->devices_cnt; i++) { - if (!drhd->devices[i]) + for (i = 0; i < drhd->scopes_cnt; i++) { + pdev = dmar_get_scope_dev(drhd->scopes[i], + drhd->segment); + if (!pdev) continue; - drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO; + pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO; + pci_dev_put(pdev); } } } diff --git a/include/linux/dmar.h b/include/linux/dmar.h index 7b776d7..cf071f9 100644 --- a/include/linux/dmar.h +++ b/include/linux/dmar.h @@ -32,8 +32,8 @@ struct dmar_drhd_unit { struct list_head list; /* list of drhd units */ struct acpi_dmar_header *hdr; /* ACPI header */ u64 reg_base_addr; /* register base address*/ - struct pci_dev **devices; /* target device array */ - int devices_cnt; /* target device count */ + struct acpi_dmar_device_scope **scopes; /* target scope array */ + int scopes_cnt; /* target scope count */ u16 segment; /* PCI domain */ u8 ignored:1; /* ignore drhd */ u8 include_all:1; @@ -55,6 +55,9 @@ extern struct list_head dmar_drhd_units; extern int dmar_table_init(void); extern int dmar_dev_scope_init(void); +extern int dmar_match_scope(struct acpi_dmar_device_scope **, int, + struct pci_dev *, u16); +extern struct pci_dev *dmar_get_scope_dev(struct acpi_dmar_device_scope *, u16); /* Intel IOMMU detection */ extern int detect_intel_iommu(void); @@ -72,6 +75,20 @@ static inline int dmar_table_init(void) { return -ENODEV; } + +static inline int dmar_match_scope(struct acpi_dmar_device_scope **scopes, + int cnt, struct pci_dev *dev, u16 segment) +{ + return 0; +} + +static inline struct pci_dev *dmar_get_scope_dev( + struct acpi_dmar_device_scope *scope, + u16 segment) +{ + return NULL; +} + static inline int enable_drhd_fault_handling(void) { return -1; @@ -212,8 +229,8 @@ struct dmar_rmrr_unit { struct acpi_dmar_header *hdr; /* ACPI header */ u64 base_address; /* reserved base address*/ u64 end_address; /* reserved end address */ - struct pci_dev **devices; /* target devices */ - int devices_cnt; /* target device count */ + struct acpi_dmar_device_scope **scopes; /* target scope array */ + int scopes_cnt; /* target scope count */ }; #define for_each_rmrr_units(rmrr) \ @@ -222,8 +239,8 @@ struct dmar_rmrr_unit { struct dmar_atsr_unit { struct list_head list; /* list of ATSR units */ struct acpi_dmar_header *hdr; /* ACPI header */ - struct pci_dev **devices; /* target devices */ - int devices_cnt; /* target device count */ + struct acpi_dmar_device_scope **scopes; /* target scope array */ + int scopes_cnt; /* target scope count */ u8 include_all:1; /* include all ports */ };