Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 358414
b: refs/heads/master
c: 668192b
h: refs/heads/master
v: v3
  • Loading branch information
Yinghai Lu authored and Bjorn Helgaas committed Jan 25, 2013
1 parent 491fc65 commit ab82966
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 45 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: 92d8aff3a317fcd6f78ed9ac13dbbaeae8cb11ed
refs/heads/master: 668192b678201d2fff27c6cc76bb003c1ec4a52a
1 change: 1 addition & 0 deletions trunk/drivers/acpi/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ struct acpi_ec {
extern struct acpi_ec *first_ec;

int acpi_pci_root_init(void);
void acpi_pci_root_hp_init(void);
int acpi_ec_init(void);
int acpi_ec_ecdt_probe(void);
int acpi_boot_ec_enable(void);
Expand Down
124 changes: 124 additions & 0 deletions trunk/drivers/acpi/pci_root.c
Original file line number Diff line number Diff line change
Expand Up @@ -673,3 +673,127 @@ int __init acpi_pci_root_init(void)

return 0;
}
/* Support root bridge hotplug */

static void handle_root_bridge_insertion(acpi_handle handle)
{
struct acpi_device *device;

if (!acpi_bus_get_device(handle, &device)) {
printk(KERN_DEBUG "acpi device exists...\n");
return;
}

if (acpi_bus_scan(handle))
printk(KERN_ERR "cannot add bridge to acpi list\n");
}

static void handle_root_bridge_removal(struct acpi_device *device)
{
struct acpi_eject_event *ej_event;

ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
if (!ej_event) {
/* Inform firmware the hot-remove operation has error */
(void) acpi_evaluate_hotplug_ost(device->handle,
ACPI_NOTIFY_EJECT_REQUEST,
ACPI_OST_SC_NON_SPECIFIC_FAILURE,
NULL);
return;
}

ej_event->device = device;
ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;

acpi_bus_hot_remove_device(ej_event);
}

static void _handle_hotplug_event_root(struct work_struct *work)
{
struct acpi_pci_root *root;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER };
struct acpi_hp_work *hp_work;
acpi_handle handle;
u32 type;

hp_work = container_of(work, struct acpi_hp_work, work);
handle = hp_work->handle;
type = hp_work->type;

root = acpi_pci_find_root(handle);

acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);

switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
/* bus enumerate */
printk(KERN_DEBUG "%s: Bus check notify on %s\n", __func__,
(char *)buffer.pointer);
if (!root)
handle_root_bridge_insertion(handle);

break;

case ACPI_NOTIFY_DEVICE_CHECK:
/* device check */
printk(KERN_DEBUG "%s: Device check notify on %s\n", __func__,
(char *)buffer.pointer);
if (!root)
handle_root_bridge_insertion(handle);
break;

case ACPI_NOTIFY_EJECT_REQUEST:
/* request device eject */
printk(KERN_DEBUG "%s: Device eject notify on %s\n", __func__,
(char *)buffer.pointer);
if (root)
handle_root_bridge_removal(root->device);
break;
default:
printk(KERN_WARNING "notify_handler: unknown event type 0x%x for %s\n",
type, (char *)buffer.pointer);
break;
}

kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
kfree(buffer.pointer);
}

static void handle_hotplug_event_root(acpi_handle handle, u32 type,
void *context)
{
alloc_acpi_hp_work(handle, type, context,
_handle_hotplug_event_root);
}

static acpi_status __init
find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
{
char objname[64];
struct acpi_buffer buffer = { .length = sizeof(objname),
.pointer = objname };
int *count = (int *)context;

if (!acpi_is_root_bridge(handle))
return AE_OK;

(*count)++;

acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);

acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_root, NULL);
printk(KERN_DEBUG "acpi root: %s notify handler installed\n", objname);

return AE_OK;
}

void __init acpi_pci_root_hp_init(void)
{
int num = 0;

acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL);

