// SPDX-License-Identifier: ISC
/*
* Copyright (C) 2022 MediaTek Inc.
*/
#include <linux/relay.h>
#include "mt7996.h"
#include "eeprom.h"
#include "mcu.h"
#include "mac.h"
#define FW_BIN_LOG_MAGIC 0x44d9c99a
/** global debugfs **/
struct hw_queue_map {
const char *name;
u8 index;
u8 pid;
u8 qid;
};
static int
mt7996_implicit_txbf_set(void *data, u64 val)
{
struct mt7996_dev *dev = data;
/* The existing connected stations shall reconnect to apply
* new implicit txbf configuration.
*/
dev->ibf = !!val;
return mt7996_mcu_set_txbf(dev, BF_HW_EN_UPDATE);
}
static int
mt7996_implicit_txbf_get(void *data, u64 *val)
{
struct mt7996_dev *dev = data;
*val = dev->ibf;
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(fops_implicit_txbf, mt7996_implicit_txbf_get,
mt7996_implicit_txbf_set, "%lld\n");
/* test knob of system error recovery */
static ssize_t
mt7996_sys_recovery_set(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct mt7996_phy *phy = file->private_data;
struct mt7996_dev *dev = phy->dev;
bool band = phy->mt76->band_idx;
char buf[16];
int ret = 0;
u16 val;
if (count >= sizeof(buf))
return -EINVAL;
if (copy_from_user(buf, user_buf, count))
return -EFAULT;
if (count && buf[count - 1] == '\n')
buf[count - 1] = '\0';
else
buf[count] = '\0';
if (kstrtou16(buf, 0, &val))
return -EINVAL;
switch (val) {
/*
* 0: grab firmware current SER state.
* 1: trigger & enable system error L1 recovery.
* 2: trigger & enable system error L2 recovery.
* 3: trigger & enable system error L3 rx abort.
* 4: trigger & enable system error L3 tx abort
* 5: trigger & enable system error L3 tx disable.
* 6: trigger & enable system error L3 bf recovery.
* 7: trigger & enable system error L4 mdp recovery.
* 8: trigger & enable system error full recovery.
* 9: trigger firmware crash.
*/
case UNI_CMD_SER_QUERY:
ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_QUERY, 0, band);
break;
case UNI_CMD_SER_SET_RECOVER_L1:
case UNI_CMD_SER_SET_RECOVER_L2:
case UNI_CMD_SER_SET_RECOVER_L3_RX_ABORT:
case UNI_CMD_SER_SET_RECOVER_L3_TX_ABORT:
case UNI_CMD_SER_SET_RECOVER_L3_TX_DISABLE:
case UNI_CMD_SER_SET_RECOVER_L3_BF:
case UNI_CMD_SER_SET_RECOVER_L4_MDP:
ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_SET, BIT(val), band);
if (ret)
return ret;
ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_TRIGGER, val, band);
break;
/* enable full chip reset */
case UNI_CMD_SER_SET_RECOVER_FULL:
mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK);
dev->recovery.state |= MT_MCU_CMD_WDT_MASK;
mt7996_reset(dev);
break;
/* WARNING: trigger firmware crash */
case UNI_CMD_SER_SET_SYSTEM_ASSERT:
ret = mt7996_mcu_trigger_assert(dev);
if (ret)
return ret;
break;
default:
break;
}
return ret ? ret : count;
}
static ssize_t
mt7996_sys_recovery_get(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct mt7996_phy *phy = file->private_data;
struct mt7996_dev *dev = phy->dev;
char *buff;
int desc = 0;
ssize_t ret;
static const size_t bufsz = 1024;
buff = kmalloc(bufsz, GFP_KERNEL);
if (!buff)
return -ENOMEM;
/* HELP */
desc += scnprintf(buff + desc, bufsz - desc,
"Please echo the correct value ...\n");
desc += scnprintf(buff + desc, bufsz - desc,
"0: grab firmware transient SER state\n");
desc += scnprintf(buff + desc, bufsz - desc,
"1: trigger system error L1 recovery\n");
desc += scnprintf(buff + desc, bufsz - desc,
"2: trigger system error L2 recovery\n");
desc