setup-bus.c 51 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 <linux/acpi.h>
29
#include "pci.h"
Linus Torvalds's avatar
Linus Torvalds committed
30

Bjorn Helgaas's avatar
Bjorn Helgaas committed
31
unsigned int pci_flags;
32

33 34
struct pci_dev_resource {
	struct list_head list;
35 36
	struct resource *res;
	struct pci_dev *dev;
37 38
	resource_size_t start;
	resource_size_t end;
39
	resource_size_t add_size;
40
	resource_size_t min_align;
41 42 43
	unsigned long flags;
};

44 45 46 47 48 49 50 51 52
static void free_list(struct list_head *head)
{
	struct pci_dev_resource *dev_res, *tmp;

	list_for_each_entry_safe(dev_res, tmp, head, list) {
		list_del(&dev_res->list);
		kfree(dev_res);
	}
}
53

54 55 56 57 58 59 60 61 62
/**
 * add_to_list() - add a new resource tracker to the list
 * @head:	Head of the list
 * @dev:	device corresponding to which the resource
 *		belongs
 * @res:	The resource to be tracked
 * @add_size:	additional size to be optionally added
 *              to the resource
 */
63
static int add_to_list(struct list_head *head,
64
		 struct pci_dev *dev, struct resource *res,
65
		 resource_size_t add_size, resource_size_t min_align)
66
{
67
	struct pci_dev_resource *tmp;
68

69
	tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
70
	if (!tmp) {
Ryan Desfosses's avatar
Ryan Desfosses committed
71
		pr_warn("add_to_list: kmalloc() failed!\n");
72
		return -ENOMEM;
73 74 75 76 77 78 79
	}

	tmp->res = res;
	tmp->dev = dev;
	tmp->start = res->start;
	tmp->end = res->end;
	tmp->flags = res->flags;
80
	tmp->add_size = add_size;
81
	tmp->min_align = min_align;
82 83

	list_add(&tmp->list, head);
84 85

	return 0;
86 87
}

88
static void remove_from_list(struct list_head *head,
89 90
				 struct resource *res)
{
91
	struct pci_dev_resource *dev_res, *tmp;
92

93 94 95 96
	list_for_each_entry_safe(dev_res, tmp, head, list) {
		if (dev_res->res == res) {
			list_del(&dev_res->list);
			kfree(dev_res);
97
			break;
98 99 100 101
		}
	}
}

102 103
static struct pci_dev_resource *res_to_dev_res(struct list_head *head,
					       struct resource *res)
104
{
105
	struct pci_dev_resource *dev_res;
106

107
	list_for_each_entry(dev_res, head, list) {
108
		if (dev_res->res == res)
109
			return dev_res;
110
	}
111

112
	return NULL;
113 114
}

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
static resource_size_t get_res_add_size(struct list_head *head,
					struct resource *res)
{
	struct pci_dev_resource *dev_res;

	dev_res = res_to_dev_res(head, res);
	return dev_res ? dev_res->add_size : 0;
}

static resource_size_t get_res_add_align(struct list_head *head,
					 struct resource *res)
{
	struct pci_dev_resource *dev_res;

	dev_res = res_to_dev_res(head, res);
	return dev_res ? dev_res->min_align : 0;
}


134
/* Sort resources by alignment */
135
static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head)
136 137 138 139 140
{
	int i;

	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
		struct resource *r;
141
		struct pci_dev_resource *dev_res, *tmp;
142
		resource_size_t r_align;
143
		struct list_head *n;
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159

		r = &dev->resource[i];

		if (r->flags & IORESOURCE_PCI_FIXED)
			continue;

		if (!(r->flags) || r->parent)
			continue;

		r_align = pci_resource_alignment(dev, r);
		if (!r_align) {
			dev_warn(&dev->dev, "BAR %d: %pR has bogus alignment\n",
				 i, r);
			continue;
		}

160 161
		tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
		if (!tmp)
162
			panic("pdev_sort_resources(): kmalloc() failed!\n");
163 164 165 166 167 168 169 170 171 172
		tmp->res = r;
		tmp->dev = dev;

		/* fallback is smallest one or list is empty*/
		n = head;
		list_for_each_entry(dev_res, head, list) {
			resource_size_t align;

			align = pci_resource_alignment(dev_res->dev,
							 dev_res->res);
173 174

			if (r_align > align) {
175
				n = &dev_res->list;
176 177 178
				break;
			}
		}
179 180
		/* Insert it just before n*/
		list_add_tail(&tmp->list, n);
181 182 183
	}
}

184
static void __dev_sort_resources(struct pci_dev *dev,
185
				 struct list_head *head)
Linus Torvalds's avatar
Linus Torvalds committed
186
{
187
	u16 class = dev->class >> 8;
Linus Torvalds's avatar
Linus Torvalds committed
188

189 190 191
	/* Don't touch classless devices or host bridges or ioapics.  */
	if (class == PCI_CLASS_NOT_DEFINED || class == PCI_CLASS_BRIDGE_HOST)
		return;
Linus Torvalds's avatar
Linus Torvalds committed
192

193 194 195 196 197 198 199
	/* Don't touch ioapic devices already enabled by firmware */
	if (class == PCI_CLASS_SYSTEM_PIC) {
		u16 command;
		pci_read_config_word(dev, PCI_COMMAND, &command);
		if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY))
			return;
	}
