mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 22:21:42 +00:00
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:
parent
16f73eb02d
commit
62ce94a7a5
@ -235,6 +235,7 @@ enum pci_bar_type {
|
||||
pci_bar_mem64, /* A 64-bit memory BAR */
|
||||
};
|
||||
|
||||
int pci_configure_extended_tags(struct pci_dev *dev, void *ign);
|
||||
bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *pl,
|
||||
int crs_timeout);
|
||||
int pci_setup_device(struct pci_dev *dev);
|
||||
|
@ -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);
|
||||
|
@ -4681,3 +4681,19 @@ static void quirk_intel_no_flr(struct pci_dev *dev)
|
||||
}
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1502, quirk_intel_no_flr);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1503, quirk_intel_no_flr);
|
||||
|
||||
static void quirk_no_ext_tags(struct pci_dev *pdev)
|
||||
{
|
||||
struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus);
|
||||
|
||||
if (!bridge)
|
||||
return;
|
||||
|
||||
bridge->no_ext_tags = 1;
|
||||
dev_info(&pdev->dev, "disabling Extended Tags (this device can't handle them)\n");
|
||||
|
||||
pci_walk_bus(bridge->bus, pci_configure_extended_tags, NULL);
|
||||
}
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0140, quirk_no_ext_tags);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0142, quirk_no_ext_tags);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0144, quirk_no_ext_tags);
|
||||
|
@ -451,6 +451,7 @@ struct pci_host_bridge {
|
||||
void *release_data;
|
||||
struct msi_controller *msi;
|
||||
unsigned int ignore_reset_delay:1; /* for entire hierarchy */
|
||||
unsigned int no_ext_tags:1; /* no Extended Tags */
|
||||
/* Resource alignment requirements */
|
||||
resource_size_t (*align_resource)(struct pci_dev *dev,
|
||||
const struct resource *res,
|
||||
|
Loading…
Reference in New Issue
Block a user