diff --git a/sys/compat/linuxkpi/common/include/linux/pci.h b/sys/compat/linuxkpi/common/include/linux/pci.h --- a/sys/compat/linuxkpi/common/include/linux/pci.h +++ b/sys/compat/linuxkpi/common/include/linux/pci.h @@ -342,6 +342,7 @@ size_t romlen; struct msi_desc **msi_desc; char *path_name; + spinlock_t pcie_cap_lock; TAILQ_HEAD(, pci_mmio_region) mmio; }; @@ -1013,35 +1014,38 @@ } static inline int -pcie_capability_set_word(struct pci_dev *dev, int pos, uint16_t val) +pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos, + uint16_t clear, uint16_t set) { int error; uint16_t v; + if (pos == PCI_EXP_LNKCTL || pos == PCI_EXP_RTCTL) + spin_lock(&dev->pcie_cap_lock); + error = pcie_capability_read_word(dev, pos, &v); - if (error != 0) - return (error); + if (error == 0) { + v &= ~clear; + v |= set; + error = pcie_capability_write_word(dev, pos, v); + } - v |= val; + if (pos == PCI_EXP_LNKCTL || pos == PCI_EXP_RTCTL) + spin_unlock(&dev->pcie_cap_lock); - error = pcie_capability_write_word(dev, pos, v); return (error); } static inline int -pcie_capability_clear_word(struct pci_dev *dev, int pos, uint16_t val) +pcie_capability_set_word(struct pci_dev *dev, int pos, uint16_t val) { - int error; - uint16_t v; - - error = pcie_capability_read_word(dev, pos, &v); - if (error != 0) - return (error); - - v &= ~val; + return (pcie_capability_clear_and_set_word(dev, pos, 0, val)); +} - error = pcie_capability_write_word(dev, pos, v); - return (error); +static inline int +pcie_capability_clear_word(struct pci_dev *dev, int pos, uint16_t val) +{ + return (pcie_capability_clear_and_set_word(dev, pos, val, 0)); } static inline int pcie_get_minimum_link(struct pci_dev *dev, diff --git a/sys/compat/linuxkpi/common/src/linux_pci.c b/sys/compat/linuxkpi/common/src/linux_pci.c --- a/sys/compat/linuxkpi/common/src/linux_pci.c +++ b/sys/compat/linuxkpi/common/src/linux_pci.c @@ -524,6 +524,7 @@ goto out_dma_init; TAILQ_INIT(&pdev->mmio); + spin_lock_init(&pdev->pcie_cap_lock); spin_lock(&pci_lock); list_add(&pdev->links, &pci_devices);