Skip to content

Commit

Permalink
wifi: iwlwifi: support ROC version 6
Browse files Browse the repository at this point in the history
Version 6 added ROC with multi repetitions.
We don't use it, but need to update the command
length.

Signed-off-by: Shaul Triebitz <shaul.triebitz@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20250205145347.956c33729d48.I609835c08f0003c084a13a1e1e505cb7bc8ecbc6@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
  • Loading branch information
Shaul Triebitz authored and Johannes Berg committed Feb 11, 2025
1 parent 9e8c760 commit af3be90
Show file tree
Hide file tree
Showing 3 changed files with 265 additions and 7 deletions.
42 changes: 38 additions & 4 deletions drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Copyright (C) 2012-2014, 2018-2020, 2022-2024 Intel Corporation
* Copyright (C) 2012-2014, 2018-2020, 2022-2025 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
Expand Down Expand Up @@ -351,7 +351,7 @@ enum iwl_roc_activity {
}; /* ROC_ACTIVITY_API_E_VER_1 */

/*
* ROC command
* ROC command v5
*
* Command requests the firmware to remain on a channel for a certain duration.
*
Expand All @@ -366,7 +366,7 @@ enum iwl_roc_activity {
* @max_delay: max delay the ROC can start in TU
* @duration: remain on channel duration in TU
*/
struct iwl_roc_req {
struct iwl_roc_req_v5 {
__le32 action;
__le32 activity;
__le32 sta_id;
Expand All @@ -375,7 +375,41 @@ struct iwl_roc_req {
__le16 reserved;
__le32 max_delay;
__le32 duration;
} __packed; /* ROC_CMD_API_S_VER_3 */
} __packed; /* ROC_CMD_API_S_VER_5 */

/*
* ROC command
*
* Command requests the firmware to remain on a channel for a certain duration.
*
* ( MAC_CONF_GROUP 0x3, ROC_CMD 0xE )
*
* @action: action to perform, see &enum iwl_ctxt_action
* @activity: type of activity, see &enum iwl_roc_activity
* @sta_id: station id, resumed during "Remain On Channel" activity.
* @channel_info: &struct iwl_fw_channel_info
* @node_addr: node MAC address for Rx filtering
* @reserved1: align to a dword
* @max_delay: max delay the ROC can start in TU
* @duration: remain on channel duration in TU
* @interval: interval between repetitions (when repetitions > 1).
* @repetitions: number of repetitions
* 0xFF: infinite repetitions. 0 or 1: single repetition.
* @reserved2: align to a dword
*/
struct iwl_roc_req {
__le32 action;
__le32 activity;
__le32 sta_id;
struct iwl_fw_channel_info channel_info;
u8 node_addr[ETH_ALEN];
__le16 reserved1;
__le32 max_delay;
__le32 duration;
__le32 interval;
u8 repetitions;
u8 reserved2[3];
} __packed; /* ROC_CMD_API_S_VER_6 */

/*
* ROC notification
Expand Down
224 changes: 224 additions & 0 deletions drivers/net/wireless/intel/iwlwifi/mld/roc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2024 - 2025 Intel Corporation
*/
#include <net/cfg80211.h>
#include <net/mac80211.h>

#include "mld.h"
#include "roc.h"
#include "hcmd.h"
#include "iface.h"
#include "sta.h"
#include "mlo.h"

#include "fw/api/context.h"
#include "fw/api/time-event.h"

#define AUX_ROC_MAX_DELAY MSEC_TO_TU(200)

static void
iwl_mld_vif_iter_emlsr_block_roc(void *data, u8 *mac, struct ieee80211_vif *vif)
{
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
int *result = data;
int ret;

ret = iwl_mld_block_emlsr_sync(mld_vif->mld, vif,
IWL_MLD_EMLSR_BLOCKED_ROC,
iwl_mld_get_primary_link(vif));
if (ret)
*result = ret;
}

int iwl_mld_start_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_channel *channel, int duration,
enum ieee80211_roc_type type)
{
struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
struct iwl_mld_int_sta *aux_sta;
struct iwl_roc_req cmd = {
.action = cpu_to_le32(FW_CTXT_ACTION_ADD),
};
u8 ver = iwl_fw_lookup_cmd_ver(mld->fw,
WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0);
u16 cmd_len = ver < 6 ? sizeof(struct iwl_roc_req_v5) : sizeof(cmd);
enum iwl_roc_activity activity;
int ret = 0;

lockdep_assert_wiphy(mld->wiphy);

ieee80211_iterate_active_interfaces_mtx(mld->hw,
IEEE80211_IFACE_ITER_NORMAL,
iwl_mld_vif_iter_emlsr_block_roc,
&ret);
if (ret)
return ret;

/* TODO: task=Hotspot 2.0 */
if (vif->type != NL80211_IFTYPE_P2P_DEVICE) {
IWL_ERR(mld, "NOT SUPPORTED: ROC on vif->type %d\n",
vif->type);

return -EOPNOTSUPP;
}

switch (type) {
case IEEE80211_ROC_TYPE_NORMAL:
activity = ROC_ACTIVITY_P2P_DISC;
break;
case IEEE80211_ROC_TYPE_MGMT_TX:
activity = ROC_ACTIVITY_P2P_NEG;
break;
default:
WARN_ONCE(1, "Got an invalid P2P ROC type\n");
return -EINVAL;
}

if (WARN_ON(mld_vif->roc_activity != ROC_NUM_ACTIVITIES))
return -EBUSY;

/* No MLO on P2P device */
aux_sta = &mld_vif->deflink.aux_sta;

ret = iwl_mld_add_aux_sta(mld, aux_sta);
if (ret)
return ret;

cmd.activity = cpu_to_le32(activity);
cmd.sta_id = cpu_to_le32(aux_sta->sta_id);
cmd.channel_info.channel = cpu_to_le32(channel->hw_value);
cmd.channel_info.band = iwl_mld_nl80211_band_to_fw(channel->band);
cmd.channel_info.width = IWL_PHY_CHANNEL_MODE20;
/* TODO: task=Hotspot 2.0, revisit those parameters when we add an ROC
* on the BSS vif
*/
cmd.max_delay = cpu_to_le32(AUX_ROC_MAX_DELAY);
cmd.duration = cpu_to_le32(MSEC_TO_TU(duration));

memcpy(cmd.node_addr, vif->addr, ETH_ALEN);

ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(MAC_CONF_GROUP, ROC_CMD),
&cmd, cmd_len);
if (ret) {
IWL_ERR(mld, "Couldn't send the ROC_CMD\n");
return ret;
}
mld_vif->roc_activity = activity;

