Blame view

drivers/pci/access.c 14.8 KB
7328c8f48   Bjorn Helgaas   PCI: Add SPDX GPL...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
  #include <linux/pci.h>
  #include <linux/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
4
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
  #include <linux/ioport.h>
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
6
  #include <linux/wait.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7

48b191487   Adrian Bunk   [PATCH] PCI: driv...
8
  #include "pci.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
  /*
   * This interrupt-safe spinlock protects all accesses to PCI
   * configuration space.
   */
a2e27787f   Jan Kiszka   PCI: Introduce IN...
13
  DEFINE_RAW_SPINLOCK(pci_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
  
  /*
df62ab5e0   Bjorn Helgaas   PCI: Tidy comments
16
17
18
   * 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.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
22
23
   */
  
  #define PCI_byte_BAD 0
  #define PCI_word_BAD (pos & 1)
  #define PCI_dword_BAD (pos & 3)
714fe383d   Thomas Gleixner   PCI: Provide Kcon...
24
25
26
27
28
29
30
  #ifdef CONFIG_PCI_LOCKLESS_CONFIG
  # define pci_lock_config(f)	do { (void)(f); } while (0)
  # define pci_unlock_config(f)	do { (void)(f); } while (0)
  #else
  # define pci_lock_config(f)	raw_spin_lock_irqsave(&pci_lock, f)
  # define pci_unlock_config(f)	raw_spin_unlock_irqrestore(&pci_lock, f)
  #endif
ff3ce480e   Bogicevic Sasa   PCI: Fix all whit...
31
  #define PCI_OP_READ(size, type, len) \
5180fd913   Keith Busch   PCI: Uninline PCI...
32
  int noinline pci_bus_read_config_##size \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
35
36
37
38
  	(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;	\
714fe383d   Thomas Gleixner   PCI: Provide Kcon...
39
  	pci_lock_config(flags);						\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
  	res = bus->ops->read(bus, devfn, pos, len, &data);		\
  	*value = (type)data;						\
714fe383d   Thomas Gleixner   PCI: Provide Kcon...
42
  	pci_unlock_config(flags);					\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
  	return res;							\
  }
ff3ce480e   Bogicevic Sasa   PCI: Fix all whit...
45
  #define PCI_OP_WRITE(size, type, len) \
5180fd913   Keith Busch   PCI: Uninline PCI...
46
  int noinline pci_bus_write_config_##size \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
51
  	(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;	\
714fe383d   Thomas Gleixner   PCI: Provide Kcon...
52
  	pci_lock_config(flags);						\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  	res = bus->ops->write(bus, devfn, pos, len, value);		\
714fe383d   Thomas Gleixner   PCI: Provide Kcon...
54
  	pci_unlock_config(flags);					\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  	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...
71

1f94a94f6   Rob Herring   PCI: Add generic ...
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
  int pci_generic_config_read(struct pci_bus *bus, unsigned int devfn,
  			    int where, int size, u32 *val)
  {
  	void __iomem *addr;
  
  	addr = bus->ops->map_bus(bus, devfn, where);
  	if (!addr) {
  		*val = ~0;
  		return PCIBIOS_DEVICE_NOT_FOUND;
  	}
  
  	if (size == 1)
  		*val = readb(addr);
  	else if (size == 2)
  		*val = readw(addr);
  	else
  		*val = readl(addr);
  
  	return PCIBIOS_SUCCESSFUL;
  }
  EXPORT_SYMBOL_GPL(pci_generic_config_read);
  
  int pci_generic_config_write(struct pci_bus *bus, unsigned int devfn,
  			     int where, int size, u32 val)
  {
  	void __iomem *addr;
  
  	addr = bus->ops->map_bus(bus, devfn, where);
  	if (!addr)
  		return PCIBIOS_DEVICE_NOT_FOUND;
  
  	if (size == 1)
  		writeb(val, addr);
  	else if (size == 2)
  		writew(val, addr);
  	else
  		writel(val, addr);
  
  	return PCIBIOS_SUCCESSFUL;
  }
  EXPORT_SYMBOL_GPL(pci_generic_config_write);
  
  int pci_generic_config_read32(struct pci_bus *bus, unsigned int devfn,
  			      int where, int size, u32 *val)
  {
  	void __iomem *addr;
  
  	addr = bus->ops->map_bus(bus, devfn, where & ~0x3);
  	if (!addr) {
  		*val = ~0;
  		return PCIBIOS_DEVICE_NOT_FOUND;
  	}
  
  	*val = readl(addr);
  
  	if (size <= 2)
  		*val = (*val >> (8 * (where & 3))) & ((1 << (size * 8)) - 1);
  
  	return PCIBIOS_SUCCESSFUL;
  }
  EXPORT_SYMBOL_GPL(pci_generic_config_read32);
  
  int pci_generic_config_write32(struct pci_bus *bus, unsigned int devfn,
  			       int where, int size, u32 val)
  {
  	void __iomem *addr;
  	u32 mask, tmp;
  
  	addr = bus->ops->map_bus(bus, devfn, where & ~0x3);
  	if (!addr)
  		return PCIBIOS_DEVICE_NOT_FOUND;
  
  	if (size == 4) {
  		writel(val, addr);
  		return PCIBIOS_SUCCESSFUL;
1f94a94f6   Rob Herring   PCI: Add generic ...
147
  	}
fb2659230   Bjorn Helgaas   PCI: Warn on poss...
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  	/*
  	 * In general, hardware that supports only 32-bit writes on PCI is
  	 * not spec-compliant.  For example, software may perform a 16-bit
  	 * write.  If the hardware only supports 32-bit accesses, we must
  	 * do a 32-bit read, merge in the 16 bits we intend to write,
  	 * followed by a 32-bit write.  If the 16 bits we *don't* intend to
  	 * write happen to have any RW1C (write-one-to-clear) bits set, we
  	 * just inadvertently cleared something we shouldn't have.
  	 */
  	dev_warn_ratelimited(&bus->dev, "%d-byte config write to %04x:%02x:%02x.%d offset %#x may corrupt adjacent RW1C bits
  ",
  			     size, pci_domain_nr(bus), bus->number,
  			     PCI_SLOT(devfn), PCI_FUNC(devfn), where);
  
  	mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8));
1f94a94f6   Rob Herring   PCI: Add generic ...
163
164
165
166
167
168
169
  	tmp = readl(addr) & mask;
  	tmp |= val << ((where & 0x3) * 8);
  	writel(tmp, addr);
  
  	return PCIBIOS_SUCCESSFUL;
  }
  EXPORT_SYMBOL_GPL(pci_generic_config_write32);