Linus Torvalds's avatar
Linus Torvalds committed
200

201 202
	pdev_sort_resources(dev, head);
}
203

Ram Pai's avatar
Ram Pai committed
204 205 206 207 208 209 210
static inline void reset_resource(struct resource *res)
{
	res->start = 0;
	res->end = 0;
	res->flags = 0;
}

211
/**
Ram Pai's avatar
Ram Pai committed
212
 * reassign_resources_sorted() - satisfy any additional resource requests
213
 *
Ram Pai's avatar
Ram Pai committed
214
 * @realloc_head : head of the list tracking requests requiring additional
215 216 217 218
 *             resources
 * @head     : head of the list tracking requests with allocated
 *             resources
 *
Ram Pai's avatar
Ram Pai committed
219
 * Walk through each element of the realloc_head and try to procure
220 221 222
 * additional resources for the element, provided the element
 * is in the head list.
 */
223 224
static void reassign_resources_sorted(struct list_head *realloc_head,
		struct list_head *head)
225 226
{
	struct resource *res;
227
	struct pci_dev_resource *add_res, *tmp;
228
	struct pci_dev_resource *dev_res;
229
	resource_size_t add_size, align;
230
	int idx;
Linus Torvalds's avatar
Linus Torvalds committed
231

232
	list_for_each_entry_safe(add_res, tmp, realloc_head, list) {
233 234
		bool found_match = false;

235
		res = add_res->res;
236 237 238 239 240
		/* skip resource that has been reset */
		if (!res->flags)
			goto out;

		/* skip this resource if not found in head list */
241 242 243 244 245
		list_for_each_entry(dev_res, head, list) {
			if (dev_res->res == res) {
				found_match = true;
				break;
			}
246
		}
247 248
		if (!found_match)/* just skip */
			continue;
249

250 251
		idx = res - &add_res->dev->resource[0];
		add_size = add_res->add_size;
252
		align = add_res->min_align;
253
		if (!resource_size(res)) {
254
			res->start = align;
255
			res->end = res->start + add_size - 1;
256
			if (pci_assign_resource(add_res->dev, idx))
257
				reset_resource(res);
258
		} else {
259
			res->flags |= add_res->flags &
260
				 (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN);
261
			if (pci_reassign_resource(add_res->dev, idx,
262
						  add_size, align))
263
				dev_printk(KERN_DEBUG, &add_res->dev->dev,
264 265 266
					   "failed to add %llx res[%d]=%pR\n",
					   (unsigned long long)add_size,
					   idx, res);
267 268
		}
out:
269 270
		list_del(&add_res->list);
		kfree(add_res);
271 272 273 274 275 276 277
	}
}

/**
 * assign_requested_resources_sorted() - satisfy resource requests
 *
 * @head : head of the list tracking requests for resources
278
 * @fail_head : head of the list tracking requests that could
279 280 281 282 283
 *		not be allocated
 *
 * Satisfy resource requests of each element in the list. Add
 * requests that could not satisfied to the failed_list.
 */
284 285
static void assign_requested_resources_sorted(struct list_head *head,
				 struct list_head *fail_head)
