194e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings#include <linux/delay.h> 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 4f6a570333e554b48ad589e7137c77c57809eee81Al Viro#include <linux/sched.h> 55a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 77ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox#include <linux/wait.h> 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 948b19148733b4826eeedfd8be9f19b61c8d010b1Adrian Bunk#include "pci.h" 1048b19148733b4826eeedfd8be9f19b61c8d010b1Adrian Bunk 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This interrupt-safe spinlock protects all accesses to PCI 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configuration space. 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16a2e27787f893621c5a6b865acf6b7766f8671328Jan KiszkaDEFINE_RAW_SPINLOCK(pci_lock); 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wrappers for all PCI configuration access functions. They just check 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * alignment, do locking and call the low-level functions pointed to 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by pci_dev->ops. 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PCI_byte_BAD 0 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PCI_word_BAD (pos & 1) 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PCI_dword_BAD (pos & 3) 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PCI_OP_READ(size,type,len) \ 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint pci_bus_read_config_##size \ 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (struct pci_bus *bus, unsigned int devfn, int pos, type *value) \ 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; \ 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; \ 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 data = 0; \ 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ 36511dd98ce8cf6dc4f8f2cb32a8af31ce9f4ba4a1Thomas Gleixner raw_spin_lock_irqsave(&pci_lock, flags); \ 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = bus->ops->read(bus, devfn, pos, len, &data); \ 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *value = (type)data; \ 39511dd98ce8cf6dc4f8f2cb32a8af31ce9f4ba4a1Thomas Gleixner raw_spin_unlock_irqrestore(&pci_lock, flags); \ 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; \ 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PCI_OP_WRITE(size,type,len) \ 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint pci_bus_write_config_##size \ 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (struct pci_bus *bus, unsigned int devfn, int pos, type value) \ 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; \ 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; \ 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ 50511dd98ce8cf6dc4f8f2cb32a8af31ce9f4ba4a1Thomas Gleixner raw_spin_lock_irqsave(&pci_lock, flags); \ 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = bus->ops->write(bus, devfn, pos, len, value); \ 52511dd98ce8cf6dc4f8f2cb32a8af31ce9f4ba4a1Thomas Gleixner raw_spin_unlock_irqrestore(&pci_lock, flags); \ 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; \ 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsPCI_OP_READ(byte, u8, 1) 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsPCI_OP_READ(word, u16, 2) 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsPCI_OP_READ(dword, u32, 4) 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsPCI_OP_WRITE(byte, u8, 1) 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsPCI_OP_WRITE(word, u16, 2) 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsPCI_OP_WRITE(dword, u32, 4) 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pci_bus_read_config_byte); 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pci_bus_read_config_word); 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pci_bus_read_config_dword); 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pci_bus_write_config_byte); 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pci_bus_write_config_word); 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pci_bus_write_config_dword); 69e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King 70a72b46c3849cdb05993015991bde548ab8b6d7acHuang Ying/** 71a72b46c3849cdb05993015991bde548ab8b6d7acHuang Ying * pci_bus_set_ops - Set raw operations of pci bus 72a72b46c3849cdb05993015991bde548ab8b6d7acHuang Ying * @bus: pci bus struct 73a72b46c3849cdb05993015991bde548ab8b6d7acHuang Ying * @ops: new raw operations 74a72b46c3849cdb05993015991bde548ab8b6d7acHuang Ying * 75a72b46c3849cdb05993015991bde548ab8b6d7acHuang Ying * Return previous raw operations 76a72b46c3849cdb05993015991bde548ab8b6d7acHuang Ying */ 77a72b46c3849cdb05993015991bde548ab8b6d7acHuang Yingstruct pci_ops *pci_bus_set_ops(struct pci_bus *bus, struct pci_ops *ops) 78a72b46c3849cdb05993015991bde548ab8b6d7acHuang Ying{ 79a72b46c3849cdb05993015991bde548ab8b6d7acHuang Ying struct pci_ops *old_ops; 80a72b46c3849cdb05993015991bde548ab8b6d7acHuang Ying unsigned long flags; 81a72b46c3849cdb05993015991bde548ab8b6d7acHuang Ying 82511dd98ce8cf6dc4f8f2cb32a8af31ce9f4ba4a1Thomas Gleixner raw_spin_lock_irqsave(&pci_lock, flags); 83a72b46c3849cdb05993015991bde548ab8b6d7acHuang Ying old_ops = bus->ops; 84a72b46c3849cdb05993015991bde548ab8b6d7acHuang Ying bus->ops = ops; 85511dd98ce8cf6dc4f8f2cb32a8af31ce9f4ba4a1Thomas Gleixner raw_spin_unlock_irqrestore(&pci_lock, flags); 86a72b46c3849cdb05993015991bde548ab8b6d7acHuang Ying return old_ops; 87a72b46c3849cdb05993015991bde548ab8b6d7acHuang Ying} 88a72b46c3849cdb05993015991bde548ab8b6d7acHuang YingEXPORT_SYMBOL(pci_bus_set_ops); 89287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger 90287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger/** 91287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger * pci_read_vpd - Read one entry from Vital Product Data 92287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger * @dev: pci device struct 93287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger * @pos: offset in vpd space 94287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger * @count: number of bytes to read 95287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger * @buf: pointer to where to store result 96287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger * 97287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger */ 98287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemmingerssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf) 99287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger{ 100287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger if (!dev->vpd || !dev->vpd->ops) 101287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger return -ENODEV; 102287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger return dev->vpd->ops->read(dev, pos, count, buf); 103287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger} 104287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen HemmingerEXPORT_SYMBOL(pci_read_vpd); 105287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger 106287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger/** 107287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger * pci_write_vpd - Write entry to Vital Product Data 108287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger * @dev: pci device struct 109287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger * @pos: offset in vpd space 110cffb2fafb726c898fec1c5ae33717741f94fda83Randy Dunlap * @count: number of bytes to write 111cffb2fafb726c898fec1c5ae33717741f94fda83Randy Dunlap * @buf: buffer containing write data 112287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger * 113287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger */ 114287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemmingerssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf) 115287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger{ 116287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger if (!dev->vpd || !dev->vpd->ops) 117287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger return -ENODEV; 118287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger return dev->vpd->ops->write(dev, pos, count, buf); 119287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger} 120287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen HemmingerEXPORT_SYMBOL(pci_write_vpd); 121287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger 1227ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox/* 1237ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox * The following routines are to prevent the user from accessing PCI config 1247ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox * space when it's unsafe to do so. Some devices require this during BIST and 1257ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox * we're required to prevent it during D-state transitions. 1267ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox * 1277ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox * We have a bit per device to indicate it's blocked and a global wait queue 1287ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox * for callers to sleep on until devices are unblocked. 1297ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox */ 130fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszkastatic DECLARE_WAIT_QUEUE_HEAD(pci_cfg_wait); 131e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King 132fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszkastatic noinline void pci_wait_cfg(struct pci_dev *dev) 1337ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox{ 1347ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox DECLARE_WAITQUEUE(wait, current); 1357ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox 136fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka __add_wait_queue(&pci_cfg_wait, &wait); 1377ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox do { 1387ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox set_current_state(TASK_UNINTERRUPTIBLE); 139511dd98ce8cf6dc4f8f2cb32a8af31ce9f4ba4a1Thomas Gleixner raw_spin_unlock_irq(&pci_lock); 1407ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox schedule(); 141511dd98ce8cf6dc4f8f2cb32a8af31ce9f4ba4a1Thomas Gleixner raw_spin_lock_irq(&pci_lock); 142fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka } while (dev->block_cfg_access); 143fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka __remove_wait_queue(&pci_cfg_wait, &wait); 144e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King} 145e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King 14634e3207205ef492451cc5c53694d4772a9728b9fGreg Thelen/* Returns 0 on success, negative values indicate error. */ 147e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King#define PCI_USER_READ_CONFIG(size,type) \ 148e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian Kingint pci_user_read_config_##size \ 149e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King (struct pci_dev *dev, int pos, type *val) \ 150e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King{ \ 151e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King int ret = 0; \ 152e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King u32 data = -1; \ 15334e3207205ef492451cc5c53694d4772a9728b9fGreg Thelen if (PCI_##size##_BAD) \ 15434e3207205ef492451cc5c53694d4772a9728b9fGreg Thelen return -EINVAL; \ 155511dd98ce8cf6dc4f8f2cb32a8af31ce9f4ba4a1Thomas Gleixner raw_spin_lock_irq(&pci_lock); \ 156fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka if (unlikely(dev->block_cfg_access)) \ 157fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka pci_wait_cfg(dev); \ 1587ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox ret = dev->bus->ops->read(dev->bus, dev->devfn, \ 159e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King pos, sizeof(type), &data); \ 160511dd98ce8cf6dc4f8f2cb32a8af31ce9f4ba4a1Thomas Gleixner raw_spin_unlock_irq(&pci_lock); \ 161e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King *val = (type)data; \ 16234e3207205ef492451cc5c53694d4772a9728b9fGreg Thelen if (ret > 0) \ 16334e3207205ef492451cc5c53694d4772a9728b9fGreg Thelen ret = -EINVAL; \ 164e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King return ret; \ 165e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King} 166e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King 16734e3207205ef492451cc5c53694d4772a9728b9fGreg Thelen/* Returns 0 on success, negative values indicate error. */ 168e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King#define PCI_USER_WRITE_CONFIG(size,type) \ 169e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian Kingint pci_user_write_config_##size \ 170e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King (struct pci_dev *dev, int pos, type val) \ 171e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King{ \ 172e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King int ret = -EIO; \ 17334e3207205ef492451cc5c53694d4772a9728b9fGreg Thelen if (PCI_##size##_BAD) \ 17434e3207205ef492451cc5c53694d4772a9728b9fGreg Thelen return -EINVAL; \ 175511dd98ce8cf6dc4f8f2cb32a8af31ce9f4ba4a1Thomas Gleixner raw_spin_lock_irq(&pci_lock); \ 176fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka if (unlikely(dev->block_cfg_access)) \ 177fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka pci_wait_cfg(dev); \ 1787ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox ret = dev->bus->ops->write(dev->bus, dev->devfn, \ 179e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King pos, sizeof(type), val); \ 180511dd98ce8cf6dc4f8f2cb32a8af31ce9f4ba4a1Thomas Gleixner raw_spin_unlock_irq(&pci_lock); \ 18134e3207205ef492451cc5c53694d4772a9728b9fGreg Thelen if (ret > 0) \ 18234e3207205ef492451cc5c53694d4772a9728b9fGreg Thelen ret = -EINVAL; \ 183e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King return ret; \ 184e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King} 185e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King 186e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian KingPCI_USER_READ_CONFIG(byte, u8) 187e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian KingPCI_USER_READ_CONFIG(word, u16) 188e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian KingPCI_USER_READ_CONFIG(dword, u32) 189e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian KingPCI_USER_WRITE_CONFIG(byte, u8) 190e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian KingPCI_USER_WRITE_CONFIG(word, u16) 191e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian KingPCI_USER_WRITE_CONFIG(dword, u32) 192e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King 19394e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings/* VPD access through PCI 2.2+ VPD capability */ 19494e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings 19594e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings#define PCI_VPD_PCI22_SIZE (PCI_VPD_ADDR_MASK + 1) 19694e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings 19794e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchingsstruct pci_vpd_pci22 { 19894e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings struct pci_vpd base; 1991120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger struct mutex lock; 2001120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger u16 flag; 20194e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings bool busy; 2021120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger u8 cap; 20394e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings}; 20494e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings 2051120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger/* 2061120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger * Wait for last operation to complete. 2071120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger * This code has to spin since there is no other notification from the PCI 2081120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger * hardware. Since the VPD is often implemented by serial attachment to an 2091120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger * EEPROM, it may take many milliseconds to complete. 21034e3207205ef492451cc5c53694d4772a9728b9fGreg Thelen * 21134e3207205ef492451cc5c53694d4772a9728b9fGreg Thelen * Returns 0 on success, negative values indicate error. 2121120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger */ 21394e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchingsstatic int pci_vpd_pci22_wait(struct pci_dev *dev) 21494e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings{ 21594e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings struct pci_vpd_pci22 *vpd = 21694e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings container_of(dev->vpd, struct pci_vpd_pci22, base); 2171120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger unsigned long timeout = jiffies + HZ/20 + 2; 2181120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger u16 status; 21994e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings int ret; 22094e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings 22194e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings if (!vpd->busy) 22294e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings return 0; 22394e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings 22494e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings for (;;) { 2251120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger ret = pci_user_read_config_word(dev, vpd->cap + PCI_VPD_ADDR, 22694e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings &status); 22734e3207205ef492451cc5c53694d4772a9728b9fGreg Thelen if (ret < 0) 22894e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings return ret; 2291120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger 2301120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger if ((status & PCI_VPD_ADDR_F) == vpd->flag) { 23194e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings vpd->busy = false; 23294e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings return 0; 23394e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings } 2341120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger 2355030718ee465c759c2a851851e79039f58b9efb3Prarit Bhargava if (time_after(jiffies, timeout)) { 2365030718ee465c759c2a851851e79039f58b9efb3Prarit Bhargava dev_printk(KERN_DEBUG, &dev->dev, 2375030718ee465c759c2a851851e79039f58b9efb3Prarit Bhargava "vpd r/w failed. This is likely a firmware " 2385030718ee465c759c2a851851e79039f58b9efb3Prarit Bhargava "bug on this device. Contact the card " 2395030718ee465c759c2a851851e79039f58b9efb3Prarit Bhargava "vendor for a firmware update."); 24094e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings return -ETIMEDOUT; 2415030718ee465c759c2a851851e79039f58b9efb3Prarit Bhargava } 2421120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger if (fatal_signal_pending(current)) 2431120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger return -EINTR; 2441120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger if (!cond_resched()) 2451120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger udelay(10); 24694e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings } 24794e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings} 24894e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings 249287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemmingerstatic ssize_t pci_vpd_pci22_read(struct pci_dev *dev, loff_t pos, size_t count, 250287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger void *arg) 25194e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings{ 25294e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings struct pci_vpd_pci22 *vpd = 25394e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings container_of(dev->vpd, struct pci_vpd_pci22, base); 254287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger int ret; 255287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger loff_t end = pos + count; 256287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger u8 *buf = arg; 25794e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings 258287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger if (pos < 0 || pos > vpd->base.len || end > vpd->base.len) 25994e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings return -EINVAL; 26094e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings 2611120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger if (mutex_lock_killable(&vpd->lock)) 2621120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger return -EINTR; 2631120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger 26494e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings ret = pci_vpd_pci22_wait(dev); 26594e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings if (ret < 0) 26694e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings goto out; 2671120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger 268287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger while (pos < end) { 269287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger u32 val; 270287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger unsigned int i, skip; 271287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger 272287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR, 273287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger pos & ~3); 274287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger if (ret < 0) 275287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger break; 276287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger vpd->busy = true; 277287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger vpd->flag = PCI_VPD_ADDR_F; 278287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger ret = pci_vpd_pci22_wait(dev); 279287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger if (ret < 0) 280287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger break; 281287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger 282287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger ret = pci_user_read_config_dword(dev, vpd->cap + PCI_VPD_DATA, &val); 283287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger if (ret < 0) 284287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger break; 285287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger 286287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger skip = pos & 3; 287287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger for (i = 0; i < sizeof(u32); i++) { 288287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger if (i >= skip) { 289287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger *buf++ = val; 290287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger if (++pos == end) 291287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger break; 292287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger } 293287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger val >>= 8; 294287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger } 295287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger } 29694e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchingsout: 2971120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger mutex_unlock(&vpd->lock); 298287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger return ret ? ret : count; 29994e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings} 30094e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings 301287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemmingerstatic ssize_t pci_vpd_pci22_write(struct pci_dev *dev, loff_t pos, size_t count, 302287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger const void *arg) 30394e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings{ 30494e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings struct pci_vpd_pci22 *vpd = 30594e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings container_of(dev->vpd, struct pci_vpd_pci22, base); 306287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger const u8 *buf = arg; 307287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger loff_t end = pos + count; 3081120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger int ret = 0; 30994e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings 310287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger if (pos < 0 || (pos & 3) || (count & 3) || end > vpd->base.len) 31194e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings return -EINVAL; 31294e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings 3131120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger if (mutex_lock_killable(&vpd->lock)) 3141120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger return -EINTR; 315287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger 31694e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings ret = pci_vpd_pci22_wait(dev); 31794e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings if (ret < 0) 31894e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings goto out; 319287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger 320287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger while (pos < end) { 321287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger u32 val; 322287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger 323287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger val = *buf++; 324287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger val |= *buf++ << 8; 325287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger val |= *buf++ << 16; 326287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger val |= *buf++ << 24; 327287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger 328287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger ret = pci_user_write_config_dword(dev, vpd->cap + PCI_VPD_DATA, val); 329287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger if (ret < 0) 330287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger break; 331287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR, 332287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger pos | PCI_VPD_ADDR_F); 333287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger if (ret < 0) 334287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger break; 335287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger 336287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger vpd->busy = true; 337287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger vpd->flag = 0; 338287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger ret = pci_vpd_pci22_wait(dev); 339d97ecd819137118b4686a753415f93215a6edacfGreg Thelen if (ret < 0) 340d97ecd819137118b4686a753415f93215a6edacfGreg Thelen break; 341287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger 342287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger pos += sizeof(u32); 343287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger } 34494e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchingsout: 3451120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger mutex_unlock(&vpd->lock); 346287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemminger return ret ? ret : count; 34794e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings} 34894e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings 34994e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchingsstatic void pci_vpd_pci22_release(struct pci_dev *dev) 35094e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings{ 35194e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings kfree(container_of(dev->vpd, struct pci_vpd_pci22, base)); 35294e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings} 35394e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings 354287d19ce2e67c15e79a187b3bdcbbea1a0a51a7dStephen Hemmingerstatic const struct pci_vpd_ops pci_vpd_pci22_ops = { 35594e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings .read = pci_vpd_pci22_read, 35694e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings .write = pci_vpd_pci22_write, 35794e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings .release = pci_vpd_pci22_release, 35894e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings}; 35994e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings 36094e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchingsint pci_vpd_pci22_init(struct pci_dev *dev) 36194e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings{ 36294e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings struct pci_vpd_pci22 *vpd; 36394e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings u8 cap; 36494e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings 36594e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings cap = pci_find_capability(dev, PCI_CAP_ID_VPD); 36694e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings if (!cap) 36794e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings return -ENODEV; 36894e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings vpd = kzalloc(sizeof(*vpd), GFP_ATOMIC); 36994e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings if (!vpd) 37094e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings return -ENOMEM; 37194e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings 37299cb233d60cbe644203f19938c729ea2bb004d70Benjamin Li vpd->base.len = PCI_VPD_PCI22_SIZE; 37394e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings vpd->base.ops = &pci_vpd_pci22_ops; 3741120f8b8169fb2cb51219d326892d963e762edb6Stephen Hemminger mutex_init(&vpd->lock); 37594e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings vpd->cap = cap; 37694e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings vpd->busy = false; 37794e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings dev->vpd = &vpd->base; 37894e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings return 0; 37994e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings} 38094e6108803469a37ee1e3c92dafdd1d59298602fBen Hutchings 381e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King/** 382db5679437a2b938c9127480a3923633721583a4fStephen Hemminger * pci_vpd_truncate - Set available Vital Product Data size 383db5679437a2b938c9127480a3923633721583a4fStephen Hemminger * @dev: pci device struct 384db5679437a2b938c9127480a3923633721583a4fStephen Hemminger * @size: available memory in bytes 385db5679437a2b938c9127480a3923633721583a4fStephen Hemminger * 386db5679437a2b938c9127480a3923633721583a4fStephen Hemminger * Adjust size of available VPD area. 387db5679437a2b938c9127480a3923633721583a4fStephen Hemminger */ 388db5679437a2b938c9127480a3923633721583a4fStephen Hemmingerint pci_vpd_truncate(struct pci_dev *dev, size_t size) 389db5679437a2b938c9127480a3923633721583a4fStephen Hemminger{ 390db5679437a2b938c9127480a3923633721583a4fStephen Hemminger if (!dev->vpd) 391db5679437a2b938c9127480a3923633721583a4fStephen Hemminger return -EINVAL; 392db5679437a2b938c9127480a3923633721583a4fStephen Hemminger 393db5679437a2b938c9127480a3923633721583a4fStephen Hemminger /* limited by the access method */ 394db5679437a2b938c9127480a3923633721583a4fStephen Hemminger if (size > dev->vpd->len) 395db5679437a2b938c9127480a3923633721583a4fStephen Hemminger return -EINVAL; 396db5679437a2b938c9127480a3923633721583a4fStephen Hemminger 397db5679437a2b938c9127480a3923633721583a4fStephen Hemminger dev->vpd->len = size; 398d407e32efe060afa2b9a797a91376ebc65b4ce11Anton Vorontsov if (dev->vpd->attr) 399d407e32efe060afa2b9a797a91376ebc65b4ce11Anton Vorontsov dev->vpd->attr->size = size; 400db5679437a2b938c9127480a3923633721583a4fStephen Hemminger 401db5679437a2b938c9127480a3923633721583a4fStephen Hemminger return 0; 402db5679437a2b938c9127480a3923633721583a4fStephen Hemminger} 403db5679437a2b938c9127480a3923633721583a4fStephen HemmingerEXPORT_SYMBOL(pci_vpd_truncate); 404db5679437a2b938c9127480a3923633721583a4fStephen Hemminger 405db5679437a2b938c9127480a3923633721583a4fStephen Hemminger/** 406fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka * pci_cfg_access_lock - Lock PCI config reads/writes 407e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King * @dev: pci device struct 408e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King * 409fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka * When access is locked, any userspace reads or writes to config 410fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka * space and concurrent lock requests will sleep until access is 411fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka * allowed via pci_cfg_access_unlocked again. 4127ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox */ 413fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszkavoid pci_cfg_access_lock(struct pci_dev *dev) 414fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka{ 415fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka might_sleep(); 416fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka 417fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka raw_spin_lock_irq(&pci_lock); 418fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka if (dev->block_cfg_access) 419fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka pci_wait_cfg(dev); 420fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka dev->block_cfg_access = 1; 421fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka raw_spin_unlock_irq(&pci_lock); 422fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka} 423fb51ccbf217c1c994607b6519c7d85250928553dJan KiszkaEXPORT_SYMBOL_GPL(pci_cfg_access_lock); 424fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka 425fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka/** 426fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka * pci_cfg_access_trylock - try to lock PCI config reads/writes 427fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka * @dev: pci device struct 428fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka * 429fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka * Same as pci_cfg_access_lock, but will return 0 if access is 430fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka * already locked, 1 otherwise. This function can be used from 431fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka * atomic contexts. 432fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka */ 433fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszkabool pci_cfg_access_trylock(struct pci_dev *dev) 434e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King{ 435e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King unsigned long flags; 436fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka bool locked = true; 437e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King 438511dd98ce8cf6dc4f8f2cb32a8af31ce9f4ba4a1Thomas Gleixner raw_spin_lock_irqsave(&pci_lock, flags); 439fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka if (dev->block_cfg_access) 440fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka locked = false; 441fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka else 442fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka dev->block_cfg_access = 1; 443511dd98ce8cf6dc4f8f2cb32a8af31ce9f4ba4a1Thomas Gleixner raw_spin_unlock_irqrestore(&pci_lock, flags); 4447ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox 445fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka return locked; 446e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King} 447fb51ccbf217c1c994607b6519c7d85250928553dJan KiszkaEXPORT_SYMBOL_GPL(pci_cfg_access_trylock); 448e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King 449e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King/** 450fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka * pci_cfg_access_unlock - Unlock PCI config reads/writes 451e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King * @dev: pci device struct 452e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King * 453fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka * This function allows PCI config accesses to resume. 4547ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox */ 455fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszkavoid pci_cfg_access_unlock(struct pci_dev *dev) 456e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King{ 457e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King unsigned long flags; 458e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King 459511dd98ce8cf6dc4f8f2cb32a8af31ce9f4ba4a1Thomas Gleixner raw_spin_lock_irqsave(&pci_lock, flags); 4607ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox 4617ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox /* This indicates a problem in the caller, but we don't need 4627ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox * to kill them, unlike a double-block above. */ 463fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka WARN_ON(!dev->block_cfg_access); 4647ea7e98fd8d02351c43ef4ab35d70f3aaa26c31dMatthew Wilcox 465fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka dev->block_cfg_access = 0; 466fb51ccbf217c1c994607b6519c7d85250928553dJan Kiszka wake_up_all(&pci_cfg_wait); 467511dd98ce8cf6dc4f8f2cb32a8af31ce9f4ba4a1Thomas Gleixner raw_spin_unlock_irqrestore(&pci_lock, flags); 468e04b0ea2e0f9c1bb0d874db4493fc7f7a623116bBrian King} 469fb51ccbf217c1c994607b6519c7d85250928553dJan KiszkaEXPORT_SYMBOL_GPL(pci_cfg_access_unlock); 470