mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/
synced 2026-04-01 22:37:41 -04:00
Compare commits
23 Commits
453a4a5f97
...
ae05340cca
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae05340cca | ||
|
|
2428083101 | ||
|
|
04f272188f | ||
|
|
f2df9567b1 | ||
|
|
2725d84efe | ||
|
|
0239fd701d | ||
|
|
e8e44c98f7 | ||
|
|
57a04a13aa | ||
|
|
976ff48c2a | ||
|
|
f73896b419 | ||
|
|
629ec78ef8 | ||
|
|
45dbf8fcea | ||
|
|
789b06f9f3 | ||
|
|
744fabc338 | ||
|
|
6525a549ec | ||
|
|
249ddd5fe2 | ||
|
|
0fd56fad9c | ||
|
|
d049e56b17 | ||
|
|
4242625f27 | ||
|
|
e225b36f83 | ||
|
|
687a95d204 | ||
|
|
323156c354 | ||
|
|
ec66ec6a5a |
@@ -2578,6 +2578,7 @@ EXPORT_SYMBOL_GPL(enetc_free_si_resources);
|
||||
|
||||
static void enetc_setup_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring)
|
||||
{
|
||||
struct enetc_si *si = container_of(hw, struct enetc_si, hw);
|
||||
int idx = tx_ring->index;
|
||||
u32 tbmr;
|
||||
|
||||
@@ -2591,10 +2592,20 @@ static void enetc_setup_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring)
|
||||
enetc_txbdr_wr(hw, idx, ENETC_TBLENR,
|
||||
ENETC_RTBLENR_LEN(tx_ring->bd_count));
|
||||
|
||||
/* clearing PI/CI registers for Tx not supported, adjust sw indexes */
|
||||
/* For ENETC v1, clearing PI/CI registers for Tx not supported,
|
||||
* adjust sw indexes
|
||||
*/
|
||||
tx_ring->next_to_use = enetc_txbdr_rd(hw, idx, ENETC_TBPIR);
|
||||
tx_ring->next_to_clean = enetc_txbdr_rd(hw, idx, ENETC_TBCIR);
|
||||
|
||||
if (tx_ring->next_to_use != tx_ring->next_to_clean &&
|
||||
!is_enetc_rev1(si)) {
|
||||
tx_ring->next_to_use = 0;
|
||||
tx_ring->next_to_clean = 0;
|
||||
enetc_txbdr_wr(hw, idx, ENETC_TBPIR, 0);
|
||||
enetc_txbdr_wr(hw, idx, ENETC_TBCIR, 0);
|
||||
}
|
||||
|
||||
/* enable Tx ints by setting pkt thr to 1 */
|
||||
enetc_txbdr_wr(hw, idx, ENETC_TBICR0, ENETC_TBICR0_ICEN | 0x1);
|
||||
|
||||
|
||||
@@ -134,6 +134,12 @@
|
||||
|
||||
/* Port operational register */
|
||||
#define ENETC4_POR 0x4100
|
||||
#define POR_TXDIS BIT(0)
|
||||
#define POR_RXDIS BIT(1)
|
||||
|
||||
/* Port status register */
|
||||
#define ENETC4_PSR 0x4104
|
||||
#define PSR_RX_BUSY BIT(1)
|
||||
|
||||
/* Port traffic class a transmit maximum SDU register */
|
||||
#define ENETC4_PTCTMSDUR(a) ((a) * 0x20 + 0x4208)
|
||||
@@ -173,6 +179,11 @@
|
||||
/* Port internal MDIO base address, use to access PCS */
|
||||
#define ENETC4_PM_IMDIO_BASE 0x5030
|
||||
|
||||
/* Port MAC 0/1 Interrupt Event Register */
|
||||
#define ENETC4_PM_IEVENT(mac) (0x5040 + (mac) * 0x400)
|
||||
#define PM_IEVENT_TX_EMPTY BIT(5)
|
||||
#define PM_IEVENT_RX_EMPTY BIT(6)
|
||||
|
||||
/* Port MAC 0/1 Pause Quanta Register */
|
||||
#define ENETC4_PM_PAUSE_QUANTA(mac) (0x5054 + (mac) * 0x400)
|
||||
|
||||
|
||||
@@ -444,20 +444,11 @@ static void enetc4_set_trx_frame_size(struct enetc_pf *pf)
|
||||
enetc4_pf_reset_tc_msdu(&si->hw);
|
||||
}
|
||||
|
||||
static void enetc4_enable_trx(struct enetc_pf *pf)
|
||||
{
|
||||
struct enetc_hw *hw = &pf->si->hw;
|
||||
|
||||
/* Enable port transmit/receive */
|
||||
enetc_port_wr(hw, ENETC4_POR, 0);
|
||||
}
|
||||
|
||||
static void enetc4_configure_port(struct enetc_pf *pf)
|
||||
{
|
||||
enetc4_configure_port_si(pf);
|
||||
enetc4_set_trx_frame_size(pf);
|
||||
enetc_set_default_rss_key(pf);
|
||||
enetc4_enable_trx(pf);
|
||||
}
|
||||
|
||||
static int enetc4_init_ntmp_user(struct enetc_si *si)
|
||||
@@ -801,15 +792,112 @@ static void enetc4_set_tx_pause(struct enetc_pf *pf, int num_rxbdr, bool tx_paus
|
||||
enetc_port_wr(hw, ENETC4_PPAUOFFTR, pause_off_thresh);
|
||||
}
|
||||
|
||||
static void enetc4_enable_mac(struct enetc_pf *pf, bool en)
|
||||
static void enetc4_mac_wait_tx_empty(struct enetc_si *si, int mac)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (read_poll_timeout(enetc_port_rd, val,
|
||||
val & PM_IEVENT_TX_EMPTY,
|
||||
100, 10000, false, &si->hw,
|
||||
ENETC4_PM_IEVENT(mac)))
|
||||
dev_warn(&si->pdev->dev,
|
||||
"MAC %d TX is not empty\n", mac);
|
||||
}
|
||||
|
||||
static void enetc4_mac_tx_graceful_stop(struct enetc_pf *pf)
|
||||
{
|
||||
struct enetc_hw *hw = &pf->si->hw;
|
||||
struct enetc_si *si = pf->si;
|
||||
u32 val;
|
||||
|
||||
val = enetc_port_rd(hw, ENETC4_POR);
|
||||
val |= POR_TXDIS;
|
||||
enetc_port_wr(hw, ENETC4_POR, val);
|
||||
|
||||
if (enetc_is_pseudo_mac(si))
|
||||
return;
|
||||
|
||||
enetc4_mac_wait_tx_empty(si, 0);
|
||||
if (si->hw_features & ENETC_SI_F_QBU)
|
||||
enetc4_mac_wait_tx_empty(si, 1);
|
||||
|
||||
val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0));
|
||||
val &= ~PM_CMD_CFG_TX_EN;
|
||||
enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val);
|
||||
}
|
||||
|
||||
static void enetc4_mac_tx_enable(struct enetc_pf *pf)
|
||||
{
|
||||
struct enetc_hw *hw = &pf->si->hw;
|
||||
struct enetc_si *si = pf->si;
|
||||
u32 val;
|
||||
|
||||
val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0));
|
||||
val &= ~(PM_CMD_CFG_TX_EN | PM_CMD_CFG_RX_EN);
|
||||
val |= en ? (PM_CMD_CFG_TX_EN | PM_CMD_CFG_RX_EN) : 0;
|
||||
val |= PM_CMD_CFG_TX_EN;
|
||||
enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val);
|
||||
|
||||
val = enetc_port_rd(hw, ENETC4_POR);
|
||||
val &= ~POR_TXDIS;
|
||||
enetc_port_wr(hw, ENETC4_POR, val);
|
||||
}
|
||||
|
||||
static void enetc4_mac_wait_rx_empty(struct enetc_si *si, int mac)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (read_poll_timeout(enetc_port_rd, val,
|
||||
val & PM_IEVENT_RX_EMPTY,
|
||||
100, 10000, false, &si->hw,
|
||||
ENETC4_PM_IEVENT(mac)))
|
||||
dev_warn(&si->pdev->dev,
|
||||
"MAC %d RX is not empty\n", mac);
|
||||
}
|
||||
|
||||
static void enetc4_mac_rx_graceful_stop(struct enetc_pf *pf)
|
||||
{
|
||||
struct enetc_hw *hw = &pf->si->hw;
|
||||
struct enetc_si *si = pf->si;
|
||||
u32 val;
|
||||
|
||||
if (enetc_is_pseudo_mac(si))
|
||||
goto check_rx_busy;
|
||||
|
||||
if (si->hw_features & ENETC_SI_F_QBU) {
|
||||
val = enetc_port_rd(hw, ENETC4_PM_CMD_CFG(1));
|
||||
val &= ~PM_CMD_CFG_RX_EN;
|
||||
enetc_port_wr(hw, ENETC4_PM_CMD_CFG(1), val);
|
||||
enetc4_mac_wait_rx_empty(si, 1);
|
||||
}
|
||||
|
||||
val = enetc_port_rd(hw, ENETC4_PM_CMD_CFG(0));
|
||||
val &= ~PM_CMD_CFG_RX_EN;
|
||||
enetc_port_wr(hw, ENETC4_PM_CMD_CFG(0), val);
|
||||
enetc4_mac_wait_rx_empty(si, 0);
|
||||
|
||||
check_rx_busy:
|
||||
if (read_poll_timeout(enetc_port_rd, val,
|
||||
!(val & PSR_RX_BUSY),
|
||||
100, 10000, false, hw,
|
||||
ENETC4_PSR))
|
||||
dev_warn(&si->pdev->dev, "Port RX busy\n");
|
||||
|
||||
val = enetc_port_rd(hw, ENETC4_POR);
|
||||
val |= POR_RXDIS;
|
||||
enetc_port_wr(hw, ENETC4_POR, val);
|
||||
}
|
||||
|
||||
static void enetc4_mac_rx_enable(struct enetc_pf *pf)
|
||||
{
|
||||
struct enetc_hw *hw = &pf->si->hw;
|
||||
struct enetc_si *si = pf->si;
|
||||
u32 val;
|
||||
|
||||
val = enetc_port_rd(hw, ENETC4_POR);
|
||||
val &= ~POR_RXDIS;
|
||||
enetc_port_wr(hw, ENETC4_POR, val);
|
||||
|
||||
val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0));
|
||||
val |= PM_CMD_CFG_RX_EN;
|
||||
enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val);
|
||||
}
|
||||
|
||||
@@ -853,7 +941,8 @@ static void enetc4_pl_mac_link_up(struct phylink_config *config,
|
||||
enetc4_set_hd_flow_control(pf, hd_fc);
|
||||
enetc4_set_tx_pause(pf, priv->num_rx_rings, tx_pause);
|
||||
enetc4_set_rx_pause(pf, rx_pause);
|
||||
enetc4_enable_mac(pf, true);
|
||||
enetc4_mac_tx_enable(pf);
|
||||
enetc4_mac_rx_enable(pf);
|
||||
}
|
||||
|
||||
static void enetc4_pl_mac_link_down(struct phylink_config *config,
|
||||
@@ -862,7 +951,8 @@ static void enetc4_pl_mac_link_down(struct phylink_config *config,
|
||||
{
|
||||
struct enetc_pf *pf = phylink_to_enetc_pf(config);
|
||||
|
||||
enetc4_enable_mac(pf, false);
|
||||
enetc4_mac_rx_graceful_stop(pf);
|
||||
enetc4_mac_tx_graceful_stop(pf);
|
||||
}
|
||||
|
||||
static const struct phylink_mac_ops enetc_pl_mac_ops = {
|
||||
|
||||
@@ -545,9 +545,6 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp,
|
||||
if (rq->perout.flags)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (rq->perout.index != fep->pps_channel)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
period.tv_sec = rq->perout.period.sec;
|
||||
period.tv_nsec = rq->perout.period.nsec;
|
||||
period_ns = timespec64_to_ns(&period);
|
||||
|
||||
@@ -244,6 +244,25 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
mtk_flow_is_valid_idev(const struct mtk_eth *eth, const struct net_device *idev)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!idev)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(eth->netdev); i++) {
|
||||
if (!eth->netdev[i])
|
||||
continue;
|
||||
|
||||
if (idev->netdev_ops == eth->netdev[i]->netdev_ops)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f,
|
||||
int ppe_index)
|
||||
@@ -270,7 +289,7 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f,
|
||||
flow_rule_match_meta(rule, &match);
|
||||
if (mtk_is_netsys_v2_or_greater(eth)) {
|
||||
idev = __dev_get_by_index(&init_net, match.key->ingress_ifindex);
|
||||
if (idev && idev->netdev_ops == eth->netdev[0]->netdev_ops) {
|
||||
if (mtk_flow_is_valid_idev(eth, idev)) {
|
||||
struct mtk_mac *mac = netdev_priv(idev);
|
||||
|
||||
if (WARN_ON(mac->ppe_idx >= eth->soc->ppe_num))
|
||||
|
||||
@@ -766,6 +766,13 @@ static void mana_get_rxbuf_cfg(struct mana_port_context *apc,
|
||||
}
|
||||
|
||||
*frag_count = 1;
|
||||
|
||||
/* In the single-buffer path, napi_build_skb() must see the
|
||||
* actual backing allocation size so skb->truesize reflects
|
||||
* the full page (or higher-order page), not just the usable
|
||||
* packet area.
|
||||
*/
|
||||
*alloc_size = PAGE_SIZE << get_order(*alloc_size);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#include <linux/ieee80211.h>
|
||||
@@ -1110,9 +1110,8 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
|
||||
struct ath11k_base *ab = ar->ab;
|
||||
struct ath11k_peer *peer;
|
||||
struct ath11k_sta *arsta = ath11k_sta_to_arsta(params->sta);
|
||||
struct dp_rx_tid *rx_tid;
|
||||
int vdev_id = arsta->arvif->vdev_id;
|
||||
dma_addr_t paddr;
|
||||
bool active;
|
||||
int ret;
|
||||
|
||||
spin_lock_bh(&ab->base_lock);
|
||||
@@ -1124,15 +1123,14 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
paddr = peer->rx_tid[params->tid].paddr;
|
||||
active = peer->rx_tid[params->tid].active;
|
||||
rx_tid = &peer->rx_tid[params->tid];
|
||||
|
||||
if (!active) {
|
||||
if (!rx_tid->active) {
|
||||
spin_unlock_bh(&ab->base_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = ath11k_peer_rx_tid_reo_update(ar, peer, peer->rx_tid, 1, 0, false);
|
||||
ret = ath11k_peer_rx_tid_reo_update(ar, peer, rx_tid, 1, 0, false);
|
||||
spin_unlock_bh(&ab->base_lock);
|
||||
if (ret) {
|
||||
ath11k_warn(ab, "failed to update reo for rx tid %d: %d\n",
|
||||
@@ -1141,7 +1139,8 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
|
||||
}
|
||||
|
||||
ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id,
|
||||
params->sta->addr, paddr,
|
||||
params->sta->addr,
|
||||
rx_tid->paddr,
|
||||
params->tid, 1, 1);
|
||||
if (ret)
|
||||
ath11k_warn(ab, "failed to send wmi to delete rx tid %d\n",
|
||||
|
||||
@@ -735,6 +735,7 @@ int ath12k_dp_rx_ampdu_stop(struct ath12k *ar,
|
||||
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
|
||||
struct ath12k_dp_link_peer *peer;
|
||||
struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(params->sta);
|
||||
struct ath12k_dp_rx_tid *rx_tid;
|
||||
struct ath12k_link_sta *arsta;
|
||||
int vdev_id;
|
||||
bool active;
|
||||
@@ -770,7 +771,8 @@ int ath12k_dp_rx_ampdu_stop(struct ath12k *ar,
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = ath12k_dp_arch_peer_rx_tid_reo_update(dp, peer, peer->dp_peer->rx_tid,
|
||||
rx_tid = &peer->dp_peer->rx_tid[params->tid];
|
||||
ret = ath12k_dp_arch_peer_rx_tid_reo_update(dp, peer, rx_tid,
|
||||
1, 0, false);
|
||||
spin_unlock_bh(&dp->dp_lock);
|
||||
if (ret) {
|
||||
|
||||
@@ -296,6 +296,11 @@ enum iwl_legacy_cmds {
|
||||
*/
|
||||
SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E,
|
||||
|
||||
/**
|
||||
* @SCAN_START_NOTIFICATION_UMAC: uses &struct iwl_umac_scan_start
|
||||
*/
|
||||
SCAN_START_NOTIFICATION_UMAC = 0xb2,
|
||||
|
||||
/**
|
||||
* @MATCH_FOUND_NOTIFICATION: scan match found
|
||||
*/
|
||||
|
||||
@@ -1156,6 +1156,16 @@ enum iwl_umac_scan_abort_status {
|
||||
IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_umac_scan_start - scan start notification
|
||||
* @uid: scan id, &enum iwl_umac_scan_uid_offsets
|
||||
* @reserved: for future use
|
||||
*/
|
||||
struct iwl_umac_scan_start {
|
||||
__le32 uid;
|
||||
__le32 reserved;
|
||||
} __packed; /* SCAN_START_UMAC_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_umac_scan_complete - scan complete notification
|
||||
* @uid: scan id, &enum iwl_umac_scan_uid_offsets
|
||||
|
||||
@@ -111,14 +111,75 @@ static bool iwl_mld_is_nic_ack_enabled(struct iwl_mld *mld,
|
||||
IEEE80211_HE_MAC_CAP2_ACK_EN);
|
||||
}
|
||||
|
||||
static void iwl_mld_set_he_support(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif,
|
||||
struct iwl_mac_config_cmd *cmd)
|
||||
struct iwl_mld_mac_wifi_gen_sta_iter_data {
|
||||
struct ieee80211_vif *vif;
|
||||
struct iwl_mac_wifi_gen_support *support;
|
||||
};
|
||||
|
||||
static void iwl_mld_mac_wifi_gen_sta_iter(void *_data,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
if (vif->type == NL80211_IFTYPE_AP)
|
||||
cmd->wifi_gen.he_ap_support = 1;
|
||||
else
|
||||
cmd->wifi_gen.he_support = 1;
|
||||
struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
|
||||
struct iwl_mld_mac_wifi_gen_sta_iter_data *data = _data;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
unsigned int link_id;
|
||||
|
||||
if (mld_sta->vif != data->vif)
|
||||
return;
|
||||
|
||||
for_each_sta_active_link(data->vif, sta, link_sta, link_id) {
|
||||
if (link_sta->he_cap.has_he)
|
||||
data->support->he_support = 1;
|
||||
if (link_sta->eht_cap.has_eht)
|
||||
data->support->eht_support = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_mld_set_wifi_gen(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif,
|
||||
struct iwl_mac_wifi_gen_support *support)
|
||||
{
|
||||
struct iwl_mld_mac_wifi_gen_sta_iter_data sta_iter_data = {
|
||||
.vif = vif,
|
||||
.support = support,
|
||||
};
|
||||
struct ieee80211_bss_conf *link_conf;
|
||||
unsigned int link_id;
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
/* for sniffer, set to HW capabilities */
|
||||
support->he_support = 1;
|
||||
support->eht_support = mld->trans->cfg->eht_supported;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
/* for AP set according to the link configs */
|
||||
for_each_vif_active_link(vif, link_conf, link_id) {
|
||||
support->he_ap_support |= link_conf->he_support;
|
||||
support->eht_support |= link_conf->eht_support;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* If we have MLO enabled, then the firmware needs to enable
|
||||
* address translation for the station(s) we add. That depends
|
||||
* on having EHT enabled in firmware, which in turn depends on
|
||||
* mac80211 in the iteration below.
|
||||
* However, mac80211 doesn't enable capabilities on the AP STA
|
||||
* until it has parsed the association response successfully,
|
||||
* so set EHT (and HE as a pre-requisite for EHT) when the vif
|
||||
* is an MLD.
|
||||
*/
|
||||
if (ieee80211_vif_is_mld(vif)) {
|
||||
support->he_support = 1;
|
||||
support->eht_support = 1;
|
||||
}
|
||||
|
||||
ieee80211_iterate_stations_mtx(mld->hw,
|
||||
iwl_mld_mac_wifi_gen_sta_iter,
|
||||
&sta_iter_data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* fill the common part for all interface types */
|
||||
@@ -128,8 +189,6 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld,
|
||||
u32 action)
|
||||
{
|
||||
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||||
struct ieee80211_bss_conf *link_conf;
|
||||
unsigned int link_id;
|
||||
|
||||
lockdep_assert_wiphy(mld->wiphy);
|
||||
|
||||
@@ -147,29 +206,7 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld,
|
||||
cmd->nic_not_ack_enabled =
|
||||
cpu_to_le32(!iwl_mld_is_nic_ack_enabled(mld, vif));
|
||||
|
||||
/* If we have MLO enabled, then the firmware needs to enable
|
||||
* address translation for the station(s) we add. That depends
|
||||
* on having EHT enabled in firmware, which in turn depends on
|
||||
* mac80211 in the code below.
|
||||
* However, mac80211 doesn't enable HE/EHT until it has parsed
|
||||
* the association response successfully, so just skip all that
|
||||
* and enable both when we have MLO.
|
||||
*/
|
||||
if (ieee80211_vif_is_mld(vif)) {
|
||||
iwl_mld_set_he_support(mld, vif, cmd);
|
||||
cmd->wifi_gen.eht_support = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
for_each_vif_active_link(vif, link_conf, link_id) {
|
||||
if (!link_conf->he_support)
|
||||
continue;
|
||||
|
||||
iwl_mld_set_he_support(mld, vif, cmd);
|
||||
|
||||
/* EHT, if supported, was already set above */
|
||||
break;
|
||||
}
|
||||
iwl_mld_set_wifi_gen(mld, vif, &cmd->wifi_gen);
|
||||
}
|
||||
|
||||
static void iwl_mld_fill_mac_cmd_sta(struct iwl_mld *mld,
|
||||
|
||||
@@ -1761,6 +1761,16 @@ static int iwl_mld_move_sta_state_up(struct iwl_mld *mld,
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_STATION)
|
||||
iwl_mld_link_set_2mhz_block(mld, vif, sta);
|
||||
|
||||
if (sta->tdls) {
|
||||
/*
|
||||
* update MAC since wifi generation flags may change,
|
||||
* we also update MAC on association to the AP via the
|
||||
* vif assoc change
|
||||
*/
|
||||
iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY);
|
||||
}
|
||||
|
||||
/* Now the link_sta's capabilities are set, update the FW */
|
||||
iwl_mld_config_tlc(mld, vif, sta);
|
||||
|
||||
@@ -1873,6 +1883,15 @@ static int iwl_mld_move_sta_state_down(struct iwl_mld *mld,
|
||||
/* just removed last TDLS STA, so enable PM */
|
||||
iwl_mld_update_mac_power(mld, vif, false);
|
||||
}
|
||||
|
||||
if (sta->tdls) {
|
||||
/*
|
||||
* update MAC since wifi generation flags may change,
|
||||
* we also update MAC on disassociation to the AP via
|
||||
* the vif assoc change
|
||||
*/
|
||||
iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY);
|
||||
}
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -171,6 +171,7 @@ static const struct iwl_hcmd_names iwl_mld_legacy_names[] = {
|
||||
HCMD_NAME(MISSED_BEACONS_NOTIFICATION),
|
||||
HCMD_NAME(MAC_PM_POWER_TABLE),
|
||||
HCMD_NAME(MFUART_LOAD_NOTIFICATION),
|
||||
HCMD_NAME(SCAN_START_NOTIFICATION_UMAC),
|
||||
HCMD_NAME(RSS_CONFIG_CMD),
|
||||
HCMD_NAME(SCAN_ITERATION_COMPLETE_UMAC),
|
||||
HCMD_NAME(REPLY_RX_MPDU_CMD),
|
||||
|
||||
@@ -739,7 +739,7 @@ iwl_mld_set_link_sel_data(struct iwl_mld *mld,
|
||||
|
||||
/* Ignore any BSS that was not seen in the last MLO scan */
|
||||
if (ktime_before(link_conf->bss->ts_boottime,
|
||||
mld->scan.last_mlo_scan_time))
|
||||
mld->scan.last_mlo_scan_start_time))
|
||||
continue;
|
||||
|
||||
data[n_data].link_id = link_id;
|
||||
@@ -945,7 +945,7 @@ static void _iwl_mld_select_links(struct iwl_mld *mld,
|
||||
if (!mld_vif->authorized || hweight16(usable_links) <= 1)
|
||||
return;
|
||||
|
||||
if (WARN(ktime_before(mld->scan.last_mlo_scan_time,
|
||||
if (WARN(ktime_before(mld->scan.last_mlo_scan_start_time,
|
||||
ktime_sub_ns(ktime_get_boottime_ns(),
|
||||
5ULL * NSEC_PER_SEC)),
|
||||
"Last MLO scan was too long ago, can't select links\n"))
|
||||
|
||||
@@ -287,6 +287,8 @@ static void iwl_mld_handle_beacon_notification(struct iwl_mld *mld,
|
||||
* at least enough bytes to cover the structure listed in the CMD_VER_ENTRY.
|
||||
*/
|
||||
|
||||
CMD_VERSIONS(scan_start_notif,
|
||||
CMD_VER_ENTRY(1, iwl_umac_scan_start))
|
||||
CMD_VERSIONS(scan_complete_notif,
|
||||
CMD_VER_ENTRY(1, iwl_umac_scan_complete))
|
||||
CMD_VERSIONS(scan_iter_complete_notif,
|
||||
@@ -360,6 +362,7 @@ DEFINE_SIMPLE_CANCELLATION(datapath_monitor, iwl_datapath_monitor_notif,
|
||||
link_id)
|
||||
DEFINE_SIMPLE_CANCELLATION(roc, iwl_roc_notif, activity)
|
||||
DEFINE_SIMPLE_CANCELLATION(scan_complete, iwl_umac_scan_complete, uid)
|
||||
DEFINE_SIMPLE_CANCELLATION(scan_start, iwl_umac_scan_start, uid)
|
||||
DEFINE_SIMPLE_CANCELLATION(probe_resp_data, iwl_probe_resp_data_notif,
|
||||
mac_id)
|
||||
DEFINE_SIMPLE_CANCELLATION(uapsd_misbehaving_ap, iwl_uapsd_misbehaving_ap_notif,
|
||||
@@ -402,6 +405,8 @@ const struct iwl_rx_handler iwl_mld_rx_handlers[] = {
|
||||
RX_HANDLER_SYNC)
|
||||
RX_HANDLER_NO_OBJECT(LEGACY_GROUP, BA_NOTIF, compressed_ba_notif,
|
||||
RX_HANDLER_SYNC)
|
||||
RX_HANDLER_OF_SCAN(LEGACY_GROUP, SCAN_START_NOTIFICATION_UMAC,
|
||||
scan_start_notif)
|
||||
RX_HANDLER_OF_SCAN(LEGACY_GROUP, SCAN_COMPLETE_UMAC,
|
||||
scan_complete_notif)
|
||||
RX_HANDLER_NO_OBJECT(LEGACY_GROUP, SCAN_ITERATION_COMPLETE_UMAC,
|
||||
|
||||
@@ -473,6 +473,9 @@ iwl_mld_scan_get_cmd_gen_flags(struct iwl_mld *mld,
|
||||
params->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ)
|
||||
flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_TRIGGER_UHB_SCAN;
|
||||
|
||||
if (scan_status == IWL_MLD_SCAN_INT_MLO)
|
||||
flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_NTF_START;
|
||||
|
||||
if (params->enable_6ghz_passive)
|
||||
flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_6GHZ_PASSIVE_SCAN;
|
||||
|
||||
@@ -1817,9 +1820,6 @@ static void iwl_mld_int_mlo_scan_start(struct iwl_mld *mld,
|
||||
ret = _iwl_mld_single_scan_start(mld, vif, req, &ies,
|
||||
IWL_MLD_SCAN_INT_MLO);
|
||||
|
||||
if (!ret)
|
||||
mld->scan.last_mlo_scan_time = ktime_get_boottime_ns();
|
||||
|
||||
IWL_DEBUG_SCAN(mld, "Internal MLO scan: ret=%d\n", ret);
|
||||
}
|
||||
|
||||
@@ -1904,6 +1904,30 @@ void iwl_mld_handle_match_found_notif(struct iwl_mld *mld,
|
||||
ieee80211_sched_scan_results(mld->hw);
|
||||
}
|
||||
|
||||
void iwl_mld_handle_scan_start_notif(struct iwl_mld *mld,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
struct iwl_umac_scan_complete *notif = (void *)pkt->data;
|
||||
u32 uid = le32_to_cpu(notif->uid);
|
||||
|
||||
if (IWL_FW_CHECK(mld, uid >= ARRAY_SIZE(mld->scan.uid_status),
|
||||
"FW reports out-of-range scan UID %d\n", uid))
|
||||
return;
|
||||
|
||||
if (IWL_FW_CHECK(mld, !(mld->scan.uid_status[uid] & mld->scan.status),
|
||||
"FW reports scan UID %d we didn't trigger\n", uid))
|
||||
return;
|
||||
|
||||
IWL_DEBUG_SCAN(mld, "Scan started: uid=%u type=%u\n", uid,
|
||||
mld->scan.uid_status[uid]);
|
||||
if (IWL_FW_CHECK(mld, mld->scan.uid_status[uid] != IWL_MLD_SCAN_INT_MLO,
|
||||
"FW reports scan start notification %d we didn't trigger\n",
|
||||
mld->scan.uid_status[uid]))
|
||||
return;
|
||||
|
||||
mld->scan.last_mlo_scan_start_time = ktime_get_boottime_ns();
|
||||
}
|
||||
|
||||
void iwl_mld_handle_scan_complete_notif(struct iwl_mld *mld,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
|
||||
@@ -27,6 +27,9 @@ int iwl_mld_sched_scan_start(struct iwl_mld *mld,
|
||||
void iwl_mld_handle_match_found_notif(struct iwl_mld *mld,
|
||||
struct iwl_rx_packet *pkt);
|
||||
|
||||
void iwl_mld_handle_scan_start_notif(struct iwl_mld *mld,
|
||||
struct iwl_rx_packet *pkt);
|
||||
|
||||
void iwl_mld_handle_scan_complete_notif(struct iwl_mld *mld,
|
||||
struct iwl_rx_packet *pkt);
|
||||
|
||||
@@ -114,8 +117,8 @@ enum iwl_mld_traffic_load {
|
||||
* in jiffies.
|
||||
* @last_start_time_jiffies: stores the last start time in jiffies
|
||||
* (interface up/reset/resume).
|
||||
* @last_mlo_scan_time: start time of the last MLO scan in nanoseconds since
|
||||
* boot.
|
||||
* @last_mlo_scan_start_time: start time of the last MLO scan in nanoseconds
|
||||
* since boot.
|
||||
*/
|
||||
struct iwl_mld_scan {
|
||||
/* Add here fields that need clean up on restart */
|
||||
@@ -136,7 +139,7 @@ struct iwl_mld_scan {
|
||||
void *cmd;
|
||||
unsigned long last_6ghz_passive_jiffies;
|
||||
unsigned long last_start_time_jiffies;
|
||||
u64 last_mlo_scan_time;
|
||||
u64 last_mlo_scan_start_time;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -2807,7 +2807,7 @@ static void iwl_mvm_nd_match_info_handler(struct iwl_mvm *mvm,
|
||||
if (IS_ERR_OR_NULL(vif))
|
||||
return;
|
||||
|
||||
if (len < sizeof(struct iwl_scan_offload_match_info)) {
|
||||
if (len < sizeof(struct iwl_scan_offload_match_info) + matches_len) {
|
||||
IWL_ERR(mvm, "Invalid scan match info notification\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -470,7 +470,8 @@ static void iwl_mvm_uats_init(struct iwl_mvm *mvm)
|
||||
.dataflags[0] = IWL_HCMD_DFL_NOCOPY,
|
||||
};
|
||||
|
||||
if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) {
|
||||
if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210 ||
|
||||
!mvm->trans->cfg->uhb_supported) {
|
||||
IWL_DEBUG_RADIO(mvm, "UATS feature is not supported\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source,
|
||||
u32 index = 0;
|
||||
u32 i, scan_timeout;
|
||||
u8 *buffer;
|
||||
u8 valuesize = 0;
|
||||
u32 valuesize = 0;
|
||||
u8 *search_ssid_vals = NULL;
|
||||
const u8 ch_list_len = request->n_channels;
|
||||
struct host_if_drv *hif_drv = vif->hif_drv;
|
||||
|
||||
@@ -402,12 +402,14 @@ static void wl1251_tx_packet_cb(struct wl1251 *wl,
|
||||
int hdrlen;
|
||||
u8 *frame;
|
||||
|
||||
skb = wl->tx_frames[result->id];
|
||||
if (skb == NULL) {
|
||||
wl1251_error("SKB for packet %d is NULL", result->id);
|
||||
if (unlikely(result->id >= ARRAY_SIZE(wl->tx_frames) ||
|
||||
wl->tx_frames[result->id] == NULL)) {
|
||||
wl1251_error("invalid packet id %u", result->id);
|
||||
return;
|
||||
}
|
||||
|
||||
skb = wl->tx_frames[result->id];
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
|
||||
|
||||
@@ -557,7 +557,6 @@ static int virt_wifi_newlink(struct net_device *dev,
|
||||
eth_hw_addr_inherit(dev, priv->lowerdev);
|
||||
netif_stacked_transfer_operstate(priv->lowerdev, dev);
|
||||
|
||||
SET_NETDEV_DEV(dev, &priv->lowerdev->dev);
|
||||
dev->ieee80211_ptr = kzalloc_obj(*dev->ieee80211_ptr);
|
||||
|
||||
if (!dev->ieee80211_ptr) {
|
||||
|
||||
@@ -5097,6 +5097,7 @@ static inline bool skb_has_extensions(struct sk_buff *skb)
|
||||
return unlikely(skb->active_extensions);
|
||||
}
|
||||
#else
|
||||
static inline void __skb_ext_put(struct skb_ext *ext) {}
|
||||
static inline void skb_ext_put(struct sk_buff *skb) {}
|
||||
static inline void skb_ext_reset(struct sk_buff *skb) {}
|
||||
static inline void skb_ext_del(struct sk_buff *skb, int unused) {}
|
||||
|
||||
@@ -17,6 +17,7 @@ struct netns_mpls {
|
||||
size_t platform_labels;
|
||||
struct mpls_route __rcu * __rcu *platform_label;
|
||||
struct mutex platform_mutex;
|
||||
seqcount_mutex_t platform_label_seq;
|
||||
|
||||
struct ctl_table_header *ctl;
|
||||
};
|
||||
|
||||
@@ -1209,6 +1209,9 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
|
||||
ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
|
||||
ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
|
||||
ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;
|
||||
ndmsg->nduseropt_pad1 = 0;
|
||||
ndmsg->nduseropt_pad2 = 0;
|
||||
ndmsg->nduseropt_pad3 = 0;
|
||||
|
||||
memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);
|
||||
|
||||
|
||||
@@ -83,14 +83,30 @@ static struct mpls_route *mpls_route_input(struct net *net, unsigned int index)
|
||||
return mpls_dereference(net, platform_label[index]);
|
||||
}
|
||||
|
||||
static struct mpls_route __rcu **mpls_platform_label_rcu(struct net *net, size_t *platform_labels)
|
||||
{
|
||||
struct mpls_route __rcu **platform_label;
|
||||
unsigned int sequence;
|
||||
|
||||
do {
|
||||
sequence = read_seqcount_begin(&net->mpls.platform_label_seq);
|
||||
platform_label = rcu_dereference(net->mpls.platform_label);
|
||||
*platform_labels = net->mpls.platform_labels;
|
||||
} while (read_seqcount_retry(&net->mpls.platform_label_seq, sequence));
|
||||
|
||||
return platform_label;
|
||||
}
|
||||
|
||||
static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned int index)
|
||||
{
|
||||
struct mpls_route __rcu **platform_label;
|
||||
size_t platform_labels;
|
||||
|
||||
if (index >= net->mpls.platform_labels)
|
||||
platform_label = mpls_platform_label_rcu(net, &platform_labels);
|
||||
|
||||
if (index >= platform_labels)
|
||||
return NULL;
|
||||
|
||||
platform_label = rcu_dereference(net->mpls.platform_label);
|
||||
return rcu_dereference(platform_label[index]);
|
||||
}
|
||||
|
||||
@@ -2240,8 +2256,7 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
if (index < MPLS_LABEL_FIRST_UNRESERVED)
|
||||
index = MPLS_LABEL_FIRST_UNRESERVED;
|
||||
|
||||
platform_label = rcu_dereference(net->mpls.platform_label);
|
||||
platform_labels = net->mpls.platform_labels;
|
||||
platform_label = mpls_platform_label_rcu(net, &platform_labels);
|
||||
|
||||
if (filter.filter_set)
|
||||
flags |= NLM_F_DUMP_FILTERED;
|
||||
@@ -2645,8 +2660,12 @@ static int resize_platform_label_table(struct net *net, size_t limit)
|
||||
}
|
||||
|
||||
/* Update the global pointers */
|
||||
local_bh_disable();
|
||||
write_seqcount_begin(&net->mpls.platform_label_seq);
|
||||
net->mpls.platform_labels = limit;
|
||||
rcu_assign_pointer(net->mpls.platform_label, labels);
|
||||
write_seqcount_end(&net->mpls.platform_label_seq);
|
||||
local_bh_enable();
|
||||
|
||||
mutex_unlock(&net->mpls.platform_mutex);
|
||||
|
||||
@@ -2728,6 +2747,8 @@ static __net_init int mpls_net_init(struct net *net)
|
||||
int i;
|
||||
|
||||
mutex_init(&net->mpls.platform_mutex);
|
||||
seqcount_mutex_init(&net->mpls.platform_label_seq, &net->mpls.platform_mutex);
|
||||
|
||||
net->mpls.platform_labels = 0;
|
||||
net->mpls.platform_label = NULL;
|
||||
net->mpls.ip_ttl_propagate = 1;
|
||||
|
||||
@@ -118,7 +118,7 @@ static DEFINE_XARRAY_ALLOC(qrtr_ports);
|
||||
* @ep: endpoint
|
||||
* @ref: reference count for node
|
||||
* @nid: node id
|
||||
* @qrtr_tx_flow: tree of qrtr_tx_flow, keyed by node << 32 | port
|
||||
* @qrtr_tx_flow: xarray of qrtr_tx_flow, keyed by node << 32 | port
|
||||
* @qrtr_tx_lock: lock for qrtr_tx_flow inserts
|
||||
* @rx_queue: receive queue
|
||||
* @item: list item for broadcast list
|
||||
@@ -129,7 +129,7 @@ struct qrtr_node {
|
||||
struct kref ref;
|
||||
unsigned int nid;
|
||||
|
||||
struct radix_tree_root qrtr_tx_flow;
|
||||
struct xarray qrtr_tx_flow;
|
||||
struct mutex qrtr_tx_lock; /* for qrtr_tx_flow */
|
||||
|
||||
struct sk_buff_head rx_queue;
|
||||
@@ -172,6 +172,7 @@ static void __qrtr_node_release(struct kref *kref)
|
||||
struct qrtr_tx_flow *flow;
|
||||
unsigned long flags;
|
||||
void __rcu **slot;
|
||||
unsigned long index;
|
||||
|
||||
spin_lock_irqsave(&qrtr_nodes_lock, flags);
|
||||
/* If the node is a bridge for other nodes, there are possibly
|
||||
@@ -189,11 +190,9 @@ static void __qrtr_node_release(struct kref *kref)
|
||||
skb_queue_purge(&node->rx_queue);
|
||||
|
||||
/* Free tx flow counters */
|
||||
radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
|
||||
flow = *slot;
|
||||
radix_tree_iter_delete(&node->qrtr_tx_flow, &iter, slot);
|
||||
xa_for_each(&node->qrtr_tx_flow, index, flow)
|
||||
kfree(flow);
|
||||
}
|
||||
xa_destroy(&node->qrtr_tx_flow);
|
||||
kfree(node);
|
||||
}
|
||||
|
||||
@@ -228,9 +227,7 @@ static void qrtr_tx_resume(struct qrtr_node *node, struct sk_buff *skb)
|
||||
|
||||
key = remote_node << 32 | remote_port;
|
||||
|
||||
rcu_read_lock();
|
||||
flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
|
||||
rcu_read_unlock();
|
||||
flow = xa_load(&node->qrtr_tx_flow, key);
|
||||
if (flow) {
|
||||
spin_lock(&flow->resume_tx.lock);
|
||||
flow->pending = 0;
|
||||
@@ -269,12 +266,13 @@ static int qrtr_tx_wait(struct qrtr_node *node, int dest_node, int dest_port,
|
||||
return 0;
|
||||
|
||||
mutex_lock(&node->qrtr_tx_lock);
|
||||
flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
|
||||
flow = xa_load(&node->qrtr_tx_flow, key);
|
||||
if (!flow) {
|
||||
flow = kzalloc_obj(*flow);
|
||||
if (flow) {
|
||||
init_waitqueue_head(&flow->resume_tx);
|
||||
if (radix_tree_insert(&node->qrtr_tx_flow, key, flow)) {
|
||||
if (xa_err(xa_store(&node->qrtr_tx_flow, key, flow,
|
||||
GFP_KERNEL))) {
|
||||
kfree(flow);
|
||||
flow = NULL;
|
||||
}
|
||||
@@ -326,9 +324,7 @@ static void qrtr_tx_flow_failed(struct qrtr_node *node, int dest_node,
|
||||
unsigned long key = (u64)dest_node << 32 | dest_port;
|
||||
struct qrtr_tx_flow *flow;
|
||||
|
||||
rcu_read_lock();
|
||||
flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
|
||||
rcu_read_unlock();
|
||||
flow = xa_load(&node->qrtr_tx_flow, key);
|
||||
if (flow) {
|
||||
spin_lock_irq(&flow->resume_tx.lock);
|
||||
flow->tx_failed = 1;
|
||||
@@ -599,7 +595,7 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid)
|
||||
node->nid = QRTR_EP_NID_AUTO;
|
||||
node->ep = ep;
|
||||
|
||||
INIT_RADIX_TREE(&node->qrtr_tx_flow, GFP_KERNEL);
|
||||
xa_init(&node->qrtr_tx_flow);
|
||||
mutex_init(&node->qrtr_tx_lock);
|
||||
|
||||
qrtr_node_assign(node, nid);
|
||||
@@ -627,6 +623,7 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
|
||||
struct qrtr_tx_flow *flow;
|
||||
struct sk_buff *skb;
|
||||
unsigned long flags;
|
||||
unsigned long index;
|
||||
void __rcu **slot;
|
||||
|
||||
mutex_lock(&node->ep_lock);
|
||||
@@ -649,10 +646,8 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
|
||||
|
||||
/* Wake up any transmitters waiting for resume-tx from the node */
|
||||
mutex_lock(&node->qrtr_tx_lock);
|
||||
radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
|
||||
flow = *slot;
|
||||
xa_for_each(&node->qrtr_tx_flow, index, flow)
|
||||
wake_up_interruptible_all(&flow->resume_tx);
|
||||
}
|
||||
mutex_unlock(&node->qrtr_tx_lock);
|
||||
|
||||
qrtr_node_release(node);
|
||||
|
||||
Reference in New Issue
Block a user