286 287
{
	struct resource *res;
288
	struct pci_dev_resource *dev_res;
289
	int idx;
290

291 292 293 294 295
	list_for_each_entry(dev_res, head, list) {
		res = dev_res->res;
		idx = res - &dev_res->dev->resource[0];
		if (resource_size(res) &&
		    pci_assign_resource(dev_res->dev, idx)) {
296
			if (fail_head) {
297 298 299 300 301 302
				/*
				 * if the failed res is for ROM BAR, and it will
				 * be enabled later, don't add it to the list
				 */
				if (!((idx == PCI_ROM_RESOURCE) &&
				      (!(res->flags & IORESOURCE_ROM_ENABLE))))
303 304
					add_to_list(fail_head,
						    dev_res->dev, res,
305 306
						    0 /* don't care */,
						    0 /* don't care */);
307
			}
Ram Pai's avatar
Ram Pai committed
308
			reset_resource(res);
309
		}
Linus Torvalds's avatar
Linus Torvalds committed
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 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
static unsigned long pci_fail_res_type_mask(struct list_head *fail_head)
{
	struct pci_dev_resource *fail_res;
	unsigned long mask = 0;

	/* check failed type */
	list_for_each_entry(fail_res, fail_head, list)
		mask |= fail_res->flags;

	/*
	 * one pref failed resource will set IORESOURCE_MEM,
	 * as we can allocate pref in non-pref range.
	 * Will release all assigned non-pref sibling resources
	 * according to that bit.
	 */
	return mask & (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH);
}

static bool pci_need_to_release(unsigned long mask, struct resource *res)
{
	if (res->flags & IORESOURCE_IO)
		return !!(mask & IORESOURCE_IO);

	/* check pref at first */
	if (res->flags & IORESOURCE_PREFETCH) {
		if (mask & IORESOURCE_PREFETCH)
			return true;
		/* count pref if its parent is non-pref */
		else if ((mask & IORESOURCE_MEM) &&
			 !(res->parent->flags & IORESOURCE_PREFETCH))
			return true;
		else
			return false;
	}

	if (res->flags & IORESOURCE_MEM)
		return !!(mask & IORESOURCE_MEM);

	return false;	/* should not get here */
}

354 355 356
static void __assign_resources_sorted(struct list_head *head,
				 struct list_head *realloc_head,
				 struct list_head *fail_head)
357
{
358 359 360 361
	/*
	 * Should not assign requested resources at first.
	 *   they could be adjacent, so later reassign can not reallocate
	 *   them one by one in parent resource window.
362
	 * Try to assign requested + add_size at beginning
363 364 365
	 *  if could do that, could get out early.
	 *  if could not do that, we still try to assign requested at first,
	 *    then try to reassign add_size for some resources.
366 367 368 369 370 371 372 373 374 375 376 377
	 *
	 * Separate three resource type checking if we need to release
	 * assigned resource after requested + add_size try.
	 *	1. if there is io port assign fail, will release assigned
	 *	   io port.
	 *	2. if there is pref mmio assign fail, release assigned
	 *	   pref mmio.
	 *	   if assigned pref mmio's parent is non-pref mmio and there
	 *	   is non-pref mmio assign fail, will release that assigned
	 *	   pref mmio.
	 *	3. if there is non-pref mmio assign fail or pref mmio
	 *	   assigned fail, will release assigned non-pref mmio.
378
	 */
379 380
	LIST_HEAD(save_head);
	LIST_HEAD(local_fail_head);
381
	struct pci_dev_resource *save_res;
382
	struct pci_dev_resource *dev_res, *tmp_res, *dev_res2;
383
	unsigned long fail_type;
384
	resource_size_t add_align, align;
385 386

	/* Check if optional add_size is there */
387
	if (!realloc_head || list_empty(realloc_head))
388 389 390
		goto requested_and_reassign;

	/* Save original start, end, flags etc at first */
391 392
	list_for_each_entry(dev_res, head, list) {
		if (add_to_list(&save_head, dev_res->dev, dev_res->res, 0, 0)) {
393
			free_list(&save_head);
394 395
			goto requested_and_reassign;
		}
396
	}
397 398

	/* Update res in head list with add_size in realloc_head list */
399
	list_for_each_entry_safe(dev_res, tmp_res, head, list) {
400 401
		dev_res->res->end += get_res_add_size(realloc_head,
							dev_res->res);
402

403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
		/*
		 * There are two kinds of additional resources in the list:
		 * 1. bridge resource  -- IORESOURCE_STARTALIGN
		 * 2. SR-IOV resource   -- IORESOURCE_SIZEALIGN
		 * Here just fix the additional alignment for bridge
		 */
		if (!(dev_res->res->flags & IORESOURCE_STARTALIGN))
			continue;

		add_align = get_res_add_align(realloc_head, dev_res->res);

		/*
		 * The "head" list is sorted by the alignment to make sure
		 * resources with bigger alignment will be assigned first.
		 * After we change the alignment of a dev_res in "head" list,
		 * we need to reorder the list by alignment to make it
		 * consistent.
		 */
		if (add_align > dev_res->res->start) {
422 423
			resource_size_t r_size = resource_size(dev_res->res);

424
			dev_res->res->start = add_align;
425
			dev_res->res->end = add_align + r_size - 1;
426 427 428 429

			list_for_each_entry(dev_res2, head, list) {
				align = pci_resource_alignment(dev_res2->dev,
							       dev_res2->res);
430
				if (add_align > align) {
431 432
					list_move_tail(&dev_res->list,
						       &dev_res2->list);
433 434
					break;
				}
435
			}
436
		}
437 438 439

	}

440 441 442 443
	/* Try updated head list with add_size added */
	assign_requested_resources_sorted(head, &local_fail_head);

	/* all assigned with add_size ? */
444
	if (list_empty(&local_fail_head)) {
445
		/* Remove head list from realloc_head list */
446 447
		list_for_each_entry(dev_res, head, list)
			remove_from_list(realloc_head, dev_res->res);
448 449
		free_list(&save_head);
		free_list(head);
450 451 452
		return;
	}

453 454 455 456 457 458 459 460 461 462 463 464 465
	/* check failed type */
	fail_type = pci_fail_res_type_mask(&local_fail_head);
	/* remove not need to be released assigned res from head list etc */
	list_for_each_entry_safe(dev_res, tmp_res, head, list)
		if (dev_res->res->parent &&
		    !pci_need_to_release(fail_type, dev_res->res)) {
			/* remove it from realloc_head list */
			remove_from_list(realloc_head, dev_res->res);
			remove_from_list(&save_head, dev_res->res);
			list_del(&dev_res->list);
			kfree(dev_res);
		}

466
	free_list(&local_fail_head);
467
	/* Release assigned resource */
468 469 470
	list_for_each_entry(dev_res, head, list)
		if (dev_res->res->parent)
			release_resource(dev_res->res);
471
	/* Restore start/end/flags from saved list */
472 473
	list_for_each_entry(save_res, &save_head, list) {
		struct resource *res = save_res->res;
474

475 476 477
		res->start = save_res->start;
		res->end = save_res->end;
		res->flags = save_res->flags;
478
	}
479
	free_list(&save_head);
480 481

requested_and_reassign:
482 483 484
	/* Satisfy the must-have resource requests */
	assign_requested_resources_sorted(head, fail_head);

485
	/* Try to satisfy any additional optional resource
486
		requests */
Ram Pai's avatar
Ram Pai committed
487 488
	if (realloc_head)
		reassign_resources_sorted(realloc_head, head);
489
	free_list(head);
490 491
}

492
static void pdev_assign_resources_sorted(struct pci_dev *dev,
493 494
				 struct list_head *add_head,
				 struct list_head *fail_head)
495
{
496
	LIST_HEAD(head);
497 498

	__dev_sort_resources(dev, &head);
499
	__assign_resources_sorted(&head, add_head, fail_head);
500 501 502 503

}

static void pbus_assign_resources_sorted(const struct pci_bus *bus,
504 505
					 struct list_head *realloc_head,
					 struct list_head *fail_head)
506 507
{
	struct pci_dev *dev;
508
	LIST_HEAD(head);
509 510 511 512

	list_for_each_entry(dev, &bus->devices, bus_list)
		__dev_sort_resources(dev, &head);

Ram Pai's avatar
Ram Pai committed
513
	__assign_resources_sorted(&head, realloc_head, fail_head);
514 515
}

516
void pci_setup_cardbus(struct pci_bus *bus)
Linus Torvalds's avatar
Linus Torvalds committed
517 518
{
	struct pci_dev *bridge = bus->self;
519
	struct resource *res;
Linus Torvalds's avatar
Linus Torvalds committed
520 521
	struct pci_bus_region region;

522 523
	dev_info(&bridge->dev, "CardBus bridge to %pR\n",
		 &bus->busn_res);
Linus Torvalds's avatar
Linus Torvalds committed
524

525
	res = bus->resource[0];
526
	pcibios_resource_to_bus(bridge->bus, &region, res);
527
	if (res->flags & IORESOURCE_IO) {
Linus Torvalds's avatar
Linus Torvalds committed
528 529 530 531
		/*
		 * The IO resource is allocated a range twice as large as it
		 * would normally need.  This allows us to set both IO regs.
		 */
532
		dev_info(&bridge->dev, "  bridge window %pR\n", res);
Linus Torvalds's avatar
Linus Torvalds committed
533 534 535 536 537 538
		pci_write_config_dword(bridge, PCI_CB_IO_BASE_0,
					region.start);
		pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0,
					region.end);
	}

539
	res = bus->resource[1];
540
	pcibios_resource_to_bus(bridge->bus, &region, res);
541 542
	if (res->flags & IORESOURCE_IO) {
		dev_info(&bridge->dev, "  bridge window %pR\n", res);
Linus Torvalds's avatar
Linus Torvalds committed
543 544 545 546 547 548
		pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
					region.start);
		pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1,
					region.end);
	}

