[PATCH] acpiphp - slot management fix - V4
[safe/jmp/linux-2.6] / drivers / pci / hotplug / shpchprm_acpi.c
index 3d2f9c5..17145e5 100644 (file)
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/acpi.h>
-#include <linux/efi.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
 #include <acpi/acpi.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/actypes.h>
 #include "shpchp.h"
-#include "shpchprm.h"
-
-#define        PCI_MAX_BUS             0x100
-#define        ACPI_STA_DEVICE_PRESENT 0x01
 
 #define        METHOD_NAME__SUN        "_SUN"
 #define        METHOD_NAME__HPP        "_HPP"
 #define        METHOD_NAME_OSHP        "OSHP"
 
-#define        PHP_RES_BUS             0xA0
-#define        PHP_RES_IO              0xA1
-#define        PHP_RES_MEM             0xA2
-#define        PHP_RES_PMEM            0xA3
-
-#define        BRIDGE_TYPE_P2P         0x00
-#define        BRIDGE_TYPE_HOST        0x01
-
-/* this should go to drivers/acpi/include/ */
-struct acpi__hpp {
-       u8      cache_line_size;
-       u8      latency_timer;
-       u8      enable_serr;
-       u8      enable_perr;
-};
-
-struct acpi_php_slot {
-       struct acpi_php_slot    *next;
-       struct acpi_bridge      *bridge;
-       acpi_handle             handle;
-       int     seg;
-       int     bus;
-       int     dev;
-       int     fun;
-       u32     sun;
-       void    *slot_ops;      /* _STA, _EJx, etc */
-       struct slot *slot;
-};             /* per func */
-
-struct acpi_bridge {
-       struct acpi_bridge      *parent;
-       struct acpi_bridge      *next;
-       struct acpi_bridge      *child;
-       acpi_handle     handle;
-       int seg;
-       int pbus;                               /* pdev->bus->number            */
-       int pdevice;                            /* PCI_SLOT(pdev->devfn)        */
-       int pfunction;                          /* PCI_DEVFN(pdev->devfn)       */
-       int bus;                                /* pdev->subordinate->number    */
-       struct acpi__hpp                *_hpp;
-       struct acpi_php_slot    *slots;
-       int scanned;
-       int type;
-};
-
-static struct acpi_bridge *acpi_bridges_head;
-
 static u8 * acpi_path_name( acpi_handle        handle)
 {
        acpi_status             status;
@@ -109,82 +52,43 @@ static u8 * acpi_path_name( acpi_handle    handle)
                return path_name;       
 }
 
-static void acpi_get__hpp ( struct acpi_bridge *ab);
-static void acpi_run_oshp ( struct acpi_bridge *ab);
-
-static int acpi_add_slot_to_php_slots(
-       struct acpi_bridge      *ab,
-       int                             bus_num,
-       acpi_handle             handle,
-       u32                             adr,
-       u32                             sun
-       )
-{
-       struct acpi_php_slot    *aps;
-       static long     samesun = -1;
-
-       aps = (struct acpi_php_slot *) kmalloc (sizeof(struct acpi_php_slot), GFP_KERNEL);
-       if (!aps) {
-               err ("acpi_shpchprm: alloc for aps fail\n");
-               return -1;
-       }
-       memset(aps, 0, sizeof(struct acpi_php_slot));
-
-       aps->handle = handle;
-       aps->bus = bus_num;
-       aps->dev = (adr >> 16) & 0xffff;
-       aps->fun = adr & 0xffff;
-       aps->sun = sun;
-
-       aps->next = ab->slots;  /* cling to the bridge */
-       aps->bridge = ab;
-       ab->slots = aps;
-
-       ab->scanned += 1;
-       if (!ab->_hpp)
-               acpi_get__hpp(ab);
-
-       acpi_run_oshp(ab);
-
-       if (sun != samesun) {
-               info("acpi_shpchprm:   Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n", aps->sun, ab->seg, 
-                       aps->bus, aps->dev, aps->fun);
-               samesun = sun;
-       }
-       return 0;
-}
-
-static void acpi_get__hpp ( struct acpi_bridge *ab)
+static acpi_status
+acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
 {
        acpi_status             status;
        u8                      nui[4];
        struct acpi_buffer      ret_buf = { 0, NULL};
        union acpi_object       *ext_obj, *package;
-       u8                      *path_name = acpi_path_name(ab->handle);
+       u8                      *path_name = acpi_path_name(handle);
        int                     i, len = 0;
 
        /* get _hpp */
-       status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf);
+       status = acpi_evaluate_object(handle, METHOD_NAME__HPP, NULL, &ret_buf);
        switch (status) {
        case AE_BUFFER_OVERFLOW:
                ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL);
                if (!ret_buf.pointer) {
-                       err ("acpi_shpchprm:%s alloc for _HPP fail\n", path_name);
-                       return;
+                       err ("%s:%s alloc for _HPP fail\n", __FUNCTION__,
+                                       path_name);
+                       return AE_NO_MEMORY;
                }
