2 * SHPCHPRM 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/config.h>
28 #include <linux/module.h>
29 #include <linux/kernel.h>
30 #include <linux/types.h>
31 #include <linux/pci.h>
32 #include <linux/init.h>
33 #include <linux/acpi.h>
34 #include <linux/efi.h>
35 #include <asm/uaccess.h>
36 #include <asm/system.h>
37 #include <acpi/acpi.h>
38 #include <acpi/acpi_bus.h>
39 #include <acpi/actypes.h>
42 #define METHOD_NAME__SUN "_SUN"
43 #define METHOD_NAME__HPP "_HPP"
44 #define METHOD_NAME_OSHP "OSHP"
46 static u8
* acpi_path_name( acpi_handle handle
)
49 static u8 path_name
[ACPI_PATHNAME_MAX
];
50 struct acpi_buffer ret_buf
= { ACPI_PATHNAME_MAX
, path_name
};
52 memset(path_name
, 0, sizeof (path_name
));
53 status
= acpi_get_name(handle
, ACPI_FULL_PATHNAME
, &ret_buf
);
55 if (ACPI_FAILURE(status
))
62 acpi_run_hpp(acpi_handle handle
, struct hotplug_params
*hpp
)
66 struct acpi_buffer ret_buf
= { 0, NULL
};
67 union acpi_object
*ext_obj
, *package
;
68 u8
*path_name
= acpi_path_name(handle
);
72 status
= acpi_evaluate_object(handle
, METHOD_NAME__HPP
, NULL
, &ret_buf
);
74 case AE_BUFFER_OVERFLOW
:
75 ret_buf
.pointer
= kmalloc (ret_buf
.length
, GFP_KERNEL
);
76 if (!ret_buf
.pointer
) {
77 err ("%s:%s alloc for _HPP fail\n", __FUNCTION__
,
81 status
= acpi_evaluate_object(handle
, METHOD_NAME__HPP
,
83 if (ACPI_SUCCESS(status
))
86 if (ACPI_FAILURE(status
)) {
87 dbg("%s:%s _HPP fail=0x%x\n", __FUNCTION__
,
93 ext_obj
= (union acpi_object
*) ret_buf
.pointer
;
94 if (ext_obj
->type
!= ACPI_TYPE_PACKAGE
) {
95 err ("%s:%s _HPP obj not a package\n", __FUNCTION__
,
101 len
= ext_obj
->package
.count
;
102 package
= (union acpi_object
*) ret_buf
.pointer
;
103 for ( i
= 0; (i
< len
) || (i
< 4); i
++) {
104 ext_obj
= (union acpi_object
*) &package
->package
.elements
[i
];
105 switch (ext_obj
->type
) {
106 case ACPI_TYPE_INTEGER
:
107 nui
[i
] = (u8
)ext_obj
->integer
.value
;
110 err ("%s:%s _HPP obj type incorrect\n", __FUNCTION__
,
113 goto free_and_return
;
117 hpp
->cache_line_size
= nui
[0];
118 hpp
->latency_timer
= nui
[1];
119 hpp
->enable_serr
= nui
[2];
120 hpp
->enable_perr
= nui
[3];
122 dbg(" _HPP: cache_line_size=0x%x\n", hpp
->cache_line_size
);
123 dbg(" _HPP: latency timer =0x%x\n", hpp
->latency_timer
);
124 dbg(" _HPP: enable SERR =0x%x\n", hpp
->enable_serr
);
125 dbg(" _HPP: enable PERR =0x%x\n", hpp
->enable_perr
);
128 kfree(ret_buf
.pointer
);
132 static void acpi_run_oshp(acpi_handle handle
)
135 u8
*path_name
= acpi_path_name(handle
);
138 status
= acpi_evaluate_object(handle
, METHOD_NAME_OSHP
, NULL
, NULL
);
139 if (ACPI_FAILURE(status
)) {
140 err("%s:%s OSHP fails=0x%x\n", __FUNCTION__
, path_name
,
143 dbg("%s:%s OSHP passes\n", __FUNCTION__
, path_name
);
147 int shpchprm_get_physical_slot_number(struct controller
*ctrl
, u32
*sun
, u8 busnum
, u8 devnum
)
149 int offset
= devnum
- ctrl
->slot_device_offset
;
151 dbg("%s: ctrl->slot_num_inc %d, offset %d\n", __FUNCTION__
, ctrl
->slot_num_inc
, offset
);
152 *sun
= (u8
) (ctrl
->first_slot
+ ctrl
->slot_num_inc
*offset
);
156 void get_hp_hw_control_from_firmware(struct pci_dev
*dev
)
159 * OSHP is an optional ACPI firmware control method. If present,
160 * we need to run it to inform BIOS that we will control SHPC
161 * hardware from now on.
163 acpi_handle handle
= DEVICE_ACPI_HANDLE(&(dev
->dev
));
166 acpi_run_oshp(handle
);
169 void get_hp_params_from_firmware(struct pci_dev
*dev
,
170 struct hotplug_params
*hpp
)
172 acpi_status status
= AE_NOT_FOUND
;
173 struct pci_dev
*pdev
= dev
;
176 * _HPP settings apply to all child buses, until another _HPP is
177 * encountered. If we don't find an _HPP for the input pci dev,
178 * look for it in the parent device scope since that would apply to
179 * this pci dev. If we don't find any _HPP, use hardcoded defaults
181 while (pdev
&& (ACPI_FAILURE(status
))) {
182 acpi_handle handle
= DEVICE_ACPI_HANDLE(&(pdev
->dev
));
185 status
= acpi_run_hpp(handle
, hpp
);
186 if (!(pdev
->bus
->parent
))
188 /* Check if a parent object supports _HPP */
189 pdev
= pdev
->bus
->parent
->self
;