549
	res = bus->resource[2];
550
	pcibios_resource_to_bus(bridge->bus, &region, res);
551 552
	if (res->flags & IORESOURCE_MEM) {
		dev_info(&bridge->dev, "  bridge window %pR\n", res);
Linus Torvalds's avatar
Linus Torvalds committed
553 554 555 556 557 558
		pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
					region.start);
		pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0,
					region.end);
	}

559
	res = bus->resource[3];
560
	pcibios_resource_to_bus(bridge->bus, &region, res);
561 562
	if (res->flags & IORESOURCE_MEM) {
		dev_info(&bridge->dev, "  bridge window %pR\n", res);
Linus Torvalds's avatar
Linus Torvalds committed
563 564 565 566 567 568
		pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
					region.start);
		pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1,
					region.end);
	}
}
569
EXPORT_SYMBOL(pci_setup_cardbus);
Linus Torvalds's avatar
Linus Torvalds committed
570 571 572 573 574 575 576 577 578 579 580 581

/* 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.  */
582
static void pci_setup_bridge_io(struct pci_dev *bridge)
Linus Torvalds's avatar
Linus Torvalds committed
583
{
584
	struct resource *res;
Linus Torvalds's avatar
Linus Torvalds committed
585
	struct pci_bus_region region;
586 587
	unsigned long io_mask;
	u8 io_base_lo, io_limit_lo;
588 589
	u16 l;
	u32 io_upper16;
Linus Torvalds's avatar
Linus Torvalds committed
590

591 592 593 594
	io_mask = PCI_IO_RANGE_MASK;
	if (bridge->io_window_1k)
		io_mask = PCI_IO_1K_RANGE_MASK;

Linus Torvalds's avatar
Linus Torvalds committed
595
	/* Set up the top and bottom of the PCI I/O segment for this bus. */
596
	res = &bridge->resource[PCI_BRIDGE_RESOURCES + 0];
597
	pcibios_resource_to_bus(bridge->bus, &region, res);
598
	if (res->flags & IORESOURCE_IO) {
599
		pci_read_config_word(bridge, PCI_IO_BASE, &l);
600 601
		io_base_lo = (region.start >> 8) & io_mask;
		io_limit_lo = (region.end >> 8) & io_mask;
602
		l = ((u16) io_limit_lo << 8) | io_base_lo;
Linus Torvalds's avatar
Linus Torvalds committed
603 604
		/* Set up upper 16 bits of I/O base/limit. */
		io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
605
		dev_info(&bridge->dev, "  bridge window %pR\n", res);
606
	} else {
Linus Torvalds's avatar
Linus Torvalds committed
607 608 609 610 611 612 613
		/* Clear upper 16 bits of I/O base/limit. */
		io_upper16 = 0;
		l = 0x00f0;
	}
	/* 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. */
614
	pci_write_config_word(bridge, PCI_IO_BASE, l);
Linus Torvalds's avatar
Linus Torvalds committed
615 616
	/* Update upper 16 bits of I/O base/limit. */
	pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16);
