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

Commit 11f6e40d authored by Vasanthakumar Thiagarajan's avatar Vasanthakumar Thiagarajan Committed by Kalle Valo
Browse files

ath6kl: Fix lockdep warning



The following is the lockdep warning which detects possible
deadlock condition with the way ar->lock and ar->list_lock
are being used.

  (&(&ar->lock)->rlock){+.-...}, at: [<ffffffffa0492d13>] ath6kl_indicate_tx_activity+0x83/0x110 [ath6kl]
 but this lock took another, SOFTIRQ-unsafe lock in the past:
  (&(&ar->list_lock)->rlock){+.+...}

 and interrupts could create inverse lock ordering between them.

 other info that might help us debug this:
  Possible interrupt unsafe locking scenario:

        CPU0                    CPU1
        ----                    ----
   lock(&(&ar->list_lock)->rlock);
                                local_irq_disable();
                                lock(&(&ar->lock)->rlock);
                                lock(&(&ar->list_lock)->rlock);
   <Interrupt>
     lock(&(&ar->lock)->rlock);

  *** DEADLOCK ***

softirqs have to be disabled when acquiring ar->list_lock to avoid
the above deadlock condition. When the above warning printed the
interface is still up and running without issue.

Reported-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
Signed-off-by: default avatarVasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent b4b2a0b1
Loading
Loading
Loading
Loading
+4 −4
Original line number Original line Diff line number Diff line
@@ -1320,9 +1320,9 @@ static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
	struct ath6kl *ar = wiphy_priv(wiphy);
	struct ath6kl *ar = wiphy_priv(wiphy);
	struct ath6kl_vif *vif = netdev_priv(ndev);
	struct ath6kl_vif *vif = netdev_priv(ndev);


	spin_lock(&ar->list_lock);
	spin_lock_bh(&ar->list_lock);
	list_del(&vif->list);
	list_del(&vif->list);
	spin_unlock(&ar->list_lock);
	spin_unlock_bh(&ar->list_lock);


	ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
	ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));


@@ -2437,9 +2437,9 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
	if (type == NL80211_IFTYPE_ADHOC)
	if (type == NL80211_IFTYPE_ADHOC)
		ar->ibss_if_active = true;
		ar->ibss_if_active = true;


	spin_lock(&ar->list_lock);
	spin_lock_bh(&ar->list_lock);
	list_add_tail(&vif->list, &ar->vif_list);
	list_add_tail(&vif->list, &ar->vif_list);
	spin_unlock(&ar->list_lock);
	spin_unlock_bh(&ar->list_lock);


	return ndev;
	return ndev;


+4 −4
Original line number Original line Diff line number Diff line
@@ -1685,17 +1685,17 @@ void ath6kl_stop_txrx(struct ath6kl *ar)
		return;
		return;
	}
	}


	spin_lock(&ar->list_lock);
	spin_lock_bh(&ar->list_lock);
	list_for_each_entry_safe(vif, tmp_vif, &ar->vif_list, list) {
	list_for_each_entry_safe(vif, tmp_vif, &ar->vif_list, list) {
		list_del(&vif->list);
		list_del(&vif->list);
		spin_unlock(&ar->list_lock);
		spin_unlock_bh(&ar->list_lock);
		ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
		ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
		rtnl_lock();
		rtnl_lock();
		ath6kl_deinit_if_data(vif);
		ath6kl_deinit_if_data(vif);
		rtnl_unlock();
		rtnl_unlock();
		spin_lock(&ar->list_lock);
		spin_lock_bh(&ar->list_lock);
	}
	}
	spin_unlock(&ar->list_lock);
	spin_unlock_bh(&ar->list_lock);


	clear_bit(WMI_READY, &ar->flag);
	clear_bit(WMI_READY, &ar->flag);


