diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-02-10 10:05:16 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-02-10 10:05:16 -0500 |
commit | 8fbcf5ecb336eb6da560f08d60e95b51d318795c (patch) | |
tree | 77a1b947838d60edd0e81d37327985de2e842b68 /drivers/acpi | |
parent | d23209680291dad6c79f1a6f187697c3884d554d (diff) | |
parent | 5c493df25a0d9e0c3bda742250ecfc5953bf4ccd (diff) |
Merge branch 'acpi-resources'
* acpi-resources: (23 commits)
Merge branch 'pci/host-generic' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci into acpi-resources
x86/irq, ACPI: Implement ACPI driver to support IOAPIC hotplug
ACPI: Add interfaces to parse IOAPIC ID for IOAPIC hotplug
x86/PCI: Refine the way to release PCI IRQ resources
x86/PCI/ACPI: Use common ACPI resource interfaces to simplify implementation
x86/PCI: Fix the range check for IO resources
PCI: Use common resource list management code instead of private implementation
resources: Move struct resource_list_entry from ACPI into resource core
ACPI: Introduce helper function acpi_dev_filter_resource_type()
ACPI: Add field offset to struct resource_list_entry
ACPI: Translate resource into master side address for bridge window resources
ACPI: Return translation offset when parsing ACPI address space resources
ACPI: Enforce stricter checks for address space descriptors
ACPI: Set flag IORESOURCE_UNSET for unassigned resources
ACPI: Normalize return value of resource parser functions
ACPI: Fix a bug in parsing ACPI Memory24 resource
ACPI: Add prefetch decoding to the address space parser
ACPI: Move the window flag logic to the combined parser
ACPI: Unify the parsing of address_space and ext_address_space
ACPI: Let the parser return false for disabled resources
...
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/Kconfig | 6 | ||||
-rw-r--r-- | drivers/acpi/Makefile | 1 | ||||
-rw-r--r-- | drivers/acpi/acpi_lpss.c | 8 | ||||
-rw-r--r-- | drivers/acpi/acpi_platform.c | 4 | ||||
-rw-r--r-- | drivers/acpi/internal.h | 7 | ||||
-rw-r--r-- | drivers/acpi/ioapic.c | 229 | ||||
-rw-r--r-- | drivers/acpi/pci_irq.c | 9 | ||||
-rw-r--r-- | drivers/acpi/pci_root.c | 3 | ||||
-rw-r--r-- | drivers/acpi/processor_core.c | 123 | ||||
-rw-r--r-- | drivers/acpi/resource.c | 353 |
10 files changed, 584 insertions, 159 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 8951cefb0a96..e6c3ddd92665 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
@@ -315,6 +315,12 @@ config ACPI_HOTPLUG_MEMORY | |||
315 | To compile this driver as a module, choose M here: | 315 | To compile this driver as a module, choose M here: |
316 | the module will be called acpi_memhotplug. | 316 | the module will be called acpi_memhotplug. |
317 | 317 | ||
318 | config ACPI_HOTPLUG_IOAPIC | ||
319 | bool | ||
320 | depends on PCI | ||
321 | depends on X86_IO_APIC | ||
322 | default y | ||
323 | |||
318 | config ACPI_SBS | 324 | config ACPI_SBS |
319 | tristate "Smart Battery System" | 325 | tristate "Smart Battery System" |
320 | depends on X86 | 326 | depends on X86 |
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 0071141b6bbc..b18cd2151ddb 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile | |||
@@ -70,6 +70,7 @@ obj-$(CONFIG_ACPI_PROCESSOR) += processor.o | |||
70 | obj-y += container.o | 70 | obj-y += container.o |
71 | obj-$(CONFIG_ACPI_THERMAL) += thermal.o | 71 | obj-$(CONFIG_ACPI_THERMAL) += thermal.o |
72 | obj-y += acpi_memhotplug.o | 72 | obj-y += acpi_memhotplug.o |
73 | obj-$(CONFIG_ACPI_HOTPLUG_IOAPIC) += ioapic.o | ||
73 | obj-$(CONFIG_ACPI_BATTERY) += battery.o | 74 | obj-$(CONFIG_ACPI_BATTERY) += battery.o |
74 | obj-$(CONFIG_ACPI_SBS) += sbshc.o | 75 | obj-$(CONFIG_ACPI_SBS) += sbshc.o |
75 | obj-$(CONFIG_ACPI_SBS) += sbs.o | 76 | obj-$(CONFIG_ACPI_SBS) += sbs.o |
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 08fbff507dc4..02e835f3cf8a 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c | |||
@@ -307,7 +307,7 @@ static int acpi_lpss_create_device(struct acpi_device *adev, | |||
307 | { | 307 | { |
308 | struct lpss_device_desc *dev_desc; | 308 | struct lpss_device_desc *dev_desc; |
309 | struct lpss_private_data *pdata; | 309 | struct lpss_private_data *pdata; |
310 | struct resource_list_entry *rentry; | 310 | struct resource_entry *rentry; |
311 | struct list_head resource_list; | 311 | struct list_head resource_list; |
312 | struct platform_device *pdev; | 312 | struct platform_device *pdev; |
313 | int ret; | 313 | int ret; |
@@ -327,12 +327,12 @@ static int acpi_lpss_create_device(struct acpi_device *adev, | |||
327 | goto err_out; | 327 | goto err_out; |
328 | 328 | ||
329 | list_for_each_entry(rentry, &resource_list, node) | 329 | list_for_each_entry(rentry, &resource_list, node) |
330 | if (resource_type(&rentry->res) == IORESOURCE_MEM) { | 330 | if (resource_type(rentry->res) == IORESOURCE_MEM) { |
331 | if (dev_desc->prv_size_override) | 331 | if (dev_desc->prv_size_override) |
332 | pdata->mmio_size = dev_desc->prv_size_override; | 332 | pdata->mmio_size = dev_desc->prv_size_override; |
333 | else | 333 | else |
334 | pdata->mmio_size = resource_size(&rentry->res); | 334 | pdata->mmio_size = resource_size(rentry->res); |
335 | pdata->mmio_base = ioremap(rentry->res.start, | 335 | pdata->mmio_base = ioremap(rentry->res->start, |
336 | pdata->mmio_size); | 336 | pdata->mmio_size); |
337 | if (!pdata->mmio_base) | 337 | if (!pdata->mmio_base) |
338 | goto err_out; | 338 | goto err_out; |
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index 6ba8beb6b9d2..1284138e42ab 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c | |||
@@ -45,7 +45,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) | |||
45 | struct platform_device *pdev = NULL; | 45 | struct platform_device *pdev = NULL; |
46 | struct acpi_device *acpi_parent; | 46 | struct acpi_device *acpi_parent; |
47 | struct platform_device_info pdevinfo; | 47 | struct platform_device_info pdevinfo; |
48 | struct resource_list_entry *rentry; | 48 | struct resource_entry *rentry; |
49 | struct list_head resource_list; | 49 | struct list_head resource_list; |
50 | struct resource *resources = NULL; | 50 | struct resource *resources = NULL; |
51 | int count; | 51 | int count; |
@@ -71,7 +71,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) | |||
71 | } | 71 | } |
72 | count = 0; | 72 | count = 0; |
73 | list_for_each_entry(rentry, &resource_list, node) | 73 | list_for_each_entry(rentry, &resource_list, node) |
74 | resources[count++] = rentry->res; | 74 | resources[count++] = *rentry->res; |
75 | 75 | ||
76 | acpi_dev_free_resource_list(&resource_list); | 76 | acpi_dev_free_resource_list(&resource_list); |
77 | } | 77 | } |
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 81ae69fde7d5..56b321aa2b1c 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h | |||
@@ -35,6 +35,13 @@ void acpi_int340x_thermal_init(void); | |||
35 | int acpi_sysfs_init(void); | 35 | int acpi_sysfs_init(void); |
36 | void acpi_container_init(void); | 36 | void acpi_container_init(void); |
37 | void acpi_memory_hotplug_init(void); | 37 | void acpi_memory_hotplug_init(void); |
38 | #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC | ||
39 | int acpi_ioapic_add(struct acpi_pci_root *root); | ||
40 | int acpi_ioapic_remove(struct acpi_pci_root *root); | ||
41 | #else | ||
42 | static inline int acpi_ioapic_add(struct acpi_pci_root *root) { return 0; } | ||
43 | static inline int acpi_ioapic_remove(struct acpi_pci_root *root) { return 0; } | ||
44 | #endif | ||
38 | #ifdef CONFIG_ACPI_DOCK | 45 | #ifdef CONFIG_ACPI_DOCK |
39 | void register_dock_dependent_device(struct acpi_device *adev, | 46 | void register_dock_dependent_device(struct acpi_device *adev, |
40 | acpi_handle dshandle); | 47 | acpi_handle dshandle); |
diff --git a/drivers/acpi/ioapic.c b/drivers/acpi/ioapic.c new file mode 100644 index 000000000000..ccdc8db16bb8 --- /dev/null +++ b/drivers/acpi/ioapic.c | |||
@@ -0,0 +1,229 @@ | |||
1 | /* | ||
2 | * IOAPIC/IOxAPIC/IOSAPIC driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Fujitsu Limited. | ||
5 | * (c) Copyright 2009 Hewlett-Packard Development Company, L.P. | ||
6 | * | ||
7 | * Copyright (C) 2014 Intel Corporation | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * Based on original drivers/pci/ioapic.c | ||
14 | * Yinghai Lu <yinghai@kernel.org> | ||
15 | * Jiang Liu <jiang.liu@intel.com> | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * This driver manages I/O APICs added by hotplug after boot. | ||
20 | * We try to claim all I/O APIC devices, but those present at boot were | ||
21 | * registered when we parsed the ACPI MADT. | ||
22 | */ | ||
23 | |||
24 | #define pr_fmt(fmt) "ACPI : IOAPIC: " fmt | ||
25 | |||
26 | #include <linux/slab.h> | ||
27 | #include <linux/acpi.h> | ||
28 | #include <linux/pci.h> | ||
29 | #include <acpi/acpi.h> | ||
30 | |||
31 | struct acpi_pci_ioapic { | ||
32 | acpi_handle root_handle; | ||
33 | acpi_handle handle; | ||
34 | u32 gsi_base; | ||
35 | struct resource res; | ||
36 | struct pci_dev *pdev; | ||
37 | struct list_head list; | ||
38 | }; | ||
39 | |||
40 | static LIST_HEAD(ioapic_list); | ||
41 | static DEFINE_MUTEX(ioapic_list_lock); | ||
42 | |||
43 | static acpi_status setup_res(struct acpi_resource *acpi_res, void *data) | ||
44 | { | ||
45 | struct resource *res = data; | ||
46 | struct resource_win win; | ||
47 | |||
48 | res->flags = 0; | ||
49 | if (acpi_dev_filter_resource_type(acpi_res, IORESOURCE_MEM) == 0) | ||
50 | return AE_OK; | ||
51 | |||
52 | if (!acpi_dev_resource_memory(acpi_res, res)) { | ||
53 | if (acpi_dev_resource_address_space(acpi_res, &win) || | ||
54 | acpi_dev_resource_ext_address_space(acpi_res, &win)) | ||
55 | *res = win.res; | ||
56 | } | ||
57 | if ((res->flags & IORESOURCE_PREFETCH) || | ||
58 | (res->flags & IORESOURCE_DISABLED)) | ||
59 | res->flags = 0; | ||
60 | |||
61 | return AE_CTRL_TERMINATE; | ||
62 | } | ||
63 | |||
64 | static bool acpi_is_ioapic(acpi_handle handle, char **type) | ||
65 | { | ||
66 | acpi_status status; | ||
67 | struct acpi_device_info *info; | ||
68 | char *hid = NULL; | ||
69 | bool match = false; | ||
70 | |||
71 | if (!acpi_has_method(handle, "_GSB")) | ||
72 | return false; | ||
73 | |||
74 | status = acpi_get_object_info(handle, &info); | ||
75 | if (ACPI_SUCCESS(status)) { | ||
76 | if (info->valid & ACPI_VALID_HID) | ||
77 | hid = info->hardware_id.string; | ||
78 | if (hid) { | ||
79 | if (strcmp(hid, "ACPI0009") == 0) { | ||
80 | *type = "IOxAPIC"; | ||
81 | match = true; | ||
82 | } else if (strcmp(hid, "ACPI000A") == 0) { | ||
83 | *type = "IOAPIC"; | ||
84 | match = true; | ||
85 | } | ||
86 | } | ||
87 | kfree(info); | ||
88 | } | ||
89 | |||
90 | return match; | ||
91 | } | ||
92 | |||
93 | static acpi_status handle_ioapic_add(acpi_handle handle, u32 lvl, | ||
94 | void *context, void **rv) | ||
95 | { | ||
96 | acpi_status status; | ||
97 | unsigned long long gsi_base; | ||
98 | struct acpi_pci_ioapic *ioapic; | ||
99 | struct pci_dev *dev = NULL; | ||
100 | struct resource *res = NULL; | ||
101 | char *type = NULL; | ||
102 | |||
103 | if (!acpi_is_ioapic(handle, &type)) | ||
104 | return AE_OK; | ||
105 | |||
106 | mutex_lock(&ioapic_list_lock); | ||
107 | list_for_each_entry(ioapic, &ioapic_list, list) | ||
108 | if (ioapic->handle == handle) { | ||
109 | mutex_unlock(&ioapic_list_lock); | ||
110 | return AE_OK; | ||
111 | } | ||
112 | |||
113 | status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsi_base); | ||
114 | if (ACPI_FAILURE(status)) { | ||
115 | acpi_handle_warn(handle, "failed to evaluate _GSB method\n"); | ||
116 | goto exit; | ||
117 | } | ||
118 | |||
119 | ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL); | ||
120 | if (!ioapic) { | ||
121 | pr_err("cannot allocate memory for new IOAPIC\n"); | ||
122 | goto exit; | ||
123 | } else { | ||
124 | ioapic->root_handle = (acpi_handle)context; | ||
125 | ioapic->handle = handle; | ||
126 | ioapic->gsi_base = (u32)gsi_base; | ||
127 | INIT_LIST_HEAD(&ioapic->list); | ||
128 | } | ||
129 | |||
130 | if (acpi_ioapic_registered(handle, (u32)gsi_base)) | ||
131 | goto done; | ||
132 | |||
133 | dev = acpi_get_pci_dev(handle); | ||
134 | if (dev && pci_resource_len(dev, 0)) { | ||
135 | if (pci_enable_device(dev) < 0) | ||
136 | goto exit_put; | ||
137 | pci_set_master(dev); | ||
138 | if (pci_request_region(dev, 0, type)) | ||
139 | goto exit_disable; | ||
140 | res = &dev->resource[0]; | ||
141 | ioapic->pdev = dev; | ||
142 | } else { | ||
143 | pci_dev_put(dev); | ||
144 | dev = NULL; | ||
145 | |||
146 | res = &ioapic->res; | ||
147 | acpi_walk_resources(handle, METHOD_NAME__CRS, setup_res, res); | ||
148 | if (res->flags == 0) { | ||
149 | acpi_handle_warn(handle, "failed to get resource\n"); | ||
150 | goto exit_free; | ||
151 | } else if (request_resource(&iomem_resource, res)) { | ||
152 | acpi_handle_warn(handle, "failed to insert resource\n"); | ||
153 | goto exit_free; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | if (acpi_register_ioapic(handle, res->start, (u32)gsi_base)) { | ||
158 | acpi_handle_warn(handle, "failed to register IOAPIC\n"); | ||
159 | goto exit_release; | ||
160 | } | ||
161 | done: | ||
162 | list_add(&ioapic->list, &ioapic_list); | ||
163 | mutex_unlock(&ioapic_list_lock); | ||
164 | |||
165 | if (dev) | ||
166 | dev_info(&dev->dev, "%s at %pR, GSI %u\n", | ||
167 | type, res, (u32)gsi_base); | ||
168 | else | ||
169 | acpi_handle_info(handle, "%s at %pR, GSI %u\n", | ||
170 | type, res, (u32)gsi_base); | ||
171 | |||
172 | return AE_OK; | ||
173 | |||
174 | exit_release: | ||
175 | if (dev) | ||
176 | pci_release_region(dev, 0); | ||
177 | else | ||
178 | release_resource(res); | ||
179 | exit_disable: | ||
180 | if (dev) | ||
181 | pci_disable_device(dev); | ||
182 | exit_put: | ||
183 | pci_dev_put(dev); | ||
184 | exit_free: | ||
185 | kfree(ioapic); | ||
186 | exit: | ||
187 | mutex_unlock(&ioapic_list_lock); | ||
188 | *(acpi_status *)rv = AE_ERROR; | ||
189 | return AE_OK; | ||
190 | } | ||
191 | |||
192 | int acpi_ioapic_add(struct acpi_pci_root *root) | ||
193 | { | ||
194 | acpi_status status, retval = AE_OK; | ||
195 | |||
196 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, root->device->handle, | ||
197 | UINT_MAX, handle_ioapic_add, NULL, | ||
198 | root->device->handle, (void **)&retval); | ||
199 | |||
200 | return ACPI_SUCCESS(status) && ACPI_SUCCESS(retval) ? 0 : -ENODEV; | ||
201 | } | ||
202 | |||
203 | int acpi_ioapic_remove(struct acpi_pci_root *root) | ||
204 | { | ||
205 | int retval = 0; | ||
206 | struct acpi_pci_ioapic *ioapic, *tmp; | ||
207 | |||
208 | mutex_lock(&ioapic_list_lock); | ||
209 | list_for_each_entry_safe(ioapic, tmp, &ioapic_list, list) { | ||
210 | if (root->device->handle != ioapic->root_handle) | ||
211 | continue; | ||
212 | |||
213 | if (acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base)) | ||
214 | retval = -EBUSY; | ||
215 | |||
216 | if (ioapic->pdev) { | ||
217 | pci_release_region(ioapic->pdev, 0); | ||
218 | pci_disable_device(ioapic->pdev); | ||
219 | pci_dev_put(ioapic->pdev); | ||
220 | } else if (ioapic->res.flags && ioapic->res.parent) { | ||
221 | release_resource(&ioapic->res); | ||
222 | } | ||
223 | list_del(&ioapic->list); | ||
224 | kfree(ioapic); | ||
225 | } | ||
226 | mutex_unlock(&ioapic_list_lock); | ||
227 | |||
228 | return retval; | ||
229 | } | ||
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index b1def411c0b8..e7f718d6918a 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c | |||
@@ -485,14 +485,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev) | |||
485 | if (!pin || !dev->irq_managed || dev->irq <= 0) | 485 | if (!pin || !dev->irq_managed || dev->irq <= 0) |
486 | return; | 486 | return; |
487 | 487 | ||
488 | /* Keep IOAPIC pin configuration when suspending */ | ||
489 | if (dev->dev.power.is_prepared) | ||
490 | return; | ||
491 | #ifdef CONFIG_PM | ||
492 | if (dev->dev.power.runtime_status == RPM_SUSPENDING) | ||
493 | return; | ||
494 | #endif | ||
495 | |||
496 | entry = acpi_pci_irq_lookup(dev, pin); | 488 | entry = acpi_pci_irq_lookup(dev, pin); |
497 | if (!entry) | 489 | if (!entry) |
498 | return; | 490 | return; |
@@ -513,5 +505,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev) | |||
513 | if (gsi >= 0) { | 505 | if (gsi >= 0) { |
514 | acpi_unregister_gsi(gsi); | 506 | acpi_unregister_gsi(gsi); |
515 | dev->irq_managed = 0; | 507 | dev->irq_managed = 0; |
508 | dev->irq = 0; | ||
516 | } | 509 | } |
517 | } | 510 | } |
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index e53e0f659204..68a5f712cd19 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c | |||
@@ -621,6 +621,7 @@ static int acpi_pci_root_add(struct acpi_device *device, | |||
621 | if (hotadd) { | 621 | if (hotadd) { |
622 | pcibios_resource_survey_bus(root->bus); | 622 | pcibios_resource_survey_bus(root->bus); |
623 | pci_assign_unassigned_root_bus_resources(root->bus); | 623 | pci_assign_unassigned_root_bus_resources(root->bus); |
624 | acpi_ioapic_add(root); | ||
624 | } | 625 | } |
625 | 626 | ||
626 | pci_lock_rescan_remove(); | 627 | pci_lock_rescan_remove(); |
@@ -644,6 +645,8 @@ static void acpi_pci_root_remove(struct acpi_device *device) | |||
644 | 645 | ||
645 | pci_stop_root_bus(root->bus); | 646 | pci_stop_root_bus(root->bus); |
646 | 647 | ||
648 | WARN_ON(acpi_ioapic_remove(root)); | ||
649 | |||
647 | device_set_run_wake(root->bus->bridge, false); | 650 | device_set_run_wake(root->bus->bridge, false); |
648 | pci_acpi_remove_bus_pm_notifier(device); | 651 | pci_acpi_remove_bus_pm_notifier(device); |
649 | 652 | ||
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 02e48394276c..7962651cdbd4 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c | |||
@@ -4,6 +4,10 @@ | |||
4 | * | 4 | * |
5 | * Alex Chiang <achiang@hp.com> | 5 | * Alex Chiang <achiang@hp.com> |
6 | * - Unified x86/ia64 implementations | 6 | * - Unified x86/ia64 implementations |
7 | * | ||
8 | * I/O APIC hotplug support | ||
9 | * Yinghai Lu <yinghai@kernel.org> | ||
10 | * Jiang Liu <jiang.liu@intel.com> | ||
7 | */ | 11 | */ |
8 | #include <linux/export.h> | 12 | #include <linux/export.h> |
9 | #include <linux/acpi.h> | 13 | #include <linux/acpi.h> |
@@ -12,6 +16,21 @@ | |||
12 | #define _COMPONENT ACPI_PROCESSOR_COMPONENT | 16 | #define _COMPONENT ACPI_PROCESSOR_COMPONENT |
13 | ACPI_MODULE_NAME("processor_core"); | 17 | ACPI_MODULE_NAME("processor_core"); |
14 | 18 | ||
19 | static struct acpi_table_madt *get_madt_table(void) | ||
20 | { | ||
21 | static struct acpi_table_madt *madt; | ||
22 | static int read_madt; | ||
23 | |||
24 | if (!read_madt) { | ||
25 | if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, | ||
26 | (struct acpi_table_header **)&madt))) | ||
27 | madt = NULL; | ||
28 | read_madt++; | ||
29 | } | ||
30 | |||
31 | return madt; | ||
32 | } | ||
33 | |||
15 | static int map_lapic_id(struct acpi_subtable_header *entry, | 34 | static int map_lapic_id(struct acpi_subtable_header *entry, |
16 | u32 acpi_id, int *apic_id) | 35 | u32 acpi_id, int *apic_id) |
17 | { | 36 | { |
@@ -67,17 +86,10 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, | |||
67 | static int map_madt_entry(int type, u32 acpi_id) | 86 | static int map_madt_entry(int type, u32 acpi_id) |
68 | { | 87 | { |
69 | unsigned long madt_end, entry; | 88 | unsigned long madt_end, entry; |
70 | static struct acpi_table_madt *madt; | ||
71 | static int read_madt; | ||
72 | int phys_id = -1; /* CPU hardware ID */ | 89 | int phys_id = -1; /* CPU hardware ID */ |
90 | struct acpi_table_madt *madt; | ||
73 | 91 | ||
74 | if (!read_madt) { | 92 | madt = get_madt_table(); |
75 | if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, | ||
76 | (struct acpi_table_header **)&madt))) | ||
77 | madt = NULL; | ||
78 | read_madt++; | ||
79 | } | ||
80 | |||
81 | if (!madt) | 93 | if (!madt) |
82 | return phys_id; | 94 | return phys_id; |
83 | 95 | ||
@@ -203,3 +215,96 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) | |||
203 | return acpi_map_cpuid(phys_id, acpi_id); | 215 | return acpi_map_cpuid(phys_id, acpi_id); |
204 | } | 216 | } |
205 | EXPORT_SYMBOL_GPL(acpi_get_cpuid); | 217 | EXPORT_SYMBOL_GPL(acpi_get_cpuid); |
218 | |||
219 | #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC | ||
220 | static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base, | ||
221 | u64 *phys_addr, int *ioapic_id) | ||
222 | { | ||
223 | struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry; | ||
224 | |||
225 | if (ioapic->global_irq_base != gsi_base) | ||
226 | return 0; | ||
227 | |||
228 | *phys_addr = ioapic->address; | ||
229 | *ioapic_id = ioapic->id; | ||
230 | return 1; | ||
231 | } | ||
232 | |||
233 | static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr) | ||
234 | { | ||
235 | struct acpi_subtable_header *hdr; | ||
236 | unsigned long madt_end, entry; | ||
237 | struct acpi_table_madt *madt; | ||
238 | int apic_id = -1; | ||
239 | |||
240 | madt = get_madt_table(); | ||
241 | if (!madt) | ||
242 | return apic_id; | ||
243 | |||
244 | entry = (unsigned long)madt; | ||
245 | madt_end = entry + madt->header.length; | ||
246 | |||
247 | /* Parse all entries looking for a match. */ | ||
248 | entry += sizeof(struct acpi_table_madt); | ||
249 | while (entry + sizeof(struct acpi_subtable_header) < madt_end) { | ||
250 | hdr = (struct acpi_subtable_header *)entry; | ||
251 | if (hdr->type == ACPI_MADT_TYPE_IO_APIC && | ||
252 | get_ioapic_id(hdr, gsi_base, phys_addr, &apic_id)) | ||
253 | break; | ||
254 | else | ||
255 | entry += hdr->length; | ||
256 | } | ||
257 | |||
258 | return apic_id; | ||
259 | } | ||
260 | |||
261 | static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base, | ||
262 | u64 *phys_addr) | ||
263 | { | ||
264 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
265 | struct acpi_subtable_header *header; | ||
266 | union acpi_object *obj; | ||
267 | int apic_id = -1; | ||
268 | |||
269 | if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer))) | ||
270 | goto exit; | ||
271 | |||
272 | if (!buffer.length || !buffer.pointer) | ||
273 | goto exit; | ||
274 | |||
275 | obj = buffer.pointer; | ||
276 | if (obj->type != ACPI_TYPE_BUFFER || | ||
277 | obj->buffer.length < sizeof(struct acpi_subtable_header)) | ||
278 | goto exit; | ||
279 | |||
280 | header = (struct acpi_subtable_header *)obj->buffer.pointer; | ||
281 | if (header->type == ACPI_MADT_TYPE_IO_APIC) | ||
282 | get_ioapic_id(header, gsi_base, phys_addr, &apic_id); | ||
283 | |||
284 | exit: | ||
285 | kfree(buffer.pointer); | ||
286 | return apic_id; | ||
287 | } | ||
288 | |||
289 | /** | ||
290 | * acpi_get_ioapic_id - Get IOAPIC ID and physical address matching @gsi_base | ||
291 | * @handle: ACPI object for IOAPIC device | ||
292 | * @gsi_base: GSI base to match with | ||
293 | * @phys_addr: Pointer to store physical address of matching IOAPIC record | ||
294 | * | ||
295 | * Walk resources returned by ACPI_MAT method, then ACPI MADT table, to search | ||
296 | * for an ACPI IOAPIC record matching @gsi_base. | ||
297 | * Return IOAPIC id and store physical address in @phys_addr if found a match, | ||
298 | * otherwise return <0. | ||
299 | */ | ||
300 | int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr) | ||
301 | { | ||
302 | int apic_id; | ||
303 | |||
304 | apic_id = parse_mat_ioapic_entry(handle, gsi_base, phys_addr); | ||
305 | if (apic_id == -1) | ||
306 | apic_id = parse_madt_ioapic_entry(gsi_base, phys_addr); | ||
307 | |||
308 | return apic_id; | ||
309 | } | ||
310 | #endif /* CONFIG_ACPI_HOTPLUG_IOAPIC */ | ||
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index d0a4d90c6bcc..4752b9939987 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c | |||
@@ -34,21 +34,34 @@ | |||
34 | #define valid_IRQ(i) (true) | 34 | #define valid_IRQ(i) (true) |
35 | #endif | 35 | #endif |
36 | 36 | ||
37 | static unsigned long acpi_dev_memresource_flags(u64 len, u8 write_protect, | 37 | static bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io) |
38 | bool window) | ||
39 | { | 38 | { |
40 | unsigned long flags = IORESOURCE_MEM; | 39 | u64 reslen = end - start + 1; |
41 | 40 | ||
42 | if (len == 0) | 41 | /* |
43 | flags |= IORESOURCE_DISABLED; | 42 | * CHECKME: len might be required to check versus a minimum |
43 | * length as well. 1 for io is fine, but for memory it does | ||
44 | * not make any sense at all. | ||
45 | */ | ||
46 | if (len && reslen && reslen == len && start <= end) | ||
47 | return true; | ||
44 | 48 | ||
45 | if (write_protect == ACPI_READ_WRITE_MEMORY) | 49 | pr_info("ACPI: invalid or unassigned resource %s [%016llx - %016llx] length [%016llx]\n", |
46 | flags |= IORESOURCE_MEM_WRITEABLE; | 50 | io ? "io" : "mem", start, end, len); |
51 | |||
52 | return false; | ||
53 | } | ||
54 | |||
55 | static void acpi_dev_memresource_flags(struct resource *res, u64 len, | ||
56 | u8 write_protect) | ||
57 | { | ||
58 | res->flags = IORESOURCE_MEM; | ||
47 | 59 | ||
48 | if (window) | 60 | if (!acpi_dev_resource_len_valid(res->start, res->end, len, false)) |
49 | flags |= IORESOURCE_WINDOW; | 61 | res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET; |
50 | 62 | ||
51 | return flags; | 63 | if (write_protect == ACPI_READ_WRITE_MEMORY) |
64 | res->flags |= IORESOURCE_MEM_WRITEABLE; | ||
52 | } | 65 | } |
53 | 66 | ||
54 | static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, | 67 | static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, |
@@ -56,7 +69,7 @@ static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, | |||
56 | { | 69 | { |
57 | res->start = start; | 70 | res->start = start; |
58 | res->end = start + len - 1; | 71 | res->end = start + len - 1; |
59 | res->flags = acpi_dev_memresource_flags(len, write_protect, false); | 72 | acpi_dev_memresource_flags(res, len, write_protect); |
60 | } | 73 | } |
61 | 74 | ||
62 | /** | 75 | /** |
@@ -67,6 +80,11 @@ static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, | |||
67 | * Check if the given ACPI resource object represents a memory resource and | 80 | * Check if the given ACPI resource object represents a memory resource and |
68 | * if that's the case, use the information in it to populate the generic | 81 | * if that's the case, use the information in it to populate the generic |
69 | * resource object pointed to by @res. | 82 | * resource object pointed to by @res. |
83 | * | ||
84 | * Return: | ||
85 | * 1) false with res->flags setting to zero: not the expected resource type | ||
86 | * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource | ||
87 | * 3) true: valid assigned resource | ||
70 | */ | 88 | */ |
71 | bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) | 89 | bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) |
72 | { | 90 | { |
@@ -77,60 +95,52 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) | |||
77 | switch (ares->type) { | 95 | switch (ares->type) { |
78 | case ACPI_RESOURCE_TYPE_MEMORY24: | 96 | case ACPI_RESOURCE_TYPE_MEMORY24: |
79 | memory24 = &ares->data.memory24; | 97 | memory24 = &ares->data.memory24; |
80 | if (!memory24->minimum && !memory24->address_length) | 98 | acpi_dev_get_memresource(res, memory24->minimum << 8, |
81 | return false; | 99 | memory24->address_length << 8, |
82 | acpi_dev_get_memresource(res, memory24->minimum, | ||
83 | memory24->address_length, | ||
84 | memory24->write_protect); | 100 | memory24->write_protect); |
85 | break; | 101 | break; |
86 | case ACPI_RESOURCE_TYPE_MEMORY32: | 102 | case ACPI_RESOURCE_TYPE_MEMORY32: |
87 | memory32 = &ares->data.memory32; | 103 | memory32 = &ares->data.memory32; |
88 | if (!memory32->minimum && !memory32->address_length) | ||
89 | return false; | ||
90 | acpi_dev_get_memresource(res, memory32->minimum, | 104 | acpi_dev_get_memresource(res, memory32->minimum, |
91 | memory32->address_length, | 105 | memory32->address_length, |
92 | memory32->write_protect); | 106 | memory32->write_protect); |
93 | break; | 107 | break; |
94 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: | 108 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: |
95 | fixed_memory32 = &ares->data.fixed_memory32; | 109 | fixed_memory32 = &ares->data.fixed_memory32; |
96 | if (!fixed_memory32->address && !fixed_memory32->address_length) | ||
97 | return false; | ||
98 | acpi_dev_get_memresource(res, fixed_memory32->address, | 110 | acpi_dev_get_memresource(res, fixed_memory32->address, |
99 | fixed_memory32->address_length, | 111 | fixed_memory32->address_length, |
100 | fixed_memory32->write_protect); | 112 | fixed_memory32->write_protect); |
101 | break; | 113 | break; |
102 | default: | 114 | default: |
115 | res->flags = 0; | ||
103 | return false; | 116 | return false; |
104 | } | 117 | } |
105 | return true; | 118 | |
119 | return !(res->flags & IORESOURCE_DISABLED); | ||
106 | } | 120 | } |
107 | EXPORT_SYMBOL_GPL(acpi_dev_resource_memory); | 121 | EXPORT_SYMBOL_GPL(acpi_dev_resource_memory); |
108 | 122 | ||
109 | static unsigned int acpi_dev_ioresource_flags(u64 start, u64 end, u8 io_decode, | 123 | static void acpi_dev_ioresource_flags(struct resource *res, u64 len, |
110 | bool window) | 124 | u8 io_decode) |
111 | { | 125 | { |
112 | int flags = IORESOURCE_IO; | 126 | res->flags = IORESOURCE_IO; |
113 | 127 | ||
114 | if (io_decode == ACPI_DECODE_16) | 128 | if (!acpi_dev_resource_len_valid(res->start, res->end, len, true)) |
115 | flags |= IORESOURCE_IO_16BIT_ADDR; | 129 | res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET; |
116 | 130 | ||
117 | if (start > end || end >= 0x10003) | 131 | if (res->end >= 0x10003) |
118 | flags |= IORESOURCE_DISABLED; | 132 | res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET; |
119 | 133 | ||
120 | if (window) | 134 | if (io_decode == ACPI_DECODE_16) |
121 | flags |= IORESOURCE_WINDOW; | 135 | res->flags |= IORESOURCE_IO_16BIT_ADDR; |
122 | |||
123 | return flags; | ||
124 | } | 136 | } |
125 | 137 | ||
126 | static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, | 138 | static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, |
127 | u8 io_decode) | 139 | u8 io_decode) |
128 | { | 140 | { |
129 | u64 end = start + len - 1; | ||
130 | |||
131 | res->start = start; | 141 | res->start = start; |
132 | res->end = end; | 142 | res->end = start + len - 1; |
133 | res->flags = acpi_dev_ioresource_flags(start, end, io_decode, false); | 143 | acpi_dev_ioresource_flags(res, len, io_decode); |
134 | } | 144 | } |
135 | 145 | ||
136 | /** | 146 | /** |
@@ -141,6 +151,11 @@ static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, | |||
141 | * Check if the given ACPI resource object represents an I/O resource and | 151 | * Check if the given ACPI resource object represents an I/O resource and |
142 | * if that's the case, use the information in it to populate the generic | 152 | * if that's the case, use the information in it to populate the generic |
143 | * resource object pointed to by @res. | 153 | * resource object pointed to by @res. |
154 | * | ||
155 | * Return: | ||
156 | * 1) false with res->flags setting to zero: not the expected resource type | ||
157 | * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource | ||
158 | * 3) true: valid assigned resource | ||
144 | */ | 159 | */ |
145 | bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) | 160 | bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) |
146 | { | 161 | { |
@@ -150,135 +165,143 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) | |||
150 | switch (ares->type) { | 165 | switch (ares->type) { |
151 | case ACPI_RESOURCE_TYPE_IO: | 166 | case ACPI_RESOURCE_TYPE_IO: |
152 | io = &ares->data.io; | 167 | io = &ares->data.io; |
153 | if (!io->minimum && !io->address_length) | ||
154 | return false; | ||
155 | acpi_dev_get_ioresource(res, io->minimum, | 168 | acpi_dev_get_ioresource(res, io->minimum, |
156 | io->address_length, | 169 | io->address_length, |
157 | io->io_decode); | 170 | io->io_decode); |
158 | break; | 171 | break; |
159 | case ACPI_RESOURCE_TYPE_FIXED_IO: | 172 | case ACPI_RESOURCE_TYPE_FIXED_IO: |
160 | fixed_io = &ares->data.fixed_io; | 173 | fixed_io = &ares->data.fixed_io; |
161 | if (!fixed_io->address && !fixed_io->address_length) | ||
162 | return false; | ||
163 | acpi_dev_get_ioresource(res, fixed_io->address, | 174 | acpi_dev_get_ioresource(res, fixed_io->address, |
164 | fixed_io->address_length, | 175 | fixed_io->address_length, |
165 | ACPI_DECODE_10); | 176 | ACPI_DECODE_10); |
166 | break; | 177 | break; |
167 | default: | 178 | default: |
179 | res->flags = 0; | ||
168 | return false; | 180 | return false; |
169 | } | 181 | } |
170 | return true; | 182 | |
183 | return !(res->flags & IORESOURCE_DISABLED); | ||
171 | } | 184 | } |
172 | EXPORT_SYMBOL_GPL(acpi_dev_resource_io); | 185 | EXPORT_SYMBOL_GPL(acpi_dev_resource_io); |
173 | 186 | ||
174 | /** | 187 | static bool acpi_decode_space(struct resource_win *win, |
175 | * acpi_dev_resource_address_space - Extract ACPI address space information. | 188 | struct acpi_resource_address *addr, |
176 | * @ares: Input ACPI resource object. | 189 | struct acpi_address64_attribute *attr) |
177 | * @res: Output generic resource object. | ||
178 | * | ||
179 | * Check if the given ACPI resource object represents an address space resource | ||
180 | * and if that's the case, use the information in it to populate the generic | ||
181 | * resource object pointed to by @res. | ||
182 | */ | ||
183 | bool acpi_dev_resource_address_space(struct acpi_resource *ares, | ||
184 | struct resource *res) | ||
185 | { | 190 | { |
186 | acpi_status status; | 191 | u8 iodec = attr->granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16; |
187 | struct acpi_resource_address64 addr; | 192 | bool wp = addr->info.mem.write_protect; |
188 | bool window; | 193 | u64 len = attr->address_length; |
189 | u64 len; | 194 | struct resource *res = &win->res; |
190 | u8 io_decode; | ||
191 | 195 | ||
192 | switch (ares->type) { | 196 | /* |
193 | case ACPI_RESOURCE_TYPE_ADDRESS16: | 197 | * Filter out invalid descriptor according to ACPI Spec 5.0, section |
194 | case ACPI_RESOURCE_TYPE_ADDRESS32: | 198 | * 6.4.3.5 Address Space Resource Descriptors. |
195 | case ACPI_RESOURCE_TYPE_ADDRESS64: | 199 | */ |
196 | break; | 200 | if ((addr->min_address_fixed != addr->max_address_fixed && len) || |
197 | default: | 201 | (addr->min_address_fixed && addr->max_address_fixed && !len)) |
198 | return false; | 202 | pr_debug("ACPI: Invalid address space min_addr_fix %d, max_addr_fix %d, len %llx\n", |
199 | } | 203 | addr->min_address_fixed, addr->max_address_fixed, len); |
200 | 204 | ||
201 | status = acpi_resource_to_address64(ares, &addr); | 205 | res->start = attr->minimum; |
202 | if (ACPI_FAILURE(status)) | 206 | res->end = attr->maximum; |
203 | return false; | ||
204 | 207 | ||
205 | res->start = addr.address.minimum; | 208 | /* |
206 | res->end = addr.address.maximum; | 209 | * For bridges that translate addresses across the bridge, |
207 | window = addr.producer_consumer == ACPI_PRODUCER; | 210 | * translation_offset is the offset that must be added to the |
211 | * address on the secondary side to obtain the address on the | ||
212 | * primary side. Non-bridge devices must list 0 for all Address | ||
213 | * Translation offset bits. | ||
214 | */ | ||
215 | if (addr->producer_consumer == ACPI_PRODUCER) { | ||
216 | res->start += attr->translation_offset; | ||
217 | res->end += attr->translation_offset; | ||
218 | } else if (attr->translation_offset) { | ||
219 | pr_debug("ACPI: translation_offset(%lld) is invalid for non-bridge device.\n", | ||
220 | attr->translation_offset); | ||
221 | } | ||
208 | 222 | ||
209 | switch(addr.resource_type) { | 223 | switch (addr->resource_type) { |
210 | case ACPI_MEMORY_RANGE: | 224 | case ACPI_MEMORY_RANGE: |
211 | len = addr.address.maximum - addr.address.minimum + 1; | 225 | acpi_dev_memresource_flags(res, len, wp); |
212 | res->flags = acpi_dev_memresource_flags(len, | ||
213 | addr.info.mem.write_protect, | ||
214 | window); | ||
215 | break; | 226 | break; |
216 | case ACPI_IO_RANGE: | 227 | case ACPI_IO_RANGE: |
217 | io_decode = addr.address.granularity == 0xfff ? | 228 | acpi_dev_ioresource_flags(res, len, iodec); |
218 | ACPI_DECODE_10 : ACPI_DECODE_16; | ||
219 | res->flags = acpi_dev_ioresource_flags(addr.address.minimum, | ||
220 | addr.address.maximum, | ||
221 | io_decode, window); | ||
222 | break; | 229 | break; |
223 | case ACPI_BUS_NUMBER_RANGE: | 230 | case ACPI_BUS_NUMBER_RANGE: |
224 | res->flags = IORESOURCE_BUS; | 231 | res->flags = IORESOURCE_BUS; |
225 | break; | 232 | break; |
226 | default: | 233 | default: |
227 | res->flags = 0; | 234 | return false; |
228 | } | 235 | } |
229 | 236 | ||
230 | return true; | 237 | win->offset = attr->translation_offset; |
238 | |||
239 | if (addr->producer_consumer == ACPI_PRODUCER) | ||
240 | res->flags |= IORESOURCE_WINDOW; | ||
241 | |||
242 | if (addr->info.mem.caching == ACPI_PREFETCHABLE_MEMORY) | ||
243 | res->flags |= IORESOURCE_PREFETCH; | ||
244 | |||
245 | return !(res->flags & IORESOURCE_DISABLED); | ||
246 | } | ||
247 | |||
248 | /** | ||
249 | * acpi_dev_resource_address_space - Extract ACPI address space information. | ||
250 | * @ares: Input ACPI resource object. | ||
251 | * @win: Output generic resource object. | ||
252 | * | ||
253 | * Check if the given ACPI resource object represents an address space resource | ||
254 | * and if that's the case, use the information in it to populate the generic | ||
255 | * resource object pointed to by @win. | ||
256 | * | ||
257 | * Return: | ||
258 | * 1) false with win->res.flags setting to zero: not the expected resource type | ||
259 | * 2) false with IORESOURCE_DISABLED in win->res.flags: valid unassigned | ||
260 | * resource | ||
261 | * 3) true: valid assigned resource | ||
262 | */ | ||
263 | bool acpi_dev_resource_address_space(struct acpi_resource *ares, | ||
264 | struct resource_win *win) | ||
265 | { | ||
266 | struct acpi_resource_address64 addr; | ||
267 | |||
268 | win->res.flags = 0; | ||
269 | if (ACPI_FAILURE(acpi_resource_to_address64(ares, &addr))) | ||
270 | return false; | ||
271 | |||
272 | return acpi_decode_space(win, (struct acpi_resource_address *)&addr, | ||
273 | &addr.address); | ||
231 | } | 274 | } |
232 | EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space); | 275 | EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space); |
233 | 276 | ||
234 | /** | 277 | /** |
235 | * acpi_dev_resource_ext_address_space - Extract ACPI address space information. | 278 | * acpi_dev_resource_ext_address_space - Extract ACPI address space information. |
236 | * @ares: Input ACPI resource object. | 279 | * @ares: Input ACPI resource object. |
237 | * @res: Output generic resource object. | 280 | * @win: Output generic resource object. |
238 | * | 281 | * |
239 | * Check if the given ACPI resource object represents an extended address space | 282 | * Check if the given ACPI resource object represents an extended address space |
240 | * resource and if that's the case, use the information in it to populate the | 283 | * resource and if that's the case, use the information in it to populate the |
241 | * generic resource object pointed to by @res. | 284 | * generic resource object pointed to by @win. |
285 | * | ||
286 | * Return: | ||
287 | * 1) false with win->res.flags setting to zero: not the expected resource type | ||
288 | * 2) false with IORESOURCE_DISABLED in win->res.flags: valid unassigned | ||
289 | * resource | ||
290 | * 3) true: valid assigned resource | ||
242 | */ | 291 | */ |
243 | bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, | 292 | bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, |
244 | struct resource *res) | 293 | struct resource_win *win) |
245 | { | 294 | { |
246 | struct acpi_resource_extended_address64 *ext_addr; | 295 | struct acpi_resource_extended_address64 *ext_addr; |
247 | bool window; | ||
248 | u64 len; | ||
249 | u8 io_decode; | ||
250 | 296 | ||
297 | win->res.flags = 0; | ||
251 | if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64) | 298 | if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64) |
252 | return false; | 299 | return false; |
253 | 300 | ||
254 | ext_addr = &ares->data.ext_address64; | 301 | ext_addr = &ares->data.ext_address64; |
255 | 302 | ||
256 | res->start = ext_addr->address.minimum; | 303 | return acpi_decode_space(win, (struct acpi_resource_address *)ext_addr, |
257 | res->end = ext_addr->address.maximum; | 304 | &ext_addr->address); |
258 | window = ext_addr->producer_consumer == ACPI_PRODUCER; | ||
259 | |||
260 | switch(ext_addr->resource_type) { | ||
261 | case ACPI_MEMORY_RANGE: | ||
262 | len = ext_addr->address.maximum - ext_addr->address.minimum + 1; | ||
263 | res->flags = acpi_dev_memresource_flags(len, | ||
264 | ext_addr->info.mem.write_protect, | ||
265 | window); | ||
266 | break; | ||
267 | case ACPI_IO_RANGE: | ||
268 | io_decode = ext_addr->address.granularity == 0xfff ? | ||
269 | ACPI_DECODE_10 : ACPI_DECODE_16; | ||
270 | res->flags = acpi_dev_ioresource_flags(ext_addr->address.minimum, | ||
271 | ext_addr->address.maximum, | ||
272 | io_decode, window); | ||
273 | break; | ||
274 | case ACPI_BUS_NUMBER_RANGE: | ||
275 | res->flags = IORESOURCE_BUS; | ||
276 | break; | ||
277 | default: | ||
278 | res->flags = 0; | ||
279 | } | ||
280 | |||
281 | return true; | ||
282 | } | 305 | } |
283 | EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space); | 306 | EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space); |
284 | 307 | ||
@@ -310,7 +333,7 @@ static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi) | |||
310 | { | 333 | { |
311 | res->start = gsi; | 334 | res->start = gsi; |
312 | res->end = gsi; | 335 | res->end = gsi; |
313 | res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED; | 336 | res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED | IORESOURCE_UNSET; |
314 | } | 337 | } |
315 | 338 | ||
316 | static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, | 339 | static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, |
@@ -369,6 +392,11 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, | |||
369 | * represented by the resource and populate the generic resource object pointed | 392 | * represented by the resource and populate the generic resource object pointed |
370 | * to by @res accordingly. If the registration of the GSI is not successful, | 393 | * to by @res accordingly. If the registration of the GSI is not successful, |
371 | * IORESOURCE_DISABLED will be set it that object's flags. | 394 | * IORESOURCE_DISABLED will be set it that object's flags. |
395 | * | ||
396 | * Return: | ||
397 | * 1) false with res->flags setting to zero: not the expected resource type | ||
398 | * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource | ||
399 | * 3) true: valid assigned resource | ||
372 | */ | 400 | */ |
373 | bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, | 401 | bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, |
374 | struct resource *res) | 402 | struct resource *res) |
@@ -402,6 +430,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, | |||
402 | ext_irq->sharable, false); | 430 | ext_irq->sharable, false); |
403 | break; | 431 | break; |
404 | default: | 432 | default: |
433 | res->flags = 0; | ||
405 | return false; | 434 | return false; |
406 | } | 435 | } |
407 | 436 | ||
@@ -415,12 +444,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt); | |||
415 | */ | 444 | */ |
416 | void acpi_dev_free_resource_list(struct list_head *list) | 445 | void acpi_dev_free_resource_list(struct list_head *list) |
417 | { | 446 | { |
418 | struct resource_list_entry *rentry, *re; | 447 | resource_list_free(list); |
419 | |||
420 | list_for_each_entry_safe(rentry, re, list, node) { | ||
421 | list_del(&rentry->node); | ||
422 | kfree(rentry); | ||
423 | } | ||
424 | } | 448 | } |
425 | EXPORT_SYMBOL_GPL(acpi_dev_free_resource_list); | 449 | EXPORT_SYMBOL_GPL(acpi_dev_free_resource_list); |
426 | 450 | ||
@@ -432,18 +456,19 @@ struct res_proc_context { | |||
432 | int error; | 456 | int error; |
433 | }; | 457 | }; |
434 | 458 | ||
435 | static acpi_status acpi_dev_new_resource_entry(struct resource *r, | 459 | static acpi_status acpi_dev_new_resource_entry(struct resource_win *win, |
436 | struct res_proc_context *c) | 460 | struct res_proc_context *c) |
437 | { | 461 | { |
438 | struct resource_list_entry *rentry; | 462 | struct resource_entry *rentry; |
439 | 463 | ||
440 | rentry = kmalloc(sizeof(*rentry), GFP_KERNEL); | 464 | rentry = resource_list_create_entry(NULL, 0); |
441 | if (!rentry) { | 465 | if (!rentry) { |
442 | c->error = -ENOMEM; | 466 | c->error = -ENOMEM; |
443 | return AE_NO_MEMORY; | 467 | return AE_NO_MEMORY; |
444 | } | 468 | } |
445 | rentry->res = *r; | 469 | *rentry->res = win->res; |
446 | list_add_tail(&rentry->node, c->list); | 470 | rentry->offset = win->offset; |
471 | resource_list_add_tail(rentry, c->list); | ||
447 | c->count++; | 472 | c->count++; |
448 | return AE_OK; | 473 | return AE_OK; |
449 | } | 474 | } |
@@ -452,7 +477,8 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, | |||
452 | void *context) | 477 | void *context) |
453 | { | 478 | { |
454 | struct res_proc_context *c = context; | 479 | struct res_proc_context *c = context; |
455 | struct resource r; | 480 | struct resource_win win; |
481 | struct resource *res = &win.res; | ||
456 | int i; | 482 | int i; |
457 | 483 | ||
458 | if (c->preproc) { | 484 | if (c->preproc) { |
@@ -467,18 +493,18 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, | |||
467 | } | 493 | } |
468 | } | 494 | } |
469 | 495 | ||
470 | memset(&r, 0, sizeof(r)); | 496 | memset(&win, 0, sizeof(win)); |
471 | 497 | ||
472 | if (acpi_dev_resource_memory(ares, &r) | 498 | if (acpi_dev_resource_memory(ares, res) |
473 | || acpi_dev_resource_io(ares, &r) | 499 | || acpi_dev_resource_io(ares, res) |
474 | || acpi_dev_resource_address_space(ares, &r) | 500 | || acpi_dev_resource_address_space(ares, &win) |
475 | || acpi_dev_resource_ext_address_space(ares, &r)) | 501 | || acpi_dev_resource_ext_address_space(ares, &win)) |
476 | return acpi_dev_new_resource_entry(&r, c); | 502 | return acpi_dev_new_resource_entry(&win, c); |
477 | 503 | ||
478 | for (i = 0; acpi_dev_resource_interrupt(ares, i, &r); i++) { | 504 | for (i = 0; acpi_dev_resource_interrupt(ares, i, res); i++) { |
479 | acpi_status status; | 505 | acpi_status status; |
480 | 506 | ||
481 | status = acpi_dev_new_resource_entry(&r, c); | 507 | status = acpi_dev_new_resource_entry(&win, c); |
482 | if (ACPI_FAILURE(status)) | 508 | if (ACPI_FAILURE(status)) |
483 | return status; | 509 | return status; |
484 | } | 510 | } |
@@ -503,7 +529,7 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, | |||
503 | * returned as the final error code. | 529 | * returned as the final error code. |
504 | * | 530 | * |
505 | * The resultant struct resource objects are put on the list pointed to by | 531 | * The resultant struct resource objects are put on the list pointed to by |
506 | * @list, that must be empty initially, as members of struct resource_list_entry | 532 | * @list, that must be empty initially, as members of struct resource_entry |
507 | * objects. Callers of this routine should use %acpi_dev_free_resource_list() to | 533 | * objects. Callers of this routine should use %acpi_dev_free_resource_list() to |
508 | * free that list. | 534 | * free that list. |
509 | * | 535 | * |
@@ -538,3 +564,58 @@ int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, | |||
538 | return c.count; | 564 | return c.count; |
539 | } | 565 | } |
540 | EXPORT_SYMBOL_GPL(acpi_dev_get_resources); | 566 | EXPORT_SYMBOL_GPL(acpi_dev_get_resources); |
567 | |||
568 | /** | ||
569 | * acpi_dev_filter_resource_type - Filter ACPI resource according to resource | ||
570 | * types | ||
571 | * @ares: Input ACPI resource object. | ||
572 | * @types: Valid resource types of IORESOURCE_XXX | ||
573 | * | ||
574 | * This is a hepler function to support acpi_dev_get_resources(), which filters | ||
575 | * ACPI resource objects according to resource types. | ||
576 | */ | ||
577 | int acpi_dev_filter_resource_type(struct acpi_resource *ares, | ||
578 | unsigned long types) | ||
579 | { | ||
580 | unsigned long type = 0; | ||
581 | |||
582 | switch (ares->type) { | ||
583 | case ACPI_RESOURCE_TYPE_MEMORY24: | ||
584 | case ACPI_RESOURCE_TYPE_MEMORY32: | ||
585 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: | ||
586 | type = IORESOURCE_MEM; | ||
587 | break; | ||
588 | case ACPI_RESOURCE_TYPE_IO: | ||
589 | case ACPI_RESOURCE_TYPE_FIXED_IO: | ||
590 | type = IORESOURCE_IO; | ||
591 | break; | ||
592 | case ACPI_RESOURCE_TYPE_IRQ: | ||
593 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: | ||
594 | type = IORESOURCE_IRQ; | ||
595 | break; | ||
596 | case ACPI_RESOURCE_TYPE_DMA: | ||
597 | case ACPI_RESOURCE_TYPE_FIXED_DMA: | ||
598 | type = IORESOURCE_DMA; | ||
599 | break; | ||
600 | case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: | ||
601 | type = IORESOURCE_REG; | ||
602 | break; | ||
603 | case ACPI_RESOURCE_TYPE_ADDRESS16: | ||
604 | case ACPI_RESOURCE_TYPE_ADDRESS32: | ||
605 | case ACPI_RESOURCE_TYPE_ADDRESS64: | ||
606 | case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: | ||
607 | if (ares->data.address.resource_type == ACPI_MEMORY_RANGE) | ||
608 | type = IORESOURCE_MEM; | ||
609 | else if (ares->data.address.resource_type == ACPI_IO_RANGE) | ||
610 | type = IORESOURCE_IO; | ||
611 | else if (ares->data.address.resource_type == | ||
612 | ACPI_BUS_NUMBER_RANGE) | ||
613 | type = IORESOURCE_BUS; | ||
614 | break; | ||
615 | default: | ||
616 | break; | ||
617 | } | ||
618 | |||
619 | return (type & types) ? 0 : 1; | ||
620 | } | ||
621 | EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type); | ||