diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2014-06-02 18:18:48 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2014-06-02 18:18:48 -0400 |
commit | 0eeb4f2af5f71f64ba6362df33ddc1f218075c52 (patch) | |
tree | a5ba0181900968cda030364e18235e93f975b093 /drivers/pci | |
parent | 617b4157a5c82ab3e9509aa388bfd3d47e0e623a (diff) | |
parent | ebdb51eb7806df56221d4536a6a9702751d6df85 (diff) |
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
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/quirks.c | 75 | ||||
-rw-r--r-- | drivers/pci/search.c | 87 |
2 files changed, 162 insertions, 0 deletions
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 92e68c7747f7..d3f29dd29876 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
@@ -3342,6 +3342,81 @@ int pci_dev_specific_reset(struct pci_dev *dev, int probe) | |||
3342 | return -ENOTTY; | 3342 | return -ENOTTY; |
3343 | } | 3343 | } |
3344 | 3344 | ||
3345 | static void quirk_dma_func0_alias(struct pci_dev *dev) | ||
3346 | { | ||
3347 | if (PCI_FUNC(dev->devfn) != 0) { | ||
3348 | dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0); | ||
3349 | dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; | ||
3350 | } | ||
3351 | } | ||
3352 | |||
3353 | /* | ||
3354 | * https://bugzilla.redhat.com/show_bug.cgi?id=605888 | ||
3355 | * | ||
3356 | * Some Ricoh devices use function 0 as the PCIe requester ID for DMA. | ||
3357 | */ | ||
3358 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RICOH, 0xe832, quirk_dma_func0_alias); | ||
3359 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RICOH, 0xe476, quirk_dma_func0_alias); | ||
3360 | |||
3361 | static void quirk_dma_func1_alias(struct pci_dev *dev) | ||
3362 | { | ||
3363 | if (PCI_FUNC(dev->devfn) != 1) { | ||
3364 | dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 1); | ||
3365 | dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; | ||
3366 | } | ||
3367 | } | ||
3368 | |||
3369 | /* | ||
3370 | * Marvell 88SE9123 uses function 1 as the requester ID for DMA. In some | ||
3371 | * SKUs function 1 is present and is a legacy IDE controller, in other | ||
3372 | * SKUs this function is not present, making this a ghost requester. | ||
3373 | * https://bugzilla.kernel.org/show_bug.cgi?id=42679 | ||
3374 | */ | ||
3375 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9123, | ||
3376 | quirk_dma_func1_alias); | ||
3377 | /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c14 */ | ||
3378 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9130, | ||
3379 | quirk_dma_func1_alias); | ||
3380 | /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c47 + c57 */ | ||
3381 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9172, | ||
3382 | quirk_dma_func1_alias); | ||
3383 | /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c59 */ | ||
3384 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x917a, | ||
3385 | quirk_dma_func1_alias); | ||
3386 | /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c46 */ | ||
3387 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0, | ||
3388 | quirk_dma_func1_alias); | ||
3389 | /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c49 */ | ||
3390 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9230, | ||
3391 | quirk_dma_func1_alias); | ||
3392 | /* https://bugs.gentoo.org/show_bug.cgi?id=497630 */ | ||
3393 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_JMICRON, | ||
3394 | PCI_DEVICE_ID_JMICRON_JMB388_ESD, | ||
3395 | quirk_dma_func1_alias); | ||
3396 | |||
3397 | /* | ||
3398 | * A few PCIe-to-PCI bridges fail to expose a PCIe capability, resulting in | ||
3399 | * using the wrong DMA alias for the device. Some of these devices can be | ||
3400 | * used as either forward or reverse bridges, so we need to test whether the | ||
3401 | * device is operating in the correct mode. We could probably apply this | ||
3402 | * quirk to PCI_ANY_ID, but for now we'll just use known offenders. The test | ||
3403 | * is for a non-root, non-PCIe bridge where the upstream device is PCIe and | ||
3404 | * is not a PCIe-to-PCI bridge, then @pdev is actually a PCIe-to-PCI bridge. | ||
3405 | */ | ||
3406 | static void quirk_use_pcie_bridge_dma_alias(struct pci_dev *pdev) | ||
3407 | { | ||
3408 | if (!pci_is_root_bus(pdev->bus) && | ||
3409 | pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE && | ||
3410 | !pci_is_pcie(pdev) && pci_is_pcie(pdev->bus->self) && | ||
3411 | pci_pcie_type(pdev->bus->self) != PCI_EXP_TYPE_PCI_BRIDGE) | ||
3412 | pdev->dev_flags |= PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS; | ||
3413 | } | ||
3414 | /* ASM1083/1085, https://bugzilla.kernel.org/show_bug.cgi?id=44881#c46 */ | ||
3415 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ASMEDIA, 0x1080, | ||
3416 | quirk_use_pcie_bridge_dma_alias); | ||
3417 | /* Tundra 8113, https://bugzilla.kernel.org/show_bug.cgi?id=44881#c43 */ | ||
3418 | DECLARE_PCI_FIXUP_HEADER(0x10e3, 0x8113, quirk_use_pcie_bridge_dma_alias); | ||
3419 | |||
3345 | static struct pci_dev *pci_func_0_dma_source(struct pci_dev *dev) | 3420 | static struct pci_dev *pci_func_0_dma_source(struct pci_dev *dev) |
3346 | { | 3421 | { |
3347 | if (!PCI_FUNC(dev->devfn)) | 3422 | if (!PCI_FUNC(dev->devfn)) |
diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 8e495bda678f..0e9a00e5ca60 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c | |||
@@ -17,6 +17,93 @@ DECLARE_RWSEM(pci_bus_sem); | |||
17 | EXPORT_SYMBOL_GPL(pci_bus_sem); | 17 | EXPORT_SYMBOL_GPL(pci_bus_sem); |
18 | 18 | ||
19 | /* | 19 | /* |
20 | * pci_for_each_dma_alias - Iterate over DMA aliases for a device | ||
21 | * @pdev: starting downstream device | ||
22 | * @fn: function to call for each alias | ||
23 | * @data: opaque data to pass to @fn | ||
24 | * | ||
25 | * Starting @pdev, walk up the bus calling @fn for each possible alias | ||
26 | * of @pdev at the root bus. | ||
27 | */ | ||
28 | int pci_for_each_dma_alias(struct pci_dev *pdev, | ||
29 | int (*fn)(struct pci_dev *pdev, | ||
30 | u16 alias, void *data), void *data) | ||
31 | { | ||
32 | struct pci_bus *bus; | ||
33 | int ret; | ||
34 | |||
35 | ret = fn(pdev, PCI_DEVID(pdev->bus->number, pdev->devfn), data); | ||
36 | if (ret) | ||
37 | return ret; | ||
38 | |||
39 | /* | ||
40 | * If the device is broken and uses an alias requester ID for | ||
41 | * DMA, iterate over that too. | ||
42 | */ | ||
43 | if (unlikely(pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN)) { | ||
44 | ret = fn(pdev, PCI_DEVID(pdev->bus->number, | ||
45 | pdev->dma_alias_devfn), data); | ||
46 | if (ret) | ||
47 | return ret; | ||
48 | } | ||
49 | |||
50 | for (bus = pdev->bus; !pci_is_root_bus(bus); bus = bus->parent) { | ||
51 | struct pci_dev *tmp; | ||
52 | |||
53 | /* Skip virtual buses */ | ||
54 | if (!bus->self) | ||
55 | continue; | ||
56 | |||
57 | tmp = bus->self; | ||
58 | |||
59 | /* | ||
60 | * PCIe-to-PCI/X bridges alias transactions from downstream | ||
61 | * devices using the subordinate bus number (PCI Express to | ||
62 | * PCI/PCI-X Bridge Spec, rev 1.0, sec 2.3). For all cases | ||
63 | * where the upstream bus is PCI/X we alias to the bridge | ||
64 | * (there are various conditions in the previous reference | ||
65 | * where the bridge may take ownership of transactions, even | ||
66 | * when the secondary interface is PCI-X). | ||
67 | */ | ||
68 | if (pci_is_pcie(tmp)) { | ||
69 | switch (pci_pcie_type(tmp)) { | ||
70 | case PCI_EXP_TYPE_ROOT_PORT: | ||
71 | case PCI_EXP_TYPE_UPSTREAM: | ||
72 | case PCI_EXP_TYPE_DOWNSTREAM: | ||
73 | continue; | ||
74 | case PCI_EXP_TYPE_PCI_BRIDGE: | ||
75 | ret = fn(tmp, | ||
76 | PCI_DEVID(tmp->subordinate->number, | ||
77 | PCI_DEVFN(0, 0)), data); | ||
78 | if (ret) | ||
79 | return ret; | ||
80 | continue; | ||
81 | case PCI_EXP_TYPE_PCIE_BRIDGE: | ||
82 | ret = fn(tmp, | ||
83 | PCI_DEVID(tmp->bus->number, | ||
84 | tmp->devfn), data); | ||
85 | if (ret) | ||
86 | return ret; | ||
87 | continue; | ||
88 | } | ||
89 | } else { | ||
90 | if (tmp->dev_flags & PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS) | ||
91 | ret = fn(tmp, | ||
92 | PCI_DEVID(tmp->subordinate->number, | ||
93 | PCI_DEVFN(0, 0)), data); | ||
94 | else | ||
95 | ret = fn(tmp, | ||
96 | PCI_DEVID(tmp->bus->number, | ||
97 | tmp->devfn), data); | ||
98 | if (ret) | ||
99 | return ret; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | return ret; | ||
104 | } | ||
105 | |||
106 | /* | ||
20 | * find the upstream PCIe-to-PCI bridge of a PCI device | 107 | * find the upstream PCIe-to-PCI bridge of a PCI device |
21 | * if the device is PCIE, return NULL | 108 | * if the device is PCIE, return NULL |
22 | * if the device isn't connected to a PCIe bridge (that is its parent is a | 109 | * if the device isn't connected to a PCIe bridge (that is its parent is a |