diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/glue.c | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp.h | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_core.c | 3 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 11 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehprm_acpi.c | 92 |
5 files changed, 89 insertions, 19 deletions
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 3937adf4e5e5..aa993715d644 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c | |||
@@ -203,6 +203,7 @@ acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus) | |||
203 | acpi_get_devices(PCI_ROOT_HID_STRING, find_pci_rootbridge, &find, NULL); | 203 | acpi_get_devices(PCI_ROOT_HID_STRING, find_pci_rootbridge, &find, NULL); |
204 | return find.handle; | 204 | return find.handle; |
205 | } | 205 | } |
206 | EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle); | ||
206 | 207 | ||
207 | /* Get device's handler per its address under its parent */ | 208 | /* Get device's handler per its address under its parent */ |
208 | struct acpi_find_child { | 209 | struct acpi_find_child { |
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index e1c2cea305f8..e71f78318d6e 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h | |||
@@ -40,6 +40,7 @@ | |||
40 | extern int pciehp_poll_mode; | 40 | extern int pciehp_poll_mode; |
41 | extern int pciehp_poll_time; | 41 | extern int pciehp_poll_time; |
42 | extern int pciehp_debug; | 42 | extern int pciehp_debug; |
43 | extern int pciehp_force; | ||
43 | 44 | ||
44 | /*#define dbg(format, arg...) do { if (pciehp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/ | 45 | /*#define dbg(format, arg...) do { if (pciehp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/ |
45 | #define dbg(format, arg...) do { if (pciehp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0) | 46 | #define dbg(format, arg...) do { if (pciehp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0) |
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 0bfc37325923..8df704860348 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c | |||
@@ -39,6 +39,7 @@ | |||
39 | int pciehp_debug; | 39 | int pciehp_debug; |
40 | int pciehp_poll_mode; | 40 | int pciehp_poll_mode; |
41 | int pciehp_poll_time; | 41 | int pciehp_poll_time; |
42 | int pciehp_force; | ||
42 | struct controller *pciehp_ctrl_list; | 43 | struct controller *pciehp_ctrl_list; |
43 | 44 | ||
44 | #define DRIVER_VERSION "0.4" | 45 | #define DRIVER_VERSION "0.4" |
@@ -52,9 +53,11 @@ MODULE_LICENSE("GPL"); | |||
52 | module_param(pciehp_debug, bool, 0644); | 53 | module_param(pciehp_debug, bool, 0644); |
53 | module_param(pciehp_poll_mode, bool, 0644); | 54 | module_param(pciehp_poll_mode, bool, 0644); |
54 | module_param(pciehp_poll_time, int, 0644); | 55 | module_param(pciehp_poll_time, int, 0644); |
56 | module_param(pciehp_force, bool, 0644); | ||
55 | MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not"); | 57 | MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not"); |
56 | MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); | 58 | MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); |
57 | MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); | 59 | MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); |
60 | MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing"); | ||
58 | 61 | ||
59 | #define PCIE_MODULE_NAME "pciehp" | 62 | #define PCIE_MODULE_NAME "pciehp" |
60 | 63 | ||
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 5c812b858847..2d2539ba7303 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
@@ -1417,9 +1417,14 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1417 | goto abort_free_ctlr; | 1417 | goto abort_free_ctlr; |
1418 | } | 1418 | } |
1419 | 1419 | ||
1420 | rc = get_hp_hw_control_from_firmware(ctrl->pci_dev); | 1420 | if (pciehp_force) { |
1421 | if (rc) | 1421 | dbg("Bypassing BIOS check for pciehp use on %s\n", |
1422 | goto abort_free_ctlr; | 1422 | pci_name(ctrl->pci_dev)); |
1423 | } else { | ||
1424 | rc = get_hp_hw_control_from_firmware(ctrl->pci_dev); | ||
1425 | if (rc) | ||
1426 | goto abort_free_ctlr; | ||
1427 | } | ||
1423 | 1428 | ||
1424 | /* Add this HPC instance into the HPC list */ | 1429 | /* Add this HPC instance into the HPC list */ |
1425 | spin_lock(&list_lock); | 1430 | spin_lock(&list_lock); |
diff --git a/drivers/pci/hotplug/pciehprm_acpi.c b/drivers/pci/hotplug/pciehprm_acpi.c index 5acdae3d52b1..4d013f86b1a5 100644 --- a/drivers/pci/hotplug/pciehprm_acpi.c +++ b/drivers/pci/hotplug/pciehprm_acpi.c | |||
@@ -132,7 +132,7 @@ static acpi_status acpi_run_oshp(acpi_handle handle) | |||
132 | /* run OSHP */ | 132 | /* run OSHP */ |
133 | status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL); | 133 | status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL); |
134 | if (ACPI_FAILURE(status)) { | 134 | if (ACPI_FAILURE(status)) { |
135 | err("%s:%s OSHP fails=0x%x\n", __FUNCTION__, path_name, | 135 | dbg("%s:%s OSHP fails=0x%x\n", __FUNCTION__, path_name, |
136 | status); | 136 | status); |
137 | } else { | 137 | } else { |
138 | dbg("%s:%s OSHP passes\n", __FUNCTION__, path_name); | 138 | dbg("%s:%s OSHP passes\n", __FUNCTION__, path_name); |
@@ -140,32 +140,92 @@ static acpi_status acpi_run_oshp(acpi_handle handle) | |||
140 | return status; | 140 | return status; |
141 | } | 141 | } |
142 | 142 | ||
143 | static int is_root_bridge(acpi_handle handle) | ||
144 | { | ||
145 | acpi_status status; | ||
146 | struct acpi_device_info *info; | ||
147 | struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
148 | int i; | ||
149 | |||
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); | ||
157 | return 1; | ||
158 | } | ||
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); | ||
164 | return 1; | ||
165 | } | ||
166 | } | ||
167 | } | ||
168 | } | ||
169 | return 0; | ||
170 | } | ||
171 | |||
143 | int get_hp_hw_control_from_firmware(struct pci_dev *dev) | 172 | int get_hp_hw_control_from_firmware(struct pci_dev *dev) |
144 | { | 173 | { |
145 | acpi_status status; | 174 | acpi_status status; |
146 | acpi_handle handle = DEVICE_ACPI_HANDLE(&(dev->dev)); | 175 | acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev)); |
176 | struct pci_dev *pdev = dev; | ||
177 | u8 *path_name; | ||
147 | /* | 178 | /* |
148 | * Per PCI firmware specification, we should run the ACPI _OSC | 179 | * Per PCI firmware specification, we should run the ACPI _OSC |
149 | * method to get control of hotplug hardware before using it | 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. | ||
150 | */ | 185 | */ |
151 | status = pci_osc_control_set(handle, | 186 | while (!handle) { |
152 | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL); | ||
153 | |||
154 | /* Fixme: fail native hotplug if _OSC does not exist for root ports */ | ||
155 | if (status == AE_NOT_FOUND) { | ||
156 | /* | 187 | /* |
157 | * Some older BIOS's don't support _OSC but support | 188 | * This hotplug controller was not listed in the ACPI name |
158 | * OSHP to do the same thing | 189 | * space at all. Try to get acpi handle of parent pci bus. |
159 | */ | 190 | */ |
160 | status = acpi_run_oshp(handle); | 191 | if (!pdev || !pdev->bus->parent) |
192 | break; | ||
193 | dbg("Could not find %s in acpi namespace, trying parent\n", | ||
194 | pci_name(pdev)); | ||
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); | ||
200 | else | ||
201 | handle = DEVICE_ACPI_HANDLE( | ||
202 | &(pdev->bus->parent->self->dev)); | ||
203 | pdev = pdev->bus->parent->self; | ||
161 | } | 204 | } |
162 | if (ACPI_FAILURE(status)) { | 205 | |
163 | err("Cannot get control of hotplug hardware\n"); | 206 | while (handle) { |
164 | return -1; | 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); | ||
216 | return 0; | ||
217 | } | ||
218 | if (is_root_bridge(handle)) | ||
219 | break; | ||
220 | chandle = handle; | ||
221 | status = acpi_get_parent(chandle, &handle); | ||
222 | if (ACPI_FAILURE(status)) | ||
223 | break; | ||
165 | } | 224 | } |
166 | 225 | ||
167 | dbg("Sucess getting control of hotplug hardware\n"); | 226 | err("Cannot get control of hotplug hardware for pci %s\n", |
168 | return 0; | 227 | pci_name(dev)); |
228 | return -1; | ||
169 | } | 229 | } |
170 | 230 | ||
171 | void get_hp_params_from_firmware(struct pci_dev *dev, | 231 | void get_hp_params_from_firmware(struct pci_dev *dev, |