Blame view

drivers/pci/access.c 11.2 KB
94e610880   Ben Hutchings   PCI: Expose PCI V...
1
  #include <linux/delay.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
  #include <linux/pci.h>
  #include <linux/module.h>
f6a570333   Al Viro   [PATCH] severing ...
4
  #include <linux/sched.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
5
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
  #include <linux/ioport.h>
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
7
  #include <linux/wait.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8

48b191487   Adrian Bunk   [PATCH] PCI: driv...
9
  #include "pci.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
  /*
   * This interrupt-safe spinlock protects all accesses to PCI
   * configuration space.
   */
a2e27787f   Jan Kiszka   PCI: Introduce IN...
14
  DEFINE_RAW_SPINLOCK(pci_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  
  /*
   *  Wrappers for all PCI configuration access functions.  They just check
   *  alignment, do locking and call the low-level functions pointed to
   *  by pci_dev->ops.
   */
  
  #define PCI_byte_BAD 0
  #define PCI_word_BAD (pos & 1)
  #define PCI_dword_BAD (pos & 3)
  
  #define PCI_OP_READ(size,type,len) \
  int pci_bus_read_config_##size \
  	(struct pci_bus *bus, unsigned int devfn, int pos, type *value)	\
  {									\
  	int res;							\
  	unsigned long flags;						\
  	u32 data = 0;							\
  	if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;	\
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
34
  	raw_spin_lock_irqsave(&pci_lock, flags);			\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
  	res = bus->ops->read(bus, devfn, pos, len, &data);		\
  	*value = (type)data;						\
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
37
  	raw_spin_unlock_irqrestore(&pci_lock, flags);		\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
42
43
44
45
46
47
  	return res;							\
  }
  
  #define PCI_OP_WRITE(size,type,len) \
  int pci_bus_write_config_##size \
  	(struct pci_bus *bus, unsigned int devfn, int pos, type value)	\
  {									\
  	int res;							\
  	unsigned long flags;						\
  	if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;	\
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
48
  	raw_spin_lock_irqsave(&pci_lock, flags);			\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
  	res = bus->ops->write(bus, devfn, pos, len, value);		\
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
50
  	raw_spin_unlock_irqrestore(&pci_lock, flags);		\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
  	return res;							\
  }
  
  PCI_OP_READ(byte, u8, 1)
  PCI_OP_READ(word, u16, 2)
  PCI_OP_READ(dword, u32, 4)
  PCI_OP_WRITE(byte, u8, 1)
  PCI_OP_WRITE(word, u16, 2)
  PCI_OP_WRITE(dword, u32, 4)
  
  EXPORT_SYMBOL(pci_bus_read_config_byte);
  EXPORT_SYMBOL(pci_bus_read_config_word);
  EXPORT_SYMBOL(pci_bus_read_config_dword);
  EXPORT_SYMBOL(pci_bus_write_config_byte);
  EXPORT_SYMBOL(pci_bus_write_config_word);
  EXPORT_SYMBOL(pci_bus_write_config_dword);
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
67

a72b46c38   Huang Ying   PCI: Add pci_bus_...
68
69
70
71
72
73
74
75
76
77
78
  /**
   * pci_bus_set_ops - Set raw operations of pci bus
   * @bus:	pci bus struct
   * @ops:	new raw operations
   *
   * Return previous raw operations
   */
  struct pci_ops *pci_bus_set_ops(struct pci_bus *bus, struct pci_ops *ops)
  {
  	struct pci_ops *old_ops;
  	unsigned long flags;
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
79
  	raw_spin_lock_irqsave(&pci_lock, flags);
a72b46c38   Huang Ying   PCI: Add pci_bus_...
80
81
  	old_ops = bus->ops;
  	bus->ops = ops;
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
82
  	raw_spin_unlock_irqrestore(&pci_lock, flags);
a72b46c38   Huang Ying   PCI: Add pci_bus_...
83
84
85
  	return old_ops;
  }
  EXPORT_SYMBOL(pci_bus_set_ops);
287d19ce2   Stephen Hemminger   PCI: revise VPD a...
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
  
  /**
   * pci_read_vpd - Read one entry from Vital Product Data
   * @dev:	pci device struct
   * @pos:	offset in vpd space
   * @count:	number of bytes to read
   * @buf:	pointer to where to store result
   *
   */
  ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf)
  {
  	if (!dev->vpd || !dev->vpd->ops)
  		return -ENODEV;
  	return dev->vpd->ops->read(dev, pos, count, buf);
  }
  EXPORT_SYMBOL(pci_read_vpd);
  
  /**
   * pci_write_vpd - Write entry to Vital Product Data
   * @dev:	pci device struct
   * @pos:	offset in vpd space
cffb2fafb   Randy Dunlap   docbooks: add/fix...
107
108
   * @count:	number of bytes to write
   * @buf:	buffer containing write data
287d19ce2   Stephen Hemminger   PCI: revise VPD a...
109
110
111
112
113
114
115
116
117
   *
   */
  ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf)
  {
  	if (!dev->vpd || !dev->vpd->ops)
  		return -ENODEV;
  	return dev->vpd->ops->write(dev, pos, count, buf);
  }
  EXPORT_SYMBOL(pci_write_vpd);
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
118
119
120
121
122
123
124
125
  /*
   * The following routines are to prevent the user from accessing PCI config
   * space when it's unsafe to do so.  Some devices require this during BIST and
   * we're required to prevent it during D-state transitions.
   *
   * We have a bit per device to indicate it's blocked and a global wait queue
   * for callers to sleep on until devices are unblocked.
   */
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
126
  static DECLARE_WAIT_QUEUE_HEAD(pci_cfg_wait);
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
127