a72b46c38   Huang Ying   PCI: Add pci_bus_...
170
171
172
173
174
175
176
177
178
179
180
  /**
   * 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_...
181
  	raw_spin_lock_irqsave(&pci_lock, flags);
a72b46c38   Huang Ying   PCI: Add pci_bus_...
182
183
  	old_ops = bus->ops;
  	bus->ops = ops;
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
184
  	raw_spin_unlock_irqrestore(&pci_lock, flags);
a72b46c38   Huang Ying   PCI: Add pci_bus_...
185
186
187
  	return old_ops;
  }
  EXPORT_SYMBOL(pci_bus_set_ops);
287d19ce2   Stephen Hemminger   PCI: revise VPD a...
188

7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
189
190
191
192
193
194
195
196
  /*
   * 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...
197
  static DECLARE_WAIT_QUEUE_HEAD(pci_cfg_wait);
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
198

fb51ccbf2   Jan Kiszka   PCI: Rework confi...
199
  static noinline void pci_wait_cfg(struct pci_dev *dev)
cc5f55c46   Bjorn Helgaas   PCI: Fix pci_cfg_...
200
  	__must_hold(&pci_lock)
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
201
  {
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
202
  	do {
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
203
  		raw_spin_unlock_irq(&pci_lock);
cc5f55c46   Bjorn Helgaas   PCI: Fix pci_cfg_...
204
  		wait_event(pci_cfg_wait, !dev->block_cfg_access);
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
205
  		raw_spin_lock_irq(&pci_lock);
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
206
  	} while (dev->block_cfg_access);
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
207
  }
34e320720   Greg Thelen   PCI: handle posit...
208
  /* Returns 0 on success, negative values indicate error. */
