diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pci-bridge-emul.c | 14 | ||||
-rw-r--r-- | drivers/pci/pci.c | 57 |
2 files changed, 59 insertions, 12 deletions
diff --git a/drivers/pci/pci-bridge-emul.c b/drivers/pci/pci-bridge-emul.c index fffa77093c08..4f4f54bc732e 100644 --- a/drivers/pci/pci-bridge-emul.c +++ b/drivers/pci/pci-bridge-emul.c @@ -50,12 +50,7 @@ static const struct pci_bridge_reg_behavior pci_regs_behavior[] = { (PCI_STATUS_CAP_LIST | PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MASK) << 16), .rsvd = GENMASK(15, 10) | ((BIT(6) | GENMASK(3, 0)) << 16), - .w1c = (PCI_STATUS_PARITY | - PCI_STATUS_SIG_TARGET_ABORT | - PCI_STATUS_REC_TARGET_ABORT | - PCI_STATUS_REC_MASTER_ABORT | - PCI_STATUS_SIG_SYSTEM_ERROR | - PCI_STATUS_DETECTED_PARITY) << 16, + .w1c = PCI_STATUS_ERROR_BITS << 16, }, [PCI_CLASS_REVISION / 4] = { .ro = ~0 }, @@ -100,12 +95,7 @@ static const struct pci_bridge_reg_behavior pci_regs_behavior[] = { PCI_STATUS_DEVSEL_MASK) << 16) | GENMASK(11, 8) | GENMASK(3, 0)), - .w1c = (PCI_STATUS_PARITY | - PCI_STATUS_SIG_TARGET_ABORT | - PCI_STATUS_REC_TARGET_ABORT | - PCI_STATUS_REC_MASTER_ABORT | - PCI_STATUS_SIG_SYSTEM_ERROR | - PCI_STATUS_DETECTED_PARITY) << 16, + .w1c = PCI_STATUS_ERROR_BITS << 16, .rsvd = ((BIT(6) | GENMASK(4, 0)) << 16), }, diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index d828ca835a98..86821313c007 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -173,6 +173,29 @@ unsigned char pci_bus_max_busnr(struct pci_bus *bus) } EXPORT_SYMBOL_GPL(pci_bus_max_busnr); +/** + * pci_status_get_and_clear_errors - return and clear error bits in PCI_STATUS + * @pdev: the PCI device + * + * Returns error bits set in PCI_STATUS and clears them. + */ +int pci_status_get_and_clear_errors(struct pci_dev *pdev) +{ + u16 status; + int ret; + + ret = pci_read_config_word(pdev, PCI_STATUS, &status); + if (ret != PCIBIOS_SUCCESSFUL) + return -EIO; + + status &= PCI_STATUS_ERROR_BITS; + if (status) + pci_write_config_word(pdev, PCI_STATUS, status); + + return status; +} +EXPORT_SYMBOL_GPL(pci_status_get_and_clear_errors); + #ifdef CONFIG_HAS_IOMEM void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar) { @@ -557,6 +580,40 @@ int pci_find_ext_capability(struct pci_dev *dev, int cap) } EXPORT_SYMBOL_GPL(pci_find_ext_capability); +/** + * pci_get_dsn - Read and return the 8-byte Device Serial Number + * @dev: PCI device to query + * + * Looks up the PCI_EXT_CAP_ID_DSN and reads the 8 bytes of the Device Serial + * Number. + * + * Returns the DSN, or zero if the capability does not exist. + */ +u64 pci_get_dsn(struct pci_dev *dev) +{ + u32 dword; + u64 dsn; + int pos; + + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DSN); + if (!pos) + return 0; + + /* + * The Device Serial Number is two dwords offset 4 bytes from the + * capability position. The specification says that the first dword is + * the lower half, and the second dword is the upper half. + */ + pos += 4; + pci_read_config_dword(dev, pos, &dword); + dsn = (u64)dword; + pci_read_config_dword(dev, pos + 4, &dword); + dsn |= ((u64)dword) << 32; + + return dsn; +} +EXPORT_SYMBOL_GPL(pci_get_dsn); + static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap) { int rc, ttl = PCI_FIND_CAP_TTL; |