setup-bus.c 21.3 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/*
 *	drivers/pci/setup-bus.c
 *
 * Extruded from code written by
 *      Dave Rusling (david.rusling@reo.mts.dec.com)
 *      David Mosberger (davidm@cs.arizona.edu)
 *	David Miller (davem@redhat.com)
 *
 * Support routines for initializing a PCI subsystem.
 */

/*
 * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
 *	     PCI-PCI bridges cleanup, sorted resource allocation.
 * Feb 2002, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
 *	     Converted to allocation in 3 passes, which gives
 *	     tighter packing. Prefetchable range support.
 */

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/cache.h>
#include <linux/slab.h>
28
#include "pci.h"
Linus Torvalds's avatar
Linus Torvalds committed
29

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
struct resource_list_x {
	struct resource_list_x *next;
	struct resource *res;
	struct pci_dev *dev;
	resource_size_t start;
	resource_size_t end;
	unsigned long flags;
};

static void add_to_failed_list(struct resource_list_x *head,
				 struct pci_dev *dev, struct resource *res)
{
	struct resource_list_x *list = head;
	struct resource_list_x *ln = list->next;
	struct resource_list_x *tmp;

	tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
	if (!tmp) {
		pr_warning("add_to_failed_list: kmalloc() failed!\n");
		return;
	}

	tmp->next = ln;
	tmp->res = res;
	tmp->dev = dev;
	tmp->start = res->start;
	tmp->end = res->end;
	tmp->flags = res->flags;
	list->next = tmp;
}

static void free_failed_list(struct resource_list_x *head)
{
	struct resource_list_x *list, *tmp;

	for (list = head->next; list;) {
		tmp = list;
		list = list->next;
		kfree(tmp);
	}

	head->next = NULL;
}

static void pbus_assign_resources_sorted(const struct pci_bus *bus,
					 struct resource_list_x *fail_head)
Linus Torvalds's avatar
Linus Torvalds committed
76
77
78
79
80
81
82
83
84
85
{
	struct pci_dev *dev;
	struct resource *res;
	struct resource_list head, *list, *tmp;
	int idx;

	head.next = NULL;
	list_for_each_entry(dev, &bus->devices, bus_list) {
		u16 class = dev->class >> 8;

86
		/* Don't touch classless devices or host bridges or ioapics.  */
Linus Torvalds's avatar
Linus Torvalds committed
87
		if (class == PCI_CLASS_NOT_DEFINED ||
88
		    class == PCI_CLASS_BRIDGE_HOST)
Linus Torvalds's avatar
Linus Torvalds committed
89
90
			continue;

91
		/* Don't touch ioapic devices already enabled by firmware */
92
		if (class == PCI_CLASS_SYSTEM_PIC) {
93
94
95
			u16 command;
			pci_read_config_word(dev, PCI_COMMAND, &command);
			if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY))
96
97
98
				continue;
		}

Linus Torvalds's avatar
Linus Torvalds committed
99
100
101
102
103
104
		pdev_sort_resources(dev, &head);
	}

	for (list = head.next; list;) {
		res = list->res;
		idx = res - &list->dev->resource[0];
105
		if (pci_assign_resource(list->dev, idx)) {
106
107
			if (fail_head && !pci_is_root_bus(list->dev->bus))
				add_to_failed_list(fail_head, list->dev, res);
108
			res->start = 0;
109
			res->end = 0;
110
111
			res->flags = 0;
		}
Linus Torvalds's avatar
Linus Torvalds committed
112
113
114
115
116
117
		tmp = list;
		list = list->next;
		kfree(tmp);
	}
}

