From: Lachlan Hodges <lachlan.hodges@morsemicro.com>
To: johannes@sipsolutions.net,
Lachlan Hodges <lachlan.hodges@morsemicro.com>,
Dan Callaghan <dan.callaghan@morsemicro.com>,
Arien Judge <arien.judge@morsemicro.com>
Cc: ayman.grais@morsemicro.com, linux-wireless@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH wireless-next v2 02/31] wifi: mm81x: add command.c
Date: Thu, 30 Apr 2026 14:55:28 +1000 [thread overview]
Message-ID: <20260430045615.334669-3-lachlan.hodges@morsemicro.com> (raw)
In-Reply-To: <20260430045615.334669-1-lachlan.hodges@morsemicro.com>
(Patches split per file for review, will be a single commit alongside
SDIO ids once review is complete. See cover letter for more
information)
Signed-off-by: Lachlan Hodges <lachlan.hodges@morsemicro.com>
---
.../net/wireless/morsemicro/mm81x/command.c | 569 ++++++++++++++++++
1 file changed, 569 insertions(+)
create mode 100644 drivers/net/wireless/morsemicro/mm81x/command.c
diff --git a/drivers/net/wireless/morsemicro/mm81x/command.c b/drivers/net/wireless/morsemicro/mm81x/command.c
new file mode 100644
index 000000000000..704453c6f139
--- /dev/null
+++ b/drivers/net/wireless/morsemicro/mm81x/command.c
@@ -0,0 +1,569 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2017-2026 Morse Micro
+ */
+
+#include <linux/types.h>
+#include <linux/atomic.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+#include "command.h"
+#include "mac.h"
+#include "ps.h"
+#include "hif.h"
+
+#define MM_MAX_COMMAND_RETRY 2
+#define HOST_CMD_DEFAULT_TIMEOUT_MS 600
+#define HOST_CMD_POWERSAVE_TIMEOUT_MS 2000
+
+#define INIT_CMD_HDR(_req, _cmd, _vif_id) \
+ ((struct host_cmd_header){ \
+ .flags = cpu_to_le16(0), \
+ .message_id = cpu_to_le16(_cmd), \
+ .len = cpu_to_le16(sizeof(_req) - sizeof((_req).hdr)), \
+ .host_id = cpu_to_le16(0), \
+ .vif_id = cpu_to_le16(_vif_id), \
+ .pad = cpu_to_le16(0), \
+ })
+
+struct host_cmd_resp_cb {
+ int ret;
+ u32 length;
+ struct host_cmd_resp *dest_resp;
+};
+
+static int mm81x_cmd_tx(struct mm81x *mors, struct host_cmd_resp *resp,
+ struct host_cmd_req *req, u32 length, u32 timeout)
+{
+ int cmd_len;
+ int ret = 0;
+ u16 host_id;
+ int retry = 0;
+ unsigned long wait_ret = 0;
+ struct sk_buff *skb;
+ struct mm81x_skbq *cmd_q = mm81x_hif_get_tx_cmd_queue(mors);
+ struct host_cmd_resp_cb *resp_cb;
+ DECLARE_COMPLETION_ONSTACK(cmd_comp);
+
+ BUILD_BUG_ON(sizeof(struct host_cmd_resp_cb) >
+ IEEE80211_TX_INFO_DRIVER_DATA_SIZE);
+
+ if (!cmd_q)
+ /* No control pageset, not supported by FW */
+ return -ENODEV;
+
+ cmd_len = sizeof(*req) + le16_to_cpu(req->hdr.len);
+ req->hdr.flags = cpu_to_le16(HOST_CMD_TYPE_REQ);
+
+ mutex_lock(&mors->cmd_wait);
+ mors->cmd_seq++;
+ if (mors->cmd_seq > HOST_CMD_HOST_ID_SEQ_MAX)
+ mors->cmd_seq = 1;
+ host_id = mors->cmd_seq << HOST_CMD_HOST_ID_SEQ_SHIFT;
+
+ mm81x_ps_disable(mors);
+
+ do {
+ req->hdr.host_id = cpu_to_le16(host_id | retry);
+
+ skb = mm81x_skbq_alloc_skb(cmd_q, cmd_len);
+ if (!skb) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ memcpy(skb->data, req, cmd_len);
+ resp_cb = (struct host_cmd_resp_cb *)IEEE80211_SKB_CB(skb)
+ ->driver_data;
+ resp_cb->length = length;
+ resp_cb->dest_resp = resp;
+
+ dev_dbg(mors->dev, "CMD 0x%04x:%04x",
+ le16_to_cpu(req->hdr.message_id),
+ le16_to_cpu(req->hdr.host_id));
+
+ mutex_lock(&mors->cmd_lock);
+ mors->cmd_comp = &cmd_comp;
+ if (retry > 0)
+ reinit_completion(&cmd_comp);
+ timeout = timeout ? timeout : HOST_CMD_DEFAULT_TIMEOUT_MS;
+ ret = mm81x_skbq_skb_tx(cmd_q, &skb, NULL,
+ MM81X_SKB_CHAN_COMMAND);
+ mutex_unlock(&mors->cmd_lock);
+
+ if (ret) {
+ dev_err(mors->dev, "mm81x_skbq_tx fail: %d", ret);
+ break;
+ }
+
+ wait_ret = wait_for_completion_timeout(
+ &cmd_comp, msecs_to_jiffies(timeout));
+ mutex_lock(&mors->cmd_lock);
+ mors->cmd_comp = NULL;
+
+ if (!wait_ret) {
+ dev_err(mors->dev,
+ "Try:%d Command %04x:%04x timeout after %u ms",
+ retry, le16_to_cpu(req->hdr.message_id),
+ le16_to_cpu(req->hdr.host_id), timeout);
+ ret = -ETIMEDOUT;
+ } else {
+ ret = (length && resp) ? le32_to_cpu(resp->status) :
+ resp_cb->ret;
+
+ dev_dbg(mors->dev, "Command 0x%04x:%04x status 0x%08x",
+ le16_to_cpu(req->hdr.message_id),
+ le16_to_cpu(req->hdr.host_id), ret);
+ if (ret) {
+ dev_err(mors->dev,
+ "Command 0x%04x:%04x error %d",
+ le16_to_cpu(req->hdr.message_id),
+ le16_to_cpu(req->hdr.host_id), ret);
+ }
+ }
+ /* Free the command request */
+ spin_lock_bh(&cmd_q->lock);
+ mm81x_skbq_skb_finish(cmd_q, skb, NULL);
+ spin_unlock_bh(&cmd_q->lock);
+ mutex_unlock(&mors->cmd_lock);
+
+ retry++;
+ } while ((ret == -ETIMEDOUT) && retry < MM_MAX_COMMAND_RETRY);
+
+ mm81x_ps_enable(mors);
+ mutex_unlock(&mors->cmd_wait);
+
+ if (ret == -ETIMEDOUT) {
+ dev_err(mors->dev, "Command %02x:%02x timed out",
+ le16_to_cpu(req->hdr.message_id),
+ le16_to_cpu(req->hdr.host_id));
+ } else if (ret != 0) {
+ dev_err(mors->dev,
+ "Command %02x:%02x failed with rc %d (0x%x)\n",
+ le16_to_cpu(req->hdr.message_id),
+ le16_to_cpu(req->hdr.host_id), ret, ret);
+ }
+
+ return ret;
+}
+
+int mm81x_cmd_resp_process(struct mm81x *mors, struct sk_buff *skb)
+{
+ int length, ret = -ESRCH; /* No such process */
+ struct mm81x_skbq *cmd_q = mm81x_hif_get_tx_cmd_queue(mors);
+ struct host_cmd_resp *src_resp = (struct host_cmd_resp *)(skb->data);
+ struct sk_buff *cmd_skb = NULL;
+ struct host_cmd_resp_cb *resp_cb;
+ struct host_cmd_resp *dest_resp;
+ struct host_cmd_req *req;
+ u16 message_id = 0;
+ u16 host_id = 0;
+ u16 resp_message_id = le16_to_cpu(src_resp->hdr.message_id);
+ u16 resp_host_id = le16_to_cpu(src_resp->hdr.host_id);
+ bool is_late_response = false;
+
+ dev_dbg(mors->dev, "EVT 0x%04x:0x%04x", resp_message_id, resp_host_id);
+
+ if (!HOST_CMD_IS_RESP(src_resp)) {
+ ret = mm81x_mac_event_recv(mors, skb);
+ goto exit_free;
+ }
+
+ mutex_lock(&mors->cmd_lock);
+
+ cmd_skb = mm81x_skbq_tx_pending(cmd_q);
+ if (cmd_skb) {
+ mm81x_skbq_pull_hdr_post_tx(cmd_skb);
+ req = (struct host_cmd_req *)cmd_skb->data;
+ message_id = le16_to_cpu(req->hdr.message_id);
+ host_id = le16_to_cpu(req->hdr.host_id);
+ }
+
+ /*
+ * If there is no pending command or the sequence ID does not match,
+ * this is a late response for a timed out command which has been
+ * cleaned up, so just free up the response. If a command was retried,
+ * the response may be from the retry or from the original command
+ * (late response) but not from both because the firmware will silently
+ * drop a retry if it received the initial request. So a mismatched
+ * retry counter is treated as a matched command and response.
+ */
+ if (!cmd_skb || message_id != resp_message_id ||
+ (host_id & HOST_CMD_HOST_ID_SEQ_MASK) !=
+ (resp_host_id & HOST_CMD_HOST_ID_SEQ_MASK)) {
+ dev_err(mors->dev,
+ "Late response for timed out req 0x%04x:%04x have 0x%04x:%04x 0x%04x",
+ resp_message_id, resp_host_id, message_id, host_id,
+ mors->cmd_seq);
+ is_late_response = true;
+ goto exit;
+ }
+ if ((host_id & HOST_CMD_HOST_ID_RETRY_MASK) !=
+ (resp_host_id & HOST_CMD_HOST_ID_RETRY_MASK))
+ dev_dbg(mors->dev,
+ "Command retry mismatch 0x%04x:%04x 0x%04x:%04x",
+ message_id, host_id, resp_message_id, resp_host_id);
+
+ resp_cb = (struct host_cmd_resp_cb *)IEEE80211_SKB_CB(cmd_skb)
+ ->driver_data;
+ length = resp_cb->length;
+ dest_resp = resp_cb->dest_resp;
+ if (length >= sizeof(struct host_cmd_resp) && dest_resp) {
+ ret = 0;
+ length = min_t(int, length,
+ le16_to_cpu(src_resp->hdr.len) +
+ sizeof(struct host_cmd_header));
+ memcpy(dest_resp, src_resp, length);
+ } else {
+ ret = le32_to_cpu(src_resp->status);
+ }
+
+ resp_cb->ret = ret;
+
+exit:
+ if (cmd_skb && !is_late_response) {
+ /* Complete if not already timed out */
+ if (mors->cmd_comp)
+ complete(mors->cmd_comp);
+ }
+
+ mutex_unlock(&mors->cmd_lock);
+exit_free:
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+int mm81x_cmd_sta_state(struct mm81x *mors, struct mm81x_vif *mors_vif, u16 aid,
+ struct ieee80211_sta *sta,
+ enum ieee80211_sta_state state)
+{
+ struct host_cmd_req_set_sta_state req = {
+ .hdr = INIT_CMD_HDR(req, HOST_CMD_ID_SET_STA_STATE,
+ mors_vif->id),
+ .aid = cpu_to_le16(aid),
+ .state = cpu_to_le16(state),
+ .uapsd_queues = sta->uapsd_queues,
+ };
+
+ memcpy(req.sta_addr, sta->addr, sizeof(req.sta_addr));
+
+ return mm81x_cmd_tx(mors, NULL, (struct host_cmd_req *)&req, 0, 0);
+}
+
+int mm81x_cmd_add_if(struct mm81x *mors, u16 *vif_id, const u8 *addr,
+ enum nl80211_iftype type)
+{
+ int ret;
+ struct host_cmd_req_add_interface req = {
+ .hdr = INIT_CMD_HDR(req, HOST_CMD_ID_ADD_INTERFACE, 0),
+ };
+ struct host_cmd_resp_add_interface resp;
+
+ switch (type) {
+ case NL80211_IFTYPE_STATION:
+ req.interface_type = cpu_to_le32(HOST_CMD_INTERFACE_TYPE_STA);
+ break;
+ case NL80211_IFTYPE_AP:
+ req.interface_type = cpu_to_le32(HOST_CMD_INTERFACE_TYPE_AP);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ memcpy(req.addr.octet, addr, sizeof(req.addr.octet));
+
+ ret = mm81x_cmd_tx(mors, (struct host_cmd_resp *)&resp,
+ (struct host_cmd_req *)&req, sizeof(resp), 0);
+ if (!ret)
+ *vif_id = le16_to_cpu(resp.hdr.vif_id);
+
+ return ret;
+}
+
+int mm81x_cmd_get_capabilities(struct mm81x *mors, u16 vif_id,
+ struct mm81x_fw_caps *capabilities)
+{
+ int ret;
+ int i;
+ struct host_cmd_req_get_capabilities req = {
+ .hdr = INIT_CMD_HDR(req, HOST_CMD_ID_GET_CAPABILITIES, vif_id),
+ };
+ struct host_cmd_resp_get_capabilities rsp;
+
+ ret = mm81x_cmd_tx(mors, (struct host_cmd_resp *)&rsp,
+ (struct host_cmd_req *)&req, sizeof(rsp), 0);
+ if (ret)
+ return ret;
+
+ capabilities->ampdu_mss = rsp.capabilities.ampdu_mss;
+ capabilities->mm81x_mmss_offset = rsp.morse_mmss_offset;
+ capabilities->beamformee_sts_capability =
+ rsp.capabilities.beamformee_sts_capability;
+ capabilities->maximum_ampdu_length_exponent =
+ rsp.capabilities.maximum_ampdu_length_exponent;
+ capabilities->number_sounding_dimensions =
+ rsp.capabilities.number_sounding_dimensions;
+ for (i = 0; i < FW_CAPABILITIES_FLAGS_WIDTH; i++)
+ capabilities->flags[i] = le32_to_cpu(rsp.capabilities.flags[i]);
+
+ return ret;
+}
+
+int mm81x_cmd_get_max_txpower(struct mm81x *mors, s32 *out_power_mbm)
+{
+ int ret;
+ struct host_cmd_req_get_max_txpower req = {
+ .hdr = INIT_CMD_HDR(req, HOST_CMD_ID_GET_MAX_TXPOWER, 0),
+ };
+ struct host_cmd_resp_get_max_txpower resp;
+
+ ret = mm81x_cmd_tx(mors, (struct host_cmd_resp *)&resp,
+ (struct host_cmd_req *)&req, sizeof(resp), 0);
+ if (!ret)
+ *out_power_mbm = QDBM_TO_MBM(le32_to_cpu(resp.power_qdbm));
+
+ return ret;
+}
+
+int mm81x_cmd_hw_scan(struct mm81x *mors, struct mm81x_hw_scan_params *params,
+ bool store)
+{
+ int ret;
+ struct host_cmd_req_hw_scan *req;
+ size_t cmd_size;
+ u8 *buf;
+ u32 flags = 0;
+
+ cmd_size = mm81x_hw_scan_h_get_cmd_size(params);
+ cmd_size = ROUND_BYTES_TO_WORD(cmd_size);
+
+ req = kzalloc(cmd_size, GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ buf = req->variable;
+
+ if (store)
+ flags = HOST_CMD_HW_SCAN_FLAGS_STORE;
+ else if (params->operation == MM81X_HW_SCAN_OP_START)
+ flags |= HOST_CMD_HW_SCAN_FLAGS_START;
+ else if (params->operation == MM81X_HW_SCAN_OP_STOP)
+ flags |= HOST_CMD_HW_SCAN_FLAGS_ABORT;
+
+ if (params->use_1mhz_probes)
+ flags |= HOST_CMD_HW_SCAN_FLAGS_1MHZ_PROBES;
+
+ if (params->operation == MM81X_HW_SCAN_OP_START) {
+ req->dwell_time_ms = cpu_to_le32(params->dwell_time_ms);
+ buf = mm81x_hw_scan_h_insert_tlvs(params, buf);
+ }
+
+ req->flags = cpu_to_le32(flags);
+ req->hdr = INIT_CMD_HDR((*req), HOST_CMD_ID_HW_SCAN, 0);
+ req->hdr.len = cpu_to_le16((u16)((buf - (u8 *)req) - sizeof(req->hdr)));
+ ret = mm81x_cmd_tx(mors, NULL, (struct host_cmd_req *)req, 0, 0);
+ kfree(req);
+
+ return ret;
+}
+
+int mm81x_cmd_set_txpower(struct mm81x *mors, s32 *out_power_mbm,
+ int txpower_mbm)
+{
+ int ret;
+ struct host_cmd_req_set_txpower req = {
+ .hdr = INIT_CMD_HDR(req, HOST_CMD_ID_SET_TXPOWER, 0),
+ .power_qdbm = cpu_to_le32(MBM_TO_QDBM(txpower_mbm)),
+ };
+ struct host_cmd_resp_set_txpower resp;
+
+ ret = mm81x_cmd_tx(mors, (struct host_cmd_resp *)&resp,
+ (struct host_cmd_req *)&req, sizeof(resp), 0);
+ if (!ret)
+ *out_power_mbm = QDBM_TO_MBM(le32_to_cpu(resp.power_qdbm));
+
+ return ret;
+}
+
+int mm81x_cmd_set_channel(struct mm81x *mors, u32 op_chan_freq_hz,
+ u8 pri_1mhz_chan_idx, u8 op_bw_mhz, u8 pri_bw_mhz,
+ s32 *power_mbm)
+{
+ int ret;
+ struct host_cmd_req_set_channel req = {
+ .hdr = INIT_CMD_HDR(req, HOST_CMD_ID_SET_CHANNEL, 0),
+ .op_chan_freq_hz = cpu_to_le32(op_chan_freq_hz),
+ .op_bw_mhz = op_bw_mhz,
+ .pri_bw_mhz = pri_bw_mhz,
+ .pri_1mhz_chan_idx = pri_1mhz_chan_idx,
+ .dot11_mode = HOST_CMD_DOT11_PROTO_MODE_AH,
+ };
+ struct host_cmd_resp_set_channel resp;
+
+ ret = mm81x_cmd_tx(mors, (struct host_cmd_resp *)&resp,
+ (struct host_cmd_req *)&req, sizeof(resp), 0);
+ if (!ret)
+ *power_mbm = QDBM_TO_MBM(le32_to_cpu(resp.power_qdbm));
+
+ return ret;
+}
+
+int mm81x_cmd_disable_key(struct mm81x *mors, struct mm81x_vif *mors_vif,
+ u16 aid, struct ieee80211_key_conf *key)
+{
+ struct host_cmd_req_disable_key req = {
+ .hdr = INIT_CMD_HDR(req, HOST_CMD_ID_DISABLE_KEY, mors_vif->id),
+ .aid = cpu_to_le32(aid),
+ .key_idx = key->hw_key_idx,
+ .key_type =
+ cpu_to_le32((key->flags & IEEE80211_KEY_FLAG_PAIRWISE) ?
+ HOST_CMD_TEMPORAL_KEY_TYPE_PTK :
+ HOST_CMD_TEMPORAL_KEY_TYPE_GTK),
+ };
+
+ return mm81x_cmd_tx(mors, NULL, (struct host_cmd_req *)&req, 0, 0);
+}
+
+int mm81x_cmd_install_key(struct mm81x *mors, struct mm81x_vif *mors_vif,
+ u16 aid, struct ieee80211_key_conf *key,
+ enum host_cmd_key_cipher cipher,
+ enum host_cmd_aes_key_len length)
+{
+ int ret;
+ struct host_cmd_req_install_key req = {
+ .hdr = INIT_CMD_HDR(req, HOST_CMD_ID_INSTALL_KEY, mors_vif->id),
+ .pn = cpu_to_le64(atomic64_read(&key->tx_pn)),
+ .aid = cpu_to_le32(aid),
+ .cipher = cipher,
+ .key_length = length,
+ .key_idx = key->keyidx,
+ .key_type = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) ?
+ HOST_CMD_TEMPORAL_KEY_TYPE_PTK :
+ HOST_CMD_TEMPORAL_KEY_TYPE_GTK,
+ };
+ struct host_cmd_resp_install_key resp;
+
+ if (key->keylen > sizeof(req.key))
+ return -EINVAL;
+
+ memcpy(req.key, key->key, key->keylen);
+
+ ret = mm81x_cmd_tx(mors, (struct host_cmd_resp *)&resp,
+ (struct host_cmd_req *)&req, sizeof(resp), 0);
+ if (!ret) {
+ key->hw_key_idx = resp.key_idx;
+ dev_dbg(mors->dev, "Installed key @ hw index: %d",
+ resp.key_idx);
+ }
+
+ return ret;
+}
+
+int mm81x_cmd_cfg_multicast_filter(struct mm81x *mors,
+ struct mm81x_vif *mors_vif)
+{
+ struct host_cmd_req_mcast_filter *req;
+ struct mcast_filter *filter = mors->mcast_filter;
+ u16 filter_list_len = sizeof(filter->addr_list[0]) * filter->count;
+ u16 alloc_len = filter_list_len + sizeof(*req);
+ int ret = 0;
+
+ req = kzalloc(alloc_len, GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ req->hdr = INIT_CMD_HDR((*req), HOST_CMD_ID_MCAST_FILTER, mors_vif->id);
+ req->hdr.len = cpu_to_le16(alloc_len - sizeof(req->hdr));
+ req->count = filter->count;
+ memcpy(req->hw_addr, filter->addr_list, filter_list_len);
+
+ ret = mm81x_cmd_tx(mors, NULL, (struct host_cmd_req *)req, 0, 0);
+ kfree(req);
+ return ret;
+}
+
+int mm81x_cmd_cfg_bss(struct mm81x *mors, u16 vif_id, u16 beacon_int,
+ u16 dtim_period, u32 cssid)
+{
+ struct host_cmd_req_bss_config req = {
+ .hdr = INIT_CMD_HDR(req, HOST_CMD_ID_BSS_CONFIG, vif_id),
+ .beacon_interval_tu = cpu_to_le16(beacon_int),
+ .cssid = cpu_to_le32(cssid),
+ .dtim_period = cpu_to_le16(dtim_period),
+ };
+
+ return mm81x_cmd_tx(mors, NULL, (struct host_cmd_req *)&req, 0, 0);
+}
+
+int mm81x_cmd_config_beacon_timer(struct mm81x *mors, void *mm81x_vif,
+ bool enabled)
+{
+ struct mm81x_vif *vif = mm81x_vif;
+ struct host_cmd_req_bss_beacon_config req = {
+ .hdr = INIT_CMD_HDR(req, HOST_CMD_ID_BSS_BEACON_CONFIG,
+ vif->id),
+ .enable = enabled,
+ };
+
+ return mm81x_cmd_tx(mors, NULL, (struct host_cmd_req *)&req, 0, 0);
+}
+
+int mm81x_cmd_set_ps(struct mm81x *mors, bool enabled)
+{
+ struct host_cmd_req_config_ps req = {
+ .hdr = INIT_CMD_HDR(req, HOST_CMD_ID_CONFIG_PS, 0),
+ .enabled = (u8)enabled,
+ };
+
+ return mm81x_cmd_tx(mors, NULL, (struct host_cmd_req *)&req, 0,
+ HOST_CMD_POWERSAVE_TIMEOUT_MS);
+}
+
+int mm81x_cmd_cfg_qos(struct mm81x *mors, struct mm81x_queue_params *params)
+{
+ struct host_cmd_req_set_qos_params req = {
+ .hdr = INIT_CMD_HDR(req, HOST_CMD_ID_SET_QOS_PARAMS, 0),
+ .uapsd = params->uapsd,
+ .queue_idx = params->aci,
+ .aifs_slot_count = params->aifs,
+ .contention_window_min = cpu_to_le16(params->cw_min),
+ .contention_window_max = cpu_to_le16(params->cw_max),
+ .max_txop_usec = cpu_to_le32(params->txop),
+ };
+
+ return mm81x_cmd_tx(mors, NULL, (struct host_cmd_req *)&req, 0, 0);
+}
+
+int mm81x_cmd_rm_if(struct mm81x *mors, u16 vif_id)
+{
+ struct host_cmd_req_remove_interface req = {
+ .hdr = INIT_CMD_HDR(req, HOST_CMD_ID_REMOVE_INTERFACE, vif_id),
+ };
+
+ return mm81x_cmd_tx(mors, NULL, (struct host_cmd_req *)&req, 0, 0);
+}
+
+int mm81x_cmd_set_frag_threshold(struct mm81x *mors, u32 frag_threshold)
+{
+ struct host_cmd_req_get_set_generic_param req = {
+ .hdr = INIT_CMD_HDR(req, HOST_CMD_ID_GET_SET_GENERIC_PARAM, 0),
+ .param_id = cpu_to_le32(HOST_CMD_PARAM_ID_FRAGMENT_THRESHOLD),
+ .action = cpu_to_le32(HOST_CMD_PARAM_ACTION_SET),
+ .value = cpu_to_le32(frag_threshold),
+ };
+
+ return mm81x_cmd_tx(mors, NULL, (struct host_cmd_req *)&req, 0, 0);
+}
+
+int mm81x_cmd_get_disabled_channels(
+ struct mm81x *mors, struct host_cmd_resp_get_disabled_channels *resp,
+ uint resp_len)
+{
+ struct host_cmd_req req = {
+ .hdr = INIT_CMD_HDR(req, HOST_CMD_ID_GET_DISABLED_CHANNELS, 0),
+ };
+
+ return mm81x_cmd_tx(mors, (struct host_cmd_resp *)resp, &req, resp_len,
+ 0);
+}
--
2.43.0
next prev parent reply other threads:[~2026-04-30 4:56 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-30 4:55 [PATCH wireless-next v2 00/31] wifi: mm81x: add mm81x driver Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 01/31] wifi: mm81x: add bus.h Lachlan Hodges
2026-04-30 4:55 ` Lachlan Hodges [this message]
2026-04-30 4:55 ` [PATCH wireless-next v2 03/31] wifi: mm81x: add command_defs.h Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 04/31] wifi: mm81x: add command.h Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 05/31] wifi: mm81x: add core.c Lachlan Hodges
2026-05-01 5:45 ` Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 06/31] wifi: mm81x: add core.h Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 07/31] wifi: mm81x: add fw.c Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 08/31] wifi: mm81x: add fw.h Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 09/31] wifi: mm81x: add hif.h Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 10/31] wifi: mm81x: add hw.c Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 11/31] wifi: mm81x: add hw.h Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 12/31] wifi: mm81x: add mac.c Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 13/31] wifi: mm81x: add mac.h Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 14/31] wifi: mm81x: add mmrc.c Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 15/31] wifi: mm81x: add mmrc.h Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 16/31] wifi: mm81x: add ps.c Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 17/31] wifi: mm81x: add ps.h Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 18/31] wifi: mm81x: add rate_code.h Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 19/31] wifi: mm81x: add rc.c Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 20/31] wifi: mm81x: add rc.h Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 21/31] mmc: sdio: add Morse Micro vendor ids Lachlan Hodges
2026-05-11 14:54 ` Ulf Hansson
2026-04-30 4:55 ` [PATCH wireless-next v2 22/31] wifi: mm81x: add sdio.c Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 23/31] wifi: mm81x: add skbq.c Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 24/31] wifi: mm81x: add skbq.h Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 25/31] wifi: mm81x: add usb.c Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 26/31] wifi: mm81x: add yaps.c Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 27/31] wifi: mm81x: add yaps.h Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 28/31] wifi: mm81x: add yaps_hw.c Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 29/31] wifi: mm81x: add yaps_hw.h Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 30/31] wifi: mm81x: add Kconfig and Makefile Lachlan Hodges
2026-04-30 4:55 ` [PATCH wireless-next v2 31/31] wifi: mm81x: add MAINTAINERS entry Lachlan Hodges
2026-04-30 5:43 ` [PATCH wireless-next v2 00/31] wifi: mm81x: add mm81x driver Lachlan Hodges
2026-04-30 6:09 ` Johannes Berg
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260430045615.334669-3-lachlan.hodges@morsemicro.com \
--to=lachlan.hodges@morsemicro.com \
--cc=arien.judge@morsemicro.com \
--cc=ayman.grais@morsemicro.com \
--cc=dan.callaghan@morsemicro.com \
--cc=johannes@sipsolutions.net \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-wireless@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox