Merge branch 'pci/iommu' into next
* pci/iommu: PCI: Add bridge DMA alias quirk for ASMedia and Tundra bridges PCI: Add support for PCIe-to-PCI bridge DMA alias quirks PCI: Add function 1 DMA alias quirk for Marvell devices PCI: Add function 0 DMA alias quirk for Ricoh devices PCI: Add support for DMA alias quirks PCI: Convert pci_dev_flags definitions to bit shifts PCI: Add DMA alias iterator
This commit is contained in:
commit
0eeb4f2af5
|
@ -3342,6 +3342,81 @@ int pci_dev_specific_reset(struct pci_dev *dev, int probe)
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* https://bugzilla.redhat.com/show_bug.cgi?id=605888
|
||||||
|
*
|
||||||
|
* Some Ricoh devices use function 0 as the PCIe requester ID for DMA.
|
||||||
|
*/
|
||||||
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RICOH, 0xe832, quirk_dma_func0_alias);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Marvell 88SE9123 uses function 1 as the requester ID for DMA. In some
|
||||||
|
* SKUs function 1 is present and is a legacy IDE controller, in other
|
||||||
|
* SKUs this function is not present, making this a ghost requester.
|
||||||
|
* https://bugzilla.kernel.org/show_bug.cgi?id=42679
|
||||||
|
*/
|
||||||
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9123,
|
||||||
|
quirk_dma_func1_alias);
|
||||||
|
/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c14 */
|
||||||
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9130,
|
||||||
|
quirk_dma_func1_alias);
|
||||||
|
/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c47 + c57 */
|
||||||
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9172,
|
||||||
|
quirk_dma_func1_alias);
|
||||||
|
/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c59 */
|
||||||
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x917a,
|
||||||
|
quirk_dma_func1_alias);
|
||||||
|
/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c46 */
|
||||||
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0,
|
||||||
|
quirk_dma_func1_alias);
|
||||||
|
/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c49 */
|
||||||
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9230,
|
||||||
|
quirk_dma_func1_alias);
|
||||||
|
/* https://bugs.gentoo.org/show_bug.cgi?id=497630 */
|
||||||
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_JMICRON,
|
||||||
|
PCI_DEVICE_ID_JMICRON_JMB388_ESD,
|
||||||
|
quirk_dma_func1_alias);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A few PCIe-to-PCI bridges fail to expose a PCIe capability, resulting in
|
||||||
|
* using the wrong DMA alias for the device. Some of these devices can be
|
||||||
|
* used as either forward or reverse bridges, so we need to test whether the
|
||||||
|
* device is operating in the correct mode. We could probably apply this
|
||||||
|
* quirk to PCI_ANY_ID, but for now we'll just use known offenders. The test
|
||||||
|
* is for a non-root, non-PCIe bridge where the upstream device is PCIe and
|
||||||
|
* is not a PCIe-to-PCI bridge, then @pdev is actually a PCIe-to-PCI bridge.
|
||||||
|
*/
|
||||||
|
static void quirk_use_pcie_bridge_dma_alias(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
if (!pci_is_root_bus(pdev->bus) &&
|
||||||
|
pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
|
||||||
|
!pci_is_pcie(pdev) && pci_is_pcie(pdev->bus->self) &&
|
||||||
|
pci_pcie_type(pdev->bus->self) != PCI_EXP_TYPE_PCI_BRIDGE)
|
||||||
|
pdev->dev_flags |= PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS;
|
||||||
|
}
|
||||||
|
/* ASM1083/1085, https://bugzilla.kernel.org/show_bug.cgi?id=44881#c46 */
|
||||||
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ASMEDIA, 0x1080,
|
||||||
|
quirk_use_pcie_bridge_dma_alias);
|
||||||
|
/* Tundra 8113, https://bugzilla.kernel.org/show_bug.cgi?id=44881#c43 */
|
||||||
|
DECLARE_PCI_FIXUP_HEADER(0x10e3, 0x8113, quirk_use_pcie_bridge_dma_alias);
|
||||||
|
|
||||||
static struct pci_dev *pci_func_0_dma_source(struct pci_dev *dev)
|
static struct pci_dev *pci_func_0_dma_source(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
if (!PCI_FUNC(dev->devfn))
|
if (!PCI_FUNC(dev->devfn))
|
||||||
|
|
|
@ -16,6 +16,93 @@
|
||||||
DECLARE_RWSEM(pci_bus_sem);
|
DECLARE_RWSEM(pci_bus_sem);
|
||||||
EXPORT_SYMBOL_GPL(pci_bus_sem);
|
EXPORT_SYMBOL_GPL(pci_bus_sem);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pci_for_each_dma_alias - Iterate over DMA aliases for a device
|
||||||
|
* @pdev: starting downstream device
|
||||||
|
* @fn: function to call for each alias
|
||||||
|
* @data: opaque data to pass to @fn
|
||||||
|
*
|
||||||
|
* Starting @pdev, walk up the bus calling @fn for each possible alias
|
||||||
|
* of @pdev at the root bus.
|
||||||
|
*/
|
||||||
|
int pci_for_each_dma_alias(struct pci_dev *pdev,
|
||||||
|
int (*fn)(struct pci_dev *pdev,
|
||||||
|
u16 alias, void *data), void *data)
|
||||||
|
{
|
||||||
|
struct pci_bus *bus;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = fn(pdev, PCI_DEVID(pdev->bus->number, pdev->devfn), data);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (bus = pdev->bus; !pci_is_root_bus(bus); bus = bus->parent) {
|
||||||
|
struct pci_dev *tmp;
|
||||||
|
|
||||||
|
/* Skip virtual buses */
|
||||||
|
if (!bus->self)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tmp = bus->self;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PCIe-to-PCI/X bridges alias transactions from downstream
|
||||||
|
* devices using the subordinate bus number (PCI Express to
|
||||||
|
* PCI/PCI-X Bridge Spec, rev 1.0, sec 2.3). For all cases
|
||||||
|
* where the upstream bus is PCI/X we alias to the bridge
|
||||||
|
* (there are various conditions in the previous reference
|
||||||
|
* where the bridge may take ownership of transactions, even
|
||||||
|
* when the secondary interface is PCI-X).
|
||||||
|
*/
|
||||||
|
if (pci_is_pcie(tmp)) {
|
||||||
|
switch (pci_pcie_type(tmp)) {
|
||||||
|
case PCI_EXP_TYPE_ROOT_PORT:
|
||||||
|
case PCI_EXP_TYPE_UPSTREAM:
|
||||||
|
case PCI_EXP_TYPE_DOWNSTREAM:
|
||||||
|
continue;
|
||||||
|
case PCI_EXP_TYPE_PCI_BRIDGE:
|
||||||
|
ret = fn(tmp,
|
||||||
|
PCI_DEVID(tmp->subordinate->number,
|
||||||
|
PCI_DEVFN(0, 0)), data);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
continue;
|
||||||
|
case PCI_EXP_TYPE_PCIE_BRIDGE:
|
||||||
|
ret = fn(tmp,
|
||||||
|
PCI_DEVID(tmp->bus->number,
|
||||||
|
tmp->devfn), data);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (tmp->dev_flags & PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS)
|
||||||
|
ret = fn(tmp,
|
||||||
|
PCI_DEVID(tmp->subordinate->number,
|
||||||
|
PCI_DEVFN(0, 0)), data);
|
||||||
|
else
|
||||||
|
ret = fn(tmp,
|
||||||
|
PCI_DEVID(tmp->bus->number,
|
||||||
|
tmp->devfn), data);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* find the upstream PCIe-to-PCI bridge of a PCI device
|
* find the upstream PCIe-to-PCI bridge of a PCI device
|
||||||
* if the device is PCIE, return NULL
|
* if the device is PCIE, return NULL
|
||||||
|
|
|
@ -164,13 +164,17 @@ enum pci_dev_flags {
|
||||||
/* INTX_DISABLE in PCI_COMMAND register disables MSI
|
/* INTX_DISABLE in PCI_COMMAND register disables MSI
|
||||||
* generation too.
|
* generation too.
|
||||||
*/
|
*/
|
||||||
PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG = (__force pci_dev_flags_t) 1,
|
PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG = (__force pci_dev_flags_t) (1 << 0),
|
||||||
/* Device configuration is irrevocably lost if disabled into D3 */
|
/* Device configuration is irrevocably lost if disabled into D3 */
|
||||||
PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2,
|
PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) (1 << 1),
|
||||||
/* Provide indication device is assigned by a Virtual Machine Manager */
|
/* Provide indication device is assigned by a Virtual Machine Manager */
|
||||||
PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) 4,
|
PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) (1 << 2),
|
||||||
/* Flag for quirk use to store if quirk-specific ACS is enabled */
|
/* Flag for quirk use to store if quirk-specific ACS is enabled */
|
||||||
PCI_DEV_FLAGS_ACS_ENABLED_QUIRK = (__force pci_dev_flags_t) 8,
|
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),
|
||||||
};
|
};
|
||||||
|
|
||||||
enum pci_irq_reroute_variant {
|
enum pci_irq_reroute_variant {
|
||||||
|
@ -268,6 +272,7 @@ struct pci_dev {
|
||||||
u8 rom_base_reg; /* which config register controls the ROM */
|
u8 rom_base_reg; /* which config register controls the ROM */
|
||||||
u8 pin; /* which interrupt pin this device uses */
|
u8 pin; /* which interrupt pin this device uses */
|
||||||
u16 pcie_flags_reg; /* cached PCIe Capabilities Register */
|
u16 pcie_flags_reg; /* cached PCIe Capabilities Register */
|
||||||
|
u8 dma_alias_devfn;/* devfn of DMA alias, if any */
|
||||||
|
|
||||||
struct pci_driver *driver; /* which driver has allocated this device */
|
struct pci_driver *driver; /* which driver has allocated this device */
|
||||||
u64 dma_mask; /* Mask of the bits of bus address this
|
u64 dma_mask; /* Mask of the bits of bus address this
|
||||||
|
@ -1809,6 +1814,10 @@ static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int pci_for_each_dma_alias(struct pci_dev *pdev,
|
||||||
|
int (*fn)(struct pci_dev *pdev,
|
||||||
|
u16 alias, void *data), void *data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pci_find_upstream_pcie_bridge - find upstream PCIe-to-PCI bridge of a device
|
* pci_find_upstream_pcie_bridge - find upstream PCIe-to-PCI bridge of a device
|
||||||
* @pdev: the PCI device
|
* @pdev: the PCI device
|
||||||
|
|
Loading…
Reference in New Issue