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

Commit c0638a45 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/hotplug'

  - Simplify SHPC existence/permission checks (Bjorn Helgaas)

  - Remove hotplug sample skeleton driver (Lukas Wunner)

  - Convert pciehp to threaded IRQ handling (Lukas Wunner)

  - Improve pciehp tolerance of missed events and initially unstable links
    (Lukas Wunner)

  - Clear spurious pciehp events on resume (Lukas Wunner)

  - Add pciehp runtime PM support, including for Thunderbolt controllers
    (Lukas Wunner)

  - Support interrupts from pciehp bridges in D3hot (Lukas Wunner)

* pci/hotplug:
  PCI: pciehp: Deduplicate presence check on probe & resume
  PCI: pciehp: Avoid implicit fallthroughs in switch statements
  PCI: Whitelist Thunderbolt ports for runtime D3
  PCI: Whitelist native hotplug ports for runtime D3
  PCI: sysfs: Resume to D0 on function reset
  PCI: pciehp: Resume parent to D0 on config space access
  PCI: pciehp: Resume to D0 on enable/disable
  PCI: pciehp: Support interrupts sent from D3hot
  PCI: pciehp: Obey compulsory command delay after resume
  PCI: pciehp: Clear spurious events earlier on resume
  PCI: portdrv: Deduplicate PM callback iterator
  PCI: pciehp: Avoid slot access during reset
  PCI: pciehp: Always enable occupied slot on probe
  PCI: pciehp: Become resilient to missed events
  PCI: pciehp: Tolerate initially unstable link
  PCI: pciehp: Declare pciehp_enable/disable_slot() static
  PCI: pciehp: Drop enable/disable lock
  PCI: pciehp: Enable/disable exclusively from IRQ thread
  PCI: pciehp: Track enable/disable status
  PCI: pciehp: Publish to user space last on probe
  PCI: hotplug: Demidlayer registration with the core
  PCI: pciehp: Drop slot workqueue
  PCI: pciehp: Handle events synchronously
  PCI: pciehp: Stop blinking on slot enable failure
  PCI: pciehp: Convert to threaded polling
  PCI: pciehp: Convert to threaded IRQ
  PCI: pciehp: Document struct slot and struct controller
  PCI: pciehp: Declare pciehp_unconfigure_device() void
  PCI: pciehp: Drop unnecessary NULL pointer check
  PCI: pciehp: Fix unprotected list iteration in IRQ handler
  PCI: pciehp: Fix use-after-free on unplug
  PCI: hotplug: Don't leak pci_slot on registration failure
  PCI: hotplug: Delete skeleton driver
  PCI: shpchp: Separate existence of SHPC and permission to use it
parents a8bcb5e5 4e6a1335
Loading
Loading
Loading
Loading
+19 −17
Original line number Diff line number Diff line
@@ -73,20 +73,6 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev)
	acpi_handle chandle, handle;
	struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };

	/*
	 * Per PCI firmware specification, we should run the ACPI _OSC
	 * method to get control of hotplug hardware before using it. If
	 * an _OSC is missing, we look for an OSHP to do the same thing.
	 * To handle different BIOS behavior, we look for _OSC on a root
	 * bridge preferentially (according to PCI fw spec). Later for
	 * OSHP within the scope of the hotplug controller and its parents,
	 * up to the host bridge under which this controller exists.
	 */
	if (shpchp_is_native(pdev))
		return 0;

	/* If _OSC exists, we should not evaluate OSHP */

	/*
	 * If there's no ACPI host bridge (i.e., ACPI support is compiled
	 * into the kernel but the hardware platform doesn't support ACPI),
@@ -97,9 +83,25 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev)
	if (!root)
		return 0;

	if (root->osc_support_set)
		goto no_control;
	/*
	 * If _OSC exists, it determines whether we're allowed to manage
	 * the SHPC.  We executed it while enumerating the host bridge.
	 */
	if (root->osc_support_set) {
		if (host->native_shpc_hotplug)
			return 0;
		return -ENODEV;
	}

	/*
	 * In the absence of _OSC, we're always allowed to manage the SHPC.
	 * However, if an OSHP method is present, we must execute it so the
	 * firmware can transfer control to the OS, e.g., direct interrupts
	 * to the OS instead of to the firmware.
	 *
	 * N.B. The PCI Firmware Spec (r3.2, sec 4.8) does not endorse
	 * searching up the ACPI hierarchy, so the loops below are suspect.
	 */
	handle = ACPI_HANDLE(&pdev->dev);
	if (!handle) {
		/*
@@ -128,7 +130,7 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev)
		if (ACPI_FAILURE(status))
			break;
	}
no_control:

	pci_info(pdev, "Cannot get control of SHPC hotplug\n");
	kfree(string.pointer);
	return -ENODEV;
+3 −19
Original line number Diff line number Diff line
@@ -254,20 +254,6 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
	return 0;
}

/**
 * release_slot - free up the memory used by a slot
 * @hotplug_slot: slot to free
 */
static void release_slot(struct hotplug_slot *hotplug_slot)
{
	struct slot *slot = hotplug_slot->private;

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

	kfree(slot->hotplug_slot);
	kfree(slot);
}

/* callback routine to initialize 'struct slot' for each slot */
int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot,
				  unsigned int sun)