617 618
}

619
static void pci_setup_bridge_mmio(struct pci_dev *bridge)
620 621 622 623
{
	struct resource *res;
	struct pci_bus_region region;
	u32 l;
Linus Torvalds's avatar
Linus Torvalds committed
624

625
	/* Set up the top and bottom of the PCI Memory segment for this bus. */
626
	res = &bridge->resource[PCI_BRIDGE_RESOURCES + 1];
627
	pcibios_resource_to_bus(bridge->bus, &region, res);
628
	if (res->flags & IORESOURCE_MEM) {
Linus Torvalds's avatar
Linus Torvalds committed
629 630
		l = (region.start >> 16) & 0xfff0;
		l |= region.end & 0xfff00000;
631
		dev_info(&bridge->dev, "  bridge window %pR\n", res);
632
	} else {
Linus Torvalds's avatar
Linus Torvalds committed
633 634 635
		l = 0x0000fff0;
	}
	pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
636 637
}

638
static void pci_setup_bridge_mmio_pref(struct pci_dev *bridge)
639 640 641 642
{
	struct resource *res;
	struct pci_bus_region region;
	u32 l, bu, lu;
Linus Torvalds's avatar
Linus Torvalds committed
643 644 645 646 647 648 649

	/* 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. */
650
	bu = lu = 0;
651
	res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2];
652
	pcibios_resource_to_bus(bridge->bus, &region, res);
653
	if (res->flags & IORESOURCE_PREFETCH) {
Linus Torvalds's avatar
Linus Torvalds committed
654 655
		l = (region.start >> 16) & 0xfff0;
		l |= region.end & 0xfff00000;
656
		if (res->flags & IORESOURCE_MEM_64) {
657 658 659
			bu = upper_32_bits(region.start);
			lu = upper_32_bits(region.end);
		}
660
		dev_info(&bridge->dev, "  bridge window %pR\n", res);
661
	} else {
Linus Torvalds's avatar
Linus Torvalds committed
662 663 664 665
		l = 0x0000fff0;
	}
	pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);

666 667 668
	/* 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);
669 670 671 672 673 674
}

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

675 676
	dev_info(&bridge->dev, "PCI bridge to %pR\n",
		 &bus->busn_res);
677 678

	if (type & IORESOURCE_IO)
679
		pci_setup_bridge_io(bridge);
680 681

	if (type & IORESOURCE_MEM)
682
		pci_setup_bridge_mmio(bridge);
683 684

	if (type & IORESOURCE_PREFETCH)
685
		pci_setup_bridge_mmio_pref(bridge);
Linus Torvalds's avatar
Linus Torvalds committed
686 687 688 689

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

Gavin Shan's avatar
Gavin Shan committed
690 691 692 693
void __weak pcibios_setup_bridge(struct pci_bus *bus, unsigned long type)
{
}

694
void pci_setup_bridge(struct pci_bus *bus)
695 696 697 698
{
	unsigned long type = IORESOURCE_IO | IORESOURCE_MEM |
				  IORESOURCE_PREFETCH;

Gavin Shan's avatar
Gavin Shan committed
699
	pcibios_setup_bridge(bus, type);
700 701 702
	__pci_setup_bridge(bus, type);
}

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

int pci_claim_bridge_resource(struct pci_dev *bridge, int i)
{
	if (i < PCI_BRIDGE_RESOURCES || i > PCI_BRIDGE_RESOURCE_END)
		return 0;

	if (pci_claim_resource(bridge, i) == 0)
		return 0;	/* claimed the window */

	if ((bridge->class >> 8) != PCI_CLASS_BRIDGE_PCI)
		return 0;

	if (!pci_bus_clip_resource(bridge, i))
		return -EINVAL;	/* clipping didn't change anything */

	switch (i - PCI_BRIDGE_RESOURCES) {
	case 0:
		pci_setup_bridge_io(bridge);
		break;
	case 1:
		pci_setup_bridge_mmio(bridge);
		break;
	case 2:
		pci_setup_bridge_mmio_pref(bridge);
		break;
	default:
		return -EINVAL;
	}

	if (pci_claim_resource(bridge, i) == 0)
		return 0;	/* claimed a smaller window */

	return -EINVAL;
}

Linus Torvalds's avatar
Linus Torvalds committed
738 739 740
/* 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. */
741
static void pci_bridge_check_ranges(struct pci_bus *bus)
Linus Torvalds's avatar
Linus Torvalds committed
742 743 744 745 746 747 748 749 750 751 752
{
	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) {
753
		pci_write_config_word(bridge, PCI_IO_BASE, 0xe0f0);
Linus Torvalds's avatar
Linus Torvalds committed
754
		pci_read_config_word(bridge, PCI_IO_BASE, &io);
755 756 757
		pci_write_config_word(bridge, PCI_IO_BASE, 0x0);
	}
	if (io)
Linus Torvalds's avatar
Linus Torvalds committed
758
		b_res[0].flags |= IORESOURCE_IO;
759

