| Yinghai Lu | 67f241f | 2009-11-11 22:27:40 -0800 | [diff] [blame] | 1 | #include <linux/init.h> | 
 | 2 | #include <linux/pci.h> | 
| Yinghai Lu | 9ad3f2c | 2010-02-10 01:20:11 -0800 | [diff] [blame] | 3 | #include <linux/range.h> | 
| Yinghai Lu | 67f241f | 2009-11-11 22:27:40 -0800 | [diff] [blame] | 4 |  | 
 | 5 | #include "bus_numa.h" | 
 | 6 |  | 
 | 7 | int pci_root_num; | 
 | 8 | struct pci_root_info pci_root_info[PCI_ROOT_NR]; | 
| Yinghai Lu | 67f241f | 2009-11-11 22:27:40 -0800 | [diff] [blame] | 9 |  | 
 | 10 | void x86_pci_root_bus_res_quirks(struct pci_bus *b) | 
 | 11 | { | 
 | 12 | 	int i; | 
 | 13 | 	int j; | 
 | 14 | 	struct pci_root_info *info; | 
 | 15 |  | 
 | 16 | 	/* don't go for it if _CRS is used already */ | 
 | 17 | 	if (b->resource[0] != &ioport_resource || | 
 | 18 | 	    b->resource[1] != &iomem_resource) | 
 | 19 | 		return; | 
 | 20 |  | 
 | 21 | 	if (!pci_root_num) | 
 | 22 | 		return; | 
 | 23 |  | 
| Yinghai Lu | 67f241f | 2009-11-11 22:27:40 -0800 | [diff] [blame] | 24 | 	for (i = 0; i < pci_root_num; i++) { | 
 | 25 | 		if (pci_root_info[i].bus_min == b->number) | 
 | 26 | 			break; | 
 | 27 | 	} | 
 | 28 |  | 
 | 29 | 	if (i == pci_root_num) | 
 | 30 | 		return; | 
 | 31 |  | 
 | 32 | 	printk(KERN_DEBUG "PCI: peer root bus %02x res updated from pci conf\n", | 
 | 33 | 			b->number); | 
 | 34 |  | 
| Bjorn Helgaas | 2fe2abf | 2010-02-23 10:24:36 -0700 | [diff] [blame] | 35 | 	pci_bus_remove_resources(b); | 
| Yinghai Lu | 67f241f | 2009-11-11 22:27:40 -0800 | [diff] [blame] | 36 | 	info = &pci_root_info[i]; | 
 | 37 | 	for (j = 0; j < info->res_num; j++) { | 
 | 38 | 		struct resource *res; | 
 | 39 | 		struct resource *root; | 
 | 40 |  | 
 | 41 | 		res = &info->res[j]; | 
| Bjorn Helgaas | 2fe2abf | 2010-02-23 10:24:36 -0700 | [diff] [blame] | 42 | 		pci_bus_add_resource(b, res, 0); | 
| Yinghai Lu | 67f241f | 2009-11-11 22:27:40 -0800 | [diff] [blame] | 43 | 		if (res->flags & IORESOURCE_IO) | 
 | 44 | 			root = &ioport_resource; | 
 | 45 | 		else | 
 | 46 | 			root = &iomem_resource; | 
 | 47 | 		insert_resource(root, res); | 
 | 48 | 	} | 
 | 49 | } | 
 | 50 |  | 
| Yinghai Lu | b74fd23 | 2010-02-10 01:20:08 -0800 | [diff] [blame] | 51 | void __devinit update_res(struct pci_root_info *info, resource_size_t start, | 
 | 52 | 			  resource_size_t end, unsigned long flags, int merge) | 
| Yinghai Lu | 67f241f | 2009-11-11 22:27:40 -0800 | [diff] [blame] | 53 | { | 
 | 54 | 	int i; | 
 | 55 | 	struct resource *res; | 
 | 56 |  | 
 | 57 | 	if (start > end) | 
 | 58 | 		return; | 
 | 59 |  | 
| Yinghai Lu | 9ad3f2c | 2010-02-10 01:20:11 -0800 | [diff] [blame] | 60 | 	if (start == MAX_RESOURCE) | 
 | 61 | 		return; | 
 | 62 |  | 
| Yinghai Lu | 67f241f | 2009-11-11 22:27:40 -0800 | [diff] [blame] | 63 | 	if (!merge) | 
 | 64 | 		goto addit; | 
 | 65 |  | 
 | 66 | 	/* try to merge it with old one */ | 
 | 67 | 	for (i = 0; i < info->res_num; i++) { | 
| Yinghai Lu | b74fd23 | 2010-02-10 01:20:08 -0800 | [diff] [blame] | 68 | 		resource_size_t final_start, final_end; | 
 | 69 | 		resource_size_t common_start, common_end; | 
| Yinghai Lu | 67f241f | 2009-11-11 22:27:40 -0800 | [diff] [blame] | 70 |  | 
 | 71 | 		res = &info->res[i]; | 
 | 72 | 		if (res->flags != flags) | 
 | 73 | 			continue; | 
 | 74 |  | 
| Yinghai Lu | b74fd23 | 2010-02-10 01:20:08 -0800 | [diff] [blame] | 75 | 		common_start = max(res->start, start); | 
 | 76 | 		common_end = min(res->end, end); | 
| Yinghai Lu | 67f241f | 2009-11-11 22:27:40 -0800 | [diff] [blame] | 77 | 		if (common_start > common_end + 1) | 
 | 78 | 			continue; | 
 | 79 |  | 
| Yinghai Lu | b74fd23 | 2010-02-10 01:20:08 -0800 | [diff] [blame] | 80 | 		final_start = min(res->start, start); | 
 | 81 | 		final_end = max(res->end, end); | 
| Yinghai Lu | 67f241f | 2009-11-11 22:27:40 -0800 | [diff] [blame] | 82 |  | 
 | 83 | 		res->start = final_start; | 
 | 84 | 		res->end = final_end; | 
 | 85 | 		return; | 
 | 86 | 	} | 
 | 87 |  | 
 | 88 | addit: | 
 | 89 |  | 
 | 90 | 	/* need to add that */ | 
 | 91 | 	if (info->res_num >= RES_NUM) | 
 | 92 | 		return; | 
 | 93 |  | 
 | 94 | 	res = &info->res[info->res_num]; | 
 | 95 | 	res->name = info->name; | 
 | 96 | 	res->flags = flags; | 
 | 97 | 	res->start = start; | 
 | 98 | 	res->end = end; | 
 | 99 | 	res->child = NULL; | 
 | 100 | 	info->res_num++; | 
 | 101 | } |