Commit a7da2161 authored by Lukas Wunner's avatar Lukas Wunner Committed by Bjorn Helgaas
Browse files

PCI: hotplug: Drop hotplug_slot_info

Ever since the PCI hotplug core was introduced in 2002, drivers had to
allocate and register a struct hotplug_slot_info for every slot:
https://git.kernel.org/tglx/history/c/a8a2069f432c



Apparently the idea was that drivers furnish the hotplug core with an
up-to-date card presence status, power status, latch status and
attention indicator status as well as notify the hotplug core of changes
thereof.  However only 4 out of 12 hotplug drivers bother to notify the
hotplug core with pci_hp_change_slot_info() and the hotplug core never
made any use of the information:  There is just a single macro in
pci_hotplug_core.c, GET_STATUS(), which uses the hotplug_slot_info if
the driver lacks the corresponding callback in hotplug_slot_ops.  The
macro is called when the user reads the attribute via sysfs.

Now, if the callback isn't defined, the attribute isn't exposed in sysfs
in the first place (see e.g. has_power_file()).  There are only two
situations when the hotplug_slot_info would actually be accessed:

* If the driver defines ->enable_slot or ->disable_slot but not
  ->get_power_status.

* If the driver defines ->set_attention_status but not
  ->get_attention_status.

There is no driver doing the former and just a single driver doing the
latter, namely pnv_php.c.  Amend it with a ->get_attention_status
callback.  With that, the hotplug_slot_info becomes completely unused by
the PCI hotplug core.  But a few drivers use it internally as a cache:

cpcihp uses it to cache the latch_status and adapter_status.
cpqhp uses it to cache the adapter_status.
pnv_php and rpaphp use it to cache the attention_status.
shpchp uses it to cache all four values.

Amend these drivers to cache the information in their private slot
struct.  shpchp's slot struct already contains members to cache the
power_status and adapter_status, so additional members are only needed
for the other two values.  In the case of cpqphp, the cached value is
only accessed in a single place, so instead of caching it, read the
current value from the hardware.

Caution:  acpiphp, cpci, cpqhp, shpchp, asus-wmi and eeepc-laptop
populate the hotplug_slot_info with initial values on probe.  That code
is herewith removed.  There is a theoretical chance that the code has
side effects without which the driver fails to function, e.g. if the
ACPI method to read the adapter status needs to be executed at least
once on probe.  That seems unlikely to me, still maintainers should
review the changes carefully for this possibility.

Rafael adds: "I'm not aware of any case in which it will break anything,
[...] but if that happens, it may be necessary to add the execution of
the control methods in question directly to the initialization part."

Signed-off-by: default avatarLukas Wunner <lukas@wunner.de>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Tyrel Datwyler <tyreld@linux.vnet.ibm.com>  # drivers/pci/hotplug/rpa*
Acked-by: Sebastian Ott <sebott@linux.ibm.com>        # drivers/pci/hotplug/s390*
Acked-by: Andy Shevchenko <andy.shevchenko@gmail.com> # drivers/platform/x86
Cc: Len Brown <lenb@kernel.org>
Cc: Scott Murray <scott@spiteful.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Oliver OHalloran <oliveroh@au1.ibm.com>
Cc: Gavin Shan <gwshan@linux.vnet.ibm.com>
Cc: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Cc: Corentin Chary <corentin.chary@gmail.com>
Cc: Darren Hart <dvhart@infradead.org>
parent 81c4b5bf
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -54,7 +54,6 @@ void pnv_cxl_release_hwirq_ranges(struct cxl_irq_ranges *irqs,

struct pnv_php_slot {
	struct hotplug_slot		slot;
	struct hotplug_slot_info	slot_info;
	uint64_t			id;
	char				*name;
	int				slot_no;
@@ -72,6 +71,7 @@ struct pnv_php_slot {
	struct pci_dev			*pdev;
	struct pci_bus			*bus;
	bool				power_state_check;
	u8				attention_state;
	void				*fdt;
	void				*dt;
	struct of_changeset		ocs;
+0 −1
Original line number Diff line number Diff line
@@ -35,7 +35,6 @@ struct acpiphp_slot;
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 */
};

+0 −6
Original line number Diff line number Diff line
@@ -270,16 +270,10 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot,
	if (!slot->hotplug_slot)
		goto error_slot;

	slot->hotplug_slot->info = &slot->info;

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

	slot->acpi_slot = acpiphp_slot;
	slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot);
	slot->hotplug_slot->info->attention_status = 0;
	slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot);
	slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);

	acpiphp_slot->slot = slot;
	slot->sun = sun;
