Blame view

drivers/pci/setup-res.c 12.7 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
  /*
df62ab5e0   Bjorn Helgaas   PCI: Tidy comments
3
   * Support routines for initializing a PCI subsystem
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
9
   *
   * Extruded from code written by
   *      Dave Rusling (david.rusling@reo.mts.dec.com)
   *      David Mosberger (davidm@cs.arizona.edu)
   *	David Miller (davem@redhat.com)
   *
df62ab5e0   Bjorn Helgaas   PCI: Tidy comments
10
11
   * Fixed for multiple PCI buses, 1999 Andrea Arcangeli <andrea@suse.de>
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
   * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
   *	     Resource sorting
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include <linux/kernel.h>
363c75db1   Paul Gortmaker   pci: Fix files ne...
16
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
21
22
  #include <linux/pci.h>
  #include <linux/errno.h>
  #include <linux/ioport.h>
  #include <linux/cache.h>
  #include <linux/slab.h>
  #include "pci.h"
6ffa2489c   Bjorn Helgaas   PCI: Separate VF ...
23
  static void pci_std_update_resource(struct pci_dev *dev, int resno)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
  {
  	struct pci_bus_region region;
9aac537e0   Bjorn Helgaas   PCI: disable MEM ...
26
27
  	bool disable;
  	u16 cmd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
  	u32 new, check, mask;
  	int reg;
14add80b5   Yu Zhao   PCI: remove unnec...
30
  	struct resource *res = dev->resource + resno;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31

63880b230   Bjorn Helgaas   PCI: Ignore BAR u...
32
33
  	/* Per SR-IOV spec 3.4.1.11, VF BARs are RO zero */
  	if (dev->is_virtfn)
70675e0b6   Wei Yang   PCI: Don't try to...
34
  		return;
70675e0b6   Wei Yang   PCI: Don't try to...
35

fb0f2b40f   Ralf Baechle   PCI legacy resour...
36
37
38
39
  	/*
  	 * Ignore resources for unimplemented BARs and unused resource slots
  	 * for 64 bit BARs.
  	 */
cf7bee5a0   Ivan Kokshaysky   [PATCH] Fix resto...
40
41
  	if (!res->flags)
  		return;
cd8a4d365   Bjorn Helgaas   PCI: Check IORESO...
42
43
  	if (res->flags & IORESOURCE_UNSET)
  		return;
fb0f2b40f   Ralf Baechle   PCI legacy resour...
44
45
46
  	/*
  	 * Ignore non-moveable resources.  This might be legacy resources for
  	 * which no functional BAR register exists or another important
80ccba118   Bjorn Helgaas   PCI: use dev_prin...
47
  	 * system resource we shouldn't move around.
fb0f2b40f   Ralf Baechle   PCI legacy resour...
48
49
50
  	 */
  	if (res->flags & IORESOURCE_PCI_FIXED)
  		return;
fc2798502   Yinghai Lu   PCI: Convert pcib...
51
  	pcibios_resource_to_bus(dev->bus, &region, res);
45d004f4a   Bjorn Helgaas   PCI: Update BARs ...
52
  	new = region.start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53

45d004f4a   Bjorn Helgaas   PCI: Update BARs ...
54
  	if (res->flags & IORESOURCE_IO) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  		mask = (u32)PCI_BASE_ADDRESS_IO_MASK;