Linus Torvalds's avatar
Linus Torvalds committed
760 761 762 763 764
	/*  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;
765

Linus Torvalds's avatar
Linus Torvalds committed
766 767 768
	pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
	if (!pmem) {
		pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE,
769
					       0xffe0fff0);
Linus Torvalds's avatar
Linus Torvalds committed
770 771 772
		pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
		pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0);
	}
773
	if (pmem) {
Linus Torvalds's avatar
Linus Torvalds committed
774
		b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
775 776
		if ((pmem & PCI_PREF_RANGE_TYPE_MASK) ==
		    PCI_PREF_RANGE_TYPE_64) {
777
			b_res[2].flags |= IORESOURCE_MEM_64;
778 779
			b_res[2].flags |= PCI_PREF_RANGE_TYPE_64;
		}
780 781 782 783 784 785 786 787 788 789 790 791 792 793 794
	}

	/* 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
795 796 797 798 799 800
}

/* 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). */
801 802
static struct resource *find_free_bus_resource(struct pci_bus *bus,
			 unsigned long type_mask, unsigned long type)
Linus Torvalds's avatar
Linus Torvalds committed
803 804 805 806
{
	int i;
	struct resource *r;

807
	pci_bus_for_each_resource(bus, r, i) {
808 809
		if (r == &ioport_resource || r == &iomem_resource)
			continue;
810 811
		if (r && (r->flags & type_mask) == type && !r->parent)
			return r;
Linus Torvalds's avatar
Linus Torvalds committed
812 813 814 815
	}
	return NULL;
}

816 817 818 819 820 821 822 823
static resource_size_t calculate_iosize(resource_size_t size,
		resource_size_t min_size,
		resource_size_t size1,
		resource_size_t old_size,
		resource_size_t align)
{
	if (size < min_size)
		size = min_size;
Ryan Desfosses's avatar
Ryan Desfosses committed
824
	if (old_size == 1)
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844
		old_size = 0;
	/* 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
	size = ALIGN(size + size1, align);
	if (size < old_size)
		size = old_size;
	return size;
}

static resource_size_t calculate_memsize(resource_size_t size,
		resource_size_t min_size,
		resource_size_t size1,
		resource_size_t old_size,
		resource_size_t align)
{
	if (size < min_size)
		size = min_size;
Ryan Desfosses's avatar
Ryan Desfosses committed
845
	if (old_size == 1)
846 847 848 849 850 851 852
		old_size = 0;
	if (size < old_size)
		size = old_size;
	size = ALIGN(size + size1, align);
	return size;
}

853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884
resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus,
						unsigned long type)
{
	return 1;
}

#define PCI_P2P_DEFAULT_MEM_ALIGN	0x100000	/* 1MiB */
#define PCI_P2P_DEFAULT_IO_ALIGN	0x1000		/* 4KiB */
#define PCI_P2P_DEFAULT_IO_ALIGN_1K	0x400		/* 1KiB */

static resource_size_t window_alignment(struct pci_bus *bus,
					unsigned long type)
{
	resource_size_t align = 1, arch_align;

	if (type & IORESOURCE_MEM)
		align = PCI_P2P_DEFAULT_MEM_ALIGN;
	else if (type & IORESOURCE_IO) {
		/*
		 * Per spec, I/O windows are 4K-aligned, but some
		 * bridges have an extension to support 1K alignment.
		 */
		if (bus->self->io_window_1k)
			align = PCI_P2P_DEFAULT_IO_ALIGN_1K;
		else
			align = PCI_P2P_DEFAULT_IO_ALIGN;
	}

	arch_align = pcibios_window_alignment(bus, type);
	return max(align, arch_align);
}

885 886 887 888 889 890
/**
 * pbus_size_io() - size the io window of a given bus
 *
 * @bus : the bus
 * @min_size : the minimum io window that must to be allocated
 * @add_size : additional optional io window
Ram Pai's avatar
Ram Pai committed
891
 * @realloc_head : track the additional io window on this list
892 893
 *
 * Sizing the IO windows of the PCI-PCI bridge is trivial,
894
 * since these windows have 1K or 4K granularity and the IO ranges
895 896 897 898
 * of non-bridge PCI devices are limited to 256 bytes.
 * We must be careful with the ISA aliasing though.
 */
static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
899
		resource_size_t add_size, struct list_head *realloc_head)
Linus Torvalds's avatar
Linus Torvalds committed
900 901
{
	struct pci_dev *dev;
902 903
	struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO,
							IORESOURCE_IO);
Wei Yang's avatar
Wei Yang committed
904
	resource_size_t size = 0, size0 = 0, size1 = 0;
905
	resource_size_t children_add_size = 0;
906
	resource_size_t min_align, align;
Linus Torvalds's avatar
Linus Torvalds committed
907 908

	if (!b_res)
909
		return;
Linus Torvalds's avatar
Linus Torvalds committed
910

911
	min_align = window_alignment(bus, IORESOURCE_IO);
Linus Torvalds's avatar
Linus Torvalds committed
912 913 914 915 916 917 918 919 920
	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;
921
			r_size = resource_size(r);
Linus Torvalds's avatar
Linus Torvalds committed
922 923 924 925 926 927

			if (r_size < 0x400)
				/* Might be re-aligned for ISA */
				size += r_size;
			else
				size1 += r_size;
928

929 930 931 932
			align = pci_resource_alignment(dev, r);
			if (align > min_align)
				min_align = align;

Ram Pai's avatar
Ram Pai committed
933 934
			if (realloc_head)
				children_add_size += get_res_add_size(realloc_head, r);
Linus Torvalds's avatar
Linus Torvalds committed
935 936
		}
	}