-               status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf);
+               status = acpi_evaluate_object(handle, METHOD_NAME__HPP,
+                               NULL, &ret_buf);
                if (ACPI_SUCCESS(status))
                        break;
        default:
                if (ACPI_FAILURE(status)) {
-                       err("acpi_shpchprm:%s _HPP fail=0x%x\n", path_name, status);
-                       return;
+                       dbg("%s:%s _HPP fail=0x%x\n", __FUNCTION__,
+                                       path_name, status);
+                       return status;
                }
        }
 
        ext_obj = (union acpi_object *) ret_buf.pointer;
        if (ext_obj->type != ACPI_TYPE_PACKAGE) {
-               err ("acpi_shpchprm:%s _HPP obj not a package\n", path_name);
+               err ("%s:%s _HPP obj not a package\n", __FUNCTION__,
+                               path_name);
+               status = AE_ERROR;
                goto free_and_return;
        }
 
@@ -197,553 +101,41 @@ static void acpi_get__hpp ( struct acpi_bridge   *ab)
                        nui[i] = (u8)ext_obj->integer.value;
                        break;
                default:
-                       err ("acpi_shpchprm:%s _HPP obj type incorrect\n", path_name);
+                       err ("%s:%s _HPP obj type incorrect\n", __FUNCTION__,
+                                       path_name);
+                       status = AE_ERROR;
                        goto free_and_return;
                }
        }
 
-       ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL);
-       if (!ab->_hpp) {
-               err ("acpi_shpchprm:%s alloc for _HPP failed\n", path_name);
-               goto free_and_return;
-       }
-       memset(ab->_hpp, 0, sizeof(struct acpi__hpp));
-
-       ab->_hpp->cache_line_size       = nui[0];
-       ab->_hpp->latency_timer         = nui[1];
-       ab->_hpp->enable_serr           = nui[2];
-       ab->_hpp->enable_perr           = nui[3];
+       hpp->cache_line_size = nui[0];
+       hpp->latency_timer = nui[1];
+       hpp->enable_serr = nui[2];
+       hpp->enable_perr = nui[3];
 
-       dbg("  _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size);
-       dbg("  _HPP: latency timer  =0x%x\n", ab->_hpp->latency_timer);
-       dbg("  _HPP: enable SERR    =0x%x\n", ab->_hpp->enable_serr);
-       dbg("  _HPP: enable PERR    =0x%x\n", ab->_hpp->enable_perr);
+       dbg("  _HPP: cache_line_size=0x%x\n", hpp->cache_line_size);
+       dbg("  _HPP: latency timer  =0x%x\n", hpp->latency_timer);
+       dbg("  _HPP: enable SERR    =0x%x\n", hpp->enable_serr);
+       dbg("  _HPP: enable PERR    =0x%x\n", hpp->enable_perr);
 
 free_and_return:
        kfree(ret_buf.pointer);
+       return status;
 }
 
