Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c2c6c85f authored by Chin-ran Lo's avatar Chin-ran Lo Committed by Kalle Valo
Browse files

mwifiex: add support for FW memory read/write operations



This patch adds support for FW memory read/write operations via debugfs.
This is useful during debugging FW issues.

Examples:

For reading FW memory location:
echo r 0x01ac > /sys/kernel/debug/mwifiex/mlan0/memrw
cat /sys/kernel/debug/mwifiex/mlan0/memrw

For writing FW memory location:
echo w 0x01ac 0x55aa > /sys/kernel/debug/mwifiex/mlan0/memrw

Signed-off-by: default avatarChin-ran Lo <crlo@marvell.com>
Signed-off-by: default avatarCathy Luo <cluo@marvell.com>
Signed-off-by: default avatarAvinash Patil <patila@marvell.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 111c6105
Loading
Loading
Loading
Loading
+79 −0
Original line number Diff line number Diff line
@@ -535,6 +535,83 @@ mwifiex_regrdwr_read(struct file *file, char __user *ubuf,
	return ret;
}

/* Proc memrw file write handler.
 * This function is called when the 'memrw' file is opened for writing
 * This function can be used to write to a memory location.
 */
static ssize_t
mwifiex_memrw_write(struct file *file, const char __user *ubuf, size_t count,
		    loff_t *ppos)
{
	int ret;
	char cmd;
	struct mwifiex_ds_mem_rw mem_rw;
	u16 cmd_action;
	struct mwifiex_private *priv = (void *)file->private_data;
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (void *)addr;
	size_t buf_size = min(count, (size_t)(PAGE_SIZE - 1));

	if (!buf)
		return -ENOMEM;

	if (copy_from_user(buf, ubuf, buf_size)) {
		ret = -EFAULT;
		goto done;
	}

	ret = sscanf(buf, "%c %x %x", &cmd, &mem_rw.addr, &mem_rw.value);
	if (ret != 3) {
		ret = -EINVAL;
		goto done;
	}

	if ((cmd == 'r') || (cmd == 'R')) {
		cmd_action = HostCmd_ACT_GEN_GET;
		mem_rw.value = 0;
	} else if ((cmd == 'w') || (cmd == 'W')) {
		cmd_action = HostCmd_ACT_GEN_SET;
	} else {
		ret = -EINVAL;
		goto done;
	}

	memcpy(&priv->mem_rw, &mem_rw, sizeof(mem_rw));
	if (mwifiex_send_cmd(priv, HostCmd_CMD_MEM_ACCESS, cmd_action, 0,
			     &mem_rw, true))
		ret = -1;
	else
		ret = count;

done:
	free_page(addr);
	return ret;
}

/* Proc memrw file read handler.
 * This function is called when the 'memrw' file is opened for reading
 * This function can be used to read from a memory location.
 */
static ssize_t
mwifiex_memrw_read(struct file *file, char __user *ubuf,
		   size_t count, loff_t *ppos)
{
	struct mwifiex_private *priv = (void *)file->private_data;
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;
	int ret, pos = 0;

	if (!buf)
		return -ENOMEM;

	pos += snprintf(buf, PAGE_SIZE, "0x%x 0x%x\n", priv->mem_rw.addr,
			priv->mem_rw.value);
	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);

	free_page(addr);
	return ret;
}

static u32 saved_offset = -1, saved_bytes = -1;

