PCI: Mark Broadcom HT2100 Root Port Extended Tags as broken

Per PCIe r3.1, sec 2.2.6.2 and 7.8.4, a Requester may not use 8-bit Tags
unless its Extended Tag Field Enable is set, but all Receivers/Completers
must handle 8-bit Tags correctly regardless of their Extended Tag Field
Enable.

Some devices do not handle 8-bit Tags as Completers, so add a quirk for
them.  If we find such a device, we disable Extended Tags for the entire
hierarchy to make peer-to-peer DMA possible.

The Broadcom HT2100 seems to have issues with handling 8-bit tags.  Mark it
as broken.

The pci_walk_bus() in the quirk handles devices we've enumerated in the
past, and pci_configure_device() handles devices we enumerate in the
future.

Fixes: 60db3a4d8c ("PCI: Enable PCIe Extended Tags if supported")
Link: https://bugzilla.redhat.com/show_bug.cgi?id=1467674
Reported-and-tested-by: Wim ten Have <wim.ten.have@oracle.com>
Signed-off-by: Sinan Kaya <okaya@codeaurora.org>
[bhelgaas: changelog, tweak messages, rename bit and quirk]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
This commit is contained in:
Sinan Kaya
2017-07-12 00:04:14 -04:00
committed by Bjorn Helgaas
parent 16f73eb02d
commit 62ce94a7a5
4 changed files with 54 additions and 7 deletions

View File

@@ -1745,21 +1745,50 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
*/
}
static void pci_configure_extended_tags(struct pci_dev *dev)
int pci_configure_extended_tags(struct pci_dev *dev, void *ign)
{
u32 dev_cap;
struct pci_host_bridge *host;
u32 cap;
u16 ctl;
int ret;
if (!pci_is_pcie(dev))
return;
return 0;
ret = pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &dev_cap);
ret = pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap);
if (ret)
return;
return 0;
if (dev_cap & PCI_EXP_DEVCAP_EXT_TAG)
if (!(cap & PCI_EXP_DEVCAP_EXT_TAG))
return 0;
ret = pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &ctl);
if (ret)
return 0;
host = pci_find_host_bridge(dev->bus);
if (!host)
return 0;
/*
* If some device in the hierarchy doesn't handle Extended Tags
* correctly, make sure they're disabled.
*/
if (host->no_ext_tags) {
if (ctl & PCI_EXP_DEVCTL_EXT_TAG) {
dev_info(&dev->dev, "disabling Extended Tags\n");
pcie_capability_clear_word(dev, PCI_EXP_DEVCTL,
PCI_EXP_DEVCTL_EXT_TAG);
}
return 0;
}
if (!(ctl & PCI_EXP_DEVCTL_EXT_TAG)) {
dev_info(&dev->dev, "enabling Extended Tags\n");
pcie_capability_set_word(dev, PCI_EXP_DEVCTL,
PCI_EXP_DEVCTL_EXT_TAG);
}
return 0;
}
static void pci_configure_device(struct pci_dev *dev)
@@ -1768,7 +1797,7 @@ static void pci_configure_device(struct pci_dev *dev)
int ret;
pci_configure_mps(dev);
pci_configure_extended_tags(dev);
pci_configure_extended_tags(dev, NULL);
memset(&hpp, 0, sizeof(hpp));
ret = pci_get_hp_params(dev, &hpp);