mirror of
https://github.com/shenmintao/aic8800d80.git
synced 2026-09-26 17:44:16 +00:00
init: add source codes from tenda
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="5721", SYMLINK+="aicudisk", RUN+="/usr/bin/eject /dev/%k"
|
||||||
|
KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="5723", SYMLINK+="tendaudisk", RUN+="/usr/bin/eject /dev/%k"
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
LOCAL_MODULE := bt_test
|
||||||
|
LOCAL_SRC_FILES := bt_test.c
|
||||||
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
LOCAL_MODULE := wifi_test
|
||||||
|
LOCAL_SRC_FILES := wifi_test.c
|
||||||
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#CROSS_COMPILE := /opt/toolchains/mips-gcc540-glibc222-64bit-r3.3.0/bin/mips-linux-gnu-
|
||||||
|
|
||||||
|
LDFLAGS := -lpthread
|
||||||
|
|
||||||
|
default: all
|
||||||
|
|
||||||
|
all: wifi_test bt_test
|
||||||
|
|
||||||
|
wifi_test: wifi_test.o
|
||||||
|
$(CROSS_COMPILE)gcc $+ -o $@
|
||||||
|
|
||||||
|
bt_test: bt_test.o
|
||||||
|
$(CROSS_COMPILE)gcc $+ $(LDFLAGS) -o $@
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CROSS_COMPILE)gcc -c $+ -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm *.o wifi_test bt_test
|
||||||
|
|
||||||
|
install:
|
||||||
|
sudo cp wifi_test /sbin
|
||||||
|
sudo cp bt_test /sbin
|
||||||
@@ -0,0 +1,288 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include<stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#define WIFI_DRIVER_FW_PATH "sta"
|
||||||
|
#define WIFI_DRIVER_MODULE_NAME "rwnx_fdrv"
|
||||||
|
#define WIFI_DRIVER_MODULE_PATH "/vendor/modules/rwnx_fdrv.ko"
|
||||||
|
#define MAX_DRV_CMD_SIZE 1536
|
||||||
|
#define TXRX_PARA SIOCDEVPRIVATE+1
|
||||||
|
|
||||||
|
static const char IFACE_DIR[] = "";
|
||||||
|
static const char DRIVER_MODULE_NAME[] = "rwnx_fdrv";
|
||||||
|
static const char DRIVER_MODULE_TAG[] = WIFI_DRIVER_MODULE_NAME " ";
|
||||||
|
static const char DRIVER_MODULE_PATH[] = WIFI_DRIVER_MODULE_PATH;
|
||||||
|
static const char DRIVER_MODULE_ARG[] = "";
|
||||||
|
static const char FIRMWARE_LOADER[] = "";
|
||||||
|
static const char DRIVER_PROP_NAME[] = "wlan.driver.status";
|
||||||
|
|
||||||
|
#ifndef TEMP_FAILURE_RETRY
|
||||||
|
#define TEMP_FAILURE_RETRY(expression) \
|
||||||
|
(__extension__ \
|
||||||
|
({ long int __result; \
|
||||||
|
do __result = (long int) (expression); \
|
||||||
|
while (__result == -1L && errno == EINTR); \
|
||||||
|
__result; }))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct android_wifi_priv_cmd {
|
||||||
|
char *buf;
|
||||||
|
int used_len;
|
||||||
|
int total_len;
|
||||||
|
} android_wifi_priv_cmd;
|
||||||
|
|
||||||
|
int wifi_send_cmd_to_net_interface(const char* if_name, int argC, char *argV[])
|
||||||
|
{
|
||||||
|
int sock;
|
||||||
|
struct ifreq ifr;
|
||||||
|
int ret = 0;
|
||||||
|
int i = 0;
|
||||||
|
char buf[MAX_DRV_CMD_SIZE];
|
||||||
|
struct android_wifi_priv_cmd priv_cmd;
|
||||||
|
char is_param_err = 0;
|
||||||
|
int buf_len = 0;
|
||||||
|
|
||||||
|
sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (sock < 0) {
|
||||||
|
printf("bad sock!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
|
strcpy(ifr.ifr_name, if_name);
|
||||||
|
|
||||||
|
if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
|
||||||
|
printf("%s Could not read interface %s flags: %s",__func__, if_name, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(ifr.ifr_flags & IFF_UP)) {
|
||||||
|
printf("%s is not up!\n",if_name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("ifr.ifr_name = %s\n", ifr.ifr_name);
|
||||||
|
memset(&priv_cmd, 0, sizeof(priv_cmd));
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
|
||||||
|
for(i=2; i<argC; i++){
|
||||||
|
strcat(buf, argV[i]);
|
||||||
|
strcat(buf, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
priv_cmd.buf = buf;
|
||||||
|
priv_cmd.used_len = strlen(buf);
|
||||||
|
priv_cmd.total_len = sizeof(buf);
|
||||||
|
ifr.ifr_data = (void*)&priv_cmd;
|
||||||
|
|
||||||
|
printf("%s:\n", argV[2]);
|
||||||
|
if (strcasecmp(argV[2], "SET_TX") == 0) {
|
||||||
|
if (argC < 8) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if (strcasecmp(argV[2], "SET_TXTONE") == 0) {
|
||||||
|
if (((argC == 4) && (argV[3][0] != '0'))
|
||||||
|
|| ((argC == 5) && (argV[3][0] == '0'))) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "SET_RX") == 0)
|
||||||
|
|| (strcasecmp(argV[2], "SET_POWER") == 0)) {
|
||||||
|
if (argC < 5) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "SET_XTAL_CAP") == 0)
|
||||||
|
|| (strcasecmp(argV[2], "SET_XTAL_CAP_FINE") == 0)) {
|
||||||
|
if (argC < 4) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "GET_EFUSE_BLOCK") == 0)
|
||||||
|
|| (strcasecmp(argV[2], "SET_FREQ_CAL") == 0)) {
|
||||||
|
if (argC < 4) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "SET_MAC_ADDR") == 0)
|
||||||
|
|| (strcasecmp(argV[2], "SET_BT_MAC_ADDR") == 0)) {
|
||||||
|
if (argC < 8) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if (strcasecmp(argV[2], "SET_VENDOR_INFO") == 0) {
|
||||||
|
if (argC < 4) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "RDWR_PWRIDX") == 0)
|
||||||
|
|| (strcasecmp(argV[2], "RDWR_PWROFST") == 0)
|
||||||
|
|| (strcasecmp(argV[2], "RDWR_EFUSE_PWROFST") == 0)) {
|
||||||
|
if (((argC == 4) && (argV[3][0] != '0'))
|
||||||
|
|| (argC == 5)
|
||||||
|
|| ((argC == 6) && (argV[3][0] == '0'))) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "RDWR_DRVIBIT") == 0)
|
||||||
|
|| (strcasecmp(argV[2], "RDWR_EFUSE_DRVIBIT") == 0)) {
|
||||||
|
if (((argC == 4) && (argV[3][0] != '0'))
|
||||||
|
|| ((argC == 5) && (argV[3][0] == '0'))) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "BT_RESET") == 0)) {
|
||||||
|
char bt_reset_hci_cmd[32] = "01 03 0c 00";
|
||||||
|
if (argC == 3) {
|
||||||
|
buf_len = priv_cmd.used_len;
|
||||||
|
memcpy(&priv_cmd.buf[buf_len], &bt_reset_hci_cmd[0], strlen(bt_reset_hci_cmd));
|
||||||
|
buf_len += strlen(bt_reset_hci_cmd);
|
||||||
|
priv_cmd.used_len = buf_len;
|
||||||
|
} else {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "BT_TXDH") == 0)) {
|
||||||
|
char bt_txdh_hci_cmd[255] = "01 06 18 0e ";
|
||||||
|
if (argC == 17) {
|
||||||
|
buf_len = priv_cmd.used_len;
|
||||||
|
int arg_len = strlen(argV[2]);
|
||||||
|
int txdh_cmd_len = strlen(bt_txdh_hci_cmd);
|
||||||
|
memcpy(&bt_txdh_hci_cmd[txdh_cmd_len], &priv_cmd.buf[arg_len+1], buf_len - arg_len - 1);
|
||||||
|
memcpy(&priv_cmd.buf[arg_len+1], &bt_txdh_hci_cmd[0], strlen(bt_txdh_hci_cmd));
|
||||||
|
buf_len += strlen(bt_txdh_hci_cmd);
|
||||||
|
priv_cmd.used_len = buf_len;
|
||||||
|
} else {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "BT_RXDH") == 0)) {
|
||||||
|
if (argC == 16) {
|
||||||
|
char bt_rxdh_hci_cmd[255] = "01 0b 18 0d ";
|
||||||
|
buf_len = priv_cmd.used_len;
|
||||||
|
int arg_len = strlen(argV[2]);
|
||||||
|
int rxdh_cmd_len = strlen(bt_rxdh_hci_cmd);
|
||||||
|
memcpy(&bt_rxdh_hci_cmd[rxdh_cmd_len], &priv_cmd.buf[arg_len+1], buf_len - arg_len - 1);
|
||||||
|
memcpy(&priv_cmd.buf[arg_len+1], &bt_rxdh_hci_cmd[0], strlen(bt_rxdh_hci_cmd));
|
||||||
|
buf_len += strlen(bt_rxdh_hci_cmd);
|
||||||
|
priv_cmd.used_len = buf_len;
|
||||||
|
} else {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "BT_STOP") == 0)) {
|
||||||
|
char bt_stop_hci_cmd[255] = "01 0C 18 01 ";
|
||||||
|
if (argC == 4) {
|
||||||
|
buf_len = priv_cmd.used_len;
|
||||||
|
int arg_len = strlen(argV[2]);
|
||||||
|
int stop_cmd_len = strlen(bt_stop_hci_cmd);
|
||||||
|
memcpy(&bt_stop_hci_cmd[stop_cmd_len], &priv_cmd.buf[arg_len+1], buf_len - arg_len - 1);
|
||||||
|
memcpy(&priv_cmd.buf[arg_len+1], &bt_stop_hci_cmd[0], strlen(bt_stop_hci_cmd));
|
||||||
|
buf_len += strlen(bt_stop_hci_cmd);
|
||||||
|
priv_cmd.used_len = buf_len;
|
||||||
|
} else {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
is_param_err = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_param_err) {
|
||||||
|
printf("param error!!!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = ioctl(sock, TXRX_PARA, &ifr)) < 0) {
|
||||||
|
printf("%s: error ioctl[TX_PARA] ret= %d\n", __func__, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&priv_cmd, ifr.ifr_data, sizeof(struct android_wifi_priv_cmd));
|
||||||
|
if (strcasecmp(argV[2], "SET_FREQ_CAL") == 0)
|
||||||
|
printf("done: freq_cal: 0x%8x\n", *(unsigned int *)priv_cmd.buf);
|
||||||
|
else if (strcasecmp(argV[2], "GET_EFUSE_BLOCK") == 0)
|
||||||
|
printf("done:efuse: 0x%8x\n", *(unsigned int *)priv_cmd.buf);
|
||||||
|
else if (strcasecmp(argV[2], "SET_XTAL_CAP") == 0)
|
||||||
|
printf("done:xtal cap: 0x%x\n", *(unsigned int *)priv_cmd.buf);
|
||||||
|
else if (strcasecmp(argV[2], "SET_XTAL_CAP_FINE") == 0)
|
||||||
|
printf("done:xtal cap fine: 0x%x\n", *(unsigned int *)priv_cmd.buf);
|
||||||
|
else if (strcasecmp(argV[2], "GET_RX_RESULT") == 0)
|
||||||
|
printf("done: getrx fcsok=%d, total=%d\n", *(unsigned int *)priv_cmd.buf, *(unsigned int *)&priv_cmd.buf[4]);
|
||||||
|
else if (strcasecmp(argV[2], "GET_MAC_ADDR") == 0) {
|
||||||
|
printf("done: get macaddr = %x : %x : %x : %x : %x : %x\n",
|
||||||
|
*(unsigned char *)&priv_cmd.buf[5], *(unsigned char *)&priv_cmd.buf[4], *(unsigned char *)&priv_cmd.buf[3],
|
||||||
|
*(unsigned char *)&priv_cmd.buf[2], *(unsigned char *)&priv_cmd.buf[1], *(unsigned char *)&priv_cmd.buf[0]);
|
||||||
|
} else if (strcasecmp(argV[2], "GET_BT_MAC_ADDR") == 0) {
|
||||||
|
printf("done: get bt macaddr = %x : %x : %x : %x : %x : %x\n",
|
||||||
|
*(unsigned char *)&priv_cmd.buf[5], *(unsigned char *)&priv_cmd.buf[4], *(unsigned char *)&priv_cmd.buf[3],
|
||||||
|
*(unsigned char *)&priv_cmd.buf[2], *(unsigned char *)&priv_cmd.buf[1], *(unsigned char *)&priv_cmd.buf[0]);
|
||||||
|
} else if (strcasecmp(argV[2], "GET_FREQ_CAL") == 0) {
|
||||||
|
unsigned int val = *(unsigned int *)&priv_cmd.buf[0];
|
||||||
|
printf("done: get_freq_cal: xtal_cap=0x%x, xtal_cap_fine=%x\n", val & 0x0000ffff, (val >> 16) & 0x0000ffff);
|
||||||
|
} else if (strcasecmp(argV[2], "GET_VENDOR_INFO") == 0) {
|
||||||
|
printf("done: get_vendor_info = 0x%x\n", *(unsigned char *)&priv_cmd.buf[0]);
|
||||||
|
} else if (strcasecmp(argV[2], "RDWR_PWRMM") == 0) {
|
||||||
|
printf("done: txpwr manual mode = %x\n", *(unsigned int *)&priv_cmd.buf[0]);
|
||||||
|
} else if (strcasecmp(argV[2], "RDWR_PWRIDX") == 0) {
|
||||||
|
char *buff = &priv_cmd.buf[0];
|
||||||
|
printf("done:\n"
|
||||||
|
"txpwr index 2.4g:\n"
|
||||||
|
" [0]=%d(ofdmlowrate)\n"
|
||||||
|
" [1]=%d(ofdmhighrate)\n"
|
||||||
|
" [2]=%d(ofdm1024qam)\n"
|
||||||
|
" [3]=%d(dsss)\n", buff[0], buff[1], buff[2], buff[3]);
|
||||||
|
printf("txpwr index 5g:\n"
|
||||||
|
" [0]=%d(ofdmlowrate)\n"
|
||||||
|
" [1]=%d(ofdmhighrate)\n"
|
||||||
|
" [2]=%d(ofdm1024qam)\n", buff[4], buff[5], buff[6]);
|
||||||
|
} else if (strcasecmp(argV[2], "RDWR_PWROFST") == 0) {
|
||||||
|
char *buff = &priv_cmd.buf[0];
|
||||||
|
printf("done:\n"
|
||||||
|
"txpwr offset 2.4g:\n"
|
||||||
|
" [0]=%d(ch1~4)\n"
|
||||||
|
" [1]=%d(ch5~9)\n"
|
||||||
|
" [2]=%d(ch10~13)\n", buff[0], buff[1], buff[2]);
|
||||||
|
printf("txpwr offset 5g:\n"
|
||||||
|
" [0]=%d(ch36~64)\n"
|
||||||
|
" [1]=%d(ch100~120)\n"
|
||||||
|
" [2]=%d(ch122~140)\n"
|
||||||
|
" [3]=%d(ch142~165)\n", buff[3], buff[4], buff[5], buff[6]);
|
||||||
|
} else if (strcasecmp(argV[2], "RDWR_DRVIBIT") == 0) {
|
||||||
|
char *buff = &priv_cmd.buf[0];
|
||||||
|
int idx = 0;
|
||||||
|
printf("done: 2.4g txgain tbl pa drv_ibit:\n");
|
||||||
|
for (idx = 0; idx < 16; idx++) {
|
||||||
|
printf(" %x", buff[idx]);
|
||||||
|
if (!((idx + 1) & 0x03)) {
|
||||||
|
printf(" [%x~%x]\n", idx - 3, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (strcasecmp(argV[2], "RDWR_EFUSE_PWROFST") == 0) {
|
||||||
|
char *buff = &priv_cmd.buf[0];
|
||||||
|
printf("done:\n"
|
||||||
|
"efuse txpwr offset 2.4g:\n"
|
||||||
|
" [0]=%d(ch1~4)\n"
|
||||||
|
" [1]=%d(ch5~9)\n"
|
||||||
|
" [2]=%d(ch10~13)\n", buff[0], buff[1], buff[2]);
|
||||||
|
printf("efuse txpwr offset 5g:\n"
|
||||||
|
" [0]=%d(ch36~64)\n"
|
||||||
|
" [1]=%d(ch100~120)\n"
|
||||||
|
" [2]=%d(ch122~140)\n"
|
||||||
|
" [3]=%d(ch142~165)\n", buff[3], buff[4], buff[5], buff[6]);
|
||||||
|
} else if (strcasecmp(argV[2], "RDWR_EFUSE_DRVIBIT") == 0) {
|
||||||
|
printf("done: efsue 2.4g txgain tbl pa drv_ibit: %x\n", priv_cmd.buf[0]);
|
||||||
|
} else {
|
||||||
|
printf("done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argC, char *argV[])
|
||||||
|
{
|
||||||
|
|
||||||
|
char* ins = "insmod";
|
||||||
|
char* rm = "rmmod";
|
||||||
|
char* ko = "rwnx_fdrv.ko";
|
||||||
|
|
||||||
|
// printf("enter!!!AIC argC=%d argV[0]=%s argV[1]=%s argV[2]=%s\n", argC, argV[0], argV[1],argV[2]);
|
||||||
|
if(argC >= 3)
|
||||||
|
wifi_send_cmd_to_net_interface(argV[1], argC, argV);
|
||||||
|
else
|
||||||
|
printf("Bad parameter! %d\n",argC);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,770 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <net/if_arp.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
|
||||||
|
//tool role
|
||||||
|
#define SERVER 0
|
||||||
|
#define CLIENT 1
|
||||||
|
#define WLAN_CLIENT 2
|
||||||
|
|
||||||
|
//interface
|
||||||
|
#define UART 0
|
||||||
|
#define USB 1
|
||||||
|
#define WLAN 2
|
||||||
|
|
||||||
|
//uart param
|
||||||
|
#define BAUDRATE 1500000
|
||||||
|
#define DATABITS 8
|
||||||
|
#define PARTY 'N'
|
||||||
|
#define STOP '1'
|
||||||
|
#define SOFTWARE_HANDSHAKE 0
|
||||||
|
#define HARDWARE_HANDSHAKE 0
|
||||||
|
|
||||||
|
//socket param
|
||||||
|
#define BT_HCI_TOOL_PORT 5001
|
||||||
|
#define SOCKER_BUFFER_SIZE 1024
|
||||||
|
|
||||||
|
#define OK 0
|
||||||
|
#define ERR -1
|
||||||
|
#define FALSE 0
|
||||||
|
#define TRUE 1
|
||||||
|
|
||||||
|
#define DOWN_FW_CFG _IOW('E', 176, int)
|
||||||
|
#define GET_USB_INFO _IOR('E', 180, int)
|
||||||
|
|
||||||
|
#define WLAN_CMD_MAX_CNT 256
|
||||||
|
#define TXRX_PARA SIOCDEVPRIVATE+1
|
||||||
|
|
||||||
|
int server_or_client = SERVER;
|
||||||
|
int interface = USB;
|
||||||
|
int bt_dev_fd = 0;
|
||||||
|
|
||||||
|
char s_baudrate[8];
|
||||||
|
|
||||||
|
char* s_hci_command[256];
|
||||||
|
char w_ifname[64];
|
||||||
|
char *w_command[WLAN_CMD_MAX_CNT];
|
||||||
|
char hci_event[256];
|
||||||
|
|
||||||
|
char dev_path[] = "/dev/aicbt_dev";
|
||||||
|
|
||||||
|
char hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 };
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct android_wifi_priv_cmd {
|
||||||
|
char *buf;
|
||||||
|
int used_len;
|
||||||
|
int total_len;
|
||||||
|
} android_wifi_priv_cmd;
|
||||||
|
|
||||||
|
|
||||||
|
void helper(){
|
||||||
|
printf("\t<-s> to be tool service. ex. \"bt_test -s uart 115200 /dev/ttyS0\" or \"bt_test -s usb\" or \"bt_test -s wlan wlan0\"\n");
|
||||||
|
//printf("\t<-s> to be tool service. ex. -s uart 115200 noflow and -s usb\n");
|
||||||
|
printf("\t<-c> to send hci cmd to interface.\n");
|
||||||
|
printf("\t<-w> to send wlan cmd to interface.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_cmd_line(int argc, char **argv){
|
||||||
|
int command_number = argc;
|
||||||
|
int command_counter = 1;
|
||||||
|
int hci_command_counter = 0;
|
||||||
|
//int error_command = 0;
|
||||||
|
|
||||||
|
while(command_counter < command_number){
|
||||||
|
if(!strcmp(argv[command_counter], "-s")){
|
||||||
|
if(!(command_number >= 3)){
|
||||||
|
printf("error command \r\n");
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
printf("bt_hci_tool server setting\r\n");
|
||||||
|
server_or_client = SERVER;
|
||||||
|
command_counter++;
|
||||||
|
if(!strcmp(argv[command_counter], "usb")){
|
||||||
|
printf("use USB\r\n");
|
||||||
|
interface = USB;
|
||||||
|
return OK;
|
||||||
|
}else if(!strcmp(argv[command_counter], "uart")){
|
||||||
|
interface = UART;
|
||||||
|
if(command_number != 5){
|
||||||
|
printf("error command \r\n");
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
command_counter++;
|
||||||
|
memcpy(s_baudrate, argv[command_counter], strlen(argv[command_counter]));
|
||||||
|
command_counter++;
|
||||||
|
memset(dev_path, 0, strlen(dev_path));
|
||||||
|
memcpy(dev_path, argv[command_counter], strlen(argv[command_counter]));
|
||||||
|
printf("use UART %d %s\r\n", atoi(s_baudrate), dev_path);
|
||||||
|
return OK;
|
||||||
|
}else if(!strcmp(argv[command_counter], "wlan")){
|
||||||
|
interface = WLAN;
|
||||||
|
if(command_number != 4){
|
||||||
|
printf("error command \r\n");
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
command_counter++;
|
||||||
|
memcpy(w_ifname, argv[command_counter], strlen(argv[command_counter]));
|
||||||
|
printf("use WLAN %s\r\n", w_ifname);
|
||||||
|
return OK;
|
||||||
|
}else{
|
||||||
|
printf("interface set error\r\n");
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
}else if(!strcmp(argv[command_counter], "-c")){
|
||||||
|
server_or_client = CLIENT;
|
||||||
|
command_counter++;
|
||||||
|
hci_command_counter = 0;
|
||||||
|
while(command_counter < command_number){
|
||||||
|
s_hci_command[hci_command_counter++] = argv[command_counter];
|
||||||
|
command_counter++;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
} else if (!strcmp(argv[command_counter], "-w")) {
|
||||||
|
int w_command_counter = 0;
|
||||||
|
server_or_client = WLAN_CLIENT;
|
||||||
|
if (command_number >= WLAN_CMD_MAX_CNT) {
|
||||||
|
printf("too much args\r\n");
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
command_counter++;
|
||||||
|
while (command_counter < command_number) {
|
||||||
|
w_command[w_command_counter++] = argv[command_counter];
|
||||||
|
command_counter++;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}else{
|
||||||
|
if (strcmp(argv[1], "-h") != 0) {
|
||||||
|
printf("unknow command %s \r\n", argv[command_counter]);
|
||||||
|
}
|
||||||
|
helper();
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
command_counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
helper();
|
||||||
|
return ERR;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_set_options(int baudrate, int databits,
|
||||||
|
char parity, char stop, int softwareHandshake, int hardwareHandshake)
|
||||||
|
{
|
||||||
|
struct termios newtio;
|
||||||
|
if (tcgetattr(bt_dev_fd, &newtio)!=0)
|
||||||
|
{
|
||||||
|
printf("tcgetattr() 3 failed \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
speed_t _baud=0;
|
||||||
|
printf("set baudrate:%d\n", baudrate);
|
||||||
|
|
||||||
|
switch (baudrate)
|
||||||
|
{
|
||||||
|
#ifdef B0
|
||||||
|
case 0: _baud=B0; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B50
|
||||||
|
case 50: _baud=B50; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B75
|
||||||
|
case 75: _baud=B75; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B110
|
||||||
|
case 110: _baud=B110; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B134
|
||||||
|
case 134: _baud=B134; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B150
|
||||||
|
case 150: _baud=B150; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B200
|
||||||
|
case 200: _baud=B200; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B300
|
||||||
|
case 300: _baud=B300; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B600
|
||||||
|
case 600: _baud=B600; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B1200
|
||||||
|
case 1200: _baud=B1200; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B1800
|
||||||
|
case 1800: _baud=B1800; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B2400
|
||||||
|
case 2400: _baud=B2400; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B4800
|
||||||
|
case 4800: _baud=B4800; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B7200
|
||||||
|
case 7200: _baud=B7200; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B9600
|
||||||
|
case 9600: _baud=B9600; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B14400
|
||||||
|
case 14400: _baud=B14400; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B19200
|
||||||
|
case 19200: _baud=B19200; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B28800
|
||||||
|
case 28800: _baud=B28800; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B38400
|
||||||
|
case 38400: _baud=B38400; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B57600
|
||||||
|
case 57600: _baud=B57600; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B76800
|
||||||
|
case 76800: _baud=B76800; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B115200
|
||||||
|
case 115200: _baud=B115200; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B128000
|
||||||
|
case 128000: _baud=B128000; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B230400
|
||||||
|
case 230400: _baud=B230400; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B460800
|
||||||
|
case 460800: _baud=B460800; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B576000
|
||||||
|
case 576000: _baud=B576000; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B921600
|
||||||
|
case 921600: _baud=B921600; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B1500000
|
||||||
|
case 1500000: _baud=B1500000; break;
|
||||||
|
#endif
|
||||||
|
#ifdef B2000000
|
||||||
|
case 2000000: _baud=B2000000; break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cfsetospeed(&newtio, (speed_t)_baud);
|
||||||
|
cfsetispeed(&newtio, (speed_t)_baud);
|
||||||
|
|
||||||
|
/* We generate mark and space parity ourself. */
|
||||||
|
if (databits == 7 && (parity=='M' || parity == 'S'))
|
||||||
|
{
|
||||||
|
databits = 8;
|
||||||
|
}
|
||||||
|
switch (databits)
|
||||||
|
{
|
||||||
|
case 5:
|
||||||
|
newtio.c_cflag = (newtio.c_cflag & ~CSIZE) | CS5;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
newtio.c_cflag = (newtio.c_cflag & ~CSIZE) | CS6;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
newtio.c_cflag = (newtio.c_cflag & ~CSIZE) | CS7;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
default:
|
||||||
|
newtio.c_cflag = (newtio.c_cflag & ~CSIZE) | CS8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
newtio.c_cflag |= CLOCAL | CREAD;
|
||||||
|
|
||||||
|
//parity
|
||||||
|
newtio.c_cflag &= ~(PARENB | PARODD);
|
||||||
|
if (parity == 'E')
|
||||||
|
{
|
||||||
|
newtio.c_cflag |= PARENB;
|
||||||
|
}
|
||||||
|
else if (parity== 'O')
|
||||||
|
{
|
||||||
|
newtio.c_cflag |= (PARENB | PARODD);
|
||||||
|
}
|
||||||
|
|
||||||
|
//hardware handshake
|
||||||
|
newtio.c_cflag &= ~CRTSCTS;
|
||||||
|
|
||||||
|
//stopbits
|
||||||
|
if (stop=='2')
|
||||||
|
{
|
||||||
|
newtio.c_cflag |= CSTOPB;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newtio.c_cflag &= ~CSTOPB;
|
||||||
|
}
|
||||||
|
|
||||||
|
newtio.c_iflag=IGNBRK;
|
||||||
|
|
||||||
|
//software handshake
|
||||||
|
if (softwareHandshake)
|
||||||
|
{
|
||||||
|
newtio.c_iflag |= IXON | IXOFF;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newtio.c_iflag &= ~(IXON|IXOFF|IXANY);
|
||||||
|
}
|
||||||
|
|
||||||
|
newtio.c_lflag=0;
|
||||||
|
newtio.c_oflag=0;
|
||||||
|
|
||||||
|
// newtio.c_cc[VTIME]=1;
|
||||||
|
// newtio.c_cc[VMIN]=60;
|
||||||
|
|
||||||
|
if (tcsetattr(bt_dev_fd, TCSANOW, &newtio)!=0)
|
||||||
|
{
|
||||||
|
printf("tcsetattr() 1 failed \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tcgetattr(bt_dev_fd, &newtio)!=0)
|
||||||
|
{
|
||||||
|
printf("tcsetattr() 4 failed \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//hardware handshake
|
||||||
|
if (hardwareHandshake)
|
||||||
|
{
|
||||||
|
newtio.c_cflag |= CRTSCTS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newtio.c_cflag &= ~CRTSCTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tcsetattr(bt_dev_fd, TCSANOW, &newtio)!=0)
|
||||||
|
{
|
||||||
|
printf("tcsetattr() 2 failed \n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned char atoh(char* s_data){
|
||||||
|
unsigned char ret_value;
|
||||||
|
char temp_value = 0;
|
||||||
|
|
||||||
|
//h
|
||||||
|
if(s_data[0] >= 48 && s_data[0] <= 57){
|
||||||
|
temp_value = s_data[0] - 48;
|
||||||
|
}else if(s_data[0] >= 65 && s_data[0] <= 70){
|
||||||
|
temp_value = (s_data[0] - 65) + 10;
|
||||||
|
}else if(s_data[0] >= 97 && s_data[0] <= 102){
|
||||||
|
temp_value = (s_data[0] - 97) + 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret_value = temp_value;
|
||||||
|
ret_value = ret_value << 4;
|
||||||
|
//printf("atoh1: ret_value:%x\r\n", ret_value);
|
||||||
|
//l
|
||||||
|
if(s_data[1] >= 48 && s_data[1] <= 57){
|
||||||
|
temp_value = s_data[1] - 48;
|
||||||
|
}else if(s_data[1] >= 65 && s_data[1] <= 70){
|
||||||
|
temp_value = (s_data[1] - 65) + 10;
|
||||||
|
}else if(s_data[1] >= 97 && s_data[1] <= 102){
|
||||||
|
temp_value = (s_data[1] - 97) + 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret_value |= temp_value;
|
||||||
|
//printf("atoh2: ret_value:%x\r\n", ret_value);
|
||||||
|
|
||||||
|
return ret_value;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int send_to_server(unsigned char* buffer, int len){
|
||||||
|
int client_socket;
|
||||||
|
struct sockaddr_in serverAddr;
|
||||||
|
//unsigned long long package_totel_counter = 0;
|
||||||
|
|
||||||
|
if((client_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0){
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
serverAddr.sin_family = AF_INET;
|
||||||
|
serverAddr.sin_port = htons(BT_HCI_TOOL_PORT);
|
||||||
|
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||||
|
|
||||||
|
if(connect(client_socket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0){
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
send(client_socket, buffer, len, 0);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_hci_command(){
|
||||||
|
int i = 0;
|
||||||
|
int command_len = 0;
|
||||||
|
unsigned char buffer[SOCKER_BUFFER_SIZE];
|
||||||
|
|
||||||
|
// printf("send hci command: \r\n");
|
||||||
|
|
||||||
|
for(i = 0;i < 256; i++){
|
||||||
|
if(s_hci_command[i] == NULL){
|
||||||
|
command_len = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[i] = atoh(s_hci_command[i]);
|
||||||
|
// printf("%02X ", buffer[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
send_to_server(buffer, i);
|
||||||
|
|
||||||
|
// printf("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_wlan_command(void)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
int command_len = 0;
|
||||||
|
unsigned char buffer[SOCKER_BUFFER_SIZE] = {0,};
|
||||||
|
while ((w_command[i] != NULL) && (i < WLAN_CMD_MAX_CNT)) {
|
||||||
|
strcat((char*)&buffer[0], w_command[i]);
|
||||||
|
strcat((char*)&buffer[0], " ");
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
command_len = strlen((char*)&buffer[0]);
|
||||||
|
printf("command_len:%d \r\n", command_len);
|
||||||
|
if (command_len > 1) {
|
||||||
|
//command_len--; // rm last space
|
||||||
|
//buffer[command_len] = '\0';
|
||||||
|
send_to_server(buffer, command_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int hci_send(char* data, int len){
|
||||||
|
int i = 0;
|
||||||
|
unsigned char tmp_data[len];
|
||||||
|
|
||||||
|
printf("COMMAND(%d): \r\n", len);
|
||||||
|
for(i = 0; i < len; i++){
|
||||||
|
tmp_data[i] = (unsigned char)data[i];
|
||||||
|
printf("%02X ", tmp_data[i]);
|
||||||
|
}
|
||||||
|
printf("\r\n");
|
||||||
|
|
||||||
|
len = write(bt_dev_fd, tmp_data, len);
|
||||||
|
if (len < 0) {
|
||||||
|
printf("write data error \n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int hci_recv(char* data, int len){
|
||||||
|
int i = 0;
|
||||||
|
unsigned char tmp_byte[64];// = 0x00;
|
||||||
|
|
||||||
|
memset(data, 0, len);
|
||||||
|
|
||||||
|
len = read(bt_dev_fd, data, len);
|
||||||
|
if (len < 0) {
|
||||||
|
printf("read error \n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
printf("EVENT(%d): \r\n", len);
|
||||||
|
for(i = 0; i < len; i++){
|
||||||
|
tmp_byte[i] = (unsigned char)data[i];
|
||||||
|
printf("%02X ", tmp_byte[i]);
|
||||||
|
}
|
||||||
|
printf("\r\n");
|
||||||
|
|
||||||
|
if(tmp_byte[1] == 0x0D) {
|
||||||
|
uint32_t rx_pkt_len = tmp_byte[4] | (tmp_byte[5] << 8) | (tmp_byte[6] << 16) | (tmp_byte[7] << 24);
|
||||||
|
uint32_t total_rx_pkts = tmp_byte[8] | (tmp_byte[9] << 8) | (tmp_byte[10] << 16) | (tmp_byte[11] << 24);
|
||||||
|
uint32_t rx_ok_pkts = tmp_byte[12] | (tmp_byte[13] << 8) | (tmp_byte[14] << 16) | (tmp_byte[15] << 24);
|
||||||
|
uint32_t rx_err_pkts = tmp_byte[16] | (tmp_byte[17] << 8) | (tmp_byte[18] << 16) | (tmp_byte[19] << 24);
|
||||||
|
uint32_t rx_err_bits = tmp_byte[20] | (tmp_byte[21] << 8) | (tmp_byte[22] << 16) | (tmp_byte[23] << 24);
|
||||||
|
float per = (float) 100 * rx_err_pkts / total_rx_pkts;
|
||||||
|
float ber = (float) 10000 * rx_err_bits / (total_rx_pkts * rx_pkt_len * 8) ;
|
||||||
|
printf("rx result: pkt_len=%d, total=%d, ok=%d, err=%d, err_bits=%d, per=%.2f%%, ber=%.4f%%%%%%\n",
|
||||||
|
rx_pkt_len, total_rx_pkts, rx_ok_pkts, rx_err_pkts, rx_err_bits, per, ber);
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wlan_send(char *data, int len)
|
||||||
|
{
|
||||||
|
int sock;
|
||||||
|
struct ifreq ifr;
|
||||||
|
int ret = 0;
|
||||||
|
int i = 0;
|
||||||
|
char wl_cmd[64];
|
||||||
|
struct android_wifi_priv_cmd priv_cmd;
|
||||||
|
char is_param_err = 0;
|
||||||
|
int buf_len = 0;
|
||||||
|
int argC = 0;
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (sock < 0) {
|
||||||
|
printf("bad sock!\n");
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
|
strcpy(ifr.ifr_name, w_ifname);
|
||||||
|
|
||||||
|
if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
|
||||||
|
printf("%s Could not read interface %s flags: %s",__func__, w_ifname, strerror(errno));
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(ifr.ifr_flags & IFF_UP)) {
|
||||||
|
printf("%s is not up!\n",w_ifname);
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("ifr.ifr_name = %s\n", ifr.ifr_name);
|
||||||
|
memset(&priv_cmd, 0, sizeof(priv_cmd));
|
||||||
|
memset(wl_cmd, 0, sizeof(wl_cmd));
|
||||||
|
// extract wlan command & argC
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (data[i] != ' ') {
|
||||||
|
if (argC == 0) {
|
||||||
|
wl_cmd[i] = data[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
argC++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("wl_cmd=%s, argC=%d\r\n", wl_cmd, argC);
|
||||||
|
|
||||||
|
priv_cmd.buf = data;
|
||||||
|
priv_cmd.used_len = len;
|
||||||
|
priv_cmd.total_len = SOCKER_BUFFER_SIZE;
|
||||||
|
ifr.ifr_data = (void*)&priv_cmd;
|
||||||
|
|
||||||
|
if ((strcasecmp(wl_cmd, "BT_RESET") == 0)) {
|
||||||
|
char bt_reset_hci_cmd[32] = "01 03 0c 00";
|
||||||
|
if (argC == 1) {
|
||||||
|
buf_len = priv_cmd.used_len;
|
||||||
|
memcpy(&priv_cmd.buf[buf_len], &bt_reset_hci_cmd[0], strlen(bt_reset_hci_cmd));
|
||||||
|
buf_len += strlen(bt_reset_hci_cmd);
|
||||||
|
priv_cmd.used_len = buf_len;
|
||||||
|
} else {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(wl_cmd, "BT_TXDH") == 0)) {
|
||||||
|
char bt_txdh_hci_cmd[255] = "01 06 18 0e ";
|
||||||
|
if (argC == 15) {
|
||||||
|
buf_len = priv_cmd.used_len;
|
||||||
|
int arg_len = strlen("BT_TXDH");
|
||||||
|
int txdh_cmd_len = strlen(bt_txdh_hci_cmd);
|
||||||
|
memcpy(&bt_txdh_hci_cmd[txdh_cmd_len], &priv_cmd.buf[arg_len+1], buf_len - arg_len - 1);
|
||||||
|
memcpy(&priv_cmd.buf[arg_len+1], &bt_txdh_hci_cmd[0], strlen(bt_txdh_hci_cmd));
|
||||||
|
buf_len += strlen(bt_txdh_hci_cmd);
|
||||||
|
priv_cmd.used_len = buf_len;
|
||||||
|
} else {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(wl_cmd, "BT_RXDH") == 0)) {
|
||||||
|
if (argC == 14) {
|
||||||
|
char bt_rxdh_hci_cmd[255] = "01 0b 18 0d ";
|
||||||
|
buf_len = priv_cmd.used_len;
|
||||||
|
int arg_len = strlen("BT_RXDH");
|
||||||
|
int rxdh_cmd_len = strlen(bt_rxdh_hci_cmd);
|
||||||
|
memcpy(&bt_rxdh_hci_cmd[rxdh_cmd_len], &priv_cmd.buf[arg_len+1], buf_len - arg_len - 1);
|
||||||
|
memcpy(&priv_cmd.buf[arg_len+1], &bt_rxdh_hci_cmd[0], strlen(bt_rxdh_hci_cmd));
|
||||||
|
buf_len += strlen(bt_rxdh_hci_cmd);
|
||||||
|
priv_cmd.used_len = buf_len;
|
||||||
|
} else {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(wl_cmd, "BT_STOP") == 0)) {
|
||||||
|
char bt_stop_hci_cmd[255] = "01 0C 18 01 ";
|
||||||
|
if (argC == 2) {
|
||||||
|
buf_len = priv_cmd.used_len;
|
||||||
|
int arg_len = strlen("BT_STOP");
|
||||||
|
int stop_cmd_len = strlen(bt_stop_hci_cmd);
|
||||||
|
memcpy(&bt_stop_hci_cmd[stop_cmd_len], &priv_cmd.buf[arg_len+1], buf_len - arg_len - 1);
|
||||||
|
memcpy(&priv_cmd.buf[arg_len+1], &bt_stop_hci_cmd[0], strlen(bt_stop_hci_cmd));
|
||||||
|
buf_len += strlen(bt_stop_hci_cmd);
|
||||||
|
priv_cmd.used_len = buf_len;
|
||||||
|
} else if ((strcasecmp(wl_cmd, "BT_DATA") == 0)) {
|
||||||
|
//char bt_raw_data_cmd[255];
|
||||||
|
int arg_len = strlen(wl_cmd);
|
||||||
|
buf_len = priv_cmd.used_len;
|
||||||
|
memcpy(&priv_cmd.buf[arg_len+1], &priv_cmd.buf[arg_len+1], buf_len - arg_len - 1);
|
||||||
|
priv_cmd.used_len = buf_len - arg_len - 1;
|
||||||
|
} else {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
is_param_err = 0;
|
||||||
|
}
|
||||||
|
if (is_param_err) {
|
||||||
|
printf("param error!!!\n");
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
if ((ret = ioctl(sock, TXRX_PARA, &ifr)) < 0) {
|
||||||
|
printf("%s: error ioctl[TX_PARA] ret= %d\n", __func__, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
memcpy(&priv_cmd, ifr.ifr_data, sizeof(struct android_wifi_priv_cmd));
|
||||||
|
if (strcasecmp(wl_cmd, "GET_BT_RX_RESULT") == 0) {
|
||||||
|
printf("done: get bt rx total=%d, ok=%d, err=%d\n", *(unsigned int *)priv_cmd.buf,
|
||||||
|
*(unsigned int *)&priv_cmd.buf[4],
|
||||||
|
*(unsigned int *)&priv_cmd.buf[8]);
|
||||||
|
} else if (strcasecmp(wl_cmd, "BT_DATA") == 0) {
|
||||||
|
unsigned char *buff = (unsigned char *)&priv_cmd.buf[1];
|
||||||
|
int len = priv_cmd.buf[0];
|
||||||
|
printf("done: %d\n", len);
|
||||||
|
for (idx = 0; idx < len; idx++) {
|
||||||
|
printf("%02x ", buff[idx]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
} else {
|
||||||
|
printf("done\n");
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dev_open(){
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
bt_dev_fd = open(dev_path, O_RDWR | O_NDELAY);
|
||||||
|
if(bt_dev_fd < 0) {
|
||||||
|
printf("dev_path %s fail to open \r\n", dev_path);
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
if(interface == UART){
|
||||||
|
tcflush(bt_dev_fd, TCIOFLUSH);
|
||||||
|
n = fcntl(bt_dev_fd, F_GETFL, 0);
|
||||||
|
fcntl(bt_dev_fd, F_SETFL, n & ~O_NDELAY);
|
||||||
|
uart_set_options(/*BAUDRATE*/atoi(s_baudrate), DATABITS, PARTY, STOP, SOFTWARE_HANDSHAKE, HARDWARE_HANDSHAKE);
|
||||||
|
}else{
|
||||||
|
ioctl(bt_dev_fd, DOWN_FW_CFG);
|
||||||
|
ioctl(bt_dev_fd, GET_USB_INFO);
|
||||||
|
}
|
||||||
|
printf("bt dev open successful\r\n");
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dev_close(){
|
||||||
|
close(bt_dev_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int socket_init(){
|
||||||
|
int client;
|
||||||
|
int server_socket;
|
||||||
|
struct sockaddr_in server_addr;
|
||||||
|
struct sockaddr_in clientAddr;
|
||||||
|
int addr_len = sizeof(clientAddr);
|
||||||
|
char buffer[SOCKER_BUFFER_SIZE];
|
||||||
|
int recv_len = 0;
|
||||||
|
|
||||||
|
if((server_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0){
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
//bzero(&server_addr, sizeof(server_addr));
|
||||||
|
memset(&server_addr, 0, sizeof(server_addr));
|
||||||
|
server_addr.sin_family = AF_INET;
|
||||||
|
server_addr.sin_port = htons(BT_HCI_TOOL_PORT);
|
||||||
|
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
//setsockopt(server_socket ,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(BOOL));
|
||||||
|
|
||||||
|
if(bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0){
|
||||||
|
printf("binding error\r\n");
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(listen(server_socket, 5) < 0){
|
||||||
|
printf("listen error");
|
||||||
|
return ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(1){
|
||||||
|
client = accept(server_socket, (struct sockaddr*)&clientAddr, (socklen_t*)&addr_len);
|
||||||
|
if(client == ERR){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
recv_len = recv(client, buffer, SOCKER_BUFFER_SIZE, 0);
|
||||||
|
if ((interface == USB) || (interface == UART)) {
|
||||||
|
hci_send(buffer, recv_len);
|
||||||
|
} else {
|
||||||
|
wlan_send(buffer, recv_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void* hci_recv_thread( void *arg ){
|
||||||
|
printf("hci recv thread ready %p\r\n", arg);
|
||||||
|
while(1){
|
||||||
|
hci_recv(hci_event, sizeof(hci_event));
|
||||||
|
// exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_server(){
|
||||||
|
int ret = ERR;
|
||||||
|
if ((interface == USB) || (interface == UART)) {
|
||||||
|
pthread_t hci_recv_th;
|
||||||
|
//init bt communication
|
||||||
|
ret = dev_open();
|
||||||
|
if(ret == ERR){
|
||||||
|
printf("dev_open fail \r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//test to send reset
|
||||||
|
printf("to test hci reset for bt device\r\n");
|
||||||
|
hci_send(hci_reset, sizeof(hci_reset));
|
||||||
|
hci_recv(hci_event, sizeof(hci_event));
|
||||||
|
ret = pthread_create( &hci_recv_th, NULL, hci_recv_thread, NULL);
|
||||||
|
printf("bt device test ok \r\n");
|
||||||
|
} else if (interface == WLAN) {
|
||||||
|
char buf[SOCKER_BUFFER_SIZE] = {"BT_RESET "};
|
||||||
|
wlan_send(buf, strlen(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
//init localhost socket
|
||||||
|
ret = socket_init();
|
||||||
|
if (!ret) {
|
||||||
|
printf("socket init done\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]){
|
||||||
|
int ret = parse_cmd_line(argc, argv);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if(server_or_client == SERVER){
|
||||||
|
start_server();
|
||||||
|
} else if (server_or_client == CLIENT) {
|
||||||
|
send_hci_command();
|
||||||
|
} else {
|
||||||
|
send_wlan_command();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,426 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include<stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#define WIFI_DRIVER_FW_PATH "sta"
|
||||||
|
#define WIFI_DRIVER_MODULE_NAME "rwnx_fdrv"
|
||||||
|
#define WIFI_DRIVER_MODULE_PATH "/vendor/modules/rwnx_fdrv.ko"
|
||||||
|
#define MAX_DRV_CMD_SIZE 1536
|
||||||
|
#define TXRX_PARA SIOCDEVPRIVATE+1
|
||||||
|
|
||||||
|
#define EFUSE_CMD_OLD_FORMAT_EN 0
|
||||||
|
|
||||||
|
//static const char IFACE_DIR[] = "";
|
||||||
|
//static const char DRIVER_MODULE_NAME[] = "rwnx_fdrv";
|
||||||
|
//static const char DRIVER_MODULE_TAG[] = WIFI_DRIVER_MODULE_NAME " ";
|
||||||
|
//static const char DRIVER_MODULE_PATH[] = WIFI_DRIVER_MODULE_PATH;
|
||||||
|
//static const char DRIVER_MODULE_ARG[] = "";
|
||||||
|
//static const char FIRMWARE_LOADER[] = "";
|
||||||
|
//static const char DRIVER_PROP_NAME[] = "wlan.driver.status";
|
||||||
|
|
||||||
|
#ifndef TEMP_FAILURE_RETRY
|
||||||
|
#define TEMP_FAILURE_RETRY(expression) \
|
||||||
|
(__extension__ \
|
||||||
|
({ long int __result; \
|
||||||
|
do __result = (long int) (expression); \
|
||||||
|
while (__result == -1L && errno == EINTR); \
|
||||||
|
__result; }))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct android_wifi_priv_cmd {
|
||||||
|
char *buf;
|
||||||
|
int used_len;
|
||||||
|
int total_len;
|
||||||
|
} android_wifi_priv_cmd;
|
||||||
|
typedef struct cob_result_ptr_t {
|
||||||
|
u_int16_t dut_rcv_golden_num;
|
||||||
|
u_int8_t golden_rcv_dut_num;
|
||||||
|
int8_t rssi_static;
|
||||||
|
int8_t snr_static;
|
||||||
|
int8_t dut_rssi_static;
|
||||||
|
u_int16_t reserved;
|
||||||
|
}cob_result_ptr_t;
|
||||||
|
int wifi_send_cmd_to_net_interface(const char* if_name, int argC, char *argV[])
|
||||||
|
{
|
||||||
|
int sock;
|
||||||
|
struct ifreq ifr;
|
||||||
|
int ret = 0;
|
||||||
|
int i = 0;
|
||||||
|
char buf[MAX_DRV_CMD_SIZE];
|
||||||
|
struct android_wifi_priv_cmd priv_cmd;
|
||||||
|
struct cob_result_ptr_t *cob_result_ptr;
|
||||||
|
char is_param_err = 0;
|
||||||
|
int buf_len = 0;
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (sock < 0) {
|
||||||
|
printf("bad sock!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
|
strcpy(ifr.ifr_name, if_name);
|
||||||
|
|
||||||
|
if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
|
||||||
|
printf("%s Could not read interface %s flags: %s",__func__, if_name, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(ifr.ifr_flags & IFF_UP)) {
|
||||||
|
printf("%s is not up!\n",if_name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("ifr.ifr_name = %s\n", ifr.ifr_name);
|
||||||
|
memset(&priv_cmd, 0, sizeof(priv_cmd));
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
|
||||||
|
for(i=2; i<argC; i++){
|
||||||
|
strcat(buf, argV[i]);
|
||||||
|
strcat(buf, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
priv_cmd.buf = buf;
|
||||||
|
priv_cmd.used_len = strlen(buf);
|
||||||
|
priv_cmd.total_len = sizeof(buf);
|
||||||
|
ifr.ifr_data = (void*)&priv_cmd;
|
||||||
|
|
||||||
|
printf("%s:\n", argV[2]);
|
||||||
|
if (strcasecmp(argV[2], "SET_TX") == 0) {
|
||||||
|
if (argC < 8) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if (strcasecmp(argV[2], "SET_TXTONE") == 0) {
|
||||||
|
if (((argC == 4) && (argV[3][0] != '0'))
|
||||||
|
|| ((argC == 5) && (argV[3][0] == '0'))) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "SET_RX") == 0)
|
||||||
|
|| (strcasecmp(argV[2], "SET_POWER") == 0)
|
||||||
|
|| (strcasecmp(argV[2], "SET_COB_CAL") == 0)) {
|
||||||
|
if (argC < 5) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "SET_XTAL_CAP") == 0)
|
||||||
|
|| (strcasecmp(argV[2], "SET_XTAL_CAP_FINE") == 0)) {
|
||||||
|
if (argC < 4) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "GET_EFUSE_BLOCK") == 0)
|
||||||
|
|| (strcasecmp(argV[2], "SET_FREQ_CAL") == 0)
|
||||||
|
|| (strcasecmp(argV[2], "SET_FREQ_CAL_FINE") == 0)) {
|
||||||
|
if (argC < 4) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "SET_MAC_ADDR") == 0)
|
||||||
|
|| (strcasecmp(argV[2], "SET_BT_MAC_ADDR") == 0)) {
|
||||||
|
if (argC < 8) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if (strcasecmp(argV[2], "SET_VENDOR_INFO") == 0) {
|
||||||
|
if (argC < 4) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if (strcasecmp(argV[2], "GET_VENDOR_INFO") == 0) {
|
||||||
|
if (argC < 3) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "RDWR_PWRIDX") == 0)
|
||||||
|
|| (strcasecmp(argV[2], "RDWR_PWRLVL") == 0)
|
||||||
|
|| (strcasecmp(argV[2], "RDWR_PWROFST") == 0)
|
||||||
|
|| (strcasecmp(argV[2], "RDWR_EFUSE_PWROFST") == 0)) {
|
||||||
|
if (((argC == 4) && (argV[3][0] != '0'))
|
||||||
|
|| (argC == 5)
|
||||||
|
|| ((argC == 6) && (argV[3][0] == '0'))) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "RDWR_DRVIBIT") == 0)
|
||||||
|
|| (strcasecmp(argV[2], "RDWR_EFUSE_DRVIBIT") == 0)) {
|
||||||
|
if (((argC == 4) && (argV[3][0] != '0'))
|
||||||
|
|| ((argC == 5) && (argV[3][0] == '0'))) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "SET_PAPR") == 0)) {
|
||||||
|
if (argC < 4) {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "BT_RESET") == 0)) {
|
||||||
|
char bt_reset_hci_cmd[32] = "01 03 0c 00";
|
||||||
|
if (argC == 3) {
|
||||||
|
buf_len = priv_cmd.used_len;
|
||||||
|
memcpy(&priv_cmd.buf[buf_len], &bt_reset_hci_cmd[0], strlen(bt_reset_hci_cmd));
|
||||||
|
buf_len += strlen(bt_reset_hci_cmd);
|
||||||
|
priv_cmd.used_len = buf_len;
|
||||||
|
} else {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "BT_TXDH") == 0)) {
|
||||||
|
char bt_txdh_hci_cmd[255] = "01 06 18 0e ";
|
||||||
|
if (argC == 17) {
|
||||||
|
buf_len = priv_cmd.used_len;
|
||||||
|
int arg_len = strlen(argV[2]);
|
||||||
|
int txdh_cmd_len = strlen(bt_txdh_hci_cmd);
|
||||||
|
memcpy(&bt_txdh_hci_cmd[txdh_cmd_len], &priv_cmd.buf[arg_len+1], buf_len - arg_len - 1);
|
||||||
|
memcpy(&priv_cmd.buf[arg_len+1], &bt_txdh_hci_cmd[0], strlen(bt_txdh_hci_cmd));
|
||||||
|
buf_len += strlen(bt_txdh_hci_cmd);
|
||||||
|
priv_cmd.used_len = buf_len;
|
||||||
|
} else {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "BT_RXDH") == 0)) {
|
||||||
|
if (argC == 16) {
|
||||||
|
char bt_rxdh_hci_cmd[255] = "01 0b 18 0d ";
|
||||||
|
buf_len = priv_cmd.used_len;
|
||||||
|
int arg_len = strlen(argV[2]);
|
||||||
|
int rxdh_cmd_len = strlen(bt_rxdh_hci_cmd);
|
||||||
|
memcpy(&bt_rxdh_hci_cmd[rxdh_cmd_len], &priv_cmd.buf[arg_len+1], buf_len - arg_len - 1);
|
||||||
|
memcpy(&priv_cmd.buf[arg_len+1], &bt_rxdh_hci_cmd[0], strlen(bt_rxdh_hci_cmd));
|
||||||
|
buf_len += strlen(bt_rxdh_hci_cmd);
|
||||||
|
priv_cmd.used_len = buf_len;
|
||||||
|
} else {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "BT_STOP") == 0)) {
|
||||||
|
char bt_stop_hci_cmd[255] = "01 0C 18 01 ";
|
||||||
|
if (argC == 4) {
|
||||||
|
buf_len = priv_cmd.used_len;
|
||||||
|
int arg_len = strlen(argV[2]);
|
||||||
|
int stop_cmd_len = strlen(bt_stop_hci_cmd);
|
||||||
|
memcpy(&bt_stop_hci_cmd[stop_cmd_len], &priv_cmd.buf[arg_len+1], buf_len - arg_len - 1);
|
||||||
|
memcpy(&priv_cmd.buf[arg_len+1], &bt_stop_hci_cmd[0], strlen(bt_stop_hci_cmd));
|
||||||
|
buf_len += strlen(bt_stop_hci_cmd);
|
||||||
|
priv_cmd.used_len = buf_len;
|
||||||
|
} else {
|
||||||
|
is_param_err = 1;
|
||||||
|
}
|
||||||
|
} else if ((strcasecmp(argV[2], "BT_DATA") == 0)) {
|
||||||
|
//char bt_raw_data_cmd[255];
|
||||||
|
int arg_len = strlen(argV[2]);
|
||||||
|
buf_len = priv_cmd.used_len;
|
||||||
|
memcpy(&priv_cmd.buf[arg_len+1], &priv_cmd.buf[arg_len+1], buf_len - arg_len - 1);
|
||||||
|
priv_cmd.used_len = buf_len - arg_len - 1;
|
||||||
|
} else {
|
||||||
|
is_param_err = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_param_err) {
|
||||||
|
printf("param error!!!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = ioctl(sock, TXRX_PARA, &ifr)) < 0) {
|
||||||
|
printf("cmd or param error\n");
|
||||||
|
printf("%s: error ioctl[TX_PARA] ret= %d\n", __func__, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&priv_cmd, ifr.ifr_data, sizeof(struct android_wifi_priv_cmd));
|
||||||
|
if (strcasecmp(argV[2], "SET_FREQ_CAL") == 0) {
|
||||||
|
#if (EFUSE_CMD_OLD_FORMAT_EN)
|
||||||
|
printf("done: freq_cal: 0x%8x\n", *(unsigned int *)priv_cmd.buf);
|
||||||
|
#else
|
||||||
|
signed char rem_cnt = (signed char)priv_cmd.buf[1];
|
||||||
|
if (rem_cnt < 0) {
|
||||||
|
printf("failed to set freq_cal, no room!\n");
|
||||||
|
} else {
|
||||||
|
printf("done: freq_cal: 0x%2x (remain:%x)\n", (unsigned char)priv_cmd.buf[0], rem_cnt);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else if (strcasecmp(argV[2], "SET_FREQ_CAL_FINE") == 0) {
|
||||||
|
#if (EFUSE_CMD_OLD_FORMAT_EN)
|
||||||
|
printf("done: freq_cal_fine: 0x%8x\n", *(unsigned int *)priv_cmd.buf);
|
||||||
|
#else
|
||||||
|
signed char rem_cnt = (signed char)priv_cmd.buf[1];
|
||||||
|
if (rem_cnt < 0) {
|
||||||
|
printf("failed to set freq_cal_fine, no room!\n");
|
||||||
|
} else {
|
||||||
|
printf("done: freq_cal_fine: 0x%2x (remain:%x)\n", (unsigned char)priv_cmd.buf[0], rem_cnt);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else if (strcasecmp(argV[2], "GET_EFUSE_BLOCK") == 0)
|
||||||
|
printf("done:efuse: 0x%8x\n", *(unsigned int *)priv_cmd.buf);
|
||||||
|
else if (strcasecmp(argV[2], "SET_XTAL_CAP") == 0)
|
||||||
|
printf("done:xtal cap: 0x%x\n", *(unsigned int *)priv_cmd.buf);
|
||||||
|
else if (strcasecmp(argV[2], "SET_XTAL_CAP_FINE") == 0)
|
||||||
|
printf("done:xtal cap fine: 0x%x\n", *(unsigned int *)priv_cmd.buf);
|
||||||
|
else if (strcasecmp(argV[2], "GET_RX_RESULT") == 0)
|
||||||
|
printf("done: getrx fcsok=%d, total=%d\n", *(unsigned int *)priv_cmd.buf, *(unsigned int *)&priv_cmd.buf[4]);
|
||||||
|
else if (strcasecmp(argV[2], "GET_MAC_ADDR") == 0) {
|
||||||
|
printf("done: get macaddr = %02x : %02x : %02x : %02x : %02x : %02x\n",
|
||||||
|
*(unsigned char *)&priv_cmd.buf[5], *(unsigned char *)&priv_cmd.buf[4], *(unsigned char *)&priv_cmd.buf[3],
|
||||||
|
*(unsigned char *)&priv_cmd.buf[2], *(unsigned char *)&priv_cmd.buf[1], *(unsigned char *)&priv_cmd.buf[0]);
|
||||||
|
#if (!EFUSE_CMD_OLD_FORMAT_EN)
|
||||||
|
printf(" (remain:%x)\n", priv_cmd.buf[6]);
|
||||||
|
#endif
|
||||||
|
} else if (strcasecmp(argV[2], "GET_BT_MAC_ADDR") == 0) {
|
||||||
|
printf("done: get bt macaddr = %02x : %02x : %02x : %02x : %02x : %02x\n",
|
||||||
|
*(unsigned char *)&priv_cmd.buf[5], *(unsigned char *)&priv_cmd.buf[4], *(unsigned char *)&priv_cmd.buf[3],
|
||||||
|
*(unsigned char *)&priv_cmd.buf[2], *(unsigned char *)&priv_cmd.buf[1], *(unsigned char *)&priv_cmd.buf[0]);
|
||||||
|
#if (!EFUSE_CMD_OLD_FORMAT_EN)
|
||||||
|
printf(" (remain:%x)\n", priv_cmd.buf[6]);
|
||||||
|
#endif
|
||||||
|
} else if (strcasecmp(argV[2], "GET_FREQ_CAL") == 0) {
|
||||||
|
#if (EFUSE_CMD_OLD_FORMAT_EN)
|
||||||
|
printf("done: get_freq_cal: xtal_cap=0x%x, xtal_cap_fine=0x%x\n", val & 0x000000ff, (val >> 8) & 0x000000ff);
|
||||||
|
#else
|
||||||
|
unsigned int val = *(unsigned int *)&priv_cmd.buf[0];
|
||||||
|
printf("done: get_freq_cal: xtal_cap=0x%x (remain:%x), xtal_cap_fine=0x%x (remain:%x)\n",
|
||||||
|
val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, (val >> 24) & 0xff);
|
||||||
|
#endif
|
||||||
|
} else if (strcasecmp(argV[2], "GET_VENDOR_INFO") == 0) {
|
||||||
|
#if (EFUSE_CMD_OLD_FORMAT_EN)
|
||||||
|
printf("done: get_vendor_info = 0x%x\n", *(unsigned char *)&priv_cmd.buf[0]);
|
||||||
|
#else
|
||||||
|
printf("done: get_vendor_info = 0x%x (remain:%x)\n", *(unsigned char *)&priv_cmd.buf[0], priv_cmd.buf[1]);
|
||||||
|
#endif
|
||||||
|
} else if (strcasecmp(argV[2], "RDWR_PWRMM") == 0) {
|
||||||
|
printf("done: txpwr manual mode = %x\n", *(unsigned int *)&priv_cmd.buf[0]);
|
||||||
|
} else if (strcasecmp(argV[2], "RDWR_PWRIDX") == 0) {
|
||||||
|
char *buff = &priv_cmd.buf[0];
|
||||||
|
printf("done:\n"
|
||||||
|
"txpwr index 2.4g:\n"
|
||||||
|
" [0]=%d(ofdmlowrate)\n"
|
||||||
|
" [1]=%d(ofdm64qam)\n"
|
||||||
|
" [2]=%d(ofdm256qam)\n"
|
||||||
|
" [3]=%d(ofdm1024qam)\n"
|
||||||
|
" [4]=%d(dsss)\n", buff[0], buff[1], buff[2], buff[3], buff[4]);
|
||||||
|
printf("txpwr index 5g:\n"
|
||||||
|
" [0]=%d(ofdmlowrate)\n"
|
||||||
|
" [1]=%d(ofdm64qam)\n"
|
||||||
|
" [2]=%d(ofdm256qam)\n"
|
||||||
|
" [3]=%d(ofdm1024qam)\n", buff[5], buff[6], buff[7], buff[8]);
|
||||||
|
} else if (strcasecmp(argV[2], "RDWR_PWRLVL") == 0) {
|
||||||
|
char *buff = &priv_cmd.buf[0];
|
||||||
|
int grp, idx;
|
||||||
|
printf("done:\n"
|
||||||
|
"txpwr index 2.4g: [0]:11b+11a/g, [1]:11n/11ac, [2]:11ax\n");
|
||||||
|
for (grp = 0; grp < 3; grp++) {
|
||||||
|
int cnt = 12;
|
||||||
|
if (grp == 1) {
|
||||||
|
cnt = 10;
|
||||||
|
}
|
||||||
|
printf(" [%x] =", grp);
|
||||||
|
for (idx = 0; idx < cnt; idx++) {
|
||||||
|
if (idx && !(idx & 0x3)) {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
printf(" %2d", buff[12 * grp + idx]);
|
||||||
|
}
|
||||||
|
printf("\r\n");
|
||||||
|
}
|
||||||
|
} else if (strcasecmp(argV[2], "RDWR_PWROFST") == 0) {
|
||||||
|
char *buff = &priv_cmd.buf[0];
|
||||||
|
|
||||||
|
printf("done:\n"
|
||||||
|
"txpwr offset 2.4g: \n"
|
||||||
|
" [0]=%d(ch1~4)\n"
|
||||||
|
" [1]=%d(ch5~9)\n"
|
||||||
|
" [2]=%d(ch10~13)\n", (int8_t)buff[0], (int8_t)buff[1], (int8_t)buff[2]);
|
||||||
|
printf("txpwr offset 5g:\n"
|
||||||
|
" [0]=%d(ch36~64)\n"
|
||||||
|
" [1]=%d(ch100~120)\n"
|
||||||
|
" [2]=%d(ch122~140)\n"
|
||||||
|
" [3]=%d(ch142~165)\n", (int8_t)buff[3], (int8_t)buff[4], (int8_t)buff[5], (int8_t)buff[6]);
|
||||||
|
} else if (strcasecmp(argV[2], "RDWR_DRVIBIT") == 0) {
|
||||||
|
char *buff = &priv_cmd.buf[0];
|
||||||
|
printf("done: 2.4g txgain tbl pa drv_ibit:\n");
|
||||||
|
for (idx = 0; idx < 16; idx++) {
|
||||||
|
printf(" %x", buff[idx]);
|
||||||
|
if (!((idx + 1) & 0x03)) {
|
||||||
|
printf(" [%x~%x]\n", idx - 3, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (strcasecmp(argV[2], "RDWR_EFUSE_PWROFST") == 0) {
|
||||||
|
char *buff = &priv_cmd.buf[0];
|
||||||
|
#if (EFUSE_CMD_OLD_FORMAT_EN)
|
||||||
|
printf("done:\n"
|
||||||
|
"efuse txpwr offset 2.4g:\n"
|
||||||
|
" [0]=%d(ch1~4)\n"
|
||||||
|
" [1]=%d(ch5~9)\n"
|
||||||
|
" [2]=%d(ch10~13)\n", (int8_t)buff[0], (int8_t)buff[1], (int8_t)buff[2]);
|
||||||
|
printf("efuse txpwr offset 5g:\n"
|
||||||
|
" [0]=%d(ch36~64)\n"
|
||||||
|
" [1]=%d(ch100~120)\n"
|
||||||
|
" [2]=%d(ch122~140)\n"
|
||||||
|
" [3]=%d(ch142~165)\n", (int8_t)buff[3], (int8_t)buff[4], (int8_t)buff[5], (int8_t)buff[6]);
|
||||||
|
#else
|
||||||
|
printf("done:\n"
|
||||||
|
"efuse txpwr offset 2.4g:\n"
|
||||||
|
" [0]=%d(remain:%x, ch1~4)\n"
|
||||||
|
" [1]=%d(remain:%x, ch5~9)\n"
|
||||||
|
" [2]=%d(remain:%x, ch10~13)\n",
|
||||||
|
(int8_t)buff[0], (int8_t)buff[3],
|
||||||
|
(int8_t)buff[1], (int8_t)buff[4],
|
||||||
|
(int8_t)buff[2], (int8_t)buff[5]);
|
||||||
|
if (ret > 6) { // 5g_en
|
||||||
|
printf("efuse txpwr offset 5g:\n"
|
||||||
|
" [0]=%d(remain:%x, ch36~64)\n"
|
||||||
|
" [1]=%d(remain:%x, ch100~120)\n"
|
||||||
|
" [2]=%d(remain:%x, ch122~140)\n"
|
||||||
|
" [3]=%d(remain:%x, ch142~165)\n",
|
||||||
|
(int8_t)buff[6], (int8_t)buff[10],
|
||||||
|
(int8_t)buff[7], (int8_t)buff[11],
|
||||||
|
(int8_t)buff[8], (int8_t)buff[12],
|
||||||
|
(int8_t)buff[9], (int8_t)buff[13]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else if (strcasecmp(argV[2], "RDWR_EFUSE_DRVIBIT") == 0) {
|
||||||
|
#if (EFUSE_CMD_OLD_FORMAT_EN)
|
||||||
|
printf("done: efsue 2.4g txgain tbl pa drv_ibit: %x\n", priv_cmd.buf[0]);
|
||||||
|
#else
|
||||||
|
int val = *(int *)&priv_cmd.buf[0];
|
||||||
|
if (val < 0) {
|
||||||
|
printf("failed to rd/wr efuse drv_ibit, ret=%d\n", val);
|
||||||
|
} else {
|
||||||
|
printf("done: efsue 2.4g txgain tbl pa drv_ibit: %x (remain: %x)\n", priv_cmd.buf[0], priv_cmd.buf[1]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else if (strcasecmp(argV[2], "GET_CAL_XTAL_RES") == 0) {
|
||||||
|
unsigned int val = *(unsigned int *)&priv_cmd.buf[0];
|
||||||
|
printf("done: get_cal_xtal_res: cap=0x%x, cap_fine=0x%x\n", val & 0x000000ff, (val >> 8) & 0x000000ff);
|
||||||
|
} else if ((strcasecmp(argV[2], "GET_COB_CAL_RES") == 0) || (strcasecmp(argV[2], "DO_COB_TEST") == 0)){
|
||||||
|
unsigned int val = *(unsigned int *)&priv_cmd.buf[0];
|
||||||
|
unsigned int val0 = *(unsigned int *)&priv_cmd.buf[4];
|
||||||
|
cob_result_ptr = (cob_result_ptr_t *) (unsigned int *)&priv_cmd.buf[8];
|
||||||
|
printf("done:\ncap= 0x%x cap_fine= 0x%x freq_ofst= %d Hz golden_rcv_dut= %d tx_rssi= %d dBm snr= %d dB dut_rcv_godlden= %d rx_rssi= %d dBm\n",
|
||||||
|
val & 0x000000ff, (val >> 8) & 0x000000ff, val0, cob_result_ptr->golden_rcv_dut_num, cob_result_ptr->rssi_static, cob_result_ptr->snr_static, cob_result_ptr->dut_rcv_golden_num, cob_result_ptr->dut_rssi_static);
|
||||||
|
} else if (strcasecmp(argV[2], "GET_BT_RX_RESULT") == 0) {
|
||||||
|
printf("done: get bt rx total=%d, ok=%d, err=%d\n", *(unsigned int *)priv_cmd.buf,
|
||||||
|
*(unsigned int *)&priv_cmd.buf[4],
|
||||||
|
*(unsigned int *)&priv_cmd.buf[8]);
|
||||||
|
} else if (strcasecmp(argV[2], "BT_DATA") == 0) {
|
||||||
|
unsigned char *buff = (unsigned char *)&priv_cmd.buf[1];
|
||||||
|
int len = priv_cmd.buf[0];
|
||||||
|
printf("done: %d\n", len);
|
||||||
|
for (idx = 0; idx < len; idx++) {
|
||||||
|
printf("%02x ", buff[idx]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argC, char *argV[])
|
||||||
|
{
|
||||||
|
|
||||||
|
//char* ins = "insmod";
|
||||||
|
//char* rm = "rmmod";
|
||||||
|
//char* ko = "rwnx_fdrv.ko";
|
||||||
|
|
||||||
|
// printf("enter!!!AIC argC=%d argV[0]=%s argV[1]=%s argV[2]=%s\n", argC, argV[0], argV[1],argV[2]);
|
||||||
|
if(argC >= 3)
|
||||||
|
wifi_send_cmd_to_net_interface(argV[1], argC, argV);
|
||||||
|
else
|
||||||
|
printf("Bad parameter! %d\n",argC);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
config AIC_WLAN_SUPPORT
|
||||||
|
bool "AIC wireless Support"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
This is support for aic wireless chip.
|
||||||
|
|
||||||
|
if AIC_WLAN_SUPPORT
|
||||||
|
source "drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig"
|
||||||
|
source "drivers/net/wireless/aic8800/aic_load_fw/Kconfig"
|
||||||
|
endif
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
CONFIG_AIC_LOADFW_SUPPORT := m
|
||||||
|
CONFIG_AIC8800_WLAN_SUPPORT := m
|
||||||
|
|
||||||
|
obj-$(CONFIG_AIC_LOADFW_SUPPORT) += aic_load_fw/
|
||||||
|
obj-$(CONFIG_AIC8800_WLAN_SUPPORT) += aic8800_fdrv/
|
||||||
|
|
||||||
|
########## config option ##########
|
||||||
|
export CONFIG_USE_FW_REQUEST = n
|
||||||
|
export CONFIG_PREALLOC_RX_SKB = n
|
||||||
|
export CONFIG_PREALLOC_TXQ = y
|
||||||
|
###################################
|
||||||
|
|
||||||
|
########## platform support list ##########
|
||||||
|
export CONFIG_PLATFORM_ROCKCHIP = n
|
||||||
|
export CONFIG_PLATFORM_ALLWINNER = n
|
||||||
|
export CONFIG_PLATFORM_AMLOGIC = n
|
||||||
|
export CONFIG_PLATFORM_HI = n
|
||||||
|
export CONFIG_PLATFORM_UBUNTU = y
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_PLATFORM_ROCKCHIP), y)
|
||||||
|
ARCH = arm64
|
||||||
|
KDIR = /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/kernel
|
||||||
|
CROSS_COMPILE = /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
|
||||||
|
ccflags-y += -DANDROID_PLATFORM
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_PLATFORM_ALLWINNER), y)
|
||||||
|
KDIR = /home/yaya/E/Allwinner/R818/R818/AndroidQ/lichee/kernel/linux-4.9
|
||||||
|
ARCH = arm64
|
||||||
|
CROSS_COMPILE = /home/yaya/E/Allwinner/R818/R818/AndroidQ/lichee/out/gcc-linaro-5.3.1-2016.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
|
||||||
|
ccflags-y += -DANDROID_PLATFORM
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_PLATFORM_AMLOGIC), y)
|
||||||
|
ccflags-y += -DANDROID_PLATFORM
|
||||||
|
ARCH = arm
|
||||||
|
CROSS_COMPILE = /home/yaya/D/Workspace/CyberQuantum/JinHaoYue/amls905x3/SDK/20191101-0tt-asop/android9.0/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/arm-linux-androidkernel-
|
||||||
|
KDIR = /home/yaya/D/Workspace/CyberQuantum/JinHaoYue/amls905x3/SDK/20191101-0tt-asop/android9.0/out/target/product/u202/obj/KERNEL_OBJ/
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_PLATFORM_HI), y)
|
||||||
|
ccflags-y += -DANDROID_PLATFORM
|
||||||
|
ARCH = arm
|
||||||
|
CROSS_COMPILE = /home/yaya/D/Workspace/CyberQuantum/JinHaoYue/amls905x3/SDK/20191101-0tt-asop/android9.0/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/arm-linux-androidkernel-
|
||||||
|
KDIR = /home/yaya/D/Workspace/CyberQuantum/JinHaoYue/amls905x3/SDK/20191101-0tt-asop/android9.0/out/target/product/u202/obj/KERNEL_OBJ/
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_PLATFORM_UBUNTU), y)
|
||||||
|
KDIR = /lib/modules/$(shell uname -r)/build
|
||||||
|
PWD = $(shell pwd)
|
||||||
|
KVER = $(shell uname -r)
|
||||||
|
MODDESTDIR = /lib/modules/$(KVER)/kernel/drivers/net/wireless/aic8800
|
||||||
|
SUBARCH = $(shell uname -m | sed -e s/i.86/i386/ -e s/armv.l/arm/ -e s/aarch64/arm64/)
|
||||||
|
ARCH ?= $(SUBARCH)
|
||||||
|
CROSS_COMPILE ?=
|
||||||
|
endif
|
||||||
|
|
||||||
|
###########################################
|
||||||
|
|
||||||
|
MAKEFLAGS +=-j$(shell nproc)
|
||||||
|
|
||||||
|
all: modules
|
||||||
|
modules:
|
||||||
|
make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
|
||||||
|
|
||||||
|
install:
|
||||||
|
mkdir -p $(MODDESTDIR)
|
||||||
|
install -p -m 644 aic_load_fw/aic_load_fw.ko $(MODDESTDIR)/
|
||||||
|
install -p -m 644 aic8800_fdrv/aic8800_fdrv.ko $(MODDESTDIR)/
|
||||||
|
/sbin/depmod -a ${KVER}
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rm -rfv $(MODDESTDIR)/aic_load_fw.ko
|
||||||
|
rm -rfv $(MODDESTDIR)/aic8800_fdrv.ko
|
||||||
|
/sbin/depmod -a ${KVER}
|
||||||
|
|
||||||
|
clean:
|
||||||
|
cd aic_load_fw/;make clean;cd ..
|
||||||
|
cd aic8800_fdrv/;make clean;cd ..
|
||||||
|
rm -rf modules.order Module.symvers .modules.order.cmd .Module.symvers.cmd .tmp_versions/
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
config AIC8800_WLAN_SUPPORT
|
||||||
|
tristate "AIC8800 wlan Support"
|
||||||
|
help
|
||||||
|
This is support for aic wifi driver.
|
||||||
|
|
||||||
|
#choice
|
||||||
|
# depends on AIC8800_WLAN_SUPPORT
|
||||||
|
# prompt "Select 8800 support platform"
|
||||||
|
#
|
||||||
|
# config PLATFORM_ROCHCHIP
|
||||||
|
# bool "PLATFORM_ROCHCHIP"
|
||||||
|
# depends on AIC8800_WLAN_SUPPORT
|
||||||
|
#
|
||||||
|
# config PLATFORM_ALLWINNER
|
||||||
|
# bool "PLATFORM_ALLWINNER"
|
||||||
|
# depends on AIC8800_WLAN_SUPPORT
|
||||||
|
#
|
||||||
|
# config PLATFORM_AMLOGIC
|
||||||
|
# bool "PLATFORM_AMLOGIC"
|
||||||
|
# depends on AIC8800_WLAN_SUPPORT
|
||||||
|
#
|
||||||
|
# config PLATFORM_UBUNTU
|
||||||
|
# bool "PLATFORM_UBUNTU"
|
||||||
|
# depends on AIC8800_WLAN_SUPPORT
|
||||||
|
#
|
||||||
|
#endchoice
|
||||||
|
#
|
||||||
|
#config USE_5G
|
||||||
|
# bool "AIC8800 force enable 5G"
|
||||||
|
# ---help---
|
||||||
|
# This is parameter that force enable 5G.
|
||||||
|
#
|
||||||
|
#config HE_FOR_OLD_KERNEL
|
||||||
|
# bool "AIC8800 support AX for old kernel"
|
||||||
|
# ---help---
|
||||||
|
# This is parameter that enable AX for old kernel.
|
||||||
@@ -0,0 +1,384 @@
|
|||||||
|
EXTRA_CFLAGS += $(USER_EXTRA_CFLAGS)
|
||||||
|
EXTRA_CFLAGS += -Wno-implicit-fallthrough
|
||||||
|
#EXTRA_CFLAGS += -Wno-unused-variable
|
||||||
|
|
||||||
|
RWNX_VERS_NUM := 6.4.3.0
|
||||||
|
|
||||||
|
CONFIG_AIC8800_WLAN_SUPPORT = m
|
||||||
|
MODULE_NAME = aic8800_fdrv
|
||||||
|
CONFIG_COUNTRY_CODE = "00"
|
||||||
|
|
||||||
|
# Support of bootrom start
|
||||||
|
CONFIG_START_FROM_BOOTROM = y
|
||||||
|
|
||||||
|
# Support of pmic setting, new version bootrom avaliable
|
||||||
|
CONFIG_PMIC_SETTING ?=n
|
||||||
|
|
||||||
|
# Select 8800DC/DW DCDC_VRF mode, check your board
|
||||||
|
CONFIG_VRF_DCDC_MODE = y
|
||||||
|
|
||||||
|
# ROM patch enabled option
|
||||||
|
CONFIG_ROM_PATCH_EN ?=y
|
||||||
|
|
||||||
|
#
|
||||||
|
# WAITING FOR KCONFIG {
|
||||||
|
#
|
||||||
|
CONFIG_RWNX_SOFTMAC ?= n
|
||||||
|
CONFIG_RWNX_FULLMAC ?= y
|
||||||
|
CONFIG_RWNX_FHOST ?= n
|
||||||
|
|
||||||
|
#
|
||||||
|
# DEBUG OPTIONS
|
||||||
|
CONFIG_RWNX_UM_HELPER_DFLT ?= "/dini/dini_bin/rwnx_umh.sh"
|
||||||
|
CONFIG_AIC_FW_PATH = "/vendor/etc/firmware"
|
||||||
|
export CONFIG_AIC_FW_PATH
|
||||||
|
|
||||||
|
#
|
||||||
|
# FW ARCH:
|
||||||
|
CONFIG_RWNX_SDM ?= n
|
||||||
|
CONFIG_RWNX_TL4 ?= n
|
||||||
|
|
||||||
|
# IPC version
|
||||||
|
CONFIG_RWNX_OLD_IPC ?= n
|
||||||
|
|
||||||
|
# Support of P2P DebugFS for enabling/disabling NoA and OppPS
|
||||||
|
CONFIG_RWNX_P2P_DEBUGFS ?= y
|
||||||
|
|
||||||
|
#
|
||||||
|
# } // WAITING FOR KCONFIG
|
||||||
|
#
|
||||||
|
|
||||||
|
# Enable A-MSDU support (need FW support)
|
||||||
|
## Select this if FW is compiled with AMSDU support
|
||||||
|
CONFIG_RWNX_SPLIT_TX_BUF ?= n
|
||||||
|
## Select this TO send AMSDU
|
||||||
|
CONFIG_RWNX_AMSDUS_TX ?= n
|
||||||
|
|
||||||
|
# Enable BFMER support (need FW support)
|
||||||
|
CONFIG_RWNX_BFMER ?= n
|
||||||
|
|
||||||
|
CONFIG_SDIO_SUPPORT =n
|
||||||
|
CONFIG_USB_SUPPORT =y
|
||||||
|
CONFIG_RX_REORDER =y
|
||||||
|
CONFIG_ARP_OFFLOAD =y
|
||||||
|
CONFIG_USE_5G = y
|
||||||
|
CONFIG_RADAR_OR_IR_DETECT =n
|
||||||
|
CONFIG_DOWNLOAD_FW =n
|
||||||
|
CONFIG_RFTEST=y
|
||||||
|
CONFIG_USB_BT=y
|
||||||
|
CONFIG_MAC_RANDOM_IF_NO_MAC_IN_EFUSE = y
|
||||||
|
CONFIG_WPA3_FOR_OLD_KERNEL = n
|
||||||
|
CONFIG_HE_FOR_OLD_KERNEL = n
|
||||||
|
CONFIG_VHT_FOR_OLD_KERNEL = n
|
||||||
|
# CONFIG_COEX = n for BT_ONLY, CONFIG_COEX =y for combo and sw
|
||||||
|
CONFIG_COEX = y
|
||||||
|
CONFIG_ALIGN_8BYTES = y
|
||||||
|
CONFIG_TXRX_THREAD_PRIO = y
|
||||||
|
CONFIG_USB_ALIGN_DATA = y
|
||||||
|
CONFIG_RX_TASKLET = n
|
||||||
|
CONFIG_TX_TASKLET = n
|
||||||
|
CONFIG_RX_NETIF_RECV_SKB = y
|
||||||
|
CONFIG_BR_SUPPORT = n
|
||||||
|
CONFIG_USB_MSG_OUT_EP = y
|
||||||
|
CONFIG_USB_MSG_IN_EP = y
|
||||||
|
CONFIG_USB_RX_REASSEMBLE = n
|
||||||
|
|
||||||
|
#DCDW support tx aggr, D80 support both
|
||||||
|
CONFIG_USB_RX_AGGR = n
|
||||||
|
CONFIG_USB_TX_AGGR = n
|
||||||
|
|
||||||
|
CONFIG_USB_NO_TRANS_DMA_MAP = n
|
||||||
|
CONFIG_GPIO_WAKEUP = n
|
||||||
|
CONFIG_CREATE_TRACE_POINTS = n
|
||||||
|
CONFIG_SUPPORT_REALTIME_CHANGE_MAC = y
|
||||||
|
CONFIG_USE_USB_ZERO_PACKET = y
|
||||||
|
CONFIG_DEBUG_FS = n
|
||||||
|
CONFIG_STA_SCAN_WHEN_P2P_WORKING = y
|
||||||
|
CONFIG_SET_VENDOR_EXTENSION_IE = n
|
||||||
|
CONFIG_VENDOR_GPIO = n
|
||||||
|
CONFIG_FWLOG_EN = n
|
||||||
|
CONFIG_FOR_IPCAM = n
|
||||||
|
CONFIG_5M10M = n
|
||||||
|
# Need to set fw path in BOARD_KERNEL_CMDLINE
|
||||||
|
CONFIG_USE_FW_REQUEST ?= n
|
||||||
|
CONFIG_USE_P2P0 = n
|
||||||
|
CONFIG_ONE_TXQ = n
|
||||||
|
CONFIG_PER_STA_FC = n
|
||||||
|
CONFIG_PREALLOC_RX_SKB ?= n
|
||||||
|
CONFIG_PREALLOC_TXQ ?= y
|
||||||
|
CONFIG_USE_WIRELESS_EXT = y
|
||||||
|
CONFIG_DPD = y
|
||||||
|
CONFIG_FORCE_DPD_CALIB = y
|
||||||
|
CONFIG_GKI = n
|
||||||
|
CONFIG_SCHED_SCAN = n
|
||||||
|
CONFIG_TEMP_COMP = n
|
||||||
|
CONFIG_POWER_LIMIT = n
|
||||||
|
# CONFIG_MCC = n for sta and p2p concurrent in same channel.
|
||||||
|
CONFIG_MCC = y
|
||||||
|
CONFIG_LOAD_BT_PATCH_IN_FDRV = n
|
||||||
|
|
||||||
|
ifneq ($(CONFIG_WIRELESS_EXT), y)
|
||||||
|
CONFIG_USE_WIRELESS_EXT = n
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Support of MU-MIMO transmission (need FW support)
|
||||||
|
ifeq ($(CONFIG_RWNX_BFMER), y)
|
||||||
|
CONFIG_RWNX_MUMIMO_TX ?= n
|
||||||
|
else
|
||||||
|
CONFIG_RWNX_MUMIMO_TX = n
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Enable handling of radar event
|
||||||
|
CONFIG_RWNX_RADAR ?= y
|
||||||
|
|
||||||
|
# Enable HW queue for Broadcast/Multicast traffic (need FW support)
|
||||||
|
CONFIG_RWNX_BCMC ?= y
|
||||||
|
|
||||||
|
# Enable Monitor+Data interface support (need FW support)
|
||||||
|
CONFIG_RWNX_MON_DATA =n
|
||||||
|
CONFIG_RWNX_MON_XMIT ?= n
|
||||||
|
CONFIG_RWNX_MON_RXFILTER ?= n
|
||||||
|
|
||||||
|
CONFIG_FILTER_TCP_ACK =y
|
||||||
|
|
||||||
|
# extra DEBUG config
|
||||||
|
CONFIG_RWNX_SW_PROFILING ?= n
|
||||||
|
CONFIG_RWNX_DBG ?= y
|
||||||
|
BR_NAME = br0
|
||||||
|
|
||||||
|
obj-$(CONFIG_AIC8800_WLAN_SUPPORT) := $(MODULE_NAME).o
|
||||||
|
$(MODULE_NAME)-y := \
|
||||||
|
rwnx_msg_tx.o \
|
||||||
|
rwnx_msg_rx.o \
|
||||||
|
rwnx_utils.o \
|
||||||
|
rwnx_cmds.o \
|
||||||
|
rwnx_irqs.o \
|
||||||
|
rwnx_cfgfile.o \
|
||||||
|
rwnx_strs.o \
|
||||||
|
rwnx_rx.o \
|
||||||
|
rwnx_tx.o \
|
||||||
|
rwnx_txq.o \
|
||||||
|
rwnx_main.o \
|
||||||
|
rwnx_mod_params.o \
|
||||||
|
rwnx_mesh.o \
|
||||||
|
rwnx_platform.o \
|
||||||
|
rwnx_pci.o \
|
||||||
|
rwnx_dini.o \
|
||||||
|
rwnx_v7.o \
|
||||||
|
ipc_host.o \
|
||||||
|
rwnx_tdls.o \
|
||||||
|
regdb.o \
|
||||||
|
md5.o \
|
||||||
|
aic_vendor.o \
|
||||||
|
aic_priv_cmd.o \
|
||||||
|
aicwf_compat_8800dc.o \
|
||||||
|
aicwf_compat_8800d80.o
|
||||||
|
|
||||||
|
$(MODULE_NAME)-$(CONFIG_BR_SUPPORT) += aic_br_ext.o
|
||||||
|
$(MODULE_NAME)-$(CONFIG_RWNX_RADAR) += rwnx_radar.o
|
||||||
|
$(MODULE_NAME)-$(CONFIG_DEBUG_FS) += rwnx_debugfs.o
|
||||||
|
$(MODULE_NAME)-$(CONFIG_DEBUG_FS) += rwnx_fw_trace.o
|
||||||
|
$(MODULE_NAME)-$(CONFIG_NL80211_TESTMODE) += rwnx_testmode.o
|
||||||
|
$(MODULE_NAME)-$(CONFIG_RWNX_BFMER) += rwnx_bfmer.o
|
||||||
|
$(MODULE_NAME)-$(CONFIG_RWNX_MUMIMO_TX) += rwnx_mu_group.o
|
||||||
|
$(MODULE_NAME)-$(CONFIG_SDIO_SUPPORT) += sdio_host.o
|
||||||
|
$(MODULE_NAME)-$(CONFIG_SDIO_SUPPORT) += aicwf_txrxif.o
|
||||||
|
$(MODULE_NAME)-$(CONFIG_SDIO_SUPPORT) += aicwf_sdio.o
|
||||||
|
$(MODULE_NAME)-$(CONFIG_FILTER_TCP_ACK) += aicwf_tcp_ack.o
|
||||||
|
|
||||||
|
$(MODULE_NAME)-$(CONFIG_USB_SUPPORT) += usb_host.o
|
||||||
|
$(MODULE_NAME)-$(CONFIG_USB_SUPPORT) += aicwf_txrxif.o
|
||||||
|
$(MODULE_NAME)-$(CONFIG_USB_SUPPORT) += aicwf_usb.o
|
||||||
|
$(MODULE_NAME)-$(CONFIG_USE_WIRELESS_EXT) += aicwf_wext_linux.o
|
||||||
|
$(MODULE_NAME)-$(CONFIG_GKI) += rwnx_gki.o
|
||||||
|
|
||||||
|
ccflags-$(CONFIG_DEBUG_FS) += -DCONFIG_RWNX_DEBUGFS
|
||||||
|
ccflags-$(CONFIG_DEBUG_FS) += -DCONFIG_RWNX_UM_HELPER_DFLT=\"$(CONFIG_RWNX_UM_HELPER_DFLT)\"
|
||||||
|
ccflags-$(CONFIG_RWNX_P2P_DEBUGFS) += -DCONFIG_RWNX_P2P_DEBUGFS
|
||||||
|
|
||||||
|
# FW VARS
|
||||||
|
ccflags-y += -DNX_VIRT_DEV_MAX=4
|
||||||
|
|
||||||
|
#for 8800D and DCDW u01
|
||||||
|
#ccflags-y += -DNX_REMOTE_STA_MAX=8
|
||||||
|
|
||||||
|
#for 8800DCDW u02
|
||||||
|
ccflags-y += -DNX_REMOTE_STA_MAX_FOR_OLD_IC=8
|
||||||
|
ccflags-y += -DNX_REMOTE_STA_MAX=32
|
||||||
|
|
||||||
|
ccflags-y += -DNX_MU_GROUP_MAX=62
|
||||||
|
ccflags-y += -DNX_TXDESC_CNT=64
|
||||||
|
ccflags-y += -DNX_TX_MAX_RATES=4
|
||||||
|
ccflags-y += -DNX_CHAN_CTXT_CNT=3
|
||||||
|
|
||||||
|
# FW ARCH:
|
||||||
|
ccflags-$(CONFIG_RWNX_SDM) += -DCONFIG_RWNX_SDM
|
||||||
|
ccflags-$(CONFIG_RWNX_TL4) += -DCONFIG_RWNX_TL4
|
||||||
|
ccflags-$(CONFIG_RWNX_OLD_IPC) += -DCONFIG_RWNX_OLD_IPC
|
||||||
|
ccflags-$(CONFIG_START_FROM_BOOTROM) += -DCONFIG_START_FROM_BOOTROM
|
||||||
|
ccflags-$(CONFIG_PMIC_SETTING) += -DCONFIG_PMIC_SETTING
|
||||||
|
ccflags-$(CONFIG_VRF_DCDC_MODE) += -DCONFIG_VRF_DCDC_MODE
|
||||||
|
ccflags-$(CONFIG_ROM_PATCH_EN) += -DCONFIG_ROM_PATCH_EN
|
||||||
|
ccflags-$(CONFIG_WPA3_FOR_OLD_KERNEL) += -DCONFIG_WPA3_FOR_OLD_KERNEL
|
||||||
|
ccflags-$(CONFIG_HE_FOR_OLD_KERNEL) += -DCONFIG_HE_FOR_OLD_KERNEL
|
||||||
|
ccflags-$(CONFIG_VHT_FOR_OLD_KERNEL) += -DCONFIG_VHT_FOR_OLD_KERNEL
|
||||||
|
ccflags-$(CONFIG_COEX) += -DCONFIG_COEX
|
||||||
|
|
||||||
|
ccflags-y += -DCONFIG_RWNX_FULLMAC
|
||||||
|
ccflags-y += -I$(src)/.
|
||||||
|
ccflags-$(CONFIG_RWNX_RADAR) += -DCONFIG_RWNX_RADAR
|
||||||
|
ccflags-$(CONFIG_RWNX_MON_DATA) += -DCONFIG_RWNX_MON_DATA
|
||||||
|
ccflags-$(CONFIG_RWNX_MON_XMIT) += -DCONFIG_RWNX_MON_XMIT
|
||||||
|
ccflags-$(CONFIG_RWNX_MON_RXFILTER) += -DCONFIG_RWNX_MON_RXFILTER
|
||||||
|
ccflags-$(CONFIG_RWNX_BFMER) += -DCONFIG_RWNX_BFMER
|
||||||
|
ccflags-$(CONFIG_RWNX_SPLIT_TX_BUF) += -DCONFIG_RWNX_SPLIT_TX_BUF
|
||||||
|
ifeq ($(CONFIG_RWNX_SPLIT_TX_BUF), y)
|
||||||
|
ccflags-$(CONFIG_RWNX_AMSDUS_TX) += -DCONFIG_RWNX_AMSDUS_TX
|
||||||
|
endif
|
||||||
|
ccflags-$(CONFIG_RWNX_DBG) += -DCONFIG_RWNX_DBG
|
||||||
|
ccflags-$(CONFIG_RWNX_SW_PROFILING) += -DCONFIG_RWNX_SW_PROFILING
|
||||||
|
ccflags-$(CONFIG_RWNX_MUMIMO_TX) += -DCONFIG_RWNX_MUMIMO_TX
|
||||||
|
ccflags-$(CONFIG_RFTEST) += -DCONFIG_RFTEST
|
||||||
|
ccflags-$(CONFIG_MCC) += -DCONFIG_MCC
|
||||||
|
ccflags-$(CONFIG_LOAD_BT_PATCH_IN_FDRV) += -DCONFIG_LOAD_BT_PATCH_IN_FDRV
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_SDIO_SUPPORT), y)
|
||||||
|
ccflags-y += -DAICWF_SDIO_SUPPORT
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_USB_SUPPORT), y)
|
||||||
|
ccflags-y += -DAICWF_USB_SUPPORT
|
||||||
|
endif
|
||||||
|
ifeq ($(CONFIG_BR_SUPPORT), y)
|
||||||
|
ccflags-y += -DCONFIG_BR_SUPPORT
|
||||||
|
ccflags-y += '-DCONFIG_BR_SUPPORT_BRNAME="'$(BR_NAME)'"'
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_RWNX_MUMIMO_TX), y)
|
||||||
|
ccflags-y += -DCONFIG_USER_MAX=2
|
||||||
|
else
|
||||||
|
ccflags-y += -DCONFIG_USER_MAX=1
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_RWNX_BCMC), y)
|
||||||
|
ccflags-y += -DNX_TXQ_CNT=5
|
||||||
|
else
|
||||||
|
ccflags-y += -DNX_TXQ_CNT=4
|
||||||
|
endif
|
||||||
|
|
||||||
|
# For old kernel (<=3.19)
|
||||||
|
ifeq ($(shell test $(VERSION) -lt 4 -a "$(CONFIG_VENDOR_RWNX)" = y ; echo $$?),0)
|
||||||
|
ccflags-y += -DCONFIG_VENDOR_RWNX_VHT_NO80
|
||||||
|
endif
|
||||||
|
|
||||||
|
ccflags-$(CONFIG_RX_REORDER) += -DAICWF_RX_REORDER
|
||||||
|
ccflags-$(CONFIG_ARP_OFFLOAD) += -DAICWF_ARP_OFFLOAD
|
||||||
|
ccflags-$(CONFIG_USE_5G) += -DUSE_5G
|
||||||
|
ccflags-$(CONFIG_RADAR_OR_IR_DETECT) += -DRADAR_OR_IR_DETECT
|
||||||
|
ccflags-$(CONFIG_DOWNLOAD_FW) += -DCONFIG_DOWNLOAD_FW
|
||||||
|
ccflags-$(CONFIG_USB_BT) += -DCONFIG_USB_BT
|
||||||
|
ccflags-$(CONFIG_ALIGN_8BYTES) += -DCONFIG_ALIGN_8BYTES
|
||||||
|
ccflags-$(CONFIG_TXRX_THREAD_PRIO) += -DCONFIG_TXRX_THREAD_PRIO
|
||||||
|
ccflags-$(CONFIG_USB_ALIGN_DATA) += -DCONFIG_USB_ALIGN_DATA
|
||||||
|
ccflags-$(CONFIG_MAC_RANDOM_IF_NO_MAC_IN_EFUSE) += -DCONFIG_MAC_RANDOM_IF_NO_MAC_IN_EFUSE
|
||||||
|
ccflags-$(CONFIG_VENDOR_GPIO) += -DCONFIG_VENDOR_GPIO
|
||||||
|
ccflags-y += -DDEFAULT_COUNTRY_CODE=""\$(CONFIG_COUNTRY_CODE)"\"
|
||||||
|
ccflags-$(CONFIG_RX_NETIF_RECV_SKB) += -DCONFIG_RX_NETIF_RECV_SKB
|
||||||
|
ccflags-$(CONFIG_USB_MSG_OUT_EP) += -DCONFIG_USB_MSG_OUT_EP
|
||||||
|
ccflags-$(CONFIG_USB_MSG_IN_EP) += -DCONFIG_USB_MSG_IN_EP
|
||||||
|
ccflags-$(CONFIG_USB_RX_REASSEMBLE) += -DCONFIG_USB_RX_REASSEMBLE
|
||||||
|
ccflags-$(CONFIG_USB_RX_AGGR) += -DCONFIG_USB_RX_AGGR
|
||||||
|
ccflags-$(CONFIG_USB_TX_AGGR) += -DCONFIG_USB_TX_AGGR
|
||||||
|
ccflags-$(CONFIG_USB_NO_TRANS_DMA_MAP) += -DCONFIG_USB_NO_TRANS_DMA_MAP
|
||||||
|
ccflags-$(CONFIG_GPIO_WAKEUP) += -DCONFIG_GPIO_WAKEUP
|
||||||
|
ccflags-$(CONFIG_CREATE_TRACE_POINTS) += -DCREATE_TRACE_POINTS
|
||||||
|
ccflags-$(CONFIG_RX_TASKLET) += -DCONFIG_RX_TASKLET
|
||||||
|
ccflags-$(CONFIG_TX_TASKLET) += -DCONFIG_TX_TASKLET
|
||||||
|
ccflags-$(CONFIG_USE_USB_ZERO_PACKET) += -DCONFIG_USE_USB_ZERO_PACKET
|
||||||
|
ccflags-$(CONFIG_STA_SCAN_WHEN_P2P_WORKING) += -DCONFIG_STA_SCAN_WHEN_P2P_WORKING
|
||||||
|
ccflags-$(CONFIG_SUPPORT_REALTIME_CHANGE_MAC) += -DCONFIG_SUPPORT_REALTIME_CHANGE_MAC
|
||||||
|
ccflags-$(CONFIG_SET_VENDOR_EXTENSION_IE) += -DCONFIG_SET_VENDOR_EXTENSION_IE
|
||||||
|
ccflags-$(CONFIG_FWLOG_EN) += -DCONFIG_FWLOG_EN
|
||||||
|
ccflags-$(CONFIG_FOR_IPCAM) += -DCONFIG_FOR_IPCAM -DCONFIG_ONE_TXQ
|
||||||
|
ccflags-$(CONFIG_5M10M) += -DCONFIG_5M10M
|
||||||
|
ccflags-$(CONFIG_USE_FW_REQUEST) += -DCONFIG_USE_FW_REQUEST
|
||||||
|
ccflags-$(CONFIG_USE_P2P0) += -DCONFIG_USE_P2P0
|
||||||
|
ccflags-$(CONFIG_ONE_TXQ) += -DCONFIG_ONE_TXQ
|
||||||
|
ccflags-$(CONFIG_PER_STA_FC) += -DCONFIG_PER_STA_FC
|
||||||
|
ccflags-$(CONFIG_PREALLOC_RX_SKB) += -DCONFIG_PREALLOC_RX_SKB
|
||||||
|
ccflags-$(CONFIG_PREALLOC_TXQ) += -DCONFIG_PREALLOC_TXQ
|
||||||
|
ccflags-$(CONFIG_USE_WIRELESS_EXT) += -DCONFIG_USE_WIRELESS_EXT
|
||||||
|
ccflags-$(CONFIG_DPD) += -DCONFIG_DPD
|
||||||
|
ccflags-$(CONFIG_FORCE_DPD_CALIB) += -DCONFIG_FORCE_DPD_CALIB -DCONFIG_DPD
|
||||||
|
ccflags-$(CONFIG_GKI) += -DCONFIG_GKI
|
||||||
|
ccflags-$(CONFIG_SCHED_SCAN) += -DCONFIG_SCHED_SCAN
|
||||||
|
ccflags-$(CONFIG_FILTER_TCP_ACK) += -DCONFIG_FILTER_TCP_ACK
|
||||||
|
ccflags-$(CONFIG_TEMP_COMP) += -DCONFIG_TEMP_COMP
|
||||||
|
ccflags-$(CONFIG_POWER_LIMIT) += -DCONFIG_POWER_LIMIT
|
||||||
|
MAKEFLAGS +=-j$(shell nproc)
|
||||||
|
|
||||||
|
# Platform support list
|
||||||
|
CONFIG_PLATFORM_ROCKCHIP ?= n
|
||||||
|
CONFIG_PLATFORM_ALLWINNER ?= n
|
||||||
|
CONFIG_PLATFORM_AMLOGIC ?= n
|
||||||
|
CONFIG_PLATFORM_HI ?= n
|
||||||
|
CONFIG_PLATFORM_UBUNTU ?= y
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_PLATFORM_ROCKCHIP), y)
|
||||||
|
ARCH := arm64
|
||||||
|
KDIR ?= /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/kernel
|
||||||
|
CROSS_COMPILE := /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
|
||||||
|
ccflags-y += -DANDROID_PLATFORM
|
||||||
|
ccflags-y += -DCONFIG_PLATFORM_ROCKCHIP
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_PLATFORM_ALLWINNER), y)
|
||||||
|
KDIR ?= /home/yaya/E/Allwinner/R818/R818/AndroidQ/lichee/kernel/linux-4.9
|
||||||
|
ARCH ?= arm64
|
||||||
|
CROSS_COMPILE ?= /home/yaya/E/Allwinner/R818/R818/AndroidQ/lichee/out/gcc-linaro-5.3.1-2016.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
|
||||||
|
ccflags-y += -DANDROID_PLATFORM
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_PLATFORM_AMLOGIC), y)
|
||||||
|
ccflags-y += -DANDROID_PLATFORM
|
||||||
|
ARCH ?= arm
|
||||||
|
CROSS_COMPILE ?= /home/yaya/D/Workspace/CyberQuantum/JinHaoYue/amls905x3/SDK/20191101-0tt-asop/android9.0/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/arm-linux-androidkernel-
|
||||||
|
KDIR ?= /home/yaya/D/Workspace/CyberQuantum/JinHaoYue/amls905x3/SDK/20191101-0tt-asop/android9.0/out/target/product/u202/obj/KERNEL_OBJ/
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_PLATFORM_HI), y)
|
||||||
|
ccflags-y += -DANDROID_PLATFORM
|
||||||
|
ccflags-y += -DCONFIG_PLATFORM_HI
|
||||||
|
ARCH ?= arm
|
||||||
|
CROSS_COMPILE ?= /home/yaya/D/Workspace/CyberQuantum/JinHaoYue/amls905x3/SDK/20191101-0tt-asop/android9.0/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/arm-linux-androidkernel-
|
||||||
|
KDIR ?= /home/yaya/D/Workspace/CyberQuantum/JinHaoYue/amls905x3/SDK/20191101-0tt-asop/android9.0/out/target/product/u202/obj/KERNEL_OBJ/
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_PLATFORM_UBUNTU), y)
|
||||||
|
KDIR ?= /lib/modules/$(shell uname -r)/build
|
||||||
|
#KDIR ?= ~/D/Workspace/CyberQuantum/Linux/linux-4.15/
|
||||||
|
PWD ?= $(shell pwd)
|
||||||
|
KVER ?= $(shell uname -r)
|
||||||
|
MODDESTDIR ?= /lib/modules/$(KVER)/kernel/drivers/net/wireless/aic8800
|
||||||
|
SUBARCH = $(shell uname -m | sed -e s/i.86/i386/ -e s/armv.l/arm/ -e s/aarch64/arm64/)
|
||||||
|
ARCH ?= $(SUBARCH)
|
||||||
|
CROSS_COMPILE ?=
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
all: modules
|
||||||
|
modules:
|
||||||
|
# make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) LLVM=1 LLVM_IAS=1 modules
|
||||||
|
make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
|
||||||
|
install:
|
||||||
|
mkdir -p $(MODDESTDIR)
|
||||||
|
install -p -m 644 $(MODULE_NAME).ko $(MODDESTDIR)
|
||||||
|
/sbin/depmod -a ${KVER}
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rm -rfv $(MODDESTDIR)/$(MODULE_NAME).ko
|
||||||
|
/sbin/depmod -a ${KVER}
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf *.o *.ko *.o.* *.mod.* modules.* Module.* .a* .o* .*.o.* *.mod .tmp* .cache.mk .modules.order.cmd .Module.symvers.cmd
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,73 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright(c) 2007 - 2017 Realtek Corporation.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of version 2 of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
#ifndef _AIC_BR_EXT_H_
|
||||||
|
#define _AIC_BR_EXT_H_
|
||||||
|
|
||||||
|
#define CL_IPV6_PASS 1
|
||||||
|
#define MACADDRLEN 6
|
||||||
|
#define WLAN_ETHHDR_LEN 14
|
||||||
|
|
||||||
|
#define NAT25_HASH_BITS 4
|
||||||
|
#define NAT25_HASH_SIZE (1 << NAT25_HASH_BITS)
|
||||||
|
#define NAT25_AGEING_TIME 300
|
||||||
|
|
||||||
|
#define NDEV_FMT "%s"
|
||||||
|
#define NDEV_ARG(ndev) ndev->name
|
||||||
|
#define ADPT_FMT "%s"
|
||||||
|
//#define ADPT_ARG(adapter) (adapter->pnetdev ? adapter->pnetdev->name : NULL)
|
||||||
|
#define FUNC_NDEV_FMT "%s(%s)"
|
||||||
|
#define FUNC_NDEV_ARG(ndev) __func__, ndev->name
|
||||||
|
#define FUNC_ADPT_FMT "%s(%s)"
|
||||||
|
//#define FUNC_ADPT_ARG(adapter) __func__, (adapter->pnetdev ? adapter->pnetdev->name : NULL)
|
||||||
|
#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
|
||||||
|
#define MAC_ARG(x) ((u8 *)(x))[0], ((u8 *)(x))[1], ((u8 *)(x))[2], ((u8 *)(x))[3], ((u8 *)(x))[4], ((u8 *)(x))[5]
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CL_IPV6_PASS
|
||||||
|
#define MAX_NETWORK_ADDR_LEN 17
|
||||||
|
#else
|
||||||
|
#define MAX_NETWORK_ADDR_LEN 11
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct nat25_network_db_entry {
|
||||||
|
struct nat25_network_db_entry *next_hash;
|
||||||
|
struct nat25_network_db_entry **pprev_hash;
|
||||||
|
atomic_t use_count;
|
||||||
|
unsigned char macAddr[6];
|
||||||
|
unsigned long ageing_timer;
|
||||||
|
unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum NAT25_METHOD {
|
||||||
|
NAT25_MIN,
|
||||||
|
NAT25_CHECK,
|
||||||
|
NAT25_INSERT,
|
||||||
|
NAT25_LOOKUP,
|
||||||
|
NAT25_PARSE,
|
||||||
|
NAT25_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
struct br_ext_info {
|
||||||
|
unsigned int nat25_disable;
|
||||||
|
unsigned int macclone_enable;
|
||||||
|
unsigned int dhcp_bcst_disable;
|
||||||
|
int addPPPoETag; /* 1: Add PPPoE relay-SID, 0: disable */
|
||||||
|
unsigned char nat25_dmzMac[MACADDRLEN];
|
||||||
|
unsigned int nat25sc_disable;
|
||||||
|
};
|
||||||
|
|
||||||
|
void nat25_db_cleanup(struct rwnx_vif *vif);
|
||||||
|
|
||||||
|
#endif /* _AIC_BR_EXT_H_ */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file private_cmd.h
|
||||||
|
*
|
||||||
|
* Copyright (C) Aicsemi 2018-2024
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _AIC_PRIV_CMD_H_
|
||||||
|
#define _AIC_PRIV_CMD_H_
|
||||||
|
|
||||||
|
#include "rwnx_defs.h"
|
||||||
|
|
||||||
|
typedef struct _android_wifi_priv_cmd {
|
||||||
|
char *buf;
|
||||||
|
int used_len;
|
||||||
|
int total_len;
|
||||||
|
} android_wifi_priv_cmd;
|
||||||
|
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
typedef struct _compat_android_wifi_priv_cmd {
|
||||||
|
compat_caddr_t buf;
|
||||||
|
int used_len;
|
||||||
|
int total_len;
|
||||||
|
} compat_android_wifi_priv_cmd;
|
||||||
|
#endif /* CONFIG_COMPAT */
|
||||||
|
|
||||||
|
int android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd);
|
||||||
|
|
||||||
|
#endif /* _AIC_PRIV_CMD_H_ */
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,346 @@
|
|||||||
|
#ifndef _AIC_VENDOR_H
|
||||||
|
#define _AIC_VENDOR_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#define GOOGLE_OUI 0x001A11
|
||||||
|
#define BRCM_OUI 0x001018
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
START_MKEEP_ALIVE,
|
||||||
|
STOP_MKEEP_ALIVE,
|
||||||
|
} GetCmdType;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
/* don't use 0 as a valid subcommand */
|
||||||
|
VENDOR_NL80211_SUBCMD_UNSPECIFIED,
|
||||||
|
|
||||||
|
/* define all vendor startup commands between 0x0 and 0x0FFF */
|
||||||
|
VENDOR_NL80211_SUBCMD_RANGE_START = 0x0001,
|
||||||
|
VENDOR_NL80211_SUBCMD_RANGE_END = 0x0FFF,
|
||||||
|
|
||||||
|
/* define all GScan related commands between 0x1000 and 0x10FF */
|
||||||
|
ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START = 0x1000,
|
||||||
|
ANDROID_NL80211_SUBCMD_GSCAN_RANGE_END = 0x10FF,
|
||||||
|
|
||||||
|
/* define all NearbyDiscovery related commands between 0x1100 and 0x11FF */
|
||||||
|
ANDROID_NL80211_SUBCMD_NBD_RANGE_START = 0x1100,
|
||||||
|
ANDROID_NL80211_SUBCMD_NBD_RANGE_END = 0x11FF,
|
||||||
|
|
||||||
|
/* define all RTT related commands between 0x1100 and 0x11FF */
|
||||||
|
ANDROID_NL80211_SUBCMD_RTT_RANGE_START = 0x1100,
|
||||||
|
ANDROID_NL80211_SUBCMD_RTT_RANGE_END = 0x11FF,
|
||||||
|
|
||||||
|
ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START = 0x1200,
|
||||||
|
ANDROID_NL80211_SUBCMD_LSTATS_RANGE_END = 0x12FF,
|
||||||
|
|
||||||
|
/* define all Logger related commands between 0x1400 and 0x14FF */
|
||||||
|
ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START = 0x1400,
|
||||||
|
ANDROID_NL80211_SUBCMD_DEBUG_RANGE_END = 0x14FF,
|
||||||
|
|
||||||
|
/* define all wifi offload related commands between 0x1600 and 0x16FF */
|
||||||
|
ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START = 0x1600,
|
||||||
|
ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_END = 0x16FF,
|
||||||
|
|
||||||
|
/* define all NAN related commands between 0x1700 and 0x17FF */
|
||||||
|
ANDROID_NL80211_SUBCMD_NAN_RANGE_START = 0x1700,
|
||||||
|
ANDROID_NL80211_SUBCMD_NAN_RANGE_END = 0x17FF,
|
||||||
|
|
||||||
|
/* define all Android Packet Filter related commands between 0x1800 and 0x18FF */
|
||||||
|
ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_START = 0x1800,
|
||||||
|
ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_END = 0x18FF,
|
||||||
|
|
||||||
|
/* This is reserved for future usage */
|
||||||
|
|
||||||
|
} ANDROID_VENDOR_SUB_COMMAND;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE = ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START,
|
||||||
|
WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE,
|
||||||
|
} WIFI_OFFLOAD_SUB_COMMAND;
|
||||||
|
|
||||||
|
|
||||||
|
enum mkeep_alive_attributes {
|
||||||
|
MKEEP_ALIVE_ATTRIBUTE_ID = 0x1,
|
||||||
|
MKEEP_ALIVE_ATTRIBUTE_IP_PKT,
|
||||||
|
MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN,
|
||||||
|
MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR,
|
||||||
|
MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR,
|
||||||
|
MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC,
|
||||||
|
MKEEP_ALIVE_ATTRIBUTE_AFTER_LAST,
|
||||||
|
MKEEP_ALIVE_ATTRIBUTE_MAX = MKEEP_ALIVE_ATTRIBUTE_AFTER_LAST - 1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum debug_sub_command {
|
||||||
|
LOGGER_START_LOGGING = ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START,
|
||||||
|
LOGGER_TRIGGER_MEM_DUMP,
|
||||||
|
LOGGER_GET_MEM_DUMP,
|
||||||
|
LOGGER_GET_VER,
|
||||||
|
LOGGER_GET_RING_STATUS,
|
||||||
|
LOGGER_GET_RING_DATA,
|
||||||
|
LOGGER_GET_FEATURE,
|
||||||
|
LOGGER_RESET_LOGGING,
|
||||||
|
LOGGER_TRIGGER_DRIVER_MEM_DUMP,
|
||||||
|
LOGGER_GET_DRIVER_MEM_DUMP,
|
||||||
|
LOGGER_START_PKT_FATE_MONITORING,
|
||||||
|
LOGGER_GET_TX_PKT_FATES,
|
||||||
|
LOGGER_GET_RX_PKT_FATES,
|
||||||
|
LOGGER_GET_WAKE_REASON_STATS,
|
||||||
|
LOGGER_DEBUG_GET_DUMP,
|
||||||
|
LOGGER_FILE_DUMP_DONE_IND,
|
||||||
|
LOGGER_SET_HAL_START,
|
||||||
|
LOGGER_HAL_STOP,
|
||||||
|
LOGGER_SET_HAL_PID,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum logger_attributes {
|
||||||
|
LOGGER_ATTRIBUTE_INVALID = 0,
|
||||||
|
LOGGER_ATTRIBUTE_DRIVER_VER,
|
||||||
|
LOGGER_ATTRIBUTE_FW_VER,
|
||||||
|
LOGGER_ATTRIBUTE_RING_ID,
|
||||||
|
LOGGER_ATTRIBUTE_RING_NAME,
|
||||||
|
LOGGER_ATTRIBUTE_RING_FLAGS,
|
||||||
|
LOGGER_ATTRIBUTE_LOG_LEVEL,
|
||||||
|
LOGGER_ATTRIBUTE_LOG_TIME_INTVAL,
|
||||||
|
LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE,
|
||||||
|
LOGGER_ATTRIBUTE_FW_DUMP_LEN,
|
||||||
|
LOGGER_ATTRIBUTE_FW_DUMP_DATA,
|
||||||
|
// LOGGER_ATTRIBUTE_FW_ERR_CODE,
|
||||||
|
LOGGER_ATTRIBUTE_RING_DATA,
|
||||||
|
LOGGER_ATTRIBUTE_RING_STATUS,
|
||||||
|
LOGGER_ATTRIBUTE_RING_NUM,
|
||||||
|
LOGGER_ATTRIBUTE_DRIVER_DUMP_LEN,
|
||||||
|
LOGGER_ATTRIBUTE_DRIVER_DUMP_DATA,
|
||||||
|
LOGGER_ATTRIBUTE_PKT_FATE_NUM,
|
||||||
|
LOGGER_ATTRIBUTE_PKT_FATE_DATA,
|
||||||
|
LOGGER_ATTRIBUTE_AFTER_LAST,
|
||||||
|
LOGGER_ATTRIBUTE_MAX = LOGGER_ATTRIBUTE_AFTER_LAST - 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum wifi_sub_command {
|
||||||
|
GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START,
|
||||||
|
GSCAN_SUBCMD_SET_CONFIG, /* 0x1001 */
|
||||||
|
GSCAN_SUBCMD_SET_SCAN_CONFIG, /* 0x1002 */
|
||||||
|
GSCAN_SUBCMD_ENABLE_GSCAN, /* 0x1003 */
|
||||||
|
GSCAN_SUBCMD_GET_SCAN_RESULTS, /* 0x1004 */
|
||||||
|
GSCAN_SUBCMD_SCAN_RESULTS, /* 0x1005 */
|
||||||
|
GSCAN_SUBCMD_SET_HOTLIST, /* 0x1006 */
|
||||||
|
GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG, /* 0x1007 */
|
||||||
|
GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, /* 0x1008 */
|
||||||
|
GSCAN_SUBCMD_GET_CHANNEL_LIST, /* 0x1009 */
|
||||||
|
WIFI_SUBCMD_GET_FEATURE_SET, /* 0x100A */
|
||||||
|
WIFI_SUBCMD_GET_FEATURE_SET_MATRIX, /* 0x100B */
|
||||||
|
WIFI_SUBCMD_SET_PNO_RANDOM_MAC_OUI, /* 0x100C */
|
||||||
|
WIFI_SUBCMD_NODFS_SET, /* 0x100D */
|
||||||
|
WIFI_SUBCMD_SET_COUNTRY_CODE, /* 0x100E */
|
||||||
|
/* Add more sub commands here */
|
||||||
|
GSCAN_SUBCMD_SET_EPNO_SSID, /* 0x100F */
|
||||||
|
WIFI_SUBCMD_SET_SSID_WHITE_LIST, /* 0x1010 */
|
||||||
|
WIFI_SUBCMD_SET_ROAM_PARAMS, /* 0x1011 */
|
||||||
|
WIFI_SUBCMD_ENABLE_LAZY_ROAM, /* 0x1012 */
|
||||||
|
WIFI_SUBCMD_SET_BSSID_PREF, /* 0x1013 */
|
||||||
|
WIFI_SUBCMD_SET_BSSID_BLACKLIST, /* 0x1014 */
|
||||||
|
GSCAN_SUBCMD_ANQPO_CONFIG, /* 0x1015 */
|
||||||
|
WIFI_SUBCMD_SET_RSSI_MONITOR, /* 0x1016 */
|
||||||
|
WIFI_SUBCMD_CONFIG_ND_OFFLOAD, /* 0x1017 */
|
||||||
|
/* Add more sub commands here */
|
||||||
|
GSCAN_SUBCMD_MAX,
|
||||||
|
APF_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_START,
|
||||||
|
APF_SUBCMD_SET_FILTER,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum gscan_attributes {
|
||||||
|
GSCAN_ATTRIBUTE_NUM_BUCKETS = 10,
|
||||||
|
GSCAN_ATTRIBUTE_BASE_PERIOD,
|
||||||
|
GSCAN_ATTRIBUTE_BUCKETS_BAND,
|
||||||
|
GSCAN_ATTRIBUTE_BUCKET_ID,
|
||||||
|
GSCAN_ATTRIBUTE_BUCKET_PERIOD,
|
||||||
|
GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
|
||||||
|
GSCAN_ATTRIBUTE_BUCKET_CHANNELS,
|
||||||
|
GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN,
|
||||||
|
GSCAN_ATTRIBUTE_REPORT_THRESHOLD,
|
||||||
|
GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE,
|
||||||
|
GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND,
|
||||||
|
|
||||||
|
GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20,
|
||||||
|
GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, /* indicates no more results */
|
||||||
|
GSCAN_ATTRIBUTE_FLUSH_FEATURE, /* Flush all the configs */
|
||||||
|
GSCAN_ENABLE_FULL_SCAN_RESULTS,
|
||||||
|
GSCAN_ATTRIBUTE_REPORT_EVENTS,
|
||||||
|
|
||||||
|
/* remaining reserved for additional attributes */
|
||||||
|
GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30,
|
||||||
|
GSCAN_ATTRIBUTE_FLUSH_RESULTS,
|
||||||
|
GSCAN_ATTRIBUTE_SCAN_RESULTS, /* flat array of wifi_scan_result */
|
||||||
|
GSCAN_ATTRIBUTE_SCAN_ID, /* indicates scan number */
|
||||||
|
GSCAN_ATTRIBUTE_SCAN_FLAGS, /* indicates if scan was aborted */
|
||||||
|
GSCAN_ATTRIBUTE_AP_FLAGS, /* flags on significant change event */
|
||||||
|
GSCAN_ATTRIBUTE_NUM_CHANNELS,
|
||||||
|
GSCAN_ATTRIBUTE_CHANNEL_LIST,
|
||||||
|
GSCAN_ATTRIBUTE_CH_BUCKET_BITMASK,
|
||||||
|
|
||||||
|
GSCAN_ATTRIBUTE_AFTER_LAST,
|
||||||
|
GSCAN_ATTRIBUTE_MAX = GSCAN_ATTRIBUTE_AFTER_LAST - 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum andr_wifi_attributes {
|
||||||
|
ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET,
|
||||||
|
ANDR_WIFI_ATTRIBUTE_FEATURE_SET,
|
||||||
|
ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI,
|
||||||
|
ANDR_WIFI_ATTRIBUTE_NODFS_SET,
|
||||||
|
ANDR_WIFI_ATTRIBUTE_COUNTRY,
|
||||||
|
ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE,
|
||||||
|
// Add more attribute here
|
||||||
|
ANDR_WIFI_ATTRIBUTE_AFTER_LAST,
|
||||||
|
ANDR_WIFI_ATTRIBUTE_MAX = ANDR_WIFI_ATTRIBUTE_AFTER_LAST - 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum wifi_support_feature {
|
||||||
|
/* Feature enums */
|
||||||
|
WIFI_FEATURE_INFRA = 0x0001, /* Basic infrastructure mode */
|
||||||
|
WIFI_FEATURE_INFRA_5G = 0x0002, /* Support for 5, GHz Band */
|
||||||
|
WIFI_FEATURE_HOTSPOT = 0x0004, /* Support for GAS/ANQP */
|
||||||
|
WIFI_FEATURE_P2P = 0x0008, /* Wifi-Direct */
|
||||||
|
WIFI_FEATURE_SOFT_AP = 0x0010, /* Soft AP */
|
||||||
|
WIFI_FEATURE_GSCAN = 0x0020, /* Google-Scan APIs */
|
||||||
|
WIFI_FEATURE_NAN = 0x0040, /* Neighbor Awareness Networking */
|
||||||
|
WIFI_FEATURE_D2D_RTT = 0x0080, /* Device-to-device RTT */
|
||||||
|
WIFI_FEATURE_D2AP_RTT = 0x0100, /* Device-to-AP RTT */
|
||||||
|
WIFI_FEATURE_BATCH_SCAN = 0x0200, /* Batched Scan (legacy) */
|
||||||
|
WIFI_FEATURE_PNO = 0x0400, /* Preferred network offload */
|
||||||
|
WIFI_FEATURE_ADDITIONAL_STA = 0x0800, /* Support for two STAs */
|
||||||
|
WIFI_FEATURE_TDLS = 0x1000, /* Tunnel directed link setup */
|
||||||
|
WIFI_FEATURE_TDLS_OFFCHANNEL = 0x2000, /* Support for TDLS off channel */
|
||||||
|
WIFI_FEATURE_EPR = 0x4000, /* Enhanced power reporting */
|
||||||
|
WIFI_FEATURE_AP_STA = 0x8000, /* Support for AP STA Concurrency */
|
||||||
|
WIFI_FEATURE_LINK_LAYER_STATS = 0x10000, /* Support for Linkstats */
|
||||||
|
WIFI_FEATURE_LOGGER = 0x20000, /* WiFi Logger */
|
||||||
|
WIFI_FEATURE_HAL_EPNO = 0x40000, /* WiFi PNO enhanced */
|
||||||
|
WIFI_FEATURE_RSSI_MONITOR = 0x80000, /* RSSI Monitor */
|
||||||
|
WIFI_FEATURE_MKEEP_ALIVE = 0x100000, /* WiFi mkeep_alive */
|
||||||
|
WIFI_FEATURE_CONFIG_NDO = 0x200000, /* ND offload configure */
|
||||||
|
WIFI_FEATURE_TX_TRANSMIT_POWER = 0x400000, /* Capture Tx transmit power levels */
|
||||||
|
WIFI_FEATURE_CONTROL_ROAMING = 0x800000, /* Enable/Disable firmware roaming */
|
||||||
|
WIFI_FEATURE_IE_WHITELIST = 0x1000000, /* Support Probe IE white listing */
|
||||||
|
WIFI_FEATURE_SCAN_RAND = 0x2000000, /* Support MAC & Probe Sequence Number randomization */
|
||||||
|
WIFI_FEATURE_INVALID = 0xFFFFFFFF, /* Invalid Feature */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum wifi_logger_feature {
|
||||||
|
WIFI_LOGGER_MEMORY_DUMP_SUPPORTED = (1 << (0)), // Memory dump of FW
|
||||||
|
WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_SUPPORTED = (1 << (1)), // PKT status
|
||||||
|
WIFI_LOGGER_CONNECT_EVENT_SUPPORTED = (1 << (2)), // Connectivity event
|
||||||
|
WIFI_LOGGER_POWER_EVENT_SUPPORTED = (1 << (3)), // POWER of Driver
|
||||||
|
WIFI_LOGGER_WAKE_LOCK_SUPPORTED = (1 << (4)), // WAKE LOCK of Driver
|
||||||
|
WIFI_LOGGER_VERBOSE_SUPPORTED = (1 << (5)), // verbose log of FW
|
||||||
|
WIFI_LOGGER_WATCHDOG_TIMER_SUPPORTED = (1 << (6)), // monitor the health of FW
|
||||||
|
WIFI_LOGGER_DRIVER_DUMP_SUPPORTED = (1 << (7)), // dumps driver state
|
||||||
|
WIFI_LOGGER_PACKET_FATE_SUPPORTED = (1 << (8)), // tracks connection packets' fate
|
||||||
|
};
|
||||||
|
|
||||||
|
enum wake_stats_attributes {
|
||||||
|
WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT,
|
||||||
|
WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE,
|
||||||
|
WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT,
|
||||||
|
WAKE_STAT_ATTRIBUTE_CMD_COUNT_USED,
|
||||||
|
WAKE_STAT_ATTRIBUTE_TOTAL_DRIVER_FW,
|
||||||
|
WAKE_STAT_ATTRIBUTE_DRIVER_FW_WAKE,
|
||||||
|
WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT,
|
||||||
|
WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT_USED,
|
||||||
|
WAKE_STAT_ATTRIBUTE_TOTAL_RX_DATA_WAKE,
|
||||||
|
WAKE_STAT_ATTRIBUTE_RX_UNICAST_COUNT,
|
||||||
|
WAKE_STAT_ATTRIBUTE_RX_MULTICAST_COUNT,
|
||||||
|
WAKE_STAT_ATTRIBUTE_RX_BROADCAST_COUNT,
|
||||||
|
WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT,
|
||||||
|
WAKE_STAT_ATTRIBUTE_RX_ICMP6_PKT,
|
||||||
|
WAKE_STAT_ATTRIBUTE_RX_ICMP6_RA,
|
||||||
|
WAKE_STAT_ATTRIBUTE_RX_ICMP6_NA,
|
||||||
|
WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS,
|
||||||
|
WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT,
|
||||||
|
WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT,
|
||||||
|
WAKE_STAT_ATTRIBUTE_OTHER__RX_MULTICAST_ADD_CNT,
|
||||||
|
WAKE_STAT_ATTRIBUTE_RX_MULTICAST_PKT_INFO,
|
||||||
|
WAKE_STAT_ATTRIBUTE_AFTER_LAST,
|
||||||
|
WAKE_STAT_ATTRIBUTE_MAX = WAKE_STAT_ATTRIBUTE_AFTER_LAST - 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum vendor_nl80211_subcmd {
|
||||||
|
/* copied from wpa_supplicant brcm definations */
|
||||||
|
VENDOR_NL80211_SUBCMD_UNSPEC = 0,
|
||||||
|
VENDOR_NL80211_SUBCMD_SET_PMK = 4,
|
||||||
|
VENDOR_NL80211_SUBCMD_SET_MAC = 6,
|
||||||
|
VENDOR_NL80211_SCMD_ACS = 9,
|
||||||
|
VENDOR_NL80211_SCMD_MAX = 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum nl80211_vendor_subcmd_attributes {
|
||||||
|
WIFI_VENDOR_ATTR_DRIVER_CMD = 0,
|
||||||
|
WIFI_VENDOR_ATTR_DRIVER_KEY_PMK = 1,
|
||||||
|
WIFI_VENDOR_ATTR_DRIVER_MAC_ADDR = 3,
|
||||||
|
WIFI_VENDOR_ATTR_DRIVER_AFTER_LAST = 5,
|
||||||
|
WIFI_VENDOR_ATTR_DRIVER_MAX =
|
||||||
|
WIFI_VENDOR_ATTR_DRIVER_AFTER_LAST - 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef int wifi_ring_buffer_id;
|
||||||
|
|
||||||
|
struct wifi_ring_buffer_status {
|
||||||
|
u8 name[32];
|
||||||
|
u32 flags;
|
||||||
|
wifi_ring_buffer_id ring_id;
|
||||||
|
u32 ring_buffer_byte_size;
|
||||||
|
u32 verbose_level;
|
||||||
|
u32 written_bytes;
|
||||||
|
u32 read_bytes;
|
||||||
|
u32 written_records;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rx_data_cnt_details_t {
|
||||||
|
int rx_unicast_cnt; /*Total rx unicast packet which woke up host */
|
||||||
|
int rx_multicast_cnt; /*Total rx multicast packet which woke up host */
|
||||||
|
int rx_broadcast_cnt; /*Total rx broadcast packet which woke up host */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rx_wake_pkt_type_classification_t {
|
||||||
|
int icmp_pkt; /*wake icmp packet count */
|
||||||
|
int icmp6_pkt; /*wake icmp6 packet count */
|
||||||
|
int icmp6_ra; /*wake icmp6 RA packet count */
|
||||||
|
int icmp6_na; /*wake icmp6 NA packet count */
|
||||||
|
int icmp6_ns; /*wake icmp6 NS packet count */
|
||||||
|
//ToDo: Any more interesting classification to add?
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rx_multicast_cnt_t{
|
||||||
|
int ipv4_rx_multicast_addr_cnt; /*Rx wake packet was ipv4 multicast */
|
||||||
|
int ipv6_rx_multicast_addr_cnt; /*Rx wake packet was ipv6 multicast */
|
||||||
|
int other_rx_multicast_addr_cnt;/*Rx wake packet was non-ipv4 and non-ipv6*/
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlan_driver_wake_reason_cnt_t {
|
||||||
|
int total_cmd_event_wake; /* Total count of cmd event wakes */
|
||||||
|
int *cmd_event_wake_cnt; /* Individual wake count array, each index a reason */
|
||||||
|
int cmd_event_wake_cnt_sz; /* Max number of cmd event wake reasons */
|
||||||
|
int cmd_event_wake_cnt_used; /* Number of cmd event wake reasons specific to the driver */
|
||||||
|
|
||||||
|
int total_driver_fw_local_wake; /* Total count of drive/fw wakes, for local reasons */
|
||||||
|
int *driver_fw_local_wake_cnt; /* Individual wake count array, each index a reason */
|
||||||
|
int driver_fw_local_wake_cnt_sz; /* Max number of local driver/fw wake reasons */
|
||||||
|
int driver_fw_local_wake_cnt_used; /* Number of local driver/fw wake reasons specific to the driver */
|
||||||
|
|
||||||
|
int total_rx_data_wake; /* total data rx packets, that woke up host */
|
||||||
|
struct rx_data_cnt_details_t rx_wake_details;
|
||||||
|
struct rx_wake_pkt_type_classification_t rx_wake_pkt_classification_info;
|
||||||
|
struct rx_multicast_cnt_t rx_multicast_wake_pkt_info;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct wl_mkeep_alive_pkt {
|
||||||
|
u16 version; /* Version for mkeep_alive */
|
||||||
|
u16 length; /* length of fixed parameters in the structure */
|
||||||
|
u32 period_msec; /* high bit on means immediate send */
|
||||||
|
u16 len_bytes;
|
||||||
|
u8 keep_alive_id; /* 0 - 3 for N = 4 */
|
||||||
|
u8 data[1];
|
||||||
|
} wl_mkeep_alive_pkt_t;
|
||||||
|
|
||||||
|
#endif /* _AIC_VENDOR_H */
|
||||||
|
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
#include "rwnx_main.h"
|
||||||
|
#include "rwnx_msg_tx.h"
|
||||||
|
#include "reg_access.h"
|
||||||
|
|
||||||
|
#define FW_USERCONFIG_NAME_8800D80 "aic_userconfig_8800d80.txt"
|
||||||
|
#define FW_POWERLIMIT_NAME_8800D80 "aic_powerlimit_8800d80.txt"
|
||||||
|
|
||||||
|
extern char aic_fw_path[200];
|
||||||
|
|
||||||
|
int rwnx_request_firmware_common(struct rwnx_hw *rwnx_hw,
|
||||||
|
u32** buffer, const char *filename);
|
||||||
|
void rwnx_plat_userconfig_parsing(char *buffer, int size);
|
||||||
|
void rwnx_release_firmware_common(u32** buffer);
|
||||||
|
|
||||||
|
|
||||||
|
int aicwf_set_rf_config_8800d80(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *cfm)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if ((ret = rwnx_send_txpwr_lvl_v3_req(rwnx_hw))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ((ret = rwnx_send_txpwr_lvl_adj_req(rwnx_hw))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ((ret = rwnx_send_txpwr_ofst2x_req(rwnx_hw))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ((ret = rwnx_send_rf_calib_req(rwnx_hw, cfm))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int rwnx_plat_userconfig_load_8800d80(struct rwnx_hw *rwnx_hw){
|
||||||
|
int size;
|
||||||
|
u32 *dst=NULL;
|
||||||
|
char *filename = FW_USERCONFIG_NAME_8800D80;
|
||||||
|
|
||||||
|
#ifndef ANDROID_PLATFORM
|
||||||
|
sprintf(aic_fw_path, "%s/%s", aic_fw_path, "aic8800D80");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
AICWFDBG(LOGINFO, "userconfig file path:%s \r\n", filename);
|
||||||
|
|
||||||
|
/* load file */
|
||||||
|
size = rwnx_request_firmware_common(rwnx_hw, &dst, filename);
|
||||||
|
if (size <= 0) {
|
||||||
|
AICWFDBG(LOGERROR, "wrong size of firmware file\n");
|
||||||
|
dst = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the file on the Embedded side */
|
||||||
|
AICWFDBG(LOGINFO, "### Load file done: %s, size=%d\n", filename, size);
|
||||||
|
|
||||||
|
rwnx_plat_userconfig_parsing((char *)dst, size);
|
||||||
|
|
||||||
|
rwnx_release_firmware_common(&dst);
|
||||||
|
|
||||||
|
AICWFDBG(LOGINFO, "userconfig download complete\n\n");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_POWER_LIMIT
|
||||||
|
extern char default_ccode[];
|
||||||
|
int rwnx_plat_powerlimit_load_8800d80(struct rwnx_hw *rwnx_hw)
|
||||||
|
{
|
||||||
|
int size;
|
||||||
|
u32 *dst=NULL;
|
||||||
|
char *filename = FW_POWERLIMIT_NAME_8800D80;
|
||||||
|
|
||||||
|
AICWFDBG(LOGINFO, "powerlimit file path:%s \r\n", filename);
|
||||||
|
|
||||||
|
/* load file */
|
||||||
|
size = rwnx_request_firmware_common(rwnx_hw, &dst, filename);
|
||||||
|
if (size <= 0) {
|
||||||
|
AICWFDBG(LOGERROR, "wrong size of cfg file\n");
|
||||||
|
dst = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AICWFDBG(LOGINFO, "### Load file done: %s, size=%d\n", filename, size);
|
||||||
|
|
||||||
|
/* parsing the file */
|
||||||
|
rwnx_plat_powerlimit_parsing((char *)dst, size, default_ccode);
|
||||||
|
|
||||||
|
rwnx_release_firmware_common(&dst);
|
||||||
|
|
||||||
|
AICWFDBG(LOGINFO, "powerlimit download complete\n\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
int rwnx_plat_userconfig_load_8800d80(struct rwnx_hw *rwnx_hw);
|
||||||
|
#ifdef CONFIG_POWER_LIMIT
|
||||||
|
int rwnx_plat_powerlimit_load_8800d80(struct rwnx_hw *rwnx_hw);
|
||||||
|
#endif
|
||||||
|
int aicwf_set_rf_config_8800d80(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *cfm);
|
||||||
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,50 @@
|
|||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_DPD
|
||||||
|
typedef struct {
|
||||||
|
uint32_t bit_mask[3];
|
||||||
|
uint32_t reserved;
|
||||||
|
uint32_t dpd_high[96];
|
||||||
|
uint32_t dpd_11b[96];
|
||||||
|
uint32_t dpd_low[96];
|
||||||
|
uint32_t idac_11b[48];
|
||||||
|
uint32_t idac_high[48];
|
||||||
|
uint32_t idac_low[48];
|
||||||
|
uint32_t loft_res[18];
|
||||||
|
uint32_t rx_iqim_res[16];
|
||||||
|
} rf_misc_ram_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t bit_mask[4];
|
||||||
|
uint32_t dpd_high[96];
|
||||||
|
uint32_t loft_res[18];
|
||||||
|
} rf_misc_ram_lite_t;
|
||||||
|
|
||||||
|
#define MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
|
||||||
|
#define DPD_RESULT_SIZE_8800DC sizeof(rf_misc_ram_lite_t)
|
||||||
|
|
||||||
|
extern rf_misc_ram_lite_t dpd_res;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int aicwf_patch_table_load(struct rwnx_hw *rwnx_hw, char *filename);
|
||||||
|
void aicwf_patch_config_8800dc(struct rwnx_hw *rwnx_hw);
|
||||||
|
int aicwf_set_rf_config_8800dc(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *cfm);
|
||||||
|
int aicwf_misc_ram_init_8800dc(struct rwnx_hw *rwnx_hw);
|
||||||
|
#ifdef CONFIG_DPD
|
||||||
|
int aicwf_misc_ram_valid_check_8800dc(struct rwnx_hw *rwnx_hw, int *valid_out);
|
||||||
|
int aicwf_plat_calib_load_8800dc(struct rwnx_hw *rwnx_hw);
|
||||||
|
int aicwf_dpd_calib_8800dc(struct rwnx_hw *rwnx_hw, rf_misc_ram_lite_t *dpd_res);
|
||||||
|
int aicwf_dpd_result_apply_8800dc(struct rwnx_hw *rwnx_hw, rf_misc_ram_lite_t *dpd_res);
|
||||||
|
#ifndef CONFIG_FORCE_DPD_CALIB
|
||||||
|
int aicwf_dpd_result_load_8800dc(struct rwnx_hw *rwnx_hw, rf_misc_ram_lite_t *dpd_res);
|
||||||
|
int aicwf_dpd_result_write_8800dc(void *buf, int buf_len);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
int aicwf_plat_patch_load_8800dc(struct rwnx_hw *rwnx_hw);
|
||||||
|
int aicwf_plat_rftest_load_8800dc(struct rwnx_hw *rwnx_hw);
|
||||||
|
int rwnx_plat_userconfig_load_8800dc(struct rwnx_hw *rwnx_hw);
|
||||||
|
int rwnx_plat_userconfig_load_8800dw(struct rwnx_hw *rwnx_hw);
|
||||||
|
#ifdef CONFIG_POWER_LIMIT
|
||||||
|
int rwnx_plat_powerlimit_load_8800dcdw(struct rwnx_hw *rwnx_hw, uint16_t chip_id);
|
||||||
|
#endif
|
||||||
|
void system_config_8800dc(struct rwnx_hw *rwnx_hw);
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#define RWNX_FN_ENTRY_STR ">>> %s()\n", __func__
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* message levels */
|
||||||
|
#define LOGERROR 0x0001
|
||||||
|
#define LOGINFO 0x0002
|
||||||
|
#define LOGTRACE 0x0004
|
||||||
|
#define LOGDEBUG 0x0008
|
||||||
|
#define LOGDATA 0x0010
|
||||||
|
|
||||||
|
extern int aicwf_dbg_level;
|
||||||
|
void rwnx_data_dump(char* tag, void* data, unsigned long len);
|
||||||
|
|
||||||
|
#define AICWF_LOG "AICWFDBG("
|
||||||
|
|
||||||
|
#define AICWFDBG(level, args, arg...) \
|
||||||
|
do { \
|
||||||
|
if (aicwf_dbg_level & level) { \
|
||||||
|
printk(AICWF_LOG#level")\t" args, ##arg); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define RWNX_DBG(fmt, ...) \
|
||||||
|
do { \
|
||||||
|
if (aicwf_dbg_level & LOGTRACE) { \
|
||||||
|
printk(AICWF_LOG"LOGTRACE)\t"fmt , ##__VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#define RWNX_DBG(fmt, ...) \
|
||||||
|
do { \
|
||||||
|
if (aicwf_dbg_level & LOGTRACE) { \
|
||||||
|
printk(AICWF_LOG"LOGTRACE"")\t" fmt, ##__VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define AICWFDBG(args, level) \
|
||||||
|
do { \
|
||||||
|
if (aicwf_dbg_level & level) { \
|
||||||
|
printk(AICWF_LOG"(%s)\t" ,#level); \
|
||||||
|
printf args; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
#ifndef _AICWF_RX_PREALLOC_H_
|
||||||
|
#define _AICWF_RX_PREALLOC_H_
|
||||||
|
|
||||||
|
#ifdef CONFIG_PREALLOC_RX_SKB
|
||||||
|
|
||||||
|
struct rx_buff {
|
||||||
|
struct list_head queue;
|
||||||
|
unsigned char *data;
|
||||||
|
u32 len;
|
||||||
|
uint8_t *start;
|
||||||
|
uint8_t *end;
|
||||||
|
uint8_t *read;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct aicwf_rx_buff_list {
|
||||||
|
struct list_head rxbuff_list;
|
||||||
|
atomic_t rxbuff_list_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct rx_buff *aicwf_prealloc_rxbuff_alloc(spinlock_t *lock);
|
||||||
|
extern void aicwf_prealloc_rxbuff_free(struct rx_buff *rxbuff, spinlock_t *lock);
|
||||||
|
extern int aicwf_prealloc_init(void);
|
||||||
|
extern void aicwf_prealloc_exit(void);
|
||||||
|
extern int aicwf_rxbuff_size_get(void);
|
||||||
|
#endif
|
||||||
|
#endif /* _AICWF_RX_PREALLOC_H_ */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,99 @@
|
|||||||
|
/**
|
||||||
|
* aicwf_sdio.h
|
||||||
|
*
|
||||||
|
* SDIO function declarations
|
||||||
|
*
|
||||||
|
* Copyright (C) AICSemi 2018-2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _AICWF_SDMMC_H_
|
||||||
|
#define _AICWF_SDMMC_H_
|
||||||
|
|
||||||
|
#ifdef AICWF_SDIO_SUPPORT
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/if_ether.h>
|
||||||
|
#include <linux/ieee80211.h>
|
||||||
|
#include <linux/semaphore.h>
|
||||||
|
#include "rwnx_cmds.h"
|
||||||
|
#define AICWF_SDIO_NAME "aicwf_sdio"
|
||||||
|
#define SDIOWIFI_FUNC_BLOCKSIZE 512
|
||||||
|
|
||||||
|
#define SDIO_VENDOR_ID_AIC 0x8800
|
||||||
|
#define SDIO_DEVICE_ID_AIC 0x0001
|
||||||
|
#define SDIOWIFI_BYTEMODE_LEN_REG 0x02
|
||||||
|
#define SDIOWIFI_INTR_CONFIG_REG 0x04
|
||||||
|
#define SDIOWIFI_SLEEP_REG 0x05
|
||||||
|
#define SDIOWIFI_WAKEUP_REG 0x09
|
||||||
|
#define SDIOWIFI_FLOW_CTRL_REG 0x0A
|
||||||
|
#define SDIOWIFI_REGISTER_BLOCK 0x0B
|
||||||
|
#define SDIOWIFI_BYTEMODE_ENABLE_REG 0x11
|
||||||
|
#define SDIOWIFI_BLOCK_CNT_REG 0x12
|
||||||
|
#define SDIOWIFI_FLOWCTRL_MASK_REG 0x7F
|
||||||
|
|
||||||
|
#define SDIOWIFI_PWR_CTRL_INTERVAL 30
|
||||||
|
#define FLOW_CTRL_RETRY_COUNT 50
|
||||||
|
#define BUFFER_SIZE 1536
|
||||||
|
#define TAIL_LEN 4
|
||||||
|
#define TXQLEN (2048*4)
|
||||||
|
|
||||||
|
#define SDIO_SLEEP_ST 0
|
||||||
|
#define SDIO_ACTIVE_ST 1
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SDIO_TYPE_DATA = 0X00,
|
||||||
|
SDIO_TYPE_CFG = 0X10,
|
||||||
|
SDIO_TYPE_CFG_CMD_RSP = 0X11,
|
||||||
|
SDIO_TYPE_CFG_DATA_CFM = 0X12
|
||||||
|
} sdio_type;
|
||||||
|
|
||||||
|
struct rwnx_hw;
|
||||||
|
|
||||||
|
|
||||||
|
struct aic_sdio_dev {
|
||||||
|
struct rwnx_hw *rwnx_hw;
|
||||||
|
struct sdio_func *func;
|
||||||
|
struct device *dev;
|
||||||
|
struct aicwf_bus *bus_if;
|
||||||
|
struct rwnx_cmd_mgr cmd_mgr;
|
||||||
|
|
||||||
|
struct aicwf_rx_priv *rx_priv;
|
||||||
|
struct aicwf_tx_priv *tx_priv;
|
||||||
|
u32 state;
|
||||||
|
|
||||||
|
//for sdio pwr ctrl
|
||||||
|
struct timer_list timer;
|
||||||
|
uint active_duration;
|
||||||
|
struct completion pwrctrl_trgg;
|
||||||
|
struct task_struct *pwrctl_tsk;
|
||||||
|
spinlock_t pwrctl_lock;
|
||||||
|
struct semaphore pwrctl_wakeup_sema;
|
||||||
|
};
|
||||||
|
int aicwf_sdio_writeb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 val);
|
||||||
|
void aicwf_sdio_hal_irqhandler(struct sdio_func *func);
|
||||||
|
void aicwf_sdio_pwrctl_timer(struct aic_sdio_dev *sdiodev, uint duration);
|
||||||
|
int aicwf_sdio_pwr_stctl(struct aic_sdio_dev *sdiodev, uint target);
|
||||||
|
int aicwf_sdio_func_init(struct aic_sdio_dev *sdiodev);
|
||||||
|
void aicwf_sdio_func_deinit(struct aic_sdio_dev *sdiodev);
|
||||||
|
int aicwf_sdio_flow_ctrl(struct aic_sdio_dev *sdiodev);
|
||||||
|
int aicwf_sdio_recv_pkt(struct aic_sdio_dev *sdiodev, struct sk_buff *skbbuf, u32 size);
|
||||||
|
int aicwf_sdio_send_pkt(struct aic_sdio_dev *sdiodev, u8 *buf, uint count);
|
||||||
|
void *aicwf_sdio_bus_init(struct aic_sdio_dev *sdiodev);
|
||||||
|
void aicwf_sdio_release(struct aic_sdio_dev *sdiodev);
|
||||||
|
void aicwf_sdio_exit(void);
|
||||||
|
void aicwf_sdio_register(void);
|
||||||
|
int aicwf_sdio_txpkt(struct aic_sdio_dev *sdiodev, struct sk_buff *pkt);
|
||||||
|
int sdio_bustx_thread(void *data);
|
||||||
|
int sdio_busrx_thread(void *data);
|
||||||
|
int aicwf_sdio_aggr(struct aicwf_tx_priv *tx_priv, struct sk_buff *pkt);
|
||||||
|
int aicwf_sdio_send(struct aicwf_tx_priv *tx_priv);
|
||||||
|
void aicwf_sdio_aggr_send(struct aicwf_tx_priv *tx_priv);
|
||||||
|
void aicwf_sdio_aggrbuf_reset(struct aicwf_tx_priv* tx_priv);
|
||||||
|
extern void aicwf_hostif_ready(void);
|
||||||
|
#ifdef CONFIG_PLATFORM_NANOPI
|
||||||
|
extern void extern_wifi_set_enable(int is_on);
|
||||||
|
extern void sdio_reinit(void);
|
||||||
|
#endif /*CONFIG_PLATFORM_NANOPI*/
|
||||||
|
|
||||||
|
#endif /* AICWF_SDIO_SUPPORT */
|
||||||
|
|
||||||
|
#endif /*_AICWF_SDMMC_H_*/
|
||||||
@@ -0,0 +1,633 @@
|
|||||||
|
#include"aicwf_tcp_ack.h"
|
||||||
|
//#include"rwnx_tx.h"
|
||||||
|
//#include "aicwf_tcp_ack.h"
|
||||||
|
#include"rwnx_defs.h"
|
||||||
|
extern int intf_tx(struct rwnx_hw *priv,struct msg_buf *msg);
|
||||||
|
struct msg_buf *intf_tcp_alloc_msg(struct msg_buf *msg)
|
||||||
|
{
|
||||||
|
//printk("%s \n",__func__);
|
||||||
|
int len=sizeof(struct msg_buf) ;
|
||||||
|
msg = kzalloc(len , GFP_ATOMIC);
|
||||||
|
if(!msg)
|
||||||
|
printk("%s: alloc failed \n", __func__);
|
||||||
|
memset(msg,0,len);
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void intf_tcp_drop_msg(struct rwnx_hw *priv,
|
||||||
|
struct msg_buf *msg)
|
||||||
|
{
|
||||||
|
//printk("%s \n",__func__);
|
||||||
|
if (msg->skb)
|
||||||
|
dev_kfree_skb_any(msg->skb);
|
||||||
|
|
||||||
|
kfree(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
|
||||||
|
void tcp_ack_timeout(unsigned long data)
|
||||||
|
#else
|
||||||
|
void tcp_ack_timeout(struct timer_list *t)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
//printk("%s \n",__func__);
|
||||||
|
struct tcp_ack_info *ack_info;
|
||||||
|
struct msg_buf *msg;
|
||||||
|
struct tcp_ack_manage *ack_m = NULL;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
|
||||||
|
ack_info = (struct tcp_ack_info *)data;
|
||||||
|
#else
|
||||||
|
ack_info = container_of(t,struct tcp_ack_info,timer);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ack_m = container_of(ack_info, struct tcp_ack_manage,
|
||||||
|
ack_info[ack_info->ack_info_num]);
|
||||||
|
|
||||||
|
write_seqlock_bh(&ack_info->seqlock);
|
||||||
|
msg = ack_info->msgbuf;
|
||||||
|
if (ack_info->busy && msg && !ack_info->in_send_msg) {
|
||||||
|
ack_info->msgbuf = NULL;
|
||||||
|
ack_info->drop_cnt = 0;
|
||||||
|
ack_info->in_send_msg = msg;
|
||||||
|
write_sequnlock_bh(&ack_info->seqlock);
|
||||||
|
intf_tx(ack_m->priv, msg);//send skb
|
||||||
|
//ack_info->in_send_msg = NULL;//add by dwx
|
||||||
|
//write_sequnlock_bh(&ack_info->seqlock);
|
||||||
|
//intf_tx(ack_m->priv, msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
write_sequnlock_bh(&ack_info->seqlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tcp_ack_init(struct rwnx_hw *priv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct tcp_ack_info *ack_info;
|
||||||
|
struct tcp_ack_manage *ack_m = &priv->ack_m;
|
||||||
|
|
||||||
|
printk("========== tcp ack debug %s \n",__func__);
|
||||||
|
memset(ack_m, 0, sizeof(struct tcp_ack_manage));
|
||||||
|
ack_m->priv = priv;
|
||||||
|
spin_lock_init(&ack_m->lock);
|
||||||
|
atomic_set(&ack_m->max_drop_cnt, TCP_ACK_DROP_CNT);
|
||||||
|
ack_m->last_time = jiffies;
|
||||||
|
ack_m->timeout = msecs_to_jiffies(ACK_OLD_TIME);
|
||||||
|
|
||||||
|
for (i = 0; i < TCP_ACK_NUM; i++) {
|
||||||
|
ack_info = &ack_m->ack_info[i];
|
||||||
|
ack_info->ack_info_num = i;
|
||||||
|
seqlock_init(&ack_info->seqlock);
|
||||||
|
ack_info->last_time = jiffies;
|
||||||
|
ack_info->timeout = msecs_to_jiffies(ACK_OLD_TIME);
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
|
||||||
|
setup_timer(&ack_info->timer, tcp_ack_timeout,
|
||||||
|
(unsigned long)ack_info);
|
||||||
|
#else
|
||||||
|
timer_setup(&ack_info->timer,tcp_ack_timeout,0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic_set(&ack_m->enable, 1);
|
||||||
|
ack_m->ack_winsize = MIN_WIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tcp_ack_deinit(struct rwnx_hw *priv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct tcp_ack_manage *ack_m = &priv->ack_m;
|
||||||
|
struct msg_buf *drop_msg = NULL;
|
||||||
|
|
||||||
|
printk("%s \n",__func__);
|
||||||
|
atomic_set(&ack_m->enable, 0);
|
||||||
|
|
||||||
|
for (i = 0; i < TCP_ACK_NUM; i++) {
|
||||||
|
drop_msg = NULL;
|
||||||
|
|
||||||
|
write_seqlock_bh(&ack_m->ack_info[i].seqlock);
|
||||||
|
del_timer(&ack_m->ack_info[i].timer);
|
||||||
|
drop_msg = ack_m->ack_info[i].msgbuf;
|
||||||
|
ack_m->ack_info[i].msgbuf = NULL;
|
||||||
|
write_sequnlock_bh(&ack_m->ack_info[i].seqlock);
|
||||||
|
|
||||||
|
if (drop_msg)
|
||||||
|
intf_tcp_drop_msg(priv, drop_msg);//drop skb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int tcp_check_quick_ack(unsigned char *buf,
|
||||||
|
struct tcp_ack_msg *msg)
|
||||||
|
{
|
||||||
|
int ip_hdr_len;
|
||||||
|
unsigned char *temp;
|
||||||
|
struct ethhdr *ethhdr;
|
||||||
|
struct iphdr *iphdr;
|
||||||
|
struct tcphdr *tcphdr;
|
||||||
|
|
||||||
|
ethhdr = (struct ethhdr *)buf;
|
||||||
|
if (ethhdr->h_proto != htons(ETH_P_IP))
|
||||||
|
return 0;
|
||||||
|
iphdr = (struct iphdr *)(ethhdr + 1);
|
||||||
|
if (iphdr->version != 4 || iphdr->protocol != IPPROTO_TCP)
|
||||||
|
return 0;
|
||||||
|
ip_hdr_len = iphdr->ihl * 4;
|
||||||
|
temp = (unsigned char *)(iphdr) + ip_hdr_len;
|
||||||
|
tcphdr = (struct tcphdr *)temp;
|
||||||
|
/* TCP_FLAG_ACK */
|
||||||
|
if (!(temp[13] & 0x10))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (temp[13] & 0x8) {
|
||||||
|
msg->saddr = iphdr->daddr;
|
||||||
|
msg->daddr = iphdr->saddr;
|
||||||
|
msg->source = tcphdr->dest;
|
||||||
|
msg->dest = tcphdr->source;
|
||||||
|
msg->seq = ntohl(tcphdr->seq);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_drop_tcp_ack(struct tcphdr *tcphdr, int tcp_tot_len,
|
||||||
|
unsigned short *win_scale)
|
||||||
|
{
|
||||||
|
//printk("%s \n",__func__);
|
||||||
|
int drop = 1;
|
||||||
|
int len = tcphdr->doff * 4;
|
||||||
|
unsigned char *ptr;
|
||||||
|
|
||||||
|
if(tcp_tot_len > len) {
|
||||||
|
drop = 0;
|
||||||
|
} else {
|
||||||
|
len -= sizeof(struct tcphdr);
|
||||||
|
ptr = (unsigned char *)(tcphdr + 1);
|
||||||
|
|
||||||
|
while ((len > 0) && drop) {
|
||||||
|
int opcode = *ptr++;
|
||||||
|
int opsize;
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case TCPOPT_EOL:
|
||||||
|
break;
|
||||||
|
case TCPOPT_NOP:
|
||||||
|
len--;
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
opsize = *ptr++;
|
||||||
|
if (opsize < 2)
|
||||||
|
break;
|
||||||
|
if (opsize > len)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
/* TODO: Add other ignore opt */
|
||||||
|
case TCPOPT_TIMESTAMP:
|
||||||
|
break;
|
||||||
|
case TCPOPT_WINDOW:
|
||||||
|
if (*ptr < 15)
|
||||||
|
*win_scale = (1 << (*ptr));
|
||||||
|
printk("%d\n",*win_scale);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
drop = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr += opsize - 2;
|
||||||
|
len -= opsize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* flag:0 for not tcp ack
|
||||||
|
* 1 for ack which can be drop
|
||||||
|
* 2 for other ack whith more info
|
||||||
|
*/
|
||||||
|
|
||||||
|
int tcp_check_ack(unsigned char *buf,
|
||||||
|
struct tcp_ack_msg *msg,
|
||||||
|
unsigned short *win_scale)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int ip_hdr_len;
|
||||||
|
int tcp_tot_len;
|
||||||
|
unsigned char *temp;
|
||||||
|
struct ethhdr *ethhdr;
|
||||||
|
struct iphdr *iphdr;
|
||||||
|
struct tcphdr *tcphdr;
|
||||||
|
|
||||||
|
ethhdr =(struct ethhdr *)buf;
|
||||||
|
if (ethhdr->h_proto != htons(ETH_P_IP))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
iphdr = (struct iphdr *)(ethhdr + 1);
|
||||||
|
if (iphdr->version != 4 || iphdr->protocol != IPPROTO_TCP)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ip_hdr_len = iphdr->ihl * 4;
|
||||||
|
temp = (unsigned char *)(iphdr) + ip_hdr_len;
|
||||||
|
tcphdr = (struct tcphdr *)temp;
|
||||||
|
/* TCP_FLAG_ACK */
|
||||||
|
if (!(temp[13] & 0x10))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
tcp_tot_len = ntohs(iphdr->tot_len) - ip_hdr_len;// tcp total len
|
||||||
|
ret = is_drop_tcp_ack(tcphdr, tcp_tot_len, win_scale);
|
||||||
|
//printk("is drop:%d \n",ret);
|
||||||
|
|
||||||
|
if (ret > 0) {
|
||||||
|
msg->saddr = iphdr->saddr;
|
||||||
|
msg->daddr = iphdr->daddr;
|
||||||
|
msg->source = tcphdr->source;
|
||||||
|
msg->dest = tcphdr->dest;
|
||||||
|
msg->seq = ntohl(tcphdr->ack_seq);
|
||||||
|
msg->win = ntohs(tcphdr->window);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return val: -1 for not match, others for match */
|
||||||
|
int tcp_ack_match(struct tcp_ack_manage *ack_m,
|
||||||
|
struct tcp_ack_msg *ack_msg)
|
||||||
|
{
|
||||||
|
int i, ret = -1;
|
||||||
|
unsigned start;
|
||||||
|
struct tcp_ack_info *ack_info;
|
||||||
|
struct tcp_ack_msg *ack;
|
||||||
|
|
||||||
|
for (i = 0; ((ret < 0) && (i < TCP_ACK_NUM)); i++) {
|
||||||
|
ack_info = &ack_m->ack_info[i];
|
||||||
|
do {
|
||||||
|
start = read_seqbegin(&ack_info->seqlock);
|
||||||
|
ret = -1;
|
||||||
|
|
||||||
|
ack = &ack_info->ack_msg;
|
||||||
|
if (ack_info->busy &&
|
||||||
|
ack->dest == ack_msg->dest &&
|
||||||
|
ack->source == ack_msg->source &&
|
||||||
|
ack->saddr == ack_msg->saddr &&
|
||||||
|
ack->daddr == ack_msg->daddr)
|
||||||
|
ret = i;
|
||||||
|
} while(read_seqretry(&ack_info->seqlock, start));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void tcp_ack_update(struct tcp_ack_manage *ack_m)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct tcp_ack_info *ack_info;
|
||||||
|
|
||||||
|
if (time_after(jiffies, ack_m->last_time + ack_m->timeout)) {
|
||||||
|
spin_lock_bh(&ack_m->lock);
|
||||||
|
ack_m->last_time = jiffies;
|
||||||
|
for (i = TCP_ACK_NUM - 1; i >= 0; i--) {
|
||||||
|
ack_info = &ack_m->ack_info[i];
|
||||||
|
write_seqlock_bh(&ack_info->seqlock);
|
||||||
|
if (ack_info->busy &&
|
||||||
|
time_after(jiffies, ack_info->last_time +
|
||||||
|
ack_info->timeout)) {
|
||||||
|
ack_m->free_index = i;
|
||||||
|
ack_m->max_num--;
|
||||||
|
ack_info->busy = 0;
|
||||||
|
}
|
||||||
|
write_sequnlock_bh(&ack_info->seqlock);
|
||||||
|
}
|
||||||
|
spin_unlock_bh(&ack_m->lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return val: -1 for no index, others for index */
|
||||||
|
int tcp_ack_alloc_index(struct tcp_ack_manage *ack_m)
|
||||||
|
{
|
||||||
|
int i, ret = -1;
|
||||||
|
struct tcp_ack_info *ack_info;
|
||||||
|
unsigned start;
|
||||||
|
|
||||||
|
spin_lock_bh(&ack_m->lock);
|
||||||
|
if (ack_m->max_num == TCP_ACK_NUM) {
|
||||||
|
spin_unlock_bh(&ack_m->lock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ack_m->free_index >= 0) {
|
||||||
|
i = ack_m->free_index;
|
||||||
|
ack_m->free_index = -1;
|
||||||
|
ack_m->max_num++;
|
||||||
|
spin_unlock_bh(&ack_m->lock);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; ((ret < 0) && (i < TCP_ACK_NUM)); i++) {
|
||||||
|
ack_info = &ack_m->ack_info[i];
|
||||||
|
do {
|
||||||
|
start = read_seqbegin(&ack_info->seqlock);
|
||||||
|
ret = -1;
|
||||||
|
if (!ack_info->busy) {
|
||||||
|
ack_m->free_index = -1;
|
||||||
|
ack_m->max_num++;
|
||||||
|
ret = i;
|
||||||
|
}
|
||||||
|
} while(read_seqretry(&ack_info->seqlock, start));
|
||||||
|
}
|
||||||
|
spin_unlock_bh(&ack_m->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* return val: 0 for not handle tx, 1 for handle tx */
|
||||||
|
int tcp_ack_handle(struct msg_buf *new_msgbuf,
|
||||||
|
struct tcp_ack_manage *ack_m,
|
||||||
|
struct tcp_ack_info *ack_info,
|
||||||
|
struct tcp_ack_msg *ack_msg,
|
||||||
|
int type)
|
||||||
|
{
|
||||||
|
int quick_ack = 0;
|
||||||
|
struct tcp_ack_msg *ack;
|
||||||
|
int ret = 0;
|
||||||
|
struct msg_buf *drop_msg = NULL;
|
||||||
|
|
||||||
|
//printk("%s %d",__func__,type);
|
||||||
|
write_seqlock_bh(&ack_info->seqlock);
|
||||||
|
|
||||||
|
ack_info->last_time = jiffies;
|
||||||
|
ack = &ack_info->ack_msg;
|
||||||
|
|
||||||
|
if (type == 2) {
|
||||||
|
if (U32_BEFORE(ack->seq, ack_msg->seq)) {
|
||||||
|
ack->seq = ack_msg->seq;
|
||||||
|
if (ack_info->psh_flag &&
|
||||||
|
!U32_BEFORE(ack_msg->seq,
|
||||||
|
ack_info->psh_seq)) {
|
||||||
|
ack_info->psh_flag = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ack_info->msgbuf) {
|
||||||
|
//printk("%lx \n",ack_info->msgbuf);
|
||||||
|
drop_msg = ack_info->msgbuf;
|
||||||
|
ack_info->msgbuf = NULL;
|
||||||
|
del_timer(&ack_info->timer);
|
||||||
|
}else{
|
||||||
|
//printk("msgbuf is NULL \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
ack_info->in_send_msg = NULL;
|
||||||
|
ack_info->drop_cnt = atomic_read(&ack_m->max_drop_cnt);
|
||||||
|
} else {
|
||||||
|
printk("%s before abnormal ack: %d, %d\n",
|
||||||
|
__func__, ack->seq, ack_msg->seq);
|
||||||
|
drop_msg = new_msgbuf;
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
} else if (U32_BEFORE(ack->seq, ack_msg->seq)) {
|
||||||
|
if (ack_info->msgbuf) {
|
||||||
|
drop_msg = ack_info->msgbuf;
|
||||||
|
ack_info->msgbuf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ack_info->psh_flag &&
|
||||||
|
!U32_BEFORE(ack_msg->seq, ack_info->psh_seq)) {
|
||||||
|
ack_info->psh_flag = 0;
|
||||||
|
quick_ack = 1;
|
||||||
|
} else {
|
||||||
|
ack_info->drop_cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ack->seq = ack_msg->seq;
|
||||||
|
|
||||||
|
if (quick_ack || (!ack_info->in_send_msg &&
|
||||||
|
(ack_info->drop_cnt >=
|
||||||
|
atomic_read(&ack_m->max_drop_cnt)))) {
|
||||||
|
ack_info->drop_cnt = 0;
|
||||||
|
ack_info->in_send_msg = new_msgbuf;
|
||||||
|
del_timer(&ack_info->timer);
|
||||||
|
} else {
|
||||||
|
ret = 1;
|
||||||
|
ack_info->msgbuf = new_msgbuf;
|
||||||
|
if (!timer_pending(&ack_info->timer))
|
||||||
|
mod_timer(&ack_info->timer,
|
||||||
|
(jiffies + msecs_to_jiffies(5)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printk("%s before ack: %d, %d\n",
|
||||||
|
__func__, ack->seq, ack_msg->seq);
|
||||||
|
drop_msg = new_msgbuf;
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_sequnlock_bh(&ack_info->seqlock);
|
||||||
|
|
||||||
|
if (drop_msg)
|
||||||
|
intf_tcp_drop_msg(ack_m->priv, drop_msg);// drop skb
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tcp_ack_handle_new(struct msg_buf *new_msgbuf,
|
||||||
|
struct tcp_ack_manage *ack_m,
|
||||||
|
struct tcp_ack_info *ack_info,
|
||||||
|
struct tcp_ack_msg *ack_msg,
|
||||||
|
int type)
|
||||||
|
{
|
||||||
|
int quick_ack = 0;
|
||||||
|
struct tcp_ack_msg *ack;
|
||||||
|
int ret = 0;
|
||||||
|
struct msg_buf *drop_msg = NULL;
|
||||||
|
struct msg_buf * send_msg = NULL;
|
||||||
|
//printk("",);
|
||||||
|
write_seqlock_bh(&ack_info->seqlock);
|
||||||
|
|
||||||
|
ack_info->last_time = jiffies;
|
||||||
|
ack = &ack_info->ack_msg;
|
||||||
|
|
||||||
|
if(U32_BEFORE(ack->seq, ack_msg->seq)){
|
||||||
|
if (ack_info->msgbuf) {
|
||||||
|
drop_msg = ack_info->msgbuf;
|
||||||
|
ack_info->msgbuf = NULL;
|
||||||
|
//ack_info->drop_cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ack_info->psh_flag &&
|
||||||
|
!U32_BEFORE(ack_msg->seq, ack_info->psh_seq)) {
|
||||||
|
ack_info->psh_flag = 0;
|
||||||
|
quick_ack = 1;
|
||||||
|
} else {
|
||||||
|
ack_info->drop_cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ack->seq = ack_msg->seq;
|
||||||
|
|
||||||
|
if(quick_ack || (!ack_info->in_send_msg &&
|
||||||
|
(ack_info->drop_cnt >=
|
||||||
|
atomic_read(&ack_m->max_drop_cnt)))){
|
||||||
|
ack_info->drop_cnt = 0;
|
||||||
|
send_msg = new_msgbuf;
|
||||||
|
ack_info->in_send_msg = send_msg;
|
||||||
|
del_timer(&ack_info->timer);
|
||||||
|
}else{
|
||||||
|
ret = 1;
|
||||||
|
ack_info->msgbuf = new_msgbuf;
|
||||||
|
if (!timer_pending(&ack_info->timer))
|
||||||
|
mod_timer(&ack_info->timer,
|
||||||
|
(jiffies + msecs_to_jiffies(5)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//ret = 1;
|
||||||
|
}else {
|
||||||
|
printk("%s before ack: %d, %d\n",
|
||||||
|
__func__, ack->seq, ack_msg->seq);
|
||||||
|
drop_msg = new_msgbuf;
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if(send_msg){
|
||||||
|
intf_tx(ack_m->priv,send_msg);
|
||||||
|
ack_info->in_send_msg=NULL;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
//ack_info->in_send_msg=NULL;
|
||||||
|
|
||||||
|
write_sequnlock_bh(&ack_info->seqlock);
|
||||||
|
|
||||||
|
/*if(send_msg){
|
||||||
|
intf_tx(ack_m->priv,send_msg);
|
||||||
|
//ack_info->in_send_msg=NULL;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if (drop_msg)
|
||||||
|
intf_tcp_drop_msg(ack_m->priv, drop_msg);// drop skb
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter_rx_tcp_ack(struct rwnx_hw *priv,
|
||||||
|
unsigned char *buf, unsigned plen)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
struct tcp_ack_msg ack_msg;
|
||||||
|
struct tcp_ack_info *ack_info;
|
||||||
|
struct tcp_ack_manage *ack_m = &priv->ack_m;
|
||||||
|
|
||||||
|
if (!atomic_read(&ack_m->enable))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((plen > MAX_TCP_ACK) ||
|
||||||
|
!tcp_check_quick_ack(buf, &ack_msg))
|
||||||
|
return;
|
||||||
|
|
||||||
|
index = tcp_ack_match(ack_m, &ack_msg);
|
||||||
|
if (index >= 0) {
|
||||||
|
ack_info = ack_m->ack_info + index;
|
||||||
|
write_seqlock_bh(&ack_info->seqlock);
|
||||||
|
ack_info->psh_flag = 1;
|
||||||
|
ack_info->psh_seq = ack_msg.seq;
|
||||||
|
write_sequnlock_bh(&ack_info->seqlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return val: 0 for not filter, 1 for filter */
|
||||||
|
int filter_send_tcp_ack(struct rwnx_hw *priv,
|
||||||
|
struct msg_buf *msgbuf,
|
||||||
|
unsigned char *buf, unsigned int plen)
|
||||||
|
{
|
||||||
|
// printk("%s \n",__func__);
|
||||||
|
int ret = 0;
|
||||||
|
int index, drop;
|
||||||
|
unsigned short win_scale = 0;
|
||||||
|
unsigned int win = 0;
|
||||||
|
struct tcp_ack_msg ack_msg;
|
||||||
|
struct tcp_ack_msg *ack;
|
||||||
|
struct tcp_ack_info *ack_info;
|
||||||
|
struct tcp_ack_manage *ack_m = &priv->ack_m;
|
||||||
|
|
||||||
|
if (plen > MAX_TCP_ACK)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
tcp_ack_update(ack_m);
|
||||||
|
drop = tcp_check_ack(buf, &ack_msg, &win_scale);
|
||||||
|
// printk("drop:%d win_scale:%d",drop,win_scale);
|
||||||
|
if (!drop && (0 == win_scale))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
index = tcp_ack_match(ack_m, &ack_msg);
|
||||||
|
if (index >= 0) {
|
||||||
|
ack_info = ack_m->ack_info + index;
|
||||||
|
if ((0 != win_scale) &&
|
||||||
|
(ack_info->win_scale != win_scale)) {
|
||||||
|
write_seqlock_bh(&ack_info->seqlock);
|
||||||
|
ack_info->win_scale = win_scale;
|
||||||
|
write_sequnlock_bh(&ack_info->seqlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drop > 0 && atomic_read(&ack_m->enable)) {
|
||||||
|
win = ack_info->win_scale * ack_msg.win;
|
||||||
|
if ((win_scale!=0) && (win < (ack_m->ack_winsize * SIZE_KB)))
|
||||||
|
{
|
||||||
|
drop = 2;
|
||||||
|
printk("%d %d %d",win_scale,win,(ack_m->ack_winsize * SIZE_KB));
|
||||||
|
}
|
||||||
|
ret = tcp_ack_handle_new(msgbuf, ack_m, ack_info,
|
||||||
|
&ack_msg, drop);
|
||||||
|
}
|
||||||
|
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = tcp_ack_alloc_index(ack_m);
|
||||||
|
if (index >= 0) {
|
||||||
|
write_seqlock_bh(&ack_m->ack_info[index].seqlock);
|
||||||
|
ack_m->ack_info[index].busy = 1;
|
||||||
|
ack_m->ack_info[index].psh_flag = 0;
|
||||||
|
ack_m->ack_info[index].last_time = jiffies;
|
||||||
|
ack_m->ack_info[index].drop_cnt =
|
||||||
|
atomic_read(&ack_m->max_drop_cnt);
|
||||||
|
ack_m->ack_info[index].win_scale =
|
||||||
|
(win_scale != 0) ? win_scale : 1;
|
||||||
|
|
||||||
|
//ack_m->ack_info[index].msgbuf = NULL;
|
||||||
|
//ack_m->ack_info[index].in_send_msg = NULL;
|
||||||
|
ack = &ack_m->ack_info[index].ack_msg;
|
||||||
|
ack->dest = ack_msg.dest;
|
||||||
|
ack->source = ack_msg.source;
|
||||||
|
ack->saddr = ack_msg.saddr;
|
||||||
|
ack->daddr = ack_msg.daddr;
|
||||||
|
ack->seq = ack_msg.seq;
|
||||||
|
write_sequnlock_bh(&ack_m->ack_info[index].seqlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void move_tcpack_msg(struct rwnx_hw *priv,
|
||||||
|
struct msg_buf *msg)
|
||||||
|
{
|
||||||
|
struct tcp_ack_info *ack_info;
|
||||||
|
struct tcp_ack_manage *ack_m = &priv->ack_m;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (!atomic_read(&ack_m->enable))
|
||||||
|
return;
|
||||||
|
|
||||||
|
//if (msg->len > MAX_TCP_ACK)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
for (i = 0; i < TCP_ACK_NUM; i++) {
|
||||||
|
ack_info = &ack_m->ack_info[i];
|
||||||
|
write_seqlock_bh(&ack_info->seqlock);
|
||||||
|
if (ack_info->busy && (ack_info->in_send_msg == msg))
|
||||||
|
ack_info->in_send_msg = NULL;
|
||||||
|
write_sequnlock_bh(&ack_info->seqlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
#ifndef _AICWF_TCP_ACK_H_
|
||||||
|
#define _AICWF_TCP_ACK_H_
|
||||||
|
|
||||||
|
#include <uapi/linux/if_ether.h>
|
||||||
|
#include <uapi/linux/tcp.h>
|
||||||
|
#include <uapi/linux/ip.h>
|
||||||
|
#include <uapi/linux/in.h>
|
||||||
|
#include <linux/moduleparam.h>
|
||||||
|
#include <net/tcp.h>
|
||||||
|
#include <linux/timer.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define TCP_ACK_NUM 32
|
||||||
|
#define TCP_ACK_EXIT_VAL 0x800
|
||||||
|
#define TCP_ACK_DROP_CNT 10
|
||||||
|
|
||||||
|
#define ACK_OLD_TIME 4000
|
||||||
|
#define U32_BEFORE(a, b) ((__s32)((__u32)a - (__u32)b) <= 0)
|
||||||
|
|
||||||
|
#define MAX_TCP_ACK 200
|
||||||
|
/*min window size in KB, it's 256KB*/
|
||||||
|
#define MIN_WIN 256
|
||||||
|
#define SIZE_KB 1024
|
||||||
|
|
||||||
|
|
||||||
|
struct msg_buf {
|
||||||
|
//struct list_head list;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
struct rwnx_vif *rwnx_vif;
|
||||||
|
|
||||||
|
/* data just tx cmd use,not include the head */
|
||||||
|
/*void *data;
|
||||||
|
void *tran_data;
|
||||||
|
unsigned long pcie_addr;
|
||||||
|
u8 type;
|
||||||
|
u8 mode;
|
||||||
|
u16 len;
|
||||||
|
unsigned long timeout;*/
|
||||||
|
|
||||||
|
/*unsigned int fifo_id;
|
||||||
|
struct sprdwl_msg_list *msglist;*/
|
||||||
|
|
||||||
|
/*unsigned char buffer_type;
|
||||||
|
struct sprdwl_xmit_msg_list *xmit_msg_list;
|
||||||
|
unsigned char msg_type;
|
||||||
|
|
||||||
|
unsigned long last_time;
|
||||||
|
u8 ctxt_id;*/
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tcp_ack_msg {
|
||||||
|
u16 source;
|
||||||
|
u16 dest;
|
||||||
|
s32 saddr;
|
||||||
|
s32 daddr;
|
||||||
|
u32 seq;
|
||||||
|
u16 win;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct tcp_ack_info {
|
||||||
|
int ack_info_num;
|
||||||
|
int busy;
|
||||||
|
int drop_cnt;
|
||||||
|
int psh_flag;
|
||||||
|
u32 psh_seq;
|
||||||
|
u16 win_scale;
|
||||||
|
/* seqlock for ack info */
|
||||||
|
seqlock_t seqlock;
|
||||||
|
unsigned long last_time;
|
||||||
|
unsigned long timeout;
|
||||||
|
struct timer_list timer;
|
||||||
|
struct msg_buf *msgbuf;
|
||||||
|
struct msg_buf *in_send_msg;
|
||||||
|
struct tcp_ack_msg ack_msg;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tcp_ack_manage {
|
||||||
|
/* 1 filter */
|
||||||
|
atomic_t enable;
|
||||||
|
int max_num;
|
||||||
|
int free_index;
|
||||||
|
unsigned long last_time;
|
||||||
|
unsigned long timeout;
|
||||||
|
atomic_t max_drop_cnt;
|
||||||
|
/* lock for tcp ack alloc and free */
|
||||||
|
spinlock_t lock;
|
||||||
|
struct rwnx_hw *priv;
|
||||||
|
struct tcp_ack_info ack_info[TCP_ACK_NUM];
|
||||||
|
/*size in KB*/
|
||||||
|
unsigned int ack_winsize;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct msg_buf *intf_tcp_alloc_msg(struct msg_buf *msg);
|
||||||
|
|
||||||
|
void tcp_ack_init(struct rwnx_hw *priv);
|
||||||
|
|
||||||
|
void tcp_ack_deinit(struct rwnx_hw *priv);
|
||||||
|
|
||||||
|
|
||||||
|
int is_drop_tcp_ack(struct tcphdr *tcphdr, int tcp_tot_len, unsigned short *win_scale);
|
||||||
|
|
||||||
|
int is_tcp_ack(struct sk_buff *skb, unsigned short *win_scale);
|
||||||
|
|
||||||
|
int filter_send_tcp_ack(struct rwnx_hw *priv, struct msg_buf *msgbuf,unsigned char *buf, unsigned int plen);
|
||||||
|
|
||||||
|
void filter_rx_tcp_ack(struct rwnx_hw *priv,unsigned char *buf, unsigned plen);
|
||||||
|
|
||||||
|
void move_tcpack_msg(struct rwnx_hw *priv, struct msg_buf * msg);
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,304 @@
|
|||||||
|
/**
|
||||||
|
* aicwf_txrxif.h
|
||||||
|
*
|
||||||
|
* bus function declarations
|
||||||
|
*
|
||||||
|
* Copyright (C) AICSemi 2018-2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _AICWF_TXRXIF_H_
|
||||||
|
#define _AICWF_TXRXIF_H_
|
||||||
|
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include "ipc_shared.h"
|
||||||
|
#include "aicwf_rx_prealloc.h"
|
||||||
|
#ifdef AICWF_SDIO_SUPPORT
|
||||||
|
#include "aicwf_sdio.h"
|
||||||
|
#else
|
||||||
|
#include "aicwf_usb.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CMD_BUF_MAX 1536
|
||||||
|
#define DATA_BUF_MAX 2048
|
||||||
|
#define TXPKT_BLOCKSIZE 512
|
||||||
|
#define MAX_AGGR_TXPKT_LEN (1536*64)
|
||||||
|
#define CMD_TX_TIMEOUT 5000
|
||||||
|
#define TX_ALIGNMENT 4
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_TX_AGGR
|
||||||
|
#define MAX_USB_AGGR_TXPKT_LEN (1536*15)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define RX_HWHRD_LEN 60 //58->60 word allined
|
||||||
|
#define CCMP_OR_WEP_INFO 8
|
||||||
|
#define MAX_RXQLEN 2000
|
||||||
|
#define RX_ALIGNMENT 4
|
||||||
|
|
||||||
|
#define DEBUG_ERROR_LEVEL 0
|
||||||
|
#define DEBUG_DEBUG_LEVEL 1
|
||||||
|
#define DEBUG_INFO_LEVEL 2
|
||||||
|
|
||||||
|
#define DBG_LEVEL DEBUG_DEBUG_LEVEL
|
||||||
|
|
||||||
|
#define txrx_err(fmt, ...) pr_err("txrx_err:<%s,%d>: " fmt, __func__, __LINE__, ##__VA_ARGS__)
|
||||||
|
#define sdio_err(fmt, ...) pr_err("sdio_err:<%s,%d>: " fmt, __func__, __LINE__, ##__VA_ARGS__)
|
||||||
|
#define usb_err(fmt, ...) pr_err("usb_err:<%s,%d>: " fmt, __func__, __LINE__, ##__VA_ARGS__)
|
||||||
|
#if DBG_LEVEL >= DEBUG_DEBUG_LEVEL
|
||||||
|
#define txrx_dbg(fmt, ...) printk("txrx: " fmt, ##__VA_ARGS__)
|
||||||
|
#define sdio_dbg(fmt, ...) printk("aicsdio: " fmt, ##__VA_ARGS__)
|
||||||
|
#define usb_dbg(fmt, ...) printk("aicusb: " fmt, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define txrx_dbg(fmt, ...)
|
||||||
|
#define sdio_dbg(fmt, ...)
|
||||||
|
#define usb_dbg(fmt, ...)
|
||||||
|
#endif
|
||||||
|
#if DBG_LEVEL >= DEBUG_INFO_LEVEL
|
||||||
|
#define txrx_info(fmt, ...) printk("aicsdio: " fmt, ##__VA_ARGS__)
|
||||||
|
#define sdio_info(fmt, ...) printk("aicsdio: " fmt, ##__VA_ARGS__)
|
||||||
|
#define usb_info(fmt, ...) printk("aicusb: " fmt, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define txrx_info(fmt, ...)
|
||||||
|
#define sdio_info(fmt, ...)
|
||||||
|
#define usb_info(fmt, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum aicwf_bus_state {
|
||||||
|
BUS_DOWN_ST,
|
||||||
|
BUS_UP_ST
|
||||||
|
};
|
||||||
|
|
||||||
|
struct aicwf_bus_ops {
|
||||||
|
int (*start) (struct device * dev);
|
||||||
|
void (*stop) (struct device * dev);
|
||||||
|
int (*txdata) (struct device * dev, struct sk_buff * skb);
|
||||||
|
int (*txmsg) (struct device * dev, u8 * msg, uint len);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct frame_queue {
|
||||||
|
u16 num_prio;
|
||||||
|
u16 hi_prio;
|
||||||
|
u16 qmax; /* max number of queued frames */
|
||||||
|
u16 qcnt;
|
||||||
|
struct sk_buff_head queuelist[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_PREALLOC_RX_SKB
|
||||||
|
struct rx_frame_queue {
|
||||||
|
u16 qmax; /* max number of queued frames */
|
||||||
|
u16 qcnt;
|
||||||
|
struct list_head queuelist;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct aicwf_bus {
|
||||||
|
union {
|
||||||
|
struct aic_sdio_dev *sdio;
|
||||||
|
struct aic_usb_dev *usb;
|
||||||
|
} bus_priv;
|
||||||
|
struct device *dev;
|
||||||
|
struct aicwf_bus_ops *ops;
|
||||||
|
enum aicwf_bus_state state;
|
||||||
|
u8 *cmd_buf;
|
||||||
|
struct completion bustx_trgg;
|
||||||
|
struct completion busrx_trgg;
|
||||||
|
#ifdef CONFIG_USB_MSG_IN_EP
|
||||||
|
struct completion msg_busrx_trgg;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct task_struct *bustx_thread;
|
||||||
|
struct task_struct *busrx_thread;
|
||||||
|
#ifdef CONFIG_USB_MSG_IN_EP
|
||||||
|
struct task_struct *msg_busrx_thread;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct aicwf_tx_priv {
|
||||||
|
#ifdef AICWF_SDIO_SUPPORT
|
||||||
|
struct aic_sdio_dev *sdiodev;
|
||||||
|
int fw_avail_bufcnt;
|
||||||
|
//for cmd tx
|
||||||
|
u8 *cmd_buf;
|
||||||
|
uint cmd_len;
|
||||||
|
bool cmd_txstate;
|
||||||
|
bool cmd_tx_succ;
|
||||||
|
struct semaphore cmd_txsema;
|
||||||
|
wait_queue_head_t cmd_txdone_wait;
|
||||||
|
//for data tx
|
||||||
|
atomic_t tx_pktcnt;
|
||||||
|
|
||||||
|
struct frame_queue txq;
|
||||||
|
spinlock_t txqlock;
|
||||||
|
struct semaphore txctl_sema;
|
||||||
|
#endif
|
||||||
|
#ifdef AICWF_USB_SUPPORT
|
||||||
|
struct aic_usb_dev *usbdev;
|
||||||
|
#ifdef CONFIG_USB_TX_AGGR
|
||||||
|
int fw_avail_bufcnt;
|
||||||
|
|
||||||
|
//for data tx
|
||||||
|
atomic_t tx_pktcnt;
|
||||||
|
|
||||||
|
struct frame_queue txq;
|
||||||
|
spinlock_t txqlock;
|
||||||
|
spinlock_t txdlock;
|
||||||
|
#endif
|
||||||
|
#endif//AICWF_USB_SUPPORT
|
||||||
|
struct sk_buff *aggr_buf;
|
||||||
|
atomic_t aggr_count;
|
||||||
|
u8 *head;
|
||||||
|
u8 *tail;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef AICWF_RX_REORDER
|
||||||
|
#define MAX_REORD_RXFRAME 250
|
||||||
|
#define REORDER_UPDATE_TIME 500//50
|
||||||
|
#define AICWF_REORDER_WINSIZE 64
|
||||||
|
//SN_LESS(a, b) a-b<0 is ture
|
||||||
|
#define SN_LESS(a, b) (((a-b)&0x800)!=0)
|
||||||
|
#define SN_EQUAL(a, b) (a == b)
|
||||||
|
|
||||||
|
struct reord_ctrl {
|
||||||
|
struct aicwf_rx_priv *rx_priv;
|
||||||
|
u8 enable;
|
||||||
|
u16 ind_sn;
|
||||||
|
u8 wsize_b;
|
||||||
|
spinlock_t reord_list_lock;
|
||||||
|
struct list_head reord_list;
|
||||||
|
struct timer_list reord_timer;
|
||||||
|
struct work_struct reord_timer_work;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct reord_ctrl_info {
|
||||||
|
u8 mac_addr[6];
|
||||||
|
struct reord_ctrl preorder_ctrl[8];
|
||||||
|
struct list_head list;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct recv_msdu {
|
||||||
|
struct sk_buff *pkt;
|
||||||
|
u8 tid;
|
||||||
|
u8 forward;
|
||||||
|
u16 seq_num;
|
||||||
|
uint len;
|
||||||
|
u8 *rx_data;
|
||||||
|
//for pending rx reorder list
|
||||||
|
struct list_head reord_pending_list;
|
||||||
|
//for total frame list, when rxframe from busif, dequeue, when submit frame to net, enqueue
|
||||||
|
struct list_head rxframe_list;
|
||||||
|
struct reord_ctrl *preorder_ctrl;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct aicwf_rx_priv {
|
||||||
|
#ifdef AICWF_SDIO_SUPPORT
|
||||||
|
struct aic_sdio_dev *sdiodev;
|
||||||
|
#endif
|
||||||
|
#ifdef AICWF_USB_SUPPORT
|
||||||
|
struct aic_usb_dev *usbdev;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void *rwnx_vif;
|
||||||
|
atomic_t rx_cnt;
|
||||||
|
u32 data_len;
|
||||||
|
spinlock_t rxqlock;
|
||||||
|
#ifdef CONFIG_PREALLOC_RX_SKB
|
||||||
|
struct rx_frame_queue rxq;
|
||||||
|
#else
|
||||||
|
struct frame_queue rxq;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_USB_RX_REASSEMBLE
|
||||||
|
struct sk_buff *rx_reassemble_skb;
|
||||||
|
u32 rx_reassemble_total_len;
|
||||||
|
u32 rx_reassemble_cur_len;
|
||||||
|
u32 rx_reassemble_total_frags;
|
||||||
|
u32 rx_reassemble_cur_frags;
|
||||||
|
|
||||||
|
struct sk_buff *rx_msg_reassemble_skb;
|
||||||
|
u32 rx_msg_reassemble_total_len;
|
||||||
|
u32 rx_msg_reassemble_cur_len;
|
||||||
|
u32 rx_msg_reassemble_total_frags;
|
||||||
|
u32 rx_msg_reassemble_cur_frags;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_MSG_IN_EP
|
||||||
|
atomic_t msg_rx_cnt;
|
||||||
|
spinlock_t msg_rxqlock;
|
||||||
|
struct frame_queue msg_rxq;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef AICWF_RX_REORDER
|
||||||
|
spinlock_t freeq_lock;
|
||||||
|
struct list_head rxframes_freequeue;
|
||||||
|
struct list_head stas_reord_list;
|
||||||
|
spinlock_t stas_reord_lock;
|
||||||
|
struct recv_msdu *recv_frames;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_PREALLOC_RX_SKB
|
||||||
|
spinlock_t rxbuff_lock;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline int aicwf_bus_start(struct aicwf_bus *bus)
|
||||||
|
{
|
||||||
|
return bus->ops->start(bus->dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void aicwf_bus_stop(struct aicwf_bus *bus)
|
||||||
|
{
|
||||||
|
bus->ops->stop(bus->dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int aicwf_bus_txdata(struct aicwf_bus *bus, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
return bus->ops->txdata(bus->dev, skb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int aicwf_bus_txmsg(struct aicwf_bus *bus, u8 *msg, uint len)
|
||||||
|
{
|
||||||
|
return bus->ops->txmsg(bus->dev, msg, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void aicwf_sched_timeout(u32 millisec)
|
||||||
|
{
|
||||||
|
ulong timeout = 0, expires = 0;
|
||||||
|
expires = jiffies + msecs_to_jiffies(millisec);
|
||||||
|
timeout = millisec;
|
||||||
|
|
||||||
|
while (timeout) {
|
||||||
|
timeout = schedule_timeout(timeout);
|
||||||
|
if (time_after(jiffies, expires))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int aicwf_bus_init(uint bus_hdrlen, struct device *dev);
|
||||||
|
void aicwf_bus_deinit(struct device *dev);
|
||||||
|
void aicwf_tx_deinit(struct aicwf_tx_priv* tx_priv);
|
||||||
|
void aicwf_rx_deinit(struct aicwf_rx_priv* rx_priv);
|
||||||
|
struct aicwf_tx_priv* aicwf_tx_init(void *arg);
|
||||||
|
struct aicwf_rx_priv* aicwf_rx_init(void *arg);
|
||||||
|
void aicwf_frame_queue_init(struct frame_queue *pq, int num_prio, int max_len);
|
||||||
|
void aicwf_frame_queue_flush(struct frame_queue *pq);
|
||||||
|
bool aicwf_frame_enq(struct device *dev, struct frame_queue *q, struct sk_buff *pkt, int prio);
|
||||||
|
bool aicwf_rxframe_enqueue(struct device *dev, struct frame_queue *q, struct sk_buff *pkt);
|
||||||
|
bool aicwf_is_framequeue_empty(struct frame_queue *pq);
|
||||||
|
void aicwf_frame_tx(void *dev, struct sk_buff *skb);
|
||||||
|
void aicwf_dev_skb_free(struct sk_buff *skb);
|
||||||
|
struct sk_buff *aicwf_frame_dequeue(struct frame_queue *pq);
|
||||||
|
struct sk_buff *aicwf_frame_queue_peek_tail(struct frame_queue *pq, int *prio_out);
|
||||||
|
#ifdef CONFIG_PREALLOC_RX_SKB
|
||||||
|
void rxbuff_queue_flush(struct aicwf_rx_priv* rx_priv);
|
||||||
|
void aicwf_rxframe_queue_init_2(struct rx_frame_queue *pq, int max_len);
|
||||||
|
void rxbuff_free(struct rx_buff *rxbuff);
|
||||||
|
struct rx_buff *rxbuff_dequeue(struct rx_frame_queue *pq);
|
||||||
|
bool aicwf_rxbuff_enqueue(struct device *dev, struct rx_frame_queue *rxq, struct rx_buff *pkt);
|
||||||
|
extern struct aicwf_rx_buff_list aic_rx_buff_list;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _AICWF_TXRXIF_H_ */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,198 @@
|
|||||||
|
/**
|
||||||
|
* aicwf_usb.h
|
||||||
|
*
|
||||||
|
* USB function declarations
|
||||||
|
*
|
||||||
|
* Copyright (C) AICSemi 2018-2020
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _AICWF_USB_H_
|
||||||
|
#define _AICWF_USB_H_
|
||||||
|
|
||||||
|
#include <linux/usb.h>
|
||||||
|
#include "rwnx_cmds.h"
|
||||||
|
|
||||||
|
#ifdef AICWF_USB_SUPPORT
|
||||||
|
|
||||||
|
/* USB Device ID */
|
||||||
|
#define USB_VENDOR_ID_AIC 0xA69C
|
||||||
|
#define USB_VENDOR_ID_TP 0x2357
|
||||||
|
#define USB_VENDOR_ID_TENDA 0x2604
|
||||||
|
|
||||||
|
#define USB_PRODUCT_ID_TP 0x014e
|
||||||
|
#define USB_PRODUCT_ID_MERCURY 0x014b
|
||||||
|
#define USB_PRODUCT_ID_FAST 0x014f
|
||||||
|
|
||||||
|
#define USB_PRODUCT_ID_TENDA 0x001f
|
||||||
|
|
||||||
|
#ifndef CONFIG_USB_BT
|
||||||
|
#define USB_PRODUCT_ID_AIC8800 0x8800
|
||||||
|
#define USB_PRODUCT_ID_AIC8801 0x8801
|
||||||
|
#define USB_PRODUCT_ID_AIC8800DC 0x88dc
|
||||||
|
#define USB_PRODUCT_ID_AIC8800DW 0x88dd
|
||||||
|
#define USB_PRODUCT_ID_AIC8800D81 0x8d81
|
||||||
|
#else
|
||||||
|
#define USB_PRODUCT_ID_AIC8801 0x8801
|
||||||
|
#define USB_PRODUCT_ID_AIC8800DC 0x88dc
|
||||||
|
#define USB_PRODUCT_ID_AIC8800DW 0x88dd
|
||||||
|
#define USB_PRODUCT_ID_AIC8800D81 0x8d81
|
||||||
|
#define USB_PRODUCT_ID_AIC8800D41 0x8d41
|
||||||
|
#define USB_PRODUCT_ID_AIC8800D83 0x8d83
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum AICWF_IC{
|
||||||
|
PRODUCT_ID_AIC8801 = 0,
|
||||||
|
PRODUCT_ID_AIC8800DC,
|
||||||
|
PRODUCT_ID_AIC8800DW,
|
||||||
|
PRODUCT_ID_AIC8800D81
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define AICWF_USB_RX_URBS (20)//(200)
|
||||||
|
#ifdef CONFIG_USB_MSG_IN_EP
|
||||||
|
#define AICWF_USB_MSG_RX_URBS (100)
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_USB_TX_AGGR
|
||||||
|
#define TXQLEN (2048*4)
|
||||||
|
#define AICWF_USB_TX_URBS (50)
|
||||||
|
#else
|
||||||
|
#define AICWF_USB_TX_URBS 50//(100)
|
||||||
|
#endif
|
||||||
|
#define AICWF_USB_TX_LOW_WATER (AICWF_USB_TX_URBS/4)//25%
|
||||||
|
#define AICWF_USB_TX_HIGH_WATER (AICWF_USB_TX_LOW_WATER*3)//75%
|
||||||
|
#ifdef CONFIG_PLATFORM_HI
|
||||||
|
#define AICWF_USB_AGGR_MAX_PKT_SIZE (2048*1)
|
||||||
|
#else
|
||||||
|
#define AICWF_USB_AGGR_MAX_PKT_SIZE (2048*10)
|
||||||
|
#endif
|
||||||
|
#define AICWF_USB_MSG_MAX_PKT_SIZE (2048)
|
||||||
|
#define AICWF_USB_MAX_PKT_SIZE (2048)
|
||||||
|
#define AICWF_USB_FC_PERSTA_HIGH_WATER 64
|
||||||
|
#define AICWF_USB_FC_PERSTA_LOW_WATER 16
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
USB_TYPE_DATA = 0X00,
|
||||||
|
USB_TYPE_CFG = 0X10,
|
||||||
|
USB_TYPE_CFG_CMD_RSP = 0X11,
|
||||||
|
USB_TYPE_CFG_DATA_CFM = 0X12,
|
||||||
|
USB_TYPE_CFG_PRINT = 0X13
|
||||||
|
} usb_type;
|
||||||
|
|
||||||
|
enum aicwf_usb_state {
|
||||||
|
USB_DOWN_ST,
|
||||||
|
USB_UP_ST,
|
||||||
|
USB_SLEEP_ST
|
||||||
|
};
|
||||||
|
|
||||||
|
struct aicwf_usb_buf {
|
||||||
|
struct list_head list;
|
||||||
|
struct aic_usb_dev *usbdev;
|
||||||
|
struct urb *urb;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
#ifdef CONFIG_PREALLOC_RX_SKB
|
||||||
|
struct rx_buff *rx_buff;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_USB_NO_TRANS_DMA_MAP
|
||||||
|
u8 *data_buf;
|
||||||
|
dma_addr_t data_dma_trans_addr;
|
||||||
|
#endif
|
||||||
|
bool cfm;
|
||||||
|
#ifdef CONFIG_USB_TX_AGGR
|
||||||
|
u8 aggr_cnt;
|
||||||
|
#endif
|
||||||
|
u8* usb_align_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct aic_usb_dev {
|
||||||
|
struct rwnx_hw *rwnx_hw;
|
||||||
|
struct aicwf_bus *bus_if;
|
||||||
|
struct usb_device *udev;
|
||||||
|
struct device *dev;
|
||||||
|
struct aicwf_rx_priv* rx_priv;
|
||||||
|
enum aicwf_usb_state state;
|
||||||
|
struct rwnx_cmd_mgr cmd_mgr;
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_TX_AGGR
|
||||||
|
struct aicwf_tx_priv *tx_priv;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct usb_anchor rx_submitted;
|
||||||
|
struct work_struct rx_urb_work;
|
||||||
|
#ifdef CONFIG_USB_MSG_IN_EP
|
||||||
|
struct usb_anchor msg_rx_submitted;
|
||||||
|
struct work_struct msg_rx_urb_work;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
spinlock_t rx_free_lock;
|
||||||
|
spinlock_t tx_free_lock;
|
||||||
|
spinlock_t tx_post_lock;
|
||||||
|
spinlock_t tx_flow_lock;
|
||||||
|
#ifdef CONFIG_USB_MSG_IN_EP
|
||||||
|
spinlock_t msg_rx_free_lock;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct list_head rx_free_list;
|
||||||
|
struct list_head tx_free_list;
|
||||||
|
struct list_head tx_post_list;
|
||||||
|
#ifdef CONFIG_USB_MSG_IN_EP
|
||||||
|
struct list_head msg_rx_free_list;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint bulk_in_pipe;
|
||||||
|
uint bulk_out_pipe;
|
||||||
|
#ifdef CONFIG_USB_MSG_OUT_EP
|
||||||
|
uint msg_out_pipe;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_USB_MSG_IN_EP
|
||||||
|
uint msg_in_pipe;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int tx_free_count;
|
||||||
|
int tx_post_count;
|
||||||
|
bool rx_prepare_ready;
|
||||||
|
#if 0
|
||||||
|
struct aicwf_usb_buf usb_tx_buf[AICWF_USB_TX_URBS];
|
||||||
|
struct aicwf_usb_buf usb_rx_buf[AICWF_USB_RX_URBS];
|
||||||
|
#else
|
||||||
|
struct aicwf_usb_buf *usb_tx_buf;
|
||||||
|
struct aicwf_usb_buf *usb_rx_buf;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_MSG_IN_EP
|
||||||
|
struct aicwf_usb_buf usb_msg_rx_buf[AICWF_USB_MSG_RX_URBS];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int msg_finished;
|
||||||
|
wait_queue_head_t msg_wait;
|
||||||
|
ulong msg_busy;
|
||||||
|
struct urb *msg_out_urb;
|
||||||
|
#ifdef CONFIG_USB_NO_TRANS_DMA_MAP
|
||||||
|
dma_addr_t cmd_dma_trans_addr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_RX_TASKLET//AIDEN tasklet
|
||||||
|
struct tasklet_struct recv_tasklet;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_TX_TASKLET//AIDEN tasklet
|
||||||
|
struct tasklet_struct xmit_tasklet;
|
||||||
|
#endif
|
||||||
|
u16 chipid;
|
||||||
|
bool tbusy;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void aicwf_usb_exit(void);
|
||||||
|
extern void aicwf_usb_register(void);
|
||||||
|
extern void aicwf_usb_tx_flowctrl(struct rwnx_hw *rwnx_hw, bool state);
|
||||||
|
#ifdef CONFIG_USB_MSG_IN_EP
|
||||||
|
int usb_msg_busrx_thread(void *data);
|
||||||
|
#endif
|
||||||
|
int usb_bustx_thread(void *data);
|
||||||
|
int usb_busrx_thread(void *data);
|
||||||
|
|
||||||
|
|
||||||
|
extern void aicwf_hostif_ready(void);
|
||||||
|
|
||||||
|
#endif /* AICWF_USB_SUPPORT */
|
||||||
|
#endif /* _AICWF_USB_H_ */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
struct scanu_result_wext{
|
||||||
|
struct list_head scanu_re_list;
|
||||||
|
struct cfg80211_bss *bss;
|
||||||
|
struct scanu_result_ind *ind;
|
||||||
|
u32_l *payload;
|
||||||
|
};
|
||||||
|
|
||||||
|
void aicwf_set_wireless_ext( struct net_device *ndev, struct rwnx_hw *rwnx_hw);
|
||||||
|
void aicwf_scan_complete_event(struct net_device *dev);
|
||||||
|
|
||||||
@@ -0,0 +1,376 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file hal_desc.h
|
||||||
|
*
|
||||||
|
* @brief File containing the definition of HW descriptors.
|
||||||
|
*
|
||||||
|
* Contains the definition and structures used by HW
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2011-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HAL_DESC_H_
|
||||||
|
#define _HAL_DESC_H_
|
||||||
|
|
||||||
|
#include "lmac_types.h"
|
||||||
|
|
||||||
|
/* Rate and policy table */
|
||||||
|
|
||||||
|
#define N_CCK 8
|
||||||
|
#define N_OFDM 8
|
||||||
|
#define N_HT (8 * 2 * 2 * 4)
|
||||||
|
#define N_VHT (10 * 4 * 2 * 8)
|
||||||
|
#define N_HE_SU (12 * 4 * 3 * 8)
|
||||||
|
#define N_HE_MU (12 * 6 * 3 * 8)
|
||||||
|
|
||||||
|
/* conversion table from NL80211 to MACHW enum */
|
||||||
|
extern const int chnl2bw[];
|
||||||
|
|
||||||
|
/* conversion table from MACHW to NL80211 enum */
|
||||||
|
extern const int bw2chnl[];
|
||||||
|
|
||||||
|
/* Rate cntrl info */
|
||||||
|
#define MCS_INDEX_TX_RCX_OFT 0
|
||||||
|
#define MCS_INDEX_TX_RCX_MASK (0x7F << MCS_INDEX_TX_RCX_OFT)
|
||||||
|
#define BW_TX_RCX_OFT 7
|
||||||
|
#define BW_TX_RCX_MASK (0x3 << BW_TX_RCX_OFT)
|
||||||
|
#define SHORT_GI_TX_RCX_OFT 9
|
||||||
|
#define SHORT_GI_TX_RCX_MASK (0x1 << SHORT_GI_TX_RCX_OFT)
|
||||||
|
#define PRE_TYPE_TX_RCX_OFT 10
|
||||||
|
#define PRE_TYPE_TX_RCX_MASK (0x1 << PRE_TYPE_TX_RCX_OFT)
|
||||||
|
#define FORMAT_MOD_TX_RCX_OFT 11
|
||||||
|
#define FORMAT_MOD_TX_RCX_MASK (0x7 << FORMAT_MOD_TX_RCX_OFT)
|
||||||
|
|
||||||
|
/* Values for formatModTx */
|
||||||
|
#define FORMATMOD_NON_HT 0
|
||||||
|
#define FORMATMOD_NON_HT_DUP_OFDM 1
|
||||||
|
#define FORMATMOD_HT_MF 2
|
||||||
|
#define FORMATMOD_HT_GF 3
|
||||||
|
#define FORMATMOD_VHT 4
|
||||||
|
#define FORMATMOD_HE_SU 5
|
||||||
|
#define FORMATMOD_HE_MU 6
|
||||||
|
#define FORMATMOD_HE_ER 7
|
||||||
|
|
||||||
|
/* Values for navProtFrmEx */
|
||||||
|
#define NAV_PROT_NO_PROT_BIT 0
|
||||||
|
#define NAV_PROT_SELF_CTS_BIT 1
|
||||||
|
#define NAV_PROT_RTS_CTS_BIT 2
|
||||||
|
#define NAV_PROT_RTS_CTS_WITH_QAP_BIT 3
|
||||||
|
#define NAV_PROT_STBC_BIT 4
|
||||||
|
|
||||||
|
/* THD MACCTRLINFO2 fields, used in struct umacdesc umac.flags */
|
||||||
|
/// WhichDescriptor definition - contains aMPDU bit and position value
|
||||||
|
/// Offset of WhichDescriptor field in the MAC CONTROL INFO 2 word
|
||||||
|
#define WHICHDESC_OFT 19
|
||||||
|
/// Mask of the WhichDescriptor field
|
||||||
|
#define WHICHDESC_MSK (0x07 << WHICHDESC_OFT)
|
||||||
|
/// Only 1 THD possible, describing an unfragmented MSDU
|
||||||
|
#define WHICHDESC_UNFRAGMENTED_MSDU (0x00 << WHICHDESC_OFT)
|
||||||
|
/// THD describing the first MPDU of a fragmented MSDU
|
||||||
|
#define WHICHDESC_FRAGMENTED_MSDU_FIRST (0x01 << WHICHDESC_OFT)
|
||||||
|
/// THD describing intermediate MPDUs of a fragmented MSDU
|
||||||
|
#define WHICHDESC_FRAGMENTED_MSDU_INT (0x02 << WHICHDESC_OFT)
|
||||||
|
/// THD describing the last MPDU of a fragmented MSDU
|
||||||
|
#define WHICHDESC_FRAGMENTED_MSDU_LAST (0x03 << WHICHDESC_OFT)
|
||||||
|
/// THD for extra descriptor starting an AMPDU
|
||||||
|
#define WHICHDESC_AMPDU_EXTRA (0x04 << WHICHDESC_OFT)
|
||||||
|
/// THD describing the first MPDU of an A-MPDU
|
||||||
|
#define WHICHDESC_AMPDU_FIRST (0x05 << WHICHDESC_OFT)
|
||||||
|
/// THD describing intermediate MPDUs of an A-MPDU
|
||||||
|
#define WHICHDESC_AMPDU_INT (0x06 << WHICHDESC_OFT)
|
||||||
|
/// THD describing the last MPDU of an A-MPDU
|
||||||
|
#define WHICHDESC_AMPDU_LAST (0x07 << WHICHDESC_OFT)
|
||||||
|
|
||||||
|
/// aMPDU bit offset
|
||||||
|
#define AMPDU_OFT 21
|
||||||
|
/// aMPDU bit
|
||||||
|
#define AMPDU_BIT CO_BIT(AMPDU_OFT)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
HW_RATE_1MBPS = 0,
|
||||||
|
HW_RATE_2MBPS = 1,
|
||||||
|
HW_RATE_5_5MBPS = 2,
|
||||||
|
HW_RATE_11MBPS = 3,
|
||||||
|
HW_RATE_6MBPS = 4,
|
||||||
|
HW_RATE_9MBPS = 5,
|
||||||
|
HW_RATE_12MBPS = 6,
|
||||||
|
HW_RATE_18MBPS = 7,
|
||||||
|
HW_RATE_24MBPS = 8,
|
||||||
|
HW_RATE_36MBPS = 9,
|
||||||
|
HW_RATE_48MBPS = 10,
|
||||||
|
HW_RATE_54MBPS = 11,
|
||||||
|
HW_RATE_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
union rwnx_mcs_index {
|
||||||
|
struct {
|
||||||
|
u32 mcs : 3;
|
||||||
|
u32 nss : 2;
|
||||||
|
} ht;
|
||||||
|
struct {
|
||||||
|
u32 mcs : 4;
|
||||||
|
u32 nss : 3;
|
||||||
|
} vht;
|
||||||
|
struct {
|
||||||
|
u32 mcs : 4;
|
||||||
|
u32 nss : 3;
|
||||||
|
} he;
|
||||||
|
u32 legacy : 7;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* c.f RW-WLAN-nX-MAC-HW-UM */
|
||||||
|
union rwnx_rate_ctrl_info {
|
||||||
|
struct {
|
||||||
|
u32 mcsIndexTx : 7;
|
||||||
|
u32 bwTx : 2;
|
||||||
|
u32 giAndPreTypeTx : 2;
|
||||||
|
u32 formatModTx : 3;
|
||||||
|
u32 navProtFrmEx : 3;
|
||||||
|
u32 mcsIndexProtTx : 7;
|
||||||
|
u32 bwProtTx : 2;
|
||||||
|
u32 formatModProtTx : 3;
|
||||||
|
u32 nRetry : 3;
|
||||||
|
};
|
||||||
|
u32 value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* c.f RW-WLAN-nX-MAC-HW-UM */
|
||||||
|
struct rwnx_power_ctrl_info {
|
||||||
|
u32 txPwrLevelPT : 8;
|
||||||
|
u32 txPwrLevelProtPT : 8;
|
||||||
|
u32 reserved :16;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* c.f RW-WLAN-nX-MAC-HW-UM */
|
||||||
|
union rwnx_pol_phy_ctrl_info_1 {
|
||||||
|
struct {
|
||||||
|
u32 rsvd1 : 3;
|
||||||
|
u32 bfFrmEx : 1;
|
||||||
|
u32 numExtnSS : 2;
|
||||||
|
u32 fecCoding : 1;
|
||||||
|
u32 stbc : 2;
|
||||||
|
u32 rsvd2 : 5;
|
||||||
|
u32 nTx : 3;
|
||||||
|
u32 nTxProt : 3;
|
||||||
|
};
|
||||||
|
u32 value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* c.f RW-WLAN-nX-MAC-HW-UM */
|
||||||
|
union rwnx_pol_phy_ctrl_info_2 {
|
||||||
|
struct {
|
||||||
|
u32 antennaSet : 8;
|
||||||
|
u32 smmIndex : 8;
|
||||||
|
u32 beamFormed : 1;
|
||||||
|
};
|
||||||
|
u32 value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* c.f RW-WLAN-nX-MAC-HW-UM */
|
||||||
|
union rwnx_pol_mac_ctrl_info_1 {
|
||||||
|
struct {
|
||||||
|
u32 keySRamIndex : 10;
|
||||||
|
u32 keySRamIndexRA : 10;
|
||||||
|
};
|
||||||
|
u32 value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* c.f RW-WLAN-nX-MAC-HW-UM */
|
||||||
|
union rwnx_pol_mac_ctrl_info_2 {
|
||||||
|
struct {
|
||||||
|
u32 longRetryLimit : 8;
|
||||||
|
u32 shortRetryLimit : 8;
|
||||||
|
u32 rtsThreshold : 12;
|
||||||
|
};
|
||||||
|
u32 value;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define POLICY_TABLE_PATTERN 0xBADCAB1E
|
||||||
|
|
||||||
|
struct tx_policy_tbl {
|
||||||
|
/* Unique Pattern at the start of Policy Table */
|
||||||
|
u32 upatterntx;
|
||||||
|
/* PHY Control 1 Information used by MAC HW */
|
||||||
|
union rwnx_pol_phy_ctrl_info_1 phyctrlinfo_1;
|
||||||
|
/* PHY Control 2 Information used by MAC HW */
|
||||||
|
union rwnx_pol_phy_ctrl_info_2 phyctrlinfo_2;
|
||||||
|
/* MAC Control 1 Information used by MAC HW */
|
||||||
|
union rwnx_pol_mac_ctrl_info_1 macctrlinfo_1;
|
||||||
|
/* MAC Control 2 Information used by MAC HW */
|
||||||
|
union rwnx_pol_mac_ctrl_info_2 macctrlinfo_2;
|
||||||
|
|
||||||
|
union rwnx_rate_ctrl_info ratectrlinfos[NX_TX_MAX_RATES];
|
||||||
|
struct rwnx_power_ctrl_info powerctrlinfos[NX_TX_MAX_RATES];
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_hw_txstatus - Bitfield of confirmation status
|
||||||
|
*
|
||||||
|
* @tx_done: packet has been processed by the firmware.
|
||||||
|
* @retry_required: packet has been transmitted but not acknoledged.
|
||||||
|
* Driver must repush it.
|
||||||
|
* @sw_retry_required: packet has not been transmitted (FW wasn't able to push
|
||||||
|
* it when it received it: not active channel ...). Driver must repush it.
|
||||||
|
* @acknowledged: packet has been acknowledged by peer
|
||||||
|
*/
|
||||||
|
union rwnx_hw_txstatus {
|
||||||
|
struct {
|
||||||
|
u32 tx_done : 1;
|
||||||
|
u32 retry_required : 1;
|
||||||
|
u32 sw_retry_required : 1;
|
||||||
|
u32 acknowledged : 1;
|
||||||
|
u32 reserved :28;
|
||||||
|
};
|
||||||
|
u32 value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct tx_cfm_tag - Structure indicating the status and other
|
||||||
|
* information about the transmission
|
||||||
|
*
|
||||||
|
* @pn: PN that was used for the transmission
|
||||||
|
* @sn: Sequence number of the packet
|
||||||
|
* @timestamp: Timestamp of first transmission of this MPDU
|
||||||
|
* @credits: Number of credits to be reallocated for the txq that push this
|
||||||
|
* buffer (can be 0 or 1)
|
||||||
|
* @ampdu_size: Size of the ampdu in which the frame has been transmitted if
|
||||||
|
* this was the last frame of the a-mpdu, and 0 if the frame is not the last
|
||||||
|
* frame on a a-mdpu.
|
||||||
|
* 1 means that the frame has been transmitted as a singleton.
|
||||||
|
* @amsdu_size: Size, in bytes, allowed to create a-msdu.
|
||||||
|
* @status: transmission status
|
||||||
|
*/
|
||||||
|
struct tx_cfm_tag
|
||||||
|
{
|
||||||
|
u16_l pn[4];
|
||||||
|
u16_l sn;
|
||||||
|
u16_l timestamp;
|
||||||
|
s8_l credits;
|
||||||
|
u8_l ampdu_size;
|
||||||
|
#ifdef CONFIG_RWNX_SPLIT_TX_BUF
|
||||||
|
u16_l amsdu_size;
|
||||||
|
#endif
|
||||||
|
union rwnx_hw_txstatus status;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_hw_txhdr - Hardware part of tx header
|
||||||
|
*
|
||||||
|
* @cfm: Information updated by fw/hardware after sending a frame
|
||||||
|
*/
|
||||||
|
struct rwnx_hw_txhdr {
|
||||||
|
struct tx_cfm_tag cfm;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* CONFIG_RWNX_FULLMAC */
|
||||||
|
|
||||||
|
/* Modem */
|
||||||
|
|
||||||
|
#define MDM_PHY_CONFIG_TRIDENT 0
|
||||||
|
#define MDM_PHY_CONFIG_ELMA 1
|
||||||
|
#define MDM_PHY_CONFIG_KARST 2
|
||||||
|
|
||||||
|
// MODEM features (from reg_mdm_stat.h)
|
||||||
|
/// MUMIMOTX field bit
|
||||||
|
#define MDM_MUMIMOTX_BIT ((u32)0x80000000)
|
||||||
|
/// MUMIMOTX field position
|
||||||
|
#define MDM_MUMIMOTX_POS 31
|
||||||
|
/// MUMIMORX field bit
|
||||||
|
#define MDM_MUMIMORX_BIT ((u32)0x40000000)
|
||||||
|
/// MUMIMORX field position
|
||||||
|
#define MDM_MUMIMORX_POS 30
|
||||||
|
/// BFMER field bit
|
||||||
|
#define MDM_BFMER_BIT ((u32)0x20000000)
|
||||||
|
/// BFMER field position
|
||||||
|
#define MDM_BFMER_POS 29
|
||||||
|
/// BFMEE field bit
|
||||||
|
#define MDM_BFMEE_BIT ((u32)0x10000000)
|
||||||
|
/// BFMEE field position
|
||||||
|
#define MDM_BFMEE_POS 28
|
||||||
|
/// LDPCDEC field bit
|
||||||
|
#define MDM_LDPCDEC_BIT ((u32)0x08000000)
|
||||||
|
/// LDPCDEC field position
|
||||||
|
#define MDM_LDPCDEC_POS 27
|
||||||
|
/// LDPCENC field bit
|
||||||
|
#define MDM_LDPCENC_BIT ((u32)0x04000000)
|
||||||
|
/// LDPCENC field position
|
||||||
|
#define MDM_LDPCENC_POS 26
|
||||||
|
/// CHBW field mask
|
||||||
|
#define MDM_CHBW_MASK ((u32)0x03000000)
|
||||||
|
/// CHBW field LSB position
|
||||||
|
#define MDM_CHBW_LSB 24
|
||||||
|
/// CHBW field width
|
||||||
|
#define MDM_CHBW_WIDTH ((u32)0x00000002)
|
||||||
|
/// DSSSCCK field bit
|
||||||
|
#define MDM_DSSSCCK_BIT ((u32)0x00800000)
|
||||||
|
/// DSSSCCK field position
|
||||||
|
#define MDM_DSSSCCK_POS 23
|
||||||
|
/// VHT field bit
|
||||||
|
#define MDM_VHT_BIT ((u32)0x00400000)
|
||||||
|
/// VHT field position
|
||||||
|
#define MDM_VHT_POS 22
|
||||||
|
/// HE field bit
|
||||||
|
#define MDM_HE_BIT ((u32)0x00200000)
|
||||||
|
/// HE field position
|
||||||
|
#define MDM_HE_POS 21
|
||||||
|
/// ESS field bit
|
||||||
|
#define MDM_ESS_BIT ((u32)0x00100000)
|
||||||
|
/// ESS field position
|
||||||
|
#define MDM_ESS_POS 20
|
||||||
|
/// RFMODE field mask
|
||||||
|
#define MDM_RFMODE_MASK ((u32)0x000F0000)
|
||||||
|
/// RFMODE field LSB position
|
||||||
|
#define MDM_RFMODE_LSB 16
|
||||||
|
/// RFMODE field width
|
||||||
|
#define MDM_RFMODE_WIDTH ((u32)0x00000004)
|
||||||
|
/// NSTS field mask
|
||||||
|
#define MDM_NSTS_MASK ((u32)0x0000F000)
|
||||||
|
/// NSTS field LSB position
|
||||||
|
#define MDM_NSTS_LSB 12
|
||||||
|
/// NSTS field width
|
||||||
|
#define MDM_NSTS_WIDTH ((u32)0x00000004)
|
||||||
|
/// NSS field mask
|
||||||
|
#define MDM_NSS_MASK ((u32)0x00000F00)
|
||||||
|
/// NSS field LSB position
|
||||||
|
#define MDM_NSS_LSB 8
|
||||||
|
/// NSS field width
|
||||||
|
#define MDM_NSS_WIDTH ((u32)0x00000004)
|
||||||
|
/// NTX field mask
|
||||||
|
#define MDM_NTX_MASK ((u32)0x000000F0)
|
||||||
|
/// NTX field LSB position
|
||||||
|
#define MDM_NTX_LSB 4
|
||||||
|
/// NTX field width
|
||||||
|
#define MDM_NTX_WIDTH ((u32)0x00000004)
|
||||||
|
/// NRX field mask
|
||||||
|
#define MDM_NRX_MASK ((u32)0x0000000F)
|
||||||
|
/// NRX field LSB position
|
||||||
|
#define MDM_NRX_LSB 0
|
||||||
|
/// NRX field width
|
||||||
|
#define MDM_NRX_WIDTH ((u32)0x00000004)
|
||||||
|
|
||||||
|
#define __MDM_PHYCFG_FROM_VERS(v) (((v) & MDM_RFMODE_MASK) >> MDM_RFMODE_LSB)
|
||||||
|
|
||||||
|
#define RIU_FCU_PRESENT_MASK ((u32)0xFF000000)
|
||||||
|
#define RIU_FCU_PRESENT_LSB 24
|
||||||
|
|
||||||
|
#define __RIU_FCU_PRESENT(v) (((v) & RIU_FCU_PRESENT_MASK) >> RIU_FCU_PRESENT_LSB == 5)
|
||||||
|
|
||||||
|
/// AGC load version field mask
|
||||||
|
#define RIU_AGC_LOAD_MASK ((u32)0x00C00000)
|
||||||
|
/// AGC load version field LSB position
|
||||||
|
#define RIU_AGC_LOAD_LSB 22
|
||||||
|
|
||||||
|
#define __RIU_AGCLOAD_FROM_VERS(v) (((v) & RIU_AGC_LOAD_MASK) >> RIU_AGC_LOAD_LSB)
|
||||||
|
|
||||||
|
#define __FPGA_TYPE(v) (((v) & 0xFFFF0000) >> 16)
|
||||||
|
|
||||||
|
#define __MDM_MAJOR_VERSION(v) (((v) & 0xFF000000) >> 24)
|
||||||
|
#define __MDM_MINOR_VERSION(v) (((v) & 0x00FF0000) >> 16)
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _HAL_DESC_H_
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
*
|
||||||
|
* @file ipc_compat.h
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2011-2019
|
||||||
|
*
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _IPC_H_
|
||||||
|
#define _IPC_H_
|
||||||
|
|
||||||
|
#define __INLINE static __attribute__((__always_inline__)) inline
|
||||||
|
|
||||||
|
#define __ALIGN4 __aligned(4)
|
||||||
|
|
||||||
|
#define ASSERT_ERR(condition) \
|
||||||
|
do { \
|
||||||
|
if (unlikely(!(condition))) { \
|
||||||
|
printk(KERN_ERR "%s:%d:ASSERT_ERR(" #condition ")\n", __FILE__, __LINE__); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#endif /* _IPC_H_ */
|
||||||
@@ -0,0 +1,771 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file ipc_host.c
|
||||||
|
*
|
||||||
|
* @brief IPC module.
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2011-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* INCLUDE FILES
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
#ifndef __KERNEL__
|
||||||
|
#include <stdio.h>
|
||||||
|
#define REG_SW_SET_PROFILING(env, value) do{ }while(0)
|
||||||
|
#define REG_SW_CLEAR_PROFILING(env, value) do{ }while(0)
|
||||||
|
#define REG_SW_CLEAR_HOSTBUF_IDX_PROFILING(env) do{ }while(0)
|
||||||
|
#define REG_SW_SET_HOSTBUF_IDX_PROFILING(env, val) do{ }while(0)
|
||||||
|
#else
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include "rwnx_defs.h"
|
||||||
|
#include "rwnx_prof.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "reg_ipc_app.h"
|
||||||
|
#include "ipc_host.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TYPES DEFINITION
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
const int nx_txdesc_cnt[] =
|
||||||
|
{
|
||||||
|
NX_TXDESC_CNT0,
|
||||||
|
NX_TXDESC_CNT1,
|
||||||
|
NX_TXDESC_CNT2,
|
||||||
|
NX_TXDESC_CNT3,
|
||||||
|
#if NX_TXQ_CNT == 5
|
||||||
|
NX_TXDESC_CNT4,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
const int nx_txdesc_cnt_msk[] =
|
||||||
|
{
|
||||||
|
NX_TXDESC_CNT0 - 1,
|
||||||
|
NX_TXDESC_CNT1 - 1,
|
||||||
|
NX_TXDESC_CNT2 - 1,
|
||||||
|
NX_TXDESC_CNT3 - 1,
|
||||||
|
#if NX_TXQ_CNT == 5
|
||||||
|
NX_TXDESC_CNT4 - 1,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
const int nx_txuser_cnt[] =
|
||||||
|
{
|
||||||
|
CONFIG_USER_MAX,
|
||||||
|
CONFIG_USER_MAX,
|
||||||
|
CONFIG_USER_MAX,
|
||||||
|
CONFIG_USER_MAX,
|
||||||
|
#if NX_TXQ_CNT == 5
|
||||||
|
1,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FUNCTIONS DEFINITIONS
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* ipc_host_rxdesc_handler() - Handle the reception of a Rx Descriptor
|
||||||
|
*
|
||||||
|
* @env: pointer to the IPC Host environment
|
||||||
|
*
|
||||||
|
* Called from general IRQ handler when status %IPC_IRQ_E2A_RXDESC is set
|
||||||
|
*/
|
||||||
|
static void ipc_host_rxdesc_handler(struct ipc_host_env_tag *env)
|
||||||
|
{
|
||||||
|
// For profiling
|
||||||
|
REG_SW_SET_PROFILING(env->pthis, SW_PROF_IRQ_E2A_RXDESC);
|
||||||
|
|
||||||
|
// LMAC has triggered an IT saying that a reception has occurred.
|
||||||
|
// Then we first need to check the validity of the current hostbuf, and the validity
|
||||||
|
// of the next hostbufs too, because it is likely that several hostbufs have been
|
||||||
|
// filled within the time needed for this irq handling
|
||||||
|
do {
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
// call the external function to indicate that a RX descriptor is received
|
||||||
|
if (env->cb.recv_data_ind(env->pthis,
|
||||||
|
env->ipc_host_rxdesc_array[env->ipc_host_rxdesc_idx].hostid) != 0)
|
||||||
|
#else
|
||||||
|
// call the external function to indicate that a RX packet is received
|
||||||
|
if (env->cb.recv_data_ind(env->pthis,
|
||||||
|
env->ipc_host_rxbuf_array[env->ipc_host_rxbuf_idx].hostid) != 0)
|
||||||
|
#endif //(CONFIG_RWNX_FULLMAC)
|
||||||
|
break;
|
||||||
|
|
||||||
|
}while(1);
|
||||||
|
|
||||||
|
// For profiling
|
||||||
|
REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IRQ_E2A_RXDESC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ipc_host_radar_handler() - Handle the reception of radar events
|
||||||
|
*
|
||||||
|
* @env: pointer to the IPC Host environment
|
||||||
|
*
|
||||||
|
* Called from general IRQ handler when status %IPC_IRQ_E2A_RADAR is set
|
||||||
|
*/
|
||||||
|
static void ipc_host_radar_handler(struct ipc_host_env_tag *env)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_RWNX_RADAR
|
||||||
|
// LMAC has triggered an IT saying that a radar event has been sent to upper layer.
|
||||||
|
// Then we first need to check the validity of the current msg buf, and the validity
|
||||||
|
// of the next buffers too, because it is likely that several buffers have been
|
||||||
|
// filled within the time needed for this irq handling
|
||||||
|
// call the external function to indicate that a RX packet is received
|
||||||
|
spin_lock_bh(&((struct rwnx_hw *)env->pthis)->radar.lock);
|
||||||
|
while (env->cb.recv_radar_ind(env->pthis,
|
||||||
|
env->ipc_host_radarbuf_array[env->ipc_host_radarbuf_idx].hostid) == 0)
|
||||||
|
;
|
||||||
|
spin_unlock_bh(&((struct rwnx_hw *)env->pthis)->radar.lock);
|
||||||
|
#endif /* CONFIG_RWNX_RADAR */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ipc_host_unsup_rx_vec_handler() - Handle the reception of unsupported rx vector
|
||||||
|
*
|
||||||
|
* @env: pointer to the IPC Host environment
|
||||||
|
*
|
||||||
|
* Called from general IRQ handler when status %IPC_IRQ_E2A_UNSUP_RX_VEC is set
|
||||||
|
*/
|
||||||
|
static void ipc_host_unsup_rx_vec_handler(struct ipc_host_env_tag *env)
|
||||||
|
{
|
||||||
|
while (env->cb.recv_unsup_rx_vec_ind(env->pthis,
|
||||||
|
env->ipc_host_unsuprxvecbuf_array[env->ipc_host_unsuprxvecbuf_idx].hostid) == 0)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ipc_host_msg_handler() - Handler for firmware message
|
||||||
|
*
|
||||||
|
* @env: pointer to the IPC Host environment
|
||||||
|
*
|
||||||
|
* Called from general IRQ handler when status %IPC_IRQ_E2A_MSG is set
|
||||||
|
*/
|
||||||
|
static void ipc_host_msg_handler(struct ipc_host_env_tag *env)
|
||||||
|
{
|
||||||
|
// For profiling
|
||||||
|
REG_SW_SET_PROFILING(env->pthis, SW_PROF_IRQ_E2A_MSG);
|
||||||
|
|
||||||
|
// LMAC has triggered an IT saying that a message has been sent to upper layer.
|
||||||
|
// Then we first need to check the validity of the current msg buf, and the validity
|
||||||
|
// of the next buffers too, because it is likely that several buffers have been
|
||||||
|
// filled within the time needed for this irq handling
|
||||||
|
// call the external function to indicate that a RX packet is received
|
||||||
|
while (env->cb.recv_msg_ind(env->pthis,
|
||||||
|
env->ipc_host_msgbuf_array[env->ipc_host_msge2a_idx].hostid) == 0)
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
// For profiling
|
||||||
|
REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IRQ_E2A_MSG);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ipc_host_msgack_handler() - Handle the reception of message acknowledgement
|
||||||
|
*
|
||||||
|
* @env: pointer to the IPC Host environment
|
||||||
|
*
|
||||||
|
* Called from general IRQ handler when status %IPC_IRQ_E2A_MSG_ACK is set
|
||||||
|
*/
|
||||||
|
static void ipc_host_msgack_handler(struct ipc_host_env_tag *env)
|
||||||
|
{
|
||||||
|
void *hostid = env->msga2e_hostid;
|
||||||
|
|
||||||
|
ASSERT_ERR(hostid);
|
||||||
|
ASSERT_ERR(env->msga2e_cnt == (((struct lmac_msg *)(&env->shared->msg_a2e_buf.msg))->src_id & 0xFF));
|
||||||
|
|
||||||
|
env->msga2e_hostid = NULL;
|
||||||
|
env->msga2e_cnt++;
|
||||||
|
env->cb.recv_msgack_ind(env->pthis, hostid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ipc_host_dbg_handler() - Handle the reception of Debug event
|
||||||
|
*
|
||||||
|
* @env: pointer to the IPC Host environment
|
||||||
|
*
|
||||||
|
* Called from general IRQ handler when status %IPC_IRQ_E2A_DBG is set
|
||||||
|
*/
|
||||||
|
static void ipc_host_dbg_handler(struct ipc_host_env_tag *env)
|
||||||
|
{
|
||||||
|
// For profiling
|
||||||
|
REG_SW_SET_PROFILING(env->pthis, SW_PROF_IRQ_E2A_DBG);
|
||||||
|
|
||||||
|
// LMAC has triggered an IT saying that a DBG message has been sent to upper layer.
|
||||||
|
// Then we first need to check the validity of the current buffer, and the validity
|
||||||
|
// of the next buffers too, because it is likely that several buffers have been
|
||||||
|
// filled within the time needed for this irq handling
|
||||||
|
// call the external function to indicate that a RX packet is received
|
||||||
|
while(env->cb.recv_dbg_ind(env->pthis,
|
||||||
|
env->ipc_host_dbgbuf_array[env->ipc_host_dbg_idx].hostid) == 0)
|
||||||
|
;
|
||||||
|
|
||||||
|
// For profiling
|
||||||
|
REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IRQ_E2A_DBG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ipc_host_tx_cfm_handler() - Handle the reception of TX confirmation
|
||||||
|
*
|
||||||
|
* @env: pointer to the IPC Host environment
|
||||||
|
* @queue_idx: index of the hardware on which the confirmation has been received
|
||||||
|
* @user_pos: index of the user position
|
||||||
|
*
|
||||||
|
* Called from general IRQ handler when status %IPC_IRQ_E2A_TXCFM is set
|
||||||
|
*/
|
||||||
|
static void ipc_host_tx_cfm_handler(struct ipc_host_env_tag *env,
|
||||||
|
const int queue_idx, const int user_pos)
|
||||||
|
{
|
||||||
|
// TX confirmation descriptors have been received
|
||||||
|
REG_SW_SET_PROFILING(env->pthis, SW_PROF_IRQ_E2A_TXCFM);
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
// Get the used index and increase it. We do the increase before knowing if the
|
||||||
|
// current buffer is confirmed because the callback function may call the
|
||||||
|
// ipc_host_txdesc_get() in case flow control was enabled and the index has to be
|
||||||
|
// already at the good value to ensure that the test of FIFO full is correct
|
||||||
|
uint32_t used_idx = env->txdesc_used_idx[queue_idx][user_pos]++;
|
||||||
|
uint32_t used_idx_mod = used_idx & nx_txdesc_cnt_msk[queue_idx];
|
||||||
|
void *host_id = env->tx_host_id[queue_idx][user_pos][used_idx_mod];
|
||||||
|
|
||||||
|
// Reset the host id in the array
|
||||||
|
env->tx_host_id[queue_idx][user_pos][used_idx_mod] = 0;
|
||||||
|
|
||||||
|
// call the external function to indicate that a TX packet is freed
|
||||||
|
if (host_id == 0)
|
||||||
|
{
|
||||||
|
// No more confirmations, so put back the used index at its initial value
|
||||||
|
env->txdesc_used_idx[queue_idx][user_pos] = used_idx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env->cb.send_data_cfm(env->pthis, host_id) != 0)
|
||||||
|
{
|
||||||
|
// No more confirmations, so put back the used index at its initial value
|
||||||
|
env->txdesc_used_idx[queue_idx][user_pos] = used_idx;
|
||||||
|
env->tx_host_id[queue_idx][user_pos][used_idx_mod] = host_id;
|
||||||
|
// and exit the loop
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
REG_SW_SET_PROFILING_CHAN(env->pthis, SW_PROF_CHAN_CTXT_CFM_HDL_BIT);
|
||||||
|
REG_SW_CLEAR_PROFILING_CHAN(env->pthis, SW_PROF_CHAN_CTXT_CFM_HDL_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IRQ_E2A_TXCFM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
bool ipc_host_tx_frames_pending(struct ipc_host_env_tag *env)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
bool tx_frames_pending = false;
|
||||||
|
|
||||||
|
for (i = 0; (i < IPC_TXQUEUE_CNT) && !tx_frames_pending; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < nx_txuser_cnt[i]; j++)
|
||||||
|
{
|
||||||
|
uint32_t used_idx = env->txdesc_used_idx[i][j];
|
||||||
|
uint32_t free_idx = env->txdesc_free_idx[i][j];
|
||||||
|
|
||||||
|
// Check if this queue is empty or not
|
||||||
|
if (used_idx != free_idx)
|
||||||
|
{
|
||||||
|
// The queue is not empty, update the flag and exit
|
||||||
|
tx_frames_pending = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (tx_frames_pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
void *ipc_host_tx_flush(struct ipc_host_env_tag *env, const int queue_idx, const int user_pos)
|
||||||
|
{
|
||||||
|
uint32_t used_idx = env->txdesc_used_idx[queue_idx][user_pos];
|
||||||
|
void *host_id = env->tx_host_id[queue_idx][user_pos][used_idx & nx_txdesc_cnt_msk[queue_idx]];
|
||||||
|
|
||||||
|
// call the external function to indicate that a TX packet is freed
|
||||||
|
if (host_id != 0)
|
||||||
|
{
|
||||||
|
// Reset the host id in the array
|
||||||
|
env->tx_host_id[queue_idx][user_pos][used_idx & nx_txdesc_cnt_msk[queue_idx]] = 0;
|
||||||
|
|
||||||
|
// Increment the used index
|
||||||
|
env->txdesc_used_idx[queue_idx][user_pos]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (host_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
void ipc_host_init(struct ipc_host_env_tag *env,
|
||||||
|
struct ipc_host_cb_tag *cb,
|
||||||
|
struct ipc_shared_env_tag *shared_env_ptr,
|
||||||
|
void *pthis)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
unsigned int size;
|
||||||
|
unsigned int * dst;
|
||||||
|
|
||||||
|
// Reset the environments
|
||||||
|
// Reset the IPC Shared memory
|
||||||
|
#if 0
|
||||||
|
/* check potential platform bug on multiple stores */
|
||||||
|
memset(shared_env_ptr, 0, sizeof(struct ipc_shared_env_tag));
|
||||||
|
#else
|
||||||
|
dst = (unsigned int *)shared_env_ptr;
|
||||||
|
size = (unsigned int)sizeof(struct ipc_shared_env_tag);
|
||||||
|
for (i=0; i < size; i+=4)
|
||||||
|
{
|
||||||
|
*dst++ = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// Reset the IPC Host environment
|
||||||
|
memset(env, 0, sizeof(struct ipc_host_env_tag));
|
||||||
|
|
||||||
|
// Initialize the shared environment pointer
|
||||||
|
env->shared = shared_env_ptr;
|
||||||
|
|
||||||
|
// Save the callbacks in our own environment
|
||||||
|
env->cb = *cb;
|
||||||
|
|
||||||
|
// Save the pointer to the register base
|
||||||
|
env->pthis = pthis;
|
||||||
|
|
||||||
|
// Initialize buffers numbers and buffers sizes needed for DMA Receptions
|
||||||
|
env->rx_bufnb = IPC_RXBUF_CNT;
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
env->rxdesc_nb = IPC_RXDESC_CNT;
|
||||||
|
#endif //(CONFIG_RWNX_FULLMAC)
|
||||||
|
env->radar_bufnb = IPC_RADARBUF_CNT;
|
||||||
|
env->radar_bufsz = sizeof(struct radar_pulse_array_desc);
|
||||||
|
env->unsuprxvec_bufnb = IPC_UNSUPRXVECBUF_CNT;
|
||||||
|
env->unsuprxvec_bufsz = max(sizeof(struct rx_vector_desc), (size_t) RADIOTAP_HDR_MAX_LEN) +
|
||||||
|
RADIOTAP_HDR_VEND_MAX_LEN + UNSUP_RX_VEC_DATA_LEN;
|
||||||
|
env->ipc_e2amsg_bufnb = IPC_MSGE2A_BUF_CNT;
|
||||||
|
env->ipc_e2amsg_bufsz = sizeof(struct ipc_e2a_msg);
|
||||||
|
env->ipc_dbg_bufnb = IPC_DBGBUF_CNT;
|
||||||
|
env->ipc_dbg_bufsz = sizeof(struct ipc_dbg_msg);
|
||||||
|
|
||||||
|
for (i = 0; i < CONFIG_USER_MAX; i++)
|
||||||
|
{
|
||||||
|
// Initialize the pointers to the hostid arrays
|
||||||
|
env->tx_host_id[0][i] = env->tx_host_id0[i];
|
||||||
|
env->tx_host_id[1][i] = env->tx_host_id1[i];
|
||||||
|
env->tx_host_id[2][i] = env->tx_host_id2[i];
|
||||||
|
env->tx_host_id[3][i] = env->tx_host_id3[i];
|
||||||
|
#if NX_TXQ_CNT == 5
|
||||||
|
env->tx_host_id[4][i] = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Initialize the pointers to the TX descriptor arrays
|
||||||
|
env->txdesc[0][i] = shared_env_ptr->txdesc0[i];
|
||||||
|
env->txdesc[1][i] = shared_env_ptr->txdesc1[i];
|
||||||
|
env->txdesc[2][i] = shared_env_ptr->txdesc2[i];
|
||||||
|
env->txdesc[3][i] = shared_env_ptr->txdesc3[i];
|
||||||
|
#if NX_TXQ_CNT == 5
|
||||||
|
env->txdesc[4][i] = NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if NX_TXQ_CNT == 5
|
||||||
|
env->tx_host_id[4][0] = env->tx_host_id4[0];
|
||||||
|
env->txdesc[4][0] = shared_env_ptr->txdesc4[0];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
void ipc_host_patt_addr_push(struct ipc_host_env_tag *env, uint32_t addr)
|
||||||
|
{
|
||||||
|
struct ipc_shared_env_tag *shared_env_ptr = env->shared;
|
||||||
|
|
||||||
|
// Copy the address
|
||||||
|
shared_env_ptr->pattern_addr = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
int ipc_host_rxbuf_push(struct ipc_host_env_tag *env,
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
uint32_t hostid,
|
||||||
|
#endif
|
||||||
|
uint32_t hostbuf)
|
||||||
|
{
|
||||||
|
struct ipc_shared_env_tag *shared_env_ptr = env->shared;
|
||||||
|
|
||||||
|
REG_SW_CLEAR_HOSTBUF_IDX_PROFILING(env->pthis);
|
||||||
|
REG_SW_SET_HOSTBUF_IDX_PROFILING(env->pthis, env->ipc_host_rxbuf_idx);
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
// Copy the hostbuf (DMA address) in the ipc shared memory
|
||||||
|
shared_env_ptr->host_rxbuf[env->ipc_host_rxbuf_idx].hostid = hostid;
|
||||||
|
shared_env_ptr->host_rxbuf[env->ipc_host_rxbuf_idx].dma_addr = hostbuf;
|
||||||
|
#else
|
||||||
|
// Save the hostid and the hostbuf in global array
|
||||||
|
env->ipc_host_rxbuf_array[env->ipc_host_rxbuf_idx].hostid = hostid;
|
||||||
|
env->ipc_host_rxbuf_array[env->ipc_host_rxbuf_idx].dma_addr = hostbuf;
|
||||||
|
|
||||||
|
shared_env_ptr->host_rxbuf[env->ipc_host_rxbuf_idx] = hostbuf;
|
||||||
|
#endif //(CONFIG_RWNX_FULLMAC)
|
||||||
|
|
||||||
|
// Signal to the embedded CPU that at least one buffer is available
|
||||||
|
ipc_app2emb_trigger_set(shared_env_ptr, IPC_IRQ_A2E_RXBUF_BACK);
|
||||||
|
|
||||||
|
// Increment the array index
|
||||||
|
env->ipc_host_rxbuf_idx = (env->ipc_host_rxbuf_idx +1)%IPC_RXBUF_CNT;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
int ipc_host_rxdesc_push(struct ipc_host_env_tag *env, void *hostid,
|
||||||
|
uint32_t hostbuf)
|
||||||
|
{
|
||||||
|
struct ipc_shared_env_tag *shared_env_ptr = env->shared;
|
||||||
|
|
||||||
|
// Reset the RX Descriptor DMA Address and increment the counter
|
||||||
|
env->ipc_host_rxdesc_array[env->ipc_host_rxdesc_idx].dma_addr = hostbuf;
|
||||||
|
env->ipc_host_rxdesc_array[env->ipc_host_rxdesc_idx].hostid = hostid;
|
||||||
|
|
||||||
|
shared_env_ptr->host_rxdesc[env->ipc_host_rxdesc_idx].dma_addr = hostbuf;
|
||||||
|
|
||||||
|
// Signal to the embedded CPU that at least one descriptor is available
|
||||||
|
ipc_app2emb_trigger_set(shared_env_ptr, IPC_IRQ_A2E_RXDESC_BACK);
|
||||||
|
|
||||||
|
env->ipc_host_rxdesc_idx = (env->ipc_host_rxdesc_idx + 1) % IPC_RXDESC_CNT;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_RWNX_FULLMAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
int ipc_host_radarbuf_push(struct ipc_host_env_tag *env, void *hostid,
|
||||||
|
uint32_t hostbuf)
|
||||||
|
{
|
||||||
|
struct ipc_shared_env_tag *shared_env_ptr = env->shared;
|
||||||
|
|
||||||
|
// Save the hostid and the hostbuf in global array
|
||||||
|
env->ipc_host_radarbuf_array[env->ipc_host_radarbuf_idx].hostid = hostid;
|
||||||
|
env->ipc_host_radarbuf_array[env->ipc_host_radarbuf_idx].dma_addr = hostbuf;
|
||||||
|
|
||||||
|
// Copy the hostbuf (DMA address) in the ipc shared memory
|
||||||
|
shared_env_ptr->radarbuf_hostbuf[env->ipc_host_radarbuf_idx] = hostbuf;
|
||||||
|
|
||||||
|
// Increment the array index
|
||||||
|
env->ipc_host_radarbuf_idx = (env->ipc_host_radarbuf_idx +1)%IPC_RADARBUF_CNT;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ipc_host_unsup_rx_vec_buf_push(struct ipc_host_env_tag *env,
|
||||||
|
void *hostid,
|
||||||
|
uint32_t hostbuf)
|
||||||
|
{
|
||||||
|
struct ipc_shared_env_tag *shared_env_ptr = env->shared;
|
||||||
|
|
||||||
|
env->ipc_host_unsuprxvecbuf_array[env->ipc_host_unsuprxvecbuf_idx].hostid = hostid;
|
||||||
|
env->ipc_host_unsuprxvecbuf_array[env->ipc_host_unsuprxvecbuf_idx].dma_addr = hostbuf;
|
||||||
|
|
||||||
|
// Copy the hostbuf (DMA address) in the ipc shared memory
|
||||||
|
shared_env_ptr->unsuprxvecbuf_hostbuf[env->ipc_host_unsuprxvecbuf_idx] = hostbuf;
|
||||||
|
|
||||||
|
// Increment the array index
|
||||||
|
env->ipc_host_unsuprxvecbuf_idx = (env->ipc_host_unsuprxvecbuf_idx + 1)%IPC_UNSUPRXVECBUF_CNT;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
int ipc_host_msgbuf_push(struct ipc_host_env_tag *env, void *hostid,
|
||||||
|
uint32_t hostbuf)
|
||||||
|
{
|
||||||
|
struct ipc_shared_env_tag *shared_env_ptr = env->shared;
|
||||||
|
|
||||||
|
// Save the hostid and the hostbuf in global array
|
||||||
|
env->ipc_host_msgbuf_array[env->ipc_host_msge2a_idx].hostid = hostid;
|
||||||
|
env->ipc_host_msgbuf_array[env->ipc_host_msge2a_idx].dma_addr = hostbuf;
|
||||||
|
|
||||||
|
// Copy the hostbuf (DMA address) in the ipc shared memory
|
||||||
|
shared_env_ptr->msg_e2a_hostbuf_addr[env->ipc_host_msge2a_idx] = hostbuf;
|
||||||
|
|
||||||
|
// Increment the array index
|
||||||
|
env->ipc_host_msge2a_idx = (env->ipc_host_msge2a_idx +1)%IPC_MSGE2A_BUF_CNT;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
int ipc_host_dbgbuf_push(struct ipc_host_env_tag *env, void *hostid,
|
||||||
|
uint32_t hostbuf)
|
||||||
|
{
|
||||||
|
struct ipc_shared_env_tag *shared_env_ptr = env->shared;
|
||||||
|
|
||||||
|
// Save the hostid and the hostbuf in global array
|
||||||
|
env->ipc_host_dbgbuf_array[env->ipc_host_dbg_idx].hostid = hostid;
|
||||||
|
env->ipc_host_dbgbuf_array[env->ipc_host_dbg_idx].dma_addr = hostbuf;
|
||||||
|
|
||||||
|
// Copy the hostbuf (DMA address) in the ipc shared memory
|
||||||
|
shared_env_ptr->dbg_hostbuf_addr[env->ipc_host_dbg_idx] = hostbuf;
|
||||||
|
|
||||||
|
// Increment the array index
|
||||||
|
env->ipc_host_dbg_idx = (env->ipc_host_dbg_idx +1)%IPC_DBGBUF_CNT;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
void ipc_host_dbginfobuf_push(struct ipc_host_env_tag *env, uint32_t infobuf)
|
||||||
|
{
|
||||||
|
struct ipc_shared_env_tag *shared_env_ptr = env->shared;
|
||||||
|
|
||||||
|
// Copy the hostbuf (DMA address) in the ipc shared memory
|
||||||
|
shared_env_ptr->la_dbginfo_addr = infobuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
volatile struct txdesc_host *ipc_host_txdesc_get(struct ipc_host_env_tag *env, const int queue_idx, const int user_pos)
|
||||||
|
{
|
||||||
|
volatile struct txdesc_host *txdesc_free;
|
||||||
|
uint32_t used_idx = env->txdesc_used_idx[queue_idx][user_pos];
|
||||||
|
uint32_t free_idx = env->txdesc_free_idx[queue_idx][user_pos];
|
||||||
|
|
||||||
|
ASSERT_ERR(queue_idx < IPC_TXQUEUE_CNT);
|
||||||
|
ASSERT_ERR((free_idx - used_idx) <= nx_txdesc_cnt[queue_idx]);
|
||||||
|
|
||||||
|
// Check if a free descriptor is available
|
||||||
|
if (free_idx != (used_idx + nx_txdesc_cnt[queue_idx]))
|
||||||
|
{
|
||||||
|
// Get the pointer to the first free descriptor
|
||||||
|
txdesc_free = env->txdesc[queue_idx][user_pos] + (free_idx & nx_txdesc_cnt_msk[queue_idx]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
txdesc_free = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return txdesc_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
void ipc_host_txdesc_push(struct ipc_host_env_tag *env, const int queue_idx,
|
||||||
|
const int user_pos, void *host_id)
|
||||||
|
{
|
||||||
|
uint32_t free_idx = env->txdesc_free_idx[queue_idx][user_pos] & nx_txdesc_cnt_msk[queue_idx];
|
||||||
|
volatile struct txdesc_host *txdesc_pushed = env->txdesc[queue_idx][user_pos] + free_idx;
|
||||||
|
|
||||||
|
|
||||||
|
// Descriptor is now ready
|
||||||
|
txdesc_pushed->ready = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
// Save the host id in the environment
|
||||||
|
env->tx_host_id[queue_idx][user_pos][free_idx] = host_id;
|
||||||
|
|
||||||
|
// Increment the index
|
||||||
|
env->txdesc_free_idx[queue_idx][user_pos]++;
|
||||||
|
|
||||||
|
// trigger interrupt!!!
|
||||||
|
//REG_SW_SET_PROFILING(env->pthis, CO_BIT(queue_idx+SW_PROF_IRQ_A2E_TXDESC_FIRSTBIT));
|
||||||
|
ipc_app2emb_trigger_setf(env->shared, CO_BIT(user_pos + queue_idx * CONFIG_USER_MAX +
|
||||||
|
IPC_IRQ_A2E_TXDESC_FIRSTBIT));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
void ipc_host_irq(struct ipc_host_env_tag *env, uint32_t status)
|
||||||
|
{
|
||||||
|
// Acknowledge the pending interrupts
|
||||||
|
ipc_emb2app_ack_clear(env->shared, status);
|
||||||
|
// And re-read the status, just to be sure that the acknowledgment is
|
||||||
|
// effective when we start the interrupt handling
|
||||||
|
ipc_emb2app_status_get(env->shared);
|
||||||
|
|
||||||
|
// Optimized for only one IRQ at a time
|
||||||
|
if (status & IPC_IRQ_E2A_RXDESC)
|
||||||
|
{
|
||||||
|
// handle the RX descriptor reception
|
||||||
|
ipc_host_rxdesc_handler(env);
|
||||||
|
}
|
||||||
|
if (status & IPC_IRQ_E2A_MSG_ACK)
|
||||||
|
{
|
||||||
|
ipc_host_msgack_handler(env);
|
||||||
|
}
|
||||||
|
if (status & IPC_IRQ_E2A_MSG)
|
||||||
|
{
|
||||||
|
ipc_host_msg_handler(env);
|
||||||
|
}
|
||||||
|
if (status & IPC_IRQ_E2A_TXCFM)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
spin_lock_bh(&((struct rwnx_hw *)env->pthis)->tx_lock);
|
||||||
|
#endif
|
||||||
|
// handle the TX confirmation reception
|
||||||
|
for (i = 0; i < IPC_TXQUEUE_CNT; i++)
|
||||||
|
{
|
||||||
|
int j = 0;
|
||||||
|
#ifdef CONFIG_RWNX_MUMIMO_TX
|
||||||
|
for (; j < nx_txuser_cnt[i]; j++)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
uint32_t q_bit = CO_BIT(j + i * CONFIG_USER_MAX + IPC_IRQ_E2A_TXCFM_POS);
|
||||||
|
if (status & q_bit)
|
||||||
|
{
|
||||||
|
// handle the confirmation
|
||||||
|
ipc_host_tx_cfm_handler(env, i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
spin_unlock_bh(&((struct rwnx_hw *)env->pthis)->tx_lock);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (status & IPC_IRQ_E2A_RADAR)
|
||||||
|
{
|
||||||
|
// handle the radar event reception
|
||||||
|
ipc_host_radar_handler(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status & IPC_IRQ_E2A_UNSUP_RX_VEC)
|
||||||
|
{
|
||||||
|
// handle the unsupported rx vector reception
|
||||||
|
ipc_host_unsup_rx_vec_handler(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status & IPC_IRQ_E2A_DBG)
|
||||||
|
{
|
||||||
|
ipc_host_dbg_handler(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status & IPC_IRQ_E2A_TBTT_PRIM)
|
||||||
|
{
|
||||||
|
env->cb.prim_tbtt_ind(env->pthis);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status & IPC_IRQ_E2A_TBTT_SEC)
|
||||||
|
{
|
||||||
|
env->cb.sec_tbtt_ind(env->pthis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
int ipc_host_msg_push(struct ipc_host_env_tag *env, void *msg_buf, uint16_t len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint32_t *src, *dst;
|
||||||
|
|
||||||
|
REG_SW_SET_PROFILING(env->pthis, SW_PROF_IPC_MSGPUSH);
|
||||||
|
|
||||||
|
ASSERT_ERR(!env->msga2e_hostid);
|
||||||
|
ASSERT_ERR(round_up(len, 4) <= sizeof(env->shared->msg_a2e_buf.msg));
|
||||||
|
|
||||||
|
// Copy the message into the IPC MSG buffer
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
src = (uint32_t*)((struct rwnx_cmd *)msg_buf)->a2e_msg;
|
||||||
|
#else
|
||||||
|
src = (uint32_t*) msg_buf;
|
||||||
|
#endif
|
||||||
|
dst = (uint32_t*)&(env->shared->msg_a2e_buf.msg);
|
||||||
|
|
||||||
|
// Copy the message in the IPC queue
|
||||||
|
for (i=0; i<len; i+=4)
|
||||||
|
{
|
||||||
|
*dst++ = *src++;
|
||||||
|
}
|
||||||
|
|
||||||
|
env->msga2e_hostid = msg_buf;
|
||||||
|
|
||||||
|
// Trigger the irq to send the message to EMB
|
||||||
|
ipc_app2emb_trigger_set(env->shared, IPC_IRQ_A2E_MSG);
|
||||||
|
|
||||||
|
REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IPC_MSGPUSH);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
void ipc_host_enable_irq(struct ipc_host_env_tag *env, uint32_t value)
|
||||||
|
{
|
||||||
|
// Enable the handled interrupts
|
||||||
|
ipc_emb2app_unmask_set(env->shared, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
void ipc_host_disable_irq(struct ipc_host_env_tag *env, uint32_t value)
|
||||||
|
{
|
||||||
|
// Enable the handled interrupts
|
||||||
|
ipc_emb2app_unmask_clear(env->shared, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
uint32_t ipc_host_get_status(struct ipc_host_env_tag *env)
|
||||||
|
{
|
||||||
|
volatile uint32_t status;
|
||||||
|
|
||||||
|
status = ipc_emb2app_status_get(env->shared);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
uint32_t ipc_host_get_rawstatus(struct ipc_host_env_tag *env)
|
||||||
|
{
|
||||||
|
volatile uint32_t rawstatus;
|
||||||
|
|
||||||
|
rawstatus = ipc_emb2app_rawstatus_get(env->shared);
|
||||||
|
|
||||||
|
return rawstatus;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,508 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file ipc_host.h
|
||||||
|
*
|
||||||
|
* @brief IPC module.
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2011-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
#ifndef _IPC_HOST_H_
|
||||||
|
#define _IPC_HOST_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* INCLUDE FILES
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
#include "ipc_shared.h"
|
||||||
|
#ifndef __KERNEL__
|
||||||
|
#include "arch.h"
|
||||||
|
#else
|
||||||
|
#include "ipc_compat.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ENUMERATION
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum ipc_host_desc_status
|
||||||
|
{
|
||||||
|
/// Descriptor is IDLE
|
||||||
|
IPC_HOST_DESC_IDLE = 0,
|
||||||
|
/// Data can be forwarded
|
||||||
|
IPC_HOST_DESC_FORWARD,
|
||||||
|
/// Data has to be kept in UMAC memory
|
||||||
|
IPC_HOST_DESC_KEEP,
|
||||||
|
/// Delete stored packet
|
||||||
|
IPC_HOST_DESC_DELETE,
|
||||||
|
/// Update Frame Length status
|
||||||
|
IPC_HOST_DESC_LEN_UPDATE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief This structure is used to initialize the MAC SW
|
||||||
|
*
|
||||||
|
* The WLAN device driver provides functions call-back with this structure
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
struct ipc_host_cb_tag
|
||||||
|
{
|
||||||
|
/// WLAN driver call-back function: send_data_cfm
|
||||||
|
int (*send_data_cfm)(void *pthis, void *host_id);
|
||||||
|
|
||||||
|
/// WLAN driver call-back function: recv_data_ind
|
||||||
|
uint8_t (*recv_data_ind)(void *pthis, void *host_id);
|
||||||
|
|
||||||
|
/// WLAN driver call-back function: recv_radar_ind
|
||||||
|
uint8_t (*recv_radar_ind)(void *pthis, void *host_id);
|
||||||
|
|
||||||
|
/// WLAN driver call-back function: recv_unsup_rx_vec_ind
|
||||||
|
uint8_t (*recv_unsup_rx_vec_ind)(void *pthis, void *host_id);
|
||||||
|
|
||||||
|
/// WLAN driver call-back function: recv_msg_ind
|
||||||
|
uint8_t (*recv_msg_ind)(void *pthis, void *host_id);
|
||||||
|
|
||||||
|
/// WLAN driver call-back function: recv_msgack_ind
|
||||||
|
uint8_t (*recv_msgack_ind)(void *pthis, void *host_id);
|
||||||
|
|
||||||
|
/// WLAN driver call-back function: recv_dbg_ind
|
||||||
|
uint8_t (*recv_dbg_ind)(void *pthis, void *host_id);
|
||||||
|
|
||||||
|
/// WLAN driver call-back function: prim_tbtt_ind
|
||||||
|
void (*prim_tbtt_ind)(void *pthis);
|
||||||
|
|
||||||
|
/// WLAN driver call-back function: sec_tbtt_ind
|
||||||
|
void (*sec_tbtt_ind)(void *pthis);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Struct used to store information about host buffers (DMA Address and local pointer)
|
||||||
|
*/
|
||||||
|
struct ipc_hostbuf
|
||||||
|
{
|
||||||
|
void *hostid; ///< ptr to hostbuf client (ipc_host client) structure
|
||||||
|
uint32_t dma_addr; ///< ptr to real hostbuf dma address
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Definition of the IPC Host environment structure.
|
||||||
|
struct ipc_host_env_tag
|
||||||
|
{
|
||||||
|
/// Structure containing the callback pointers
|
||||||
|
struct ipc_host_cb_tag cb;
|
||||||
|
|
||||||
|
/// Pointer to the shared environment
|
||||||
|
struct ipc_shared_env_tag *shared;
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
// Array used to store the descriptor addresses
|
||||||
|
struct ipc_hostbuf ipc_host_rxdesc_array[IPC_RXDESC_CNT];
|
||||||
|
// Index of the host RX descriptor array (ipc_shared environment)
|
||||||
|
uint8_t ipc_host_rxdesc_idx;
|
||||||
|
/// Store the number of RX Descriptors
|
||||||
|
uint8_t rxdesc_nb;
|
||||||
|
#endif //(CONFIG_RWNX_FULLMAC)
|
||||||
|
|
||||||
|
/// Fields for Data Rx handling
|
||||||
|
// Index used for ipc_host_rxbuf_array to point to current buffer
|
||||||
|
uint8_t ipc_host_rxbuf_idx;
|
||||||
|
// Store the number of Rx Data buffers
|
||||||
|
uint32_t rx_bufnb;
|
||||||
|
// Store the size of the Rx Data buffers
|
||||||
|
uint32_t rx_bufsz;
|
||||||
|
|
||||||
|
/// Fields for Radar events handling
|
||||||
|
// Global array used to store the hostid and hostbuf addresses
|
||||||
|
struct ipc_hostbuf ipc_host_radarbuf_array[IPC_RADARBUF_CNT];
|
||||||
|
// Index used for ipc_host_rxbuf_array to point to current buffer
|
||||||
|
uint8_t ipc_host_radarbuf_idx;
|
||||||
|
// Store the number of radar event buffers
|
||||||
|
uint32_t radar_bufnb;
|
||||||
|
// Store the size of the radar event buffers
|
||||||
|
uint32_t radar_bufsz;
|
||||||
|
|
||||||
|
///Fields for Unsupported frame handling
|
||||||
|
// Global array used to store the hostid and hostbuf addresses
|
||||||
|
struct ipc_hostbuf ipc_host_unsuprxvecbuf_array[IPC_UNSUPRXVECBUF_CNT];
|
||||||
|
// Index used for ipc_host_unsuprxvecbuf_array to point to current buffer
|
||||||
|
uint8_t ipc_host_unsuprxvecbuf_idx;
|
||||||
|
// Store the number of unsupported rx vector buffers
|
||||||
|
uint32_t unsuprxvec_bufnb;
|
||||||
|
// Store the size of unsupported rx vector buffers
|
||||||
|
uint32_t unsuprxvec_bufsz;
|
||||||
|
|
||||||
|
// Index used that points to the first free TX desc
|
||||||
|
uint32_t txdesc_free_idx[IPC_TXQUEUE_CNT][CONFIG_USER_MAX];
|
||||||
|
// Index used that points to the first used TX desc
|
||||||
|
uint32_t txdesc_used_idx[IPC_TXQUEUE_CNT][CONFIG_USER_MAX];
|
||||||
|
// Array storing the currently pushed host ids for the BK queue
|
||||||
|
void *tx_host_id0[CONFIG_USER_MAX][NX_TXDESC_CNT0];
|
||||||
|
// Array storing the currently pushed host ids for the BE queue
|
||||||
|
void *tx_host_id1[CONFIG_USER_MAX][NX_TXDESC_CNT1];
|
||||||
|
// Array storing the currently pushed host ids for the VI queue
|
||||||
|
void *tx_host_id2[CONFIG_USER_MAX][NX_TXDESC_CNT2];
|
||||||
|
// Array storing the currently pushed host ids for the VO queue
|
||||||
|
void *tx_host_id3[CONFIG_USER_MAX][NX_TXDESC_CNT3];
|
||||||
|
#if NX_TXQ_CNT == 5
|
||||||
|
// Array storing the currently pushed host ids for the BCN queue
|
||||||
|
void *tx_host_id4[1][NX_TXDESC_CNT4];
|
||||||
|
#endif
|
||||||
|
// Pointer to the different host ids arrays, per IPC queue
|
||||||
|
void **tx_host_id[IPC_TXQUEUE_CNT][CONFIG_USER_MAX];
|
||||||
|
// Pointer to the different TX descriptor arrays, per IPC queue
|
||||||
|
volatile struct txdesc_host *txdesc[IPC_TXQUEUE_CNT][CONFIG_USER_MAX];
|
||||||
|
|
||||||
|
/// Fields for Emb->App MSGs handling
|
||||||
|
// Global array used to store the hostid and hostbuf addresses for msg/ind
|
||||||
|
struct ipc_hostbuf ipc_host_msgbuf_array[IPC_MSGE2A_BUF_CNT];
|
||||||
|
// Index of the MSG E2A buffers array to point to current buffer
|
||||||
|
uint8_t ipc_host_msge2a_idx;
|
||||||
|
// Store the number of E2A MSG buffers
|
||||||
|
uint32_t ipc_e2amsg_bufnb;
|
||||||
|
// Store the size of the E2A MSG buffers
|
||||||
|
uint32_t ipc_e2amsg_bufsz;
|
||||||
|
|
||||||
|
/// E2A ACKs of A2E MSGs
|
||||||
|
uint8_t msga2e_cnt;
|
||||||
|
void *msga2e_hostid;
|
||||||
|
|
||||||
|
/// Fields for Debug MSGs handling
|
||||||
|
// Global array used to store the hostid and hostbuf addresses for Debug messages
|
||||||
|
struct ipc_hostbuf ipc_host_dbgbuf_array[IPC_DBGBUF_CNT];
|
||||||
|
// Index of the Debug messages buffers array to point to current buffer
|
||||||
|
uint8_t ipc_host_dbg_idx;
|
||||||
|
// Store the number of Debug messages buffers
|
||||||
|
uint32_t ipc_dbg_bufnb;
|
||||||
|
// Store the size of the Debug messages buffers
|
||||||
|
uint32_t ipc_dbg_bufsz;
|
||||||
|
|
||||||
|
/// Pointer to the attached object (used in callbacks and register accesses)
|
||||||
|
void *pthis;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const int nx_txdesc_cnt[];
|
||||||
|
extern const int nx_txuser_cnt[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief Returns the full/not full status of the queue the index of which is
|
||||||
|
* passed as parameter.
|
||||||
|
*
|
||||||
|
* @param[in] env Pointer to the IPC host environment
|
||||||
|
* @param[in] queue_idx Index of the queue to be checked
|
||||||
|
*
|
||||||
|
* @return true if the queue is full, false otherwise
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
__INLINE bool ipc_host_queue_full(struct ipc_host_env_tag *env,
|
||||||
|
const int queue_idx)
|
||||||
|
{
|
||||||
|
return (env->txdesc_free_idx[queue_idx] ==
|
||||||
|
(env->txdesc_used_idx[queue_idx] + nx_txdesc_cnt[queue_idx]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief Initialize the IPC running on the Application CPU.
|
||||||
|
*
|
||||||
|
* This function:
|
||||||
|
* - initializes the IPC software environments
|
||||||
|
* - enables the interrupts in the IPC block
|
||||||
|
*
|
||||||
|
* @param[in] env Pointer to the IPC host environment
|
||||||
|
*
|
||||||
|
* @warning Since this function resets the IPC Shared memory, it must be called
|
||||||
|
* before the LMAC FW is launched because LMAC sets some init values in IPC
|
||||||
|
* Shared memory at boot.
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
void ipc_host_init(struct ipc_host_env_tag *env,
|
||||||
|
struct ipc_host_cb_tag *cb,
|
||||||
|
struct ipc_shared_env_tag *shared_env_ptr,
|
||||||
|
void *pthis);
|
||||||
|
|
||||||
|
/** @addtogroup IPC_TX
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief Retrieve a new free Tx descriptor (host side).
|
||||||
|
*
|
||||||
|
* This function returns a pointer to the next Tx descriptor available from the
|
||||||
|
* queue queue_idx to the host driver. The driver will have to fill it with the
|
||||||
|
* appropriate endianness and to send it to the
|
||||||
|
* emb side with ipc_host_txdesc_push().
|
||||||
|
*
|
||||||
|
* This function should only be called once until ipc_host_txdesc_push() is called.
|
||||||
|
*
|
||||||
|
* This function will return NULL if the queue is full.
|
||||||
|
*
|
||||||
|
* @param[in] env Pointer to the IPC host environment
|
||||||
|
* @param[in] queue_idx Queue index. The index can be inferred from the
|
||||||
|
* user priority of the incoming packet.
|
||||||
|
* @param[in] user_pos User position. If MU-MIMO is not used, this value
|
||||||
|
* shall be 0.
|
||||||
|
* @return Pointer to the next Tx descriptor free. This can
|
||||||
|
* point to the host memory or to shared memory,
|
||||||
|
* depending on IPC implementation.
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
volatile struct txdesc_host *ipc_host_txdesc_get(struct ipc_host_env_tag *env,
|
||||||
|
const int queue_idx,
|
||||||
|
const int user_pos);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief Push a filled Tx descriptor (host side).
|
||||||
|
*
|
||||||
|
* This function sets the next Tx descriptor available by the host side:
|
||||||
|
* - as used for the host side
|
||||||
|
* - as available for the emb side.
|
||||||
|
* The Tx descriptor must be correctly filled before calling this function.
|
||||||
|
*
|
||||||
|
* This function may trigger an IRQ to the emb CPU depending on the interrupt
|
||||||
|
* mitigation policy and on the push count.
|
||||||
|
*
|
||||||
|
* @param[in] env Pointer to the IPC host environment
|
||||||
|
* @param[in] queue_idx Queue index. Same value than ipc_host_txdesc_get()
|
||||||
|
* @param[in] user_pos User position. If MU-MIMO is not used, this value
|
||||||
|
* shall be 0.
|
||||||
|
* @param[in] host_id Parameter indicated by the IPC at TX confirmation,
|
||||||
|
* that allows the driver finding the buffer
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
void ipc_host_txdesc_push(struct ipc_host_env_tag *env, const int queue_idx,
|
||||||
|
const int user_pos, void *host_id);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief Check if there are TX frames pending in the TX queues.
|
||||||
|
*
|
||||||
|
* @param[in] env Pointer to the IPC host environment
|
||||||
|
*
|
||||||
|
* @return true if there are frames pending, false otherwise.
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
bool ipc_host_tx_frames_pending(struct ipc_host_env_tag *env);
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief Get and flush a packet from the IPC queue passed as parameter.
|
||||||
|
*
|
||||||
|
* @param[in] env Pointer to the IPC host environment
|
||||||
|
* @param[in] queue_idx Index of the queue to flush
|
||||||
|
* @param[in] user_pos User position to flush
|
||||||
|
*
|
||||||
|
* @return The flushed hostid if there is one, 0 otherwise.
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
void *ipc_host_tx_flush(struct ipc_host_env_tag *env, const int queue_idx,
|
||||||
|
const int user_pos);
|
||||||
|
|
||||||
|
/// @} IPC_TX
|
||||||
|
|
||||||
|
/** @addtogroup IPC_RX
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
void ipc_host_patt_addr_push(struct ipc_host_env_tag *env, uint32_t addr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief Push a pre-allocated buffer descriptor for Rx packet (host side)
|
||||||
|
*
|
||||||
|
* This function should be called by the host IRQ handler to supply the
|
||||||
|
* embedded side with new empty buffer.
|
||||||
|
*
|
||||||
|
* @param[in] env Pointer to the IPC host environment
|
||||||
|
* @param[in] hostid Packet ID used by the host (skbuff pointer on Linux)
|
||||||
|
* @param[in] hostbuf Pointer to the start of the buffer payload in the
|
||||||
|
* host memory (this may be inferred from the skbuff?)
|
||||||
|
* The length of this buffer should be predefined
|
||||||
|
* between host and emb statically (constant needed?).
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
int ipc_host_rxbuf_push(struct ipc_host_env_tag *env,
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
uint32_t hostid,
|
||||||
|
#endif
|
||||||
|
uint32_t hostbuf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief Push a pre-allocated Descriptor
|
||||||
|
*
|
||||||
|
* This function should be called by the host IRQ handler to supply the
|
||||||
|
* embedded side with new empty buffer.
|
||||||
|
*
|
||||||
|
* @param[in] env Pointer to the IPC host environment
|
||||||
|
* @param[in] hostid Address of packet for host
|
||||||
|
* @param[in] hostbuf Pointer to the start of the buffer payload in the
|
||||||
|
* host memory. The length of this buffer should be
|
||||||
|
* predefined between host and emb statically.
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
int ipc_host_rxdesc_push(struct ipc_host_env_tag *env, void *hostid,
|
||||||
|
uint32_t hostbuf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief Push a pre-allocated radar event buffer descriptor
|
||||||
|
*
|
||||||
|
* This function is called at Init time to initialize all radar event buffers.
|
||||||
|
* Then each time embedded send a radar event, this function is used to push
|
||||||
|
* back the same buffer once it has been handled.
|
||||||
|
*
|
||||||
|
* @param[in] env Pointer to the IPC host environment
|
||||||
|
* @param[in] hostid Address of packet for host
|
||||||
|
* @param[in] hostbuf Pointer to the start of the buffer payload in the
|
||||||
|
* host memory. The length of this buffer should be
|
||||||
|
* predefined between host and emb statically.
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
int ipc_host_radarbuf_push(struct ipc_host_env_tag *env, void *hostid,
|
||||||
|
uint32_t hostbuf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief Push a pre-allocated unsupported rx vector buffer descriptor
|
||||||
|
*
|
||||||
|
* This function is called at Init time to initialize all unsupported rx vector
|
||||||
|
* buffers. Then each time the embedded sends a unsupported rx vector, this
|
||||||
|
* function is used to push a new unsupported rx vector buffer.
|
||||||
|
*
|
||||||
|
* @param[in] env Pointer to the IPC host environment
|
||||||
|
* @param[in] hostid Address of packet for host
|
||||||
|
* @param[in] hostbuf Pointer to the start of the buffer payload in the
|
||||||
|
* host memory. The length of this buffer should be
|
||||||
|
* predefined between host and emb statically.
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
int ipc_host_unsup_rx_vec_buf_push(struct ipc_host_env_tag *env, void *hostid,
|
||||||
|
uint32_t hostbuf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief Push a pre-allocated buffer descriptor for IPC MSGs (host side)
|
||||||
|
*
|
||||||
|
* This function is called at Init time to initialize all Emb2App messages
|
||||||
|
* buffers. Then each time embedded send a IPC message, this function is used
|
||||||
|
* to push back the same buffer once it has been handled.
|
||||||
|
*
|
||||||
|
* @param[in] env Pointer to the IPC host environment
|
||||||
|
* @param[in] hostid Address of buffer for host
|
||||||
|
* @param[in] hostbuf Address of buffer for embedded
|
||||||
|
* The length of this buffer should be predefined
|
||||||
|
* between host and emb statically.
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
int ipc_host_msgbuf_push(struct ipc_host_env_tag *env, void *hostid,
|
||||||
|
uint32_t hostbuf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief Push a pre-allocated buffer descriptor for Debug messages (host side)
|
||||||
|
*
|
||||||
|
* This function is called at Init time to initialize all debug messages.
|
||||||
|
* Then each time embedded send a debug message, this function is used to push
|
||||||
|
* back the same buffer once it has been handled.
|
||||||
|
*
|
||||||
|
* @param[in] env Pointer to the IPC host environment
|
||||||
|
* @param[in] hostid Address of buffer for host
|
||||||
|
* @param[in] hostbuf Address of buffer for embedded
|
||||||
|
* The length of this buffer should be predefined
|
||||||
|
* between host and emb statically.
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
int ipc_host_dbgbuf_push(struct ipc_host_env_tag *env, void *hostid,
|
||||||
|
uint32_t hostbuf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief Push the pre-allocated logic analyzer and debug information buffer
|
||||||
|
*
|
||||||
|
* @param[in] env Pointer to the IPC host environment
|
||||||
|
* @param[in] infobuf Address of buffer for embedded
|
||||||
|
* The length of this buffer should be predefined
|
||||||
|
* between host and emb statically.
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
void ipc_host_dbginfobuf_push(struct ipc_host_env_tag *env, uint32_t infobuf);
|
||||||
|
|
||||||
|
/// @} IPC_RX
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** @addtogroup IPC_MISC
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief Handle all IPC interrupts on the host side.
|
||||||
|
*
|
||||||
|
* The following interrupts should be handled:
|
||||||
|
* Tx confirmation, Rx buffer requests, Rx packet ready and kernel messages
|
||||||
|
*
|
||||||
|
* @param[in] env Pointer to the IPC host environment
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
void ipc_host_irq(struct ipc_host_env_tag *env, uint32_t status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief Send a message to the embedded side
|
||||||
|
*
|
||||||
|
* @param[in] env Pointer to the IPC host environment
|
||||||
|
* @param[in] msg_buf Pointer to the message buffer
|
||||||
|
* @param[in] msg_len Length of the message to be transmitted
|
||||||
|
*
|
||||||
|
* @return Non-null value on failure
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
int ipc_host_msg_push(struct ipc_host_env_tag *env, void *msg_buf, uint16_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief Enable IPC interrupts
|
||||||
|
*
|
||||||
|
* @param[in] env Global ipc_host environment pointer
|
||||||
|
* @param[in] value Bitfield of the interrupts to enable
|
||||||
|
*
|
||||||
|
* @warning After calling this function, IPC interrupts can be triggered at any
|
||||||
|
* time. Potentially, an interrupt could happen even before returning from the
|
||||||
|
* function if there is a request pending from the embedded side.
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
void ipc_host_enable_irq(struct ipc_host_env_tag *env, uint32_t value);
|
||||||
|
void ipc_host_disable_irq(struct ipc_host_env_tag *env, uint32_t value);
|
||||||
|
|
||||||
|
uint32_t ipc_host_get_status(struct ipc_host_env_tag *env);
|
||||||
|
uint32_t ipc_host_get_rawstatus(struct ipc_host_env_tag *env);
|
||||||
|
|
||||||
|
/// @} IPC_MISC
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _IPC_HOST_H_
|
||||||
@@ -0,0 +1,802 @@
|
|||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
*
|
||||||
|
* @file ipc_shared.h
|
||||||
|
*
|
||||||
|
* @brief Shared data between both IPC modules.
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2011-2019
|
||||||
|
*
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _IPC_SHARED_H_
|
||||||
|
#define _IPC_SHARED_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* INCLUDE FILES
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
#include "ipc_compat.h"
|
||||||
|
#include "lmac_mac.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DEFINES AND MACROS
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
#define CO_BIT(pos) (1U<<(pos))
|
||||||
|
|
||||||
|
#define IPC_TXQUEUE_CNT NX_TXQ_CNT
|
||||||
|
#define NX_TXDESC_CNT0 8
|
||||||
|
#define NX_TXDESC_CNT1 64
|
||||||
|
#define NX_TXDESC_CNT2 64
|
||||||
|
#define NX_TXDESC_CNT3 32
|
||||||
|
#if NX_TXQ_CNT == 5
|
||||||
|
#define NX_TXDESC_CNT4 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of Host buffers available for Data Rx handling (through DMA)
|
||||||
|
*/
|
||||||
|
#define IPC_RXBUF_CNT 128
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of shared descriptors available for Data RX handling
|
||||||
|
*/
|
||||||
|
#define IPC_RXDESC_CNT 128
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of Host buffers available for Radar events handling (through DMA)
|
||||||
|
*/
|
||||||
|
#define IPC_RADARBUF_CNT 16
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of Host buffers available for unsupported Rx vectors handling (through DMA)
|
||||||
|
*/
|
||||||
|
#define IPC_UNSUPRXVECBUF_CNT 8
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Size of RxVector
|
||||||
|
*/
|
||||||
|
#define IPC_RXVEC_SIZE 16
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of Host buffers available for Emb->App MSGs sending (through DMA)
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
#define IPC_MSGE2A_BUF_CNT 64
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Number of Host buffers available for Debug Messages sending (through DMA)
|
||||||
|
*/
|
||||||
|
#define IPC_DBGBUF_CNT 32
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Length used in MSGs structures
|
||||||
|
*/
|
||||||
|
#define IPC_A2E_MSG_BUF_SIZE 127 // size in 4-byte words
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
#define IPC_E2A_MSG_SIZE_BASE 256 // size in 4-byte words
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_TL4
|
||||||
|
#define IPC_E2A_MSG_PARAM_SIZE (IPC_E2A_MSG_SIZE_BASE + (IPC_E2A_MSG_SIZE_BASE / 2))
|
||||||
|
#else
|
||||||
|
#define IPC_E2A_MSG_PARAM_SIZE IPC_E2A_MSG_SIZE_BASE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Debug messages buffers size (in bytes)
|
||||||
|
*/
|
||||||
|
#define IPC_DBG_PARAM_SIZE 256
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define used for Rx hostbuf validity.
|
||||||
|
* This value should appear only when hostbuf was used for a Reception.
|
||||||
|
*/
|
||||||
|
#define RX_DMA_OVER_PATTERN 0xAAAAAA00
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define used for MSG buffers validity.
|
||||||
|
* This value will be written only when a MSG buffer is used for sending from Emb to App.
|
||||||
|
*/
|
||||||
|
#define IPC_MSGE2A_VALID_PATTERN 0xADDEDE2A
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define used for Debug messages buffers validity.
|
||||||
|
* This value will be written only when a DBG buffer is used for sending from Emb to App.
|
||||||
|
*/
|
||||||
|
#define IPC_DBG_VALID_PATTERN 0x000CACA0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Length of the receive vectors, in bytes
|
||||||
|
*/
|
||||||
|
#define DMA_HDR_PHYVECT_LEN 36
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximum number of payload addresses and lengths present in the descriptor
|
||||||
|
*/
|
||||||
|
#define NX_TX_PAYLOAD_MAX 6
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Message struct/ID API version
|
||||||
|
*/
|
||||||
|
#define MSG_API_VER 15
|
||||||
|
|
||||||
|
/*
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
// c.f LMAC/src/tx/tx_swdesc.h
|
||||||
|
/// Descriptor filled by the Host
|
||||||
|
struct hostdesc
|
||||||
|
{
|
||||||
|
/// Pointer to packet payload
|
||||||
|
//u32_l packet_addr;
|
||||||
|
/// Size of the payload
|
||||||
|
u16_l packet_len;
|
||||||
|
u16_l flags_ext;
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
/// Address of the status descriptor in host memory (used for confirmation upload)
|
||||||
|
u32_l status_desc_addr;
|
||||||
|
/// Destination Address
|
||||||
|
struct mac_addr eth_dest_addr;
|
||||||
|
/// Source Address
|
||||||
|
struct mac_addr eth_src_addr;
|
||||||
|
/// Ethernet Type
|
||||||
|
u16_l ethertype;
|
||||||
|
#else /* ! CONFIG_RWNX_FULLMAC */
|
||||||
|
#ifdef CONFIG_RWNX_AGG_TX
|
||||||
|
///Sequence Number for AMPDU MPDUs - for quick check if it's allowed within window
|
||||||
|
u16_l sn;
|
||||||
|
#endif /* CONFIG_RWNX_AGG_TX */
|
||||||
|
/// Padding between the buffer control structure and the MPDU in host memory
|
||||||
|
u8_l padding;
|
||||||
|
#endif /* CONFIG_RWNX_FULLMAC */
|
||||||
|
u8_l ac;
|
||||||
|
/// Packet TID (0xFF if not a QoS frame)
|
||||||
|
u8_l tid;
|
||||||
|
/// Interface Id
|
||||||
|
u8_l vif_idx;
|
||||||
|
/// Station Id (0xFF if station is unknown)
|
||||||
|
u8_l staid;
|
||||||
|
#ifdef CONFIG_RWNX_MUMIMO_TX
|
||||||
|
/// MU-MIMO information (GroupId and User Position in the group) - The GroupId
|
||||||
|
/// is located on bits 0-5 and the User Position on bits 6-7. The GroupId value is set
|
||||||
|
/// to 63 if MU-MIMO shall not be used
|
||||||
|
u8_l mumimo_info;
|
||||||
|
#endif /* CONFIG_RWNX_MUMIMO_TX */
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
/// TX flags
|
||||||
|
u16_l flags;
|
||||||
|
#endif /* CONFIG_RWNX_FULLMAC */
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Descriptor filled by the UMAC
|
||||||
|
struct umacdesc
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_RWNX_AGG_TX
|
||||||
|
///First Sequence Number of the BlockAck window
|
||||||
|
u16_l sn_win;
|
||||||
|
/// Flags from UMAC (match tx_hd.macctrlinfo2 format)
|
||||||
|
u32_l flags;
|
||||||
|
/// PHY related flags field - rate, GI type, BW type - filled by driver
|
||||||
|
u32_l phy_flags;
|
||||||
|
#endif //(CONFIG_RWNX_AGG_TX)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct txdesc_api
|
||||||
|
{
|
||||||
|
/// Information provided by Host
|
||||||
|
struct hostdesc host;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct txdesc_host
|
||||||
|
{
|
||||||
|
u32_l ready;
|
||||||
|
|
||||||
|
/// API of the embedded part
|
||||||
|
struct txdesc_api api;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Comes from ipc_dma.h
|
||||||
|
/// Element in the pool of TX DMA bridge descriptors.
|
||||||
|
struct dma_desc
|
||||||
|
{
|
||||||
|
/** Application subsystem address which is used as source address for DMA payload
|
||||||
|
* transfer*/
|
||||||
|
u32_l src;
|
||||||
|
/** Points to the start of the embedded data buffer associated with this descriptor.
|
||||||
|
* This address acts as the destination address for the DMA payload transfer*/
|
||||||
|
u32_l dest;
|
||||||
|
/// Complete length of the buffer in memory
|
||||||
|
u16_l length;
|
||||||
|
/// Control word for the DMA engine (e.g. for interrupt generation)
|
||||||
|
u16_l ctrl;
|
||||||
|
/// Pointer to the next element of the chained list
|
||||||
|
u32_l next;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Comes from la.h
|
||||||
|
/// Length of the configuration data of a logic analyzer
|
||||||
|
#define LA_CONF_LEN 10
|
||||||
|
|
||||||
|
/// Structure containing the configuration data of a logic analyzer
|
||||||
|
struct la_conf_tag
|
||||||
|
{
|
||||||
|
u32_l conf[LA_CONF_LEN];
|
||||||
|
u32_l trace_len;
|
||||||
|
u32_l diag_conf;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Size of a logic analyzer memory
|
||||||
|
#define LA_MEM_LEN (1024 * 1024)
|
||||||
|
|
||||||
|
/// Type of errors
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
/// Recoverable error, not requiring any action from Upper MAC
|
||||||
|
DBG_ERROR_RECOVERABLE = 0,
|
||||||
|
/// Fatal error, requiring Upper MAC to reset Lower MAC and HW and restart operation
|
||||||
|
DBG_ERROR_FATAL
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Maximum length of the SW diag trace
|
||||||
|
#define DBG_SW_DIAG_MAX_LEN 1024
|
||||||
|
|
||||||
|
/// Maximum length of the error trace
|
||||||
|
#define DBG_ERROR_TRACE_SIZE 256
|
||||||
|
|
||||||
|
/// Number of MAC diagnostic port banks
|
||||||
|
#define DBG_DIAGS_MAC_MAX 48
|
||||||
|
|
||||||
|
/// Number of PHY diagnostic port banks
|
||||||
|
#define DBG_DIAGS_PHY_MAX 32
|
||||||
|
|
||||||
|
/// Maximum size of the RX header descriptor information in the debug dump
|
||||||
|
#define DBG_RHD_MEM_LEN (5 * 1024)
|
||||||
|
|
||||||
|
/// Maximum size of the RX buffer descriptor information in the debug dump
|
||||||
|
#define DBG_RBD_MEM_LEN (5 * 1024)
|
||||||
|
|
||||||
|
/// Maximum size of the TX header descriptor information in the debug dump
|
||||||
|
#define DBG_THD_MEM_LEN (10 * 1024)
|
||||||
|
|
||||||
|
/// Structure containing the information about the PHY channel that is used
|
||||||
|
struct phy_channel_info
|
||||||
|
{
|
||||||
|
/// PHY channel information 1
|
||||||
|
u32_l info1;
|
||||||
|
/// PHY channel information 2
|
||||||
|
u32_l info2;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Debug information forwarded to host when an error occurs
|
||||||
|
struct dbg_debug_info_tag
|
||||||
|
{
|
||||||
|
/// Type of error (0: recoverable, 1: fatal)
|
||||||
|
u32_l error_type;
|
||||||
|
/// Pointer to the first RX Header Descriptor chained to the MAC HW
|
||||||
|
u32_l rhd;
|
||||||
|
/// Size of the RX header descriptor buffer
|
||||||
|
u32_l rhd_len;
|
||||||
|
/// Pointer to the first RX Buffer Descriptor chained to the MAC HW
|
||||||
|
u32_l rbd;
|
||||||
|
/// Size of the RX buffer descriptor buffer
|
||||||
|
u32_l rbd_len;
|
||||||
|
/// Pointer to the first TX Header Descriptors chained to the MAC HW
|
||||||
|
u32_l thd[NX_TXQ_CNT];
|
||||||
|
/// Size of the TX header descriptor buffer
|
||||||
|
u32_l thd_len[NX_TXQ_CNT];
|
||||||
|
/// MAC HW diag configuration
|
||||||
|
u32_l hw_diag;
|
||||||
|
/// Error message
|
||||||
|
u32_l error[DBG_ERROR_TRACE_SIZE/4];
|
||||||
|
/// SW diag configuration length
|
||||||
|
u32_l sw_diag_len;
|
||||||
|
/// SW diag configuration
|
||||||
|
u32_l sw_diag[DBG_SW_DIAG_MAX_LEN/4];
|
||||||
|
/// PHY channel information
|
||||||
|
struct phy_channel_info chan_info;
|
||||||
|
/// Embedded LA configuration
|
||||||
|
struct la_conf_tag la_conf;
|
||||||
|
/// MAC diagnostic port state
|
||||||
|
u16_l diags_mac[DBG_DIAGS_MAC_MAX];
|
||||||
|
/// PHY diagnostic port state
|
||||||
|
u16_l diags_phy[DBG_DIAGS_PHY_MAX];
|
||||||
|
/// MAC HW RX Header descriptor pointer
|
||||||
|
u32_l rhd_hw_ptr;
|
||||||
|
/// MAC HW RX Buffer descriptor pointer
|
||||||
|
u32_l rbd_hw_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Full debug dump that is forwarded to host in case of error
|
||||||
|
struct dbg_debug_dump_tag
|
||||||
|
{
|
||||||
|
/// Debug information
|
||||||
|
struct dbg_debug_info_tag dbg_info;
|
||||||
|
|
||||||
|
/// RX header descriptor memory
|
||||||
|
u32_l rhd_mem[DBG_RHD_MEM_LEN/4];
|
||||||
|
|
||||||
|
/// RX buffer descriptor memory
|
||||||
|
u32_l rbd_mem[DBG_RBD_MEM_LEN/4];
|
||||||
|
|
||||||
|
/// TX header descriptor memory
|
||||||
|
u32_l thd_mem[NX_TXQ_CNT][DBG_THD_MEM_LEN/4];
|
||||||
|
|
||||||
|
/// Logic analyzer memory
|
||||||
|
u32_l la_mem[LA_MEM_LEN/4];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Number of pulses in a radar event structure
|
||||||
|
#define RADAR_PULSE_MAX 4
|
||||||
|
|
||||||
|
/// Definition of an array of radar pulses
|
||||||
|
struct radar_pulse_array_desc
|
||||||
|
{
|
||||||
|
/// Buffer containing the radar pulses
|
||||||
|
u32_l pulse[RADAR_PULSE_MAX];
|
||||||
|
/// Index of the radar detection chain that detected those pulses
|
||||||
|
u32_l idx;
|
||||||
|
/// Number of valid pulses in the buffer
|
||||||
|
u32_l cnt;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Bit mapping inside a radar pulse element
|
||||||
|
struct radar_pulse {
|
||||||
|
s32_l freq:6; /** Freq (resolution is 2Mhz range is [-Fadc/4 .. Fadc/4]) */
|
||||||
|
u32_l fom:4; /** Figure of Merit */
|
||||||
|
u32_l len:6; /** Length of the current radar pulse (resolution is 2us) */
|
||||||
|
u32_l rep:16; /** Time interval between the previous radar event
|
||||||
|
and the current one (in us) */
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Definition of a RX vector descriptor
|
||||||
|
struct rx_vector_desc
|
||||||
|
{
|
||||||
|
/// PHY channel information
|
||||||
|
struct phy_channel_info phy_info;
|
||||||
|
|
||||||
|
/// RX vector 1
|
||||||
|
u32_l rx_vect1[IPC_RXVEC_SIZE/4];
|
||||||
|
|
||||||
|
/// Used to print a valid rx vector
|
||||||
|
u32_l pattern;
|
||||||
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
struct rxdesc_tag
|
||||||
|
{
|
||||||
|
/// Host Buffer Address
|
||||||
|
u32_l host_id;
|
||||||
|
/// Length
|
||||||
|
u32_l frame_len;
|
||||||
|
/// Status
|
||||||
|
u16_l status;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
* @defgroup IPC IPC
|
||||||
|
* @ingroup NXMAC
|
||||||
|
* @brief Inter Processor Communication module.
|
||||||
|
*
|
||||||
|
* The IPC module implements the protocol to communicate between the Host CPU
|
||||||
|
* and the Embedded CPU.
|
||||||
|
*
|
||||||
|
* @see http://en.wikipedia.org/wiki/Circular_buffer
|
||||||
|
* For more information about the ring buffer typical use and difficulties.
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
* @addtogroup IPC_TX IPC Tx path
|
||||||
|
* @ingroup IPC
|
||||||
|
* @brief IPC Tx path structures and functions
|
||||||
|
*
|
||||||
|
* A typical use case of the IPC Tx path API:
|
||||||
|
* @msc
|
||||||
|
* hscale = "2";
|
||||||
|
*
|
||||||
|
* a [label=Driver],
|
||||||
|
* b [label="IPC host"],
|
||||||
|
* c [label="IPC emb"],
|
||||||
|
* d [label=Firmware];
|
||||||
|
*
|
||||||
|
* --- [label="Tx descriptor queue example"];
|
||||||
|
* a=>a [label="Driver receives a Tx packet from OS"];
|
||||||
|
* a=>b [label="ipc_host_txdesc_get()"];
|
||||||
|
* a<<b [label="struct txdesc_host *"];
|
||||||
|
* a=>a [label="Driver fill the descriptor"];
|
||||||
|
* a=>b [label="ipc_host_txdesc_push()"];
|
||||||
|
* ... [label="(several Tx desc can be pushed)"];
|
||||||
|
* b:>c [label="Tx desc queue filled IRQ"];
|
||||||
|
* c=>>d [label="EDCA sub-scheduler callback"];
|
||||||
|
* c<<d [label="Tx desc queue to pop"];
|
||||||
|
* c=>>d [label="UMAC Tx desc callback"];
|
||||||
|
* ... [label="(several Tx desc can be popped)"];
|
||||||
|
* d=>d [label="Packets are sent or discarded"];
|
||||||
|
* --- [label="Tx confirm queue example"];
|
||||||
|
* c<=d [label="ipc_emb_txcfm_push()"];
|
||||||
|
* c>>d [label="Request accepted"];
|
||||||
|
* ... [label="(several Tx cfm can be pushed)"];
|
||||||
|
* b<:c [label="Tx cfm queue filled IRQ"];
|
||||||
|
* a<<=b [label="Driver's Tx Confirm callback"];
|
||||||
|
* a=>b [label="ipc_host_txcfm_pop()"];
|
||||||
|
* a<<b [label="struct ipc_txcfm"];
|
||||||
|
* a<=a [label="Packets are freed by the driver"];
|
||||||
|
* @endmsc
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// @} IPC_TX
|
||||||
|
|
||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
* @defgroup IPC_RX IPC Rx path
|
||||||
|
* @ingroup IPC
|
||||||
|
* @brief IPC Rx path functions and structures
|
||||||
|
*
|
||||||
|
* A typical use case of the IPC Rx path API:
|
||||||
|
* @msc
|
||||||
|
* hscale = "2";
|
||||||
|
*
|
||||||
|
* a [label=Firmware],
|
||||||
|
* b [label="IPC emb"],
|
||||||
|
* c [label="IPC host"],
|
||||||
|
* d [label=Driver];
|
||||||
|
*
|
||||||
|
* --- [label="Rx buffer and desc queues usage example"];
|
||||||
|
* d=>c [label="ipc_host_rxbuf_push()"];
|
||||||
|
* d=>c [label="ipc_host_rxbuf_push()"];
|
||||||
|
* d=>c [label="ipc_host_rxbuf_push()"];
|
||||||
|
* ... [label="(several Rx buffer are pushed)"];
|
||||||
|
* a=>a [label=" Frame is received\n from the medium"];
|
||||||
|
* a<<b [label="struct ipc_rxbuf"];
|
||||||
|
* a=>a [label=" Firmware fill the buffer\n with received frame"];
|
||||||
|
* a<<b [label="Push accepted"];
|
||||||
|
* ... [label="(several Rx desc can be pushed)"];
|
||||||
|
* b:>c [label="Rx desc queue filled IRQ"];
|
||||||
|
* c=>>d [label="Driver Rx packet callback"];
|
||||||
|
* c<=d [label="ipc_host_rxdesc_pop()"];
|
||||||
|
* d=>d [label="Rx packet is handed \nover to the OS "];
|
||||||
|
* ... [label="(several Rx desc can be poped)"];
|
||||||
|
* --- [label="Rx buffer request exemple"];
|
||||||
|
* b:>c [label="Low Rx buffer count IRQ"];
|
||||||
|
* a<<b [label="struct ipc_rxbuf"];
|
||||||
|
* c=>>d [label="Driver Rx buffer callback"];
|
||||||
|
* d=>c [label="ipc_host_rxbuf_push()"];
|
||||||
|
* d=>c [label="ipc_host_rxbuf_push()"];
|
||||||
|
* d=>c [label="ipc_host_rxbuf_push()"];
|
||||||
|
* ... [label="(several Rx buffer are pushed)"];
|
||||||
|
* @endmsc
|
||||||
|
*
|
||||||
|
* @addtogroup IPC_RX
|
||||||
|
* @{
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// @} IPC_RX
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
* @defgroup IPC_MISC IPC Misc
|
||||||
|
* @ingroup IPC
|
||||||
|
* @brief IPC miscellaneous functions
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
/** IPC header structure. This structure is stored at the beginning of every IPC message.
|
||||||
|
* @warning This structure's size must NOT exceed 4 bytes in length.
|
||||||
|
*/
|
||||||
|
struct ipc_header
|
||||||
|
{
|
||||||
|
/// IPC message type.
|
||||||
|
u16_l type;
|
||||||
|
/// IPC message size in number of bytes.
|
||||||
|
u16_l size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ipc_msg_elt
|
||||||
|
{
|
||||||
|
/// Message header (alignment forced on word size, see allocation in shared env).
|
||||||
|
struct ipc_header header __ALIGN4;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Message structure for MSGs from Emb to App
|
||||||
|
struct ipc_e2a_msg
|
||||||
|
{
|
||||||
|
u16_l id; ///< Message id.
|
||||||
|
u16_l dummy_dest_id;
|
||||||
|
u16_l dummy_src_id;
|
||||||
|
u16_l param_len; ///< Parameter embedded struct length.
|
||||||
|
u32_l pattern; ///< Used to stamp a valid MSG buffer
|
||||||
|
u32_l param[IPC_E2A_MSG_PARAM_SIZE]; ///< Parameter embedded struct. Must be word-aligned.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Message structure for Debug messages from Emb to App
|
||||||
|
struct ipc_dbg_msg
|
||||||
|
{
|
||||||
|
u32_l string[IPC_DBG_PARAM_SIZE/4]; ///< Debug string
|
||||||
|
u32_l pattern; ///< Used to stamp a valid buffer
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Message structure for MSGs from App to Emb.
|
||||||
|
/// Actually a sub-structure will be used when filling the messages.
|
||||||
|
struct ipc_a2e_msg
|
||||||
|
{
|
||||||
|
u32_l dummy_word; // used to cope with kernel message structure
|
||||||
|
u32_l msg[IPC_A2E_MSG_BUF_SIZE]; // body of the msg
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ipc_shared_rx_buf
|
||||||
|
{
|
||||||
|
/// < ptr to hostbuf client (ipc_host client) structure
|
||||||
|
u32_l hostid;
|
||||||
|
/// < ptr to real hostbuf dma address
|
||||||
|
u32_l dma_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ipc_shared_rx_desc
|
||||||
|
{
|
||||||
|
/// DMA Address
|
||||||
|
u32_l dma_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Structure containing FW characteristics for compatibility checking
|
||||||
|
struct compatibility_tag {
|
||||||
|
/// Size of IPC shared memory
|
||||||
|
u16_l ipc_shared_size;
|
||||||
|
/// Message struct/ID API version
|
||||||
|
u16_l msg_api;
|
||||||
|
/// Version of IPC shared
|
||||||
|
u8_l ipc_shared_version;
|
||||||
|
/// Number of host buffers available for Emb->App MSGs sending
|
||||||
|
u8_l msge2a_buf_cnt;
|
||||||
|
/// Number of host buffers available for Debug Messages sending
|
||||||
|
u8_l dbgbuf_cnt;
|
||||||
|
/// Number of host buffers available for Radar events handling
|
||||||
|
u8_l radarbuf_cnt;
|
||||||
|
/// Number of host buffers available for unsupported Rx vectors handling
|
||||||
|
u8_l unsuprxvecbuf_cnt;
|
||||||
|
/// Number of shared descriptors available for Data RX handling
|
||||||
|
u8_l rxdesc_cnt;
|
||||||
|
/// Number of host buffers available for Data Rx handling
|
||||||
|
u8_l rxbuf_cnt;
|
||||||
|
/// Number of descriptors in BK TX queue (power of 2, min 4, max 64)
|
||||||
|
u8_l bk_txq;
|
||||||
|
/// Number of descriptors in BE TX queue (power of 2, min 4, max 64)
|
||||||
|
u8_l be_txq;
|
||||||
|
/// Number of descriptors in VI TX queue (power of 2, min 4, max 64)
|
||||||
|
u8_l vi_txq;
|
||||||
|
/// Number of descriptors in VO TX queue (power of 2, min 4, max 64)
|
||||||
|
u8_l vo_txq;
|
||||||
|
/// Number of descriptors in BCN TX queue (power of 2, min 4, max 64)
|
||||||
|
u8_l bcn_txq;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TYPE and STRUCT DEFINITIONS
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// Indexes are defined in the MIB shared structure
|
||||||
|
struct ipc_shared_env_tag
|
||||||
|
{
|
||||||
|
volatile struct compatibility_tag comp_info; //FW characteristics
|
||||||
|
|
||||||
|
volatile struct ipc_a2e_msg msg_a2e_buf; // room for MSG to be sent from App to Emb
|
||||||
|
|
||||||
|
// Fields for MSGs sending from Emb to App
|
||||||
|
volatile struct ipc_e2a_msg msg_e2a_buf; // room to build the MSG to be DMA Xferred
|
||||||
|
volatile struct dma_desc msg_dma_desc; // DMA descriptor for Emb->App MSGs Xfers
|
||||||
|
volatile u32_l msg_e2a_hostbuf_addr [IPC_MSGE2A_BUF_CNT]; // buffers @ for DMA Xfers
|
||||||
|
|
||||||
|
// Fields for Debug MSGs sending from Emb to App
|
||||||
|
volatile struct ipc_dbg_msg dbg_buf; // room to build the MSG to be DMA Xferred
|
||||||
|
volatile struct dma_desc dbg_dma_desc; // DMA descriptor for Emb->App MSGs Xfers
|
||||||
|
volatile u32_l dbg_hostbuf_addr [IPC_DBGBUF_CNT]; // buffers @ for MSGs DMA Xfers
|
||||||
|
volatile u32_l la_dbginfo_addr; // Host buffer address for the debug information
|
||||||
|
volatile u32_l pattern_addr;
|
||||||
|
volatile u32_l radarbuf_hostbuf [IPC_RADARBUF_CNT]; // buffers @ for Radar Events
|
||||||
|
volatile u32_l unsuprxvecbuf_hostbuf [IPC_UNSUPRXVECBUF_CNT]; // buffers @ for unsupported Rx vectors
|
||||||
|
volatile struct txdesc_host txdesc0[CONFIG_USER_MAX][NX_TXDESC_CNT0];
|
||||||
|
volatile struct txdesc_host txdesc1[CONFIG_USER_MAX][NX_TXDESC_CNT1];
|
||||||
|
volatile struct txdesc_host txdesc2[CONFIG_USER_MAX][NX_TXDESC_CNT2];
|
||||||
|
volatile struct txdesc_host txdesc3[CONFIG_USER_MAX][NX_TXDESC_CNT3];
|
||||||
|
#if NX_TXQ_CNT == 5
|
||||||
|
volatile struct txdesc_host txdesc4[1][NX_TXDESC_CNT4];
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
// RX Descriptors Array
|
||||||
|
volatile struct ipc_shared_rx_desc host_rxdesc[IPC_RXDESC_CNT];
|
||||||
|
// RX Buffers Array
|
||||||
|
volatile struct ipc_shared_rx_buf host_rxbuf[IPC_RXBUF_CNT];
|
||||||
|
#else
|
||||||
|
// buffers @ for Data Rx
|
||||||
|
volatile u32_l host_rxbuf[IPC_RXBUF_CNT];
|
||||||
|
#endif /* CONFIG_RWNX_FULLMAC */
|
||||||
|
|
||||||
|
u32_l buffered[NX_REMOTE_STA_MAX][TID_MAX];
|
||||||
|
|
||||||
|
volatile uint16_t trace_pattern;
|
||||||
|
volatile uint32_t trace_start;
|
||||||
|
volatile uint32_t trace_end;
|
||||||
|
volatile uint32_t trace_size;
|
||||||
|
volatile uint32_t trace_offset;
|
||||||
|
volatile uint32_t trace_nb_compo;
|
||||||
|
volatile uint32_t trace_offset_compo;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct ipc_shared_env_tag ipc_shared_env;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TYPE and STRUCT DEFINITIONS
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
// IRQs from app to emb
|
||||||
|
/// Interrupts bits used for the TX descriptors of the AC queues
|
||||||
|
#ifdef CONFIG_RWNX_MUMIMO_TX
|
||||||
|
#ifdef CONFIG_RWNX_OLD_IPC
|
||||||
|
#error "MU-MIMO cannot be compiled for old IPC"
|
||||||
|
#endif
|
||||||
|
/// Interrupts bits used
|
||||||
|
#if CONFIG_USER_MAX > 3
|
||||||
|
#define IPC_IRQ_A2E_USER_MSK 0xF
|
||||||
|
#elif CONFIG_USER_MAX > 2
|
||||||
|
#define IPC_IRQ_A2E_USER_MSK 0x7
|
||||||
|
#else
|
||||||
|
#define IPC_IRQ_A2E_USER_MSK 0x3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Offset of the interrupts for AC0
|
||||||
|
#define IPC_IRQ_A2E_AC0_OFT 8
|
||||||
|
/// Mask of the interrupts for AC0
|
||||||
|
#define IPC_IRQ_A2E_AC0_MSK (IPC_IRQ_A2E_USER_MSK << IPC_IRQ_A2E_AC0_OFT)
|
||||||
|
/// Offset of the interrupts for AC1
|
||||||
|
#define IPC_IRQ_A2E_AC1_OFT (IPC_IRQ_A2E_AC0_OFT + CONFIG_USER_MAX)
|
||||||
|
/// Mask of the interrupts for AC1
|
||||||
|
#define IPC_IRQ_A2E_AC1_MSK (IPC_IRQ_A2E_USER_MSK << IPC_IRQ_A2E_AC1_OFT)
|
||||||
|
/// Offset of the interrupts for AC2
|
||||||
|
#define IPC_IRQ_A2E_AC2_OFT (IPC_IRQ_A2E_AC1_OFT + CONFIG_USER_MAX)
|
||||||
|
/// Mask of the interrupts for AC2
|
||||||
|
#define IPC_IRQ_A2E_AC2_MSK (IPC_IRQ_A2E_USER_MSK << IPC_IRQ_A2E_AC2_OFT)
|
||||||
|
/// Offset of the interrupts for AC3
|
||||||
|
#define IPC_IRQ_A2E_AC3_OFT (IPC_IRQ_A2E_AC2_OFT + CONFIG_USER_MAX)
|
||||||
|
/// Mask of the interrupts for AC3
|
||||||
|
#define IPC_IRQ_A2E_AC3_MSK (IPC_IRQ_A2E_USER_MSK << IPC_IRQ_A2E_AC3_OFT)
|
||||||
|
/// Offset of the interrupts for BCN
|
||||||
|
#define IPC_IRQ_A2E_BCN_OFT (IPC_IRQ_A2E_AC3_OFT + CONFIG_USER_MAX)
|
||||||
|
/// Mask of the interrupts for BCN
|
||||||
|
#define IPC_IRQ_A2E_BCN_MSK CO_BIT(IPC_IRQ_A2E_BCN_OFT)
|
||||||
|
|
||||||
|
#define IPC_IRQ_A2E_AC_TXDESC (IPC_IRQ_A2E_AC0_MSK | IPC_IRQ_A2E_AC1_MSK | \
|
||||||
|
IPC_IRQ_A2E_AC2_MSK | IPC_IRQ_A2E_AC3_MSK)
|
||||||
|
|
||||||
|
/// Interrupts bits used for the TX descriptors of the BCN queue
|
||||||
|
#if NX_TXQ_CNT < 5
|
||||||
|
#define IPC_IRQ_A2E_BCN_TXDESC 0
|
||||||
|
#else
|
||||||
|
#define IPC_IRQ_A2E_BCN_TXDESC (0x01 << IPC_IRQ_A2E_BCN_OFT)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// IPC TX descriptor interrupt mask
|
||||||
|
#define IPC_IRQ_A2E_TXDESC (IPC_IRQ_A2E_AC_TXDESC | IPC_IRQ_A2E_BCN_TXDESC)
|
||||||
|
#else
|
||||||
|
/// IPC TX descriptor interrupt mask
|
||||||
|
#define IPC_IRQ_A2E_TXDESC 0xFF00
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define IPC_IRQ_A2E_TXDESC_FIRSTBIT (8)
|
||||||
|
#define IPC_IRQ_A2E_RXBUF_BACK CO_BIT(5)
|
||||||
|
#define IPC_IRQ_A2E_RXDESC_BACK CO_BIT(4)
|
||||||
|
|
||||||
|
#define IPC_IRQ_A2E_MSG CO_BIT(1)
|
||||||
|
#define IPC_IRQ_A2E_DBG CO_BIT(0)
|
||||||
|
|
||||||
|
#define IPC_IRQ_A2E_ALL (IPC_IRQ_A2E_TXDESC|IPC_IRQ_A2E_MSG|IPC_IRQ_A2E_DBG)
|
||||||
|
|
||||||
|
// IRQs from emb to app
|
||||||
|
#define IPC_IRQ_E2A_TXCFM_POS 7
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_MUMIMO_TX
|
||||||
|
#ifdef CONFIG_RWNX_OLD_IPC
|
||||||
|
#error "MU-MIMO cannot be compiled for old IPC"
|
||||||
|
#endif
|
||||||
|
/// Interrupts bits used
|
||||||
|
#if CONFIG_USER_MAX > 3
|
||||||
|
#define IPC_IRQ_E2A_USER_MSK 0xF
|
||||||
|
#elif CONFIG_USER_MAX > 2
|
||||||
|
#define IPC_IRQ_E2A_USER_MSK 0x7
|
||||||
|
#else
|
||||||
|
#define IPC_IRQ_E2A_USER_MSK 0x3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Offset of the interrupts for AC0
|
||||||
|
#define IPC_IRQ_E2A_AC0_OFT IPC_IRQ_E2A_TXCFM_POS
|
||||||
|
/// Mask of the interrupts for AC0
|
||||||
|
#define IPC_IRQ_E2A_AC0_MSK (IPC_IRQ_E2A_USER_MSK << IPC_IRQ_E2A_AC0_OFT)
|
||||||
|
/// Offset of the interrupts for AC1
|
||||||
|
#define IPC_IRQ_E2A_AC1_OFT (IPC_IRQ_E2A_AC0_OFT + CONFIG_USER_MAX)
|
||||||
|
/// Mask of the interrupts for AC1
|
||||||
|
#define IPC_IRQ_E2A_AC1_MSK (IPC_IRQ_E2A_USER_MSK << IPC_IRQ_E2A_AC1_OFT)
|
||||||
|
/// Offset of the interrupts for AC2
|
||||||
|
#define IPC_IRQ_E2A_AC2_OFT (IPC_IRQ_E2A_AC1_OFT + CONFIG_USER_MAX)
|
||||||
|
/// Mask of the interrupts for AC2
|
||||||
|
#define IPC_IRQ_E2A_AC2_MSK (IPC_IRQ_E2A_USER_MSK << IPC_IRQ_E2A_AC2_OFT)
|
||||||
|
/// Offset of the interrupts for AC3
|
||||||
|
#define IPC_IRQ_E2A_AC3_OFT (IPC_IRQ_E2A_AC2_OFT + CONFIG_USER_MAX)
|
||||||
|
/// Mask of the interrupts for AC3
|
||||||
|
#define IPC_IRQ_E2A_AC3_MSK (IPC_IRQ_E2A_USER_MSK << IPC_IRQ_E2A_AC3_OFT)
|
||||||
|
/// Offset of the interrupts for BCN
|
||||||
|
#define IPC_IRQ_E2A_BCN_OFT (IPC_IRQ_E2A_AC3_OFT + CONFIG_USER_MAX)
|
||||||
|
/// Mask of the interrupts for BCN
|
||||||
|
#define IPC_IRQ_E2A_BCN_MSK CO_BIT(IPC_IRQ_E2A_BCN_OFT)
|
||||||
|
|
||||||
|
#define IPC_IRQ_E2A_AC_TXCFM (IPC_IRQ_E2A_AC0_MSK | IPC_IRQ_E2A_AC1_MSK | \
|
||||||
|
IPC_IRQ_E2A_AC2_MSK | IPC_IRQ_E2A_AC3_MSK)
|
||||||
|
|
||||||
|
/// Interrupts bits used for the TX descriptors of the BCN queue
|
||||||
|
#if NX_TXQ_CNT < 5
|
||||||
|
#define IPC_IRQ_E2A_BCN_TXCFM 0
|
||||||
|
#else
|
||||||
|
#define IPC_IRQ_E2A_BCN_TXCFM (0x01 << IPC_IRQ_E2A_BCN_OFT)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// IPC TX descriptor interrupt mask
|
||||||
|
#define IPC_IRQ_E2A_TXCFM (IPC_IRQ_E2A_AC_TXCFM | IPC_IRQ_E2A_BCN_TXCFM)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define IPC_IRQ_E2A_TXCFM ((1 << NX_TXQ_CNT) - 1 ) << IPC_IRQ_E2A_TXCFM_POS
|
||||||
|
|
||||||
|
#endif /* CONFIG_RWNX_MUMIMO_TX */
|
||||||
|
|
||||||
|
#define IPC_IRQ_E2A_UNSUP_RX_VEC CO_BIT(7)
|
||||||
|
#define IPC_IRQ_E2A_RADAR CO_BIT(6)
|
||||||
|
#define IPC_IRQ_E2A_TBTT_SEC CO_BIT(5)
|
||||||
|
#define IPC_IRQ_E2A_TBTT_PRIM CO_BIT(4)
|
||||||
|
#define IPC_IRQ_E2A_RXDESC CO_BIT(3)
|
||||||
|
#define IPC_IRQ_E2A_MSG_ACK CO_BIT(2)
|
||||||
|
#define IPC_IRQ_E2A_MSG CO_BIT(1)
|
||||||
|
#define IPC_IRQ_E2A_DBG CO_BIT(0)
|
||||||
|
|
||||||
|
#define IPC_IRQ_E2A_ALL ( IPC_IRQ_E2A_TXCFM \
|
||||||
|
| IPC_IRQ_E2A_RXDESC \
|
||||||
|
| IPC_IRQ_E2A_MSG_ACK \
|
||||||
|
| IPC_IRQ_E2A_MSG \
|
||||||
|
| IPC_IRQ_E2A_DBG \
|
||||||
|
| IPC_IRQ_E2A_TBTT_PRIM \
|
||||||
|
| IPC_IRQ_E2A_TBTT_SEC \
|
||||||
|
| IPC_IRQ_E2A_RADAR \
|
||||||
|
| IPC_IRQ_E2A_UNSUP_RX_VEC)
|
||||||
|
|
||||||
|
// FLAGS for RX desc
|
||||||
|
#define IPC_RX_FORWARD CO_BIT(1)
|
||||||
|
#define IPC_RX_INTRABSS CO_BIT(0)
|
||||||
|
|
||||||
|
|
||||||
|
// IPC message TYPE
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
IPC_MSG_NONE = 0,
|
||||||
|
IPC_MSG_WRAP,
|
||||||
|
IPC_MSG_KMSG,
|
||||||
|
|
||||||
|
IPC_DBG_STRING,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _IPC_SHARED_H_
|
||||||
|
|
||||||
@@ -0,0 +1,588 @@
|
|||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
*
|
||||||
|
* @file lmac_mac_types.h
|
||||||
|
*
|
||||||
|
* @brief MAC related definitions.
|
||||||
|
*
|
||||||
|
* Adapted from mac_types.h to used lmac_types.h instead of standard types
|
||||||
|
* eg: perl -pi -e '$_ =~ s/uint(\d{1,2})_t/u$1_l/g; \
|
||||||
|
* $_ =~ s/int(\d{1,2})_t/s$1_l/g; \
|
||||||
|
* $_ =~ s/CO_BIT/BIT/g;' lmac_mac.h
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2011-2019
|
||||||
|
*
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LMAC_MAC_H_
|
||||||
|
#define LMAC_MAC_H_
|
||||||
|
|
||||||
|
#include "lmac_types.h"
|
||||||
|
|
||||||
|
/// Interface types
|
||||||
|
enum mac_vif_type
|
||||||
|
{
|
||||||
|
/// ESS STA interface
|
||||||
|
VIF_STA,
|
||||||
|
/// IBSS STA interface
|
||||||
|
VIF_IBSS,
|
||||||
|
/// AP interface
|
||||||
|
VIF_AP,
|
||||||
|
/// Mesh Point interface
|
||||||
|
VIF_MESH_POINT,
|
||||||
|
/// Monitor interface
|
||||||
|
VIF_MONITOR,
|
||||||
|
/// Unknown type
|
||||||
|
VIF_UNKNOWN
|
||||||
|
};
|
||||||
|
|
||||||
|
/// MAC address length in bytes.
|
||||||
|
#define MAC_ADDR_LEN 6
|
||||||
|
|
||||||
|
/// MAC address structure.
|
||||||
|
struct mac_addr
|
||||||
|
{
|
||||||
|
/// Array of 16-bit words that make up the MAC address.
|
||||||
|
u16_l array[MAC_ADDR_LEN/2];
|
||||||
|
};
|
||||||
|
|
||||||
|
/// SSID maximum length.
|
||||||
|
#define MAC_SSID_LEN 32
|
||||||
|
|
||||||
|
/// SSID.
|
||||||
|
struct mac_ssid
|
||||||
|
{
|
||||||
|
/// Actual length of the SSID.
|
||||||
|
u8_l length;
|
||||||
|
/// Array containing the SSID name.
|
||||||
|
u8_l array[MAC_SSID_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
/// BSS type
|
||||||
|
enum mac_bss_type
|
||||||
|
{
|
||||||
|
INFRASTRUCTURE_MODE = 1,
|
||||||
|
INDEPENDENT_BSS_MODE,
|
||||||
|
ANY_BSS_MODE
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Channel Band
|
||||||
|
enum mac_chan_band
|
||||||
|
{
|
||||||
|
/// 2.4GHz Band
|
||||||
|
PHY_BAND_2G4,
|
||||||
|
/// 5GHz band
|
||||||
|
PHY_BAND_5G,
|
||||||
|
/// Number of bands
|
||||||
|
PHY_BAND_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Operating Channel Bandwidth
|
||||||
|
enum mac_chan_bandwidth
|
||||||
|
{
|
||||||
|
/// 20MHz BW
|
||||||
|
PHY_CHNL_BW_20,
|
||||||
|
/// 40MHz BW
|
||||||
|
PHY_CHNL_BW_40,
|
||||||
|
/// 80MHz BW
|
||||||
|
PHY_CHNL_BW_80,
|
||||||
|
/// 160MHz BW
|
||||||
|
PHY_CHNL_BW_160,
|
||||||
|
/// 80+80MHz BW
|
||||||
|
PHY_CHNL_BW_80P80,
|
||||||
|
/// Reserved BW
|
||||||
|
PHY_CHNL_BW_OTHER,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// max number of channels in the 2.4 GHZ band
|
||||||
|
#define MAC_DOMAINCHANNEL_24G_MAX 14
|
||||||
|
|
||||||
|
/// max number of channels in the 5 GHZ band
|
||||||
|
#define MAC_DOMAINCHANNEL_5G_MAX 28
|
||||||
|
|
||||||
|
/// Channel Flag
|
||||||
|
enum mac_chan_flags
|
||||||
|
{
|
||||||
|
/// Cannot initiate radiation on this channel
|
||||||
|
CHAN_NO_IR = BIT(0),
|
||||||
|
/// Channel is not allowed
|
||||||
|
CHAN_DISABLED = BIT(1),
|
||||||
|
/// Radar detection required on this channel
|
||||||
|
CHAN_RADAR = BIT(2),
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Primary Channel definition
|
||||||
|
struct mac_chan_def
|
||||||
|
{
|
||||||
|
/// Frequency of the channel (in MHz)
|
||||||
|
u16_l freq;
|
||||||
|
/// RF band (@ref mac_chan_band)
|
||||||
|
u8_l band;
|
||||||
|
/// Additional information (@ref mac_chan_flags)
|
||||||
|
u8_l flags;
|
||||||
|
/// Max transmit power allowed on this channel (dBm)
|
||||||
|
s8_l tx_power;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Operating Channel
|
||||||
|
struct mac_chan_op
|
||||||
|
{
|
||||||
|
/// Band (@ref mac_chan_band)
|
||||||
|
u8_l band;
|
||||||
|
/// Channel type (@ref mac_chan_bandwidth)
|
||||||
|
u8_l type;
|
||||||
|
/// Frequency for Primary 20MHz channel (in MHz)
|
||||||
|
u16_l prim20_freq;
|
||||||
|
/// Frequency center of the contiguous channel or center of Primary 80+80 (in MHz)
|
||||||
|
u16_l center1_freq;
|
||||||
|
/// Frequency center of the non-contiguous secondary 80+80 (in MHz)
|
||||||
|
u16_l center2_freq;
|
||||||
|
/// Max transmit power allowed on this channel (dBm)
|
||||||
|
s8_l tx_power;
|
||||||
|
/// Additional information (@ref mac_chan_flags)
|
||||||
|
u8_l flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Cipher suites (order is important as it is used by MACHW)
|
||||||
|
enum mac_cipher_suite
|
||||||
|
{
|
||||||
|
/// 00-0F-AC 1
|
||||||
|
MAC_CIPHER_WEP40 = 0,
|
||||||
|
/// 00-0F-AC 2
|
||||||
|
MAC_CIPHER_TKIP = 1,
|
||||||
|
/// 00-0F-AC 4
|
||||||
|
MAC_CIPHER_CCMP = 2,
|
||||||
|
/// 00-0F-AC 5
|
||||||
|
MAC_CIPHER_WEP104 = 3,
|
||||||
|
/// 00-14-72 1
|
||||||
|
MAC_CIPHER_WPI_SMS4 = 4,
|
||||||
|
/// 00-0F-AC 6 (aka AES_CMAC)
|
||||||
|
MAC_CIPHER_BIP_CMAC_128 = 5,
|
||||||
|
|
||||||
|
// following cipher are not supported by MACHW
|
||||||
|
/// 00-0F-AC 08
|
||||||
|
MAC_CIPHER_GCMP_128,
|
||||||
|
/// 00-0F-AC 09
|
||||||
|
MAC_CIPHER_GCMP_256,
|
||||||
|
/// 00-0F-AC 10
|
||||||
|
MAC_CIPHER_CCMP_256,
|
||||||
|
/// 00-0F-AC 11
|
||||||
|
MAC_CIPHER_BIP_GMAC_128,
|
||||||
|
/// 00-0F-AC 12
|
||||||
|
MAC_CIPHER_BIP_GMAC_256,
|
||||||
|
/// 00-0F-AC 13
|
||||||
|
MAC_CIPHER_BIP_CMAC_256,
|
||||||
|
|
||||||
|
MAC_CIPHER_INVALID = 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Authentication and Key Management suite
|
||||||
|
enum mac_akm_suite
|
||||||
|
{
|
||||||
|
/// No security
|
||||||
|
MAC_AKM_NONE,
|
||||||
|
/// Pre RSN (WEP or WPA)
|
||||||
|
MAC_AKM_PRE_RSN,
|
||||||
|
/// 00-0F-AC 1
|
||||||
|
MAC_AKM_8021X,
|
||||||
|
/// 00-0F-AC 2
|
||||||
|
MAC_AKM_PSK,
|
||||||
|
/// 00-0F-AC 3
|
||||||
|
MAC_AKM_FT_8021X,
|
||||||
|
/// 00-0F-AC 4
|
||||||
|
MAC_AKM_FT_PSK,
|
||||||
|
/// 00-0F-AC 5
|
||||||
|
MAC_AKM_8021X_SHA256,
|
||||||
|
/// 00-0F-AC 6
|
||||||
|
MAC_AKM_PSK_SHA256,
|
||||||
|
/// 00-0F-AC 7
|
||||||
|
MAC_AKM_TDLS,
|
||||||
|
/// 00-0F-AC 8
|
||||||
|
MAC_AKM_SAE,
|
||||||
|
/// 00-0F-AC 9
|
||||||
|
MAC_AKM_FT_OVER_SAE,
|
||||||
|
/// 00-0F-AC 11
|
||||||
|
MAC_AKM_8021X_SUITE_B,
|
||||||
|
/// 00-0F-AC 12
|
||||||
|
MAC_AKM_8021X_SUITE_B_192,
|
||||||
|
/// 00-0F-AC 14
|
||||||
|
MAC_AKM_FILS_SHA256,
|
||||||
|
/// 00-0F-AC 15
|
||||||
|
MAC_AKM_FILS_SHA384,
|
||||||
|
/// 00-0F-AC 16
|
||||||
|
MAC_AKM_FT_FILS_SHA256,
|
||||||
|
/// 00-0F-AC 17
|
||||||
|
MAC_AKM_FT_FILS_SHA384,
|
||||||
|
/// 00-0F-AC 18
|
||||||
|
MAC_AKM_OWE,
|
||||||
|
|
||||||
|
/// 00-14-72 1
|
||||||
|
MAC_AKM_WAPI_CERT,
|
||||||
|
/// 00-14-72 2
|
||||||
|
MAC_AKM_WAPI_PSK,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Scan result element, parsed from beacon or probe response frames.
|
||||||
|
struct mac_scan_result
|
||||||
|
{
|
||||||
|
/// Scan result is valid
|
||||||
|
bool valid_flag;
|
||||||
|
/// Network BSSID.
|
||||||
|
struct mac_addr bssid;
|
||||||
|
/// Network name.
|
||||||
|
struct mac_ssid ssid;
|
||||||
|
/// Network type (@ref mac_bss_type).
|
||||||
|
u16_l bsstype;
|
||||||
|
/// Network channel.
|
||||||
|
struct mac_chan_def *chan;
|
||||||
|
/// Network beacon period (in TU).
|
||||||
|
u16_l beacon_period;
|
||||||
|
/// Capability information
|
||||||
|
u16_l cap_info;
|
||||||
|
/// Supported AKM (bit-field of @ref mac_akm_suite)
|
||||||
|
u32_l akm;
|
||||||
|
/// Group cipher (bit-field of @ref mac_cipher_suite)
|
||||||
|
u16_l group_cipher;
|
||||||
|
/// Group cipher (bit-field of @ref mac_cipher_suite)
|
||||||
|
u16_l pairwise_cipher;
|
||||||
|
/// RSSI of the scanned BSS (in dBm)
|
||||||
|
s8_l rssi;
|
||||||
|
///Multi-BSSID index (0 if this is the reference (i.e. transmitted) BSSID)
|
||||||
|
u8_l mluti_bssid_index;
|
||||||
|
///Maximum BSSID indicator
|
||||||
|
u8_l max_bssid_indicator;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Legacy rate 802.11 definitions
|
||||||
|
enum mac_legacy_rates
|
||||||
|
{
|
||||||
|
/// DSSS/CCK 1Mbps
|
||||||
|
MAC_RATE_1MBPS = 2,
|
||||||
|
/// DSSS/CCK 2Mbps
|
||||||
|
MAC_RATE_2MBPS = 4,
|
||||||
|
/// DSSS/CCK 5.5Mbps
|
||||||
|
MAC_RATE_5_5MBPS = 11,
|
||||||
|
/// OFDM 6Mbps
|
||||||
|
MAC_RATE_6MBPS = 12,
|
||||||
|
/// OFDM 9Mbps
|
||||||
|
MAC_RATE_9MBPS = 18,
|
||||||
|
/// DSSS/CCK 11Mbps
|
||||||
|
MAC_RATE_11MBPS = 22,
|
||||||
|
/// OFDM 12Mbps
|
||||||
|
MAC_RATE_12MBPS = 24,
|
||||||
|
/// OFDM 18Mbps
|
||||||
|
MAC_RATE_18MBPS = 36,
|
||||||
|
/// OFDM 24Mbps
|
||||||
|
MAC_RATE_24MBPS = 48,
|
||||||
|
/// OFDM 36Mbps
|
||||||
|
MAC_RATE_36MBPS = 72,
|
||||||
|
/// OFDM 48Mbps
|
||||||
|
MAC_RATE_48MBPS = 96,
|
||||||
|
/// OFDM 54Mbps
|
||||||
|
MAC_RATE_54MBPS = 108
|
||||||
|
};
|
||||||
|
|
||||||
|
/// BSS Membership Selector definitions
|
||||||
|
enum mac_bss_membership
|
||||||
|
{
|
||||||
|
/// HT PHY
|
||||||
|
MAC_BSS_MEMBERSHIP_HT_PHY = 127,
|
||||||
|
/// VHT PHY
|
||||||
|
MAC_BSS_MEMBERSHIP_VHT_PHY = 126,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// MAC rateset maximum length
|
||||||
|
#define MAC_RATESET_LEN 12
|
||||||
|
|
||||||
|
/// Structure containing the legacy rateset of a station
|
||||||
|
struct mac_rateset
|
||||||
|
{
|
||||||
|
/// Number of legacy rates supported
|
||||||
|
u8_l length;
|
||||||
|
/// Array of legacy rates
|
||||||
|
u8_l array[MAC_RATESET_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
/// MAC Security Key maximum length
|
||||||
|
#define MAC_SEC_KEY_LEN 32 // TKIP keys 256 bits (max length) with MIC keys
|
||||||
|
|
||||||
|
/// Structure defining a security key
|
||||||
|
struct mac_sec_key
|
||||||
|
{
|
||||||
|
/// Key material length
|
||||||
|
u8_l length;
|
||||||
|
/// Key material
|
||||||
|
u32_l array[MAC_SEC_KEY_LEN/4];
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Access Category enumeration
|
||||||
|
enum mac_ac
|
||||||
|
{
|
||||||
|
/// Background
|
||||||
|
AC_BK = 0,
|
||||||
|
/// Best-effort
|
||||||
|
AC_BE,
|
||||||
|
/// Video
|
||||||
|
AC_VI,
|
||||||
|
/// Voice
|
||||||
|
AC_VO,
|
||||||
|
/// Number of access categories
|
||||||
|
AC_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Traffic ID enumeration
|
||||||
|
enum mac_tid
|
||||||
|
{
|
||||||
|
/// TID_0. Mapped to @ref AC_BE as per 802.11 standard.
|
||||||
|
TID_0,
|
||||||
|
/// TID_1. Mapped to @ref AC_BK as per 802.11 standard.
|
||||||
|
TID_1,
|
||||||
|
/// TID_2. Mapped to @ref AC_BK as per 802.11 standard.
|
||||||
|
TID_2,
|
||||||
|
/// TID_3. Mapped to @ref AC_BE as per 802.11 standard.
|
||||||
|
TID_3,
|
||||||
|
/// TID_4. Mapped to @ref AC_VI as per 802.11 standard.
|
||||||
|
TID_4,
|
||||||
|
/// TID_5. Mapped to @ref AC_VI as per 802.11 standard.
|
||||||
|
TID_5,
|
||||||
|
/// TID_6. Mapped to @ref AC_VO as per 802.11 standard.
|
||||||
|
TID_6,
|
||||||
|
/// TID_7. Mapped to @ref AC_VO as per 802.11 standard.
|
||||||
|
TID_7,
|
||||||
|
/// Non standard Management TID used internally
|
||||||
|
TID_MGT,
|
||||||
|
/// Number of TID supported
|
||||||
|
TID_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
/// MCS bitfield maximum size (in bytes)
|
||||||
|
#define MAX_MCS_LEN 16 // 16 * 8 = 128
|
||||||
|
|
||||||
|
/// MAC HT capability information element
|
||||||
|
struct mac_htcapability
|
||||||
|
{
|
||||||
|
/// HT capability information
|
||||||
|
u16_l ht_capa_info;
|
||||||
|
/// A-MPDU parameters
|
||||||
|
u8_l a_mpdu_param;
|
||||||
|
/// Supported MCS
|
||||||
|
u8_l mcs_rate[MAX_MCS_LEN];
|
||||||
|
/// HT extended capability information
|
||||||
|
u16_l ht_extended_capa;
|
||||||
|
/// Beamforming capability information
|
||||||
|
u32_l tx_beamforming_capa;
|
||||||
|
/// Antenna selection capability information
|
||||||
|
u8_l asel_capa;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// MAC VHT capability information element
|
||||||
|
struct mac_vhtcapability
|
||||||
|
{
|
||||||
|
/// VHT capability information
|
||||||
|
u32_l vht_capa_info;
|
||||||
|
/// RX MCS map
|
||||||
|
u16_l rx_mcs_map;
|
||||||
|
/// RX highest data rate
|
||||||
|
u16_l rx_highest;
|
||||||
|
/// TX MCS map
|
||||||
|
u16_l tx_mcs_map;
|
||||||
|
/// TX highest data rate
|
||||||
|
u16_l tx_highest;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Length (in bytes) of the MAC HE capability field
|
||||||
|
#define MAC_HE_MAC_CAPA_LEN 6
|
||||||
|
/// Length (in bytes) of the PHY HE capability field
|
||||||
|
#define MAC_HE_PHY_CAPA_LEN 11
|
||||||
|
/// Maximum length (in bytes) of the PPE threshold data
|
||||||
|
#define MAC_HE_PPE_THRES_MAX_LEN 25
|
||||||
|
|
||||||
|
/// Structure listing the per-NSS, per-BW supported MCS combinations
|
||||||
|
struct mac_he_mcs_nss_supp
|
||||||
|
{
|
||||||
|
/// per-NSS supported MCS in RX, for BW <= 80MHz
|
||||||
|
u16_l rx_mcs_80;
|
||||||
|
/// per-NSS supported MCS in TX, for BW <= 80MHz
|
||||||
|
u16_l tx_mcs_80;
|
||||||
|
/// per-NSS supported MCS in RX, for BW = 160MHz
|
||||||
|
u16_l rx_mcs_160;
|
||||||
|
/// per-NSS supported MCS in TX, for BW = 160MHz
|
||||||
|
u16_l tx_mcs_160;
|
||||||
|
/// per-NSS supported MCS in RX, for BW = 80+80MHz
|
||||||
|
u16_l rx_mcs_80p80;
|
||||||
|
/// per-NSS supported MCS in TX, for BW = 80+80MHz
|
||||||
|
u16_l tx_mcs_80p80;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// MAC HE capability information element
|
||||||
|
struct mac_hecapability
|
||||||
|
{
|
||||||
|
/// MAC HE capabilities
|
||||||
|
u8_l mac_cap_info[MAC_HE_MAC_CAPA_LEN];
|
||||||
|
/// PHY HE capabilities
|
||||||
|
u8_l phy_cap_info[MAC_HE_PHY_CAPA_LEN];
|
||||||
|
/// Supported MCS combinations
|
||||||
|
struct mac_he_mcs_nss_supp mcs_supp;
|
||||||
|
/// PPE Thresholds data
|
||||||
|
u8_l ppe_thres[MAC_HE_PPE_THRES_MAX_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Station flags
|
||||||
|
enum mac_sta_flags
|
||||||
|
{
|
||||||
|
/// Bit indicating that a STA has QoS (WMM) capability
|
||||||
|
STA_QOS_CAPA = BIT(0),
|
||||||
|
/// Bit indicating that a STA has HT capability
|
||||||
|
STA_HT_CAPA = BIT(1),
|
||||||
|
/// Bit indicating that a STA has VHT capability
|
||||||
|
STA_VHT_CAPA = BIT(2),
|
||||||
|
/// Bit indicating that a STA has MFP capability
|
||||||
|
STA_MFP_CAPA = BIT(3),
|
||||||
|
/// Bit indicating that the STA included the Operation Notification IE
|
||||||
|
STA_OPMOD_NOTIF = BIT(4),
|
||||||
|
/// Bit indicating that a STA has HE capability
|
||||||
|
STA_HE_CAPA = BIT(5),
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Connection flags
|
||||||
|
enum mac_connection_flags
|
||||||
|
{
|
||||||
|
/// Flag indicating whether the control port is controlled by host or not
|
||||||
|
CONTROL_PORT_HOST = BIT(0),
|
||||||
|
/// Flag indicating whether the control port frame shall be sent unencrypted
|
||||||
|
CONTROL_PORT_NO_ENC = BIT(1),
|
||||||
|
/// Flag indicating whether HT and VHT shall be disabled or not
|
||||||
|
DISABLE_HT = BIT(2),
|
||||||
|
/// Flag indicating whether WPA or WPA2 authentication is in use
|
||||||
|
WPA_WPA2_IN_USE = BIT(3),
|
||||||
|
/// Flag indicating whether MFP is in use
|
||||||
|
MFP_IN_USE = BIT(4),
|
||||||
|
// Flag indicating Roam
|
||||||
|
REASSOCIATION = BIT(5),
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_HE_FOR_OLD_KERNEL
|
||||||
|
#define IEEE80211_HE_MAC_CAP2_ALL_ACK 0x02
|
||||||
|
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G 0x02
|
||||||
|
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G 0x04
|
||||||
|
#define IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD 0x20
|
||||||
|
#define IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US 0x40
|
||||||
|
#define IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS 0x80
|
||||||
|
#define IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS 0x01
|
||||||
|
#define IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US 0x02
|
||||||
|
#define IEEE80211_HE_PHY_CAP2_DOPPLER_RX 0x20
|
||||||
|
#define IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ 0x08
|
||||||
|
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM 0x18
|
||||||
|
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1 0x00
|
||||||
|
#define IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA 0x40
|
||||||
|
#define IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE 0x01
|
||||||
|
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 0x0c
|
||||||
|
#define IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK 0x40
|
||||||
|
#define IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK 0x80
|
||||||
|
#define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU 0x01
|
||||||
|
#define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU 0x02
|
||||||
|
#define IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB 0x04
|
||||||
|
#define IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB 0x08
|
||||||
|
#define IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT 0x80
|
||||||
|
#define IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO 0x40
|
||||||
|
#define IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI 0x04
|
||||||
|
#define IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G 0x02
|
||||||
|
#define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB 0x10
|
||||||
|
#define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB 0x20
|
||||||
|
|
||||||
|
struct ieee80211_he_cap_elem {
|
||||||
|
u8 mac_cap_info[6];
|
||||||
|
u8 phy_cap_info[11];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct ieee80211_he_mcs_nss_supp {
|
||||||
|
__le16 rx_mcs_80;
|
||||||
|
__le16 tx_mcs_80;
|
||||||
|
__le16 rx_mcs_160;
|
||||||
|
__le16 tx_mcs_160;
|
||||||
|
__le16 rx_mcs_80p80;
|
||||||
|
__le16 tx_mcs_80p80;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define IEEE80211_HE_PPE_THRES_MAX_LEN 25
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
|
||||||
|
#define WLAN_EID_EXTENSION 255
|
||||||
|
/* Element ID Extensions for Element ID 255 */
|
||||||
|
|
||||||
|
enum ieee80211_eid_ext {
|
||||||
|
WLAN_EID_EXT_ASSOC_DELAY_INFO = 1,
|
||||||
|
WLAN_EID_EXT_FILS_REQ_PARAMS = 2,
|
||||||
|
WLAN_EID_EXT_FILS_KEY_CONFIRM = 3,
|
||||||
|
WLAN_EID_EXT_FILS_SESSION = 4,
|
||||||
|
WLAN_EID_EXT_FILS_HLP_CONTAINER = 5,
|
||||||
|
WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN = 6,
|
||||||
|
WLAN_EID_EXT_KEY_DELIVERY = 7,
|
||||||
|
WLAN_EID_EXT_FILS_WRAPPED_DATA = 8,
|
||||||
|
WLAN_EID_EXT_FILS_PUBLIC_KEY = 12,
|
||||||
|
WLAN_EID_EXT_FILS_NONCE = 13,
|
||||||
|
WLAN_EID_EXT_FUTURE_CHAN_GUIDANCE = 14,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
|
||||||
|
#define WLAN_EID_EXT_HE_CAPABILITY 35
|
||||||
|
#define WLAN_EID_EXT_HE_OPERATION 36
|
||||||
|
#define WLAN_EID_EXT_UORA 37
|
||||||
|
#define WLAN_EID_EXT_HE_MU_EDCA 38
|
||||||
|
#define WLAN_EID_EXT_HE_SPR 39
|
||||||
|
#define WLAN_EID_EXT_NDP_FEEDBACK_REPORT_PARAMSET 41
|
||||||
|
#define WLAN_EID_EXT_BSS_COLOR_CHG_ANN 42
|
||||||
|
#define WLAN_EID_EXT_QUIET_TIME_PERIOD_SETUP 43
|
||||||
|
#define WLAN_EID_EXT_ESS_REPORT 45
|
||||||
|
#define WLAN_EID_EXT_OPS 46
|
||||||
|
#define WLAN_EID_EXT_HE_BSS_LOAD 47
|
||||||
|
#define WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME 52
|
||||||
|
#define WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION 55
|
||||||
|
#define WLAN_EID_EXT_NON_INHERITANCE 56
|
||||||
|
#define WLAN_EID_EXT_KNOWN_BSSID 57
|
||||||
|
#define WLAN_EID_EXT_SHORT_SSID_LIST 58
|
||||||
|
#define WLAN_EID_EXT_HE_6GHZ_CAPA 59
|
||||||
|
#define WLAN_EID_EXT_UL_MU_POWER_CAPA 60
|
||||||
|
#define WLAN_EID_EXT_EHT_OPERATION 106
|
||||||
|
#define WLAN_EID_EXT_EHT_MULTI_LINK 107
|
||||||
|
#define WLAN_EID_EXT_EHT_CAPABILITY 108
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct ieee80211_sta_he_cap {
|
||||||
|
bool has_he;
|
||||||
|
struct ieee80211_he_cap_elem he_cap_elem;
|
||||||
|
struct ieee80211_he_mcs_nss_supp he_mcs_nss_supp;
|
||||||
|
u8 ppe_thres[IEEE80211_HE_PPE_THRES_MAX_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ieee80211_sband_iftype_data {
|
||||||
|
u16 types_mask;
|
||||||
|
struct ieee80211_sta_he_cap he_cap;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) || defined(CONFIG_VHT_FOR_OLD_KERNEL)
|
||||||
|
struct ieee80211_vht_mcs_info {
|
||||||
|
__le16 rx_mcs_map;
|
||||||
|
__le16 rx_highest;
|
||||||
|
__le16 tx_mcs_map;
|
||||||
|
__le16 tx_highest;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct ieee80211_vht_cap {
|
||||||
|
__le32 vht_cap_info;
|
||||||
|
struct ieee80211_vht_mcs_info supp_mcs;
|
||||||
|
};
|
||||||
|
#define WLAN_EID_VHT_CAPABILITY 191
|
||||||
|
|
||||||
|
struct ieee80211_sta_vht_cap {
|
||||||
|
bool vht_supported;
|
||||||
|
u32 cap; /* use IEEE80211_VHT_CAP_ */
|
||||||
|
struct ieee80211_vht_mcs_info vht_mcs;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
#endif // LMAC_MAC_H_
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,62 @@
|
|||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
*
|
||||||
|
* @file co_types.h
|
||||||
|
*
|
||||||
|
* @brief This file replaces the need to include stdint or stdbool typical headers,
|
||||||
|
* which may not be available in all toolchains, and adds new types
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2009-2019
|
||||||
|
*
|
||||||
|
* $Rev: $
|
||||||
|
*
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LMAC_INT_H_
|
||||||
|
#define _LMAC_INT_H_
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
* @addtogroup CO_INT
|
||||||
|
* @ingroup COMMON
|
||||||
|
* @brief Common integer standard types (removes use of stdint)
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DEFINES
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
|
||||||
|
#include <linux/bits.h>
|
||||||
|
#else
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_TL4
|
||||||
|
typedef uint16_t u8_l;
|
||||||
|
typedef int16_t s8_l;
|
||||||
|
typedef uint16_t bool_l;
|
||||||
|
#else
|
||||||
|
typedef uint8_t u8_l;
|
||||||
|
typedef int8_t s8_l;
|
||||||
|
typedef bool bool_l;
|
||||||
|
#endif
|
||||||
|
typedef uint16_t u16_l;
|
||||||
|
typedef int16_t s16_l;
|
||||||
|
typedef uint32_t u32_l;
|
||||||
|
typedef int32_t s32_l;
|
||||||
|
typedef uint64_t u64_l;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// @} CO_INT
|
||||||
|
#endif // _LMAC_INT_H_
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
#include <linux/memory.h>
|
||||||
|
#include "md5.h"
|
||||||
|
|
||||||
|
unsigned char PADDING[]={0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||||
|
|
||||||
|
void MD5Init(MD5_CTX *context)
|
||||||
|
{
|
||||||
|
context->count[0] = 0;
|
||||||
|
context->count[1] = 0;
|
||||||
|
context->state[0] = 0x67452301;
|
||||||
|
context->state[1] = 0xEFCDAB89;
|
||||||
|
context->state[2] = 0x98BADCFE;
|
||||||
|
context->state[3] = 0x10325476;
|
||||||
|
}
|
||||||
|
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen)
|
||||||
|
{
|
||||||
|
unsigned int i = 0,index = 0,partlen = 0;
|
||||||
|
index = (context->count[0] >> 3) & 0x3F;
|
||||||
|
partlen = 64 - index;
|
||||||
|
context->count[0] += inputlen << 3;
|
||||||
|
if(context->count[0] < (inputlen << 3))
|
||||||
|
context->count[1]++;
|
||||||
|
context->count[1] += inputlen >> 29;
|
||||||
|
|
||||||
|
if(inputlen >= partlen)
|
||||||
|
{
|
||||||
|
memcpy(&context->buffer[index],input,partlen);
|
||||||
|
MD5Transform(context->state,context->buffer);
|
||||||
|
for(i = partlen;i+64 <= inputlen;i+=64)
|
||||||
|
MD5Transform(context->state,&input[i]);
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
memcpy(&context->buffer[index],&input[i],inputlen-i);
|
||||||
|
}
|
||||||
|
void MD5Final(MD5_CTX *context,unsigned char digest[16])
|
||||||
|
{
|
||||||
|
unsigned int index = 0,padlen = 0;
|
||||||
|
unsigned char bits[8];
|
||||||
|
index = (context->count[0] >> 3) & 0x3F;
|
||||||
|
padlen = (index < 56)?(56-index):(120-index);
|
||||||
|
MD5Encode(bits,context->count,8);
|
||||||
|
MD5Update(context,PADDING,padlen);
|
||||||
|
MD5Update(context,bits,8);
|
||||||
|
MD5Encode(digest,context->state,16);
|
||||||
|
}
|
||||||
|
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len)
|
||||||
|
{
|
||||||
|
unsigned int i = 0,j = 0;
|
||||||
|
while(j < len)
|
||||||
|
{
|
||||||
|
output[j] = input[i] & 0xFF;
|
||||||
|
output[j+1] = (input[i] >> 8) & 0xFF;
|
||||||
|
output[j+2] = (input[i] >> 16) & 0xFF;
|
||||||
|
output[j+3] = (input[i] >> 24) & 0xFF;
|
||||||
|
i++;
|
||||||
|
j+=4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len)
|
||||||
|
{
|
||||||
|
unsigned int i = 0,j = 0;
|
||||||
|
while(j < len)
|
||||||
|
{
|
||||||
|
output[i] = (input[j]) |
|
||||||
|
(input[j+1] << 8) |
|
||||||
|
(input[j+2] << 16) |
|
||||||
|
(input[j+3] << 24);
|
||||||
|
i++;
|
||||||
|
j+=4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void MD5Transform(unsigned int state[4],unsigned char block[64])
|
||||||
|
{
|
||||||
|
unsigned int a = state[0];
|
||||||
|
unsigned int b = state[1];
|
||||||
|
unsigned int c = state[2];
|
||||||
|
unsigned int d = state[3];
|
||||||
|
unsigned int x[64];
|
||||||
|
MD5Decode(x,block,64);
|
||||||
|
FF(a, b, c, d, x[ 0], 7, 0xd76aa478); /* 1 */
|
||||||
|
FF(d, a, b, c, x[ 1], 12, 0xe8c7b756); /* 2 */
|
||||||
|
FF(c, d, a, b, x[ 2], 17, 0x242070db); /* 3 */
|
||||||
|
FF(b, c, d, a, x[ 3], 22, 0xc1bdceee); /* 4 */
|
||||||
|
FF(a, b, c, d, x[ 4], 7, 0xf57c0faf); /* 5 */
|
||||||
|
FF(d, a, b, c, x[ 5], 12, 0x4787c62a); /* 6 */
|
||||||
|
FF(c, d, a, b, x[ 6], 17, 0xa8304613); /* 7 */
|
||||||
|
FF(b, c, d, a, x[ 7], 22, 0xfd469501); /* 8 */
|
||||||
|
FF(a, b, c, d, x[ 8], 7, 0x698098d8); /* 9 */
|
||||||
|
FF(d, a, b, c, x[ 9], 12, 0x8b44f7af); /* 10 */
|
||||||
|
FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
|
||||||
|
FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
|
||||||
|
FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
|
||||||
|
FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
|
||||||
|
FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
|
||||||
|
FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */
|
||||||
|
|
||||||
|
/* Round 2 */
|
||||||
|
GG(a, b, c, d, x[ 1], 5, 0xf61e2562); /* 17 */
|
||||||
|
GG(d, a, b, c, x[ 6], 9, 0xc040b340); /* 18 */
|
||||||
|
GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
|
||||||
|
GG(b, c, d, a, x[ 0], 20, 0xe9b6c7aa); /* 20 */
|
||||||
|
GG(a, b, c, d, x[ 5], 5, 0xd62f105d); /* 21 */
|
||||||
|
GG(d, a, b, c, x[10], 9, 0x2441453); /* 22 */
|
||||||
|
GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
|
||||||
|
GG(b, c, d, a, x[ 4], 20, 0xe7d3fbc8); /* 24 */
|
||||||
|
GG(a, b, c, d, x[ 9], 5, 0x21e1cde6); /* 25 */
|
||||||
|
GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
|
||||||
|
GG(c, d, a, b, x[ 3], 14, 0xf4d50d87); /* 27 */
|
||||||
|
GG(b, c, d, a, x[ 8], 20, 0x455a14ed); /* 28 */
|
||||||
|
GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
|
||||||
|
GG(d, a, b, c, x[ 2], 9, 0xfcefa3f8); /* 30 */
|
||||||
|
GG(c, d, a, b, x[ 7], 14, 0x676f02d9); /* 31 */
|
||||||
|
GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */
|
||||||
|
|
||||||
|
/* Round 3 */
|
||||||
|
HH(a, b, c, d, x[ 5], 4, 0xfffa3942); /* 33 */
|
||||||
|
HH(d, a, b, c, x[ 8], 11, 0x8771f681); /* 34 */
|
||||||
|
HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
|
||||||
|
HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
|
||||||
|
HH(a, b, c, d, x[ 1], 4, 0xa4beea44); /* 37 */
|
||||||
|
HH(d, a, b, c, x[ 4], 11, 0x4bdecfa9); /* 38 */
|
||||||
|
HH(c, d, a, b, x[ 7], 16, 0xf6bb4b60); /* 39 */
|
||||||
|
HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
|
||||||
|
HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
|
||||||
|
HH(d, a, b, c, x[ 0], 11, 0xeaa127fa); /* 42 */
|
||||||
|
HH(c, d, a, b, x[ 3], 16, 0xd4ef3085); /* 43 */
|
||||||
|
HH(b, c, d, a, x[ 6], 23, 0x4881d05); /* 44 */
|
||||||
|
HH(a, b, c, d, x[ 9], 4, 0xd9d4d039); /* 45 */
|
||||||
|
HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
|
||||||
|
HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
|
||||||
|
HH(b, c, d, a, x[ 2], 23, 0xc4ac5665); /* 48 */
|
||||||
|
|
||||||
|
/* Round 4 */
|
||||||
|
II(a, b, c, d, x[ 0], 6, 0xf4292244); /* 49 */
|
||||||
|
II(d, a, b, c, x[ 7], 10, 0x432aff97); /* 50 */
|
||||||
|
II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
|
||||||
|
II(b, c, d, a, x[ 5], 21, 0xfc93a039); /* 52 */
|
||||||
|
II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
|
||||||
|
II(d, a, b, c, x[ 3], 10, 0x8f0ccc92); /* 54 */
|
||||||
|
II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
|
||||||
|
II(b, c, d, a, x[ 1], 21, 0x85845dd1); /* 56 */
|
||||||
|
II(a, b, c, d, x[ 8], 6, 0x6fa87e4f); /* 57 */
|
||||||
|
II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
|
||||||
|
II(c, d, a, b, x[ 6], 15, 0xa3014314); /* 59 */
|
||||||
|
II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
|
||||||
|
II(a, b, c, d, x[ 4], 6, 0xf7537e82); /* 61 */
|
||||||
|
II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
|
||||||
|
II(c, d, a, b, x[ 2], 15, 0x2ad7d2bb); /* 63 */
|
||||||
|
II(b, c, d, a, x[ 9], 21, 0xeb86d391); /* 64 */
|
||||||
|
state[0] += a;
|
||||||
|
state[1] += b;
|
||||||
|
state[2] += c;
|
||||||
|
state[3] += d;
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#ifndef MD5_H
|
||||||
|
#define MD5_H
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int count[2];
|
||||||
|
unsigned int state[4];
|
||||||
|
unsigned char buffer[64];
|
||||||
|
}MD5_CTX;
|
||||||
|
|
||||||
|
|
||||||
|
#define F(x,y,z) ((x & y) | (~x & z))
|
||||||
|
#define G(x,y,z) ((x & z) | (y & ~z))
|
||||||
|
#define H(x,y,z) (x^y^z)
|
||||||
|
#define I(x,y,z) (y ^ (x | ~z))
|
||||||
|
#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))
|
||||||
|
#define FF(a,b,c,d,x,s,ac) \
|
||||||
|
{ \
|
||||||
|
a += F(b,c,d) + x + ac; \
|
||||||
|
a = ROTATE_LEFT(a,s); \
|
||||||
|
a += b; \
|
||||||
|
}
|
||||||
|
#define GG(a,b,c,d,x,s,ac) \
|
||||||
|
{ \
|
||||||
|
a += G(b,c,d) + x + ac; \
|
||||||
|
a = ROTATE_LEFT(a,s); \
|
||||||
|
a += b; \
|
||||||
|
}
|
||||||
|
#define HH(a,b,c,d,x,s,ac) \
|
||||||
|
{ \
|
||||||
|
a += H(b,c,d) + x + ac; \
|
||||||
|
a = ROTATE_LEFT(a,s); \
|
||||||
|
a += b; \
|
||||||
|
}
|
||||||
|
#define II(a,b,c,d,x,s,ac) \
|
||||||
|
{ \
|
||||||
|
a += I(b,c,d) + x + ac; \
|
||||||
|
a = ROTATE_LEFT(a,s); \
|
||||||
|
a += b; \
|
||||||
|
}
|
||||||
|
void MD5Init(MD5_CTX *context);
|
||||||
|
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen);
|
||||||
|
void MD5Final(MD5_CTX *context,unsigned char digest[16]);
|
||||||
|
void MD5Transform(unsigned int state[4],unsigned char block[64]);
|
||||||
|
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len);
|
||||||
|
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file reg_access.h
|
||||||
|
*
|
||||||
|
* @brief Definitions and macros for MAC HW and platform register accesses
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2011-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef REG_ACCESS_H_
|
||||||
|
#define REG_ACCESS_H_
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Addresses within RWNX_ADDR_CPU
|
||||||
|
*****************************************************************************/
|
||||||
|
#define RAM_LMAC_FW_ADDR 0x00150000
|
||||||
|
|
||||||
|
#define ROM_FMAC_FW_ADDR 0x00010000
|
||||||
|
#define RAM_FMAC_FW_ADDR 0x00120000
|
||||||
|
#define ROM_FMAC_PATCH_ADDR 0x00180000
|
||||||
|
#ifdef CONFIG_DPD
|
||||||
|
#define ROM_FMAC_CALIB_ADDR 0x00130000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Addresses within RWNX_ADDR_SYSTEM
|
||||||
|
*****************************************************************************/
|
||||||
|
/* Shard RAM */
|
||||||
|
#define SHARED_RAM_START_ADDR 0x00000000
|
||||||
|
|
||||||
|
/* IPC registers */
|
||||||
|
#define IPC_REG_BASE_ADDR 0x00800000
|
||||||
|
|
||||||
|
/* System Controller Registers */
|
||||||
|
#define SYSCTRL_SIGNATURE_ADDR 0x00900000
|
||||||
|
// old diag register name
|
||||||
|
#define SYSCTRL_DIAG_CONF_ADDR 0x00900068
|
||||||
|
#define SYSCTRL_PHYDIAG_CONF_ADDR 0x00900074
|
||||||
|
#define SYSCTRL_RIUDIAG_CONF_ADDR 0x00900078
|
||||||
|
// new diag register name
|
||||||
|
#define SYSCTRL_DIAG_CONF0 0x00900064
|
||||||
|
#define SYSCTRL_DIAG_CONF1 0x00900068
|
||||||
|
#define SYSCTRL_DIAG_CONF2 0x00900074
|
||||||
|
#define SYSCTRL_DIAG_CONF3 0x00900078
|
||||||
|
#define SYSCTRL_MISC_CNTL_ADDR 0x009000E0
|
||||||
|
#define BOOTROM_ENABLE BIT(4)
|
||||||
|
#define FPGA_B_RESET BIT(1)
|
||||||
|
#define SOFT_RESET BIT(0)
|
||||||
|
|
||||||
|
/* MAC platform */
|
||||||
|
#define NXMAC_VERSION_1_ADDR 0x00B00004
|
||||||
|
#define NXMAC_MU_MIMO_TX_BIT BIT(19)
|
||||||
|
#define NXMAC_BFMER_BIT BIT(18)
|
||||||
|
#define NXMAC_BFMEE_BIT BIT(17)
|
||||||
|
#define NXMAC_MAC_80211MH_FORMAT_BIT BIT(16)
|
||||||
|
#define NXMAC_COEX_BIT BIT(14)
|
||||||
|
#define NXMAC_WAPI_BIT BIT(13)
|
||||||
|
#define NXMAC_TPC_BIT BIT(12)
|
||||||
|
#define NXMAC_VHT_BIT BIT(11)
|
||||||
|
#define NXMAC_HT_BIT BIT(10)
|
||||||
|
#define NXMAC_RCE_BIT BIT(8)
|
||||||
|
#define NXMAC_CCMP_BIT BIT(7)
|
||||||
|
#define NXMAC_TKIP_BIT BIT(6)
|
||||||
|
#define NXMAC_WEP_BIT BIT(5)
|
||||||
|
#define NXMAC_SECURITY_BIT BIT(4)
|
||||||
|
#define NXMAC_SME_BIT BIT(3)
|
||||||
|
#define NXMAC_HCCA_BIT BIT(2)
|
||||||
|
#define NXMAC_EDCA_BIT BIT(1)
|
||||||
|
#define NXMAC_QOS_BIT BIT(0)
|
||||||
|
|
||||||
|
#define NXMAC_RX_CNTRL_ADDR 0x00B00060
|
||||||
|
#define NXMAC_EN_DUPLICATE_DETECTION_BIT BIT(31)
|
||||||
|
#define NXMAC_ACCEPT_UNKNOWN_BIT BIT(30)
|
||||||
|
#define NXMAC_ACCEPT_OTHER_DATA_FRAMES_BIT BIT(29)
|
||||||
|
#define NXMAC_ACCEPT_QO_S_NULL_BIT BIT(28)
|
||||||
|
#define NXMAC_ACCEPT_QCFWO_DATA_BIT BIT(27)
|
||||||
|
#define NXMAC_ACCEPT_Q_DATA_BIT BIT(26)
|
||||||
|
#define NXMAC_ACCEPT_CFWO_DATA_BIT BIT(25)
|
||||||
|
#define NXMAC_ACCEPT_DATA_BIT BIT(24)
|
||||||
|
#define NXMAC_ACCEPT_OTHER_CNTRL_FRAMES_BIT BIT(23)
|
||||||
|
#define NXMAC_ACCEPT_CF_END_BIT BIT(22)
|
||||||
|
#define NXMAC_ACCEPT_ACK_BIT BIT(21)
|
||||||
|
#define NXMAC_ACCEPT_CTS_BIT BIT(20)
|
||||||
|
#define NXMAC_ACCEPT_RTS_BIT BIT(19)
|
||||||
|
#define NXMAC_ACCEPT_PS_POLL_BIT BIT(18)
|
||||||
|
#define NXMAC_ACCEPT_BA_BIT BIT(17)
|
||||||
|
#define NXMAC_ACCEPT_BAR_BIT BIT(16)
|
||||||
|
#define NXMAC_ACCEPT_OTHER_MGMT_FRAMES_BIT BIT(15)
|
||||||
|
#define NXMAC_ACCEPT_BFMEE_FRAMES_BIT BIT(14)
|
||||||
|
#define NXMAC_ACCEPT_ALL_BEACON_BIT BIT(13)
|
||||||
|
#define NXMAC_ACCEPT_NOT_EXPECTED_BA_BIT BIT(12)
|
||||||
|
#define NXMAC_ACCEPT_DECRYPT_ERROR_FRAMES_BIT BIT(11)
|
||||||
|
#define NXMAC_ACCEPT_BEACON_BIT BIT(10)
|
||||||
|
#define NXMAC_ACCEPT_PROBE_RESP_BIT BIT(9)
|
||||||
|
#define NXMAC_ACCEPT_PROBE_REQ_BIT BIT(8)
|
||||||
|
#define NXMAC_ACCEPT_MY_UNICAST_BIT BIT(7)
|
||||||
|
#define NXMAC_ACCEPT_UNICAST_BIT BIT(6)
|
||||||
|
#define NXMAC_ACCEPT_ERROR_FRAMES_BIT BIT(5)
|
||||||
|
#define NXMAC_ACCEPT_OTHER_BSSID_BIT BIT(4)
|
||||||
|
#define NXMAC_ACCEPT_BROADCAST_BIT BIT(3)
|
||||||
|
#define NXMAC_ACCEPT_MULTICAST_BIT BIT(2)
|
||||||
|
#define NXMAC_DONT_DECRYPT_BIT BIT(1)
|
||||||
|
#define NXMAC_EXC_UNENCRYPTED_BIT BIT(0)
|
||||||
|
|
||||||
|
#define NXMAC_DEBUG_PORT_SEL_ADDR 0x00B00510
|
||||||
|
#define NXMAC_SW_SET_PROFILING_ADDR 0x00B08564
|
||||||
|
#define NXMAC_SW_CLEAR_PROFILING_ADDR 0x00B08568
|
||||||
|
|
||||||
|
/* Modem Status */
|
||||||
|
#define MDM_HDMCONFIG_ADDR 0x00C00000
|
||||||
|
|
||||||
|
/* Clock gating configuration */
|
||||||
|
#define MDM_MEMCLKCTRL0_ADDR 0x00C00848
|
||||||
|
#define MDM_CLKGATEFCTRL0_ADDR 0x00C00874
|
||||||
|
#define CRM_CLKGATEFCTRL0_ADDR 0x00940010
|
||||||
|
|
||||||
|
/* AGC (trident) */
|
||||||
|
#define AGC_RWNXAGCCNTL_ADDR 0x00C02060
|
||||||
|
|
||||||
|
/* LDPC RAM*/
|
||||||
|
#define PHY_LDPC_RAM_ADDR 0x00C09000
|
||||||
|
|
||||||
|
/* FCU (elma )*/
|
||||||
|
#define FCU_RWNXFCAGCCNTL_ADDR 0x00C09034
|
||||||
|
|
||||||
|
/* AGC RAM */
|
||||||
|
#define PHY_AGC_UCODE_ADDR 0x00C0A000
|
||||||
|
|
||||||
|
/* RIU */
|
||||||
|
#define RIU_RWNXVERSION_ADDR 0x00C0B000
|
||||||
|
#define RIU_RWNXDYNAMICCONFIG_ADDR 0x00C0B008
|
||||||
|
#define RIU_AGCMEMBISTSTAT_ADDR 0x00C0B238
|
||||||
|
#define RIU_AGCMEMSIGNATURESTAT_ADDR 0x00C0B23C
|
||||||
|
#define RIU_RWNXAGCCNTL_ADDR 0x00C0B390
|
||||||
|
|
||||||
|
/* FCU RAM */
|
||||||
|
#define PHY_FCU_UCODE_ADDR 0x00C0E000
|
||||||
|
|
||||||
|
/* RF ITF */
|
||||||
|
#define FPGAB_MPIF_SEL_ADDR 0x00C10030
|
||||||
|
#define RF_V6_DIAGPORT_CONF1_ADDR 0x00C10010
|
||||||
|
#define RF_v6_PHYDIAG_CONF1_ADDR 0x00C10018
|
||||||
|
|
||||||
|
#define RF_V7_DIAGPORT_CONF1_ADDR 0x00F10010
|
||||||
|
#define RF_v7_PHYDIAG_CONF1_ADDR 0x00F10018
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Macros for generated register files
|
||||||
|
*****************************************************************************/
|
||||||
|
/* Macros for IPC registers access (used in reg_ipc_app.h) */
|
||||||
|
#define REG_IPC_APP_RD(env, INDEX) \
|
||||||
|
(*(volatile u32*)((u8*)env + IPC_REG_BASE_ADDR + 4*(INDEX)))
|
||||||
|
|
||||||
|
#define REG_IPC_APP_WR(env, INDEX, value) \
|
||||||
|
(*(volatile u32*)((u8*)env + IPC_REG_BASE_ADDR + 4*(INDEX)) = value)
|
||||||
|
|
||||||
|
#endif /* REG_ACCESS_H_ */
|
||||||
@@ -0,0 +1,299 @@
|
|||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_ipc_app.h
|
||||||
|
*
|
||||||
|
* @brief IPC module register definitions
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2011-2019
|
||||||
|
*
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _REG_IPC_APP_H_
|
||||||
|
#define _REG_IPC_APP_H_
|
||||||
|
|
||||||
|
#ifndef __KERNEL__
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "arch.h"
|
||||||
|
#else
|
||||||
|
#include "ipc_compat.h"
|
||||||
|
#endif
|
||||||
|
#include "reg_access.h"
|
||||||
|
|
||||||
|
#define REG_IPC_APP_DECODING_MASK 0x0000007F
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief APP2EMB_TRIGGER register definition
|
||||||
|
* <pre>
|
||||||
|
* Bits Field Name Reset Value
|
||||||
|
* ----- ------------------ -----------
|
||||||
|
* 31:00 APP2EMB_TRIGGER 0x0
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
#define IPC_APP2EMB_TRIGGER_ADDR 0x12000000
|
||||||
|
#define IPC_APP2EMB_TRIGGER_OFFSET 0x00000000
|
||||||
|
#define IPC_APP2EMB_TRIGGER_INDEX 0x00000000
|
||||||
|
#define IPC_APP2EMB_TRIGGER_RESET 0x00000000
|
||||||
|
|
||||||
|
__INLINE u32 ipc_app2emb_trigger_get(void *env)
|
||||||
|
{
|
||||||
|
return REG_IPC_APP_RD(env, IPC_APP2EMB_TRIGGER_INDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
__INLINE void ipc_app2emb_trigger_set(void *env, u32 value)
|
||||||
|
{
|
||||||
|
REG_IPC_APP_WR(env, IPC_APP2EMB_TRIGGER_INDEX, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// field definitions
|
||||||
|
#define IPC_APP2EMB_TRIGGER_MASK ((u32)0xFFFFFFFF)
|
||||||
|
#define IPC_APP2EMB_TRIGGER_LSB 0
|
||||||
|
#define IPC_APP2EMB_TRIGGER_WIDTH ((u32)0x00000020)
|
||||||
|
|
||||||
|
#define IPC_APP2EMB_TRIGGER_RST 0x0
|
||||||
|
|
||||||
|
__INLINE u32 ipc_app2emb_trigger_getf(void *env)
|
||||||
|
{
|
||||||
|
u32 localVal = REG_IPC_APP_RD(env, IPC_APP2EMB_TRIGGER_INDEX);
|
||||||
|
ASSERT_ERR((localVal & ~((u32)0xFFFFFFFF)) == 0);
|
||||||
|
return (localVal >> 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
__INLINE void ipc_app2emb_trigger_setf(void *env, u32 app2embtrigger)
|
||||||
|
{
|
||||||
|
ASSERT_ERR((((u32)app2embtrigger << 0) & ~((u32)0xFFFFFFFF)) == 0);
|
||||||
|
REG_IPC_APP_WR(env, IPC_APP2EMB_TRIGGER_INDEX, (u32)app2embtrigger << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief EMB2APP_RAWSTATUS register definition
|
||||||
|
* <pre>
|
||||||
|
* Bits Field Name Reset Value
|
||||||
|
* ----- ------------------ -----------
|
||||||
|
* 31:00 EMB2APP_RAWSTATUS 0x0
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
#define IPC_EMB2APP_RAWSTATUS_ADDR 0x12000004
|
||||||
|
#define IPC_EMB2APP_RAWSTATUS_OFFSET 0x00000004
|
||||||
|
#define IPC_EMB2APP_RAWSTATUS_INDEX 0x00000001
|
||||||
|
#define IPC_EMB2APP_RAWSTATUS_RESET 0x00000000
|
||||||
|
|
||||||
|
__INLINE u32 ipc_emb2app_rawstatus_get(void *env)
|
||||||
|
{
|
||||||
|
return REG_IPC_APP_RD(env, IPC_EMB2APP_RAWSTATUS_INDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
__INLINE void ipc_emb2app_rawstatus_set(void *env, u32 value)
|
||||||
|
{
|
||||||
|
REG_IPC_APP_WR(env, IPC_EMB2APP_RAWSTATUS_INDEX, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// field definitions
|
||||||
|
#define IPC_EMB2APP_RAWSTATUS_MASK ((u32)0xFFFFFFFF)
|
||||||
|
#define IPC_EMB2APP_RAWSTATUS_LSB 0
|
||||||
|
#define IPC_EMB2APP_RAWSTATUS_WIDTH ((u32)0x00000020)
|
||||||
|
|
||||||
|
#define IPC_EMB2APP_RAWSTATUS_RST 0x0
|
||||||
|
|
||||||
|
__INLINE u32 ipc_emb2app_rawstatus_getf(void *env)
|
||||||
|
{
|
||||||
|
u32 localVal = REG_IPC_APP_RD(env, IPC_EMB2APP_RAWSTATUS_INDEX);
|
||||||
|
ASSERT_ERR((localVal & ~((u32)0xFFFFFFFF)) == 0);
|
||||||
|
return (localVal >> 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief EMB2APP_ACK register definition
|
||||||
|
* <pre>
|
||||||
|
* Bits Field Name Reset Value
|
||||||
|
* ----- ------------------ -----------
|
||||||
|
* 31:00 EMB2APP_ACK 0x0
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
#define IPC_EMB2APP_ACK_ADDR 0x12000008
|
||||||
|
#define IPC_EMB2APP_ACK_OFFSET 0x00000008
|
||||||
|
#define IPC_EMB2APP_ACK_INDEX 0x00000002
|
||||||
|
#define IPC_EMB2APP_ACK_RESET 0x00000000
|
||||||
|
|
||||||
|
__INLINE u32 ipc_emb2app_ack_get(void *env)
|
||||||
|
{
|
||||||
|
return REG_IPC_APP_RD(env, IPC_EMB2APP_ACK_INDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
__INLINE void ipc_emb2app_ack_clear(void *env, u32 value)
|
||||||
|
{
|
||||||
|
REG_IPC_APP_WR(env, IPC_EMB2APP_ACK_INDEX, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// field definitions
|
||||||
|
#define IPC_EMB2APP_ACK_MASK ((u32)0xFFFFFFFF)
|
||||||
|
#define IPC_EMB2APP_ACK_LSB 0
|
||||||
|
#define IPC_EMB2APP_ACK_WIDTH ((u32)0x00000020)
|
||||||
|
|
||||||
|
#define IPC_EMB2APP_ACK_RST 0x0
|
||||||
|
|
||||||
|
__INLINE u32 ipc_emb2app_ack_getf(void *env)
|
||||||
|
{
|
||||||
|
u32 localVal = REG_IPC_APP_RD(env, IPC_EMB2APP_ACK_INDEX);
|
||||||
|
ASSERT_ERR((localVal & ~((u32)0xFFFFFFFF)) == 0);
|
||||||
|
return (localVal >> 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
__INLINE void ipc_emb2app_ack_clearf(void *env, u32 emb2appack)
|
||||||
|
{
|
||||||
|
ASSERT_ERR((((u32)emb2appack << 0) & ~((u32)0xFFFFFFFF)) == 0);
|
||||||
|
REG_IPC_APP_WR(env, IPC_EMB2APP_ACK_INDEX, (u32)emb2appack << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief EMB2APP_UNMASK_SET register definition
|
||||||
|
* <pre>
|
||||||
|
* Bits Field Name Reset Value
|
||||||
|
* ----- ------------------ -----------
|
||||||
|
* 31:00 EMB2APP_UNMASK 0x0
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
#define IPC_EMB2APP_UNMASK_SET_ADDR 0x1200000C
|
||||||
|
#define IPC_EMB2APP_UNMASK_SET_OFFSET 0x0000000C
|
||||||
|
#define IPC_EMB2APP_UNMASK_SET_INDEX 0x00000003
|
||||||
|
#define IPC_EMB2APP_UNMASK_SET_RESET 0x00000000
|
||||||
|
|
||||||
|
__INLINE u32 ipc_emb2app_unmask_get(void *env)
|
||||||
|
{
|
||||||
|
return REG_IPC_APP_RD(env, IPC_EMB2APP_UNMASK_SET_INDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
__INLINE void ipc_emb2app_unmask_set(void *env, u32 value)
|
||||||
|
{
|
||||||
|
REG_IPC_APP_WR(env, IPC_EMB2APP_UNMASK_SET_INDEX, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// field definitions
|
||||||
|
#define IPC_EMB2APP_UNMASK_MASK ((u32)0xFFFFFFFF)
|
||||||
|
#define IPC_EMB2APP_UNMASK_LSB 0
|
||||||
|
#define IPC_EMB2APP_UNMASK_WIDTH ((u32)0x00000020)
|
||||||
|
|
||||||
|
#define IPC_EMB2APP_UNMASK_RST 0x0
|
||||||
|
|
||||||
|
__INLINE u32 ipc_emb2app_unmask_getf(void *env)
|
||||||
|
{
|
||||||
|
u32 localVal = REG_IPC_APP_RD(env, IPC_EMB2APP_UNMASK_SET_INDEX);
|
||||||
|
ASSERT_ERR((localVal & ~((u32)0xFFFFFFFF)) == 0);
|
||||||
|
return (localVal >> 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
__INLINE void ipc_emb2app_unmask_setf(void *env, u32 emb2appunmask)
|
||||||
|
{
|
||||||
|
ASSERT_ERR((((u32)emb2appunmask << 0) & ~((u32)0xFFFFFFFF)) == 0);
|
||||||
|
REG_IPC_APP_WR(env, IPC_EMB2APP_UNMASK_SET_INDEX, (u32)emb2appunmask << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief EMB2APP_UNMASK_CLEAR register definition
|
||||||
|
* <pre>
|
||||||
|
* Bits Field Name Reset Value
|
||||||
|
* ----- ------------------ -----------
|
||||||
|
* 31:00 EMB2APP_UNMASK 0x0
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
#define IPC_EMB2APP_UNMASK_CLEAR_ADDR 0x12000010
|
||||||
|
#define IPC_EMB2APP_UNMASK_CLEAR_OFFSET 0x00000010
|
||||||
|
#define IPC_EMB2APP_UNMASK_CLEAR_INDEX 0x00000004
|
||||||
|
#define IPC_EMB2APP_UNMASK_CLEAR_RESET 0x00000000
|
||||||
|
|
||||||
|
__INLINE void ipc_emb2app_unmask_clear(void *env, u32 value)
|
||||||
|
{
|
||||||
|
REG_IPC_APP_WR(env, IPC_EMB2APP_UNMASK_CLEAR_INDEX, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fields defined in symmetrical set/clear register
|
||||||
|
__INLINE void ipc_emb2app_unmask_clearf(void *env, u32 emb2appunmask)
|
||||||
|
{
|
||||||
|
ASSERT_ERR((((u32)emb2appunmask << 0) & ~((u32)0xFFFFFFFF)) == 0);
|
||||||
|
REG_IPC_APP_WR(env, IPC_EMB2APP_UNMASK_CLEAR_INDEX, (u32)emb2appunmask << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief EMB2APP_STATUS register definition
|
||||||
|
* <pre>
|
||||||
|
* Bits Field Name Reset Value
|
||||||
|
* ----- ------------------ -----------
|
||||||
|
* 31:00 EMB2APP_STATUS 0x0
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_RWNX_OLD_IPC
|
||||||
|
#define IPC_EMB2APP_STATUS_ADDR 0x12000014
|
||||||
|
#define IPC_EMB2APP_STATUS_OFFSET 0x00000014
|
||||||
|
#define IPC_EMB2APP_STATUS_INDEX 0x00000005
|
||||||
|
#else
|
||||||
|
#define IPC_EMB2APP_STATUS_ADDR 0x1200001C
|
||||||
|
#define IPC_EMB2APP_STATUS_OFFSET 0x0000001C
|
||||||
|
#define IPC_EMB2APP_STATUS_INDEX 0x00000007
|
||||||
|
#endif
|
||||||
|
#define IPC_EMB2APP_STATUS_RESET 0x00000000
|
||||||
|
|
||||||
|
__INLINE u32 ipc_emb2app_status_get(void *env)
|
||||||
|
{
|
||||||
|
return REG_IPC_APP_RD(env, IPC_EMB2APP_STATUS_INDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
__INLINE void ipc_emb2app_status_set(void *env, u32 value)
|
||||||
|
{
|
||||||
|
REG_IPC_APP_WR(env, IPC_EMB2APP_STATUS_INDEX, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// field definitions
|
||||||
|
#define IPC_EMB2APP_STATUS_MASK ((u32)0xFFFFFFFF)
|
||||||
|
#define IPC_EMB2APP_STATUS_LSB 0
|
||||||
|
#define IPC_EMB2APP_STATUS_WIDTH ((u32)0x00000020)
|
||||||
|
|
||||||
|
#define IPC_EMB2APP_STATUS_RST 0x0
|
||||||
|
|
||||||
|
__INLINE u32 ipc_emb2app_status_getf(void *env)
|
||||||
|
{
|
||||||
|
u32 localVal = REG_IPC_APP_RD(env, IPC_EMB2APP_STATUS_INDEX);
|
||||||
|
ASSERT_ERR((localVal & ~((u32)0xFFFFFFFF)) == 0);
|
||||||
|
return (localVal >> 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief APP_SIGNATURE register definition
|
||||||
|
* <pre>
|
||||||
|
* Bits Field Name Reset Value
|
||||||
|
* ----- ------------------ ----------
|
||||||
|
* 31:00 APP_SIGNATURE 0x0
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
#define IPC_APP_SIGNATURE_ADDR 0x12000040
|
||||||
|
#define IPC_APP_SIGNATURE_OFFSET 0x00000040
|
||||||
|
#define IPC_APP_SIGNATURE_INDEX 0x00000010
|
||||||
|
#define IPC_APP_SIGNATURE_RESET 0x00000000
|
||||||
|
|
||||||
|
__INLINE u32 ipc_app_signature_get(void *env)
|
||||||
|
{
|
||||||
|
return REG_IPC_APP_RD(env, IPC_APP_SIGNATURE_INDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
__INLINE void ipc_app_signature_set(void *env, u32 value)
|
||||||
|
{
|
||||||
|
REG_IPC_APP_WR(env, IPC_APP_SIGNATURE_INDEX, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// field definitions
|
||||||
|
#define IPC_APP_SIGNATURE_MASK ((u32)0xFFFFFFFF)
|
||||||
|
#define IPC_APP_SIGNATURE_LSB 0
|
||||||
|
#define IPC_APP_SIGNATURE_WIDTH ((u32)0x00000020)
|
||||||
|
|
||||||
|
#define IPC_APP_SIGNATURE_RST 0x0
|
||||||
|
|
||||||
|
__INLINE u32 ipc_app_signature_getf(void *env)
|
||||||
|
{
|
||||||
|
u32 localVal = REG_IPC_APP_RD(env, IPC_APP_SIGNATURE_INDEX);
|
||||||
|
ASSERT_ERR((localVal & ~((u32)0xFFFFFFFF)) == 0);
|
||||||
|
return (localVal >> 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _REG_IPC_APP_H_
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,105 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_bfmer.c
|
||||||
|
*
|
||||||
|
* @brief VHT Beamformer function definitions
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2016-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* INCLUDE FILES
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include "rwnx_bfmer.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FUNCTION DEFINITIONS
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
int rwnx_bfmer_report_add(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta,
|
||||||
|
unsigned int length)
|
||||||
|
{
|
||||||
|
gfp_t flags;
|
||||||
|
struct rwnx_bfmer_report *bfm_report ;
|
||||||
|
|
||||||
|
if (in_softirq())
|
||||||
|
flags = GFP_ATOMIC;
|
||||||
|
else
|
||||||
|
flags = GFP_KERNEL;
|
||||||
|
|
||||||
|
/* Allocate a structure that will contain the beamforming report */
|
||||||
|
bfm_report = kmalloc(sizeof(*bfm_report) + length, flags);
|
||||||
|
|
||||||
|
|
||||||
|
/* Check report allocation */
|
||||||
|
if (!bfm_report) {
|
||||||
|
/* Do not use beamforming */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store report length */
|
||||||
|
bfm_report->length = length;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Need to provide a Virtual Address to the MAC so that it can
|
||||||
|
* upload the received Beamforming Report in driver memory
|
||||||
|
*/
|
||||||
|
bfm_report->dma_addr = dma_map_single(rwnx_hw->dev, &bfm_report->report[0],
|
||||||
|
length, DMA_FROM_DEVICE);
|
||||||
|
|
||||||
|
/* Check DMA mapping result */
|
||||||
|
if (dma_mapping_error(rwnx_hw->dev, bfm_report->dma_addr)) {
|
||||||
|
/* Free allocated report */
|
||||||
|
kfree(bfm_report);
|
||||||
|
/* And leave */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store report structure */
|
||||||
|
rwnx_sta->bfm_report = bfm_report;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rwnx_bfmer_report_del(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta)
|
||||||
|
{
|
||||||
|
/* Verify if a report has been allocated */
|
||||||
|
if (rwnx_sta->bfm_report) {
|
||||||
|
struct rwnx_bfmer_report *bfm_report = rwnx_sta->bfm_report;
|
||||||
|
|
||||||
|
/* Unmap DMA region */
|
||||||
|
dma_unmap_single(rwnx_hw->dev, bfm_report->dma_addr,
|
||||||
|
bfm_report->length, DMA_BIDIRECTIONAL);
|
||||||
|
|
||||||
|
/* Free allocated report structure and clean the pointer */
|
||||||
|
kfree(bfm_report);
|
||||||
|
rwnx_sta->bfm_report = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
u8 rwnx_bfmer_get_rx_nss(const struct ieee80211_vht_cap *vht_capa)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
u8 rx_nss = 0;
|
||||||
|
u16 rx_mcs_map = le16_to_cpu(vht_capa->supp_mcs.rx_mcs_map);
|
||||||
|
|
||||||
|
for (i = 7; i >= 0; i--) {
|
||||||
|
u8 mcs = (rx_mcs_map >> (2 * i)) & 3;
|
||||||
|
|
||||||
|
if (mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
|
||||||
|
rx_nss = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rx_nss;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_RWNX_FULLMAC */
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_bfmer.h
|
||||||
|
*
|
||||||
|
* @brief VHT Beamformer function declarations
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2016-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RWNX_BFMER_H_
|
||||||
|
#define _RWNX_BFMER_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* INCLUDE FILES
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rwnx_defs.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEFINES
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// Maximal supported report length (in bytes)
|
||||||
|
#define RWNX_BFMER_REPORT_MAX_LEN 2048
|
||||||
|
|
||||||
|
/// Size of the allocated report space (twice the maximum report length)
|
||||||
|
#define RWNX_BFMER_REPORT_SPACE_SIZE (RWNX_BFMER_REPORT_MAX_LEN * 2)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TYPE DEFINITIONS
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure used to store a beamforming report.
|
||||||
|
*/
|
||||||
|
struct rwnx_bfmer_report {
|
||||||
|
dma_addr_t dma_addr; /* Virtual address provided to MAC for
|
||||||
|
DMA transfer of the Beamforming Report */
|
||||||
|
unsigned int length; /* Report Length */
|
||||||
|
u8 report[1]; /* Report to be used for VHT TX Beamforming */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FUNCTION DECLARATIONS
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief Allocate memory aiming to contains the Beamforming Report received
|
||||||
|
* from a Beamformee capable capable.
|
||||||
|
* The providing length shall be large enough to contain the VHT Compressed
|
||||||
|
* Beaforming Report and the MU Exclusive part.
|
||||||
|
* It also perform a DMA Mapping providing an address to be provided to the HW
|
||||||
|
* responsible for the DMA transfer of the report.
|
||||||
|
* If successful a struct rwnx_bfmer_report object is allocated, it's address
|
||||||
|
* is stored in rwnx_sta->bfm_report.
|
||||||
|
*
|
||||||
|
* @param[in] rwnx_hw PHY Information
|
||||||
|
* @param[in] rwnx_sta Peer STA Information
|
||||||
|
* @param[in] length Memory size to be allocated
|
||||||
|
*
|
||||||
|
* @return 0 if operation is successful, else -1.
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
int rwnx_bfmer_report_add(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta,
|
||||||
|
unsigned int length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief Free a previously allocated memory intended to be used for
|
||||||
|
* Beamforming Reports.
|
||||||
|
*
|
||||||
|
* @param[in] rwnx_hw PHY Information
|
||||||
|
* @param[in] rwnx_sta Peer STA Information
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
void rwnx_bfmer_report_del(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta);
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @brief Parse a Rx VHT-MCS map in order to deduce the maximum number of
|
||||||
|
* Spatial Streams supported by a beamformee.
|
||||||
|
*
|
||||||
|
* @param[in] vht_capa Received VHT Capability field.
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
u8 rwnx_bfmer_get_rx_nss(const struct ieee80211_vht_cap *vht_capa);
|
||||||
|
#endif /* CONFIG_RWNX_FULLMAC */
|
||||||
|
|
||||||
|
#endif /* _RWNX_BFMER_H_ */
|
||||||
@@ -0,0 +1,237 @@
|
|||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_configparse.c
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
#include <linux/firmware.h>
|
||||||
|
#include <linux/if_ether.h>
|
||||||
|
|
||||||
|
#include "rwnx_defs.h"
|
||||||
|
#include "rwnx_cfgfile.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static const char *rwnx_find_tag(const u8 *file_data, unsigned int file_size,
|
||||||
|
const char *tag_name, unsigned int tag_len)
|
||||||
|
{
|
||||||
|
unsigned int curr, line_start = 0, line_size;
|
||||||
|
|
||||||
|
RWNX_DBG(RWNX_FN_ENTRY_STR);
|
||||||
|
|
||||||
|
/* Walk through all the lines of the configuration file */
|
||||||
|
while (line_start < file_size) {
|
||||||
|
/* Search the end of the current line (or the end of the file) */
|
||||||
|
for (curr = line_start; curr < file_size; curr++)
|
||||||
|
if (file_data[curr] == '\n')
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Compute the line size */
|
||||||
|
line_size = curr - line_start;
|
||||||
|
|
||||||
|
/* Check if this line contains the expected tag */
|
||||||
|
if ((line_size == (strlen(tag_name) + tag_len)) &&
|
||||||
|
(!strncmp(&file_data[line_start], tag_name, strlen(tag_name))))
|
||||||
|
return (&file_data[line_start + strlen(tag_name)]);
|
||||||
|
|
||||||
|
/* Move to next line */
|
||||||
|
line_start = curr + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tag not found */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the Config file used at init time
|
||||||
|
*/
|
||||||
|
int rwnx_parse_configfile(struct rwnx_hw *rwnx_hw, const char *filename,
|
||||||
|
struct rwnx_conf_file *config)
|
||||||
|
{
|
||||||
|
const struct firmware *config_fw;
|
||||||
|
u8 dflt_mac[ETH_ALEN] = { 0, 111, 111, 111, 111, 0 };
|
||||||
|
int ret;
|
||||||
|
const u8 *tag_ptr;
|
||||||
|
|
||||||
|
RWNX_DBG(RWNX_FN_ENTRY_STR);
|
||||||
|
|
||||||
|
if ((ret = request_firmware(&config_fw, filename, rwnx_hw->dev))) {
|
||||||
|
printk(KERN_CRIT "%s: Failed to get %s (%d)\n", __func__, filename, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get MAC Address */
|
||||||
|
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
|
||||||
|
"MAC_ADDR=", strlen("00:00:00:00:00:00"));
|
||||||
|
if (tag_ptr != NULL) {
|
||||||
|
u8 *addr = config->mac_addr;
|
||||||
|
if (sscanf(tag_ptr,
|
||||||
|
"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
|
||||||
|
addr + 0, addr + 1, addr + 2,
|
||||||
|
addr + 3, addr + 4, addr + 5) != ETH_ALEN)
|
||||||
|
memcpy(config->mac_addr, dflt_mac, ETH_ALEN);
|
||||||
|
} else
|
||||||
|
memcpy(config->mac_addr, dflt_mac, ETH_ALEN);
|
||||||
|
|
||||||
|
RWNX_DBG("MAC Address is:\n%pM\n", config->mac_addr);
|
||||||
|
|
||||||
|
/* Release the configuration file */
|
||||||
|
release_firmware(config_fw);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the Config file used at init time
|
||||||
|
*/
|
||||||
|
int rwnx_parse_phy_configfile(struct rwnx_hw *rwnx_hw, const char *filename,
|
||||||
|
struct rwnx_phy_conf_file *config, int path)
|
||||||
|
{
|
||||||
|
const struct firmware *config_fw;
|
||||||
|
int ret;
|
||||||
|
const u8 *tag_ptr;
|
||||||
|
|
||||||
|
RWNX_DBG(RWNX_FN_ENTRY_STR);
|
||||||
|
|
||||||
|
if ((ret = request_firmware(&config_fw, filename, rwnx_hw->dev))) {
|
||||||
|
printk(KERN_CRIT "%s: Failed to get %s (%d)\n", __func__, filename, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get Trident path mapping */
|
||||||
|
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
|
||||||
|
"TRD_PATH_MAPPING=", strlen("00"));
|
||||||
|
if (tag_ptr != NULL) {
|
||||||
|
u8 val;
|
||||||
|
if (sscanf(tag_ptr, "%hhx", &val) == 1)
|
||||||
|
config->trd.path_mapping = val;
|
||||||
|
else
|
||||||
|
config->trd.path_mapping = path;
|
||||||
|
} else
|
||||||
|
config->trd.path_mapping = path;
|
||||||
|
|
||||||
|
RWNX_DBG("Trident path mapping is: %d\n", config->trd.path_mapping);
|
||||||
|
|
||||||
|
/* Get DC offset compensation */
|
||||||
|
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
|
||||||
|
"TX_DC_OFF_COMP=", strlen("00000000"));
|
||||||
|
if (tag_ptr != NULL) {
|
||||||
|
if (sscanf(tag_ptr, "%08x", &config->trd.tx_dc_off_comp) != 1)
|
||||||
|
config->trd.tx_dc_off_comp = 0;
|
||||||
|
} else
|
||||||
|
config->trd.tx_dc_off_comp = 0;
|
||||||
|
|
||||||
|
RWNX_DBG("TX DC offset compensation is: %08X\n", config->trd.tx_dc_off_comp);
|
||||||
|
|
||||||
|
/* Get Karst TX IQ compensation value for path0 on 2.4GHz */
|
||||||
|
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
|
||||||
|
"KARST_TX_IQ_COMP_2_4G_PATH_0=", strlen("00000000"));
|
||||||
|
if (tag_ptr != NULL) {
|
||||||
|
if (sscanf(tag_ptr, "%08x", &config->karst.tx_iq_comp_2_4G[0]) != 1)
|
||||||
|
config->karst.tx_iq_comp_2_4G[0] = 0x01000000;
|
||||||
|
} else
|
||||||
|
config->karst.tx_iq_comp_2_4G[0] = 0x01000000;
|
||||||
|
|
||||||
|
RWNX_DBG("Karst TX IQ compensation for path 0 on 2.4GHz is: %08X\n", config->karst.tx_iq_comp_2_4G[0]);
|
||||||
|
|
||||||
|
/* Get Karst TX IQ compensation value for path1 on 2.4GHz */
|
||||||
|
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
|
||||||
|
"KARST_TX_IQ_COMP_2_4G_PATH_1=", strlen("00000000"));
|
||||||
|
if (tag_ptr != NULL) {
|
||||||
|
if (sscanf(tag_ptr, "%08x", &config->karst.tx_iq_comp_2_4G[1]) != 1)
|
||||||
|
config->karst.tx_iq_comp_2_4G[1] = 0x01000000;
|
||||||
|
} else
|
||||||
|
config->karst.tx_iq_comp_2_4G[1] = 0x01000000;
|
||||||
|
|
||||||
|
RWNX_DBG("Karst TX IQ compensation for path 1 on 2.4GHz is: %08X\n", config->karst.tx_iq_comp_2_4G[1]);
|
||||||
|
|
||||||
|
/* Get Karst RX IQ compensation value for path0 on 2.4GHz */
|
||||||
|
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
|
||||||
|
"KARST_RX_IQ_COMP_2_4G_PATH_0=", strlen("00000000"));
|
||||||
|
if (tag_ptr != NULL) {
|
||||||
|
if (sscanf(tag_ptr, "%08x", &config->karst.rx_iq_comp_2_4G[0]) != 1)
|
||||||
|
config->karst.rx_iq_comp_2_4G[0] = 0x01000000;
|
||||||
|
} else
|
||||||
|
config->karst.rx_iq_comp_2_4G[0] = 0x01000000;
|
||||||
|
|
||||||
|
RWNX_DBG("Karst RX IQ compensation for path 0 on 2.4GHz is: %08X\n", config->karst.rx_iq_comp_2_4G[0]);
|
||||||
|
|
||||||
|
/* Get Karst RX IQ compensation value for path1 on 2.4GHz */
|
||||||
|
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
|
||||||
|
"KARST_RX_IQ_COMP_2_4G_PATH_1=", strlen("00000000"));
|
||||||
|
if (tag_ptr != NULL) {
|
||||||
|
if (sscanf(tag_ptr, "%08x", &config->karst.rx_iq_comp_2_4G[1]) != 1)
|
||||||
|
config->karst.rx_iq_comp_2_4G[1] = 0x01000000;
|
||||||
|
} else
|
||||||
|
config->karst.rx_iq_comp_2_4G[1] = 0x01000000;
|
||||||
|
|
||||||
|
RWNX_DBG("Karst RX IQ compensation for path 1 on 2.4GHz is: %08X\n", config->karst.rx_iq_comp_2_4G[1]);
|
||||||
|
|
||||||
|
/* Get Karst TX IQ compensation value for path0 on 5GHz */
|
||||||
|
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
|
||||||
|
"KARST_TX_IQ_COMP_5G_PATH_0=", strlen("00000000"));
|
||||||
|
if (tag_ptr != NULL) {
|
||||||
|
if (sscanf(tag_ptr, "%08x", &config->karst.tx_iq_comp_5G[0]) != 1)
|
||||||
|
config->karst.tx_iq_comp_5G[0] = 0x01000000;
|
||||||
|
} else
|
||||||
|
config->karst.tx_iq_comp_5G[0] = 0x01000000;
|
||||||
|
|
||||||
|
RWNX_DBG("Karst TX IQ compensation for path 0 on 5GHz is: %08X\n", config->karst.tx_iq_comp_5G[0]);
|
||||||
|
|
||||||
|
/* Get Karst TX IQ compensation value for path1 on 5GHz */
|
||||||
|
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
|
||||||
|
"KARST_TX_IQ_COMP_5G_PATH_1=", strlen("00000000"));
|
||||||
|
if (tag_ptr != NULL) {
|
||||||
|
if (sscanf(tag_ptr, "%08x", &config->karst.tx_iq_comp_5G[1]) != 1)
|
||||||
|
config->karst.tx_iq_comp_5G[1] = 0x01000000;
|
||||||
|
} else
|
||||||
|
config->karst.tx_iq_comp_5G[1] = 0x01000000;
|
||||||
|
|
||||||
|
RWNX_DBG("Karst TX IQ compensation for path 1 on 5GHz is: %08X\n", config->karst.tx_iq_comp_5G[1]);
|
||||||
|
|
||||||
|
/* Get Karst RX IQ compensation value for path0 on 5GHz */
|
||||||
|
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
|
||||||
|
"KARST_RX_IQ_COMP_5G_PATH_0=", strlen("00000000"));
|
||||||
|
if (tag_ptr != NULL) {
|
||||||
|
if (sscanf(tag_ptr, "%08x", &config->karst.rx_iq_comp_5G[0]) != 1)
|
||||||
|
config->karst.rx_iq_comp_5G[0] = 0x01000000;
|
||||||
|
} else
|
||||||
|
config->karst.rx_iq_comp_5G[0] = 0x01000000;
|
||||||
|
|
||||||
|
RWNX_DBG("Karst RX IQ compensation for path 0 on 5GHz is: %08X\n", config->karst.rx_iq_comp_5G[0]);
|
||||||
|
|
||||||
|
/* Get Karst RX IQ compensation value for path1 on 5GHz */
|
||||||
|
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
|
||||||
|
"KARST_RX_IQ_COMP_5G_PATH_1=", strlen("00000000"));
|
||||||
|
if (tag_ptr != NULL) {
|
||||||
|
if (sscanf(tag_ptr, "%08x", &config->karst.rx_iq_comp_5G[1]) != 1)
|
||||||
|
config->karst.rx_iq_comp_5G[1] = 0x01000000;
|
||||||
|
} else
|
||||||
|
config->karst.rx_iq_comp_5G[1] = 0x01000000;
|
||||||
|
|
||||||
|
RWNX_DBG("Karst RX IQ compensation for path 1 on 5GHz is: %08X\n", config->karst.rx_iq_comp_5G[1]);
|
||||||
|
|
||||||
|
/* Get Karst default path */
|
||||||
|
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
|
||||||
|
"KARST_DEFAULT_PATH=", strlen("00"));
|
||||||
|
if (tag_ptr != NULL) {
|
||||||
|
u8 val;
|
||||||
|
if (sscanf(tag_ptr, "%hhx", &val) == 1)
|
||||||
|
config->karst.path_used = val;
|
||||||
|
else
|
||||||
|
config->karst.path_used = path;
|
||||||
|
} else
|
||||||
|
config->karst.path_used = path;
|
||||||
|
|
||||||
|
RWNX_DBG("Karst default path is: %d\n", config->karst.path_used);
|
||||||
|
|
||||||
|
/* Release the configuration file */
|
||||||
|
release_firmware(config_fw);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_cfgfile.h
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RWNX_CFGFILE_H_
|
||||||
|
#define _RWNX_CFGFILE_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure used to retrieve information from the Config file used at Initialization time
|
||||||
|
*/
|
||||||
|
struct rwnx_conf_file {
|
||||||
|
u8 mac_addr[ETH_ALEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure used to retrieve information from the PHY Config file used at Initialization time
|
||||||
|
*/
|
||||||
|
struct rwnx_phy_conf_file {
|
||||||
|
struct phy_trd_cfg_tag trd;
|
||||||
|
struct phy_karst_cfg_tag karst;
|
||||||
|
};
|
||||||
|
|
||||||
|
int rwnx_parse_configfile(struct rwnx_hw *rwnx_hw, const char *filename,
|
||||||
|
struct rwnx_conf_file *config);
|
||||||
|
|
||||||
|
int rwnx_parse_phy_configfile(struct rwnx_hw *rwnx_hw, const char *filename,
|
||||||
|
struct rwnx_phy_conf_file *config, int path);
|
||||||
|
|
||||||
|
#endif /* _RWNX_CFGFILE_H_ */
|
||||||
@@ -0,0 +1,545 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* rwnx_cmds.c
|
||||||
|
*
|
||||||
|
* Handles queueing (push to IPC, ack/cfm from IPC) of commands issued to
|
||||||
|
* LMAC FW
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2014-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
//#define CREATE_TRACE_POINTS
|
||||||
|
#include <linux/list.h>
|
||||||
|
|
||||||
|
#include "rwnx_cmds.h"
|
||||||
|
#include "rwnx_defs.h"
|
||||||
|
#include "rwnx_strs.h"
|
||||||
|
#include "rwnx_events.h"
|
||||||
|
#include "aicwf_txrxif.h"
|
||||||
|
#ifdef AICWF_SDIO_SUPPORT
|
||||||
|
#include "aicwf_sdio.h"
|
||||||
|
#else
|
||||||
|
#include "aicwf_usb.h"
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
extern int aicwf_sdio_writeb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 val);
|
||||||
|
|
||||||
|
void rwnx_cmd_free(struct rwnx_cmd *cmd);
|
||||||
|
|
||||||
|
static void cmd_dump(const struct rwnx_cmd *cmd)
|
||||||
|
{
|
||||||
|
printk(KERN_CRIT "tkn[%d] flags:%04x result:%3d cmd:%4d-%-24s - reqcfm(%4d-%-s)\n",
|
||||||
|
cmd->tkn, cmd->flags, cmd->result, cmd->id, RWNX_ID2STR(cmd->id),
|
||||||
|
cmd->reqid, cmd->reqid != (lmac_msg_id_t)-1 ? RWNX_ID2STR(cmd->reqid) : "none");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void cmd_complete(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd)
|
||||||
|
{
|
||||||
|
//RWNX_DBG(RWNX_FN_ENTRY_STR);
|
||||||
|
lockdep_assert_held(&cmd_mgr->lock);
|
||||||
|
|
||||||
|
list_del(&cmd->list);
|
||||||
|
cmd_mgr->queue_sz--;
|
||||||
|
|
||||||
|
cmd->flags |= RWNX_CMD_FLAG_DONE;
|
||||||
|
if (cmd->flags & RWNX_CMD_FLAG_NONBLOCK) {
|
||||||
|
rwnx_cmd_free(cmd);//kfree(cmd);AIDEN
|
||||||
|
} else {
|
||||||
|
if (RWNX_CMD_WAIT_COMPLETE(cmd->flags)) {
|
||||||
|
cmd->result = 0;
|
||||||
|
complete(&cmd->complete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmd_mgr_queue_force_defer(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd)
|
||||||
|
{
|
||||||
|
bool defer_push = false;
|
||||||
|
|
||||||
|
RWNX_DBG(RWNX_FN_ENTRY_STR);
|
||||||
|
#ifdef CREATE_TRACE_POINTS
|
||||||
|
trace_msg_send(cmd->id);
|
||||||
|
#endif
|
||||||
|
spin_lock_bh(&cmd_mgr->lock);
|
||||||
|
|
||||||
|
if (cmd_mgr->state == RWNX_CMD_MGR_STATE_CRASHED) {
|
||||||
|
printk(KERN_CRIT"cmd queue crashed\n");
|
||||||
|
cmd->result = -EPIPE;
|
||||||
|
spin_unlock_bh(&cmd_mgr->lock);
|
||||||
|
return -EPIPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_RWNX_FHOST
|
||||||
|
if (!list_empty(&cmd_mgr->cmds)) {
|
||||||
|
if (cmd_mgr->queue_sz == cmd_mgr->max_queue_sz) {
|
||||||
|
printk(KERN_CRIT"Too many cmds (%d) already queued\n",
|
||||||
|
cmd_mgr->max_queue_sz);
|
||||||
|
cmd->result = -ENOMEM;
|
||||||
|
spin_unlock_bh(&cmd_mgr->lock);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
cmd->flags |= RWNX_CMD_FLAG_WAIT_PUSH;
|
||||||
|
defer_push = true;
|
||||||
|
|
||||||
|
if (cmd->flags & RWNX_CMD_FLAG_REQ_CFM)
|
||||||
|
cmd->flags |= RWNX_CMD_FLAG_WAIT_CFM;
|
||||||
|
|
||||||
|
cmd->tkn = cmd_mgr->next_tkn++;
|
||||||
|
cmd->result = -EINTR;
|
||||||
|
|
||||||
|
if (!(cmd->flags & RWNX_CMD_FLAG_NONBLOCK))
|
||||||
|
init_completion(&cmd->complete);
|
||||||
|
|
||||||
|
list_add_tail(&cmd->list, &cmd_mgr->cmds);
|
||||||
|
cmd_mgr->queue_sz++;
|
||||||
|
spin_unlock_bh(&cmd_mgr->lock);
|
||||||
|
|
||||||
|
WAKE_CMD_WORK(cmd_mgr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rwnx_msg_free_(struct lmac_msg *msg);
|
||||||
|
|
||||||
|
|
||||||
|
static int cmd_mgr_queue(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
#ifdef AICWF_SDIO_SUPPORT
|
||||||
|
struct aic_sdio_dev *sdiodev = container_of(cmd_mgr, struct aic_sdio_dev, cmd_mgr);
|
||||||
|
#endif
|
||||||
|
#ifdef AICWF_USB_SUPPORT
|
||||||
|
|
||||||
|
struct aic_usb_dev *usbdev = container_of(cmd_mgr, struct aic_usb_dev, cmd_mgr);
|
||||||
|
#endif
|
||||||
|
bool defer_push = false;
|
||||||
|
|
||||||
|
//RWNX_DBG(RWNX_FN_ENTRY_STR);
|
||||||
|
#ifdef CREATE_TRACE_POINTS
|
||||||
|
trace_msg_send(cmd->id);
|
||||||
|
#endif
|
||||||
|
spin_lock_bh(&cmd_mgr->lock);
|
||||||
|
|
||||||
|
if (cmd_mgr->state == RWNX_CMD_MGR_STATE_CRASHED) {
|
||||||
|
printk(KERN_CRIT"cmd queue crashed\n");
|
||||||
|
cmd->result = -EPIPE;
|
||||||
|
spin_unlock_bh(&cmd_mgr->lock);
|
||||||
|
return -EPIPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_RWNX_FHOST
|
||||||
|
if (!list_empty(&cmd_mgr->cmds)) {
|
||||||
|
struct rwnx_cmd *last;
|
||||||
|
|
||||||
|
if (cmd_mgr->queue_sz == cmd_mgr->max_queue_sz) {
|
||||||
|
printk(KERN_CRIT"Too many cmds (%d) already queued\n",
|
||||||
|
cmd_mgr->max_queue_sz);
|
||||||
|
cmd->result = -ENOMEM;
|
||||||
|
spin_unlock_bh(&cmd_mgr->lock);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
last = list_entry(cmd_mgr->cmds.prev, struct rwnx_cmd, list);
|
||||||
|
if (last->flags & (RWNX_CMD_FLAG_WAIT_ACK | RWNX_CMD_FLAG_WAIT_PUSH | RWNX_CMD_FLAG_WAIT_CFM)) {
|
||||||
|
#if 0 // queue even NONBLOCK command.
|
||||||
|
if (cmd->flags & RWNX_CMD_FLAG_NONBLOCK) {
|
||||||
|
printk(KERN_CRIT"cmd queue busy\n");
|
||||||
|
cmd->result = -EBUSY;
|
||||||
|
spin_unlock_bh(&cmd_mgr->lock);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
cmd->flags |= RWNX_CMD_FLAG_WAIT_PUSH;
|
||||||
|
defer_push = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
cmd->flags |= RWNX_CMD_FLAG_WAIT_ACK;
|
||||||
|
#endif
|
||||||
|
if (cmd->flags & RWNX_CMD_FLAG_REQ_CFM)
|
||||||
|
cmd->flags |= RWNX_CMD_FLAG_WAIT_CFM;
|
||||||
|
|
||||||
|
cmd->tkn = cmd_mgr->next_tkn++;
|
||||||
|
cmd->result = -EINTR;
|
||||||
|
|
||||||
|
if (!(cmd->flags & RWNX_CMD_FLAG_NONBLOCK))
|
||||||
|
init_completion(&cmd->complete);
|
||||||
|
|
||||||
|
list_add_tail(&cmd->list, &cmd_mgr->cmds);
|
||||||
|
cmd_mgr->queue_sz++;
|
||||||
|
|
||||||
|
if(cmd->a2e_msg->id == ME_TRAFFIC_IND_REQ
|
||||||
|
#ifdef AICWF_ARP_OFFLOAD
|
||||||
|
|| cmd->a2e_msg->id == MM_SET_ARPOFFLOAD_REQ
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
defer_push = true;
|
||||||
|
cmd->flags |= RWNX_CMD_FLAG_WAIT_PUSH;
|
||||||
|
//printk("defer push: tkn=%d\r\n", cmd->tkn);
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_unlock_bh(&cmd_mgr->lock);
|
||||||
|
if (!defer_push) {
|
||||||
|
AICWFDBG(LOGTRACE, "queue:id=%x, param_len=%u\n",cmd->a2e_msg->id, cmd->a2e_msg->param_len);
|
||||||
|
|
||||||
|
#ifdef AICWF_SDIO_SUPPORT
|
||||||
|
aicwf_set_cmd_tx((void *)(sdiodev), cmd->a2e_msg, sizeof(struct lmac_msg) + cmd->a2e_msg->param_len);
|
||||||
|
#else
|
||||||
|
aicwf_set_cmd_tx((void *)(usbdev), cmd->a2e_msg, sizeof(struct lmac_msg) + cmd->a2e_msg->param_len);
|
||||||
|
#endif
|
||||||
|
//rwnx_ipc_msg_push(rwnx_hw, cmd, RWNX_CMD_A2EMSG_LEN(cmd->a2e_msg));
|
||||||
|
|
||||||
|
kfree(cmd->a2e_msg);
|
||||||
|
} else {
|
||||||
|
if(cmd_mgr->queue_sz <= 1){
|
||||||
|
WAKE_CMD_WORK(cmd_mgr);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(cmd->flags & RWNX_CMD_FLAG_NONBLOCK)) {
|
||||||
|
#ifdef CONFIG_RWNX_FHOST
|
||||||
|
if (wait_for_completion_killable(&cmd->complete)) {
|
||||||
|
cmd->result = -EINTR;
|
||||||
|
spin_lock_bh(&cmd_mgr->lock);
|
||||||
|
cmd_complete(cmd_mgr, cmd);
|
||||||
|
spin_unlock_bh(&cmd_mgr->lock);
|
||||||
|
/* TODO: kill the cmd at fw level */
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
unsigned long tout = msecs_to_jiffies(RWNX_80211_CMD_TIMEOUT_MS/*AIDEN workaround* cmd_mgr->queue_sz*/);
|
||||||
|
if (!wait_for_completion_killable_timeout(&cmd->complete, tout)) {
|
||||||
|
printk(KERN_CRIT"%s cmd timed-out cmd_mgr->queue_sz:%d\n", __func__,cmd_mgr->queue_sz);
|
||||||
|
#ifdef AICWF_SDIO_SUPPORT
|
||||||
|
ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_WAKEUP_REG, 2);
|
||||||
|
if (ret < 0) {
|
||||||
|
sdio_err("reg:%d write failed!\n", SDIOWIFI_WAKEUP_REG);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
cmd_dump(cmd);
|
||||||
|
spin_lock_bh(&cmd_mgr->lock);
|
||||||
|
|
||||||
|
cmd_mgr->state = RWNX_CMD_MGR_STATE_CRASHED;
|
||||||
|
if (!(cmd->flags & RWNX_CMD_FLAG_DONE)) {
|
||||||
|
cmd->result = -ETIMEDOUT;
|
||||||
|
cmd_complete(cmd_mgr, cmd);
|
||||||
|
}
|
||||||
|
ret = -ETIMEDOUT;
|
||||||
|
spin_unlock_bh(&cmd_mgr->lock);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
rwnx_cmd_free(cmd);//kfree(cmd);AIDEN
|
||||||
|
if(!list_empty(&cmd_mgr->cmds) && usbdev->state == USB_UP_ST)
|
||||||
|
WAKE_CMD_WORK(cmd_mgr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
cmd->result = 0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static int cmd_mgr_llind(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd)
|
||||||
|
{
|
||||||
|
struct rwnx_cmd *cur, *acked = NULL, *next = NULL;
|
||||||
|
|
||||||
|
RWNX_DBG(RWNX_FN_ENTRY_STR);
|
||||||
|
|
||||||
|
spin_lock_bh(&cmd_mgr->lock);
|
||||||
|
list_for_each_entry(cur, &cmd_mgr->cmds, list) {
|
||||||
|
if (!acked) {
|
||||||
|
if (cur->tkn == cmd->tkn) {
|
||||||
|
if (WARN_ON_ONCE(cur != cmd)) {
|
||||||
|
cmd_dump(cmd);
|
||||||
|
}
|
||||||
|
acked = cur;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cur->flags & RWNX_CMD_FLAG_WAIT_PUSH) {
|
||||||
|
next = cur;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!acked) {
|
||||||
|
printk(KERN_CRIT "Error: acked cmd not found\n");
|
||||||
|
} else {
|
||||||
|
cmd->flags &= ~RWNX_CMD_FLAG_WAIT_ACK;
|
||||||
|
if (RWNX_CMD_WAIT_COMPLETE(cmd->flags))
|
||||||
|
cmd_complete(cmd_mgr, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next) {
|
||||||
|
#if 0 //there is no ack
|
||||||
|
struct rwnx_hw *rwnx_hw = container_of(cmd_mgr, struct rwnx_hw, cmd_mgr);
|
||||||
|
next->flags &= ~RWNX_CMD_FLAG_WAIT_PUSH;
|
||||||
|
rwnx_ipc_msg_push(rwnx_hw, next, RWNX_CMD_A2EMSG_LEN(next->a2e_msg));
|
||||||
|
kfree(next->a2e_msg);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
spin_unlock(&cmd_mgr->lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_mgr_task_process(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct rwnx_cmd_mgr *cmd_mgr = container_of(work, struct rwnx_cmd_mgr, cmdWork);
|
||||||
|
struct rwnx_cmd *cur, *next = NULL;
|
||||||
|
unsigned long tout;
|
||||||
|
|
||||||
|
RWNX_DBG(RWNX_FN_ENTRY_STR);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
next = NULL;
|
||||||
|
spin_lock_bh(&cmd_mgr->lock);
|
||||||
|
|
||||||
|
list_for_each_entry(cur, &cmd_mgr->cmds, list) {
|
||||||
|
if (cur->flags & RWNX_CMD_FLAG_WAIT_PUSH) { //just judge the first
|
||||||
|
next = cur;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
spin_unlock_bh(&cmd_mgr->lock);
|
||||||
|
|
||||||
|
if(next == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (next) {
|
||||||
|
#ifdef AICWF_SDIO_SUPPORT
|
||||||
|
struct aic_sdio_dev *sdiodev = container_of(cmd_mgr, struct aic_sdio_dev, cmd_mgr);
|
||||||
|
#endif
|
||||||
|
#ifdef AICWF_USB_SUPPORT
|
||||||
|
struct aic_usb_dev *usbdev = container_of(cmd_mgr, struct aic_usb_dev, cmd_mgr);
|
||||||
|
#endif
|
||||||
|
next->flags &= ~RWNX_CMD_FLAG_WAIT_PUSH;
|
||||||
|
|
||||||
|
//printk("cmd_process, cmd->id=%d, tkn=%d\r\n",next->reqid, next->tkn);
|
||||||
|
//rwnx_ipc_msg_push(rwnx_hw, next, RWNX_CMD_A2EMSG_LEN(next->a2e_msg));
|
||||||
|
#ifdef AICWF_SDIO_SUPPORT
|
||||||
|
aicwf_set_cmd_tx((void *)(sdiodev), next->a2e_msg, sizeof(struct lmac_msg) + next->a2e_msg->param_len);
|
||||||
|
#else
|
||||||
|
aicwf_set_cmd_tx((void *)(usbdev), next->a2e_msg, sizeof(struct lmac_msg) + next->a2e_msg->param_len);
|
||||||
|
#endif
|
||||||
|
kfree(next->a2e_msg);
|
||||||
|
|
||||||
|
tout = msecs_to_jiffies(RWNX_80211_CMD_TIMEOUT_MS * cmd_mgr->queue_sz);
|
||||||
|
if (!wait_for_completion_killable_timeout(&next->complete, tout)) {
|
||||||
|
printk(KERN_CRIT"%s cmd timed-out cmd_mgr->queue_sz:%d\n", __func__, cmd_mgr->queue_sz);
|
||||||
|
cmd_dump(next);
|
||||||
|
spin_lock_bh(&cmd_mgr->lock);
|
||||||
|
//AIDEN workaround
|
||||||
|
cmd_mgr->state = RWNX_CMD_MGR_STATE_CRASHED;
|
||||||
|
if (!(next->flags & RWNX_CMD_FLAG_DONE)) {
|
||||||
|
next->result = -ETIMEDOUT;
|
||||||
|
cmd_complete(cmd_mgr, next);
|
||||||
|
}
|
||||||
|
spin_unlock_bh(&cmd_mgr->lock);
|
||||||
|
} else
|
||||||
|
rwnx_cmd_free(next);//kfree(next);AIDEN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int cmd_mgr_run_callback(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd,
|
||||||
|
struct rwnx_cmd_e2amsg *msg, msg_cb_fct cb)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (! cb){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//RWNX_DBG(RWNX_FN_ENTRY_STR);
|
||||||
|
#ifndef CONFIG_DEBUG_ATOMIC_SLEEP
|
||||||
|
//spin_lock_bh(&rwnx_hw->cb_lock);
|
||||||
|
#endif
|
||||||
|
res = cb(rwnx_hw, cmd, msg);
|
||||||
|
#ifndef CONFIG_DEBUG_ATOMIC_SLEEP
|
||||||
|
//spin_unlock_bh(&rwnx_hw->cb_lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
|
||||||
|
*/
|
||||||
|
static int cmd_mgr_msgind(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd_e2amsg *msg,
|
||||||
|
msg_cb_fct cb)
|
||||||
|
{
|
||||||
|
#ifdef AICWF_SDIO_SUPPORT
|
||||||
|
struct aic_sdio_dev *sdiodev = container_of(cmd_mgr, struct aic_sdio_dev, cmd_mgr);
|
||||||
|
struct rwnx_hw *rwnx_hw = sdiodev->rwnx_hw;
|
||||||
|
#endif
|
||||||
|
#ifdef AICWF_USB_SUPPORT
|
||||||
|
struct aic_usb_dev *usbdev = container_of(cmd_mgr, struct aic_usb_dev, cmd_mgr);
|
||||||
|
struct rwnx_hw *rwnx_hw = usbdev->rwnx_hw;
|
||||||
|
#endif
|
||||||
|
struct rwnx_cmd *cmd, *pos;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
// RWNX_DBG(RWNX_FN_ENTRY_STR);
|
||||||
|
#ifdef CREATE_TRACE_POINTS
|
||||||
|
trace_msg_recv(msg->id);
|
||||||
|
#endif
|
||||||
|
AICWFDBG(LOGTRACE, "%s cmd->id=%d\n", __func__, msg->id);
|
||||||
|
spin_lock_bh(&cmd_mgr->lock);
|
||||||
|
list_for_each_entry_safe(cmd, pos, &cmd_mgr->cmds, list) {
|
||||||
|
if (cmd->reqid == msg->id &&
|
||||||
|
(cmd->flags & RWNX_CMD_FLAG_WAIT_CFM)) {
|
||||||
|
|
||||||
|
if (!cmd_mgr_run_callback(rwnx_hw, cmd, msg, cb)) {
|
||||||
|
found = true;
|
||||||
|
cmd->flags &= ~RWNX_CMD_FLAG_WAIT_CFM;
|
||||||
|
|
||||||
|
if (WARN((msg->param_len > RWNX_CMD_E2AMSG_LEN_MAX),
|
||||||
|
"Unexpect E2A msg len %d > %d\n", msg->param_len,
|
||||||
|
RWNX_CMD_E2AMSG_LEN_MAX)) {
|
||||||
|
msg->param_len = RWNX_CMD_E2AMSG_LEN_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd->e2a_msg && msg->param_len)
|
||||||
|
memcpy(cmd->e2a_msg, &msg->param, msg->param_len);
|
||||||
|
|
||||||
|
if (RWNX_CMD_WAIT_COMPLETE(cmd->flags))
|
||||||
|
cmd_complete(cmd_mgr, cmd);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock_bh(&cmd_mgr->lock);
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
cmd_mgr_run_callback(rwnx_hw, NULL, msg, cb);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void cmd_mgr_print(struct rwnx_cmd_mgr *cmd_mgr)
|
||||||
|
{
|
||||||
|
struct rwnx_cmd *cur;
|
||||||
|
|
||||||
|
spin_lock_bh(&cmd_mgr->lock);
|
||||||
|
RWNX_DBG("q_sz/max: %2d / %2d - next tkn: %d\n",
|
||||||
|
cmd_mgr->queue_sz, cmd_mgr->max_queue_sz,
|
||||||
|
cmd_mgr->next_tkn);
|
||||||
|
list_for_each_entry(cur, &cmd_mgr->cmds, list) {
|
||||||
|
cmd_dump(cur);
|
||||||
|
}
|
||||||
|
spin_unlock_bh(&cmd_mgr->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmd_mgr_drain(struct rwnx_cmd_mgr *cmd_mgr)
|
||||||
|
{
|
||||||
|
struct rwnx_cmd *cur, *nxt;
|
||||||
|
|
||||||
|
RWNX_DBG(RWNX_FN_ENTRY_STR);
|
||||||
|
|
||||||
|
spin_lock_bh(&cmd_mgr->lock);
|
||||||
|
list_for_each_entry_safe(cur, nxt, &cmd_mgr->cmds, list) {
|
||||||
|
list_del(&cur->list);
|
||||||
|
cmd_mgr->queue_sz--;
|
||||||
|
if (!(cur->flags & RWNX_CMD_FLAG_NONBLOCK))
|
||||||
|
complete(&cur->complete);
|
||||||
|
}
|
||||||
|
spin_unlock_bh(&cmd_mgr->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rwnx_cmd_mgr_init(struct rwnx_cmd_mgr *cmd_mgr)
|
||||||
|
{
|
||||||
|
RWNX_DBG(RWNX_FN_ENTRY_STR);
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&cmd_mgr->cmds);
|
||||||
|
cmd_mgr->state = RWNX_CMD_MGR_STATE_INITED;
|
||||||
|
spin_lock_init(&cmd_mgr->lock);
|
||||||
|
cmd_mgr->max_queue_sz = RWNX_CMD_MAX_QUEUED;
|
||||||
|
cmd_mgr->queue = &cmd_mgr_queue;
|
||||||
|
cmd_mgr->print = &cmd_mgr_print;
|
||||||
|
cmd_mgr->drain = &cmd_mgr_drain;
|
||||||
|
cmd_mgr->llind = &cmd_mgr_llind;
|
||||||
|
cmd_mgr->msgind = &cmd_mgr_msgind;
|
||||||
|
|
||||||
|
INIT_WORK(&cmd_mgr->cmdWork, cmd_mgr_task_process);
|
||||||
|
cmd_mgr->cmd_wq = create_singlethread_workqueue("cmd_wq");
|
||||||
|
if (!cmd_mgr->cmd_wq) {
|
||||||
|
txrx_err("insufficient memory to create cmd workqueue.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rwnx_cmd_mgr_deinit(struct rwnx_cmd_mgr *cmd_mgr)
|
||||||
|
{
|
||||||
|
if(cmd_mgr->print && cmd_mgr->drain){
|
||||||
|
cmd_mgr->print(cmd_mgr);
|
||||||
|
cmd_mgr->drain(cmd_mgr);
|
||||||
|
cmd_mgr->print(cmd_mgr);
|
||||||
|
flush_workqueue(cmd_mgr->cmd_wq);
|
||||||
|
destroy_workqueue(cmd_mgr->cmd_wq);
|
||||||
|
memset(cmd_mgr, 0, sizeof(*cmd_mgr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void aicwf_set_cmd_tx(void *dev, struct lmac_msg *msg, uint len)
|
||||||
|
{
|
||||||
|
u8 *buffer = NULL;
|
||||||
|
u16 index = 0;
|
||||||
|
#ifdef AICWF_SDIO_SUPPORT
|
||||||
|
struct aic_sdio_dev *sdiodev = (struct aic_sdio_dev *)dev;
|
||||||
|
struct aicwf_bus *bus = sdiodev->bus_if;
|
||||||
|
#else
|
||||||
|
struct aic_usb_dev *usbdev = (struct aic_usb_dev *)dev;
|
||||||
|
struct aicwf_bus *bus = NULL;
|
||||||
|
if (!usbdev->state) {
|
||||||
|
printk("down msg \n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bus = usbdev->bus_if;
|
||||||
|
#endif
|
||||||
|
buffer = bus->cmd_buf;
|
||||||
|
|
||||||
|
memset(buffer, 0, CMD_BUF_MAX);
|
||||||
|
buffer[0] = (len+4) & 0x00ff;
|
||||||
|
buffer[1] = ((len+4) >> 8) &0x0f;
|
||||||
|
buffer[2] = 0x11;
|
||||||
|
buffer[3] = 0x0;
|
||||||
|
index += 4;
|
||||||
|
//there is a dummy word
|
||||||
|
index += 4;
|
||||||
|
|
||||||
|
//make sure little endian
|
||||||
|
put_u16(&buffer[index], msg->id);
|
||||||
|
index += 2;
|
||||||
|
put_u16(&buffer[index], msg->dest_id);
|
||||||
|
index += 2;
|
||||||
|
put_u16(&buffer[index], msg->src_id);
|
||||||
|
index += 2;
|
||||||
|
put_u16(&buffer[index], msg->param_len);
|
||||||
|
index += 2;
|
||||||
|
memcpy(&buffer[index], (u8 *)msg->param, msg->param_len);
|
||||||
|
|
||||||
|
aicwf_bus_txmsg(bus, buffer, len + 8);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* rwnx_cmds.h
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2014-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RWNX_CMDS_H_
|
||||||
|
#define _RWNX_CMDS_H_
|
||||||
|
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/completion.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include "lmac_msg.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_SDM
|
||||||
|
#define RWNX_80211_CMD_TIMEOUT_MS (20 * 300)
|
||||||
|
#elif defined(CONFIG_RWNX_FHOST)
|
||||||
|
#define RWNX_80211_CMD_TIMEOUT_MS (10000)
|
||||||
|
#else
|
||||||
|
#define RWNX_80211_CMD_TIMEOUT_MS 4000//500//300
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define RWNX_CMD_FLAG_NONBLOCK BIT(0)
|
||||||
|
#define RWNX_CMD_FLAG_REQ_CFM BIT(1)
|
||||||
|
#define RWNX_CMD_FLAG_WAIT_PUSH BIT(2)
|
||||||
|
#define RWNX_CMD_FLAG_WAIT_ACK BIT(3)
|
||||||
|
#define RWNX_CMD_FLAG_WAIT_CFM BIT(4)
|
||||||
|
#define RWNX_CMD_FLAG_DONE BIT(5)
|
||||||
|
/* ATM IPC design makes it possible to get the CFM before the ACK,
|
||||||
|
* otherwise this could have simply been a state enum */
|
||||||
|
#define RWNX_CMD_WAIT_COMPLETE(flags) \
|
||||||
|
(!(flags & (RWNX_CMD_FLAG_WAIT_ACK | RWNX_CMD_FLAG_WAIT_CFM)))
|
||||||
|
|
||||||
|
#define RWNX_CMD_MAX_QUEUED 16//8 AIDEN
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_FHOST
|
||||||
|
#include "ipc_fhost.h"
|
||||||
|
#define rwnx_cmd_e2amsg ipc_fhost_msg
|
||||||
|
#define rwnx_cmd_a2emsg ipc_fhost_msg
|
||||||
|
#define RWNX_CMD_A2EMSG_LEN(m) (m->param_len)
|
||||||
|
#define RWNX_CMD_E2AMSG_LEN_MAX IPC_FHOST_MSG_BUF_SIZE
|
||||||
|
struct rwnx_term_stream;
|
||||||
|
|
||||||
|
#else /* !CONFIG_RWNX_FHOST*/
|
||||||
|
#include "ipc_shared.h"
|
||||||
|
#define rwnx_cmd_e2amsg ipc_e2a_msg
|
||||||
|
#define rwnx_cmd_a2emsg lmac_msg
|
||||||
|
#define RWNX_CMD_A2EMSG_LEN(m) (sizeof(struct lmac_msg) + m->param_len)
|
||||||
|
#define RWNX_CMD_E2AMSG_LEN_MAX (IPC_E2A_MSG_PARAM_SIZE * 4)
|
||||||
|
|
||||||
|
#endif /* CONFIG_RWNX_FHOST*/
|
||||||
|
|
||||||
|
struct rwnx_hw;
|
||||||
|
struct rwnx_cmd;
|
||||||
|
typedef int (*msg_cb_fct)(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd,
|
||||||
|
struct rwnx_cmd_e2amsg *msg);
|
||||||
|
static inline void put_u16(u8 *buf, u16 data)
|
||||||
|
{
|
||||||
|
buf[0] = (u8)(data&0x00ff);
|
||||||
|
buf[1] = (u8)((data >> 8)&0x00ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum rwnx_cmd_mgr_state {
|
||||||
|
RWNX_CMD_MGR_STATE_DEINIT,
|
||||||
|
RWNX_CMD_MGR_STATE_INITED,
|
||||||
|
RWNX_CMD_MGR_STATE_CRASHED,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rwnx_cmd {
|
||||||
|
struct list_head list;
|
||||||
|
lmac_msg_id_t id;
|
||||||
|
lmac_msg_id_t reqid;
|
||||||
|
struct rwnx_cmd_a2emsg *a2e_msg;
|
||||||
|
char *e2a_msg;
|
||||||
|
u32 tkn;
|
||||||
|
u16 flags;
|
||||||
|
|
||||||
|
struct completion complete;
|
||||||
|
u32 result;
|
||||||
|
u8 used;
|
||||||
|
int array_id;
|
||||||
|
#ifdef CONFIG_RWNX_FHOST
|
||||||
|
struct rwnx_term_stream *stream;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rwnx_cmd_mgr {
|
||||||
|
enum rwnx_cmd_mgr_state state;
|
||||||
|
spinlock_t lock;
|
||||||
|
u32 next_tkn;
|
||||||
|
u32 queue_sz;
|
||||||
|
u32 max_queue_sz;
|
||||||
|
|
||||||
|
struct list_head cmds;
|
||||||
|
|
||||||
|
int (*queue)(struct rwnx_cmd_mgr *, struct rwnx_cmd *);
|
||||||
|
int (*llind)(struct rwnx_cmd_mgr *, struct rwnx_cmd *);
|
||||||
|
int (*msgind)(struct rwnx_cmd_mgr *, struct rwnx_cmd_e2amsg *, msg_cb_fct);
|
||||||
|
void (*print)(struct rwnx_cmd_mgr *);
|
||||||
|
void (*drain)(struct rwnx_cmd_mgr *);
|
||||||
|
|
||||||
|
struct work_struct cmdWork;
|
||||||
|
struct workqueue_struct *cmd_wq;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define WAKE_CMD_WORK(cmd_mgr) \
|
||||||
|
do { \
|
||||||
|
queue_work((cmd_mgr)->cmd_wq, &cmd_mgr->cmdWork); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
void rwnx_cmd_mgr_init(struct rwnx_cmd_mgr *cmd_mgr);
|
||||||
|
void rwnx_cmd_mgr_deinit(struct rwnx_cmd_mgr *cmd_mgr);
|
||||||
|
int cmd_mgr_queue_force_defer(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd);
|
||||||
|
void aicwf_set_cmd_tx(void *dev, struct lmac_msg *msg, uint len);
|
||||||
|
|
||||||
|
#endif /* _RWNX_CMDS_H_ */
|
||||||
@@ -0,0 +1,431 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_compat.h
|
||||||
|
*
|
||||||
|
* Ensure driver compilation for linux 3.16 to 3.19
|
||||||
|
*
|
||||||
|
* To avoid too many #if LINUX_VERSION_CODE if the code, when prototype change
|
||||||
|
* between different kernel version:
|
||||||
|
* - For external function, define a macro whose name is the function name with
|
||||||
|
* _compat suffix and prototype (actually the number of parameter) of the
|
||||||
|
* latest version. Then latest version this macro simply call the function
|
||||||
|
* and for older kernel version it call the function adapting the api.
|
||||||
|
* - For internal function (e.g. cfg80211_ops) do the same but the macro name
|
||||||
|
* doesn't need to have the _compat suffix when the function is not used
|
||||||
|
* directly by the driver
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2018
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
#ifndef _RWNX_COMPAT_H_
|
||||||
|
#define _RWNX_COMPAT_H_
|
||||||
|
#include <linux/version.h>
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
|
||||||
|
#error "Minimum kernel version supported is 3.10"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Generic */
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
|
||||||
|
#define __bf_shf(x) (__builtin_ffsll(x) - 1)
|
||||||
|
#define FIELD_PREP(_mask, _val) \
|
||||||
|
(((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask))
|
||||||
|
#else
|
||||||
|
#include <linux/bitfield.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* CFG80211 */
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 20, 0)
|
||||||
|
#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_MASK
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE > KERNEL_VERSION(5, 15, 60)
|
||||||
|
#define IEEE80211_MAX_AMPDU_BUF IEEE80211_MAX_AMPDU_BUF_HE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
|
||||||
|
#define IEEE80211_RADIOTAP_HE 23
|
||||||
|
#define IEEE80211_RADIOTAP_HE_MU 24
|
||||||
|
|
||||||
|
struct ieee80211_radiotap_he {
|
||||||
|
__le16 data1, data2, data3, data4, data5, data6;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ieee80211_radiotap_he_bits {
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA1_FORMAT_MASK = 3,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA1_FORMAT_SU = 0,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA1_FORMAT_EXT_SU = 1,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA1_FORMAT_MU = 2,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA1_FORMAT_TRIG = 3,
|
||||||
|
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN = 0x0004,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA1_BEAM_CHANGE_KNOWN = 0x0008,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN = 0x0010,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN = 0x0020,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA1_DATA_DCM_KNOWN = 0x0040,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA1_CODING_KNOWN = 0x0080,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN = 0x0100,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA1_STBC_KNOWN = 0x0200,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN = 0x0400,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE2_KNOWN = 0x0800,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE3_KNOWN = 0x1000,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE4_KNOWN = 0x2000,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN = 0x4000,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN = 0x8000,
|
||||||
|
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN = 0x0001,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN = 0x0002,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN = 0x0004,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN = 0x0008,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA2_TXBF_KNOWN = 0x0010,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN = 0x0020,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN = 0x0040,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA2_MIDAMBLE_KNOWN = 0x0080,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET = 0x3f00,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET_KNOWN = 0x4000,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC = 0x8000,
|
||||||
|
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR = 0x003f,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA3_BEAM_CHANGE = 0x0040,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA3_UL_DL = 0x0080,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA3_DATA_MCS = 0x0f00,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA3_DATA_DCM = 0x1000,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA3_CODING = 0x2000,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG = 0x4000,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA3_STBC = 0x8000,
|
||||||
|
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE = 0x000f,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA4_MU_STA_ID = 0x7ff0,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE1 = 0x000f,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE2 = 0x00f0,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE3 = 0x0f00,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE4 = 0xf000,
|
||||||
|
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC = 0x000f,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_20MHZ = 0,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_40MHZ = 1,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_80MHZ = 2,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_160MHZ = 3,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_26T = 4,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_52T = 5,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_106T = 6,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_242T = 7,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_484T = 8,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_996T = 9,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_2x996T = 10,
|
||||||
|
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_GI = 0x0030,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_GI_0_8 = 0,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_GI_1_6 = 1,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_GI_3_2 = 2,
|
||||||
|
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE = 0x00c0,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_UNKNOWN = 0,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_1X = 1,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X = 2,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X = 3,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS = 0x0700,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD = 0x3000,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_TXBF = 0x4000,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG = 0x8000,
|
||||||
|
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA6_NSTS = 0x000f,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA6_DOPPLER = 0x0010,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA6_TXOP = 0x7f00,
|
||||||
|
IEEE80211_RADIOTAP_HE_DATA6_MIDAMBLE_PDCTY = 0x8000,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ieee80211_radiotap_he_mu {
|
||||||
|
__le16 flags1, flags2;
|
||||||
|
u8 ru_ch1[4];
|
||||||
|
u8 ru_ch2[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ieee80211_radiotap_he_mu_bits {
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS = 0x000f,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS_KNOWN = 0x0010,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM = 0x0020,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM_KNOWN = 0x0040,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_CTR_26T_RU_KNOWN = 0x0080,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_RU_KNOWN = 0x0100,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_RU_KNOWN = 0x0200,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU_KNOWN = 0x1000,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU = 0x2000,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_COMP_KNOWN = 0x4000,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN = 0x8000,
|
||||||
|
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW = 0x0003,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_20MHZ = 0x0000,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_40MHZ = 0x0001,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_80MHZ = 0x0002,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_160MHZ = 0x0003,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN = 0x0004,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP = 0x0008,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS = 0x00f0,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW = 0x0300,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN= 0x0400,
|
||||||
|
IEEE80211_RADIOTAP_HE_MU_FLAGS2_CH2_CTR_26T_RU = 0x0800,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)
|
||||||
|
#define rwnx_cfg80211_add_iface(wiphy, name, name_assign_type, type, params) \
|
||||||
|
rwnx_cfg80211_add_iface(wiphy, name, type, u32 *flags, params)
|
||||||
|
#else
|
||||||
|
#define rwnx_cfg80211_add_iface(wiphy, name, name_assign_type, type, params) \
|
||||||
|
rwnx_cfg80211_add_iface(wiphy, name, name_assign_type, type, u32 *flags, params)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define rwnx_cfg80211_change_iface(wiphy, dev, type, params) \
|
||||||
|
rwnx_cfg80211_change_iface(wiphy, dev, type, u32 *flags, params)
|
||||||
|
|
||||||
|
#define CCFS0(vht) vht->center_freq_seg1_idx
|
||||||
|
#define CCFS1(vht) vht->center_freq_seg2_idx
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define CCFS0(vht) vht->center_freq_seg0_idx
|
||||||
|
#define CCFS1(vht) vht->center_freq_seg1_idx
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
|
||||||
|
#define cfg80211_cqm_rssi_notify(dev, event, level, gfp) \
|
||||||
|
cfg80211_cqm_rssi_notify(dev, event, gfp)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
|
||||||
|
#define ieee80211_amsdu_to_8023s(skb, list, addr, iftype, extra_headroom, check_da, check_sa) \
|
||||||
|
ieee80211_amsdu_to_8023s(skb, list, addr, iftype, extra_headroom, false)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)
|
||||||
|
#define NUM_NL80211_BANDS IEEE80211_NUM_BANDS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
|
||||||
|
#define cfg80211_disconnected(dev, reason, ie, len, local, gfp) \
|
||||||
|
cfg80211_disconnected(dev, reason, ie, len, gfp)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)) && !(defined CONFIG_VENDOR_RWNX)
|
||||||
|
#define ieee80211_chandef_to_operating_class(chan_def, op_class) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)
|
||||||
|
#define SURVEY_INFO_TIME SURVEY_INFO_CHANNEL_TIME
|
||||||
|
#define SURVEY_INFO_TIME_BUSY SURVEY_INFO_CHANNEL_TIME_BUSY
|
||||||
|
#define SURVEY_INFO_TIME_EXT_BUSY SURVEY_INFO_CHANNEL_TIME_EXT_BUSY
|
||||||
|
#define SURVEY_INFO_TIME_RX SURVEY_INFO_CHANNEL_TIME_RX
|
||||||
|
#define SURVEY_INFO_TIME_TX SURVEY_INFO_CHANNEL_TIME_TX
|
||||||
|
|
||||||
|
#define SURVEY_TIME(s) s->channel_time
|
||||||
|
#define SURVEY_TIME_BUSY(s) s->channel_time_busy
|
||||||
|
#else
|
||||||
|
#define SURVEY_TIME(s) s->time
|
||||||
|
#define SURVEY_TIME_BUSY(s) s->time_busy
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)
|
||||||
|
#define cfg80211_ch_switch_started_notify(dev, chandef, count)
|
||||||
|
|
||||||
|
#define WLAN_BSS_COEX_INFORMATION_REQUEST BIT(0)
|
||||||
|
#define WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING BIT(2)
|
||||||
|
#define WLAN_EXT_CAPA4_TDLS_BUFFER_STA BIT(4)
|
||||||
|
#define WLAN_EXT_CAPA4_TDLS_PEER_PSM BIT(5)
|
||||||
|
#define WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH BIT(6)
|
||||||
|
#define WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED BIT(7)
|
||||||
|
#define NL80211_FEATURE_TDLS_CHANNEL_SWITCH 0
|
||||||
|
|
||||||
|
#define STA_TDLS_INITIATOR(sta) 0
|
||||||
|
|
||||||
|
#define REGULATORY_IGNORE_STALE_KICKOFF 0
|
||||||
|
#else
|
||||||
|
#define STA_TDLS_INITIATOR(sta) sta->tdls_initiator
|
||||||
|
#ifndef REGULATORY_IGNORE_STALE_KICKOFF
|
||||||
|
#define REGULATORY_IGNORE_STALE_KICKOFF 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
|
||||||
|
#define cfg80211_rx_mgmt(wdev, freq, rssi, buf, len, flags) \
|
||||||
|
cfg80211_rx_mgmt(wdev, freq, rssi, buf, len, flags, GFP_ATOMIC)
|
||||||
|
#elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)
|
||||||
|
#define cfg80211_rx_mgmt(wdev, freq, rssi, buf, len, flags) \
|
||||||
|
cfg80211_rx_mgmt(wdev, freq, rssi, buf, len, GFP_ATOMIC)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
|
||||||
|
#define rwnx_cfg80211_tdls_mgmt(wiphy, dev, peer, act, tok, status, peer_capability, initiator, buf, len) \
|
||||||
|
rwnx_cfg80211_tdls_mgmt(wiphy, dev, peer, act, tok, status, peer_capability, buf, len)
|
||||||
|
#else
|
||||||
|
#define rwnx_cfg80211_tdls_mgmt(wiphy, dev, peer, act, tok, status, peer_capability, initiator, buf, len) \
|
||||||
|
rwnx_cfg80211_tdls_mgmt(wiphy, dev, peer, act, tok, status, buf, len)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
struct ieee80211_wmm_ac_param {
|
||||||
|
u8 aci_aifsn; /* AIFSN, ACM, ACI */
|
||||||
|
u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */
|
||||||
|
__le16 txop_limit;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct ieee80211_wmm_param_ie {
|
||||||
|
u8 element_id; /* Element ID: 221 (0xdd); */
|
||||||
|
u8 len; /* Length: 24 */
|
||||||
|
/* required fields for WMM version 1 */
|
||||||
|
u8 oui[3]; /* 00:50:f2 */
|
||||||
|
u8 oui_type; /* 2 */
|
||||||
|
u8 oui_subtype; /* 1 */
|
||||||
|
u8 version; /* 1 for WMM version 1.0 */
|
||||||
|
u8 qos_info; /* AP/STA specific QoS info */
|
||||||
|
u8 reserved; /* 0 */
|
||||||
|
/* AC_BE, AC_BK, AC_VI, AC_VO */
|
||||||
|
struct ieee80211_wmm_ac_param ac[4];
|
||||||
|
} __packed;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
|
||||||
|
enum {
|
||||||
|
IEEE80211_HE_MCS_SUPPORT_0_7 = 0,
|
||||||
|
IEEE80211_HE_MCS_SUPPORT_0_9 = 1,
|
||||||
|
IEEE80211_HE_MCS_SUPPORT_0_11 = 2,
|
||||||
|
IEEE80211_HE_MCS_NOT_SUPPORTED = 3,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* MAC80211 */
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0)
|
||||||
|
#define rwnx_ops_mgd_prepare_tx(hw, vif, duration) \
|
||||||
|
rwnx_ops_mgd_prepare_tx(hw, vif)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
|
||||||
|
|
||||||
|
#define RX_ENC_HT(s) s->flag |= RX_FLAG_HT
|
||||||
|
#define RX_ENC_HT_GF(s) s->flag |= (RX_FLAG_HT | RX_FLAG_HT_GF)
|
||||||
|
#define RX_ENC_VHT(s) s->flag |= RX_FLAG_HT
|
||||||
|
#define RX_ENC_HE(s) s->flag |= RX_FLAG_HT
|
||||||
|
#define RX_ENC_FLAG_SHORT_GI(s) s->flag |= RX_FLAG_SHORT_GI
|
||||||
|
#define RX_ENC_FLAG_SHORT_PRE(s) s->flag |= RX_FLAG_SHORTPRE
|
||||||
|
#define RX_ENC_FLAG_LDPC(s) s->flag |= RX_FLAG_LDPC
|
||||||
|
#define RX_BW_40MHZ(s) s->flag |= RX_FLAG_40MHZ
|
||||||
|
#define RX_BW_80MHZ(s) s->vht_flag |= RX_VHT_FLAG_80MHZ
|
||||||
|
#define RX_BW_160MHZ(s) s->vht_flag |= RX_VHT_FLAG_160MHZ
|
||||||
|
#define RX_NSS(s) s->vht_nss
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define RX_ENC_HT(s) s->encoding = RX_ENC_HT
|
||||||
|
#define RX_ENC_HT_GF(s) { s->encoding = RX_ENC_HT; \
|
||||||
|
s->enc_flags |= RX_ENC_FLAG_HT_GF; }
|
||||||
|
#define RX_ENC_VHT(s) s->encoding = RX_ENC_VHT
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
|
||||||
|
#define RX_ENC_HE(s) s->encoding = RX_ENC_VHT
|
||||||
|
#else
|
||||||
|
#define RX_ENC_HE(s) s->encoding = RX_ENC_HE
|
||||||
|
#endif
|
||||||
|
#define RX_ENC_FLAG_SHORT_GI(s) s->enc_flags |= RX_ENC_FLAG_SHORT_GI
|
||||||
|
#define RX_ENC_FLAG_SHORT_PRE(s) s->enc_flags |= RX_ENC_FLAG_SHORTPRE
|
||||||
|
#define RX_ENC_FLAG_LDPC(s) s->enc_flags |= RX_ENC_FLAG_LDPC
|
||||||
|
#define RX_BW_40MHZ(s) s->bw = RATE_INFO_BW_40
|
||||||
|
#define RX_BW_80MHZ(s) s->bw = RATE_INFO_BW_80
|
||||||
|
#define RX_BW_160MHZ(s) s->bw = RATE_INFO_BW_160
|
||||||
|
#define RX_NSS(s) s->nss
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
|
||||||
|
#define ieee80211_cqm_rssi_notify(vif, event, level, gfp) \
|
||||||
|
ieee80211_cqm_rssi_notify(vif, event, gfp)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_VENDOR_RWNX_AMSDUS_TX
|
||||||
|
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0))
|
||||||
|
#define rwnx_ops_ampdu_action(hw, vif, params) \
|
||||||
|
rwnx_ops_ampdu_action(hw, vif, enum ieee80211_ampdu_mlme_action action, \
|
||||||
|
struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size)
|
||||||
|
#elif (LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0))
|
||||||
|
#define rwnx_ops_ampdu_action(hw, vif, params) \
|
||||||
|
rwnx_ops_ampdu_action(hw, vif, enum ieee80211_ampdu_mlme_action action, \
|
||||||
|
struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size, \
|
||||||
|
bool amsdu)
|
||||||
|
#endif
|
||||||
|
#endif /* CONFIG_VENDOR_RWNX_AMSDUS_TX */
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
|
||||||
|
#define IEEE80211_HW_SUPPORT_FAST_XMIT 0
|
||||||
|
#define ieee80211_hw_check(hw, feat) (hw->flags & IEEE80211_HW_##feat)
|
||||||
|
#define ieee80211_hw_set(hw, feat) {hw->flags |= IEEE80211_HW_##feat;}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)
|
||||||
|
#define rwnx_ops_sw_scan_start(hw, vif, mac_addr) \
|
||||||
|
rwnx_ops_sw_scan_start(hw)
|
||||||
|
#define rwnx_ops_sw_scan_complete(hw, vif) \
|
||||||
|
rwnx_ops_sw_scan_complete(hw)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
|
||||||
|
#define rwnx_ops_hw_scan(hw, vif, hw_req) \
|
||||||
|
rwnx_ops_hw_scan(hw, vif, struct cfg80211_scan_request *req)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* NET */
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
|
||||||
|
#define rwnx_select_queue(dev, skb, sb_dev) \
|
||||||
|
rwnx_select_queue(dev, skb)
|
||||||
|
#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
|
||||||
|
#define rwnx_select_queue(dev, skb, sb_dev) \
|
||||||
|
rwnx_select_queue(dev, skb, void *accel_priv, select_queue_fallback_t fallback)
|
||||||
|
#elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0)
|
||||||
|
#define rwnx_select_queue(dev, skb, sb_dev) \
|
||||||
|
rwnx_select_queue(dev, skb, sb_dev, select_queue_fallback_t fallback)
|
||||||
|
#else
|
||||||
|
#define rwnx_select_queue(dev, skb, sb_dev) \
|
||||||
|
rwnx_select_queue(dev, skb, sb_dev)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0)) && !(defined CONFIG_VENDOR_RWNX)
|
||||||
|
#define sk_pacing_shift_update(sk, shift)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
|
||||||
|
#define alloc_netdev_mqs(size, name, assign, setup, txqs, rxqs) \
|
||||||
|
alloc_netdev_mqs(size, name, setup, txqs, rxqs)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
|
||||||
|
#define NET_NAME_UNKNOWN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* TRACE */
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
|
||||||
|
#define trace_print_symbols_seq ftrace_print_symbols_seq
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
|
||||||
|
#define trace_seq_buffer_ptr(p) p->buffer + p->len
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* TIME */
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
|
||||||
|
#define time64_to_tm(t, o, tm) time_to_tm((time_t)t, o, tm)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)
|
||||||
|
#define ktime_get_real_seconds get_seconds
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
|
||||||
|
typedef __s64 time64_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _RWNX_COMPAT_H_ */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,203 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_debugfs.h
|
||||||
|
*
|
||||||
|
* @brief Miscellaneous utility function definitions
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _RWNX_DEBUGFS_H_
|
||||||
|
#define _RWNX_DEBUGFS_H_
|
||||||
|
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
#include <linux/if_ether.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include "rwnx_fw_trace.h"
|
||||||
|
|
||||||
|
struct rwnx_hw;
|
||||||
|
struct rwnx_sta;
|
||||||
|
|
||||||
|
/* some macros taken from iwlwifi */
|
||||||
|
/* TODO: replace with generic read and fill read buffer in open to avoid double
|
||||||
|
* reads */
|
||||||
|
#define DEBUGFS_ADD_FILE(name, parent, mode) do { \
|
||||||
|
if (!debugfs_create_file(#name, mode, parent, rwnx_hw, \
|
||||||
|
&rwnx_dbgfs_##name##_ops)) \
|
||||||
|
goto err; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \
|
||||||
|
struct dentry *__tmp; \
|
||||||
|
__tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \
|
||||||
|
parent, ptr); \
|
||||||
|
if (IS_ERR(__tmp) || !__tmp) \
|
||||||
|
goto err; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define DEBUGFS_ADD_X64(name, parent, ptr) do { \
|
||||||
|
struct dentry *__tmp; \
|
||||||
|
__tmp = debugfs_create_x64(#name, S_IWUSR | S_IRUSR, \
|
||||||
|
parent, ptr); \
|
||||||
|
if (IS_ERR(__tmp) || !__tmp) \
|
||||||
|
goto err; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define DEBUGFS_ADD_U64(name, parent, ptr, mode) do { \
|
||||||
|
struct dentry *__tmp; \
|
||||||
|
__tmp = debugfs_create_u64(#name, mode, \
|
||||||
|
parent, ptr); \
|
||||||
|
if (IS_ERR(__tmp) || !__tmp) \
|
||||||
|
goto err; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define DEBUGFS_ADD_X32(name, parent, ptr) do { \
|
||||||
|
struct dentry *__tmp; \
|
||||||
|
__tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR, \
|
||||||
|
parent, ptr); \
|
||||||
|
if (IS_ERR(__tmp) || !__tmp) \
|
||||||
|
goto err; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)
|
||||||
|
#define DEBUGFS_ADD_U32(name, parent, ptr, mode) do { \
|
||||||
|
debugfs_create_u32(#name, mode, \
|
||||||
|
parent, ptr); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define DEBUGFS_ADD_U32(name, parent, ptr, mode) do { \
|
||||||
|
struct dentry *__tmp; \
|
||||||
|
__tmp = debugfs_create_u32(#name, mode, \
|
||||||
|
parent, ptr); \
|
||||||
|
if (IS_ERR(__tmp) || !__tmp) \
|
||||||
|
goto err; \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* file operation */
|
||||||
|
#define DEBUGFS_READ_FUNC(name) \
|
||||||
|
static ssize_t rwnx_dbgfs_##name##_read(struct file *file, \
|
||||||
|
char __user *user_buf, \
|
||||||
|
size_t count, loff_t *ppos);
|
||||||
|
|
||||||
|
#define DEBUGFS_WRITE_FUNC(name) \
|
||||||
|
static ssize_t rwnx_dbgfs_##name##_write(struct file *file, \
|
||||||
|
const char __user *user_buf,\
|
||||||
|
size_t count, loff_t *ppos);
|
||||||
|
|
||||||
|
#define DEBUGFS_OPEN_FUNC(name) \
|
||||||
|
static int rwnx_dbgfs_##name##_open(struct inode *inode, \
|
||||||
|
struct file *file);
|
||||||
|
|
||||||
|
#define DEBUGFS_RELEASE_FUNC(name) \
|
||||||
|
static int rwnx_dbgfs_##name##_release(struct inode *inode, \
|
||||||
|
struct file *file);
|
||||||
|
|
||||||
|
#define DEBUGFS_READ_FILE_OPS(name) \
|
||||||
|
DEBUGFS_READ_FUNC(name); \
|
||||||
|
static const struct file_operations rwnx_dbgfs_##name##_ops = { \
|
||||||
|
.read = rwnx_dbgfs_##name##_read, \
|
||||||
|
.open = simple_open, \
|
||||||
|
.llseek = generic_file_llseek, \
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DEBUGFS_WRITE_FILE_OPS(name) \
|
||||||
|
DEBUGFS_WRITE_FUNC(name); \
|
||||||
|
static const struct file_operations rwnx_dbgfs_##name##_ops = { \
|
||||||
|
.write = rwnx_dbgfs_##name##_write, \
|
||||||
|
.open = simple_open, \
|
||||||
|
.llseek = generic_file_llseek, \
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DEBUGFS_READ_WRITE_FILE_OPS(name) \
|
||||||
|
DEBUGFS_READ_FUNC(name); \
|
||||||
|
DEBUGFS_WRITE_FUNC(name); \
|
||||||
|
static const struct file_operations rwnx_dbgfs_##name##_ops = { \
|
||||||
|
.write = rwnx_dbgfs_##name##_write, \
|
||||||
|
.read = rwnx_dbgfs_##name##_read, \
|
||||||
|
.open = simple_open, \
|
||||||
|
.llseek = generic_file_llseek, \
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DEBUGFS_READ_WRITE_OPEN_RELEASE_FILE_OPS(name) \
|
||||||
|
DEBUGFS_READ_FUNC(name); \
|
||||||
|
DEBUGFS_WRITE_FUNC(name); \
|
||||||
|
DEBUGFS_OPEN_FUNC(name); \
|
||||||
|
DEBUGFS_RELEASE_FUNC(name); \
|
||||||
|
static const struct file_operations rwnx_dbgfs_##name##_ops = { \
|
||||||
|
.write = rwnx_dbgfs_##name##_write, \
|
||||||
|
.read = rwnx_dbgfs_##name##_read, \
|
||||||
|
.open = rwnx_dbgfs_##name##_open, \
|
||||||
|
.release = rwnx_dbgfs_##name##_release, \
|
||||||
|
.llseek = generic_file_llseek, \
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_DEBUGFS
|
||||||
|
|
||||||
|
struct rwnx_debugfs {
|
||||||
|
unsigned long long rateidx;
|
||||||
|
struct dentry *dir;
|
||||||
|
bool trace_prst;
|
||||||
|
|
||||||
|
char helper_cmd[64];
|
||||||
|
//struct work_struct helper_work;
|
||||||
|
bool helper_scheduled;
|
||||||
|
spinlock_t umh_lock;
|
||||||
|
bool unregistering;
|
||||||
|
|
||||||
|
#ifndef CONFIG_RWNX_FHOST
|
||||||
|
struct rwnx_fw_log fw_log;
|
||||||
|
#endif /* CONFIG_RWNX_FHOST */
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
struct work_struct rc_stat_work;
|
||||||
|
uint8_t rc_sta[NX_REMOTE_STA_MAX];
|
||||||
|
uint8_t rc_write;
|
||||||
|
uint8_t rc_read;
|
||||||
|
struct dentry *dir_rc;
|
||||||
|
struct dentry *dir_sta[NX_REMOTE_STA_MAX];
|
||||||
|
int rc_config[NX_REMOTE_STA_MAX];
|
||||||
|
struct list_head rc_config_save;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
|
||||||
|
// Max duration in msecs to save rate config for a sta after disconnection
|
||||||
|
#define RC_CONFIG_DUR 600000
|
||||||
|
|
||||||
|
struct rwnx_rc_config_save {
|
||||||
|
struct list_head list;
|
||||||
|
unsigned long timestamp;
|
||||||
|
int rate;
|
||||||
|
u8 mac_addr[ETH_ALEN];
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int rwnx_dbgfs_register(struct rwnx_hw *rwnx_hw, const char *name);
|
||||||
|
void rwnx_dbgfs_unregister(struct rwnx_hw *rwnx_hw);
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
void rwnx_dbgfs_register_rc_stat(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta);
|
||||||
|
void rwnx_dbgfs_unregister_rc_stat(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
|
||||||
|
struct rwnx_debugfs {
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline int rwnx_dbgfs_register(struct rwnx_hw *rwnx_hw, const char *name) { return 0; }
|
||||||
|
static inline void rwnx_dbgfs_unregister(struct rwnx_hw *rwnx_hw) {}
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
static inline void rwnx_dbgfs_register_rc_stat(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta) {}
|
||||||
|
static inline void rwnx_dbgfs_unregister_rc_stat(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta) {}
|
||||||
|
#endif
|
||||||
|
#endif /* CONFIG_RWNX_DEBUGFS */
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _RWNX_DEBUGFS_H_ */
|
||||||
@@ -0,0 +1,803 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_defs.h
|
||||||
|
*
|
||||||
|
* @brief Main driver structure declarations for fullmac driver
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RWNX_DEFS_H_
|
||||||
|
#define _RWNX_DEFS_H_
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/dmapool.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <net/cfg80211.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
#include "rwnx_mod_params.h"
|
||||||
|
#include "rwnx_debugfs.h"
|
||||||
|
#include "rwnx_tx.h"
|
||||||
|
#include "rwnx_rx.h"
|
||||||
|
#include "rwnx_radar.h"
|
||||||
|
#include "rwnx_utils.h"
|
||||||
|
#include "rwnx_mu_group.h"
|
||||||
|
#include "rwnx_platform.h"
|
||||||
|
#include "rwnx_cmds.h"
|
||||||
|
#include "rwnx_compat.h"
|
||||||
|
#ifdef CONFIG_FILTER_TCP_ACK
|
||||||
|
#include "aicwf_tcp_ack.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef AICWF_SDIO_SUPPORT
|
||||||
|
#include "aicwf_sdio.h"
|
||||||
|
#include "sdio_host.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef AICWF_USB_SUPPORT
|
||||||
|
#include "usb_host.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_BR_SUPPORT
|
||||||
|
#include "aic_br_ext.h"
|
||||||
|
#endif /* CONFIG_BR_SUPPORT */
|
||||||
|
|
||||||
|
#define WPI_HDR_LEN 18
|
||||||
|
#define WPI_PN_LEN 16
|
||||||
|
#define WPI_PN_OFST 2
|
||||||
|
#define WPI_MIC_LEN 16
|
||||||
|
#define WPI_KEY_LEN 32
|
||||||
|
#define WPI_SUBKEY_LEN 16 // WPI key is actually two 16bytes key
|
||||||
|
|
||||||
|
#define LEGACY_PS_ID 0
|
||||||
|
#define UAPSD_ID 1
|
||||||
|
|
||||||
|
#define PS_SP_INTERRUPTED 255
|
||||||
|
#define MAC_ADDR_LEN 6
|
||||||
|
|
||||||
|
//because android kernel 5.15 uses kernel 6.0 or 6.1 kernel api
|
||||||
|
#ifdef ANDROID_PLATFORM
|
||||||
|
#define HIGH_KERNEL_VERSION KERNEL_VERSION(5, 15, 41)
|
||||||
|
#define HIGH_KERNEL_VERSION2 KERNEL_VERSION(5, 15, 41)
|
||||||
|
#define HIGH_KERNEL_VERSION3 KERNEL_VERSION(5, 15, 104)
|
||||||
|
#define HIGH_KERNEL_VERSION4 KERNEL_VERSION(6, 1, 0)
|
||||||
|
#else
|
||||||
|
#define HIGH_KERNEL_VERSION KERNEL_VERSION(6, 0, 0)
|
||||||
|
#define HIGH_KERNEL_VERSION2 KERNEL_VERSION(6, 1, 0)
|
||||||
|
#define HIGH_KERNEL_VERSION3 KERNEL_VERSION(6, 3, 0)
|
||||||
|
#define HIGH_KERNEL_VERSION4 KERNEL_VERSION(6, 3, 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef IEEE80211_MAX_AMPDU_BUF
|
||||||
|
#define IEEE80211_MAX_AMPDU_BUF 0x100
|
||||||
|
#endif
|
||||||
|
#ifndef IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB
|
||||||
|
#define IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB 0x08
|
||||||
|
#endif
|
||||||
|
#ifndef IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB
|
||||||
|
#define IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB 0x04
|
||||||
|
#endif
|
||||||
|
#ifndef IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA
|
||||||
|
#define IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA 0x40
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= HIGH_KERNEL_VERSION
|
||||||
|
#define IEEE80211_MAX_AMPDU_BUF IEEE80211_MAX_AMPDU_BUF_HE
|
||||||
|
#define IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB
|
||||||
|
#define IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB
|
||||||
|
#define IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) || defined(CONFIG_VHT_FOR_OLD_KERNEL)
|
||||||
|
enum nl80211_ac {
|
||||||
|
NL80211_AC_VO,
|
||||||
|
NL80211_AC_VI,
|
||||||
|
NL80211_AC_BE,
|
||||||
|
NL80211_AC_BK,
|
||||||
|
NL80211_NUM_ACS
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) || defined(CONFIG_VHT_FOR_OLD_KERNEL)
|
||||||
|
struct ieee80211_vht_operation {
|
||||||
|
u8 vht_op_info_chwidth;
|
||||||
|
u8 vht_op_info_chan_center_freq_seg1_idx;
|
||||||
|
u8 vht_op_info_chan_center_freq_seg2_idx;
|
||||||
|
__le16 vht_basic_mcs_set;
|
||||||
|
} __packed;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
|
||||||
|
#define NL80211_IFTYPE_P2P_DEVICE 10
|
||||||
|
#define IEEE80211_RADIOTAP_AMPDU_STATUS 20
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) || defined(CONFIG_VHT_FOR_OLD_KERNEL)
|
||||||
|
#define IEEE80211_RADIOTAP_VHT 21
|
||||||
|
#define IEEE80211_RADIOTAP_VHT_KNOWN_GI 0x0004
|
||||||
|
#define IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH 0x0040
|
||||||
|
|
||||||
|
#define IEEE80211_RADIOTAP_VHT_FLAG_STBC 0x01
|
||||||
|
#define IEEE80211_RADIOTAP_VHT_FLAG_SGI 0x04
|
||||||
|
|
||||||
|
#define NL80211_FEATURE_CELL_BASE_REG_HINTS 1 << 3
|
||||||
|
#define NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL 1 << 4
|
||||||
|
#define NL80211_FEATURE_SAE 1 << 5
|
||||||
|
#define NL80211_FEATURE_LOW_PRIORITY_SCAN 1 << 6
|
||||||
|
#define NL80211_FEATURE_SCAN_FLUSH 1 << 7
|
||||||
|
#define NL80211_FEATURE_AP_SCAN 1 << 8
|
||||||
|
#define NL80211_FEATURE_VIF_TXPOWER 1 << 9
|
||||||
|
#define NL80211_FEATURE_NEED_OBSS_SCAN 1 << 10
|
||||||
|
#define NL80211_FEATURE_P2P_GO_CTWIN 1 << 11
|
||||||
|
#define NL80211_FEATURE_P2P_GO_OPPPS 1 << 12
|
||||||
|
|
||||||
|
/* 802.11ac VHT Capabilities */
|
||||||
|
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000
|
||||||
|
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 0x00000001
|
||||||
|
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 0x00000002
|
||||||
|
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004
|
||||||
|
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008
|
||||||
|
#define IEEE80211_VHT_CAP_RXLDPC 0x00000010
|
||||||
|
#define IEEE80211_VHT_CAP_SHORT_GI_80 0x00000020
|
||||||
|
#define IEEE80211_VHT_CAP_SHORT_GI_160 0x00000040
|
||||||
|
#define IEEE80211_VHT_CAP_TXSTBC 0x00000080
|
||||||
|
#define IEEE80211_VHT_CAP_RXSTBC_1 0x00000100
|
||||||
|
#define IEEE80211_VHT_CAP_RXSTBC_2 0x00000200
|
||||||
|
#define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300
|
||||||
|
#define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400
|
||||||
|
#define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800
|
||||||
|
#define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000
|
||||||
|
#define IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX 0x00006000
|
||||||
|
#define IEEE80211_VHT_CAP_SOUNDING_DIMENTION_MAX 0x00030000
|
||||||
|
#define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE 0x00080000
|
||||||
|
#define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE 0x00100000
|
||||||
|
#define IEEE80211_VHT_CAP_VHT_TXOP_PS 0x00200000
|
||||||
|
#define IEEE80211_VHT_CAP_HTC_VHT 0x00400000
|
||||||
|
#define IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT 23
|
||||||
|
#define IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK \
|
||||||
|
(7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT)
|
||||||
|
#define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB 0x08000000
|
||||||
|
#define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB 0x0c000000
|
||||||
|
#define IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN 0x10000000
|
||||||
|
#define IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN 0x20000000
|
||||||
|
|
||||||
|
enum ieee80211_vht_mcs_support {
|
||||||
|
IEEE80211_VHT_MCS_SUPPORT_0_7 = 0,
|
||||||
|
IEEE80211_VHT_MCS_SUPPORT_0_8 = 1,
|
||||||
|
IEEE80211_VHT_MCS_SUPPORT_0_9 = 2,
|
||||||
|
IEEE80211_VHT_MCS_NOT_SUPPORTED = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum nl80211_chan_width {
|
||||||
|
NL80211_CHAN_WIDTH_20_NOHT,
|
||||||
|
NL80211_CHAN_WIDTH_20,
|
||||||
|
NL80211_CHAN_WIDTH_40,
|
||||||
|
NL80211_CHAN_WIDTH_80,
|
||||||
|
NL80211_CHAN_WIDTH_80P80,
|
||||||
|
NL80211_CHAN_WIDTH_160,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cfg80211_chan_def {
|
||||||
|
struct ieee80211_channel *chan;
|
||||||
|
enum nl80211_chan_width width;
|
||||||
|
u32 center_freq1;
|
||||||
|
u32 center_freq2;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum nl80211_mesh_power_mode {
|
||||||
|
NL80211_MESH_POWER_UNKNOWN,
|
||||||
|
NL80211_MESH_POWER_ACTIVE,
|
||||||
|
NL80211_MESH_POWER_LIGHT_SLEEP,
|
||||||
|
NL80211_MESH_POWER_DEEP_SLEEP,
|
||||||
|
__NL80211_MESH_POWER_AFTER_LAST,
|
||||||
|
NL80211_MESH_POWER_MAX = __NL80211_MESH_POWER_AFTER_LAST - 1
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
|
||||||
|
#define NL80211_MESHCONF_POWER_MODE 26
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TDLS capabililites to be enabled in the 5th byte of the
|
||||||
|
* @WLAN_EID_EXT_CAPABILITY information element
|
||||||
|
*/
|
||||||
|
#define WLAN_EXT_CAPA5_TDLS_ENABLED BIT(5)
|
||||||
|
#define WLAN_EXT_CAPA5_TDLS_PROHIBITED BIT(6)
|
||||||
|
|
||||||
|
#define WLAN_EXT_CAPA8_OPMODE_NOTIF BIT(6)
|
||||||
|
|
||||||
|
/* TDLS specific payload type in the LLC/SNAP header */
|
||||||
|
#define WLAN_TDLS_SNAP_RFTYPE 0x2
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_bcn - Information of the beacon in used (AP mode)
|
||||||
|
*
|
||||||
|
* @head: head portion of beacon (before TIM IE)
|
||||||
|
* @tail: tail portion of beacon (after TIM IE)
|
||||||
|
* @ies: extra IEs (not used ?)
|
||||||
|
* @head_len: length of head data
|
||||||
|
* @tail_len: length of tail data
|
||||||
|
* @ies_len: length of extra IEs data
|
||||||
|
* @tim_len: length of TIM IE
|
||||||
|
* @len: Total beacon len (head + tim + tail + extra)
|
||||||
|
* @dtim: dtim period
|
||||||
|
*/
|
||||||
|
struct rwnx_bcn {
|
||||||
|
u8 *head;
|
||||||
|
u8 *tail;
|
||||||
|
u8 *ies;
|
||||||
|
size_t head_len;
|
||||||
|
size_t tail_len;
|
||||||
|
size_t ies_len;
|
||||||
|
size_t tim_len;
|
||||||
|
size_t len;
|
||||||
|
u8 dtim;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_key - Key information
|
||||||
|
*
|
||||||
|
* @hw_idx: Idx of the key from hardware point of view
|
||||||
|
*/
|
||||||
|
struct rwnx_key {
|
||||||
|
u8 hw_idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure containing information about a Mesh Path
|
||||||
|
*/
|
||||||
|
struct rwnx_mesh_path {
|
||||||
|
struct list_head list; /* For rwnx_vif.mesh_paths */
|
||||||
|
u8 path_idx; /* Path Index */
|
||||||
|
struct mac_addr tgt_mac_addr; /* Target MAC Address */
|
||||||
|
struct rwnx_sta *p_nhop_sta; /* Pointer to the Next Hop STA */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rwnx_mesh_proxy {
|
||||||
|
struct list_head list; /* For rwnx_vif.mesh_proxy */
|
||||||
|
struct mac_addr ext_sta_addr; /* Address of the External STA */
|
||||||
|
struct mac_addr proxy_addr; /* Proxy MAC Address */
|
||||||
|
bool local; /* Indicate if interface is a proxy for the device */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_csa - Information for CSA (Channel Switch Announcement)
|
||||||
|
*
|
||||||
|
* @vif: Pointer to the vif doing the CSA
|
||||||
|
* @bcn: Beacon to use after CSA
|
||||||
|
* @elem: IPC buffer to send the new beacon to the fw
|
||||||
|
* @chandef: defines the channel to use after the switch
|
||||||
|
* @count: Current csa counter
|
||||||
|
* @status: Status of the CSA at fw level
|
||||||
|
* @ch_idx: Index of the new channel context
|
||||||
|
* @work: work scheduled at the end of CSA
|
||||||
|
*/
|
||||||
|
struct rwnx_csa {
|
||||||
|
struct rwnx_vif *vif;
|
||||||
|
struct rwnx_bcn bcn;
|
||||||
|
struct rwnx_ipc_elem_var elem;
|
||||||
|
struct cfg80211_chan_def chandef;
|
||||||
|
int count;
|
||||||
|
int status;
|
||||||
|
int ch_idx;
|
||||||
|
struct work_struct work;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct apm_probe_sta {
|
||||||
|
u8 sta_mac_addr[6];
|
||||||
|
u8 vif_idx;
|
||||||
|
u64 probe_id;
|
||||||
|
struct work_struct apmprobestaWork;
|
||||||
|
struct workqueue_struct *apmprobesta_wq;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Possible States of the TDLS link.
|
||||||
|
enum tdls_status_tag {
|
||||||
|
/// TDLS link is not active (no TDLS peer connected)
|
||||||
|
TDLS_LINK_IDLE,
|
||||||
|
/// TDLS Setup Request transmitted
|
||||||
|
TDLS_SETUP_REQ_TX,
|
||||||
|
/// TDLS Setup Response transmitted
|
||||||
|
TDLS_SETUP_RSP_TX,
|
||||||
|
/// TDLS link is active (TDLS peer connected)
|
||||||
|
TDLS_LINK_ACTIVE,
|
||||||
|
/// TDLS Max Number of states.
|
||||||
|
TDLS_STATE_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure used to save information relative to the TDLS peer.
|
||||||
|
* This is also linked within the rwnx_hw vifs list.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct rwnx_tdls {
|
||||||
|
bool active; /* Indicate if TDLS link is active */
|
||||||
|
bool initiator; /* Indicate if TDLS peer is the TDLS initiator */
|
||||||
|
bool chsw_en; /* Indicate if channel switch is enabled */
|
||||||
|
u8 last_tid; /* TID of the latest MPDU transmitted over the
|
||||||
|
TDLS direct link to the TDLS STA */
|
||||||
|
u16 last_sn; /* Sequence number of the latest MPDU transmitted
|
||||||
|
over the TDLS direct link to the TDLS STA */
|
||||||
|
bool ps_on; /* Indicate if the power save is enabled on the
|
||||||
|
TDLS STA */
|
||||||
|
bool chsw_allowed; /* Indicate if TDLS channel switch is allowed */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum rwnx_ap_flags - AP flags
|
||||||
|
*
|
||||||
|
* @RWNX_AP_ISOLATE Isolate clients (i.e. Don't brige packets transmitted by
|
||||||
|
* one client for another one)
|
||||||
|
*/
|
||||||
|
enum rwnx_ap_flags {
|
||||||
|
RWNX_AP_ISOLATE = BIT(0),
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure used to save information relative to the managed interfaces.
|
||||||
|
* This is also linked within the rwnx_hw vifs list.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct rwnx_vif {
|
||||||
|
struct list_head list;
|
||||||
|
struct rwnx_hw *rwnx_hw;
|
||||||
|
struct wireless_dev wdev;
|
||||||
|
struct net_device *ndev;
|
||||||
|
struct net_device_stats net_stats;
|
||||||
|
struct rwnx_key key[6];
|
||||||
|
unsigned long drv_flags;
|
||||||
|
atomic_t drv_conn_state;
|
||||||
|
u8 is_conn;
|
||||||
|
u8 drv_vif_index; /* Identifier of the VIF in driver */
|
||||||
|
u8 vif_index; /* Identifier of the station in FW */
|
||||||
|
u8 ch_index; /* Channel context identifier */
|
||||||
|
bool up; /* Indicate if associated netdev is up
|
||||||
|
(i.e. Interface is created at fw level) */
|
||||||
|
bool use_4addr; /* Should we use 4addresses mode */
|
||||||
|
bool is_resending; /* Indicate if a frame is being resent on this interface */
|
||||||
|
bool user_mpm; /* In case of Mesh Point VIF, indicate if MPM is handled by userspace */
|
||||||
|
bool roc_tdls; /* Indicate if the ROC has been called by a
|
||||||
|
TDLS station */
|
||||||
|
u8 tdls_status; /* Status of the TDLS link */
|
||||||
|
bool tdls_chsw_prohibited; /* Indicate if TDLS Channel Switch is prohibited */
|
||||||
|
bool wep_enabled; /* 1 if WEP is enabled */
|
||||||
|
bool wep_auth_err; /* 1 if auth status code is not supported auth alg when WEP enabled */
|
||||||
|
enum nl80211_auth_type last_auth_type; /* Authentication type (algorithm) sent in the last connection
|
||||||
|
when WEP enabled */
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
struct rwnx_sta *ap; /* Pointer to the peer STA entry allocated for
|
||||||
|
the AP */
|
||||||
|
struct rwnx_sta *tdls_sta; /* Pointer to the TDLS station */
|
||||||
|
bool external_auth; /* Indicate if external authentication is in progress */
|
||||||
|
u32 group_cipher_type;
|
||||||
|
u32 paired_cipher_type;
|
||||||
|
//connected network info start
|
||||||
|
char ssid[33];//ssid max is 32, but this has one spare for '\0'
|
||||||
|
int ssid_len;
|
||||||
|
u8 bssid[ETH_ALEN];
|
||||||
|
u32 conn_owner_nlportid;
|
||||||
|
bool is_roam;
|
||||||
|
//connected network info end
|
||||||
|
} sta;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u16 flags; /* see rwnx_ap_flags */
|
||||||
|
struct list_head sta_list; /* List of STA connected to the AP */
|
||||||
|
struct rwnx_bcn bcn; /* beacon */
|
||||||
|
u8 bcmc_index; /* Index of the BCMC sta to use */
|
||||||
|
#if (defined CONFIG_HE_FOR_OLD_KERNEL) || (defined CONFIG_VHT_FOR_OLD_KERNEL)
|
||||||
|
u8 aic_index;
|
||||||
|
#endif
|
||||||
|
struct rwnx_csa *csa;
|
||||||
|
|
||||||
|
struct list_head mpath_list; /* List of Mesh Paths used on this interface */
|
||||||
|
struct list_head proxy_list; /* List of Proxies Information used on this interface */
|
||||||
|
bool create_path; /* Indicate if we are waiting for a MESH_CREATE_PATH_CFM
|
||||||
|
message */
|
||||||
|
int generation; /* Increased each time the list of Mesh Paths is updated */
|
||||||
|
enum nl80211_mesh_power_mode mesh_pm; /* mesh power save mode currently set in firmware */
|
||||||
|
enum nl80211_mesh_power_mode next_mesh_pm; /* mesh power save mode for next peer */
|
||||||
|
} ap;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
struct rwnx_vif *master; /* pointer on master interface */
|
||||||
|
struct rwnx_sta *sta_4a;
|
||||||
|
} ap_vlan;
|
||||||
|
};
|
||||||
|
|
||||||
|
u8_l key_has_add;
|
||||||
|
u8_l is_p2p_vif;
|
||||||
|
struct apm_probe_sta sta_probe;
|
||||||
|
|
||||||
|
#ifdef CONFIG_BR_SUPPORT
|
||||||
|
spinlock_t br_ext_lock;
|
||||||
|
/* unsigned int macclone_completed; */
|
||||||
|
struct nat25_network_db_entry *nethash[NAT25_HASH_SIZE];
|
||||||
|
int pppoe_connection_in_progress;
|
||||||
|
unsigned char pppoe_addr[MACADDRLEN];
|
||||||
|
unsigned char scdb_mac[MACADDRLEN];
|
||||||
|
unsigned char scdb_ip[4];
|
||||||
|
struct nat25_network_db_entry *scdb_entry;
|
||||||
|
unsigned char br_mac[MACADDRLEN];
|
||||||
|
unsigned char br_ip[4];
|
||||||
|
|
||||||
|
struct br_ext_info ethBrExtInfo;
|
||||||
|
#endif /* CONFIG_BR_SUPPORT */
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RWNX_VIF_TYPE(rwnx_vif) (rwnx_vif->wdev.iftype)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure used to store information relative to PS mode.
|
||||||
|
*
|
||||||
|
* @active: True when the sta is in PS mode.
|
||||||
|
* If false, other values should be ignored
|
||||||
|
* @pkt_ready: Number of packets buffered for the sta in drv's txq
|
||||||
|
* (1 counter for Legacy PS and 1 for U-APSD)
|
||||||
|
* @sp_cnt: Number of packets that remain to be pushed in the service period.
|
||||||
|
* 0 means that no service period is in progress
|
||||||
|
* (1 counter for Legacy PS and 1 for U-APSD)
|
||||||
|
*/
|
||||||
|
struct rwnx_sta_ps {
|
||||||
|
bool active;
|
||||||
|
u16 pkt_ready[2];
|
||||||
|
u16 sp_cnt[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_rx_rate_stats - Store statistics for RX rates
|
||||||
|
*
|
||||||
|
* @table: Table indicating how many frame has been receive which each
|
||||||
|
* rate index. Rate index is the same as the one used by RC algo for TX
|
||||||
|
* @size: Size of the table array
|
||||||
|
* @cpt: number of frames received
|
||||||
|
*/
|
||||||
|
struct rwnx_rx_rate_stats {
|
||||||
|
int *table;
|
||||||
|
int size;
|
||||||
|
int cpt;
|
||||||
|
int rate_cnt;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_sta_stats - Structure Used to store statistics specific to a STA
|
||||||
|
*
|
||||||
|
* @last_rx: Hardware vector of the last received frame
|
||||||
|
* @rx_rate: Statistics of the received rates
|
||||||
|
*/
|
||||||
|
struct rwnx_sta_stats {
|
||||||
|
//#ifdef CONFIG_RWNX_DEBUGFS
|
||||||
|
struct hw_vect last_rx;
|
||||||
|
struct rwnx_rx_rate_stats rx_rate;
|
||||||
|
//#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#if (defined CONFIG_HE_FOR_OLD_KERNEL) || (defined CONFIG_VHT_FOR_OLD_KERNEL)
|
||||||
|
struct aic_sta {
|
||||||
|
u8 sta_idx; /* Identifier of the station */
|
||||||
|
bool he; /* Flag indicating if the station supports HE */
|
||||||
|
bool vht; /* Flag indicating if the station supports VHT */
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure used to save information relative to the managed stations.
|
||||||
|
*/
|
||||||
|
struct rwnx_sta {
|
||||||
|
struct list_head list;
|
||||||
|
u16 aid; /* association ID */
|
||||||
|
u8 sta_idx; /* Identifier of the station */
|
||||||
|
u8 vif_idx; /* Identifier of the VIF (fw id) the station
|
||||||
|
belongs to */
|
||||||
|
u8 vlan_idx; /* Identifier of the VLAN VIF (fw id) the station
|
||||||
|
belongs to (= vif_idx if no vlan in used) */
|
||||||
|
enum nl80211_band band; /* Band */
|
||||||
|
enum nl80211_chan_width width; /* Channel width */
|
||||||
|
u16 center_freq; /* Center frequency */
|
||||||
|
u32 center_freq1; /* Center frequency 1 */
|
||||||
|
u32 center_freq2; /* Center frequency 2 */
|
||||||
|
u8 ch_idx; /* Identifier of the channel
|
||||||
|
context the station belongs to */
|
||||||
|
bool qos; /* Flag indicating if the station
|
||||||
|
supports QoS */
|
||||||
|
u8 acm; /* Bitfield indicating which queues
|
||||||
|
have AC mandatory */
|
||||||
|
u16 uapsd_tids; /* Bitfield indicating which tids are subject to
|
||||||
|
UAPSD */
|
||||||
|
u8 mac_addr[ETH_ALEN]; /* MAC address of the station */
|
||||||
|
struct rwnx_key key;
|
||||||
|
bool valid; /* Flag indicating if the entry is valid */
|
||||||
|
struct rwnx_sta_ps ps; /* Information when STA is in PS (AP only) */
|
||||||
|
#ifdef CONFIG_RWNX_BFMER
|
||||||
|
struct rwnx_bfmer_report *bfm_report; /* Beamforming report to be used for
|
||||||
|
VHT TX Beamforming */
|
||||||
|
#ifdef CONFIG_RWNX_MUMIMO_TX
|
||||||
|
struct rwnx_sta_group_info group_info; /* MU grouping information for the STA */
|
||||||
|
#endif /* CONFIG_RWNX_MUMIMO_TX */
|
||||||
|
#endif /* CONFIG_RWNX_BFMER */
|
||||||
|
|
||||||
|
bool ht; /* Flag indicating if the station
|
||||||
|
supports HT */
|
||||||
|
bool vht; /* Flag indicating if the station
|
||||||
|
supports VHT */
|
||||||
|
u32 ac_param[AC_MAX]; /* EDCA parameters */
|
||||||
|
struct rwnx_tdls tdls; /* TDLS station information */
|
||||||
|
struct rwnx_sta_stats stats;
|
||||||
|
enum nl80211_mesh_power_mode mesh_pm; /* link-specific mesh power save mode */
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline const u8 *rwnx_sta_addr(struct rwnx_sta *rwnx_sta) {
|
||||||
|
return rwnx_sta->mac_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_SPLIT_TX_BUF
|
||||||
|
struct rwnx_amsdu_stats {
|
||||||
|
int done;
|
||||||
|
int failed;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct rwnx_stats {
|
||||||
|
int cfm_balance[NX_TXQ_CNT];
|
||||||
|
unsigned long last_rx, last_tx; /* jiffies */
|
||||||
|
int ampdus_tx[IEEE80211_MAX_AMPDU_BUF];
|
||||||
|
int ampdus_rx[IEEE80211_MAX_AMPDU_BUF];
|
||||||
|
int ampdus_rx_map[4];
|
||||||
|
int ampdus_rx_miss;
|
||||||
|
#ifdef CONFIG_RWNX_SPLIT_TX_BUF
|
||||||
|
struct rwnx_amsdu_stats amsdus[NX_TX_PAYLOAD_MAX];
|
||||||
|
#endif
|
||||||
|
int amsdus_rx[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rwnx_sec_phy_chan {
|
||||||
|
u16 prim20_freq;
|
||||||
|
u16 center_freq1;
|
||||||
|
u16 center_freq2;
|
||||||
|
enum nl80211_band band;
|
||||||
|
u8 type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Structure that will contains all RoC information received from cfg80211 */
|
||||||
|
struct rwnx_roc_elem {
|
||||||
|
struct wireless_dev *wdev;
|
||||||
|
struct ieee80211_channel *chan;
|
||||||
|
unsigned int duration;
|
||||||
|
/* Used to avoid call of CFG80211 callback upon expiration of RoC */
|
||||||
|
bool mgmt_roc;
|
||||||
|
/* Indicate if we have switch on the RoC channel */
|
||||||
|
bool on_chan;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Structure containing channel survey information received from MAC */
|
||||||
|
struct rwnx_survey_info {
|
||||||
|
// Filled
|
||||||
|
u32 filled;
|
||||||
|
// Amount of time in ms the radio spent on the channel
|
||||||
|
u32 chan_time_ms;
|
||||||
|
// Amount of time the primary channel was sensed busy
|
||||||
|
u32 chan_time_busy_ms;
|
||||||
|
// Noise in dbm
|
||||||
|
s8 noise_dbm;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RWNX_CH_NOT_SET 0xFF
|
||||||
|
#define RWNX_INVALID_VIF 0xFF
|
||||||
|
#define RWNX_INVALID_STA 0xFF
|
||||||
|
|
||||||
|
/* Structure containing channel context information */
|
||||||
|
struct rwnx_chanctx {
|
||||||
|
struct cfg80211_chan_def chan_def; /* channel description */
|
||||||
|
u8 count; /* number of vif using this ctxt */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_phy_info - Phy information
|
||||||
|
*
|
||||||
|
* @phy_cnt: Number of phy interface
|
||||||
|
* @cfg: Configuration send to firmware
|
||||||
|
* @sec_chan: Channel configuration of the second phy interface (if phy_cnt > 1)
|
||||||
|
* @limit_bw: Set to true to limit BW on requested channel. Only set to use
|
||||||
|
* VHT with old radio that don't support 80MHz (deprecated)
|
||||||
|
*/
|
||||||
|
struct rwnx_phy_info {
|
||||||
|
u8 cnt;
|
||||||
|
struct phy_cfg_tag cfg;
|
||||||
|
struct rwnx_sec_phy_chan sec_chan;
|
||||||
|
bool limit_bw;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* rwnx driver status */
|
||||||
|
|
||||||
|
enum rwnx_drv_connect_status {
|
||||||
|
RWNX_DRV_STATUS_DISCONNECTED = 0,
|
||||||
|
RWNX_DRV_STATUS_DISCONNECTING,
|
||||||
|
RWNX_DRV_STATUS_CONNECTING,
|
||||||
|
RWNX_DRV_STATUS_CONNECTED,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct sta_tx_flowctrl {
|
||||||
|
atomic_t tx_pending_cnt;
|
||||||
|
u8 flowctrl;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rwnx_hw {
|
||||||
|
struct rwnx_mod_params *mod_params;
|
||||||
|
struct device *dev;
|
||||||
|
#ifdef AICWF_SDIO_SUPPORT
|
||||||
|
struct aic_sdio_dev *sdiodev;
|
||||||
|
#endif
|
||||||
|
#ifdef AICWF_USB_SUPPORT
|
||||||
|
struct aic_usb_dev *usbdev;
|
||||||
|
#endif
|
||||||
|
struct wiphy *wiphy;
|
||||||
|
struct list_head vifs;
|
||||||
|
struct rwnx_vif *vif_table[NX_VIRT_DEV_MAX + NX_REMOTE_STA_MAX]; /* indexed with fw id */
|
||||||
|
struct rwnx_sta sta_table[NX_REMOTE_STA_MAX + NX_VIRT_DEV_MAX];
|
||||||
|
#ifdef CONFIG_HE_FOR_OLD_KERNEL
|
||||||
|
struct aic_sta aic_table[NX_REMOTE_STA_MAX + NX_VIRT_DEV_MAX];
|
||||||
|
#endif
|
||||||
|
struct rwnx_survey_info survey[SCAN_CHANNEL_MAX];
|
||||||
|
struct cfg80211_scan_request *scan_request;
|
||||||
|
#ifdef CONFIG_SCHED_SCAN
|
||||||
|
struct cfg80211_sched_scan_request *sched_scan_req;
|
||||||
|
#endif
|
||||||
|
struct rwnx_chanctx chanctx_table[NX_CHAN_CTXT_CNT];
|
||||||
|
u8 cur_chanctx;
|
||||||
|
|
||||||
|
u8 monitor_vif; /* FW id of the monitor interface, RWNX_INVALID_VIF if no monitor vif at fw level */
|
||||||
|
#ifdef CONFIG_FILTER_TCP_ACK
|
||||||
|
/* tcp ack management */
|
||||||
|
struct tcp_ack_manage ack_m;
|
||||||
|
#endif
|
||||||
|
/* RoC Management */
|
||||||
|
struct rwnx_roc_elem *roc_elem; /* Information provided by cfg80211 in its remain on channel request */
|
||||||
|
u32 roc_cookie_cnt; /* Counter used to identify RoC request sent by cfg80211 */
|
||||||
|
|
||||||
|
struct rwnx_cmd_mgr *cmd_mgr;
|
||||||
|
|
||||||
|
struct rwnx_plat *plat;
|
||||||
|
|
||||||
|
spinlock_t tx_lock;
|
||||||
|
spinlock_t cb_lock;
|
||||||
|
struct mutex mutex; /* per-device perimeter lock */
|
||||||
|
|
||||||
|
struct tasklet_struct task;
|
||||||
|
struct mm_version_cfm version_cfm; /* Lower layers versions - obtained via MM_VERSION_REQ */
|
||||||
|
|
||||||
|
u32 tcp_pacing_shift;
|
||||||
|
|
||||||
|
/* IPC */
|
||||||
|
struct ipc_host_env_tag *ipc_env;
|
||||||
|
#ifdef AICWF_SDIO_SUPPORT
|
||||||
|
struct sdio_host_env_tag sdio_env;
|
||||||
|
#endif
|
||||||
|
#ifdef AICWF_USB_SUPPORT
|
||||||
|
struct usb_host_env_tag usb_env;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct rwnx_ipc_elem_pool e2amsgs_pool;
|
||||||
|
struct rwnx_ipc_elem_pool dbgmsgs_pool;
|
||||||
|
struct rwnx_ipc_elem_pool e2aradars_pool;
|
||||||
|
struct rwnx_ipc_elem_var pattern_elem;
|
||||||
|
struct rwnx_ipc_dbgdump_elem dbgdump_elem;
|
||||||
|
struct rwnx_ipc_elem_pool e2arxdesc_pool;
|
||||||
|
struct rwnx_ipc_skb_elem *e2aunsuprxvec_elems;
|
||||||
|
//struct rwnx_ipc_rxbuf_elems rxbuf_elems;
|
||||||
|
struct rwnx_ipc_elem_var scan_ie;
|
||||||
|
|
||||||
|
struct kmem_cache *sw_txhdr_cache;
|
||||||
|
|
||||||
|
struct rwnx_debugfs debugfs;
|
||||||
|
struct rwnx_stats stats;
|
||||||
|
|
||||||
|
#ifdef CONFIG_PREALLOC_TXQ
|
||||||
|
struct rwnx_txq *txq;
|
||||||
|
#else
|
||||||
|
struct rwnx_txq txq[NX_NB_TXQ];
|
||||||
|
#endif
|
||||||
|
struct rwnx_hwq hwq[NX_TXQ_CNT];
|
||||||
|
|
||||||
|
u64 avail_idx_map;
|
||||||
|
u8 vif_started;
|
||||||
|
bool adding_sta;
|
||||||
|
struct rwnx_phy_info phy;
|
||||||
|
|
||||||
|
struct rwnx_radar radar;
|
||||||
|
|
||||||
|
/* extended capabilities supported */
|
||||||
|
u8 ext_capa[8];
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_MUMIMO_TX
|
||||||
|
struct rwnx_mu_info mu;
|
||||||
|
#endif
|
||||||
|
u8 is_p2p_alive;
|
||||||
|
u8 is_p2p_connected;
|
||||||
|
struct timer_list p2p_alive_timer;
|
||||||
|
struct rwnx_vif *p2p_dev_vif;
|
||||||
|
atomic_t p2p_alive_timer_count;
|
||||||
|
bool band_5g_support;
|
||||||
|
bool fwlog_en;
|
||||||
|
bool scanning;
|
||||||
|
bool p2p_working;
|
||||||
|
|
||||||
|
struct work_struct apmStalossWork;
|
||||||
|
struct workqueue_struct *apmStaloss_wq;
|
||||||
|
u8 apm_vif_idx;
|
||||||
|
u8 sta_mac_addr[6];
|
||||||
|
#ifdef CONFIG_SCHED_SCAN
|
||||||
|
bool is_sched_scan;
|
||||||
|
#endif//CONFIG_SCHED_SCAN
|
||||||
|
|
||||||
|
struct sta_tx_flowctrl sta_flowctrl[NX_REMOTE_STA_MAX];
|
||||||
|
#if 0
|
||||||
|
bool he_flag;
|
||||||
|
#endif
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
|
||||||
|
struct mac_chan_op ap_chan;
|
||||||
|
struct ieee80211_channel set_chan;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_VHT_FOR_OLD_KERNEL
|
||||||
|
struct ieee80211_sta_vht_cap vht_cap_2G;
|
||||||
|
struct ieee80211_sta_vht_cap vht_cap_5G;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_USE_WIRELESS_EXT
|
||||||
|
bool wext_scan;
|
||||||
|
struct completion wext_scan_com;
|
||||||
|
struct list_head wext_scanre_list;
|
||||||
|
char wext_essid[32];
|
||||||
|
int support_freqs[SCAN_CHANNEL_MAX];
|
||||||
|
int support_freqs_number;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
u8 *rwnx_build_bcn(struct rwnx_bcn *bcn, struct cfg80211_beacon_data *new);
|
||||||
|
|
||||||
|
void rwnx_chanctx_link(struct rwnx_vif *vif, u8 idx,
|
||||||
|
struct cfg80211_chan_def *chandef);
|
||||||
|
void rwnx_chanctx_unlink(struct rwnx_vif *vif);
|
||||||
|
int rwnx_chanctx_valid(struct rwnx_hw *rwnx_hw, u8 idx);
|
||||||
|
|
||||||
|
extern u8 chip_id;
|
||||||
|
static inline bool is_multicast_sta(int sta_idx)
|
||||||
|
{
|
||||||
|
|
||||||
|
if((g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8801) ||
|
||||||
|
((g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800DC ||
|
||||||
|
g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800DW) && chip_id < 3)){
|
||||||
|
return (sta_idx >= NX_REMOTE_STA_MAX_FOR_OLD_IC);
|
||||||
|
}else{
|
||||||
|
return (sta_idx >= NX_REMOTE_STA_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
struct rwnx_sta *rwnx_get_sta(struct rwnx_hw *rwnx_hw, const u8 *mac_addr);
|
||||||
|
|
||||||
|
static inline uint8_t master_vif_idx(struct rwnx_vif *vif)
|
||||||
|
{
|
||||||
|
if (unlikely(vif->wdev.iftype == NL80211_IFTYPE_AP_VLAN)) {
|
||||||
|
return vif->ap_vlan.master->vif_index;
|
||||||
|
} else {
|
||||||
|
return vif->vif_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rwnx_external_auth_enable(struct rwnx_vif *vif);
|
||||||
|
void rwnx_external_auth_disable(struct rwnx_vif *vif);
|
||||||
|
|
||||||
|
#endif /* _RWNX_DEFS_H_ */
|
||||||
@@ -0,0 +1,294 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_dini.c - Add support for dini platform
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rwnx_dini.h"
|
||||||
|
#include "rwnx_defs.h"
|
||||||
|
#include "rwnx_irqs.h"
|
||||||
|
#include "reg_access.h"
|
||||||
|
|
||||||
|
/* Config FPGA is accessed via bar0 */
|
||||||
|
#define CFPGA_DMA0_CTRL_REG 0x02C
|
||||||
|
#define CFPGA_DMA1_CTRL_REG 0x04C
|
||||||
|
#define CFPGA_DMA2_CTRL_REG 0x06C
|
||||||
|
#define CFPGA_UINTR_SRC_REG 0x0E8
|
||||||
|
#define CFPGA_UINTR_MASK_REG 0x0EC
|
||||||
|
#define CFPGA_BAR4_HIADDR_REG 0x100
|
||||||
|
#define CFPGA_BAR4_LOADDR_REG 0x104
|
||||||
|
#define CFPGA_BAR4_LOADDR_MASK_REG 0x110
|
||||||
|
#define CFPGA_BAR_TOUT 0x120
|
||||||
|
|
||||||
|
#define CFPGA_DMA_CTRL_ENABLE 0x00001400
|
||||||
|
#define CFPGA_DMA_CTRL_DISABLE 0x00001000
|
||||||
|
#define CFPGA_DMA_CTRL_CLEAR 0x00001800
|
||||||
|
#define CFPGA_DMA_CTRL_REREAD_TIME_MASK (BIT(10) - 1)
|
||||||
|
|
||||||
|
#define CFPGA_BAR4_LOADDR_MASK_MAX 0xFF000000
|
||||||
|
|
||||||
|
#define CFPGA_PCIEX_IT 0x00000001
|
||||||
|
#define CFPGA_ALL_ITS 0x0000000F
|
||||||
|
|
||||||
|
/* Programmable BAR4 Window start address */
|
||||||
|
#define CPU_RAM_WINDOW_HIGH 0x00000000
|
||||||
|
#define CPU_RAM_WINDOW_LOW 0x00000000
|
||||||
|
#define AHB_BRIDGE_WINDOW_HIGH 0x00000000
|
||||||
|
#define AHB_BRIDGE_WINDOW_LOW 0x60000000
|
||||||
|
|
||||||
|
struct rwnx_dini
|
||||||
|
{
|
||||||
|
u8 *pci_bar0_vaddr;
|
||||||
|
u8 *pci_bar4_vaddr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u32 mv_cfg_fpga_dma_ctrl_regs[] = {
|
||||||
|
CFPGA_DMA0_CTRL_REG,
|
||||||
|
CFPGA_DMA1_CTRL_REG,
|
||||||
|
CFPGA_DMA2_CTRL_REG
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This also clears running transactions */
|
||||||
|
static void dini_dma_on(struct rwnx_dini *rwnx_dini)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
u32 reread_time;
|
||||||
|
volatile void *reg;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(mv_cfg_fpga_dma_ctrl_regs); i++) {
|
||||||
|
reg = rwnx_dini->pci_bar0_vaddr + mv_cfg_fpga_dma_ctrl_regs[i];
|
||||||
|
reread_time = readl(reg) & CFPGA_DMA_CTRL_REREAD_TIME_MASK;
|
||||||
|
|
||||||
|
writel(CFPGA_DMA_CTRL_CLEAR | reread_time, reg);
|
||||||
|
writel(CFPGA_DMA_CTRL_ENABLE | reread_time, reg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This also clears running transactions */
|
||||||
|
static void dini_dma_off(struct rwnx_dini *rwnx_dini)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
u32 reread_time;
|
||||||
|
volatile void *reg;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(mv_cfg_fpga_dma_ctrl_regs); i++) {
|
||||||
|
reg = rwnx_dini->pci_bar0_vaddr + mv_cfg_fpga_dma_ctrl_regs[i];
|
||||||
|
reread_time = readl(reg) & CFPGA_DMA_CTRL_REREAD_TIME_MASK;
|
||||||
|
|
||||||
|
writel(CFPGA_DMA_CTRL_DISABLE | reread_time, reg);
|
||||||
|
writel(CFPGA_DMA_CTRL_CLEAR | reread_time, reg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Configure address range for BAR4.
|
||||||
|
* By default BAR4_LOADDR_MASK value is 0xFF000000, then there is no need to
|
||||||
|
* change it because the addresses we need to access are covered by this mask
|
||||||
|
*/
|
||||||
|
static void dini_set_bar4_win(u32 low, u32 high, struct rwnx_dini *rwnx_dini)
|
||||||
|
{
|
||||||
|
writel(low, rwnx_dini->pci_bar0_vaddr + CFPGA_BAR4_LOADDR_REG);
|
||||||
|
writel(high, rwnx_dini->pci_bar0_vaddr + CFPGA_BAR4_HIADDR_REG);
|
||||||
|
writel(CFPGA_BAR4_LOADDR_MASK_MAX,
|
||||||
|
rwnx_dini->pci_bar0_vaddr + CFPGA_BAR4_LOADDR_MASK_REG);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable User Interrupts of CFPGA that trigger PCIe IRQs on PCIE_10
|
||||||
|
* and request the corresponding IRQ line
|
||||||
|
*/
|
||||||
|
int rwnx_cfpga_irq_enable(struct rwnx_hw *rwnx_hw)
|
||||||
|
{
|
||||||
|
struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
|
||||||
|
struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
|
||||||
|
unsigned int cfpga_uintr_mask;
|
||||||
|
volatile void *reg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* sched_setscheduler on ONESHOT threaded irq handler for BCNs ? */
|
||||||
|
if ((ret = request_irq(rwnx_hw->plat->pci_dev->irq, rwnx_irq_hdlr, 0,
|
||||||
|
"rwnx", rwnx_hw)))
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
reg = rwnx_dini->pci_bar0_vaddr + CFPGA_UINTR_MASK_REG;
|
||||||
|
cfpga_uintr_mask = readl(reg);
|
||||||
|
writel(cfpga_uintr_mask | CFPGA_PCIEX_IT, reg);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable User Interrupts of CFPGA that trigger PCIe IRQs on PCIE_10
|
||||||
|
* and free the corresponding IRQ line
|
||||||
|
*/
|
||||||
|
int rwnx_cfpga_irq_disable(struct rwnx_hw *rwnx_hw)
|
||||||
|
{
|
||||||
|
struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
|
||||||
|
struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
|
||||||
|
unsigned int cfpga_uintr_mask;
|
||||||
|
volatile void *reg;
|
||||||
|
|
||||||
|
reg = rwnx_dini->pci_bar0_vaddr + CFPGA_UINTR_MASK_REG;
|
||||||
|
cfpga_uintr_mask = readl(reg);
|
||||||
|
writel(cfpga_uintr_mask & ~CFPGA_PCIEX_IT, reg);
|
||||||
|
|
||||||
|
free_irq(rwnx_hw->plat->pci_dev->irq, rwnx_hw);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rwnx_dini_platform_enable(struct rwnx_hw *rwnx_hw)
|
||||||
|
{
|
||||||
|
struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
|
||||||
|
struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_SDM
|
||||||
|
writel(0x0000FFFF, rwnx_dini->pci_bar0_vaddr + CFPGA_BAR_TOUT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
dini_dma_on(rwnx_dini);
|
||||||
|
return rwnx_cfpga_irq_enable(rwnx_hw);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rwnx_dini_platform_disable(struct rwnx_hw *rwnx_hw)
|
||||||
|
{
|
||||||
|
struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
|
||||||
|
struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = rwnx_cfpga_irq_disable(rwnx_hw);
|
||||||
|
dini_dma_off(rwnx_dini);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rwnx_dini_platform_deinit(struct rwnx_plat *rwnx_plat)
|
||||||
|
{
|
||||||
|
struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
|
||||||
|
|
||||||
|
pci_disable_device(rwnx_plat->pci_dev);
|
||||||
|
iounmap(rwnx_dini->pci_bar0_vaddr);
|
||||||
|
iounmap(rwnx_dini->pci_bar4_vaddr);
|
||||||
|
pci_release_regions(rwnx_plat->pci_dev);
|
||||||
|
|
||||||
|
kfree(rwnx_plat);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8* rwnx_dini_get_address(struct rwnx_plat *rwnx_plat, int addr_name,
|
||||||
|
unsigned int offset)
|
||||||
|
{
|
||||||
|
struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
|
||||||
|
|
||||||
|
if (WARN(addr_name >= RWNX_ADDR_MAX, "Invalid address %d", addr_name))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (addr_name == RWNX_ADDR_CPU)
|
||||||
|
dini_set_bar4_win(CPU_RAM_WINDOW_LOW, CPU_RAM_WINDOW_HIGH, rwnx_dini);
|
||||||
|
else
|
||||||
|
dini_set_bar4_win(AHB_BRIDGE_WINDOW_LOW, AHB_BRIDGE_WINDOW_HIGH, rwnx_dini);
|
||||||
|
|
||||||
|
return rwnx_dini->pci_bar4_vaddr + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rwnx_dini_ack_irq(struct rwnx_plat *rwnx_plat)
|
||||||
|
{
|
||||||
|
struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
|
||||||
|
|
||||||
|
writel(CFPGA_ALL_ITS, rwnx_dini->pci_bar0_vaddr + CFPGA_UINTR_SRC_REG);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const u32 rwnx_dini_config_reg[] = {
|
||||||
|
NXMAC_DEBUG_PORT_SEL_ADDR,
|
||||||
|
SYSCTRL_DIAG_CONF_ADDR,
|
||||||
|
RF_V6_DIAGPORT_CONF1_ADDR,
|
||||||
|
RF_v6_PHYDIAG_CONF1_ADDR,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int rwnx_dini_get_config_reg(struct rwnx_plat *rwnx_plat, const u32 **list)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*list = rwnx_dini_config_reg;
|
||||||
|
return ARRAY_SIZE(rwnx_dini_config_reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_dini_platform_init - Initialize the DINI platform
|
||||||
|
*
|
||||||
|
* @pci_dev PCI device
|
||||||
|
* @rwnx_plat Pointer on struct rwnx_stat * to be populated
|
||||||
|
*
|
||||||
|
* @return 0 on success, < 0 otherwise
|
||||||
|
*
|
||||||
|
* Allocate and initialize a rwnx_plat structure for the dini platform.
|
||||||
|
*/
|
||||||
|
int rwnx_dini_platform_init(struct pci_dev *pci_dev, struct rwnx_plat **rwnx_plat)
|
||||||
|
{
|
||||||
|
struct rwnx_dini *rwnx_dini;
|
||||||
|
u16 pci_cmd;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
*rwnx_plat = kzalloc(sizeof(struct rwnx_plat) + sizeof(struct rwnx_dini),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!*rwnx_plat)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
rwnx_dini = (struct rwnx_dini *)(*rwnx_plat)->priv;
|
||||||
|
|
||||||
|
/* Hotplug fixups */
|
||||||
|
pci_read_config_word(pci_dev, PCI_COMMAND, &pci_cmd);
|
||||||
|
pci_cmd |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
|
||||||
|
pci_write_config_word(pci_dev, PCI_COMMAND, pci_cmd);
|
||||||
|
pci_write_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES >> 2);
|
||||||
|
|
||||||
|
if ((ret = pci_enable_device(pci_dev))) {
|
||||||
|
dev_err(&(pci_dev->dev), "pci_enable_device failed\n");
|
||||||
|
goto out_enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_set_master(pci_dev);
|
||||||
|
|
||||||
|
if ((ret = pci_request_regions(pci_dev, KBUILD_MODNAME))) {
|
||||||
|
dev_err(&(pci_dev->dev), "pci_request_regions failed\n");
|
||||||
|
goto out_request;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(rwnx_dini->pci_bar0_vaddr = (u8 *)pci_ioremap_bar(pci_dev, 0))) {
|
||||||
|
dev_err(&(pci_dev->dev), "pci_ioremap_bar(%d) failed\n", 0);
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out_bar0;
|
||||||
|
}
|
||||||
|
if (!(rwnx_dini->pci_bar4_vaddr = (u8 *)pci_ioremap_bar(pci_dev, 4))) {
|
||||||
|
dev_err(&(pci_dev->dev), "pci_ioremap_bar(%d) failed\n", 4);
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out_bar4;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*rwnx_plat)->enable = rwnx_dini_platform_enable;
|
||||||
|
(*rwnx_plat)->disable = rwnx_dini_platform_disable;
|
||||||
|
(*rwnx_plat)->deinit = rwnx_dini_platform_deinit;
|
||||||
|
(*rwnx_plat)->get_address = rwnx_dini_get_address;
|
||||||
|
(*rwnx_plat)->ack_irq = rwnx_dini_ack_irq;
|
||||||
|
(*rwnx_plat)->get_config_reg = rwnx_dini_get_config_reg;
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_SDM
|
||||||
|
writel(0x0000FFFF, rwnx_dini->pci_bar0_vaddr + CFPGA_BAR_TOUT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_bar4:
|
||||||
|
iounmap(rwnx_dini->pci_bar0_vaddr);
|
||||||
|
out_bar0:
|
||||||
|
pci_release_regions(pci_dev);
|
||||||
|
out_request:
|
||||||
|
pci_disable_device(pci_dev);
|
||||||
|
out_enable:
|
||||||
|
kfree(*rwnx_plat);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_dini.h
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RWNX_DINI_H_
|
||||||
|
#define _RWNX_DINI_H_
|
||||||
|
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include "rwnx_platform.h"
|
||||||
|
|
||||||
|
int rwnx_dini_platform_init(struct pci_dev *pci_dev,
|
||||||
|
struct rwnx_plat **rwnx_plat);
|
||||||
|
|
||||||
|
#endif /* _RWNX_DINI_H_ */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,568 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_fw_dump.c
|
||||||
|
*
|
||||||
|
* @brief Definition of debug fs entries to process fw dump
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <linux/kmod.h>
|
||||||
|
#include <linux/debugfs.h>
|
||||||
|
|
||||||
|
#include "rwnx_defs.h"
|
||||||
|
#include "rwnx_debugfs.h"
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_rhd_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *priv = file->private_data;
|
||||||
|
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
|
||||||
|
ssize_t read;
|
||||||
|
|
||||||
|
mutex_lock(&priv->dbgdump_elem.mutex);
|
||||||
|
if (!priv->debugfs.trace_prst) {
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
read = simple_read_from_buffer(user_buf, count, ppos,
|
||||||
|
dump->rhd_mem,
|
||||||
|
dump->dbg_info.rhd_len);
|
||||||
|
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGFS_READ_FILE_OPS(rhd);
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_rbd_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *priv = file->private_data;
|
||||||
|
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
|
||||||
|
ssize_t read;
|
||||||
|
|
||||||
|
mutex_lock(&priv->dbgdump_elem.mutex);
|
||||||
|
if (!priv->debugfs.trace_prst) {
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
read = simple_read_from_buffer(user_buf, count, ppos,
|
||||||
|
dump->rbd_mem,
|
||||||
|
dump->dbg_info.rbd_len);
|
||||||
|
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGFS_READ_FILE_OPS(rbd);
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_thdx_read(struct file *file, char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos, int idx)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *priv = file->private_data;
|
||||||
|
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
|
||||||
|
ssize_t read;
|
||||||
|
|
||||||
|
mutex_lock(&priv->dbgdump_elem.mutex);
|
||||||
|
if (!priv->debugfs.trace_prst) {
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
read = simple_read_from_buffer(user_buf, count, ppos,
|
||||||
|
&dump->thd_mem[idx],
|
||||||
|
dump->dbg_info.thd_len[idx]);
|
||||||
|
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_thd0_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
return rwnx_dbgfs_thdx_read(file, user_buf, count, ppos, 0);
|
||||||
|
}
|
||||||
|
DEBUGFS_READ_FILE_OPS(thd0);
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_thd1_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
return rwnx_dbgfs_thdx_read(file, user_buf, count, ppos, 1);
|
||||||
|
}
|
||||||
|
DEBUGFS_READ_FILE_OPS(thd1);
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_thd2_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
return rwnx_dbgfs_thdx_read(file, user_buf, count, ppos, 2);
|
||||||
|
}
|
||||||
|
DEBUGFS_READ_FILE_OPS(thd2);
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_thd3_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
return rwnx_dbgfs_thdx_read(file, user_buf, count, ppos, 3);
|
||||||
|
}
|
||||||
|
DEBUGFS_READ_FILE_OPS(thd3);
|
||||||
|
|
||||||
|
#if (NX_TXQ_CNT == 5)
|
||||||
|
static ssize_t rwnx_dbgfs_thd4_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
return rwnx_dbgfs_thdx_read(file, user_buf, count, ppos, 4);
|
||||||
|
}
|
||||||
|
DEBUGFS_READ_FILE_OPS(thd4);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_mactrace_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *priv = file->private_data;
|
||||||
|
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
|
||||||
|
ssize_t read;
|
||||||
|
|
||||||
|
mutex_lock(&priv->dbgdump_elem.mutex);
|
||||||
|
if (!priv->debugfs.trace_prst) {
|
||||||
|
char msg[64];
|
||||||
|
|
||||||
|
scnprintf(msg, sizeof(msg), "Force trigger\n");
|
||||||
|
rwnx_dbgfs_trigger_fw_dump(priv, msg);
|
||||||
|
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
read = simple_read_from_buffer(user_buf, count, ppos,
|
||||||
|
dump->la_mem,
|
||||||
|
dump->dbg_info.la_conf.trace_len);
|
||||||
|
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
DEBUGFS_READ_FILE_OPS(mactrace);
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_macdiags_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *priv = file->private_data;
|
||||||
|
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
|
||||||
|
ssize_t read;
|
||||||
|
|
||||||
|
mutex_lock(&priv->dbgdump_elem.mutex);
|
||||||
|
if (!priv->debugfs.trace_prst) {
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
read = simple_read_from_buffer(user_buf, count, ppos,
|
||||||
|
dump->dbg_info.diags_mac,
|
||||||
|
DBG_DIAGS_MAC_MAX * 2);
|
||||||
|
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGFS_READ_FILE_OPS(macdiags);
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_phydiags_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *priv = file->private_data;
|
||||||
|
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
|
||||||
|
ssize_t read;
|
||||||
|
|
||||||
|
mutex_lock(&priv->dbgdump_elem.mutex);
|
||||||
|
if (!priv->debugfs.trace_prst) {
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
read = simple_read_from_buffer(user_buf, count, ppos,
|
||||||
|
dump->dbg_info.diags_phy,
|
||||||
|
DBG_DIAGS_PHY_MAX * 2);
|
||||||
|
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGFS_READ_FILE_OPS(phydiags);
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_hwdiags_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *priv = file->private_data;
|
||||||
|
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
|
||||||
|
char buf[16];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&priv->dbgdump_elem.mutex);
|
||||||
|
if (!priv->debugfs.trace_prst) {
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
|
||||||
|
"%08X\n", dump->dbg_info.hw_diag);
|
||||||
|
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return simple_read_from_buffer(user_buf, count, ppos, buf, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGFS_READ_FILE_OPS(hwdiags);
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_plfdiags_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *priv = file->private_data;
|
||||||
|
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
|
||||||
|
char buf[16];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&priv->dbgdump_elem.mutex);
|
||||||
|
if (!priv->debugfs.trace_prst) {
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
|
||||||
|
"%08X\n", dump->dbg_info.la_conf.diag_conf);
|
||||||
|
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return simple_read_from_buffer(user_buf, count, ppos, buf, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGFS_READ_FILE_OPS(plfdiags);
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_swdiags_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *priv = file->private_data;
|
||||||
|
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
|
||||||
|
ssize_t read;
|
||||||
|
|
||||||
|
mutex_lock(&priv->dbgdump_elem.mutex);
|
||||||
|
if (!priv->debugfs.trace_prst) {
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
read = simple_read_from_buffer(user_buf, count, ppos,
|
||||||
|
&dump->dbg_info.sw_diag,
|
||||||
|
dump->dbg_info.sw_diag_len);
|
||||||
|
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGFS_READ_FILE_OPS(swdiags);
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_error_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *priv = file->private_data;
|
||||||
|
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
|
||||||
|
ssize_t read;
|
||||||
|
|
||||||
|
mutex_lock(&priv->dbgdump_elem.mutex);
|
||||||
|
if (!priv->debugfs.trace_prst) {
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
read = simple_read_from_buffer(user_buf, count, ppos,
|
||||||
|
dump->dbg_info.error,
|
||||||
|
strlen((char *)dump->dbg_info.error));
|
||||||
|
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGFS_READ_FILE_OPS(error);
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_rxdesc_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *priv = file->private_data;
|
||||||
|
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
|
||||||
|
char buf[32];
|
||||||
|
int ret;
|
||||||
|
ssize_t read;
|
||||||
|
|
||||||
|
mutex_lock(&priv->dbgdump_elem.mutex);
|
||||||
|
if (!priv->debugfs.trace_prst) {
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
|
||||||
|
"%08X\n%08X\n", dump->dbg_info.rhd,
|
||||||
|
dump->dbg_info.rbd);
|
||||||
|
read = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
|
||||||
|
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGFS_READ_FILE_OPS(rxdesc);
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_txdesc_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *priv = file->private_data;
|
||||||
|
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
|
||||||
|
char buf[64];
|
||||||
|
int len = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
mutex_lock(&priv->dbgdump_elem.mutex);
|
||||||
|
if (!priv->debugfs.trace_prst) {
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < NX_TXQ_CNT; i++) {
|
||||||
|
len += scnprintf(&buf[len], min_t(size_t, sizeof(buf) - len - 1, count),
|
||||||
|
"%08X\n", dump->dbg_info.thd[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGFS_READ_FILE_OPS(txdesc);
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_macrxptr_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *priv = file->private_data;
|
||||||
|
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
|
||||||
|
ssize_t read;
|
||||||
|
|
||||||
|
mutex_lock(&priv->dbgdump_elem.mutex);
|
||||||
|
if (!priv->debugfs.trace_prst) {
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
read = simple_read_from_buffer(user_buf, count, ppos,
|
||||||
|
&dump->dbg_info.rhd_hw_ptr,
|
||||||
|
2 * sizeof(dump->dbg_info.rhd_hw_ptr));
|
||||||
|
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGFS_READ_FILE_OPS(macrxptr);
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_lamacconf_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *priv = file->private_data;
|
||||||
|
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
|
||||||
|
ssize_t read;
|
||||||
|
|
||||||
|
mutex_lock(&priv->dbgdump_elem.mutex);
|
||||||
|
if (!priv->debugfs.trace_prst) {
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
read = simple_read_from_buffer(user_buf, count, ppos,
|
||||||
|
dump->dbg_info.la_conf.conf,
|
||||||
|
LA_CONF_LEN * 4);
|
||||||
|
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
DEBUGFS_READ_FILE_OPS(lamacconf);
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_chaninfo_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *priv = file->private_data;
|
||||||
|
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
|
||||||
|
char buf[4 * 32];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&priv->dbgdump_elem.mutex);
|
||||||
|
if (!priv->debugfs.trace_prst) {
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
|
||||||
|
"type: %d\n"
|
||||||
|
"prim20_freq: %d MHz\n"
|
||||||
|
"center1_freq: %d MHz\n"
|
||||||
|
"center2_freq: %d MHz\n",
|
||||||
|
(dump->dbg_info.chan_info.info1 >> 8) & 0xFF,
|
||||||
|
(dump->dbg_info.chan_info.info1 >> 16) & 0xFFFF,
|
||||||
|
(dump->dbg_info.chan_info.info2 >> 0) & 0xFFFF,
|
||||||
|
(dump->dbg_info.chan_info.info2 >> 16) & 0xFFFF);
|
||||||
|
|
||||||
|
mutex_unlock(&priv->dbgdump_elem.mutex);
|
||||||
|
return simple_read_from_buffer(user_buf, count, ppos, buf, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGFS_READ_FILE_OPS(chaninfo);
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_um_helper_read(struct file *file,
|
||||||
|
char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *priv = file->private_data;
|
||||||
|
char buf[sizeof(priv->debugfs.helper_cmd)];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
|
||||||
|
"%s", priv->debugfs.helper_cmd);
|
||||||
|
|
||||||
|
return simple_read_from_buffer(user_buf, count, ppos, buf, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t rwnx_dbgfs_um_helper_write(struct file *file,
|
||||||
|
const char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *priv = file->private_data;
|
||||||
|
int eobuf = min_t(size_t, sizeof(priv->debugfs.helper_cmd) - 1, count);
|
||||||
|
|
||||||
|
priv->debugfs.helper_cmd[eobuf] = '\0';
|
||||||
|
if (copy_from_user(priv->debugfs.helper_cmd, user_buf, eobuf))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGFS_READ_WRITE_FILE_OPS(um_helper);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calls a userspace pgm
|
||||||
|
*/
|
||||||
|
int rwnx_um_helper(struct rwnx_debugfs *rwnx_debugfs, const char *cmd)
|
||||||
|
{
|
||||||
|
char *envp[] = { "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
|
||||||
|
char **argv;
|
||||||
|
int argc, ret;
|
||||||
|
|
||||||
|
if (!rwnx_debugfs->dir ||
|
||||||
|
!strlen((cmd = cmd ? cmd : rwnx_debugfs->helper_cmd)))
|
||||||
|
return 0;
|
||||||
|
argv = argv_split(in_interrupt() ? GFP_ATOMIC : GFP_KERNEL, cmd, &argc);
|
||||||
|
if (!argc)
|
||||||
|
return PTR_ERR(argv);
|
||||||
|
|
||||||
|
if ((ret = call_usermodehelper(argv[0], argv, envp,
|
||||||
|
UMH_WAIT_PROC | UMH_KILLABLE)))
|
||||||
|
printk(KERN_CRIT "Failed to call %s (%s returned %d)\n",
|
||||||
|
argv[0], cmd, ret);
|
||||||
|
argv_free(argv);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rwnx_um_helper_work(struct work_struct *ws)
|
||||||
|
{
|
||||||
|
struct rwnx_debugfs *rwnx_debugfs = container_of(ws, struct rwnx_debugfs,
|
||||||
|
helper_work);
|
||||||
|
struct rwnx_hw *rwnx_hw = container_of(rwnx_debugfs, struct rwnx_hw,
|
||||||
|
debugfs);
|
||||||
|
rwnx_um_helper(rwnx_debugfs, NULL);
|
||||||
|
if (!rwnx_debugfs->unregistering)
|
||||||
|
rwnx_umh_done(rwnx_hw);
|
||||||
|
rwnx_debugfs->helper_scheduled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rwnx_trigger_um_helper(struct rwnx_debugfs *rwnx_debugfs)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *rwnx_hw = container_of(rwnx_debugfs, struct rwnx_hw,
|
||||||
|
debugfs);
|
||||||
|
|
||||||
|
if (rwnx_debugfs->helper_scheduled == true) {
|
||||||
|
dev_err(rwnx_hw->dev, "%s: Already scheduled\n", __func__);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_lock_bh(&rwnx_debugfs->umh_lock);
|
||||||
|
if (rwnx_debugfs->unregistering) {
|
||||||
|
spin_unlock_bh(&rwnx_debugfs->umh_lock);
|
||||||
|
dev_err(rwnx_hw->dev, "%s: unregistering\n", __func__);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
rwnx_debugfs->helper_scheduled = true;
|
||||||
|
schedule_work(&rwnx_debugfs->helper_work);
|
||||||
|
spin_unlock_bh(&rwnx_debugfs->umh_lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rwnx_dbgfs_register_fw_dump(struct rwnx_hw *rwnx_hw,
|
||||||
|
struct dentry *dir_drv,
|
||||||
|
struct dentry *dir_diags)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct rwnx_debugfs *rwnx_debugfs = &rwnx_hw->debugfs;
|
||||||
|
|
||||||
|
BUILD_BUG_ON(sizeof(CONFIG_RWNX_UM_HELPER_DFLT) >=
|
||||||
|
sizeof(rwnx_debugfs->helper_cmd));
|
||||||
|
strncpy(rwnx_debugfs->helper_cmd,
|
||||||
|
CONFIG_RWNX_UM_HELPER_DFLT, sizeof(rwnx_debugfs->helper_cmd));
|
||||||
|
INIT_WORK(&rwnx_debugfs->helper_work, rwnx_um_helper_work);
|
||||||
|
DEBUGFS_ADD_FILE(um_helper, dir_drv, S_IWUSR | S_IRUSR);
|
||||||
|
|
||||||
|
rwnx_debugfs->trace_prst = rwnx_debugfs->helper_scheduled = false;
|
||||||
|
spin_lock_init(&rwnx_debugfs->umh_lock);
|
||||||
|
DEBUGFS_ADD_FILE(rhd, dir_diags, S_IRUSR);
|
||||||
|
DEBUGFS_ADD_FILE(rbd, dir_diags, S_IRUSR);
|
||||||
|
DEBUGFS_ADD_FILE(thd0, dir_diags, S_IRUSR);
|
||||||
|
DEBUGFS_ADD_FILE(thd1, dir_diags, S_IRUSR);
|
||||||
|
DEBUGFS_ADD_FILE(thd2, dir_diags, S_IRUSR);
|
||||||
|
DEBUGFS_ADD_FILE(thd3, dir_diags, S_IRUSR);
|
||||||
|
#if (NX_TXQ_CNT == 5)
|
||||||
|
DEBUGFS_ADD_FILE(thd4, dir_diags, S_IRUSR);
|
||||||
|
#endif
|
||||||
|
DEBUGFS_ADD_FILE(mactrace, dir_diags, S_IRUSR);
|
||||||
|
DEBUGFS_ADD_FILE(macdiags, dir_diags, S_IRUSR);
|
||||||
|
DEBUGFS_ADD_FILE(phydiags, dir_diags, S_IRUSR);
|
||||||
|
DEBUGFS_ADD_FILE(plfdiags, dir_diags, S_IRUSR);
|
||||||
|
DEBUGFS_ADD_FILE(hwdiags, dir_diags, S_IRUSR);
|
||||||
|
DEBUGFS_ADD_FILE(swdiags, dir_diags, S_IRUSR);
|
||||||
|
DEBUGFS_ADD_FILE(error, dir_diags, S_IRUSR);
|
||||||
|
DEBUGFS_ADD_FILE(rxdesc, dir_diags, S_IRUSR);
|
||||||
|
DEBUGFS_ADD_FILE(txdesc, dir_diags, S_IRUSR);
|
||||||
|
DEBUGFS_ADD_FILE(macrxptr, dir_diags, S_IRUSR);
|
||||||
|
DEBUGFS_ADD_FILE(lamacconf, dir_diags, S_IRUSR);
|
||||||
|
DEBUGFS_ADD_FILE(chaninfo, dir_diags, S_IRUSR);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_fw_trace.c
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2017-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include "rwnx_fw_trace.h"
|
||||||
|
|
||||||
|
int rwnx_fw_log_init(struct rwnx_fw_log *fw_log)
|
||||||
|
{
|
||||||
|
u8 *buf = kmalloc(FW_LOG_SIZE, GFP_KERNEL);
|
||||||
|
if (!buf)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
fw_log->buf.data = buf;
|
||||||
|
fw_log->buf.start = fw_log->buf.data;
|
||||||
|
fw_log->buf.size = 0;
|
||||||
|
fw_log->buf.end = fw_log->buf.data;
|
||||||
|
fw_log->buf.dataend = fw_log->buf.data + FW_LOG_SIZE;
|
||||||
|
spin_lock_init(&fw_log->lock);
|
||||||
|
|
||||||
|
printk("fw_log_init: %lx, %lx\n", (unsigned long)fw_log->buf.start, (unsigned long)(fw_log->buf.dataend));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rwnx_fw_log_deinit(struct rwnx_fw_log *fw_log)
|
||||||
|
{
|
||||||
|
if (!fw_log)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (fw_log->buf.data)
|
||||||
|
kfree(fw_log->buf.data);
|
||||||
|
fw_log->buf.start = NULL;
|
||||||
|
fw_log->buf.end = NULL;
|
||||||
|
fw_log->buf.size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* rwnx_fw_trace.h
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2017-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RWNX_FW_TRACE_H_
|
||||||
|
#define _RWNX_FW_TRACE_H_
|
||||||
|
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
|
#define FW_LOG_SIZE (10240)
|
||||||
|
|
||||||
|
struct rwnx_fw_log_buf {
|
||||||
|
uint8_t *data;
|
||||||
|
uint8_t *start;
|
||||||
|
uint8_t *end;
|
||||||
|
uint8_t *dataend;
|
||||||
|
uint32_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rwnx_fw_log {
|
||||||
|
struct rwnx_fw_log_buf buf;
|
||||||
|
spinlock_t lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
int rwnx_fw_log_init(struct rwnx_fw_log *fw_log);
|
||||||
|
void rwnx_fw_log_deinit(struct rwnx_fw_log *fw_log);
|
||||||
|
#endif /* _RWNX_FW_TRACE_H_ */
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
|
||||||
|
|
||||||
|
void rwnx_gki_skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
struct sk_buff *prev = old;
|
||||||
|
struct sk_buff *next = prev->next;
|
||||||
|
spin_lock_irqsave(&list->lock, flags);
|
||||||
|
WRITE_ONCE(newsk->next, next);
|
||||||
|
WRITE_ONCE(newsk->prev, prev);
|
||||||
|
WRITE_ONCE(next->prev, newsk);
|
||||||
|
WRITE_ONCE(prev->next, newsk);
|
||||||
|
list->qlen++;
|
||||||
|
spin_unlock_irqrestore(&list->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#ifndef __RWNX_GKI_H
|
||||||
|
#define __RWNX_GKI_H
|
||||||
|
|
||||||
|
#ifdef CONFIG_GKI
|
||||||
|
void rwnx_gki_skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list);
|
||||||
|
#define rwnx_skb_append rwnx_gki_skb_append
|
||||||
|
#else
|
||||||
|
#define rwnx_skb_append skb_append
|
||||||
|
#endif//CONFIG_GKI
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_irqs.c
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
|
||||||
|
#include "rwnx_defs.h"
|
||||||
|
#include "ipc_host.h"
|
||||||
|
#include "rwnx_prof.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_irq_hdlr - IRQ handler
|
||||||
|
*
|
||||||
|
* Handler registerd by the platform driver
|
||||||
|
*/
|
||||||
|
irqreturn_t rwnx_irq_hdlr(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *rwnx_hw = (struct rwnx_hw *)dev_id;
|
||||||
|
disable_irq_nosync(irq);
|
||||||
|
tasklet_schedule(&rwnx_hw->task);
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_task - Bottom half for IRQ handler
|
||||||
|
*
|
||||||
|
* Read irq status and process accordingly
|
||||||
|
*/
|
||||||
|
void rwnx_task(unsigned long data)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *rwnx_hw = (struct rwnx_hw *)data;
|
||||||
|
REG_SW_SET_PROFILING(rwnx_hw, SW_PROF_RWNX_IPC_IRQ_HDLR);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
|
||||||
|
u32 status, statuses = 0;
|
||||||
|
|
||||||
|
/* Ack unconditionnally in case ipc_host_get_status does not see the irq */
|
||||||
|
rwnx_plat->ack_irq(rwnx_plat);
|
||||||
|
|
||||||
|
while ((status = ipc_host_get_status(rwnx_hw->ipc_env))) {
|
||||||
|
statuses |= status;
|
||||||
|
/* All kinds of IRQs will be handled in one shot (RX, MSG, DBG, ...)
|
||||||
|
* this will ack IPC irqs not the cfpga irqs */
|
||||||
|
ipc_host_irq(rwnx_hw->ipc_env, status);
|
||||||
|
|
||||||
|
rwnx_plat->ack_irq(rwnx_plat);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
//if (statuses & IPC_IRQ_E2A_RXDESC)
|
||||||
|
// rwnx_hw->stats.last_rx = now;
|
||||||
|
//if (statuses & IPC_IRQ_E2A_TXCFM)
|
||||||
|
// rwnx_hw->stats.last_tx = now;
|
||||||
|
AICWFDBG(LOGTRACE, "rwnx_task\n");
|
||||||
|
spin_lock_bh(&rwnx_hw->tx_lock);
|
||||||
|
rwnx_hwq_process_all(rwnx_hw);
|
||||||
|
spin_unlock_bh(&rwnx_hw->tx_lock);
|
||||||
|
#if 0
|
||||||
|
enable_irq(rwnx_platform_get_irq(rwnx_plat));
|
||||||
|
#endif
|
||||||
|
REG_SW_CLEAR_PROFILING(rwnx_hw, SW_PROF_RWNX_IPC_IRQ_HDLR);
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_irqs.h
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
#ifndef _RWNX_IRQS_H_
|
||||||
|
#define _RWNX_IRQS_H_
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
|
||||||
|
/* IRQ handler to be registered by platform driver */
|
||||||
|
irqreturn_t rwnx_irq_hdlr(int irq, void *dev_id);
|
||||||
|
|
||||||
|
void rwnx_task(unsigned long data);
|
||||||
|
|
||||||
|
#endif /* _RWNX_IRQS_H_ */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_main.h
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RWNX_MAIN_H_
|
||||||
|
#define _RWNX_MAIN_H_
|
||||||
|
|
||||||
|
#include "rwnx_defs.h"
|
||||||
|
|
||||||
|
int rwnx_cfg80211_init(struct rwnx_plat *rwnx_plat, void **platform_data);
|
||||||
|
void rwnx_cfg80211_deinit(struct rwnx_hw *rwnx_hw);
|
||||||
|
extern int testmode;
|
||||||
|
extern u8 chip_id;
|
||||||
|
extern u8 chip_sub_id;
|
||||||
|
extern u8 chip_mcu_id;
|
||||||
|
|
||||||
|
#define CHIP_ID_H_MASK 0xC0
|
||||||
|
#define IS_CHIP_ID_H() ((chip_id & CHIP_ID_H_MASK) == CHIP_ID_H_MASK)
|
||||||
|
|
||||||
|
#endif /* _RWNX_MAIN_H_ */
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_mesh.c
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2016-2019
|
||||||
|
*
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* INCLUDE FILES
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rwnx_mesh.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FUNCTION DEFINITIONS
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct rwnx_mesh_proxy *rwnx_get_mesh_proxy_info(struct rwnx_vif *p_rwnx_vif, u8 *p_sta_addr, bool local)
|
||||||
|
{
|
||||||
|
struct rwnx_mesh_proxy *p_mesh_proxy = NULL;
|
||||||
|
struct rwnx_mesh_proxy *p_cur_proxy;
|
||||||
|
|
||||||
|
/* Look for proxied devices with provided address */
|
||||||
|
list_for_each_entry(p_cur_proxy, &p_rwnx_vif->ap.proxy_list, list) {
|
||||||
|
if (p_cur_proxy->local != local) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp(&p_cur_proxy->ext_sta_addr, p_sta_addr, ETH_ALEN)) {
|
||||||
|
p_mesh_proxy = p_cur_proxy;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the found information */
|
||||||
|
return p_mesh_proxy;
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_mesh.h
|
||||||
|
*
|
||||||
|
* @brief VHT Beamformer function declarations
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2016-2019
|
||||||
|
*
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RWNX_MESH_H_
|
||||||
|
#define _RWNX_MESH_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* INCLUDE FILES
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rwnx_defs.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEFINES
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TYPE DEFINITIONS
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FUNCTION DECLARATIONS
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
* @brief TODO [LT]
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
struct rwnx_mesh_proxy *rwnx_get_mesh_proxy_info(struct rwnx_vif *p_rwnx_vif, u8 *p_sta_addr, bool local);
|
||||||
|
|
||||||
|
#endif /* _RWNX_MESH_H_ */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_mod_params.h
|
||||||
|
*
|
||||||
|
* @brief Declaration of module parameters
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RWNX_MOD_PARAM_H_
|
||||||
|
#define _RWNX_MOD_PARAM_H_
|
||||||
|
|
||||||
|
struct rwnx_mod_params {
|
||||||
|
bool ht_on;
|
||||||
|
bool vht_on;
|
||||||
|
bool he_on;
|
||||||
|
int mcs_map;
|
||||||
|
int he_mcs_map;
|
||||||
|
bool he_ul_on;
|
||||||
|
bool ldpc_on;
|
||||||
|
bool stbc_on;
|
||||||
|
bool gf_rx_on;
|
||||||
|
int phy_cfg;
|
||||||
|
int uapsd_timeout;
|
||||||
|
bool ap_uapsd_on;
|
||||||
|
bool sgi;
|
||||||
|
bool sgi80;
|
||||||
|
bool use_2040;
|
||||||
|
bool use_80;
|
||||||
|
bool custregd;
|
||||||
|
bool custchan;
|
||||||
|
int nss;
|
||||||
|
int amsdu_rx_max;
|
||||||
|
bool bfmee;
|
||||||
|
bool bfmer;
|
||||||
|
bool mesh;
|
||||||
|
bool murx;
|
||||||
|
bool mutx;
|
||||||
|
bool mutx_on;
|
||||||
|
unsigned int roc_dur_max;
|
||||||
|
int listen_itv;
|
||||||
|
bool listen_bcmc;
|
||||||
|
int lp_clk_ppm;
|
||||||
|
bool ps_on;
|
||||||
|
int tx_lft;
|
||||||
|
int amsdu_maxnb;
|
||||||
|
int uapsd_queues;
|
||||||
|
bool tdls;
|
||||||
|
bool uf;
|
||||||
|
bool auto_reply;
|
||||||
|
char *ftl;
|
||||||
|
bool dpsm;
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
bool ant_div;
|
||||||
|
#endif /* CONFIG_RWNX_FULLMAC */
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct rwnx_mod_params rwnx_mod_params;
|
||||||
|
|
||||||
|
struct rwnx_hw;
|
||||||
|
struct wiphy;
|
||||||
|
int rwnx_handle_dynparams(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy);
|
||||||
|
void rwnx_custregd(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy);
|
||||||
|
void rwnx_enable_wapi(struct rwnx_hw *rwnx_hw);
|
||||||
|
void rwnx_enable_mfp(struct rwnx_hw *rwnx_hw);
|
||||||
|
|
||||||
|
#endif /* _RWNX_MOD_PARAM_H_ */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_msg_rx.h
|
||||||
|
*
|
||||||
|
* @brief RX function declarations
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RWNX_MSG_RX_H_
|
||||||
|
#define _RWNX_MSG_RX_H_
|
||||||
|
|
||||||
|
void rwnx_rx_handle_msg(struct rwnx_hw *rwnx_hw, struct ipc_e2a_msg *msg);
|
||||||
|
void rwnx_rx_handle_print(struct rwnx_hw *rwnx_hw, u8 *msg, u32 len);
|
||||||
|
|
||||||
|
#endif /* _RWNX_MSG_RX_H_ */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,187 @@
|
|||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_msg_tx.h
|
||||||
|
*
|
||||||
|
* @brief TX function declarations
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RWNX_MSG_TX_H_
|
||||||
|
#define _RWNX_MSG_TX_H_
|
||||||
|
|
||||||
|
#include "rwnx_defs.h"
|
||||||
|
|
||||||
|
int rwnx_send_reset(struct rwnx_hw *rwnx_hw);
|
||||||
|
int rwnx_send_start(struct rwnx_hw *rwnx_hw);
|
||||||
|
int rwnx_send_version_req(struct rwnx_hw *rwnx_hw, struct mm_version_cfm *cfm);
|
||||||
|
int rwnx_send_add_if(struct rwnx_hw *rwnx_hw, const unsigned char *mac,
|
||||||
|
enum nl80211_iftype iftype, bool p2p, struct mm_add_if_cfm *cfm);
|
||||||
|
int rwnx_send_remove_if(struct rwnx_hw *rwnx_hw, u8 vif_index, bool defer);
|
||||||
|
int rwnx_send_set_channel(struct rwnx_hw *rwnx_hw, int phy_idx,
|
||||||
|
struct mm_set_channel_cfm *cfm);
|
||||||
|
int rwnx_send_key_add(struct rwnx_hw *rwnx_hw, u8 vif_idx, u8 sta_idx, bool pairwise,
|
||||||
|
u8 *key, u8 key_len, u8 key_idx, u8 cipher_suite,
|
||||||
|
struct mm_key_add_cfm *cfm);
|
||||||
|
int rwnx_send_key_del(struct rwnx_hw *rwnx_hw, uint8_t hw_key_idx);
|
||||||
|
int rwnx_send_bcn(struct rwnx_hw *rwnx_hw,u8 *buf, u8 vif_idx, u16 bcn_len);
|
||||||
|
|
||||||
|
int rwnx_send_bcn_change(struct rwnx_hw *rwnx_hw, u8 vif_idx, u32 bcn_addr,
|
||||||
|
u16 bcn_len, u16 tim_oft, u16 tim_len, u16 *csa_oft);
|
||||||
|
int rwnx_send_tim_update(struct rwnx_hw *rwnx_hw, u8 vif_idx, u16 aid,
|
||||||
|
u8 tx_status);
|
||||||
|
int rwnx_send_roc(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
|
||||||
|
struct ieee80211_channel *chan, unsigned int duration, struct mm_remain_on_channel_cfm *roc_cfm);
|
||||||
|
int rwnx_send_cancel_roc(struct rwnx_hw *rwnx_hw);
|
||||||
|
int rwnx_send_set_power(struct rwnx_hw *rwnx_hw, u8 vif_idx, s8 pwr,
|
||||||
|
struct mm_set_power_cfm *cfm);
|
||||||
|
int rwnx_send_set_edca(struct rwnx_hw *rwnx_hw, u8 hw_queue, u32 param,
|
||||||
|
bool uapsd, u8 inst_nbr);
|
||||||
|
int rwnx_send_tdls_chan_switch_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
|
||||||
|
struct rwnx_sta *rwnx_sta, bool sta_initiator,
|
||||||
|
u8 oper_class, struct cfg80211_chan_def *chandef,
|
||||||
|
struct tdls_chan_switch_cfm *cfm);
|
||||||
|
int rwnx_send_tdls_cancel_chan_switch_req(struct rwnx_hw *rwnx_hw,
|
||||||
|
struct rwnx_vif *rwnx_vif,
|
||||||
|
struct rwnx_sta *rwnx_sta,
|
||||||
|
struct tdls_cancel_chan_switch_cfm *cfm);
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_P2P_DEBUGFS
|
||||||
|
int rwnx_send_p2p_oppps_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
|
||||||
|
u8 ctw, struct mm_set_p2p_oppps_cfm *cfm);
|
||||||
|
int rwnx_send_p2p_noa_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
|
||||||
|
int count, int interval, int duration,
|
||||||
|
bool dyn_noa, struct mm_set_p2p_noa_cfm *cfm);
|
||||||
|
#endif /* CONFIG_RWNX_P2P_DEBUGFS */
|
||||||
|
|
||||||
|
#ifdef AICWF_ARP_OFFLOAD
|
||||||
|
int rwnx_send_arpoffload_en_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
|
||||||
|
u32_l ipaddr, u8_l enable);
|
||||||
|
#endif
|
||||||
|
int rwnx_send_rf_config_req(struct rwnx_hw *rwnx_hw, u8_l ofst, u8_l sel, u8_l *tbl, u16_l len);
|
||||||
|
int rwnx_send_rf_calib_req(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *cfm);
|
||||||
|
int rwnx_send_get_macaddr_req(struct rwnx_hw *rwnx_hw, struct mm_get_mac_addr_cfm *cfm);
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
int rwnx_send_me_config_req(struct rwnx_hw *rwnx_hw);
|
||||||
|
int rwnx_send_me_chan_config_req(struct rwnx_hw *rwnx_hw);
|
||||||
|
int rwnx_send_me_set_control_port_req(struct rwnx_hw *rwnx_hw, bool opened,
|
||||||
|
u8 sta_idx);
|
||||||
|
int rwnx_send_me_sta_add(struct rwnx_hw *rwnx_hw, struct station_parameters *params,
|
||||||
|
const u8 *mac, u8 inst_nbr, struct me_sta_add_cfm *cfm);
|
||||||
|
int rwnx_send_me_sta_del(struct rwnx_hw *rwnx_hw, u8 sta_idx, bool tdls_sta);
|
||||||
|
int rwnx_send_me_traffic_ind(struct rwnx_hw *rwnx_hw, u8 sta_idx, bool uapsd, u8 tx_status);
|
||||||
|
int rwnx_send_me_rc_stats(struct rwnx_hw *rwnx_hw, u8 sta_idx,
|
||||||
|
struct me_rc_stats_cfm *cfm);
|
||||||
|
int rwnx_send_me_rc_set_rate(struct rwnx_hw *rwnx_hw,
|
||||||
|
u8 sta_idx,
|
||||||
|
u16 rate_idx);
|
||||||
|
int rwnx_send_me_set_ps_mode(struct rwnx_hw *rwnx_hw, u8 ps_mode);
|
||||||
|
int rwnx_send_me_set_lp_level(struct rwnx_hw *rwnx_hw, u8 lp_level);
|
||||||
|
int rwnx_send_sm_connect_req(struct rwnx_hw *rwnx_hw,
|
||||||
|
struct rwnx_vif *rwnx_vif,
|
||||||
|
struct cfg80211_connect_params *sme,
|
||||||
|
struct sm_connect_cfm *cfm);
|
||||||
|
int rwnx_send_sm_disconnect_req(struct rwnx_hw *rwnx_hw,
|
||||||
|
struct rwnx_vif *rwnx_vif,
|
||||||
|
u16 reason);
|
||||||
|
int rwnx_send_sm_external_auth_required_rsp(struct rwnx_hw *rwnx_hw,
|
||||||
|
struct rwnx_vif *rwnx_vif,
|
||||||
|
u16 status);
|
||||||
|
int rwnx_send_apm_start_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
|
||||||
|
struct cfg80211_ap_settings *settings,
|
||||||
|
struct apm_start_cfm *cfm,
|
||||||
|
struct rwnx_ipc_elem_var *elem);
|
||||||
|
int rwnx_send_apm_stop_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif);
|
||||||
|
int rwnx_send_scanu_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
|
||||||
|
struct cfg80211_scan_request *param);
|
||||||
|
int rwnx_send_scanu_cancel_req(struct rwnx_hw *rwnx_hw,
|
||||||
|
struct scan_cancel_cfm *cfm);
|
||||||
|
|
||||||
|
int rwnx_send_apm_start_cac_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
|
||||||
|
struct cfg80211_chan_def *chandef,
|
||||||
|
struct apm_start_cac_cfm *cfm);
|
||||||
|
int rwnx_send_apm_stop_cac_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif);
|
||||||
|
int rwnx_send_tdls_peer_traffic_ind_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif);
|
||||||
|
int rwnx_send_config_monitor_req(struct rwnx_hw *rwnx_hw,
|
||||||
|
struct cfg80211_chan_def *chandef,
|
||||||
|
struct me_config_monitor_cfm *cfm);
|
||||||
|
int rwnx_send_mesh_start_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
|
||||||
|
const struct mesh_config *conf, const struct mesh_setup *setup,
|
||||||
|
struct mesh_start_cfm *cfm);
|
||||||
|
int rwnx_send_mesh_stop_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
|
||||||
|
struct mesh_stop_cfm *cfm);
|
||||||
|
int rwnx_send_mesh_update_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
|
||||||
|
u32 mask, const struct mesh_config *p_mconf, struct mesh_update_cfm *cfm);
|
||||||
|
int rwnx_send_mesh_peer_info_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
|
||||||
|
u8 sta_idx, struct mesh_peer_info_cfm *cfm);
|
||||||
|
void rwnx_send_mesh_peer_update_ntf(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
|
||||||
|
u8 sta_idx, u8 mlink_state);
|
||||||
|
void rwnx_send_mesh_path_create_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif, u8 *tgt_addr);
|
||||||
|
int rwnx_send_mesh_path_update_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif, const u8 *tgt_addr,
|
||||||
|
const u8 *p_nhop_addr, struct mesh_path_update_cfm *cfm);
|
||||||
|
void rwnx_send_mesh_proxy_add_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif, u8 *ext_addr);
|
||||||
|
#endif /* CONFIG_RWNX_FULLMAC */
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_BFMER
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
void rwnx_send_bfmer_enable(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta,
|
||||||
|
const struct ieee80211_vht_cap *vht_cap);
|
||||||
|
#endif /* CONFIG_RWNX_FULLMAC */
|
||||||
|
#ifdef CONFIG_RWNX_MUMIMO_TX
|
||||||
|
int rwnx_send_mu_group_update_req(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta);
|
||||||
|
#endif /* CONFIG_RWNX_MUMIMO_TX */
|
||||||
|
#endif /* CONFIG_RWNX_BFMER */
|
||||||
|
|
||||||
|
/* Debug messages */
|
||||||
|
int rwnx_send_dbg_trigger_req(struct rwnx_hw *rwnx_hw, char *msg);
|
||||||
|
int rwnx_send_dbg_mem_read_req(struct rwnx_hw *rwnx_hw, u32 mem_addr,
|
||||||
|
struct dbg_mem_read_cfm *cfm);
|
||||||
|
int rwnx_send_dbg_mem_write_req(struct rwnx_hw *rwnx_hw, u32 mem_addr,
|
||||||
|
u32 mem_data);
|
||||||
|
int rwnx_send_dbg_mem_mask_write_req(struct rwnx_hw *rwnx_hw, u32 mem_addr,
|
||||||
|
u32 mem_mask, u32 mem_data);
|
||||||
|
int rwnx_send_dbg_set_mod_filter_req(struct rwnx_hw *rwnx_hw, u32 filter);
|
||||||
|
#ifdef CONFIG_RFTEST
|
||||||
|
int rwnx_send_rftest_req(struct rwnx_hw *rwnx_hw, u32_l cmd, u32_l argc, u8_l *argv, struct dbg_rftest_cmd_cfm *cfm);
|
||||||
|
#endif
|
||||||
|
int rwnx_send_dbg_set_sev_filter_req(struct rwnx_hw *rwnx_hw, u32 filter);
|
||||||
|
int rwnx_send_dbg_get_sys_stat_req(struct rwnx_hw *rwnx_hw,
|
||||||
|
struct dbg_get_sys_stat_cfm *cfm);
|
||||||
|
int rwnx_send_dbg_mem_block_write_req(struct rwnx_hw *rwnx_hw, u32 mem_addr,
|
||||||
|
u32 mem_size, u32 *mem_data);
|
||||||
|
int rwnx_send_dbg_start_app_req(struct rwnx_hw *rwnx_hw, u32 boot_addr,
|
||||||
|
u32 boot_type);
|
||||||
|
int rwnx_send_dbg_gpio_write_req(struct rwnx_hw *rwnx_hw, u8_l gpio_idx, u8_l gpio_val);
|
||||||
|
int rwnx_send_dbg_gpio_read_req(struct rwnx_hw *rwnx_hw, u8_l gpio_idx, struct dbg_gpio_read_cfm *cfm);
|
||||||
|
int rwnx_send_dbg_gpio_init_req(struct rwnx_hw *rwnx_hw, u8_l gpio_idx, u8_l gpio_dir, u8_l gpio_val);
|
||||||
|
int rwnx_send_cfg_rssi_req(struct rwnx_hw *rwnx_hw, u8 vif_index, int rssi_thold, u32 rssi_hyst);
|
||||||
|
int rwnx_send_disable_agg_req(struct rwnx_hw *rwnx_hw, u8_l agg_disable, u8_l agg_disable_rx, u8_l sta_idx);
|
||||||
|
int rwnx_send_coex_req(struct rwnx_hw *rwnx_hw, u8_l disable_coexnull, u8_l enable_nullcts);
|
||||||
|
int rwnx_send_get_sta_info_req(struct rwnx_hw *rwnx_hw, u8_l sta_idx, struct mm_get_sta_info_cfm *cfm);
|
||||||
|
int rwnx_send_set_stack_start_req(struct rwnx_hw *rwnx_hw, u8_l on, u8_l efuse_valid, u8_l set_vendor_info,
|
||||||
|
u8_l fwtrace_redir_en, struct mm_set_stack_start_cfm *cfm);
|
||||||
|
int rwnx_send_txop_req(struct rwnx_hw *rwnx_hw, uint16_t *txop, u8_l long_nav_en, u8_l cfe_en);
|
||||||
|
int rwnx_send_set_temp_comp_req(struct rwnx_hw *rwnx_hw, struct mm_set_vendor_swconfig_cfm *cfm);
|
||||||
|
int rwnx_send_vendor_hwconfig_req(struct rwnx_hw *rwnx_hw, uint32_t hwconfig_id, int32_t *param, int32_t *param_out);
|
||||||
|
int rwnx_send_vendor_swconfig_req(struct rwnx_hw *rwnx_hw, uint32_t swconfig_id, int32_t *param_in, int32_t *param_out);
|
||||||
|
int rwnx_send_mask_set_ext_flags_req(struct rwnx_hw *rwnx_hw, uint32_t flags_mask, uint32_t flags_val, struct mm_set_vendor_swconfig_cfm *cfm);
|
||||||
|
|
||||||
|
int rwnx_send_get_fw_version_req(struct rwnx_hw *rwnx_hw, struct mm_get_fw_version_cfm *cfm);
|
||||||
|
int rwnx_send_txpwr_idx_req(struct rwnx_hw *rwnx_hw);
|
||||||
|
int rwnx_send_txpwr_ofst_req(struct rwnx_hw *rwnx_hw);
|
||||||
|
int rwnx_send_txpwr_ofst2x_req(struct rwnx_hw *rwnx_hw);
|
||||||
|
int rwnx_send_set_filter(struct rwnx_hw *rwnx_hw, uint32_t filter);
|
||||||
|
int rwnx_send_txpwr_lvl_req(struct rwnx_hw *rwnx_hw);
|
||||||
|
int rwnx_send_txpwr_lvl_v3_req(struct rwnx_hw *rwnx_hw);
|
||||||
|
int rwnx_send_txpwr_lvl_adj_req(struct rwnx_hw *rwnx_hw);
|
||||||
|
|
||||||
|
//#ifdef CONFIG_USB_BT
|
||||||
|
int rwnx_send_reboot(struct rwnx_hw *rwnx_hw);
|
||||||
|
//#endif // CONFIG_USB_BT
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _RWNX_MSG_TX_H_ */
|
||||||
@@ -0,0 +1,659 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_mu_group.c
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2016-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rwnx_defs.h"
|
||||||
|
#include "rwnx_msg_tx.h"
|
||||||
|
#include "rwnx_events.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_mu_group_sta_init - Initialize group information for a STA
|
||||||
|
*
|
||||||
|
* @sta: Sta to initialize
|
||||||
|
*/
|
||||||
|
void rwnx_mu_group_sta_init(struct rwnx_sta *sta,
|
||||||
|
const struct ieee80211_vht_cap *vht_cap)
|
||||||
|
{
|
||||||
|
sta->group_info.map = 0;
|
||||||
|
sta->group_info.cnt = 0;
|
||||||
|
sta->group_info.active.next = LIST_POISON1;
|
||||||
|
sta->group_info.update.next = LIST_POISON1;
|
||||||
|
sta->group_info.last_update = 0;
|
||||||
|
sta->group_info.traffic = 0;
|
||||||
|
sta->group_info.group = 0;
|
||||||
|
|
||||||
|
if (!vht_cap ||
|
||||||
|
!(vht_cap->vht_cap_info & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) {
|
||||||
|
sta->group_info.map = RWNX_SU_GROUP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_mu_group_sta_del - Remove a sta from all MU group
|
||||||
|
*
|
||||||
|
* @rwnx_hw: main driver data
|
||||||
|
* @sta: STA to remove
|
||||||
|
*
|
||||||
|
* Remove one sta from all the MU groups it belongs to.
|
||||||
|
*/
|
||||||
|
void rwnx_mu_group_sta_del(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta)
|
||||||
|
{
|
||||||
|
struct rwnx_mu_info *mu = &rwnx_hw->mu;
|
||||||
|
int i, j, group_id;
|
||||||
|
bool lock_taken;
|
||||||
|
u64 map;
|
||||||
|
|
||||||
|
lock_taken = (down_interruptible(&mu->lock) == 0);
|
||||||
|
|
||||||
|
group_sta_for_each(sta, group_id, map) {
|
||||||
|
struct rwnx_mu_group *group = rwnx_mu_group_from_id(mu, group_id);
|
||||||
|
|
||||||
|
for (i = 0; i < CONFIG_USER_MAX; i++) {
|
||||||
|
if (group->users[i] == sta) {
|
||||||
|
group->users[i] = NULL;
|
||||||
|
group->user_cnt --;
|
||||||
|
/* Don't keep group with only one user */
|
||||||
|
if (group->user_cnt == 1) {
|
||||||
|
for (j = 0; j < CONFIG_USER_MAX; j++) {
|
||||||
|
if (group->users[j]) {
|
||||||
|
group->users[j]->group_info.cnt--;
|
||||||
|
group->users[j]->group_info.map &= ~BIT_ULL(group->group_id);
|
||||||
|
if (group->users[j]->group_info.group == group_id)
|
||||||
|
group->users[j]->group_info.group = 0;
|
||||||
|
group->user_cnt --;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mu->group_cnt--;
|
||||||
|
trace_mu_group_delete(group->group_id);
|
||||||
|
} else {
|
||||||
|
trace_mu_group_update(group);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WARN((i == CONFIG_USER_MAX), "sta %d doesn't belongs to group %d",
|
||||||
|
sta->sta_idx, group_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
sta->group_info.map = 0;
|
||||||
|
sta->group_info.cnt = 0;
|
||||||
|
sta->group_info.traffic = 0;
|
||||||
|
|
||||||
|
if (sta->group_info.active.next != LIST_POISON1)
|
||||||
|
list_del(&sta->group_info.active);
|
||||||
|
|
||||||
|
if (sta->group_info.update.next != LIST_POISON1)
|
||||||
|
list_del(&sta->group_info.update);
|
||||||
|
|
||||||
|
if (lock_taken)
|
||||||
|
up(&mu->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_mu_group_sta_get_map - Get the list of group a STA belongs to
|
||||||
|
*
|
||||||
|
* @sta: pointer to the sta
|
||||||
|
*
|
||||||
|
* @return the list of group a STA belongs to as a bitfield
|
||||||
|
*/
|
||||||
|
u64 rwnx_mu_group_sta_get_map(struct rwnx_sta *sta)
|
||||||
|
{
|
||||||
|
if (sta)
|
||||||
|
return sta->group_info.map;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_mu_group_sta_get_pos - Get sta position in a group
|
||||||
|
*
|
||||||
|
* @rwnx_hw: main driver data
|
||||||
|
* @sta: pointer to the sta
|
||||||
|
* @group_id: Group id
|
||||||
|
*
|
||||||
|
* @return the positon of @sta in group @group_id or -1 if the sta
|
||||||
|
* doesn't belongs to the group (or group id is invalid)
|
||||||
|
*/
|
||||||
|
int rwnx_mu_group_sta_get_pos(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
|
||||||
|
int group_id)
|
||||||
|
{
|
||||||
|
struct rwnx_mu_group *group;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
group = rwnx_mu_group_from_id(&rwnx_hw->mu, group_id);
|
||||||
|
if (!group)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (i = 0; i < CONFIG_USER_MAX; i++) {
|
||||||
|
if (group->users[i] == sta)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
WARN(1, "sta %d doesn't belongs to group %d",
|
||||||
|
sta->sta_idx, group_id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_mu_group_move_head - Move (or add) one element at the top of a list
|
||||||
|
*
|
||||||
|
* @list: list pointer
|
||||||
|
* @elem: element to move (or add) at the top of @list
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static inline
|
||||||
|
void rwnx_mu_group_move_head(struct list_head *list, struct list_head *elem)
|
||||||
|
{
|
||||||
|
if (elem->next != LIST_POISON1) {
|
||||||
|
__list_del_entry(elem);
|
||||||
|
}
|
||||||
|
list_add(elem, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_mu_group_remove_users - Remove all the users of a group
|
||||||
|
*
|
||||||
|
* @mu: pointer on MU info
|
||||||
|
* @group: pointer on group to remove users from
|
||||||
|
*
|
||||||
|
* Loop over all users one one group and remove this group from their
|
||||||
|
* map (and count).
|
||||||
|
* Each users is also added to the update_sta list, so that group info
|
||||||
|
* will be resent to fw for this user.
|
||||||
|
*/
|
||||||
|
static inline
|
||||||
|
void rwnx_mu_group_remove_users(struct rwnx_mu_info *mu,
|
||||||
|
struct rwnx_mu_group *group)
|
||||||
|
{
|
||||||
|
struct rwnx_sta *sta;
|
||||||
|
int i, group_id = group->group_id;
|
||||||
|
|
||||||
|
for (i = 0; i < CONFIG_USER_MAX; i++) {
|
||||||
|
if (group->users[i]) {
|
||||||
|
sta = group->users[i];
|
||||||
|
group->users[i] = NULL;
|
||||||
|
sta->group_info.cnt--;
|
||||||
|
sta->group_info.map &= ~BIT_ULL(group_id);
|
||||||
|
rwnx_mu_group_move_head(&mu->update_sta,
|
||||||
|
&sta->group_info.update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group->user_cnt)
|
||||||
|
mu->group_cnt--;
|
||||||
|
group->user_cnt = 0;
|
||||||
|
trace_mu_group_delete(group_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_mu_group_add_users - Add users to a group
|
||||||
|
*
|
||||||
|
* @mu: pointer on MU info
|
||||||
|
* @group: pointer on group to add users in
|
||||||
|
* @nb_user: number of users to ad
|
||||||
|
* @users: table of user to add
|
||||||
|
*
|
||||||
|
* Add @nb_users to @group (which may already have users)
|
||||||
|
* Each new users is added to the first free position.
|
||||||
|
* It is assume that @group has at least @nb_user free position. If it is not
|
||||||
|
* case it only add the number of users needed to complete the group.
|
||||||
|
* Each users (effectively added to @group) is also added to the update_sta
|
||||||
|
* list, so that group info will be resent to fw for this user.
|
||||||
|
*/
|
||||||
|
static inline
|
||||||
|
void rwnx_mu_group_add_users(struct rwnx_mu_info *mu,
|
||||||
|
struct rwnx_mu_group *group,
|
||||||
|
int nb_user, struct rwnx_sta **users)
|
||||||
|
{
|
||||||
|
int i, j, group_id = group->group_id;
|
||||||
|
|
||||||
|
if (!group->user_cnt)
|
||||||
|
mu->group_cnt++;
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
for (i = 0; i < nb_user ; i++) {
|
||||||
|
for (; j < CONFIG_USER_MAX ; j++) {
|
||||||
|
if (group->users[j] == NULL) {
|
||||||
|
group->users[j] = users[i];
|
||||||
|
users[i]->group_info.cnt ++;
|
||||||
|
users[i]->group_info.map |= BIT_ULL(group_id);
|
||||||
|
|
||||||
|
rwnx_mu_group_move_head(&(mu->update_sta),
|
||||||
|
&(users[i]->group_info.update));
|
||||||
|
group->user_cnt ++;
|
||||||
|
j ++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
WARN(j == (CONFIG_USER_MAX - 1),
|
||||||
|
"Too many user for group %d (nb_user=%d)",
|
||||||
|
group_id, group->user_cnt + nb_user - i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trace_mu_group_update(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_mu_group_create_one - create on group with a specific group of user
|
||||||
|
*
|
||||||
|
* @mu: pointer on MU info
|
||||||
|
* @nb_user: number of user to include in the group (<= CONFIG_USER_MAX)
|
||||||
|
* @users: table of users
|
||||||
|
*
|
||||||
|
* Try to create a new group with a specific group of users.
|
||||||
|
* 1- First it checks if a group containing all this users already exists.
|
||||||
|
*
|
||||||
|
* 2- Then it checks if it is possible to complete a group which already
|
||||||
|
* contains at least one user.
|
||||||
|
*
|
||||||
|
* 3- Finally it create a new group. To do so, it take take the last group of
|
||||||
|
* the active_groups list, remove all its current users and add the new ones
|
||||||
|
*
|
||||||
|
* In all cases, the group selected is moved at the top of the active_groups
|
||||||
|
* list
|
||||||
|
*
|
||||||
|
* @return 1 if a new group has been created and 0 otherwise
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int rwnx_mu_group_create_one(struct rwnx_mu_info *mu, int nb_user,
|
||||||
|
struct rwnx_sta **users, int *nb_group_left)
|
||||||
|
{
|
||||||
|
int i, group_id;
|
||||||
|
struct rwnx_mu_group *group;
|
||||||
|
u64 group_match;
|
||||||
|
u64 group_avail;
|
||||||
|
|
||||||
|
group_match = users[0]->group_info.map;
|
||||||
|
group_avail = users[0]->group_info.map;
|
||||||
|
for (i = 1; i < nb_user ; i++) {
|
||||||
|
group_match &= users[i]->group_info.map;
|
||||||
|
group_avail |= users[i]->group_info.map;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group_match) {
|
||||||
|
/* a group (or more) with all the users already exist */
|
||||||
|
group_id = RWNX_GET_FIRST_GROUP_ID(group_match);
|
||||||
|
group = rwnx_mu_group_from_id(mu, group_id);
|
||||||
|
rwnx_mu_group_move_head(&mu->active_groups, &group->list);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_USER_MAX > 2
|
||||||
|
if (group_avail) {
|
||||||
|
/* check if we can complete a group */
|
||||||
|
struct rwnx_sta *users2[CONFIG_USER_MAX];
|
||||||
|
int nb_user2;
|
||||||
|
|
||||||
|
group_for_each(group_id, group_avail) {
|
||||||
|
group = rwnx_mu_group_from_id(mu, group_id);
|
||||||
|
if (group->user_cnt == CONFIG_USER_MAX)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
nb_user2 = 0;
|
||||||
|
for (i = 0; i < nb_user ; i++) {
|
||||||
|
if (!(users[i]->group_info.map & BIT_ULL(group_id))) {
|
||||||
|
users2[nb_user2] = users[i];
|
||||||
|
nb_user2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((group->user_cnt + nb_user2) <= CONFIG_USER_MAX) {
|
||||||
|
rwnx_mu_group_add_users(mu, group, nb_user2, users2);
|
||||||
|
rwnx_mu_group_move_head(&mu->active_groups, &group->list);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_USER_MAX > 2*/
|
||||||
|
|
||||||
|
/* create a new group */
|
||||||
|
group = list_last_entry(&mu->active_groups, struct rwnx_mu_group, list);
|
||||||
|
rwnx_mu_group_remove_users(mu, group);
|
||||||
|
rwnx_mu_group_add_users(mu, group, nb_user, users);
|
||||||
|
rwnx_mu_group_move_head(&mu->active_groups, &group->list);
|
||||||
|
(*nb_group_left)--;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_mu_group_create - Create new groups containing one specific sta
|
||||||
|
*
|
||||||
|
* @mu: pointer on MU info
|
||||||
|
* @sta: sta to add in each group
|
||||||
|
* @nb_group_left: maximum number to new group allowed. (updated on exit)
|
||||||
|
*
|
||||||
|
* This will try to create "all the possible" group with a specific sta being
|
||||||
|
* a member of all these group.
|
||||||
|
* The function simply loops over the @active_sta list (starting from @sta).
|
||||||
|
* When it has (CONFIG_USER_MAX - 1) users it try to create a new group with
|
||||||
|
* these users (plus @sta).
|
||||||
|
* Loops end when there is no more users, or no more new group is allowed
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void rwnx_mu_group_create(struct rwnx_mu_info *mu, struct rwnx_sta *sta,
|
||||||
|
int *nb_group_left)
|
||||||
|
{
|
||||||
|
struct rwnx_sta *user_sta = sta;
|
||||||
|
struct rwnx_sta *users[CONFIG_USER_MAX];
|
||||||
|
int nb_user = 1;
|
||||||
|
|
||||||
|
users[0] = sta;
|
||||||
|
while (*nb_group_left) {
|
||||||
|
|
||||||
|
list_for_each_entry_continue(user_sta, &mu->active_sta, group_info.active) {
|
||||||
|
users[nb_user] = user_sta;
|
||||||
|
if (++nb_user == CONFIG_USER_MAX) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nb_user > 1) {
|
||||||
|
if (rwnx_mu_group_create_one(mu, nb_user, users, nb_group_left))
|
||||||
|
(*nb_group_left)--;
|
||||||
|
|
||||||
|
if (nb_user < CONFIG_USER_MAX)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
nb_user = 1;
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_mu_group_work - process function of the "group_work"
|
||||||
|
*
|
||||||
|
* The work is scheduled when several sta (MU beamformee capable) are active.
|
||||||
|
* When called, the @active_sta contains the list of the active sta (starting
|
||||||
|
* from the most recent one), and @active_groups is the list of all possible
|
||||||
|
* groups ordered so that the first one is the most recently used.
|
||||||
|
*
|
||||||
|
* This function will create new groups, starting from group containing the
|
||||||
|
* most "active" sta.
|
||||||
|
* For example if the list of sta is :
|
||||||
|
* sta8 -> sta3 -> sta4 -> sta7 -> sta1
|
||||||
|
* and the number of user per group is 3, it will create grooups :
|
||||||
|
* - sta8 / sta3 / sta4
|
||||||
|
* - sta8 / sta7 / sta1
|
||||||
|
* - sta3 / sta4 / sta7
|
||||||
|
* - sta3 / sta1
|
||||||
|
* - sta4 / sta7 / sta1
|
||||||
|
* - sta7 / sta1
|
||||||
|
*
|
||||||
|
* To create new group, the least used group are first selected.
|
||||||
|
* It is only allowed to create NX_MU_GROUP_MAX per iteration.
|
||||||
|
*
|
||||||
|
* Once groups have been updated, mu group information is update to the fw.
|
||||||
|
* To do so it use the @update_sta list to know which sta has been affected.
|
||||||
|
* As it is necessary to wait for fw confirmation before using this new group
|
||||||
|
* MU is temporarily disabled during group update
|
||||||
|
*
|
||||||
|
* Work is then rescheduled.
|
||||||
|
*
|
||||||
|
* At the end of the function, both @active_sta and @update_sta list are empty.
|
||||||
|
*
|
||||||
|
* Note:
|
||||||
|
* - This is still a WIP, and will require more tuning
|
||||||
|
* - not all combinations are created, to avoid to much processing.
|
||||||
|
* - reschedule delay should be adaptative
|
||||||
|
*/
|
||||||
|
void rwnx_mu_group_work(struct work_struct *ws)
|
||||||
|
{
|
||||||
|
struct delayed_work *dw = container_of(ws, struct delayed_work, work);
|
||||||
|
struct rwnx_mu_info *mu = container_of(dw, struct rwnx_mu_info, group_work);
|
||||||
|
struct rwnx_hw *rwnx_hw = container_of(mu, struct rwnx_hw, mu);
|
||||||
|
struct rwnx_sta *sta, *next;
|
||||||
|
int nb_group_left = NX_MU_GROUP_MAX;
|
||||||
|
|
||||||
|
if (WARN(!rwnx_hw->mod_params->mutx,
|
||||||
|
"In group formation work, but mutx disabled"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (down_interruptible(&mu->lock) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mu->update_count++;
|
||||||
|
if (!mu->update_count)
|
||||||
|
mu->update_count++;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(sta, next, &mu->active_sta, group_info.active) {
|
||||||
|
if (nb_group_left)
|
||||||
|
rwnx_mu_group_create(mu, sta, &nb_group_left);
|
||||||
|
|
||||||
|
sta->group_info.last_update = mu->update_count;
|
||||||
|
list_del(&sta->group_info.active);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! list_empty(&mu->update_sta)) {
|
||||||
|
list_for_each_entry_safe(sta, next, &mu->update_sta, group_info.update) {
|
||||||
|
rwnx_send_mu_group_update_req(rwnx_hw, sta);
|
||||||
|
list_del(&sta->group_info.update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mu->next_group_select = jiffies;
|
||||||
|
rwnx_mu_group_sta_select(rwnx_hw);
|
||||||
|
up(&mu->lock);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_mu_group_init - Initialize MU groups
|
||||||
|
*
|
||||||
|
* @rwnx_hw: main driver data
|
||||||
|
*
|
||||||
|
* Initialize all MU group
|
||||||
|
*/
|
||||||
|
void rwnx_mu_group_init(struct rwnx_hw *rwnx_hw)
|
||||||
|
{
|
||||||
|
struct rwnx_mu_info *mu = &rwnx_hw->mu;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&mu->active_groups);
|
||||||
|
INIT_LIST_HEAD(&mu->active_sta);
|
||||||
|
INIT_LIST_HEAD(&mu->update_sta);
|
||||||
|
|
||||||
|
for (i = 0; i < NX_MU_GROUP_MAX; i++) {
|
||||||
|
int j;
|
||||||
|
mu->groups[i].user_cnt = 0;
|
||||||
|
mu->groups[i].group_id = i + 1;
|
||||||
|
for (j = 0; j < CONFIG_USER_MAX; j++) {
|
||||||
|
mu->groups[i].users[j] = NULL;
|
||||||
|
}
|
||||||
|
list_add(&mu->groups[i].list, &mu->active_groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
mu->update_count = 1;
|
||||||
|
mu->group_cnt = 0;
|
||||||
|
mu->next_group_select = jiffies;
|
||||||
|
INIT_DELAYED_WORK(&mu->group_work, rwnx_mu_group_work);
|
||||||
|
sema_init(&mu->lock, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_mu_set_active_sta - mark a STA as active
|
||||||
|
*
|
||||||
|
* @rwnx_hw: main driver data
|
||||||
|
* @sta: pointer to the sta
|
||||||
|
* @traffic: Number of buffers to add in the sta's traffic counter
|
||||||
|
*
|
||||||
|
* If @sta is MU beamformee capable (and MU-MIMO tx is enabled) move the
|
||||||
|
* sta at the top of the @active_sta list.
|
||||||
|
* It also schedule the group_work if not already scheduled and the list
|
||||||
|
* contains more than one sta.
|
||||||
|
*
|
||||||
|
* If a STA was already in the list during the last group update
|
||||||
|
* (i.e. sta->group_info.last_update == mu->update_count) it is not added
|
||||||
|
* back to the list until a sta that wasn't active during the last update is
|
||||||
|
* added. This is to avoid scheduling group update with a list of sta that
|
||||||
|
* were all already in the list during previous update.
|
||||||
|
*
|
||||||
|
* It is called with mu->lock taken.
|
||||||
|
*/
|
||||||
|
void rwnx_mu_set_active_sta(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
|
||||||
|
int traffic)
|
||||||
|
{
|
||||||
|
struct rwnx_mu_info *mu = &rwnx_hw->mu;
|
||||||
|
|
||||||
|
if (!sta || (sta->group_info.map & RWNX_SU_GROUP))
|
||||||
|
return;
|
||||||
|
|
||||||
|
sta->group_info.traffic += traffic;
|
||||||
|
|
||||||
|
if ((sta->group_info.last_update != mu->update_count) ||
|
||||||
|
!list_empty(&mu->active_sta)) {
|
||||||
|
|
||||||
|
rwnx_mu_group_move_head(&mu->active_sta, &sta->group_info.active);
|
||||||
|
|
||||||
|
if (!delayed_work_pending(&mu->group_work) &&
|
||||||
|
!list_is_singular(&mu->active_sta)) {
|
||||||
|
schedule_delayed_work(&mu->group_work,
|
||||||
|
msecs_to_jiffies(RWNX_MU_GROUP_INTERVAL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_mu_set_active_group - mark a MU group as active
|
||||||
|
*
|
||||||
|
* @rwnx_hw: main driver data
|
||||||
|
* @group_id: Group id
|
||||||
|
*
|
||||||
|
* move a group at the top of the @active_groups list
|
||||||
|
*/
|
||||||
|
void rwnx_mu_set_active_group(struct rwnx_hw *rwnx_hw, int group_id)
|
||||||
|
{
|
||||||
|
struct rwnx_mu_info *mu = &rwnx_hw->mu;
|
||||||
|
struct rwnx_mu_group *group = rwnx_mu_group_from_id(mu, group_id);
|
||||||
|
|
||||||
|
rwnx_mu_group_move_head(&mu->active_groups, &group->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_mu_group_sta_select - Select the best group for MU stas
|
||||||
|
*
|
||||||
|
* @rwnx_hw: main driver data
|
||||||
|
*
|
||||||
|
* For each MU capable client of AP interfaces this function tries to select
|
||||||
|
* the best group to use.
|
||||||
|
*
|
||||||
|
* In first pass, gather information from all stations to form statistics
|
||||||
|
* for each group for the previous @RWNX_MU_GROUP_SELECT_INTERVAL interval:
|
||||||
|
* - number of buffers transmitted
|
||||||
|
* - number of user
|
||||||
|
*
|
||||||
|
* Then groups with more than 2 active users, are assigned after being ordered
|
||||||
|
* by traffic :
|
||||||
|
* - group with highest traffic is selected: set this group for all its users
|
||||||
|
* - update nb_users for all others group (as one sta may be in several groups)
|
||||||
|
* - select the next group that have still mor than 2 users and assign it.
|
||||||
|
* - continue until all group are processed
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void rwnx_mu_group_sta_select(struct rwnx_hw *rwnx_hw)
|
||||||
|
{
|
||||||
|
struct rwnx_mu_info *mu = &rwnx_hw->mu;
|
||||||
|
int nb_users[NX_MU_GROUP_MAX + 1];
|
||||||
|
int traffic[NX_MU_GROUP_MAX + 1];
|
||||||
|
int order[NX_MU_GROUP_MAX + 1];
|
||||||
|
struct rwnx_sta *sta;
|
||||||
|
struct rwnx_vif *vif;
|
||||||
|
struct list_head *head;
|
||||||
|
u64 map;
|
||||||
|
int i, j, update, group_id, tmp, cnt = 0;
|
||||||
|
|
||||||
|
if (!mu->group_cnt || time_before(jiffies, mu->next_group_select))
|
||||||
|
return;
|
||||||
|
|
||||||
|
list_for_each_entry(vif, &rwnx_hw->vifs, list) {
|
||||||
|
|
||||||
|
if (RWNX_VIF_TYPE(vif) != NL80211_IFTYPE_AP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
head = &vif->ap.sta_list;
|
||||||
|
#else
|
||||||
|
head = &vif->stations;
|
||||||
|
#endif /* CONFIG_RWNX_FULLMAC */
|
||||||
|
|
||||||
|
memset(nb_users, 0, sizeof(nb_users));
|
||||||
|
memset(traffic, 0, sizeof(traffic));
|
||||||
|
list_for_each_entry(sta, head, list) {
|
||||||
|
int sta_traffic = sta->group_info.traffic;
|
||||||
|
|
||||||
|
/* reset statistics for next selection */
|
||||||
|
sta->group_info.traffic = 0;
|
||||||
|
if (sta->group_info.group)
|
||||||
|
trace_mu_group_selection(sta, 0);
|
||||||
|
sta->group_info.group = 0;
|
||||||
|
|
||||||
|
if (sta->group_info.cnt == 0 ||
|
||||||
|
sta_traffic < RWNX_MU_GROUP_MIN_TRAFFIC)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
group_sta_for_each(sta, group_id, map) {
|
||||||
|
nb_users[group_id]++;
|
||||||
|
traffic[group_id] += sta_traffic;
|
||||||
|
|
||||||
|
/* list group with 2 users or more */
|
||||||
|
if (nb_users[group_id] == 2)
|
||||||
|
order[cnt++] = group_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reorder list of group with more that 2 users */
|
||||||
|
update = 1;
|
||||||
|
while(update) {
|
||||||
|
update = 0;
|
||||||
|
for (i = 0; i < cnt - 1; i++) {
|
||||||
|
if (traffic[order[i]] < traffic[order[i + 1]]) {
|
||||||
|
tmp = order[i];
|
||||||
|
order[i] = order[i + 1];
|
||||||
|
order[i + 1] = tmp;
|
||||||
|
update = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now assign group in traffic order */
|
||||||
|
for (i = 0; i < cnt ; i ++) {
|
||||||
|
struct rwnx_mu_group *group;
|
||||||
|
group_id = order[i];
|
||||||
|
|
||||||
|
if (nb_users[group_id] < 2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
group = rwnx_mu_group_from_id(mu, group_id);
|
||||||
|
for (j = 0; j < CONFIG_USER_MAX ; j++) {
|
||||||
|
if (group->users[j]) {
|
||||||
|
trace_mu_group_selection(group->users[j], group_id);
|
||||||
|
group->users[j]->group_info.group = group_id;
|
||||||
|
|
||||||
|
group_sta_for_each(group->users[j], tmp, map) {
|
||||||
|
if (group_id != tmp)
|
||||||
|
nb_users[tmp]--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mu->next_group_select = jiffies +
|
||||||
|
msecs_to_jiffies(RWNX_MU_GROUP_SELECT_INTERVAL);
|
||||||
|
mu->next_group_select |= 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_mu_group.h
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2016-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
#ifndef _RWNX_MU_GROUP_H_
|
||||||
|
#define _RWNX_MU_GROUP_H_
|
||||||
|
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
#include <linux/semaphore.h>
|
||||||
|
|
||||||
|
struct rwnx_hw;
|
||||||
|
struct rwnx_sta;
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_MUMIMO_TX
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_sta_group_info - Group Information for a STA
|
||||||
|
*
|
||||||
|
* @active: node for @mu->active_sta list
|
||||||
|
* @update: node for @mu->update_sta list
|
||||||
|
* @cnt: Number of groups the STA belongs to
|
||||||
|
* @map: Bitfield of groups the sta belongs to
|
||||||
|
* @traffic: Number of buffers sent since previous group selection
|
||||||
|
* @group: Id of the group selected by previous group selection
|
||||||
|
* (cf @rwnx_mu_group_sta_select)
|
||||||
|
*/
|
||||||
|
struct rwnx_sta_group_info {
|
||||||
|
struct list_head active;
|
||||||
|
struct list_head update;
|
||||||
|
u16 last_update;
|
||||||
|
int cnt;
|
||||||
|
u64 map;
|
||||||
|
int traffic;
|
||||||
|
u8 group;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct mu_group_info - Information about the users of a group
|
||||||
|
*
|
||||||
|
* @list: node for mu->active_groups
|
||||||
|
* @group_id: Group identifier
|
||||||
|
* @user_cnt: Number of the users in the group
|
||||||
|
* @users: Pointer to the sta, ordered by user position
|
||||||
|
*/
|
||||||
|
struct rwnx_mu_group {
|
||||||
|
struct list_head list;
|
||||||
|
int group_id;
|
||||||
|
int user_cnt;
|
||||||
|
struct rwnx_sta *users[CONFIG_USER_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_mu_info - Information about all MU group
|
||||||
|
*
|
||||||
|
* @active_groups: List of all possible groups. Ordered from the most recently
|
||||||
|
* used one to the least one (and possibly never used)
|
||||||
|
* @active_sta: List of MU beamformee sta that have been active (since previous
|
||||||
|
* group update). Ordered from the most recently active.
|
||||||
|
* @update_sta: List of sta whose group information has changed and need to be
|
||||||
|
* updated at fw level
|
||||||
|
* @groups: Table of all groups
|
||||||
|
* @group_work: Work item used to schedule group update
|
||||||
|
* @update_count: Counter used to identify the last group formation update.
|
||||||
|
* (cf rwnx_sta_group_info.last_update)
|
||||||
|
* @lock: Lock taken during group update. If tx happens lock is taken, then tx
|
||||||
|
* will not used MU.
|
||||||
|
* @next_group_assign: Next time the group selection should be run
|
||||||
|
* (ref @rwnx_mu_group_sta_select)
|
||||||
|
* @group_cnt: Number of group created
|
||||||
|
*/
|
||||||
|
struct rwnx_mu_info {
|
||||||
|
struct list_head active_groups;
|
||||||
|
struct list_head active_sta;
|
||||||
|
struct list_head update_sta;
|
||||||
|
struct rwnx_mu_group groups[NX_MU_GROUP_MAX];
|
||||||
|
struct delayed_work group_work;
|
||||||
|
u16 update_count;
|
||||||
|
struct semaphore lock;
|
||||||
|
unsigned long next_group_select;
|
||||||
|
u8 group_cnt;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RWNX_SU_GROUP BIT_ULL(0)
|
||||||
|
#define RWNX_MU_GROUP_MASK 0x7ffffffffffffffeULL
|
||||||
|
#define RWNX_MU_GROUP_INTERVAL 200 /* in ms */
|
||||||
|
#define RWNX_MU_GROUP_SELECT_INTERVAL 100 /* in ms */
|
||||||
|
// minimum traffic in a RWNX_MU_GROUP_SELECT_INTERVAL to consider the sta
|
||||||
|
#define RWNX_MU_GROUP_MIN_TRAFFIC 50 /* in number of packet */
|
||||||
|
|
||||||
|
|
||||||
|
#define RWNX_GET_FIRST_GROUP_ID(map) (fls64(map) - 1)
|
||||||
|
|
||||||
|
#define group_sta_for_each(sta, id, map) \
|
||||||
|
map = sta->group_info.map & RWNX_MU_GROUP_MASK; \
|
||||||
|
for (id = (fls64(map) - 1) ; id > 0 ; \
|
||||||
|
map &= ~(u64)BIT_ULL(id), id = (fls64(map) - 1))
|
||||||
|
|
||||||
|
#define group_for_each(id, map) \
|
||||||
|
for (id = (fls64(map) - 1) ; id > 0 ; \
|
||||||
|
map &= ~(u64)BIT_ULL(id), id = (fls64(map) - 1))
|
||||||
|
|
||||||
|
#define RWNX_MUMIMO_INFO_POS_ID(info) (((info) >> 6) & 0x3)
|
||||||
|
#define RWNX_MUMIMO_INFO_GROUP_ID(info) ((info) & 0x3f)
|
||||||
|
|
||||||
|
static inline
|
||||||
|
struct rwnx_mu_group *rwnx_mu_group_from_id(struct rwnx_mu_info *mu, int id)
|
||||||
|
{
|
||||||
|
if (id > NX_MU_GROUP_MAX)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return &mu->groups[id - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void rwnx_mu_group_sta_init(struct rwnx_sta *sta,
|
||||||
|
const struct ieee80211_vht_cap *vht_cap);
|
||||||
|
void rwnx_mu_group_sta_del(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta);
|
||||||
|
u64 rwnx_mu_group_sta_get_map(struct rwnx_sta *sta);
|
||||||
|
int rwnx_mu_group_sta_get_pos(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
|
||||||
|
int group_id);
|
||||||
|
|
||||||
|
void rwnx_mu_group_init(struct rwnx_hw *rwnx_hw);
|
||||||
|
|
||||||
|
void rwnx_mu_set_active_sta(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
|
||||||
|
int traffic);
|
||||||
|
void rwnx_mu_set_active_group(struct rwnx_hw *rwnx_hw, int group_id);
|
||||||
|
void rwnx_mu_group_sta_select(struct rwnx_hw *rwnx_hw);
|
||||||
|
|
||||||
|
|
||||||
|
#else /* ! CONFIG_RWNX_MUMIMO_TX */
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void rwnx_mu_group_sta_init(struct rwnx_sta *sta,
|
||||||
|
const struct ieee80211_vht_cap *vht_cap)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void rwnx_mu_group_sta_del(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
u64 rwnx_mu_group_sta_get_map(struct rwnx_sta *sta)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
int rwnx_mu_group_sta_get_pos(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
|
||||||
|
int group_id)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void rwnx_mu_group_init(struct rwnx_hw *rwnx_hw)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void rwnx_mu_set_active_sta(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
|
||||||
|
int traffic)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void rwnx_mu_set_active_group(struct rwnx_hw *rwnx_hw, int group_id)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void rwnx_mu_group_sta_select(struct rwnx_hw *rwnx_hw)
|
||||||
|
{}
|
||||||
|
|
||||||
|
#endif /* CONFIG_RWNX_MUMIMO_TX */
|
||||||
|
|
||||||
|
#endif /* _RWNX_MU_GROUP_H_ */
|
||||||
|
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_pci.c
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
|
||||||
|
#include "rwnx_defs.h"
|
||||||
|
#include "rwnx_dini.h"
|
||||||
|
#include "rwnx_v7.h"
|
||||||
|
|
||||||
|
#define PCI_VENDOR_ID_DINIGROUP 0x17DF
|
||||||
|
#define PCI_DEVICE_ID_DINIGROUP_DNV6_F2PCIE 0x1907
|
||||||
|
|
||||||
|
#define PCI_DEVICE_ID_XILINX_CEVA_VIRTEX7 0x7011
|
||||||
|
|
||||||
|
static const struct pci_device_id rwnx_pci_ids[] = {
|
||||||
|
{PCI_DEVICE(PCI_VENDOR_ID_DINIGROUP, PCI_DEVICE_ID_DINIGROUP_DNV6_F2PCIE)},
|
||||||
|
{PCI_DEVICE(PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_XILINX_CEVA_VIRTEX7)},
|
||||||
|
{0,}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Uncomment this for depmod to create module alias */
|
||||||
|
/* We don't want this on development platform */
|
||||||
|
//MODULE_DEVICE_TABLE(pci, rwnx_pci_ids);
|
||||||
|
|
||||||
|
static int rwnx_pci_probe(struct pci_dev *pci_dev,
|
||||||
|
const struct pci_device_id *pci_id)
|
||||||
|
{
|
||||||
|
struct rwnx_plat *rwnx_plat = NULL;
|
||||||
|
void *drvdata;
|
||||||
|
int ret = -ENODEV;
|
||||||
|
|
||||||
|
RWNX_DBG(RWNX_FN_ENTRY_STR);
|
||||||
|
|
||||||
|
if (pci_id->vendor == PCI_VENDOR_ID_DINIGROUP) {
|
||||||
|
ret = rwnx_dini_platform_init(pci_dev, &rwnx_plat);
|
||||||
|
} else if (pci_id->vendor == PCI_VENDOR_ID_XILINX) {
|
||||||
|
ret = rwnx_v7_platform_init(pci_dev, &rwnx_plat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
rwnx_plat->pci_dev = pci_dev;
|
||||||
|
|
||||||
|
ret = rwnx_platform_init(rwnx_plat, &drvdata);
|
||||||
|
pci_set_drvdata(pci_dev, drvdata);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
rwnx_plat->deinit(rwnx_plat);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rwnx_pci_remove(struct pci_dev *pci_dev)
|
||||||
|
{
|
||||||
|
struct rwnx_hw *rwnx_hw;
|
||||||
|
struct rwnx_plat *rwnx_plat;
|
||||||
|
|
||||||
|
RWNX_DBG(RWNX_FN_ENTRY_STR);
|
||||||
|
|
||||||
|
rwnx_hw = pci_get_drvdata(pci_dev);
|
||||||
|
rwnx_plat = rwnx_hw->plat;
|
||||||
|
|
||||||
|
rwnx_platform_deinit(rwnx_hw);
|
||||||
|
rwnx_plat->deinit(rwnx_plat);
|
||||||
|
|
||||||
|
pci_set_drvdata(pci_dev, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct pci_driver rwnx_pci_drv = {
|
||||||
|
.name = KBUILD_MODNAME,
|
||||||
|
.id_table = rwnx_pci_ids,
|
||||||
|
.probe = rwnx_pci_probe,
|
||||||
|
.remove = rwnx_pci_remove
|
||||||
|
};
|
||||||
|
|
||||||
|
int rwnx_pci_register_drv(void)
|
||||||
|
{
|
||||||
|
return pci_register_driver(&rwnx_pci_drv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rwnx_pci_unregister_drv(void)
|
||||||
|
{
|
||||||
|
pci_unregister_driver(&rwnx_pci_drv);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_pci.h
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RWNX_PCI_H_
|
||||||
|
#define _RWNX_PCI_H_
|
||||||
|
|
||||||
|
int rwnx_pci_register_drv(void);
|
||||||
|
void rwnx_pci_unregister_drv(void);
|
||||||
|
|
||||||
|
#endif /* _RWNX_PCI_H_ */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,152 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_platorm.h
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RWNX_PLATFORM_H_
|
||||||
|
#define _RWNX_PLATFORM_H_
|
||||||
|
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include "lmac_msg.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define RWNX_CONFIG_FW_NAME "rwnx_settings.ini"
|
||||||
|
#define RWNX_PHY_CONFIG_TRD_NAME "rwnx_trident.ini"
|
||||||
|
#define RWNX_PHY_CONFIG_KARST_NAME "rwnx_karst.ini"
|
||||||
|
#define RWNX_AGC_FW_NAME "agcram.bin"
|
||||||
|
#define RWNX_LDPC_RAM_NAME "ldpcram.bin"
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
#define RWNX_MAC_FW_BASE_NAME "fmacfw"
|
||||||
|
#elif defined CONFIG_RWNX_FHOST
|
||||||
|
#define RWNX_MAC_FW_BASE_NAME "fhostfw"
|
||||||
|
#endif /* CONFIG_RWNX_FULLMAC */
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_TL4
|
||||||
|
#define RWNX_MAC_FW_NAME RWNX_MAC_FW_BASE_NAME".hex"
|
||||||
|
#else
|
||||||
|
#define RWNX_MAC_FW_NAME RWNX_MAC_FW_BASE_NAME".ihex"
|
||||||
|
#define RWNX_MAC_FW_NAME2 RWNX_MAC_FW_BASE_NAME".bin"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define RWNX_FCU_FW_NAME "fcuram.bin"
|
||||||
|
#if (defined(CONFIG_DPD) && !defined(CONFIG_FORCE_DPD_CALIB))
|
||||||
|
#define FW_DPDRESULT_NAME_8800DC "aic_dpdresult_lite_8800dc.bin"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define POWER_LEVEL_INVALID_VAL (127)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FW_NORMAL_MODE = 0,
|
||||||
|
FW_RFTEST_MODE = 1,
|
||||||
|
FW_BLE_SCAN_WAKEUP_MODE = 2,
|
||||||
|
FW_M2D_OTA_MODE = 3,
|
||||||
|
FW_DPDCALIB_MODE = 4,
|
||||||
|
FW_BLE_SCAN_AD_FILTER_MODE = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of memory to access (cf rwnx_plat.get_address)
|
||||||
|
*
|
||||||
|
* @RWNX_ADDR_CPU To access memory of the embedded CPU
|
||||||
|
* @RWNX_ADDR_SYSTEM To access memory/registers of one subsystem of the
|
||||||
|
* embedded system
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
enum rwnx_platform_addr {
|
||||||
|
RWNX_ADDR_CPU,
|
||||||
|
RWNX_ADDR_SYSTEM,
|
||||||
|
RWNX_ADDR_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rwnx_hw;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_plat - Operation pointers for RWNX PCI platform
|
||||||
|
*
|
||||||
|
* @pci_dev: pointer to pci dev
|
||||||
|
* @enabled: Set if embedded platform has been enabled (i.e. fw loaded and
|
||||||
|
* ipc started)
|
||||||
|
* @enable: Configure communication with the fw (i.e. configure the transfers
|
||||||
|
* enable and register interrupt)
|
||||||
|
* @disable: Stop communication with the fw
|
||||||
|
* @deinit: Free all ressources allocated for the embedded platform
|
||||||
|
* @get_address: Return the virtual address to access the requested address on
|
||||||
|
* the platform.
|
||||||
|
* @ack_irq: Acknowledge the irq at link level.
|
||||||
|
* @get_config_reg: Return the list (size + pointer) of registers to restore in
|
||||||
|
* order to reload the platform while keeping the current configuration.
|
||||||
|
*
|
||||||
|
* @priv Private data for the link driver
|
||||||
|
*/
|
||||||
|
struct rwnx_plat {
|
||||||
|
struct pci_dev *pci_dev;
|
||||||
|
|
||||||
|
#ifdef AICWF_SDIO_SUPPORT
|
||||||
|
struct aic_sdio_dev *sdiodev;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef AICWF_USB_SUPPORT
|
||||||
|
struct aic_usb_dev *usbdev;
|
||||||
|
#endif
|
||||||
|
bool enabled;
|
||||||
|
bool wait_disconnect_cb;
|
||||||
|
|
||||||
|
int (*enable)(struct rwnx_hw *rwnx_hw);
|
||||||
|
int (*disable)(struct rwnx_hw *rwnx_hw);
|
||||||
|
void (*deinit)(struct rwnx_plat *rwnx_plat);
|
||||||
|
u8* (*get_address)(struct rwnx_plat *rwnx_plat, int addr_name,
|
||||||
|
unsigned int offset);
|
||||||
|
void (*ack_irq)(struct rwnx_plat *rwnx_plat);
|
||||||
|
int (*get_config_reg)(struct rwnx_plat *rwnx_plat, const u32 **list);
|
||||||
|
|
||||||
|
u8 priv[0] __aligned(sizeof(void *));
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RWNX_ADDR(plat, base, offset) \
|
||||||
|
plat->get_address(plat, base, offset)
|
||||||
|
|
||||||
|
#define RWNX_REG_READ(plat, base, offset) \
|
||||||
|
readl(plat->get_address(plat, base, offset))
|
||||||
|
|
||||||
|
#define RWNX_REG_WRITE(val, plat, base, offset) \
|
||||||
|
writel(val, plat->get_address(plat, base, offset))
|
||||||
|
|
||||||
|
extern struct rwnx_plat *g_rwnx_plat;
|
||||||
|
|
||||||
|
int rwnx_platform_init(struct rwnx_plat *rwnx_plat, void **platform_data);
|
||||||
|
void rwnx_platform_deinit(struct rwnx_hw *rwnx_hw);
|
||||||
|
|
||||||
|
int rwnx_platform_on(struct rwnx_hw *rwnx_hw, void *config);
|
||||||
|
void rwnx_platform_off(struct rwnx_hw *rwnx_hw, void **config);
|
||||||
|
|
||||||
|
int is_file_exist(char* name);
|
||||||
|
void get_userconfig_txpwr_lvl_in_fdrv(txpwr_lvl_conf_t *txpwr_lvl);
|
||||||
|
void get_userconfig_txpwr_lvl_v2_in_fdrv(txpwr_lvl_conf_v2_t *txpwr_lvl_v2);
|
||||||
|
void get_userconfig_txpwr_lvl_v3_in_fdrv(txpwr_lvl_conf_v3_t *txpwr_lvl_v3);
|
||||||
|
void get_userconfig_txpwr_lvl_adj_in_fdrv(txpwr_lvl_adj_conf_t *txpwr_lvl_adj);
|
||||||
|
void get_userconfig_txpwr_ofst_in_fdrv(txpwr_ofst_conf_t *txpwr_ofst);
|
||||||
|
void get_userconfig_txpwr_ofst2x_in_fdrv(txpwr_ofst2x_conf_t *txpwr_ofst2x);
|
||||||
|
void get_userconfig_txpwr_loss(txpwr_loss_conf_t *txpwr_loss);
|
||||||
|
void rwnx_plat_userconfig_parsing(char *buffer, int size);
|
||||||
|
#ifdef CONFIG_POWER_LIMIT
|
||||||
|
void rwnx_plat_powerlimit_parsing(char *buffer, int size, char *cc);
|
||||||
|
int8_t get_powerlimit_by_freq(uint8_t band, uint16_t freq);
|
||||||
|
int8_t get_powerlimit_by_chnum(uint8_t chnum);
|
||||||
|
#endif
|
||||||
|
int rwnx_platform_register_drv(void);
|
||||||
|
void rwnx_platform_unregister_drv(void);
|
||||||
|
|
||||||
|
extern struct device *rwnx_platform_get_dev(struct rwnx_plat *rwnx_plat);
|
||||||
|
|
||||||
|
static inline unsigned int rwnx_platform_get_irq(struct rwnx_plat *rwnx_plat)
|
||||||
|
{
|
||||||
|
return rwnx_plat->pci_dev->irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _RWNX_PLATFORM_H_ */
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_prof.h
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RWNX_PROF_H_
|
||||||
|
#define _RWNX_PROF_H_
|
||||||
|
|
||||||
|
#include "reg_access.h"
|
||||||
|
#include "rwnx_platform.h"
|
||||||
|
|
||||||
|
static inline void rwnx_prof_set(struct rwnx_hw *rwnx_hw, int val)
|
||||||
|
{
|
||||||
|
struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
|
||||||
|
RWNX_REG_WRITE(val, rwnx_plat, RWNX_ADDR_SYSTEM, NXMAC_SW_SET_PROFILING_ADDR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void rwnx_prof_clear(struct rwnx_hw *rwnx_hw, int val)
|
||||||
|
{
|
||||||
|
struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
|
||||||
|
RWNX_REG_WRITE(val, rwnx_plat, RWNX_ADDR_SYSTEM, NXMAC_SW_CLEAR_PROFILING_ADDR);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* Defines for SW Profiling registers values */
|
||||||
|
enum {
|
||||||
|
TX_IPC_IRQ,
|
||||||
|
TX_IPC_EVT,
|
||||||
|
TX_PREP_EVT,
|
||||||
|
TX_DMA_IRQ,
|
||||||
|
TX_MAC_IRQ,
|
||||||
|
TX_PAYL_HDL,
|
||||||
|
TX_CFM_EVT,
|
||||||
|
TX_IPC_CFM,
|
||||||
|
RX_MAC_IRQ, // 8
|
||||||
|
RX_TRIGGER_EVT,
|
||||||
|
RX_DMA_IRQ,
|
||||||
|
RX_DMA_EVT,
|
||||||
|
RX_IPC_IND,
|
||||||
|
RX_MPDU_XFER,
|
||||||
|
DBG_PROF_MAX
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SW_PROF_HOSTBUF_IDX = 12,
|
||||||
|
/****** IPC IRQs related signals ******/
|
||||||
|
/* E2A direction */
|
||||||
|
SW_PROF_IRQ_E2A_RXDESC = 16, // to make sure we let 16 bits available for LMAC FW
|
||||||
|
SW_PROF_IRQ_E2A_TXCFM,
|
||||||
|
SW_PROF_IRQ_E2A_DBG,
|
||||||
|
SW_PROF_IRQ_E2A_MSG,
|
||||||
|
SW_PROF_IPC_MSGPUSH,
|
||||||
|
SW_PROF_MSGALLOC,
|
||||||
|
SW_PROF_MSGIND,
|
||||||
|
SW_PROF_DBGIND,
|
||||||
|
|
||||||
|
/* A2E direction */
|
||||||
|
SW_PROF_IRQ_A2E_TXCFM_BACK,
|
||||||
|
|
||||||
|
/****** Driver functions related signals ******/
|
||||||
|
SW_PROF_WAIT_QUEUE_STOP,
|
||||||
|
SW_PROF_WAIT_QUEUE_WAKEUP,
|
||||||
|
SW_PROF_RWNXDATAIND,
|
||||||
|
SW_PROF_RWNX_IPC_IRQ_HDLR,
|
||||||
|
SW_PROF_RWNX_IPC_THR_IRQ_HDLR,
|
||||||
|
SW_PROF_IEEE80211RX,
|
||||||
|
SW_PROF_RWNX_PATTERN,
|
||||||
|
SW_PROF_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
// [LT]For debug purpose only
|
||||||
|
#if (0)
|
||||||
|
#define SW_PROF_CHAN_CTXT_CFM_HDL_BIT (21)
|
||||||
|
#define SW_PROF_CHAN_CTXT_CFM_BIT (22)
|
||||||
|
#define SW_PROF_CHAN_CTXT_CFM_SWDONE_BIT (23)
|
||||||
|
#define SW_PROF_CHAN_CTXT_PUSH_BIT (24)
|
||||||
|
#define SW_PROF_CHAN_CTXT_QUEUE_BIT (25)
|
||||||
|
#define SW_PROF_CHAN_CTXT_TX_BIT (26)
|
||||||
|
#define SW_PROF_CHAN_CTXT_TX_PAUSE_BIT (27)
|
||||||
|
#define SW_PROF_CHAN_CTXT_PSWTCH_BIT (28)
|
||||||
|
#define SW_PROF_CHAN_CTXT_SWTCH_BIT (29)
|
||||||
|
|
||||||
|
// TO DO: update this
|
||||||
|
|
||||||
|
#define REG_SW_SET_PROFILING_CHAN(env, bit) \
|
||||||
|
rwnx_prof_set((struct rwnx_hw*)env, BIT(bit))
|
||||||
|
|
||||||
|
#define REG_SW_CLEAR_PROFILING_CHAN(env, bit) \
|
||||||
|
rwnx_prof_clear((struct rwnx_hw*)env, BIT(bit))
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define SW_PROF_CHAN_CTXT_CFM_HDL_BIT (0)
|
||||||
|
#define SW_PROF_CHAN_CTXT_CFM_BIT (0)
|
||||||
|
#define SW_PROF_CHAN_CTXT_CFM_SWDONE_BIT (0)
|
||||||
|
#define SW_PROF_CHAN_CTXT_PUSH_BIT (0)
|
||||||
|
#define SW_PROF_CHAN_CTXT_QUEUE_BIT (0)
|
||||||
|
#define SW_PROF_CHAN_CTXT_TX_BIT (0)
|
||||||
|
#define SW_PROF_CHAN_CTXT_TX_PAUSE_BIT (0)
|
||||||
|
#define SW_PROF_CHAN_CTXT_PSWTCH_BIT (0)
|
||||||
|
#define SW_PROF_CHAN_CTXT_SWTCH_BIT (0)
|
||||||
|
|
||||||
|
#define REG_SW_SET_PROFILING_CHAN(env, bit) do {} while (0)
|
||||||
|
#define REG_SW_CLEAR_PROFILING_CHAN(env, bit) do {} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_SW_PROFILING
|
||||||
|
/* Macros for SW PRofiling registers access */
|
||||||
|
#define REG_SW_SET_PROFILING(env, bit) \
|
||||||
|
rwnx_prof_set((struct rwnx_hw*)env, BIT(bit))
|
||||||
|
|
||||||
|
#define REG_SW_SET_HOSTBUF_IDX_PROFILING(env, val) \
|
||||||
|
rwnx_prof_set((struct rwnx_hw*)env, val<<(SW_PROF_HOSTBUF_IDX))
|
||||||
|
|
||||||
|
#define REG_SW_CLEAR_PROFILING(env, bit) \
|
||||||
|
rwnx_prof_clear((struct rwnx_hw*)env, BIT(bit))
|
||||||
|
|
||||||
|
#define REG_SW_CLEAR_HOSTBUF_IDX_PROFILING(env) \
|
||||||
|
rwnx_prof_clear((struct rwnx_hw*)env,0x0F<<(SW_PROF_HOSTBUF_IDX))
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define REG_SW_SET_PROFILING(env, value) do {} while (0)
|
||||||
|
#define REG_SW_CLEAR_PROFILING(env, value) do {} while (0)
|
||||||
|
#define REG_SW_SET_HOSTBUF_IDX_PROFILING(env, val) do {} while (0)
|
||||||
|
#define REG_SW_CLEAR_HOSTBUF_IDX_PROFILING(env) do {} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _RWNX_PROF_H_ */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,160 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_radar.h
|
||||||
|
*
|
||||||
|
* @brief Functions to handle radar detection
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
#ifndef _RWNX_RADAR_H_
|
||||||
|
#define _RWNX_RADAR_H_
|
||||||
|
|
||||||
|
#include <linux/nl80211.h>
|
||||||
|
|
||||||
|
struct rwnx_vif;
|
||||||
|
struct rwnx_hw;
|
||||||
|
|
||||||
|
enum rwnx_radar_chain {
|
||||||
|
RWNX_RADAR_RIU = 0,
|
||||||
|
RWNX_RADAR_FCU,
|
||||||
|
RWNX_RADAR_LAST
|
||||||
|
};
|
||||||
|
|
||||||
|
enum rwnx_radar_detector {
|
||||||
|
RWNX_RADAR_DETECT_DISABLE = 0, /* Ignore radar pulses */
|
||||||
|
RWNX_RADAR_DETECT_ENABLE = 1, /* Process pattern detection but do not
|
||||||
|
report radar to upper layer (for test) */
|
||||||
|
RWNX_RADAR_DETECT_REPORT = 2 /* Process pattern detection and report
|
||||||
|
radar to upper layer. */
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_RADAR
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
|
#define RWNX_RADAR_PULSE_MAX 32
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_radar_pulses - List of pulses reported by HW
|
||||||
|
* @index: write index
|
||||||
|
* @count: number of valid pulses
|
||||||
|
* @buffer: buffer of pulses
|
||||||
|
*/
|
||||||
|
struct rwnx_radar_pulses {
|
||||||
|
/* Last radar pulses received */
|
||||||
|
int index;
|
||||||
|
int count;
|
||||||
|
u32 buffer[RWNX_RADAR_PULSE_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct dfs_pattern_detector - DFS pattern detector
|
||||||
|
* @region: active DFS region, NL80211_DFS_UNSET until set
|
||||||
|
* @num_radar_types: number of different radar types
|
||||||
|
* @last_pulse_ts: time stamp of last valid pulse in usecs
|
||||||
|
* @prev_jiffies:
|
||||||
|
* @radar_detector_specs: array of radar detection specs
|
||||||
|
* @channel_detectors: list connecting channel_detector elements
|
||||||
|
*/
|
||||||
|
struct dfs_pattern_detector {
|
||||||
|
u8 enabled;
|
||||||
|
enum nl80211_dfs_regions region;
|
||||||
|
u8 num_radar_types;
|
||||||
|
u64 last_pulse_ts;
|
||||||
|
u32 prev_jiffies;
|
||||||
|
const struct radar_detector_specs *radar_spec;
|
||||||
|
struct list_head detectors[];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NX_NB_RADAR_DETECTED 4
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_radar_detected - List of radar detected
|
||||||
|
*/
|
||||||
|
struct rwnx_radar_detected {
|
||||||
|
u16 index;
|
||||||
|
u16 count;
|
||||||
|
s64 time[NX_NB_RADAR_DETECTED];
|
||||||
|
s16 freq[NX_NB_RADAR_DETECTED];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct rwnx_radar {
|
||||||
|
struct rwnx_radar_pulses pulses[RWNX_RADAR_LAST];
|
||||||
|
struct dfs_pattern_detector *dpd[RWNX_RADAR_LAST];
|
||||||
|
struct rwnx_radar_detected detected[RWNX_RADAR_LAST];
|
||||||
|
struct work_struct detection_work; /* Work used to process radar pulses */
|
||||||
|
spinlock_t lock; /* lock for pulses processing */
|
||||||
|
|
||||||
|
/* In softmac cac is handled by mac80211 */
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
struct delayed_work cac_work; /* Work used to handle CAC */
|
||||||
|
struct rwnx_vif *cac_vif; /* vif on which we started CAC */
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
bool rwnx_radar_detection_init(struct rwnx_radar *radar);
|
||||||
|
void rwnx_radar_detection_deinit(struct rwnx_radar *radar);
|
||||||
|
bool rwnx_radar_set_domain(struct rwnx_radar *radar,
|
||||||
|
enum nl80211_dfs_regions region);
|
||||||
|
void rwnx_radar_detection_enable(struct rwnx_radar *radar, u8 enable, u8 chain);
|
||||||
|
bool rwnx_radar_detection_is_enable(struct rwnx_radar *radar, u8 chain);
|
||||||
|
void rwnx_radar_start_cac(struct rwnx_radar *radar, u32 cac_time_ms,
|
||||||
|
struct rwnx_vif *vif);
|
||||||
|
void rwnx_radar_cancel_cac(struct rwnx_radar *radar);
|
||||||
|
void rwnx_radar_detection_enable_on_cur_channel(struct rwnx_hw *rwnx_hw);
|
||||||
|
int rwnx_radar_dump_pattern_detector(char *buf, size_t len,
|
||||||
|
struct rwnx_radar *radar, u8 chain);
|
||||||
|
int rwnx_radar_dump_radar_detected(char *buf, size_t len,
|
||||||
|
struct rwnx_radar *radar, u8 chain);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
struct rwnx_radar {
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline bool rwnx_radar_detection_init(struct rwnx_radar *radar)
|
||||||
|
{return true;}
|
||||||
|
|
||||||
|
static inline void rwnx_radar_detection_deinit(struct rwnx_radar *radar)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static inline bool rwnx_radar_set_domain(struct rwnx_radar *radar,
|
||||||
|
enum nl80211_dfs_regions region)
|
||||||
|
{return true;}
|
||||||
|
|
||||||
|
static inline void rwnx_radar_detection_enable(struct rwnx_radar *radar,
|
||||||
|
u8 enable, u8 chain)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static inline bool rwnx_radar_detection_is_enable(struct rwnx_radar *radar,
|
||||||
|
u8 chain)
|
||||||
|
{return false;}
|
||||||
|
|
||||||
|
static inline void rwnx_radar_start_cac(struct rwnx_radar *radar,
|
||||||
|
u32 cac_time_ms, struct rwnx_vif *vif)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static inline void rwnx_radar_cancel_cac(struct rwnx_radar *radar)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static inline void rwnx_radar_detection_enable_on_cur_channel(struct rwnx_hw *rwnx_hw)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static inline int rwnx_radar_dump_pattern_detector(char *buf, size_t len,
|
||||||
|
struct rwnx_radar *radar,
|
||||||
|
u8 chain)
|
||||||
|
{return 0;}
|
||||||
|
|
||||||
|
static inline int rwnx_radar_dump_radar_detected(char *buf, size_t len,
|
||||||
|
struct rwnx_radar *radar,
|
||||||
|
u8 chain)
|
||||||
|
{return 0;}
|
||||||
|
|
||||||
|
#endif /* CONFIG_RWNX_RADAR */
|
||||||
|
|
||||||
|
#endif // _RWNX_RADAR_H_
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,402 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_rx.h
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
#ifndef _RWNX_RX_H_
|
||||||
|
#define _RWNX_RX_H_
|
||||||
|
|
||||||
|
#include "aicwf_txrxif.h"
|
||||||
|
|
||||||
|
#define SERVER_PORT 67
|
||||||
|
#define CLIENT_PORT 68
|
||||||
|
#define DHCP_MAGIC 0x63825363
|
||||||
|
#define DHCP_ACK 5
|
||||||
|
#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */
|
||||||
|
#define DHCP_OPTION_END 255
|
||||||
|
|
||||||
|
enum rx_status_bits
|
||||||
|
{
|
||||||
|
/// The buffer can be forwarded to the networking stack
|
||||||
|
RX_STAT_FORWARD = 1 << 0,
|
||||||
|
/// A new buffer has to be allocated
|
||||||
|
RX_STAT_ALLOC = 1 << 1,
|
||||||
|
/// The buffer has to be deleted
|
||||||
|
RX_STAT_DELETE = 1 << 2,
|
||||||
|
/// The length of the buffer has to be updated
|
||||||
|
RX_STAT_LEN_UPDATE = 1 << 3,
|
||||||
|
/// The length in the Ethernet header has to be updated
|
||||||
|
RX_STAT_ETH_LEN_UPDATE = 1 << 4,
|
||||||
|
/// Simple copy
|
||||||
|
RX_STAT_COPY = 1 << 5,
|
||||||
|
/// Spurious frame (inform upper layer and discard)
|
||||||
|
RX_STAT_SPURIOUS = 1 << 6,
|
||||||
|
/// packet for monitor interface
|
||||||
|
RX_STAT_MONITOR = 1 << 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decryption status subfields.
|
||||||
|
* {
|
||||||
|
*/
|
||||||
|
#define RWNX_RX_HD_DECR_UNENC 0 // ENCRYPTION TYPE NONE
|
||||||
|
#define RWNX_RX_HD_DECR_WEP 1 // ENCRYPTION TYPE WEP
|
||||||
|
#define RWNX_RX_HD_DECR_TKIP 2 // ENCRYPTION TYPE TKIP
|
||||||
|
#define RWNX_RX_HD_DECR_CCMP128 3 // ENCRYPTION TYPE CCMP128
|
||||||
|
#define RWNX_RX_HD_DECR_CCMP256 4 // ENCRYPTION TYPE CCMP256
|
||||||
|
#define RWNX_RX_HD_DECR_GCMP128 5 // ENCRYPTION TYPE GCMP128
|
||||||
|
#define RWNX_RX_HD_DECR_GCMP256 6 // ENCRYPTION TYPE GCMP256
|
||||||
|
#define RWNX_RX_HD_DECR_WAPI 7 // ENCRYPTION TYPE WAPI
|
||||||
|
// @}
|
||||||
|
|
||||||
|
//#ifdef CONFIG_RWNX_MON_DATA
|
||||||
|
#if 0
|
||||||
|
#define RX_MACHDR_BACKUP_LEN 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct rx_vector_1_old {
|
||||||
|
/** Receive Vector 1a */
|
||||||
|
u32 leg_length :12;
|
||||||
|
u32 leg_rate : 4;
|
||||||
|
u32 ht_length :16;
|
||||||
|
|
||||||
|
/** Receive Vector 1b */
|
||||||
|
u32 _ht_length : 4; // FIXME
|
||||||
|
u32 short_gi : 1;
|
||||||
|
u32 stbc : 2;
|
||||||
|
u32 smoothing : 1;
|
||||||
|
u32 mcs : 7;
|
||||||
|
u32 pre_type : 1;
|
||||||
|
u32 format_mod : 3;
|
||||||
|
u32 ch_bw : 2;
|
||||||
|
u32 n_sts : 3;
|
||||||
|
u32 lsig_valid : 1;
|
||||||
|
u32 sounding : 1;
|
||||||
|
u32 num_extn_ss : 2;
|
||||||
|
u32 aggregation : 1;
|
||||||
|
u32 fec_coding : 1;
|
||||||
|
u32 dyn_bw : 1;
|
||||||
|
u32 doze_not_allowed : 1;
|
||||||
|
|
||||||
|
/** Receive Vector 1c */
|
||||||
|
u32 antenna_set : 8;
|
||||||
|
u32 partial_aid : 9;
|
||||||
|
u32 group_id : 6;
|
||||||
|
u32 first_user : 1;
|
||||||
|
s32 rssi1 : 8;
|
||||||
|
|
||||||
|
/** Receive Vector 1d */
|
||||||
|
s32 rssi2 : 8;
|
||||||
|
s32 rssi3 : 8;
|
||||||
|
s32 rssi4 : 8;
|
||||||
|
u32 reserved_1d : 8;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rx_leg_vect
|
||||||
|
{
|
||||||
|
u8 dyn_bw_in_non_ht : 1;
|
||||||
|
u8 chn_bw_in_non_ht : 2;
|
||||||
|
u8 rsvd_nht : 4;
|
||||||
|
u8 lsig_valid : 1;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct rx_ht_vect
|
||||||
|
{
|
||||||
|
u16 sounding : 1;
|
||||||
|
u16 smoothing : 1;
|
||||||
|
u16 short_gi : 1;
|
||||||
|
u16 aggregation : 1;
|
||||||
|
u16 stbc : 1;
|
||||||
|
u16 num_extn_ss : 2;
|
||||||
|
u16 lsig_valid : 1;
|
||||||
|
u16 mcs : 7;
|
||||||
|
u16 fec : 1;
|
||||||
|
u16 length :16;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct rx_vht_vect
|
||||||
|
{
|
||||||
|
u8 sounding : 1;
|
||||||
|
u8 beamformed : 1;
|
||||||
|
u8 short_gi : 1;
|
||||||
|
u8 rsvd_vht1 : 1;
|
||||||
|
u8 stbc : 1;
|
||||||
|
u8 doze_not_allowed : 1;
|
||||||
|
u8 first_user : 1;
|
||||||
|
u8 rsvd_vht2 : 1;
|
||||||
|
u16 partial_aid : 9;
|
||||||
|
u16 group_id : 6;
|
||||||
|
u16 rsvd_vht3 : 1;
|
||||||
|
u32 mcs : 4;
|
||||||
|
u32 nss : 3;
|
||||||
|
u32 fec : 1;
|
||||||
|
u32 length :20;
|
||||||
|
u32 rsvd_vht4 : 4;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct rx_he_vect
|
||||||
|
{
|
||||||
|
u8 sounding : 1;
|
||||||
|
u8 beamformed : 1;
|
||||||
|
u8 gi_type : 2;
|
||||||
|
u8 stbc : 1;
|
||||||
|
u8 rsvd_he1 : 3;
|
||||||
|
|
||||||
|
u8 uplink_flag : 1;
|
||||||
|
u8 beam_change : 1;
|
||||||
|
u8 dcm : 1;
|
||||||
|
u8 he_ltf_type : 2;
|
||||||
|
u8 doppler : 1;
|
||||||
|
u8 rsvd_he2 : 2;
|
||||||
|
|
||||||
|
u8 bss_color : 6;
|
||||||
|
u8 rsvd_he3 : 2;
|
||||||
|
|
||||||
|
u8 txop_duration : 7;
|
||||||
|
u8 rsvd_he4 : 1;
|
||||||
|
|
||||||
|
u8 pe_duration : 4;
|
||||||
|
u8 spatial_reuse : 4;
|
||||||
|
|
||||||
|
u8 sig_b_comp_mode : 1;
|
||||||
|
u8 dcm_sig_b : 1;
|
||||||
|
u8 mcs_sig_b : 3;
|
||||||
|
u8 ru_size : 3;
|
||||||
|
|
||||||
|
u32 mcs : 4;
|
||||||
|
u32 nss : 3;
|
||||||
|
u32 fec : 1;
|
||||||
|
u32 length :20;
|
||||||
|
u32 rsvd_he6 : 4;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct rx_vector_1 {
|
||||||
|
u8 format_mod : 4;
|
||||||
|
u8 ch_bw : 3;
|
||||||
|
u8 pre_type : 1;
|
||||||
|
u8 antenna_set : 8;
|
||||||
|
s32 rssi_leg : 8;
|
||||||
|
u32 leg_length :12;
|
||||||
|
u32 leg_rate : 4;
|
||||||
|
s32 rssi1 : 8;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct rx_leg_vect leg;
|
||||||
|
struct rx_ht_vect ht;
|
||||||
|
struct rx_vht_vect vht;
|
||||||
|
struct rx_he_vect he;
|
||||||
|
};
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct rx_vector_2_old {
|
||||||
|
/** Receive Vector 2a */
|
||||||
|
u32 rcpi : 8;
|
||||||
|
u32 evm1 : 8;
|
||||||
|
u32 evm2 : 8;
|
||||||
|
u32 evm3 : 8;
|
||||||
|
|
||||||
|
/** Receive Vector 2b */
|
||||||
|
u32 evm4 : 8;
|
||||||
|
u32 reserved2b_1 : 8;
|
||||||
|
u32 reserved2b_2 : 8;
|
||||||
|
u32 reserved2b_3 : 8;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rx_vector_2 {
|
||||||
|
/** Receive Vector 2a */
|
||||||
|
u32 rcpi1 : 8;
|
||||||
|
u32 rcpi2 : 8;
|
||||||
|
u32 rcpi3 : 8;
|
||||||
|
u32 rcpi4 : 8;
|
||||||
|
|
||||||
|
/** Receive Vector 2b */
|
||||||
|
u32 evm1 : 8;
|
||||||
|
u32 evm2 : 8;
|
||||||
|
u32 evm3 : 8;
|
||||||
|
u32 evm4 : 8;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct phy_channel_info_desc {
|
||||||
|
/** PHY channel information 1 */
|
||||||
|
u32 phy_band : 8;
|
||||||
|
u32 phy_channel_type : 8;
|
||||||
|
u32 phy_prim20_freq : 16;
|
||||||
|
/** PHY channel information 2 */
|
||||||
|
u32 phy_center1_freq : 16;
|
||||||
|
u32 phy_center2_freq : 16;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hw_vect {
|
||||||
|
/** Total length for the MPDU transfer */
|
||||||
|
u32 len :16;
|
||||||
|
|
||||||
|
u32 reserved : 8;//data type is included
|
||||||
|
/** AMPDU Status Information */
|
||||||
|
u32 mpdu_cnt : 6;
|
||||||
|
u32 ampdu_cnt : 2;
|
||||||
|
|
||||||
|
/** TSF Low */
|
||||||
|
__le32 tsf_lo;
|
||||||
|
/** TSF High */
|
||||||
|
__le32 tsf_hi;
|
||||||
|
|
||||||
|
/** Receive Vector 1 */
|
||||||
|
struct rx_vector_1 rx_vect1;
|
||||||
|
/** Receive Vector 2 */
|
||||||
|
struct rx_vector_2 rx_vect2;
|
||||||
|
|
||||||
|
/** Status **/
|
||||||
|
u32 rx_vect2_valid : 1;
|
||||||
|
u32 resp_frame : 1;
|
||||||
|
/** Decryption Status */
|
||||||
|
u32 decr_status : 3;
|
||||||
|
u32 rx_fifo_oflow : 1;
|
||||||
|
|
||||||
|
/** Frame Unsuccessful */
|
||||||
|
u32 undef_err : 1;
|
||||||
|
u32 phy_err : 1;
|
||||||
|
u32 fcs_err : 1;
|
||||||
|
u32 addr_mismatch : 1;
|
||||||
|
u32 ga_frame : 1;
|
||||||
|
u32 current_ac : 2;
|
||||||
|
|
||||||
|
u32 frm_successful_rx : 1;
|
||||||
|
/** Descriptor Done */
|
||||||
|
u32 desc_done_rx : 1;
|
||||||
|
/** Key Storage RAM Index */
|
||||||
|
u32 key_sram_index : 10;
|
||||||
|
/** Key Storage RAM Index Valid */
|
||||||
|
u32 key_sram_v : 1;
|
||||||
|
u32 type : 2;
|
||||||
|
u32 subtype : 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
//#ifdef CONFIG_RWNX_MON_DATA
|
||||||
|
#if 0
|
||||||
|
/// MAC header backup descriptor
|
||||||
|
struct mon_machdrdesc
|
||||||
|
{
|
||||||
|
/// Length of the buffer
|
||||||
|
u32 buf_len;
|
||||||
|
/// Buffer containing mac header, LLC and SNAP
|
||||||
|
u8 buffer[RX_MACHDR_BACKUP_LEN];
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct hw_rxhdr {
|
||||||
|
/** RX vector */
|
||||||
|
struct hw_vect hwvect;
|
||||||
|
|
||||||
|
/** PHY channel information */
|
||||||
|
struct phy_channel_info_desc phy_info;
|
||||||
|
|
||||||
|
/** RX flags */
|
||||||
|
u32 flags_is_amsdu : 1;
|
||||||
|
u32 flags_is_80211_mpdu: 1;
|
||||||
|
u32 flags_is_4addr : 1;
|
||||||
|
u32 flags_new_peer : 1;
|
||||||
|
#if defined(AICWF_SDIO_SUPPORT) || defined(AICWF_USB_SUPPORT)
|
||||||
|
u32 flags_user_prio : 1; // aic: fw not fill any more
|
||||||
|
u32 flags_need_reord : 1;
|
||||||
|
u32 flags_upload : 1;
|
||||||
|
#else
|
||||||
|
u32 flags_user_prio : 3;
|
||||||
|
#endif
|
||||||
|
#ifndef AICWF_RX_REORDER
|
||||||
|
u32 flags_rsvd0 : 1;
|
||||||
|
#else
|
||||||
|
u32 is_monitor_vif : 1;
|
||||||
|
#endif
|
||||||
|
u32 flags_vif_idx : 8; // 0xFF if invalid VIF index
|
||||||
|
u32 flags_sta_idx : 8; // 0xFF if invalid STA index
|
||||||
|
u32 flags_dst_idx : 8; // 0xFF if unknown destination STA
|
||||||
|
//#ifdef CONFIG_RWNX_MON_DATA
|
||||||
|
#if 0
|
||||||
|
/// MAC header backup descriptor (used only for MSDU when there is a monitor and a data interface)
|
||||||
|
struct mon_machdrdesc mac_hdr_backup;
|
||||||
|
#endif
|
||||||
|
/** Pattern indicating if the buffer is available for the driver */
|
||||||
|
u32 pattern;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const u8 legrates_lut[];
|
||||||
|
extern u16 legrates_lut_rate[];
|
||||||
|
extern u16 tx_legrates_lut_rate[];
|
||||||
|
|
||||||
|
struct DHCPInfo {
|
||||||
|
u8 op;
|
||||||
|
u8 htype;
|
||||||
|
u8 hlen;
|
||||||
|
u8 hops;
|
||||||
|
u32 xid;
|
||||||
|
u16 secs;
|
||||||
|
u16 flags;
|
||||||
|
u32 ciaddr;
|
||||||
|
u32 yiaddr;
|
||||||
|
u32 siaddr;
|
||||||
|
u32 giaddr;
|
||||||
|
u8 chaddr[16];
|
||||||
|
u8 sname[64];
|
||||||
|
u8 file[128];
|
||||||
|
u32 cookie;
|
||||||
|
u8 options[308]; /* 312 - cookie */
|
||||||
|
};
|
||||||
|
|
||||||
|
u8 rwnx_unsup_rx_vec_ind(void *pthis, void *hostid);
|
||||||
|
u8 rwnx_rxdataind(void *pthis, void *hostid);
|
||||||
|
u8 rwnx_rxdataind_aicwf(struct rwnx_hw *rwnx_hw, void *hostid, void *rx_priv);
|
||||||
|
int aicwf_process_rxframes(struct aicwf_rx_priv *rx_priv);
|
||||||
|
#ifdef CONFIG_USB_MSG_IN_EP
|
||||||
|
int aicwf_process_msg_rxframes(struct aicwf_rx_priv *rx_priv);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef AICWF_ARP_OFFLOAD
|
||||||
|
void arpoffload_proc(struct sk_buff *skb, struct rwnx_vif *rwnx_vif);
|
||||||
|
#endif
|
||||||
|
#ifdef AICWF_RX_REORDER
|
||||||
|
struct recv_msdu *reord_rxframe_alloc(spinlock_t *lock, struct list_head *q);
|
||||||
|
void reord_rxframe_free(spinlock_t *lock, struct list_head *q, struct list_head *list);
|
||||||
|
struct reord_ctrl_info *reord_init_sta( struct aicwf_rx_priv *rx_priv, const u8 *mac_addr);
|
||||||
|
void reord_deinit_sta(struct aicwf_rx_priv *rx_priv, struct reord_ctrl_info *reord_info);
|
||||||
|
int reord_need_check(struct reord_ctrl *preorder_ctrl, u16 seq_num);
|
||||||
|
int reord_rxframe_enqueue(struct reord_ctrl *preorder_ctrl, struct recv_msdu *prframe);
|
||||||
|
void reord_timeout_worker(struct work_struct *work);
|
||||||
|
int reord_single_frame_ind(struct aicwf_rx_priv *rx_priv, struct recv_msdu *prframe);
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)
|
||||||
|
void reord_timeout_handler (ulong data);
|
||||||
|
#else
|
||||||
|
void reord_timeout_handler (struct timer_list *t);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_HE_FOR_OLD_KERNEL
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 197)
|
||||||
|
struct element {
|
||||||
|
u8 id;
|
||||||
|
u8 datalen;
|
||||||
|
u8 data[];
|
||||||
|
};
|
||||||
|
/* element iteration helpers */
|
||||||
|
#define for_each_element(_elem, _data, _datalen) \
|
||||||
|
for (_elem = (const struct element *)(_data); \
|
||||||
|
(const u8 *)(_data) + (_datalen) - (const u8 *)_elem >= \
|
||||||
|
(int)sizeof(*_elem) && \
|
||||||
|
(const u8 *)(_data) + (_datalen) - (const u8 *)_elem >= \
|
||||||
|
(int)sizeof(*_elem) + _elem->datalen; \
|
||||||
|
_elem = (const struct element *)(_elem->data + _elem->datalen))
|
||||||
|
|
||||||
|
#define for_each_element_id(element, _id, data, datalen) \
|
||||||
|
for_each_element(element, data, datalen) \
|
||||||
|
if (element->id == (_id))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _RWNX_RX_H_ */
|
||||||
@@ -0,0 +1,267 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_strs.c
|
||||||
|
*
|
||||||
|
* @brief Miscellaneous debug strings
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2014-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lmac_msg.h"
|
||||||
|
|
||||||
|
static const char *const rwnx_mmid2str[MSG_I(MM_MAX)] = {
|
||||||
|
[MSG_I(MM_RESET_REQ)] = "MM_RESET_REQ",
|
||||||
|
[MSG_I(MM_RESET_CFM)] = "MM_RESET_CFM",
|
||||||
|
[MSG_I(MM_START_REQ)] = "MM_START_REQ",
|
||||||
|
[MSG_I(MM_START_CFM)] = "MM_START_CFM",
|
||||||
|
[MSG_I(MM_VERSION_REQ)] = "MM_VERSION_REQ",
|
||||||
|
[MSG_I(MM_VERSION_CFM)] = "MM_VERSION_CFM",
|
||||||
|
[MSG_I(MM_ADD_IF_REQ)] = "MM_ADD_IF_REQ",
|
||||||
|
[MSG_I(MM_ADD_IF_CFM)] = "MM_ADD_IF_CFM",
|
||||||
|
[MSG_I(MM_REMOVE_IF_REQ)] = "MM_REMOVE_IF_REQ",
|
||||||
|
[MSG_I(MM_REMOVE_IF_CFM)] = "MM_REMOVE_IF_CFM",
|
||||||
|
[MSG_I(MM_STA_ADD_REQ)] = "MM_STA_ADD_REQ",
|
||||||
|
[MSG_I(MM_STA_ADD_CFM)] = "MM_STA_ADD_CFM",
|
||||||
|
[MSG_I(MM_STA_DEL_REQ)] = "MM_STA_DEL_REQ",
|
||||||
|
[MSG_I(MM_STA_DEL_CFM)] = "MM_STA_DEL_CFM",
|
||||||
|
[MSG_I(MM_SET_FILTER_REQ)] = "MM_SET_FILTER_REQ",
|
||||||
|
[MSG_I(MM_SET_FILTER_CFM)] = "MM_SET_FILTER_CFM",
|
||||||
|
[MSG_I(MM_SET_CHANNEL_REQ)] = "MM_SET_CHANNEL_REQ",
|
||||||
|
[MSG_I(MM_SET_CHANNEL_CFM)] = "MM_SET_CHANNEL_CFM",
|
||||||
|
[MSG_I(MM_SET_DTIM_REQ)] = "MM_SET_DTIM_REQ",
|
||||||
|
[MSG_I(MM_SET_DTIM_CFM)] = "MM_SET_DTIM_CFM",
|
||||||
|
[MSG_I(MM_SET_BEACON_INT_REQ)] = "MM_SET_BEACON_INT_REQ",
|
||||||
|
[MSG_I(MM_SET_BEACON_INT_CFM)] = "MM_SET_BEACON_INT_CFM",
|
||||||
|
[MSG_I(MM_SET_BASIC_RATES_REQ)] = "MM_SET_BASIC_RATES_REQ",
|
||||||
|
[MSG_I(MM_SET_BASIC_RATES_CFM)] = "MM_SET_BASIC_RATES_CFM",
|
||||||
|
[MSG_I(MM_SET_BSSID_REQ)] = "MM_SET_BSSID_REQ",
|
||||||
|
[MSG_I(MM_SET_BSSID_CFM)] = "MM_SET_BSSID_CFM",
|
||||||
|
[MSG_I(MM_SET_EDCA_REQ)] = "MM_SET_EDCA_REQ",
|
||||||
|
[MSG_I(MM_SET_EDCA_CFM)] = "MM_SET_EDCA_CFM",
|
||||||
|
[MSG_I(MM_SET_MODE_REQ)] = "MM_SET_MODE_REQ",
|
||||||
|
[MSG_I(MM_SET_MODE_CFM)] = "MM_SET_MODE_CFM",
|
||||||
|
[MSG_I(MM_SET_VIF_STATE_REQ)] = "MM_SET_VIF_STATE_REQ",
|
||||||
|
[MSG_I(MM_SET_VIF_STATE_CFM)] = "MM_SET_VIF_STATE_CFM",
|
||||||
|
[MSG_I(MM_SET_SLOTTIME_REQ)] = "MM_SET_SLOTTIME_REQ",
|
||||||
|
[MSG_I(MM_SET_SLOTTIME_CFM)] = "MM_SET_SLOTTIME_CFM",
|
||||||
|
[MSG_I(MM_SET_IDLE_REQ)] = "MM_SET_IDLE_REQ",
|
||||||
|
[MSG_I(MM_SET_IDLE_CFM)] = "MM_SET_IDLE_CFM",
|
||||||
|
[MSG_I(MM_KEY_ADD_REQ)] = "MM_KEY_ADD_REQ",
|
||||||
|
[MSG_I(MM_KEY_ADD_CFM)] = "MM_KEY_ADD_CFM",
|
||||||
|
[MSG_I(MM_KEY_DEL_REQ)] = "MM_KEY_DEL_REQ",
|
||||||
|
[MSG_I(MM_KEY_DEL_CFM)] = "MM_KEY_DEL_CFM",
|
||||||
|
[MSG_I(MM_BA_ADD_REQ)] = "MM_BA_ADD_REQ",
|
||||||
|
[MSG_I(MM_BA_ADD_CFM)] = "MM_BA_ADD_CFM",
|
||||||
|
[MSG_I(MM_BA_DEL_REQ)] = "MM_BA_DEL_REQ",
|
||||||
|
[MSG_I(MM_BA_DEL_CFM)] = "MM_BA_DEL_CFM",
|
||||||
|
[MSG_I(MM_PRIMARY_TBTT_IND)] = "MM_PRIMARY_TBTT_IND",
|
||||||
|
[MSG_I(MM_SECONDARY_TBTT_IND)] = "MM_SECONDARY_TBTT_IND",
|
||||||
|
[MSG_I(MM_SET_POWER_REQ)] = "MM_SET_POWER_REQ",
|
||||||
|
[MSG_I(MM_SET_POWER_CFM)] = "MM_SET_POWER_CFM",
|
||||||
|
[MSG_I(MM_DBG_TRIGGER_REQ)] = "MM_DBG_TRIGGER_REQ",
|
||||||
|
[MSG_I(MM_SET_PS_MODE_REQ)] = "MM_SET_PS_MODE_REQ",
|
||||||
|
[MSG_I(MM_SET_PS_MODE_CFM)] = "MM_SET_PS_MODE_CFM",
|
||||||
|
[MSG_I(MM_CHAN_CTXT_ADD_REQ)] = "MM_CHAN_CTXT_ADD_REQ",
|
||||||
|
[MSG_I(MM_CHAN_CTXT_ADD_CFM)] = "MM_CHAN_CTXT_ADD_CFM",
|
||||||
|
[MSG_I(MM_CHAN_CTXT_DEL_REQ)] = "MM_CHAN_CTXT_DEL_REQ",
|
||||||
|
[MSG_I(MM_CHAN_CTXT_DEL_CFM)] = "MM_CHAN_CTXT_DEL_CFM",
|
||||||
|
[MSG_I(MM_CHAN_CTXT_LINK_REQ)] = "MM_CHAN_CTXT_LINK_REQ",
|
||||||
|
[MSG_I(MM_CHAN_CTXT_LINK_CFM)] = "MM_CHAN_CTXT_LINK_CFM",
|
||||||
|
[MSG_I(MM_CHAN_CTXT_UNLINK_REQ)] = "MM_CHAN_CTXT_UNLINK_REQ",
|
||||||
|
[MSG_I(MM_CHAN_CTXT_UNLINK_CFM)] = "MM_CHAN_CTXT_UNLINK_CFM",
|
||||||
|
[MSG_I(MM_CHAN_CTXT_UPDATE_REQ)] = "MM_CHAN_CTXT_UPDATE_REQ",
|
||||||
|
[MSG_I(MM_CHAN_CTXT_UPDATE_CFM)] = "MM_CHAN_CTXT_UPDATE_CFM",
|
||||||
|
[MSG_I(MM_CHAN_CTXT_SCHED_REQ)] = "MM_CHAN_CTXT_SCHED_REQ",
|
||||||
|
[MSG_I(MM_CHAN_CTXT_SCHED_CFM)] = "MM_CHAN_CTXT_SCHED_CFM",
|
||||||
|
[MSG_I(MM_BCN_CHANGE_REQ)] = "MM_BCN_CHANGE_REQ",
|
||||||
|
[MSG_I(MM_BCN_CHANGE_CFM)] = "MM_BCN_CHANGE_CFM",
|
||||||
|
[MSG_I(MM_TIM_UPDATE_REQ)] = "MM_TIM_UPDATE_REQ",
|
||||||
|
[MSG_I(MM_TIM_UPDATE_CFM)] = "MM_TIM_UPDATE_CFM",
|
||||||
|
[MSG_I(MM_CONNECTION_LOSS_IND)] = "MM_CONNECTION_LOSS_IND",
|
||||||
|
[MSG_I(MM_CHANNEL_SWITCH_IND)] = "MM_CHANNEL_SWITCH_IND",
|
||||||
|
[MSG_I(MM_CHANNEL_PRE_SWITCH_IND)] = "MM_CHANNEL_PRE_SWITCH_IND",
|
||||||
|
[MSG_I(MM_REMAIN_ON_CHANNEL_REQ)] = "MM_REMAIN_ON_CHANNEL_REQ",
|
||||||
|
[MSG_I(MM_REMAIN_ON_CHANNEL_CFM)] = "MM_REMAIN_ON_CHANNEL_CFM",
|
||||||
|
[MSG_I(MM_REMAIN_ON_CHANNEL_EXP_IND)] = "MM_REMAIN_ON_CHANNEL_EXP_IND",
|
||||||
|
[MSG_I(MM_PS_CHANGE_IND)] = "MM_PS_CHANGE_IND",
|
||||||
|
[MSG_I(MM_TRAFFIC_REQ_IND)] = "MM_TRAFFIC_REQ_IND",
|
||||||
|
[MSG_I(MM_SET_PS_OPTIONS_REQ)] = "MM_SET_PS_OPTIONS_REQ",
|
||||||
|
[MSG_I(MM_SET_PS_OPTIONS_CFM)] = "MM_SET_PS_OPTIONS_CFM",
|
||||||
|
[MSG_I(MM_P2P_VIF_PS_CHANGE_IND)] = "MM_P2P_VIF_PS_CHANGE_IND",
|
||||||
|
[MSG_I(MM_CSA_COUNTER_IND)] = "MM_CSA_COUNTER_IND",
|
||||||
|
[MSG_I(MM_CHANNEL_SURVEY_IND)] = "MM_CHANNEL_SURVEY_IND",
|
||||||
|
[MSG_I(MM_SET_P2P_NOA_REQ)] = "MM_SET_P2P_NOA_REQ",
|
||||||
|
[MSG_I(MM_SET_P2P_OPPPS_REQ)] = "MM_SET_P2P_OPPPS_REQ",
|
||||||
|
[MSG_I(MM_SET_P2P_NOA_CFM)] = "MM_SET_P2P_NOA_CFM",
|
||||||
|
[MSG_I(MM_SET_P2P_OPPPS_CFM)] = "MM_SET_P2P_OPPPS_CFM",
|
||||||
|
[MSG_I(MM_CFG_RSSI_REQ)] = "MM_CFG_RSSI_REQ",
|
||||||
|
[MSG_I(MM_RSSI_STATUS_IND)] = "MM_RSSI_STATUS_IND",
|
||||||
|
[MSG_I(MM_CSA_FINISH_IND)] = "MM_CSA_FINISH_IND",
|
||||||
|
[MSG_I(MM_CSA_TRAFFIC_IND)] = "MM_CSA_TRAFFIC_IND",
|
||||||
|
[MSG_I(MM_MU_GROUP_UPDATE_REQ)] = "MM_MU_GROUP_UPDATE_REQ",
|
||||||
|
[MSG_I(MM_MU_GROUP_UPDATE_CFM)] = "MM_MU_GROUP_UPDATE_CFM",
|
||||||
|
|
||||||
|
[MSG_I(MM_SET_ARPOFFLOAD_REQ)] = "MM_SET_ARPOFFLOAD_REQ",
|
||||||
|
[MSG_I(MM_SET_ARPOFFLOAD_CFM)] = "MM_SET_ARPOFFLOAD_CFM",
|
||||||
|
[MSG_I(MM_SET_AGG_DISABLE_REQ)] = "MM_SET_AGG_DISABLE_REQ",
|
||||||
|
[MSG_I(MM_SET_AGG_DISABLE_CFM)] = "MM_SET_AGG_DISABLE_CFM",
|
||||||
|
[MSG_I(MM_SET_COEX_REQ)] = "MM_SET_COEX_REQ",
|
||||||
|
[MSG_I(MM_SET_COEX_CFM)] = "MM_SET_COEX_CFM",
|
||||||
|
[MSG_I(MM_SET_RF_CONFIG_REQ)] = "MM_SET_RF_CONFIG_REQ",
|
||||||
|
[MSG_I(MM_SET_RF_CONFIG_CFM)] = "MM_SET_RF_CONFIG_CFM",
|
||||||
|
[MSG_I(MM_SET_RF_CALIB_REQ)] = "MM_SET_RF_CALIB_REQ",
|
||||||
|
[MSG_I(MM_SET_RF_CALIB_CFM)] = "MM_SET_RF_CALIB_CFM",
|
||||||
|
|
||||||
|
[MSG_I(MM_GET_MAC_ADDR_REQ)] = "MM_GET_MAC_ADDR_REQ",
|
||||||
|
[MSG_I(MM_GET_MAC_ADDR_CFM)] = "MM_GET_MAC_ADDR_CFM",
|
||||||
|
[MSG_I(MM_GET_STA_INFO_REQ)] = "MM_GET_STA_INFO_REQ",
|
||||||
|
[MSG_I(MM_GET_STA_INFO_CFM)] = "MM_GET_STA_INFO_CFM",
|
||||||
|
[MSG_I(MM_SET_TXPWR_IDX_LVL_REQ)] = "MM_SET_TXPWR_IDX_LVL_REQ",
|
||||||
|
[MSG_I(MM_SET_TXPWR_IDX_LVL_CFM)] = "MM_SET_TXPWR_IDX_LVL_CFM",
|
||||||
|
[MSG_I(MM_SET_TXPWR_OFST_REQ)] = "MM_SET_TXPWR_OFST_REQ",
|
||||||
|
[MSG_I(MM_SET_TXPWR_OFST_CFM)] = "MM_SET_TXPWR_OFST_CFM",
|
||||||
|
[MSG_I(MM_SET_STACK_START_REQ)] = "MM_SET_STACK_START_REQ",
|
||||||
|
[MSG_I(MM_SET_STACK_START_CFM)] = "MM_SET_STACK_START_CFM",
|
||||||
|
[MSG_I(MM_APM_STALOSS_IND)] = "MM_APM_STALOSS_IND",
|
||||||
|
[MSG_I(MM_SET_VENDOR_HWCONFIG_REQ)] = "MM_SET_VENDOR_HWCONFIG_REQ",
|
||||||
|
[MSG_I(MM_SET_VENDOR_HWCONFIG_CFM)] = "MM_SET_VENDOR_HWCONFIG_CFM",
|
||||||
|
[MSG_I(MM_GET_FW_VERSION_REQ)] = "MM_GET_FW_VERSION_REQ",
|
||||||
|
[MSG_I(MM_GET_FW_VERSION_CFM)] = "MM_GET_FW_VERSION_CFM",
|
||||||
|
[MSG_I(MM_SET_RESUME_RESTORE_REQ)] = "MM_SET_RESUME_RESTORE_REQ",
|
||||||
|
[MSG_I(MM_SET_RESUME_RESTORE_CFM)] = "MM_SET_RESUME_RESTORE_CFM",
|
||||||
|
[MSG_I(MM_GET_WIFI_DISABLE_REQ)] = "MM_GET_WIFI_DISABLE_REQ",
|
||||||
|
[MSG_I(MM_GET_WIFI_DISABLE_CFM)] = "MM_GET_WIFI_DISABLE_CFM",
|
||||||
|
[MSG_I(MM_CFG_RSSI_CFM)] = "MM_CFG_RSSI_CFM",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const rwnx_dbgid2str[MSG_I(DBG_MAX)] = {
|
||||||
|
[MSG_I(DBG_MEM_READ_REQ)] = "DBG_MEM_READ_REQ",
|
||||||
|
[MSG_I(DBG_MEM_READ_CFM)] = "DBG_MEM_READ_CFM",
|
||||||
|
[MSG_I(DBG_MEM_WRITE_REQ)] = "DBG_MEM_WRITE_REQ",
|
||||||
|
[MSG_I(DBG_MEM_WRITE_CFM)] = "DBG_MEM_WRITE_CFM",
|
||||||
|
[MSG_I(DBG_SET_MOD_FILTER_REQ)] = "DBG_SET_MOD_FILTER_REQ",
|
||||||
|
[MSG_I(DBG_SET_MOD_FILTER_CFM)] = "DBG_SET_MOD_FILTER_CFM",
|
||||||
|
[MSG_I(DBG_SET_SEV_FILTER_REQ)] = "DBG_SET_SEV_FILTER_REQ",
|
||||||
|
[MSG_I(DBG_SET_SEV_FILTER_CFM)] = "DBG_SET_SEV_FILTER_CFM",
|
||||||
|
[MSG_I(DBG_ERROR_IND)] = "DBG_ERROR_IND",
|
||||||
|
[MSG_I(DBG_GET_SYS_STAT_REQ)] = "DBG_GET_SYS_STAT_REQ",
|
||||||
|
[MSG_I(DBG_GET_SYS_STAT_CFM)] = "DBG_GET_SYS_STAT_CFM",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const rwnx_scanid2str[MSG_I(SCAN_MAX)] = {
|
||||||
|
[MSG_I(SCAN_START_REQ)] = "SCAN_START_REQ",
|
||||||
|
[MSG_I(SCAN_START_CFM)] = "SCAN_START_CFM",
|
||||||
|
[MSG_I(SCAN_DONE_IND)] = "SCAN_DONE_IND",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const rwnx_tdlsid2str[MSG_I(TDLS_MAX)] = {
|
||||||
|
[MSG_I(TDLS_CHAN_SWITCH_CFM)] = "TDLS_CHAN_SWITCH_CFM",
|
||||||
|
[MSG_I(TDLS_CHAN_SWITCH_REQ)] = "TDLS_CHAN_SWITCH_REQ",
|
||||||
|
[MSG_I(TDLS_CHAN_SWITCH_IND)] = "TDLS_CHAN_SWITCH_IND",
|
||||||
|
[MSG_I(TDLS_CHAN_SWITCH_BASE_IND)] = "TDLS_CHAN_SWITCH_BASE_IND",
|
||||||
|
[MSG_I(TDLS_CANCEL_CHAN_SWITCH_REQ)] = "TDLS_CANCEL_CHAN_SWITCH_REQ",
|
||||||
|
[MSG_I(TDLS_CANCEL_CHAN_SWITCH_CFM)] = "TDLS_CANCEL_CHAN_SWITCH_CFM",
|
||||||
|
[MSG_I(TDLS_PEER_PS_IND)] = "TDLS_PEER_PS_IND",
|
||||||
|
[MSG_I(TDLS_PEER_TRAFFIC_IND_REQ)] = "TDLS_PEER_TRAFFIC_IND_REQ",
|
||||||
|
[MSG_I(TDLS_PEER_TRAFFIC_IND_CFM)] = "TDLS_PEER_TRAFFIC_IND_CFM",
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
|
||||||
|
static const char *const rwnx_scanuid2str[MSG_I(SCANU_MAX)] = {
|
||||||
|
[MSG_I(SCANU_START_REQ)] = "SCANU_START_REQ",
|
||||||
|
[MSG_I(SCANU_START_CFM)] = "SCANU_START_CFM",
|
||||||
|
[MSG_I(SCANU_JOIN_REQ)] = "SCANU_JOIN_REQ",
|
||||||
|
[MSG_I(SCANU_JOIN_CFM)] = "SCANU_JOIN_CFM",
|
||||||
|
[MSG_I(SCANU_RESULT_IND)] = "SCANU_RESULT_IND",
|
||||||
|
[MSG_I(SCANU_FAST_REQ)] = "SCANU_FAST_REQ",
|
||||||
|
[MSG_I(SCANU_FAST_CFM)] = "SCANU_FAST_CFM",
|
||||||
|
[MSG_I(SCANU_VENDOR_IE_REQ)] = "SCANU_VENDOR_IE_REQ",
|
||||||
|
[MSG_I(SCANU_VENDOR_IE_CFM)] = "SCANU_VENDOR_IE_CFM",
|
||||||
|
[MSG_I(SCANU_START_CFM_ADDTIONAL)] = "SCANU_START_CFM_ADDTIONAL",
|
||||||
|
[MSG_I(SCANU_CANCEL_REQ)] = "SCANU_CANCEL_REQ",
|
||||||
|
[MSG_I(SCANU_CANCEL_CFM)] = "SCANU_CANCEL_CFM",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const rwnx_meid2str[MSG_I(ME_MAX)] = {
|
||||||
|
[MSG_I(ME_CONFIG_REQ)] = "ME_CONFIG_REQ",
|
||||||
|
[MSG_I(ME_CONFIG_CFM)] = "ME_CONFIG_CFM",
|
||||||
|
[MSG_I(ME_CHAN_CONFIG_REQ)] = "ME_CHAN_CONFIG_REQ",
|
||||||
|
[MSG_I(ME_CHAN_CONFIG_CFM)] = "ME_CHAN_CONFIG_CFM",
|
||||||
|
[MSG_I(ME_SET_CONTROL_PORT_REQ)] = "ME_SET_CONTROL_PORT_REQ",
|
||||||
|
[MSG_I(ME_SET_CONTROL_PORT_CFM)] = "ME_SET_CONTROL_PORT_CFM",
|
||||||
|
[MSG_I(ME_TKIP_MIC_FAILURE_IND)] = "ME_TKIP_MIC_FAILURE_IND",
|
||||||
|
[MSG_I(ME_STA_ADD_REQ)] = "ME_STA_ADD_REQ",
|
||||||
|
[MSG_I(ME_STA_ADD_CFM)] = "ME_STA_ADD_CFM",
|
||||||
|
[MSG_I(ME_STA_DEL_REQ)] = "ME_STA_DEL_REQ",
|
||||||
|
[MSG_I(ME_STA_DEL_CFM)] = "ME_STA_DEL_CFM",
|
||||||
|
[MSG_I(ME_TX_CREDITS_UPDATE_IND)]= "ME_TX_CREDITS_UPDATE_IND",
|
||||||
|
[MSG_I(ME_RC_STATS_REQ)] = "ME_RC_STATS_REQ",
|
||||||
|
[MSG_I(ME_RC_STATS_CFM)] = "ME_RC_STATS_CFM",
|
||||||
|
[MSG_I(ME_RC_SET_RATE_REQ)] = "ME_RC_SET_RATE_REQ",
|
||||||
|
[MSG_I(ME_TRAFFIC_IND_REQ)] = "ME_TRAFFIC_IND_REQ",
|
||||||
|
[MSG_I(ME_TRAFFIC_IND_CFM)] = "ME_TRAFFIC_IND_CFM",
|
||||||
|
[MSG_I(ME_SET_PS_MODE_REQ)] = "ME_SET_PS_MODE_REQ",
|
||||||
|
[MSG_I(ME_SET_PS_MODE_CFM)] = "ME_SET_PS_MODE_CFM",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const rwnx_smid2str[MSG_I(SM_MAX)] = {
|
||||||
|
[MSG_I(SM_CONNECT_REQ)] = "SM_CONNECT_REQ",
|
||||||
|
[MSG_I(SM_CONNECT_CFM)] = "SM_CONNECT_CFM",
|
||||||
|
[MSG_I(SM_CONNECT_IND)] = "SM_CONNECT_IND",
|
||||||
|
[MSG_I(SM_DISCONNECT_REQ)] = "SM_DISCONNECT_REQ",
|
||||||
|
[MSG_I(SM_DISCONNECT_CFM)] = "SM_DISCONNECT_CFM",
|
||||||
|
[MSG_I(SM_DISCONNECT_IND)] = "SM_DISCONNECT_IND",
|
||||||
|
[MSG_I(SM_EXTERNAL_AUTH_REQUIRED_IND)] = "SM_EXTERNAL_AUTH_REQUIRED_IND",
|
||||||
|
[MSG_I(SM_EXTERNAL_AUTH_REQUIRED_RSP)] = "SM_EXTERNAL_AUTH_REQUIRED_RSP",
|
||||||
|
[MSG_I(SM_EXTERNAL_AUTH_REQUIRED_RSP_CFM)] = "SM_EXTERNAL_AUTH_REQUIRED_RSP_CFM",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const rwnx_apmid2str[MSG_I(APM_MAX)] = {
|
||||||
|
[MSG_I(APM_START_REQ)] = "APM_START_REQ",
|
||||||
|
[MSG_I(APM_START_CFM)] = "APM_START_CFM",
|
||||||
|
[MSG_I(APM_STOP_REQ)] = "APM_STOP_REQ",
|
||||||
|
[MSG_I(APM_STOP_CFM)] = "APM_STOP_CFM",
|
||||||
|
[MSG_I(APM_START_CAC_REQ)] = "APM_START_CAC_REQ",
|
||||||
|
[MSG_I(APM_START_CAC_CFM)] = "APM_START_CAC_CFM",
|
||||||
|
[MSG_I(APM_STOP_CAC_REQ)] = "APM_STOP_CAC_REQ",
|
||||||
|
[MSG_I(APM_STOP_CAC_CFM)] = "APM_STOP_CAC_CFM",
|
||||||
|
[MSG_I(APM_SET_BEACON_IE_REQ)] = "APM_SET_BEACON_IE_REQ",
|
||||||
|
[MSG_I(APM_SET_BEACON_IE_CFM)] = "APM_SET_BEACON_IE_CFM",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const rwnx_meshid2str[MSG_I(MESH_MAX)] = {
|
||||||
|
[MSG_I(MESH_START_REQ)] = "MESH_START_REQ",
|
||||||
|
[MSG_I(MESH_START_CFM)] = "MESH_START_CFM",
|
||||||
|
[MSG_I(MESH_STOP_REQ)] = "MESH_STOP_REQ",
|
||||||
|
[MSG_I(MESH_STOP_CFM)] = "MESH_STOP_CFM",
|
||||||
|
[MSG_I(MESH_UPDATE_REQ)] = "MESH_UPDATE_REQ",
|
||||||
|
[MSG_I(MESH_UPDATE_CFM)] = "MESH_UPDATE_CFM",
|
||||||
|
[MSG_I(MESH_PATH_CREATE_REQ)] = "MESH_PATH_CREATE_REQ",
|
||||||
|
[MSG_I(MESH_PATH_CREATE_CFM)] = "MESH_PATH_CREATE_CFM",
|
||||||
|
[MSG_I(MESH_PATH_UPDATE_REQ)] = "MESH_PATH_UPDATE_REQ",
|
||||||
|
[MSG_I(MESH_PATH_UPDATE_CFM)] = "MESH_PATH_UPDATE_CFM",
|
||||||
|
[MSG_I(MESH_PROXY_ADD_REQ)] = "MESH_PROXY_ADD_REQ",
|
||||||
|
[MSG_I(MESH_PEER_UPDATE_IND)] = "MESH_PEER_UPDATE_IND",
|
||||||
|
[MSG_I(MESH_PATH_UPDATE_IND)] = "MESH_PATH_UPDATE_IND",
|
||||||
|
[MSG_I(MESH_PROXY_UPDATE_IND)] = "MESH_PROXY_UPDATE_IND",
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* CONFIG_RWNX_FULLMAC */
|
||||||
|
|
||||||
|
const char *const *rwnx_id2str[TASK_LAST_EMB + 1] = {
|
||||||
|
[TASK_MM] = rwnx_mmid2str,
|
||||||
|
[TASK_DBG] = rwnx_dbgid2str,
|
||||||
|
[TASK_SCAN] = rwnx_scanid2str,
|
||||||
|
[TASK_TDLS] = rwnx_tdlsid2str,
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
[TASK_SCANU] = rwnx_scanuid2str,
|
||||||
|
[TASK_ME] = rwnx_meid2str,
|
||||||
|
[TASK_SM] = rwnx_smid2str,
|
||||||
|
[TASK_APM] = rwnx_apmid2str,
|
||||||
|
[TASK_MESH] = rwnx_meshid2str,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_strs.h
|
||||||
|
*
|
||||||
|
* @brief Miscellaneous debug strings
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2014-2019
|
||||||
|
*
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RWNX_STRS_H_
|
||||||
|
#define _RWNX_STRS_H_
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_FHOST
|
||||||
|
|
||||||
|
#define RWNX_ID2STR(tag) "Cmd"
|
||||||
|
|
||||||
|
#else
|
||||||
|
#include "lmac_msg.h"
|
||||||
|
|
||||||
|
#define RWNX_ID2STR(tag) (((MSG_T(tag) < ARRAY_SIZE(rwnx_id2str)) && \
|
||||||
|
(rwnx_id2str[MSG_T(tag)]) && \
|
||||||
|
((rwnx_id2str[MSG_T(tag)])[MSG_I(tag)])) ? \
|
||||||
|
(rwnx_id2str[MSG_T(tag)])[MSG_I(tag)] : "unknown")
|
||||||
|
|
||||||
|
extern const char *const *rwnx_id2str[TASK_LAST_EMB + 1];
|
||||||
|
#endif /* CONFIG_RWNX_FHOST */
|
||||||
|
|
||||||
|
#endif /* _RWNX_STRS_H_ */
|
||||||
@@ -0,0 +1,796 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_tx.c
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* INCLUDE FILES
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rwnx_tdls.h"
|
||||||
|
#include "rwnx_compat.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FUNCTION DEFINITIONS
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
static u16
|
||||||
|
rwnx_get_tdls_sta_capab(struct rwnx_vif *rwnx_vif, u16 status_code)
|
||||||
|
{
|
||||||
|
u16 capab = 0;
|
||||||
|
|
||||||
|
/* The capability will be 0 when sending a failure code */
|
||||||
|
if (status_code != 0)
|
||||||
|
return capab;
|
||||||
|
|
||||||
|
if (rwnx_vif->sta.ap->band != NL80211_BAND_2GHZ)
|
||||||
|
return capab;
|
||||||
|
|
||||||
|
capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
|
||||||
|
capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
|
||||||
|
|
||||||
|
return capab;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rwnx_tdls_prepare_encap_data(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
|
||||||
|
const u8 *peer, u8 action_code, u8 dialog_token,
|
||||||
|
u16 status_code, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct ieee80211_tdls_data *tf;
|
||||||
|
tf = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_data) - sizeof(tf->u));
|
||||||
|
|
||||||
|
// set eth header
|
||||||
|
memcpy(tf->da, peer, ETH_ALEN);
|
||||||
|
memcpy(tf->sa, rwnx_hw->wiphy->perm_addr, ETH_ALEN);
|
||||||
|
tf->ether_type = cpu_to_be16(ETH_P_TDLS);
|
||||||
|
|
||||||
|
// set common TDLS info
|
||||||
|
tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
|
||||||
|
tf->category = WLAN_CATEGORY_TDLS;
|
||||||
|
tf->action_code = action_code;
|
||||||
|
|
||||||
|
// set action specific TDLS info
|
||||||
|
switch (action_code) {
|
||||||
|
case WLAN_TDLS_SETUP_REQUEST:
|
||||||
|
skb_put(skb, sizeof(tf->u.setup_req));
|
||||||
|
tf->u.setup_req.dialog_token = dialog_token;
|
||||||
|
tf->u.setup_req.capability =
|
||||||
|
cpu_to_le16(rwnx_get_tdls_sta_capab(rwnx_vif, status_code));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WLAN_TDLS_SETUP_RESPONSE:
|
||||||
|
skb_put(skb, sizeof(tf->u.setup_resp));
|
||||||
|
tf->u.setup_resp.status_code = cpu_to_le16(status_code);
|
||||||
|
tf->u.setup_resp.dialog_token = dialog_token;
|
||||||
|
tf->u.setup_resp.capability =
|
||||||
|
cpu_to_le16(rwnx_get_tdls_sta_capab(rwnx_vif, status_code));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WLAN_TDLS_SETUP_CONFIRM:
|
||||||
|
skb_put(skb, sizeof(tf->u.setup_cfm));
|
||||||
|
tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
|
||||||
|
tf->u.setup_cfm.dialog_token = dialog_token;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WLAN_TDLS_TEARDOWN:
|
||||||
|
skb_put(skb, sizeof(tf->u.teardown));
|
||||||
|
tf->u.teardown.reason_code = cpu_to_le16(status_code);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WLAN_TDLS_DISCOVERY_REQUEST:
|
||||||
|
skb_put(skb, sizeof(tf->u.discover_req));
|
||||||
|
tf->u.discover_req.dialog_token = dialog_token;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rwnx_prep_tdls_direct(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
|
||||||
|
const u8 *peer, u8 action_code, u8 dialog_token,
|
||||||
|
u16 status_code, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct ieee80211_mgmt *mgmt;
|
||||||
|
|
||||||
|
mgmt = (void *)skb_put(skb, 24);
|
||||||
|
memset(mgmt, 0, 24);
|
||||||
|
memcpy(mgmt->da, peer, ETH_ALEN);
|
||||||
|
memcpy(mgmt->sa, rwnx_hw->wiphy->perm_addr, ETH_ALEN);
|
||||||
|
memcpy(mgmt->bssid, rwnx_vif->sta.ap->mac_addr, ETH_ALEN);
|
||||||
|
|
||||||
|
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||||
|
IEEE80211_STYPE_ACTION);
|
||||||
|
|
||||||
|
switch (action_code) {
|
||||||
|
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
|
||||||
|
skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
|
||||||
|
mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
|
||||||
|
mgmt->u.action.u.tdls_discover_resp.action_code = WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
|
||||||
|
mgmt->u.action.u.tdls_discover_resp.dialog_token = dialog_token;
|
||||||
|
mgmt->u.action.u.tdls_discover_resp.capability =
|
||||||
|
cpu_to_le16(rwnx_get_tdls_sta_capab(rwnx_vif, status_code));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rwnx_add_srates_ie(struct rwnx_hw *rwnx_hw, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
u8 i, rates, *pos;
|
||||||
|
int rate;
|
||||||
|
struct ieee80211_supported_band *rwnx_band_2GHz = rwnx_hw->wiphy->bands[NL80211_BAND_2GHZ];
|
||||||
|
|
||||||
|
rates = 8;
|
||||||
|
|
||||||
|
if (skb_tailroom(skb) < rates + 2)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
pos = skb_put(skb, rates + 2);
|
||||||
|
*pos++ = WLAN_EID_SUPP_RATES;
|
||||||
|
*pos++ = rates;
|
||||||
|
for (i = 0; i < rates; i++) {
|
||||||
|
rate = rwnx_band_2GHz->bitrates[i].bitrate;
|
||||||
|
rate = DIV_ROUND_UP(rate, 5);
|
||||||
|
*pos++ = (u8)rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rwnx_add_ext_srates_ie(struct rwnx_hw *rwnx_hw, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
u8 i, exrates, *pos;
|
||||||
|
int rate;
|
||||||
|
struct ieee80211_supported_band *rwnx_band_2GHz = rwnx_hw->wiphy->bands[NL80211_BAND_2GHZ];
|
||||||
|
|
||||||
|
exrates = rwnx_band_2GHz->n_bitrates - 8;
|
||||||
|
|
||||||
|
if (skb_tailroom(skb) < exrates + 2)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
pos = skb_put(skb, exrates + 2);
|
||||||
|
*pos++ = WLAN_EID_EXT_SUPP_RATES;
|
||||||
|
*pos++ = exrates;
|
||||||
|
for (i = 8; i < (8+exrates); i++) {
|
||||||
|
rate = rwnx_band_2GHz->bitrates[i].bitrate;
|
||||||
|
rate = DIV_ROUND_UP(rate, 5);
|
||||||
|
*pos++ = (u8)rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rwnx_tdls_add_supp_channels(struct rwnx_hw *rwnx_hw, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Add possible channels for TDLS. These are channels that are allowed
|
||||||
|
* to be active.
|
||||||
|
*/
|
||||||
|
u8 subband_cnt = 0;
|
||||||
|
u8 *pos_subband;
|
||||||
|
u8 *pos = skb_put(skb, 2);
|
||||||
|
struct ieee80211_supported_band *rwnx_band_2GHz = rwnx_hw->wiphy->bands[NL80211_BAND_2GHZ];
|
||||||
|
//#ifdef USE_5G
|
||||||
|
struct ieee80211_supported_band *rwnx_band_5GHz = rwnx_hw->wiphy->bands[NL80211_BAND_5GHZ];
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
*pos++ = WLAN_EID_SUPPORTED_CHANNELS;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 5GHz and 2GHz channels numbers can overlap. Ignore this for now, as
|
||||||
|
* this doesn't happen in real world scenarios.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 2GHz, with 5MHz spacing */
|
||||||
|
pos_subband = skb_put(skb, 2);
|
||||||
|
if (rwnx_band_2GHz->n_channels > 0)
|
||||||
|
{
|
||||||
|
*pos_subband++ = ieee80211_frequency_to_channel(rwnx_band_2GHz->channels[0].center_freq);
|
||||||
|
*pos_subband++ = rwnx_band_2GHz->n_channels;
|
||||||
|
subband_cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 5GHz, with 20MHz spacing */
|
||||||
|
pos_subband = skb_put(skb, 2);
|
||||||
|
//#ifdef USE_5G
|
||||||
|
if(rwnx_hw->band_5g_support){
|
||||||
|
if (rwnx_band_5GHz->n_channels > 0)
|
||||||
|
{
|
||||||
|
*pos_subband++ = ieee80211_frequency_to_channel(rwnx_band_5GHz->channels[0].center_freq);
|
||||||
|
*pos_subband++ = rwnx_band_5GHz->n_channels;
|
||||||
|
subband_cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
|
/* length */
|
||||||
|
*pos = 2 * subband_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rwnx_tdls_add_ext_capab(struct rwnx_hw *rwnx_hw, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
u8 *pos = (void *)skb_put(skb, 7);
|
||||||
|
bool chan_switch = rwnx_hw->wiphy->features &
|
||||||
|
NL80211_FEATURE_TDLS_CHANNEL_SWITCH;
|
||||||
|
|
||||||
|
*pos++ = WLAN_EID_EXT_CAPABILITY;
|
||||||
|
*pos++ = 5; /* len */
|
||||||
|
*pos++ = 0x0;
|
||||||
|
*pos++ = 0x0;
|
||||||
|
*pos++ = 0x0;
|
||||||
|
*pos++ = WLAN_EXT_CAPA4_TDLS_BUFFER_STA |
|
||||||
|
(chan_switch ? WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH : 0);
|
||||||
|
*pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rwnx_add_wmm_info_ie(struct sk_buff *skb, u8 qosinfo)
|
||||||
|
{
|
||||||
|
u8 *pos = (void *)skb_put(skb, 9);
|
||||||
|
|
||||||
|
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
|
||||||
|
*pos++ = 7; /* len */
|
||||||
|
*pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
|
||||||
|
*pos++ = 0x50;
|
||||||
|
*pos++ = 0xf2;
|
||||||
|
*pos++ = 2; /* WME */
|
||||||
|
*pos++ = 0; /* WME info */
|
||||||
|
*pos++ = 1; /* WME ver */
|
||||||
|
*pos++ = qosinfo; /* U-APSD no in use */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* translate numbering in the WMM parameter IE to the mac80211 notation */
|
||||||
|
static u8 rwnx_ac_from_wmm(int ac)
|
||||||
|
{
|
||||||
|
switch (ac) {
|
||||||
|
default:
|
||||||
|
WARN_ON_ONCE(1);
|
||||||
|
case 0:
|
||||||
|
return AC_BE;
|
||||||
|
case 1:
|
||||||
|
return AC_BK;
|
||||||
|
case 2:
|
||||||
|
return AC_VI;
|
||||||
|
case 3:
|
||||||
|
return AC_VO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rwnx_add_wmm_param_ie(struct sk_buff *skb, u8 acm_bits, u32 *ac_params)
|
||||||
|
{
|
||||||
|
struct ieee80211_wmm_param_ie *wmm;
|
||||||
|
int i, j;
|
||||||
|
u8 cw_min, cw_max;
|
||||||
|
bool acm;
|
||||||
|
|
||||||
|
wmm = (void *)skb_put(skb, sizeof(struct ieee80211_wmm_param_ie));
|
||||||
|
memset(wmm, 0, sizeof(*wmm));
|
||||||
|
|
||||||
|
wmm->element_id = WLAN_EID_VENDOR_SPECIFIC;
|
||||||
|
wmm->len = sizeof(*wmm) - 2;
|
||||||
|
|
||||||
|
wmm->oui[0] = 0x00; /* Microsoft OUI 00:50:F2 */
|
||||||
|
wmm->oui[1] = 0x50;
|
||||||
|
wmm->oui[2] = 0xf2;
|
||||||
|
wmm->oui_type = 2; /* WME */
|
||||||
|
wmm->oui_subtype = 1; /* WME param */
|
||||||
|
wmm->version = 1; /* WME ver */
|
||||||
|
wmm->qos_info = 0; /* U-APSD not in use */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use the EDCA parameters defined for the BSS, or default if the AP
|
||||||
|
* doesn't support it, as mandated by 802.11-2012 section 10.22.4
|
||||||
|
*/
|
||||||
|
for (i = 0; i < AC_MAX; i++) {
|
||||||
|
j = rwnx_ac_from_wmm(i);
|
||||||
|
cw_min = (ac_params[j] & 0xF0 ) >> 4;
|
||||||
|
cw_max = (ac_params[j] & 0xF00 ) >> 8;
|
||||||
|
acm = (acm_bits & (1 << j)) != 0;
|
||||||
|
|
||||||
|
wmm->ac[i].aci_aifsn = (i << 5) | (acm << 4) | (ac_params[j] & 0xF);
|
||||||
|
wmm->ac[i].cw = (cw_max << 4) | cw_min;
|
||||||
|
wmm->ac[i].txop_limit = (ac_params[j] & 0x0FFFF000 ) >> 12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rwnx_tdls_add_oper_classes(struct rwnx_vif *rwnx_vif, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
u8 *pos;
|
||||||
|
u8 op_class;
|
||||||
|
struct cfg80211_chan_def chan_def;
|
||||||
|
struct ieee80211_channel chan;
|
||||||
|
|
||||||
|
chan.band = rwnx_vif->sta.ap->band;
|
||||||
|
chan.center_freq = rwnx_vif->sta.ap->center_freq;
|
||||||
|
chan_def.chan = &chan;
|
||||||
|
chan_def.width = rwnx_vif->sta.ap->width;
|
||||||
|
chan_def.center_freq1 = rwnx_vif->sta.ap->center_freq1;
|
||||||
|
chan_def.center_freq2 = rwnx_vif->sta.ap->center_freq2;
|
||||||
|
|
||||||
|
if (!ieee80211_chandef_to_operating_class(&chan_def, &op_class))
|
||||||
|
return;
|
||||||
|
|
||||||
|
pos = skb_put(skb, 4);
|
||||||
|
*pos++ = WLAN_EID_SUPPORTED_REGULATORY_CLASSES;
|
||||||
|
*pos++ = 2; /* len */
|
||||||
|
|
||||||
|
// current op class
|
||||||
|
*pos++ = op_class;
|
||||||
|
*pos++ = op_class; /* give current operating class as alternate too */
|
||||||
|
|
||||||
|
// need to add 5GHz classes?
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rwnx_ie_build_ht_cap(struct sk_buff *skb, struct ieee80211_sta_ht_cap *ht_cap,
|
||||||
|
u16 cap)
|
||||||
|
{
|
||||||
|
u8 *pos;
|
||||||
|
__le16 tmp;
|
||||||
|
|
||||||
|
pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
|
||||||
|
*pos++ = WLAN_EID_HT_CAPABILITY;
|
||||||
|
*pos++ = sizeof(struct ieee80211_ht_cap);
|
||||||
|
memset(pos, 0, sizeof(struct ieee80211_ht_cap));
|
||||||
|
|
||||||
|
/* capability flags */
|
||||||
|
tmp = cpu_to_le16(cap);
|
||||||
|
memcpy(pos, &tmp, sizeof(u16));
|
||||||
|
pos += sizeof(u16);
|
||||||
|
|
||||||
|
/* AMPDU parameters */
|
||||||
|
*pos++ = ht_cap->ampdu_factor |
|
||||||
|
(ht_cap->ampdu_density <<
|
||||||
|
IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
|
||||||
|
|
||||||
|
/* MCS set */
|
||||||
|
memcpy(pos, &ht_cap->mcs, sizeof(ht_cap->mcs));
|
||||||
|
pos += sizeof(ht_cap->mcs);
|
||||||
|
|
||||||
|
/* extended capabilities */
|
||||||
|
pos += sizeof(__le16);
|
||||||
|
|
||||||
|
/* BF capabilities */
|
||||||
|
pos += sizeof(__le32);
|
||||||
|
|
||||||
|
/* antenna selection */
|
||||||
|
pos += sizeof(u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rwnx_ie_build_vht_cap(struct sk_buff *skb, struct ieee80211_sta_vht_cap *vht_cap,
|
||||||
|
u32 cap)
|
||||||
|
{
|
||||||
|
u8 *pos;
|
||||||
|
__le32 tmp;
|
||||||
|
|
||||||
|
pos = skb_put(skb, 14);
|
||||||
|
|
||||||
|
*pos++ = WLAN_EID_VHT_CAPABILITY;
|
||||||
|
*pos++ = sizeof(struct ieee80211_vht_cap);
|
||||||
|
memset(pos, 0, sizeof(struct ieee80211_vht_cap));
|
||||||
|
|
||||||
|
/* capability flags */
|
||||||
|
tmp = cpu_to_le32(cap);
|
||||||
|
memcpy(pos, &tmp, sizeof(u32));
|
||||||
|
pos += sizeof(u32);
|
||||||
|
|
||||||
|
/* VHT MCS set */
|
||||||
|
memcpy(pos, &vht_cap->vht_mcs, sizeof(vht_cap->vht_mcs));
|
||||||
|
pos += sizeof(vht_cap->vht_mcs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rwnx_tdls_add_bss_coex_ie(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
u8 *pos = (void *)skb_put(skb, 3);
|
||||||
|
|
||||||
|
*pos++ = WLAN_EID_BSS_COEX_2040;
|
||||||
|
*pos++ = 1; /* len */
|
||||||
|
|
||||||
|
*pos++ = WLAN_BSS_COEX_INFORMATION_REQUEST;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rwnx_tdls_add_link_ie(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
|
||||||
|
struct sk_buff *skb, const u8 *peer,
|
||||||
|
bool initiator)
|
||||||
|
{
|
||||||
|
struct ieee80211_tdls_lnkie *lnkid;
|
||||||
|
const u8 *init_addr, *rsp_addr;
|
||||||
|
|
||||||
|
if (initiator) {
|
||||||
|
init_addr = rwnx_hw->wiphy->perm_addr;
|
||||||
|
rsp_addr = peer;
|
||||||
|
} else {
|
||||||
|
init_addr = peer;
|
||||||
|
rsp_addr = rwnx_hw->wiphy->perm_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
|
||||||
|
|
||||||
|
lnkid->ie_type = WLAN_EID_LINK_ID;
|
||||||
|
lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2;
|
||||||
|
|
||||||
|
memcpy(lnkid->bssid, rwnx_vif->sta.ap->mac_addr, ETH_ALEN);
|
||||||
|
memcpy(lnkid->init_sta, init_addr, ETH_ALEN);
|
||||||
|
memcpy(lnkid->resp_sta, rsp_addr, ETH_ALEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rwnx_tdls_add_aid_ie(struct rwnx_vif *rwnx_vif, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
u8 *pos = (void *)skb_put(skb, 4);
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
|
||||||
|
*pos++ = WLAN_EID_AID;
|
||||||
|
#else
|
||||||
|
*pos++ = 197;
|
||||||
|
#endif
|
||||||
|
*pos++ = 2; /* len */
|
||||||
|
*pos++ = rwnx_vif->sta.ap->aid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 *
|
||||||
|
rwnx_ie_build_ht_oper(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
|
||||||
|
u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
|
||||||
|
u16 prot_mode)
|
||||||
|
{
|
||||||
|
struct ieee80211_ht_operation *ht_oper;
|
||||||
|
/* Build HT Information */
|
||||||
|
*pos++ = WLAN_EID_HT_OPERATION;
|
||||||
|
*pos++ = sizeof(struct ieee80211_ht_operation);
|
||||||
|
ht_oper = (struct ieee80211_ht_operation *)pos;
|
||||||
|
ht_oper->primary_chan = ieee80211_frequency_to_channel(
|
||||||
|
rwnx_vif->sta.ap->center_freq);
|
||||||
|
switch (rwnx_vif->sta.ap->width) {
|
||||||
|
case NL80211_CHAN_WIDTH_160:
|
||||||
|
case NL80211_CHAN_WIDTH_80P80:
|
||||||
|
case NL80211_CHAN_WIDTH_80:
|
||||||
|
case NL80211_CHAN_WIDTH_40:
|
||||||
|
if (rwnx_vif->sta.ap->center_freq1 > rwnx_vif->sta.ap->center_freq)
|
||||||
|
ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
|
||||||
|
else
|
||||||
|
ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
|
||||||
|
rwnx_vif->sta.ap->width != NL80211_CHAN_WIDTH_20_NOHT &&
|
||||||
|
rwnx_vif->sta.ap->width != NL80211_CHAN_WIDTH_20)
|
||||||
|
ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
|
||||||
|
|
||||||
|
ht_oper->operation_mode = cpu_to_le16(prot_mode);
|
||||||
|
ht_oper->stbc_param = 0x0000;
|
||||||
|
|
||||||
|
/* It seems that Basic MCS set and Supported MCS set
|
||||||
|
are identical for the first 10 bytes */
|
||||||
|
memset(&ht_oper->basic_set, 0, 16);
|
||||||
|
memcpy(&ht_oper->basic_set, &ht_cap->mcs, 10);
|
||||||
|
|
||||||
|
return pos + sizeof(struct ieee80211_ht_operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 *
|
||||||
|
rwnx_ie_build_vht_oper(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
|
||||||
|
u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
|
||||||
|
u16 prot_mode)
|
||||||
|
{
|
||||||
|
struct ieee80211_vht_operation *vht_oper;
|
||||||
|
/* Build HT Information */
|
||||||
|
*pos++ = WLAN_EID_VHT_OPERATION;
|
||||||
|
*pos++ = sizeof(struct ieee80211_vht_operation);
|
||||||
|
vht_oper = (struct ieee80211_vht_operation *)pos;
|
||||||
|
|
||||||
|
switch (rwnx_vif->sta.ap->width) {
|
||||||
|
case NL80211_CHAN_WIDTH_80:
|
||||||
|
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ; // Channel Width
|
||||||
|
CCFS0(vht_oper) =
|
||||||
|
ieee80211_frequency_to_channel(rwnx_vif->sta.ap->center_freq); // Channel Center Frequency Segment 0
|
||||||
|
CCFS1(vht_oper) = 0; // Channel Center Frequency Segment 1 (N.A.)
|
||||||
|
break;
|
||||||
|
case NL80211_CHAN_WIDTH_160:
|
||||||
|
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_160MHZ; // Channel Width
|
||||||
|
CCFS0(vht_oper) =
|
||||||
|
ieee80211_frequency_to_channel(rwnx_vif->sta.ap->center_freq); // Channel Center Frequency Segment 0
|
||||||
|
CCFS1(vht_oper) = 0; // Channel Center Frequency Segment 1 (N.A.)
|
||||||
|
break;
|
||||||
|
case NL80211_CHAN_WIDTH_80P80:
|
||||||
|
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80P80MHZ; // Channel Width
|
||||||
|
CCFS0(vht_oper) =
|
||||||
|
ieee80211_frequency_to_channel(rwnx_vif->sta.ap->center_freq1); // Channel Center Frequency Segment 0
|
||||||
|
CCFS1(vht_oper) =
|
||||||
|
ieee80211_frequency_to_channel(rwnx_vif->sta.ap->center_freq2); // Channel Center Frequency Segment 1
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_USE_HT;
|
||||||
|
CCFS0(vht_oper) = 0;
|
||||||
|
CCFS1(vht_oper) = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
vht_oper->basic_mcs_set = cpu_to_le16(rwnx_hw->mod_params->mcs_map);
|
||||||
|
|
||||||
|
return pos + sizeof(struct ieee80211_vht_operation);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rwnx_tdls_add_setup_start_ies(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
|
||||||
|
struct sk_buff *skb, const u8 *peer,
|
||||||
|
u8 action_code, bool initiator,
|
||||||
|
const u8 *extra_ies, size_t extra_ies_len)
|
||||||
|
{
|
||||||
|
enum nl80211_band band = rwnx_vif->sta.ap->band;
|
||||||
|
struct ieee80211_supported_band *sband;
|
||||||
|
struct ieee80211_sta_ht_cap ht_cap;
|
||||||
|
struct ieee80211_sta_vht_cap vht_cap;
|
||||||
|
size_t offset = 0, noffset;
|
||||||
|
u8 *pos;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
|
||||||
|
rwnx_add_srates_ie(rwnx_hw, skb);
|
||||||
|
rwnx_add_ext_srates_ie(rwnx_hw, skb);
|
||||||
|
rwnx_tdls_add_supp_channels(rwnx_hw, skb);
|
||||||
|
rwnx_tdls_add_ext_capab(rwnx_hw, skb);
|
||||||
|
|
||||||
|
/* add the QoS element if we support it */
|
||||||
|
if (/*local->hw.queues >= IEEE80211_NUM_ACS &&*/
|
||||||
|
action_code != WLAN_PUB_ACTION_TDLS_DISCOVER_RES)
|
||||||
|
rwnx_add_wmm_info_ie(skb, 0); /* no U-APSD */
|
||||||
|
|
||||||
|
rwnx_tdls_add_oper_classes(rwnx_vif, skb);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* with TDLS we can switch channels, and HT-caps are not necessarily
|
||||||
|
* the same on all bands. The specification limits the setup to a
|
||||||
|
* single HT-cap, so use the current band for now.
|
||||||
|
*/
|
||||||
|
sband = rwnx_hw->wiphy->bands[band];
|
||||||
|
memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
|
||||||
|
if (((action_code == WLAN_TDLS_SETUP_REQUEST) ||
|
||||||
|
(action_code == WLAN_TDLS_SETUP_RESPONSE) ||
|
||||||
|
(action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES)) &&
|
||||||
|
ht_cap.ht_supported /* (!sta || sta->sta.ht_cap.ht_supported)*/) {
|
||||||
|
rwnx_ie_build_ht_cap(skb, &ht_cap, ht_cap.cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ht_cap.ht_supported &&
|
||||||
|
(ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
|
||||||
|
rwnx_tdls_add_bss_coex_ie(skb);
|
||||||
|
|
||||||
|
rwnx_tdls_add_link_ie(rwnx_hw, rwnx_vif, skb, peer, initiator);
|
||||||
|
|
||||||
|
memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap));
|
||||||
|
if (vht_cap.vht_supported) {
|
||||||
|
rwnx_tdls_add_aid_ie(rwnx_vif, skb);
|
||||||
|
rwnx_ie_build_vht_cap(skb, &vht_cap, vht_cap.cap);
|
||||||
|
// Operating mode Notification (optional)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add any remaining IEs */
|
||||||
|
if (extra_ies_len) {
|
||||||
|
noffset = extra_ies_len;
|
||||||
|
pos = skb_put(skb, noffset - offset);
|
||||||
|
memcpy(pos, extra_ies + offset, noffset - offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
rwnx_tdls_add_setup_cfm_ies(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
|
||||||
|
struct sk_buff *skb, const u8 *peer, bool initiator,
|
||||||
|
const u8 *extra_ies, size_t extra_ies_len)
|
||||||
|
{
|
||||||
|
struct ieee80211_supported_band *sband;
|
||||||
|
enum nl80211_band band = rwnx_vif->sta.ap->band;
|
||||||
|
struct ieee80211_sta_ht_cap ht_cap;
|
||||||
|
struct ieee80211_sta_vht_cap vht_cap;
|
||||||
|
|
||||||
|
size_t offset = 0, noffset;
|
||||||
|
struct rwnx_sta *sta, *ap_sta;
|
||||||
|
u8 *pos;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
|
||||||
|
sta = rwnx_get_sta(rwnx_hw, peer);
|
||||||
|
ap_sta = rwnx_vif->sta.ap;
|
||||||
|
if (WARN_ON_ONCE(!sta || !ap_sta)) {
|
||||||
|
rcu_read_unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add the QoS param IE if both the peer and we support it */
|
||||||
|
if (sta->qos)
|
||||||
|
rwnx_add_wmm_param_ie(skb, ap_sta->acm, ap_sta->ac_param);
|
||||||
|
|
||||||
|
/* if HT support is only added in TDLS, we need an HT-operation IE */
|
||||||
|
sband = rwnx_hw->wiphy->bands[band];
|
||||||
|
memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
|
||||||
|
if (ht_cap.ht_supported && !ap_sta->ht && sta->ht) {
|
||||||
|
pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation));
|
||||||
|
/* send an empty HT operation IE */
|
||||||
|
rwnx_ie_build_ht_oper(rwnx_hw, rwnx_vif, pos, &ht_cap, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
rwnx_tdls_add_link_ie(rwnx_hw, rwnx_vif, skb, peer, initiator);
|
||||||
|
|
||||||
|
memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap));
|
||||||
|
if (vht_cap.vht_supported && !ap_sta->vht && sta->vht) {
|
||||||
|
pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_operation));
|
||||||
|
rwnx_ie_build_vht_oper(rwnx_hw, rwnx_vif, pos, &ht_cap, 0);
|
||||||
|
// Operating mode Notification (optional)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add any remaining IEs */
|
||||||
|
if (extra_ies_len) {
|
||||||
|
noffset = extra_ies_len;
|
||||||
|
pos = skb_put(skb, noffset - offset);
|
||||||
|
memcpy(pos, extra_ies + offset, noffset - offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rwnx_tdls_add_ies(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
|
||||||
|
struct sk_buff *skb, const u8 *peer,
|
||||||
|
u8 action_code, u16 status_code,
|
||||||
|
bool initiator, const u8 *extra_ies,
|
||||||
|
size_t extra_ies_len, u8 oper_class,
|
||||||
|
struct cfg80211_chan_def *chandef)
|
||||||
|
{
|
||||||
|
switch (action_code) {
|
||||||
|
case WLAN_TDLS_SETUP_REQUEST:
|
||||||
|
case WLAN_TDLS_SETUP_RESPONSE:
|
||||||
|
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
|
||||||
|
if (status_code == 0)
|
||||||
|
rwnx_tdls_add_setup_start_ies(rwnx_hw, rwnx_vif, skb, peer, action_code,
|
||||||
|
initiator, extra_ies, extra_ies_len);
|
||||||
|
break;
|
||||||
|
case WLAN_TDLS_SETUP_CONFIRM:
|
||||||
|
if (status_code == 0)
|
||||||
|
rwnx_tdls_add_setup_cfm_ies(rwnx_hw, rwnx_vif, skb, peer, initiator,
|
||||||
|
extra_ies, extra_ies_len);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WLAN_TDLS_TEARDOWN:
|
||||||
|
case WLAN_TDLS_DISCOVERY_REQUEST:
|
||||||
|
if (extra_ies_len)
|
||||||
|
memcpy(skb_put(skb, extra_ies_len), extra_ies,
|
||||||
|
extra_ies_len);
|
||||||
|
if (status_code == 0 || action_code == WLAN_TDLS_TEARDOWN)
|
||||||
|
rwnx_tdls_add_link_ie(rwnx_hw, rwnx_vif, skb, peer, initiator);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rwnx_tdls_send_mgmt_packet_data(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
|
||||||
|
const u8 *peer, u8 action_code, u8 dialog_token,
|
||||||
|
u16 status_code, u32 peer_capability, bool initiator,
|
||||||
|
const u8 *extra_ies, size_t extra_ies_len, u8 oper_class,
|
||||||
|
struct cfg80211_chan_def *chandef)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int ret = 0;
|
||||||
|
struct ieee80211_supported_band *rwnx_band_2GHz = rwnx_hw->wiphy->bands[NL80211_BAND_2GHZ];
|
||||||
|
//#ifdef USE_5G
|
||||||
|
struct ieee80211_supported_band *rwnx_band_5GHz = rwnx_hw->wiphy->bands[NL80211_BAND_5GHZ];
|
||||||
|
//#endif
|
||||||
|
int channels = rwnx_band_2GHz->n_channels;
|
||||||
|
|
||||||
|
if (rwnx_hw->band_5g_support){
|
||||||
|
channels += rwnx_band_5GHz->n_channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
skb = netdev_alloc_skb(rwnx_vif->ndev,
|
||||||
|
sizeof(struct ieee80211_tdls_data) + // ethhdr + TDLS info
|
||||||
|
10 + /* supported rates */
|
||||||
|
6 + /* extended supported rates */
|
||||||
|
(2 + channels) + /* supported channels */
|
||||||
|
//#ifdef USE_5G
|
||||||
|
//(2 + rwnx_band_2GHz->n_channels + rwnx_band_5GHz->n_channels) + /* supported channels */
|
||||||
|
//#else
|
||||||
|
//(2 + rwnx_band_2GHz->n_channels) + /* supported channels */
|
||||||
|
//#endif
|
||||||
|
sizeof(struct ieee_types_extcap) +
|
||||||
|
sizeof(struct ieee80211_wmm_param_ie) +
|
||||||
|
4 + /* oper classes */
|
||||||
|
28 + //sizeof(struct ieee80211_ht_cap) +
|
||||||
|
sizeof(struct ieee_types_bss_co_2040) +
|
||||||
|
sizeof(struct ieee80211_tdls_lnkie) +
|
||||||
|
(2 + sizeof(struct ieee80211_vht_cap)) +
|
||||||
|
4 + /*AID*/
|
||||||
|
(2 + sizeof(struct ieee80211_ht_operation)) +
|
||||||
|
extra_ies_len);
|
||||||
|
|
||||||
|
if (!skb)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch (action_code) {
|
||||||
|
case WLAN_TDLS_SETUP_REQUEST:
|
||||||
|
case WLAN_TDLS_SETUP_RESPONSE:
|
||||||
|
case WLAN_TDLS_SETUP_CONFIRM:
|
||||||
|
case WLAN_TDLS_TEARDOWN:
|
||||||
|
case WLAN_TDLS_DISCOVERY_REQUEST:
|
||||||
|
ret = rwnx_tdls_prepare_encap_data(rwnx_hw, rwnx_vif, peer, action_code,
|
||||||
|
dialog_token, status_code, skb);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
|
||||||
|
ret = rwnx_prep_tdls_direct(rwnx_hw, rwnx_vif, peer, action_code,
|
||||||
|
dialog_token, status_code, skb);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = -ENOTSUPP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
rwnx_tdls_add_ies(rwnx_hw, rwnx_vif, skb, peer, action_code, status_code,
|
||||||
|
initiator, extra_ies, extra_ies_len, oper_class, chandef);
|
||||||
|
|
||||||
|
if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) {
|
||||||
|
u64 cookie;
|
||||||
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
|
||||||
|
struct cfg80211_mgmt_tx_params params;
|
||||||
|
|
||||||
|
params.len = skb->len;
|
||||||
|
params.buf = skb->data;
|
||||||
|
ret = rwnx_start_mgmt_xmit(rwnx_vif, NULL, ¶ms, false, &cookie);
|
||||||
|
#else
|
||||||
|
ret = rwnx_start_mgmt_xmit(rwnx_vif, NULL, NULL, false, 0, skb->data, skb->len, false, false, &cookie);
|
||||||
|
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (action_code) {
|
||||||
|
case WLAN_TDLS_SETUP_REQUEST:
|
||||||
|
case WLAN_TDLS_SETUP_RESPONSE:
|
||||||
|
case WLAN_TDLS_SETUP_CONFIRM:
|
||||||
|
skb->priority = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
skb->priority = 5;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = rwnx_select_txq(rwnx_vif, skb);
|
||||||
|
ret = rwnx_start_xmit(skb, rwnx_vif->ndev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
dev_kfree_skb(skb);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_tdls.h
|
||||||
|
*
|
||||||
|
* @brief TDLS function declarations
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RWNX_TDLS_H_
|
||||||
|
#define RWNX_TDLS_H_
|
||||||
|
|
||||||
|
#include "rwnx_defs.h"
|
||||||
|
|
||||||
|
struct ieee_types_header {
|
||||||
|
u8 element_id;
|
||||||
|
u8 len;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct ieee_types_bss_co_2040 {
|
||||||
|
struct ieee_types_header ieee_hdr;
|
||||||
|
u8 bss_2040co;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct ieee_types_extcap {
|
||||||
|
struct ieee_types_header ieee_hdr;
|
||||||
|
u8 ext_capab[8];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct ieee_types_vht_cap {
|
||||||
|
struct ieee_types_header ieee_hdr;
|
||||||
|
struct ieee80211_vht_cap vhtcap;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct ieee_types_vht_oper {
|
||||||
|
struct ieee_types_header ieee_hdr;
|
||||||
|
struct ieee80211_vht_operation vhtoper;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct ieee_types_aid {
|
||||||
|
struct ieee_types_header ieee_hdr;
|
||||||
|
u16 aid;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
int rwnx_tdls_send_mgmt_packet_data(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
|
||||||
|
const u8 *peer, u8 action_code, u8 dialog_token,
|
||||||
|
u16 status_code, u32 peer_capability, bool initiator,
|
||||||
|
const u8 *extra_ies, size_t extra_ies_len, u8 oper_class,
|
||||||
|
struct cfg80211_chan_def *chandef);
|
||||||
|
|
||||||
|
#endif /* RWNX_TDLS_H_ */
|
||||||
@@ -0,0 +1,226 @@
|
|||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
*
|
||||||
|
* @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 ***/
|
||||||
|
if ((status = rwnx_send_dbg_mem_read_req(rwnx_hw, mem_addr, &mem_read_cfm)))
|
||||||
|
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 */
|
||||||
|
if ((status = rwnx_send_dbg_mem_write_req(rwnx_hw, mem_addr, val32)))
|
||||||
|
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 */
|
||||||
|
if ((status = rwnx_send_dbg_set_mod_filter_req(rwnx_hw, filter)))
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RWNX_TM_CMD_APP2DEV_SET_DBGSEVFILTER:
|
||||||
|
{
|
||||||
|
/* Send the command to the LMAC */
|
||||||
|
if ((status = rwnx_send_dbg_set_sev_filter_req(rwnx_hw, filter)))
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_testmode.h
|
||||||
|
*
|
||||||
|
* @brief Test mode function declarations
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RWNX_TESTMODE_H_
|
||||||
|
#define RWNX_TESTMODE_H_
|
||||||
|
|
||||||
|
#include <net/mac80211.h>
|
||||||
|
#include <net/netlink.h>
|
||||||
|
|
||||||
|
/* Commands from user space to kernel space(RWNX_TM_CMD_APP2DEV_XX) and
|
||||||
|
* from and kernel space to user space(RWNX_TM_CMD_DEV2APP_XX).
|
||||||
|
* The command ID is carried with RWNX_TM_ATTR_COMMAND.
|
||||||
|
*/
|
||||||
|
enum rwnx_tm_cmd_t {
|
||||||
|
/* commands from user application to access register */
|
||||||
|
RWNX_TM_CMD_APP2DEV_REG_READ = 1,
|
||||||
|
RWNX_TM_CMD_APP2DEV_REG_WRITE,
|
||||||
|
|
||||||
|
/* commands from user application to select the Debug levels */
|
||||||
|
RWNX_TM_CMD_APP2DEV_SET_DBGMODFILTER,
|
||||||
|
RWNX_TM_CMD_APP2DEV_SET_DBGSEVFILTER,
|
||||||
|
|
||||||
|
/* commands to access registers without sending messages to LMAC layer,
|
||||||
|
* this must be used when LMAC FW is stuck. */
|
||||||
|
RWNX_TM_CMD_APP2DEV_REG_READ_DBG,
|
||||||
|
RWNX_TM_CMD_APP2DEV_REG_WRITE_DBG,
|
||||||
|
|
||||||
|
RWNX_TM_CMD_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum rwnx_tm_attr_t {
|
||||||
|
RWNX_TM_ATTR_NOT_APPLICABLE = 0,
|
||||||
|
|
||||||
|
RWNX_TM_ATTR_COMMAND,
|
||||||
|
|
||||||
|
/* When RWNX_TM_ATTR_COMMAND is RWNX_TM_CMD_APP2DEV_REG_XXX,
|
||||||
|
* The mandatory fields are:
|
||||||
|
* RWNX_TM_ATTR_REG_OFFSET for the offset of the target register;
|
||||||
|
* RWNX_TM_ATTR_REG_VALUE32 for value */
|
||||||
|
RWNX_TM_ATTR_REG_OFFSET,
|
||||||
|
RWNX_TM_ATTR_REG_VALUE32,
|
||||||
|
|
||||||
|
/* When RWNX_TM_ATTR_COMMAND is RWNX_TM_CMD_APP2DEV_SET_DBGXXXFILTER,
|
||||||
|
* The mandatory field is RWNX_TM_ATTR_REG_FILTER. */
|
||||||
|
RWNX_TM_ATTR_REG_FILTER,
|
||||||
|
|
||||||
|
RWNX_TM_ATTR_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
int rwnx_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb);
|
||||||
|
int rwnx_testmode_dbg_filter(struct ieee80211_hw *hw, struct nlattr **tb);
|
||||||
|
int rwnx_testmode_reg_dbg(struct ieee80211_hw *hw, struct nlattr **tb);
|
||||||
|
|
||||||
|
#endif /* RWNX_TESTMODE_H_ */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,198 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_tx.h
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
#ifndef _RWNX_TX_H_
|
||||||
|
#define _RWNX_TX_H_
|
||||||
|
|
||||||
|
#include <linux/ieee80211.h>
|
||||||
|
#include <net/cfg80211.h>
|
||||||
|
#include <linux/netdevice.h>
|
||||||
|
#include "lmac_types.h"
|
||||||
|
#include "ipc_shared.h"
|
||||||
|
#include "rwnx_txq.h"
|
||||||
|
#include "hal_desc.h"
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
|
||||||
|
#define IEEE80211_NUM_TIDS 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define RWNX_HWQ_BK 0
|
||||||
|
#define RWNX_HWQ_BE 1
|
||||||
|
#define RWNX_HWQ_VI 2
|
||||||
|
#define RWNX_HWQ_VO 3
|
||||||
|
#define RWNX_HWQ_BCMC 4
|
||||||
|
#define RWNX_HWQ_NB NX_TXQ_CNT
|
||||||
|
#define RWNX_HWQ_ALL_ACS (RWNX_HWQ_BK | RWNX_HWQ_BE | RWNX_HWQ_VI | RWNX_HWQ_VO)
|
||||||
|
#define RWNX_HWQ_ALL_ACS_BIT ( BIT(RWNX_HWQ_BK) | BIT(RWNX_HWQ_BE) | \
|
||||||
|
BIT(RWNX_HWQ_VI) | BIT(RWNX_HWQ_VO) )
|
||||||
|
|
||||||
|
#define RWNX_TX_LIFETIME_MS 1000
|
||||||
|
#define RWNX_TX_MAX_RATES NX_TX_MAX_RATES
|
||||||
|
|
||||||
|
#define RWNX_SWTXHDR_ALIGN_SZ 4
|
||||||
|
#define RWNX_SWTXHDR_ALIGN_MSK (RWNX_SWTXHDR_ALIGN_SZ - 1)
|
||||||
|
#define RWNX_SWTXHDR_ALIGN_PADS(x) \
|
||||||
|
((RWNX_SWTXHDR_ALIGN_SZ - ((x) & RWNX_SWTXHDR_ALIGN_MSK)) \
|
||||||
|
& RWNX_SWTXHDR_ALIGN_MSK)
|
||||||
|
#if RWNX_SWTXHDR_ALIGN_SZ & RWNX_SWTXHDR_ALIGN_MSK
|
||||||
|
#error bad RWNX_SWTXHDR_ALIGN_SZ
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define AMSDU_PADDING(x) ((4 - ((x) & 0x3)) & 0x3)
|
||||||
|
|
||||||
|
#define TXU_CNTRL_RETRY BIT(0)
|
||||||
|
#define TXU_CNTRL_MORE_DATA BIT(2)
|
||||||
|
#define TXU_CNTRL_MGMT BIT(3)
|
||||||
|
#define TXU_CNTRL_MGMT_NO_CCK BIT(4)
|
||||||
|
#define TXU_CNTRL_AMSDU BIT(6)
|
||||||
|
#define TXU_CNTRL_MGMT_ROBUST BIT(7)
|
||||||
|
#define TXU_CNTRL_USE_4ADDR BIT(8)
|
||||||
|
#define TXU_CNTRL_EOSP BIT(9)
|
||||||
|
#define TXU_CNTRL_MESH_FWD BIT(10)
|
||||||
|
#define TXU_CNTRL_TDLS BIT(11)
|
||||||
|
|
||||||
|
extern const int rwnx_tid2hwq[IEEE80211_NUM_TIDS];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_amsdu_txhdr - Structure added in skb headroom (instead of
|
||||||
|
* rwnx_txhdr) for amsdu subframe buffer (except for the first subframe
|
||||||
|
* that has a normal rwnx_txhdr)
|
||||||
|
*
|
||||||
|
* @list List of other amsdu subframe (rwnx_sw_txhdr.amsdu.hdrs)
|
||||||
|
* @map_len Length to be downloaded for this subframe
|
||||||
|
* @dma_addr Buffer address form embedded point of view
|
||||||
|
* @skb skb
|
||||||
|
* @pad padding added before this subframe
|
||||||
|
* (only use when amsdu must be dismantled)
|
||||||
|
* @msdu_len Size, in bytes, of the MSDU (without padding nor amsdu header)
|
||||||
|
*/
|
||||||
|
struct rwnx_amsdu_txhdr {
|
||||||
|
struct list_head list;
|
||||||
|
size_t map_len;
|
||||||
|
dma_addr_t dma_addr;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
u16 pad;
|
||||||
|
u16 msdu_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_amsdu - Structure to manage creation of an A-MSDU, updated
|
||||||
|
* only In the first subframe of an A-MSDU
|
||||||
|
*
|
||||||
|
* @hdrs List of subframe of rwnx_amsdu_txhdr
|
||||||
|
* @len Current size for this A-MDSU (doesn't take padding into account)
|
||||||
|
* 0 means that no amsdu is in progress
|
||||||
|
* @nb Number of subframe in the amsdu
|
||||||
|
* @pad Padding to add before adding a new subframe
|
||||||
|
*/
|
||||||
|
struct rwnx_amsdu {
|
||||||
|
struct list_head hdrs;
|
||||||
|
u16 len;
|
||||||
|
u8 nb;
|
||||||
|
u8 pad;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_sw_txhdr - Software part of tx header
|
||||||
|
*
|
||||||
|
* @rwnx_sta sta to which this buffer is addressed
|
||||||
|
* @rwnx_vif vif that send the buffer
|
||||||
|
* @txq pointer to TXQ used to send the buffer
|
||||||
|
* @hw_queue Index of the HWQ used to push the buffer.
|
||||||
|
* May be different than txq->hwq->id on confirmation.
|
||||||
|
* @frame_len Size of the frame (doesn't not include mac header)
|
||||||
|
* (Only used to update stat, can't we use skb->len instead ?)
|
||||||
|
* @headroom Headroom added in skb to add rwnx_txhdr
|
||||||
|
* (Only used to remove it before freeing skb, is it needed ?)
|
||||||
|
* @amsdu Description of amsdu whose first subframe is this buffer
|
||||||
|
* (amsdu.nb = 0 means this buffer is not part of amsdu)
|
||||||
|
* @skb skb received from transmission
|
||||||
|
* @map_len Length mapped for DMA (only rwnx_hw_txhdr and data are mapped)
|
||||||
|
* @dma_addr DMA address after mapping
|
||||||
|
* @desc Buffer description that will be copied in shared mem for FW
|
||||||
|
*/
|
||||||
|
struct rwnx_sw_txhdr {
|
||||||
|
struct rwnx_sta *rwnx_sta;
|
||||||
|
struct rwnx_vif *rwnx_vif;
|
||||||
|
struct rwnx_txq *txq;
|
||||||
|
u8 hw_queue;
|
||||||
|
u16 frame_len;
|
||||||
|
u16 headroom;
|
||||||
|
#ifdef CONFIG_RWNX_AMSDUS_TX
|
||||||
|
struct rwnx_amsdu amsdu;
|
||||||
|
#endif
|
||||||
|
u32 need_cfm;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
size_t map_len;
|
||||||
|
dma_addr_t dma_addr;
|
||||||
|
struct txdesc_api desc;
|
||||||
|
u8 raw_frame;
|
||||||
|
u8 fixed_rate;
|
||||||
|
u16 rate_config;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_txhdr - Stucture to control transimission of packet
|
||||||
|
* (Added in skb headroom)
|
||||||
|
*
|
||||||
|
* @sw_hdr: Information from driver
|
||||||
|
* @cache_guard:
|
||||||
|
* @hw_hdr: Information for/from hardware
|
||||||
|
*/
|
||||||
|
struct rwnx_txhdr {
|
||||||
|
struct rwnx_sw_txhdr *sw_hdr;
|
||||||
|
char cache_guard[L1_CACHE_BYTES];
|
||||||
|
struct rwnx_hw_txhdr hw_hdr;
|
||||||
|
};
|
||||||
|
|
||||||
|
u16 rwnx_select_txq(struct rwnx_vif *rwnx_vif, struct sk_buff *skb);
|
||||||
|
netdev_tx_t rwnx_start_xmit(struct sk_buff *skb, struct net_device *dev);
|
||||||
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
|
||||||
|
int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta,
|
||||||
|
struct cfg80211_mgmt_tx_params *params, bool offchan,
|
||||||
|
u64 *cookie);
|
||||||
|
#else
|
||||||
|
int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta,
|
||||||
|
struct ieee80211_channel *channel, bool offchan,
|
||||||
|
unsigned int wait, const u8* buf, size_t len,
|
||||||
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
|
||||||
|
bool no_cck,
|
||||||
|
#endif
|
||||||
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
|
||||||
|
bool dont_wait_for_ack,
|
||||||
|
#endif
|
||||||
|
u64 *cookie);
|
||||||
|
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
|
||||||
|
#ifdef CONFIG_RWNX_MON_XMIT
|
||||||
|
int rwnx_start_monitor_if_xmit(struct sk_buff *skb, struct net_device *dev);
|
||||||
|
#endif
|
||||||
|
int rwnx_txdatacfm(void *pthis, void *host_id);
|
||||||
|
|
||||||
|
struct rwnx_hw;
|
||||||
|
struct rwnx_sta;
|
||||||
|
void rwnx_set_traffic_status(struct rwnx_hw *rwnx_hw,
|
||||||
|
struct rwnx_sta *sta,
|
||||||
|
bool available,
|
||||||
|
u8 ps_id);
|
||||||
|
void rwnx_ps_bh_enable(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
|
||||||
|
bool enable);
|
||||||
|
void rwnx_ps_bh_traffic_req(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
|
||||||
|
u16 pkt_req, u8 ps_id);
|
||||||
|
|
||||||
|
void rwnx_switch_vif_sta_txq(struct rwnx_sta *sta, struct rwnx_vif *old_vif,
|
||||||
|
struct rwnx_vif *new_vif);
|
||||||
|
|
||||||
|
int rwnx_dbgfs_print_sta(char *buf, size_t size, struct rwnx_sta *sta,
|
||||||
|
struct rwnx_hw *rwnx_hw);
|
||||||
|
void rwnx_txq_credit_update(struct rwnx_hw *rwnx_hw, int sta_idx, u8 tid,
|
||||||
|
s8 update);
|
||||||
|
void rwnx_tx_push(struct rwnx_hw *rwnx_hw, struct rwnx_txhdr *txhdr, int flags);
|
||||||
|
|
||||||
|
#endif /* _RWNX_TX_H_ */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,397 @@
|
|||||||
|
/**
|
||||||
|
****************************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_txq.h
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
****************************************************************************************
|
||||||
|
*/
|
||||||
|
#ifndef _RWNX_TXQ_H_
|
||||||
|
#define _RWNX_TXQ_H_
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/ieee80211.h>
|
||||||
|
|
||||||
|
#include <net/mac80211.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
/**
|
||||||
|
* Fullmac TXQ configuration:
|
||||||
|
* - STA: 1 TXQ per TID (limited to 8)
|
||||||
|
* 1 TXQ for bufferable MGT frames
|
||||||
|
* - VIF: 1 TXQ for Multi/Broadcast +
|
||||||
|
* 1 TXQ for MGT for unknown STAs or non-bufferable MGT frames
|
||||||
|
* - 1 TXQ for offchannel transmissions
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Txq mapping looks like
|
||||||
|
* for NX_REMOTE_STA_MAX=10 and NX_VIRT_DEV_MAX=4
|
||||||
|
*
|
||||||
|
* | TXQ | NDEV_ID | VIF | STA | TID | HWQ |
|
||||||
|
* |-----+---------+-----+-------+------+-----|-
|
||||||
|
* | 0 | 0 | | 0 | 0 | 1 | 9 TXQ per STA
|
||||||
|
* | 1 | 1 | | 0 | 1 | 0 | (8 data + 1 mgmt)
|
||||||
|
* | 2 | 2 | | 0 | 2 | 0 |
|
||||||
|
* | 3 | 3 | | 0 | 3 | 1 |
|
||||||
|
* | 4 | 4 | | 0 | 4 | 2 |
|
||||||
|
* | 5 | 5 | | 0 | 5 | 2 |
|
||||||
|
* | 6 | 6 | | 0 | 6 | 3 |
|
||||||
|
* | 7 | 7 | | 0 | 7 | 3 |
|
||||||
|
* | 8 | N/A | | 0 | MGMT | 3 |
|
||||||
|
* |-----+---------+-----+-------+------+-----|-
|
||||||
|
* | ... | | | | | | Same for all STAs
|
||||||
|
* |-----+---------+-----+-------+------+-----|-
|
||||||
|
* | 90 | 80 | 0 | BC/MC | 0 | 1/4 | 1 TXQ for BC/MC per VIF
|
||||||
|
* | ... | | | | | |
|
||||||
|
* | 93 | 80 | 3 | BC/MC | 0 | 1/4 |
|
||||||
|
* |-----+---------+-----+-------+------+-----|-
|
||||||
|
* | 94 | N/A | 0 | N/A | MGMT | 3 | 1 TXQ for unknown STA per VIF
|
||||||
|
* | ... | | | | | |
|
||||||
|
* | 97 | N/A | 3 | N/A | MGMT | 3 |
|
||||||
|
* |-----+---------+-----+-------+------+-----|-
|
||||||
|
* | 98 | N/A | | N/A | MGMT | 3 | 1 TXQ for offchannel frame
|
||||||
|
*/
|
||||||
|
#define NX_NB_TID_PER_STA 8
|
||||||
|
#define NX_NB_TXQ_PER_STA (NX_NB_TID_PER_STA + 1)
|
||||||
|
#define NX_NB_TXQ_PER_VIF 2
|
||||||
|
#define NX_NB_TXQ ((NX_NB_TXQ_PER_STA * NX_REMOTE_STA_MAX) + \
|
||||||
|
(NX_NB_TXQ_PER_VIF * NX_VIRT_DEV_MAX) + 1)
|
||||||
|
|
||||||
|
#define NX_FIRST_VIF_TXQ_IDX (NX_REMOTE_STA_MAX * NX_NB_TXQ_PER_STA)
|
||||||
|
#define NX_FIRST_BCMC_TXQ_IDX NX_FIRST_VIF_TXQ_IDX
|
||||||
|
#define NX_FIRST_UNK_TXQ_IDX (NX_FIRST_BCMC_TXQ_IDX + NX_VIRT_DEV_MAX)
|
||||||
|
|
||||||
|
#define NX_FIRST_VIF_TXQ_IDX_FOR_OLD_IC (NX_REMOTE_STA_MAX_FOR_OLD_IC * NX_NB_TXQ_PER_STA)
|
||||||
|
#define NX_FIRST_BCMC_TXQ_IDX_FOR_OLD_IC NX_FIRST_VIF_TXQ_IDX_FOR_OLD_IC
|
||||||
|
#define NX_FIRST_UNK_TXQ_IDX_FOR_OLD_IC (NX_FIRST_BCMC_TXQ_IDX_FOR_OLD_IC + NX_VIRT_DEV_MAX)
|
||||||
|
|
||||||
|
|
||||||
|
#define NX_OFF_CHAN_TXQ_IDX (NX_FIRST_VIF_TXQ_IDX + \
|
||||||
|
(NX_VIRT_DEV_MAX * NX_NB_TXQ_PER_VIF))
|
||||||
|
|
||||||
|
#define NX_OFF_CHAN_TXQ_IDX_FOR_OLD_IC (NX_FIRST_VIF_TXQ_IDX_FOR_OLD_IC + \
|
||||||
|
(NX_VIRT_DEV_MAX * NX_NB_TXQ_PER_VIF))
|
||||||
|
|
||||||
|
|
||||||
|
#define NX_BCMC_TXQ_TYPE 0
|
||||||
|
#define NX_UNK_TXQ_TYPE 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Each data TXQ is a netdev queue. TXQ to send MGT are not data TXQ as
|
||||||
|
* they did not recieved buffer from netdev interface.
|
||||||
|
* Need to allocate the maximum case.
|
||||||
|
* AP : all STAs + 1 BC/MC
|
||||||
|
*/
|
||||||
|
#define NX_NB_NDEV_TXQ ((NX_NB_TID_PER_STA * NX_REMOTE_STA_MAX) + 1 )
|
||||||
|
#define NX_NB_NDEV_TXQ_FOR_OLD_IC ((NX_NB_TID_PER_STA * NX_REMOTE_STA_MAX_FOR_OLD_IC) + 1)
|
||||||
|
|
||||||
|
#define NX_BCMC_TXQ_NDEV_IDX (NX_NB_TID_PER_STA * NX_REMOTE_STA_MAX)
|
||||||
|
#define NX_BCMC_TXQ_NDEV_IDX_FOR_OLD_IC (NX_NB_TID_PER_STA * NX_REMOTE_STA_MAX_FOR_OLD_IC)
|
||||||
|
#define NX_STA_NDEV_IDX(tid, sta_idx) ((tid) + (sta_idx) * NX_NB_TID_PER_STA)
|
||||||
|
#define NDEV_NO_TXQ 0xffff
|
||||||
|
#if (NX_NB_NDEV_TXQ >= NDEV_NO_TXQ)
|
||||||
|
#error("Need to increase struct rwnx_txq->ndev_idx size")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* stop netdev queue when number of queued buffers if greater than this */
|
||||||
|
#define RWNX_NDEV_FLOW_CTRL_STOP 64
|
||||||
|
/* restart netdev queue when number of queued buffers is lower than this */
|
||||||
|
#define RWNX_NDEV_FLOW_CTRL_RESTART 64
|
||||||
|
|
||||||
|
#endif /* CONFIG_RWNX_FULLMAC */
|
||||||
|
|
||||||
|
#define TXQ_INACTIVE 0xffff
|
||||||
|
#if (NX_NB_TXQ >= TXQ_INACTIVE)
|
||||||
|
#error("Need to increase struct rwnx_txq->idx size")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NX_TXQ_INITIAL_CREDITS 64
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TXQ tid sorted by decreasing priority
|
||||||
|
*/
|
||||||
|
extern const int nx_tid_prio[NX_NB_TID_PER_STA];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_hwq - Structure used to save information relative to
|
||||||
|
* an AC TX queue (aka HW queue)
|
||||||
|
* @list: List of TXQ, that have buffers ready for this HWQ
|
||||||
|
* @credits: available credit for the queue (i.e. nb of buffers that
|
||||||
|
* can be pushed to FW )
|
||||||
|
* @id Id of the HWQ among RWNX_HWQ_....
|
||||||
|
* @size size of the queue
|
||||||
|
* @need_processing Indicate if hwq should be processed
|
||||||
|
* @len number of packet ready to be pushed to fw for this HW queue
|
||||||
|
* @len_stop threshold to stop mac80211(i.e. netdev) queues. Stop queue when
|
||||||
|
* driver has more than @len_stop packets ready.
|
||||||
|
* @len_start threshold to wake mac8011 queues. Wake queue when driver has
|
||||||
|
* less than @len_start packets ready.
|
||||||
|
*/
|
||||||
|
struct rwnx_hwq {
|
||||||
|
struct list_head list;
|
||||||
|
u8 size;
|
||||||
|
u8 id;
|
||||||
|
bool need_processing;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum rwnx_push_flags - Flags of pushed buffer
|
||||||
|
*
|
||||||
|
* @RWNX_PUSH_RETRY Pushing a buffer for retry
|
||||||
|
* @RWNX_PUSH_IMMEDIATE Pushing a buffer without queuing it first
|
||||||
|
*/
|
||||||
|
enum rwnx_push_flags {
|
||||||
|
RWNX_PUSH_RETRY = BIT(0),
|
||||||
|
RWNX_PUSH_IMMEDIATE = BIT(1),
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum rwnx_txq_flags - TXQ status flag
|
||||||
|
*
|
||||||
|
* @RWNX_TXQ_IN_HWQ_LIST: The queue is scheduled for transmission
|
||||||
|
* @RWNX_TXQ_STOP_FULL: No more credits for the queue
|
||||||
|
* @RWNX_TXQ_STOP_CSA: CSA is in progress
|
||||||
|
* @RWNX_TXQ_STOP_STA_PS: Destiniation sta is currently in power save mode
|
||||||
|
* @RWNX_TXQ_STOP_VIF_PS: Vif owning this queue is currently in power save mode
|
||||||
|
* @RWNX_TXQ_STOP_CHAN: Channel of this queue is not the current active channel
|
||||||
|
* @RWNX_TXQ_STOP_MU_POS: TXQ is stopped waiting for all the buffers pushed to
|
||||||
|
* fw to be confirmed
|
||||||
|
* @RWNX_TXQ_STOP: All possible reason to have a txq stopped
|
||||||
|
* @RWNX_TXQ_NDEV_FLOW_CTRL: associated netdev queue is currently stopped.
|
||||||
|
* Note: when a TXQ is flowctrl it is NOT stopped
|
||||||
|
*/
|
||||||
|
enum rwnx_txq_flags {
|
||||||
|
RWNX_TXQ_IN_HWQ_LIST = BIT(0),
|
||||||
|
RWNX_TXQ_STOP_FULL = BIT(1),
|
||||||
|
RWNX_TXQ_STOP_CSA = BIT(2),
|
||||||
|
RWNX_TXQ_STOP_STA_PS = BIT(3),
|
||||||
|
RWNX_TXQ_STOP_VIF_PS = BIT(4),
|
||||||
|
RWNX_TXQ_STOP_CHAN = BIT(5),
|
||||||
|
RWNX_TXQ_STOP_MU_POS = BIT(6),
|
||||||
|
RWNX_TXQ_STOP = (RWNX_TXQ_STOP_FULL | RWNX_TXQ_STOP_CSA |
|
||||||
|
RWNX_TXQ_STOP_STA_PS | RWNX_TXQ_STOP_VIF_PS |
|
||||||
|
RWNX_TXQ_STOP_CHAN) ,
|
||||||
|
RWNX_TXQ_NDEV_FLOW_CTRL = BIT(7),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_txq - Structure used to save information relative to
|
||||||
|
* a RA/TID TX queue
|
||||||
|
*
|
||||||
|
* @idx: Unique txq idx. Set to TXQ_INACTIVE if txq is not used.
|
||||||
|
* @status: bitfield of @rwnx_txq_flags.
|
||||||
|
* @credits: available credit for the queue (i.e. nb of buffers that
|
||||||
|
* can be pushed to FW).
|
||||||
|
* @pkt_sent: number of consecutive pkt sent without leaving HW queue list
|
||||||
|
* @pkt_pushed: number of pkt currently pending for transmission confirmation
|
||||||
|
* @sched_list: list node for HW queue schedule list (rwnx_hwq.list)
|
||||||
|
* @sk_list: list of buffers to push to fw
|
||||||
|
* @last_retry_skb: pointer on the last skb in @sk_list that is a retry.
|
||||||
|
* (retry skb are stored at the beginning of the list)
|
||||||
|
* NULL if no retry skb is queued in @sk_list
|
||||||
|
* @nb_retry: Number of retry packet queued.
|
||||||
|
* @hwq: Pointer on the associated HW queue.
|
||||||
|
* @push_limit: number of packet to push before removing the txq from hwq list.
|
||||||
|
* (we always have push_limit < skb_queue_len(sk_list))
|
||||||
|
* @tid: TID
|
||||||
|
*
|
||||||
|
* FULLMAC specific
|
||||||
|
* @ps_id: Index to use for Power save mode (LEGACY or UAPSD)
|
||||||
|
* @ndev_idx: txq idx from netdev point of view (0xFF for non netdev queue)
|
||||||
|
* @ndev: pointer to ndev of the corresponding vif
|
||||||
|
* @amsdu: pointer to rwnx_sw_txhdr of the first subframe of the A-MSDU.
|
||||||
|
* NULL if no A-MSDU frame is in construction
|
||||||
|
* @amsdu_len: Maximum size allowed for an A-MSDU. 0 means A-MSDU not allowed
|
||||||
|
*/
|
||||||
|
struct rwnx_txq {
|
||||||
|
u16 idx;
|
||||||
|
u8 status;
|
||||||
|
s8 credits;
|
||||||
|
u8 pkt_sent;
|
||||||
|
u8 pkt_pushed[CONFIG_USER_MAX];
|
||||||
|
struct list_head sched_list;
|
||||||
|
struct sk_buff_head sk_list;
|
||||||
|
struct sk_buff *last_retry_skb;
|
||||||
|
struct rwnx_hwq *hwq;
|
||||||
|
int nb_retry;
|
||||||
|
u8 push_limit;
|
||||||
|
u8 tid;
|
||||||
|
#ifdef CONFIG_MAC80211_TXQ
|
||||||
|
unsigned long nb_ready_mac80211;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
struct rwnx_sta *sta;
|
||||||
|
u8 ps_id;
|
||||||
|
u16 ndev_idx;
|
||||||
|
struct net_device *ndev;
|
||||||
|
#ifdef CONFIG_RWNX_AMSDUS_TX
|
||||||
|
struct rwnx_sw_txhdr *amsdu;
|
||||||
|
u16 amsdu_len;
|
||||||
|
#endif /* CONFIG_RWNX_AMSDUS_TX */
|
||||||
|
#endif /* CONFIG_RWNX_FULLMAC */
|
||||||
|
#ifdef CONFIG_RWNX_MUMIMO_TX
|
||||||
|
u8 mumimo_info;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rwnx_sta;
|
||||||
|
struct rwnx_vif;
|
||||||
|
struct rwnx_hw;
|
||||||
|
struct rwnx_sw_txhdr;
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_MUMIMO_TX
|
||||||
|
#define RWNX_TXQ_GROUP_ID(txq) ((txq)->mumimo_info & 0x3f)
|
||||||
|
#define RWNX_TXQ_POS_ID(txq) (((txq)->mumimo_info >> 6) & 0x3)
|
||||||
|
#else
|
||||||
|
#define RWNX_TXQ_GROUP_ID(txq) 0
|
||||||
|
#define RWNX_TXQ_POS_ID(txq) 0
|
||||||
|
#endif /* CONFIG_RWNX_MUMIMO_TX */
|
||||||
|
|
||||||
|
static inline bool rwnx_txq_is_stopped(struct rwnx_txq *txq)
|
||||||
|
{
|
||||||
|
return (txq->status & RWNX_TXQ_STOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool rwnx_txq_is_full(struct rwnx_txq *txq)
|
||||||
|
{
|
||||||
|
return (txq->status & RWNX_TXQ_STOP_FULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool rwnx_txq_is_scheduled(struct rwnx_txq *txq)
|
||||||
|
{
|
||||||
|
return (txq->status & RWNX_TXQ_IN_HWQ_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* foreach_sta_txq - Macro to iterate over all TXQ of a STA in increasing
|
||||||
|
* TID order
|
||||||
|
*
|
||||||
|
* @sta: pointer to rwnx_sta
|
||||||
|
* @txq: pointer to rwnx_txq updated with the next TXQ at each iteration
|
||||||
|
* @tid: int updated with the TXQ tid at each iteration
|
||||||
|
* @rwnx_hw: main driver data
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_MAC80211_TXQ
|
||||||
|
#define foreach_sta_txq(sta, txq, tid, rwnx_hw) \
|
||||||
|
for (tid = 0, txq = rwnx_txq_sta_get(sta, 0); \
|
||||||
|
tid < NX_NB_TXQ_PER_STA; \
|
||||||
|
tid++, txq = rwnx_txq_sta_get(sta, tid))
|
||||||
|
|
||||||
|
#elif defined(CONFIG_RWNX_FULLMAC) /* CONFIG_RWNX_FULLMAC */
|
||||||
|
#define foreach_sta_txq(sta, txq, tid, rwnx_hw) \
|
||||||
|
for (tid = 0, txq = rwnx_txq_sta_get(sta, 0, rwnx_hw); \
|
||||||
|
tid < (is_multicast_sta(sta->sta_idx) ? 1 : NX_NB_TXQ_PER_STA); \
|
||||||
|
tid++, txq++)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* foreach_sta_txq_prio - Macro to iterate over all TXQ of a STA in
|
||||||
|
* decreasing priority order
|
||||||
|
*
|
||||||
|
* @sta: pointer to rwnx_sta
|
||||||
|
* @txq: pointer to rwnx_txq updated with the next TXQ at each iteration
|
||||||
|
* @tid: int updated with the TXQ tid at each iteration
|
||||||
|
* @i: int updated with ieration count
|
||||||
|
* @rwnx_hw: main driver data
|
||||||
|
*
|
||||||
|
* Note: For fullmac txq for mgmt frame is skipped
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
#define foreach_sta_txq_prio(sta, txq, tid, i, rwnx_hw) \
|
||||||
|
for (i = 0, tid = nx_tid_prio[0], txq = rwnx_txq_sta_get(sta, tid, rwnx_hw); \
|
||||||
|
i < NX_NB_TID_PER_STA; \
|
||||||
|
i++, tid = nx_tid_prio[i], txq = rwnx_txq_sta_get(sta, tid, rwnx_hw))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* foreach_vif_txq - Macro to iterate over all TXQ of a VIF (in AC order)
|
||||||
|
*
|
||||||
|
* @vif: pointer to rwnx_vif
|
||||||
|
* @txq: pointer to rwnx_txq updated with the next TXQ at each iteration
|
||||||
|
* @ac: int updated with the TXQ ac at each iteration
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_MAC80211_TXQ
|
||||||
|
#define foreach_vif_txq(vif, txq, ac) \
|
||||||
|
for (ac = RWNX_HWQ_BK, txq = rwnx_txq_vif_get(vif, ac); \
|
||||||
|
ac < NX_NB_TXQ_PER_VIF; \
|
||||||
|
ac++, txq = rwnx_txq_vif_get(vif, ac))
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define foreach_vif_txq(vif, txq, ac) \
|
||||||
|
for (ac = RWNX_HWQ_BK, txq = &vif->txqs[0]; \
|
||||||
|
ac < NX_NB_TXQ_PER_VIF; \
|
||||||
|
ac++, txq++)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
struct rwnx_txq *rwnx_txq_sta_get(struct rwnx_sta *sta, u8 tid,
|
||||||
|
struct rwnx_hw * rwnx_hw);
|
||||||
|
struct rwnx_txq *rwnx_txq_vif_get(struct rwnx_vif *vif, u8 type);
|
||||||
|
#endif /* CONFIG_RWNX_FULLMAC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_txq_vif_get_status - return status bits related to the vif
|
||||||
|
*
|
||||||
|
* @rwnx_vif: Pointer to vif structure
|
||||||
|
*/
|
||||||
|
static inline u8 rwnx_txq_vif_get_status(struct rwnx_vif *rwnx_vif)
|
||||||
|
{
|
||||||
|
struct rwnx_txq *txq = rwnx_txq_vif_get(rwnx_vif, 0);
|
||||||
|
return (txq->status & (RWNX_TXQ_STOP_CHAN | RWNX_TXQ_STOP_VIF_PS));
|
||||||
|
}
|
||||||
|
|
||||||
|
void rwnx_txq_vif_init(struct rwnx_hw * rwnx_hw, struct rwnx_vif *vif,
|
||||||
|
u8 status);
|
||||||
|
void rwnx_txq_vif_deinit(struct rwnx_hw * rwnx_hw, struct rwnx_vif *vif);
|
||||||
|
void rwnx_txq_sta_init(struct rwnx_hw * rwnx_hw, struct rwnx_sta *rwnx_sta,
|
||||||
|
u8 status);
|
||||||
|
void rwnx_txq_sta_deinit(struct rwnx_hw * rwnx_hw, struct rwnx_sta *rwnx_sta);
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
void rwnx_txq_unk_vif_init(struct rwnx_vif *rwnx_vif);
|
||||||
|
void rwnx_txq_unk_vif_deinit(struct rwnx_vif *vif);
|
||||||
|
void rwnx_txq_offchan_init(struct rwnx_vif *rwnx_vif);
|
||||||
|
void rwnx_txq_offchan_deinit(struct rwnx_vif *rwnx_vif);
|
||||||
|
void rwnx_txq_tdls_vif_init(struct rwnx_vif *rwnx_vif);
|
||||||
|
void rwnx_txq_tdls_vif_deinit(struct rwnx_vif *vif);
|
||||||
|
void rwnx_txq_tdls_sta_start(struct rwnx_vif *rwnx_vif, u16 reason,
|
||||||
|
struct rwnx_hw *rwnx_hw);
|
||||||
|
void rwnx_txq_tdls_sta_stop(struct rwnx_vif *rwnx_vif, u16 reason,
|
||||||
|
struct rwnx_hw *rwnx_hw);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void rwnx_txq_add_to_hw_list(struct rwnx_txq *txq);
|
||||||
|
void rwnx_txq_del_from_hw_list(struct rwnx_txq *txq);
|
||||||
|
void rwnx_txq_stop(struct rwnx_txq *txq, u16 reason);
|
||||||
|
void rwnx_txq_start(struct rwnx_txq *txq, u16 reason);
|
||||||
|
void rwnx_txq_vif_start(struct rwnx_vif *vif, u16 reason,
|
||||||
|
struct rwnx_hw *rwnx_hw);
|
||||||
|
void rwnx_txq_vif_stop(struct rwnx_vif *vif, u16 reason,
|
||||||
|
struct rwnx_hw *rwnx_hw);
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
void rwnx_txq_sta_start(struct rwnx_sta *sta, u16 reason,
|
||||||
|
struct rwnx_hw *rwnx_hw);
|
||||||
|
void rwnx_txq_sta_stop(struct rwnx_sta *sta, u16 reason,
|
||||||
|
struct rwnx_hw *rwnx_hw);
|
||||||
|
void rwnx_txq_offchan_start(struct rwnx_hw *rwnx_hw);
|
||||||
|
void rwnx_txq_sta_switch_vif(struct rwnx_sta *sta, struct rwnx_vif *old_vif,
|
||||||
|
struct rwnx_vif *new_vif);
|
||||||
|
|
||||||
|
#endif /* CONFIG_RWNX_FULLMAC */
|
||||||
|
|
||||||
|
int rwnx_txq_queue_skb(struct sk_buff *skb, struct rwnx_txq *txq,
|
||||||
|
struct rwnx_hw *rwnx_hw, bool retry);
|
||||||
|
void rwnx_txq_confirm_any(struct rwnx_hw *rwnx_hw, struct rwnx_txq *txq,
|
||||||
|
struct rwnx_hwq *hwq, struct rwnx_sw_txhdr *sw_txhdr);
|
||||||
|
|
||||||
|
|
||||||
|
void rwnx_hwq_init(struct rwnx_hw *rwnx_hw);
|
||||||
|
void rwnx_hwq_process(struct rwnx_hw *rwnx_hw, struct rwnx_hwq *hwq);
|
||||||
|
void rwnx_hwq_process_all(struct rwnx_hw *rwnx_hw);
|
||||||
|
|
||||||
|
#endif /* _RWNX_TXQ_H_ */
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* rwnx_utils.c
|
||||||
|
*
|
||||||
|
* IPC utility function definitions
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*/
|
||||||
|
#include "rwnx_utils.h"
|
||||||
|
#include "rwnx_defs.h"
|
||||||
|
#include "rwnx_rx.h"
|
||||||
|
#include "rwnx_tx.h"
|
||||||
|
#include "rwnx_msg_rx.h"
|
||||||
|
#include "rwnx_debugfs.h"
|
||||||
|
#include "rwnx_prof.h"
|
||||||
|
#include "ipc_host.h"
|
||||||
|
|
||||||
|
|
||||||
|
extern int get_testmode(void);
|
||||||
|
extern void get_fw_path(char* fw_path);
|
||||||
|
extern int testmode;
|
||||||
|
extern char aic_fw_path[200];
|
||||||
|
|
||||||
|
int rwnx_init_aic(struct rwnx_hw *rwnx_hw)
|
||||||
|
{
|
||||||
|
RWNX_DBG(RWNX_FN_ENTRY_STR);
|
||||||
|
#ifdef AICWF_SDIO_SUPPORT
|
||||||
|
aicwf_sdio_host_init(&(rwnx_hw->sdio_env), NULL, NULL, rwnx_hw);
|
||||||
|
#else
|
||||||
|
aicwf_usb_host_init(&(rwnx_hw->usb_env), NULL, NULL, rwnx_hw);
|
||||||
|
#endif
|
||||||
|
rwnx_cmd_mgr_init(rwnx_hw->cmd_mgr);
|
||||||
|
|
||||||
|
testmode = get_testmode();
|
||||||
|
memset(aic_fw_path, 0, 200);
|
||||||
|
get_fw_path(aic_fw_path);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
/**
|
||||||
|
* rwnx_ipc_utils.h
|
||||||
|
*
|
||||||
|
* IPC utility function declarations
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*/
|
||||||
|
#ifndef _RWNX_IPC_UTILS_H_
|
||||||
|
#define _RWNX_IPC_UTILS_H_
|
||||||
|
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
|
#include <linux/dmapool.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
|
||||||
|
#include "lmac_msg.h"
|
||||||
|
#include "aicwf_debug.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#ifdef CONFIG_RWNX_DBG
|
||||||
|
/* #define RWNX_DBG(format, arg...) pr_warn(format, ## arg) */
|
||||||
|
#define RWNX_DBG printk
|
||||||
|
#else
|
||||||
|
#define RWNX_DBG(a...) do {} while (0)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
enum rwnx_dev_flag {
|
||||||
|
RWNX_DEV_RESTARTING,
|
||||||
|
RWNX_DEV_STACK_RESTARTING,
|
||||||
|
RWNX_DEV_STARTED,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rwnx_hw;
|
||||||
|
struct rwnx_sta;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_ipc_elem - Generic IPC buffer of fixed size
|
||||||
|
*
|
||||||
|
* @addr: Host address of the buffer.
|
||||||
|
* @dma_addr: DMA address of the buffer.
|
||||||
|
*/
|
||||||
|
struct rwnx_ipc_elem {
|
||||||
|
void *addr;
|
||||||
|
dma_addr_t dma_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_ipc_elem_pool - Generic pool of IPC buffers of fixed size
|
||||||
|
*
|
||||||
|
* @nb: Number of buffers currenlty allocated in the pool
|
||||||
|
* @buf: Array of buffers (size of array is @nb)
|
||||||
|
* @pool: DMA pool in which buffers have been allocated
|
||||||
|
*/
|
||||||
|
struct rwnx_ipc_elem_pool {
|
||||||
|
int nb;
|
||||||
|
struct rwnx_ipc_elem *buf;
|
||||||
|
struct dma_pool *pool;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_ipc_elem - Generic IPC buffer of variable size
|
||||||
|
*
|
||||||
|
* @addr: Host address of the buffer.
|
||||||
|
* @dma_addr: DMA address of the buffer.
|
||||||
|
* @size: Size, in bytes, of the buffer
|
||||||
|
*/
|
||||||
|
struct rwnx_ipc_elem_var {
|
||||||
|
void *addr;
|
||||||
|
dma_addr_t dma_addr;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_ipc_dbgdump_elem - IPC buffer for debug dump
|
||||||
|
*
|
||||||
|
* @mutex: Mutex to protect access to debug dump
|
||||||
|
* @buf: IPC buffer
|
||||||
|
*/
|
||||||
|
struct rwnx_ipc_dbgdump_elem {
|
||||||
|
struct mutex mutex;
|
||||||
|
struct rwnx_ipc_elem_var buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u32 rwnx_rxbuff_pattern = 0xCAFEFADE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximum Length of Radiotap header vendor specific data(in bytes)
|
||||||
|
*/
|
||||||
|
#define RADIOTAP_HDR_VEND_MAX_LEN 16
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximum Radiotap Header Length without vendor specific data (in bytes)
|
||||||
|
*/
|
||||||
|
#define RADIOTAP_HDR_MAX_LEN 80
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unsupported HT Frame data length (in bytes)
|
||||||
|
*/
|
||||||
|
#define UNSUP_RX_VEC_DATA_LEN 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_ipc_skb_elem - IPC buffer for SKB element
|
||||||
|
*
|
||||||
|
* @skb: Pointer to the skb buffer allocated
|
||||||
|
* @dma_addr: DMA address of the data buffer fo skb
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct rwnx_ipc_skb_elem {
|
||||||
|
struct sk_buff *skb;
|
||||||
|
dma_addr_t dma_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_RWNX_FULLMAC
|
||||||
|
|
||||||
|
/* Maximum number of rx buffer the fw may use at the same time */
|
||||||
|
#define RWNX_RXBUFF_MAX (64 * NX_REMOTE_STA_MAX)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rwnx_ipc_rxbuf_elems - IPC buffers for RX
|
||||||
|
*
|
||||||
|
* @skb: Array of buffer push to FW.
|
||||||
|
* @idx: Index of the last pushed skb.(Use to find the next free entry quicker)
|
||||||
|
*
|
||||||
|
* Note: contrary to softmac version, dma_addr are stored inside skb->cb.
|
||||||
|
* (cf &struct rwnx_skb_cb)
|
||||||
|
*/
|
||||||
|
struct rwnx_ipc_rxbuf_elems {
|
||||||
|
struct sk_buff *skb[RWNX_RXBUFF_MAX];
|
||||||
|
int idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* CONFIG_RWNX_FULLMAC */
|
||||||
|
#endif /* _RWNX_IPC_UTILS_H_ */
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_v7.c - Support for v7 platform
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rwnx_v7.h"
|
||||||
|
#include "rwnx_defs.h"
|
||||||
|
#include "rwnx_irqs.h"
|
||||||
|
#include "reg_access.h"
|
||||||
|
#include "hal_desc.h"
|
||||||
|
|
||||||
|
struct rwnx_v7
|
||||||
|
{
|
||||||
|
u8 *pci_bar0_vaddr;
|
||||||
|
u8 *pci_bar1_vaddr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int rwnx_v7_platform_enable(struct rwnx_hw *rwnx_hw)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* sched_setscheduler on ONESHOT threaded irq handler for BCNs ? */
|
||||||
|
ret = request_irq(rwnx_hw->plat->pci_dev->irq, rwnx_irq_hdlr, 0,
|
||||||
|
"rwnx", rwnx_hw);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rwnx_v7_platform_disable(struct rwnx_hw *rwnx_hw)
|
||||||
|
{
|
||||||
|
free_irq(rwnx_hw->plat->pci_dev->irq, rwnx_hw);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rwnx_v7_platform_deinit(struct rwnx_plat *rwnx_plat)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_PCI
|
||||||
|
struct rwnx_v7 *rwnx_v7 = (struct rwnx_v7 *)rwnx_plat->priv;
|
||||||
|
|
||||||
|
pci_disable_device(rwnx_plat->pci_dev);
|
||||||
|
iounmap(rwnx_v7->pci_bar0_vaddr);
|
||||||
|
iounmap(rwnx_v7->pci_bar1_vaddr);
|
||||||
|
pci_release_regions(rwnx_plat->pci_dev);
|
||||||
|
pci_clear_master(rwnx_plat->pci_dev);
|
||||||
|
pci_disable_msi(rwnx_plat->pci_dev);
|
||||||
|
#endif
|
||||||
|
kfree(rwnx_plat);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8* rwnx_v7_get_address(struct rwnx_plat *rwnx_plat, int addr_name,
|
||||||
|
unsigned int offset)
|
||||||
|
{
|
||||||
|
struct rwnx_v7 *rwnx_v7 = (struct rwnx_v7 *)rwnx_plat->priv;
|
||||||
|
|
||||||
|
if (WARN(addr_name >= RWNX_ADDR_MAX, "Invalid address %d", addr_name))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (addr_name == RWNX_ADDR_CPU)
|
||||||
|
return rwnx_v7->pci_bar0_vaddr + offset;
|
||||||
|
else
|
||||||
|
return rwnx_v7->pci_bar1_vaddr + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rwnx_v7_ack_irq(struct rwnx_plat *rwnx_plat)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static const u32 rwnx_v7_config_reg[] = {
|
||||||
|
NXMAC_DEBUG_PORT_SEL_ADDR,
|
||||||
|
SYSCTRL_DIAG_CONF_ADDR,
|
||||||
|
SYSCTRL_PHYDIAG_CONF_ADDR,
|
||||||
|
SYSCTRL_RIUDIAG_CONF_ADDR,
|
||||||
|
RF_V7_DIAGPORT_CONF1_ADDR,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u32 rwnx_v7_he_config_reg[] = {
|
||||||
|
SYSCTRL_DIAG_CONF0,
|
||||||
|
SYSCTRL_DIAG_CONF1,
|
||||||
|
SYSCTRL_DIAG_CONF2,
|
||||||
|
SYSCTRL_DIAG_CONF3,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int rwnx_v7_get_config_reg(struct rwnx_plat *rwnx_plat, const u32 **list)
|
||||||
|
{
|
||||||
|
u32 fpga_sign;
|
||||||
|
|
||||||
|
if (!list)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fpga_sign = RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, SYSCTRL_SIGNATURE_ADDR);
|
||||||
|
if (__FPGA_TYPE(fpga_sign) == 0xc0ca) {
|
||||||
|
*list = rwnx_v7_he_config_reg;
|
||||||
|
return ARRAY_SIZE(rwnx_v7_he_config_reg);
|
||||||
|
} else {
|
||||||
|
*list = rwnx_v7_config_reg;
|
||||||
|
return ARRAY_SIZE(rwnx_v7_config_reg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rwnx_v7_platform_init - Initialize the DINI platform
|
||||||
|
*
|
||||||
|
* @pci_dev PCI device
|
||||||
|
* @rwnx_plat Pointer on struct rwnx_stat * to be populated
|
||||||
|
*
|
||||||
|
* @return 0 on success, < 0 otherwise
|
||||||
|
*
|
||||||
|
* Allocate and initialize a rwnx_plat structure for the dini platform.
|
||||||
|
*/
|
||||||
|
int rwnx_v7_platform_init(struct pci_dev *pci_dev, struct rwnx_plat **rwnx_plat)
|
||||||
|
{
|
||||||
|
struct rwnx_v7 *rwnx_v7;
|
||||||
|
u16 pci_cmd;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
*rwnx_plat = kzalloc(sizeof(struct rwnx_plat) + sizeof(struct rwnx_v7),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!*rwnx_plat)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
rwnx_v7 = (struct rwnx_v7 *)(*rwnx_plat)->priv;
|
||||||
|
|
||||||
|
/* Hotplug fixups */
|
||||||
|
pci_read_config_word(pci_dev, PCI_COMMAND, &pci_cmd);
|
||||||
|
pci_cmd |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
|
||||||
|
pci_write_config_word(pci_dev, PCI_COMMAND, pci_cmd);
|
||||||
|
pci_write_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES >> 2);
|
||||||
|
|
||||||
|
if ((ret = pci_enable_device(pci_dev))) {
|
||||||
|
dev_err(&(pci_dev->dev), "pci_enable_device failed\n");
|
||||||
|
goto out_enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_set_master(pci_dev);
|
||||||
|
|
||||||
|
if ((ret = pci_request_regions(pci_dev, KBUILD_MODNAME))) {
|
||||||
|
dev_err(&(pci_dev->dev), "pci_request_regions failed\n");
|
||||||
|
goto out_request;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PCI
|
||||||
|
if (pci_enable_msi(pci_dev))
|
||||||
|
{
|
||||||
|
dev_err(&(pci_dev->dev), "pci_enable_msi failed\n");
|
||||||
|
goto out_msi;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!(rwnx_v7->pci_bar0_vaddr = (u8 *)pci_ioremap_bar(pci_dev, 0))) {
|
||||||
|
dev_err(&(pci_dev->dev), "pci_ioremap_bar(%d) failed\n", 0);
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out_bar0;
|
||||||
|
}
|
||||||
|
if (!(rwnx_v7->pci_bar1_vaddr = (u8 *)pci_ioremap_bar(pci_dev, 1))) {
|
||||||
|
dev_err(&(pci_dev->dev), "pci_ioremap_bar(%d) failed\n", 1);
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out_bar1;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*rwnx_plat)->enable = rwnx_v7_platform_enable;
|
||||||
|
(*rwnx_plat)->disable = rwnx_v7_platform_disable;
|
||||||
|
(*rwnx_plat)->deinit = rwnx_v7_platform_deinit;
|
||||||
|
(*rwnx_plat)->get_address = rwnx_v7_get_address;
|
||||||
|
(*rwnx_plat)->ack_irq = rwnx_v7_ack_irq;
|
||||||
|
(*rwnx_plat)->get_config_reg = rwnx_v7_get_config_reg;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_bar1:
|
||||||
|
iounmap(rwnx_v7->pci_bar0_vaddr);
|
||||||
|
out_bar0:
|
||||||
|
#ifdef CONFIG_PCI
|
||||||
|
pci_disable_msi(pci_dev);
|
||||||
|
out_msi:
|
||||||
|
#endif
|
||||||
|
pci_release_regions(pci_dev);
|
||||||
|
out_request:
|
||||||
|
#ifdef CONFIG_PCI
|
||||||
|
pci_clear_master(pci_dev);
|
||||||
|
#endif
|
||||||
|
pci_disable_device(pci_dev);
|
||||||
|
out_enable:
|
||||||
|
kfree(*rwnx_plat);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
*
|
||||||
|
* @file rwnx_v7.h
|
||||||
|
*
|
||||||
|
* Copyright (C) RivieraWaves 2012-2019
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RWNX_V7_H_
|
||||||
|
#define _RWNX_V7_H_
|
||||||
|
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include "rwnx_platform.h"
|
||||||
|
|
||||||
|
int rwnx_v7_platform_init(struct pci_dev *pci_dev,
|
||||||
|
struct rwnx_plat **rwnx_plat);
|
||||||
|
|
||||||
|
#endif /* _RWNX_V7_H_ */
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user