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

Commit 130b3b8d authored by Vivek Pernamitta's avatar Vivek Pernamitta
Browse files

msm: pci: Release spinlock before notifying client



Release spinlock before notifying client driver and acquire
spinlock once done because once host notifies client driver with
an event, client can schedule an recovery in same context before
returning and expects an new event which could cause an race
condition if spinlock is acquired.
Also use list_for_each_entry_safe() while travesing the list of
registered clients for notification.

Change-Id: I6ae55032acdb1a5b14f473eadacb7a009a8df753
Signed-off-by: default avatarVivek Pernamitta <vpernami@codeaurora.org>
parent 8bbe4188
Loading
Loading
Loading
Loading
+17 −4
Original line number Diff line number Diff line
@@ -5031,13 +5031,13 @@ EXPORT_SYMBOL(msm_pcie_enumerate);
static void msm_pcie_notify_client(struct msm_pcie_dev_t *dev,
					enum msm_pcie_event event)
{
	struct msm_pcie_register_event *reg_itr;
	struct msm_pcie_register_event *reg_itr, *temp;
	struct msm_pcie_notify *notify;
	struct msm_pcie_notify client_notify;
	unsigned long flags;

	spin_lock_irqsave(&dev->evt_reg_list_lock, flags);
	list_for_each_entry(reg_itr, &dev->event_reg_list, node) {
	list_for_each_entry_safe(reg_itr, temp, &dev->event_reg_list, node) {
		if ((reg_itr->events & event) && reg_itr->callback) {
			notify = &reg_itr->notify;
			client_notify.event = event;
@@ -5046,8 +5046,19 @@ static void msm_pcie_notify_client(struct msm_pcie_dev_t *dev,
			client_notify.options = notify->options;
			PCIE_DUMP(dev, "PCIe: callback RC%d for event %d\n",
				  dev->rc_idx, event);

			/* Release spinlock before notifying client driver
			 * and acquire it once done because once host notifies
			 * client driver with an event, client can schedule an
			 * recovery in same context before returning and
			 * expects an new event which could cause an race
			 * condition if spinlock is acquired.
			 */
			spin_unlock_irqrestore(&dev->evt_reg_list_lock, flags);

			reg_itr->callback(&client_notify);

			spin_lock_irqsave(&dev->evt_reg_list_lock, flags);
			if ((reg_itr->options & MSM_PCIE_CONFIG_NO_RECOVERY) &&
					(event == MSM_PCIE_EVENT_LINKDOWN)) {
				dev->user_suspend = true;
@@ -8050,7 +8061,7 @@ int msm_pcie_register_event(struct msm_pcie_register_event *reg)
{
	int ret = 0;
	struct msm_pcie_dev_t *pcie_dev;
	struct msm_pcie_register_event *reg_itr;
	struct msm_pcie_register_event *reg_itr, *temp;
	struct pci_dev *pcidev;
	unsigned long flags;

@@ -8074,7 +8085,9 @@ int msm_pcie_register_event(struct msm_pcie_register_event *reg)
	pcidev = (struct pci_dev *)reg->user;

	spin_lock_irqsave(&pcie_dev->evt_reg_list_lock, flags);
	list_for_each_entry(reg_itr, &pcie_dev->event_reg_list, node) {
	list_for_each_entry_safe(reg_itr, temp,
				 &pcie_dev->event_reg_list, node) {

		if (reg_itr->user == reg->user) {
			PCIE_ERR(pcie_dev,
				 "PCIe: RC%d: EP BDF 0x%4x already registered\n",