return 0;
}

static void
iwl_mld_vif_iter_emlsr_unblock_roc(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);

iwl_mld_unblock_emlsr(mld_vif->mld, vif, IWL_MLD_EMLSR_BLOCKED_ROC);
}

static void iwl_mld_destroy_roc(struct iwl_mld *mld,
struct ieee80211_vif *vif,
struct iwl_mld_vif *mld_vif)
{
mld_vif->roc_activity = ROC_NUM_ACTIVITIES;

ieee80211_iterate_active_interfaces_mtx(mld->hw,
IEEE80211_IFACE_ITER_NORMAL,
iwl_mld_vif_iter_emlsr_unblock_roc,
NULL);

/* wait until every tx has seen that roc_activity has been reset */
synchronize_net();
/* from here, no new tx will be added
* we can flush the Tx on the queues
*/

iwl_mld_flush_link_sta_txqs(mld, mld_vif->deflink.aux_sta.sta_id);

iwl_mld_remove_aux_sta(mld, vif, &vif->bss_conf);
}

int iwl_mld_cancel_roc(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
struct iwl_roc_req cmd = {
.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
};
u8 ver = iwl_fw_lookup_cmd_ver(mld->fw,
WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0);
u16 cmd_len = ver < 6 ? sizeof(struct iwl_roc_req_v5) : sizeof(cmd);
int ret;

lockdep_assert_wiphy(mld->wiphy);

/* TODO: task=Hotspot 2.0 */
if (WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE))
return -EOPNOTSUPP;

/* No roc activity running it's probably already done */
if (mld_vif->roc_activity == ROC_NUM_ACTIVITIES)
return 0;

cmd.activity = cpu_to_le32(mld_vif->roc_activity);

ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(MAC_CONF_GROUP, ROC_CMD),
&cmd, cmd_len);
if (ret)
IWL_ERR(mld, "Couldn't send the command to cancel the ROC\n");

/* We may have raced with the firmware expiring the ROC instance at
* this very moment. In that case, we can have a notification in the
* async processing queue. However, none can arrive _after_ this as
* ROC_CMD was sent synchronously, i.e. we waited for a response and
* the firmware cannot refer to this ROC after the response. Thus,
* if we just cancel the notification (if there's one) we'll be at a
* clean state for any possible next ROC.
*/
iwl_mld_cancel_notifications_of_object(mld, IWL_MLD_OBJECT_TYPE_ROC,
mld_vif->roc_activity);

iwl_mld_destroy_roc(mld, vif, mld_vif);

return 0;
}

void iwl_mld_handle_roc_notif(struct iwl_mld *mld,
struct iwl_rx_packet *pkt)
{
const struct iwl_roc_notif *notif = (void *)pkt->data;
u32 activity = le32_to_cpu(notif->activity);
/* TODO: task=Hotspot 2.0 - roc can run on BSS */
struct ieee80211_vif *vif = mld->p2p_device_vif;
struct iwl_mld_vif *mld_vif;

if (WARN_ON(!vif))
return;

mld_vif = iwl_mld_vif_from_mac80211(vif);
/* It is possible that the ROC was canceled
* but the notification was already fired.
*/
if (mld_vif->roc_activity != activity)
return;

if (le32_to_cpu(notif->success) &&
le32_to_cpu(notif->started)) {
/* We had a successful start */
ieee80211_ready_on_channel(mld->hw);
} else {
/* ROC was not successful, tell the firmware to remove it */
if (le32_to_cpu(notif->started))
iwl_mld_cancel_roc(mld->hw, vif);
else
iwl_mld_destroy_roc(mld, vif, mld_vif);
/* we need to let know mac80211 about end OR
* an unsuccessful start
*/
ieee80211_remain_on_channel_expired(mld->hw);
}
}
6 changes: 3 additions & 3 deletions drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2012-2014, 2018-2024 Intel Corporation
* Copyright (C) 2012-2014, 2018-2025 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2017 Intel Deutschland GmbH
*/
Expand Down Expand Up @@ -771,7 +771,7 @@ static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm,

static void iwl_mvm_roc_rm_cmd(struct iwl_mvm *mvm, u32 activity)
{
struct iwl_roc_req roc_cmd = {
struct iwl_roc_req_v5 roc_cmd = {
.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
.activity = cpu_to_le32(activity),
};
Expand Down Expand Up @@ -1100,7 +1100,7 @@ int iwl_mvm_roc_add_cmd(struct iwl_mvm *mvm,
{
int res;
u32 duration_tu, delay;
struct iwl_roc_req roc_req = {
struct iwl_roc_req_v5 roc_req = {
.action = cpu_to_le32(FW_CTXT_ACTION_ADD),
.activity = cpu_to_le32(activity),
.sta_id = cpu_to_le32(mvm->aux_sta.sta_id),
Expand Down

0 comments on commit af3be90

Please sign in to comment.