printk(KERN_DEBUG "Found %d acpi root devices\n", num);
}
3 changes: 3 additions & 0 deletions trunk/drivers/acpi/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -1706,5 +1706,8 @@ int __init acpi_scan_init(void)
}

acpi_update_all_gpes();

acpi_pci_root_hp_init();

return 0;
}
59 changes: 15 additions & 44 deletions trunk/drivers/pci/hotplug/acpiphp_glue.c
Original file line number Diff line number Diff line change
Expand Up @@ -543,10 +543,13 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
acpi_status status;
acpi_handle handle = bridge->handle;

status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
if (bridge->type != BRIDGE_TYPE_HOST) {
status = acpi_remove_notify_handler(handle,
ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_bridge);
if (ACPI_FAILURE(status))
err("failed to remove notify handler\n");
if (ACPI_FAILURE(status))
err("failed to remove notify handler\n");
}

if ((bridge->type != BRIDGE_TYPE_HOST) &&
((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)) {
Expand Down Expand Up @@ -630,9 +633,6 @@ static void remove_bridge(struct acpi_pci_root *root)
bridge = acpiphp_handle_to_bridge(handle);
if (bridge)
cleanup_bridge(bridge);
else
acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_bridge);
}

static int power_on_slot(struct acpiphp_slot *slot)
Expand Down Expand Up @@ -1123,18 +1123,12 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus)
}

/* Program resources in newly inserted bridge */
static int acpiphp_configure_bridge (acpi_handle handle)
static int acpiphp_configure_p2p_bridge(acpi_handle handle)
{
struct pci_bus *bus;
struct pci_dev *pdev = acpi_get_pci_dev(handle);
struct pci_bus *bus = pdev->subordinate;

if (acpi_is_root_bridge(handle)) {
struct acpi_pci_root *root = acpi_pci_find_root(handle);
bus = root->bus;
} else {
struct pci_dev *pdev = acpi_get_pci_dev(handle);
bus = pdev->subordinate;
pci_dev_put(pdev);
}
pci_dev_put(pdev);

pci_bus_size_bridges(bus);
pci_bus_assign_resources(bus);
Expand All @@ -1144,7 +1138,7 @@ static int acpiphp_configure_bridge (acpi_handle handle)
return 0;
}

static void handle_bridge_insertion(acpi_handle handle, u32 type)
static void handle_p2p_bridge_insertion(acpi_handle handle, u32 type)
{
struct acpi_device *device;

Expand All @@ -1162,8 +1156,8 @@ static void handle_bridge_insertion(acpi_handle handle, u32 type)
err("ACPI device object missing\n");
return;
}
if (!acpiphp_configure_bridge(handle))
add_bridge(handle);
if (!acpiphp_configure_p2p_bridge(handle))
add_p2p_bridge(handle);
else
err("cannot configure and start bridge\n");

Expand Down Expand Up @@ -1221,7 +1215,7 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)

if (acpi_bus_get_device(handle, &device)) {
/* This bridge must have just been physically inserted */
handle_bridge_insertion(handle, type);
handle_p2p_bridge_insertion(handle, type);
goto out;
}

Expand Down Expand Up @@ -1396,21 +1390,6 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type,
alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func);
}

static acpi_status
find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
{
int *count = (int *)context;

if (!acpi_is_root_bridge(handle))
return AE_OK;

(*count)++;
acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_bridge, NULL);

return AE_OK ;
}

static struct acpi_pci_driver acpi_pci_hp_driver = {
.add = add_bridge,
.remove = remove_bridge,
Expand All @@ -1421,15 +1400,7 @@ static struct acpi_pci_driver acpi_pci_hp_driver = {
*/
int __init acpiphp_glue_init(void)
{
int num = 0;

acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL);

if (num <= 0)
return -1;
else
acpi_pci_register_driver(&acpi_pci_hp_driver);
acpi_pci_register_driver(&acpi_pci_hp_driver);

return 0;
}
Expand Down

0 comments on commit ab82966

Please sign in to comment.