18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/pci.h>
38c2ecf20Sopenharmony_ci#include <linux/module.h>
48c2ecf20Sopenharmony_ci#include <linux/slab.h>
58c2ecf20Sopenharmony_ci#include <linux/ioport.h>
68c2ecf20Sopenharmony_ci#include <linux/wait.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "pci.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci/*
118c2ecf20Sopenharmony_ci * This interrupt-safe spinlock protects all accesses to PCI
128c2ecf20Sopenharmony_ci * configuration space.
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ciDEFINE_RAW_SPINLOCK(pci_lock);
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/*
188c2ecf20Sopenharmony_ci * Wrappers for all PCI configuration access functions.  They just check
198c2ecf20Sopenharmony_ci * alignment, do locking and call the low-level functions pointed to
208c2ecf20Sopenharmony_ci * by pci_dev->ops.
218c2ecf20Sopenharmony_ci */
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define PCI_byte_BAD 0
248c2ecf20Sopenharmony_ci#define PCI_word_BAD (pos & 1)
258c2ecf20Sopenharmony_ci#define PCI_dword_BAD (pos & 3)
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_LOCKLESS_CONFIG
288c2ecf20Sopenharmony_ci# define pci_lock_config(f)	do { (void)(f); } while (0)
298c2ecf20Sopenharmony_ci# define pci_unlock_config(f)	do { (void)(f); } while (0)
308c2ecf20Sopenharmony_ci#else
318c2ecf20Sopenharmony_ci# define pci_lock_config(f)	raw_spin_lock_irqsave(&pci_lock, f)
328c2ecf20Sopenharmony_ci# define pci_unlock_config(f)	raw_spin_unlock_irqrestore(&pci_lock, f)
338c2ecf20Sopenharmony_ci#endif
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define PCI_OP_READ(size, type, len) \
368c2ecf20Sopenharmony_ciint noinline pci_bus_read_config_##size \
378c2ecf20Sopenharmony_ci	(struct pci_bus *bus, unsigned int devfn, int pos, type *value)	\
388c2ecf20Sopenharmony_ci{									\
398c2ecf20Sopenharmony_ci	int res;							\
408c2ecf20Sopenharmony_ci	unsigned long flags;						\
418c2ecf20Sopenharmony_ci	u32 data = 0;							\
428c2ecf20Sopenharmony_ci	if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;	\
438c2ecf20Sopenharmony_ci	pci_lock_config(flags);						\
448c2ecf20Sopenharmony_ci	res = bus->ops->read(bus, devfn, pos, len, &data);		\
458c2ecf20Sopenharmony_ci	*value = (type)data;						\
468c2ecf20Sopenharmony_ci	pci_unlock_config(flags);					\
478c2ecf20Sopenharmony_ci	return res;							\
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#define PCI_OP_WRITE(size, type, len) \
518c2ecf20Sopenharmony_ciint noinline pci_bus_write_config_##size \
528c2ecf20Sopenharmony_ci	(struct pci_bus *bus, unsigned int devfn, int pos, type value)	\
538c2ecf20Sopenharmony_ci{									\
548c2ecf20Sopenharmony_ci	int res;							\
558c2ecf20Sopenharmony_ci	unsigned long flags;						\
568c2ecf20Sopenharmony_ci	if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;	\
578c2ecf20Sopenharmony_ci	pci_lock_config(flags);						\
588c2ecf20Sopenharmony_ci	res = bus->ops->write(bus, devfn, pos, len, value);		\
598c2ecf20Sopenharmony_ci	pci_unlock_config(flags);					\
608c2ecf20Sopenharmony_ci	return res;							\
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ciPCI_OP_READ(byte, u8, 1)
648c2ecf20Sopenharmony_ciPCI_OP_READ(word, u16, 2)
658c2ecf20Sopenharmony_ciPCI_OP_READ(dword, u32, 4)
668c2ecf20Sopenharmony_ciPCI_OP_WRITE(byte, u8, 1)
678c2ecf20Sopenharmony_ciPCI_OP_WRITE(word, u16, 2)
688c2ecf20Sopenharmony_ciPCI_OP_WRITE(dword, u32, 4)
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_bus_read_config_byte);
718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_bus_read_config_word);
728c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_bus_read_config_dword);
738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_bus_write_config_byte);
748c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_bus_write_config_word);
758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_bus_write_config_dword);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ciint pci_generic_config_read(struct pci_bus *bus, unsigned int devfn,
788c2ecf20Sopenharmony_ci			    int where, int size, u32 *val)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	void __iomem *addr;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	addr = bus->ops->map_bus(bus, devfn, where);
838c2ecf20Sopenharmony_ci	if (!addr) {
848c2ecf20Sopenharmony_ci		*val = ~0;
858c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	if (size == 1)
898c2ecf20Sopenharmony_ci		*val = readb(addr);
908c2ecf20Sopenharmony_ci	else if (size == 2)
918c2ecf20Sopenharmony_ci		*val = readw(addr);
928c2ecf20Sopenharmony_ci	else
938c2ecf20Sopenharmony_ci		*val = readl(addr);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_generic_config_read);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ciint pci_generic_config_write(struct pci_bus *bus, unsigned int devfn,
1008c2ecf20Sopenharmony_ci			     int where, int size, u32 val)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	void __iomem *addr;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	addr = bus->ops->map_bus(bus, devfn, where);
1058c2ecf20Sopenharmony_ci	if (!addr)
1068c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	if (size == 1)
1098c2ecf20Sopenharmony_ci		writeb(val, addr);
1108c2ecf20Sopenharmony_ci	else if (size == 2)
1118c2ecf20Sopenharmony_ci		writew(val, addr);
1128c2ecf20Sopenharmony_ci	else
1138c2ecf20Sopenharmony_ci		writel(val, addr);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_generic_config_write);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ciint pci_generic_config_read32(struct pci_bus *bus, unsigned int devfn,
1208c2ecf20Sopenharmony_ci			      int where, int size, u32 *val)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	void __iomem *addr;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	addr = bus->ops->map_bus(bus, devfn, where & ~0x3);
1258c2ecf20Sopenharmony_ci	if (!addr) {
1268c2ecf20Sopenharmony_ci		*val = ~0;
1278c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	*val = readl(addr);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	if (size <= 2)
1338c2ecf20Sopenharmony_ci		*val = (*val >> (8 * (where & 3))) & ((1 << (size * 8)) - 1);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_generic_config_read32);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ciint pci_generic_config_write32(struct pci_bus *bus, unsigned int devfn,
1408c2ecf20Sopenharmony_ci			       int where, int size, u32 val)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	void __iomem *addr;
1438c2ecf20Sopenharmony_ci	u32 mask, tmp;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	addr = bus->ops->map_bus(bus, devfn, where & ~0x3);
1468c2ecf20Sopenharmony_ci	if (!addr)
1478c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	if (size == 4) {
1508c2ecf20Sopenharmony_ci		writel(val, addr);
1518c2ecf20Sopenharmony_ci		return PCIBIOS_SUCCESSFUL;
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	/*
1558c2ecf20Sopenharmony_ci	 * In general, hardware that supports only 32-bit writes on PCI is
1568c2ecf20Sopenharmony_ci	 * not spec-compliant.  For example, software may perform a 16-bit
1578c2ecf20Sopenharmony_ci	 * write.  If the hardware only supports 32-bit accesses, we must
1588c2ecf20Sopenharmony_ci	 * do a 32-bit read, merge in the 16 bits we intend to write,
1598c2ecf20Sopenharmony_ci	 * followed by a 32-bit write.  If the 16 bits we *don't* intend to
1608c2ecf20Sopenharmony_ci	 * write happen to have any RW1C (write-one-to-clear) bits set, we
1618c2ecf20Sopenharmony_ci	 * just inadvertently cleared something we shouldn't have.
1628c2ecf20Sopenharmony_ci	 */
1638c2ecf20Sopenharmony_ci	if (!bus->unsafe_warn) {
1648c2ecf20Sopenharmony_ci		dev_warn(&bus->dev, "%d-byte config write to %04x:%02x:%02x.%d offset %#x may corrupt adjacent RW1C bits\n",
1658c2ecf20Sopenharmony_ci			 size, pci_domain_nr(bus), bus->number,
1668c2ecf20Sopenharmony_ci			 PCI_SLOT(devfn), PCI_FUNC(devfn), where);
1678c2ecf20Sopenharmony_ci		bus->unsafe_warn = 1;
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8));
1718c2ecf20Sopenharmony_ci	tmp = readl(addr) & mask;
1728c2ecf20Sopenharmony_ci	tmp |= val << ((where & 0x3) * 8);
1738c2ecf20Sopenharmony_ci	writel(tmp, addr);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_generic_config_write32);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci/**
1808c2ecf20Sopenharmony_ci * pci_bus_set_ops - Set raw operations of pci bus
1818c2ecf20Sopenharmony_ci * @bus:	pci bus struct
1828c2ecf20Sopenharmony_ci * @ops:	new raw operations
1838c2ecf20Sopenharmony_ci *
1848c2ecf20Sopenharmony_ci * Return previous raw operations
1858c2ecf20Sopenharmony_ci */
1868c2ecf20Sopenharmony_cistruct pci_ops *pci_bus_set_ops(struct pci_bus *bus, struct pci_ops *ops)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	struct pci_ops *old_ops;
1898c2ecf20Sopenharmony_ci	unsigned long flags;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&pci_lock, flags);
1928c2ecf20Sopenharmony_ci	old_ops = bus->ops;
1938c2ecf20Sopenharmony_ci	bus->ops = ops;
1948c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pci_lock, flags);
1958c2ecf20Sopenharmony_ci	return old_ops;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_bus_set_ops);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci/*
2008c2ecf20Sopenharmony_ci * The following routines are to prevent the user from accessing PCI config
2018c2ecf20Sopenharmony_ci * space when it's unsafe to do so.  Some devices require this during BIST and
2028c2ecf20Sopenharmony_ci * we're required to prevent it during D-state transitions.
2038c2ecf20Sopenharmony_ci *
2048c2ecf20Sopenharmony_ci * We have a bit per device to indicate it's blocked and a global wait queue
2058c2ecf20Sopenharmony_ci * for callers to sleep on until devices are unblocked.
2068c2ecf20Sopenharmony_ci */
2078c2ecf20Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(pci_cfg_wait);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic noinline void pci_wait_cfg(struct pci_dev *dev)
2108c2ecf20Sopenharmony_ci	__must_hold(&pci_lock)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	do {
2138c2ecf20Sopenharmony_ci		raw_spin_unlock_irq(&pci_lock);
2148c2ecf20Sopenharmony_ci		wait_event(pci_cfg_wait, !dev->block_cfg_access);
2158c2ecf20Sopenharmony_ci		raw_spin_lock_irq(&pci_lock);
2168c2ecf20Sopenharmony_ci	} while (dev->block_cfg_access);
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci/* Returns 0 on success, negative values indicate error. */
2208c2ecf20Sopenharmony_ci#define PCI_USER_READ_CONFIG(size, type)					\
2218c2ecf20Sopenharmony_ciint pci_user_read_config_##size						\
2228c2ecf20Sopenharmony_ci	(struct pci_dev *dev, int pos, type *val)			\
2238c2ecf20Sopenharmony_ci{									\
2248c2ecf20Sopenharmony_ci	int ret = PCIBIOS_SUCCESSFUL;					\
2258c2ecf20Sopenharmony_ci	u32 data = -1;							\
2268c2ecf20Sopenharmony_ci	if (PCI_##size##_BAD)						\
2278c2ecf20Sopenharmony_ci		return -EINVAL;						\
2288c2ecf20Sopenharmony_ci	raw_spin_lock_irq(&pci_lock);				\
2298c2ecf20Sopenharmony_ci	if (unlikely(dev->block_cfg_access))				\
2308c2ecf20Sopenharmony_ci		pci_wait_cfg(dev);					\
2318c2ecf20Sopenharmony_ci	ret = dev->bus->ops->read(dev->bus, dev->devfn,			\
2328c2ecf20Sopenharmony_ci					pos, sizeof(type), &data);	\
2338c2ecf20Sopenharmony_ci	raw_spin_unlock_irq(&pci_lock);				\
2348c2ecf20Sopenharmony_ci	*val = (type)data;						\
2358c2ecf20Sopenharmony_ci	return pcibios_err_to_errno(ret);				\
2368c2ecf20Sopenharmony_ci}									\
2378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_user_read_config_##size);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci/* Returns 0 on success, negative values indicate error. */
2408c2ecf20Sopenharmony_ci#define PCI_USER_WRITE_CONFIG(size, type)				\
2418c2ecf20Sopenharmony_ciint pci_user_write_config_##size					\
2428c2ecf20Sopenharmony_ci	(struct pci_dev *dev, int pos, type val)			\
2438c2ecf20Sopenharmony_ci{									\
2448c2ecf20Sopenharmony_ci	int ret = PCIBIOS_SUCCESSFUL;					\
2458c2ecf20Sopenharmony_ci	if (PCI_##size##_BAD)						\
2468c2ecf20Sopenharmony_ci		return -EINVAL;						\
2478c2ecf20Sopenharmony_ci	raw_spin_lock_irq(&pci_lock);				\
2488c2ecf20Sopenharmony_ci	if (unlikely(dev->block_cfg_access))				\
2498c2ecf20Sopenharmony_ci		pci_wait_cfg(dev);					\
2508c2ecf20Sopenharmony_ci	ret = dev->bus->ops->write(dev->bus, dev->devfn,		\
2518c2ecf20Sopenharmony_ci					pos, sizeof(type), val);	\
2528c2ecf20Sopenharmony_ci	raw_spin_unlock_irq(&pci_lock);				\
2538c2ecf20Sopenharmony_ci	return pcibios_err_to_errno(ret);				\
2548c2ecf20Sopenharmony_ci}									\
2558c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_user_write_config_##size);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ciPCI_USER_READ_CONFIG(byte, u8)
2588c2ecf20Sopenharmony_ciPCI_USER_READ_CONFIG(word, u16)
2598c2ecf20Sopenharmony_ciPCI_USER_READ_CONFIG(dword, u32)
2608c2ecf20Sopenharmony_ciPCI_USER_WRITE_CONFIG(byte, u8)
2618c2ecf20Sopenharmony_ciPCI_USER_WRITE_CONFIG(word, u16)
2628c2ecf20Sopenharmony_ciPCI_USER_WRITE_CONFIG(dword, u32)
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci/**
2658c2ecf20Sopenharmony_ci * pci_cfg_access_lock - Lock PCI config reads/writes
2668c2ecf20Sopenharmony_ci * @dev:	pci device struct
2678c2ecf20Sopenharmony_ci *
2688c2ecf20Sopenharmony_ci * When access is locked, any userspace reads or writes to config
2698c2ecf20Sopenharmony_ci * space and concurrent lock requests will sleep until access is
2708c2ecf20Sopenharmony_ci * allowed via pci_cfg_access_unlock() again.
2718c2ecf20Sopenharmony_ci */
2728c2ecf20Sopenharmony_civoid pci_cfg_access_lock(struct pci_dev *dev)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	might_sleep();
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	raw_spin_lock_irq(&pci_lock);
2778c2ecf20Sopenharmony_ci	if (dev->block_cfg_access)
2788c2ecf20Sopenharmony_ci		pci_wait_cfg(dev);
2798c2ecf20Sopenharmony_ci	dev->block_cfg_access = 1;
2808c2ecf20Sopenharmony_ci	raw_spin_unlock_irq(&pci_lock);
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_cfg_access_lock);
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci/**
2858c2ecf20Sopenharmony_ci * pci_cfg_access_trylock - try to lock PCI config reads/writes
2868c2ecf20Sopenharmony_ci * @dev:	pci device struct
2878c2ecf20Sopenharmony_ci *
2888c2ecf20Sopenharmony_ci * Same as pci_cfg_access_lock, but will return 0 if access is
2898c2ecf20Sopenharmony_ci * already locked, 1 otherwise. This function can be used from
2908c2ecf20Sopenharmony_ci * atomic contexts.
2918c2ecf20Sopenharmony_ci */
2928c2ecf20Sopenharmony_cibool pci_cfg_access_trylock(struct pci_dev *dev)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	unsigned long flags;
2958c2ecf20Sopenharmony_ci	bool locked = true;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&pci_lock, flags);
2988c2ecf20Sopenharmony_ci	if (dev->block_cfg_access)
2998c2ecf20Sopenharmony_ci		locked = false;
3008c2ecf20Sopenharmony_ci	else
3018c2ecf20Sopenharmony_ci		dev->block_cfg_access = 1;
3028c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pci_lock, flags);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	return locked;
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_cfg_access_trylock);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci/**
3098c2ecf20Sopenharmony_ci * pci_cfg_access_unlock - Unlock PCI config reads/writes
3108c2ecf20Sopenharmony_ci * @dev:	pci device struct
3118c2ecf20Sopenharmony_ci *
3128c2ecf20Sopenharmony_ci * This function allows PCI config accesses to resume.
3138c2ecf20Sopenharmony_ci */
3148c2ecf20Sopenharmony_civoid pci_cfg_access_unlock(struct pci_dev *dev)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	unsigned long flags;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&pci_lock, flags);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	/*
3218c2ecf20Sopenharmony_ci	 * This indicates a problem in the caller, but we don't need
3228c2ecf20Sopenharmony_ci	 * to kill them, unlike a double-block above.
3238c2ecf20Sopenharmony_ci	 */
3248c2ecf20Sopenharmony_ci	WARN_ON(!dev->block_cfg_access);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	dev->block_cfg_access = 0;
3278c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pci_lock, flags);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	wake_up_all(&pci_cfg_wait);
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_cfg_access_unlock);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic inline int pcie_cap_version(const struct pci_dev *dev)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	return pcie_caps_reg(dev) & PCI_EXP_FLAGS_VERS;
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cibool pcie_cap_has_lnkctl(const struct pci_dev *dev)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci	int type = pci_pcie_type(dev);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	return type == PCI_EXP_TYPE_ENDPOINT ||
3438c2ecf20Sopenharmony_ci	       type == PCI_EXP_TYPE_LEG_END ||
3448c2ecf20Sopenharmony_ci	       type == PCI_EXP_TYPE_ROOT_PORT ||
3458c2ecf20Sopenharmony_ci	       type == PCI_EXP_TYPE_UPSTREAM ||
3468c2ecf20Sopenharmony_ci	       type == PCI_EXP_TYPE_DOWNSTREAM ||
3478c2ecf20Sopenharmony_ci	       type == PCI_EXP_TYPE_PCI_BRIDGE ||
3488c2ecf20Sopenharmony_ci	       type == PCI_EXP_TYPE_PCIE_BRIDGE;
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_cistatic inline bool pcie_cap_has_sltctl(const struct pci_dev *dev)
3528c2ecf20Sopenharmony_ci{
3538c2ecf20Sopenharmony_ci	return pcie_downstream_port(dev) &&
3548c2ecf20Sopenharmony_ci	       pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT;
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cibool pcie_cap_has_rtctl(const struct pci_dev *dev)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	int type = pci_pcie_type(dev);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	return type == PCI_EXP_TYPE_ROOT_PORT ||
3628c2ecf20Sopenharmony_ci	       type == PCI_EXP_TYPE_RC_EC;
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cistatic bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	if (!pci_is_pcie(dev))
3688c2ecf20Sopenharmony_ci		return false;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	switch (pos) {
3718c2ecf20Sopenharmony_ci	case PCI_EXP_FLAGS:
3728c2ecf20Sopenharmony_ci		return true;
3738c2ecf20Sopenharmony_ci	case PCI_EXP_DEVCAP:
3748c2ecf20Sopenharmony_ci	case PCI_EXP_DEVCTL:
3758c2ecf20Sopenharmony_ci	case PCI_EXP_DEVSTA:
3768c2ecf20Sopenharmony_ci		return true;
3778c2ecf20Sopenharmony_ci	case PCI_EXP_LNKCAP:
3788c2ecf20Sopenharmony_ci	case PCI_EXP_LNKCTL:
3798c2ecf20Sopenharmony_ci	case PCI_EXP_LNKSTA:
3808c2ecf20Sopenharmony_ci		return pcie_cap_has_lnkctl(dev);
3818c2ecf20Sopenharmony_ci	case PCI_EXP_SLTCAP:
3828c2ecf20Sopenharmony_ci	case PCI_EXP_SLTCTL:
3838c2ecf20Sopenharmony_ci	case PCI_EXP_SLTSTA:
3848c2ecf20Sopenharmony_ci		return pcie_cap_has_sltctl(dev);
3858c2ecf20Sopenharmony_ci	case PCI_EXP_RTCTL:
3868c2ecf20Sopenharmony_ci	case PCI_EXP_RTCAP:
3878c2ecf20Sopenharmony_ci	case PCI_EXP_RTSTA:
3888c2ecf20Sopenharmony_ci		return pcie_cap_has_rtctl(dev);
3898c2ecf20Sopenharmony_ci	case PCI_EXP_DEVCAP2:
3908c2ecf20Sopenharmony_ci	case PCI_EXP_DEVCTL2:
3918c2ecf20Sopenharmony_ci	case PCI_EXP_LNKCAP2:
3928c2ecf20Sopenharmony_ci	case PCI_EXP_LNKCTL2:
3938c2ecf20Sopenharmony_ci	case PCI_EXP_LNKSTA2:
3948c2ecf20Sopenharmony_ci		return pcie_cap_version(dev) > 1;
3958c2ecf20Sopenharmony_ci	default:
3968c2ecf20Sopenharmony_ci		return false;
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci/*
4018c2ecf20Sopenharmony_ci * Note that these accessor functions are only for the "PCI Express
4028c2ecf20Sopenharmony_ci * Capability" (see PCIe spec r3.0, sec 7.8).  They do not apply to the
4038c2ecf20Sopenharmony_ci * other "PCI Express Extended Capabilities" (AER, VC, ACS, MFVC, etc.)
4048c2ecf20Sopenharmony_ci */
4058c2ecf20Sopenharmony_ciint pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	int ret;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	*val = 0;
4108c2ecf20Sopenharmony_ci	if (pos & 1)
4118c2ecf20Sopenharmony_ci		return PCIBIOS_BAD_REGISTER_NUMBER;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	if (pcie_capability_reg_implemented(dev, pos)) {
4148c2ecf20Sopenharmony_ci		ret = pci_read_config_word(dev, pci_pcie_cap(dev) + pos, val);
4158c2ecf20Sopenharmony_ci		/*
4168c2ecf20Sopenharmony_ci		 * Reset *val to 0 if pci_read_config_word() fails, it may
4178c2ecf20Sopenharmony_ci		 * have been written as 0xFFFF if hardware error happens
4188c2ecf20Sopenharmony_ci		 * during pci_read_config_word().
4198c2ecf20Sopenharmony_ci		 */
4208c2ecf20Sopenharmony_ci		if (ret)
4218c2ecf20Sopenharmony_ci			*val = 0;
4228c2ecf20Sopenharmony_ci		return ret;
4238c2ecf20Sopenharmony_ci	}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	/*
4268c2ecf20Sopenharmony_ci	 * For Functions that do not implement the Slot Capabilities,
4278c2ecf20Sopenharmony_ci	 * Slot Status, and Slot Control registers, these spaces must
4288c2ecf20Sopenharmony_ci	 * be hardwired to 0b, with the exception of the Presence Detect
4298c2ecf20Sopenharmony_ci	 * State bit in the Slot Status register of Downstream Ports,
4308c2ecf20Sopenharmony_ci	 * which must be hardwired to 1b.  (PCIe Base Spec 3.0, sec 7.8)
4318c2ecf20Sopenharmony_ci	 */
4328c2ecf20Sopenharmony_ci	if (pci_is_pcie(dev) && pcie_downstream_port(dev) &&
4338c2ecf20Sopenharmony_ci	    pos == PCI_EXP_SLTSTA)
4348c2ecf20Sopenharmony_ci		*val = PCI_EXP_SLTSTA_PDS;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	return 0;
4378c2ecf20Sopenharmony_ci}
4388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcie_capability_read_word);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ciint pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	int ret;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	*val = 0;
4458c2ecf20Sopenharmony_ci	if (pos & 3)
4468c2ecf20Sopenharmony_ci		return PCIBIOS_BAD_REGISTER_NUMBER;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	if (pcie_capability_reg_implemented(dev, pos)) {
4498c2ecf20Sopenharmony_ci		ret = pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, val);
4508c2ecf20Sopenharmony_ci		/*
4518c2ecf20Sopenharmony_ci		 * Reset *val to 0 if pci_read_config_dword() fails, it may
4528c2ecf20Sopenharmony_ci		 * have been written as 0xFFFFFFFF if hardware error happens
4538c2ecf20Sopenharmony_ci		 * during pci_read_config_dword().
4548c2ecf20Sopenharmony_ci		 */
4558c2ecf20Sopenharmony_ci		if (ret)
4568c2ecf20Sopenharmony_ci			*val = 0;
4578c2ecf20Sopenharmony_ci		return ret;
4588c2ecf20Sopenharmony_ci	}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	if (pci_is_pcie(dev) && pcie_downstream_port(dev) &&
4618c2ecf20Sopenharmony_ci	    pos == PCI_EXP_SLTSTA)
4628c2ecf20Sopenharmony_ci		*val = PCI_EXP_SLTSTA_PDS;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	return 0;
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcie_capability_read_dword);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ciint pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	if (pos & 1)
4718c2ecf20Sopenharmony_ci		return PCIBIOS_BAD_REGISTER_NUMBER;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	if (!pcie_capability_reg_implemented(dev, pos))
4748c2ecf20Sopenharmony_ci		return 0;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	return pci_write_config_word(dev, pci_pcie_cap(dev) + pos, val);
4778c2ecf20Sopenharmony_ci}
4788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcie_capability_write_word);
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ciint pcie_capability_write_dword(struct pci_dev *dev, int pos, u32 val)
4818c2ecf20Sopenharmony_ci{
4828c2ecf20Sopenharmony_ci	if (pos & 3)
4838c2ecf20Sopenharmony_ci		return PCIBIOS_BAD_REGISTER_NUMBER;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	if (!pcie_capability_reg_implemented(dev, pos))
4868c2ecf20Sopenharmony_ci		return 0;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	return pci_write_config_dword(dev, pci_pcie_cap(dev) + pos, val);
4898c2ecf20Sopenharmony_ci}
4908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcie_capability_write_dword);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ciint pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos,
4938c2ecf20Sopenharmony_ci				       u16 clear, u16 set)
4948c2ecf20Sopenharmony_ci{
4958c2ecf20Sopenharmony_ci	int ret;
4968c2ecf20Sopenharmony_ci	u16 val;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	ret = pcie_capability_read_word(dev, pos, &val);
4998c2ecf20Sopenharmony_ci	if (!ret) {
5008c2ecf20Sopenharmony_ci		val &= ~clear;
5018c2ecf20Sopenharmony_ci		val |= set;
5028c2ecf20Sopenharmony_ci		ret = pcie_capability_write_word(dev, pos, val);
5038c2ecf20Sopenharmony_ci	}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	return ret;
5068c2ecf20Sopenharmony_ci}
5078c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcie_capability_clear_and_set_word);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ciint pcie_capability_clear_and_set_dword(struct pci_dev *dev, int pos,
5108c2ecf20Sopenharmony_ci					u32 clear, u32 set)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	int ret;
5138c2ecf20Sopenharmony_ci	u32 val;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	ret = pcie_capability_read_dword(dev, pos, &val);
5168c2ecf20Sopenharmony_ci	if (!ret) {
5178c2ecf20Sopenharmony_ci		val &= ~clear;
5188c2ecf20Sopenharmony_ci		val |= set;
5198c2ecf20Sopenharmony_ci		ret = pcie_capability_write_dword(dev, pos, val);
5208c2ecf20Sopenharmony_ci	}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	return ret;
5238c2ecf20Sopenharmony_ci}
5248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcie_capability_clear_and_set_dword);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ciint pci_read_config_byte(const struct pci_dev *dev, int where, u8 *val)
5278c2ecf20Sopenharmony_ci{
5288c2ecf20Sopenharmony_ci	if (pci_dev_is_disconnected(dev)) {
5298c2ecf20Sopenharmony_ci		*val = ~0;
5308c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
5318c2ecf20Sopenharmony_ci	}
5328c2ecf20Sopenharmony_ci	return pci_bus_read_config_byte(dev->bus, dev->devfn, where, val);
5338c2ecf20Sopenharmony_ci}
5348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_read_config_byte);
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ciint pci_read_config_word(const struct pci_dev *dev, int where, u16 *val)
5378c2ecf20Sopenharmony_ci{
5388c2ecf20Sopenharmony_ci	if (pci_dev_is_disconnected(dev)) {
5398c2ecf20Sopenharmony_ci		*val = ~0;
5408c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci	return pci_bus_read_config_word(dev->bus, dev->devfn, where, val);
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_read_config_word);
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ciint pci_read_config_dword(const struct pci_dev *dev, int where,
5478c2ecf20Sopenharmony_ci					u32 *val)
5488c2ecf20Sopenharmony_ci{
5498c2ecf20Sopenharmony_ci	if (pci_dev_is_disconnected(dev)) {
5508c2ecf20Sopenharmony_ci		*val = ~0;
5518c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
5528c2ecf20Sopenharmony_ci	}
5538c2ecf20Sopenharmony_ci	return pci_bus_read_config_dword(dev->bus, dev->devfn, where, val);
5548c2ecf20Sopenharmony_ci}
5558c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_read_config_dword);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ciint pci_write_config_byte(const struct pci_dev *dev, int where, u8 val)
5588c2ecf20Sopenharmony_ci{
5598c2ecf20Sopenharmony_ci	if (pci_dev_is_disconnected(dev))
5608c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
5618c2ecf20Sopenharmony_ci	return pci_bus_write_config_byte(dev->bus, dev->devfn, where, val);
5628c2ecf20Sopenharmony_ci}
5638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_write_config_byte);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ciint pci_write_config_word(const struct pci_dev *dev, int where, u16 val)
5668c2ecf20Sopenharmony_ci{
5678c2ecf20Sopenharmony_ci	if (pci_dev_is_disconnected(dev))
5688c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
5698c2ecf20Sopenharmony_ci	return pci_bus_write_config_word(dev->bus, dev->devfn, where, val);
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_write_config_word);
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ciint pci_write_config_dword(const struct pci_dev *dev, int where,
5748c2ecf20Sopenharmony_ci					 u32 val)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	if (pci_dev_is_disconnected(dev))
5778c2ecf20Sopenharmony_ci		return PCIBIOS_DEVICE_NOT_FOUND;
5788c2ecf20Sopenharmony_ci	return pci_bus_write_config_dword(dev->bus, dev->devfn, where, val);
5798c2ecf20Sopenharmony_ci}
5808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_write_config_dword);
581