aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiang Liu <jiang.liu@huawei.com>2012-06-22 02:55:12 -0400
committerBjorn Helgaas <bhelgaas@google.com>2012-06-22 17:16:23 -0400
commit376f70acfe4bd97493299cdfc00a8d235279d267 (patch)
treed01d16dd08be5216c3186e69bcd5f9f0ada415ce
parent846e402300ffa2131239dcf82265b5366cd755f4 (diff)
x86/PCI: use RCU list to protect mmconfig list
Use RCU list to protect mmconfig list from dynamic change when supporting PCI host bridge hotplug. Reviewed-by: Yinghai Lu <yinghai@kernel.org> Signed-off-by: Jiang Liu <liuj97@gmail.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
-rw-r--r--arch/x86/pci/mmconfig-shared.c18
-rw-r--r--arch/x86/pci/mmconfig_32.c13
-rw-r--r--arch/x86/pci/mmconfig_64.c13
3 files changed, 34 insertions, 10 deletions
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index 5e2cd2aa2889..0ac97d54bcac 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -17,6 +17,8 @@
17#include <linux/bitmap.h> 17#include <linux/bitmap.h>
18#include <linux/dmi.h> 18#include <linux/dmi.h>
19#include <linux/slab.h> 19#include <linux/slab.h>
20#include <linux/mutex.h>
21#include <linux/rculist.h>
20#include <asm/e820.h> 22#include <asm/e820.h>
21#include <asm/pci_x86.h> 23#include <asm/pci_x86.h>
22#include <asm/acpi.h> 24#include <asm/acpi.h>
@@ -25,6 +27,7 @@
25 27
26/* Indicate if the mmcfg resources have been placed into the resource table. */ 28/* Indicate if the mmcfg resources have been placed into the resource table. */
27static int __initdata pci_mmcfg_resources_inserted; 29static int __initdata pci_mmcfg_resources_inserted;
30static DEFINE_MUTEX(pci_mmcfg_lock);
28 31
29LIST_HEAD(pci_mmcfg_list); 32LIST_HEAD(pci_mmcfg_list);
30 33
@@ -45,20 +48,20 @@ static __init void free_all_mmcfg(void)
45 pci_mmconfig_remove(cfg); 48 pci_mmconfig_remove(cfg);
46} 49}
47 50
48static __init void list_add_sorted(struct pci_mmcfg_region *new) 51static __devinit void list_add_sorted(struct pci_mmcfg_region *new)
49{ 52{
50 struct pci_mmcfg_region *cfg; 53 struct pci_mmcfg_region *cfg;
51 54
52 /* keep list sorted by segment and starting bus number */ 55 /* keep list sorted by segment and starting bus number */
53 list_for_each_entry(cfg, &pci_mmcfg_list, list) { 56 list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) {
54 if (cfg->segment > new->segment || 57 if (cfg->segment > new->segment ||
55 (cfg->segment == new->segment && 58 (cfg->segment == new->segment &&
56 cfg->start_bus >= new->start_bus)) { 59 cfg->start_bus >= new->start_bus)) {
57 list_add_tail(&new->list, &cfg->list); 60 list_add_tail_rcu(&new->list, &cfg->list);
58 return; 61 return;
59 } 62 }
60 } 63 }
61 list_add_tail(&new->list, &pci_mmcfg_list); 64 list_add_tail_rcu(&new->list, &pci_mmcfg_list);
62} 65}
63 66
64static __devinit struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, 67static __devinit struct pci_mmcfg_region *pci_mmconfig_alloc(int segment,
@@ -101,8 +104,11 @@ static __init struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
101 struct pci_mmcfg_region *new; 104 struct pci_mmcfg_region *new;
102 105
103 new = pci_mmconfig_alloc(segment, start, end, addr); 106 new = pci_mmconfig_alloc(segment, start, end, addr);
104 if (new) 107 if (new) {
108 mutex_lock(&pci_mmcfg_lock);
105 list_add_sorted(new); 109 list_add_sorted(new);
110 mutex_unlock(&pci_mmcfg_lock);
111 }
106 112
107 return new; 113 return new;
108} 114}
@@ -111,7 +117,7 @@ struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus)
111{ 117{
112 struct pci_mmcfg_region *cfg; 118 struct pci_mmcfg_region *cfg;
113 119
114 list_for_each_entry(cfg, &pci_mmcfg_list, list) 120 list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
115 if (cfg->segment == segment && 121 if (cfg->segment == segment &&
116 cfg->start_bus <= bus && bus <= cfg->end_bus) 122 cfg->start_bus <= bus && bus <= cfg->end_bus)
117 return cfg; 123 return cfg;
diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c
index 5372e86834c0..5dad04aa6b37 100644
--- a/arch/x86/pci/mmconfig_32.c
+++ b/arch/x86/pci/mmconfig_32.c
@@ -11,6 +11,7 @@
11 11
12#include <linux/pci.h> 12#include <linux/pci.h>
13#include <linux/init.h> 13#include <linux/init.h>
14#include <linux/rcupdate.h>
14#include <asm/e820.h> 15#include <asm/e820.h>
15#include <asm/pci_x86.h> 16#include <asm/pci_x86.h>
16#include <acpi/acpi.h> 17#include <acpi/acpi.h>
@@ -60,9 +61,12 @@ err: *value = -1;
60 return -EINVAL; 61 return -EINVAL;
61 } 62 }
62 63
64 rcu_read_lock();
63 base = get_base_addr(seg, bus, devfn); 65 base = get_base_addr(seg, bus, devfn);
64 if (!base) 66 if (!base) {
67 rcu_read_unlock();
65 goto err; 68 goto err;
69 }
66 70
67 raw_spin_lock_irqsave(&pci_config_lock, flags); 71 raw_spin_lock_irqsave(&pci_config_lock, flags);
68 72
@@ -80,6 +84,7 @@ err: *value = -1;
80 break; 84 break;
81 } 85 }
82 raw_spin_unlock_irqrestore(&pci_config_lock, flags); 86 raw_spin_unlock_irqrestore(&pci_config_lock, flags);
87 rcu_read_unlock();
83 88
84 return 0; 89 return 0;
85} 90}
@@ -93,9 +98,12 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
93 if ((bus > 255) || (devfn > 255) || (reg > 4095)) 98 if ((bus > 255) || (devfn > 255) || (reg > 4095))
94 return -EINVAL; 99 return -EINVAL;
95 100
101 rcu_read_lock();
96 base = get_base_addr(seg, bus, devfn); 102 base = get_base_addr(seg, bus, devfn);
97 if (!base) 103 if (!base) {
104 rcu_read_unlock();
98 return -EINVAL; 105 return -EINVAL;
106 }
99 107
100 raw_spin_lock_irqsave(&pci_config_lock, flags); 108 raw_spin_lock_irqsave(&pci_config_lock, flags);
101 109
@@ -113,6 +121,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
113 break; 121 break;
114 } 122 }
115 raw_spin_unlock_irqrestore(&pci_config_lock, flags); 123 raw_spin_unlock_irqrestore(&pci_config_lock, flags);
124 rcu_read_unlock();
116 125
117 return 0; 126 return 0;
118} 127}
diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c
index 915a493502cb..acc48c5b6863 100644
--- a/arch/x86/pci/mmconfig_64.c
+++ b/arch/x86/pci/mmconfig_64.c
@@ -9,6 +9,7 @@
9#include <linux/init.h> 9#include <linux/init.h>
10#include <linux/acpi.h> 10#include <linux/acpi.h>
11#include <linux/bitmap.h> 11#include <linux/bitmap.h>
12#include <linux/rcupdate.h>
12#include <asm/e820.h> 13#include <asm/e820.h>
13#include <asm/pci_x86.h> 14#include <asm/pci_x86.h>
14 15
@@ -34,9 +35,12 @@ err: *value = -1;
34 return -EINVAL; 35 return -EINVAL;
35 } 36 }
36 37
38 rcu_read_lock();
37 addr = pci_dev_base(seg, bus, devfn); 39 addr = pci_dev_base(seg, bus, devfn);
38 if (!addr) 40 if (!addr) {
41 rcu_read_unlock();
39 goto err; 42 goto err;
43 }
40 44
41 switch (len) { 45 switch (len) {
42 case 1: 46 case 1:
@@ -49,6 +53,7 @@ err: *value = -1;
49 *value = mmio_config_readl(addr + reg); 53 *value = mmio_config_readl(addr + reg);
50 break; 54 break;
51 } 55 }
56 rcu_read_unlock();
52 57
53 return 0; 58 return 0;
54} 59}
@@ -62,9 +67,12 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
62 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) 67 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
63 return -EINVAL; 68 return -EINVAL;
64 69
70 rcu_read_lock();
65 addr = pci_dev_base(seg, bus, devfn); 71 addr = pci_dev_base(seg, bus, devfn);
66 if (!addr) 72 if (!addr) {
73 rcu_read_unlock();
67 return -EINVAL; 74 return -EINVAL;
75 }
68 76
69 switch (len) { 77 switch (len) {
70 case 1: 78 case 1:
@@ -77,6 +85,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
77 mmio_config_writel(addr + reg, value); 85 mmio_config_writel(addr + reg, value);
78 break; 86 break;
79 } 87 }
88 rcu_read_unlock();
80 89
81 return 0; 90 return 0;
82} 91}