45d004f4a   Bjorn Helgaas   PCI: Update BARs ...
56
57
  		new |= res->flags & ~PCI_BASE_ADDRESS_IO_MASK;
  	} else if (resno == PCI_ROM_RESOURCE) {
76dc52684   Matthias Kaehlcke   PCI: Make PCI_ROM...
58
  		mask = PCI_ROM_ADDRESS_MASK;
45d004f4a   Bjorn Helgaas   PCI: Update BARs ...
59
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
  		mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
45d004f4a   Bjorn Helgaas   PCI: Update BARs ...
61
62
  		new |= res->flags & ~PCI_BASE_ADDRESS_MEM_MASK;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63

286c2378a   Bjorn Helgaas   PCI: Remove pci_r...
64
65
66
  	if (resno < PCI_ROM_RESOURCE) {
  		reg = PCI_BASE_ADDRESS_0 + 4 * resno;
  	} else if (resno == PCI_ROM_RESOURCE) {
0b457dde3   Bjorn Helgaas   PCI: Add comments...
67
68
69
70
  
  		/*
  		 * Apparently some Matrox devices have ROM BARs that read
  		 * as zero when disabled, so don't update ROM BARs unless
16bbbc874   Bjorn Helgaas   PCI: Replace lkml...
71
72
  		 * they're enabled.  See
  		 * https://lore.kernel.org/r/43147B3D.1030309@vc.cvut.cz/
0b457dde3   Bjorn Helgaas   PCI: Add comments...
73
  		 */
755528c86   Linus Torvalds   Ignore disabled R...
74
75
  		if (!(res->flags & IORESOURCE_ROM_ENABLE))
  			return;
286c2378a   Bjorn Helgaas   PCI: Remove pci_r...
76
77
  
  		reg = dev->rom_base_reg;
755528c86   Linus Torvalds   Ignore disabled R...
78
  		new |= PCI_ROM_ADDRESS_ENABLE;
286c2378a   Bjorn Helgaas   PCI: Remove pci_r...
79
80
  	} else
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81

9aac537e0   Bjorn Helgaas   PCI: disable MEM ...
82
83
84
85
86
87
88
89
90
91
92
  	/*
  	 * We can't update a 64-bit BAR atomically, so when possible,
  	 * disable decoding so that a half-updated BAR won't conflict
  	 * with another device.
  	 */
  	disable = (res->flags & IORESOURCE_MEM_64) && !dev->mmio_always_on;
  	if (disable) {
  		pci_read_config_word(dev, PCI_COMMAND, &cmd);
  		pci_write_config_word(dev, PCI_COMMAND,
  				      cmd & ~PCI_COMMAND_MEMORY);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
95
96
  	pci_write_config_dword(dev, reg, new);
  	pci_read_config_dword(dev, reg, &check);
  
  	if ((new ^ check) & mask) {
7506dc798   Frederick Lawler   PCI: Add wrappers...
97
98
  		pci_err(dev, "BAR %d: error updating (%#08x != %#08x)
  ",
80ccba118   Bjorn Helgaas   PCI: use dev_prin...
99
  			resno, new, check);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
  	}
28c6821a0   Bjorn Helgaas   PCI: fold pci_cal...
101
  	if (res->flags & IORESOURCE_MEM_64) {
cf7bee5a0   Ivan Kokshaysky   [PATCH] Fix resto...
102
  		new = region.start >> 16 >> 16;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
  		pci_write_config_dword(dev, reg + 4, new);
  		pci_read_config_dword(dev, reg + 4, &check);
  		if (check != new) {
7506dc798   Frederick Lawler   PCI: Add wrappers...
106
107
  			pci_err(dev, "BAR %d: error updating (high %#08x != %#08x)
  ",
227f06470   Ryan Desfosses   PCI: Merge multi-...
108
  				resno, new, check);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
  		}
  	}
9aac537e0   Bjorn Helgaas   PCI: disable MEM ...
111
112
113
  
  	if (disable)
  		pci_write_config_word(dev, PCI_COMMAND, cmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
  }
6ffa2489c   Bjorn Helgaas   PCI: Separate VF ...
115
116
117
118
119
120
121
122
123
  void pci_update_resource(struct pci_dev *dev, int resno)
  {
  	if (resno <= PCI_ROM_RESOURCE)
  		pci_std_update_resource(dev, resno);
  #ifdef CONFIG_PCI_IOV
  	else if (resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END)
  		pci_iov_update_resource(dev, resno);
  #endif
  }
96bde06a2   Sam Ravnborg   pci: do not mark ...
124
  int pci_claim_resource(struct pci_dev *dev, int resource)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
  {
  	struct resource *res = &dev->resource[resource];
966f3a757   Bjorn Helgaas   PCI: for address ...
127
  	struct resource *root, *conflict;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128

29003beb7   Bjorn Helgaas   PCI: Don't try to...
129
  	if (res->flags & IORESOURCE_UNSET) {
7506dc798   Frederick Lawler   PCI: Add wrappers...
130
131
  		pci_info(dev, "can't claim BAR %d %pR: no address assigned
  ",
29003beb7   Bjorn Helgaas   PCI: Don't try to...
132
133
134
  			 resource, res);
  		return -EINVAL;
  	}
16d917b13   Bjorn Helgaas   PCI: Don't attemp...
135
136
137
138
139
140
141
  	/*
  	 * If we have a shadow copy in RAM, the PCI device doesn't respond
  	 * to the shadow range, so we don't need to claim it, and upstream
  	 * bridges don't need to route the range to the device.
  	 */
  	if (res->flags & IORESOURCE_ROM_SHADOW)
  		return 0;
cebd78a8c   Matthew Wilcox   Fix pci_claim_res...
142
  	root = pci_find_parent_resource(dev, res);
865df576e   Bjorn Helgaas   PCI: improve disc...
143
  	if (!root) {
7506dc798   Frederick Lawler   PCI: Add wrappers...
144
145
  		pci_info(dev, "can't claim BAR %d %pR: no compatible bridge window
  ",
29003beb7   Bjorn Helgaas   PCI: Don't try to...
146
  			 resource, res);
c770cb4cb   Bjorn Helgaas   PCI: Mark invalid...
147
  		res->flags |= IORESOURCE_UNSET;
865df576e   Bjorn Helgaas   PCI: improve disc...
148
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
  	}
966f3a757   Bjorn Helgaas   PCI: for address ...
150
151
  	conflict = request_resource_conflict(root, res);
  	if (conflict) {
7506dc798   Frederick Lawler   PCI: Add wrappers...
152
153
  		pci_info(dev, "can't claim BAR %d %pR: address conflict with %s %pR
  ",
29003beb7   Bjorn Helgaas   PCI: Don't try to...
154
  			 resource, res, conflict->name, conflict);
c770cb4cb   Bjorn Helgaas   PCI: Mark invalid...
155
  		res->flags |= IORESOURCE_UNSET;
966f3a757   Bjorn Helgaas   PCI: for address ...
156
157
  		return -EBUSY;
  	}
865df576e   Bjorn Helgaas   PCI: improve disc...
158

966f3a757   Bjorn Helgaas   PCI: for address ...
159
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
  }
eaa959df2   Jesse Barnes   PCI: export pci_c...
161
  EXPORT_SYMBOL(pci_claim_resource);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162

32a9a682b   Yuji Shimada   PCI: allow assign...
163
164
  void pci_disable_bridge_window(struct pci_dev *dev)
  {
32a9a682b   Yuji Shimada   PCI: allow assign...
165
166
167
168
169
170
171
172
  	/* MMIO Base/Limit */
  	pci_write_config_dword(dev, PCI_MEMORY_BASE, 0x0000fff0);
  
  	/* Prefetchable MMIO Base/Limit */
  	pci_write_config_dword(dev, PCI_PREF_LIMIT_UPPER32, 0);
  	pci_write_config_dword(dev, PCI_PREF_MEMORY_BASE, 0x0000fff0);
  	pci_write_config_dword(dev, PCI_PREF_BASE_UPPER32, 0xffffffff);
  }
2bbc69422   Ram Pai   PCI : ability to ...
173

6535943fb   Myron Stowe   x86/PCI: Convert ...
174
175
176
177
178
179
180
181
182
183
184
185
186
  /*
   * Generic function that returns a value indicating that the device's
   * original BIOS BAR address was not saved and so is not available for
   * reinstatement.
   *
   * Can be over-ridden by architecture specific code that implements
   * reinstatement functionality rather than leaving it disabled when
   * normal allocation attempts fail.
   */
  resource_size_t __weak pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx)
  {
  	return 0;
  }
f7625980f   Bjorn Helgaas   PCI: Fix whitespa...
187
  static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
2bbc69422   Ram Pai   PCI : ability to ...
188
189
190
  		int resno, resource_size_t size)
  {
  	struct resource *root, *conflict;
6535943fb   Myron Stowe   x86/PCI: Convert ...
191
  	resource_size_t fw_addr, start, end;
58c84eda0   Bjorn Helgaas   PCI: fall back to...
192

6535943fb   Myron Stowe   x86/PCI: Convert ...
193
194
  	fw_addr = pcibios_retrieve_fw_addr(dev, resno);
  	if (!fw_addr)
947788359   Bjorn Helgaas   PCI: Return conve...
195
  		return -ENOMEM;
6535943fb   Myron Stowe   x86/PCI: Convert ...
196

2bbc69422   Ram Pai   PCI : ability to ...
197
198
  	start = res->start;
  	end = res->end;
6535943fb   Myron Stowe   x86/PCI: Convert ...
199
  	res->start = fw_addr;
2bbc69422   Ram Pai   PCI : ability to ...
200
  	res->end = res->start + size - 1;
0b26cd694   Bjorn Helgaas   PCI: Clear IORESO...
201
  	res->flags &= ~IORESOURCE_UNSET;
351fc6d1a   Myron Stowe   PCI: Fix starting...
202
203
204
205
206
207
208
209
  
  	root = pci_find_parent_resource(dev, res);
  	if (!root) {
  		if (res->flags & IORESOURCE_IO)
  			root = &ioport_resource;
  		else
  			root = &iomem_resource;
  	}
7506dc798   Frederick Lawler   PCI: Add wrappers...
210
211
  	pci_info(dev, "BAR %d: trying firmware assignment %pR
  ",
2bbc69422   Ram Pai   PCI : ability to ...
212
213
214
  		 resno, res);
  	conflict = request_resource_conflict(root, res);
  	if (conflict) {
7506dc798   Frederick Lawler   PCI: Add wrappers...
215
216
  		pci_info(dev, "BAR %d: %pR conflicts with %s %pR
  ",
947788359   Bjorn Helgaas   PCI: Return conve...
217
  			 resno, res, conflict->name, conflict);
2bbc69422   Ram Pai   PCI : ability to ...
218
219
  		res->start = start;
  		res->end = end;
0b26cd694   Bjorn Helgaas   PCI: Clear IORESO...
220
  		res->flags |= IORESOURCE_UNSET;
947788359   Bjorn Helgaas   PCI: Return conve...
221
  		return -EBUSY;
2bbc69422   Ram Pai   PCI : ability to ...
222
  	}
947788359   Bjorn Helgaas   PCI: Return conve...
223
  	return 0;
2bbc69422   Ram Pai   PCI : ability to ...
224
  }
