diff options
| -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, |
