231 lines
6.0 KiB
C
231 lines
6.0 KiB
C
|
/**
|
||
|
****************************************************************************************
|
||
|
*
|
||
|
* @file rwnx_testmode.c
|
||
|
*
|
||
|
* @brief Test mode function definitions
|
||
|
*
|
||
|
* Copyright (C) RivieraWaves 2012-2019
|
||
|
*
|
||
|
****************************************************************************************
|
||
|
*/
|
||
|
|
||
|
#include <net/mac80211.h>
|
||
|
#include <net/netlink.h>
|
||
|
|
||
|
#include "rwnx_testmode.h"
|
||
|
#include "rwnx_msg_tx.h"
|
||
|
#include "rwnx_dini.h"
|
||
|
#include "reg_access.h"
|
||
|
|
||
|
/*
|
||
|
* This function handles the user application commands for register access.
|
||
|
*
|
||
|
* It retrieves command ID carried with RWNX_TM_ATTR_COMMAND and calls to the
|
||
|
* handlers respectively.
|
||
|
*
|
||
|
* If it's an unknown commdn ID, -ENOSYS is returned; or -ENOMSG if the
|
||
|
* mandatory fields(RWNX_TM_ATTR_REG_OFFSET,RWNX_TM_ATTR_REG_VALUE32)
|
||
|
* are missing; Otherwise 0 is replied indicating the success of the command execution.
|
||
|
*
|
||
|
* If RWNX_TM_ATTR_COMMAND is RWNX_TM_CMD_APP2DEV_REG_READ, the register read
|
||
|
* value is returned with RWNX_TM_ATTR_REG_VALUE32.
|
||
|
*
|
||
|
* @hw: ieee80211_hw object that represents the device
|
||
|
* @tb: general message fields from the user space
|
||
|
*/
|
||
|
int rwnx_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
|
||
|
{
|
||
|
struct rwnx_hw *rwnx_hw = hw->priv;
|
||
|
u32 mem_addr, val32;
|
||
|
struct sk_buff *skb;
|
||
|
int status = 0;
|
||
|
|
||
|
/* First check if register address is there */
|
||
|
if (!tb[RWNX_TM_ATTR_REG_OFFSET]) {
|
||
|
printk("Error finding register offset\n");
|
||
|
return -ENOMSG;
|
||
|
}
|
||
|
|
||
|
mem_addr = nla_get_u32(tb[RWNX_TM_ATTR_REG_OFFSET]);
|
||
|
|
||
|
switch (nla_get_u32(tb[RWNX_TM_ATTR_COMMAND])) {
|
||
|
case RWNX_TM_CMD_APP2DEV_REG_READ:
|
||
|
{
|
||
|
struct dbg_mem_read_cfm mem_read_cfm;
|
||
|
|
||
|
/*** Send the command to the LMAC ***/
|
||
|
status = rwnx_send_dbg_mem_read_req(rwnx_hw, mem_addr, &mem_read_cfm);
|
||
|
if (status)
|
||
|
return status;
|
||
|
|
||
|
/* Allocate the answer message */
|
||
|
skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
|
||
|
if (!skb) {
|
||
|
printk("Error allocating memory\n");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
|
||
|
val32 = mem_read_cfm.memdata;
|
||
|
if (nla_put_u32(skb, RWNX_TM_ATTR_REG_VALUE32, val32))
|
||
|
goto nla_put_failure;
|
||
|
|
||
|
/* Send the answer to upper layer */
|
||
|
status = cfg80211_testmode_reply(skb);
|
||
|
if (status < 0)
|
||
|
printk("Error sending msg : %d\n", status);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case RWNX_TM_CMD_APP2DEV_REG_WRITE:
|
||
|
{
|
||
|
if (!tb[RWNX_TM_ATTR_REG_VALUE32]) {
|
||
|
printk("Error finding value to write\n");
|
||
|
return -ENOMSG;
|
||
|
} else {
|
||
|
val32 = nla_get_u32(tb[RWNX_TM_ATTR_REG_VALUE32]);
|
||
|
/* Send the command to the LMAC */
|
||
|
status = rwnx_send_dbg_mem_write_req(rwnx_hw, mem_addr, val32);
|
||
|
if (status)
|
||
|
return status;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
printk("Unknown testmode register command ID\n");
|
||
|
return -ENOSYS;
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
|
||
|
nla_put_failure:
|
||
|
kfree_skb(skb);
|
||
|
return -EMSGSIZE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* This function handles the user application commands for Debug filter settings.
|
||
|
*
|
||
|
* @hw: ieee80211_hw object that represents the device
|
||
|
* @tb: general message fields from the user space
|
||
|
*/
|
||
|
int rwnx_testmode_dbg_filter(struct ieee80211_hw *hw, struct nlattr **tb)
|
||
|
{
|
||
|
struct rwnx_hw *rwnx_hw = hw->priv;
|
||
|
u32 filter;
|
||
|
int status = 0;
|
||
|
|
||
|
/* First check if the filter is there */
|
||
|
if (!tb[RWNX_TM_ATTR_REG_FILTER]) {
|
||
|
printk("Error finding filter value\n");
|
||
|
return -ENOMSG;
|
||
|
}
|
||
|
|
||
|
filter = nla_get_u32(tb[RWNX_TM_ATTR_REG_FILTER]);
|
||
|
RWNX_DBG("testmode debug filter, setting: 0x%x\n", filter);
|
||
|
|
||
|
switch (nla_get_u32(tb[RWNX_TM_ATTR_COMMAND])) {
|
||
|
case RWNX_TM_CMD_APP2DEV_SET_DBGMODFILTER:
|
||
|
{
|
||
|
/* Send the command to the LMAC */
|
||
|
status = rwnx_send_dbg_set_mod_filter_req(rwnx_hw, filter);
|
||
|
if (status)
|
||
|
return status;
|
||
|
}
|
||
|
break;
|
||
|
case RWNX_TM_CMD_APP2DEV_SET_DBGSEVFILTER:
|
||
|
{
|
||
|
/* Send the command to the LMAC */
|
||
|
status = rwnx_send_dbg_set_sev_filter_req(rwnx_hw, filter);
|
||
|
if (status)
|
||
|
return status;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
printk("Unknown testmode register command ID\n");
|
||
|
return -ENOSYS;
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* This function handles the user application commands for register access without using
|
||
|
* the normal LMAC messaging way.
|
||
|
* This time register access will be done through direct PCI BAR windows. This can be used
|
||
|
* to access registers even when the :AMC FW is stuck.
|
||
|
*
|
||
|
* @hw: ieee80211_hw object that represents the device
|
||
|
* @tb: general message fields from the user space
|
||
|
*/
|
||
|
int rwnx_testmode_reg_dbg(struct ieee80211_hw *hw, struct nlattr **tb)
|
||
|
{
|
||
|
struct rwnx_hw *rwnx_hw = hw->priv;
|
||
|
struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
|
||
|
u32 mem_addr;
|
||
|
struct sk_buff *skb;
|
||
|
int status = 0;
|
||
|
volatile unsigned int reg_value = 0;
|
||
|
unsigned int offset;
|
||
|
|
||
|
/* First check if register address is there */
|
||
|
if (!tb[RWNX_TM_ATTR_REG_OFFSET]) {
|
||
|
printk("Error finding register offset\n");
|
||
|
return -ENOMSG;
|
||
|
}
|
||
|
|
||
|
mem_addr = nla_get_u32(tb[RWNX_TM_ATTR_REG_OFFSET]);
|
||
|
offset = mem_addr & 0x00FFFFFF;
|
||
|
|
||
|
switch (nla_get_u32(tb[RWNX_TM_ATTR_COMMAND])) {
|
||
|
case RWNX_TM_CMD_APP2DEV_REG_READ_DBG:
|
||
|
{
|
||
|
/*** Send the command to the LMAC ***/
|
||
|
reg_value = RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, offset);
|
||
|
|
||
|
/* Allocate the answer message */
|
||
|
skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
|
||
|
if (!skb) {
|
||
|
printk("Error allocating memory\n");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
|
||
|
if (nla_put_u32(skb, RWNX_TM_ATTR_REG_VALUE32, reg_value))
|
||
|
goto nla_put_failure;
|
||
|
|
||
|
/* Send the answer to upper layer */
|
||
|
status = cfg80211_testmode_reply(skb);
|
||
|
if (status < 0)
|
||
|
printk("Error sending msg : %d\n", status);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case RWNX_TM_CMD_APP2DEV_REG_WRITE_DBG:
|
||
|
{
|
||
|
if (!tb[RWNX_TM_ATTR_REG_VALUE32]) {
|
||
|
printk("Error finding value to write\n");
|
||
|
return -ENOMSG;
|
||
|
} else {
|
||
|
reg_value = nla_get_u32(tb[RWNX_TM_ATTR_REG_VALUE32]);
|
||
|
|
||
|
/* Send the command to the LMAC */
|
||
|
RWNX_REG_WRITE(reg_value, rwnx_plat, RWNX_ADDR_SYSTEM,
|
||
|
offset);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
printk("Unknown testmode register command ID\n");
|
||
|
return -ENOSYS;
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
|
||
|
nla_put_failure:
|
||
|
kfree_skb(skb);
|
||
|
return -EMSGSIZE;
|
||
|
}
|