118
void pci_setup_cardbus(struct pci_bus *bus)
Linus Torvalds's avatar
Linus Torvalds committed
119
120
{
	struct pci_dev *bridge = bus->self;
121
	struct resource *res;
Linus Torvalds's avatar
Linus Torvalds committed
122
123
	struct pci_bus_region region;

124
125
	dev_info(&bridge->dev, "CardBus bridge to [bus %02x-%02x]\n",
		 bus->secondary, bus->subordinate);
Linus Torvalds's avatar
Linus Torvalds committed
126

127
128
129
	res = bus->resource[0];
	pcibios_resource_to_bus(bridge, &region, res);
	if (res->flags & IORESOURCE_IO) {
Linus Torvalds's avatar
Linus Torvalds committed
130
131
132
133
		/*
		 * The IO resource is allocated a range twice as large as it
		 * would normally need.  This allows us to set both IO regs.
		 */
134
		dev_info(&bridge->dev, "  bridge window %pR\n", res);
Linus Torvalds's avatar
Linus Torvalds committed
135
136
137
138
139
140
		pci_write_config_dword(bridge, PCI_CB_IO_BASE_0,
					region.start);
		pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0,
					region.end);
	}

141
142
143
144
	res = bus->resource[1];
	pcibios_resource_to_bus(bridge, &region, res);
	if (res->flags & IORESOURCE_IO) {
		dev_info(&bridge->dev, "  bridge window %pR\n", res);
Linus Torvalds's avatar
Linus Torvalds committed
145
146
147
148
149
150
		pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
					region.start);
		pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1,
					region.end);
	}

151
152
153
154
	res = bus->resource[2];
	pcibios_resource_to_bus(bridge, &region, res);
	if (res->flags & IORESOURCE_MEM) {
		dev_info(&bridge->dev, "  bridge window %pR\n", res);
Linus Torvalds's avatar
Linus Torvalds committed
155
156
157
158
159
160
		pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
					region.start);
		pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0,
					region.end);
	}

161
162
163
164
	res = bus->resource[3];
	pcibios_resource_to_bus(bridge, &region, res);
	if (res->flags & IORESOURCE_MEM) {
		dev_info(&bridge->dev, "  bridge window %pR\n", res);
Linus Torvalds's avatar
Linus Torvalds committed
165
166
167
168
169
170
		pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
					region.start);
		pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1,
					region.end);
	}
}
171
EXPORT_SYMBOL(pci_setup_cardbus);
Linus Torvalds's avatar
Linus Torvalds committed
172
173
174
175
176
177
178
179
180
181
182
183

/* Initialize bridges with base/limit values we have collected.
   PCI-to-PCI Bridge Architecture Specification rev. 1.1 (1998)
   requires that if there is no I/O ports or memory behind the
   bridge, corresponding range must be turned off by writing base
   value greater than limit to the bridge's base/limit registers.

   Note: care must be taken when updating I/O base/limit registers
   of bridges which support 32-bit I/O. This update requires two
   config space writes, so it's quite possible that an I/O window of
   the bridge will have some undesirable address (e.g. 0) after the
   first write. Ditto 64-bit prefetchable MMIO.  */
184
static void pci_setup_bridge_io(struct pci_bus *bus)
Linus Torvalds's avatar
Linus Torvalds committed
185
186
{
	struct pci_dev *bridge = bus->self;
187
	struct resource *res;
Linus Torvalds's avatar
Linus Torvalds committed
188
	struct pci_bus_region region;
189
	u32 l, io_upper16;
Linus Torvalds's avatar
Linus Torvalds committed
190
191

	/* Set up the top and bottom of the PCI I/O segment for this bus. */
192
193
194
	res = bus->resource[0];
	pcibios_resource_to_bus(bridge, &region, res);
	if (res->flags & IORESOURCE_IO) {
Linus Torvalds's avatar
Linus Torvalds committed
195
196
197
198
199
200
		pci_read_config_dword(bridge, PCI_IO_BASE, &l);
		l &= 0xffff0000;
		l |= (region.start >> 8) & 0x00f0;
		l |= region.end & 0xf000;
		/* Set up upper 16 bits of I/O base/limit. */
		io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
201
		dev_info(&bridge->dev, "  bridge window %pR\n", res);
202
	} else {
Linus Torvalds's avatar
Linus Torvalds committed
203
204
205
		/* Clear upper 16 bits of I/O base/limit. */
		io_upper16 = 0;
		l = 0x00f0;
206
		dev_info(&bridge->dev, "  bridge window [io  disabled]\n");
Linus Torvalds's avatar
Linus Torvalds committed
207
208
209
210
211
212
213
	}
	/* Temporarily disable the I/O range before updating PCI_IO_BASE. */
	pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff);
	/* Update lower 16 bits of I/O base/limit. */
	pci_write_config_dword(bridge, PCI_IO_BASE, l);
	/* Update upper 16 bits of I/O base/limit. */
	pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16);
