aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/acpi_pcihp.c
diff options
context:
space:
mode:
authorKristen Accardi <kristen.c.accardi@intel.com>2006-03-03 13:16:05 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-03-23 17:35:17 -0500
commit783c49fc506d9afe4784390b556fa25ede5d6d1f (patch)
tree8090c2251193211129816254f16f10cbb33ed20c /drivers/pci/hotplug/acpi_pcihp.c
parentf5afe8064f3087bead8fea7e32547c2a3ada5fd0 (diff)
[PATCH] PCI Hotplug: add common acpi functions to core
shpchprm_acpi.c and pciehprm_acpi.c are nearly identical. In addition, there are functions in both these files that are also in acpiphp_glue.c. This patch will remove duplicate functions from shpchp, pciehp, and acpiphp and move this functionality to pci_hotplug, as it is not hardware specific. Get rid of shpchprm* and pciehprm* files since they are no longer needed. shpchprm_nonacpi.c and pciehprm_nonacpi.c are identical, as well as shpchprm_legacy.c and can be replaced with a macro. This patch also changes acpiphp to use the common hpp code. Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci/hotplug/acpi_pcihp.c')
-rw-r--r--drivers/pci/hotplug/acpi_pcihp.c227
1 files changed, 227 insertions, 0 deletions
diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c
new file mode 100644
index 000000000000..0f7135317542
--- /dev/null
+++ b/drivers/pci/hotplug/acpi_pcihp.c
@@ -0,0 +1,227 @@
1/*
2 * Common ACPI functions for hot plug platforms
3 *
4 * Copyright (C) 2006 Intel Corporation
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 *
23 * Send feedback to <kristen.c.accardi@intel.com>
24 *
25 */
26
27#include <linux/module.h>
28#include <linux/kernel.h>
29#include <linux/types.h>
30#include <linux/pci.h>
31#include <acpi/acpi.h>
32#include <acpi/acpi_bus.h>
33#include <acpi/actypes.h>
34#include "pci_hotplug.h"
35
36#define METHOD_NAME__SUN "_SUN"
37#define METHOD_NAME__HPP "_HPP"
38#define METHOD_NAME_OSHP "OSHP"
39
40/* acpi_path_name
41 *
42 * @handle - the acpi_handle of the object who's name you want.
43 *
44 * Caller must free buffer.
45 */
46u8 * acpi_path_name(acpi_handle handle)
47{
48 acpi_status status;
49 struct acpi_buffer ret_buf = {ACPI_ALLOCATE_BUFFER, NULL};
50 union acpi_object *obj;
51
52 status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &ret_buf);
53 if (ACPI_FAILURE(status)) {
54 return NULL;
55 }
56 obj = ret_buf.pointer;
57 return obj->string.pointer;
58}
59EXPORT_SYMBOL_GPL(acpi_path_name);
60
61
62
63static acpi_status
64acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
65{
66 acpi_status status;
67 u8 nui[4];
68 struct acpi_buffer ret_buf = { 0, NULL};
69 union acpi_object *ext_obj, *package;
70 u8 *path_name = acpi_path_name(handle);
71 int i, len = 0;
72
73 /* get _hpp */
74 status = acpi_evaluate_object(handle, METHOD_NAME__HPP, NULL, &ret_buf);
75 switch (status) {
76 case AE_BUFFER_OVERFLOW:
77 ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL);
78 if (!ret_buf.pointer) {
79 printk(KERN_ERR "%s:%s alloc for _HPP fail\n",
80 __FUNCTION__, path_name);
81 acpi_os_free(path_name);
82 return AE_NO_MEMORY;
83 }
84 status = acpi_evaluate_object(handle, METHOD_NAME__HPP,
85 NULL, &ret_buf);
86 if (ACPI_SUCCESS(status))
87 break;
88 default:
89 if (ACPI_FAILURE(status)) {
90 pr_debug("%s:%s _HPP fail=0x%x\n", __FUNCTION__,
91 path_name, status);
92 acpi_os_free(path_name);
93 return status;
94 }
95 }
96
97 ext_obj = (union acpi_object *) ret_buf.pointer;
98 if (ext_obj->type != ACPI_TYPE_PACKAGE) {
99 printk(KERN_ERR "%s:%s _HPP obj not a package\n", __FUNCTION__,
100 path_name);
101 status = AE_ERROR;
102 goto free_and_return;
103 }
104
105 len = ext_obj->package.count;
106 package = (union acpi_object *) ret_buf.pointer;
107 for ( i = 0; (i < len) || (i < 4); i++) {
108 ext_obj = (union acpi_object *) &package->package.elements[i];
109 switch (ext_obj->type) {
110 case ACPI_TYPE_INTEGER:
111 nui[i] = (u8)ext_obj->integer.value;
112 break;
113 default:
114 printk(KERN_ERR "%s:%s _HPP obj type incorrect\n",
115 __FUNCTION__, path_name);
116 status = AE_ERROR;
117 goto free_and_return;
118 }
119 }
120
121 hpp->cache_line_size = nui[0];
122 hpp->latency_timer = nui[1];
123 hpp->enable_serr = nui[2];
124 hpp->enable_perr = nui[3];
125
126 pr_debug(" _HPP: cache_line_size=0x%x\n", hpp->cache_line_size);
127 pr_debug(" _HPP: latency timer =0x%x\n", hpp->latency_timer);
128 pr_debug(" _HPP: enable SERR =0x%x\n", hpp->enable_serr);
129 pr_debug(" _HPP: enable PERR =0x%x\n", hpp->enable_perr);
130
131free_and_return:
132 acpi_os_free(path_name);
133 kfree(ret_buf.pointer);
134 return status;
135}
136
137
138
139/* acpi_run_oshp - get control of hotplug from the firmware
140 *
141 * @handle - the handle of the hotplug controller.
142 */
143acpi_status acpi_run_oshp(acpi_handle handle)
144{
145 acpi_status status;
146 u8 *path_name = acpi_path_name(handle);
147
148 /* run OSHP */
149 status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL);
150 if (ACPI_FAILURE(status))
151 printk(KERN_ERR "%s:%s OSHP fails=0x%x\n", __FUNCTION__,
152 path_name, status);
153 else
154 pr_debug("%s:%s OSHP passes\n", __FUNCTION__, path_name);
155 acpi_os_free(path_name);
156 return status;
157}
158EXPORT_SYMBOL_GPL(acpi_run_oshp);
159
160
161
162/* acpi_get_hp_params_from_firmware
163 *
164 * @dev - the pci_dev of the newly added device
165 * @hpp - allocated by the caller
166 */
167acpi_status acpi_get_hp_params_from_firmware(struct pci_dev *dev,
168 struct hotplug_params *hpp)
169{
170 acpi_status status = AE_NOT_FOUND;
171 struct pci_dev *pdev = dev;
172
173 /*
174 * _HPP settings apply to all child buses, until another _HPP is
175 * encountered. If we don't find an _HPP for the input pci dev,
176 * look for it in the parent device scope since that would apply to
177 * this pci dev. If we don't find any _HPP, use hardcoded defaults
178 */
179 while (pdev && (ACPI_FAILURE(status))) {
180 acpi_handle handle = DEVICE_ACPI_HANDLE(&(pdev->dev));
181 if (!handle)
182 break;
183 status = acpi_run_hpp(handle, hpp);
184 if (!(pdev->bus->parent))
185 break;
186 /* Check if a parent object supports _HPP */
187 pdev = pdev->bus->parent->self;
188 }
189 return status;
190}
191EXPORT_SYMBOL_GPL(acpi_get_hp_params_from_firmware);
192
193
194/* acpi_root_bridge - check to see if this acpi object is a root bridge
195 *
196 * @handle - the acpi object in question.
197 */
198int acpi_root_bridge(acpi_handle handle)
199{
200 acpi_status status;
201 struct acpi_device_info *info;
202 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
203 int i;
204
205 status = acpi_get_object_info(handle, &buffer);
206 if (ACPI_SUCCESS(status)) {
207 info = buffer.pointer;
208 if ((info->valid & ACPI_VALID_HID) &&
209 !strcmp(PCI_ROOT_HID_STRING,
210 info->hardware_id.value)) {
211 acpi_os_free(buffer.pointer);
212 return 1;
213 }
214 if (info->valid & ACPI_VALID_CID) {
215 for (i=0; i < info->compatibility_id.count; i++) {
216 if (!strcmp(PCI_ROOT_HID_STRING,
217 info->compatibility_id.id[i].value)) {
218 acpi_os_free(buffer.pointer);
219 return 1;
220 }
221 }
222 }
223 acpi_os_free(buffer.pointer);
224 }
225 return 0;
226}
227EXPORT_SYMBOL_GPL(acpi_root_bridge);