937

938
	size0 = calculate_iosize(size, min_size, size1,
939
			resource_size(b_res), min_align);
940 941
	if (children_add_size > add_size)
		add_size = children_add_size;
Ram Pai's avatar
Ram Pai committed
942
	size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :
Yinghai Lu's avatar
Yinghai Lu committed
943
		calculate_iosize(size, min_size, add_size + size1,
944
			resource_size(b_res), min_align);
945
	if (!size0 && !size1) {
946
		if (b_res->start || b_res->end)
947 948
			dev_info(&bus->self->dev, "disabling bridge window %pR to %pR (unused)\n",
				 b_res, &bus->busn_res);
Linus Torvalds's avatar
Linus Torvalds committed
949 950 951
		b_res->flags = 0;
		return;
	}
952 953

	b_res->start = min_align;
954
	b_res->end = b_res->start + size0 - 1;
955
	b_res->flags |= IORESOURCE_STARTALIGN;
956
	if (size1 > size0 && realloc_head) {
957 958
		add_to_list(realloc_head, bus->self, b_res, size1-size0,
			    min_align);
959 960 961
		dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window %pR to %pR add_size %llx\n",
			   b_res, &bus->busn_res,
			   (unsigned long long)size1-size0);
962
	}
Linus Torvalds's avatar
Linus Torvalds committed
963 964
}

Gavin Shan's avatar
Gavin Shan committed
965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986
static inline resource_size_t calculate_mem_align(resource_size_t *aligns,
						  int max_order)
{
	resource_size_t align = 0;
	resource_size_t min_align = 0;
	int order;

	for (order = 0; order <= max_order; order++) {
		resource_size_t align1 = 1;

		align1 <<= (order + 20);

		if (!align)
			min_align = align1;
		else if (ALIGN(align + min_align, min_align) < align1)
			min_align = align1 >> 1;
		align += aligns[order];
	}

	return min_align;
}

987 988 989 990
/**
 * pbus_size_mem() - size the memory window of a given bus
 *
 * @bus : the bus
991 992
 * @mask: mask the resource flag, then compare it with type
 * @type: the type of free resource from bridge
993 994
 * @type2: second match type
 * @type3: third match type
995 996
 * @min_size : the minimum memory window that must to be allocated
 * @add_size : additional optional memory window
Ram Pai's avatar
Ram Pai committed
997
 * @realloc_head : track the additional memory window on this list
998 999 1000
 *
 * Calculate the size of the bus and minimal alignment which
 * guarantees that all child resources fit in this size.
1001 1002 1003 1004
 *
 * Returns -ENOSPC if there's no available bus resource of the desired type.
 * Otherwise, sets the bus resource start/end to indicate the required
 * size, adds things to realloc_head (if supplied), and returns 0.
1005
 */
1006
static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
1007 1008 1009 1010
			 unsigned long type, unsigned long type2,
			 unsigned long type3,
			 resource_size_t min_size, resource_size_t add_size,
			 struct list_head *realloc_head)
Linus Torvalds's avatar
Linus Torvalds committed
1011 1012
{
	struct pci_dev *dev;
1013
	resource_size_t min_align, align, size, size0, size1;
1014
	resource_size_t aligns[18];	/* Alignments from 1Mb to 128Gb */
Linus Torvalds's avatar
Linus Torvalds committed
1015
	int order, max_order;
1016 1017
	struct resource *b_res = find_free_bus_resource(bus,
					mask | IORESOURCE_PREFETCH, type);
1018
	resource_size_t children_add_size = 0;
1019 1020
	resource_size_t children_add_align = 0;
	resource_size_t add_align = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1021 1022

	if (!b_res)
1023
		return -ENOSPC;
Linus Torvalds's avatar
Linus Torvalds committed
1024 1025 1026 1027 1028 1029 1030

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

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

Linus Torvalds's avatar
Linus Torvalds committed
1032 1033
		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
			struct resource *r = &dev->resource[i];
1034
			resource_size_t r_size;
Linus Torvalds's avatar
Linus Torvalds committed
1035

1036 1037 1038 1039
			if (r->parent || (r->flags & IORESOURCE_PCI_FIXED) ||
			    ((r->flags & mask) != type &&
			     (r->flags & mask) != type2 &&
			     (r->flags & mask) != type3))
Linus Torvalds's avatar
Linus Torvalds committed
1040
				continue;
1041
			r_size = resource_size(r);
1042 1043
#ifdef CONFIG_PCI_IOV
			/* put SRIOV requested res to the optional list */
Ram Pai's avatar
Ram Pai committed
1044
			if (realloc_head && i >= PCI_IOV_RESOURCES &&
1045
					i <= PCI_IOV_RESOURCE_END) {
1046
				add_align = max(pci_resource_alignment(dev, r), add_align);
1047
				r->end = r->start - 1;
1048
				add_to_list(realloc_head, dev, r, r_size, 0/* don't care */);
1049 1050 1051 1052
				children_add_size += r_size;
				continue;
			}
#endif
Alan's avatar
Alan committed
1053 1054 1055 1056 1057 1058
			/*
			 * aligns[0] is for 1MB (since bridge memory
			 * windows are always at least 1MB aligned), so
			 * keep "order" from being negative for smaller
			 * resources.
			 */
1059
			align = pci_resource_alignment(dev, r);
Linus Torvalds's avatar
Linus Torvalds committed
1060
			order = __ffs(align) - 20;
Alan's avatar
Alan committed
1061 1062 1063
			if (order < 0)
				order = 0;
			if (order >= ARRAY_SIZE(aligns)) {
1064 1065
				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
1066 1067 1068
				r->flags = 0;
				continue;
			}
1069
			size += max(r_size, align);
Linus Torvalds's avatar
Linus Torvalds committed
1070 1071
			/* Exclude ranges with size > align from
			   calculation of the alignment. */
1072
			if (r_size <= align)
Linus Torvalds's avatar
Linus Torvalds committed
1073 1074 1075
				aligns[order] += align;
			if (order > max_order)
				max_order = order;
1076

1077
			if (realloc_head) {
Ram Pai's avatar
Ram Pai committed
1078
				children_add_size += get_res_add_size(realloc_head, r);
1079 1080 1081
				children_add_align = get_res_add_align(realloc_head, r);
				add_align = max(add_align, children_add_align);
			}
Linus Torvalds's avatar
Linus Torvalds committed
1082 1083
		}
	}
