bl_iot_sdk/components/bl602/bl602_wifidrv/bl60x_wifi_driver/bl_utils.c
2020-10-26 20:35:25 +08:00

516 lines
18 KiB
C

/*
* Copyright (c) 2020 Bouffalolab.
*
* This file is part of
* *** Bouffalolab Software Dev Kit ***
* (see www.bouffalolab.com).
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of Bouffalo Lab nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <lwip/api.h>
#include <lwip/opt.h>
#include <lwip/def.h>
#include <lwip/mem.h>
#include <lwip/pbuf.h>
#include <lwip/netif.h>
#include <wifi_mgmr_ext.h>
#include "ipc_shared.h"
#include "ipc_host.h"
#include "bl_utils.h"
#include "bl_rx.h"
#include "bl_tx.h"
#include "bl_cmds.h"
#undef os_printf
#define os_printf(...) do {} while(0)
extern struct bl_hw wifi_hw;
#if 1
typedef struct bl_custom_pbuf
{
struct pbuf_custom p;
void *swdesc;
} bl_custom_pbuf_t;
#else
typedef struct bl_custom_pbuf
{
struct pbuf_custom p;
uint32_t payload[1800 >> 2];
} bl_custom_pbuf_t;
#undef LWIP_DECLARE_MEMORY_ALIGNED
#ifdef CONF_USER_ENABLE_PSRAM
#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[LWIP_MEM_ALIGN_BUFFER(size)] __attribute__((section(".wifi_psram")))
LWIP_MEMPOOL_DECLARE(RX_POOL, 100, sizeof(bl_custom_pbuf_t), "bl_zero_copy_rx");
#else
#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[LWIP_MEM_ALIGN_BUFFER(size)] __attribute__((section(".wifi_ram")))
LWIP_MEMPOOL_DECLARE(RX_POOL, 24, sizeof(bl_custom_pbuf_t), "bl_zero_copy_rx");
#endif
#endif
static void my_pbuf_free_custom(struct pbuf *p)
{
bl_custom_pbuf_t* my_pbuf = (bl_custom_pbuf_t*)p;
void bl60x_firmwre_mpdu_free(void *swdesc);
//printf("--- cb free@%p\r\n", my_pbuf->swdesc);
bl60x_firmwre_mpdu_free(my_pbuf->swdesc);
}
static void my_pbuf_free_custom_fake(struct pbuf *p)
{
/*nothing needs to be done for tailed pbuf*/
}
static inline struct bl_vif *bl_rx_get_vif(int vif_idx)
{
struct bl_vif *bl_vif = NULL;
struct bl_hw *bl_hw = &wifi_hw;
if (vif_idx == 0xFF) {
list_for_each_entry(bl_vif, &bl_hw->vifs, list) {
if (bl_vif->up)
return bl_vif;
}
return NULL;
} else if (vif_idx < NX_VIRT_DEV_MAX) {
bl_vif = &(bl_hw->vif_table[vif_idx]);
if (!bl_vif || !bl_vif->up)
return NULL;
}
return bl_vif;
}
/**
* bl_rx_mgmt - Process one 802.11 management frame
*
* @bl_hw: main driver data
* @bl_vif: vif that received the buffer
* @skb: skb received
* @rxhdr: HW rx descriptor
*
* Process the management frame and free the corresponding skb
*/
static void bl_rx_mgmt(uint32_t *skb, struct hw_rxhdr *hw_rxhdr, int len)
{
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb;
static uint32_t counter;
#if 0
if ( (0x01 == mgmt->sa[0] && 0x00 == mgmt->sa[1]) ||
(0x01 == mgmt->da[0] && 0x00 == mgmt->da[1]) ||
(0x01 == mgmt->bssid[0] && 0x00 == mgmt->bssid[1])) {
printf("[RX] %d, %08X %04X, DATA addr1: %02X:%02X:%02X:%02X:%02X:%02X addr2: %02X:%02X:%02X:%02X:%02X:%02X, addr3: %02X:%02X:%02X:%02X:%02X:%02X\r\n",
len,
(unsigned int)counter++,
mgmt->frame_control,
mgmt->da[0],
mgmt->da[1],
mgmt->da[2],
mgmt->da[3],
mgmt->da[4],
mgmt->da[5],
mgmt->sa[0],
mgmt->sa[1],
mgmt->sa[2],
mgmt->sa[3],
mgmt->sa[4],
mgmt->sa[5],
mgmt->bssid[0],
mgmt->bssid[1],
mgmt->bssid[2],
mgmt->bssid[3],
mgmt->bssid[4],
mgmt->bssid[5]
);
}
#endif
(void)counter;
if (ieee80211_is_beacon(mgmt->frame_control)) {
#if 0
os_printf("[RX] %04X BCN Received, freq %u, rssi %d\r\n",
mgmt->frame_control,
hw_rxhdr->phy_prim20_freq,
hw_rxhdr->hwvect.rssi1
);
#endif
} else if ((ieee80211_is_deauth(mgmt->frame_control) ||
ieee80211_is_disassoc(mgmt->frame_control)) &&
(mgmt->u.deauth.reason_code == WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA ||
mgmt->u.deauth.reason_code == WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA)) {
if (ieee80211_is_deauth(mgmt->frame_control)) {
os_printf("[RX] Deauth Received\r\n");
} else if (ieee80211_is_disassoc(mgmt->frame_control)) {
os_printf("[RX] Disassoc Received\r\n");
}
} else if ((ieee80211_is_action(mgmt->frame_control) &&
(mgmt->u.action.category == 6))) {
os_printf("[RX] FT EVENT\r\n");
} else if (ieee80211_is_data(mgmt->frame_control)){
os_printf("[RX] %08X %04X, DATA SA: %02X:%02X:%02X:%02X:%02X:%02X DA: %02X:%02X:%02X:%02X:%02X:%02X\r\n",
(unsigned int)counter++,
mgmt->frame_control,
mgmt->sa[0],
mgmt->sa[1],
mgmt->sa[2],
mgmt->sa[3],
mgmt->sa[4],
mgmt->sa[5],
mgmt->da[0],
mgmt->da[1],
mgmt->da[2],
mgmt->da[3],
mgmt->da[4],
mgmt->da[5]
);
} else if (ieee80211_is_data_qos(mgmt->frame_control)){
printf("[RX] %04X QOS DATA %02X:%02X:%02X:%02X:%02X:%02X\r\n",
mgmt->frame_control,
mgmt->da[0],
mgmt->da[1],
mgmt->da[2],
mgmt->da[3],
mgmt->da[4],
mgmt->da[5]
);
} else {
os_printf("[RX] Upload MGMT Frame? %04X\r\n", mgmt->frame_control);
}
}
struct wifi_pkt {
uint32_t pkt[4];
void *pbuf[4];
uint16_t len[4];
};
static void dump_pkt_infor(struct hw_rxhdr *hw_rxhdr)
{
#define PACKET_TEST_INTERVAL (4 * 1000)
int16_t freq_offset = 0;
static int32_t freq_offset_all = 0;
uint16_t gain_status = 0;
static uint32_t packets_num = 0;
static uint32_t packets_lasttime = 0;
gain_status = ((uint16_t)(hw_rxhdr->hwvect.rssi3)) | (((uint16_t)hw_rxhdr->hwvect.rssi4) << 8);
if ((int32_t)xTaskGetTickCount() - (int32_t)packets_lasttime > PACKET_TEST_INTERVAL) {
packets_num = 0;
freq_offset_all = 0;
}
packets_num++;
packets_lasttime = xTaskGetTickCount();
if (hw_rxhdr->hwvect.format_mod >=2) {
/*11n mode*/
freq_offset = (((uint32_t) hw_rxhdr->hwvect.evm3) | (((uint32_t)hw_rxhdr->hwvect.evm4) << 8));
freq_offset_all += ((int)(freq_offset * 20 / 2440));
printf("[11n] %04d bytes[%03lu], rssi %d, %04x, lna %02u, rbb %02u, dg %02d; evm3_4 %03d, freq_offset %d, ppm %f\r\n",
hw_rxhdr->hwvect.len,
packets_num,
hw_rxhdr->hwvect.rssi1,
gain_status,
gain_status & 0xF,
(gain_status >> 4) & 0x1F,
(gain_status >> 9 & 0x7F),
freq_offset,
(int)(freq_offset * 20 / 2440),
((float) (freq_offset_all)) / packets_num
);
} else if (hw_rxhdr->hwvect.leg_rate > 3) {
/*11g mode*/
freq_offset = (((uint32_t) hw_rxhdr->hwvect.evm3) | (((uint32_t)hw_rxhdr->hwvect.evm4) << 8));
freq_offset_all += ((int)(freq_offset * 20 / 2440));
printf("[11g] %04d bytes[%03lu], rssi %d, %04x, lna %02u, rbb %02u, dg %02d; evm3_4 %03d, freq_offset %d, ppm %f\r\n",
hw_rxhdr->hwvect.len,
packets_num,
hw_rxhdr->hwvect.rssi1,
gain_status,
gain_status & 0xF,
(gain_status >> 4) & 0x1F,
(gain_status >> 9 & 0x7F),
freq_offset,
(int)(freq_offset * 20 / 2440),
((float)(freq_offset_all)) / packets_num
);
} else {
/*11b mode*/
freq_offset = ((int32_t)0) - (((int32_t)(hw_rxhdr->hwvect.evm3 << 24)) >> 24);
freq_offset_all += ((int)(freq_offset * 0.7));
printf("[11b] %04d bytes[%03lu], fcs_err %d, rssi %d, %04x, lna %02u, rbb %02u, dg %02d; evm3 %04u:%03d, freq_offset %d, ppm %f\r\n",
hw_rxhdr->hwvect.len,
packets_num,
hw_rxhdr->hwvect.fcs_err,
hw_rxhdr->hwvect.rssi1,
gain_status,
gain_status & 0xF,
(gain_status >> 4) & 0x1F,
(gain_status >> 9 & 0x7F),
hw_rxhdr->hwvect.evm3,
freq_offset,
(int)(freq_offset * 0.7),
((float)(freq_offset_all)) / packets_num
);
}
}
int tcpip_stack_input(void *swdesc, uint8_t status, void *hwhdr, unsigned int msdu_offset, struct wifi_pkt *pkt)
{
struct hw_rxhdr *hw_rxhdr = (struct hw_rxhdr*)hwhdr;
uint32_t *skb = (uint32_t*)(pkt->pkt[0]), *skb_payload;
struct bl_vif *bl_vif;
/* Check if we need to forward the buffer */
if (status & RX_STAT_FORWARD) {
bl_vif = bl_rx_get_vif(hw_rxhdr->flags_vif_idx);
skb_payload = (uint32_t*)((uint32_t)(skb) + msdu_offset);
if (hw_rxhdr->flags_is_80211_mpdu) {
//TODO fix spilted buff
//dump_pkt_infor(hw_rxhdr);
bl_rx_pkt_cb((uint8_t*)skb_payload, hw_rxhdr->hwvect.len);
bl_rx_mgmt(skb_payload, hw_rxhdr, hw_rxhdr->hwvect.len);
} else {
struct ethhdr *hdr = (struct ethhdr *)(skb_payload);
(void)hdr;
if (hw_rxhdr->flags_sta_idx != 0xff) {
if (hw_rxhdr->flags_is_4addr && !bl_vif->use_4addr) {
printf("[RX] Trigger 4addr unexpected frame\r\n");
}
}
os_printf("********************ETH Start******************************\r\n");
os_printf(" Eth Dst %02X%02X%02X%02X%02X%02X\r\n",
hdr->h_dest[0],
hdr->h_dest[1],
hdr->h_dest[2],
hdr->h_dest[3],
hdr->h_dest[4],
hdr->h_dest[5]
);
os_printf(" Eth Src %02X%02X%02X%02X%02X%02X\r\n",
hdr->h_source[0],
hdr->h_source[1],
hdr->h_source[2],
hdr->h_source[3],
hdr->h_source[4],
hdr->h_source[5]
);
os_printf(" Eth Proto %04X, %p:%p, len %u\r\n", hdr->h_proto, bl_vif, bl_vif ? bl_vif->dev : NULL, hw_rxhdr->hwvect.len);
os_printf("********************ETH End******************************\r\n");
if (wifi_mgmr_ext_dump_needed()) {
dump_pkt_infor(hw_rxhdr);
}
if (bl_vif) {
/* allocate buffer for memory piece*/
struct pbuf *h, *t;
int i;
bl_custom_pbuf_t* my_pbuf;
//FIXME performance for PSRAM?
my_pbuf = (bl_custom_pbuf_t*)pkt->pbuf[0];
memset(my_pbuf, 0, sizeof(bl_custom_pbuf_t));
my_pbuf->p.custom_free_function = my_pbuf_free_custom;
my_pbuf->swdesc = swdesc;
h = pbuf_alloced_custom(
PBUF_RAW,
pkt->len[0] - msdu_offset,
PBUF_REF,
&my_pbuf->p,
(uint8_t*)(pkt->pkt[0]) + msdu_offset,
pkt->len[0] - msdu_offset
);
#if 0
printf("Header %p, len %u\r\n", h, pkt->len[0]);
#endif
i = 1;//header is already set
while (i < sizeof(pkt->pkt)/sizeof(pkt->pkt[0])) {
if (0 == pkt->len[i]) {
/*empty item. break now*/
#if 0
printf("break @%d len %u\r\n", i, pkt->len[i]);
#endif
break;
}
my_pbuf = (bl_custom_pbuf_t*)pkt->pbuf[i];
memset(my_pbuf, 0, sizeof(bl_custom_pbuf_t));
my_pbuf->p.custom_free_function = my_pbuf_free_custom_fake;
t = pbuf_alloced_custom(
PBUF_RAW,
pkt->len[i],
PBUF_REF,
&my_pbuf->p,
(uint8_t*)(pkt->pkt[i]),
pkt->len[i]
);
pbuf_cat(h, t);
#if 0
printf("chaining... %p, len %u\r\n",
t,
pkt->len[i]
);
#endif
i++;
}
if (bl_vif->dev && ERR_OK == bl_vif->dev->input(h, bl_vif->dev)) {
return 0;
}
} else {
printf("------ Frame received but no active vif (%d)\r\n", hw_rxhdr->flags_vif_idx);
}
}
}
return -1;
}
u8 bl_radarind(void *pthis, void *hostid)
{
os_printf("%s: Enter\r\n", __func__);
return 0;
}
u8 bl_msgackind(void *pthis, void *hostid)
{
struct bl_hw *bl_hw = (struct bl_hw *)pthis;
os_printf("[IPC] MSG ACKED @%p\r\n", hostid);
bl_hw->cmd_mgr.llind(&bl_hw->cmd_mgr, (struct bl_cmd *)hostid);
return 0;
}
u8 bl_dbgind(void *pthis, void *hostid)
{
os_printf("%s: Enter\r\n", __func__);
return 0;
}
void bl_prim_tbtt_ind(void *pthis)
{
os_printf("%s: Enter\r\n", __func__);
return;
}
void bl_sec_tbtt_ind(void *pthis)
{
os_printf("%s: Enter\r\n", __func__);
return;
}
//FIXME TODO use cache?
int bl_utils_idx_lookup(struct bl_hw *bl_hw, uint8_t *mac)
{
int i;
struct bl_sta *sta;
for (i = 0; i < sizeof(bl_hw->sta_table)/sizeof(bl_hw->sta_table[0]); i++) {
sta = &(bl_hw->sta_table[i]);
if (0 == sta->is_used) {
/*empty entry*/
continue;
}
if (memcmp(sta->sta_addr.array, mac, 6)) {
/*NOT match*/
continue;
} else {
/*mac address found*/
break;
}
}
//FIXME use 0x0A for un-valid sta_idx?
return (sizeof(bl_hw->sta_table)/sizeof(bl_hw->sta_table[0])) == i ? wifi_hw.ap_bcmc_idx : i;
}
static struct ipc_host_env_tag *ipc_env;
int bl_ipc_init(struct bl_hw *bl_hw, struct ipc_shared_env_tag *ipc_shared_mem)
{
struct ipc_host_cb_tag cb;
memset(&cb, 0, sizeof(cb));
/* initialize the API interface */
cb.recv_data_ind = NULL;
cb.recv_radar_ind = bl_radarind;
cb.recv_msg_ind = NULL;
cb.recv_msgack_ind = bl_msgackind;
cb.recv_dbg_ind = bl_dbgind;
cb.send_data_cfm = bl_txdatacfm;
cb.prim_tbtt_ind = bl_prim_tbtt_ind;
cb.sec_tbtt_ind = bl_sec_tbtt_ind;
/* set the IPC environment */
bl_hw->ipc_env = (struct ipc_host_env_tag *) os_malloc(sizeof(struct ipc_host_env_tag));
ipc_env = bl_hw->ipc_env;
/* call the initialization of the IPC */
ipc_host_init(bl_hw->ipc_env, &cb, ipc_shared_mem, bl_hw);
bl_cmd_mgr_init(&bl_hw->cmd_mgr);
return 0;
}
void bl_utils_dump(void)
{
int i, cnt;
struct pbuf *p;
struct bl_txhdr *txhdr;
puts("---------- bl_utils_dump -----------\r\n");
printf("txdesc_free_idx: %lu(%lu)\r\n",
ipc_env->txdesc_free_idx,
ipc_env->txdesc_free_idx & (NX_TXDESC_CNT0 - 1)
);
printf("txdesc_used_idx: %lu(%lu)\r\n",
ipc_env->txdesc_used_idx,
ipc_env->txdesc_used_idx & (NX_TXDESC_CNT0 - 1)
);
cnt = sizeof(ipc_env->tx_host_id0)/sizeof(ipc_env->tx_host_id0[0]);
printf("tx_host_id0 cnt: %d(used %ld)\r\n",
cnt,
(int32_t)ipc_env->txdesc_free_idx - (int32_t)ipc_env->txdesc_used_idx
);
puts( " list: pbuf status ptr status\r\n");
for (i = 0; i < cnt; i++) {
if (ipc_env->txdesc_used_idx + i == ipc_env->txdesc_free_idx) {
/*break on empty*/
break;
}
p = (struct pbuf*)(ipc_env->tx_host_id0[(ipc_env->txdesc_used_idx + i) & (NX_TXDESC_CNT0 - 1)]);
txhdr = (struct bl_txhdr*)(((uint32_t)p->payload) + RWNX_HWTXHDR_ALIGN_PADS((uint32_t)p->payload));
printf(" [%lu]%p(%p:%08lX)\r\n",
(ipc_env->txdesc_used_idx + i) & (NX_TXDESC_CNT0 - 1),
p,
p ? (void*)(txhdr->host.status_addr) : 0,
p ? txhdr->status.value : 0
);
}
puts("========== bl_utils_dump End =======\r\n");
}