-static void acpi_run_oshp ( struct acpi_bridge *ab)
-{
-       acpi_status             status;
-       u8                      *path_name = acpi_path_name(ab->handle);
-
-       /* run OSHP */
-       status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, NULL);
-       if (ACPI_FAILURE(status)) {
-               err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status);
-       } else
-               dbg("acpi_pciehprm:%s OSHP passes =0x%x\n", path_name, status);
-       return;
-}
-
-/* find acpi_bridge downword from ab.  */
-static struct acpi_bridge *
-find_acpi_bridge_by_bus(
-       struct acpi_bridge *ab,
-       int seg,
-       int bus         /* pdev->subordinate->number */
-       )
-{
-       struct acpi_bridge      *lab = NULL;
-
-       if (!ab)
-               return NULL;
-
-       if ((ab->bus == bus) && (ab->seg == seg))
-               return ab;
-
-       if (ab->child)
-               lab = find_acpi_bridge_by_bus(ab->child, seg, bus);
-
-       if (!lab)
-       if (ab->next)
-               lab = find_acpi_bridge_by_bus(ab->next, seg, bus);
-
-       return lab;
-}
-
-/*
- * Build a device tree of ACPI PCI Bridges
- */
-static void shpchprm_acpi_register_a_bridge (
-       struct acpi_bridge      **head,
-       struct acpi_bridge      *pab,   /* parent bridge to which child bridge is added */
-       struct acpi_bridge      *cab    /* child bridge to add */
-       )
-{
-       struct acpi_bridge      *lpab;
-       struct acpi_bridge      *lcab;
-
-       lpab = find_acpi_bridge_by_bus(*head, pab->seg, pab->bus);
-       if (!lpab) {
-               if (!(pab->type & BRIDGE_TYPE_HOST))
-                       warn("PCI parent bridge s:b(%x:%x) not in list.\n", pab->seg, pab->bus);
-               pab->next = *head;
-               *head = pab;
-               lpab = pab;
-       }
-
-       if ((cab->type & BRIDGE_TYPE_HOST) && (pab == cab))
-               return;
-
-       lcab = find_acpi_bridge_by_bus(*head, cab->seg, cab->bus);
-       if (lcab) {
-               if ((pab->bus != lcab->parent->bus) || (lcab->bus != cab->bus))
-                       err("PCI child bridge s:b(%x:%x) in list with diff parent.\n", cab->seg, cab->bus);
-               return;
-       } else
-               lcab = cab;
-
-       lcab->parent = lpab;
-       lcab->next = lpab->child;
-       lpab->child = lcab;
-}
-
-static acpi_status shpchprm_acpi_build_php_slots_callback(
-       acpi_handle     handle,
-       u32             Level,
-       void            *context,
-       void            **retval
-       )
+static void acpi_run_oshp(acpi_handle handle)
 {
-       ulong           bus_num;
-       ulong           seg_num;
-       ulong           sun, adr;
-       ulong           padr = 0;
-       acpi_handle             phandle = NULL;
-       struct acpi_bridge      *pab = (struct acpi_bridge *)context;
-       struct acpi_bridge      *lab;
        acpi_status             status;
        u8                      *path_name = acpi_path_name(handle);
 
-       /* get _SUN */
-       status = acpi_evaluate_integer(handle, METHOD_NAME__SUN, NULL, &sun);
-       switch(status) {
-       case AE_NOT_FOUND:
-               return AE_OK;
-       default:
-               if (ACPI_FAILURE(status)) {
-                       err("acpi_shpchprm:%s _SUN fail=0x%x\n", path_name, status);
-                       return status;
-               }
-       }
-
-       /* get _ADR. _ADR must exist if _SUN exists */
-       status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
-       if (ACPI_FAILURE(status)) {
-               err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status);
-               return status;
-       }
-
-       dbg("acpi_shpchprm:%s sun=0x%08x adr=0x%08x\n", path_name, (u32)sun, (u32)adr);
-
-       status = acpi_get_parent(handle, &phandle);
+       /* run OSHP */
+       status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL);
        if (ACPI_FAILURE(status)) {
-               err("acpi_shpchprm:%s get_parent fail=0x%x\n", path_name, status);
-               return (status);
-       }
-
-       bus_num = pab->bus;
-       seg_num = pab->seg;
-
-       if (pab->bus == bus_num) {
-               lab = pab;
+               err("%s:%s OSHP fails=0x%x\n", __FUNCTION__, path_name,
+                               status);
        } else {
-               dbg("WARN: pab is not parent\n");
-               lab = find_acpi_bridge_by_bus(pab, seg_num, bus_num);
-               if (!lab) {
-                       dbg("acpi_shpchprm: alloc new P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun);
-                       lab = (struct acpi_bridge *)kmalloc(sizeof(struct acpi_bridge), GFP_KERNEL);
-                       if (!lab) {
-                               err("acpi_shpchprm: alloc for ab fail\n");
-                               return AE_NO_MEMORY;
-                       }
-                       memset(lab, 0, sizeof(struct acpi_bridge));
-
-                       lab->handle = phandle;
-                       lab->pbus = pab->bus;
-                       lab->pdevice = (int)(padr >> 16) & 0xffff;
-                       lab->pfunction = (int)(padr & 0xffff);
-                       lab->bus = (int)bus_num;
-                       lab->scanned = 0;
-                       lab->type = BRIDGE_TYPE_P2P;
-
-                       shpchprm_acpi_register_a_bridge (&acpi_bridges_head, pab, lab);
-               } else
-                       dbg("acpi_shpchprm: found P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun);
-       }
-
-       acpi_add_slot_to_php_slots(lab, (int)bus_num, handle, (u32)adr, (u32)sun);
-       return (status);
-}
-
-static int shpchprm_acpi_build_php_slots(
-       struct acpi_bridge      *ab,
-       u32                     depth
-       )
-{
-       acpi_status     status;
-       u8              *path_name = acpi_path_name(ab->handle);
-
-       /* Walk down this pci bridge to get _SUNs if any behind P2P */
-       status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
-                               ab->handle,
-                               depth,
-                               shpchprm_acpi_build_php_slots_callback,
-                               ab,
-                               NULL );
-       if (ACPI_FAILURE(status)) {
-               dbg("acpi_shpchprm:%s walk for _SUN on pci bridge seg:bus(%x:%x) fail=0x%x\n", path_name, ab->seg, ab->bus, status);
-               return -1;
-       }
-
-       return 0;
-}
-
-static void build_a_bridge(
-       struct acpi_bridge      *pab,
-       struct acpi_bridge      *ab
-       )
-{
-       u8              *path_name = acpi_path_name(ab->handle);
-
-       shpchprm_acpi_register_a_bridge (&acpi_bridges_head, pab, ab);
-
-       switch (ab->type) {
-       case BRIDGE_TYPE_HOST:
-               dbg("acpi_shpchprm: Registered PCI HOST Bridge(%02x)    on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n",
-                       ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name);
-               break;
-       case BRIDGE_TYPE_P2P:
-               dbg("acpi_shpchprm: Registered PCI  P2P Bridge(%02x-%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n",
-                       ab->pbus, ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name);
-               break;
-       };
-
-       /* build any immediate PHP slots under this pci bridge */
-       shpchprm_acpi_build_php_slots(ab, 1);
-}
-
-static struct acpi_bridge * add_p2p_bridge(
-       acpi_handle handle,
-       struct acpi_bridge      *pab,   /* parent */
-       ulong   adr
-       )
-{
-       struct acpi_bridge      *ab;
-       struct pci_dev  *pdev;
-       ulong           devnum, funcnum;
-       u8                      *path_name = acpi_path_name(handle);
-
-       ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL);
-       if (!ab) {
-               err("acpi_shpchprm: alloc for ab fail\n");
-               return NULL;
-       }
-       memset(ab, 0, sizeof(struct acpi_bridge));
-
-       devnum = (adr >> 16) & 0xffff;
-       funcnum = adr & 0xffff;
-
-       pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum));
-       if (!pdev || !pdev->subordinate) {
-               err("acpi_shpchprm:%s is not a P2P Bridge\n", path_name);
-               kfree(ab);
-               return NULL;
-       }
-
-       ab->handle = handle;
-       ab->seg = pab->seg;
-       ab->pbus = pab->bus;            /* or pdev->bus->number */
-       ab->pdevice = devnum;           /* or PCI_SLOT(pdev->devfn) */
-       ab->pfunction = funcnum;        /* or PCI_FUNC(pdev->devfn) */
-       ab->bus = pdev->subordinate->number;
-       ab->scanned = 0;
-       ab->type = BRIDGE_TYPE_P2P;
-
-       dbg("acpi_shpchprm: P2P(%x-%x) on pci=b:d:f(%x:%x:%x) acpi=b:d:f(%x:%x:%x) [%s]\n",
-               pab->bus, ab->bus, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
-               pab->bus, (u32)devnum, (u32)funcnum, path_name);
-
-       build_a_bridge(pab, ab);
-
-       return ab;
-}
-
-static acpi_status scan_p2p_bridge(
-       acpi_handle             handle,
-       u32                     Level,
-       void                    *context,
-       void                    **retval
-       )
-{
-       struct acpi_bridge      *pab = (struct acpi_bridge *)context;
-       struct acpi_bridge      *ab;
-       acpi_status             status;
-       ulong           adr = 0;
-       u8                      *path_name = acpi_path_name(handle);
-       ulong           devnum, funcnum;
-       struct pci_dev  *pdev;
-
-       /* get device, function */
-       status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
-       if (ACPI_FAILURE(status)) {
-               if (status != AE_NOT_FOUND)
-                       err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status);
-               return AE_OK;
+               dbg("%s:%s OSHP passes\n", __FUNCTION__, path_name);
        }
