aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRui Wang <rui.y.wang@intel.com>2016-08-17 04:00:36 -0400
committerIngo Molnar <mingo@kernel.org>2016-08-18 05:45:18 -0400
commit162b83bd5f1d7124e21da78bcf2685b9824d9ef0 (patch)
tree780ea3f1c6871f50afd0cc2905e99da55248aac3
parent6ab7eba5db93c11d61f6f7fbe21edbc875b26c1a (diff)
x86/ioapic: Fix lost IOAPIC resource after hot-removal and hotadd
IOAPIC resource at 0xfecxxxxx gets lost from /proc/iomem after hot-removing and then hot-adding the IOAPIC device. After system boot, in /proc/iomem: fec00000-fecfffff : PNP0003:00 fec00000-fec003ff : IOAPIC 0 fec01000-fec013ff : IOAPIC 1 fec40000-fec403ff : IOAPIC 2 fec80000-fec803ff : IOAPIC 3 fecc0000-fecc03ff : IOAPIC 4 Then hot-remove IOAPIC 2 and hot-add it again: fec00000-fecfffff : PNP0003:00 fec00000-fec003ff : IOAPIC 0 fec01000-fec013ff : IOAPIC 1 fec80000-fec803ff : IOAPIC 3 fecc0000-fecc03ff : IOAPIC 4 The range at 0xfec40000 is lost from /proc/iomem - which is a bug. This bug happens because handle_ioapic_add() requests resources from either PCI config BAR or ACPI "_CRS", not both. But Intel platforms map the IOxAPIC registers both at the PCI config BAR (called MBAR, dynamic), and at the ACPI "_CRS" (called ABAR, static). The 0xfecX_YZ00 to 0xfecX_YZFF range appears in "_CRS" of each IOAPIC device. Both ranges should be claimed from /proc/iomem for exclusive use. Signed-off-by: Rui Wang <rui.y.wang@intel.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: bhelgaas@google.com Cc: helgaas@kernel.org Cc: linux-acpi@vger.kernel.org Cc: linux-pci@vger.kernel.org Cc: rjw@rjwysocki.net Cc: tony.luck@intel.com Link: http://lkml.kernel.org/r/1471420837-31003-5-git-send-email-rui.y.wang@intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--drivers/acpi/ioapic.c36
1 files changed, 20 insertions, 16 deletions
diff --git a/drivers/acpi/ioapic.c b/drivers/acpi/ioapic.c
index 8ab6d426c178..ee201111e063 100644
--- a/drivers/acpi/ioapic.c
+++ b/drivers/acpi/ioapic.c
@@ -97,7 +97,7 @@ static acpi_status handle_ioapic_add(acpi_handle handle, u32 lvl,
97 unsigned long long gsi_base; 97 unsigned long long gsi_base;
98 struct acpi_pci_ioapic *ioapic; 98 struct acpi_pci_ioapic *ioapic;
99 struct pci_dev *dev = NULL; 99 struct pci_dev *dev = NULL;
100 struct resource *res = NULL; 100 struct resource *res = NULL, *pci_res = NULL, *crs_res;
101 char *type = NULL; 101 char *type = NULL;
102 102
103 if (!acpi_is_ioapic(handle, &type)) 103 if (!acpi_is_ioapic(handle, &type))
@@ -137,23 +137,28 @@ static acpi_status handle_ioapic_add(acpi_handle handle, u32 lvl,
137 pci_set_master(dev); 137 pci_set_master(dev);
138 if (pci_request_region(dev, 0, type)) 138 if (pci_request_region(dev, 0, type))
139 goto exit_disable; 139 goto exit_disable;
140 res = &dev->resource[0]; 140 pci_res = &dev->resource[0];
141 ioapic->pdev = dev; 141 ioapic->pdev = dev;
142 } else { 142 } else {
143 pci_dev_put(dev); 143 pci_dev_put(dev);
144 dev = NULL; 144 dev = NULL;
145 }
145 146
146 res = &ioapic->res; 147 crs_res = &ioapic->res;
147 acpi_walk_resources(handle, METHOD_NAME__CRS, setup_res, res); 148 acpi_walk_resources(handle, METHOD_NAME__CRS, setup_res, crs_res);
148 if (res->flags == 0) { 149 if (crs_res->flags == 0) {
149 acpi_handle_warn(handle, "failed to get resource\n"); 150 acpi_handle_warn(handle, "failed to get resource\n");
150 goto exit_free; 151 goto exit_release;
151 } else if (request_resource(&iomem_resource, res)) { 152 } else if (request_resource(&iomem_resource, crs_res)) {
152 acpi_handle_warn(handle, "failed to insert resource\n"); 153 acpi_handle_warn(handle, "failed to insert resource\n");
153 goto exit_free; 154 goto exit_release;
154 }
155 } 155 }
156 156
157 /* try pci resource first, then "_CRS" resource */
158 res = pci_res;
159 if (!res || !res->flags)
160 res = crs_res;
161
157 if (acpi_register_ioapic(handle, res->start, (u32)gsi_base)) { 162 if (acpi_register_ioapic(handle, res->start, (u32)gsi_base)) {
158 acpi_handle_warn(handle, "failed to register IOAPIC\n"); 163 acpi_handle_warn(handle, "failed to register IOAPIC\n");
159 goto exit_release; 164 goto exit_release;
@@ -174,14 +179,13 @@ done:
174exit_release: 179exit_release:
175 if (dev) 180 if (dev)
176 pci_release_region(dev, 0); 181 pci_release_region(dev, 0);
177 else 182 if (ioapic->res.flags && ioapic->res.parent)
178 release_resource(res); 183 release_resource(&ioapic->res);
179exit_disable: 184exit_disable:
180 if (dev) 185 if (dev)
181 pci_disable_device(dev); 186 pci_disable_device(dev);
182exit_put: 187exit_put:
183 pci_dev_put(dev); 188 pci_dev_put(dev);
184exit_free:
185 kfree(ioapic); 189 kfree(ioapic);
186exit: 190exit:
187 mutex_unlock(&ioapic_list_lock); 191 mutex_unlock(&ioapic_list_lock);
@@ -217,9 +221,9 @@ int acpi_ioapic_remove(struct acpi_pci_root *root)
217 pci_release_region(ioapic->pdev, 0); 221 pci_release_region(ioapic->pdev, 0);
218 pci_disable_device(ioapic->pdev); 222 pci_disable_device(ioapic->pdev);
219 pci_dev_put(ioapic->pdev); 223 pci_dev_put(ioapic->pdev);
220 } else if (ioapic->res.flags && ioapic->res.parent) {
221 release_resource(&ioapic->res);
222 } 224 }
225 if (ioapic->res.flags && ioapic->res.parent)
226 release_resource(&ioapic->res);
223 list_del(&ioapic->list); 227 list_del(&ioapic->list);
224 kfree(ioapic); 228 kfree(ioapic);
225 } 229 }