2 * PCIEHPRM ACPI: PHP Resource Manager for ACPI platform
4 * Copyright (C) 2003-2004 Intel Corporation
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.
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
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.
23 * Send feedback to <kristen.c.accardi@intel.com>
27 #include <linux/module.h>
28 #include <linux/kernel.h>
29 #include <linux/types.h>
30 #include <linux/pci.h>
31 #include <linux/acpi.h>
32 #include <linux/pci-acpi.h>
33 #include <acpi/acpi_bus.h>
34 #include <acpi/actypes.h>
37 #define METHOD_NAME__SUN "_SUN"
38 #define METHOD_NAME__HPP "_HPP"
39 #define METHOD_NAME_OSHP "OSHP"
41 static u8
* acpi_path_name( acpi_handle handle
)
44 static u8 path_name
[ACPI_PATHNAME_MAX
];
45 struct acpi_buffer ret_buf
= { ACPI_PATHNAME_MAX
, path_name
};
47 memset(path_name
, 0, sizeof (path_name
));
48 status
= acpi_get_name(handle
, ACPI_FULL_PATHNAME
, &ret_buf
);
50 if (ACPI_FAILURE(status
))
57 acpi_run_hpp(acpi_handle handle
, struct hotplug_params
*hpp
)
61 struct acpi_buffer ret_buf
= { 0, NULL
};
62 union acpi_object
*ext_obj
, *package
;
63 u8
*path_name
= acpi_path_name(handle
);
67 status
= acpi_evaluate_object(handle
, METHOD_NAME__HPP
, NULL
, &ret_buf
);
69 case AE_BUFFER_OVERFLOW
:
70 ret_buf
.pointer
= kmalloc (ret_buf
.length
, GFP_KERNEL
);
71 if (!ret_buf
.pointer
) {
72 err ("%s:%s alloc for _HPP fail\n", __FUNCTION__
,
76 status
= acpi_evaluate_object(handle
, METHOD_NAME__HPP
,
78 if (ACPI_SUCCESS(status
))
81 if (ACPI_FAILURE(status
)) {
82 dbg("%s:%s _HPP fail=0x%x\n", __FUNCTION__
,
88 ext_obj
= (union acpi_object
*) ret_buf
.pointer
;
89 if (ext_obj
->type
!= ACPI_TYPE_PACKAGE
) {
90 err ("%s:%s _HPP obj not a package\n", __FUNCTION__
,
96 len
= ext_obj
->package
.count
;
97 package
= (union acpi_object
*) ret_buf
.pointer
;
98 for ( i
= 0; (i
< len
) || (i
< 4); i
++) {
99 ext_obj
= (union acpi_object
*) &package
->package
.elements
[i
];
100 switch (ext_obj
->type
) {
101 case ACPI_TYPE_INTEGER
:
102 nui
[i
] = (u8
)ext_obj
->integer
.value
;
105 err ("%s:%s _HPP obj type incorrect\n", __FUNCTION__
,
108 goto free_and_return
;
112 hpp
->cache_line_size
= nui
[0];
113 hpp
->latency_timer
= nui
[1];
114 hpp
->enable_serr
= nui
[2];
115 hpp
->enable_perr
= nui
[3];
117 dbg(" _HPP: cache_line_size=0x%x\n", hpp
->cache_line_size
);
118 dbg(" _HPP: latency timer =0x%x\n", hpp
->latency_timer
);
119 dbg(" _HPP: enable SERR =0x%x\n", hpp
->enable_serr
);
120 dbg(" _HPP: enable PERR =0x%x\n", hpp
->enable_perr
);
123 kfree(ret_buf
.pointer
);
127 static acpi_status
acpi_run_oshp(acpi_handle handle
)
130 u8
*path_name
= acpi_path_name(handle
);
133 status
= acpi_evaluate_object(handle
, METHOD_NAME_OSHP
, NULL
, NULL
);
134 if (ACPI_FAILURE(status
)) {
135 dbg("%s:%s OSHP fails=0x%x\n", __FUNCTION__
, path_name
,
138 dbg("%s:%s OSHP passes\n", __FUNCTION__
, path_name
);
143 static int is_root_bridge(acpi_handle handle
)
146 struct acpi_device_info
*info
;
147 struct acpi_buffer buffer
= {ACPI_ALLOCATE_BUFFER
, NULL
};
150 status
= acpi_get_object_info(handle
, &buffer
);
151 if (ACPI_SUCCESS(status
)) {
152 info
= buffer
.pointer
;
153 if ((info
->valid
& ACPI_VALID_HID
) &&
154 !strcmp(PCI_ROOT_HID_STRING
,
155 info
->hardware_id
.value
)) {
156 acpi_os_free(buffer
.pointer
);
159 if (info
->valid
& ACPI_VALID_CID
) {
160 for (i
=0; i
< info
->compatibility_id
.count
; i
++) {
161 if (!strcmp(PCI_ROOT_HID_STRING
,
162 info
->compatibility_id
.id
[i
].value
)) {
163 acpi_os_free(buffer
.pointer
);
172 int pciehp_get_hp_hw_control_from_firmware(struct pci_dev
*dev
)
175 acpi_handle chandle
, handle
= DEVICE_ACPI_HANDLE(&(dev
->dev
));
176 struct pci_dev
*pdev
= dev
;
179 * Per PCI firmware specification, we should run the ACPI _OSC
180 * method to get control of hotplug hardware before using it.
181 * If an _OSC is missing, we look for an OSHP to do the same thing.
182 * To handle different BIOS behavior, we look for _OSC and OSHP
183 * within the scope of the hotplug controller and its parents, upto
184 * the host bridge under which this controller exists.
188 * This hotplug controller was not listed in the ACPI name
189 * space at all. Try to get acpi handle of parent pci bus.
191 if (!pdev
|| !pdev
->bus
->parent
)
193 dbg("Could not find %s in acpi namespace, trying parent\n",
195 if (!pdev
->bus
->parent
->self
)
196 /* Parent must be a host bridge */
197 handle
= acpi_get_pci_rootbridge_handle(
198 pci_domain_nr(pdev
->bus
->parent
),
199 pdev
->bus
->parent
->number
);
201 handle
= DEVICE_ACPI_HANDLE(
202 &(pdev
->bus
->parent
->self
->dev
));
203 pdev
= pdev
->bus
->parent
->self
;
207 path_name
= acpi_path_name(handle
);
208 dbg("Trying to get hotplug control for %s \n", path_name
);
209 status
= pci_osc_control_set(handle
,
210 OSC_PCI_EXPRESS_NATIVE_HP_CONTROL
);
211 if (status
== AE_NOT_FOUND
)
212 status
= acpi_run_oshp(handle
);
213 if (ACPI_SUCCESS(status
)) {
214 dbg("Gained control for hotplug HW for pci %s (%s)\n",
215 pci_name(dev
), path_name
);
218 if (is_root_bridge(handle
))
221 status
= acpi_get_parent(chandle
, &handle
);
222 if (ACPI_FAILURE(status
))
226 err("Cannot get control of hotplug hardware for pci %s\n",
231 void pciehp_get_hp_params_from_firmware(struct pci_dev
*dev
,
232 struct hotplug_params
*hpp
)
234 acpi_status status
= AE_NOT_FOUND
;
235 struct pci_dev
*pdev
= dev
;
238 * _HPP settings apply to all child buses, until another _HPP is
239 * encountered. If we don't find an _HPP for the input pci dev,
240 * look for it in the parent device scope since that would apply to
241 * this pci dev. If we don't find any _HPP, use hardcoded defaults
243 while (pdev
&& (ACPI_FAILURE(status
))) {
244 acpi_handle handle
= DEVICE_ACPI_HANDLE(&(pdev
->dev
));
247 status
= acpi_run_hpp(handle
, hpp
);
248 if (!(pdev
->bus
->parent
))
250 /* Check if a parent object supports _HPP */
251 pdev
= pdev
->bus
->parent
->self
;