diff options
Diffstat (limited to 'drivers/pci/pci-acpi.c')
-rw-r--r-- | drivers/pci/pci-acpi.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c new file mode 100644 index 000000000000..968eb32f292d --- /dev/null +++ b/drivers/pci/pci-acpi.c | |||
@@ -0,0 +1,209 @@ | |||
1 | /* | ||
2 | * File: pci-acpi.c | ||
3 | * Purpose: Provide PCI supports in ACPI | ||
4 | * | ||
5 | * Copyright (C) 2004 Intel | ||
6 | * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) | ||
7 | */ | ||
8 | |||
9 | #include <linux/delay.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/pci.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <acpi/acpi.h> | ||
14 | #include <acpi/acnamesp.h> | ||
15 | #include <acpi/acresrc.h> | ||
16 | #include <acpi/acpi_bus.h> | ||
17 | |||
18 | #include <linux/pci-acpi.h> | ||
19 | |||
20 | static u32 ctrlset_buf[3] = {0, 0, 0}; | ||
21 | static u32 global_ctrlsets = 0; | ||
22 | u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66}; | ||
23 | |||
24 | static acpi_status | ||
25 | acpi_query_osc ( | ||
26 | acpi_handle handle, | ||
27 | u32 level, | ||
28 | void *context, | ||
29 | void **retval ) | ||
30 | { | ||
31 | acpi_status status; | ||
32 | struct acpi_object_list input; | ||
33 | union acpi_object in_params[4]; | ||
34 | struct acpi_buffer output; | ||
35 | union acpi_object out_obj; | ||
36 | u32 osc_dw0; | ||
37 | |||
38 | /* Setting up output buffer */ | ||
39 | output.length = sizeof(out_obj) + 3*sizeof(u32); | ||
40 | output.pointer = &out_obj; | ||
41 | |||
42 | /* Setting up input parameters */ | ||
43 | input.count = 4; | ||
44 | input.pointer = in_params; | ||
45 | in_params[0].type = ACPI_TYPE_BUFFER; | ||
46 | in_params[0].buffer.length = 16; | ||
47 | in_params[0].buffer.pointer = OSC_UUID; | ||
48 | in_params[1].type = ACPI_TYPE_INTEGER; | ||
49 | in_params[1].integer.value = 1; | ||
50 | in_params[2].type = ACPI_TYPE_INTEGER; | ||
51 | in_params[2].integer.value = 3; | ||
52 | in_params[3].type = ACPI_TYPE_BUFFER; | ||
53 | in_params[3].buffer.length = 12; | ||
54 | in_params[3].buffer.pointer = (u8 *)context; | ||
55 | |||
56 | status = acpi_evaluate_object(handle, "_OSC", &input, &output); | ||
57 | if (ACPI_FAILURE (status)) { | ||
58 | printk(KERN_DEBUG | ||
59 | "Evaluate _OSC Set fails. Status = 0x%04x\n", status); | ||
60 | return status; | ||
61 | } | ||
62 | if (out_obj.type != ACPI_TYPE_BUFFER) { | ||
63 | printk(KERN_DEBUG | ||
64 | "Evaluate _OSC returns wrong type\n"); | ||
65 | return AE_TYPE; | ||
66 | } | ||
67 | osc_dw0 = *((u32 *) out_obj.buffer.pointer); | ||
68 | if (osc_dw0) { | ||
69 | if (osc_dw0 & OSC_REQUEST_ERROR) | ||
70 | printk(KERN_DEBUG "_OSC request fails\n"); | ||
71 | if (osc_dw0 & OSC_INVALID_UUID_ERROR) | ||
72 | printk(KERN_DEBUG "_OSC invalid UUID\n"); | ||
73 | if (osc_dw0 & OSC_INVALID_REVISION_ERROR) | ||
74 | printk(KERN_DEBUG "_OSC invalid revision\n"); | ||
75 | if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) { | ||
76 | /* Update Global Control Set */ | ||
77 | global_ctrlsets = *((u32 *)(out_obj.buffer.pointer+8)); | ||
78 | return AE_OK; | ||
79 | } | ||
80 | return AE_ERROR; | ||
81 | } | ||
82 | |||
83 | /* Update Global Control Set */ | ||
84 | global_ctrlsets = *((u32 *)(out_obj.buffer.pointer + 8)); | ||
85 | return AE_OK; | ||
86 | } | ||
87 | |||
88 | |||
89 | static acpi_status | ||
90 | acpi_run_osc ( | ||
91 | acpi_handle handle, | ||
92 | u32 level, | ||
93 | void *context, | ||
94 | void **retval ) | ||
95 | { | ||
96 | acpi_status status; | ||
97 | struct acpi_object_list input; | ||
98 | union acpi_object in_params[4]; | ||
99 | struct acpi_buffer output; | ||
100 | union acpi_object out_obj; | ||
101 | u32 osc_dw0; | ||
102 | |||
103 | /* Setting up output buffer */ | ||
104 | output.length = sizeof(out_obj) + 3*sizeof(u32); | ||
105 | output.pointer = &out_obj; | ||
106 | |||
107 | /* Setting up input parameters */ | ||
108 | input.count = 4; | ||
109 | input.pointer = in_params; | ||
110 | in_params[0].type = ACPI_TYPE_BUFFER; | ||
111 | in_params[0].buffer.length = 16; | ||
112 | in_params[0].buffer.pointer = OSC_UUID; | ||
113 | in_params[1].type = ACPI_TYPE_INTEGER; | ||
114 | in_params[1].integer.value = 1; | ||
115 | in_params[2].type = ACPI_TYPE_INTEGER; | ||
116 | in_params[2].integer.value = 3; | ||
117 | in_params[3].type = ACPI_TYPE_BUFFER; | ||
118 | in_params[3].buffer.length = 12; | ||
119 | in_params[3].buffer.pointer = (u8 *)context; | ||
120 | |||
121 | status = acpi_evaluate_object(handle, "_OSC", &input, &output); | ||
122 | if (ACPI_FAILURE (status)) { | ||
123 | printk(KERN_DEBUG | ||
124 | "Evaluate _OSC Set fails. Status = 0x%04x\n", status); | ||
125 | return status; | ||
126 | } | ||
127 | if (out_obj.type != ACPI_TYPE_BUFFER) { | ||
128 | printk(KERN_DEBUG | ||
129 | "Evaluate _OSC returns wrong type\n"); | ||
130 | return AE_TYPE; | ||
131 | } | ||
132 | osc_dw0 = *((u32 *) out_obj.buffer.pointer); | ||
133 | if (osc_dw0) { | ||
134 | if (osc_dw0 & OSC_REQUEST_ERROR) | ||
135 | printk(KERN_DEBUG "_OSC request fails\n"); | ||
136 | if (osc_dw0 & OSC_INVALID_UUID_ERROR) | ||
137 | printk(KERN_DEBUG "_OSC invalid UUID\n"); | ||
138 | if (osc_dw0 & OSC_INVALID_REVISION_ERROR) | ||
139 | printk(KERN_DEBUG "_OSC invalid revision\n"); | ||
140 | if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) { | ||
141 | printk(KERN_DEBUG "_OSC FW not grant req. control\n"); | ||
142 | return AE_SUPPORT; | ||
143 | } | ||
144 | return AE_ERROR; | ||
145 | } | ||
146 | return AE_OK; | ||
147 | } | ||
148 | |||
149 | /** | ||
150 | * pci_osc_support_set - register OS support to Firmware | ||
151 | * @flags: OS support bits | ||
152 | * | ||
153 | * Update OS support fields and doing a _OSC Query to obtain an update | ||
154 | * from Firmware on supported control bits. | ||
155 | **/ | ||
156 | acpi_status pci_osc_support_set(u32 flags) | ||
157 | { | ||
158 | u32 temp; | ||
159 | |||
160 | if (!(flags & OSC_SUPPORT_MASKS)) { | ||
161 | return AE_TYPE; | ||
162 | } | ||
163 | ctrlset_buf[OSC_SUPPORT_TYPE] |= (flags & OSC_SUPPORT_MASKS); | ||
164 | |||
165 | /* do _OSC query for all possible controls */ | ||
166 | temp = ctrlset_buf[OSC_CONTROL_TYPE]; | ||
167 | ctrlset_buf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; | ||
168 | ctrlset_buf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; | ||
169 | acpi_get_devices ( PCI_ROOT_HID_STRING, | ||
170 | acpi_query_osc, | ||
171 | ctrlset_buf, | ||
172 | NULL ); | ||
173 | ctrlset_buf[OSC_QUERY_TYPE] = !OSC_QUERY_ENABLE; | ||
174 | ctrlset_buf[OSC_CONTROL_TYPE] = temp; | ||
175 | return AE_OK; | ||
176 | } | ||
177 | EXPORT_SYMBOL(pci_osc_support_set); | ||
178 | |||
179 | /** | ||
180 | * pci_osc_control_set - commit requested control to Firmware | ||
181 | * @flags: driver's requested control bits | ||
182 | * | ||
183 | * Attempt to take control from Firmware on requested control bits. | ||
184 | **/ | ||
185 | acpi_status pci_osc_control_set(u32 flags) | ||
186 | { | ||
187 | acpi_status status; | ||
188 | u32 ctrlset; | ||
189 | |||
190 | ctrlset = (flags & OSC_CONTROL_MASKS); | ||
191 | if (!ctrlset) { | ||
192 | return AE_TYPE; | ||
193 | } | ||
194 | if (ctrlset_buf[OSC_SUPPORT_TYPE] && | ||
195 | ((global_ctrlsets & ctrlset) != ctrlset)) { | ||
196 | return AE_SUPPORT; | ||
197 | } | ||
198 | ctrlset_buf[OSC_CONTROL_TYPE] |= ctrlset; | ||
199 | status = acpi_get_devices ( PCI_ROOT_HID_STRING, | ||
200 | acpi_run_osc, | ||
201 | ctrlset_buf, | ||
202 | NULL ); | ||
203 | if (ACPI_FAILURE (status)) { | ||
204 | ctrlset_buf[OSC_CONTROL_TYPE] &= ~ctrlset; | ||
205 | } | ||
206 | |||
207 | return status; | ||
208 | } | ||
209 | EXPORT_SYMBOL(pci_osc_control_set); | ||