Skip to content

Commit 62ce94a

Browse files
Sinan Kayabjorn-helgaas
authored andcommitted
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: 60db3a4 ("PCI: Enable PCIe Extended Tags if supported") Link: https://bugzilla.redhat.com/show_bug.cgi?id=1467674 Reported-and-tested-by: Wim ten Have <[email protected]> Signed-off-by: Sinan Kaya <[email protected]> [bhelgaas: changelog, tweak messages, rename bit and quirk] Signed-off-by: Bjorn Helgaas <[email protected]>
1 parent 16f73eb commit 62ce94a

File tree

4 files changed

+54
-7
lines changed

4 files changed

+54
-7
lines changed

drivers/pci/pci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ enum pci_bar_type {
235235
pci_bar_mem64, /* A 64-bit memory BAR */
236236
};
237237

238+
int pci_configure_extended_tags(struct pci_dev *dev, void *ign);
238239
bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *pl,
239240
int crs_timeout);
240241
int pci_setup_device(struct pci_dev *dev);

drivers/pci/probe.c

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1745,21 +1745,50 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
17451745
*/
17461746
}
17471747

1748-
static void pci_configure_extended_tags(struct pci_dev *dev)
1748+
int pci_configure_extended_tags(struct pci_dev *dev, void *ign)
17491749
{
1750-
u32 dev_cap;
1750+
struct pci_host_bridge *host;
1751+
u32 cap;
1752+
u16 ctl;
17511753
int ret;
17521754

17531755
if (!pci_is_pcie(dev))
1754-
return;
1756+
return 0;
17551757

1756-
ret = pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &dev_cap);
1758+
ret = pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap);
17571759
if (ret)
1758-
return;
1760+
return 0;
1761+
1762+
if (!(cap & PCI_EXP_DEVCAP_EXT_TAG))
1763+
return 0;
17591764

1760-
if (dev_cap & PCI_EXP_DEVCAP_EXT_TAG)
1765+
ret = pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &ctl);
1766+
if (ret)
1767+
return 0;
1768+
1769+
host = pci_find_host_bridge(dev->bus);
1770+
if (!host)
1771+
return 0;
1772+
1773+
/*
1774+
* If some device in the hierarchy doesn't handle Extended Tags
1775+
* correctly, make sure they're disabled.
1776+
*/
1777+
if (host->no_ext_tags) {
1778+
if (ctl & PCI_EXP_DEVCTL_EXT_TAG) {
1779+
dev_info(&dev->dev, "disabling Extended Tags\n");
1780+
pcie_capability_clear_word(dev, PCI_EXP_DEVCTL,
1781+
PCI_EXP_DEVCTL_EXT_TAG);
1782+
}
1783+
return 0;
1784+
}
1785+
1786+
if (!(ctl & PCI_EXP_DEVCTL_EXT_TAG)) {
1787+
dev_info(&dev->dev, "enabling Extended Tags\n");
17611788
pcie_capability_set_word(dev, PCI_EXP_DEVCTL,
17621789
PCI_EXP_DEVCTL_EXT_TAG);
1790+
}
1791+
return 0;
17631792
}
17641793

17651794
static void pci_configure_device(struct pci_dev *dev)
@@ -1768,7 +1797,7 @@ static void pci_configure_device(struct pci_dev *dev)
17681797
int ret;
17691798

17701799
pci_configure_mps(dev);
1771-
pci_configure_extended_tags(dev);
1800+
pci_configure_extended_tags(dev, NULL);
17721801

17731802
memset(&hpp, 0, sizeof(hpp));
17741803
ret = pci_get_hp_params(dev, &hpp);

drivers/pci/quirks.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4681,3 +4681,19 @@ static void quirk_intel_no_flr(struct pci_dev *dev)
46814681
}
46824682
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1502, quirk_intel_no_flr);
46834683
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1503, quirk_intel_no_flr);
4684+
4685+
static void quirk_no_ext_tags(struct pci_dev *pdev)
4686+
{
4687+
struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus);
4688+
4689+
if (!bridge)
4690+
return;
4691+
4692+
bridge->no_ext_tags = 1;
4693+
dev_info(&pdev->dev, "disabling Extended Tags (this device can't handle them)\n");
4694+
4695+
pci_walk_bus(bridge->bus, pci_configure_extended_tags, NULL);
4696+
}
4697+
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0140, quirk_no_ext_tags);
4698+
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0142, quirk_no_ext_tags);
4699+
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0144, quirk_no_ext_tags);

include/linux/pci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,7 @@ struct pci_host_bridge {
451451
void *release_data;
452452
struct msi_controller *msi;
453453
unsigned int ignore_reset_delay:1; /* for entire hierarchy */
454+
unsigned int no_ext_tags:1; /* no Extended Tags */
454455
/* Resource alignment requirements */
455456
resource_size_t (*align_resource)(struct pci_dev *dev,
456457
const struct resource *res,

0 commit comments

Comments
 (0)