ecf677c8d   Palmer Dabbelt   PCI: Add a generi...
225
226
227
228
229
230
231
232
233
234
235
236
  /*
   * We don't have to worry about legacy ISA devices, so nothing to do here.
   * This is marked as __weak because multiple architectures define it; it should
   * eventually go away.
   */
  resource_size_t __weak pcibios_align_resource(void *data,
  					      const struct resource *res,
  					      resource_size_t size,
  					      resource_size_t align)
  {
         return res->start;
  }
fe6dacdb1   Bjorn Helgaas   PCI: reorder __pc...
237
238
239
240
241
242
243
244
  static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
  		int resno, resource_size_t size, resource_size_t align)
  {
  	struct resource *res = dev->resource + resno;
  	resource_size_t min;
  	int ret;
  
  	min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
67d29b5c6   Bjorn Helgaas   PCI: Add resource...
245
246
247
248
249
250
251
  	/*
  	 * First, try exact prefetching match.  Even if a 64-bit
  	 * prefetchable bridge window is below 4GB, we can't put a 32-bit
  	 * prefetchable resource in it because pbus_size_mem() assumes a
  	 * 64-bit window will contain no 32-bit resources.  If we assign
  	 * things differently than they were sized, not everything will fit.
  	 */
fe6dacdb1   Bjorn Helgaas   PCI: reorder __pc...
252
  	ret = pci_bus_alloc_resource(bus, res, size, align, min,
5b2854155   Yinghai Lu   PCI: Restrict 64-...
253
  				     IORESOURCE_PREFETCH | IORESOURCE_MEM_64,
fe6dacdb1   Bjorn Helgaas   PCI: reorder __pc...
254
  				     pcibios_align_resource, dev);
d3689df04   Bjorn Helgaas   PCI: Simplify __p...
255
256
  	if (ret == 0)
  		return 0;
fe6dacdb1   Bjorn Helgaas   PCI: reorder __pc...
257

67d29b5c6   Bjorn Helgaas   PCI: Add resource...
258
259
260
261
  	/*
  	 * If the prefetchable window is only 32 bits wide, we can put
  	 * 64-bit prefetchable resources in it.
  	 */
d3689df04   Bjorn Helgaas   PCI: Simplify __p...
262
  	if ((res->flags & (IORESOURCE_PREFETCH | IORESOURCE_MEM_64)) ==
5b2854155   Yinghai Lu   PCI: Restrict 64-...
263
  	     (IORESOURCE_PREFETCH | IORESOURCE_MEM_64)) {
5b2854155   Yinghai Lu   PCI: Restrict 64-...
264
265
  		ret = pci_bus_alloc_resource(bus, res, size, align, min,
  					     IORESOURCE_PREFETCH,
fe6dacdb1   Bjorn Helgaas   PCI: reorder __pc...
266
  					     pcibios_align_resource, dev);
d3689df04   Bjorn Helgaas   PCI: Simplify __p...
267
268
  		if (ret == 0)
  			return 0;
fe6dacdb1   Bjorn Helgaas   PCI: reorder __pc...
269
  	}
5b2854155   Yinghai Lu   PCI: Restrict 64-...
270

67d29b5c6   Bjorn Helgaas   PCI: Add resource...
271
272
273
274
275
276
277
  	/*
  	 * If we didn't find a better match, we can put any memory resource
  	 * in a non-prefetchable window.  If this resource is 32 bits and
  	 * non-prefetchable, the first call already tried the only possibility
  	 * so we don't need to try again.
  	 */
  	if (res->flags & (IORESOURCE_PREFETCH | IORESOURCE_MEM_64))
fe6dacdb1   Bjorn Helgaas   PCI: reorder __pc...
278
279
  		ret = pci_bus_alloc_resource(bus, res, size, align, min, 0,
  					     pcibios_align_resource, dev);
67d29b5c6   Bjorn Helgaas   PCI: Add resource...
280

fe6dacdb1   Bjorn Helgaas   PCI: reorder __pc...
281
282
  	return ret;
  }