214
215
216
217
218
219
220
221
}

static void pci_setup_bridge_mmio(struct pci_bus *bus)
{
	struct pci_dev *bridge = bus->self;
	struct resource *res;
	struct pci_bus_region region;
	u32 l;
Linus Torvalds's avatar
Linus Torvalds committed
222

223
	/* Set up the top and bottom of the PCI Memory segment for this bus. */
224
225
226
	res = bus->resource[1];
	pcibios_resource_to_bus(bridge, &region, res);
	if (res->flags & IORESOURCE_MEM) {
Linus Torvalds's avatar
Linus Torvalds committed
227
228
		l = (region.start >> 16) & 0xfff0;
		l |= region.end & 0xfff00000;
229
		dev_info(&bridge->dev, "  bridge window %pR\n", res);
230
	} else {
Linus Torvalds's avatar
Linus Torvalds committed
231
		l = 0x0000fff0;
232
		dev_info(&bridge->dev, "  bridge window [mem disabled]\n");
Linus Torvalds's avatar
Linus Torvalds committed
233
234
	}
	pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
235
236
237
238
239
240
241
242
}

static void pci_setup_bridge_mmio_pref(struct pci_bus *bus)
{
	struct pci_dev *bridge = bus->self;
	struct resource *res;
	struct pci_bus_region region;
	u32 l, bu, lu;
Linus Torvalds's avatar
Linus Torvalds committed
243
244
245
246
247
248
249

	/* Clear out the upper 32 bits of PREF limit.
	   If PCI_PREF_BASE_UPPER32 was non-zero, this temporarily
	   disables PREF range, which is ok. */
	pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);

	/* Set up PREF base/limit. */
250
	bu = lu = 0;
251
252
253
	res = bus->resource[2];
	pcibios_resource_to_bus(bridge, &region, res);
	if (res->flags & IORESOURCE_PREFETCH) {
Linus Torvalds's avatar
Linus Torvalds committed
254
255
		l = (region.start >> 16) & 0xfff0;
		l |= region.end & 0xfff00000;
256
		if (res->flags & IORESOURCE_MEM_64) {
257
258
259
			bu = upper_32_bits(region.start);
			lu = upper_32_bits(region.end);
		}
260
		dev_info(&bridge->dev, "  bridge window %pR\n", res);
261
	} else {
Linus Torvalds's avatar
Linus Torvalds committed
262
		l = 0x0000fff0;
263
		dev_info(&bridge->dev, "  bridge window [mem pref disabled]\n");
Linus Torvalds's avatar
Linus Torvalds committed
264
265
266
	}
	pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);

267
268
269
	/* Set the upper 32 bits of PREF base & limit. */
	pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu);
	pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu);
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
}

static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type)
{
	struct pci_dev *bridge = bus->self;

	if (pci_is_enabled(bridge))
		return;

	dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n",
		 bus->secondary, bus->subordinate);

	if (type & IORESOURCE_IO)
		pci_setup_bridge_io(bus);

	if (type & IORESOURCE_MEM)
		pci_setup_bridge_mmio(bus);

	if (type & IORESOURCE_PREFETCH)
		pci_setup_bridge_mmio_pref(bus);