+3 −3
Original line number Original line Diff line number Diff line
@@ -1046,15 +1046,15 @@ struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar)
{
{
	struct ath6kl_vif *vif;
	struct ath6kl_vif *vif;


	spin_lock(&ar->list_lock);
	spin_lock_bh(&ar->list_lock);
	if (list_empty(&ar->vif_list)) {
	if (list_empty(&ar->vif_list)) {
		spin_unlock(&ar->list_lock);
		spin_unlock_bh(&ar->list_lock);
		return NULL;
		return NULL;
	}
	}


	vif = list_first_entry(&ar->vif_list, struct ath6kl_vif, list);
	vif = list_first_entry(&ar->vif_list, struct ath6kl_vif, list);


	spin_unlock(&ar->list_lock);
	spin_unlock_bh(&ar->list_lock);


	return vif;
	return vif;
}
}
+7 −7
Original line number Original line Diff line number Diff line
@@ -470,10 +470,10 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,


stop_adhoc_netq:
stop_adhoc_netq:
	/* FIXME: Locking */
	/* FIXME: Locking */
	spin_lock(&ar->list_lock);
	spin_lock_bh(&ar->list_lock);
	list_for_each_entry(vif, &ar->vif_list, list) {
	list_for_each_entry(vif, &ar->vif_list, list) {
		if (vif->nw_type == ADHOC_NETWORK) {
		if (vif->nw_type == ADHOC_NETWORK) {
			spin_unlock(&ar->list_lock);
			spin_unlock_bh(&ar->list_lock);


			spin_lock_bh(&vif->if_lock);
			spin_lock_bh(&vif->if_lock);
			set_bit(NETQ_STOPPED, &vif->flags);
			set_bit(NETQ_STOPPED, &vif->flags);
@@ -483,7 +483,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
			return action;
			return action;
		}
		}
	}
	}
	spin_unlock(&ar->list_lock);
	spin_unlock_bh(&ar->list_lock);


	return action;
	return action;
}
}
@@ -637,16 +637,16 @@ void ath6kl_tx_complete(void *context, struct list_head *packet_queue)
	__skb_queue_purge(&skb_queue);
	__skb_queue_purge(&skb_queue);


	/* FIXME: Locking */
	/* FIXME: Locking */
	spin_lock(&ar->list_lock);
	spin_lock_bh(&ar->list_lock);
	list_for_each_entry(vif, &ar->vif_list, list) {
	list_for_each_entry(vif, &ar->vif_list, list) {
		if (test_bit(CONNECTED, &vif->flags) &&
		if (test_bit(CONNECTED, &vif->flags) &&
		    !flushing[vif->fw_vif_idx]) {
		    !flushing[vif->fw_vif_idx]) {
			spin_unlock(&ar->list_lock);
			spin_unlock_bh(&ar->list_lock);
			netif_wake_queue(vif->ndev);
			netif_wake_queue(vif->ndev);
			spin_lock(&ar->list_lock);
			spin_lock_bh(&ar->list_lock);
		}
		}
	}
	}
	spin_unlock(&ar->list_lock);
	spin_unlock_bh(&ar->list_lock);


	if (wake_event)
	if (wake_event)
		wake_up(&ar->event_wq);
		wake_up(&ar->event_wq);
+2 −2
Original line number Original line Diff line number Diff line
@@ -89,14 +89,14 @@ struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx)
		return NULL;
		return NULL;


	/* FIXME: Locking */
	/* FIXME: Locking */
	spin_lock(&ar->list_lock);
	spin_lock_bh(&ar->list_lock);
	list_for_each_entry(vif, &ar->vif_list, list) {
	list_for_each_entry(vif, &ar->vif_list, list) {
		if (vif->fw_vif_idx == if_idx) {
		if (vif->fw_vif_idx == if_idx) {
			found = vif;
			found = vif;
			break;
			break;
		}
		}
	}
	}
	spin_unlock(&ar->list_lock);
	spin_unlock_bh(&ar->list_lock);


	return found;
	return found;
}
}