Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/net/wireless/mediatek/mt76/mt7921/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 34 kB image not shown  

Quelle  mcu.c   Sprache: C

 
// SPDX-License-Identifier: ISC
/* Copyright (C) 2020 MediaTek Inc. */

#include <linux/fs.h>
#include <linux/firmware.h>
#include "mt7921.h"
#include "mcu.h"
#include "../mt76_connac2_mac.h"
#include "../mt792x_trace.h"

#define MT_STA_BFER   BIT(0)
#define MT_STA_BFEE   BIT(1)

static bool mt7921_disable_clc;
module_param_named(disable_clc, mt7921_disable_clc, bool, 0644);
MODULE_PARM_DESC(disable_clc, "disable CLC support");

int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
         struct sk_buff *skb, int seq)
{
 int mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd);
 struct mt76_connac2_mcu_rxd *rxd;
 int ret = 0;

 if (!skb) {
  dev_err(mdev->dev, "Message %08x (seq %d) timeout\n",
   cmd, seq);
  mt792x_reset(mdev);

  return -ETIMEDOUT;
 }

 rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
 if (seq != rxd->seq)
  return -EAGAIN;

 if (cmd == MCU_CMD(PATCH_SEM_CONTROL) ||
     cmd == MCU_CMD(PATCH_FINISH_REQ)) {
  skb_pull(skb, sizeof(*rxd) - 4);
  ret = *skb->data;
 } else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) {
  skb_pull(skb, sizeof(*rxd) + 4);
  ret = le32_to_cpu(*(__le32 *)skb->data);
 } else if (cmd == MCU_UNI_CMD(DEV_INFO_UPDATE) ||
     cmd == MCU_UNI_CMD(BSS_INFO_UPDATE) ||
     cmd == MCU_UNI_CMD(STA_REC_UPDATE) ||
     cmd == MCU_UNI_CMD(HIF_CTRL) ||
     cmd == MCU_UNI_CMD(OFFLOAD) ||
     cmd == MCU_UNI_CMD(SUSPEND)) {
  struct mt76_connac_mcu_uni_event *event;

  skb_pull(skb, sizeof(*rxd));
  event = (struct mt76_connac_mcu_uni_event *)skb->data;
  ret = le32_to_cpu(event->status);
  /* skip invalid event */
  if (mcu_cmd != event->cid)
   ret = -EAGAIN;
 } else if (cmd == MCU_CE_QUERY(REG_READ)) {
  struct mt76_connac_mcu_reg_event *event;

  skb_pull(skb, sizeof(*rxd));
  event = (struct mt76_connac_mcu_reg_event *)skb->data;
  ret = (int)le32_to_cpu(event->val);
 } else if (cmd == MCU_EXT_CMD(WF_RF_PIN_CTRL)) {
  struct mt7921_wf_rf_pin_ctrl_event *event;

  skb_pull(skb, sizeof(*rxd));
  event = (struct mt7921_wf_rf_pin_ctrl_event *)skb->data;
  ret = (int)event->result;
 } else {
  skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
 }

 return ret;
}
EXPORT_SYMBOL_GPL(mt7921_mcu_parse_response);

static int mt7921_mcu_read_eeprom(struct mt792x_dev *dev, u32 offset, u8 *val)
{
 struct mt7921_mcu_eeprom_info *res, req = {
  .addr = cpu_to_le32(round_down(offset,
        MT7921_EEPROM_BLOCK_SIZE)),
 };
 struct sk_buff *skb;
 int ret;

 ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(EFUSE_ACCESS),
     &req, sizeof(req), true, &skb);
 if (ret)
  return ret;

 res = (struct mt7921_mcu_eeprom_info *)skb->data;
 *val = res->data[offset % MT7921_EEPROM_BLOCK_SIZE];
 dev_kfree_skb(skb);

 return 0;
}

#ifdef CONFIG_PM

static int
mt7921_mcu_set_ipv6_ns_filter(struct mt76_dev *dev,
         struct ieee80211_vif *vif, bool suspend)
{
 struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
 struct {
  struct {
   u8 bss_idx;
   u8 pad[3];
  } __packed hdr;
  struct mt76_connac_arpns_tlv arpns;
 } req = {
  .hdr = {
   .bss_idx = mvif->bss_conf.mt76.idx,
  },
  .arpns = {
   .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ND),
   .len = cpu_to_le16(sizeof(struct mt76_connac_arpns_tlv)),
   .mode = suspend,
  },
 };

 return mt76_mcu_send_msg(dev, MCU_UNI_CMD_OFFLOAD, &req, sizeof(req),
     true);
}

void mt7921_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
 if (IS_ENABLED(CONFIG_IPV6)) {
  struct mt76_phy *phy = priv;

  mt7921_mcu_set_ipv6_ns_filter(phy->dev, vif,
           !test_bit(MT76_STATE_RUNNING,
           &phy->state));
 }

 mt76_connac_mcu_set_suspend_iter(priv, mac, vif);
}

#endif /* CONFIG_PM */

static void
mt7921_mcu_uni_roc_event(struct mt792x_dev *dev, struct sk_buff *skb)
{
 struct mt7921_roc_grant_tlv *grant;
 struct mt76_connac2_mcu_rxd *rxd;
 int duration;

 rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
 grant = (struct mt7921_roc_grant_tlv *)(rxd->tlv + 4);

 /* should never happen */
 WARN_ON_ONCE((le16_to_cpu(grant->tag) != UNI_EVENT_ROC_GRANT));

 if (grant->reqtype == MT7921_ROC_REQ_ROC)
  ieee80211_ready_on_channel(dev->mt76.phy.hw);

 dev->phy.roc_grant = true;
 wake_up(&dev->phy.roc_wait);
 duration = le32_to_cpu(grant->max_interval);
 mod_timer(&dev->phy.roc_timer,
    jiffies + msecs_to_jiffies(duration));
}