Linus Torvalds's avatar
Linus Torvalds committed
290
291
292
293

	pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
}

294
295
296
297
298
299
300
301
static void pci_setup_bridge(struct pci_bus *bus)
{
	unsigned long type = IORESOURCE_IO | IORESOURCE_MEM |
				  IORESOURCE_PREFETCH;

	__pci_setup_bridge(bus, type);
}

Linus Torvalds's avatar
Linus Torvalds committed
302
303
304
/* Check whether the bridge supports optional I/O and
   prefetchable memory ranges. If not, the respective
   base/limit registers must be read-only and read as 0. */
305
static void pci_bridge_check_ranges(struct pci_bus *bus)
Linus Torvalds's avatar
Linus Torvalds committed
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
{
	u16 io;
	u32 pmem;
	struct pci_dev *bridge = bus->self;
	struct resource *b_res;

	b_res = &bridge->resource[PCI_BRIDGE_RESOURCES];
	b_res[1].flags |= IORESOURCE_MEM;

	pci_read_config_word(bridge, PCI_IO_BASE, &io);
	if (!io) {
		pci_write_config_word(bridge, PCI_IO_BASE, 0xf0f0);
		pci_read_config_word(bridge, PCI_IO_BASE, &io);
 		pci_write_config_word(bridge, PCI_IO_BASE, 0x0);
 	}
 	if (io)
		b_res[0].flags |= IORESOURCE_IO;
	/*  DECchip 21050 pass 2 errata: the bridge may miss an address
	    disconnect boundary by one PCI data phase.
	    Workaround: do not use prefetching on this device. */
	if (bridge->vendor == PCI_VENDOR_ID_DEC && bridge->device == 0x0001)
		return;
	pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
	if (!pmem) {
		pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE,
					       0xfff0fff0);
		pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
		pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0);
	}
335
	if (pmem) {
Linus Torvalds's avatar
Linus Torvalds committed
336
		b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
		if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64)
			b_res[2].flags |= IORESOURCE_MEM_64;
	}

	/* double check if bridge does support 64 bit pref */
	if (b_res[2].flags & IORESOURCE_MEM_64) {
		u32 mem_base_hi, tmp;
		pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32,
					 &mem_base_hi);
		pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32,
					       0xffffffff);
		pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, &tmp);
		if (!tmp)
			b_res[2].flags &= ~IORESOURCE_MEM_64;
		pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32,
				       mem_base_hi);
	}
Linus Torvalds's avatar
Linus Torvalds committed
354
355
356
357
358
359
}

/* Helper function for sizing routines: find first available
   bus resource of a given type. Note: we intentionally skip
   the bus resources which have already been assigned (that is,
   have non-NULL parent resource). */
360
static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned long type)
Linus Torvalds's avatar
Linus Torvalds committed
361
362
363
364
365
366
367
368
{
	int i;
	struct resource *r;
	unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
				  IORESOURCE_PREFETCH;

	for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
		r = bus->resource[i];
369
370
		if (r == &ioport_resource || r == &iomem_resource)
			continue;
371
372
		if (r && (r->flags & type_mask) == type && !r->parent)
			return r;
Linus Torvalds's avatar
Linus Torvalds committed
373
374
375
376
377
378
379
380
	}
	return NULL;
}

/* Sizing the IO windows of the PCI-PCI bridge is trivial,
   since these windows have 4K granularity and the IO ranges
   of non-bridge PCI devices are limited to 256 bytes.
   We must be careful with the ISA aliasing though. */
381
static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size)
Linus Torvalds's avatar
Linus Torvalds committed
382
383
384
{
	struct pci_dev *dev;
	struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
385
	unsigned long size = 0, size1 = 0, old_size;
Linus Torvalds's avatar
Linus Torvalds committed
386
387
388
389
390
391
392
393
394
395
396
397
398

	if (!b_res)
 		return;

	list_for_each_entry(dev, &bus->devices, bus_list) {
		int i;

		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
			struct resource *r = &dev->resource[i];
			unsigned long r_size;

			if (r->parent || !(r->flags & IORESOURCE_IO))
				continue;
399
			r_size = resource_size(r);
Linus Torvalds's avatar
Linus Torvalds committed
400
401
402
403
404
405
406
407

			if (r_size < 0x400)
				/* Might be re-aligned for ISA */
				size += r_size;
			else
				size1 += r_size;
		}
	}
408
409
	if (size < min_size)
		size = min_size;
410
411
412
	old_size = resource_size(b_res);
	if (old_size == 1)
		old_size = 0;
Linus Torvalds's avatar
Linus Torvalds committed
413
414
415
416
417
/* To be fixed in 2.5: we should have sort of HAVE_ISA
   flag in the struct pci_bus. */
#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
	size = (size & 0xff) + ((size & ~0xffUL) << 2);
#endif
418
	size = ALIGN(size + size1, 4096);
419
420
	if (size < old_size)
		size = old_size;
Linus Torvalds's avatar
Linus Torvalds committed
421
	if (!size) {
422
423
424
425
		if (b_res->start || b_res->end)
			dev_info(&bus->self->dev, "disabling bridge window "
				 "%pR to [bus %02x-%02x] (unused)\n", b_res,
				 bus->secondary, bus->subordinate);
Linus Torvalds's avatar
Linus Torvalds committed
426
427
428
429
430
431
		b_res->flags = 0;
		return;
	}
	/* Alignment of the IO window is always 4K */
	b_res->start = 4096;
	b_res->end = b_res->start + size - 1;
432
	b_res->flags |= IORESOURCE_STARTALIGN;
Linus Torvalds's avatar
Linus Torvalds committed
433
434
435
436
}

/* Calculate the size of the bus and minimal alignment which
   guarantees that all child resources fit in this size. */
437
438
static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
			 unsigned long type, resource_size_t min_size)
Linus Torvalds's avatar
Linus Torvalds committed
439
440
{
	struct pci_dev *dev;
441
	resource_size_t min_align, align, size, old_size;
442
	resource_size_t aligns[12];	/* Alignments from 1Mb to 2Gb */
Linus Torvalds's avatar
Linus Torvalds committed
443
444
	int order, max_order;
	struct resource *b_res = find_free_bus_resource(bus, type);
445
	unsigned int mem64_mask = 0;
Linus Torvalds's avatar
Linus Torvalds committed
446
447
448
449
450
451
452
453

	if (!b_res)
		return 0;

	memset(aligns, 0, sizeof(aligns));
	max_order = 0;
	size = 0;

454
455
456
	mem64_mask = b_res->flags & IORESOURCE_MEM_64;
	b_res->flags &= ~IORESOURCE_MEM_64;

Linus Torvalds's avatar
Linus Torvalds committed
457
458
	list_for_each_entry(dev, &bus->devices, bus_list) {
		int i;
459

Linus Torvalds's avatar
Linus Torvalds committed
460
461
		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
			struct resource *r = &dev->resource[i];
462
			resource_size_t r_size;
Linus Torvalds's avatar
Linus Torvalds committed
463
464
465

			if (r->parent || (r->flags & mask) != type)
				continue;
466
			r_size = resource_size(r);
Linus Torvalds's avatar
Linus Torvalds committed
467
			/* For bridges size != alignment */
468
			align = pci_resource_alignment(dev, r);
Linus Torvalds's avatar
Linus Torvalds committed
469
470
			order = __ffs(align) - 20;
			if (order > 11) {
471
472
473
				dev_warn(&dev->dev, "disabling BAR %d: %pR "
					 "(bad alignment %#llx)\n", i, r,
					 (unsigned long long) align);
Linus Torvalds's avatar
Linus Torvalds committed
474
475
476
477
478
479
480
481
482
483
484
485
				r->flags = 0;
				continue;
			}
			size += r_size;
			if (order < 0)
				order = 0;
			/* Exclude ranges with size > align from
			   calculation of the alignment. */
			if (r_size == align)
				aligns[order] += align;
			if (order > max_order)
				max_order = order;
486
			mem64_mask &= r->flags & IORESOURCE_MEM_64;
Linus Torvalds's avatar
Linus Torvalds committed
487
488
		}
	}
489
490
	if (size < min_size)
		size = min_size;
491
492
493
494
495
	old_size = resource_size(b_res);
	if (old_size == 1)
		old_size = 0;
	if (size < old_size)
		size = old_size;
Linus Torvalds's avatar
Linus Torvalds committed
496
497
498
499

	align = 0;
	min_align = 0;
	for (order = 0; order <= max_order; order++) {
500
501
502
503
		resource_size_t align1 = 1;

		align1 <<= (order + 20);

Linus Torvalds's avatar
Linus Torvalds committed
504
505
		if (!align)
			min_align = align1;
506
		else if (ALIGN(align + min_align, min_align) < align1)
Linus Torvalds's avatar
Linus Torvalds committed
507
508
509
			min_align = align1 >> 1;
		align += aligns[order];
	}
510
	size = ALIGN(size, min_align);
Linus Torvalds's avatar
Linus Torvalds committed
511
	if (!size) {
512
513
514
515
		if (b_res->start || b_res->end)
			dev_info(&bus->self->dev, "disabling bridge window "
				 "%pR to [bus %02x-%02x] (unused)\n", b_res,
				 bus->secondary, bus->subordinate);
Linus Torvalds's avatar
Linus Torvalds committed
516
517
518
519
520
		b_res->flags = 0;
		return 1;
	}
	b_res->start = min_align;
	b_res->end = size + min_align - 1;
521
	b_res->flags |= IORESOURCE_STARTALIGN;
522
	b_res->flags |= mem64_mask;
Linus Torvalds's avatar
Linus Torvalds committed
523
524
525
	return 1;
}

526
static void pci_bus_size_cardbus(struct pci_bus *bus)
Linus Torvalds's avatar
Linus Torvalds committed
527
528
529
530
531
532
533
534
535
{
	struct pci_dev *bridge = bus->self;
	struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES];
	u16 ctrl;

	/*
	 * Reserve some resources for CardBus.  We reserve
	 * a fixed amount of bus space for CardBus bridges.
	 */
536
537
538
	b_res[0].start = 0;
	b_res[0].end = pci_cardbus_io_size - 1;
	b_res[0].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN;
Linus Torvalds's avatar
Linus Torvalds committed
539

540
541
542
	b_res[1].start = 0;
	b_res[1].end = pci_cardbus_io_size - 1;
	b_res[1].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN;
Linus Torvalds's avatar
Linus Torvalds committed
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560

	/*
	 * Check whether prefetchable memory is supported
	 * by this bridge.
	 */
	pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
	if (!(ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0)) {
		ctrl |= PCI_CB_BRIDGE_CTL_PREFETCH_MEM0;
		pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl);
		pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
	}

	/*
	 * If we have prefetchable memory support, allocate
	 * two regions.  Otherwise, allocate one region of
	 * twice the size.
	 */
	if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {
561
562
563
		b_res[2].start = 0;
		b_res[2].end = pci_cardbus_mem_size - 1;
		b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_SIZEALIGN;
Linus Torvalds's avatar
Linus Torvalds committed
564

565
566
567
		b_res[3].start = 0;
		b_res[3].end = pci_cardbus_mem_size - 1;
		b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN;
Linus Torvalds's avatar
Linus Torvalds committed
568
	} else {
569
570
571
		b_res[3].start = 0;
		b_res[3].end = pci_cardbus_mem_size * 2 - 1;
		b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN;
Linus Torvalds's avatar
Linus Torvalds committed
572
573
574
	}
}

575
void __ref pci_bus_size_bridges(struct pci_bus *bus)
Linus Torvalds's avatar
Linus Torvalds committed
576
577
578
{
	struct pci_dev *dev;
	unsigned long mask, prefmask;
579
	resource_size_t min_mem_size = 0, min_io_size = 0;
Linus Torvalds's avatar
Linus Torvalds committed
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608

	list_for_each_entry(dev, &bus->devices, bus_list) {
		struct pci_bus *b = dev->subordinate;
		if (!b)
			continue;

		switch (dev->class >> 8) {
		case PCI_CLASS_BRIDGE_CARDBUS:
			pci_bus_size_cardbus(b);
			break;

		case PCI_CLASS_BRIDGE_PCI:
		default:
			pci_bus_size_bridges(b);
			break;
		}
	}

	/* The root bus? */
	if (!bus->self)
		return;

	switch (bus->self->class >> 8) {
	case PCI_CLASS_BRIDGE_CARDBUS:
		/* don't size cardbuses yet. */
		break;

	case PCI_CLASS_BRIDGE_PCI:
		pci_bridge_check_ranges(bus);
609
610
611
612
		if (bus->self->is_hotplug_bridge) {
			min_io_size  = pci_hotplug_io_size;
			min_mem_size = pci_hotplug_mem_size;
		}
Linus Torvalds's avatar
Linus Torvalds committed
613
	default:
614
		pbus_size_io(bus, min_io_size);
Linus Torvalds's avatar
Linus Torvalds committed
615
616
617
618
619
620
621
		/* If the bridge supports prefetchable range, size it
		   separately. If it doesn't, or its prefetchable window
		   has already been allocated by arch code, try
		   non-prefetchable range for both types of PCI memory
		   resources. */
		mask = IORESOURCE_MEM;
		prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH;
622
		if (pbus_size_mem(bus, prefmask, prefmask, min_mem_size))
Linus Torvalds's avatar
Linus Torvalds committed
623
			mask = prefmask; /* Success, size non-prefetch only. */
624
625
626
		else
			min_mem_size += min_mem_size;
		pbus_size_mem(bus, mask, IORESOURCE_MEM, min_mem_size);
Linus Torvalds's avatar
Linus Torvalds committed
627
628
629
630
631
		break;
	}
}
EXPORT_SYMBOL(pci_bus_size_bridges);

632
633
static void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
					 struct resource_list_x *fail_head)
Linus Torvalds's avatar
Linus Torvalds committed
634
635
636
637
{
	struct pci_bus *b;
	struct pci_dev *dev;

638
	pbus_assign_resources_sorted(bus, fail_head);
Linus Torvalds's avatar
Linus Torvalds committed
639
640
641
642
643
644

	list_for_each_entry(dev, &bus->devices, bus_list) {
		b = dev->subordinate;
		if (!b)
			continue;

645
		__pci_bus_assign_resources(b, fail_head);
Linus Torvalds's avatar
Linus Torvalds committed
646
647
648
649
650
651
652
653
654
655
656

		switch (dev->class >> 8) {
		case PCI_CLASS_BRIDGE_PCI:
			pci_setup_bridge(b);
			break;

		case PCI_CLASS_BRIDGE_CARDBUS:
			pci_setup_cardbus(b);
			break;

		default:
657
658
			dev_info(&dev->dev, "not setting up bridge for bus "
				 "%04x:%02x\n", pci_domain_nr(b), b->number);
Linus Torvalds's avatar
Linus Torvalds committed
659
660
661
662
			break;
		}
	}
}
663
664
665
666
667