@@ -287,7 +273,6 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot,
	slot->hotplug_slot->info = &slot->info;

	slot->hotplug_slot->private = slot;
	slot->hotplug_slot->release = &release_slot;
	slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;

	slot->acpi_slot = acpiphp_slot;
@@ -324,13 +309,12 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot,
void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
{
	struct slot *slot = acpiphp_slot->slot;
	int retval = 0;

	pr_info("Slot [%s] unregistered\n", slot_name(slot));

	retval = pci_hp_deregister(slot->hotplug_slot);
	if (retval)
		pr_err("pci_hp_deregister failed with error %d\n", retval);
	pci_hp_deregister(slot->hotplug_slot);
	kfree(slot->hotplug_slot);
	kfree(slot);
}


+4 −10
Original line number Diff line number Diff line
@@ -195,10 +195,8 @@ get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
	return 0;
}

static void release_slot(struct hotplug_slot *hotplug_slot)
static void release_slot(struct slot *slot)
{
	struct slot *slot = hotplug_slot->private;

	kfree(slot->hotplug_slot->info);
	kfree(slot->hotplug_slot);
	pci_dev_put(slot->dev);
@@ -253,7 +251,6 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
		snprintf(name, SLOT_NAME_SIZE, "%02x:%02x", bus->number, i);

		hotplug_slot->private = slot;
		hotplug_slot->release = &release_slot;
		hotplug_slot->ops = &cpci_hotplug_slot_ops;

		/*
@@ -308,12 +305,8 @@ cpci_hp_unregister_bus(struct pci_bus *bus)
			slots--;

			dbg("deregistering slot %s", slot_name(slot));
			status = pci_hp_deregister(slot->hotplug_slot);
			if (status) {
				err("pci_hp_deregister failed with error %d",
				    status);
				break;
			}
			pci_hp_deregister(slot->hotplug_slot);
			release_slot(slot);
		}
	}
	up_write(&list_rwsem);
@@ -623,6 +616,7 @@ cleanup_slots(void)
	list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) {
		list_del(&slot->slot_list);
		pci_hp_deregister(slot->hotplug_slot);
		release_slot(slot);
	}
cleanup_null:
	up_write(&list_rwsem);
+3 −13
Original line number Diff line number Diff line
@@ -266,17 +266,6 @@ static void __iomem *get_SMBIOS_entry(void __iomem *smbios_start,
	return previous;
}

static void release_slot(struct hotplug_slot *hotplug_slot)
{
	struct slot *slot = hotplug_slot->private;

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

	kfree(slot->hotplug_slot->info);
	kfree(slot->hotplug_slot);
	kfree(slot);
}

static int ctrl_slot_cleanup(struct controller *ctrl)
{
	struct slot *old_slot, *next_slot;
@@ -285,9 +274,11 @@ static int ctrl_slot_cleanup(struct controller *ctrl)
	ctrl->slot = NULL;

	while (old_slot) {
		/* memory will be freed by the release_slot callback */
		next_slot = old_slot->next;
		pci_hp_deregister(old_slot->hotplug_slot);
		kfree(old_slot->hotplug_slot->info);
		kfree(old_slot->hotplug_slot);
		kfree(old_slot);
		old_slot = next_slot;
	}

@@ -678,7 +669,6 @@ static int ctrl_slot_setup(struct controller *ctrl,
			((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04;

		/* register this slot with the hotplug pci core */
		hotplug_slot->release = &release_slot;
		hotplug_slot->private = slot;
		snprintf(name, SLOT_NAME_SIZE, "%u", slot->number);
		hotplug_slot->ops = &cpqphp_hotplug_slot_ops;
+14 −1
Original line number Diff line number Diff line
@@ -673,7 +673,20 @@ static void free_slots(void)

	list_for_each_entry_safe(slot_cur, next, &ibmphp_slot_head,
				 ibm_slot_list) {
		pci_hp_deregister(slot_cur->hotplug_slot);
		pci_hp_del(slot_cur->hotplug_slot);
		slot_cur->ctrl = NULL;
		slot_cur->bus_on = NULL;

		/*
		 * We don't want to actually remove the resources,
		 * since ibmphp_free_resources() will do just that.
		 */
		ibmphp_unconfigure_card(&slot_cur, -1);

		pci_hp_destroy(slot_cur->hotplug_slot);
		kfree(slot_cur->hotplug_slot->info);
		kfree(slot_cur->hotplug_slot);
		kfree(slot_cur);
	}
	debug("%s -- exit\n", __func__);
}
Loading