aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug
diff options
context:
space:
mode:
authorrajesh.shah@intel.com <rajesh.shah@intel.com>2005-10-31 19:20:12 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2005-11-10 19:09:15 -0500
commita3a45ec8f8edaf088449e37fe81c99cbf580b9bd (patch)
treea6aaadb26ee068609b9520755e58a0fcdff588fd /drivers/pci/hotplug
parent427bf532b5ad6db5addc2bce675d13f874397c0c (diff)
[PATCH] pciehp: clean-up how we request control of hotplug hardware
This patch further tweaks how we request control of hotplug controller hardware from BIOS. We first search the ACPI namespace corresponding to a specific hotplug controller looking for an _OSC or OSHP method. On failure, we successively move to the ACPI parent object, till we hit the highest level host bridge in the hierarchy. This allows for different types of BIOS's which place the _OSC/OSHP methods at various places in the acpi namespace, while still not encroaching on the namespace of some other root level host bridge. This patch also introduces a new load time option (pciehp_force) that allows us to bypass all _OSC/OSHP checking. Not supporting these methods seems to be be the most common ACPI firmware problem we've run into. This will still _not_ allow the pciehp driver to work correctly if the BIOS really doesn't support pciehp (i.e. if it doesn't generate a hotplug interrupt). Use this option with caution. Some BIOS's may deliberately not build any _OSC/OSHP methods to make sure it retains control the hotplug hardware. Using the pciehp_force parameter for such systems can lead to two separate entities trying to control the same hardware. Signed-off-by: Rajesh Shah <rajesh.shah@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci/hotplug')
-rw-r--r--drivers/pci/hotplug/pciehp.h1
-rw-r--r--drivers/pci/hotplug/pciehp_core.c3
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c11
-rw-r--r--drivers/pci/hotplug/pciehprm_acpi.c92
4 files changed, 88 insertions, 19 deletions
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 @@
40extern int pciehp_poll_mode; 40extern int pciehp_poll_mode;
41extern int pciehp_poll_time; 41extern int pciehp_poll_time;
42extern int pciehp_debug; 42extern int pciehp_debug;
43extern 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 @@
39int pciehp_debug; 39int pciehp_debug;
40int pciehp_poll_mode; 40int pciehp_poll_mode;
41int pciehp_poll_time; 41int pciehp_poll_time;
42int pciehp_force;
42struct controller *pciehp_ctrl_list; 43struct 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");
52module_param(pciehp_debug, bool, 0644); 53module_param(pciehp_debug, bool, 0644);
53module_param(pciehp_poll_mode, bool, 0644); 54module_param(pciehp_poll_mode, bool, 0644);
54module_param(pciehp_poll_time, int, 0644); 55module_param(pciehp_poll_time, int, 0644);
56module_param(pciehp_force, bool, 0644);
55MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not"); 57MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not");
56MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); 58MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not");
57MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); 59MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
60MODULE_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
143static 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
143int get_hp_hw_control_from_firmware(struct pci_dev *dev) 172int 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
171void get_hp_params_from_firmware(struct pci_dev *dev, 231void get_hp_params_from_firmware(struct pci_dev *dev,