void __ref pci_bus_assign_resources(const struct pci_bus *bus)
{
	__pci_bus_assign_resources(bus, NULL);
}
Linus Torvalds's avatar
Linus Torvalds committed
668
669
EXPORT_SYMBOL(pci_bus_assign_resources);

670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
static void pci_bridge_release_resources(struct pci_bus *bus,
					  unsigned long type)
{
	int idx;
	bool changed = false;
	struct pci_dev *dev;
	struct resource *r;
	unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
				  IORESOURCE_PREFETCH;

	dev = bus->self;
	for (idx = PCI_BRIDGE_RESOURCES; idx <= PCI_BRIDGE_RESOURCE_END;
	     idx++) {
		r = &dev->resource[idx];
		if ((r->flags & type_mask) != type)
			continue;
		if (!r->parent)
			continue;
		/*
		 * if there are children under that, we should release them
		 *  all
		 */
		release_child_resources(r);
		if (!release_resource(r)) {
			dev_printk(KERN_DEBUG, &dev->dev,
				 "resource %d %pR released\n", idx, r);
			/* keep the old size */
			r->end = resource_size(r) - 1;
			r->start = 0;
			r->flags = 0;
			changed = true;
		}
	}

	if (changed) {
		/* avoiding touch the one without PREF */
		if (type & IORESOURCE_PREFETCH)
			type = IORESOURCE_PREFETCH;
		__pci_setup_bridge(bus, type);
	}
}

enum release_type {
	leaf_only,
	whole_subtree,
};
/*
 * try to release pci bridge resources that is from leaf bridge,
 * so we can allocate big new one later
 */
static void __ref pci_bus_release_bridge_resources(struct pci_bus *bus,
						   unsigned long type,
						   enum release_type rel_type)
{
	struct pci_dev *dev;
	bool is_leaf_bridge = true;

	list_for_each_entry(dev, &bus->devices, bus_list) {
		struct pci_bus *b = dev->subordinate;
		if (!b)
			continue;

		is_leaf_bridge = false;

		if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
			continue;

		if (rel_type == whole_subtree)
			pci_bus_release_bridge_resources(b, type,
						 whole_subtree);
	}

	if (pci_is_root_bus(bus))
		return;

	if ((bus->self->class >> 8) != PCI_CLASS_BRIDGE_PCI)
		return;

	if ((rel_type == whole_subtree) || is_leaf_bridge)
		pci_bridge_release_resources(bus, type);
}

752
753
754
755
756
757
static void pci_bus_dump_res(struct pci_bus *bus)
{
        int i;

        for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
                struct resource *res = bus->resource[i];
758
759

		if (!res || !res->end || !res->flags)
760
761
                        continue;

762
		dev_printk(KERN_DEBUG, &bus->dev, "resource %d %pR\n", i, res);
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
        }
}

static void pci_bus_dump_resources(struct pci_bus *bus)
{
	struct pci_bus *b;
	struct pci_dev *dev;


	pci_bus_dump_res(bus);

	list_for_each_entry(dev, &bus->devices, bus_list) {
		b = dev->subordinate;
		if (!b)
			continue;

		pci_bus_dump_resources(b);
	}
}

Linus Torvalds's avatar
Linus Torvalds committed
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
void __init
pci_assign_unassigned_resources(void)
{
	struct pci_bus *bus;

	/* Depth first, calculate sizes and alignments of all
	   subordinate buses. */
	list_for_each_entry(bus, &pci_root_buses, node) {
		pci_bus_size_bridges(bus);
	}
	/* Depth last, allocate resources and update the hardware. */
	list_for_each_entry(bus, &pci_root_buses, node) {
		pci_bus_assign_resources(bus);
		pci_enable_bridges(bus);
	}
798
799
800
801
802

	/* dump the resource on buses */
	list_for_each_entry(bus, &pci_root_buses, node) {
		pci_bus_dump_resources(bus);
	}
Linus Torvalds's avatar
Linus Torvalds committed
803
}