-
Notifications
You must be signed in to change notification settings - Fork 9
/
ecrnx_testmode.c
executable file
·226 lines (194 loc) · 6.85 KB
/
ecrnx_testmode.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/**
****************************************************************************************
*
* @file ecrnx_testmode.c
*
* @brief Test mode function definitions
*
* Copyright (C) ESWIN 2015-2020
*
****************************************************************************************
*/
#include <net/mac80211.h>
#include <net/netlink.h>
#include "ecrnx_testmode.h"
#include "ecrnx_msg_tx.h"
#include "ecrnx_dini.h"
#include "reg_access.h"
/*
* This function handles the user application commands for register access.
*
* It retrieves command ID carried with ECRNX_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(ECRNX_TM_ATTR_REG_OFFSET,ECRNX_TM_ATTR_REG_VALUE32)
* are missing; Otherwise 0 is replied indicating the success of the command execution.
*
* If ECRNX_TM_ATTR_COMMAND is ECRNX_TM_CMD_APP2DEV_REG_READ, the register read
* value is returned with ECRNX_TM_ATTR_REG_VALUE32.
*
* @hw: ieee80211_hw object that represents the device
* @tb: general message fields from the user space
*/
int ecrnx_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
{
struct ecrnx_hw *ecrnx_hw = hw->priv;
u32 mem_addr, val32;
struct sk_buff *skb;
int status = 0;
/* First check if register address is there */
if (!tb[ECRNX_TM_ATTR_REG_OFFSET]) {
ecrnx_printk_err("Error finding register offset\n");
return -ENOMSG;
}
mem_addr = nla_get_u32(tb[ECRNX_TM_ATTR_REG_OFFSET]);
switch (nla_get_u32(tb[ECRNX_TM_ATTR_COMMAND])) {
case ECRNX_TM_CMD_APP2DEV_REG_READ:
{
struct dbg_mem_read_cfm mem_read_cfm;
/*** Send the command to the LMAC ***/
if ((status = ecrnx_send_dbg_mem_read_req(ecrnx_hw, mem_addr, &mem_read_cfm)))
return status;
/* Allocate the answer message */
skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
if (!skb) {
ecrnx_printk_err("Error allocating memory\n");
return -ENOMEM;
}
val32 = mem_read_cfm.memdata;
if (nla_put_u32(skb, ECRNX_TM_ATTR_REG_VALUE32, val32))
goto nla_put_failure;
/* Send the answer to upper layer */
status = cfg80211_testmode_reply(skb);
if (status < 0)
ecrnx_printk_err("Error sending msg : %d\n", status);
}
break;
case ECRNX_TM_CMD_APP2DEV_REG_WRITE:
{
if (!tb[ECRNX_TM_ATTR_REG_VALUE32]) {
ecrnx_printk_err("Error finding value to write\n");
return -ENOMSG;
} else {
val32 = nla_get_u32(tb[ECRNX_TM_ATTR_REG_VALUE32]);
/* Send the command to the LMAC */
if ((status = ecrnx_send_dbg_mem_write_req(ecrnx_hw, mem_addr, val32)))
return status;
}
}
break;
default:
ecrnx_printk_err("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 ecrnx_testmode_dbg_filter(struct ieee80211_hw *hw, struct nlattr **tb)
{
struct ecrnx_hw *ecrnx_hw = hw->priv;
u32 filter;
int status = 0;
/* First check if the filter is there */
if (!tb[ECRNX_TM_ATTR_REG_FILTER]) {
ecrnx_printk_err("Error finding filter value\n");
return -ENOMSG;
}
filter = nla_get_u32(tb[ECRNX_TM_ATTR_REG_FILTER]);
ecrnx_printk_debug("testmode debug filter, setting: 0x%x\n", filter);
switch (nla_get_u32(tb[ECRNX_TM_ATTR_COMMAND])) {
case ECRNX_TM_CMD_APP2DEV_SET_DBGMODFILTER:
{
/* Send the command to the LMAC */
if ((status = ecrnx_send_dbg_set_mod_filter_req(ecrnx_hw, filter)))
return status;
}
break;
case ECRNX_TM_CMD_APP2DEV_SET_DBGSEVFILTER:
{
/* Send the command to the LMAC */
if ((status = ecrnx_send_dbg_set_sev_filter_req(ecrnx_hw, filter)))
return status;
}
break;
default:
ecrnx_printk_err("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 ecrnx_testmode_reg_dbg(struct ieee80211_hw *hw, struct nlattr **tb)
{
struct ecrnx_hw *ecrnx_hw = hw->priv;
struct ecrnx_plat *ecrnx_plat = ecrnx_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[ECRNX_TM_ATTR_REG_OFFSET]) {
ecrnx_printk_err("Error finding register offset\n");
return -ENOMSG;
}
mem_addr = nla_get_u32(tb[ECRNX_TM_ATTR_REG_OFFSET]);
offset = mem_addr & 0x00FFFFFF;
switch (nla_get_u32(tb[ECRNX_TM_ATTR_COMMAND])) {
case ECRNX_TM_CMD_APP2DEV_REG_READ_DBG:
{
/*** Send the command to the LMAC ***/
reg_value = ECRNX_REG_READ(ecrnx_plat, ECRNX_ADDR_SYSTEM, offset);
/* Allocate the answer message */
skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
if (!skb) {
ecrnx_printk_err("Error allocating memory\n");
return -ENOMEM;
}
if (nla_put_u32(skb, ECRNX_TM_ATTR_REG_VALUE32, reg_value))
goto nla_put_failure;
/* Send the answer to upper layer */
status = cfg80211_testmode_reply(skb);
if (status < 0)
ecrnx_printk_err("Error sending msg : %d\n", status);
}
break;
case ECRNX_TM_CMD_APP2DEV_REG_WRITE_DBG:
{
if (!tb[ECRNX_TM_ATTR_REG_VALUE32]) {
ecrnx_printk_err("Error finding value to write\n");
return -ENOMSG;
} else {
reg_value = nla_get_u32(tb[ECRNX_TM_ATTR_REG_VALUE32]);
/* Send the command to the LMAC */
ECRNX_REG_WRITE(reg_value, ecrnx_plat, ECRNX_ADDR_SYSTEM,
offset);
}
}
break;
default:
ecrnx_printk_err("Unknown testmode register command ID\n");
return -ENOSYS;
}
return status;
nla_put_failure:
kfree_skb(skb);
return -EMSGSIZE;
}