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); 210