diff options
author | Jiang Liu <jiang.liu@huawei.com> | 2012-06-22 02:55:12 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2012-06-22 17:16:23 -0400 |
commit | 376f70acfe4bd97493299cdfc00a8d235279d267 (patch) | |
tree | d01d16dd08be5216c3186e69bcd5f9f0ada415ce | |
parent | 846e402300ffa2131239dcf82265b5366cd755f4 (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.c | 18 | ||||
-rw-r--r-- | arch/x86/pci/mmconfig_32.c | 13 | ||||
-rw-r--r-- | arch/x86/pci/mmconfig_64.c | 13 |
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. */ |
27 | static int __initdata pci_mmcfg_resources_inserted; | 29 | static int __initdata pci_mmcfg_resources_inserted; |
30 | static DEFINE_MUTEX(pci_mmcfg_lock); | ||
28 | 31 | ||
29 | LIST_HEAD(pci_mmcfg_list); | 32 | LIST_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 | ||
48 | static __init void list_add_sorted(struct pci_mmcfg_region *new) | 51 | static __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 | ||
64 | static __devinit struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, | 67 | static __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 | } |