Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
783c49fc | 2 | * Common ACPI functions for hot plug platforms |
1da177e4 | 3 | * |
783c49fc | 4 | * Copyright (C) 2006 Intel Corporation |
1da177e4 LT |
5 | * |
6 | * All rights reserved. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2 of the License, or (at | |
11 | * your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, but | |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | |
16 | * NON INFRINGEMENT. See the GNU General Public License for more | |
17 | * details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
22 | * | |
8cf4c195 | 23 | * Send feedback to <kristen.c.accardi@intel.com> |
1da177e4 LT |
24 | * |
25 | */ | |
26 | ||
1da177e4 LT |
27 | #include <linux/module.h> |
28 | #include <linux/kernel.h> | |
29 | #include <linux/types.h> | |
30 | #include <linux/pci.h> | |
783c49fc | 31 | #include <acpi/acpi.h> |
1da177e4 LT |
32 | #include <acpi/acpi_bus.h> |
33 | #include <acpi/actypes.h> | |
783c49fc | 34 | #include "pci_hotplug.h" |
1da177e4 LT |
35 | |
36 | #define METHOD_NAME__SUN "_SUN" | |
37 | #define METHOD_NAME__HPP "_HPP" | |
38 | #define METHOD_NAME_OSHP "OSHP" | |
39 | ||
1da177e4 | 40 | |
a8a2be94 | 41 | static acpi_status |
42 | acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) | |
1da177e4 LT |
43 | { |
44 | acpi_status status; | |
45 | u8 nui[4]; | |
46 | struct acpi_buffer ret_buf = { 0, NULL}; | |
b2e6e3ba | 47 | struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; |
1da177e4 | 48 | union acpi_object *ext_obj, *package; |
1da177e4 LT |
49 | int i, len = 0; |
50 | ||
b2e6e3ba MT |
51 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); |
52 | ||
1da177e4 | 53 | /* get _hpp */ |
a8a2be94 | 54 | status = acpi_evaluate_object(handle, METHOD_NAME__HPP, NULL, &ret_buf); |
1da177e4 LT |
55 | switch (status) { |
56 | case AE_BUFFER_OVERFLOW: | |
57 | ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL); | |
58 | if (!ret_buf.pointer) { | |
783c49fc | 59 | printk(KERN_ERR "%s:%s alloc for _HPP fail\n", |
b2e6e3ba MT |
60 | __FUNCTION__, (char *)string.pointer); |
61 | acpi_os_free(string.pointer); | |
a8a2be94 | 62 | return AE_NO_MEMORY; |
1da177e4 | 63 | } |
a8a2be94 | 64 | status = acpi_evaluate_object(handle, METHOD_NAME__HPP, |
65 | NULL, &ret_buf); | |
1da177e4 LT |
66 | if (ACPI_SUCCESS(status)) |
67 | break; | |
68 | default: | |
69 | if (ACPI_FAILURE(status)) { | |
783c49fc | 70 | pr_debug("%s:%s _HPP fail=0x%x\n", __FUNCTION__, |
b2e6e3ba MT |
71 | (char *)string.pointer, status); |
72 | acpi_os_free(string.pointer); | |
a8a2be94 | 73 | return status; |
1da177e4 LT |
74 | } |
75 | } | |
76 | ||
77 | ext_obj = (union acpi_object *) ret_buf.pointer; | |
78 | if (ext_obj->type != ACPI_TYPE_PACKAGE) { | |
783c49fc | 79 | printk(KERN_ERR "%s:%s _HPP obj not a package\n", __FUNCTION__, |
b2e6e3ba | 80 | (char *)string.pointer); |
a8a2be94 | 81 | status = AE_ERROR; |
1da177e4 LT |
82 | goto free_and_return; |
83 | } | |
84 | ||
85 | len = ext_obj->package.count; | |
86 | package = (union acpi_object *) ret_buf.pointer; | |
87 | for ( i = 0; (i < len) || (i < 4); i++) { | |
88 | ext_obj = (union acpi_object *) &package->package.elements[i]; | |
89 | switch (ext_obj->type) { | |
90 | case ACPI_TYPE_INTEGER: | |
91 | nui[i] = (u8)ext_obj->integer.value; | |
92 | break; | |
93 | default: | |
783c49fc | 94 | printk(KERN_ERR "%s:%s _HPP obj type incorrect\n", |
b2e6e3ba | 95 | __FUNCTION__, (char *)string.pointer); |
a8a2be94 | 96 | status = AE_ERROR; |
1da177e4 LT |
97 | goto free_and_return; |
98 | } | |
99 | } | |
100 | ||
a8a2be94 | 101 | hpp->cache_line_size = nui[0]; |
102 | hpp->latency_timer = nui[1]; | |
103 | hpp->enable_serr = nui[2]; | |
104 | hpp->enable_perr = nui[3]; | |
1da177e4 | 105 | |
783c49fc KA |
106 | pr_debug(" _HPP: cache_line_size=0x%x\n", hpp->cache_line_size); |
107 | pr_debug(" _HPP: latency timer =0x%x\n", hpp->latency_timer); | |
108 | pr_debug(" _HPP: enable SERR =0x%x\n", hpp->enable_serr); | |
109 | pr_debug(" _HPP: enable PERR =0x%x\n", hpp->enable_perr); | |
1da177e4 LT |
110 | |
111 | free_and_return: | |
b2e6e3ba MT |
112 | acpi_os_free(string.pointer); |
113 | acpi_os_free(ret_buf.pointer); | |
a8a2be94 | 114 | return status; |
1da177e4 LT |
115 | } |
116 | ||
783c49fc KA |
117 | |
118 | ||
119 | /* acpi_run_oshp - get control of hotplug from the firmware | |
120 | * | |
121 | * @handle - the handle of the hotplug controller. | |
122 | */ | |
123 | acpi_status acpi_run_oshp(acpi_handle handle) | |
1da177e4 LT |
124 | { |
125 | acpi_status status; | |
b2e6e3ba MT |
126 | struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; |
127 | ||
128 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); | |
1da177e4 LT |
129 | |
130 | /* run OSHP */ | |
a8a2be94 | 131 | status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL); |
783c49fc KA |
132 | if (ACPI_FAILURE(status)) |
133 | printk(KERN_ERR "%s:%s OSHP fails=0x%x\n", __FUNCTION__, | |
b2e6e3ba | 134 | (char *)string.pointer, status); |
783c49fc | 135 | else |
b2e6e3ba MT |
136 | pr_debug("%s:%s OSHP passes\n", __FUNCTION__, |
137 | (char *)string.pointer); | |
138 | ||
139 | acpi_os_free(string.pointer); | |
783c49fc KA |
140 | return status; |
141 | } | |
142 | EXPORT_SYMBOL_GPL(acpi_run_oshp); | |
143 | ||
144 | ||
145 | ||
146 | /* acpi_get_hp_params_from_firmware | |
147 | * | |
148 | * @dev - the pci_dev of the newly added device | |
149 | * @hpp - allocated by the caller | |
150 | */ | |
151 | acpi_status acpi_get_hp_params_from_firmware(struct pci_dev *dev, | |
152 | struct hotplug_params *hpp) | |
153 | { | |
154 | acpi_status status = AE_NOT_FOUND; | |
155 | struct pci_dev *pdev = dev; | |
156 | ||
157 | /* | |
158 | * _HPP settings apply to all child buses, until another _HPP is | |
159 | * encountered. If we don't find an _HPP for the input pci dev, | |
160 | * look for it in the parent device scope since that would apply to | |
161 | * this pci dev. If we don't find any _HPP, use hardcoded defaults | |
162 | */ | |
163 | while (pdev && (ACPI_FAILURE(status))) { | |
164 | acpi_handle handle = DEVICE_ACPI_HANDLE(&(pdev->dev)); | |
165 | if (!handle) | |
166 | break; | |
167 | status = acpi_run_hpp(handle, hpp); | |
168 | if (!(pdev->bus->parent)) | |
169 | break; | |
170 | /* Check if a parent object supports _HPP */ | |
171 | pdev = pdev->bus->parent->self; | |
1da177e4 | 172 | } |
a8a2be94 | 173 | return status; |
1da177e4 | 174 | } |
783c49fc KA |
175 | EXPORT_SYMBOL_GPL(acpi_get_hp_params_from_firmware); |
176 | ||
1da177e4 | 177 | |
783c49fc KA |
178 | /* acpi_root_bridge - check to see if this acpi object is a root bridge |
179 | * | |
180 | * @handle - the acpi object in question. | |
181 | */ | |
182 | int acpi_root_bridge(acpi_handle handle) | |
a3a45ec8 | 183 | { |
184 | acpi_status status; | |
185 | struct acpi_device_info *info; | |
186 | struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; | |
187 | int i; | |
188 | ||
189 | status = acpi_get_object_info(handle, &buffer); | |
190 | if (ACPI_SUCCESS(status)) { | |
191 | info = buffer.pointer; | |
192 | if ((info->valid & ACPI_VALID_HID) && | |
193 | !strcmp(PCI_ROOT_HID_STRING, | |
194 | info->hardware_id.value)) { | |
195 | acpi_os_free(buffer.pointer); | |
196 | return 1; | |
197 | } | |
198 | if (info->valid & ACPI_VALID_CID) { | |
199 | for (i=0; i < info->compatibility_id.count; i++) { | |
200 | if (!strcmp(PCI_ROOT_HID_STRING, | |
201 | info->compatibility_id.id[i].value)) { | |
202 | acpi_os_free(buffer.pointer); | |
203 | return 1; | |
204 | } | |
205 | } | |
206 | } | |
783c49fc | 207 | acpi_os_free(buffer.pointer); |
a3a45ec8 | 208 | } |
209 | return 0; | |
210 | } | |
783c49fc | 211 | EXPORT_SYMBOL_GPL(acpi_root_bridge); |