static void
mt7921_mcu_scan_event(struct mt792x_dev *dev, struct sk_buff *skb)
{
 struct mt76_phy *mphy = &dev->mt76.phy;
 struct mt792x_phy *phy = mphy->priv;

 spin_lock_bh(&dev->mt76.lock);
 __skb_queue_tail(&phy->scan_event_list, skb);
 spin_unlock_bh(&dev->mt76.lock);

 ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work,
         MT792x_HW_SCAN_TIMEOUT);
}

static void
mt7921_mcu_connection_loss_iter(void *priv, u8 *mac,
    struct ieee80211_vif *vif)
{
 struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;
 struct mt76_connac_beacon_loss_event *event = priv;

 if (mvif->idx != event->bss_idx)
  return;

 if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER) ||
     vif->type != NL80211_IFTYPE_STATION)
  return;

 ieee80211_connection_loss(vif);
}

static void
mt7921_mcu_connection_loss_event(struct mt792x_dev *dev, struct sk_buff *skb)
{
 struct mt76_connac_beacon_loss_event *event;
 struct mt76_phy *mphy = &dev->mt76.phy;

 skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
 event = (struct mt76_connac_beacon_loss_event *)skb->data;

 ieee80211_iterate_active_interfaces_atomic(mphy->hw,
     IEEE80211_IFACE_ITER_RESUME_ALL,
     mt7921_mcu_connection_loss_iter, event);
}

static void
mt7921_mcu_debug_msg_event(struct mt792x_dev *dev, struct sk_buff *skb)
{
 struct mt7921_debug_msg {
  __le16 id;
  u8 type;
  u8 flag;
  __le32 value;
  __le16 len;
  u8 content[512];
 } __packed * msg;

 skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
 msg = (struct mt7921_debug_msg *)skb->data;

 if (msg->type == 3) { /* fw log */
  u16 len = min_t(u16, le16_to_cpu(msg->len), 512);
  int i;

  for (i = 0 ; i < len; i++) {
   if (!msg->content[i])
    msg->content[i] = ' ';
  }
  wiphy_info(mt76_hw(dev)->wiphy, "%.*s", len, msg->content);
 }
}

static void
mt7921_mcu_low_power_event(struct mt792x_dev *dev, struct sk_buff *skb)
{
 struct mt7921_mcu_lp_event {
  u8 state;
  u8 reserved[3];
 } __packed * event;

 skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
 event = (struct mt7921_mcu_lp_event *)skb->data;

 trace_lp_event(dev, event->state);
}

static void
mt7921_mcu_tx_done_event(struct mt792x_dev *dev, struct sk_buff *skb)
{
 struct mt7921_mcu_tx_done_event *event;

 skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
 event = (struct mt7921_mcu_tx_done_event *)skb->data;

 mt7921_mac_add_txs(dev, event->txs);
}

static void
mt7921_mcu_rssi_monitor_iter(void *priv, u8 *mac,
        struct ieee80211_vif *vif)
{
 struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
 struct mt76_connac_rssi_notify_event *event = priv;
 enum nl80211_cqm_rssi_threshold_event nl_event;
 s32 rssi = le32_to_cpu(event->rssi[mvif->bss_conf.mt76.idx]);

 if (!rssi)
  return;

 if (!(vif->driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI))
  return;

 if (rssi > vif->bss_conf.cqm_rssi_thold)
  nl_event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
 else
  nl_event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;

 ieee80211_cqm_rssi_notify(vif, nl_event, rssi, GFP_KERNEL);
}

static void
mt7921_mcu_rssi_monitor_event(struct mt792x_dev *dev, struct sk_buff *skb)
{
 struct mt76_connac_rssi_notify_event *event;

 skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
 event = (struct mt76_connac_rssi_notify_event *)skb->data;

 ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
         IEEE80211_IFACE_ITER_RESUME_ALL,
         mt7921_mcu_rssi_monitor_iter, event);
}

static void
mt7921_mcu_rx_unsolicited_event(struct mt792x_dev *dev, struct sk_buff *skb)
{
 struct mt76_connac2_mcu_rxd *rxd;

 rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
 switch (rxd->eid) {
 case MCU_EVENT_BSS_BEACON_LOSS:
  mt7921_mcu_connection_loss_event(dev, skb);
  break;
 case MCU_EVENT_SCHED_SCAN_DONE:
 case MCU_EVENT_SCAN_DONE:
  mt7921_mcu_scan_event(dev, skb);
  return;
 case MCU_EVENT_DBG_MSG:
  mt7921_mcu_debug_msg_event(dev, skb);
  break;
 case MCU_EVENT_COREDUMP:
  dev->fw_assert = true;
  mt76_connac_mcu_coredump_event(&dev->mt76, skb,
            &dev->coredump);
  return;
 case MCU_EVENT_LP_INFO:
  mt7921_mcu_low_power_event(dev, skb);
  break;
 case MCU_EVENT_TX_DONE:
  mt7921_mcu_tx_done_event(dev, skb);
  break;
 case MCU_EVENT_RSSI_NOTIFY:
  mt7921_mcu_rssi_monitor_event(dev, skb);
  break;
 default:
  break;
 }
 dev_kfree_skb(skb);
}

static void
mt7921_mcu_uni_rx_unsolicited_event(struct mt792x_dev *dev,
        struct sk_buff *skb)
{
 struct mt76_connac2_mcu_rxd *rxd;

 rxd = (struct mt76_connac2_mcu_rxd *)skb->data;

 switch (rxd->eid) {
 case MCU_UNI_EVENT_ROC:
  mt7921_mcu_uni_roc_event(dev, skb);
  break;
 default:
  break;
 }
 dev_kfree_skb(skb);
}

