Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit abe5430e authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branch 'acpi-pci-hotplug'

* acpi-pci-hotplug: (34 commits)
  ACPI / PM: Hold acpi_scan_lock over system PM transitions
  ACPI / hotplug / PCI: Fix NULL pointer dereference in cleanup_bridge()
  PCI / ACPI: Use dev_dbg() instead of dev_info() in acpi_pci_set_power_state()
  ACPI / hotplug / PCI: Get rid of check_sub_bridges()
  ACPI / hotplug / PCI: Clean up bridge_mutex usage
  ACPI / hotplug / PCI: Redefine enable_device() and disable_device()
  ACPI / hotplug / PCI: Sanitize acpiphp_get_(latch)|(adapter)_status()
  ACPI / hotplug / PCI: Get rid of unused constants in acpiphp.h
  ACPI / hotplug / PCI: Check for new devices on enabled slots
  ACPI / hotplug / PCI: Allow slots without new devices to be rescanned
  ACPI / hotplug / PCI: Do not check SLOT_ENABLED in enable_device()
  ACPI / hotplug / PCI: Do not exectute _PS0 and _PS3 directly
  ACPI / hotplug / PCI: Do not queue up event handling work items in vain
  ACPI / hotplug / PCI: Consolidate slot disabling and ejecting
  ACPI / hotplug / PCI: Drop redundant checks from check_hotplug_bridge()
  ACPI / hotplug / PCI: Rework namespace scanning and trimming routines
  ACPI / hotplug / PCI: Store parent in functions and bus in slots
  ACPI / hotplug / PCI: Drop handle field from struct acpiphp_bridge
  ACPI / hotplug / PCI: Drop handle field from struct acpiphp_func
  ACPI / hotplug / PCI: Embed function struct into struct acpiphp_context
  ...
parents c92f56cb ad07277e
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -210,6 +210,8 @@ static void pcibios_allocate_bridge_resources(struct pci_dev *dev)
		r = &dev->resource[idx];
		if (!r->flags)
			continue;
		if (r->parent)	/* Already allocated */
			continue;
		if (!r->start || pci_claim_resource(dev, idx) < 0) {
			/*
			 * Something is wrong with the region.
@@ -318,6 +320,8 @@ static void pcibios_allocate_dev_rom_resource(struct pci_dev *dev)
	r = &dev->resource[PCI_ROM_RESOURCE];
	if (!r->flags || !r->start)
		return;
	if (r->parent) /* Already allocated */
		return;

	if (pci_claim_resource(dev, PCI_ROM_RESOURCE) < 0) {
		r->end -= r->start;
+9 −5
Original line number Diff line number Diff line
@@ -159,13 +159,17 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
	return AE_OK;
}

void acpi_pci_slot_enumerate(struct pci_bus *bus, acpi_handle handle)
void acpi_pci_slot_enumerate(struct pci_bus *bus)
{
	acpi_handle handle = ACPI_HANDLE(bus->bridge);

	if (handle) {
		mutex_lock(&slot_list_lock);
		acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
				    register_slot, NULL, bus, NULL);
		mutex_unlock(&slot_list_lock);
	}
}

void acpi_pci_slot_remove(struct pci_bus *bus)
{
+24 −15
Original line number Diff line number Diff line
@@ -420,10 +420,21 @@ static void acpi_pm_finish(void)
}

/**
 *	acpi_pm_end - Finish up suspend sequence.
 * acpi_pm_start - Start system PM transition.
 */
static void acpi_pm_start(u32 acpi_state)
{
	acpi_target_sleep_state = acpi_state;
	acpi_sleep_tts_switch(acpi_target_sleep_state);
	acpi_scan_lock_acquire();
}

/**
 * acpi_pm_end - Finish up system PM transition.
 */
static void acpi_pm_end(void)
{
	acpi_scan_lock_release();
	/*
	 * This is necessary in case acpi_pm_finish() is not called during a
	 * failing transition to a sleep state.
@@ -451,21 +462,19 @@ static u32 acpi_suspend_states[] = {
static int acpi_suspend_begin(suspend_state_t pm_state)
{
	u32 acpi_state = acpi_suspend_states[pm_state];
	int error = 0;
	int error;

	error = (nvs_nosave || nvs_nosave_s3) ? 0 : suspend_nvs_alloc();
	if (error)
		return error;

	if (sleep_states[acpi_state]) {
		acpi_target_sleep_state = acpi_state;
		acpi_sleep_tts_switch(acpi_target_sleep_state);
	} else {
		printk(KERN_ERR "ACPI does not support this state: %d\n",
			pm_state);
		error = -ENOSYS;
	if (!sleep_states[acpi_state]) {
		pr_err("ACPI does not support sleep state S%u\n", acpi_state);
		return -ENOSYS;
	}
	return error;

	acpi_pm_start(acpi_state);
	return 0;
}

/**
@@ -631,10 +640,8 @@ static int acpi_hibernation_begin(void)
	int error;

	error = nvs_nosave ? 0 : suspend_nvs_alloc();
	if (!error) {
		acpi_target_sleep_state = ACPI_STATE_S4;
		acpi_sleep_tts_switch(acpi_target_sleep_state);
	}
	if (!error)
		acpi_pm_start(ACPI_STATE_S4);

	return error;
}
@@ -713,8 +720,10 @@ static int acpi_hibernation_begin_old(void)
	if (!error) {
		if (!nvs_nosave)
			error = suspend_nvs_alloc();
		if (!error)
		if (!error) {
			acpi_target_sleep_state = ACPI_STATE_S4;
			acpi_scan_lock_acquire();
		}
	}
	return error;
}
+27 −27
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@
#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)

struct acpiphp_context;
struct acpiphp_bridge;
struct acpiphp_slot;

@@ -59,6 +60,7 @@ struct slot {
	struct hotplug_slot	*hotplug_slot;
	struct acpiphp_slot	*acpi_slot;
	struct hotplug_slot_info info;
	unsigned int sun;	/* ACPI _SUN (Slot User Number) value */
};