+2 −0
Original line number Diff line number Diff line
@@ -32,6 +32,8 @@ struct slot {
	unsigned int devfn;
	struct pci_bus *bus;
	struct pci_dev *dev;
	unsigned int latch_status:1;
	unsigned int adapter_status:1;
	unsigned int extracting;
	struct hotplug_slot *hotplug_slot;
	struct list_head slot_list;
+14 −58
Original line number Diff line number Diff line
@@ -67,26 +67,6 @@ static const struct hotplug_slot_ops cpci_hotplug_slot_ops = {
	.get_latch_status = get_latch_status,
};

static int
update_latch_status(struct hotplug_slot *hotplug_slot, u8 value)
{
	struct hotplug_slot_info info;

	memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info));
	info.latch_status = value;
	return pci_hp_change_slot_info(hotplug_slot, &info);
}

static int
update_adapter_status(struct hotplug_slot *hotplug_slot, u8 value)
{
	struct hotplug_slot_info info;

	memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info));
	info.adapter_status = value;
	return pci_hp_change_slot_info(hotplug_slot, &info);
}

static int
enable_slot(struct hotplug_slot *hotplug_slot)
{
@@ -135,8 +115,7 @@ disable_slot(struct hotplug_slot *hotplug_slot)
			goto disable_error;
	}

	if (update_adapter_status(slot->hotplug_slot, 0))
		warn("failure to update adapter file");
	slot->adapter_status = 0;

	if (slot->extracting) {
		slot->extracting = 0;
@@ -184,20 +163,23 @@ set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
static int
get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
	*value = hotplug_slot->info->adapter_status;
	struct slot *slot = hotplug_slot->private;

	*value = slot->adapter_status;
	return 0;
}

static int
get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
{
	*value = hotplug_slot->info->latch_status;
	struct slot *slot = hotplug_slot->private;

	*value = slot->latch_status;
	return 0;
}

static void release_slot(struct slot *slot)
{
	kfree(slot->hotplug_slot->info);
	kfree(slot->hotplug_slot);
	pci_dev_put(slot->dev);
	kfree(slot);
@@ -210,7 +192,6 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
{
	struct slot *slot;
	struct hotplug_slot *hotplug_slot;
	struct hotplug_slot_info *info;
	char name[SLOT_NAME_SIZE];
	int status;
	int i;
@@ -237,13 +218,6 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
		}
		slot->hotplug_slot = hotplug_slot;

		info = kzalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
		if (!info) {
			status = -ENOMEM;
			goto error_hpslot;
		}
		hotplug_slot->info = info;

		slot->bus = bus;
		slot->number = i;
		slot->devfn = PCI_DEVFN(i, 0);
@@ -253,19 +227,11 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
		hotplug_slot->private = slot;
		hotplug_slot->ops = &cpci_hotplug_slot_ops;

		/*
		 * Initialize the slot info structure with some known
		 * good values.
		 */
		dbg("initializing slot %s", name);
		info->power_status = cpci_get_power_status(slot);
		info->attention_status = cpci_get_attention_status(slot);

		dbg("registering slot %s", name);
		status = pci_hp_register(slot->hotplug_slot, bus, i, name);
		if (status) {
			err("pci_hp_register failed with error %d", status);
			goto error_info;
			goto error_hpslot;
		}
		dbg("slot registered with name: %s", slot_name(slot));

@@ -276,8 +242,6 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
		up_write(&list_rwsem);
	}
	return 0;
error_info:
	kfree(info);
error_hpslot:
	kfree(hotplug_slot);
error_slot:
@@ -359,10 +323,8 @@ init_slots(int clear_ins)
			    __func__, slot_name(slot));
		dev = pci_get_slot(slot->bus, PCI_DEVFN(slot->number, 0));
		if (dev) {
			if (update_adapter_status(slot->hotplug_slot, 1))
				warn("failure to update adapter file");
			if (update_latch_status(slot->hotplug_slot, 1))
				warn("failure to update latch file");
			slot->adapter_status = 1;
			slot->latch_status = 1;
			slot->dev = dev;
		}
	}
@@ -424,11 +386,8 @@ check_slots(void)
			dbg("%s - slot %s HS_CSR (2) = %04x",
			    __func__, slot_name(slot), hs_csr);

			if (update_latch_status(slot->hotplug_slot, 1))
				warn("failure to update latch file");

			if (update_adapter_status(slot->hotplug_slot, 1))
				warn("failure to update adapter file");
			slot->latch_status = 1;
			slot->adapter_status = 1;

			cpci_led_off(slot);

@@ -449,9 +408,7 @@ check_slots(void)
			    __func__, slot_name(slot), hs_csr);

			if (!slot->extracting) {
				if (update_latch_status(slot->hotplug_slot, 0))
					warn("failure to update latch file");

				slot->latch_status = 0;
				slot->extracting = 1;
				atomic_inc(&extracting);
			}
@@ -465,8 +422,7 @@ check_slots(void)
				 */
				err("card in slot %s was improperly removed",
				    slot_name(slot));
				if (update_adapter_status(slot->hotplug_slot, 0))
					warn("failure to update adapter file");
				slot->adapter_status = 0;
				slot->extracting = 0;
				atomic_dec(&extracting);
			}
Loading