void mt7921_mcu_rx_event(struct mt792x_dev *dev, struct sk_buff *skb)
{
 struct mt76_connac2_mcu_rxd *rxd;

 if (skb_linearize(skb))
  return;

 rxd = (struct mt76_connac2_mcu_rxd *)skb->data;

 if (rxd->option & MCU_UNI_CMD_UNSOLICITED_EVENT) {
  mt7921_mcu_uni_rx_unsolicited_event(dev, skb);
  return;
 }

 if (rxd->eid == 0x6) {
  mt76_mcu_rx_event(&dev->mt76, skb);
  return;
 }

 if (rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT ||
     rxd->eid == MCU_EVENT_BSS_BEACON_LOSS ||
     rxd->eid == MCU_EVENT_SCHED_SCAN_DONE ||
     rxd->eid == MCU_EVENT_RSSI_NOTIFY ||
     rxd->eid == MCU_EVENT_SCAN_DONE ||
     rxd->eid == MCU_EVENT_TX_DONE ||
     rxd->eid == MCU_EVENT_DBG_MSG ||
     rxd->eid == MCU_EVENT_COREDUMP ||
     rxd->eid == MCU_EVENT_LP_INFO ||
     !rxd->seq)
  mt7921_mcu_rx_unsolicited_event(dev, skb);
 else
  mt76_mcu_rx_event(&dev->mt76, skb);
}

/** starec & wtbl **/
int mt7921_mcu_uni_tx_ba(struct mt792x_dev *dev,
    struct ieee80211_ampdu_params *params,
    bool enable)
{
 struct mt792x_sta *msta = (struct mt792x_sta *)params->sta->drv_priv;

 if (enable && !params->amsdu)
  msta->deflink.wcid.amsdu = false;

 return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->bss_conf.mt76, params,
          MCU_UNI_CMD(STA_REC_UPDATE),
          enable, true);
}

int mt7921_mcu_uni_rx_ba(struct mt792x_dev *dev,
    struct ieee80211_ampdu_params *params,
    bool enable)
{
 struct mt792x_sta *msta = (struct mt792x_sta *)params->sta->drv_priv;

 return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->bss_conf.mt76, params,
          MCU_UNI_CMD(STA_REC_UPDATE),
          enable, false);
}

static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name)
{
 const struct mt76_connac2_fw_trailer *hdr;
 const struct mt76_connac2_fw_region *region;
 const struct mt7921_clc *clc;
 struct mt76_dev *mdev = &dev->mt76;
 struct mt792x_phy *phy = &dev->phy;
 const struct firmware *fw;
 int ret, i, len, offset = 0;
 u8 *clc_base = NULL, hw_encap = 0;

 dev->phy.clc_chan_conf = 0xff;
 if (mt7921_disable_clc ||
     mt76_is_usb(&dev->mt76))
  return 0;

 if (mt76_is_mmio(&dev->mt76)) {
  ret = mt7921_mcu_read_eeprom(dev, MT_EE_HW_TYPE, &hw_encap);
  if (ret)
   return ret;
  hw_encap = u8_get_bits(hw_encap, MT_EE_HW_TYPE_ENCAP);
 }

 ret = request_firmware(&fw, fw_name, mdev->dev);
 if (ret)
  return ret;

 if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
  dev_err(mdev->dev, "Invalid firmware\n");
  ret = -EINVAL;
  goto out;
 }

 hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));
 for (i = 0; i < hdr->n_region; i++) {
  region = (const void *)((const u8 *)hdr -
     (hdr->n_region - i) * sizeof(*region));
  len = le32_to_cpu(region->len);

  /* check if we have valid buffer size */
  if (offset + len > fw->size) {
   dev_err(mdev->dev, "Invalid firmware region\n");
   ret = -EINVAL;
   goto out;
  }

  if ((region->feature_set & FW_FEATURE_NON_DL) &&
      region->type == FW_TYPE_CLC) {
   clc_base = (u8 *)(fw->data + offset);
   break;
  }
  offset += len;
 }

 if (!clc_base)
  goto out;

 for (offset = 0; offset < len; offset += le32_to_cpu(clc->len)) {
  clc = (const struct mt7921_clc *)(clc_base + offset);

  /* do not init buf again if chip reset triggered */
  if (phy->clc[clc->idx])
   continue;

  /* header content sanity */
  if (clc->idx == MT7921_CLC_POWER &&
      u8_get_bits(clc->type, MT_EE_HW_TYPE_ENCAP) != hw_encap)
   continue;

  phy->clc[clc->idx] = devm_kmemdup(mdev->dev, clc,
        le32_to_cpu(clc->len),
        GFP_KERNEL);

  if (!phy->clc[clc->idx]) {
   ret = -ENOMEM;
   goto out;
  }
 }
 ret = mt7921_mcu_set_clc(dev, "00", ENVIRON_INDOOR);
out:
 release_firmware(fw);

 return ret;
}

static void mt7921_mcu_parse_tx_resource(struct mt76_dev *dev,
      struct sk_buff *skb)
{
 struct mt76_sdio *sdio = &dev->sdio;
 struct mt7921_tx_resource {
  __le32 version;
  __le32 pse_data_quota;
  __le32 pse_mcu_quota;
  __le32 ple_data_quota;
  __le32 ple_mcu_quota;
  __le16 pse_page_size;
  __le16 ple_page_size;
  u8 pp_padding;
  u8 pad[3];
 } __packed * tx_res;

 tx_res = (struct mt7921_tx_resource *)skb->data;
 sdio->sched.pse_data_quota = le32_to_cpu(tx_res->pse_data_quota);
 sdio->pse_mcu_quota_max = le32_to_cpu(tx_res->pse_mcu_quota);
 /* The mcu quota usage of this function itself must be taken into consideration */
 sdio->sched.pse_mcu_quota =
  sdio->sched.pse_mcu_quota ? sdio->pse_mcu_quota_max : sdio->pse_mcu_quota_max - 1;
 sdio->sched.ple_data_quota = le32_to_cpu(tx_res->ple_data_quota);
 sdio->sched.pse_page_size = le16_to_cpu(tx_res->pse_page_size);
 sdio->sched.deficit = tx_res->pp_padding;
}