d6776e6d5   Nikhil P Rao   PCI: fix truncati...
283
284
  static int _pci_assign_resource(struct pci_dev *dev, int resno,
  				resource_size_t size, resource_size_t min_align)
2bbc69422   Ram Pai   PCI : ability to ...
285
  {
2bbc69422   Ram Pai   PCI : ability to ...
286
287
  	struct pci_bus *bus;
  	int ret;
58c84eda0   Bjorn Helgaas   PCI: fall back to...
288

2bbc69422   Ram Pai   PCI : ability to ...
289
290
291
292
293
294
  	bus = dev->bus;
  	while ((ret = __pci_assign_resource(bus, dev, resno, size, min_align))) {
  		if (!bus->parent || !bus->self->transparent)
  			break;
  		bus = bus->parent;
  	}
2bbc69422   Ram Pai   PCI : ability to ...
295
296
  	return ret;
  }
d09ee9687   Yinghai Lu   PCI: improve reso...
297
298
299
  int pci_assign_resource(struct pci_dev *dev, int resno)
  {
  	struct resource *res = dev->resource + resno;
2bbc69422   Ram Pai   PCI : ability to ...
300
  	resource_size_t align, size;
d09ee9687   Yinghai Lu   PCI: improve reso...
301
  	int ret;
2ea4adf75   Bjorn Helgaas   PCI: Don't assign...
302
303
  	if (res->flags & IORESOURCE_PCI_FIXED)
  		return 0;
bd064f0a2   Bjorn Helgaas   PCI: Mark resourc...
304
  	res->flags |= IORESOURCE_UNSET;
6faf17f6f   Chris Wright   PCI SR-IOV: corre...
305
  	align = pci_resource_alignment(dev, res);
d09ee9687   Yinghai Lu   PCI: improve reso...
306
  	if (!align) {
7506dc798   Frederick Lawler   PCI: Add wrappers...
307
308
  		pci_info(dev, "BAR %d: can't assign %pR (bogus alignment)
  ",
227f06470   Ryan Desfosses   PCI: Merge multi-...
309
  			 resno, res);
d09ee9687   Yinghai Lu   PCI: improve reso...
310
311
  		return -EINVAL;
  	}
2bbc69422   Ram Pai   PCI : ability to ...
312
313
  	size = resource_size(res);
  	ret = _pci_assign_resource(dev, resno, size, align);
d09ee9687   Yinghai Lu   PCI: improve reso...
314

2bbc69422   Ram Pai   PCI : ability to ...
315
316
317
318
319
  	/*
  	 * If we failed to assign anything, let's try the address
  	 * where firmware left it.  That at least has a chance of
  	 * working, which is better than just leaving it disabled.
  	 */
64da465e9   Bjorn Helgaas   PCI: Tidy resourc...
320
  	if (ret < 0) {
7506dc798   Frederick Lawler   PCI: Add wrappers...
321
322
  		pci_info(dev, "BAR %d: no space for %pR
  ", resno, res);
2bbc69422   Ram Pai   PCI : ability to ...
323
  		ret = pci_revert_fw_address(res, dev, resno, size);
64da465e9   Bjorn Helgaas   PCI: Tidy resourc...
324
  	}
d09ee9687   Yinghai Lu   PCI: improve reso...
325

64da465e9   Bjorn Helgaas   PCI: Tidy resourc...
326
  	if (ret < 0) {
7506dc798   Frederick Lawler   PCI: Add wrappers...
327
328
  		pci_info(dev, "BAR %d: failed to assign %pR
  ", resno, res);
28f6dbe2c   Bjorn Helgaas   PCI: Cleanup cont...
329
  		return ret;
64da465e9   Bjorn Helgaas   PCI: Tidy resourc...
330
  	}
28f6dbe2c   Bjorn Helgaas   PCI: Cleanup cont...
331
332
333
  
  	res->flags &= ~IORESOURCE_UNSET;
  	res->flags &= ~IORESOURCE_STARTALIGN;
7506dc798   Frederick Lawler   PCI: Add wrappers...
334
335
  	pci_info(dev, "BAR %d: assigned %pR
  ", resno, res);
28f6dbe2c   Bjorn Helgaas   PCI: Cleanup cont...
336
337
338
339
  	if (resno < PCI_BRIDGE_RESOURCES)
  		pci_update_resource(dev, resno);
  
  	return 0;
d09ee9687   Yinghai Lu   PCI: improve reso...
340
  }
b7fe94342   Ryan Desfosses   PCI: Move EXPORT_...
341
  EXPORT_SYMBOL(pci_assign_resource);
d09ee9687   Yinghai Lu   PCI: improve reso...
342

fe6dacdb1   Bjorn Helgaas   PCI: reorder __pc...
343
344
345
346
  int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsize,
  			resource_size_t min_align)
  {
  	struct resource *res = dev->resource + resno;
c33377082   Guo Chao   PCI: Keep origina...
347
  	unsigned long flags;
fe6dacdb1   Bjorn Helgaas   PCI: reorder __pc...
348
349
  	resource_size_t new_size;
  	int ret;
2ea4adf75   Bjorn Helgaas   PCI: Don't assign...
350
351
  	if (res->flags & IORESOURCE_PCI_FIXED)
  		return 0;
c33377082   Guo Chao   PCI: Keep origina...
352
  	flags = res->flags;
bd064f0a2   Bjorn Helgaas   PCI: Mark resourc...
353
  	res->flags |= IORESOURCE_UNSET;
fe6dacdb1   Bjorn Helgaas   PCI: reorder __pc...
354
  	if (!res->parent) {
7506dc798   Frederick Lawler   PCI: Add wrappers...
355
356
  		pci_info(dev, "BAR %d: can't reassign an unassigned resource %pR
  ",
227f06470   Ryan Desfosses   PCI: Merge multi-...
357
  			 resno, res);
fe6dacdb1   Bjorn Helgaas   PCI: reorder __pc...
358
359
360
361
362
363
  		return -EINVAL;
  	}
  
  	/* already aligned with min_align */
  	new_size = resource_size(res) + addsize;
  	ret = _pci_assign_resource(dev, resno, new_size, min_align);
28f6dbe2c   Bjorn Helgaas   PCI: Cleanup cont...
364
  	if (ret) {
c33377082   Guo Chao   PCI: Keep origina...
365
  		res->flags = flags;
7506dc798   Frederick Lawler   PCI: Add wrappers...
366
367
  		pci_info(dev, "BAR %d: %pR (failed to expand by %#llx)
  ",
c33377082   Guo Chao   PCI: Keep origina...
368
  			 resno, res, (unsigned long long) addsize);
28f6dbe2c   Bjorn Helgaas   PCI: Cleanup cont...
369
  		return ret;
fe6dacdb1   Bjorn Helgaas   PCI: reorder __pc...
370
  	}
c33377082   Guo Chao   PCI: Keep origina...
371

28f6dbe2c   Bjorn Helgaas   PCI: Cleanup cont...
372
373
  	res->flags &= ~IORESOURCE_UNSET;
  	res->flags &= ~IORESOURCE_STARTALIGN;
7506dc798   Frederick Lawler   PCI: Add wrappers...
374
375
  	pci_info(dev, "BAR %d: reassigned %pR (expanded by %#llx)
  ",
64da465e9   Bjorn Helgaas   PCI: Tidy resourc...
376
  		 resno, res, (unsigned long long) addsize);
28f6dbe2c   Bjorn Helgaas   PCI: Cleanup cont...
377
378
379
380
  	if (resno < PCI_BRIDGE_RESOURCES)
  		pci_update_resource(dev, resno);
  
  	return 0;
fe6dacdb1   Bjorn Helgaas   PCI: reorder __pc...
381
  }
8bb705e3e   Christian König   PCI: Add pci_resi...
382
383
384
  void pci_release_resource(struct pci_dev *dev, int resno)
  {
  	struct resource *res = dev->resource + resno;
7506dc798   Frederick Lawler   PCI: Add wrappers...
385
386
  	pci_info(dev, "BAR %d: releasing %pR
  ", resno, res);
c37406e05   Christian König   PCI: Allow releas...
387
388
389
  
  	if (!res->parent)
  		return;
8bb705e3e   Christian König   PCI: Add pci_resi...
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
417
418
419
420
421
422
423
424
425
426
427
428
429
  	release_resource(res);
  	res->end = resource_size(res) - 1;
  	res->start = 0;
  	res->flags |= IORESOURCE_UNSET;
  }
  EXPORT_SYMBOL(pci_release_resource);
  
  int pci_resize_resource(struct pci_dev *dev, int resno, int size)
  {
  	struct resource *res = dev->resource + resno;
  	int old, ret;
  	u32 sizes;
  	u16 cmd;
  
  	/* Make sure the resource isn't assigned before resizing it. */
  	if (!(res->flags & IORESOURCE_UNSET))
  		return -EBUSY;
  
  	pci_read_config_word(dev, PCI_COMMAND, &cmd);
  	if (cmd & PCI_COMMAND_MEMORY)
  		return -EBUSY;
  
  	sizes = pci_rebar_get_possible_sizes(dev, resno);
  	if (!sizes)
  		return -ENOTSUPP;
  
  	if (!(sizes & BIT(size)))
  		return -EINVAL;
  
  	old = pci_rebar_get_current_size(dev, resno);
  	if (old < 0)
  		return old;
  
  	ret = pci_rebar_set_size(dev, resno, size);
  	if (ret)
  		return ret;
  
  	res->end = res->start + pci_rebar_size_to_bytes(size) - 1;
  
  	/* Check if the new config works by trying to assign everything. */
d09ddd819   Ard Biesheuvel   PCI: Allow pci_re...
430
431
432
433
434
  	if (dev->bus->self) {
  		ret = pci_reassign_bridge_resources(dev->bus->self, res->flags);
  		if (ret)
  			goto error_resize;
  	}
8bb705e3e   Christian König   PCI: Add pci_resi...
435
436
437
438
439
440
441
442
  	return 0;
  
  error_resize:
  	pci_rebar_set_size(dev, resno, old);
  	res->end = res->start + pci_rebar_size_to_bytes(old) - 1;
  	return ret;
  }
  EXPORT_SYMBOL(pci_resize_resource);
842de40d9   Bjorn Helgaas   PCI: add generic ...
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
  int pci_enable_resources(struct pci_dev *dev, int mask)
  {
  	u16 cmd, old_cmd;
  	int i;
  	struct resource *r;
  
  	pci_read_config_word(dev, PCI_COMMAND, &cmd);
  	old_cmd = cmd;
  
  	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
  		if (!(mask & (1 << i)))
  			continue;
  
  		r = &dev->resource[i];
  
  		if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM)))
  			continue;
  		if ((i == PCI_ROM_RESOURCE) &&
  				(!(r->flags & IORESOURCE_ROM_ENABLE)))
  			continue;
3cedcc362   Bjorn Helgaas   PCI: Don't enable...
463
  		if (r->flags & IORESOURCE_UNSET) {
7506dc798   Frederick Lawler   PCI: Add wrappers...
464
465
  			pci_err(dev, "can't enable device: BAR %d %pR not assigned
  ",
3cedcc362   Bjorn Helgaas   PCI: Don't enable...
466
467
468
  				i, r);
  			return -EINVAL;
  		}
842de40d9   Bjorn Helgaas   PCI: add generic ...
469
  		if (!r->parent) {
7506dc798   Frederick Lawler   PCI: Add wrappers...
470
471
  			pci_err(dev, "can't enable device: BAR %d %pR not claimed
  ",
3cedcc362   Bjorn Helgaas   PCI: Don't enable...
472
  				i, r);
842de40d9   Bjorn Helgaas   PCI: add generic ...
473
474
475
476
477
478
479
480
481
482
  			return -EINVAL;
  		}
  
  		if (r->flags & IORESOURCE_IO)
  			cmd |= PCI_COMMAND_IO;
  		if (r->flags & IORESOURCE_MEM)
  			cmd |= PCI_COMMAND_MEMORY;
  	}
  
  	if (cmd != old_cmd) {
7506dc798   Frederick Lawler   PCI: Add wrappers...
483
484
  		pci_info(dev, "enabling device (%04x -> %04x)
  ", old_cmd, cmd);
842de40d9   Bjorn Helgaas   PCI: add generic ...
485
486
487
488
  		pci_write_config_word(dev, PCI_COMMAND, cmd);
  	}
  	return 0;
  }