Skip to content

Commit

Permalink
Merge branch 'pci/yinghai-root-bus-hotplug' into next
Browse files Browse the repository at this point in the history
* pci/yinghai-root-bus-hotplug:
  PCI: Put pci_dev in device tree as early as possible
  PCI: Skip attaching driver in device_add()
  PCI: acpiphp: Keep driver loaded even if no slots found
  PCI/ACPI: Print info if host bridge notify handler installation fails
  PCI: acpiphp: Move host bridge hotplug to pci_root.c
  PCI/ACPI: acpiphp: Rename alloc_acpiphp_hp_work() to alloc_acpi_hp_work()
  PCI: Make device create/destroy logic symmetric
  PCI: Fix reference count leak in pci_dev_present()
  PCI: Set pci_dev dev_node early so IOAPIC irq_descs are allocated locally
  PCI: Add root bus children dev's res to fail list
  PCI: acpiphp: Add is_hotplug_bridge detection

Conflicts:
	drivers/pci/pci.h
  • Loading branch information
Bjorn Helgaas committed Jan 27, 2013
2 parents fb45579 + 4f53509 commit 939de1d
Show file tree
Hide file tree
Showing 18 changed files with 274 additions and 219 deletions.
1 change: 1 addition & 0 deletions 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
24 changes: 22 additions & 2 deletions drivers/acpi/osl.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,7 @@ static acpi_osd_handler acpi_irq_handler;
static void *acpi_irq_context;
static struct workqueue_struct *kacpid_wq;
static struct workqueue_struct *kacpi_notify_wq;
struct workqueue_struct *kacpi_hotplug_wq;
EXPORT_SYMBOL(kacpi_hotplug_wq);
static struct workqueue_struct *kacpi_hotplug_wq;

/*
* This list of permanent mappings is for memory that may be accessed from
Expand Down Expand Up @@ -1778,3 +1777,24 @@ void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state,
{
__acpi_os_prepare_sleep = func;
}

void alloc_acpi_hp_work(acpi_handle handle, u32 type, void *context,
void (*func)(struct work_struct *work))
{
struct acpi_hp_work *hp_work;
int ret;

hp_work = kmalloc(sizeof(*hp_work), GFP_KERNEL);
if (!hp_work)
return;

hp_work->handle = handle;
hp_work->type = type;
hp_work->context = context;

INIT_WORK(&hp_work->work, func);
ret = queue_work(kacpi_hotplug_wq, &hp_work->work);
if (!ret)
kfree(hp_work);
}
EXPORT_SYMBOL_GPL(alloc_acpi_hp_work);
130 changes: 130 additions & 0 deletions drivers/acpi/pci_root.c
Original file line number Diff line number Diff line change
Expand Up @@ -655,3 +655,133 @@ 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)
{
acpi_status status;
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);

status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_root, NULL);
if (ACPI_FAILURE(status))
printk(KERN_DEBUG "acpi root: %s notify handler is not installed, exit status: %u\n",
objname, (unsigned int)status);
else
printk(KERN_DEBUG "acpi root: %s notify handler is 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 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;
}
79 changes: 15 additions & 64 deletions drivers/pci/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,68 +161,35 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { }

/**
* pci_bus_add_device - add a single device
* pci_bus_add_device - start driver for a single device
* @dev: device to add
*
* This adds a single pci device to the global
* device list and adds sysfs and procfs entries
* This adds add sysfs entries and start device drivers
*/
int pci_bus_add_device(struct pci_dev *dev)
{
int retval;

pci_fixup_device(pci_fixup_final, dev);

retval = pcibios_add_device(dev);
if (retval)
return retval;

retval = device_add(&dev->dev);
if (retval)
return retval;

dev->is_added = 1;
pci_proc_attach_device(dev);
/*
* Can not put in pci_device_add yet because resources
* are not assigned yet for some devices.
*/
pci_create_sysfs_dev_files(dev);
return 0;
}

/**
* pci_bus_add_child - add a child bus
* @bus: bus to add
*
* This adds sysfs entries for a single bus
*/
int pci_bus_add_child(struct pci_bus *bus)
{
int retval;
dev->match_driver = true;
retval = device_attach(&dev->dev);
WARN_ON(retval < 0);

if (bus->bridge)
bus->dev.parent = bus->bridge;

retval = device_register(&bus->dev);
if (retval)
return retval;

bus->is_added = 1;

/* Create legacy_io and legacy_mem files for this bus */
pci_create_legacy_files(bus);
dev->is_added = 1;

return retval;
return 0;
}

/**
* pci_bus_add_devices - insert newly discovered PCI devices
* pci_bus_add_devices - start driver for PCI devices
* @bus: bus to check for new devices
*
* Add newly discovered PCI devices (which are on the bus->devices
* list) to the global PCI device list, add the sysfs and procfs
* entries. Where a bridge is found, add the discovered bus to
* the parents list of child buses, and recurse (breadth-first
* to be compatible with 2.4)
*
* Call hotplug for each new devices.
* Start driver for PCI devices and add some sysfs entries.
*/
void pci_bus_add_devices(const struct pci_bus *bus)
{
Expand All @@ -235,36 +202,20 @@ void pci_bus_add_devices(const struct pci_bus *bus)
if (dev->is_added)
continue;
retval = pci_bus_add_device(dev);
if (retval)
dev_err(&dev->dev, "Error adding device, continuing\n");
}

list_for_each_entry(dev, &bus->devices, bus_list) {
BUG_ON(!dev->is_added);

child = dev->subordinate;
/*
* If there is an unattached subordinate bus, attach
* it and then scan for unattached PCI devices.
*/

if (!child)
continue;
if (list_empty(&child->node)) {
down_write(&pci_bus_sem);
list_add_tail(&child->node, &dev->bus->children);
up_write(&pci_bus_sem);
}
pci_bus_add_devices(child);

/*
* register the bus with sysfs as the parent is now
* properly registered.
*/
if (child->is_added)
continue;
retval = pci_bus_add_child(child);
if (retval)
dev_err(&dev->dev, "Error adding bus, continuing\n");
child->is_added = 1;
}
}

Expand Down
1 change: 0 additions & 1 deletion drivers/pci/hotplug/acpiphp.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,6 @@ extern void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot);
/* acpiphp_glue.c */
extern int acpiphp_glue_init (void);
extern void acpiphp_glue_exit (void);
extern int acpiphp_get_num_slots (void);
typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);

extern int acpiphp_enable_slot (struct acpiphp_slot *slot);
Expand Down
23 changes: 2 additions & 21 deletions drivers/pci/hotplug/acpiphp_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
bool acpiphp_debug;

/* local variables */
static int num_slots;
static struct acpiphp_attention_info *attention_info;

#define DRIVER_VERSION "0.5"
Expand Down Expand Up @@ -272,25 +271,6 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
return 0;
}

static int __init init_acpi(void)
{
int retval;

/* initialize internal data structure etc. */
retval = acpiphp_glue_init();

/* read initial number of slots */
if (!retval) {
num_slots = acpiphp_get_num_slots();
if (num_slots == 0) {
acpiphp_glue_exit();
retval = -ENODEV;
}
}

return retval;
}

/**
* release_slot - free up the memory used by a slot
* @hotplug_slot: slot to free
Expand Down Expand Up @@ -379,7 +359,8 @@ static int __init acpiphp_init(void)
return 0;

/* read all the ACPI info from the system */
return init_acpi();
/* initialize internal data structure etc. */
return acpiphp_glue_init();
}


Expand Down
Loading

0 comments on commit 939de1d

Please sign in to comment.