static void mt7921_mcu_parse_phy_cap(struct mt76_dev *dev,
         struct sk_buff *skb)
{
 struct mt7921_phy_cap {
  u8 ht;
  u8 vht;
  u8 _5g;
  u8 max_bw;
  u8 nss;
  u8 dbdc;
  u8 tx_ldpc;
  u8 rx_ldpc;
  u8 tx_stbc;
  u8 rx_stbc;
  u8 hw_path;
  u8 he;
 } __packed * cap;

 enum {
  WF0_24G,
  WF0_5G
 };

 cap = (struct mt7921_phy_cap *)skb->data;

 dev->phy.antenna_mask = BIT(cap->nss) - 1;
 dev->phy.chainmask = dev->phy.antenna_mask;
 dev->phy.cap.has_2ghz = cap->hw_path & BIT(WF0_24G);
 dev->phy.cap.has_5ghz = cap->hw_path & BIT(WF0_5G);
}

static int mt7921_mcu_get_nic_capability(struct mt792x_phy *mphy)
{
 struct mt76_connac_cap_hdr {
  __le16 n_element;
  u8 rsv[2];
 } __packed * hdr;
 struct sk_buff *skb;
 struct mt76_phy *phy = mphy->mt76;
 int ret, i;

 ret = mt76_mcu_send_and_get_msg(phy->dev, MCU_CE_CMD(GET_NIC_CAPAB),
     NULL, 0, true, &skb);
 if (ret)
  return ret;

 hdr = (struct mt76_connac_cap_hdr *)skb->data;
 if (skb->len < sizeof(*hdr)) {
  ret = -EINVAL;
  goto out;
 }

 skb_pull(skb, sizeof(*hdr));

 for (i = 0; i < le16_to_cpu(hdr->n_element); i++) {
  struct tlv_hdr {
   __le32 type;
   __le32 len;
  } __packed * tlv = (struct tlv_hdr *)skb->data;
  int len;

  if (skb->len < sizeof(*tlv))
   break;

  skb_pull(skb, sizeof(*tlv));

  len = le32_to_cpu(tlv->len);
  if (skb->len < len)
   break;

  switch (le32_to_cpu(tlv->type)) {
  case MT_NIC_CAP_6G:
   phy->cap.has_6ghz = skb->data[0];
   break;
  case MT_NIC_CAP_MAC_ADDR:
   memcpy(phy->macaddr, (void *)skb->data, ETH_ALEN);
   break;
  case MT_NIC_CAP_PHY:
   mt7921_mcu_parse_phy_cap(phy->dev, skb);
   break;
  case MT_NIC_CAP_TX_RESOURCE:
   if (mt76_is_sdio(phy->dev))
    mt7921_mcu_parse_tx_resource(phy->dev,
            skb);
   break;
  case MT_NIC_CAP_CHIP_CAP:
   memcpy(&mphy->chip_cap, (void *)skb->data, sizeof(u64));
   break;
  default:
   break;
  }
  skb_pull(skb, len);
 }
out:
 dev_kfree_skb(skb);

 return ret;
}

int mt7921_mcu_fw_log_2_host(struct mt792x_dev *dev, u8 ctrl)
{
 struct {
  u8 ctrl_val;
  u8 pad[3];
 } data = {
  .ctrl_val = ctrl
 };

 return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(FWLOG_2_HOST),
     &data, sizeof(data), false);
}

int mt7921_run_firmware(struct mt792x_dev *dev)
{
 int err;

 err = mt792x_load_firmware(dev);
 if (err)
  return err;

 err = mt7921_mcu_get_nic_capability(&dev->phy);
 if (err)
  return err;

 set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
 err = mt7921_load_clc(dev, mt792x_ram_name(dev));
 if (err)
  return err;

 return mt7921_mcu_fw_log_2_host(dev, 1);
}
EXPORT_SYMBOL_GPL(mt7921_run_firmware);

int mt7921_mcu_radio_led_ctrl(struct mt792x_dev *dev, u8 value)
{
 struct {
  u8 ctrlid;
  u8 rsv[3];
 } __packed req = {
  .ctrlid = value,
 };

 return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ID_RADIO_ON_OFF_CTRL),
    &req, sizeof(req), false);
}
EXPORT_SYMBOL_GPL(mt7921_mcu_radio_led_ctrl);

int mt7921_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_vif *vif)
{
 struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
 struct edca {
  __le16 cw_min;
  __le16 cw_max;
  __le16 txop;
  __le16 aifs;
  u8 guardtime;
  u8 acm;
 } __packed;
 struct mt7921_mcu_tx {
  struct edca edca[IEEE80211_NUM_ACS];
  u8 bss_idx;
  u8 qos;
  u8 wmm_idx;
  u8 pad;
 } __packed req = {
  .bss_idx = mvif->bss_conf.mt76.idx,
  .qos = vif->bss_conf.qos,
  .wmm_idx = mvif->bss_conf.mt76.wmm_idx,
 };
 struct mu_edca {
  u8 cw_min;
  u8 cw_max;
  u8 aifsn;
  u8 acm;
  u8 timer;
  u8 padding[3];
 };
 struct mt7921_mcu_mu_tx {
  u8 ver;
  u8 pad0;
  __le16 len;
  u8 bss_idx;
  u8 qos;
  u8 wmm_idx;
  u8 pad1;
  struct mu_edca edca[IEEE80211_NUM_ACS];
  u8 pad3[32];
 } __packed req_mu = {
  .bss_idx = mvif->bss_conf.mt76.idx,
  .qos = vif->bss_conf.qos,
  .wmm_idx = mvif->bss_conf.mt76.wmm_idx,
 };
 static const int to_aci[] = { 1, 0, 2, 3 };
 int ac, ret;

 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
  struct ieee80211_tx_queue_params *q = &mvif->bss_conf.queue_params[ac];
  struct edca *e = &req.edca[to_aci[ac]];

  e->aifs = cpu_to_le16(q->aifs);
  e->txop = cpu_to_le16(q->txop);

  if (q->cw_min)
   e->cw_min = cpu_to_le16(q->cw_min);
  else
   e->cw_min = cpu_to_le16(5);

  if (q->cw_max)
   e->cw_max = cpu_to_le16(q->cw_max);
  else
   e->cw_max = cpu_to_le16(10);
 }

 ret = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_EDCA_PARMS), &req,
    sizeof(req), false);
 if (ret)
  return ret;

 if (!vif->bss_conf.he_support)
  return 0;

 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
  struct ieee80211_he_mu_edca_param_ac_rec *q;
  struct mu_edca *e;

  if (!mvif->bss_conf.queue_params[ac].mu_edca)
   break;

  q = &mvif->bss_conf.queue_params[ac].mu_edca_param_rec;
  e = &(req_mu.edca[to_aci[ac]]);

  e->cw_min = q->ecw_min_max & 0xf;
  e->cw_max = (q->ecw_min_max & 0xf0) >> 4;
  e->aifsn = q->aifsn;
  e->timer = q->mu_edca_timer;
 }

 return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_MU_EDCA_PARMS),
     &req_mu, sizeof(req_mu), false);
}