fb51ccbf2   Jan Kiszka   PCI: Rework confi...
128
  static noinline void pci_wait_cfg(struct pci_dev *dev)
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
129
130
  {
  	DECLARE_WAITQUEUE(wait, current);
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
131
  	__add_wait_queue(&pci_cfg_wait, &wait);
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
132
133
  	do {
  		set_current_state(TASK_UNINTERRUPTIBLE);
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
134
  		raw_spin_unlock_irq(&pci_lock);
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
135
  		schedule();
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
136
  		raw_spin_lock_irq(&pci_lock);
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
137
138
  	} while (dev->block_cfg_access);
  	__remove_wait_queue(&pci_cfg_wait, &wait);
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
139
  }
34e320720   Greg Thelen   PCI: handle posit...
140
  /* Returns 0 on success, negative values indicate error. */
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
141
142
143
144
  #define PCI_USER_READ_CONFIG(size,type)					\
  int pci_user_read_config_##size						\
  	(struct pci_dev *dev, int pos, type *val)			\
  {									\
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
145
146
  	int ret = 0;							\
  	u32 data = -1;							\
34e320720   Greg Thelen   PCI: handle posit...
147
148
  	if (PCI_##size##_BAD)						\
  		return -EINVAL;						\
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
149
  	raw_spin_lock_irq(&pci_lock);				\
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
150
151
  	if (unlikely(dev->block_cfg_access))				\
  		pci_wait_cfg(dev);					\
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
152
  	ret = dev->bus->ops->read(dev->bus, dev->devfn,			\
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
153
  					pos, sizeof(type), &data);	\
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
154
  	raw_spin_unlock_irq(&pci_lock);				\
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
155
  	*val = (type)data;						\
34e320720   Greg Thelen   PCI: handle posit...
156
157
  	if (ret > 0)							\
  		ret = -EINVAL;						\
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
158
159
  	return ret;							\
  }
34e320720   Greg Thelen   PCI: handle posit...
160
  /* Returns 0 on success, negative values indicate error. */
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
161
162
163
164
  #define PCI_USER_WRITE_CONFIG(size,type)				\
  int pci_user_write_config_##size					\
  	(struct pci_dev *dev, int pos, type val)			\
  {									\
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
165
  	int ret = -EIO;							\
34e320720   Greg Thelen   PCI: handle posit...
166
167
  	if (PCI_##size##_BAD)						\
  		return -EINVAL;						\
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
168
  	raw_spin_lock_irq(&pci_lock);				\
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
169
170
  	if (unlikely(dev->block_cfg_access))				\
  		pci_wait_cfg(dev);					\
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
171
  	ret = dev->bus->ops->write(dev->bus, dev->devfn,		\
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
172
  					pos, sizeof(type), val);	\
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
173
  	raw_spin_unlock_irq(&pci_lock);				\
34e320720   Greg Thelen   PCI: handle posit...
174
175
  	if (ret > 0)							\
  		ret = -EINVAL;						\
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
176
177
178
179
180
181
182
183
184
  	return ret;							\
  }
  
  PCI_USER_READ_CONFIG(byte, u8)
  PCI_USER_READ_CONFIG(word, u16)
  PCI_USER_READ_CONFIG(dword, u32)
  PCI_USER_WRITE_CONFIG(byte, u8)
  PCI_USER_WRITE_CONFIG(word, u16)
  PCI_USER_WRITE_CONFIG(dword, u32)
94e610880   Ben Hutchings   PCI: Expose PCI V...
185
186
187
188
189
190
  /* VPD access through PCI 2.2+ VPD capability */
  
  #define PCI_VPD_PCI22_SIZE (PCI_VPD_ADDR_MASK + 1)
  
  struct pci_vpd_pci22 {
  	struct pci_vpd base;
1120f8b81   Stephen Hemminger   PCI: handle long ...
191
192
  	struct mutex lock;
  	u16	flag;
94e610880   Ben Hutchings   PCI: Expose PCI V...
193
  	bool	busy;
1120f8b81   Stephen Hemminger   PCI: handle long ...
194
  	u8	cap;
94e610880   Ben Hutchings   PCI: Expose PCI V...
195
  };
1120f8b81   Stephen Hemminger   PCI: handle long ...
196
197
198
199
200
  /*
   * Wait for last operation to complete.
   * This code has to spin since there is no other notification from the PCI
   * hardware. Since the VPD is often implemented by serial attachment to an
   * EEPROM, it may take many milliseconds to complete.
34e320720   Greg Thelen   PCI: handle posit...
201
202
   *
   * Returns 0 on success, negative values indicate error.
1120f8b81   Stephen Hemminger   PCI: handle long ...
203
   */
94e610880   Ben Hutchings   PCI: Expose PCI V...
204
205
206
207
  static int pci_vpd_pci22_wait(struct pci_dev *dev)
  {
  	struct pci_vpd_pci22 *vpd =
  		container_of(dev->vpd, struct pci_vpd_pci22, base);
1120f8b81   Stephen Hemminger   PCI: handle long ...
208
209
  	unsigned long timeout = jiffies + HZ/20 + 2;
  	u16 status;
94e610880   Ben Hutchings   PCI: Expose PCI V...
210
211
212
213
  	int ret;
  
  	if (!vpd->busy)
  		return 0;
94e610880   Ben Hutchings   PCI: Expose PCI V...
214
  	for (;;) {
1120f8b81   Stephen Hemminger   PCI: handle long ...
215
  		ret = pci_user_read_config_word(dev, vpd->cap + PCI_VPD_ADDR,
94e610880   Ben Hutchings   PCI: Expose PCI V...
216
  						&status);
34e320720   Greg Thelen   PCI: handle posit...
217
  		if (ret < 0)
94e610880   Ben Hutchings   PCI: Expose PCI V...
218
  			return ret;
1120f8b81   Stephen Hemminger   PCI: handle long ...
219
220
  
  		if ((status & PCI_VPD_ADDR_F) == vpd->flag) {
94e610880   Ben Hutchings   PCI: Expose PCI V...
221
222
223
  			vpd->busy = false;
  			return 0;
  		}
1120f8b81   Stephen Hemminger   PCI: handle long ...
224

5030718ee   Prarit Bhargava   PCI: output FW wa...
225
226
227
228
229
  		if (time_after(jiffies, timeout)) {
  			dev_printk(KERN_DEBUG, &dev->dev,
  				   "vpd r/w failed.  This is likely a firmware "
  				   "bug on this device.  Contact the card "
  				   "vendor for a firmware update.");
94e610880   Ben Hutchings   PCI: Expose PCI V...
230
  			return -ETIMEDOUT;
5030718ee   Prarit Bhargava   PCI: output FW wa...
231
  		}
1120f8b81   Stephen Hemminger   PCI: handle long ...
232
233
234
235
  		if (fatal_signal_pending(current))
  			return -EINTR;
  		if (!cond_resched())
  			udelay(10);
94e610880   Ben Hutchings   PCI: Expose PCI V...
236
237
  	}
  }
287d19ce2   Stephen Hemminger   PCI: revise VPD a...
238
239
  static ssize_t pci_vpd_pci22_read(struct pci_dev *dev, loff_t pos, size_t count,
  				  void *arg)
94e610880   Ben Hutchings   PCI: Expose PCI V...
240
241
242
  {
  	struct pci_vpd_pci22 *vpd =
  		container_of(dev->vpd, struct pci_vpd_pci22, base);
287d19ce2   Stephen Hemminger   PCI: revise VPD a...
243
244
245
  	int ret;
  	loff_t end = pos + count;
  	u8 *buf = arg;
94e610880   Ben Hutchings   PCI: Expose PCI V...
246

287d19ce2   Stephen Hemminger   PCI: revise VPD a...
247
  	if (pos < 0 || pos > vpd->base.len || end > vpd->base.len)
94e610880   Ben Hutchings   PCI: Expose PCI V...
248
  		return -EINVAL;
94e610880   Ben Hutchings   PCI: Expose PCI V...
249

1120f8b81   Stephen Hemminger   PCI: handle long ...
250
251
  	if (mutex_lock_killable(&vpd->lock))
  		return -EINTR;
94e610880   Ben Hutchings   PCI: Expose PCI V...
252
253
254
  	ret = pci_vpd_pci22_wait(dev);
  	if (ret < 0)
  		goto out;
1120f8b81   Stephen Hemminger   PCI: handle long ...
255

287d19ce2   Stephen Hemminger   PCI: revise VPD a...
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
  	while (pos < end) {
  		u32 val;
  		unsigned int i, skip;
  
  		ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR,
  						 pos & ~3);
  		if (ret < 0)
  			break;
  		vpd->busy = true;
  		vpd->flag = PCI_VPD_ADDR_F;
  		ret = pci_vpd_pci22_wait(dev);
  		if (ret < 0)
  			break;
  
  		ret = pci_user_read_config_dword(dev, vpd->cap + PCI_VPD_DATA, &val);
  		if (ret < 0)
  			break;
  
  		skip = pos & 3;
  		for (i = 0;  i < sizeof(u32); i++) {
  			if (i >= skip) {
  				*buf++ = val;
  				if (++pos == end)
  					break;
  			}
  			val >>= 8;
  		}
  	}
94e610880   Ben Hutchings   PCI: Expose PCI V...
284
  out:
1120f8b81   Stephen Hemminger   PCI: handle long ...
285
  	mutex_unlock(&vpd->lock);
287d19ce2   Stephen Hemminger   PCI: revise VPD a...
286
  	return ret ? ret : count;
94e610880   Ben Hutchings   PCI: Expose PCI V...
287
  }
287d19ce2   Stephen Hemminger   PCI: revise VPD a...
288
289
  static ssize_t pci_vpd_pci22_write(struct pci_dev *dev, loff_t pos, size_t count,
  				   const void *arg)
94e610880   Ben Hutchings   PCI: Expose PCI V...
290
291
292
  {
  	struct pci_vpd_pci22 *vpd =
  		container_of(dev->vpd, struct pci_vpd_pci22, base);
287d19ce2   Stephen Hemminger   PCI: revise VPD a...
293
294
  	const u8 *buf = arg;
  	loff_t end = pos + count;
1120f8b81   Stephen Hemminger   PCI: handle long ...
295
  	int ret = 0;
94e610880   Ben Hutchings   PCI: Expose PCI V...
296

287d19ce2   Stephen Hemminger   PCI: revise VPD a...
297
  	if (pos < 0 || (pos & 3) || (count & 3) || end > vpd->base.len)
94e610880   Ben Hutchings   PCI: Expose PCI V...
298
  		return -EINVAL;
1120f8b81   Stephen Hemminger   PCI: handle long ...
299
300
  	if (mutex_lock_killable(&vpd->lock))
  		return -EINTR;
287d19ce2   Stephen Hemminger   PCI: revise VPD a...
301

94e610880   Ben Hutchings   PCI: Expose PCI V...
302
303
304
  	ret = pci_vpd_pci22_wait(dev);
  	if (ret < 0)
  		goto out;
287d19ce2   Stephen Hemminger   PCI: revise VPD a...
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
  
  	while (pos < end) {
  		u32 val;
  
  		val = *buf++;
  		val |= *buf++ << 8;
  		val |= *buf++ << 16;
  		val |= *buf++ << 24;
  
  		ret = pci_user_write_config_dword(dev, vpd->cap + PCI_VPD_DATA, val);
  		if (ret < 0)
  			break;
  		ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR,
  						 pos | PCI_VPD_ADDR_F);
  		if (ret < 0)
  			break;
  
  		vpd->busy = true;
  		vpd->flag = 0;
  		ret = pci_vpd_pci22_wait(dev);
d97ecd819   Greg Thelen   PCI: check pci_vp...
325
326
  		if (ret < 0)
  			break;
287d19ce2   Stephen Hemminger   PCI: revise VPD a...
327
328
329
  
  		pos += sizeof(u32);
  	}
94e610880   Ben Hutchings   PCI: Expose PCI V...
330
  out:
1120f8b81   Stephen Hemminger   PCI: handle long ...
331
  	mutex_unlock(&vpd->lock);
287d19ce2   Stephen Hemminger   PCI: revise VPD a...
332
  	return ret ? ret : count;
94e610880   Ben Hutchings   PCI: Expose PCI V...
333
  }