/*
@@ -749,6 +826,7 @@ MWIFIEX_DFS_FILE_READ_OPS(getlog);
MWIFIEX_DFS_FILE_READ_OPS(fw_dump);
MWIFIEX_DFS_FILE_OPS(regrdwr);
MWIFIEX_DFS_FILE_OPS(rdeeprom);
MWIFIEX_DFS_FILE_OPS(memrw);
MWIFIEX_DFS_FILE_OPS(hscfg);
MWIFIEX_DFS_FILE_OPS(histogram);

@@ -773,6 +851,7 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
	MWIFIEX_DFS_ADD_FILE(regrdwr);
	MWIFIEX_DFS_ADD_FILE(rdeeprom);
	MWIFIEX_DFS_ADD_FILE(fw_dump);
	MWIFIEX_DFS_ADD_FILE(memrw);
	MWIFIEX_DFS_ADD_FILE(hscfg);
	MWIFIEX_DFS_ADD_FILE(histogram);
}
+9 −0
Original line number Diff line number Diff line
@@ -323,6 +323,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_802_11_SUBSCRIBE_EVENT            0x0075
#define HostCmd_CMD_802_11_TX_RATE_QUERY              0x007f
#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS     0x0083
#define HostCmd_CMD_MEM_ACCESS                        0x0086
#define HostCmd_CMD_CFG_DATA                          0x008f
#define HostCmd_CMD_VERSION_EXT                       0x0097
#define HostCmd_CMD_MEF_CFG                           0x009a
@@ -1576,6 +1577,13 @@ struct mwifiex_ie_types_extcap {
	u8 ext_capab[0];
} __packed;

struct host_cmd_ds_mem_access {
	__le16 action;
	__le16 reserved;
	__le32 addr;
	__le32 value;
};

struct mwifiex_ie_types_qos_info {
	struct mwifiex_ie_types_header header;
	u8 qos_info;
@@ -1958,6 +1966,7 @@ struct host_cmd_ds_command {
		struct host_cmd_ds_p2p_mode_cfg mode_cfg;
		struct host_cmd_ds_802_11_ibss_status ibss_coalescing;
		struct host_cmd_ds_mef_cfg mef_cfg;
		struct host_cmd_ds_mem_access mem;
		struct host_cmd_ds_mac_reg_access mac_reg;
		struct host_cmd_ds_bbp_reg_access bbp_reg;
		struct host_cmd_ds_rf_reg_access rf_reg;
+5 −0
Original line number Diff line number Diff line
@@ -342,6 +342,11 @@ struct mwifiex_ds_read_eeprom {
	u8 value[MAX_EEPROM_DATA];
};

struct mwifiex_ds_mem_rw {
	u32 addr;
	u32 value;
};

#define IEEE_MAX_IE_SIZE		256

#define MWIFIEX_IE_HDR_SIZE	(sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE)
+1 −0
Original line number Diff line number Diff line
@@ -611,6 +611,7 @@ struct mwifiex_private {
	struct delayed_work dfs_chan_sw_work;
	struct cfg80211_beacon_data beacon_after;
	struct mwifiex_11h_intf_state state_11h;
	struct mwifiex_ds_mem_rw mem_rw;
};


+23 −0
Original line number Diff line number Diff line
@@ -1071,6 +1071,26 @@ static int mwifiex_cmd_ibss_coalescing_status(struct host_cmd_ds_command *cmd,
	return 0;
}

/* This function prepares command buffer to get/set memory location value.
 */
static int
mwifiex_cmd_mem_access(struct host_cmd_ds_command *cmd, u16 cmd_action,
		       void *pdata_buf)
{
	struct mwifiex_ds_mem_rw *mem_rw = (void *)pdata_buf;
	struct host_cmd_ds_mem_access *mem_access = (void *)&cmd->params.mem;

	cmd->command = cpu_to_le16(HostCmd_CMD_MEM_ACCESS);
	cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mem_access) +
				S_DS_GEN);

	mem_access->action = cpu_to_le16(cmd_action);
	mem_access->addr = cpu_to_le32(mem_rw->addr);
	mem_access->value = cpu_to_le32(mem_rw->value);

	return 0;
}

/*
 * This function prepares command to set/get register value.
 *
@@ -1885,6 +1905,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
	case HostCmd_CMD_802_11_SCAN_EXT:
		ret = mwifiex_cmd_802_11_scan_ext(priv, cmd_ptr, data_buf);
		break;
	case HostCmd_CMD_MEM_ACCESS:
		ret = mwifiex_cmd_mem_access(cmd_ptr, cmd_action, data_buf);
		break;
	case HostCmd_CMD_MAC_REG_ACCESS:
	case HostCmd_CMD_BBP_REG_ACCESS:
	case HostCmd_CMD_RF_REG_ACCESS:
Loading