int mt7921_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_vif *vif,
         struct ieee80211_channel *chan, int duration,
         enum mt7921_roc_req type, u8 token_id)
{
 int center_ch = ieee80211_frequency_to_channel(chan->center_freq);
 struct mt792x_dev *dev = phy->dev;
 struct {
  struct {
   u8 rsv[4];
  } __packed hdr;
  struct roc_acquire_tlv {
   __le16 tag;
   __le16 len;
   u8 bss_idx;
   u8 tokenid;
   u8 control_channel;
   u8 sco;
   u8 band;
   u8 bw;
   u8 center_chan;
   u8 center_chan2;
   u8 bw_from_ap;
   u8 center_chan_from_ap;
   u8 center_chan2_from_ap;
   u8 reqtype;
   __le32 maxinterval;
   u8 dbdcband;
   u8 rsv[3];
  } __packed roc;
 } __packed req = {
  .roc = {
   .tag = cpu_to_le16(UNI_ROC_ACQUIRE),
   .len = cpu_to_le16(sizeof(struct roc_acquire_tlv)),
   .tokenid = token_id,
   .reqtype = type,
   .maxinterval = cpu_to_le32(duration),
   .bss_idx = vif->bss_conf.mt76.idx,
   .control_channel = chan->hw_value,
   .bw = CMD_CBW_20MHZ,
   .bw_from_ap = CMD_CBW_20MHZ,
   .center_chan = center_ch,
   .center_chan_from_ap = center_ch,
   .dbdcband = 0xff, /* auto */
  },
 };

 if (chan->hw_value < center_ch)
  req.roc.sco = 1; /* SCA */
 else if (chan->hw_value > center_ch)
  req.roc.sco = 3; /* SCB */

 switch (chan->band) {
 case NL80211_BAND_6GHZ:
  req.roc.band = 3;
  break;
 case NL80211_BAND_5GHZ:
  req.roc.band = 2;
  break;
 default:
  req.roc.band = 1;
  break;
 }

 return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(ROC),
     &req, sizeof(req), false);
}

int mt7921_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_vif *vif,
    u8 token_id)
{
 struct mt792x_dev *dev = phy->dev;
 struct {
  struct {
   u8 rsv[4];
  } __packed hdr;
  struct roc_abort_tlv {
   __le16 tag;
   __le16 len;
   u8 bss_idx;
   u8 tokenid;
   u8 dbdcband;
   u8 rsv[5];
  } __packed abort;
 } __packed req = {
  .abort = {
   .tag = cpu_to_le16(UNI_ROC_ABORT),
   .len = cpu_to_le16(sizeof(struct roc_abort_tlv)),
   .tokenid = token_id,
   .bss_idx = vif->bss_conf.mt76.idx,
   .dbdcband = 0xff, /* auto*/
  },
 };

 return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(ROC),
     &req, sizeof(req), false);
}

int mt7921_mcu_set_chan_info(struct mt792x_phy *phy, int cmd)
{
 struct mt792x_dev *dev = phy->dev;
 struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
 int freq1 = chandef->center_freq1;
 struct {
  u8 control_ch;
  u8 center_ch;
  u8 bw;
  u8 tx_streams_num;
  u8 rx_streams; /* mask or num */
  u8 switch_reason;
  u8 band_idx;
  u8 center_ch2; /* for 80+80 only */
  __le16 cac_case;
  u8 channel_band;
  u8 rsv0;
  __le32 outband_freq;
  u8 txpower_drop;
  u8 ap_bw;
  u8 ap_center_ch;
  u8 rsv1[57];
 } __packed req = {
  .control_ch = chandef->chan->hw_value,
  .center_ch = ieee80211_frequency_to_channel(freq1),
  .bw = mt76_connac_chan_bw(chandef),
  .tx_streams_num = hweight8(phy->mt76->antenna_mask),
  .rx_streams = phy->mt76->antenna_mask,
  .band_idx = phy != &dev->phy,
 };

 if (chandef->chan->band == NL80211_BAND_6GHZ)
  req.channel_band = 2;
 else
  req.channel_band = chandef->chan->band;

 if (cmd == MCU_EXT_CMD(SET_RX_PATH) ||
     dev->mt76.hw->conf.flags & IEEE80211_CONF_MONITOR)
  req.switch_reason = CH_SWITCH_NORMAL;
 else if (phy->mt76->offchannel)
  req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
 else if (!cfg80211_reg_can_beacon(dev->mt76.hw->wiphy, chandef,
       NL80211_IFTYPE_AP))
  req.switch_reason = CH_SWITCH_DFS;
 else
  req.switch_reason = CH_SWITCH_NORMAL;

 if (cmd == MCU_EXT_CMD(CHANNEL_SWITCH))
  req.rx_streams = hweight8(req.rx_streams);

 if (chandef->width == NL80211_CHAN_WIDTH_80P80) {
  int freq2 = chandef->center_freq2;

  req.center_ch2 = ieee80211_frequency_to_channel(freq2);
 }

 return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
}

