Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 28251
b: refs/heads/master
c: 551bcb7
h: refs/heads/master
i:
  28249: f7589f9
  28247: 1507114
v: v3
  • Loading branch information
MUNEDA Takahiro authored and Greg Kroah-Hartman committed Jun 19, 2006
1 parent 29ff9ea commit abc161b
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 10 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 92c9be95549632da09088320f202fa5c05b21ddf
refs/heads/master: 551bcb75b3d9f23348a524210ccfff26d865e425
5 changes: 5 additions & 0 deletions trunk/drivers/pci/hotplug/acpiphp.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ struct acpiphp_bridge {
struct list_head list;
acpi_handle handle;
struct acpiphp_slot *slots;

/* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */
struct acpiphp_func *func;

int type;
int nr_slots;

Expand Down Expand Up @@ -122,6 +126,7 @@ struct acpiphp_slot {
*/
struct acpiphp_func {
struct acpiphp_slot *slot; /* parent */
struct acpiphp_bridge *bridge; /* Ejectable PCI-to-PCI bridge */

struct list_head sibling;
struct pci_dev *pci_dev;
Expand Down
126 changes: 117 additions & 9 deletions trunk/drivers/pci/hotplug/acpiphp_glue.c
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,13 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)

/* install notify handler */
if (bridge->type != BRIDGE_TYPE_HOST) {
if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
status = acpi_remove_notify_handler(bridge->func->handle,
ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_func);
if (ACPI_FAILURE(status))
err("failed to remove notify handler\n");
}
status = acpi_install_notify_handler(bridge->handle,
ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_bridge,
Expand All @@ -331,6 +338,66 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)
}


/* find acpiphp_func from acpiphp_bridge */
static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle)
{
struct list_head *node, *l;
struct acpiphp_bridge *bridge;
struct acpiphp_slot *slot;
struct acpiphp_func *func;

list_for_each(node, &bridge_list) {
bridge = list_entry(node, struct acpiphp_bridge, list);
for (slot = bridge->slots; slot; slot = slot->next) {
list_for_each(l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func,
sibling);
if (func->handle == handle)
return func;
}
}
}

return NULL;
}


static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge)
{
acpi_handle dummy_handle;

if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
"_STA", &dummy_handle)))
bridge->flags |= BRIDGE_HAS_STA;

if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
"_EJ0", &dummy_handle)))
bridge->flags |= BRIDGE_HAS_EJ0;

if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
"_PS0", &dummy_handle)))
bridge->flags |= BRIDGE_HAS_PS0;

if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
"_PS3", &dummy_handle)))
bridge->flags |= BRIDGE_HAS_PS3;

/* is this ejectable p2p bridge? */
if (bridge->flags & BRIDGE_HAS_EJ0) {
struct acpiphp_func *func;

dbg("found ejectable p2p bridge\n");

/* make link between PCI bridge and PCI function */
func = acpiphp_bridge_handle_to_function(bridge->handle);
if (!func)
return;
bridge->func = func;
func->bridge = bridge;
}
}


/* allocate and initialize host bridge data structure */
static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus)
{
Expand Down Expand Up @@ -364,6 +431,7 @@ static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev)

bridge->type = BRIDGE_TYPE_P2P;
bridge->handle = handle;
config_p2p_bridge_flags(bridge);

bridge->pci_dev = pci_dev_get(pci_dev);
bridge->pci_bus = pci_dev->subordinate;
Expand Down Expand Up @@ -423,7 +491,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
find_p2p_bridge, dev->subordinate, NULL);
if (ACPI_FAILURE(status))
warn("find_p2p_bridge faied (error code = 0x%x)\n", status);
warn("find_p2p_bridge failed (error code = 0x%x)\n", status);

out:
pci_dev_put(dev);
Expand Down Expand Up @@ -486,7 +554,7 @@ static int add_bridge(acpi_handle handle)
find_p2p_bridge, pci_bus, NULL);

if (ACPI_FAILURE(status))
warn("find_p2p_bridge faied (error code = 0x%x)\n",status);
warn("find_p2p_bridge failed (error code = 0x%x)\n", status);

return 0;
}
Expand Down Expand Up @@ -516,6 +584,16 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
if (ACPI_FAILURE(status))
err("failed to remove notify handler\n");

if ((bridge->type != BRIDGE_TYPE_HOST) &&
((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)) {
status = acpi_install_notify_handler(bridge->func->handle,
ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_func,
bridge->func);
if (ACPI_FAILURE(status))
err("failed to install interrupt notify handler\n");
}

slot = bridge->slots;
while (slot) {
struct acpiphp_slot *next = slot->next;
Expand Down Expand Up @@ -549,6 +627,11 @@ cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
{
struct acpiphp_bridge *bridge;

/* cleanup p2p bridges under this P2P bridge
in a depth-first manner */
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
cleanup_p2p_bridge, NULL, NULL);

if (!(bridge = acpiphp_handle_to_bridge(handle)))
return AE_OK;
cleanup_bridge(bridge);
Expand All @@ -559,15 +642,14 @@ static void remove_bridge(acpi_handle handle)
{
struct acpiphp_bridge *bridge;

/* cleanup p2p bridges under this host bridge
in a depth-first manner */
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
(u32)1, cleanup_p2p_bridge, NULL, NULL);

bridge = acpiphp_handle_to_bridge(handle);
if (bridge) {
if (bridge)
cleanup_bridge(bridge);
} else {
/* clean-up p2p bridges under this host bridge */
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
ACPI_UINT32_MAX, cleanup_p2p_bridge,
NULL, NULL);
}
}

static struct pci_dev * get_apic_pci_info(acpi_handle handle)
Expand Down Expand Up @@ -881,6 +963,7 @@ static int enable_device(struct acpiphp_slot *slot)
struct acpiphp_func *func;
int retval = 0;
int num, max, pass;
acpi_status status;

if (slot->flags & SLOT_ENABLED)
goto err_exit;
Expand Down Expand Up @@ -933,6 +1016,17 @@ static int enable_device(struct acpiphp_slot *slot)
func = list_entry(l, struct acpiphp_func, sibling);
func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device,
func->function));
if (!func->pci_dev)
continue;

if (func->pci_dev->hdr_type != PCI_HEADER_TYPE_BRIDGE &&
func->pci_dev->hdr_type != PCI_HEADER_TYPE_CARDBUS)
continue;

status = find_p2p_bridge(func->handle, (u32)1, bus, NULL);
if (ACPI_FAILURE(status))
warn("find_p2p_bridge failed (error code = 0x%x)\n",
status);
}

slot->flags |= SLOT_ENABLED;
Expand All @@ -958,6 +1052,13 @@ static int disable_device(struct acpiphp_slot *slot)
list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling);

if (func->bridge) {
/* cleanup p2p bridges under this P2P bridge */
cleanup_p2p_bridge(func->bridge->handle,
(u32)1, NULL, NULL);
func->bridge = NULL;
}

acpiphp_bus_trim(func->handle);
/* try to remove anyway.
* acpiphp_bus_add might have been failed */
Expand Down Expand Up @@ -1292,6 +1393,13 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
case ACPI_NOTIFY_EJECT_REQUEST:
/* request device eject */
dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
if ((bridge->type != BRIDGE_TYPE_HOST) &&
(bridge->flags & BRIDGE_HAS_EJ0)) {
struct acpiphp_slot *slot;
slot = bridge->func->slot;
if (!acpiphp_disable_slot(slot))
acpiphp_eject_slot(slot);
}
break;

case ACPI_NOTIFY_FREQUENCY_MISMATCH:
Expand Down

0 comments on commit abc161b

Please sign in to comment.