ff3ce480e   Bogicevic Sasa   PCI: Fix all whit...
209
  #define PCI_USER_READ_CONFIG(size, type)					\
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
210
211
212
  int pci_user_read_config_##size						\
  	(struct pci_dev *dev, int pos, type *val)			\
  {									\
d97ffe236   Gavin Shan   PCI: Fix return v...
213
  	int ret = PCIBIOS_SUCCESSFUL;					\
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
214
  	u32 data = -1;							\
34e320720   Greg Thelen   PCI: handle posit...
215
216
  	if (PCI_##size##_BAD)						\
  		return -EINVAL;						\
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
217
  	raw_spin_lock_irq(&pci_lock);				\
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
218
219
  	if (unlikely(dev->block_cfg_access))				\
  		pci_wait_cfg(dev);					\
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
220
  	ret = dev->bus->ops->read(dev->bus, dev->devfn,			\
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
221
  					pos, sizeof(type), &data);	\
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
222
  	raw_spin_unlock_irq(&pci_lock);				\
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
223
  	*val = (type)data;						\
d97ffe236   Gavin Shan   PCI: Fix return v...
224
  	return pcibios_err_to_errno(ret);				\
c63587d7f   Alex Williamson   PCI: export pci_u...
225
226
  }									\
  EXPORT_SYMBOL_GPL(pci_user_read_config_##size);
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
227

34e320720   Greg Thelen   PCI: handle posit...
228
  /* Returns 0 on success, negative values indicate error. */
ff3ce480e   Bogicevic Sasa   PCI: Fix all whit...
229
  #define PCI_USER_WRITE_CONFIG(size, type)				\
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
230
231
232
  int pci_user_write_config_##size					\
  	(struct pci_dev *dev, int pos, type val)			\
  {									\
d97ffe236   Gavin Shan   PCI: Fix return v...
233
  	int ret = PCIBIOS_SUCCESSFUL;					\
34e320720   Greg Thelen   PCI: handle posit...
234
235
  	if (PCI_##size##_BAD)						\
  		return -EINVAL;						\
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
236
  	raw_spin_lock_irq(&pci_lock);				\
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
237
238
  	if (unlikely(dev->block_cfg_access))				\
  		pci_wait_cfg(dev);					\
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
239
  	ret = dev->bus->ops->write(dev->bus, dev->devfn,		\
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
240
  					pos, sizeof(type), val);	\
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
241
  	raw_spin_unlock_irq(&pci_lock);				\
d97ffe236   Gavin Shan   PCI: Fix return v...
242
  	return pcibios_err_to_errno(ret);				\
c63587d7f   Alex Williamson   PCI: export pci_u...
243
244
  }									\
  EXPORT_SYMBOL_GPL(pci_user_write_config_##size);
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
245
246
247
248
249
250
251
252
253
  
  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)
  
  /**
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
254
   * pci_cfg_access_lock - Lock PCI config reads/writes
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
255
256
   * @dev:	pci device struct
   *
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
257
258
   * When access is locked, any userspace reads or writes to config
   * space and concurrent lock requests will sleep until access is
0b131b139   Brian Norris   PCI: Fix typo pci...
259
   * allowed via pci_cfg_access_unlock() again.
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
260
   */
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
  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...
282
283
  {
  	unsigned long flags;
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
284
  	bool locked = true;
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
285

511dd98ce   Thomas Gleixner   PCI: Convert pci_...
286
  	raw_spin_lock_irqsave(&pci_lock, flags);
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
287
288
289
290
  	if (dev->block_cfg_access)
  		locked = false;
  	else
  		dev->block_cfg_access = 1;
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
291
  	raw_spin_unlock_irqrestore(&pci_lock, flags);
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
292

fb51ccbf2   Jan Kiszka   PCI: Rework confi...
293
  	return locked;
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
294
  }
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
295
  EXPORT_SYMBOL_GPL(pci_cfg_access_trylock);
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
296
297
  
  /**
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
298
   * pci_cfg_access_unlock - Unlock PCI config reads/writes
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
299
300
   * @dev:	pci device struct
   *
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
301
   * This function allows PCI config accesses to resume.
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
302
   */
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
303
  void pci_cfg_access_unlock(struct pci_dev *dev)
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
304
305
  {
  	unsigned long flags;
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
306
  	raw_spin_lock_irqsave(&pci_lock, flags);
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
307

df62ab5e0   Bjorn Helgaas   PCI: Tidy comments
308
309
310
311
  	/*
  	 * 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...
312
  	WARN_ON(!dev->block_cfg_access);
7ea7e98fd   Matthew Wilcox   PCI: Block on acc...
313

fb51ccbf2   Jan Kiszka   PCI: Rework confi...
314
  	dev->block_cfg_access = 0;
511dd98ce   Thomas Gleixner   PCI: Convert pci_...
315
  	raw_spin_unlock_irqrestore(&pci_lock, flags);
cdcb33f98   Bjorn Helgaas   PCI: Avoid possib...
316
317
  
  	wake_up_all(&pci_cfg_wait);
e04b0ea2e   Brian King   [PATCH] PCI: Bloc...
318
  }
fb51ccbf2   Jan Kiszka   PCI: Rework confi...
319
  EXPORT_SYMBOL_GPL(pci_cfg_access_unlock);
8c0d3a02c   Jiang Liu   PCI: Add accessor...
320
321
322
  
  static inline int pcie_cap_version(const struct pci_dev *dev)
  {
1c531d82e   Myron Stowe   PCI: Use PCI Expr...
323
  	return pcie_caps_reg(dev) & PCI_EXP_FLAGS_VERS;
8c0d3a02c   Jiang Liu   PCI: Add accessor...
324
  }
7a1562d4f   Yinghai Lu   PCI: Apply _HPX L...
325
  bool pcie_cap_has_lnkctl(const struct pci_dev *dev)
8c0d3a02c   Jiang Liu   PCI: Add accessor...
326
327
  {
  	int type = pci_pcie_type(dev);
c8b303d02   Bjorn Helgaas   PCI: Remove PCIe ...
328
  	return type == PCI_EXP_TYPE_ENDPOINT ||
d3694d4fa   Bjorn Helgaas   PCI: Allow PCIe C...
329
330
331
332
333
334
  	       type == PCI_EXP_TYPE_LEG_END ||
  	       type == PCI_EXP_TYPE_ROOT_PORT ||
  	       type == PCI_EXP_TYPE_UPSTREAM ||
  	       type == PCI_EXP_TYPE_DOWNSTREAM ||
  	       type == PCI_EXP_TYPE_PCI_BRIDGE ||
  	       type == PCI_EXP_TYPE_PCIE_BRIDGE;
8c0d3a02c   Jiang Liu   PCI: Add accessor...
335
336
337
338
  }
  
  static inline bool pcie_cap_has_sltctl(const struct pci_dev *dev)
  {
ffb4d6026   Bjorn Helgaas   PCI: Add pcie_dow...
339
  	return pcie_downstream_port(dev) &&
6d3a1741f   Bjorn Helgaas   PCI: Support PCIe...
340
  	       pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT;
8c0d3a02c   Jiang Liu   PCI: Add accessor...
341
342
343
344
345
  }
  
  static inline bool pcie_cap_has_rtctl(const struct pci_dev *dev)
  {
  	int type = pci_pcie_type(dev);
c8b303d02   Bjorn Helgaas   PCI: Remove PCIe ...
346
  	return type == PCI_EXP_TYPE_ROOT_PORT ||
8c0d3a02c   Jiang Liu   PCI: Add accessor...
347
348
349
350
351
352
353
354
355
  	       type == PCI_EXP_TYPE_RC_EC;
  }
  
  static bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos)
  {
  	if (!pci_is_pcie(dev))
  		return false;
  
  	switch (pos) {
969daa349   Alex Williamson   PCI: Fix PCI Expr...
356
  	case PCI_EXP_FLAGS:
8c0d3a02c   Jiang Liu   PCI: Add accessor...
357
358
359
360
  		return true;
  	case PCI_EXP_DEVCAP:
  	case PCI_EXP_DEVCTL:
  	case PCI_EXP_DEVSTA:
fed245151   Bjorn Helgaas   PCI: Remove pcie_...
361
  		return true;
8c0d3a02c   Jiang Liu   PCI: Add accessor...
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  	case PCI_EXP_LNKCAP:
  	case PCI_EXP_LNKCTL:
  	case PCI_EXP_LNKSTA:
  		return pcie_cap_has_lnkctl(dev);
  	case PCI_EXP_SLTCAP:
  	case PCI_EXP_SLTCTL:
  	case PCI_EXP_SLTSTA:
  		return pcie_cap_has_sltctl(dev);
  	case PCI_EXP_RTCTL:
  	case PCI_EXP_RTCAP:
  	case PCI_EXP_RTSTA:
  		return pcie_cap_has_rtctl(dev);
  	case PCI_EXP_DEVCAP2:
  	case PCI_EXP_DEVCTL2:
  	case PCI_EXP_LNKCAP2:
  	case PCI_EXP_LNKCTL2:
  	case PCI_EXP_LNKSTA2:
  		return pcie_cap_version(dev) > 1;
  	default:
  		return false;
  	}
  }
  
  /*
   * Note that these accessor functions are only for the "PCI Express
   * Capability" (see PCIe spec r3.0, sec 7.8).  They do not apply to the
   * other "PCI Express Extended Capabilities" (AER, VC, ACS, MFVC, etc.)
   */
  int pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val)
  {
  	int ret;
  
  	*val = 0;
  	if (pos & 1)
  		return -EINVAL;
  
  	if (pcie_capability_reg_implemented(dev, pos)) {
  		ret = pci_read_config_word(dev, pci_pcie_cap(dev) + pos, val);
  		/*
  		 * Reset *val to 0 if pci_read_config_word() fails, it may
  		 * have been written as 0xFFFF if hardware error happens
  		 * during pci_read_config_word().
  		 */
  		if (ret)
  			*val = 0;
  		return ret;
  	}
  
  	/*
  	 * For Functions that do not implement the Slot Capabilities,
  	 * Slot Status, and Slot Control registers, these spaces must
  	 * be hardwired to 0b, with the exception of the Presence Detect
  	 * State bit in the Slot Status register of Downstream Ports,
  	 * which must be hardwired to 1b.  (PCIe Base Spec 3.0, sec 7.8)
  	 */
ffb4d6026   Bjorn Helgaas   PCI: Add pcie_dow...
417
418
  	if (pci_is_pcie(dev) && pcie_downstream_port(dev) &&
  	    pos == PCI_EXP_SLTSTA)
8c0d3a02c   Jiang Liu   PCI: Add accessor...
419
  		*val = PCI_EXP_SLTSTA_PDS;
8c0d3a02c   Jiang Liu   PCI: Add accessor...
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
  
  	return 0;
  }
  EXPORT_SYMBOL(pcie_capability_read_word);
  
  int pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val)
  {
  	int ret;
  
  	*val = 0;
  	if (pos & 3)
  		return -EINVAL;
  
  	if (pcie_capability_reg_implemented(dev, pos)) {
  		ret = pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, val);
  		/*
  		 * Reset *val to 0 if pci_read_config_dword() fails, it may
  		 * have been written as 0xFFFFFFFF if hardware error happens
  		 * during pci_read_config_dword().
  		 */
  		if (ret)
  			*val = 0;
  		return ret;
  	}
ffb4d6026   Bjorn Helgaas   PCI: Add pcie_dow...
444
445
  	if (pci_is_pcie(dev) && pcie_downstream_port(dev) &&
  	    pos == PCI_EXP_SLTSTA)
8c0d3a02c   Jiang Liu   PCI: Add accessor...
446
  		*val = PCI_EXP_SLTSTA_PDS;
8c0d3a02c   Jiang Liu   PCI: Add accessor...
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
  
  	return 0;
  }
  EXPORT_SYMBOL(pcie_capability_read_dword);
  
  int pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val)
  {
  	if (pos & 1)
  		return -EINVAL;
  
  	if (!pcie_capability_reg_implemented(dev, pos))
  		return 0;
  
  	return pci_write_config_word(dev, pci_pcie_cap(dev) + pos, val);
  }
  EXPORT_SYMBOL(pcie_capability_write_word);
  
  int pcie_capability_write_dword(struct pci_dev *dev, int pos, u32 val)
  {
  	if (pos & 3)
  		return -EINVAL;
  
  	if (!pcie_capability_reg_implemented(dev, pos))
  		return 0;
  
  	return pci_write_config_dword(dev, pci_pcie_cap(dev) + pos, val);
  }
  EXPORT_SYMBOL(pcie_capability_write_dword);
  
  int pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos,
  				       u16 clear, u16 set)
  {
  	int ret;
  	u16 val;
  
  	ret = pcie_capability_read_word(dev, pos, &val);
  	if (!ret) {
  		val &= ~clear;
  		val |= set;
  		ret = pcie_capability_write_word(dev, pos, val);
  	}
  
  	return ret;
  }
  EXPORT_SYMBOL(pcie_capability_clear_and_set_word);
  
  int pcie_capability_clear_and_set_dword(struct pci_dev *dev, int pos,
  					u32 clear, u32 set)
  {
  	int ret;
  	u32 val;
  
  	ret = pcie_capability_read_dword(dev, pos, &val);
  	if (!ret) {
  		val &= ~clear;
  		val |= set;
  		ret = pcie_capability_write_dword(dev, pos, val);
  	}
  
  	return ret;
  }
  EXPORT_SYMBOL(pcie_capability_clear_and_set_dword);