int mt7921_mcu_set_eeprom(struct mt792x_dev *dev)
{
 struct req_hdr {
  u8 buffer_mode;
  u8 format;
  __le16 len;
 } __packed req = {
  .buffer_mode = EE_MODE_EFUSE,
  .format = EE_FORMAT_WHOLE,
 };

 return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EFUSE_BUFFER_MODE),
     &req, sizeof(req), true);
}
EXPORT_SYMBOL_GPL(mt7921_mcu_set_eeprom);

int mt7921_mcu_uni_bss_ps(struct mt792x_dev *dev, struct ieee80211_vif *vif)
{
 struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
 struct {
  struct {
   u8 bss_idx;
   u8 pad[3];
  } __packed hdr;
  struct ps_tlv {
   __le16 tag;
   __le16 len;
   u8 ps_state; /* 0: device awake
      * 1: static power save
      * 2: dynamic power saving
      * 3: enter TWT power saving
      * 4: leave TWT power saving
      */

   u8 pad[3];
  } __packed ps;
 } __packed ps_req = {
  .hdr = {
   .bss_idx = mvif->bss_conf.mt76.idx,
  },
  .ps = {
   .tag = cpu_to_le16(UNI_BSS_INFO_PS),
   .len = cpu_to_le16(sizeof(struct ps_tlv)),
   .ps_state = vif->cfg.ps ? 2 : 0,
  },
 };

 if (vif->type != NL80211_IFTYPE_STATION)
  return -EOPNOTSUPP;

 return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE),
     &ps_req, sizeof(ps_req), true);
}

static int
mt7921_mcu_uni_bss_bcnft(struct mt792x_dev *dev, struct ieee80211_vif *vif,
    bool enable)
{
 struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
 struct {
  struct {
   u8 bss_idx;
   u8 pad[3];
  } __packed hdr;
  struct bcnft_tlv {
   __le16 tag;
   __le16 len;
   __le16 bcn_interval;
   u8 dtim_period;
   u8 pad;
  } __packed bcnft;
 } __packed bcnft_req = {
  .hdr = {
   .bss_idx = mvif->bss_conf.mt76.idx,
  },
  .bcnft = {
   .tag = cpu_to_le16(UNI_BSS_INFO_BCNFT),
   .len = cpu_to_le16(sizeof(struct bcnft_tlv)),
   .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int),
   .dtim_period = vif->bss_conf.dtim_period,
  },
 };

 if (vif->type != NL80211_IFTYPE_STATION)
  return 0;

 return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE),
     &bcnft_req, sizeof(bcnft_req), true);
}

int
mt7921_mcu_set_bss_pm(struct mt792x_dev *dev, struct ieee80211_vif *vif,
        bool enable)
{
 struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
 struct {
  u8 bss_idx;
  u8 dtim_period;
  __le16 aid;
  __le16 bcn_interval;
  __le16 atim_window;
  u8 uapsd;
  u8 bmc_delivered_ac;
  u8 bmc_triggered_ac;
  u8 pad;
 } req = {
  .bss_idx = mvif->bss_conf.mt76.idx,
  .aid = cpu_to_le16(vif->cfg.aid),
  .dtim_period = vif->bss_conf.dtim_period,
  .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int),
 };
 struct {
  u8 bss_idx;
  u8 pad[3];
 } req_hdr = {
  .bss_idx = mvif->bss_conf.mt76.idx,
 };
 int err;

 err = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_ABORT),
    &req_hdr, sizeof(req_hdr), false);
 if (err < 0 || !enable)
  return err;

 return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_CONNECTED),
     &req, sizeof(req), false);
}

int mt7921_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_sta *sta,
     struct ieee80211_vif *vif, bool enable,
     enum mt76_sta_info_state state)
{
 struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
 int rssi = -ewma_rssi_read(&mvif->bss_conf.rssi);
 struct mt76_sta_cmd_info info = {
  .sta = sta,
  .vif = vif,
  .enable = enable,
  .cmd = MCU_UNI_CMD(STA_REC_UPDATE),
  .state = state,
  .offload_fw = true,
  .rcpi = to_rcpi(rssi),
 };
 struct mt792x_sta *msta;

 msta = sta ? (struct mt792x_sta *)sta->drv_priv : NULL;
 info.wcid = msta ? &msta->deflink.wcid : &mvif->sta.deflink.wcid;
 info.newly = msta ? state != MT76_STA_INFO_STATE_ASSOC : true;

 return mt76_connac_mcu_sta_cmd(&dev->mphy, &info);
}

int mt7921_mcu_set_beacon_filter(struct mt792x_dev *dev,
     struct ieee80211_vif *vif,
     bool enable)
{
#define MT7921_FIF_BIT_CLR  BIT(1)
#define MT7921_FIF_BIT_SET  BIT(0)
 int err;

 if (enable) {
  err = mt7921_mcu_uni_bss_bcnft(dev, vif, true);
  if (err)
   return err;

  err = mt7921_mcu_set_rxfilter(dev, 0,
           MT7921_FIF_BIT_SET,
           MT_WF_RFCR_DROP_OTHER_BEACON);
  if (err)
   return err;

  return 0;
 }

 err = mt7921_mcu_set_bss_pm(dev, vif, false);
 if (err)
  return err;

 err = mt7921_mcu_set_rxfilter(dev, 0,
          MT7921_FIF_BIT_CLR,
          MT_WF_RFCR_DROP_OTHER_BEACON);
 if (err)
  return err;

 return 0;
}

int mt7921_get_txpwr_info(struct mt792x_dev *dev, struct mt7921_txpwr *txpwr)
{
 struct mt7921_txpwr_event *event;
 struct mt7921_txpwr_req req = {
  .dbdc_idx = 0,
 };
 struct sk_buff *skb;
 int ret;

 ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CE_CMD(GET_TXPWR),
     &req, sizeof(req), true, &skb);
 if (ret)
  return ret;

 event = (struct mt7921_txpwr_event *)skb->data;
 WARN_ON(skb->len != le16_to_cpu(event->len));
 memcpy(txpwr, &event->txpwr, sizeof(event->txpwr));

 dev_kfree_skb(skb);

 return 0;
}

