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

Commit 50b52fde authored by Rajat Jain's avatar Rajat Jain Committed by Bjorn Helgaas
Browse files

PCI: pciehp: Add hotplug_lock to serialize hotplug events



Today it is there is no protection around pciehp_enable_slot() and
pciehp_disable_slot() to ensure that they complete before another
hot-plug operation can be done on that particular slot.

This patch introduces the slot->hotplug_lock to ensure that any hotplug
operations (add / remove) complete before another hotplug event can begin
processing on that particular slot.

Signed-off-by: default avatarRajat Jain <rajatxjain@gmail.com>
Signed-off-by: default avatarRajat Jain <rajatjain@juniper.net>
Signed-off-by: default avatarGuenter Roeck <groeck@juniper.net>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
parent c4f2f5e4
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -76,6 +76,7 @@ struct slot {
	struct hotplug_slot *hotplug_slot;
	struct hotplug_slot *hotplug_slot;
	struct delayed_work work;	/* work for button event */
	struct delayed_work work;	/* work for button event */
	struct mutex lock;
	struct mutex lock;
	struct mutex hotplug_lock;
	struct workqueue_struct *wq;
	struct workqueue_struct *wq;
};
};


+6 −1
Original line number Original line Diff line number Diff line
@@ -283,8 +283,11 @@ static int pciehp_probe(struct pcie_device *dev)
	slot = ctrl->slot;
	slot = ctrl->slot;
	pciehp_get_adapter_status(slot, &occupied);
	pciehp_get_adapter_status(slot, &occupied);
	pciehp_get_power_status(slot, &poweron);
	pciehp_get_power_status(slot, &poweron);
	if (occupied && pciehp_force)
	if (occupied && pciehp_force) {
		mutex_lock(&slot->hotplug_lock);
		pciehp_enable_slot(slot);
		pciehp_enable_slot(slot);
		mutex_unlock(&slot->hotplug_lock);
	}
	/* If empty slot's power status is on, turn power off */
	/* If empty slot's power status is on, turn power off */
	if (!occupied && poweron && POWER_CTRL(ctrl))
	if (!occupied && poweron && POWER_CTRL(ctrl))
		pciehp_power_off_slot(slot);
		pciehp_power_off_slot(slot);
@@ -328,10 +331,12 @@ static int pciehp_resume (struct pcie_device *dev)


	/* Check if slot is occupied */
	/* Check if slot is occupied */
	pciehp_get_adapter_status(slot, &status);
	pciehp_get_adapter_status(slot, &status);
	mutex_lock(&slot->hotplug_lock);
	if (status)
	if (status)
		pciehp_enable_slot(slot);
		pciehp_enable_slot(slot);
	else
	else
		pciehp_disable_slot(slot);
		pciehp_disable_slot(slot);
	mutex_unlock(&slot->hotplug_lock);
	return 0;
	return 0;
}
}
#endif /* PM */
#endif /* PM */
+15 −2
Original line number Original line Diff line number Diff line
@@ -293,6 +293,7 @@ static void pciehp_power_thread(struct work_struct *work)
	struct power_work_info *info =
	struct power_work_info *info =
		container_of(work, struct power_work_info, work);
		container_of(work, struct power_work_info, work);
	struct slot *p_slot = info->p_slot;
	struct slot *p_slot = info->p_slot;
	int ret;


	switch (info->req) {
	switch (info->req) {
	case DISABLE_REQ:
	case DISABLE_REQ:
@@ -300,7 +301,9 @@ static void pciehp_power_thread(struct work_struct *work)
			 "Disabling domain:bus:device=%04x:%02x:00\n",
			 "Disabling domain:bus:device=%04x:%02x:00\n",
			 pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
			 pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
			 p_slot->ctrl->pcie->port->subordinate->number);
			 p_slot->ctrl->pcie->port->subordinate->number);
		mutex_lock(&p_slot->hotplug_lock);
		pciehp_disable_slot(p_slot);
		pciehp_disable_slot(p_slot);
		mutex_unlock(&p_slot->hotplug_lock);
		mutex_lock(&p_slot->lock);
		mutex_lock(&p_slot->lock);
		p_slot->state = STATIC_STATE;
		p_slot->state = STATIC_STATE;
		mutex_unlock(&p_slot->lock);
		mutex_unlock(&p_slot->lock);
@@ -310,7 +313,10 @@ static void pciehp_power_thread(struct work_struct *work)
			 "Enabling domain:bus:device=%04x:%02x:00\n",
			 "Enabling domain:bus:device=%04x:%02x:00\n",
			 pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
			 pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
			 p_slot->ctrl->pcie->port->subordinate->number);
			 p_slot->ctrl->pcie->port->subordinate->number);
		if (pciehp_enable_slot(p_slot))
		mutex_lock(&p_slot->hotplug_lock);
		ret = pciehp_enable_slot(p_slot);
		mutex_unlock(&p_slot->hotplug_lock);
		if (ret)
			pciehp_green_led_off(p_slot);
			pciehp_green_led_off(p_slot);
		mutex_lock(&p_slot->lock);
		mutex_lock(&p_slot->lock);
		p_slot->state = STATIC_STATE;
		p_slot->state = STATIC_STATE;
@@ -546,6 +552,9 @@ static void interrupt_event_handler(struct work_struct *work)
	kfree(info);
	kfree(info);
}
}


/*
 * Note: This function must be called with slot->hotplug_lock held
 */
int pciehp_enable_slot(struct slot *p_slot)
int pciehp_enable_slot(struct slot *p_slot)
{
{
	u8 getstatus = 0;
	u8 getstatus = 0;
@@ -584,7 +593,9 @@ int pciehp_enable_slot(struct slot *p_slot)
	return rc;
	return rc;
}
}



/*
 * Note: This function must be called with slot->hotplug_lock held
 */
int pciehp_disable_slot(struct slot *p_slot)
int pciehp_disable_slot(struct slot *p_slot)
{
{
	u8 getstatus = 0;
	u8 getstatus = 0;
@@ -617,7 +628,9 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot)
	case STATIC_STATE:
	case STATIC_STATE:
		p_slot->state = POWERON_STATE;
		p_slot->state = POWERON_STATE;
		mutex_unlock(&p_slot->lock);
		mutex_unlock(&p_slot->lock);
		mutex_lock(&p_slot->hotplug_lock);
		retval = pciehp_enable_slot(p_slot);
		retval = pciehp_enable_slot(p_slot);
		mutex_unlock(&p_slot->hotplug_lock);
		mutex_lock(&p_slot->lock);
		mutex_lock(&p_slot->lock);
		p_slot->state = STATIC_STATE;
		p_slot->state = STATIC_STATE;
		break;
		break;
+1 −0
Original line number Original line Diff line number Diff line
@@ -686,6 +686,7 @@ static int pcie_init_slot(struct controller *ctrl)


	slot->ctrl = ctrl;
	slot->ctrl = ctrl;
	mutex_init(&slot->lock);
	mutex_init(&slot->lock);
	mutex_init(&slot->hotplug_lock);
	INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
	INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
	ctrl->slot = slot;
	ctrl->slot = slot;
	return 0;
	return 0;