blob: 2ee41eda4bc67828f27e449ecdc7022f16563549 [file] [log] [blame]
From 5bdd94800111ac1742558a5d6e8b9daae0c24e79 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Thu, 29 Aug 2024 09:47:44 +0800
Subject: [PATCH 189/193] mtk: mt76: mt7996: add efuse write protection
Add efuse write protection in case that the user overwritten
the FT value stored in efuse.
Reference change list (Logan):
https://gerrit.mediatek.inc/c/neptune/wlan_driver/logan/+/9473737
https://gerrit.mediatek.inc/c/neptune/wlan_driver/logan/+/9497426
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Change-Id: If50d6965da8d9488d44c9da77a4bfca9906da9bc
---
mt7996/mcu.c | 11 +---
mt7996/mt7996.h | 23 ++++++++
mt7996/testmode.c | 135 ++++++++++++++++++++++++++++++++++++++++++----
mt7996/testmode.h | 6 +++
4 files changed, 157 insertions(+), 18 deletions(-)
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
index b584a0e..cd10ee9 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
@@ -5115,13 +5115,6 @@ static int mt7996_mcu_set_cal_free_data(struct mt7996_dev *dev)
#define MT_EE_CAL_FREE_MAX_SIZE 30
#define MT_EE_7977BN_OFFSET (0x1200 - 0x500)
#define MT_EE_END_OFFSET 0xffff
- enum adie_type {
- ADIE_7975,
- ADIE_7976,
- ADIE_7977,
- ADIE_7978,
- ADIE_7979,
- };
static const u16 adie_offs_list[][MT_EE_CAL_FREE_MAX_SIZE] = {
[ADIE_7975] = {0x5cd, 0x5cf, 0x5d1, 0x5d3, 0x6c0, 0x6c1, 0x6c2, 0x6c3,
0x7a1, 0x7a6, 0x7a8, 0x7aa, -1},
@@ -5151,10 +5144,10 @@ static int mt7996_mcu_set_cal_free_data(struct mt7996_dev *dev)
0x127a, 0x127b, 0x127c, 0x127e, 0x1280, -1},
};
static const u16 adie_base_7996[] = {
- 0x400, 0x1e00, 0x1200
+ EFUSE_BASE_OFFS_ADIE0, EFUSE_BASE_OFFS_ADIE1, EFUSE_BASE_OFFS_ADIE2
};
static const u16 adie_base_7992[] = {
- 0x400, 0x1200, 0x0
+ EFUSE_BASE_OFFS_ADIE0, EFUSE_BASE_OFFS_ADIE1_7992, 0x0
};
static const u16 *adie_offs[__MT_MAX_BAND];
static const u16 *eep_offs[__MT_MAX_BAND];
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
index e65d2a6..ddc44de 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
@@ -180,6 +180,29 @@ enum mt7996_eeprom_mode {
EXT_EEPROM_MODE,
};
+enum mt7996_ddie_type {
+ DDIE_7996,
+ DDIE_7992,
+ DDIE_TYPE_NUM,
+};
+
+enum mt7996_adie_type {
+ ADIE_7975,
+ ADIE_7976,
+ ADIE_7977,
+ ADIE_7978,
+ ADIE_7979,
+ ADIE_TYPE_NUM,
+};
+
+enum mt7996_efuse_base_offs {
+ EFUSE_BASE_OFFS_DDIE = 0x0,
+ EFUSE_BASE_OFFS_ADIE0 = 0x400,
+ EFUSE_BASE_OFFS_ADIE2 = 0x1200,
+ EFUSE_BASE_OFFS_ADIE1_7992 = 0x1200,
+ EFUSE_BASE_OFFS_ADIE1 = 0x1e00,
+};
+
enum mt7996_coredump_state {
MT7996_COREDUMP_IDLE = 0,
MT7996_COREDUMP_MANUAL_WA,
diff --git a/mt7996/testmode.c b/mt7996/testmode.c
index b369263..6e1cfcf 100644
--- a/mt7996/testmode.c
+++ b/mt7996/testmode.c
@@ -2133,6 +2133,127 @@ mt7996_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg)
return 0;
}
+static bool
+mt7996_tm_efuse_update_is_valid(struct mt7996_dev *dev, u32 offset, u8 *write_buf)
+{
+#define PROT_OFFS_MAX_SIZE 8
+#define EFUSE_PROT_END_OFFSET 0xffff
+#define EFUSE_PROT_ALL_MASK GENMASK(15, 0)
+ static const struct efuse_region ddie_prot_offs[][PROT_OFFS_MAX_SIZE] = {
+ [DDIE_7996] = {{.start = 0x10, .end = 0x18f, .prot_mask = -1},
+ {.start = 0x1b0, .end = 0x2bf, .prot_mask = -1},
+ {.start = 0x2c0, .end = 0x2cf, .prot_mask = GENMASK(15, 6)},
+ {.start = 0x2d0, .end = 0x2ff, .prot_mask = -1},
+ {.start = 0x300, .end = 0x30f, .prot_mask = GENMASK(15, 1)},
+ {.start = 0x310, .end = 0x31f, .prot_mask = GENMASK(15, 1)},
+ {.start = 0x320, .end = 0x3ff, .prot_mask = -1},
+ {.start = -1}},
+ [DDIE_7992] = {{.start = 0x10, .end = 0x18f, .prot_mask = -1},
+ {.start = 0x1b0, .end = 0x3ff, .prot_mask = -1},
+ {.start = -1}},
+ };
+ static const struct efuse_region adie_prot_offs[][PROT_OFFS_MAX_SIZE] = {
+ [ADIE_7975] = {{.start = 0x5c0, .end = 0x62f, .prot_mask = -1},
+ {.start = 0x6c0, .end = 0x6ff, .prot_mask = -1},
+ {.start = 0x7a0, .end = 0x7af, .prot_mask = BIT(1) | BIT(9)},
+ {.start = 0x7b0, .end = 0x7bf, .prot_mask = -1},
+ {.start = -1}},
+ [ADIE_7976] = {{.start = 0x0, .end = 0x7f, .prot_mask = -1},
+ {.start = 0x790, .end = 0x79f,
+ .prot_mask = GENMASK(15, 10) | GENMASK(8, 0)},
+ {.start = 0x7a0, .end = 0x7af,
+ .prot_mask = BIT(6) | BIT(8) | BIT(10)},
+ {.start = 0x7b0, .end = 0x7bf, .prot_mask = -1},
+ {.start = -1}},
+ [ADIE_7977] = {{.start = 0x0, .end = 0x5f, .prot_mask = -1},
+ {.start = 0x60, .end = 0x6f, .prot_mask = GENMASK(14, 0)},
+ {.start = 0x70, .end = 0x7f,
+ .prot_mask = GENMASK(15, 14) | GENMASK(12, 0)},
+ {.start = 0x80, .end = 0x10f, .prot_mask = -1},
+ {.start = -1}},
+ };
+ static const struct efuse_region *prot_offs;
+ u8 read_buf[MT76_TM_EEPROM_BLOCK_SIZE], *eeprom = dev->mt76.eeprom.data;
+ int ret, i = 0;
+ u16 base;
+
+ if (!write_buf)
+ return false;
+
+ memset(read_buf, 0, MT76_TM_EEPROM_BLOCK_SIZE);
+ ret = mt7996_mcu_get_eeprom(dev, offset, read_buf,
+ MT76_TM_EEPROM_BLOCK_SIZE, EFUSE_MODE);
+ if (ret && ret != -EINVAL)
+ return false;
+
+ /* no change in this block, so skip it */
+ if (!memcmp(eeprom + offset, read_buf, MT76_TM_EEPROM_BLOCK_SIZE))
+ return false;
+
+ memcpy(write_buf, eeprom + offset, MT76_TM_EEPROM_BLOCK_SIZE);
+
+ switch (mt76_chip(&dev->mt76)) {
+ case 0x7990:
+ if (offset < EFUSE_BASE_OFFS_ADIE0) {
+ base = EFUSE_BASE_OFFS_DDIE;
+ prot_offs = ddie_prot_offs[DDIE_7996];
+ } else if (offset >= EFUSE_BASE_OFFS_ADIE0 &&
+ offset < EFUSE_BASE_OFFS_ADIE2) {
+ base = EFUSE_BASE_OFFS_ADIE0;
+ if (dev->chip_sku == MT7996_VAR_TYPE_233 ||
+ dev->fem_type == MT7996_FEM_EXT)
+ prot_offs = adie_prot_offs[ADIE_7976];
+ else
+ prot_offs = adie_prot_offs[ADIE_7975];
+ } else if (offset >= EFUSE_BASE_OFFS_ADIE2 &&
+ offset < EFUSE_BASE_OFFS_ADIE1) {
+ base = EFUSE_BASE_OFFS_ADIE2;
+ prot_offs = adie_prot_offs[ADIE_7977];
+ } else {
+ base = EFUSE_BASE_OFFS_ADIE1;
+ prot_offs = adie_prot_offs[ADIE_7977];
+ }
+ break;
+ case 0x7992:
+ /* block all the adie region in efuse for kite */
+ if (offset >= EFUSE_BASE_OFFS_ADIE0)
+ return false;
+ base = EFUSE_BASE_OFFS_DDIE;
+ prot_offs = ddie_prot_offs[DDIE_7992];
+ break;
+ default:
+ return false;
+ }
+
+ /* check efuse protection */
+ while (prot_offs[i].start != EFUSE_PROT_END_OFFSET) {
+ if (offset >= prot_offs[i].start + base &&
+ offset <= prot_offs[i].end + base) {
+ unsigned long prot_mask = prot_offs[i].prot_mask;
+ int j;
+
+ if (prot_mask == EFUSE_PROT_ALL_MASK)
+ return false;
+
+ for_each_set_bit(j, &prot_mask, MT76_TM_EEPROM_BLOCK_SIZE) {
+ if (write_buf[j] != read_buf[j]) {
+ write_buf[j] = read_buf[j];
+ dev_warn(dev->mt76.dev,
+ "offset %x is invalid to write\n",
+ offset + j);
+ }
+ }
+ break;
+ }
+ i++;
+ }
+
+ if (!memcmp(read_buf, write_buf, MT76_TM_EEPROM_BLOCK_SIZE))
+ return false;
+
+ return true;
+}
+
static int
mt7996_tm_write_back_to_efuse(struct mt7996_dev *dev)
{
@@ -2141,8 +2262,9 @@ mt7996_tm_write_back_to_efuse(struct mt7996_dev *dev)
.len = cpu_to_le16(sizeof(req) - 4 +
MT76_TM_EEPROM_BLOCK_SIZE),
};
- u8 read_buf[MT76_TM_EEPROM_BLOCK_SIZE], *eeprom = dev->mt76.eeprom.data;
int msg_len = sizeof(req) + MT76_TM_EEPROM_BLOCK_SIZE;
+ u8 *eeprom = dev->mt76.eeprom.data;
+ u8 write_buf[MT76_TM_EEPROM_BLOCK_SIZE];
int i, ret = -EINVAL;
/* prevent from damaging chip id in efuse */
@@ -2152,13 +2274,8 @@ mt7996_tm_write_back_to_efuse(struct mt7996_dev *dev)
for (i = 0; i < MT7996_EEPROM_SIZE; i += MT76_TM_EEPROM_BLOCK_SIZE) {
struct sk_buff *skb;
- memset(read_buf, 0, MT76_TM_EEPROM_BLOCK_SIZE);
- ret = mt7996_mcu_get_eeprom(dev, i, read_buf, sizeof(read_buf),
- EFUSE_MODE);
- if (ret && ret != -EINVAL)
- return ret;
-
- if (!memcmp(eeprom + i, read_buf, MT76_TM_EEPROM_BLOCK_SIZE))
+ memset(write_buf, 0, MT76_TM_EEPROM_BLOCK_SIZE);
+ if (!mt7996_tm_efuse_update_is_valid(dev, i, write_buf))
continue;
skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, msg_len);
@@ -2167,7 +2284,7 @@ mt7996_tm_write_back_to_efuse(struct mt7996_dev *dev)
req.addr = cpu_to_le32(i);
skb_put_data(skb, &req, sizeof(req));
- skb_put_data(skb, eeprom + i, MT76_TM_EEPROM_BLOCK_SIZE);
+ skb_put_data(skb, write_buf, MT76_TM_EEPROM_BLOCK_SIZE);
ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_WM_UNI_CMD(EFUSE_CTRL), true);
diff --git a/mt7996/testmode.h b/mt7996/testmode.h
index 5c720da..154392d 100644
--- a/mt7996/testmode.h
+++ b/mt7996/testmode.h
@@ -363,4 +363,10 @@ struct mt7996_tm_rdd_ipi_ctrl {
__le32 tx_assert_time; /* unit: us */
} __packed;
+struct efuse_region {
+ u16 start;
+ u16 end;
+ u16 prot_mask;
+};
+
#endif
--
2.45.2