162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/pci.h> 362306a36Sopenharmony_ci#include <linux/module.h> 462306a36Sopenharmony_ci#include <linux/slab.h> 562306a36Sopenharmony_ci#include <linux/ioport.h> 662306a36Sopenharmony_ci#include <linux/wait.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "pci.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* 1162306a36Sopenharmony_ci * This interrupt-safe spinlock protects all accesses to PCI 1262306a36Sopenharmony_ci * configuration space. 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ciDEFINE_RAW_SPINLOCK(pci_lock); 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* 1862306a36Sopenharmony_ci * Wrappers for all PCI configuration access functions. They just check 1962306a36Sopenharmony_ci * alignment, do locking and call the low-level functions pointed to 2062306a36Sopenharmony_ci * by pci_dev->ops. 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define PCI_byte_BAD 0 2462306a36Sopenharmony_ci#define PCI_word_BAD (pos & 1) 2562306a36Sopenharmony_ci#define PCI_dword_BAD (pos & 3) 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#ifdef CONFIG_PCI_LOCKLESS_CONFIG 2862306a36Sopenharmony_ci# define pci_lock_config(f) do { (void)(f); } while (0) 2962306a36Sopenharmony_ci# define pci_unlock_config(f) do { (void)(f); } while (0) 3062306a36Sopenharmony_ci#else 3162306a36Sopenharmony_ci# define pci_lock_config(f) raw_spin_lock_irqsave(&pci_lock, f) 3262306a36Sopenharmony_ci# define pci_unlock_config(f) raw_spin_unlock_irqrestore(&pci_lock, f) 3362306a36Sopenharmony_ci#endif 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define PCI_OP_READ(size, type, len) \ 3662306a36Sopenharmony_ciint noinline pci_bus_read_config_##size \ 3762306a36Sopenharmony_ci (struct pci_bus *bus, unsigned int devfn, int pos, type *value) \ 3862306a36Sopenharmony_ci{ \ 3962306a36Sopenharmony_ci int res; \ 4062306a36Sopenharmony_ci unsigned long flags; \ 4162306a36Sopenharmony_ci u32 data = 0; \ 4262306a36Sopenharmony_ci if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ 4362306a36Sopenharmony_ci pci_lock_config(flags); \ 4462306a36Sopenharmony_ci res = bus->ops->read(bus, devfn, pos, len, &data); \ 4562306a36Sopenharmony_ci if (res) \ 4662306a36Sopenharmony_ci PCI_SET_ERROR_RESPONSE(value); \ 4762306a36Sopenharmony_ci else \ 4862306a36Sopenharmony_ci *value = (type)data; \ 4962306a36Sopenharmony_ci pci_unlock_config(flags); \ 5062306a36Sopenharmony_ci return res; \ 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#define PCI_OP_WRITE(size, type, len) \ 5462306a36Sopenharmony_ciint noinline pci_bus_write_config_##size \ 5562306a36Sopenharmony_ci (struct pci_bus *bus, unsigned int devfn, int pos, type value) \ 5662306a36Sopenharmony_ci{ \ 5762306a36Sopenharmony_ci int res; \ 5862306a36Sopenharmony_ci unsigned long flags; \ 5962306a36Sopenharmony_ci if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ 6062306a36Sopenharmony_ci pci_lock_config(flags); \ 6162306a36Sopenharmony_ci res = bus->ops->write(bus, devfn, pos, len, value); \ 6262306a36Sopenharmony_ci pci_unlock_config(flags); \ 6362306a36Sopenharmony_ci return res; \ 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ciPCI_OP_READ(byte, u8, 1) 6762306a36Sopenharmony_ciPCI_OP_READ(word, u16, 2) 6862306a36Sopenharmony_ciPCI_OP_READ(dword, u32, 4) 6962306a36Sopenharmony_ciPCI_OP_WRITE(byte, u8, 1) 7062306a36Sopenharmony_ciPCI_OP_WRITE(word, u16, 2) 7162306a36Sopenharmony_ciPCI_OP_WRITE(dword, u32, 4) 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ciEXPORT_SYMBOL(pci_bus_read_config_byte); 7462306a36Sopenharmony_ciEXPORT_SYMBOL(pci_bus_read_config_word); 7562306a36Sopenharmony_ciEXPORT_SYMBOL(pci_bus_read_config_dword); 7662306a36Sopenharmony_ciEXPORT_SYMBOL(pci_bus_write_config_byte); 7762306a36Sopenharmony_ciEXPORT_SYMBOL(pci_bus_write_config_word); 7862306a36Sopenharmony_ciEXPORT_SYMBOL(pci_bus_write_config_dword); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ciint pci_generic_config_read(struct pci_bus *bus, unsigned int devfn, 8162306a36Sopenharmony_ci int where, int size, u32 *val) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci void __iomem *addr; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci addr = bus->ops->map_bus(bus, devfn, where); 8662306a36Sopenharmony_ci if (!addr) 8762306a36Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (size == 1) 9062306a36Sopenharmony_ci *val = readb(addr); 9162306a36Sopenharmony_ci else if (size == 2) 9262306a36Sopenharmony_ci *val = readw(addr); 9362306a36Sopenharmony_ci else 9462306a36Sopenharmony_ci *val = readl(addr); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_generic_config_read); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ciint pci_generic_config_write(struct pci_bus *bus, unsigned int devfn, 10162306a36Sopenharmony_ci int where, int size, u32 val) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci void __iomem *addr; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci addr = bus->ops->map_bus(bus, devfn, where); 10662306a36Sopenharmony_ci if (!addr) 10762306a36Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (size == 1) 11062306a36Sopenharmony_ci writeb(val, addr); 11162306a36Sopenharmony_ci else if (size == 2) 11262306a36Sopenharmony_ci writew(val, addr); 11362306a36Sopenharmony_ci else 11462306a36Sopenharmony_ci writel(val, addr); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_generic_config_write); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ciint pci_generic_config_read32(struct pci_bus *bus, unsigned int devfn, 12162306a36Sopenharmony_ci int where, int size, u32 *val) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci void __iomem *addr; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci addr = bus->ops->map_bus(bus, devfn, where & ~0x3); 12662306a36Sopenharmony_ci if (!addr) 12762306a36Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci *val = readl(addr); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (size <= 2) 13262306a36Sopenharmony_ci *val = (*val >> (8 * (where & 3))) & ((1 << (size * 8)) - 1); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_generic_config_read32); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ciint pci_generic_config_write32(struct pci_bus *bus, unsigned int devfn, 13962306a36Sopenharmony_ci int where, int size, u32 val) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci void __iomem *addr; 14262306a36Sopenharmony_ci u32 mask, tmp; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci addr = bus->ops->map_bus(bus, devfn, where & ~0x3); 14562306a36Sopenharmony_ci if (!addr) 14662306a36Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (size == 4) { 14962306a36Sopenharmony_ci writel(val, addr); 15062306a36Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* 15462306a36Sopenharmony_ci * In general, hardware that supports only 32-bit writes on PCI is 15562306a36Sopenharmony_ci * not spec-compliant. For example, software may perform a 16-bit 15662306a36Sopenharmony_ci * write. If the hardware only supports 32-bit accesses, we must 15762306a36Sopenharmony_ci * do a 32-bit read, merge in the 16 bits we intend to write, 15862306a36Sopenharmony_ci * followed by a 32-bit write. If the 16 bits we *don't* intend to 15962306a36Sopenharmony_ci * write happen to have any RW1C (write-one-to-clear) bits set, we 16062306a36Sopenharmony_ci * just inadvertently cleared something we shouldn't have. 16162306a36Sopenharmony_ci */ 16262306a36Sopenharmony_ci if (!bus->unsafe_warn) { 16362306a36Sopenharmony_ci dev_warn(&bus->dev, "%d-byte config write to %04x:%02x:%02x.%d offset %#x may corrupt adjacent RW1C bits\n", 16462306a36Sopenharmony_ci size, pci_domain_nr(bus), bus->number, 16562306a36Sopenharmony_ci PCI_SLOT(devfn), PCI_FUNC(devfn), where); 16662306a36Sopenharmony_ci bus->unsafe_warn = 1; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8)); 17062306a36Sopenharmony_ci tmp = readl(addr) & mask; 17162306a36Sopenharmony_ci tmp |= val << ((where & 0x3) * 8); 17262306a36Sopenharmony_ci writel(tmp, addr); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_generic_config_write32); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/** 17962306a36Sopenharmony_ci * pci_bus_set_ops - Set raw operations of pci bus 18062306a36Sopenharmony_ci * @bus: pci bus struct 18162306a36Sopenharmony_ci * @ops: new raw operations 18262306a36Sopenharmony_ci * 18362306a36Sopenharmony_ci * Return previous raw operations 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_cistruct pci_ops *pci_bus_set_ops(struct pci_bus *bus, struct pci_ops *ops) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct pci_ops *old_ops; 18862306a36Sopenharmony_ci unsigned long flags; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci raw_spin_lock_irqsave(&pci_lock, flags); 19162306a36Sopenharmony_ci old_ops = bus->ops; 19262306a36Sopenharmony_ci bus->ops = ops; 19362306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&pci_lock, flags); 19462306a36Sopenharmony_ci return old_ops; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ciEXPORT_SYMBOL(pci_bus_set_ops); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci/* 19962306a36Sopenharmony_ci * The following routines are to prevent the user from accessing PCI config 20062306a36Sopenharmony_ci * space when it's unsafe to do so. Some devices require this during BIST and 20162306a36Sopenharmony_ci * we're required to prevent it during D-state transitions. 20262306a36Sopenharmony_ci * 20362306a36Sopenharmony_ci * We have a bit per device to indicate it's blocked and a global wait queue 20462306a36Sopenharmony_ci * for callers to sleep on until devices are unblocked. 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(pci_cfg_wait); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic noinline void pci_wait_cfg(struct pci_dev *dev) 20962306a36Sopenharmony_ci __must_hold(&pci_lock) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci do { 21262306a36Sopenharmony_ci raw_spin_unlock_irq(&pci_lock); 21362306a36Sopenharmony_ci wait_event(pci_cfg_wait, !dev->block_cfg_access); 21462306a36Sopenharmony_ci raw_spin_lock_irq(&pci_lock); 21562306a36Sopenharmony_ci } while (dev->block_cfg_access); 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/* Returns 0 on success, negative values indicate error. */ 21962306a36Sopenharmony_ci#define PCI_USER_READ_CONFIG(size, type) \ 22062306a36Sopenharmony_ciint pci_user_read_config_##size \ 22162306a36Sopenharmony_ci (struct pci_dev *dev, int pos, type *val) \ 22262306a36Sopenharmony_ci{ \ 22362306a36Sopenharmony_ci int ret = PCIBIOS_SUCCESSFUL; \ 22462306a36Sopenharmony_ci u32 data = -1; \ 22562306a36Sopenharmony_ci if (PCI_##size##_BAD) \ 22662306a36Sopenharmony_ci return -EINVAL; \ 22762306a36Sopenharmony_ci raw_spin_lock_irq(&pci_lock); \ 22862306a36Sopenharmony_ci if (unlikely(dev->block_cfg_access)) \ 22962306a36Sopenharmony_ci pci_wait_cfg(dev); \ 23062306a36Sopenharmony_ci ret = dev->bus->ops->read(dev->bus, dev->devfn, \ 23162306a36Sopenharmony_ci pos, sizeof(type), &data); \ 23262306a36Sopenharmony_ci raw_spin_unlock_irq(&pci_lock); \ 23362306a36Sopenharmony_ci if (ret) \ 23462306a36Sopenharmony_ci PCI_SET_ERROR_RESPONSE(val); \ 23562306a36Sopenharmony_ci else \ 23662306a36Sopenharmony_ci *val = (type)data; \ 23762306a36Sopenharmony_ci return pcibios_err_to_errno(ret); \ 23862306a36Sopenharmony_ci} \ 23962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_user_read_config_##size); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/* Returns 0 on success, negative values indicate error. */ 24262306a36Sopenharmony_ci#define PCI_USER_WRITE_CONFIG(size, type) \ 24362306a36Sopenharmony_ciint pci_user_write_config_##size \ 24462306a36Sopenharmony_ci (struct pci_dev *dev, int pos, type val) \ 24562306a36Sopenharmony_ci{ \ 24662306a36Sopenharmony_ci int ret = PCIBIOS_SUCCESSFUL; \ 24762306a36Sopenharmony_ci if (PCI_##size##_BAD) \ 24862306a36Sopenharmony_ci return -EINVAL; \ 24962306a36Sopenharmony_ci raw_spin_lock_irq(&pci_lock); \ 25062306a36Sopenharmony_ci if (unlikely(dev->block_cfg_access)) \ 25162306a36Sopenharmony_ci pci_wait_cfg(dev); \ 25262306a36Sopenharmony_ci ret = dev->bus->ops->write(dev->bus, dev->devfn, \ 25362306a36Sopenharmony_ci pos, sizeof(type), val); \ 25462306a36Sopenharmony_ci raw_spin_unlock_irq(&pci_lock); \ 25562306a36Sopenharmony_ci return pcibios_err_to_errno(ret); \ 25662306a36Sopenharmony_ci} \ 25762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_user_write_config_##size); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ciPCI_USER_READ_CONFIG(byte, u8) 26062306a36Sopenharmony_ciPCI_USER_READ_CONFIG(word, u16) 26162306a36Sopenharmony_ciPCI_USER_READ_CONFIG(dword, u32) 26262306a36Sopenharmony_ciPCI_USER_WRITE_CONFIG(byte, u8) 26362306a36Sopenharmony_ciPCI_USER_WRITE_CONFIG(word, u16) 26462306a36Sopenharmony_ciPCI_USER_WRITE_CONFIG(dword, u32) 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci/** 26762306a36Sopenharmony_ci * pci_cfg_access_lock - Lock PCI config reads/writes 26862306a36Sopenharmony_ci * @dev: pci device struct 26962306a36Sopenharmony_ci * 27062306a36Sopenharmony_ci * When access is locked, any userspace reads or writes to config 27162306a36Sopenharmony_ci * space and concurrent lock requests will sleep until access is 27262306a36Sopenharmony_ci * allowed via pci_cfg_access_unlock() again. 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_civoid pci_cfg_access_lock(struct pci_dev *dev) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci might_sleep(); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci raw_spin_lock_irq(&pci_lock); 27962306a36Sopenharmony_ci if (dev->block_cfg_access) 28062306a36Sopenharmony_ci pci_wait_cfg(dev); 28162306a36Sopenharmony_ci dev->block_cfg_access = 1; 28262306a36Sopenharmony_ci raw_spin_unlock_irq(&pci_lock); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_cfg_access_lock); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci/** 28762306a36Sopenharmony_ci * pci_cfg_access_trylock - try to lock PCI config reads/writes 28862306a36Sopenharmony_ci * @dev: pci device struct 28962306a36Sopenharmony_ci * 29062306a36Sopenharmony_ci * Same as pci_cfg_access_lock, but will return 0 if access is 29162306a36Sopenharmony_ci * already locked, 1 otherwise. This function can be used from 29262306a36Sopenharmony_ci * atomic contexts. 29362306a36Sopenharmony_ci */ 29462306a36Sopenharmony_cibool pci_cfg_access_trylock(struct pci_dev *dev) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci unsigned long flags; 29762306a36Sopenharmony_ci bool locked = true; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci raw_spin_lock_irqsave(&pci_lock, flags); 30062306a36Sopenharmony_ci if (dev->block_cfg_access) 30162306a36Sopenharmony_ci locked = false; 30262306a36Sopenharmony_ci else 30362306a36Sopenharmony_ci dev->block_cfg_access = 1; 30462306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&pci_lock, flags); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci return locked; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_cfg_access_trylock); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci/** 31162306a36Sopenharmony_ci * pci_cfg_access_unlock - Unlock PCI config reads/writes 31262306a36Sopenharmony_ci * @dev: pci device struct 31362306a36Sopenharmony_ci * 31462306a36Sopenharmony_ci * This function allows PCI config accesses to resume. 31562306a36Sopenharmony_ci */ 31662306a36Sopenharmony_civoid pci_cfg_access_unlock(struct pci_dev *dev) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci unsigned long flags; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci raw_spin_lock_irqsave(&pci_lock, flags); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* 32362306a36Sopenharmony_ci * This indicates a problem in the caller, but we don't need 32462306a36Sopenharmony_ci * to kill them, unlike a double-block above. 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_ci WARN_ON(!dev->block_cfg_access); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci dev->block_cfg_access = 0; 32962306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&pci_lock, flags); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci wake_up_all(&pci_cfg_wait); 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_cfg_access_unlock); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic inline int pcie_cap_version(const struct pci_dev *dev) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci return pcie_caps_reg(dev) & PCI_EXP_FLAGS_VERS; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cibool pcie_cap_has_lnkctl(const struct pci_dev *dev) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci int type = pci_pcie_type(dev); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return type == PCI_EXP_TYPE_ENDPOINT || 34562306a36Sopenharmony_ci type == PCI_EXP_TYPE_LEG_END || 34662306a36Sopenharmony_ci type == PCI_EXP_TYPE_ROOT_PORT || 34762306a36Sopenharmony_ci type == PCI_EXP_TYPE_UPSTREAM || 34862306a36Sopenharmony_ci type == PCI_EXP_TYPE_DOWNSTREAM || 34962306a36Sopenharmony_ci type == PCI_EXP_TYPE_PCI_BRIDGE || 35062306a36Sopenharmony_ci type == PCI_EXP_TYPE_PCIE_BRIDGE; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cibool pcie_cap_has_lnkctl2(const struct pci_dev *dev) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci return pcie_cap_has_lnkctl(dev) && pcie_cap_version(dev) > 1; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic inline bool pcie_cap_has_sltctl(const struct pci_dev *dev) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci return pcie_downstream_port(dev) && 36162306a36Sopenharmony_ci pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cibool pcie_cap_has_rtctl(const struct pci_dev *dev) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci int type = pci_pcie_type(dev); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return type == PCI_EXP_TYPE_ROOT_PORT || 36962306a36Sopenharmony_ci type == PCI_EXP_TYPE_RC_EC; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci if (!pci_is_pcie(dev)) 37562306a36Sopenharmony_ci return false; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci switch (pos) { 37862306a36Sopenharmony_ci case PCI_EXP_FLAGS: 37962306a36Sopenharmony_ci return true; 38062306a36Sopenharmony_ci case PCI_EXP_DEVCAP: 38162306a36Sopenharmony_ci case PCI_EXP_DEVCTL: 38262306a36Sopenharmony_ci case PCI_EXP_DEVSTA: 38362306a36Sopenharmony_ci return true; 38462306a36Sopenharmony_ci case PCI_EXP_LNKCAP: 38562306a36Sopenharmony_ci case PCI_EXP_LNKCTL: 38662306a36Sopenharmony_ci case PCI_EXP_LNKSTA: 38762306a36Sopenharmony_ci return pcie_cap_has_lnkctl(dev); 38862306a36Sopenharmony_ci case PCI_EXP_SLTCAP: 38962306a36Sopenharmony_ci case PCI_EXP_SLTCTL: 39062306a36Sopenharmony_ci case PCI_EXP_SLTSTA: 39162306a36Sopenharmony_ci return pcie_cap_has_sltctl(dev); 39262306a36Sopenharmony_ci case PCI_EXP_RTCTL: 39362306a36Sopenharmony_ci case PCI_EXP_RTCAP: 39462306a36Sopenharmony_ci case PCI_EXP_RTSTA: 39562306a36Sopenharmony_ci return pcie_cap_has_rtctl(dev); 39662306a36Sopenharmony_ci case PCI_EXP_DEVCAP2: 39762306a36Sopenharmony_ci case PCI_EXP_DEVCTL2: 39862306a36Sopenharmony_ci return pcie_cap_version(dev) > 1; 39962306a36Sopenharmony_ci case PCI_EXP_LNKCAP2: 40062306a36Sopenharmony_ci case PCI_EXP_LNKCTL2: 40162306a36Sopenharmony_ci case PCI_EXP_LNKSTA2: 40262306a36Sopenharmony_ci return pcie_cap_has_lnkctl2(dev); 40362306a36Sopenharmony_ci default: 40462306a36Sopenharmony_ci return false; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci/* 40962306a36Sopenharmony_ci * Note that these accessor functions are only for the "PCI Express 41062306a36Sopenharmony_ci * Capability" (see PCIe spec r3.0, sec 7.8). They do not apply to the 41162306a36Sopenharmony_ci * other "PCI Express Extended Capabilities" (AER, VC, ACS, MFVC, etc.) 41262306a36Sopenharmony_ci */ 41362306a36Sopenharmony_ciint pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci int ret; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci *val = 0; 41862306a36Sopenharmony_ci if (pos & 1) 41962306a36Sopenharmony_ci return PCIBIOS_BAD_REGISTER_NUMBER; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (pcie_capability_reg_implemented(dev, pos)) { 42262306a36Sopenharmony_ci ret = pci_read_config_word(dev, pci_pcie_cap(dev) + pos, val); 42362306a36Sopenharmony_ci /* 42462306a36Sopenharmony_ci * Reset *val to 0 if pci_read_config_word() fails; it may 42562306a36Sopenharmony_ci * have been written as 0xFFFF (PCI_ERROR_RESPONSE) if the 42662306a36Sopenharmony_ci * config read failed on PCI. 42762306a36Sopenharmony_ci */ 42862306a36Sopenharmony_ci if (ret) 42962306a36Sopenharmony_ci *val = 0; 43062306a36Sopenharmony_ci return ret; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci /* 43462306a36Sopenharmony_ci * For Functions that do not implement the Slot Capabilities, 43562306a36Sopenharmony_ci * Slot Status, and Slot Control registers, these spaces must 43662306a36Sopenharmony_ci * be hardwired to 0b, with the exception of the Presence Detect 43762306a36Sopenharmony_ci * State bit in the Slot Status register of Downstream Ports, 43862306a36Sopenharmony_ci * which must be hardwired to 1b. (PCIe Base Spec 3.0, sec 7.8) 43962306a36Sopenharmony_ci */ 44062306a36Sopenharmony_ci if (pci_is_pcie(dev) && pcie_downstream_port(dev) && 44162306a36Sopenharmony_ci pos == PCI_EXP_SLTSTA) 44262306a36Sopenharmony_ci *val = PCI_EXP_SLTSTA_PDS; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci return 0; 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ciEXPORT_SYMBOL(pcie_capability_read_word); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ciint pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci int ret; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci *val = 0; 45362306a36Sopenharmony_ci if (pos & 3) 45462306a36Sopenharmony_ci return PCIBIOS_BAD_REGISTER_NUMBER; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (pcie_capability_reg_implemented(dev, pos)) { 45762306a36Sopenharmony_ci ret = pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, val); 45862306a36Sopenharmony_ci /* 45962306a36Sopenharmony_ci * Reset *val to 0 if pci_read_config_dword() fails; it may 46062306a36Sopenharmony_ci * have been written as 0xFFFFFFFF (PCI_ERROR_RESPONSE) if 46162306a36Sopenharmony_ci * the config read failed on PCI. 46262306a36Sopenharmony_ci */ 46362306a36Sopenharmony_ci if (ret) 46462306a36Sopenharmony_ci *val = 0; 46562306a36Sopenharmony_ci return ret; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (pci_is_pcie(dev) && pcie_downstream_port(dev) && 46962306a36Sopenharmony_ci pos == PCI_EXP_SLTSTA) 47062306a36Sopenharmony_ci *val = PCI_EXP_SLTSTA_PDS; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci return 0; 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ciEXPORT_SYMBOL(pcie_capability_read_dword); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ciint pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci if (pos & 1) 47962306a36Sopenharmony_ci return PCIBIOS_BAD_REGISTER_NUMBER; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if (!pcie_capability_reg_implemented(dev, pos)) 48262306a36Sopenharmony_ci return 0; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci return pci_write_config_word(dev, pci_pcie_cap(dev) + pos, val); 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ciEXPORT_SYMBOL(pcie_capability_write_word); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ciint pcie_capability_write_dword(struct pci_dev *dev, int pos, u32 val) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci if (pos & 3) 49162306a36Sopenharmony_ci return PCIBIOS_BAD_REGISTER_NUMBER; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (!pcie_capability_reg_implemented(dev, pos)) 49462306a36Sopenharmony_ci return 0; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci return pci_write_config_dword(dev, pci_pcie_cap(dev) + pos, val); 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ciEXPORT_SYMBOL(pcie_capability_write_dword); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ciint pcie_capability_clear_and_set_word_unlocked(struct pci_dev *dev, int pos, 50162306a36Sopenharmony_ci u16 clear, u16 set) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci int ret; 50462306a36Sopenharmony_ci u16 val; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci ret = pcie_capability_read_word(dev, pos, &val); 50762306a36Sopenharmony_ci if (ret) 50862306a36Sopenharmony_ci return ret; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci val &= ~clear; 51162306a36Sopenharmony_ci val |= set; 51262306a36Sopenharmony_ci return pcie_capability_write_word(dev, pos, val); 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ciEXPORT_SYMBOL(pcie_capability_clear_and_set_word_unlocked); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ciint pcie_capability_clear_and_set_word_locked(struct pci_dev *dev, int pos, 51762306a36Sopenharmony_ci u16 clear, u16 set) 51862306a36Sopenharmony_ci{ 51962306a36Sopenharmony_ci unsigned long flags; 52062306a36Sopenharmony_ci int ret; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci spin_lock_irqsave(&dev->pcie_cap_lock, flags); 52362306a36Sopenharmony_ci ret = pcie_capability_clear_and_set_word_unlocked(dev, pos, clear, set); 52462306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->pcie_cap_lock, flags); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci return ret; 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ciEXPORT_SYMBOL(pcie_capability_clear_and_set_word_locked); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ciint pcie_capability_clear_and_set_dword(struct pci_dev *dev, int pos, 53162306a36Sopenharmony_ci u32 clear, u32 set) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci int ret; 53462306a36Sopenharmony_ci u32 val; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci ret = pcie_capability_read_dword(dev, pos, &val); 53762306a36Sopenharmony_ci if (ret) 53862306a36Sopenharmony_ci return ret; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci val &= ~clear; 54162306a36Sopenharmony_ci val |= set; 54262306a36Sopenharmony_ci return pcie_capability_write_dword(dev, pos, val); 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ciEXPORT_SYMBOL(pcie_capability_clear_and_set_dword); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ciint pci_read_config_byte(const struct pci_dev *dev, int where, u8 *val) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci if (pci_dev_is_disconnected(dev)) { 54962306a36Sopenharmony_ci PCI_SET_ERROR_RESPONSE(val); 55062306a36Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci return pci_bus_read_config_byte(dev->bus, dev->devfn, where, val); 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ciEXPORT_SYMBOL(pci_read_config_byte); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ciint pci_read_config_word(const struct pci_dev *dev, int where, u16 *val) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci if (pci_dev_is_disconnected(dev)) { 55962306a36Sopenharmony_ci PCI_SET_ERROR_RESPONSE(val); 56062306a36Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci return pci_bus_read_config_word(dev->bus, dev->devfn, where, val); 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ciEXPORT_SYMBOL(pci_read_config_word); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ciint pci_read_config_dword(const struct pci_dev *dev, int where, 56762306a36Sopenharmony_ci u32 *val) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci if (pci_dev_is_disconnected(dev)) { 57062306a36Sopenharmony_ci PCI_SET_ERROR_RESPONSE(val); 57162306a36Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci return pci_bus_read_config_dword(dev->bus, dev->devfn, where, val); 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ciEXPORT_SYMBOL(pci_read_config_dword); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ciint pci_write_config_byte(const struct pci_dev *dev, int where, u8 val) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci if (pci_dev_is_disconnected(dev)) 58062306a36Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 58162306a36Sopenharmony_ci return pci_bus_write_config_byte(dev->bus, dev->devfn, where, val); 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ciEXPORT_SYMBOL(pci_write_config_byte); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ciint pci_write_config_word(const struct pci_dev *dev, int where, u16 val) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci if (pci_dev_is_disconnected(dev)) 58862306a36Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 58962306a36Sopenharmony_ci return pci_bus_write_config_word(dev->bus, dev->devfn, where, val); 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ciEXPORT_SYMBOL(pci_write_config_word); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ciint pci_write_config_dword(const struct pci_dev *dev, int where, 59462306a36Sopenharmony_ci u32 val) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci if (pci_dev_is_disconnected(dev)) 59762306a36Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 59862306a36Sopenharmony_ci return pci_bus_write_config_dword(dev->bus, dev->devfn, where, val); 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ciEXPORT_SYMBOL(pci_write_config_dword); 601