| 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 | } |