aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/mtip32xx
diff options
context:
space:
mode:
authorAsai Thambi S P <asamymuthupa@micron.com>2014-03-13 21:45:15 -0400
committerJens Axboe <axboe@fb.com>2014-04-22 21:48:52 -0400
commitd1e714db8129a1d3670e449b87719c78e2c76f9f (patch)
tree34ed981357620ab4d648edc4d680d85f079e2a51 /drivers/block/mtip32xx
parentaf5ded8ccf21627f9614afc03b356712666ed225 (diff)
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>
Diffstat (limited to 'drivers/block/mtip32xx')
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index 27641bc83962..fb624469d0ee 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -4483,6 +4483,57 @@ static DEFINE_HANDLER(5);
4483static DEFINE_HANDLER(6); 4483static DEFINE_HANDLER(6);
4484static DEFINE_HANDLER(7); 4484static DEFINE_HANDLER(7);
4485 4485
4486static void mtip_disable_link_opts(struct driver_data *dd, struct pci_dev *pdev)
4487{
4488 int pos;
4489 unsigned short pcie_dev_ctrl;
4490
4491 pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
4492 if (pos) {
4493 pci_read_config_word(pdev,
4494 pos + PCI_EXP_DEVCTL,
4495 &pcie_dev_ctrl);
4496 if (pcie_dev_ctrl & (1 << 11) ||
4497 pcie_dev_ctrl & (1 << 4)) {
4498 dev_info(&dd->pdev->dev,
4499 "Disabling ERO/No-Snoop on bridge device %04x:%04x\n",
4500 pdev->vendor, pdev->device);
4501 pcie_dev_ctrl &= ~(PCI_EXP_DEVCTL_NOSNOOP_EN |
4502 PCI_EXP_DEVCTL_RELAX_EN);
4503 pci_write_config_word(pdev,
4504 pos + PCI_EXP_DEVCTL,
4505 pcie_dev_ctrl);
4506 }
4507 }
4508}
4509
4510static void mtip_fix_ero_nosnoop(struct driver_data *dd, struct pci_dev *pdev)
4511{
4512 /*
4513 * This workaround is specific to AMD/ATI chipset with a PCI upstream
4514 * device with device id 0x5aXX
4515 */
4516 if (pdev->bus && pdev->bus->self) {
4517 if (pdev->bus->self->vendor == PCI_VENDOR_ID_ATI &&
4518 ((pdev->bus->self->device & 0xff00) == 0x5a00)) {
4519 mtip_disable_link_opts(dd, pdev->bus->self);
4520 } else {
4521 /* Check further up the topology */
4522 struct pci_dev *parent_dev = pdev->bus->self;
4523 if (parent_dev->bus &&
4524 parent_dev->bus->parent &&
4525 parent_dev->bus->parent->self &&
4526 parent_dev->bus->parent->self->vendor ==
4527 PCI_VENDOR_ID_ATI &&
4528 (parent_dev->bus->parent->self->device &
4529 0xff00) == 0x5a00) {
4530 mtip_disable_link_opts(dd,
4531 parent_dev->bus->parent->self);
4532 }
4533 }
4534 }
4535}
4536
4486/* 4537/*
4487 * Called for each supported PCI device detected. 4538 * Called for each supported PCI device detected.
4488 * 4539 *
@@ -4634,6 +4685,8 @@ static int mtip_pci_probe(struct pci_dev *pdev,
4634 goto msi_initialize_err; 4685 goto msi_initialize_err;
4635 } 4686 }
4636 4687
4688 mtip_fix_ero_nosnoop(dd, pdev);
4689
4637 /* Initialize the block layer. */ 4690 /* Initialize the block layer. */
4638 rv = mtip_block_initialize(dd); 4691 rv = mtip_block_initialize(dd);
4639 if (rv < 0) { 4692 if (rv < 0) {