-
-       devnum = (adr >> 16) & 0xffff;
-       funcnum = adr & 0xffff;
-
-       pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum));
-       if (!pdev)
-               return AE_OK;
-       if (!pdev->subordinate)
-               return AE_OK;
-
-       ab = add_p2p_bridge(handle, pab, adr);
-       if (ab) {
-               status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
-                                       handle,
-                                       (u32)1,
-                                       scan_p2p_bridge,
-                                       ab,
-                                       NULL);
-               if (ACPI_FAILURE(status))
-                       dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status);
-       }
-
-       return AE_OK;
-}
-
-static struct acpi_bridge * add_host_bridge(
-       acpi_handle handle,
-       ulong   segnum,
-       ulong   busnum
-       )
-{
-       ulong                   adr = 0;
-       acpi_status             status;
-       struct acpi_bridge      *ab;
-       u8                      *path_name = acpi_path_name(handle);
-
-       /* get device, function: host br adr is always 0000 though.  */
-       status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
-       if (ACPI_FAILURE(status)) {
-               err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status);
-               return NULL;
-       }
-       dbg("acpi_shpchprm: ROOT PCI seg(0x%x)bus(0x%x)dev(0x%x)func(0x%x) [%s]\n", (u32)segnum, (u32)busnum, 
-               (u32)(adr >> 16) & 0xffff, (u32)adr & 0xffff, path_name);
-
-       ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL);
-       if (!ab) {
-               err("acpi_shpchprm: alloc for ab fail\n");
-               return NULL;
-       }
-       memset(ab, 0, sizeof(struct acpi_bridge));
-
-       ab->handle = handle;
-       ab->seg = (int)segnum;
-       ab->bus = ab->pbus = (int)busnum;
-       ab->pdevice = (int)(adr >> 16) & 0xffff;
-       ab->pfunction = (int)(adr & 0xffff);
-       ab->scanned = 0;
-       ab->type = BRIDGE_TYPE_HOST;
-
-       build_a_bridge(ab, ab);
-
-       return ab;
-}
-
-static acpi_status acpi_scan_from_root_pci_callback (
-       acpi_handle     handle,
-       u32                     Level,
-       void            *context,
-       void            **retval
-       )
-{
-       ulong           segnum = 0;
-       ulong           busnum = 0;
-       acpi_status             status;
-       struct acpi_bridge      *ab;
-       u8                      *path_name = acpi_path_name(handle);
-
-       /* get bus number of this pci root bridge */
-       status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &segnum);
-       if (ACPI_FAILURE(status)) {
-               if (status != AE_NOT_FOUND) {
-                       err("acpi_shpchprm:%s evaluate _SEG fail=0x%x\n", path_name, status);
-                       return status;
-               }
-               segnum = 0;
-       }
-
-       /* get bus number of this pci root bridge */
-       status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, &busnum);
-       if (ACPI_FAILURE(status)) {
-               err("acpi_shpchprm:%s evaluate _BBN fail=0x%x\n", path_name, status);
-               return (status);
-       }
-
-       ab = add_host_bridge(handle, segnum, busnum);
-       if (ab) {
-               status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
-                                       handle,
-                                       1,
-                                       scan_p2p_bridge,
-                                       ab,
-                                       NULL);
-               if (ACPI_FAILURE(status))
-                       dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status);
-       }
-
-       return AE_OK;
-}
-
-static int shpchprm_acpi_scan_pci (void)
-{
-       acpi_status     status;
-
-       /*
-        * TBD: traverse LDM device tree with the help of
-        *  unified ACPI augmented for php device population.
-        */
-       status = acpi_get_devices ( PCI_ROOT_HID_STRING,
-                               acpi_scan_from_root_pci_callback,
-                               NULL,
-                               NULL );
-       if (ACPI_FAILURE(status)) {
-               err("acpi_shpchprm:get_device PCI ROOT HID fail=0x%x\n", status);
-               return -1;
-       }
-
-       return 0;
-}
-
-int shpchprm_init(enum php_ctlr_type ctlr_type)
-{
-       int     rc;
-
-       if (ctlr_type != PCI)
-               return -ENODEV;
-
-       dbg("shpchprm ACPI init <enter>\n");
-       acpi_bridges_head = NULL;
-
-       /* construct PCI bus:device tree of acpi_handles */
-       rc = shpchprm_acpi_scan_pci();
-       if (rc)
-               return rc;
-
-       dbg("shpchprm ACPI init %s\n", (rc)?"fail":"success");
-       return rc;
-}
-
-static void free_a_slot(struct acpi_php_slot *aps)
-{
-       dbg("        free a php func of slot(0x%02x) on PCI b:d:f=0x%02x:%02x:%02x\n", aps->sun, aps->bus, aps->dev, aps->fun);
-
-       kfree(aps);
-}
-
-static void free_a_bridge( struct acpi_bridge  *ab)
-{
-       struct acpi_php_slot    *aps, *next;
-
-       switch (ab->type) {
-       case BRIDGE_TYPE_HOST:
-               dbg("Free ACPI PCI HOST Bridge(%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n",
-                       ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction);
-               break;
-       case BRIDGE_TYPE_P2P:
-               dbg("Free ACPI PCI P2P Bridge(%x-%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n",
-                       ab->pbus, ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction);
-               break;
-       };
-
-       /* free slots first */
-       for (aps = ab->slots; aps; aps = next) {
-               next = aps->next;
-               free_a_slot(aps);
-       }
-
-       kfree(ab);
-}
-
-static void shpchprm_free_bridges ( struct acpi_bridge *ab)
-{
-       if (!ab)
-               return;
-
-       if (ab->child)
-               shpchprm_free_bridges (ab->child);
-
-       if (ab->next)
-               shpchprm_free_bridges (ab->next);
-
-       free_a_bridge(ab);
-}
-
-void shpchprm_cleanup(void)
-{
-       shpchprm_free_bridges (acpi_bridges_head);
-}
-
-static int get_number_of_slots (
-       struct acpi_bridge      *ab,
-       int                             selfonly
-       )
-{
-       struct acpi_php_slot    *aps;
-       int     prev_slot = -1;
-       int     slot_num = 0;
-
-       for ( aps = ab->slots; aps; aps = aps->next)
-               if (aps->dev != prev_slot) {
-                       prev_slot = aps->dev;
-                       slot_num++;
-               }
-
-       if (ab->child)
-               slot_num += get_number_of_slots (ab->child, 0);
-
-       if (selfonly)
-               return slot_num;
-
-       if (ab->next)
-               slot_num += get_number_of_slots (ab->next, 0);
-
-       return slot_num;
-}
-
-static struct acpi_php_slot * get_acpi_slot (
-       struct acpi_bridge *ab,
-       u32 sun
-       )
-{
-       struct acpi_php_slot    *aps = NULL;
-
-       for ( aps = ab->slots; aps; aps = aps->next)
-               if (aps->sun == sun)
-                       return aps;
-
-       if (!aps && ab->child) {
-               aps = (struct acpi_php_slot *)get_acpi_slot (ab->child, sun);
-               if (aps)
-                       return aps;
-       }
-
-       if (!aps && ab->next) {
-               aps = (struct acpi_php_slot *)get_acpi_slot (ab->next, sun);
-               if (aps)
-                       return aps;
-       }
-
-       return aps;
-
 }
 
 int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum)