1084

Gavin Shan's avatar
Gavin Shan committed
1085
	min_align = calculate_mem_align(aligns, max_order);
1086
	min_align = max(min_align, window_alignment(bus, b_res->flags));
1087
	size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align);
1088
	add_align = max(min_align, add_align);
1089 1090
	if (children_add_size > add_size)
		add_size = children_add_size;
Ram Pai's avatar
Ram Pai committed
1091
	size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :
Yinghai Lu's avatar
Yinghai Lu committed
1092
		calculate_memsize(size, min_size, add_size,
1093
				resource_size(b_res), add_align);
1094
	if (!size0 && !size1) {
1095
		if (b_res->start || b_res->end)
1096 1097
			dev_info(&bus->self->dev, "disabling bridge window %pR to %pR (unused)\n",
				 b_res, &bus->busn_res);
Linus Torvalds's avatar
Linus Torvalds committed
1098
		b_res->flags = 0;
1099
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1100 1101
	}
	b_res->start = min_align;
1102
	b_res->end = size0 + min_align - 1;
1103
	b_res->flags |= IORESOURCE_STARTALIGN;
1104
	if (size1 > size0 && realloc_head) {
1105 1106
		add_to_list(realloc_head, bus->self, b_res, size1-size0, add_align);
		dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window %pR to %pR add_size %llx add_align %llx\n",
1107
			   b_res, &bus->busn_res,
1108 1109
			   (unsigned long long) (size1 - size0),
			   (unsigned long long) add_align);
1110
	}
1111
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1112 1113
}

1114 1115 1116 1117 1118 1119 1120 1121 1122 1123
unsigned long pci_cardbus_resource_alignment(struct resource *res)
{
	if (res->flags & IORESOURCE_IO)
		return pci_cardbus_io_size;
	if (res->flags & IORESOURCE_MEM)
		return pci_cardbus_mem_size;
	return 0;
}

static void pci_bus_size_cardbus(struct pci_bus *bus,
1124
			struct list_head *realloc_head)
Linus Torvalds's avatar
Linus Torvalds committed
1125 1126 1127
{
	struct pci_dev *bridge = bus->self;
	struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES];
1128
	resource_size_t b_res_3_size = pci_cardbus_mem_size * 2;
Linus Torvalds's avatar
Linus Torvalds committed
1129 1130
	u16 ctrl;

1131 1132
	if (b_res[0].parent)
		goto handle_b_res_1;
Linus Torvalds's avatar
Linus Torvalds committed
1133 1134 1135 1136
	/*
	 * Reserve some resources for CardBus.  We reserve
	 * a fixed amount of bus space for CardBus bridges.
	 */
1137 1138 1139 1140 1141 1142 1143 1144
	b_res[0].start = pci_cardbus_io_size;
	b_res[0].end = b_res[0].start + pci_cardbus_io_size - 1;
	b_res[0].flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
	if (realloc_head) {
		b_res[0].end -= pci_cardbus_io_size;
		add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size,
				pci_cardbus_io_size);
	}
Linus Torvalds's avatar
Linus Torvalds committed
1145

1146 1147 1148
handle_b_res_1:
	if (b_res[1].parent)
		goto handle_b_res_2;
1149 1150 1151 1152 1153 1154 1155 1156
	b_res[1].start = pci_cardbus_io_size;
	b_res[1].end = b_res[1].start + pci_cardbus_io_size - 1;
	b_res[1].flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
	if (realloc_head) {
		b_res[1].end -= pci_cardbus_io_size;
		add_to_list(realloc_head, bridge, b_res+1, pci_cardbus_io_size,
				 pci_cardbus_io_size);
	}
Linus Torvalds's avatar
Linus Torvalds committed
1157

1158
handle_b_res_2:
1159 1160 1161 1162 1163 1164 1165 1166
	/* MEM1 must not be pref mmio */
	pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
	if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM1) {
		ctrl &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM1;
		pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl);
		pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
	}

Linus Torvalds's avatar
Linus Torvalds committed
1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177
	/*
	 * 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);
	}

1178 1179
	if (b_res[2].parent)
		goto handle_b_res_3;
Linus Torvalds's avatar
Linus Torvalds committed
1180 1181 1182 1183 1184 1185
	/*
	 * 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) {
1186 1187 1188 1189 1190