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:
Коммит
0eeb4f2af5
|
@ -3342,6 +3342,81 @@ int pci_dev_specific_reset(struct pci_dev *dev, int probe)
|
|||
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)
|
||||
{
|
||||
if (!PCI_FUNC(dev->devfn))
|
||||
|
|
|
@ -16,6 +16,93 @@
|
|||
DECLARE_RWSEM(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
|
||||
* if the device is PCIE, return NULL
|
||||
|
|
|
@ -164,13 +164,17 @@ enum pci_dev_flags {
|
|||
/* INTX_DISABLE in PCI_COMMAND register disables MSI
|
||||
* 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 */
|
||||
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 */
|
||||
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 */
|
||||
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 {
|
||||
|
@ -268,6 +272,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 */
|
||||
|
||||
struct pci_driver *driver; /* which driver has allocated this device */
|
||||
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
|
||||
|
||||
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
|
||||
* @pdev: the PCI device
|
||||
|
|
Загрузка…
Ссылка в новой задаче