@@ -755,108 +147,40 @@ int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn
        return 0;
 }
 
-int shpchprm_set_hpp(
-       struct controller *ctrl,
-       struct pci_func *func,
-       u8      card_type
-       )
+void get_hp_hw_control_from_firmware(struct pci_dev *dev)
 {
-       struct acpi_bridge      *ab;
-       struct pci_bus lpci_bus, *pci_bus;
-       int                             rc = 0;
-       unsigned int    devfn;
-       u8                              cls= 0x08;      /* default cache line size      */
-       u8                              lt = 0x40;      /* default latency timer        */
-       u8                              ep = 0;
-       u8                              es = 0;
-
-       memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
-       pci_bus = &lpci_bus;
-       pci_bus->number = func->bus;
-       devfn = PCI_DEVFN(func->device, func->function);
-
-       ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus);
-
-       if (ab) {
-               if (ab->_hpp) {
-                       lt  = (u8)ab->_hpp->latency_timer;
-                       cls = (u8)ab->_hpp->cache_line_size;
-                       ep  = (u8)ab->_hpp->enable_perr;
-                       es  = (u8)ab->_hpp->enable_serr;
-               } else
-                       dbg("_hpp: no _hpp for B/D/F=%#x/%#x/%#x. use default value\n", func->bus, func->device, func->function);
-       } else
-               dbg("_hpp: no acpi bridge for B/D/F = %#x/%#x/%#x. use default value\n", func->bus, func->device, func->function);
-
-
-       if (card_type == PCI_HEADER_TYPE_BRIDGE) {
-               /* set subordinate Latency Timer */
-               rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, lt);
-       }
-
-       /* set base Latency Timer */
-       rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, lt);
-       dbg("  set latency timer  =0x%02x: %x\n", lt, rc);
-
-       rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, cls);
-       dbg("  set cache_line_size=0x%02x: %x\n", cls, rc);
-
-       return rc;
+       /*
+        * OSHP is an optional ACPI firmware control method. If present,
+        * we need to run it to inform BIOS that we will control SHPC
+        * hardware from now on.
+        */
+       acpi_handle handle = DEVICE_ACPI_HANDLE(&(dev->dev));
+       if (!handle)
+               return;
+       acpi_run_oshp(handle);
 }
 
