diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2005-10-28 18:57:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-10-28 18:57:32 -0400 |
commit | 7efe5d7c3e3a82e43b0f8fb29c6797317bce7a9a (patch) | |
tree | 2e246004dfc130947574e340a4968239b3f2d20b /drivers/pci/access.c | |
parent | dbe0580d0d2fccf63b0349840a7ae3dbb16f3074 (diff) | |
parent | f8977d0a9b7ac84cfe700278a2ca64cb33c93a13 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/pci-2.6
Diffstat (limited to 'drivers/pci/access.c')
-rw-r--r-- | drivers/pci/access.c | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 24a76de49f41..2a42add7f563 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c | |||
@@ -60,3 +60,92 @@ EXPORT_SYMBOL(pci_bus_read_config_dword); | |||
60 | EXPORT_SYMBOL(pci_bus_write_config_byte); | 60 | EXPORT_SYMBOL(pci_bus_write_config_byte); |
61 | EXPORT_SYMBOL(pci_bus_write_config_word); | 61 | EXPORT_SYMBOL(pci_bus_write_config_word); |
62 | EXPORT_SYMBOL(pci_bus_write_config_dword); | 62 | EXPORT_SYMBOL(pci_bus_write_config_dword); |
63 | |||
64 | static u32 pci_user_cached_config(struct pci_dev *dev, int pos) | ||
65 | { | ||
66 | u32 data; | ||
67 | |||
68 | data = dev->saved_config_space[pos/sizeof(dev->saved_config_space[0])]; | ||
69 | data >>= (pos % sizeof(dev->saved_config_space[0])) * 8; | ||
70 | return data; | ||
71 | } | ||
72 | |||
73 | #define PCI_USER_READ_CONFIG(size,type) \ | ||
74 | int pci_user_read_config_##size \ | ||
75 | (struct pci_dev *dev, int pos, type *val) \ | ||
76 | { \ | ||
77 | unsigned long flags; \ | ||
78 | int ret = 0; \ | ||
79 | u32 data = -1; \ | ||
80 | if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ | ||
81 | spin_lock_irqsave(&pci_lock, flags); \ | ||
82 | if (likely(!dev->block_ucfg_access)) \ | ||
83 | ret = dev->bus->ops->read(dev->bus, dev->devfn, \ | ||
84 | pos, sizeof(type), &data); \ | ||
85 | else if (pos < sizeof(dev->saved_config_space)) \ | ||
86 | data = pci_user_cached_config(dev, pos); \ | ||
87 | spin_unlock_irqrestore(&pci_lock, flags); \ | ||
88 | *val = (type)data; \ | ||
89 | return ret; \ | ||
90 | } | ||
91 | |||
92 | #define PCI_USER_WRITE_CONFIG(size,type) \ | ||
93 | int pci_user_write_config_##size \ | ||
94 | (struct pci_dev *dev, int pos, type val) \ | ||
95 | { \ | ||
96 | unsigned long flags; \ | ||
97 | int ret = -EIO; \ | ||
98 | if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ | ||
99 | spin_lock_irqsave(&pci_lock, flags); \ | ||
100 | if (likely(!dev->block_ucfg_access)) \ | ||
101 | ret = dev->bus->ops->write(dev->bus, dev->devfn, \ | ||
102 | pos, sizeof(type), val); \ | ||
103 | spin_unlock_irqrestore(&pci_lock, flags); \ | ||
104 | return ret; \ | ||
105 | } | ||
106 | |||
107 | PCI_USER_READ_CONFIG(byte, u8) | ||
108 | PCI_USER_READ_CONFIG(word, u16) | ||
109 | PCI_USER_READ_CONFIG(dword, u32) | ||
110 | PCI_USER_WRITE_CONFIG(byte, u8) | ||
111 | PCI_USER_WRITE_CONFIG(word, u16) | ||
112 | PCI_USER_WRITE_CONFIG(dword, u32) | ||
113 | |||
114 | /** | ||
115 | * pci_block_user_cfg_access - Block userspace PCI config reads/writes | ||
116 | * @dev: pci device struct | ||
117 | * | ||
118 | * This function blocks any userspace PCI config accesses from occurring. | ||
119 | * When blocked, any writes will be bit bucketed and reads will return the | ||
120 | * data saved using pci_save_state for the first 64 bytes of config | ||
121 | * space and return 0xff for all other config reads. | ||
122 | **/ | ||
123 | void pci_block_user_cfg_access(struct pci_dev *dev) | ||
124 | { | ||
125 | unsigned long flags; | ||
126 | |||
127 | pci_save_state(dev); | ||
128 | |||
129 | /* spinlock to synchronize with anyone reading config space now */ | ||
130 | spin_lock_irqsave(&pci_lock, flags); | ||
131 | dev->block_ucfg_access = 1; | ||
132 | spin_unlock_irqrestore(&pci_lock, flags); | ||
133 | } | ||
134 | EXPORT_SYMBOL_GPL(pci_block_user_cfg_access); | ||
135 | |||
136 | /** | ||
137 | * pci_unblock_user_cfg_access - Unblock userspace PCI config reads/writes | ||
138 | * @dev: pci device struct | ||
139 | * | ||
140 | * This function allows userspace PCI config accesses to resume. | ||
141 | **/ | ||
142 | void pci_unblock_user_cfg_access(struct pci_dev *dev) | ||
143 | { | ||
144 | unsigned long flags; | ||
145 | |||
146 | /* spinlock to synchronize with anyone reading saved config space */ | ||
147 | spin_lock_irqsave(&pci_lock, flags); | ||
148 | dev->block_ucfg_access = 0; | ||
149 | spin_unlock_irqrestore(&pci_lock, flags); | ||
150 | } | ||
151 | EXPORT_SYMBOL_GPL(pci_unblock_user_cfg_access); | ||