static inline const char *slot_name(struct slot *slot)
@@ -75,15 +77,11 @@ struct acpiphp_bridge {
	struct list_head list;
	struct list_head slots;
	struct kref ref;
	acpi_handle handle;

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

	int nr_slots;

	u32 flags;

	/* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */
	struct pci_bus *pci_bus;

@@ -99,15 +97,13 @@ struct acpiphp_bridge {
 */
struct acpiphp_slot {
	struct list_head node;
	struct acpiphp_bridge *bridge;	/* parent */
	struct pci_bus *bus;
	struct list_head funcs;		/* one slot may have different
					   objects (i.e. for each function) */
	struct slot *slot;
	struct mutex crit_sect;

	u8		device;		/* pci device# */

	unsigned long long sun;		/* ACPI _SUN (slot unique number) */
	u32		flags;		/* see below */
};

@@ -119,15 +115,32 @@ struct acpiphp_slot {
 * typically 8 objects per slot (i.e. for each PCI function)
 */
struct acpiphp_func {
	struct acpiphp_slot *slot;	/* parent */
	struct acpiphp_bridge *parent;
	struct acpiphp_slot *slot;

	struct list_head sibling;
	acpi_handle	handle;

	u8		function;	/* pci function# */
	u32		flags;		/* see below */
};

struct acpiphp_context {
	acpi_handle handle;
	struct acpiphp_func func;
	struct acpiphp_bridge *bridge;
	unsigned int refcount;
};

static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func)
{
	return container_of(func, struct acpiphp_context, func);
}

static inline acpi_handle func_to_handle(struct acpiphp_func *func)
{
	return func_to_context(func)->handle;
}

/*
 * struct acpiphp_attention_info - device specific attention registration
 *
@@ -141,45 +154,32 @@ struct acpiphp_attention_info
	struct module *owner;
};

/* PCI bus bridge HID */
#define ACPI_PCI_HOST_HID		"PNP0A03"

/* ACPI _STA method value (ignore bit 4; battery present) */
#define ACPI_STA_ALL			(0x0000000f)

/* bridge flags */
#define BRIDGE_HAS_EJ0		(0x00000001)

/* slot flags */

#define SLOT_POWEREDON		(0x00000001)
#define SLOT_ENABLED		(0x00000002)
#define SLOT_MULTIFUNCTION	(0x00000004)
#define SLOT_ENABLED		(0x00000001)

/* function flags */

#define FUNC_HAS_STA		(0x00000001)
#define FUNC_HAS_EJ0		(0x00000002)
#define FUNC_HAS_PS0		(0x00000010)
#define FUNC_HAS_PS1		(0x00000020)
#define FUNC_HAS_PS2		(0x00000040)
#define FUNC_HAS_PS3		(0x00000080)
#define FUNC_HAS_DCK            (0x00000100)
#define FUNC_HAS_DCK            (0x00000004)

/* function prototypes */

/* acpiphp_core.c */
int acpiphp_register_attention(struct acpiphp_attention_info*info);
int acpiphp_unregister_attention(struct acpiphp_attention_info *info);
int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot);
int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot, unsigned int sun);
void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot);

/* acpiphp_glue.c */
typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);

int acpiphp_enable_slot(struct acpiphp_slot *slot);
int acpiphp_disable_slot(struct acpiphp_slot *slot);
int acpiphp_eject_slot(struct acpiphp_slot *slot);
int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot);
u8 acpiphp_get_power_status(struct acpiphp_slot *slot);
u8 acpiphp_get_attention_status(struct acpiphp_slot *slot);
u8 acpiphp_get_latch_status(struct acpiphp_slot *slot);
+7 −11
Original line number Diff line number Diff line
@@ -155,15 +155,11 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
static int disable_slot(struct hotplug_slot *hotplug_slot)
{
	struct slot *slot = hotplug_slot->private;
	int retval;

	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));

	/* disable the specified slot */
	retval = acpiphp_disable_slot(slot->acpi_slot);
	if (!retval)
		retval = acpiphp_eject_slot(slot->acpi_slot);
	return retval;
	return acpiphp_disable_and_eject_slot(slot->acpi_slot);
}


@@ -290,7 +286,8 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
}

/* callback routine to initialize 'struct slot' for each slot */
int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot,
				  unsigned int sun)
{
	struct slot *slot;
	int retval = -ENOMEM;
@@ -317,12 +314,11 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
	slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);

	acpiphp_slot->slot = slot;
	snprintf(name, SLOT_NAME_SIZE, "%llu", slot->acpi_slot->sun);
	slot->sun = sun;
	snprintf(name, SLOT_NAME_SIZE, "%u", sun);

	retval = pci_hp_register(slot->hotplug_slot,
					acpiphp_slot->bridge->pci_bus,
					acpiphp_slot->device,
					name);
	retval = pci_hp_register(slot->hotplug_slot, acpiphp_slot->bus,
				 acpiphp_slot->device, name);
	if (retval == -EBUSY)
		goto error_hpslot;
	if (retval) {
Loading