-void shpchprm_enable_card(
-       struct controller *ctrl,
-       struct pci_func *func,
-       u8 card_type)
+void get_hp_params_from_firmware(struct pci_dev *dev,
+               struct hotplug_params *hpp)
 {
-       u16 command, cmd, bcommand, bcmd;
-       struct pci_bus lpci_bus, *pci_bus;
-       struct acpi_bridge      *ab;
-       unsigned int devfn;
-       int rc;
-
-       memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
-       pci_bus = &lpci_bus;
-       pci_bus->number = func->bus;
-       devfn = PCI_DEVFN(func->device, func->function);
-
-       rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command);
-
-       if (card_type == PCI_HEADER_TYPE_BRIDGE) {
-               rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand);
-       }
-
-       cmd = command  = command | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
-               | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
-       bcmd = bcommand  = bcommand | PCI_BRIDGE_CTL_NO_ISA;
+       acpi_status status = AE_NOT_FOUND;
+       struct pci_dev *pdev = dev;
 
-       ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus);
-       if (ab) {
-               if (ab->_hpp) {
-                       if (ab->_hpp->enable_perr) {
-                               command |= PCI_COMMAND_PARITY;
-                               bcommand |= PCI_BRIDGE_CTL_PARITY;
-                       } else {
-                               command &= ~PCI_COMMAND_PARITY;
-                               bcommand &= ~PCI_BRIDGE_CTL_PARITY;
-                       }
-                       if (ab->_hpp->enable_serr) {
-                               command |= PCI_COMMAND_SERR;
-                               bcommand |= PCI_BRIDGE_CTL_SERR;
-                       } else {
-                               command &= ~PCI_COMMAND_SERR;
-                               bcommand &= ~PCI_BRIDGE_CTL_SERR;
-                       }
-               } else
-                       dbg("no _hpp for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function);
-       } else
-               dbg("no acpi bridge for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function);
-
-       if (command != cmd) {
-               rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
-       }
-       if ((card_type == PCI_HEADER_TYPE_BRIDGE) && (bcommand != bcmd)) {
-               rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
+       /*
+        * _HPP settings apply to all child buses, until another _HPP is
+        * encountered. If we don't find an _HPP for the input pci dev,
+        * look for it in the parent device scope since that would apply to
+        * this pci dev. If we don't find any _HPP, use hardcoded defaults
+        */
+       while (pdev && (ACPI_FAILURE(status))) {
+               acpi_handle handle = DEVICE_ACPI_HANDLE(&(pdev->dev));
+               if (!handle)
+                       break;
+               status = acpi_run_hpp(handle, hpp);
+               if (!(pdev->bus->parent))
+                       break;
+               /* Check if a parent object supports _HPP */
+               pdev = pdev->bus->parent->self;
        }
 }