forked from openwrt/mt76
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add utility for using testmode support
Signed-off-by: Felix Fietkau <[email protected]>
- Loading branch information
Showing
7 changed files
with
916 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,14 @@ | ||
.* | ||
*.o | ||
*.ko | ||
*.mod | ||
*.mod.c | ||
Module.symvers | ||
*.symvers | ||
*.symvers.tmp | ||
modules.order | ||
ipkg-* | ||
CMakeFiles | ||
CMakeCache.txt | ||
cmake_install.cmake | ||
tools/Makefile | ||
tools/mt76-test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
cmake_minimum_required(VERSION 2.8) | ||
|
||
PROJECT(mt76-test C) | ||
ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3) | ||
|
||
ADD_EXECUTABLE(mt76-test main.c fields.c eeprom.c) | ||
TARGET_LINK_LIBRARIES(mt76-test nl-tiny) | ||
|
||
SET(CMAKE_INSTALL_PREFIX /usr) | ||
|
||
INSTALL(TARGETS mt76-test | ||
RUNTIME DESTINATION sbin | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# MT76 testmode utility | ||
|
||
This utility can be used to perform some support functions required for Rx/Tx calibration, similar to the ATE command set of the SDK driver. | ||
Its main functionality is setting test parameters and dumping statistics. It can also be used to prepare modified EEPROM data for writing into flash. | ||
|
||
## Basic syntax | ||
|
||
- Set parameters: | ||
- `mt76-test phy0 set <parameter>=<value>`[...] | ||
- Show current parameter set: | ||
- `mt76-test phy0 dump` | ||
- Show statistics | ||
- `mt76-test phy0 dump stats` | ||
|
||
## Running tests | ||
|
||
The test state is controlled through the `state` parameter. The following state values are supported: | ||
|
||
- `off`: Normal operation (default) | ||
- `idle`: Testmode enabled, but no specific test active | ||
- `tx_frames`: Send a number of packets with configurable rate/txpower | ||
- `rx_frames`: Receive packets and show RSSI and packet count/PER | ||
|
||
Setting a state activates it even if the value is the same as before. Setting it to `tx_frames` triggers sending packets immediately. Setting `rx_frames` enables receive mode and can also be used to clear rx statistics. | ||
|
||
## Notes | ||
|
||
To run tests, you first need to disable all normal interfaces, set up a monitor mode interface and configure it to the channel/bandwidth you intend to use. | ||
|
||
|
||
## Parameters: | ||
|
||
| Parameter name | ATE parameter | Description | | ||
|--|--|--| | ||
| `state` | `ATE` | Test state | | ||
| `tx_count` | `ATETXCNT` | Number of packets to send | | ||
| `tx_length` | `ATETXLEN` | Length of packets to send | | ||
| `tx_rate_mode` | `ATETXMODE` | PHY mode (possible values: `cck`, `ofdm`, `ht`, `vht`) | | ||
| `tx_rate_nss` | | Number of spatial streams (VHT only) | | ||
| `tx_rate_idx` | `ATETXMCS` | MCS or legacy rate index | | ||
| `tx_rate_sgi` | `ATETXGI` | Enable short guard interval | | ||
| `tx_rate_ldpc` | `ATETXLDPC` | Enable LDPC | | ||
| `tx_power_control` | `ATETXPOWERCTRL` | Firmware transmit power control feature | | ||
| `tx_power` | `ATETXPOW0-3` | Per-chain half-dBm transmit power, `0` means default value, e.g. `10,0,0,0` | | ||
| `tx_antenna` | `ATETXANT` | Transmit antenna bitmask | | ||
| `freq_offset` | `ATETXFREQOFFSET` | Frequency offset | | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,263 @@ | ||
// SPDX-License-Identifier: ISC | ||
/* Copyright (C) 2020 Felix Fietkau <[email protected]> */ | ||
#define _GNU_SOURCE | ||
#include <sys/mman.h> | ||
#include <sys/stat.h> | ||
|
||
#include <stdio.h> | ||
#include <unistd.h> | ||
#include <string.h> | ||
#include <fcntl.h> | ||
#include <errno.h> | ||
|
||
#include "mt76-test.h" | ||
|
||
static const char *mtd_part; | ||
static uint32_t mtd_offset; | ||
|
||
static char *eeprom_file; | ||
static int eeprom_fd = -1; | ||
unsigned char *eeprom_data; | ||
|
||
static int mt76_eeprom_dump_cb(struct nl_msg *msg, void *arg) | ||
{ | ||
struct nlattr *tb[NUM_MT76_TM_ATTRS]; | ||
struct nlattr *attr; | ||
|
||
attr = unl_find_attr(&unl, msg, NL80211_ATTR_TESTDATA); | ||
if (!attr) | ||
return NL_SKIP; | ||
|
||
nla_parse_nested(tb, MT76_TM_ATTR_MAX, attr, msg_field.policy); | ||
if (!tb[MT76_TM_ATTR_MTD_PART] || !tb[MT76_TM_ATTR_MTD_OFFSET]) | ||
return NL_SKIP; | ||
|
||
mtd_part = strdup(nla_get_string(tb[MT76_TM_ATTR_MTD_PART])); | ||
mtd_offset = nla_get_u32(tb[MT76_TM_ATTR_MTD_OFFSET]); | ||
|
||
return NL_SKIP; | ||
} | ||
|
||
static FILE *mtd_open(const char *mtd) | ||
{ | ||
char line[128], name[64]; | ||
FILE *fp; | ||
int i; | ||
|
||
fp = fopen("/proc/mtd", "r"); | ||
if (!fp) | ||
return NULL; | ||
|
||
snprintf(name, sizeof(name), "\"%s\"", mtd); | ||
while (fgets(line, sizeof(line), fp)) { | ||
if (!sscanf(line, "mtd%d:", &i) || !strstr(line, name)) | ||
continue; | ||
|
||
snprintf(line, sizeof(line), "/dev/mtd%d", i); | ||
fclose(fp); | ||
return fopen(line, "r"); | ||
} | ||
fclose(fp); | ||
|
||
return NULL; | ||
} | ||
|
||
|
||
static int | ||
mt76_eeprom_create_file(void) | ||
{ | ||
char buf[1024]; | ||
ssize_t len; | ||
FILE *f; | ||
int fd; | ||
|
||
f = mtd_open(mtd_part); | ||
if (!f) { | ||
fprintf(stderr, "Failed to open MTD device\n"); | ||
return -1; | ||
} | ||
|
||
fd = open(eeprom_file, O_RDWR | O_CREAT | O_EXCL); | ||
if (fd < 0) | ||
goto out; | ||
|
||
while ((len = fread(buf, 1, sizeof(buf), f)) > 0) { | ||
ssize_t w; | ||
|
||
retry: | ||
w = write(fd, buf, len); | ||
if (w > 0) | ||
continue; | ||
|
||
if (errno == EINTR) | ||
goto retry; | ||
|
||
perror("write"); | ||
unlink(eeprom_file); | ||
close(fd); | ||
fd = -1; | ||
goto out; | ||
} | ||
|
||
lseek(fd, 0, SEEK_SET); | ||
|
||
out: | ||
fclose(f); | ||
return fd; | ||
} | ||
|
||
static bool | ||
mt76_eeprom_file_exists(void) | ||
{ | ||
struct stat st; | ||
|
||
return stat(eeprom_file, &st) == 0; | ||
} | ||
|
||
static int | ||
mt76_eeprom_init_file(void) | ||
{ | ||
int fd; | ||
|
||
if (!mt76_eeprom_file_exists()) | ||
return mt76_eeprom_create_file(); | ||
|
||
fd = open(eeprom_file, O_RDWR); | ||
if (fd < 0) | ||
perror("open"); | ||
|
||
return fd; | ||
} | ||
|
||
int mt76_eeprom_init(int phy) | ||
{ | ||
struct nl_msg *msg; | ||
|
||
msg = unl_genl_msg(&unl, NL80211_CMD_TESTMODE, true); | ||
nla_put_u32(msg, NL80211_ATTR_WIPHY, phy); | ||
unl_genl_request(&unl, msg, mt76_eeprom_dump_cb, NULL); | ||
|
||
if (!mtd_part) { | ||
fprintf(stderr, "Could not find MTD partition information\n"); | ||
return -1; | ||
} | ||
|
||
eeprom_file = malloc(sizeof(EEPROM_FILE_PATH_FMT) + strlen(mtd_part)); | ||
sprintf(eeprom_file, EEPROM_FILE_PATH_FMT, mtd_part); | ||
|
||
eeprom_fd = mt76_eeprom_init_file(); | ||
if (eeprom_fd < 0) | ||
return -1; | ||
|
||
eeprom_data = mmap(NULL, EEPROM_PART_SIZE, PROT_READ | PROT_WRITE, | ||
MAP_SHARED, eeprom_fd, mtd_offset); | ||
if (!eeprom_data) { | ||
perror("mmap"); | ||
close(eeprom_fd); | ||
return -1; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
void mt76_eeprom_close(void) | ||
{ | ||
if (eeprom_fd < 0) | ||
return; | ||
|
||
msync(eeprom_data, EEPROM_PART_SIZE, MS_SYNC); | ||
munmap(eeprom_data, EEPROM_PART_SIZE); | ||
close(eeprom_fd); | ||
eeprom_fd = -1; | ||
} | ||
|
||
static int | ||
mt76_eeprom_set(int argc, char **argv) | ||
{ | ||
for (; argc > 0; argc--, argv++) { | ||
char *addr_str = argv[0]; | ||
char *val_str = strchr(addr_str, '='); | ||
unsigned long addr, val; | ||
char *err; | ||
|
||
if (!val_str) { | ||
fprintf(stderr, "Invalid argument: %s\n", addr_str); | ||
return 1; | ||
} | ||
|
||
*(val_str++) = 0; | ||
|
||
addr = strtoul(addr_str, &err, 0); | ||
if ((err && *err) || addr >= EEPROM_PART_SIZE) { | ||
fprintf(stderr, "Invalid address: %s\n", addr_str); | ||
return 1; | ||
} | ||
|
||
val = strtoul(val_str, &err, 0); | ||
if ((err && *err) || val >= 0xff) { | ||
fprintf(stderr, "Invalid value: %s\n", val_str); | ||
return 1; | ||
} | ||
|
||
eeprom_data[addr] = val; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int | ||
mt76_eeprom_changes(void) | ||
{ | ||
unsigned char *buf; | ||
FILE *f; | ||
int i; | ||
|
||
f = mtd_open(mtd_part); | ||
if (!f) { | ||
fprintf(stderr, "Cannot open MTD device\n"); | ||
return 1; | ||
} | ||
|
||
buf = malloc(EEPROM_PART_SIZE); | ||
fseek(f, mtd_offset, SEEK_SET); | ||
fread(buf, 1, EEPROM_PART_SIZE, f); | ||
for (i = 0; i < EEPROM_PART_SIZE; i++) { | ||
if (buf[i] == eeprom_data[i]) | ||
continue; | ||
|
||
printf("[%04x] %02x => %02x\n", i, buf[i], eeprom_data[i]); | ||
} | ||
free(buf); | ||
|
||
return 0; | ||
} | ||
|
||
|
||
int mt76_eeprom(int phy, int argc, char **argv) | ||
{ | ||
const char *cmd; | ||
int ret = 0; | ||
|
||
if (argc < 1) | ||
usage(); | ||
|
||
if (mt76_eeprom_init(phy)) | ||
return 1; | ||
|
||
cmd = argv[0]; | ||
argv++; | ||
argc--; | ||
|
||
if (!strcmp(cmd, "file")) | ||
printf("%s\n", eeprom_file); | ||
else if (!strcmp(cmd, "set")) | ||
ret = mt76_eeprom_set(argc, argv); | ||
else if (!strcmp(cmd, "reset")) | ||
unlink(eeprom_file); | ||
else if (!strcmp(cmd, "changes")) | ||
ret = mt76_eeprom_changes(); | ||
|
||
mt76_eeprom_close(); | ||
|
||
return ret; | ||
} |
Oops, something went wrong.