int mt7921_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif,
      bool enable)
{
 struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;
 struct {
  struct {
   u8 band_idx;
   u8 pad[3];
  } __packed hdr;
  struct sniffer_enable_tlv {
   __le16 tag;
   __le16 len;
   u8 enable;
   u8 pad[3];
  } __packed enable;
 } req = {
  .hdr = {
   .band_idx = mvif->band_idx,
  },
  .enable = {
   .tag = cpu_to_le16(0),
   .len = cpu_to_le16(sizeof(struct sniffer_enable_tlv)),
   .enable = enable,
  },
 };

 return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(SNIFFER), &req, sizeof(req),
     true);
}

int mt7921_mcu_config_sniffer(struct mt792x_vif *vif,
         struct ieee80211_chanctx_conf *ctx)
{
 struct cfg80211_chan_def *chandef = &ctx->def;
 int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2;
 static const u8 ch_band[] = {
  [NL80211_BAND_2GHZ] = 1,
  [NL80211_BAND_5GHZ] = 2,
  [NL80211_BAND_6GHZ] = 3,
 };
 static const u8 ch_width[] = {
  [NL80211_CHAN_WIDTH_20_NOHT] = 0,
  [NL80211_CHAN_WIDTH_20] = 0,
  [NL80211_CHAN_WIDTH_40] = 0,
  [NL80211_CHAN_WIDTH_80] = 1,
  [NL80211_CHAN_WIDTH_160] = 2,
  [NL80211_CHAN_WIDTH_80P80] = 3,
  [NL80211_CHAN_WIDTH_5] = 4,
  [NL80211_CHAN_WIDTH_10] = 5,
  [NL80211_CHAN_WIDTH_320] = 6,
 };
 struct {
  struct {
   u8 band_idx;
   u8 pad[3];
  } __packed hdr;
  struct config_tlv {
   __le16 tag;
   __le16 len;
   u16 aid;
   u8 ch_band;
   u8 bw;
   u8 control_ch;
   u8 sco;
   u8 center_ch;
   u8 center_ch2;
   u8 drop_err;
   u8 pad[3];
  } __packed tlv;
 } __packed req = {
  .hdr = {
   .band_idx = vif->bss_conf.mt76.band_idx,
  },
  .tlv = {
   .tag = cpu_to_le16(1),
   .len = cpu_to_le16(sizeof(req.tlv)),
   .control_ch = chandef->chan->hw_value,
   .center_ch = ieee80211_frequency_to_channel(freq1),
   .drop_err = 1,
  },
 };
 if (chandef->chan->band < ARRAY_SIZE(ch_band))
  req.tlv.ch_band = ch_band[chandef->chan->band];
 if (chandef->width < ARRAY_SIZE(ch_width))
  req.tlv.bw = ch_width[chandef->width];

 if (freq2)
  req.tlv.center_ch2 = ieee80211_frequency_to_channel(freq2);

 if (req.tlv.control_ch < req.tlv.center_ch)
  req.tlv.sco = 1; /* SCA */
 else if (req.tlv.control_ch > req.tlv.center_ch)
  req.tlv.sco = 3; /* SCB */

 return mt76_mcu_send_msg(vif->phy->mt76->dev, MCU_UNI_CMD(SNIFFER),
     &req, sizeof(req), true);
}

int
mt7921_mcu_uni_add_beacon_offload(struct mt792x_dev *dev,
      struct ieee80211_hw *hw,
      struct ieee80211_vif *vif,
      bool enable)
{
 struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
 struct mt76_wcid *wcid = &dev->mt76.global_wcid;
 struct ieee80211_mutable_offsets offs;
 struct {
  struct req_hdr {
   u8 bss_idx;
   u8 pad[3];
  } __packed hdr;
  struct bcn_content_tlv {
   __le16 tag;
   __le16 len;
   __le16 tim_ie_pos;
   __le16 csa_ie_pos;
   __le16 bcc_ie_pos;
   /* 0: disable beacon offload
 * 1: enable beacon offload
 * 2: update probe respond offload
 */

   u8 enable;
   /* 0: legacy format (TXD + payload)
 * 1: only cap field IE
 */

   u8 type;
   __le16 pkt_len;
   u8 pkt[512];
  } __packed beacon_tlv;
 } req = {
  .hdr = {
   .bss_idx = mvif->bss_conf.mt76.idx,
  },
  .beacon_tlv = {
   .tag = cpu_to_le16(UNI_BSS_INFO_BCN_CONTENT),
   .len = cpu_to_le16(sizeof(struct bcn_content_tlv)),
   .enable = enable,
  },
 };
 struct sk_buff *skb;

 /* support enable/update process only
 * disable flow would be handled in bss stop handler automatically
 */

 if (!enable)
  return -EOPNOTSUPP;

 skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs, 0);
 if (!skb)
  return -EINVAL;

 if (skb->len > 512 - MT_TXD_SIZE) {
  dev_err(dev->mt76.dev, "beacon size limit exceed\n");
  dev_kfree_skb(skb);
  return -EINVAL;
 }

 mt76_connac2_mac_write_txwi(&dev->mt76, (__le32 *)(req.beacon_tlv.pkt),
        skb, wcid, NULL, 0, 0, BSS_CHANGED_BEACON);
 memcpy(req.beacon_tlv.pkt + MT_TXD_SIZE, skb->data, skb->len);
 req.beacon_tlv.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
 req.beacon_tlv.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset);

 if (offs.cntdwn_counter_offs[0]) {
  u16 csa_offs;

  csa_offs = MT_TXD_SIZE + offs.cntdwn_counter_offs[0] - 4;
  req.beacon_tlv.csa_ie_pos = cpu_to_le16(csa_offs);
 }
 dev_kfree_skb(skb);

 return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE),
     &req, sizeof(req), true);
}

