]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/pci/hotplug/acpi_pcihp.c
Merge branch 'bzip2-lzma-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-omap-h63xx.git] / drivers / pci / hotplug / acpi_pcihp.c
index 2c981cbb0719c61f6faed445719c5f48f4d523cf..fbc63d5e459fd4182f35f5beffc9bee1a875c8d8 100644 (file)
@@ -30,9 +30,8 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
+#include <linux/acpi.h>
 #include <linux/pci-acpi.h>
-#include <acpi/acpi.h>
-#include <acpi/acpi_bus.h>
 
 #define MY_NAME        "acpi_pcihp"
 
@@ -333,19 +332,14 @@ acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus,
 {
        acpi_status status = AE_NOT_FOUND;
        acpi_handle handle, phandle;
-       struct pci_bus *pbus = bus;
-       struct pci_dev *pdev;
-
-       do {
-               pdev = pbus->self;
-               if (!pdev) {
-                       handle = acpi_get_pci_rootbridge_handle(
-                               pci_domain_nr(pbus), pbus->number);
+       struct pci_bus *pbus;
+
+       handle = NULL;
+       for (pbus = bus; pbus; pbus = pbus->parent) {
+               handle = acpi_pci_get_bridge_handle(pbus);
+               if (handle)
                        break;
-               }
-               handle = DEVICE_ACPI_HANDLE(&(pdev->dev));
-               pbus = pbus->parent;
-       } while (!handle);
+       }
 
        /*
         * _HPP settings apply to all child buses, until another _HPP is
@@ -378,12 +372,10 @@ EXPORT_SYMBOL_GPL(acpi_get_hp_params_from_firmware);
  *
  * Attempt to take hotplug control from firmware.
  */
-int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags)
+int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags)
 {
        acpi_status status;
        acpi_handle chandle, handle;
-       struct pci_dev *pdev = dev;
-       struct pci_bus *parent;
        struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };
 
        flags &= (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |
@@ -408,33 +400,25 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags)
                acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
                dbg("Trying to get hotplug control for %s\n",
                                (char *)string.pointer);
-               status = pci_osc_control_set(handle, flags);
+               status = acpi_pci_osc_control_set(handle, flags);
                if (ACPI_SUCCESS(status))
                        goto got_one;
                kfree(string.pointer);
                string = (struct acpi_buffer){ ACPI_ALLOCATE_BUFFER, NULL };
        }
 
-       pdev = dev;
-       handle = DEVICE_ACPI_HANDLE(&dev->dev);
-       while (!handle) {
+       handle = DEVICE_ACPI_HANDLE(&pdev->dev);
+       if (!handle) {
                /*
                 * This hotplug controller was not listed in the ACPI name
                 * space at all. Try to get acpi handle of parent pci bus.
                 */
-               if (!pdev || !pdev->bus->parent)
-                       break;
-               parent = pdev->bus->parent;
-               dbg("Could not find %s in acpi namespace, trying parent\n",
-                   pci_name(pdev));
-               if (!parent->self)
-                       /* Parent must be a host bridge */
-                       handle = acpi_get_pci_rootbridge_handle(
-                                       pci_domain_nr(parent),
-                                       parent->number);
-               else
-                       handle = DEVICE_ACPI_HANDLE(&(parent->self->dev));
-               pdev = parent->self;
+               struct pci_bus *pbus;
+               for (pbus = pdev->bus; pbus; pbus = pbus->parent) {
+                       handle = acpi_pci_get_bridge_handle(pbus);
+                       if (handle)
+                               break;
+               }
        }
 
        while (handle) {
@@ -453,13 +437,13 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags)
        }
 
        dbg("Cannot get control of hotplug hardware for pci %s\n",
-           pci_name(dev));
+           pci_name(pdev));
 
        kfree(string.pointer);
        return -ENODEV;
 got_one:
-       dbg("Gained control for hotplug HW for pci %s (%s)\n", pci_name(dev),
-                       (char *)string.pointer);
+       dbg("Gained control for hotplug HW for pci %s (%s)\n",
+           pci_name(pdev), (char *)string.pointer);
        kfree(string.pointer);
        return 0;
 }
@@ -500,5 +484,74 @@ int acpi_root_bridge(acpi_handle handle)
 }
 EXPORT_SYMBOL_GPL(acpi_root_bridge);
 
+
+static int is_ejectable(acpi_handle handle)
+{
+       acpi_status status;
+       acpi_handle tmp;
+       unsigned long long removable;
+       status = acpi_get_handle(handle, "_ADR", &tmp);
+       if (ACPI_FAILURE(status))
+               return 0;
+       status = acpi_get_handle(handle, "_EJ0", &tmp);
+       if (ACPI_SUCCESS(status))
+               return 1;
+       status = acpi_evaluate_integer(handle, "_RMV", NULL, &removable);
+       if (ACPI_SUCCESS(status) && removable)
+               return 1;
+       return 0;
+}
+
+/**
+ * acpi_pcihp_check_ejectable - check if handle is ejectable ACPI PCI slot
+ * @pbus: the PCI bus of the PCI slot corresponding to 'handle'
+ * @handle: ACPI handle to check
+ *
+ * Return 1 if handle is ejectable PCI slot, 0 otherwise.
+ */
+int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle)
+{
+       acpi_handle bridge_handle, parent_handle;
+
+       if (!(bridge_handle = acpi_pci_get_bridge_handle(pbus)))
+               return 0;
+       if ((ACPI_FAILURE(acpi_get_parent(handle, &parent_handle))))
+               return 0;
+       if (bridge_handle != parent_handle)
+               return 0;
+       return is_ejectable(handle);
+}
+EXPORT_SYMBOL_GPL(acpi_pci_check_ejectable);
+
+static acpi_status
+check_hotplug(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+       int *found = (int *)context;
+       if (is_ejectable(handle)) {
+               *found = 1;
+               return AE_CTRL_TERMINATE;
+       }
+       return AE_OK;
+}
+
+/**
+ * acpi_pci_detect_ejectable - check if the PCI bus has ejectable slots
+ * @pbus - PCI bus to scan
+ *
+ * Returns 1 if the PCI bus has ACPI based ejectable slots, 0 otherwise.
+ */
+int acpi_pci_detect_ejectable(struct pci_bus *pbus)
+{
+       acpi_handle handle;
+       int found = 0;
+
+       if (!(handle = acpi_pci_get_bridge_handle(pbus)))
+               return 0;
+       acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
+                           check_hotplug, (void *)&found, NULL);
+       return found;
+}
+EXPORT_SYMBOL_GPL(acpi_pci_detect_ejectable);
+
 module_param(debug_acpi, bool, 0644);
 MODULE_PARM_DESC(debug_acpi, "Debugging mode for ACPI enabled or not");