d3881e501   Keith Busch   PCI: Export PCI d...
509
510
511
  
  int pci_read_config_byte(const struct pci_dev *dev, int where, u8 *val)
  {
4b1038834   Keith Busch   PCI: Don't attemp...
512
513
  	if (pci_dev_is_disconnected(dev)) {
  		*val = ~0;
449e2f9e9   Brian Norris   PCI: Make error c...
514
  		return PCIBIOS_DEVICE_NOT_FOUND;
4b1038834   Keith Busch   PCI: Don't attemp...
515
  	}
d3881e501   Keith Busch   PCI: Export PCI d...
516
517
518
519
520
521
  	return pci_bus_read_config_byte(dev->bus, dev->devfn, where, val);
  }
  EXPORT_SYMBOL(pci_read_config_byte);
  
  int pci_read_config_word(const struct pci_dev *dev, int where, u16 *val)
  {
4b1038834   Keith Busch   PCI: Don't attemp...
522
523
  	if (pci_dev_is_disconnected(dev)) {
  		*val = ~0;
449e2f9e9   Brian Norris   PCI: Make error c...
524
  		return PCIBIOS_DEVICE_NOT_FOUND;
4b1038834   Keith Busch   PCI: Don't attemp...
525
  	}
d3881e501   Keith Busch   PCI: Export PCI d...
526
527
528
529
530
531
532
  	return pci_bus_read_config_word(dev->bus, dev->devfn, where, val);
  }
  EXPORT_SYMBOL(pci_read_config_word);
  
  int pci_read_config_dword(const struct pci_dev *dev, int where,
  					u32 *val)
  {
4b1038834   Keith Busch   PCI: Don't attemp...
533
534
  	if (pci_dev_is_disconnected(dev)) {
  		*val = ~0;
449e2f9e9   Brian Norris   PCI: Make error c...
535
  		return PCIBIOS_DEVICE_NOT_FOUND;
4b1038834   Keith Busch   PCI: Don't attemp...
536
  	}
d3881e501   Keith Busch   PCI: Export PCI d...
537
538
539
540
541
542
  	return pci_bus_read_config_dword(dev->bus, dev->devfn, where, val);
  }
  EXPORT_SYMBOL(pci_read_config_dword);
  
  int pci_write_config_byte(const struct pci_dev *dev, int where, u8 val)
  {
4b1038834   Keith Busch   PCI: Don't attemp...
543
  	if (pci_dev_is_disconnected(dev))
449e2f9e9   Brian Norris   PCI: Make error c...
544
  		return PCIBIOS_DEVICE_NOT_FOUND;
d3881e501   Keith Busch   PCI: Export PCI d...
545
546
547
548
549
550
  	return pci_bus_write_config_byte(dev->bus, dev->devfn, where, val);
  }
  EXPORT_SYMBOL(pci_write_config_byte);
  
  int pci_write_config_word(const struct pci_dev *dev, int where, u16 val)
  {
4b1038834   Keith Busch   PCI: Don't attemp...
551
  	if (pci_dev_is_disconnected(dev))
449e2f9e9   Brian Norris   PCI: Make error c...
552
  		return PCIBIOS_DEVICE_NOT_FOUND;
d3881e501   Keith Busch   PCI: Export PCI d...
553
554
555
556
557
558
559
  	return pci_bus_write_config_word(dev->bus, dev->devfn, where, val);
  }
  EXPORT_SYMBOL(pci_write_config_word);
  
  int pci_write_config_dword(const struct pci_dev *dev, int where,
  					 u32 val)
  {
4b1038834   Keith Busch   PCI: Don't attemp...
560
  	if (pci_dev_is_disconnected(dev))
449e2f9e9   Brian Norris   PCI: Make error c...
561
  		return PCIBIOS_DEVICE_NOT_FOUND;
d3881e501   Keith Busch   PCI: Export PCI d...
562
563
564
  	return pci_bus_write_config_dword(dev->bus, dev->devfn, where, val);
  }
  EXPORT_SYMBOL(pci_write_config_dword);