static
int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
    enum environment_cap env_cap,
    struct mt7921_clc *clc,
    u8 idx)
{
#define CLC_CAP_EVT_EN BIT(0)
#define CLC_CAP_DTS_EN BIT(1)
 struct sk_buff *skb, *ret_skb = NULL;
 struct {
  u8 ver;
  u8 pad0;
  __le16 len;
  u8 idx;
  u8 env;
  u8 acpi_conf;
  u8 cap;
  u8 alpha2[2];
  u8 type[2];
  u8 env_6g;
  u8 mtcl_conf;
  u8 rsvd[62];
 } __packed req = {
  .ver = 1,
  .idx = idx,
  .env = env_cap,
  .env_6g = dev->phy.power_type,
  .acpi_conf = mt792x_acpi_get_flags(&dev->phy),
  .mtcl_conf = mt792x_acpi_get_mtcl_conf(&dev->phy, alpha2),
 };
 int ret, valid_cnt = 0;
 u32 buf_len = 0;
 u8 *pos;

 if (!clc)
  return 0;

 if (dev->phy.chip_cap & MT792x_CHIP_CAP_CLC_EVT_EN)
  req.cap |= CLC_CAP_EVT_EN;
 if (mt76_find_power_limits_node(&dev->mt76))
  req.cap |= CLC_CAP_DTS_EN;

 buf_len = le32_to_cpu(clc->len) - sizeof(*clc);
 pos = clc->data;
 while (buf_len > 16) {
  struct mt7921_clc_rule *rule = (struct mt7921_clc_rule *)pos;
  u16 len = le16_to_cpu(rule->len);
  u16 offset = len + sizeof(*rule);

  pos += offset;
  buf_len -= offset;
  if (rule->alpha2[0] != alpha2[0] ||
      rule->alpha2[1] != alpha2[1])
   continue;

  memcpy(req.alpha2, rule->alpha2, 2);
  memcpy(req.type, rule->type, 2);

  req.len = cpu_to_le16(sizeof(req) + len);
  skb = __mt76_mcu_msg_alloc(&dev->mt76, &req,
        le16_to_cpu(req.len),
        sizeof(req), GFP_KERNEL);
  if (!skb)
   return -ENOMEM;
  skb_put_data(skb, rule->data, len);

  ret = mt76_mcu_skb_send_and_get_msg(&dev->mt76, skb,
          MCU_CE_CMD(SET_CLC),
          !!(req.cap & CLC_CAP_EVT_EN),
          &ret_skb);
  if (ret < 0)
   return ret;

  if (ret_skb) {
   struct mt7921_clc_info_tlv *info;

   info = (struct mt7921_clc_info_tlv *)(ret_skb->data + 4);
   dev->phy.clc_chan_conf = info->chan_conf;
   dev_kfree_skb(ret_skb);
  }

  valid_cnt++;
 }

 if (!valid_cnt)
  return -ENOENT;

 return 0;
}

int mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
         enum environment_cap env_cap)
{
 struct mt792x_phy *phy = (struct mt792x_phy *)&dev->phy;
 int i, ret;

 /* submit all clc config */
 for (i = 0; i < ARRAY_SIZE(phy->clc); i++) {
  ret = __mt7921_mcu_set_clc(dev, alpha2, env_cap,
        phy->clc[i], i);

  /* If no country found, set "00" as default */
  if (ret == -ENOENT)
   ret = __mt7921_mcu_set_clc(dev, "00",
         ENVIRON_INDOOR,
         phy->clc[i], i);
  if (ret < 0)
   return ret;
 }
 return 0;
}

int mt7921_mcu_get_temperature(struct mt792x_phy *phy)
{
 struct mt792x_dev *dev = phy->dev;
 struct {
  u8 ctrl_id;
  u8 action;
  u8 band_idx;
  u8 rsv[5];
 } req = {
  .ctrl_id = THERMAL_SENSOR_TEMP_QUERY,
  .band_idx = phy->mt76->band_idx,
 };

 return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req,
     sizeof(req), true);
}

int mt7921_mcu_wf_rf_pin_ctrl(struct mt792x_phy *phy, u8 action)
{
 struct mt792x_dev *dev = phy->dev;
 struct {
  u8 action;
  u8 value;
 } req = {
  .action = action,
  .value = 0,
 };

 return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(WF_RF_PIN_CTRL), &req,
     sizeof(req), action ? true : false);
}

int mt7921_mcu_set_rxfilter(struct mt792x_dev *dev, u32 fif,
       u8 bit_op, u32 bit_map)
{
 struct {
  u8 rsv[4];
  u8 mode;
  u8 rsv2[3];
  __le32 fif;
  __le32 bit_map; /* bit_* for bitmap update */
  u8 bit_op;
  u8 pad[51];
 } __packed data = {
  .mode = fif ? 1 : 2,
  .fif = cpu_to_le32(fif),
  .bit_map = cpu_to_le32(bit_map),
  .bit_op = bit_op,
 };

 return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_RX_FILTER),
     &data, sizeof(data), false);
}

int mt7921_mcu_set_rssimonitor(struct mt792x_dev *dev, struct ieee80211_vif *vif)
{
 struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
 struct {
  u8 enable;
  s8 cqm_rssi_high;
  s8 cqm_rssi_low;
  u8 bss_idx;
  u16 duration;
  u8 rsv2[2];
 } __packed data = {
  .enable = vif->cfg.assoc,
  .cqm_rssi_high = vif->bss_conf.cqm_rssi_thold + vif->bss_conf.cqm_rssi_hyst,
  .cqm_rssi_low = vif->bss_conf.cqm_rssi_thold - vif->bss_conf.cqm_rssi_hyst,
  .bss_idx = mvif->bss_conf.mt76.idx,
 };

 return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(RSSI_MONITOR),
     &data, sizeof(data), false);
}

Messung V0.5
C=98 H=91 G=94

¤ Dauer der Verarbeitung: 0.19 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.