diff options
author | Asai Thambi S P <asamymuthupa@micron.com> | 2014-03-13 21:45:15 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2014-04-22 21:48:52 -0400 |
commit | d1e714db8129a1d3670e449b87719c78e2c76f9f (patch) | |
tree | 34ed981357620ab4d648edc4d680d85f079e2a51 /drivers/block/mtip32xx | |
parent | af5ded8ccf21627f9614afc03b356712666ed225 (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.c | 53 |
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); | |||
4483 | static DEFINE_HANDLER(6); | 4483 | static DEFINE_HANDLER(6); |
4484 | static DEFINE_HANDLER(7); | 4484 | static DEFINE_HANDLER(7); |
4485 | 4485 | ||
4486 | static 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 | |||
4510 | static 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) { |