* [PATCH v4 0/6] PCI: Support multiple DMA aliases @ 2016-02-24 19:43 Bjorn Helgaas 2016-02-24 19:43 ` [PATCH v4 1/6] PCI: Add pci_add_dma_alias() to abstract implementation Bjorn Helgaas ` (6 more replies) 0 siblings, 7 replies; 28+ messages in thread From: Bjorn Helgaas @ 2016-02-24 19:43 UTC (permalink / raw) To: Jacek Lawrynowicz Cc: linux-pci, Alex Williamson, Joerg Roedel, David Woodhouse, iommu This is a revision of Jacek's v3 posting: http://lkml.kernel.org/r/1454152012-46337-1-git-send-email-jacek.lawrynowicz@intel.com The changes from v3 are: - Split into smaller patches for reviewability - Move printk when adding DMA alias - Change dma_alias_is_enabled() interface to take two pci_devs - Rename dma_alias_is_enabled() to indicate PCI context The only remaining thing I want to sort out is the dma_alias_is_enabled() vs pci_for_each_dma_alias() question Alex raised. I'll respond to the relevant part of the patch in this series with my specific questions. --- Bjorn Helgaas (1): PCI: Rename dma_alias_is_enabled() to pci_devs_are_dma_aliases() Jacek Lawrynowicz (5): PCI: Add pci_add_dma_alias() to abstract implementation PCI: Move informational printk to pci_add_dma_alias() PCI: Add support for multiple DMA aliases pci: Add DMA alias quirk for mic_x200_dma PCI: Squash pci_dev_flags to remove holes drivers/iommu/iommu.c | 18 +++++++++++------- drivers/pci/pci.c | 23 +++++++++++++++++++++++ drivers/pci/pci.h | 2 ++ drivers/pci/probe.c | 1 + drivers/pci/quirks.c | 34 +++++++++++++++++++--------------- drivers/pci/search.c | 14 +++++++++----- include/linux/pci.h | 12 +++++------- 7 files changed, 70 insertions(+), 34 deletions(-) ^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v4 1/6] PCI: Add pci_add_dma_alias() to abstract implementation 2016-02-24 19:43 [PATCH v4 0/6] PCI: Support multiple DMA aliases Bjorn Helgaas @ 2016-02-24 19:43 ` Bjorn Helgaas [not found] ` <20160224194345.7585.20639.stgit-1RhO1Y9PlrlHTL0Zs8A6p/gx64E7kk8eUsxypvmhUTTZJqsBc5GL+g@public.gmane.org> 2016-02-24 19:43 ` [PATCH v4 2/6] PCI: Move informational printk to pci_add_dma_alias() Bjorn Helgaas ` (5 subsequent siblings) 6 siblings, 1 reply; 28+ messages in thread From: Bjorn Helgaas @ 2016-02-24 19:43 UTC (permalink / raw) To: Jacek Lawrynowicz Cc: linux-pci, Alex Williamson, Joerg Roedel, David Woodhouse, iommu From: Jacek Lawrynowicz <jacek.lawrynowicz@intel.com> Add a pci_add_dma_alias() interface to encapsulate the details of adding an alias. No functional change intended. --- drivers/pci/pci.c | 14 ++++++++++++++ drivers/pci/pci.h | 2 ++ drivers/pci/quirks.c | 19 +++++++------------ 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 602eb42..7fccc8a 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4568,6 +4568,20 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode, return 0; } +/** + * pci_add_dma_alias - Add a DMA devfn alias for a device + * @dev: the PCI device for which alias is added + * @devfn: alias slot and function + * + * This helper encodes 8-bit devfn as bit number in dma_alias_mask. + * It should be called early, preferably as PCI fixup header quirk. + */ +void pci_add_dma_alias(struct pci_dev *dev, u8 devfn) +{ + dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0); + dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; +} + bool pci_device_is_present(struct pci_dev *pdev) { u32 v; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 9a1660f..c5dc8dc 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -335,4 +335,6 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe) } #endif +void pci_add_dma_alias(struct pci_dev *dev, u8 devfn); + #endif /* DRIVERS_PCI_H */ diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 0575a1e..df28dce 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3581,10 +3581,8 @@ int pci_dev_specific_reset(struct pci_dev *dev, int probe) static void quirk_dma_func0_alias(struct pci_dev *dev) { - if (PCI_FUNC(dev->devfn) != 0) { - dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0); - dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; - } + if (PCI_FUNC(dev->devfn) != 0) + pci_add_dma_alias(dev, PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); } /* @@ -3597,10 +3595,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RICOH, 0xe476, quirk_dma_func0_alias); static void quirk_dma_func1_alias(struct pci_dev *dev) { - if (PCI_FUNC(dev->devfn) != 1) { - dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 1); - dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; - } + if (PCI_FUNC(dev->devfn) != 1) + pci_add_dma_alias(dev, PCI_DEVFN(PCI_SLOT(dev->devfn), 1)); } /* @@ -3667,11 +3663,10 @@ static void quirk_fixed_dma_alias(struct pci_dev *dev) id = pci_match_id(fixed_dma_alias_tbl, dev); if (id) { - dev->dma_alias_devfn = id->driver_data; - dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; + pci_add_dma_alias(dev, id->driver_data); dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n", - PCI_SLOT(dev->dma_alias_devfn), - PCI_FUNC(dev->dma_alias_devfn)); + PCI_SLOT(id->driver_data), + PCI_FUNC(id->driver_data)); } } ^ permalink raw reply related [flat|nested] 28+ messages in thread
[parent not found: <20160224194345.7585.20639.stgit-1RhO1Y9PlrlHTL0Zs8A6p/gx64E7kk8eUsxypvmhUTTZJqsBc5GL+g@public.gmane.org>]
* Re: [PATCH v4 1/6] PCI: Add pci_add_dma_alias() to abstract implementation [not found] ` <20160224194345.7585.20639.stgit-1RhO1Y9PlrlHTL0Zs8A6p/gx64E7kk8eUsxypvmhUTTZJqsBc5GL+g@public.gmane.org> @ 2016-04-08 20:18 ` Alex Williamson 0 siblings, 0 replies; 28+ messages in thread From: Alex Williamson @ 2016-04-08 20:18 UTC (permalink / raw) To: Bjorn Helgaas Cc: linux-pci-u79uwXL29TY76Z2rM5mHXA, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, David Woodhouse, Joerg Roedel On Wed, 24 Feb 2016 13:43:45 -0600 Bjorn Helgaas <bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> wrote: > From: Jacek Lawrynowicz <jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> > > Add a pci_add_dma_alias() interface to encapsulate the details of adding an > alias. No functional change intended. > --- > drivers/pci/pci.c | 14 ++++++++++++++ > drivers/pci/pci.h | 2 ++ > drivers/pci/quirks.c | 19 +++++++------------ > 3 files changed, 23 insertions(+), 12 deletions(-) > > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c > index 602eb42..7fccc8a 100644 > --- a/drivers/pci/pci.c > +++ b/drivers/pci/pci.c > @@ -4568,6 +4568,20 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode, > return 0; > } > > +/** > + * pci_add_dma_alias - Add a DMA devfn alias for a device > + * @dev: the PCI device for which alias is added > + * @devfn: alias slot and function > + * > + * This helper encodes 8-bit devfn as bit number in dma_alias_mask. > + * It should be called early, preferably as PCI fixup header quirk. > + */ > +void pci_add_dma_alias(struct pci_dev *dev, u8 devfn) > +{ > + dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0); This should be: dev->dma_alias_devfn = devfn; It was silently fixed in 3/6. Also needs a Sign-off. With those changes: Reviewed-by: Alex Williamson <alex.williamson-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> > + dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; > +} > + > bool pci_device_is_present(struct pci_dev *pdev) > { > u32 v; > diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h > index 9a1660f..c5dc8dc 100644 > --- a/drivers/pci/pci.h > +++ b/drivers/pci/pci.h > @@ -335,4 +335,6 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe) > } > #endif > > +void pci_add_dma_alias(struct pci_dev *dev, u8 devfn); > + > #endif /* DRIVERS_PCI_H */ > diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c > index 0575a1e..df28dce 100644 > --- a/drivers/pci/quirks.c > +++ b/drivers/pci/quirks.c > @@ -3581,10 +3581,8 @@ int pci_dev_specific_reset(struct pci_dev *dev, int probe) > > static void quirk_dma_func0_alias(struct pci_dev *dev) > { > - if (PCI_FUNC(dev->devfn) != 0) { > - dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0); > - dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; > - } > + if (PCI_FUNC(dev->devfn) != 0) > + pci_add_dma_alias(dev, PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); > } > > /* > @@ -3597,10 +3595,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RICOH, 0xe476, quirk_dma_func0_alias); > > static void quirk_dma_func1_alias(struct pci_dev *dev) > { > - if (PCI_FUNC(dev->devfn) != 1) { > - dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 1); > - dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; > - } > + if (PCI_FUNC(dev->devfn) != 1) > + pci_add_dma_alias(dev, PCI_DEVFN(PCI_SLOT(dev->devfn), 1)); > } > > /* > @@ -3667,11 +3663,10 @@ static void quirk_fixed_dma_alias(struct pci_dev *dev) > > id = pci_match_id(fixed_dma_alias_tbl, dev); > if (id) { > - dev->dma_alias_devfn = id->driver_data; > - dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; > + pci_add_dma_alias(dev, id->driver_data); > dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n", > - PCI_SLOT(dev->dma_alias_devfn), > - PCI_FUNC(dev->dma_alias_devfn)); > + PCI_SLOT(id->driver_data), > + PCI_FUNC(id->driver_data)); > } > } > > ^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v4 2/6] PCI: Move informational printk to pci_add_dma_alias() 2016-02-24 19:43 [PATCH v4 0/6] PCI: Support multiple DMA aliases Bjorn Helgaas 2016-02-24 19:43 ` [PATCH v4 1/6] PCI: Add pci_add_dma_alias() to abstract implementation Bjorn Helgaas @ 2016-02-24 19:43 ` Bjorn Helgaas [not found] ` <20160224194354.7585.30654.stgit-1RhO1Y9PlrlHTL0Zs8A6p/gx64E7kk8eUsxypvmhUTTZJqsBc5GL+g@public.gmane.org> 2016-02-24 19:44 ` [PATCH v4 3/6] PCI: Add support for multiple DMA aliases Bjorn Helgaas ` (4 subsequent siblings) 6 siblings, 1 reply; 28+ messages in thread From: Bjorn Helgaas @ 2016-02-24 19:43 UTC (permalink / raw) To: Jacek Lawrynowicz Cc: linux-pci, Alex Williamson, Joerg Roedel, David Woodhouse, iommu From: Jacek Lawrynowicz <jacek.lawrynowicz@intel.com> One of the quirks that adds DMA aliases logs an informational message in dmesg. Move that to pci_add_dma_alias() so all users log the message consistently. No functional change intended (except extra message). --- drivers/pci/pci.c | 2 ++ drivers/pci/quirks.c | 6 +----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7fccc8a..8b0a637 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4580,6 +4580,8 @@ void pci_add_dma_alias(struct pci_dev *dev, u8 devfn) { dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0); dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; + dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n", + PCI_SLOT(devfn), PCI_FUNC(devfn)); } bool pci_device_is_present(struct pci_dev *pdev) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index df28dce..cf023ea 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3662,12 +3662,8 @@ static void quirk_fixed_dma_alias(struct pci_dev *dev) const struct pci_device_id *id; id = pci_match_id(fixed_dma_alias_tbl, dev); - if (id) { + if (id) pci_add_dma_alias(dev, id->driver_data); - dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n", - PCI_SLOT(id->driver_data), - PCI_FUNC(id->driver_data)); - } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ADAPTEC2, 0x0285, quirk_fixed_dma_alias); ^ permalink raw reply related [flat|nested] 28+ messages in thread
[parent not found: <20160224194354.7585.30654.stgit-1RhO1Y9PlrlHTL0Zs8A6p/gx64E7kk8eUsxypvmhUTTZJqsBc5GL+g@public.gmane.org>]
* Re: [PATCH v4 2/6] PCI: Move informational printk to pci_add_dma_alias() [not found] ` <20160224194354.7585.30654.stgit-1RhO1Y9PlrlHTL0Zs8A6p/gx64E7kk8eUsxypvmhUTTZJqsBc5GL+g@public.gmane.org> @ 2016-04-08 20:19 ` Alex Williamson 0 siblings, 0 replies; 28+ messages in thread From: Alex Williamson @ 2016-04-08 20:19 UTC (permalink / raw) To: Bjorn Helgaas Cc: linux-pci-u79uwXL29TY76Z2rM5mHXA, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, David Woodhouse, Joerg Roedel On Wed, 24 Feb 2016 13:43:54 -0600 Bjorn Helgaas <bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> wrote: > From: Jacek Lawrynowicz <jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> > > One of the quirks that adds DMA aliases logs an informational message in > dmesg. Move that to pci_add_dma_alias() so all users log the message > consistently. No functional change intended (except extra message). > --- > drivers/pci/pci.c | 2 ++ > drivers/pci/quirks.c | 6 +----- > 2 files changed, 3 insertions(+), 5 deletions(-) Needs a Sign-off, otherwise: Reviewed-by: Alex Williamson <alex.williamson-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> > > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c > index 7fccc8a..8b0a637 100644 > --- a/drivers/pci/pci.c > +++ b/drivers/pci/pci.c > @@ -4580,6 +4580,8 @@ void pci_add_dma_alias(struct pci_dev *dev, u8 devfn) > { > dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0); > dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; > + dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n", > + PCI_SLOT(devfn), PCI_FUNC(devfn)); > } > > bool pci_device_is_present(struct pci_dev *pdev) > diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c > index df28dce..cf023ea 100644 > --- a/drivers/pci/quirks.c > +++ b/drivers/pci/quirks.c > @@ -3662,12 +3662,8 @@ static void quirk_fixed_dma_alias(struct pci_dev *dev) > const struct pci_device_id *id; > > id = pci_match_id(fixed_dma_alias_tbl, dev); > - if (id) { > + if (id) > pci_add_dma_alias(dev, id->driver_data); > - dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n", > - PCI_SLOT(id->driver_data), > - PCI_FUNC(id->driver_data)); > - } > } > > DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ADAPTEC2, 0x0285, quirk_fixed_dma_alias); > ^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v4 3/6] PCI: Add support for multiple DMA aliases 2016-02-24 19:43 [PATCH v4 0/6] PCI: Support multiple DMA aliases Bjorn Helgaas 2016-02-24 19:43 ` [PATCH v4 1/6] PCI: Add pci_add_dma_alias() to abstract implementation Bjorn Helgaas 2016-02-24 19:43 ` [PATCH v4 2/6] PCI: Move informational printk to pci_add_dma_alias() Bjorn Helgaas @ 2016-02-24 19:44 ` Bjorn Helgaas 2016-02-25 14:38 ` Bjorn Helgaas 2016-02-24 19:44 ` [PATCH v4 4/6] PCI: Rename dma_alias_is_enabled() to pci_devs_are_dma_aliases() Bjorn Helgaas ` (3 subsequent siblings) 6 siblings, 1 reply; 28+ messages in thread From: Bjorn Helgaas @ 2016-02-24 19:44 UTC (permalink / raw) To: Jacek Lawrynowicz Cc: linux-pci, Alex Williamson, Joerg Roedel, David Woodhouse, iommu From: Jacek Lawrynowicz <jacek.lawrynowicz@intel.com> <Insert changelog here> --- drivers/iommu/iommu.c | 17 ++++++++++------- drivers/pci/pci.c | 11 +++++++++-- drivers/pci/probe.c | 1 + drivers/pci/search.c | 14 +++++++++----- include/linux/pci.h | 4 +--- 5 files changed, 30 insertions(+), 17 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 0e3b009..a214e19 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -659,9 +659,15 @@ static struct iommu_group *get_pci_function_alias_group(struct pci_dev *pdev, return NULL; } +static bool dma_alias_is_enabled(struct pci_dev *dev, u8 devfn) +{ + return dev->dma_alias_mask && + test_bit(devfn, dev->dma_alias_mask); +} + /* - * Look for aliases to or from the given device for exisiting groups. The - * dma_alias_devfn only supports aliases on the same bus, therefore the search + * Look for aliases to or from the given device for existing groups. DMA + * aliases are only supported on the same bus, therefore the search * space is quite small (especially since we're really only looking at pcie * device, and therefore only expect multiple slots on the root complex or * downstream switch ports). It's conceivable though that a pair of @@ -686,11 +692,8 @@ static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev, continue; /* We alias them or they alias us */ - if (((pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && - pdev->dma_alias_devfn == tmp->devfn) || - ((tmp->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && - tmp->dma_alias_devfn == pdev->devfn)) { - + if (dma_alias_is_enabled(pdev, tmp->devfn) || + dma_alias_is_enabled(tmp, pdev->devfn)) { group = get_pci_alias_group(tmp, devfns); if (group) { pci_dev_put(tmp); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 8b0a637..eb4dd49 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4578,8 +4578,15 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode, */ void pci_add_dma_alias(struct pci_dev *dev, u8 devfn) { - dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0); - dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; + if (!dev->dma_alias_mask) + dev->dma_alias_mask = kcalloc(BITS_TO_LONGS(U8_MAX), + sizeof(long), GFP_KERNEL); + if (!dev->dma_alias_mask) { + dev_warn(&dev->dev, "Unable to allocate DMA alias mask\n"); + return; + } + + set_bit(devfn, dev->dma_alias_mask); dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n", PCI_SLOT(devfn), PCI_FUNC(devfn)); } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 6d7ab9b..23fc397 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1503,6 +1503,7 @@ static void pci_release_dev(struct device *dev) pcibios_release_device(pci_dev); pci_bus_put(pci_dev->bus); kfree(pci_dev->driver_override); + kfree(pci_dev->dma_alias_mask); kfree(pci_dev); } diff --git a/drivers/pci/search.c b/drivers/pci/search.c index a20ce7d..33e0f03 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -40,11 +40,15 @@ int pci_for_each_dma_alias(struct pci_dev *pdev, * If the device is broken and uses an alias requester ID for * DMA, iterate over that too. */ - if (unlikely(pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN)) { - ret = fn(pdev, PCI_DEVID(pdev->bus->number, - pdev->dma_alias_devfn), data); - if (ret) - return ret; + if (unlikely(pdev->dma_alias_mask)) { + u8 devfn; + + for_each_set_bit(devfn, pdev->dma_alias_mask, U8_MAX) { + ret = fn(pdev, PCI_DEVID(pdev->bus->number, devfn), + data); + if (ret) + return ret; + } } for (bus = pdev->bus; !pci_is_root_bus(bus); bus = bus->parent) { diff --git a/include/linux/pci.h b/include/linux/pci.h index 27df4a6..d9e0c84 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -172,8 +172,6 @@ enum pci_dev_flags { PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) (1 << 2), /* Flag for quirk use to store if quirk-specific ACS is enabled */ PCI_DEV_FLAGS_ACS_ENABLED_QUIRK = (__force pci_dev_flags_t) (1 << 3), - /* Flag to indicate the device uses dma_alias_devfn */ - PCI_DEV_FLAGS_DMA_ALIAS_DEVFN = (__force pci_dev_flags_t) (1 << 4), /* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */ PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 5), /* Do not use bus resets for device */ @@ -279,7 +277,7 @@ struct pci_dev { u8 rom_base_reg; /* which config register controls the ROM */ u8 pin; /* which interrupt pin this device uses */ u16 pcie_flags_reg; /* cached PCIe Capabilities Register */ - u8 dma_alias_devfn;/* devfn of DMA alias, if any */ + unsigned long *dma_alias_mask;/* mask of enabled devfn aliases */ struct pci_driver *driver; /* which driver has allocated this device */ u64 dma_mask; /* Mask of the bits of bus address this ^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [PATCH v4 3/6] PCI: Add support for multiple DMA aliases 2016-02-24 19:44 ` [PATCH v4 3/6] PCI: Add support for multiple DMA aliases Bjorn Helgaas @ 2016-02-25 14:38 ` Bjorn Helgaas 2016-02-25 15:41 ` Lawrynowicz, Jacek 2016-03-14 22:43 ` [PATCH v4 " David Woodhouse 0 siblings, 2 replies; 28+ messages in thread From: Bjorn Helgaas @ 2016-02-25 14:38 UTC (permalink / raw) To: Bjorn Helgaas Cc: Jacek Lawrynowicz, linux-pci, Alex Williamson, Joerg Roedel, David Woodhouse, iommu On Wed, Feb 24, 2016 at 01:44:06PM -0600, Bjorn Helgaas wrote: > From: Jacek Lawrynowicz <jacek.lawrynowicz@intel.com> > > <Insert changelog here> (Sorry, I should have copied this changelog in the patch; I copied this manually from your v3 posting): > This patch solves IOMMU support issues with PCIe non-transparent bridges > that use Requester ID look-up tables (LUT), e.g. PEX8733. Before exiting > the bridge, packet's RID is rewritten according to LUT programmed by > a driver. Modified packets are then passed to a destination bus and > processed upstream. The problem is that such packets seem to come from > non-existent nodes that are hidden behind NTB and are not discoverable > by a destination node, so IOMMU discards them. Adding DMA alias for a > given LUT entry allows IOMMU to create a proper mapping that enables > inter-node communication. A specific example here would help me understand. Here's how I understand this (correct me if I'm wrong): We're talking about a DMA packet being forwarded upstream from an NTB. The NTB uses the LUT to rewrite the RID in the DMA packet. The new RID from the LUT is unknown to the IOMMU, so it discards the DMA packet. > The current DMA alias implementation supports only single alias, so it's > not possible to connect more than two nodes when IOMMU is enabled. This > implementation enables all possible aliases on a given bus (256) that > are stored in a bitset. Alias devfn is directly translated to a bit > number. The bitset is not allocated for devices that have no need for > DMA aliases. I think "two nodes" is referring to two PCIe devices on the other side of the NTB. You want DMA packets from those devices to have different RIDs so the IOMMU can distinguish them. The LUT entries basically create aliases of the NTB (one alias for each device beyond the NTB). Your quirk uses pci_add_dma_alias(), and the aliases are all on the same bus as the NTB itself. The quirk adds PCI_DEVFN(0x10, 0x0), PCI_DEVFN(0x11, 0x0), and PCI_DEVFN(0x12, 0x0). Shouldn't there be some connection between this and the LUT programming? I assume the LUT is programmed to correspond to those aliases. Does this mean you're limited to three devices beyond the NTB? > --- > drivers/iommu/iommu.c | 17 ++++++++++------- > drivers/pci/pci.c | 11 +++++++++-- > drivers/pci/probe.c | 1 + > drivers/pci/search.c | 14 +++++++++----- > include/linux/pci.h | 4 +--- > 5 files changed, 30 insertions(+), 17 deletions(-) > > diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c > index 0e3b009..a214e19 100644 > --- a/drivers/iommu/iommu.c > +++ b/drivers/iommu/iommu.c > @@ -659,9 +659,15 @@ static struct iommu_group *get_pci_function_alias_group(struct pci_dev *pdev, > return NULL; > } > > +static bool dma_alias_is_enabled(struct pci_dev *dev, u8 devfn) > +{ > + return dev->dma_alias_mask && > + test_bit(devfn, dev->dma_alias_mask); > +} > + > /* > - * Look for aliases to or from the given device for exisiting groups. The > - * dma_alias_devfn only supports aliases on the same bus, therefore the search > + * Look for aliases to or from the given device for existing groups. DMA > + * aliases are only supported on the same bus, therefore the search I'm trying to reconcile this statement that "DMA aliases are only supported on the same bus" (which was there even before this patch) with the fact that pci_for_each_dma_alias() does not have that limitation. > * space is quite small (especially since we're really only looking at pcie > * device, and therefore only expect multiple slots on the root complex or > * downstream switch ports). It's conceivable though that a pair of > @@ -686,11 +692,8 @@ static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev, > continue; > > /* We alias them or they alias us */ > - if (((pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && > - pdev->dma_alias_devfn == tmp->devfn) || > - ((tmp->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && > - tmp->dma_alias_devfn == pdev->devfn)) { > - > + if (dma_alias_is_enabled(pdev, tmp->devfn) || > + dma_alias_is_enabled(tmp, pdev->devfn)) { > group = get_pci_alias_group(tmp, devfns); We basically have this: for_each_pci_dev(tmp) { if (<pdev and tmp are DMA aliases>) group = get_pci_alias_group(); ... } The DMA alias stuff relies on PCI internals, so it doesn't doesn't seem quite right to use things like PCI_DEV_FLAGS_DMA_ALIAS_DEVFN and dma_alias_devfn here in the IOMMU code. I'm trying to figure out why we don't do something like the following instead: callback(struct pci_dev *pdev, u16 alias, void *opaque) { struct iommu_group *group; group = get_pci_alias_group(); if (group) return group; return 0; } pci_for_each_dma_alias(pdev, callback, ...); Is the existing code some sort of optimization, e.g., checking PCI_DEV_FLAGS_DMA_ALIAS_DEVFN is cheaper than using pci_for_each_dma_alias()? It seems like this won't work for some very unlikely but theoretically possible topologies, e.g., PCIe Root Complex/IOMMU PCIe switch A PCIe to conventional PCI bridge PCI to PCIe Root Complex PCIe NTB Here, I think the IOMMU will only see RIDs from PCIe switch A, but the current code only looks at DMA aliases that are on the same bus as the PCIe NTB. Wouldn't using pci_for_each_dma_alias() handle this correctly? > if (group) { > pci_dev_put(tmp); ^ permalink raw reply [flat|nested] 28+ messages in thread
* RE: [PATCH v4 3/6] PCI: Add support for multiple DMA aliases 2016-02-25 14:38 ` Bjorn Helgaas @ 2016-02-25 15:41 ` Lawrynowicz, Jacek 2016-02-29 22:44 ` Bjorn Helgaas 2016-03-14 22:43 ` [PATCH v4 " David Woodhouse 1 sibling, 1 reply; 28+ messages in thread From: Lawrynowicz, Jacek @ 2016-02-25 15:41 UTC (permalink / raw) To: Bjorn Helgaas, Bjorn Helgaas Cc: linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Joerg Roedel, David Woodhouse, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org [-- Attachment #1.1: Type: text/plain, Size: 7404 bytes --] > -----Original Message----- > From: Bjorn Helgaas [mailto:helgaas-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org] > Sent: Thursday, February 25, 2016 3:39 PM > To: Bjorn Helgaas <bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> > Cc: Lawrynowicz, Jacek <jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>; linux- > pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; Alex Williamson <alex.williamson-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>; Joerg > Roedel <jroedel-l3A5Bk7waGM@public.gmane.org>; David Woodhouse <dwmw2-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>; > iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org > Subject: Re: [PATCH v4 3/6] PCI: Add support for multiple DMA aliases > > On Wed, Feb 24, 2016 at 01:44:06PM -0600, Bjorn Helgaas wrote: > > From: Jacek Lawrynowicz <jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> > > > > <Insert changelog here> > > (Sorry, I should have copied this changelog in the patch; I copied > this manually from your v3 posting): > > > This patch solves IOMMU support issues with PCIe non-transparent bridges > > that use Requester ID look-up tables (LUT), e.g. PEX8733. Before exiting > > the bridge, packet's RID is rewritten according to LUT programmed by > > a driver. Modified packets are then passed to a destination bus and > > processed upstream. The problem is that such packets seem to come from > > non-existent nodes that are hidden behind NTB and are not discoverable > > by a destination node, so IOMMU discards them. Adding DMA alias for a > > given LUT entry allows IOMMU to create a proper mapping that enables > > inter-node communication. > > A specific example here would help me understand. Here's how I > understand this (correct me if I'm wrong): We're talking about a DMA > packet being forwarded upstream from an NTB. The NTB uses the LUT to > rewrite the RID in the DMA packet. The new RID from the LUT is > unknown to the IOMMU, so it discards the DMA packet. Yes, this is exactly the problem. > > The current DMA alias implementation supports only single alias, so it's > > not possible to connect more than two nodes when IOMMU is enabled. This > > implementation enables all possible aliases on a given bus (256) that > > are stored in a bitset. Alias devfn is directly translated to a bit > > number. The bitset is not allocated for devices that have no need for > > DMA aliases. > > I think "two nodes" is referring to two PCIe devices on the other side > of the NTB. You want DMA packets from those devices to have different > RIDs so the IOMMU can distinguish them. Right. > The LUT entries basically create aliases of the NTB (one alias for > each device beyond the NTB). Your quirk uses pci_add_dma_alias(), and > the aliases are all on the same bus as the NTB itself. > > The quirk adds PCI_DEVFN(0x10, 0x0), PCI_DEVFN(0x11, 0x0), and > PCI_DEVFN(0x12, 0x0). Shouldn't there be some connection between this > and the LUT programming? I assume the LUT is programmed to correspond > to those aliases. Does this mean you're limited to three devices > beyond the NTB? Yes, there is an indirect connection between LUT table and devfns used in the quirk. Dev part is an offset in the LUT table and function is taken from the device behind the NTB. So the driver can only change the dev part by using different LUT offsets. We don't plan to modify this quirk. The number of PCIe devices beyond single x200 card NTB will not change. Two are used by x200 CPU (host bridge & root port) and one is used by x200 DMA engine. I'm not sure introducing some dependencies to make sure the offsets are set correctly is really worth it. So regarding the improvements in the patch description, you want me to update and repost it? BTW I posted x200 DMA driver (the client for this change) on DMA list: https://lkml.org/lkml/2016/2/9/287 I'm working on integrating review comments and hope to get it included in 4.6. Regards, Jacek > > --- > > drivers/iommu/iommu.c | 17 ++++++++++------- > > drivers/pci/pci.c | 11 +++++++++-- > > drivers/pci/probe.c | 1 + > > drivers/pci/search.c | 14 +++++++++----- > > include/linux/pci.h | 4 +--- > > 5 files changed, 30 insertions(+), 17 deletions(-) > > > > diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c > > index 0e3b009..a214e19 100644 > > --- a/drivers/iommu/iommu.c > > +++ b/drivers/iommu/iommu.c > > @@ -659,9 +659,15 @@ static struct iommu_group > *get_pci_function_alias_group(struct pci_dev *pdev, > > return NULL; > > } > > > > +static bool dma_alias_is_enabled(struct pci_dev *dev, u8 devfn) > > +{ > > + return dev->dma_alias_mask && > > + test_bit(devfn, dev->dma_alias_mask); > > +} > > + > > /* > > - * Look for aliases to or from the given device for exisiting groups. The > > - * dma_alias_devfn only supports aliases on the same bus, therefore the > search > > + * Look for aliases to or from the given device for existing groups. DMA > > + * aliases are only supported on the same bus, therefore the search > > I'm trying to reconcile this statement that "DMA aliases are only > supported on the same bus" (which was there even before this patch) > with the fact that pci_for_each_dma_alias() does not have that > limitation. > > > * space is quite small (especially since we're really only looking at pcie > > * device, and therefore only expect multiple slots on the root complex or > > * downstream switch ports). It's conceivable though that a pair of > > @@ -686,11 +692,8 @@ static struct iommu_group *get_pci_alias_group(struct > pci_dev *pdev, > > continue; > > > > /* We alias them or they alias us */ > > - if (((pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) > && > > - pdev->dma_alias_devfn == tmp->devfn) || > > - ((tmp->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && > > - tmp->dma_alias_devfn == pdev->devfn)) { > > - > > + if (dma_alias_is_enabled(pdev, tmp->devfn) || > > + dma_alias_is_enabled(tmp, pdev->devfn)) { > > group = get_pci_alias_group(tmp, devfns); > > We basically have this: > > for_each_pci_dev(tmp) { > if (<pdev and tmp are DMA aliases>) > group = get_pci_alias_group(); > ... > } > > The DMA alias stuff relies on PCI internals, so it doesn't doesn't > seem quite right to use things like PCI_DEV_FLAGS_DMA_ALIAS_DEVFN and > dma_alias_devfn here in the IOMMU code. > > I'm trying to figure out why we don't do something like the following > instead: > > callback(struct pci_dev *pdev, u16 alias, void *opaque) > { > struct iommu_group *group; > > group = get_pci_alias_group(); > if (group) > return group; > > return 0; > } > > pci_for_each_dma_alias(pdev, callback, ...); > > Is the existing code some sort of optimization, e.g., checking > PCI_DEV_FLAGS_DMA_ALIAS_DEVFN is cheaper than using > pci_for_each_dma_alias()? > > It seems like this won't work for some very unlikely but theoretically > possible topologies, e.g., > > PCIe Root Complex/IOMMU > PCIe switch A > PCIe to conventional PCI bridge > PCI to PCIe Root Complex > PCIe NTB > > Here, I think the IOMMU will only see RIDs from PCIe switch A, but the > current code only looks at DMA aliases that are on the same bus as the > PCIe NTB. Wouldn't using pci_for_each_dma_alias() handle this > correctly? > > > if (group) { > > pci_dev_put(tmp); [-- Attachment #1.2: smime.p7s --] [-- Type: application/pkcs7-signature, Size: 7756 bytes --] [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4 3/6] PCI: Add support for multiple DMA aliases 2016-02-25 15:41 ` Lawrynowicz, Jacek @ 2016-02-29 22:44 ` Bjorn Helgaas 2016-03-01 16:57 ` Jacek Lawrynowicz ` (2 more replies) 0 siblings, 3 replies; 28+ messages in thread From: Bjorn Helgaas @ 2016-02-29 22:44 UTC (permalink / raw) To: Lawrynowicz, Jacek Cc: Bjorn Helgaas, linux-pci@vger.kernel.org, Alex Williamson, Joerg Roedel, David Woodhouse, iommu@lists.linux-foundation.org On Thu, Feb 25, 2016 at 03:41:51PM +0000, Lawrynowicz, Jacek wrote: > > -----Original Message----- > > From: Bjorn Helgaas [mailto:helgaas@kernel.org] > > Sent: Thursday, February 25, 2016 3:39 PM > > To: Bjorn Helgaas <bhelgaas@google.com> > > Cc: Lawrynowicz, Jacek <jacek.lawrynowicz@intel.com>; linux- > > pci@vger.kernel.org; Alex Williamson <alex.williamson@redhat.com>; Joerg > > Roedel <jroedel@suse.de>; David Woodhouse <dwmw2@infradead.org>; > > iommu@lists.linux-foundation.org > > Subject: Re: [PATCH v4 3/6] PCI: Add support for multiple DMA aliases > > > > On Wed, Feb 24, 2016 at 01:44:06PM -0600, Bjorn Helgaas wrote: > > > From: Jacek Lawrynowicz <jacek.lawrynowicz@intel.com> > > > > > > <Insert changelog here> > > > > (Sorry, I should have copied this changelog in the patch; I copied > > this manually from your v3 posting): > > > > > This patch solves IOMMU support issues with PCIe non-transparent bridges > > > that use Requester ID look-up tables (LUT), e.g. PEX8733. Before exiting > > > the bridge, packet's RID is rewritten according to LUT programmed by > > > a driver. Modified packets are then passed to a destination bus and > > > processed upstream. The problem is that such packets seem to come from > > > non-existent nodes that are hidden behind NTB and are not discoverable > > > by a destination node, so IOMMU discards them. Adding DMA alias for a > > > given LUT entry allows IOMMU to create a proper mapping that enables > > > inter-node communication. > > > > A specific example here would help me understand. Here's how I > > understand this (correct me if I'm wrong): We're talking about a DMA > > packet being forwarded upstream from an NTB. The NTB uses the LUT to > > rewrite the RID in the DMA packet. The new RID from the LUT is > > unknown to the IOMMU, so it discards the DMA packet. > > Yes, this is exactly the problem. > > > > The current DMA alias implementation supports only single alias, so it's > > > not possible to connect more than two nodes when IOMMU is enabled. This > > > implementation enables all possible aliases on a given bus (256) that > > > are stored in a bitset. Alias devfn is directly translated to a bit > > > number. The bitset is not allocated for devices that have no need for > > > DMA aliases. > > > > I think "two nodes" is referring to two PCIe devices on the other side > > of the NTB. You want DMA packets from those devices to have different > > RIDs so the IOMMU can distinguish them. > > Right. > > > The LUT entries basically create aliases of the NTB (one alias for > > each device beyond the NTB). Your quirk uses pci_add_dma_alias(), and > > the aliases are all on the same bus as the NTB itself. > > > > The quirk adds PCI_DEVFN(0x10, 0x0), PCI_DEVFN(0x11, 0x0), and > > PCI_DEVFN(0x12, 0x0). Shouldn't there be some connection between this > > and the LUT programming? I assume the LUT is programmed to correspond > > to those aliases. Does this mean you're limited to three devices > > beyond the NTB? > > Yes, there is an indirect connection between LUT table and devfns used in the > quirk. > Dev part is an offset in the LUT table and function is taken from the device > behind the NTB. > So the driver can only change the dev part by using different LUT offsets. > We don't plan to modify this quirk. The number of PCIe devices beyond single > x200 card NTB will not change. > Two are used by x200 CPU (host bridge & root port) and one is used by x200 DMA > engine. > I'm not sure introducing some dependencies to make sure the offsets are set > correctly is really worth it. I'd like at least a comment that points to the specific x200 code that must coordinate with this. > So regarding the improvements in the patch description, you want me to update > and repost it? Yes, please. > BTW I posted x200 DMA driver (the client for this change) on DMA list: > https://lkml.org/lkml/2016/2/9/287 > I'm working on integrating review comments and hope to get it included in 4.6. What about my questions on the code itself, below? > > > --- > > > drivers/iommu/iommu.c | 17 ++++++++++------- > > > drivers/pci/pci.c | 11 +++++++++-- > > > drivers/pci/probe.c | 1 + > > > drivers/pci/search.c | 14 +++++++++----- > > > include/linux/pci.h | 4 +--- > > > 5 files changed, 30 insertions(+), 17 deletions(-) > > > > > > diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c > > > index 0e3b009..a214e19 100644 > > > --- a/drivers/iommu/iommu.c > > > +++ b/drivers/iommu/iommu.c > > > @@ -659,9 +659,15 @@ static struct iommu_group > > *get_pci_function_alias_group(struct pci_dev *pdev, > > > return NULL; > > > } > > > > > > +static bool dma_alias_is_enabled(struct pci_dev *dev, u8 devfn) > > > +{ > > > + return dev->dma_alias_mask && > > > + test_bit(devfn, dev->dma_alias_mask); > > > +} > > > + > > > /* > > > - * Look for aliases to or from the given device for exisiting groups. The > > > - * dma_alias_devfn only supports aliases on the same bus, therefore the > > search > > > + * Look for aliases to or from the given device for existing groups. DMA > > > + * aliases are only supported on the same bus, therefore the search > > > > I'm trying to reconcile this statement that "DMA aliases are only > > supported on the same bus" (which was there even before this patch) > > with the fact that pci_for_each_dma_alias() does not have that > > limitation. > > > > > * space is quite small (especially since we're really only looking at pcie > > > * device, and therefore only expect multiple slots on the root complex or > > > * downstream switch ports). It's conceivable though that a pair of > > > @@ -686,11 +692,8 @@ static struct iommu_group *get_pci_alias_group(struct > > pci_dev *pdev, > > > continue; > > > > > > /* We alias them or they alias us */ > > > - if (((pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) > > && > > > - pdev->dma_alias_devfn == tmp->devfn) || > > > - ((tmp->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && > > > - tmp->dma_alias_devfn == pdev->devfn)) { > > > - > > > + if (dma_alias_is_enabled(pdev, tmp->devfn) || > > > + dma_alias_is_enabled(tmp, pdev->devfn)) { > > > group = get_pci_alias_group(tmp, devfns); > > > > We basically have this: > > > > for_each_pci_dev(tmp) { > > if (<pdev and tmp are DMA aliases>) > > group = get_pci_alias_group(); > > ... > > } > > > > The DMA alias stuff relies on PCI internals, so it doesn't doesn't > > seem quite right to use things like PCI_DEV_FLAGS_DMA_ALIAS_DEVFN and > > dma_alias_devfn here in the IOMMU code. > > > > I'm trying to figure out why we don't do something like the following > > instead: > > > > callback(struct pci_dev *pdev, u16 alias, void *opaque) > > { > > struct iommu_group *group; > > > > group = get_pci_alias_group(); > > if (group) > > return group; > > > > return 0; > > } > > > > pci_for_each_dma_alias(pdev, callback, ...); > > > > Is the existing code some sort of optimization, e.g., checking > > PCI_DEV_FLAGS_DMA_ALIAS_DEVFN is cheaper than using > > pci_for_each_dma_alias()? > > > > It seems like this won't work for some very unlikely but theoretically > > possible topologies, e.g., > > > > PCIe Root Complex/IOMMU > > PCIe switch A > > PCIe to conventional PCI bridge > > PCI to PCIe Root Complex > > PCIe NTB > > > > Here, I think the IOMMU will only see RIDs from PCIe switch A, but the > > current code only looks at DMA aliases that are on the same bus as the > > PCIe NTB. Wouldn't using pci_for_each_dma_alias() handle this > > correctly? > > > > > if (group) { > > > pci_dev_put(tmp); ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4 3/6] PCI: Add support for multiple DMA aliases 2016-02-29 22:44 ` Bjorn Helgaas @ 2016-03-01 16:57 ` Jacek Lawrynowicz 2016-03-03 14:22 ` [PATCH] " Jacek Lawrynowicz 2016-03-03 14:38 ` [PATCH v5 3/6] " Jacek Lawrynowicz 2 siblings, 0 replies; 28+ messages in thread From: Jacek Lawrynowicz @ 2016-03-01 16:57 UTC (permalink / raw) To: Bjorn Helgaas, Joerg Roedel, David Woodhouse Cc: Bjorn Helgaas, linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org On Mon, Feb 29, 2016 at 04:44:17PM -0600, Bjorn Helgaas wrote: > On Thu, Feb 25, 2016 at 03:41:51PM +0000, Lawrynowicz, Jacek wrote: > > > -----Original Message----- > > > From: Bjorn Helgaas [mailto:helgaas-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org] > > > Sent: Thursday, February 25, 2016 3:39 PM > > > To: Bjorn Helgaas <bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> > > > Cc: Lawrynowicz, Jacek <jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>; linux- > > > pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; Alex Williamson <alex.williamson-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>; Joerg > > > Roedel <jroedel-l3A5Bk7waGM@public.gmane.org>; David Woodhouse <dwmw2-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>; > > > iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org > > > Subject: Re: [PATCH v4 3/6] PCI: Add support for multiple DMA aliases > > > > > > On Wed, Feb 24, 2016 at 01:44:06PM -0600, Bjorn Helgaas wrote: > > > > From: Jacek Lawrynowicz <jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> > > What about my questions on the code itself, below? > Sorry but I'm not able to answer it. Maybe Joerg or David could help here? > > > > --- > > > > drivers/iommu/iommu.c | 17 ++++++++++------- > > > > drivers/pci/pci.c | 11 +++++++++-- > > > > drivers/pci/probe.c | 1 + > > > > drivers/pci/search.c | 14 +++++++++----- > > > > include/linux/pci.h | 4 +--- > > > > 5 files changed, 30 insertions(+), 17 deletions(-) > > > > > > > > diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c > > > > index 0e3b009..a214e19 100644 > > > > --- a/drivers/iommu/iommu.c > > > > +++ b/drivers/iommu/iommu.c > > > > @@ -659,9 +659,15 @@ static struct iommu_group > > > *get_pci_function_alias_group(struct pci_dev *pdev, > > > > return NULL; > > > > } > > > > > > > > +static bool dma_alias_is_enabled(struct pci_dev *dev, u8 devfn) > > > > +{ > > > > + return dev->dma_alias_mask && > > > > + test_bit(devfn, dev->dma_alias_mask); > > > > +} > > > > + > > > > /* > > > > - * Look for aliases to or from the given device for exisiting groups. The > > > > - * dma_alias_devfn only supports aliases on the same bus, therefore the > > > search > > > > + * Look for aliases to or from the given device for existing groups. DMA > > > > + * aliases are only supported on the same bus, therefore the search > > > > > > I'm trying to reconcile this statement that "DMA aliases are only > > > supported on the same bus" (which was there even before this patch) > > > with the fact that pci_for_each_dma_alias() does not have that > > > limitation. > > > > > > > * space is quite small (especially since we're really only looking at pcie > > > > * device, and therefore only expect multiple slots on the root complex or > > > > * downstream switch ports). It's conceivable though that a pair of > > > > @@ -686,11 +692,8 @@ static struct iommu_group *get_pci_alias_group(struct > > > pci_dev *pdev, > > > > continue; > > > > > > > > /* We alias them or they alias us */ > > > > - if (((pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) > > > && > > > > - pdev->dma_alias_devfn == tmp->devfn) || > > > > - ((tmp->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && > > > > - tmp->dma_alias_devfn == pdev->devfn)) { > > > > - > > > > + if (dma_alias_is_enabled(pdev, tmp->devfn) || > > > > + dma_alias_is_enabled(tmp, pdev->devfn)) { > > > > group = get_pci_alias_group(tmp, devfns); > > > > > > We basically have this: > > > > > > for_each_pci_dev(tmp) { > > > if (<pdev and tmp are DMA aliases>) > > > group = get_pci_alias_group(); > > > ... > > > } > > > > > > The DMA alias stuff relies on PCI internals, so it doesn't doesn't > > > seem quite right to use things like PCI_DEV_FLAGS_DMA_ALIAS_DEVFN and > > > dma_alias_devfn here in the IOMMU code. > > > > > > I'm trying to figure out why we don't do something like the following > > > instead: > > > > > > callback(struct pci_dev *pdev, u16 alias, void *opaque) > > > { > > > struct iommu_group *group; > > > > > > group = get_pci_alias_group(); > > > if (group) > > > return group; > > > > > > return 0; > > > } > > > > > > pci_for_each_dma_alias(pdev, callback, ...); > > > > > > Is the existing code some sort of optimization, e.g., checking > > > PCI_DEV_FLAGS_DMA_ALIAS_DEVFN is cheaper than using > > > pci_for_each_dma_alias()? > > > > > > It seems like this won't work for some very unlikely but theoretically > > > possible topologies, e.g., > > > > > > PCIe Root Complex/IOMMU > > > PCIe switch A > > > PCIe to conventional PCI bridge > > > PCI to PCIe Root Complex > > > PCIe NTB > > > > > > Here, I think the IOMMU will only see RIDs from PCIe switch A, but the > > > current code only looks at DMA aliases that are on the same bus as the > > > PCIe NTB. Wouldn't using pci_for_each_dma_alias() handle this > > > correctly? > > > > > > > if (group) { > > > > pci_dev_put(tmp); > > ^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH] PCI: Add support for multiple DMA aliases 2016-02-29 22:44 ` Bjorn Helgaas 2016-03-01 16:57 ` Jacek Lawrynowicz @ 2016-03-03 14:22 ` Jacek Lawrynowicz 2016-03-03 14:38 ` [PATCH v5 3/6] " Jacek Lawrynowicz 2 siblings, 0 replies; 28+ messages in thread From: Jacek Lawrynowicz @ 2016-03-03 14:22 UTC (permalink / raw) To: helgaas-DgEjT+Ai2ygdnm+yROfE0A Cc: jroedel-l3A5Bk7waGM, linux-pci-u79uwXL29TY76Z2rM5mHXA, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, dwmw2-wEGCiKHe2LqWVfeAwA7xHQ This patch solves IOMMU support issues with PCIe non-transparent bridges that use Requester ID look-up tables (RID-LUT), e.g. PEX8733. The NTB connects devices in two independent PCI domains. Devices separated by the NTB are not able to discover each other. A PCI packet being forwared from one domain to another has to have its RID modified so it appears on correct bus and completions are forwarded back to the original domain through the NTB. RID is translated using preprogrammed table (LUT) and the PCI packet propagates upstream away from the NTB. If the destination system has IOMMU enabled, the packet will be discarded because the new RID is unknown to the IOMMU. Adding a DMA alias for the new RID allows IOMMU to properly recognize the packet. Each device behind the NTB has a unique RID assigned in the RID-LUT. Current DMA alias implementation supports only single alias, so it's not possible to support mutiple devices behind the NTB when IOMMU is enabled. This implementation enables all possible aliases on a given bus (256) that are stored in a bitset. Alias devfn is directly translated to a bit number. The bitset is not allocated for devices that have no need for DMA aliases. More details can be found in following article: http://www.plxtech.com/files/pdf/technical/expresslane/RTC_Enabling%20MulitHostSystemDesigns.pdf Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> Acked-by: David Woodhouse <David.Woodhouse-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> Acked-by: Joerg Roedel <jroedel-l3A5Bk7waGM@public.gmane.org> --- I updated the commit message based on discussion with Bjorn. It should be now a little easier to understand. I'm not resubmitting the whole patch set because it could make the thread harder to follow. drivers/iommu/iommu.c | 17 ++++++++++------- drivers/pci/pci.c | 11 +++++++++-- drivers/pci/probe.c | 1 + drivers/pci/search.c | 14 +++++++++----- include/linux/pci.h | 4 +--- 5 files changed, 30 insertions(+), 17 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index bfd4f7c..4c10da1 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -659,9 +659,15 @@ static struct iommu_group *get_pci_function_alias_group(struct pci_dev *pdev, return NULL; } +static bool dma_alias_is_enabled(struct pci_dev *dev, u8 devfn) +{ + return dev->dma_alias_mask && + test_bit(devfn, dev->dma_alias_mask); +} + /* - * Look for aliases to or from the given device for exisiting groups. The - * dma_alias_devfn only supports aliases on the same bus, therefore the search + * Look for aliases to or from the given device for existing groups. DMA + * aliases are only supported on the same bus, therefore the search * space is quite small (especially since we're really only looking at pcie * device, and therefore only expect multiple slots on the root complex or * downstream switch ports). It's conceivable though that a pair of @@ -686,11 +692,8 @@ static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev, continue; /* We alias them or they alias us */ - if (((pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && - pdev->dma_alias_devfn == tmp->devfn) || - ((tmp->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && - tmp->dma_alias_devfn == pdev->devfn)) { - + if (dma_alias_is_enabled(pdev, tmp->devfn) || + dma_alias_is_enabled(tmp, pdev->devfn)) { group = get_pci_alias_group(tmp, devfns); if (group) { pci_dev_put(tmp); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e5e2c9d..33f3d24 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4577,8 +4577,15 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode, */ void pci_add_dma_alias(struct pci_dev *dev, u8 devfn) { - dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0); - dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; + if (!dev->dma_alias_mask) + dev->dma_alias_mask = kcalloc(BITS_TO_LONGS(U8_MAX), + sizeof(long), GFP_KERNEL); + if (!dev->dma_alias_mask) { + dev_warn(&dev->dev, "Unable to allocate DMA alias mask\n"); + return; + } + + set_bit(devfn, dev->dma_alias_mask); dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n", PCI_SLOT(devfn), PCI_FUNC(devfn)); } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 5eb378f..cf09307 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1502,6 +1502,7 @@ static void pci_release_dev(struct device *dev) pcibios_release_device(pci_dev); pci_bus_put(pci_dev->bus); kfree(pci_dev->driver_override); + kfree(pci_dev->dma_alias_mask); kfree(pci_dev); } diff --git a/drivers/pci/search.c b/drivers/pci/search.c index a20ce7d..33e0f03 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -40,11 +40,15 @@ int pci_for_each_dma_alias(struct pci_dev *pdev, * If the device is broken and uses an alias requester ID for * DMA, iterate over that too. */ - if (unlikely(pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN)) { - ret = fn(pdev, PCI_DEVID(pdev->bus->number, - pdev->dma_alias_devfn), data); - if (ret) - return ret; + if (unlikely(pdev->dma_alias_mask)) { + u8 devfn; + + for_each_set_bit(devfn, pdev->dma_alias_mask, U8_MAX) { + ret = fn(pdev, PCI_DEVID(pdev->bus->number, devfn), + data); + if (ret) + return ret; + } } for (bus = pdev->bus; !pci_is_root_bus(bus); bus = bus->parent) { diff --git a/include/linux/pci.h b/include/linux/pci.h index 614d70d..0c176e5 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -172,8 +172,6 @@ enum pci_dev_flags { PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) (1 << 2), /* Flag for quirk use to store if quirk-specific ACS is enabled */ PCI_DEV_FLAGS_ACS_ENABLED_QUIRK = (__force pci_dev_flags_t) (1 << 3), - /* Flag to indicate the device uses dma_alias_devfn */ - PCI_DEV_FLAGS_DMA_ALIAS_DEVFN = (__force pci_dev_flags_t) (1 << 4), /* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */ PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 5), /* Do not use bus resets for device */ @@ -279,7 +277,7 @@ struct pci_dev { u8 rom_base_reg; /* which config register controls the ROM */ u8 pin; /* which interrupt pin this device uses */ u16 pcie_flags_reg; /* cached PCIe Capabilities Register */ - u8 dma_alias_devfn;/* devfn of DMA alias, if any */ + unsigned long *dma_alias_mask;/* mask of enabled devfn aliases */ struct pci_driver *driver; /* which driver has allocated this device */ u64 dma_mask; /* Mask of the bits of bus address this -- 1.8.3.1 ^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v5 3/6] PCI: Add support for multiple DMA aliases 2016-02-29 22:44 ` Bjorn Helgaas 2016-03-01 16:57 ` Jacek Lawrynowicz 2016-03-03 14:22 ` [PATCH] " Jacek Lawrynowicz @ 2016-03-03 14:38 ` Jacek Lawrynowicz 2016-04-08 20:19 ` Alex Williamson 2 siblings, 1 reply; 28+ messages in thread From: Jacek Lawrynowicz @ 2016-03-03 14:38 UTC (permalink / raw) To: helgaas Cc: jroedel, dwmw2, alex.williamson, linux-pci, iommu, Jacek Lawrynowicz This patch solves IOMMU support issues with PCIe non-transparent bridges that use Requester ID look-up tables (RID-LUT), e.g. PEX8733. The NTB connects devices in two independent PCI domains. Devices separated by the NTB are not able to discover each other. A PCI packet being forwared from one domain to another has to have its RID modified so it appears on correct bus and completions are forwarded back to the original domain through the NTB. RID is translated using preprogrammed table (LUT) and the PCI packet propagates upstream away from the NTB. If the destination system has IOMMU enabled, the packet will be discarded because the new RID is unknown to the IOMMU. Adding a DMA alias for the new RID allows IOMMU to properly recognize the packet. Each device behind the NTB has a unique RID assigned in the RID-LUT. Current DMA alias implementation supports only single alias, so it's not possible to support mutiple devices behind the NTB when IOMMU is enabled. This implementation enables all possible aliases on a given bus (256) that are stored in a bitset. Alias devfn is directly translated to a bit number. The bitset is not allocated for devices that have no need for DMA aliases. More details can be found in following article: http://www.plxtech.com/files/pdf/technical/expresslane/RTC_Enabling%20MulitHostSystemDesigns.pdf Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz@intel.com> Acked-by: David Woodhouse <David.Woodhouse@intel.com> Acked-by: Joerg Roedel <jroedel@suse.de> --- I updated the commit message based on discussion with Bjorn. It should be now a little easier to understand. I'm not resubmitting the whole patch set because it could make the thread harder to follow. This time resubmitting with correct subject. drivers/iommu/iommu.c | 17 ++++++++++------- drivers/pci/pci.c | 11 +++++++++-- drivers/pci/probe.c | 1 + drivers/pci/search.c | 14 +++++++++----- include/linux/pci.h | 4 +--- 5 files changed, 30 insertions(+), 17 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index bfd4f7c..4c10da1 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -659,9 +659,15 @@ static struct iommu_group *get_pci_function_alias_group(struct pci_dev *pdev, return NULL; } +static bool dma_alias_is_enabled(struct pci_dev *dev, u8 devfn) +{ + return dev->dma_alias_mask && + test_bit(devfn, dev->dma_alias_mask); +} + /* - * Look for aliases to or from the given device for exisiting groups. The - * dma_alias_devfn only supports aliases on the same bus, therefore the search + * Look for aliases to or from the given device for existing groups. DMA + * aliases are only supported on the same bus, therefore the search * space is quite small (especially since we're really only looking at pcie * device, and therefore only expect multiple slots on the root complex or * downstream switch ports). It's conceivable though that a pair of @@ -686,11 +692,8 @@ static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev, continue; /* We alias them or they alias us */ - if (((pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && - pdev->dma_alias_devfn == tmp->devfn) || - ((tmp->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && - tmp->dma_alias_devfn == pdev->devfn)) { - + if (dma_alias_is_enabled(pdev, tmp->devfn) || + dma_alias_is_enabled(tmp, pdev->devfn)) { group = get_pci_alias_group(tmp, devfns); if (group) { pci_dev_put(tmp); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e5e2c9d..33f3d24 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4577,8 +4577,15 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode, */ void pci_add_dma_alias(struct pci_dev *dev, u8 devfn) { - dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0); - dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; + if (!dev->dma_alias_mask) + dev->dma_alias_mask = kcalloc(BITS_TO_LONGS(U8_MAX), + sizeof(long), GFP_KERNEL); + if (!dev->dma_alias_mask) { + dev_warn(&dev->dev, "Unable to allocate DMA alias mask\n"); + return; + } + + set_bit(devfn, dev->dma_alias_mask); dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n", PCI_SLOT(devfn), PCI_FUNC(devfn)); } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 5eb378f..cf09307 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1502,6 +1502,7 @@ static void pci_release_dev(struct device *dev) pcibios_release_device(pci_dev); pci_bus_put(pci_dev->bus); kfree(pci_dev->driver_override); + kfree(pci_dev->dma_alias_mask); kfree(pci_dev); } diff --git a/drivers/pci/search.c b/drivers/pci/search.c index a20ce7d..33e0f03 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -40,11 +40,15 @@ int pci_for_each_dma_alias(struct pci_dev *pdev, * If the device is broken and uses an alias requester ID for * DMA, iterate over that too. */ - if (unlikely(pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN)) { - ret = fn(pdev, PCI_DEVID(pdev->bus->number, - pdev->dma_alias_devfn), data); - if (ret) - return ret; + if (unlikely(pdev->dma_alias_mask)) { + u8 devfn; + + for_each_set_bit(devfn, pdev->dma_alias_mask, U8_MAX) { + ret = fn(pdev, PCI_DEVID(pdev->bus->number, devfn), + data); + if (ret) + return ret; + } } for (bus = pdev->bus; !pci_is_root_bus(bus); bus = bus->parent) { diff --git a/include/linux/pci.h b/include/linux/pci.h index 614d70d..0c176e5 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -172,8 +172,6 @@ enum pci_dev_flags { PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) (1 << 2), /* Flag for quirk use to store if quirk-specific ACS is enabled */ PCI_DEV_FLAGS_ACS_ENABLED_QUIRK = (__force pci_dev_flags_t) (1 << 3), - /* Flag to indicate the device uses dma_alias_devfn */ - PCI_DEV_FLAGS_DMA_ALIAS_DEVFN = (__force pci_dev_flags_t) (1 << 4), /* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */ PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 5), /* Do not use bus resets for device */ @@ -279,7 +277,7 @@ struct pci_dev { u8 rom_base_reg; /* which config register controls the ROM */ u8 pin; /* which interrupt pin this device uses */ u16 pcie_flags_reg; /* cached PCIe Capabilities Register */ - u8 dma_alias_devfn;/* devfn of DMA alias, if any */ + unsigned long *dma_alias_mask;/* mask of enabled devfn aliases */ struct pci_driver *driver; /* which driver has allocated this device */ u64 dma_mask; /* Mask of the bits of bus address this -- 1.8.3.1 ^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [PATCH v5 3/6] PCI: Add support for multiple DMA aliases 2016-03-03 14:38 ` [PATCH v5 3/6] " Jacek Lawrynowicz @ 2016-04-08 20:19 ` Alex Williamson 0 siblings, 0 replies; 28+ messages in thread From: Alex Williamson @ 2016-04-08 20:19 UTC (permalink / raw) To: Jacek Lawrynowicz; +Cc: helgaas, jroedel, dwmw2, linux-pci, iommu On Thu, 3 Mar 2016 15:38:02 +0100 Jacek Lawrynowicz <jacek.lawrynowicz@intel.com> wrote: > This patch solves IOMMU support issues with PCIe non-transparent bridges > that use Requester ID look-up tables (RID-LUT), e.g. PEX8733. > > The NTB connects devices in two independent PCI domains. Devices > separated by the NTB are not able to discover each other. A PCI packet > being forwared from one domain to another has to have its RID modified > so it appears on correct bus and completions are forwarded back to the > original domain through the NTB. RID is translated using preprogrammed > table (LUT) and the PCI packet propagates upstream away from the NTB. > If the destination system has IOMMU enabled, the packet will be > discarded because the new RID is unknown to the IOMMU. Adding a DMA > alias for the new RID allows IOMMU to properly recognize the packet. > > Each device behind the NTB has a unique RID assigned in the RID-LUT. > Current DMA alias implementation supports only single alias, so it's not > possible to support mutiple devices behind the NTB when IOMMU is enabled. > > This implementation enables all possible aliases on a given bus (256) > that are stored in a bitset. Alias devfn is directly translated to a bit > number. The bitset is not allocated for devices that have no need for > DMA aliases. > > More details can be found in following article: > http://www.plxtech.com/files/pdf/technical/expresslane/RTC_Enabling%20MulitHostSystemDesigns.pdf > > Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz@intel.com> > Acked-by: David Woodhouse <David.Woodhouse@intel.com> > Acked-by: Joerg Roedel <jroedel@suse.de> > --- > I updated the commit message based on discussion with Bjorn. It should be > now a little easier to understand. I'm not resubmitting the whole patch set > because it could make the thread harder to follow. > > This time resubmitting with correct subject. > > drivers/iommu/iommu.c | 17 ++++++++++------- > drivers/pci/pci.c | 11 +++++++++-- > drivers/pci/probe.c | 1 + > drivers/pci/search.c | 14 +++++++++----- > include/linux/pci.h | 4 +--- > 5 files changed, 30 insertions(+), 17 deletions(-) > > diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c > index bfd4f7c..4c10da1 100644 > --- a/drivers/iommu/iommu.c > +++ b/drivers/iommu/iommu.c > @@ -659,9 +659,15 @@ static struct iommu_group *get_pci_function_alias_group(struct pci_dev *pdev, > return NULL; > } > > +static bool dma_alias_is_enabled(struct pci_dev *dev, u8 devfn) > +{ > + return dev->dma_alias_mask && > + test_bit(devfn, dev->dma_alias_mask); > +} > + > /* > - * Look for aliases to or from the given device for exisiting groups. The > - * dma_alias_devfn only supports aliases on the same bus, therefore the search > + * Look for aliases to or from the given device for existing groups. DMA > + * aliases are only supported on the same bus, therefore the search > * space is quite small (especially since we're really only looking at pcie > * device, and therefore only expect multiple slots on the root complex or > * downstream switch ports). It's conceivable though that a pair of > @@ -686,11 +692,8 @@ static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev, > continue; > > /* We alias them or they alias us */ > - if (((pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && > - pdev->dma_alias_devfn == tmp->devfn) || > - ((tmp->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && > - tmp->dma_alias_devfn == pdev->devfn)) { > - > + if (dma_alias_is_enabled(pdev, tmp->devfn) || > + dma_alias_is_enabled(tmp, pdev->devfn)) { > group = get_pci_alias_group(tmp, devfns); > if (group) { > pci_dev_put(tmp); > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c > index e5e2c9d..33f3d24 100644 > --- a/drivers/pci/pci.c > +++ b/drivers/pci/pci.c > @@ -4577,8 +4577,15 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode, > */ > void pci_add_dma_alias(struct pci_dev *dev, u8 devfn) > { > - dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0); > - dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; > + if (!dev->dma_alias_mask) > + dev->dma_alias_mask = kcalloc(BITS_TO_LONGS(U8_MAX), > + sizeof(long), GFP_KERNEL); > + if (!dev->dma_alias_mask) { > + dev_warn(&dev->dev, "Unable to allocate DMA alias mask\n"); > + return; > + } > + > + set_bit(devfn, dev->dma_alias_mask); This silently fixes the bug in 1/, it should be updated after 1/ is fixed. Otherwise, Reviewed-by: Alex Williamson <alex.williamson@redhat.com> > dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n", > PCI_SLOT(devfn), PCI_FUNC(devfn)); > } > diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c > index 5eb378f..cf09307 100644 > --- a/drivers/pci/probe.c > +++ b/drivers/pci/probe.c > @@ -1502,6 +1502,7 @@ static void pci_release_dev(struct device *dev) > pcibios_release_device(pci_dev); > pci_bus_put(pci_dev->bus); > kfree(pci_dev->driver_override); > + kfree(pci_dev->dma_alias_mask); > kfree(pci_dev); > } > > diff --git a/drivers/pci/search.c b/drivers/pci/search.c > index a20ce7d..33e0f03 100644 > --- a/drivers/pci/search.c > +++ b/drivers/pci/search.c > @@ -40,11 +40,15 @@ int pci_for_each_dma_alias(struct pci_dev *pdev, > * If the device is broken and uses an alias requester ID for > * DMA, iterate over that too. > */ > - if (unlikely(pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN)) { > - ret = fn(pdev, PCI_DEVID(pdev->bus->number, > - pdev->dma_alias_devfn), data); > - if (ret) > - return ret; > + if (unlikely(pdev->dma_alias_mask)) { > + u8 devfn; > + > + for_each_set_bit(devfn, pdev->dma_alias_mask, U8_MAX) { > + ret = fn(pdev, PCI_DEVID(pdev->bus->number, devfn), > + data); > + if (ret) > + return ret; > + } > } > > for (bus = pdev->bus; !pci_is_root_bus(bus); bus = bus->parent) { > diff --git a/include/linux/pci.h b/include/linux/pci.h > index 614d70d..0c176e5 100644 > --- a/include/linux/pci.h > +++ b/include/linux/pci.h > @@ -172,8 +172,6 @@ enum pci_dev_flags { > PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) (1 << 2), > /* Flag for quirk use to store if quirk-specific ACS is enabled */ > PCI_DEV_FLAGS_ACS_ENABLED_QUIRK = (__force pci_dev_flags_t) (1 << 3), > - /* Flag to indicate the device uses dma_alias_devfn */ > - PCI_DEV_FLAGS_DMA_ALIAS_DEVFN = (__force pci_dev_flags_t) (1 << 4), > /* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */ > PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 5), > /* Do not use bus resets for device */ > @@ -279,7 +277,7 @@ struct pci_dev { > u8 rom_base_reg; /* which config register controls the ROM */ > u8 pin; /* which interrupt pin this device uses */ > u16 pcie_flags_reg; /* cached PCIe Capabilities Register */ > - u8 dma_alias_devfn;/* devfn of DMA alias, if any */ > + unsigned long *dma_alias_mask;/* mask of enabled devfn aliases */ > > struct pci_driver *driver; /* which driver has allocated this device */ > u64 dma_mask; /* Mask of the bits of bus address this ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4 3/6] PCI: Add support for multiple DMA aliases 2016-02-25 14:38 ` Bjorn Helgaas 2016-02-25 15:41 ` Lawrynowicz, Jacek @ 2016-03-14 22:43 ` David Woodhouse [not found] ` <1457995420.78634.63.camel-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org> 1 sibling, 1 reply; 28+ messages in thread From: David Woodhouse @ 2016-03-14 22:43 UTC (permalink / raw) To: Bjorn Helgaas, Bjorn Helgaas, Lawrynowicz, Jacek Cc: Joerg Roedel, linux-pci, iommu [-- Attachment #1: Type: text/plain, Size: 3109 bytes --] On Thu, 2016-02-25 at 08:38 -0600, Bjorn Helgaas wrote: > > > /* > > - * Look for aliases to or from the given device for exisiting groups. The > > - * dma_alias_devfn only supports aliases on the same bus, therefore the search > > + * Look for aliases to or from the given device for existing groups. DMA > > + * aliases are only supported on the same bus, therefore the search > > I'm trying to reconcile this statement that "DMA aliases are only > supported on the same bus" (which was there even before this patch) > with the fact that pci_for_each_dma_alias() does not have that > limitation. Doesn't it? You can still only set a DMA alias on the same bus with pci_add_dma_alias(), can't you? > > * space is quite small (especially since we're really only looking at pcie > > * device, and therefore only expect multiple slots on the root complex or > > * downstream switch ports). It's conceivable though that a pair of > > @@ -686,11 +692,8 @@ static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev, > > continue; > > > > /* We alias them or they alias us */ > > - if (((pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && > > - pdev->dma_alias_devfn == tmp->devfn) || > > - ((tmp->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && > > - tmp->dma_alias_devfn == pdev->devfn)) { > > - > > + if (dma_alias_is_enabled(pdev, tmp->devfn) || > > + dma_alias_is_enabled(tmp, pdev->devfn)) { > > group = get_pci_alias_group(tmp, devfns); > > We basically have this: > > for_each_pci_dev(tmp) { > if () > group = get_pci_alias_group(); > ... > } Strictly, that's: for_each_pci_dev(tmp) { if (pdev is an alias of tmp || tmp is an alias of pdev) group = get_pci_alias_group(); ... } > The DMA alias stuff relies on PCI internals, so it doesn't doesn't > seem quite right to use things like PCI_DEV_FLAGS_DMA_ALIAS_DEVFN and > dma_alias_devfn here in the IOMMU code. > > I'm trying to figure out why we don't do something like the following > instead: > > callback(struct pci_dev *pdev, u16 alias, void *opaque) > { > struct iommu_group *group; > > group = get_pci_alias_group(); > if (group) > return group; > > return 0; > } > > pci_for_each_dma_alias(pdev, callback, ...); And this would be equivalent to for_each_pci_dev(tmp) { if (tmp is an alias of pdev) group = get_pci_alias_group(); ... } The "is an alias of" property is not commutative. Perhaps it should be. But that's hard because in some cases the alias doesn't even *exist* as a real PCI device. It's just that you appear to get DMA transactions from a given source-id. -- dwmw2 [-- Attachment #2: smime.p7s --] [-- Type: application/x-pkcs7-signature, Size: 5691 bytes --] ^ permalink raw reply [flat|nested] 28+ messages in thread
[parent not found: <1457995420.78634.63.camel-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>]
* Re: [PATCH v4 3/6] PCI: Add support for multiple DMA aliases [not found] ` <1457995420.78634.63.camel-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org> @ 2016-03-16 0:48 ` Bjorn Helgaas 2016-04-08 16:06 ` Bjorn Helgaas 0 siblings, 1 reply; 28+ messages in thread From: Bjorn Helgaas @ 2016-03-16 0:48 UTC (permalink / raw) To: David Woodhouse Cc: Bjorn Helgaas, linux-pci-u79uwXL29TY76Z2rM5mHXA, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Joerg Roedel On Mon, Mar 14, 2016 at 10:43:40PM +0000, David Woodhouse wrote: > On Thu, 2016-02-25 at 08:38 -0600, Bjorn Helgaas wrote: > > > > > /* > > > - * Look for aliases to or from the given device for exisiting groups. The > > > - * dma_alias_devfn only supports aliases on the same bus, therefore the search > > > + * Look for aliases to or from the given device for existing groups. DMA > > > + * aliases are only supported on the same bus, therefore the search > > > > I'm trying to reconcile this statement that "DMA aliases are only > > supported on the same bus" (which was there even before this patch) > > with the fact that pci_for_each_dma_alias() does not have that > > limitation. > > Doesn't it? You can still only set a DMA alias on the same bus with > pci_add_dma_alias(), can't you? I guess it's true that PCI_DEV_FLAGS_DMA_ALIAS_DEVFN and the proposed pci_add_dma_alias() only add aliases on the same bus. I was thinking about a scenario like this: 00:00.0 PCIe-to-PCI bridge to [bus 01] 01:01.0 conventional PCI device where I think 01:00.0 is a DMA alias for 01:01.0 because the bridge takes ownership of DMA transactions from 01:01.0 and assigns a Requester ID of 01:00.0 (secondary bus number, device 0, function 0). > > > * space is quite small (especially since we're really only looking at pcie > > > * device, and therefore only expect multiple slots on the root complex or > > > * downstream switch ports). It's conceivable though that a pair of > > > @@ -686,11 +692,8 @@ static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev, > > > continue; > > > > > > /* We alias them or they alias us */ > > > - if (((pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && > > > - pdev->dma_alias_devfn == tmp->devfn) || > > > - ((tmp->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && > > > - tmp->dma_alias_devfn == pdev->devfn)) { > > > - > > > + if (dma_alias_is_enabled(pdev, tmp->devfn) || > > > + dma_alias_is_enabled(tmp, pdev->devfn)) { > > > group = get_pci_alias_group(tmp, devfns); > > > > We basically have this: > > > > for_each_pci_dev(tmp) { > > if () > > group = get_pci_alias_group(); > > ... > > } > > Strictly, that's: > > for_each_pci_dev(tmp) { > if (pdev is an alias of tmp || tmp is an alias of pdev) > group = get_pci_alias_group(); > ... > } OK. > > I'm trying to figure out why we don't do something like the following > > instead: > > > > callback(struct pci_dev *pdev, u16 alias, void *opaque) > > { > > struct iommu_group *group; > > > > group = get_pci_alias_group(); > > if (group) > > return group; > > > > return 0; > > } > > > > pci_for_each_dma_alias(pdev, callback, ...); > > And this would be equivalent to > > for_each_pci_dev(tmp) { > if (tmp is an alias of pdev) > group = get_pci_alias_group(); > ... > } > > The "is an alias of" property is not commutative. Perhaps it should be. > But that's hard because in some cases the alias doesn't even *exist* as > a real PCI device. It's just that you appear to get DMA transactions > from a given source-id. Right. In my example above, 01:00.0 is not a PCI device; it's only a Requester ID that is fabricated by the bridge when it forwards DMA transactions upstream. I think I'm confused because I don't really understand IOMMU groups. Let me explain what I think they are and you can correct me when I go wrong. The iommu_group_alloc() comment says "The IOMMU group represents the minimum granularity of the IOMMU." So I suppose the IOMMU cannot distinguish between devices in a group. All the devices in the group use the same set of DMA mappings. Granting device A DMA access to a buffer grants the same access to all other members of A's IOMMU group. That would mean my question was fundamentally backwards. In get_pci_alias_group(A), we're not trying to figure out what all the aliases of A are, which is what pci_for_each_dma_alias() does. Instead, we're trying to figure out which IOMMU group A belongs to. But I still don't quite understand how aliases fit into this. Let's go back to my example and assume we've already put 00:00.0 and 01:01.0 in IOMMU groups: 00:00.0 PCIe-to-PCI bridge to [bus 01] # in IOMMU group G0 01:01.0 conventional PCI device # in IOMMU group G1 I assume these devices are in different IOMMU groups because if the bridge generated its own DMA, it would use Requester ID 00:00.0, which is distinct from the 01:00.0 it would use when forwarding DMAs from its secondary side. What happens when we add 01:02.0? I think 01:01.0 and 01:02.0 should both end up in IOMMU group G1 because the IOMMU will see only Requester ID 01:00.0, so it can't distinguish them. When we add 01:02.0, the ops->add_device() ... ops->device_group() path calls pci_device_group(01:02.0): pci_device_group(01:02.0) pci_for_each_dma_alias(01:02.0, get_pci_alias_or_group) get_pci_alias_or_group(01:02.0, 01:02.0) # callback return 0 # 01:02.0 group not set yet get_pci_alias_or_group(00:00.0, 01:00.0) # callback return 1 # 00:00.0 is in G0 It seems like we'll assign 01:02.0 to group G0, when I think it should be in G1. Where did I go wrong? Bjorn ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4 3/6] PCI: Add support for multiple DMA aliases 2016-03-16 0:48 ` Bjorn Helgaas @ 2016-04-08 16:06 ` Bjorn Helgaas 2016-04-08 16:09 ` David Woodhouse 2016-04-08 17:31 ` Alex Williamson 0 siblings, 2 replies; 28+ messages in thread From: Bjorn Helgaas @ 2016-04-08 16:06 UTC (permalink / raw) To: David Woodhouse Cc: Bjorn Helgaas, Lawrynowicz, Jacek, Joerg Roedel, linux-pci, iommu On Tue, Mar 15, 2016 at 07:48:17PM -0500, Bjorn Helgaas wrote: > On Mon, Mar 14, 2016 at 10:43:40PM +0000, David Woodhouse wrote: > > On Thu, 2016-02-25 at 08:38 -0600, Bjorn Helgaas wrote: > > > > > > > /* > > > > - * Look for aliases to or from the given device for exisiting groups. The > > > > - * dma_alias_devfn only supports aliases on the same bus, therefore the search > > > > + * Look for aliases to or from the given device for existing groups. DMA > > > > + * aliases are only supported on the same bus, therefore the search > > > > > > I'm trying to reconcile this statement that "DMA aliases are only > > > supported on the same bus" (which was there even before this patch) > > > with the fact that pci_for_each_dma_alias() does not have that > > > limitation. > > > > Doesn't it? You can still only set a DMA alias on the same bus with > > pci_add_dma_alias(), can't you? > > I guess it's true that PCI_DEV_FLAGS_DMA_ALIAS_DEVFN and the proposed > pci_add_dma_alias() only add aliases on the same bus. I was thinking > about a scenario like this: > > 00:00.0 PCIe-to-PCI bridge to [bus 01] > 01:01.0 conventional PCI device > > where I think 01:00.0 is a DMA alias for 01:01.0 because the bridge > takes ownership of DMA transactions from 01:01.0 and assigns a > Requester ID of 01:00.0 (secondary bus number, device 0, function 0). > > > > > * space is quite small (especially since we're really only looking at pcie > > > > * device, and therefore only expect multiple slots on the root complex or > > > > * downstream switch ports). It's conceivable though that a pair of > > > > @@ -686,11 +692,8 @@ static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev, > > > > continue; > > > > > > > > /* We alias them or they alias us */ > > > > - if (((pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && > > > > - pdev->dma_alias_devfn == tmp->devfn) || > > > > - ((tmp->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && > > > > - tmp->dma_alias_devfn == pdev->devfn)) { > > > > - > > > > + if (dma_alias_is_enabled(pdev, tmp->devfn) || > > > > + dma_alias_is_enabled(tmp, pdev->devfn)) { > > > > group = get_pci_alias_group(tmp, devfns); > > > > > > We basically have this: > > > > > > for_each_pci_dev(tmp) { > > > if () > > > group = get_pci_alias_group(); > > > ... > > > } > > > > Strictly, that's: > > > > for_each_pci_dev(tmp) { > > if (pdev is an alias of tmp || tmp is an alias of pdev) > > group = get_pci_alias_group(); > > ... > > } > > OK. > > > > I'm trying to figure out why we don't do something like the following > > > instead: > > > > > > callback(struct pci_dev *pdev, u16 alias, void *opaque) > > > { > > > struct iommu_group *group; > > > > > > group = get_pci_alias_group(); > > > if (group) > > > return group; > > > > > > return 0; > > > } > > > > > > pci_for_each_dma_alias(pdev, callback, ...); > > > > And this would be equivalent to > > > > for_each_pci_dev(tmp) { > > if (tmp is an alias of pdev) > > group = get_pci_alias_group(); > > ... > > } > > > > The "is an alias of" property is not commutative. Perhaps it should be. > > But that's hard because in some cases the alias doesn't even *exist* as > > a real PCI device. It's just that you appear to get DMA transactions > > from a given source-id. > > Right. In my example above, 01:00.0 is not a PCI device; it's only a > Requester ID that is fabricated by the bridge when it forwards DMA > transactions upstream. > > I think I'm confused because I don't really understand IOMMU groups. > > Let me explain what I think they are and you can correct me when I go > wrong. The iommu_group_alloc() comment says "The IOMMU group > represents the minimum granularity of the IOMMU." So I suppose the > IOMMU cannot distinguish between devices in a group. All the devices > in the group use the same set of DMA mappings. Granting device A DMA > access to a buffer grants the same access to all other members of A's > IOMMU group. > > That would mean my question was fundamentally backwards. In > get_pci_alias_group(A), we're not trying to figure out what all the > aliases of A are, which is what pci_for_each_dma_alias() does. > > Instead, we're trying to figure out which IOMMU group A belongs to. > But I still don't quite understand how aliases fit into this. Let's > go back to my example and assume we've already put 00:00.0 and 01:01.0 > in IOMMU groups: > > 00:00.0 PCIe-to-PCI bridge to [bus 01] # in IOMMU group G0 > 01:01.0 conventional PCI device # in IOMMU group G1 > > I assume these devices are in different IOMMU groups because if the > bridge generated its own DMA, it would use Requester ID 00:00.0, which > is distinct from the 01:00.0 it would use when forwarding DMAs from > its secondary side. > > What happens when we add 01:02.0? I think 01:01.0 and 01:02.0 should > both end up in IOMMU group G1 because the IOMMU will see only > Requester ID 01:00.0, so it can't distinguish them. > > When we add 01:02.0, the ops->add_device() ... ops->device_group() > path calls pci_device_group(01:02.0): > > pci_device_group(01:02.0) > pci_for_each_dma_alias(01:02.0, get_pci_alias_or_group) > get_pci_alias_or_group(01:02.0, 01:02.0) # callback > return 0 # 01:02.0 group not set yet > get_pci_alias_or_group(00:00.0, 01:00.0) # callback > return 1 # 00:00.0 is in G0 > > It seems like we'll assign 01:02.0 to group G0, when I think it should > be in G1. Where did I go wrong? Ping? ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4 3/6] PCI: Add support for multiple DMA aliases 2016-04-08 16:06 ` Bjorn Helgaas @ 2016-04-08 16:09 ` David Woodhouse 2016-04-08 17:31 ` Alex Williamson 1 sibling, 0 replies; 28+ messages in thread From: David Woodhouse @ 2016-04-08 16:09 UTC (permalink / raw) To: Bjorn Helgaas, alex.williamson-H+wXaHxf7aLQT0dZR+AlfA Cc: Bjorn Helgaas, linux-pci-u79uwXL29TY76Z2rM5mHXA, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Joerg Roedel [-- Attachment #1.1: Type: text/plain, Size: 226 bytes --] On Fri, 2016-04-08 at 11:06 -0500, Bjorn Helgaas wrote: > > I think I'm confused because I don't really understand IOMMU > > groups. ,,, > Ping? I think this ended up being more of a Alex question... -- dwmw2 [-- Attachment #1.2: smime.p7s --] [-- Type: application/x-pkcs7-signature, Size: 5691 bytes --] [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4 3/6] PCI: Add support for multiple DMA aliases 2016-04-08 16:06 ` Bjorn Helgaas 2016-04-08 16:09 ` David Woodhouse @ 2016-04-08 17:31 ` Alex Williamson 1 sibling, 0 replies; 28+ messages in thread From: Alex Williamson @ 2016-04-08 17:31 UTC (permalink / raw) To: Bjorn Helgaas Cc: David Woodhouse, Bjorn Helgaas, Lawrynowicz, Jacek, Joerg Roedel, linux-pci, iommu On Fri, 8 Apr 2016 11:06:32 -0500 Bjorn Helgaas <helgaas@kernel.org> wrote: > On Tue, Mar 15, 2016 at 07:48:17PM -0500, Bjorn Helgaas wrote: > > On Mon, Mar 14, 2016 at 10:43:40PM +0000, David Woodhouse wrote: > > > On Thu, 2016-02-25 at 08:38 -0600, Bjorn Helgaas wrote: > > > > > > > > > /* > > > > > - * Look for aliases to or from the given device for exisiting groups. The > > > > > - * dma_alias_devfn only supports aliases on the same bus, therefore the search > > > > > + * Look for aliases to or from the given device for existing groups. DMA > > > > > + * aliases are only supported on the same bus, therefore the search > > > > > > > > I'm trying to reconcile this statement that "DMA aliases are only > > > > supported on the same bus" (which was there even before this patch) > > > > with the fact that pci_for_each_dma_alias() does not have that > > > > limitation. > > > > > > Doesn't it? You can still only set a DMA alias on the same bus with > > > pci_add_dma_alias(), can't you? > > > > I guess it's true that PCI_DEV_FLAGS_DMA_ALIAS_DEVFN and the proposed > > pci_add_dma_alias() only add aliases on the same bus. I was thinking > > about a scenario like this: > > > > 00:00.0 PCIe-to-PCI bridge to [bus 01] > > 01:01.0 conventional PCI device > > > > where I think 01:00.0 is a DMA alias for 01:01.0 because the bridge > > takes ownership of DMA transactions from 01:01.0 and assigns a > > Requester ID of 01:00.0 (secondary bus number, device 0, function 0). This is true, but this is a topology alias, not a quirk. pci_for_each_dma_alias() already handles this case. It would trigger the callback function for any direct alias of the conventional device as well as the bridge itself. Obviously we don't end up with any quirks for conventional devices because the aliases are masked behind the bridge anyway. > > > > > * space is quite small (especially since we're really only looking at pcie > > > > > * device, and therefore only expect multiple slots on the root complex or > > > > > * downstream switch ports). It's conceivable though that a pair of > > > > > @@ -686,11 +692,8 @@ static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev, > > > > > continue; > > > > > > > > > > /* We alias them or they alias us */ > > > > > - if (((pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && > > > > > - pdev->dma_alias_devfn == tmp->devfn) || > > > > > - ((tmp->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && > > > > > - tmp->dma_alias_devfn == pdev->devfn)) { > > > > > - > > > > > + if (dma_alias_is_enabled(pdev, tmp->devfn) || > > > > > + dma_alias_is_enabled(tmp, pdev->devfn)) { > > > > > group = get_pci_alias_group(tmp, devfns); > > > > > > > > We basically have this: > > > > > > > > for_each_pci_dev(tmp) { > > > > if () > > > > group = get_pci_alias_group(); > > > > ... > > > > } > > > > > > Strictly, that's: > > > > > > for_each_pci_dev(tmp) { > > > if (pdev is an alias of tmp || tmp is an alias of pdev) > > > group = get_pci_alias_group(); > > > ... > > > } > > > > OK. > > > > > > I'm trying to figure out why we don't do something like the following > > > > instead: > > > > > > > > callback(struct pci_dev *pdev, u16 alias, void *opaque) > > > > { > > > > struct iommu_group *group; > > > > > > > > group = get_pci_alias_group(); > > > > if (group) > > > > return group; > > > > > > > > return 0; > > > > } > > > > > > > > pci_for_each_dma_alias(pdev, callback, ...); > > > > > > And this would be equivalent to > > > > > > for_each_pci_dev(tmp) { > > > if (tmp is an alias of pdev) > > > group = get_pci_alias_group(); > > > ... > > > } > > > > > > The "is an alias of" property is not commutative. Perhaps it should be. > > > But that's hard because in some cases the alias doesn't even *exist* as > > > a real PCI device. It's just that you appear to get DMA transactions > > > from a given source-id. > > > > Right. In my example above, 01:00.0 is not a PCI device; it's only a > > Requester ID that is fabricated by the bridge when it forwards DMA > > transactions upstream. > > > > I think I'm confused because I don't really understand IOMMU groups. > > > > Let me explain what I think they are and you can correct me when I go > > wrong. The iommu_group_alloc() comment says "The IOMMU group > > represents the minimum granularity of the IOMMU." So I suppose the > > IOMMU cannot distinguish between devices in a group. All the devices > > in the group use the same set of DMA mappings. Granting device A DMA > > access to a buffer grants the same access to all other members of A's > > IOMMU group. > > > > That would mean my question was fundamentally backwards. In > > get_pci_alias_group(A), we're not trying to figure out what all the > > aliases of A are, which is what pci_for_each_dma_alias() does. > > > > Instead, we're trying to figure out which IOMMU group A belongs to. > > But I still don't quite understand how aliases fit into this. Let's > > go back to my example and assume we've already put 00:00.0 and 01:01.0 > > in IOMMU groups: > > > > 00:00.0 PCIe-to-PCI bridge to [bus 01] # in IOMMU group G0 > > 01:01.0 conventional PCI device # in IOMMU group G1 > > > > I assume these devices are in different IOMMU groups because if the > > bridge generated its own DMA, it would use Requester ID 00:00.0, which > > is distinct from the 01:00.0 it would use when forwarding DMAs from > > its secondary side. The actual requester ID of the bridge depends on quirks as well, see PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS, so it might either be the bridge itself or the subordinate bus address. However, trace how these groups would be created, the bridge device is discovered first, so we call pci_device_group() for it. since it's on the root bus and it's the 0th function, there will be no existing groups for it to alias, so it gets a new group. Then we discover 01:01.0, pci_device_group() calls pci_for_each_dma_alias(), which hits the bridge, regardless of which alias is used. So 01:01.0 ends up in the same iommu group as the bridge. From the purist standpoint of iommu groups, your expectations are probably correct, but we also include within IOMMU groups DMA isolation between devices. So if two devices can DMA between each other without it necessarily passing through the iommu, the devices are grouped together. The more important cases of this are ACS isolation on PCI-e devices, but it still sort of applies to this conventional PCI example here. > > What happens when we add 01:02.0? I think 01:01.0 and 01:02.0 > > should both end up in IOMMU group G1 because the IOMMU will see only > > Requester ID 01:00.0, so it can't distinguish them. > > > > When we add 01:02.0, the ops->add_device() ... ops->device_group() > > path calls pci_device_group(01:02.0): > > > > pci_device_group(01:02.0) > > pci_for_each_dma_alias(01:02.0, get_pci_alias_or_group) > > get_pci_alias_or_group(01:02.0, 01:02.0) # callback > > return 0 # 01:02.0 group not set yet > > get_pci_alias_or_group(00:00.0, 01:00.0) # callback > > return 1 # 00:00.0 is in G0 > > > > It seems like we'll assign 01:02.0 to group G0, when I think it > > should be in G1. Where did I go wrong? In fact they're all part of G0, so you went wrong assuming the initial grouping rather than applying the same rules and tracing how 01:01.0 is added. It's not an ideal representation, it tends to be more conservative than necessary in some cases, but keeping the group attached to devices has advantages in being able to search and find points like this where we don't necessarily have access to the group behind the bridge without tying it to the bridge itself. Thanks, Alex ^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v4 4/6] PCI: Rename dma_alias_is_enabled() to pci_devs_are_dma_aliases() 2016-02-24 19:43 [PATCH v4 0/6] PCI: Support multiple DMA aliases Bjorn Helgaas ` (2 preceding siblings ...) 2016-02-24 19:44 ` [PATCH v4 3/6] PCI: Add support for multiple DMA aliases Bjorn Helgaas @ 2016-02-24 19:44 ` Bjorn Helgaas 2016-04-08 20:19 ` Alex Williamson [not found] ` <20160224193926.7585.10833.stgit-1RhO1Y9PlrlHTL0Zs8A6p/gx64E7kk8eUsxypvmhUTTZJqsBc5GL+g@public.gmane.org> ` (2 subsequent siblings) 6 siblings, 1 reply; 28+ messages in thread From: Bjorn Helgaas @ 2016-02-24 19:44 UTC (permalink / raw) To: Jacek Lawrynowicz Cc: linux-pci, Alex Williamson, Joerg Roedel, David Woodhouse, iommu This should be folded into the previous patch. I left it separate to show the interface difference more clearly. Also, pci_devs_are_dma_aliases() uses PCI internals (dma_alias_mask), so I think it should be in PCI code instead of in IOMMU code. That would mean both it and pci_add_dma_alias() should probably be declared in include/linux/pci.h (but not exported to modules with EXPORT_SYMBOL()). --- drivers/iommu/iommu.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index a214e19..031d06b 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -659,10 +659,12 @@ static struct iommu_group *get_pci_function_alias_group(struct pci_dev *pdev, return NULL; } -static bool dma_alias_is_enabled(struct pci_dev *dev, u8 devfn) +static bool pci_devs_are_dma_aliases(struct pci_dev *pdev1, struct pci_dev *pdev2) { - return dev->dma_alias_mask && - test_bit(devfn, dev->dma_alias_mask); + return (pdev1->dma_alias_mask && + test_bit(pdev2->devfn, pdev1->dma_alias_mask)) || + (pdev2->dma_alias_mask && + test_bit(pdev1->devfn, pdev2->dma_alias_mask)); } /* @@ -692,8 +694,7 @@ static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev, continue; /* We alias them or they alias us */ - if (dma_alias_is_enabled(pdev, tmp->devfn) || - dma_alias_is_enabled(tmp, pdev->devfn)) { + if (pci_devs_are_dma_aliases(pdev, tmp)) { group = get_pci_alias_group(tmp, devfns); if (group) { pci_dev_put(tmp); ^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [PATCH v4 4/6] PCI: Rename dma_alias_is_enabled() to pci_devs_are_dma_aliases() 2016-02-24 19:44 ` [PATCH v4 4/6] PCI: Rename dma_alias_is_enabled() to pci_devs_are_dma_aliases() Bjorn Helgaas @ 2016-04-08 20:19 ` Alex Williamson 0 siblings, 0 replies; 28+ messages in thread From: Alex Williamson @ 2016-04-08 20:19 UTC (permalink / raw) To: Bjorn Helgaas Cc: Jacek Lawrynowicz, linux-pci, Joerg Roedel, David Woodhouse, iommu On Wed, 24 Feb 2016 13:44:15 -0600 Bjorn Helgaas <bhelgaas@google.com> wrote: > This should be folded into the previous patch. I left it separate to show > the interface difference more clearly. > > Also, pci_devs_are_dma_aliases() uses PCI internals (dma_alias_mask), so I > think it should be in PCI code instead of in IOMMU code. That would mean > both it and pci_add_dma_alias() should probably be declared in > include/linux/pci.h (but not exported to modules with EXPORT_SYMBOL()). > --- > drivers/iommu/iommu.c | 11 ++++++----- > 1 file changed, 6 insertions(+), 5 deletions(-) Needs a Sign-off. Reviewed-by: Alex Williamson <alex.williamson@redhat.com> > > diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c > index a214e19..031d06b 100644 > --- a/drivers/iommu/iommu.c > +++ b/drivers/iommu/iommu.c > @@ -659,10 +659,12 @@ static struct iommu_group *get_pci_function_alias_group(struct pci_dev *pdev, > return NULL; > } > > -static bool dma_alias_is_enabled(struct pci_dev *dev, u8 devfn) > +static bool pci_devs_are_dma_aliases(struct pci_dev *pdev1, struct pci_dev *pdev2) > { > - return dev->dma_alias_mask && > - test_bit(devfn, dev->dma_alias_mask); > + return (pdev1->dma_alias_mask && > + test_bit(pdev2->devfn, pdev1->dma_alias_mask)) || > + (pdev2->dma_alias_mask && > + test_bit(pdev1->devfn, pdev2->dma_alias_mask)); > } > > /* > @@ -692,8 +694,7 @@ static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev, > continue; > > /* We alias them or they alias us */ > - if (dma_alias_is_enabled(pdev, tmp->devfn) || > - dma_alias_is_enabled(tmp, pdev->devfn)) { > + if (pci_devs_are_dma_aliases(pdev, tmp)) { > group = get_pci_alias_group(tmp, devfns); > if (group) { > pci_dev_put(tmp); > ^ permalink raw reply [flat|nested] 28+ messages in thread
[parent not found: <20160224193926.7585.10833.stgit-1RhO1Y9PlrlHTL0Zs8A6p/gx64E7kk8eUsxypvmhUTTZJqsBc5GL+g@public.gmane.org>]
* [PATCH v4 5/6] pci: Add DMA alias quirk for mic_x200_dma [not found] ` <20160224193926.7585.10833.stgit-1RhO1Y9PlrlHTL0Zs8A6p/gx64E7kk8eUsxypvmhUTTZJqsBc5GL+g@public.gmane.org> @ 2016-02-24 19:44 ` Bjorn Helgaas via iommu 2016-03-03 14:53 ` [PATCH v5 5/6] PCI: " Jacek Lawrynowicz 0 siblings, 1 reply; 28+ messages in thread From: Bjorn Helgaas via iommu @ 2016-02-24 19:44 UTC (permalink / raw) To: Jacek Lawrynowicz Cc: linux-pci-u79uwXL29TY76Z2rM5mHXA, Joerg Roedel, David Woodhouse, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA From: Jacek Lawrynowicz <jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> MIC x200 NTB forwards PCIe traffic using multiple alien RID. They have to be added as aliases to the DMA device in order to allow buffer access when IOMMU is enabled. Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> Acked-by: David Woodhouse <David.Woodhouse-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> --- drivers/pci/quirks.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index cf023ea..ac23a30 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3696,6 +3696,19 @@ DECLARE_PCI_FIXUP_HEADER(0x1283, 0x8892, quirk_use_pcie_bridge_dma_alias); DECLARE_PCI_FIXUP_HEADER(0x8086, 0x244e, quirk_use_pcie_bridge_dma_alias); /* + * MIC x200 NTB forwards PCIe traffic using multiple alien RID. They have to + * be added as aliases to the DMA device in order to allow buffer access + * when IOMMU is enabled. + */ +static void quirk_mic_x200_dma_alias(struct pci_dev *pdev) +{ + pci_add_dma_alias(pdev, PCI_DEVFN(0x10, 0x0)); + pci_add_dma_alias(pdev, PCI_DEVFN(0x11, 0x0)); + pci_add_dma_alias(pdev, PCI_DEVFN(0x12, 0x3)); +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2264, quirk_mic_x200_dma_alias); + +/* * Intersil/Techwell TW686[4589]-based video capture cards have an empty (zero) * class code. Fix it. */ ^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v5 5/6] PCI: Add DMA alias quirk for mic_x200_dma 2016-02-24 19:44 ` [PATCH v4 5/6] pci: Add DMA alias quirk for mic_x200_dma Bjorn Helgaas via iommu @ 2016-03-03 14:53 ` Jacek Lawrynowicz [not found] ` <1457016800-11903-1-git-send-email-jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> 0 siblings, 1 reply; 28+ messages in thread From: Jacek Lawrynowicz @ 2016-03-03 14:53 UTC (permalink / raw) To: helgaas Cc: jroedel, dwmw2, alex.williamson, linux-pci, iommu, Jacek Lawrynowicz MIC x200 NTB forwards PCIe traffic using multiple alien RID. They have to be added as aliases to the DMA device in order to allow buffer access when IOMMU is enabled. Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz@intel.com> Acked-by: David Woodhouse <David.Woodhouse@intel.com> --- Updated quirk comment with requirement that aliases have to be matching values programmed in the EEPROM. The LUT table on x200 is static so there is no need to program it from the driver. drivers/pci/quirks.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 51927a5..e66f09d 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3696,6 +3696,20 @@ DECLARE_PCI_FIXUP_HEADER(0x1283, 0x8892, quirk_use_pcie_bridge_dma_alias); DECLARE_PCI_FIXUP_HEADER(0x8086, 0x244e, quirk_use_pcie_bridge_dma_alias); /* + * MIC x200 NTB forwards PCIe traffic using multiple alien RIDs. They have to + * be added as aliases to the DMA device in order to allow buffer access + * when IOMMU is enabled. Following devfns have to match RIT-LUT table + * programmed in the EEPROM. + */ +static void quirk_mic_x200_dma_alias(struct pci_dev *pdev) +{ + pci_add_dma_alias(pdev, PCI_DEVFN(0x10, 0x0)); + pci_add_dma_alias(pdev, PCI_DEVFN(0x11, 0x0)); + pci_add_dma_alias(pdev, PCI_DEVFN(0x12, 0x3)); +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2264, quirk_mic_x200_dma_alias); + +/* * Intersil/Techwell TW686[4589]-based video capture cards have an empty (zero) * class code. Fix it. */ -- 1.8.3.1 ^ permalink raw reply related [flat|nested] 28+ messages in thread
[parent not found: <1457016800-11903-1-git-send-email-jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>]
* Re: [PATCH v5 5/6] PCI: Add DMA alias quirk for mic_x200_dma [not found] ` <1457016800-11903-1-git-send-email-jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> @ 2016-04-08 20:19 ` Alex Williamson 0 siblings, 0 replies; 28+ messages in thread From: Alex Williamson @ 2016-04-08 20:19 UTC (permalink / raw) To: Jacek Lawrynowicz Cc: dwmw2-wEGCiKHe2LqWVfeAwA7xHQ, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, jroedel-l3A5Bk7waGM, helgaas-DgEjT+Ai2ygdnm+yROfE0A, linux-pci-u79uwXL29TY76Z2rM5mHXA On Thu, 3 Mar 2016 15:53:20 +0100 Jacek Lawrynowicz <jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> wrote: > MIC x200 NTB forwards PCIe traffic using multiple alien RID. They have to > be added as aliases to the DMA device in order to allow buffer access > when IOMMU is enabled. > > Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> > Acked-by: David Woodhouse <David.Woodhouse-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> > --- Reviewed-by: Alex Williamson <alex.williamson-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> > Updated quirk comment with requirement that aliases have to be matching > values programmed in the EEPROM. The LUT table on x200 is static so there > is no need to program it from the driver. > > drivers/pci/quirks.c | 14 ++++++++++++++ > 1 file changed, 14 insertions(+) > > diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c > index 51927a5..e66f09d 100644 > --- a/drivers/pci/quirks.c > +++ b/drivers/pci/quirks.c > @@ -3696,6 +3696,20 @@ DECLARE_PCI_FIXUP_HEADER(0x1283, 0x8892, quirk_use_pcie_bridge_dma_alias); > DECLARE_PCI_FIXUP_HEADER(0x8086, 0x244e, quirk_use_pcie_bridge_dma_alias); > > /* > + * MIC x200 NTB forwards PCIe traffic using multiple alien RIDs. They have to > + * be added as aliases to the DMA device in order to allow buffer access > + * when IOMMU is enabled. Following devfns have to match RIT-LUT table > + * programmed in the EEPROM. > + */ > +static void quirk_mic_x200_dma_alias(struct pci_dev *pdev) > +{ > + pci_add_dma_alias(pdev, PCI_DEVFN(0x10, 0x0)); > + pci_add_dma_alias(pdev, PCI_DEVFN(0x11, 0x0)); > + pci_add_dma_alias(pdev, PCI_DEVFN(0x12, 0x3)); > +} > +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2264, quirk_mic_x200_dma_alias); > + > +/* > * Intersil/Techwell TW686[4589]-based video capture cards have an empty (zero) > * class code. Fix it. > */ ^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v4 6/6] PCI: Squash pci_dev_flags to remove holes 2016-02-24 19:43 [PATCH v4 0/6] PCI: Support multiple DMA aliases Bjorn Helgaas ` (4 preceding siblings ...) [not found] ` <20160224193926.7585.10833.stgit-1RhO1Y9PlrlHTL0Zs8A6p/gx64E7kk8eUsxypvmhUTTZJqsBc5GL+g@public.gmane.org> @ 2016-02-24 19:44 ` Bjorn Helgaas 2016-04-08 20:19 ` Alex Williamson 2016-04-12 4:38 ` [PATCH v4 0/6] PCI: Support multiple DMA aliases Bjorn Helgaas 6 siblings, 1 reply; 28+ messages in thread From: Bjorn Helgaas @ 2016-02-24 19:44 UTC (permalink / raw) To: Jacek Lawrynowicz Cc: linux-pci, Alex Williamson, Joerg Roedel, David Woodhouse, iommu From: Jacek Lawrynowicz <jacek.lawrynowicz@intel.com> After removing PCI_DEV_FLAGS_DMA_ALIAS_DEVFN, the (1 << 4) value was unused. Squash the other values so all the bits are adjacent. No functional change intended. (I'm not sure this is worth doing. We have 16 flag bits and we're not even close to exhausting them. But if we do squash them, it should be in a separate patch so we don't clutter up the main patches.) --- include/linux/pci.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/pci.h b/include/linux/pci.h index d9e0c84..4e36024 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -173,13 +173,13 @@ enum pci_dev_flags { /* Flag for quirk use to store if quirk-specific ACS is enabled */ PCI_DEV_FLAGS_ACS_ENABLED_QUIRK = (__force pci_dev_flags_t) (1 << 3), /* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */ - PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 5), + PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 4), /* Do not use bus resets for device */ - PCI_DEV_FLAGS_NO_BUS_RESET = (__force pci_dev_flags_t) (1 << 6), + PCI_DEV_FLAGS_NO_BUS_RESET = (__force pci_dev_flags_t) (1 << 5), /* Do not use PM reset even if device advertises NoSoftRst- */ - PCI_DEV_FLAGS_NO_PM_RESET = (__force pci_dev_flags_t) (1 << 7), + PCI_DEV_FLAGS_NO_PM_RESET = (__force pci_dev_flags_t) (1 << 6), /* Get VPD from function 0 VPD */ - PCI_DEV_FLAGS_VPD_REF_F0 = (__force pci_dev_flags_t) (1 << 8), + PCI_DEV_FLAGS_VPD_REF_F0 = (__force pci_dev_flags_t) (1 << 7), }; enum pci_irq_reroute_variant { ^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [PATCH v4 6/6] PCI: Squash pci_dev_flags to remove holes 2016-02-24 19:44 ` [PATCH v4 6/6] PCI: Squash pci_dev_flags to remove holes Bjorn Helgaas @ 2016-04-08 20:19 ` Alex Williamson 0 siblings, 0 replies; 28+ messages in thread From: Alex Williamson @ 2016-04-08 20:19 UTC (permalink / raw) To: Bjorn Helgaas Cc: Jacek Lawrynowicz, linux-pci, Joerg Roedel, David Woodhouse, iommu On Wed, 24 Feb 2016 13:44:31 -0600 Bjorn Helgaas <bhelgaas@google.com> wrote: > From: Jacek Lawrynowicz <jacek.lawrynowicz@intel.com> > > After removing PCI_DEV_FLAGS_DMA_ALIAS_DEVFN, the (1 << 4) value was > unused. Squash the other values so all the bits are adjacent. No > functional change intended. > > (I'm not sure this is worth doing. We have 16 flag bits and we're not > even close to exhausting them. But if we do squash them, it should be > in a separate patch so we don't clutter up the main patches.) > --- Needs a Sign-off Reviewed-by: Alex Williamson <alex.williamson@redhat.com> > include/linux/pci.h | 8 ++++---- > 1 file changed, 4 insertions(+), 4 deletions(-) > > diff --git a/include/linux/pci.h b/include/linux/pci.h > index d9e0c84..4e36024 100644 > --- a/include/linux/pci.h > +++ b/include/linux/pci.h > @@ -173,13 +173,13 @@ enum pci_dev_flags { > /* Flag for quirk use to store if quirk-specific ACS is enabled */ > PCI_DEV_FLAGS_ACS_ENABLED_QUIRK = (__force pci_dev_flags_t) (1 << 3), > /* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */ > - PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 5), > + PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 4), > /* Do not use bus resets for device */ > - PCI_DEV_FLAGS_NO_BUS_RESET = (__force pci_dev_flags_t) (1 << 6), > + PCI_DEV_FLAGS_NO_BUS_RESET = (__force pci_dev_flags_t) (1 << 5), > /* Do not use PM reset even if device advertises NoSoftRst- */ > - PCI_DEV_FLAGS_NO_PM_RESET = (__force pci_dev_flags_t) (1 << 7), > + PCI_DEV_FLAGS_NO_PM_RESET = (__force pci_dev_flags_t) (1 << 6), > /* Get VPD from function 0 VPD */ > - PCI_DEV_FLAGS_VPD_REF_F0 = (__force pci_dev_flags_t) (1 << 8), > + PCI_DEV_FLAGS_VPD_REF_F0 = (__force pci_dev_flags_t) (1 << 7), > }; > > enum pci_irq_reroute_variant { > ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4 0/6] PCI: Support multiple DMA aliases 2016-02-24 19:43 [PATCH v4 0/6] PCI: Support multiple DMA aliases Bjorn Helgaas ` (5 preceding siblings ...) 2016-02-24 19:44 ` [PATCH v4 6/6] PCI: Squash pci_dev_flags to remove holes Bjorn Helgaas @ 2016-04-12 4:38 ` Bjorn Helgaas 2016-04-12 16:20 ` Lawrynowicz, Jacek 2016-04-12 18:10 ` Bjorn Helgaas 6 siblings, 2 replies; 28+ messages in thread From: Bjorn Helgaas @ 2016-04-12 4:38 UTC (permalink / raw) To: Bjorn Helgaas Cc: Jacek Lawrynowicz, linux-pci, Alex Williamson, Joerg Roedel, David Woodhouse, iommu On Wed, Feb 24, 2016 at 01:43:32PM -0600, Bjorn Helgaas wrote: > This is a revision of Jacek's v3 posting: > http://lkml.kernel.org/r/1454152012-46337-1-git-send-email-jacek.lawrynowicz@intel.com > > The changes from v3 are: > > - Split into smaller patches for reviewability > - Move printk when adding DMA alias > - Change dma_alias_is_enabled() interface to take two pci_devs > - Rename dma_alias_is_enabled() to indicate PCI context > > The only remaining thing I want to sort out is the dma_alias_is_enabled() > vs pci_for_each_dma_alias() question Alex raised. I'll respond to the > relevant part of the patch in this series with my specific questions. > > --- > > Bjorn Helgaas (1): > PCI: Rename dma_alias_is_enabled() to pci_devs_are_dma_aliases() > > Jacek Lawrynowicz (5): > PCI: Add pci_add_dma_alias() to abstract implementation > PCI: Move informational printk to pci_add_dma_alias() > PCI: Add support for multiple DMA aliases > pci: Add DMA alias quirk for mic_x200_dma > PCI: Squash pci_dev_flags to remove holes I applied this series to pci/ntb for v4.7. It got a little confusing with v5 versions of a couple patches posted, and a couple issues Alex found, so here's the series as applied: commit f0af9593372abfde34460aa1250e670cc535a7d8 Author: Bjorn Helgaas <bhelgaas@google.com> Date: Wed Feb 24 13:43:45 2016 -0600 PCI: Add pci_add_dma_alias() to abstract implementation Add a pci_add_dma_alias() interface to encapsulate the details of adding an alias. No functional change intended. Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Alex Williamson <alex.williamson@redhat.com> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 25e0327..1162118 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4578,6 +4578,20 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode, return 0; } +/** + * pci_add_dma_alias - Add a DMA devfn alias for a device + * @dev: the PCI device for which alias is added + * @devfn: alias slot and function + * + * This helper encodes 8-bit devfn as bit number in dma_alias_mask. + * It should be called early, preferably as PCI fixup header quirk. + */ +void pci_add_dma_alias(struct pci_dev *dev, u8 devfn) +{ + dev->dma_alias_devfn = devfn; + dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; +} + bool pci_device_is_present(struct pci_dev *pdev) { u32 v; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 8e67802..e45a7a8 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3610,10 +3610,8 @@ int pci_dev_specific_reset(struct pci_dev *dev, int probe) static void quirk_dma_func0_alias(struct pci_dev *dev) { - if (PCI_FUNC(dev->devfn) != 0) { - dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0); - dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; - } + if (PCI_FUNC(dev->devfn) != 0) + pci_add_dma_alias(dev, PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); } /* @@ -3626,10 +3624,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RICOH, 0xe476, quirk_dma_func0_alias); static void quirk_dma_func1_alias(struct pci_dev *dev) { - if (PCI_FUNC(dev->devfn) != 1) { - dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 1); - dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; - } + if (PCI_FUNC(dev->devfn) != 1) + pci_add_dma_alias(dev, PCI_DEVFN(PCI_SLOT(dev->devfn), 1)); } /* @@ -3696,11 +3692,10 @@ static void quirk_fixed_dma_alias(struct pci_dev *dev) id = pci_match_id(fixed_dma_alias_tbl, dev); if (id) { - dev->dma_alias_devfn = id->driver_data; - dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; + pci_add_dma_alias(dev, id->driver_data); dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n", - PCI_SLOT(dev->dma_alias_devfn), - PCI_FUNC(dev->dma_alias_devfn)); + PCI_SLOT(id->driver_data), + PCI_FUNC(id->driver_data)); } } diff --git a/include/linux/pci.h b/include/linux/pci.h index 004b813..7e70190 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1988,6 +1988,7 @@ static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev) } #endif +void pci_add_dma_alias(struct pci_dev *dev, u8 devfn); int pci_for_each_dma_alias(struct pci_dev *pdev, int (*fn)(struct pci_dev *pdev, u16 alias, void *data), void *data); commit 48c830809ce6e143781172c03a9794cb66802b31 Author: Bjorn Helgaas <bhelgaas@google.com> Date: Wed Feb 24 13:43:54 2016 -0600 PCI: Move informational printk to pci_add_dma_alias() One of the quirks that adds DMA aliases logs an informational message in dmesg. Move that to pci_add_dma_alias() so all users log the message consistently. No functional change intended (except extra message). Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Alex Williamson <alex.williamson@redhat.com> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 1162118..c82ebd0 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4590,6 +4590,8 @@ void pci_add_dma_alias(struct pci_dev *dev, u8 devfn) { dev->dma_alias_devfn = devfn; dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; + dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n", + PCI_SLOT(devfn), PCI_FUNC(devfn)); } bool pci_device_is_present(struct pci_dev *pdev) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e45a7a8..7559e40 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3691,12 +3691,8 @@ static void quirk_fixed_dma_alias(struct pci_dev *dev) const struct pci_device_id *id; id = pci_match_id(fixed_dma_alias_tbl, dev); - if (id) { + if (id) pci_add_dma_alias(dev, id->driver_data); - dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n", - PCI_SLOT(id->driver_data), - PCI_FUNC(id->driver_data)); - } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ADAPTEC2, 0x0285, quirk_fixed_dma_alias); commit 338c3149a221527e202ee26b1e35f76c965bb6c0 Author: Jacek Lawrynowicz <jacek.lawrynowicz@intel.com> Date: Thu Mar 3 15:38:02 2016 +0100 PCI: Add support for multiple DMA aliases Solve IOMMU support issues with PCIe non-transparent bridges that use Requester ID look-up tables (RID-LUT), e.g., the PEX8733. The NTB connects devices in two independent PCI domains. Devices separated by the NTB are not able to discover each other. A PCI packet being forwared from one domain to another has to have its RID modified so it appears on correct bus and completions are forwarded back to the original domain through the NTB. The RID is translated using a preprogrammed table (LUT) and the PCI packet propagates upstream away from the NTB. If the destination system has IOMMU enabled, the packet will be discarded because the new RID is unknown to the IOMMU. Adding a DMA alias for the new RID allows IOMMU to properly recognize the packet. Each device behind the NTB has a unique RID assigned in the RID-LUT. The current DMA alias implementation supports only a single alias, so it's not possible to support mutiple devices behind the NTB when IOMMU is enabled. Enable all possible aliases on a given bus (256) that are stored in a bitset. Alias devfn is directly translated to a bit number. The bitset is not allocated for devices that have no need for DMA aliases. More details can be found in the following article: http://www.plxtech.com/files/pdf/technical/expresslane/RTC_Enabling%20MulitHostSystemDesigns.pdf Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz@intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Alex Williamson <alex.williamson@redhat.com> Acked-by: David Woodhouse <David.Woodhouse@intel.com> Acked-by: Joerg Roedel <jroedel@suse.de> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index bfd4f7c..1b49e94 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -660,8 +660,8 @@ static struct iommu_group *get_pci_function_alias_group(struct pci_dev *pdev, } /* - * Look for aliases to or from the given device for exisiting groups. The - * dma_alias_devfn only supports aliases on the same bus, therefore the search + * Look for aliases to or from the given device for existing groups. DMA + * aliases are only supported on the same bus, therefore the search * space is quite small (especially since we're really only looking at pcie * device, and therefore only expect multiple slots on the root complex or * downstream switch ports). It's conceivable though that a pair of @@ -686,11 +686,7 @@ static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev, continue; /* We alias them or they alias us */ - if (((pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && - pdev->dma_alias_devfn == tmp->devfn) || - ((tmp->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && - tmp->dma_alias_devfn == pdev->devfn)) { - + if (pci_devs_are_dma_aliases(pdev, tmp)) { group = get_pci_alias_group(tmp, devfns); if (group) { pci_dev_put(tmp); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index c82ebd0..0b90c21 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4588,12 +4588,27 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode, */ void pci_add_dma_alias(struct pci_dev *dev, u8 devfn) { - dev->dma_alias_devfn = devfn; - dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; + if (!dev->dma_alias_mask) + dev->dma_alias_mask = kcalloc(BITS_TO_LONGS(U8_MAX), + sizeof(long), GFP_KERNEL); + if (!dev->dma_alias_mask) { + dev_warn(&dev->dev, "Unable to allocate DMA alias mask\n"); + return; + } + + set_bit(devfn, dev->dma_alias_mask); dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n", PCI_SLOT(devfn), PCI_FUNC(devfn)); } +bool pci_devs_are_dma_aliases(struct pci_dev *dev1, struct pci_dev *dev2) +{ + return (dev1->dma_alias_mask && + test_bit(dev2->devfn, dev1->dma_alias_mask)) || + (dev2->dma_alias_mask && + test_bit(dev1->devfn, dev2->dma_alias_mask)); +} + bool pci_device_is_present(struct pci_dev *pdev) { u32 v; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 8004f67..ae7daeb 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1537,6 +1537,7 @@ static void pci_release_dev(struct device *dev) pcibios_release_device(pci_dev); pci_bus_put(pci_dev->bus); kfree(pci_dev->driver_override); + kfree(pci_dev->dma_alias_mask); kfree(pci_dev); } diff --git a/drivers/pci/search.c b/drivers/pci/search.c index a20ce7d..33e0f03 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -40,11 +40,15 @@ int pci_for_each_dma_alias(struct pci_dev *pdev, * If the device is broken and uses an alias requester ID for * DMA, iterate over that too. */ - if (unlikely(pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN)) { - ret = fn(pdev, PCI_DEVID(pdev->bus->number, - pdev->dma_alias_devfn), data); - if (ret) - return ret; + if (unlikely(pdev->dma_alias_mask)) { + u8 devfn; + + for_each_set_bit(devfn, pdev->dma_alias_mask, U8_MAX) { + ret = fn(pdev, PCI_DEVID(pdev->bus->number, devfn), + data); + if (ret) + return ret; + } } for (bus = pdev->bus; !pci_is_root_bus(bus); bus = bus->parent) { diff --git a/include/linux/pci.h b/include/linux/pci.h index 7e70190..5581d05 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -166,8 +166,6 @@ enum pci_dev_flags { PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) (1 << 2), /* Flag for quirk use to store if quirk-specific ACS is enabled */ PCI_DEV_FLAGS_ACS_ENABLED_QUIRK = (__force pci_dev_flags_t) (1 << 3), - /* Flag to indicate the device uses dma_alias_devfn */ - PCI_DEV_FLAGS_DMA_ALIAS_DEVFN = (__force pci_dev_flags_t) (1 << 4), /* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */ PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 5), /* Do not use bus resets for device */ @@ -273,7 +271,7 @@ struct pci_dev { u8 rom_base_reg; /* which config register controls the ROM */ u8 pin; /* which interrupt pin this device uses */ u16 pcie_flags_reg; /* cached PCIe Capabilities Register */ - u8 dma_alias_devfn;/* devfn of DMA alias, if any */ + unsigned long *dma_alias_mask;/* mask of enabled devfn aliases */ struct pci_driver *driver; /* which driver has allocated this device */ u64 dma_mask; /* Mask of the bits of bus address this @@ -1989,6 +1987,7 @@ static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev) #endif void pci_add_dma_alias(struct pci_dev *dev, u8 devfn); +bool pci_devs_are_dma_aliases(struct pci_dev *dev1, struct pci_dev *dev2); int pci_for_each_dma_alias(struct pci_dev *pdev, int (*fn)(struct pci_dev *pdev, u16 alias, void *data), void *data); commit 8e6b62b5dc00bee0bd1f6fada928969159b8083a Author: Jacek Lawrynowicz <jacek.lawrynowicz@intel.com> Date: Thu Mar 3 15:53:20 2016 +0100 PCI: Add DMA alias quirk for mic_x200_dma The MIC x200 NTB forwards DMA transactions upstream using multiple alien RIDs. These RIDs have to be added as aliases to the DMA device to allow buffer access when the IOMMU is enabled. Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz@intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Alex Williamson <alex.williamson@redhat.com> Acked-by: David Woodhouse <David.Woodhouse@intel.com> diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 7559e40..5cccc78 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3725,6 +3725,20 @@ DECLARE_PCI_FIXUP_HEADER(0x1283, 0x8892, quirk_use_pcie_bridge_dma_alias); DECLARE_PCI_FIXUP_HEADER(0x8086, 0x244e, quirk_use_pcie_bridge_dma_alias); /* + * MIC x200 NTB forwards PCIe traffic using multiple alien RIDs. They have to + * be added as aliases to the DMA device in order to allow buffer access + * when IOMMU is enabled. Following devfns have to match RIT-LUT table + * programmed in the EEPROM. + */ +static void quirk_mic_x200_dma_alias(struct pci_dev *pdev) +{ + pci_add_dma_alias(pdev, PCI_DEVFN(0x10, 0x0)); + pci_add_dma_alias(pdev, PCI_DEVFN(0x11, 0x0)); + pci_add_dma_alias(pdev, PCI_DEVFN(0x12, 0x3)); +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2264, quirk_mic_x200_dma_alias); + +/* * Intersil/Techwell TW686[4589]-based video capture cards have an empty (zero) * class code. Fix it. */ ^ permalink raw reply related [flat|nested] 28+ messages in thread
* RE: [PATCH v4 0/6] PCI: Support multiple DMA aliases 2016-04-12 4:38 ` [PATCH v4 0/6] PCI: Support multiple DMA aliases Bjorn Helgaas @ 2016-04-12 16:20 ` Lawrynowicz, Jacek 2016-04-12 18:10 ` Bjorn Helgaas 1 sibling, 0 replies; 28+ messages in thread From: Lawrynowicz, Jacek @ 2016-04-12 16:20 UTC (permalink / raw) To: Bjorn Helgaas, Bjorn Helgaas Cc: linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Joerg Roedel, David Woodhouse, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org [-- Attachment #1.1.1: Type: text/plain, Size: 16615 bytes --] Great, thanks! I tested pci/ntb tree and it works but I had to add another PCI ID. Would it be a problem to add second PCI ID to the x200 quirk in this patch set? I attached a patch with additional line. Regards, Jacek > -----Original Message----- > From: Bjorn Helgaas [mailto:helgaas-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org] > Sent: Tuesday, April 12, 2016 6:38 AM > To: Bjorn Helgaas <bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> > Cc: Lawrynowicz, Jacek <jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>; linux- > pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; Alex Williamson <alex.williamson-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>; Joerg > Roedel <jroedel-l3A5Bk7waGM@public.gmane.org>; David Woodhouse <dwmw2-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>; > iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org > Subject: Re: [PATCH v4 0/6] PCI: Support multiple DMA aliases > > On Wed, Feb 24, 2016 at 01:43:32PM -0600, Bjorn Helgaas wrote: > > This is a revision of Jacek's v3 posting: > > http://lkml.kernel.org/r/1454152012-46337-1-git-send-email- > jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org > > > > The changes from v3 are: > > > > - Split into smaller patches for reviewability > > - Move printk when adding DMA alias > > - Change dma_alias_is_enabled() interface to take two pci_devs > > - Rename dma_alias_is_enabled() to indicate PCI context > > > > The only remaining thing I want to sort out is the dma_alias_is_enabled() > > vs pci_for_each_dma_alias() question Alex raised. I'll respond to the > > relevant part of the patch in this series with my specific questions. > > > > --- > > > > Bjorn Helgaas (1): > > PCI: Rename dma_alias_is_enabled() to pci_devs_are_dma_aliases() > > > > Jacek Lawrynowicz (5): > > PCI: Add pci_add_dma_alias() to abstract implementation > > PCI: Move informational printk to pci_add_dma_alias() > > PCI: Add support for multiple DMA aliases > > pci: Add DMA alias quirk for mic_x200_dma > > PCI: Squash pci_dev_flags to remove holes > > I applied this series to pci/ntb for v4.7. It got a little confusing > with v5 versions of a couple patches posted, and a couple issues Alex > found, so here's the series as applied: > > commit f0af9593372abfde34460aa1250e670cc535a7d8 > Author: Bjorn Helgaas <bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> > Date: Wed Feb 24 13:43:45 2016 -0600 > > PCI: Add pci_add_dma_alias() to abstract implementation > > Add a pci_add_dma_alias() interface to encapsulate the details of adding an > alias. No functional change intended. > > Signed-off-by: Bjorn Helgaas <bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> > Reviewed-by: Alex Williamson <alex.williamson-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> > > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c > index 25e0327..1162118 100644 > --- a/drivers/pci/pci.c > +++ b/drivers/pci/pci.c > @@ -4578,6 +4578,20 @@ int pci_set_vga_state(struct pci_dev *dev, bool > decode, > return 0; > } > > +/** > + * pci_add_dma_alias - Add a DMA devfn alias for a device > + * @dev: the PCI device for which alias is added > + * @devfn: alias slot and function > + * > + * This helper encodes 8-bit devfn as bit number in dma_alias_mask. > + * It should be called early, preferably as PCI fixup header quirk. > + */ > +void pci_add_dma_alias(struct pci_dev *dev, u8 devfn) > +{ > + dev->dma_alias_devfn = devfn; > + dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; > +} > + > bool pci_device_is_present(struct pci_dev *pdev) > { > u32 v; > diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c > index 8e67802..e45a7a8 100644 > --- a/drivers/pci/quirks.c > +++ b/drivers/pci/quirks.c > @@ -3610,10 +3610,8 @@ int pci_dev_specific_reset(struct pci_dev *dev, int > probe) > > static void quirk_dma_func0_alias(struct pci_dev *dev) > { > - if (PCI_FUNC(dev->devfn) != 0) { > - dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0); > - dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; > - } > + if (PCI_FUNC(dev->devfn) != 0) > + pci_add_dma_alias(dev, PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); > } > > /* > @@ -3626,10 +3624,8 @@ > DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RICOH, 0xe476, > quirk_dma_func0_alias); > > static void quirk_dma_func1_alias(struct pci_dev *dev) > { > - if (PCI_FUNC(dev->devfn) != 1) { > - dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 1); > - dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; > - } > + if (PCI_FUNC(dev->devfn) != 1) > + pci_add_dma_alias(dev, PCI_DEVFN(PCI_SLOT(dev->devfn), 1)); > } > > /* > @@ -3696,11 +3692,10 @@ static void quirk_fixed_dma_alias(struct pci_dev > *dev) > > id = pci_match_id(fixed_dma_alias_tbl, dev); > if (id) { > - dev->dma_alias_devfn = id->driver_data; > - dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; > + pci_add_dma_alias(dev, id->driver_data); > dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n", > - PCI_SLOT(dev->dma_alias_devfn), > - PCI_FUNC(dev->dma_alias_devfn)); > + PCI_SLOT(id->driver_data), > + PCI_FUNC(id->driver_data)); > } > } > > diff --git a/include/linux/pci.h b/include/linux/pci.h > index 004b813..7e70190 100644 > --- a/include/linux/pci.h > +++ b/include/linux/pci.h > @@ -1988,6 +1988,7 @@ static inline struct eeh_dev > *pci_dev_to_eeh_dev(struct pci_dev *pdev) > } > #endif > > +void pci_add_dma_alias(struct pci_dev *dev, u8 devfn); > int pci_for_each_dma_alias(struct pci_dev *pdev, > int (*fn)(struct pci_dev *pdev, > u16 alias, void *data), void *data); > > commit 48c830809ce6e143781172c03a9794cb66802b31 > Author: Bjorn Helgaas <bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> > Date: Wed Feb 24 13:43:54 2016 -0600 > > PCI: Move informational printk to pci_add_dma_alias() > > One of the quirks that adds DMA aliases logs an informational message in > dmesg. Move that to pci_add_dma_alias() so all users log the message > consistently. No functional change intended (except extra message). > > Signed-off-by: Bjorn Helgaas <bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> > Reviewed-by: Alex Williamson <alex.williamson-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> > > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c > index 1162118..c82ebd0 100644 > --- a/drivers/pci/pci.c > +++ b/drivers/pci/pci.c > @@ -4590,6 +4590,8 @@ void pci_add_dma_alias(struct pci_dev *dev, u8 devfn) > { > dev->dma_alias_devfn = devfn; > dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; > + dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n", > + PCI_SLOT(devfn), PCI_FUNC(devfn)); > } > > bool pci_device_is_present(struct pci_dev *pdev) > diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c > index e45a7a8..7559e40 100644 > --- a/drivers/pci/quirks.c > +++ b/drivers/pci/quirks.c > @@ -3691,12 +3691,8 @@ static void quirk_fixed_dma_alias(struct pci_dev *dev) > const struct pci_device_id *id; > > id = pci_match_id(fixed_dma_alias_tbl, dev); > - if (id) { > + if (id) > pci_add_dma_alias(dev, id->driver_data); > - dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n", > - PCI_SLOT(id->driver_data), > - PCI_FUNC(id->driver_data)); > - } > } > > DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ADAPTEC2, 0x0285, > quirk_fixed_dma_alias); > > commit 338c3149a221527e202ee26b1e35f76c965bb6c0 > Author: Jacek Lawrynowicz <jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> > Date: Thu Mar 3 15:38:02 2016 +0100 > > PCI: Add support for multiple DMA aliases > > Solve IOMMU support issues with PCIe non-transparent bridges that use > Requester ID look-up tables (RID-LUT), e.g., the PEX8733. > > The NTB connects devices in two independent PCI domains. Devices separated > by the NTB are not able to discover each other. A PCI packet being > forwared from one domain to another has to have its RID modified so it > appears on correct bus and completions are forwarded back to the original > domain through the NTB. The RID is translated using a preprogrammed table > (LUT) and the PCI packet propagates upstream away from the NTB. If the > destination system has IOMMU enabled, the packet will be discarded because > the new RID is unknown to the IOMMU. Adding a DMA alias for the new RID > allows IOMMU to properly recognize the packet. > > Each device behind the NTB has a unique RID assigned in the RID-LUT. The > current DMA alias implementation supports only a single alias, so it's not > possible to support mutiple devices behind the NTB when IOMMU is enabled. > > Enable all possible aliases on a given bus (256) that are stored in a > bitset. Alias devfn is directly translated to a bit number. The bitset is > not allocated for devices that have no need for DMA aliases. > > More details can be found in the following article: > > http://www.plxtech.com/files/pdf/technical/expresslane/RTC_Enabling%20Muli > tHostSystemDesigns.pdf > > Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> > Signed-off-by: Bjorn Helgaas <bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> > Reviewed-by: Alex Williamson <alex.williamson-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> > Acked-by: David Woodhouse <David.Woodhouse-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> > Acked-by: Joerg Roedel <jroedel-l3A5Bk7waGM@public.gmane.org> > > diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c > index bfd4f7c..1b49e94 100644 > --- a/drivers/iommu/iommu.c > +++ b/drivers/iommu/iommu.c > @@ -660,8 +660,8 @@ static struct iommu_group > *get_pci_function_alias_group(struct pci_dev *pdev, > } > > /* > - * Look for aliases to or from the given device for exisiting groups. The > - * dma_alias_devfn only supports aliases on the same bus, therefore the search > + * Look for aliases to or from the given device for existing groups. DMA > + * aliases are only supported on the same bus, therefore the search > * space is quite small (especially since we're really only looking at pcie > * device, and therefore only expect multiple slots on the root complex or > * downstream switch ports). It's conceivable though that a pair of > @@ -686,11 +686,7 @@ static struct iommu_group *get_pci_alias_group(struct > pci_dev *pdev, > continue; > > /* We alias them or they alias us */ > - if (((pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) > && > - pdev->dma_alias_devfn == tmp->devfn) || > - ((tmp->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN) && > - tmp->dma_alias_devfn == pdev->devfn)) { > - > + if (pci_devs_are_dma_aliases(pdev, tmp)) { > group = get_pci_alias_group(tmp, devfns); > if (group) { > pci_dev_put(tmp); > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c > index c82ebd0..0b90c21 100644 > --- a/drivers/pci/pci.c > +++ b/drivers/pci/pci.c > @@ -4588,12 +4588,27 @@ int pci_set_vga_state(struct pci_dev *dev, bool > decode, > */ > void pci_add_dma_alias(struct pci_dev *dev, u8 devfn) > { > - dev->dma_alias_devfn = devfn; > - dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; > + if (!dev->dma_alias_mask) > + dev->dma_alias_mask = kcalloc(BITS_TO_LONGS(U8_MAX), > + sizeof(long), GFP_KERNEL); > + if (!dev->dma_alias_mask) { > + dev_warn(&dev->dev, "Unable to allocate DMA alias mask\n"); > + return; > + } > + > + set_bit(devfn, dev->dma_alias_mask); > dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n", > PCI_SLOT(devfn), PCI_FUNC(devfn)); > } > > +bool pci_devs_are_dma_aliases(struct pci_dev *dev1, struct pci_dev *dev2) > +{ > + return (dev1->dma_alias_mask && > + test_bit(dev2->devfn, dev1->dma_alias_mask)) || > + (dev2->dma_alias_mask && > + test_bit(dev1->devfn, dev2->dma_alias_mask)); > +} > + > bool pci_device_is_present(struct pci_dev *pdev) > { > u32 v; > diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c > index 8004f67..ae7daeb 100644 > --- a/drivers/pci/probe.c > +++ b/drivers/pci/probe.c > @@ -1537,6 +1537,7 @@ static void pci_release_dev(struct device *dev) > pcibios_release_device(pci_dev); > pci_bus_put(pci_dev->bus); > kfree(pci_dev->driver_override); > + kfree(pci_dev->dma_alias_mask); > kfree(pci_dev); > } > > diff --git a/drivers/pci/search.c b/drivers/pci/search.c > index a20ce7d..33e0f03 100644 > --- a/drivers/pci/search.c > +++ b/drivers/pci/search.c > @@ -40,11 +40,15 @@ int pci_for_each_dma_alias(struct pci_dev *pdev, > * If the device is broken and uses an alias requester ID for > * DMA, iterate over that too. > */ > - if (unlikely(pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN)) { > - ret = fn(pdev, PCI_DEVID(pdev->bus->number, > - pdev->dma_alias_devfn), data); > - if (ret) > - return ret; > + if (unlikely(pdev->dma_alias_mask)) { > + u8 devfn; > + > + for_each_set_bit(devfn, pdev->dma_alias_mask, U8_MAX) { > + ret = fn(pdev, PCI_DEVID(pdev->bus->number, devfn), > + data); > + if (ret) > + return ret; > + } > } > > for (bus = pdev->bus; !pci_is_root_bus(bus); bus = bus->parent) { > diff --git a/include/linux/pci.h b/include/linux/pci.h > index 7e70190..5581d05 100644 > --- a/include/linux/pci.h > +++ b/include/linux/pci.h > @@ -166,8 +166,6 @@ enum pci_dev_flags { > PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) (1 << 2), > /* Flag for quirk use to store if quirk-specific ACS is enabled */ > PCI_DEV_FLAGS_ACS_ENABLED_QUIRK = (__force pci_dev_flags_t) (1 > << 3), > - /* Flag to indicate the device uses dma_alias_devfn */ > - PCI_DEV_FLAGS_DMA_ALIAS_DEVFN = (__force pci_dev_flags_t) (1 << > 4), > /* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */ > PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << > 5), > /* Do not use bus resets for device */ > @@ -273,7 +271,7 @@ struct pci_dev { > u8 rom_base_reg; /* which config register controls > the ROM */ > u8 pin; /* which interrupt pin this device uses */ > u16 pcie_flags_reg; /* cached PCIe Capabilities > Register */ > - u8 dma_alias_devfn;/* devfn of DMA alias, if any */ > + unsigned long *dma_alias_mask;/* mask of enabled devfn aliases */ > > struct pci_driver *driver; /* which driver has allocated this device */ > u64 dma_mask; /* Mask of the bits of bus address this > @@ -1989,6 +1987,7 @@ static inline struct eeh_dev > *pci_dev_to_eeh_dev(struct pci_dev *pdev) > #endif > > void pci_add_dma_alias(struct pci_dev *dev, u8 devfn); > +bool pci_devs_are_dma_aliases(struct pci_dev *dev1, struct pci_dev *dev2); > int pci_for_each_dma_alias(struct pci_dev *pdev, > int (*fn)(struct pci_dev *pdev, > u16 alias, void *data), void *data); > > commit 8e6b62b5dc00bee0bd1f6fada928969159b8083a > Author: Jacek Lawrynowicz <jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> > Date: Thu Mar 3 15:53:20 2016 +0100 > > PCI: Add DMA alias quirk for mic_x200_dma > > The MIC x200 NTB forwards DMA transactions upstream using multiple alien > RIDs. These RIDs have to be added as aliases to the DMA device to allow > buffer access when the IOMMU is enabled. > > Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> > Signed-off-by: Bjorn Helgaas <bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> > Reviewed-by: Alex Williamson <alex.williamson-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> > Acked-by: David Woodhouse <David.Woodhouse-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> > > diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c > index 7559e40..5cccc78 100644 > --- a/drivers/pci/quirks.c > +++ b/drivers/pci/quirks.c > @@ -3725,6 +3725,20 @@ DECLARE_PCI_FIXUP_HEADER(0x1283, 0x8892, > quirk_use_pcie_bridge_dma_alias); > DECLARE_PCI_FIXUP_HEADER(0x8086, 0x244e, > quirk_use_pcie_bridge_dma_alias); > > /* > + * MIC x200 NTB forwards PCIe traffic using multiple alien RIDs. They have to > + * be added as aliases to the DMA device in order to allow buffer access > + * when IOMMU is enabled. Following devfns have to match RIT-LUT table > + * programmed in the EEPROM. > + */ > +static void quirk_mic_x200_dma_alias(struct pci_dev *pdev) > +{ > + pci_add_dma_alias(pdev, PCI_DEVFN(0x10, 0x0)); > + pci_add_dma_alias(pdev, PCI_DEVFN(0x11, 0x0)); > + pci_add_dma_alias(pdev, PCI_DEVFN(0x12, 0x3)); > +} > +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2264, > quirk_mic_x200_dma_alias); > + > +/* > * Intersil/Techwell TW686[4589]-based video capture cards have an empty > (zero) > * class code. Fix it. > */ [-- Attachment #1.1.2: 0001-PCI-Add-DMA-alias-quirk-for-mic_x200_dma.patch --] [-- Type: application/octet-stream, Size: 2001 bytes --] >From 2c4c6ae7e915290f8b432f0fca9c77b03bc63609 Mon Sep 17 00:00:00 2001 From: Jacek Lawrynowicz <jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> Date: Thu, 3 Mar 2016 15:53:20 +0100 Subject: [PATCH] PCI: Add DMA alias quirk for mic_x200_dma The MIC x200 NTB forwards DMA transactions upstream using multiple alien RIDs. These RIDs have to be added as aliases to the DMA device to allow buffer access when the IOMMU is enabled. Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> Signed-off-by: Bjorn Helgaas <bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> Reviewed-by: Alex Williamson <alex.williamson-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> Acked-by: David Woodhouse <David.Woodhouse-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> --- drivers/pci/quirks.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 7559e40..8889ac4 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3725,6 +3725,21 @@ DECLARE_PCI_FIXUP_HEADER(0x1283, 0x8892, quirk_use_pcie_bridge_dma_alias); DECLARE_PCI_FIXUP_HEADER(0x8086, 0x244e, quirk_use_pcie_bridge_dma_alias); /* + * MIC x200 NTB forwards PCIe traffic using multiple alien RIDs. They have to + * be added as aliases to the DMA device in order to allow buffer access + * when IOMMU is enabled. Following devfns have to match RIT-LUT table + * programmed in the EEPROM. + */ +static void quirk_mic_x200_dma_alias(struct pci_dev *pdev) +{ + pci_add_dma_alias(pdev, PCI_DEVFN(0x10, 0x0)); + pci_add_dma_alias(pdev, PCI_DEVFN(0x11, 0x0)); + pci_add_dma_alias(pdev, PCI_DEVFN(0x12, 0x3)); +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2260, quirk_mic_x200_dma_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2264, quirk_mic_x200_dma_alias); + +/* * Intersil/Techwell TW686[4589]-based video capture cards have an empty (zero) * class code. Fix it. */ -- 1.8.3.1 [-- Attachment #1.2: smime.p7s --] [-- Type: application/pkcs7-signature, Size: 7756 bytes --] [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [PATCH v4 0/6] PCI: Support multiple DMA aliases 2016-04-12 4:38 ` [PATCH v4 0/6] PCI: Support multiple DMA aliases Bjorn Helgaas 2016-04-12 16:20 ` Lawrynowicz, Jacek @ 2016-04-12 18:10 ` Bjorn Helgaas 1 sibling, 0 replies; 28+ messages in thread From: Bjorn Helgaas @ 2016-04-12 18:10 UTC (permalink / raw) To: Bjorn Helgaas Cc: Jacek Lawrynowicz, linux-pci, Alex Williamson, Joerg Roedel, David Woodhouse, iommu On Mon, Apr 11, 2016 at 11:38:28PM -0500, Bjorn Helgaas wrote: > On Wed, Feb 24, 2016 at 01:43:32PM -0600, Bjorn Helgaas wrote: > > This is a revision of Jacek's v3 posting: > > http://lkml.kernel.org/r/1454152012-46337-1-git-send-email-jacek.lawrynowicz@intel.com > > > > The changes from v3 are: > > > > - Split into smaller patches for reviewability > > - Move printk when adding DMA alias > > - Change dma_alias_is_enabled() interface to take two pci_devs > > - Rename dma_alias_is_enabled() to indicate PCI context > > > > The only remaining thing I want to sort out is the dma_alias_is_enabled() > > vs pci_for_each_dma_alias() question Alex raised. I'll respond to the > > relevant part of the patch in this series with my specific questions. > > > > --- > > > > Bjorn Helgaas (1): > > PCI: Rename dma_alias_is_enabled() to pci_devs_are_dma_aliases() > > > > Jacek Lawrynowicz (5): > > PCI: Add pci_add_dma_alias() to abstract implementation > > PCI: Move informational printk to pci_add_dma_alias() > > PCI: Add support for multiple DMA aliases > > pci: Add DMA alias quirk for mic_x200_dma > > PCI: Squash pci_dev_flags to remove holes > > I applied this series to pci/ntb for v4.7. Jacek sent another patch to add a second PCI ID. I don't see it on the list, probably because it's got too much fancy encoding. I applied it, so the last patch now looks like this: commit b1a928cdb477037fb7c10fbf94c47f65f2bcce77 Author: Jacek Lawrynowicz <jacek.lawrynowicz@intel.com> Date: Thu Mar 3 15:53:20 2016 +0100 PCI: Add DMA alias quirk for mic_x200_dma The MIC x200 NTB forwards DMA transactions upstream using multiple alien RIDs. These RIDs have to be added as aliases to the DMA device to allow buffer access when the IOMMU is enabled. Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz@intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Alex Williamson <alex.williamson@redhat.com> Acked-by: David Woodhouse <David.Woodhouse@intel.com> diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 7559e40..8889ac4 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3725,6 +3725,21 @@ DECLARE_PCI_FIXUP_HEADER(0x1283, 0x8892, quirk_use_pcie_bridge_dma_alias); DECLARE_PCI_FIXUP_HEADER(0x8086, 0x244e, quirk_use_pcie_bridge_dma_alias); /* + * MIC x200 NTB forwards PCIe traffic using multiple alien RIDs. They have to + * be added as aliases to the DMA device in order to allow buffer access + * when IOMMU is enabled. Following devfns have to match RIT-LUT table + * programmed in the EEPROM. + */ +static void quirk_mic_x200_dma_alias(struct pci_dev *pdev) +{ + pci_add_dma_alias(pdev, PCI_DEVFN(0x10, 0x0)); + pci_add_dma_alias(pdev, PCI_DEVFN(0x11, 0x0)); + pci_add_dma_alias(pdev, PCI_DEVFN(0x12, 0x3)); +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2260, quirk_mic_x200_dma_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2264, quirk_mic_x200_dma_alias); + +/* * Intersil/Techwell TW686[4589]-based video capture cards have an empty (zero) * class code. Fix it. */ ^ permalink raw reply related [flat|nested] 28+ messages in thread
end of thread, other threads:[~2016-04-12 18:10 UTC | newest] Thread overview: 28+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2016-02-24 19:43 [PATCH v4 0/6] PCI: Support multiple DMA aliases Bjorn Helgaas 2016-02-24 19:43 ` [PATCH v4 1/6] PCI: Add pci_add_dma_alias() to abstract implementation Bjorn Helgaas [not found] ` <20160224194345.7585.20639.stgit-1RhO1Y9PlrlHTL0Zs8A6p/gx64E7kk8eUsxypvmhUTTZJqsBc5GL+g@public.gmane.org> 2016-04-08 20:18 ` Alex Williamson 2016-02-24 19:43 ` [PATCH v4 2/6] PCI: Move informational printk to pci_add_dma_alias() Bjorn Helgaas [not found] ` <20160224194354.7585.30654.stgit-1RhO1Y9PlrlHTL0Zs8A6p/gx64E7kk8eUsxypvmhUTTZJqsBc5GL+g@public.gmane.org> 2016-04-08 20:19 ` Alex Williamson 2016-02-24 19:44 ` [PATCH v4 3/6] PCI: Add support for multiple DMA aliases Bjorn Helgaas 2016-02-25 14:38 ` Bjorn Helgaas 2016-02-25 15:41 ` Lawrynowicz, Jacek 2016-02-29 22:44 ` Bjorn Helgaas 2016-03-01 16:57 ` Jacek Lawrynowicz 2016-03-03 14:22 ` [PATCH] " Jacek Lawrynowicz 2016-03-03 14:38 ` [PATCH v5 3/6] " Jacek Lawrynowicz 2016-04-08 20:19 ` Alex Williamson 2016-03-14 22:43 ` [PATCH v4 " David Woodhouse [not found] ` <1457995420.78634.63.camel-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org> 2016-03-16 0:48 ` Bjorn Helgaas 2016-04-08 16:06 ` Bjorn Helgaas 2016-04-08 16:09 ` David Woodhouse 2016-04-08 17:31 ` Alex Williamson 2016-02-24 19:44 ` [PATCH v4 4/6] PCI: Rename dma_alias_is_enabled() to pci_devs_are_dma_aliases() Bjorn Helgaas 2016-04-08 20:19 ` Alex Williamson [not found] ` <20160224193926.7585.10833.stgit-1RhO1Y9PlrlHTL0Zs8A6p/gx64E7kk8eUsxypvmhUTTZJqsBc5GL+g@public.gmane.org> 2016-02-24 19:44 ` [PATCH v4 5/6] pci: Add DMA alias quirk for mic_x200_dma Bjorn Helgaas via iommu 2016-03-03 14:53 ` [PATCH v5 5/6] PCI: " Jacek Lawrynowicz [not found] ` <1457016800-11903-1-git-send-email-jacek.lawrynowicz-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> 2016-04-08 20:19 ` Alex Williamson 2016-02-24 19:44 ` [PATCH v4 6/6] PCI: Squash pci_dev_flags to remove holes Bjorn Helgaas 2016-04-08 20:19 ` Alex Williamson 2016-04-12 4:38 ` [PATCH v4 0/6] PCI: Support multiple DMA aliases Bjorn Helgaas 2016-04-12 16:20 ` Lawrynowicz, Jacek 2016-04-12 18:10 ` Bjorn Helgaas
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).