[rdkb][common][bsp][Refactor and sync wifi from openwrt]
[Description]
a0c7684 [MAC80211][mt76][update mt76 patches]
a2e0f7c [MAC80211][core][Remove start disabled patch in eagle]
4562ef0 [MAC80211][hostapd][Refactor hostapd patch for git am]
22614f8 [mt76][Add vendor cmd to get available color bitmap]
b7b4fef [mac80211][Track obss color bitmap]
3f4ab41 [hostapd][Add hostapd_cli cmd to get available color bitmap]
cb120e7 [MAC80211][core][remove ba timer disabled patches]
24f983f [MAC80211][misc][sync iproute2 package]
3e866ee [MAC80211][core][Mark DFS channel available for CSA]
bdc6428 [MAC80211][hostapd][Mark DFS channel available for CSA]
9113e92 [MAC80211][app][Add eagle testmode iwpriv wrapper support]
d6bd8f4 [mac80211][mt76][Refactor mt76 patches]
7829a83 [MAC80211][mt76][Add monitor vif check in testmode]
19ead62 [mt76][eagle][hostapd mbssid and ema support]
[Release-log]
Change-Id: I75bf6ff01bc50054404bca23fd31cff9d1bc8d86
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0010-wifi-mt76-mt7996-add-thermal-protection-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0010-wifi-mt76-mt7996-add-thermal-protection-support.patch
new file mode 100644
index 0000000..319eb1f
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0010-wifi-mt76-mt7996-add-thermal-protection-support.patch
@@ -0,0 +1,437 @@
+From 1744b5397ad4240ce41bf88bfff2eef34d76d587 Mon Sep 17 00:00:00 2001
+From: Howard Hsu <howard-yh.hsu@mediatek.com>
+Date: Thu, 2 Feb 2023 21:20:31 +0800
+Subject: [PATCH 10/19] wifi: mt76: mt7996: add thermal protection support
+
+This commit includes the following changes:
+1. implement MTK thermal protection driver API
+2. support Linux cooling device control
+
+Change-Id: I8fecc28f5b17ee50ae4644d1dd17d188dd694731
+---
+ mt76_connac_mcu.h | 1 +
+ mt7996/init.c | 105 +++++++++++++++++++++++++++++++++++++++++++++
+ mt7996/main.c | 8 ++++
+ mt7996/mcu.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++
+ mt7996/mcu.h | 44 +++++++++++++++++++
+ mt7996/mt7996.h | 15 +++++++
+ 6 files changed, 279 insertions(+)
+
+diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
+index 6f30a0fb..fa10d823 100644
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -1009,6 +1009,7 @@ enum {
+ MCU_UNI_EVENT_FW_LOG_2_HOST = 0x04,
+ MCU_UNI_EVENT_IE_COUNTDOWN = 0x09,
+ MCU_UNI_EVENT_RDD_REPORT = 0x11,
++ MCU_UNI_EVENT_THERMAL = 0x35,
+ };
+
+ #define MCU_UNI_CMD_EVENT BIT(1)
+diff --git a/mt7996/init.c b/mt7996/init.c
+index 946da93e..5a22cd81 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -41,6 +41,98 @@ static const struct ieee80211_iface_combination if_comb[] = {
+ }
+ };
+
++static int
++mt7996_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
++ unsigned long *state)
++{
++ *state = MT7996_CDEV_THROTTLE_MAX;
++
++ return 0;
++}
++
++static int
++mt7996_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
++ unsigned long *state)
++{
++ struct mt7996_phy *phy = cdev->devdata;
++
++ *state = phy->cdev_state;
++
++ return 0;
++}
++
++static int
++mt7996_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
++ unsigned long state)
++{
++ struct mt7996_phy *phy = cdev->devdata;
++ u8 throttling = MT7996_THERMAL_THROTTLE_MAX - state;
++ int ret;
++
++ if (state > MT7996_CDEV_THROTTLE_MAX) {
++ dev_err(phy->dev->mt76.dev,
++ "please specify a valid throttling state\n");
++ return -EINVAL;
++ }
++
++ if (state == phy->cdev_state)
++ return 0;
++
++ /*
++ * cooling_device convention: 0 = no cooling, more = more cooling
++ * mcu convention: 1 = max cooling, more = less cooling
++ */
++ ret = mt7996_mcu_set_thermal_throttling(phy, throttling);
++ if (ret)
++ return ret;
++
++ phy->cdev_state = state;
++
++ return 0;
++}
++
++static const struct thermal_cooling_device_ops mt7996_thermal_ops = {
++ .get_max_state = mt7996_thermal_get_max_throttle_state,
++ .get_cur_state = mt7996_thermal_get_cur_throttle_state,
++ .set_cur_state = mt7996_thermal_set_cur_throttle_state,
++};
++
++static void mt7996_unregister_thermal(struct mt7996_phy *phy)
++{
++ struct wiphy *wiphy = phy->mt76->hw->wiphy;
++
++ if (!phy->cdev)
++ return;
++
++ sysfs_remove_link(&wiphy->dev.kobj, "cooling_device");
++ thermal_cooling_device_unregister(phy->cdev);
++}
++
++static int mt7996_thermal_init(struct mt7996_phy *phy)
++{
++ struct wiphy *wiphy = phy->mt76->hw->wiphy;
++ struct thermal_cooling_device *cdev;
++ const char *name;
++
++ name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s",
++ wiphy_name(wiphy));
++
++ cdev = thermal_cooling_device_register(name, phy, &mt7996_thermal_ops);
++ if (!IS_ERR(cdev)) {
++ if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj,
++ "cooling_device") < 0)
++ thermal_cooling_device_unregister(cdev);
++ else
++ phy->cdev = cdev;
++ }
++
++ /* initialize critical/maximum high temperature */
++ phy->throttle_temp[MT7996_CRIT_TEMP_IDX] = MT7996_CRIT_TEMP;
++ phy->throttle_temp[MT7996_MAX_TEMP_IDX] = MT7996_MAX_TEMP;
++
++ return 0;
++}
++
+ static void mt7996_led_set_config(struct led_classdev *led_cdev,
+ u8 delay_on, u8 delay_off)
+ {
+@@ -367,6 +459,10 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
+ if (ret)
+ goto error;
+
++ ret = mt7996_thermal_init(phy);
++ if (ret)
++ goto error;
++
+ ret = mt7996_init_debugfs(phy);
+ if (ret)
+ goto error;
+@@ -387,6 +483,8 @@ mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band)
+ if (!phy)
+ return;
+
++ mt7996_unregister_thermal(phy);
++
+ mphy = phy->dev->mt76.phys[band];
+ mt76_unregister_phy(mphy);
+ ieee80211_free_hw(mphy->hw);
+@@ -876,6 +974,10 @@ int mt7996_register_device(struct mt7996_dev *dev)
+ if (ret)
+ return ret;
+
++ ret = mt7996_thermal_init(&dev->phy);
++ if (ret)
++ return ret;
++
+ ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
+
+ ret = mt7996_register_phy(dev, mt7996_phy2(dev), MT_BAND1);
+@@ -893,6 +995,9 @@ void mt7996_unregister_device(struct mt7996_dev *dev)
+ {
+ mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2);
+ mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1);
++
++ mt7996_unregister_thermal(&dev->phy);
++
+ mt76_unregister_device(&dev->mt76);
+ mt7996_mcu_exit(dev);
+ mt7996_tx_token_put(dev);
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 44d23e1d..d8d578c0 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -54,6 +54,14 @@ static int mt7996_start(struct ieee80211_hw *hw)
+ if (ret)
+ goto out;
+
++ ret = mt7996_mcu_set_thermal_throttling(phy, MT7996_THERMAL_THROTTLE_MAX);
++ if (ret)
++ goto out;
++
++ ret = mt7996_mcu_set_thermal_protect(phy);
++ if (ret)
++ goto out;
++
+ set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
+
+ ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index b6bd36c2..3820a63e 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -443,6 +443,34 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
+ }
+ }
+
++static void
++mt7996_mcu_rx_thermal_notify(struct mt7996_dev *dev, struct sk_buff *skb)
++{
++#define THERMAL_NOTIFY_TAG 0x4
++#define THERMAL_NOTIFY 0x2
++ struct mt76_phy *mphy = &dev->mt76.phy;
++ struct mt7996_mcu_thermal_notify *n;
++ struct mt7996_phy *phy;
++
++ n = (struct mt7996_mcu_thermal_notify *)skb->data;
++
++ if (n->tag != THERMAL_NOTIFY_TAG)
++ return;
++
++ if (n->event_id != THERMAL_NOTIFY)
++ return;
++
++ if (n->band_idx > MT_BAND2)
++ return;
++
++ mphy = dev->mt76.phys[n->band_idx];
++ if (!mphy)
++ return;
++
++ phy = (struct mt7996_phy *)mphy->priv;
++ phy->throttle_state = n->duty_percent;
++}
++
+ static void
+ mt7996_mcu_rx_ext_event(struct mt7996_dev *dev, struct sk_buff *skb)
+ {
+@@ -487,6 +515,9 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
+ case MCU_UNI_EVENT_RDD_REPORT:
+ mt7996_mcu_rx_radar_detected(dev, skb);
+ break;
++ case MCU_UNI_EVENT_THERMAL:
++ mt7996_mcu_rx_thermal_notify(dev, skb);
++ break;
+ default:
+ break;
+ }
+@@ -3277,6 +3308,81 @@ out:
+ return 0;
+ }
+
++
++int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state)
++{
++ struct {
++ u8 _rsv[4];
++
++ __le16 tag;
++ __le16 len;
++
++ struct mt7996_mcu_thermal_ctrl ctrl;
++ } __packed req = {
++ .tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG),
++ .len = cpu_to_le16(sizeof(req) - 4),
++ .ctrl = {
++ .band_idx = phy->mt76->band_idx,
++ },
++ };
++ int level, ret;
++
++ /* set duty cycle and level */
++ for (level = 0; level < 4; level++) {
++ req.ctrl.duty.duty_level = level;
++ req.ctrl.duty.duty_cycle = state;
++ state /= 2;
++
++ ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
++ &req, sizeof(req), false);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++}
++
++int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy)
++{
++#define SUSTAIN_PERIOD 10
++ struct {
++ u8 _rsv[4];
++
++ __le16 tag;
++ __le16 len;
++
++ struct mt7996_mcu_thermal_ctrl ctrl;
++ struct mt7996_mcu_thermal_enable enable;
++ } __packed req = {
++ .len = cpu_to_le16(sizeof(req) - 4 - sizeof(req.enable)),
++ .ctrl = {
++ .band_idx = phy->mt76->band_idx,
++ .type.protect_type = 1,
++ .type.trigger_type = 1,
++ },
++ };
++ int ret;
++
++ req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DISABLE);
++
++ ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
++ &req, sizeof(req) - sizeof(req.enable), false);
++ if (ret)
++ return ret;
++
++ /* set high-temperature trigger threshold */
++ req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_ENABLE);
++ /* add a safety margin ~10 */
++ req.enable.restore_temp = cpu_to_le32(phy->throttle_temp[0] - 10);
++ req.enable.trigger_temp = cpu_to_le32(phy->throttle_temp[1]);
++ req.enable.sustain_time = cpu_to_le16(SUSTAIN_PERIOD);
++
++ req.len = cpu_to_le16(sizeof(req) - 4);
++
++ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
++ &req, sizeof(req), false);
++}
++
+ int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 val, u8 band)
+ {
+ struct {
+diff --git a/mt7996/mcu.h b/mt7996/mcu.h
+index dd0c5ac5..7fefc28f 100644
+--- a/mt7996/mcu.h
++++ b/mt7996/mcu.h
+@@ -30,6 +30,28 @@ struct mt7996_mcu_uni_event {
+ __le32 status; /* 0: success, others: fail */
+ } __packed;
+
++struct mt7996_mcu_thermal_ctrl {
++ u8 ctrl_id;
++ u8 band_idx;
++ union {
++ struct {
++ u8 protect_type; /* 1: duty admit, 2: radio off */
++ u8 trigger_type; /* 0: low, 1: high */
++ } __packed type;
++ struct {
++ u8 duty_level; /* level 0~3 */
++ u8 duty_cycle;
++ } __packed duty;
++ };
++} __packed;
++
++struct mt7996_mcu_thermal_enable {
++ __le32 trigger_temp;
++ __le32 restore_temp;
++ __le16 sustain_time;
++ u8 rsv[2];
++} __packed;
++
+ struct mt7996_mcu_csa_notify {
+ struct mt7996_mcu_rxd rxd;
+
+@@ -153,6 +175,22 @@ struct mt7996_mcu_mib {
+ __le64 data;
+ } __packed;
+
++struct mt7996_mcu_thermal_notify {
++ struct mt7996_mcu_rxd rxd;
++
++ u8 __rsv1[4];
++
++ __le16 tag;
++ __le16 len;
++
++ u8 event_id;
++ u8 band_idx;
++ u8 level_idx;
++ u8 duty_percent;
++ __le32 restore_temp;
++ u8 __rsv2[4];
++} __packed;
++
+ enum mt7996_chan_mib_offs {
+ UNI_MIB_OBSS_AIRTIME = 26,
+ UNI_MIB_NON_WIFI_TIME = 27,
+@@ -642,6 +680,12 @@ enum{
+ UNI_CMD_SR_SET_SIGA = 0xd0,
+ };
+
++enum {
++ UNI_CMD_THERMAL_PROTECT_ENABLE = 0x6,
++ UNI_CMD_THERMAL_PROTECT_DISABLE,
++ UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG,
++};
++
+ enum {
+ UNI_CMD_ACCESS_REG_BASIC = 0x0,
+ UNI_CMD_ACCESS_RF_REG_BASIC,
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 997a0bf0..25b20fa6 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -43,6 +43,13 @@
+ #define MT7996_MAX_STA_TWT_AGRT 8
+ #define MT7996_MAX_QUEUE (__MT_RXQ_MAX + __MT_MCUQ_MAX + 3)
+
++#define MT7996_THERMAL_THROTTLE_MAX 100
++#define MT7996_CDEV_THROTTLE_MAX 99
++#define MT7996_CRIT_TEMP_IDX 0
++#define MT7996_MAX_TEMP_IDX 1
++#define MT7996_CRIT_TEMP 110
++#define MT7996_MAX_TEMP 120
++
+ struct mt7996_vif;
+ struct mt7996_sta;
+ struct mt7996_dfs_pulse;
+@@ -211,6 +218,11 @@ struct mt7996_phy {
+
+ struct ieee80211_vif *monitor_vif;
+
++ struct thermal_cooling_device *cdev;
++ u8 cdev_state;
++ u8 throttle_state;
++ u32 throttle_temp[2]; /* 0: critical high, 1: maximum */
++
+ u32 rxfilter;
+ u64 omac_mask;
+
+@@ -437,6 +449,9 @@ int mt7996_mcu_set_radar_th(struct mt7996_dev *dev, int index,
+ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable);
+ int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val);
+ int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch);
++int mt7996_mcu_get_temperature(struct mt7996_phy *phy);
++int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state);
++int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy);
+ int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
+ u8 rx_sel, u8 val);
+ int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy,
+--
+2.39.2
+