94e610880   Ben Hutchings   PCI: Expose PCI V...
334
335
336
337
  static void pci_vpd_pci22_release(struct pci_dev *dev)
  {
  	kfree(container_of(dev->vpd, struct pci_vpd_pci22, base));
  }
287d19ce2   Stephen Hemminger   PCI: revise VPD a...
338
  static const struct pci_vpd_ops pci_vpd_pci22_ops = {
94e610880   Ben Hutchings   PCI: Expose PCI V...
339
340
  	.read = pci_vpd_pci22_read,
  	.write = pci_vpd_pci22_write,
94e610880   Ben Hutchings   PCI: Expose PCI V...
341
342
343
344
345
346
347
348
349
350
351
352
353
354
  	.release = pci_vpd_pci22_release,
  };
  
  int pci_vpd_pci22_init(struct pci_dev *dev)
  {
  	struct pci_vpd_pci22 *vpd;
  	u8 cap;
  
  	cap = pci_find_capability(dev, PCI_CAP_ID_VPD);
  	if (!cap)
  		return -ENODEV;
  	vpd = kzalloc(sizeof(*vpd), GFP_ATOMIC);
  	if (!vpd)
  		return -ENOMEM;
99cb233d6   Benjamin Li   PCI: Limit VPD re...
355
  	vpd->base.len = PCI_VPD_PCI22_SIZE;
94e610880   Ben Hutchings   PCI: Expose PCI V...
356
  	vpd->base.ops = &pci_vpd_pci22_ops;
1120f8b81   Stephen Hemminger   PCI: handle long ...
357
  	mutex_init(&vpd->lock);
94e610880   Ben Hutchings   PCI: Expose PCI V...
358
359
360
361
362
  	vpd->cap = cap;
  	vpd->busy = false;
  	dev->vpd = &vpd->base;
  	return 0;
  }
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
363
  /**
db5679437   Stephen Hemminger   PCI: add interfac...
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
   * pci_vpd_truncate - Set available Vital Product Data size
   * @dev:	pci device struct
   * @size:	available memory in bytes
   *
   * Adjust size of available VPD area.
   */
  int pci_vpd_truncate(struct pci_dev *dev, size_t size)
  {
  	if (!dev->vpd)
  		return -EINVAL;
  
  	/* limited by the access method */
  	if (size > dev->vpd->len)
  		return -EINVAL;
  
  	dev->vpd->len = size;
d407e32ef   Anton Vorontsov   PCI: Fix oops in ...
380
381
  	if (dev->vpd->attr)
  		dev->vpd->attr->size = size;
db5679437   Stephen Hemminger   PCI: add interfac...
382
383
384
385
386
387
  
  	return 0;
  }
  EXPORT_SYMBOL(pci_vpd_truncate);
  
  /**
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
388
   * pci_cfg_access_lock - Lock PCI config reads/writes
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
389
390
   * @dev:	pci device struct
   *
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
391
392
393
   * When access is locked, any userspace reads or writes to config
   * space and concurrent lock requests will sleep until access is
   * allowed via pci_cfg_access_unlocked again.
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
394
   */
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
  void pci_cfg_access_lock(struct pci_dev *dev)
  {
  	might_sleep();
  
  	raw_spin_lock_irq(&pci_lock);
  	if (dev->block_cfg_access)
  		pci_wait_cfg(dev);
  	dev->block_cfg_access = 1;
  	raw_spin_unlock_irq(&pci_lock);
  }
  EXPORT_SYMBOL_GPL(pci_cfg_access_lock);
  
  /**
   * pci_cfg_access_trylock - try to lock PCI config reads/writes
   * @dev:	pci device struct
   *
   * Same as pci_cfg_access_lock, but will return 0 if access is
   * already locked, 1 otherwise. This function can be used from
   * atomic contexts.
   */
  bool pci_cfg_access_trylock(struct pci_dev *dev)
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
416
417
  {
  	unsigned long flags;
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
418
  	bool locked = true;
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
419

511dd98ce   Thomas Gleixner   PCI: Convert pci_...
420
  	raw_spin_lock_irqsave(&pci_lock, flags);
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
421
422
423
424
  	if (dev->block_cfg_access)
  		locked = false;
  	else
  		dev->block_cfg_access = 1;
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
425
  	raw_spin_unlock_irqrestore(&pci_lock, flags);
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
426

fb51ccbf2   Jan Kiszka   PCI: Rework confi...
427
  	return locked;
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
428
  }
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
429
  EXPORT_SYMBOL_GPL(pci_cfg_access_trylock);
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
430
431
  
  /**
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
432
   * pci_cfg_access_unlock - Unlock PCI config reads/writes
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
433
434
   * @dev:	pci device struct
   *
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
435
   * This function allows PCI config accesses to resume.
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
436
   */
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
437
  void pci_cfg_access_unlock(struct pci_dev *dev)
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
438
439
  {
  	unsigned long flags;
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
440
  	raw_spin_lock_irqsave(&pci_lock, flags);
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
441
442
443
  
  	/* This indicates a problem in the caller, but we don't need
  	 * to kill them, unlike a double-block above. */
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
444
  	WARN_ON(!dev->block_cfg_access);
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
445

fb51ccbf2   Jan Kiszka   PCI: Rework confi...
446
447
  	dev->block_cfg_access = 0;
  	wake_up_all(&pci_cfg_wait);
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
448
  	raw_spin_unlock_irqrestore(&pci_lock, flags);
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
449
  }
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
450
  EXPORT_SYMBOL_GPL(pci_cfg_access_unlock);