1 /* 2 * This file is part of wl1271 3 * 4 * Copyright (C) 2010 Nokia Corporation 5 * 6 * Contact: Luciano Coelho <luciano.coelho@nokia.com> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * version 2 as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 * 02110-1301 USA 21 * 22 */ 23 #include "testmode.h" 24 25 #include <linux/pm_runtime.h> 26 #include <linux/slab.h> 27 #include <net/genetlink.h> 28 29 #include "wlcore.h" 30 #include "debug.h" 31 #include "acx.h" 32 #include "io.h" 33 34 #define WL1271_TM_MAX_DATA_LENGTH 1024 35 36 enum wl1271_tm_commands { 37 WL1271_TM_CMD_UNSPEC, 38 WL1271_TM_CMD_TEST, 39 WL1271_TM_CMD_INTERROGATE, 40 WL1271_TM_CMD_CONFIGURE, 41 WL1271_TM_CMD_NVS_PUSH, /* Not in use. Keep to not break ABI */ 42 WL1271_TM_CMD_SET_PLT_MODE, 43 WL1271_TM_CMD_RECOVER, /* Not in use. Keep to not break ABI */ 44 WL1271_TM_CMD_GET_MAC, 45 46 __WL1271_TM_CMD_AFTER_LAST 47 }; 48 #define WL1271_TM_CMD_MAX (__WL1271_TM_CMD_AFTER_LAST - 1) 49 50 enum wl1271_tm_attrs { 51 WL1271_TM_ATTR_UNSPEC, 52 WL1271_TM_ATTR_CMD_ID, 53 WL1271_TM_ATTR_ANSWER, 54 WL1271_TM_ATTR_DATA, 55 WL1271_TM_ATTR_IE_ID, 56 WL1271_TM_ATTR_PLT_MODE, 57 58 __WL1271_TM_ATTR_AFTER_LAST 59 }; 60 #define WL1271_TM_ATTR_MAX (__WL1271_TM_ATTR_AFTER_LAST - 1) 61 62 static struct nla_policy wl1271_tm_policy[WL1271_TM_ATTR_MAX + 1] = { 63 [WL1271_TM_ATTR_CMD_ID] = { .type = NLA_U32 }, 64 [WL1271_TM_ATTR_ANSWER] = { .type = NLA_U8 }, 65 [WL1271_TM_ATTR_DATA] = { .type = NLA_BINARY, 66 .len = WL1271_TM_MAX_DATA_LENGTH }, 67 [WL1271_TM_ATTR_IE_ID] = { .type = NLA_U32 }, 68 [WL1271_TM_ATTR_PLT_MODE] = { .type = NLA_U32 }, 69 }; 70 71 72 static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[]) 73 { 74 int buf_len, ret, len; 75 struct sk_buff *skb; 76 void *buf; 77 u8 answer = 0; 78 79 wl1271_debug(DEBUG_TESTMODE, "testmode cmd test"); 80 81 if (!tb[WL1271_TM_ATTR_DATA]) 82 return -EINVAL; 83 84 buf = nla_data(tb[WL1271_TM_ATTR_DATA]); 85 buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]); 86 87 if (tb[WL1271_TM_ATTR_ANSWER]) 88 answer = nla_get_u8(tb[WL1271_TM_ATTR_ANSWER]); 89 90 if (buf_len > sizeof(struct wl1271_command)) 91 return -EMSGSIZE; 92 93 mutex_lock(&wl->mutex); 94 95 if (unlikely(wl->state != WLCORE_STATE_ON)) { 96 ret = -EINVAL; 97 goto out; 98 } 99 100 ret = pm_runtime_get_sync(wl->dev); 101 if (ret < 0) { 102 pm_runtime_put_noidle(wl->dev); 103 goto out; 104 } 105 106 ret = wl1271_cmd_test(wl, buf, buf_len, answer); 107 if (ret < 0) { 108 wl1271_warning("testmode cmd test failed: %d", ret); 109 goto out_sleep; 110 } 111 112 if (answer) { 113 /* If we got bip calibration answer print radio status */ 114 struct wl1271_cmd_cal_p2g *params = 115 (struct wl1271_cmd_cal_p2g *) buf; 116 117 s16 radio_status = (s16) le16_to_cpu(params->radio_status); 118 119 if (params->test.id == TEST_CMD_P2G_CAL && 120 radio_status < 0) 121 wl1271_warning("testmode cmd: radio status=%d", 122 radio_status); 123 else 124 wl1271_info("testmode cmd: radio status=%d", 125 radio_status); 126 127 len = nla_total_size(buf_len); 128 skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len); 129 if (!skb) { 130 ret = -ENOMEM; 131 goto out_sleep; 132 } 133 134 if (nla_put(skb, WL1271_TM_ATTR_DATA, buf_len, buf)) { 135 kfree_skb(skb); 136 ret = -EMSGSIZE; 137 goto out_sleep; 138 } 139 140 ret = cfg80211_testmode_reply(skb); 141 if (ret < 0) 142 goto out_sleep; 143 } 144 145 out_sleep: 146 pm_runtime_mark_last_busy(wl->dev); 147 pm_runtime_put_autosuspend(wl->dev); 148 out: 149 mutex_unlock(&wl->mutex); 150 151 return ret; 152 } 153 154 static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[]) 155 { 156 int ret; 157 struct wl1271_command *cmd; 158 struct sk_buff *skb; 159 u8 ie_id; 160 161 wl1271_debug(DEBUG_TESTMODE, "testmode cmd interrogate"); 162 163 if (!tb[WL1271_TM_ATTR_IE_ID]) 164 return -EINVAL; 165 166 ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]); 167 168 mutex_lock(&wl->mutex); 169 170 if (unlikely(wl->state != WLCORE_STATE_ON)) { 171 ret = -EINVAL; 172 goto out; 173 } 174 175 ret = pm_runtime_get_sync(wl->dev); 176 if (ret < 0) { 177 pm_runtime_put_noidle(wl->dev); 178 goto out; 179 } 180 181 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 182 if (!cmd) { 183 ret = -ENOMEM; 184 goto out_sleep; 185 } 186 187 ret = wl1271_cmd_interrogate(wl, ie_id, cmd, 188 sizeof(struct acx_header), sizeof(*cmd)); 189 if (ret < 0) { 190 wl1271_warning("testmode cmd interrogate failed: %d", ret); 191 goto out_free; 192 } 193 194 skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, sizeof(*cmd)); 195 if (!skb) { 196 ret = -ENOMEM; 197 goto out_free; 198 } 199 200 if (nla_put(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd)) { 201 kfree_skb(skb); 202 ret = -EMSGSIZE; 203 goto out_free; 204 } 205 206 ret = cfg80211_testmode_reply(skb); 207 if (ret < 0) 208 goto out_free; 209 210 out_free: 211 kfree(cmd); 212 out_sleep: 213 pm_runtime_mark_last_busy(wl->dev); 214 pm_runtime_put_autosuspend(wl->dev); 215 out: 216 mutex_unlock(&wl->mutex); 217 218 return ret; 219 } 220 221 static int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[]) 222 { 223 int buf_len, ret; 224 void *buf; 225 u8 ie_id; 226 227 wl1271_debug(DEBUG_TESTMODE, "testmode cmd configure"); 228 229 if (!tb[WL1271_TM_ATTR_DATA]) 230 return -EINVAL; 231 if (!tb[WL1271_TM_ATTR_IE_ID]) 232 return -EINVAL; 233 234 ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]); 235 buf = nla_data(tb[WL1271_TM_ATTR_DATA]); 236 buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]); 237 238 if (buf_len > sizeof(struct wl1271_command)) 239 return -EMSGSIZE; 240 241 mutex_lock(&wl->mutex); 242 ret = wl1271_cmd_configure(wl, ie_id, buf, buf_len); 243 mutex_unlock(&wl->mutex); 244 245 if (ret < 0) { 246 wl1271_warning("testmode cmd configure failed: %d", ret); 247 return ret; 248 } 249 250 return 0; 251 } 252 253 static int wl1271_tm_detect_fem(struct wl1271 *wl, struct nlattr *tb[]) 254 { 255 /* return FEM type */ 256 int ret, len; 257 struct sk_buff *skb; 258 259 ret = wl1271_plt_start(wl, PLT_FEM_DETECT); 260 if (ret < 0) 261 goto out; 262 263 mutex_lock(&wl->mutex); 264 265 len = nla_total_size(sizeof(wl->fem_manuf)); 266 skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len); 267 if (!skb) { 268 ret = -ENOMEM; 269 goto out_mutex; 270 } 271 272 if (nla_put(skb, WL1271_TM_ATTR_DATA, sizeof(wl->fem_manuf), 273 &wl->fem_manuf)) { 274 kfree_skb(skb); 275 ret = -EMSGSIZE; 276 goto out_mutex; 277 } 278 279 ret = cfg80211_testmode_reply(skb); 280 281 out_mutex: 282 mutex_unlock(&wl->mutex); 283 284 /* We always stop plt after DETECT mode */ 285 wl1271_plt_stop(wl); 286 out: 287 return ret; 288 } 289 290 static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[]) 291 { 292 u32 val; 293 int ret; 294 295 wl1271_debug(DEBUG_TESTMODE, "testmode cmd set plt mode"); 296 297 if (!tb[WL1271_TM_ATTR_PLT_MODE]) 298 return -EINVAL; 299 300 val = nla_get_u32(tb[WL1271_TM_ATTR_PLT_MODE]); 301 302 switch (val) { 303 case PLT_OFF: 304 ret = wl1271_plt_stop(wl); 305 break; 306 case PLT_ON: 307 case PLT_CHIP_AWAKE: 308 ret = wl1271_plt_start(wl, val); 309 break; 310 case PLT_FEM_DETECT: 311 ret = wl1271_tm_detect_fem(wl, tb); 312 break; 313 default: 314 ret = -EINVAL; 315 break; 316 } 317 318 return ret; 319 } 320 321 static int wl12xx_tm_cmd_get_mac(struct wl1271 *wl, struct nlattr *tb[]) 322 { 323 struct sk_buff *skb; 324 u8 mac_addr[ETH_ALEN]; 325 int ret = 0; 326 327 mutex_lock(&wl->mutex); 328 329 if (!wl->plt) { 330 ret = -EINVAL; 331 goto out; 332 } 333 334 if (wl->fuse_oui_addr == 0 && wl->fuse_nic_addr == 0) { 335 ret = -EOPNOTSUPP; 336 goto out; 337 } 338 339 mac_addr[0] = (u8)(wl->fuse_oui_addr >> 16); 340 mac_addr[1] = (u8)(wl->fuse_oui_addr >> 8); 341 mac_addr[2] = (u8) wl->fuse_oui_addr; 342 mac_addr[3] = (u8)(wl->fuse_nic_addr >> 16); 343 mac_addr[4] = (u8)(wl->fuse_nic_addr >> 8); 344 mac_addr[5] = (u8) wl->fuse_nic_addr; 345 346 skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, ETH_ALEN); 347 if (!skb) { 348 ret = -ENOMEM; 349 goto out; 350 } 351 352 if (nla_put(skb, WL1271_TM_ATTR_DATA, ETH_ALEN, mac_addr)) { 353 kfree_skb(skb); 354 ret = -EMSGSIZE; 355 goto out; 356 } 357 358 ret = cfg80211_testmode_reply(skb); 359 if (ret < 0) 360 goto out; 361 362 out: 363 mutex_unlock(&wl->mutex); 364 return ret; 365 } 366 367 int wl1271_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 368 void *data, int len) 369 { 370 struct wl1271 *wl = hw->priv; 371 struct nlattr *tb[WL1271_TM_ATTR_MAX + 1]; 372 u32 nla_cmd; 373 int err; 374 375 err = nla_parse(tb, WL1271_TM_ATTR_MAX, data, len, wl1271_tm_policy, 376 NULL); 377 if (err) 378 return err; 379 380 if (!tb[WL1271_TM_ATTR_CMD_ID]) 381 return -EINVAL; 382 383 nla_cmd = nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID]); 384 385 /* Only SET_PLT_MODE is allowed in case of mode PLT_CHIP_AWAKE */ 386 if (wl->plt_mode == PLT_CHIP_AWAKE && 387 nla_cmd != WL1271_TM_CMD_SET_PLT_MODE) 388 return -EOPNOTSUPP; 389 390 switch (nla_cmd) { 391 case WL1271_TM_CMD_TEST: 392 return wl1271_tm_cmd_test(wl, tb); 393 case WL1271_TM_CMD_INTERROGATE: 394 return wl1271_tm_cmd_interrogate(wl, tb); 395 case WL1271_TM_CMD_CONFIGURE: 396 return wl1271_tm_cmd_configure(wl, tb); 397 case WL1271_TM_CMD_SET_PLT_MODE: 398 return wl1271_tm_cmd_set_plt_mode(wl, tb); 399 case WL1271_TM_CMD_GET_MAC: 400 return wl12xx_tm_cmd_get_mac(wl, tb); 401 default: 402 return -EOPNOTSUPP; 403 } 404 } 405