forked from Minki/linux
mtip32xx: Fix ERO and NoSnoop values in PCIe upstream on AMD systems
A hardware quirk in P320h/P420m interfere with PCIe transactions on some AMD chipsets, making P320h/P420m unusable. This workaround is to disable ERO and NoSnoop bits in the parent and root complex for normal functioning of these devices NOTE: This workaround is specific to AMD chipset with a PCIe upstream device with device id 0x5aXX Signed-off-by: Asai Thambi S P <asamymuthupa@micron.com> Signed-off-by: Sam Bradshaw <sbradshaw@micron.com> Cc: stable@kernel.org Signed-off-by: Jens Axboe <axboe@fb.com>
This commit is contained in:
parent
af5ded8ccf
commit
d1e714db81
@ -4483,6 +4483,57 @@ static DEFINE_HANDLER(5);
|
||||
static DEFINE_HANDLER(6);
|
||||
static DEFINE_HANDLER(7);
|
||||
|
||||
static void mtip_disable_link_opts(struct driver_data *dd, struct pci_dev *pdev)
|
||||
{
|
||||
int pos;
|
||||
unsigned short pcie_dev_ctrl;
|
||||
|
||||
pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
|
||||
if (pos) {
|
||||
pci_read_config_word(pdev,
|
||||
pos + PCI_EXP_DEVCTL,
|
||||
&pcie_dev_ctrl);
|
||||
if (pcie_dev_ctrl & (1 << 11) ||
|
||||
pcie_dev_ctrl & (1 << 4)) {
|
||||
dev_info(&dd->pdev->dev,
|
||||
"Disabling ERO/No-Snoop on bridge device %04x:%04x\n",
|
||||
pdev->vendor, pdev->device);
|
||||
pcie_dev_ctrl &= ~(PCI_EXP_DEVCTL_NOSNOOP_EN |
|
||||
PCI_EXP_DEVCTL_RELAX_EN);
|
||||
pci_write_config_word(pdev,
|
||||
pos + PCI_EXP_DEVCTL,
|
||||
pcie_dev_ctrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void mtip_fix_ero_nosnoop(struct driver_data *dd, struct pci_dev *pdev)
|
||||
{
|
||||
/*
|
||||
* This workaround is specific to AMD/ATI chipset with a PCI upstream
|
||||
* device with device id 0x5aXX
|
||||
*/
|
||||
if (pdev->bus && pdev->bus->self) {
|
||||
if (pdev->bus->self->vendor == PCI_VENDOR_ID_ATI &&
|
||||
((pdev->bus->self->device & 0xff00) == 0x5a00)) {
|
||||
mtip_disable_link_opts(dd, pdev->bus->self);
|
||||
} else {
|
||||
/* Check further up the topology */
|
||||
struct pci_dev *parent_dev = pdev->bus->self;
|
||||
if (parent_dev->bus &&
|
||||
parent_dev->bus->parent &&
|
||||
parent_dev->bus->parent->self &&
|
||||
parent_dev->bus->parent->self->vendor ==
|
||||
PCI_VENDOR_ID_ATI &&
|
||||
(parent_dev->bus->parent->self->device &
|
||||
0xff00) == 0x5a00) {
|
||||
mtip_disable_link_opts(dd,
|
||||
parent_dev->bus->parent->self);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Called for each supported PCI device detected.
|
||||
*
|
||||
@ -4634,6 +4685,8 @@ static int mtip_pci_probe(struct pci_dev *pdev,
|
||||
goto msi_initialize_err;
|
||||
}
|
||||
|
||||
mtip_fix_ero_nosnoop(dd, pdev);
|
||||
|
||||
/* Initialize the block layer. */
|
||||
rv = mtip_block_initialize(dd);
|
||||
if (rv < 0) {
|
||||
|
Loading…
Reference in New Issue
Block a user