/******************************************************************************
|
*
|
* Copyright(c) 2019 Realtek Corporation. All rights reserved.
|
*
|
* 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.
|
*
|
******************************************************************************/
|
|
#include "fwcmd.h"
|
#include "mcc.h"
|
|
#if MAC_AX_FEATURE_HV
|
#include "../hv_ax/dbgpkg_hv.h"
|
#endif
|
|
/* 8852A/8852B: the format of H2C/DLFW descriptor: WD Body
|
* 8852C: the format of H2C/DLFW descriptor: RX Descriptor
|
* WD body max len: 24 bytes
|
* RX descriptor max len: 32 bytes
|
* We use the max RX descriptor size as the header size
|
* WD_BODY_LEN_V1 = RX descriptor max len = 32 bytes
|
*/
|
|
#define H2CB_CMD_HDR_SIZE (FWCMD_HDR_LEN + WD_BODY_LEN_V1)
|
#define H2CB_CMD_SIZE (H2C_CMD_LEN - FWCMD_HDR_LEN)
|
#define H2CB_CMD_QLEN 8
|
|
#define H2CB_DATA_HDR_SIZE (FWCMD_HDR_LEN + WD_BODY_LEN_V1)
|
#define H2CB_DATA_SIZE (H2C_DATA_LEN - FWCMD_HDR_LEN)
|
#define H2CB_DATA_QLEN 4
|
|
#define H2CB_LONG_DATA_HDR_SIZE (FWCMD_HDR_LEN + WD_BODY_LEN)
|
#define H2CB_LONG_DATA_SIZE (H2C_LONG_DATA_LEN - FWCMD_HDR_LEN)
|
#define H2CB_LONG_DATA_QLEN 1
|
|
#define FWCMD_WQ_MAX_JOB_NUM 5
|
|
#define FWCMD_LMT 12
|
|
#define MAC_AX_H2C_LMT_EN 0
|
|
#define FWCMD_H2CREG_BYTE0_SH 0
|
#define FWCMD_H2CREG_BYTE0_MSK 0xFF
|
#define FWCMD_H2CREG_BYTE1_SH 8
|
#define FWCMD_H2CREG_BYTE1_MSK 0xFF
|
#define FWCMD_H2CREG_BYTE2_SH 16
|
#define FWCMD_H2CREG_BYTE2_MSK 0xFF
|
#define FWCMD_H2CREG_BYTE3_SH 24
|
#define FWCMD_H2CREG_BYTE3_MSK 0xFF
|
|
#define BCN_GRPIE_OFST_EN BIT(7)
|
|
static struct h2c_buf_head h2cb_head[H2CB_CLASS_MAX];
|
static struct fwcmd_wkb_head fwcmd_wq_head;
|
|
struct fwcmd_outsrc_info {
|
#define MAX_OUTSRC_LEN 60 //need to extend if needed
|
u32 dword0[MAX_OUTSRC_LEN];
|
};
|
|
struct c2h_event_id_proc {
|
u8 cat;
|
u8 cls;
|
u8 func;
|
u32 (*hdl)(struct mac_ax_adapter *adapter, struct rtw_c2h_info *c2h,
|
enum phl_msg_evt_id *id, u8 *c2h_info);
|
};
|
|
static inline u32 h2cb_queue_len(struct h2c_buf_head *list)
|
{
|
return list->qlen;
|
}
|
|
static inline void __h2cb_queue_head_init(struct h2c_buf_head *list)
|
{
|
list->prev = (struct h2c_buf *)list;
|
list->next = (struct h2c_buf *)list;
|
list->qlen = 0;
|
list->suspend = 0;
|
}
|
|
static inline void h2cb_queue_head_init(struct mac_ax_adapter *adapter,
|
struct h2c_buf_head *list)
|
{
|
PLTFM_MUTEX_INIT(&list->lock);
|
__h2cb_queue_head_init(list);
|
}
|
|
static inline void __h2cb_insert(struct h2c_buf *new_h2cb, struct h2c_buf *prev,
|
struct h2c_buf *next,
|
struct h2c_buf_head *list)
|
{
|
new_h2cb->next = next;
|
new_h2cb->prev = prev;
|
next->prev = new_h2cb;
|
prev->next = new_h2cb;
|
list->qlen++;
|
}
|
|
static inline void __h2cb_queue_before(struct h2c_buf_head *list,
|
struct h2c_buf *next,
|
struct h2c_buf *new_h2cb)
|
{
|
__h2cb_insert(new_h2cb, next->prev, next, list);
|
}
|
|
static inline void __h2cb_queue_tail(struct h2c_buf_head *list,
|
struct h2c_buf *new_h2cb)
|
{
|
__h2cb_queue_before(list, (struct h2c_buf *)list, new_h2cb);
|
}
|
|
static inline void __h2cb_unlink(struct h2c_buf *h2cb,
|
struct h2c_buf_head *list)
|
{
|
struct h2c_buf *next, *prev;
|
|
list->qlen--;
|
next = h2cb->next;
|
prev = h2cb->prev;
|
h2cb->prev = NULL;
|
h2cb->next = NULL;
|
next->prev = prev;
|
prev->next = next;
|
}
|
|
static inline struct h2c_buf *h2cb_peek(struct h2c_buf_head *list)
|
{
|
struct h2c_buf *h2cb = list->next;
|
|
if (h2cb == (struct h2c_buf *)list)
|
h2cb = NULL;
|
return h2cb;
|
}
|
|
#if MAC_AX_PHL_H2C
|
u32 h2c_agg_enqueue(struct mac_ax_adapter *adapter, struct rtw_h2c_pkt *h2cb)
|
#else
|
u32 h2c_agg_enqueue(struct mac_ax_adapter *adapter, struct h2c_buf *h2cb)
|
#endif
|
{
|
struct mac_ax_h2c_agg_node *h2c_agg_node = NULL;
|
u32 ret = MACSUCCESS;
|
|
PLTFM_MUTEX_LOCK(&adapter->h2c_agg_info.h2c_agg_lock);
|
|
if (!adapter->h2c_agg_info.h2c_agg_en) {
|
/* return fall and send the H2C pkt by the orginal function*/
|
ret = MACNOITEM;
|
goto fail;
|
}
|
|
h2c_agg_node = (struct mac_ax_h2c_agg_node *)
|
PLTFM_MALLOC(sizeof(struct mac_ax_h2c_agg_node));
|
if (!h2c_agg_node) {
|
/* return fall and send the H2C pkt by the orginal function*/
|
ret = MACBUFALLOC;
|
goto fail;
|
}
|
|
PLTFM_MEMSET(h2c_agg_node, 0, sizeof(struct mac_ax_h2c_agg_node));
|
h2c_agg_node->h2c_pkt = (u8 *)h2cb;
|
h2c_agg_node->next = NULL;
|
adapter->h2c_agg_info.h2c_agg_pkt_num++;
|
|
if (!adapter->h2c_agg_info.h2c_agg_queue_head) {
|
adapter->h2c_agg_info.h2c_agg_queue_head = h2c_agg_node;
|
adapter->h2c_agg_info.h2c_agg_queue_last = h2c_agg_node;
|
} else {
|
adapter->h2c_agg_info.h2c_agg_queue_last->next = h2c_agg_node;
|
adapter->h2c_agg_info.h2c_agg_queue_last = h2c_agg_node;
|
}
|
|
fail:
|
PLTFM_MUTEX_UNLOCK(&adapter->h2c_agg_info.h2c_agg_lock);
|
return ret;
|
}
|
|
#if MAC_AX_PHL_H2C
|
static inline u8 *h2cb_tail_pointer(const struct rtw_h2c_pkt *h2cb)
|
{
|
return h2cb->vir_tail;
|
}
|
#else
|
static inline u8 *h2cb_tail_pointer(const struct h2c_buf *h2cb)
|
{
|
return h2cb->tail;
|
}
|
#endif
|
|
static inline struct h2c_buf *h2cb_dequeue(struct h2c_buf_head *list)
|
{
|
struct h2c_buf *h2cb = h2cb_peek(list);
|
|
if (h2cb)
|
__h2cb_unlink(h2cb, list);
|
return h2cb;
|
}
|
|
static u8 *__h2cb_alloc_buf_pool(struct mac_ax_adapter *adapter,
|
struct h2c_buf_head *list, u32 size, int num)
|
{
|
u32 block_size = (size * num);
|
u8 *ptr;
|
|
ptr = (u8 *)PLTFM_MALLOC(block_size);
|
list->pool = ptr;
|
list->size = block_size;
|
|
return ptr;
|
}
|
|
static struct h2c_buf *__h2cb_alloc(struct mac_ax_adapter *adapter,
|
enum h2c_buf_class buf_class,
|
u32 hdr_size, u8 *buf_ptr, int buf_size)
|
{
|
struct h2c_buf *h2cb;
|
|
//_ASSERT_(!buf_ptr);
|
|
h2cb = (struct h2c_buf *)PLTFM_MALLOC(sizeof(struct h2c_buf));
|
if (!h2cb)
|
return NULL;
|
PLTFM_MEMSET(h2cb, 0, sizeof(struct h2c_buf));
|
|
h2cb->_class_ = buf_class;
|
h2cb->id = 0;
|
h2cb->master = 0;
|
h2cb->len = 0;
|
h2cb->head = buf_ptr;
|
h2cb->end = h2cb->head + buf_size;
|
h2cb->data = h2cb->head + hdr_size;
|
h2cb->tail = h2cb->data;
|
h2cb->hdr_len = hdr_size;
|
h2cb->flags |= H2CB_FLAGS_FREED;
|
|
return h2cb;
|
}
|
|
static u32 __h2cb_free(struct mac_ax_adapter *adapter,
|
enum h2c_buf_class buf_class)
|
{
|
struct h2c_buf_head *list_head = &h2cb_head[buf_class];
|
struct h2c_buf *h2cb;
|
|
if (buf_class >= H2CB_CLASS_LAST)
|
return MACNOITEM;
|
|
if (!list_head->pool)
|
return MACNPTR;
|
|
if (!h2cb_queue_len(list_head))
|
return MACSUCCESS;
|
|
while ((h2cb = h2cb_dequeue(list_head)))
|
PLTFM_FREE(h2cb, sizeof(struct h2c_buf));
|
|
PLTFM_FREE(list_head->pool, list_head->size);
|
list_head->pool = NULL;
|
list_head->size = 0;
|
PLTFM_MUTEX_DEINIT(&list_head->lock);
|
|
return MACSUCCESS;
|
}
|
|
static u32 __h2cb_init(struct mac_ax_adapter *adapter,
|
enum h2c_buf_class buf_class, u32 num, u32 buf_size,
|
u32 hdr_size, u32 tailer_size)
|
{
|
u32 i;
|
u8 *ptr;
|
struct h2c_buf_head *list_head = &h2cb_head[buf_class];
|
u32 real_size = buf_size + hdr_size + tailer_size;
|
struct h2c_buf *h2cb;
|
|
if (buf_class >= H2CB_CLASS_LAST)
|
return MACNOITEM;
|
|
if (h2cb_queue_len(list_head))
|
return MACBUFSZ;
|
|
h2cb_queue_head_init(adapter, list_head);
|
|
ptr = __h2cb_alloc_buf_pool(adapter, list_head, real_size, num);
|
if (!ptr)
|
return MACNPTR;
|
|
for (i = 0; i < num; i++) {
|
h2cb = __h2cb_alloc(adapter,
|
buf_class, hdr_size, ptr, real_size);
|
if (!h2cb)
|
goto h2cb_fail;
|
__h2cb_queue_tail(list_head, h2cb);
|
ptr += real_size;
|
}
|
|
return MACSUCCESS;
|
h2cb_fail:
|
__h2cb_free(adapter, buf_class);
|
|
return MACBUFALLOC;
|
}
|
|
static inline u32 fwcmd_wkb_queue_len(struct fwcmd_wkb_head *list)
|
{
|
return list->qlen;
|
};
|
|
static inline void __fwcmd_wkb_queue_head_init(struct fwcmd_wkb_head *list)
|
{
|
list->prev = (struct h2c_buf *)list;
|
list->next = (struct h2c_buf *)list;
|
list->qlen = 0;
|
};
|
|
static inline void fwcmd_wkb_queue_head_init(struct mac_ax_adapter *adapter,
|
struct fwcmd_wkb_head *list)
|
{
|
PLTFM_MUTEX_INIT(&list->lock);
|
__fwcmd_wkb_queue_head_init(list);
|
}
|
|
static u32 __fwcmd_wkb_init(struct mac_ax_adapter *adapter)
|
{
|
struct fwcmd_wkb_head *list_head = &fwcmd_wq_head;
|
|
if (fwcmd_wkb_queue_len(list_head))
|
return MACBUFSZ;
|
|
fwcmd_wkb_queue_head_init(adapter, list_head);
|
|
return MACSUCCESS;
|
}
|
|
u32 h2cb_init(struct mac_ax_adapter *adapter)
|
{
|
u32 ret;
|
|
ret = __h2cb_init(adapter, H2CB_CLASS_CMD, H2CB_CMD_QLEN,
|
H2CB_CMD_SIZE, H2CB_CMD_HDR_SIZE, 0);
|
if (ret)
|
return ret;
|
|
ret = __h2cb_init(adapter, H2CB_CLASS_DATA, H2CB_DATA_QLEN,
|
H2CB_DATA_SIZE, H2CB_DATA_HDR_SIZE, 0);
|
if (ret)
|
return ret;
|
|
ret = __h2cb_init(adapter, H2CB_CLASS_LONG_DATA, H2CB_LONG_DATA_QLEN,
|
H2CB_LONG_DATA_SIZE, H2CB_LONG_DATA_HDR_SIZE, 0);
|
if (ret)
|
return ret;
|
|
ret = __fwcmd_wkb_init(adapter);
|
if (ret)
|
return ret;
|
|
return MACSUCCESS;
|
}
|
|
u32 h2cb_exit(struct mac_ax_adapter *adapter)
|
{
|
struct fwcmd_wkb_head *list_head = &fwcmd_wq_head;
|
|
if (fwcmd_wkb_queue_len(list_head))
|
return MACBUFSZ;
|
|
__h2cb_free(adapter, H2CB_CLASS_CMD);
|
__h2cb_free(adapter, H2CB_CLASS_DATA);
|
__h2cb_free(adapter, H2CB_CLASS_LONG_DATA);
|
|
return MACSUCCESS;
|
}
|
|
u32 h2c_end_flow(struct mac_ax_adapter *adapter)
|
{
|
struct mac_ax_fw_info *fwinfo = &adapter->fw_info;
|
|
PLTFM_MUTEX_LOCK(&fwinfo->seq_lock);
|
fwinfo->h2c_seq++;
|
PLTFM_MUTEX_UNLOCK(&fwinfo->seq_lock);
|
|
return MACSUCCESS;
|
}
|
|
#if MAC_AX_PHL_H2C
|
struct rtw_h2c_pkt *h2cb_alloc(struct mac_ax_adapter *adapter,
|
enum h2c_buf_class buf_class)
|
{
|
struct rtw_h2c_pkt *h2cb;
|
#if MAC_AX_H2C_LMT_EN
|
struct mac_ax_fw_info *fwinfo = &adapter->fw_info;
|
u8 diff;
|
u8 cnt = 100;
|
#endif
|
|
if (buf_class >= H2CB_CLASS_LAST) {
|
PLTFM_MSG_ERR("[ERR]unknown class\n");
|
return NULL;
|
}
|
|
#if MAC_AX_H2C_LMT_EN
|
while (--cnt) {
|
if (fwinfo->h2c_seq >= fwinfo->rec_seq)
|
diff = fwinfo->h2c_seq - fwinfo->rec_seq;
|
else
|
diff = (255 - fwinfo->rec_seq) + fwinfo->h2c_seq;
|
|
if (diff < FWCMD_LMT)
|
break;
|
PLTFM_DELAY_US(100);
|
}
|
|
if (diff >= FWCMD_LMT) {
|
PLTFM_MSG_ERR("The number of H2C has reached the limitation\n");
|
PLTFM_MSG_ERR("curr: %d, rec: %d\n",
|
fwinfo->h2c_seq, fwinfo->rec_seq);
|
return NULL;
|
}
|
#endif
|
|
h2cb = PLTFM_QUERY_H2C(buf_class);
|
|
return h2cb;
|
}
|
|
void h2cb_free(struct mac_ax_adapter *adapter, struct rtw_h2c_pkt *h2cb)
|
{
|
}
|
|
u8 *h2cb_push(struct rtw_h2c_pkt *h2cb, u32 len)
|
{
|
h2cb->vir_data -= len;
|
h2cb->data_len += len;
|
|
if (h2cb->vir_data < h2cb->vir_head)
|
return NULL;
|
|
return h2cb->vir_data;
|
}
|
|
u8 *h2cb_pull(struct rtw_h2c_pkt *h2cb, u32 len)
|
{
|
h2cb->vir_data += len;
|
|
if (h2cb->vir_data > h2cb->vir_end)
|
return NULL;
|
|
if (h2cb->data_len < len)
|
return NULL;
|
|
h2cb->data_len -= len;
|
|
return h2cb->vir_data;
|
}
|
|
u8 *h2cb_put(struct rtw_h2c_pkt *h2cb, u32 len)
|
{
|
u8 *tmp = h2cb_tail_pointer(h2cb);
|
|
h2cb->vir_tail += len;
|
h2cb->data_len += len;
|
|
if (h2cb->vir_tail > h2cb->vir_end)
|
return NULL;
|
|
return tmp;
|
}
|
|
u32 h2c_pkt_set_hdr(struct mac_ax_adapter *adapter, struct rtw_h2c_pkt *h2cb,
|
u8 type, u8 cat, u8 _class_, u8 func, u16 rack, u16 dack)
|
{
|
struct fwcmd_hdr *hdr;
|
struct mac_ax_fw_info *fwinfo = &adapter->fw_info;
|
|
if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY)
|
return MACFWNONRDY;
|
|
if (adapter->sm.mac_rdy != MAC_AX_MAC_RDY) {
|
PLTFM_MSG_TRACE("%s: MAC is not ready\n", __func__);
|
adapter->stats.h2c_pkt_uninit++;
|
}
|
|
hdr = (struct fwcmd_hdr *)h2cb_push(h2cb, FWCMD_HDR_LEN);
|
if (!hdr)
|
return MACNPTR;
|
|
hdr->hdr0 = cpu_to_le32(SET_WORD(type, H2C_HDR_DEL_TYPE) |
|
SET_WORD(cat, H2C_HDR_CAT) |
|
SET_WORD(_class_, H2C_HDR_CLASS) |
|
SET_WORD(func, H2C_HDR_FUNC) |
|
SET_WORD(fwinfo->h2c_seq, H2C_HDR_H2C_SEQ));
|
|
hdr->hdr1 = cpu_to_le32(SET_WORD(h2cb->data_len, H2C_HDR_TOTAL_LEN) |
|
(rack || !(fwinfo->h2c_seq & 3) ?
|
H2C_HDR_REC_ACK : 0) |
|
(dack ? H2C_HDR_DONE_ACK : 0));
|
|
h2cb->id = SET_FWCMD_ID(type, cat, _class_, func);
|
h2cb->h2c_seq = fwinfo->h2c_seq;
|
|
return MACSUCCESS;
|
}
|
|
u32 h2c_pkt_set_hdr_fwdl(struct mac_ax_adapter *adapter,
|
struct rtw_h2c_pkt *h2cb, u8 type, u8 cat,
|
u8 _class_, u8 func, u16 rack, u16 dack)
|
{
|
struct fwcmd_hdr *hdr;
|
struct mac_ax_fw_info *fwinfo = &adapter->fw_info;
|
|
hdr = (struct fwcmd_hdr *)h2cb_push(h2cb, FWCMD_HDR_LEN);
|
if (!hdr)
|
return MACNPTR;
|
|
hdr->hdr0 = cpu_to_le32(SET_WORD(type, H2C_HDR_DEL_TYPE) |
|
SET_WORD(cat, H2C_HDR_CAT) |
|
SET_WORD(_class_, H2C_HDR_CLASS) |
|
SET_WORD(func, H2C_HDR_FUNC) |
|
SET_WORD(fwinfo->h2c_seq, H2C_HDR_H2C_SEQ));
|
|
hdr->hdr1 = cpu_to_le32(SET_WORD(h2cb->data_len, H2C_HDR_TOTAL_LEN) |
|
(rack ? H2C_HDR_REC_ACK : 0) |
|
(dack ? H2C_HDR_DONE_ACK : 0));
|
|
h2cb->id = SET_FWCMD_ID(type, cat, _class_, func);
|
h2cb->h2c_seq = fwinfo->h2c_seq;
|
|
return MACSUCCESS;
|
}
|
|
u32 h2c_pkt_set_cmd(struct mac_ax_adapter *adapter, struct rtw_h2c_pkt *h2cb,
|
u8 *cmd, u32 len)
|
{
|
u8 *buf;
|
|
buf = h2cb_put(h2cb, len);
|
if (!buf)
|
return MACNPTR;
|
PLTFM_MEMCPY(buf, cmd, len);
|
return MACSUCCESS;
|
}
|
|
u32 h2c_pkt_build_txd(struct mac_ax_adapter *adapter, struct rtw_h2c_pkt *h2cb)
|
{
|
u8 *buf;
|
u32 ret;
|
u32 txd_len;
|
struct rtw_t_meta_data info = {0};
|
struct mac_ax_ops *ops = adapter_to_mac_ops(adapter);
|
|
info.type = RTW_PHL_PKT_TYPE_H2C;
|
info.pktlen = (u16)h2cb->data_len;
|
txd_len = ops->txdesc_len(adapter, &info);
|
if (adapter->hw_info->intf == MAC_AX_INTF_USB) {
|
if (((info.pktlen + txd_len) & (512 - 1)) == 0) {
|
buf = h2cb_put(h2cb, 4);
|
if (!buf) {
|
PLTFM_MSG_ERR("Avoid USB 512-byte FAIL\n");
|
return MACNPTR;
|
}
|
info.pktlen = (u16)h2cb->data_len;
|
txd_len = ops->txdesc_len(adapter, &info);
|
}
|
}
|
|
buf = h2cb_push(h2cb, txd_len);
|
if (!buf)
|
return MACNPTR;
|
|
ret = ops->build_txdesc(adapter, &info, buf, txd_len);
|
if (ret)
|
return ret;
|
|
return MACSUCCESS;
|
}
|
|
u32 fwcmd_wq_idle(struct mac_ax_adapter *adapter, u32 id)
|
{
|
return MACSUCCESS;
|
}
|
|
#else
|
struct h2c_buf *h2cb_alloc(struct mac_ax_adapter *adapter,
|
enum h2c_buf_class buf_class)
|
{
|
struct h2c_buf_head *list_head = &h2cb_head[buf_class];
|
struct h2c_buf *h2cb;
|
|
if (buf_class >= H2CB_CLASS_LAST) {
|
PLTFM_MSG_ERR("[ERR]unknown class\n");
|
return NULL;
|
}
|
|
PLTFM_MUTEX_LOCK(&list_head->lock);
|
|
h2cb = h2cb_dequeue(list_head);
|
if (!h2cb) {
|
PLTFM_MSG_ERR("[ERR]allocate h2cb, class : %d\n", buf_class);
|
goto h2cb_fail;
|
}
|
|
if (!(h2cb->flags & H2CB_FLAGS_FREED)) {
|
PLTFM_MSG_ERR("[ERR]not freed flag\n");
|
PLTFM_FREE(h2cb, sizeof(struct h2c_buf));
|
goto h2cb_fail;
|
}
|
|
h2cb->flags &= ~H2CB_FLAGS_FREED;
|
PLTFM_MUTEX_UNLOCK(&list_head->lock);
|
|
return h2cb;
|
h2cb_fail:
|
PLTFM_MUTEX_UNLOCK(&list_head->lock);
|
return NULL;
|
}
|
|
void h2cb_free(struct mac_ax_adapter *adapter, struct h2c_buf *h2cb)
|
{
|
struct h2c_buf_head *list_head;
|
|
if (h2cb->flags & H2CB_FLAGS_FREED) {
|
PLTFM_MSG_ERR("[ERR]freed flag\n");
|
return;
|
}
|
|
if (h2cb->_class_ >= H2CB_CLASS_LAST) {
|
PLTFM_MSG_ERR("[ERR]unknown class\n");
|
return;
|
}
|
|
list_head = &h2cb_head[h2cb->_class_];
|
|
h2cb->len = 0;
|
h2cb->data = h2cb->head + h2cb->hdr_len;
|
h2cb->tail = h2cb->data;
|
h2cb->flags |= H2CB_FLAGS_FREED;
|
|
PLTFM_MUTEX_LOCK(&list_head->lock);
|
__h2cb_queue_tail(list_head, h2cb);
|
PLTFM_MUTEX_UNLOCK(&list_head->lock);
|
}
|
|
u8 *h2cb_push(struct h2c_buf *h2cb, u32 len)
|
{
|
h2cb->data -= len;
|
h2cb->len += len;
|
|
if (h2cb->data < h2cb->head)
|
return NULL;
|
|
return h2cb->data;
|
}
|
|
u8 *h2cb_pull(struct h2c_buf *h2cb, u32 len)
|
{
|
h2cb->data += len;
|
|
if (h2cb->data > h2cb->end)
|
return NULL;
|
|
if (h2cb->len < len)
|
return NULL;
|
|
h2cb->len -= len;
|
|
return h2cb->data;
|
}
|
|
u8 *h2cb_put(struct h2c_buf *h2cb, u32 len)
|
{
|
u8 *tmp = h2cb_tail_pointer(h2cb);
|
|
h2cb->tail += len;
|
h2cb->len += len;
|
|
if (h2cb->tail > h2cb->end)
|
return NULL;
|
|
return tmp;
|
}
|
|
u32 h2c_pkt_set_hdr(struct mac_ax_adapter *adapter, struct h2c_buf *h2cb,
|
u8 type, u8 cat, u8 _class_, u8 func, u16 rack, u16 dack)
|
{
|
struct fwcmd_hdr *hdr;
|
struct mac_ax_fw_info *fwinfo = &adapter->fw_info;
|
|
if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY)
|
return MACFWNONRDY;
|
|
if (adapter->sm.mac_rdy != MAC_AX_MAC_RDY) {
|
PLTFM_MSG_TRACE("MAC is not ready\n");
|
adapter->stats.h2c_pkt_uninit++;
|
}
|
|
hdr = (struct fwcmd_hdr *)h2cb_push(h2cb, FWCMD_HDR_LEN);
|
if (!hdr)
|
return MACNPTR;
|
|
hdr->hdr0 = cpu_to_le32(SET_WORD(type, H2C_HDR_DEL_TYPE) |
|
SET_WORD(cat, H2C_HDR_CAT) |
|
SET_WORD(_class_, H2C_HDR_CLASS) |
|
SET_WORD(func, H2C_HDR_FUNC) |
|
SET_WORD(fwinfo->h2c_seq, H2C_HDR_H2C_SEQ));
|
|
hdr->hdr1 = cpu_to_le32(SET_WORD(h2cb->len, H2C_HDR_TOTAL_LEN) |
|
(rack || !(fwinfo->h2c_seq & 3) ?
|
H2C_HDR_REC_ACK : 0) |
|
(dack ? H2C_HDR_DONE_ACK : 0));
|
|
h2cb->id = SET_FWCMD_ID(type, cat, _class_, func);
|
h2cb->h2c_seq = fwinfo->h2c_seq;
|
|
return 0;
|
}
|
|
u32 h2c_pkt_set_hdr_fwdl(struct mac_ax_adapter *adapter,
|
struct h2c_buf *h2cb, u8 type, u8 cat,
|
u8 _class_, u8 func, u16 rack, u16 dack)
|
{
|
struct fwcmd_hdr *hdr;
|
struct mac_ax_fw_info *fwinfo = &adapter->fw_info;
|
|
hdr = (struct fwcmd_hdr *)h2cb_push(h2cb, FWCMD_HDR_LEN);
|
if (!hdr)
|
return MACNPTR;
|
|
hdr->hdr0 = cpu_to_le32(SET_WORD(type, H2C_HDR_DEL_TYPE) |
|
SET_WORD(cat, H2C_HDR_CAT) |
|
SET_WORD(_class_, H2C_HDR_CLASS) |
|
SET_WORD(func, H2C_HDR_FUNC) |
|
SET_WORD(fwinfo->h2c_seq, H2C_HDR_H2C_SEQ));
|
|
hdr->hdr1 = cpu_to_le32(SET_WORD(h2cb->len, H2C_HDR_TOTAL_LEN) |
|
(rack ? H2C_HDR_REC_ACK : 0) |
|
(dack ? H2C_HDR_DONE_ACK : 0));
|
|
h2cb->id = SET_FWCMD_ID(type, cat, _class_, func);
|
h2cb->h2c_seq = fwinfo->h2c_seq;
|
|
return 0;
|
}
|
|
u32 h2c_pkt_set_cmd(struct mac_ax_adapter *adapter, struct h2c_buf *h2cb,
|
u8 *cmd, u32 len)
|
{
|
u8 *buf;
|
|
buf = h2cb_put(h2cb, len);
|
if (!buf)
|
return MACNPTR;
|
PLTFM_MEMCPY(buf, cmd, len);
|
return MACSUCCESS;
|
}
|
|
u32 h2c_pkt_build_txd(struct mac_ax_adapter *adapter, struct h2c_buf *h2cb)
|
{
|
u8 *buf;
|
u32 ret;
|
u32 txd_len;
|
struct rtw_t_meta_data info = {0};
|
struct mac_ax_ops *ops = adapter_to_mac_ops(adapter);
|
|
info.type = RTW_PHL_PKT_TYPE_H2C;
|
info.pktlen = (u16)h2cb->len;
|
txd_len = ops->txdesc_len(adapter, &info);
|
if (adapter->hw_info->intf == MAC_AX_INTF_USB) {
|
if (((info.pktlen + txd_len) & (512 - 1)) == 0) {
|
buf = h2cb_put(h2cb, 4);
|
if (!buf) {
|
PLTFM_MSG_ERR("Avoid USB 512-byte FAIL\n");
|
return MACNPTR;
|
}
|
info.pktlen = (u16)h2cb->len;
|
txd_len = ops->txdesc_len(adapter, &info);
|
}
|
}
|
|
buf = h2cb_push(h2cb, txd_len);
|
if (!buf)
|
return MACNPTR;
|
|
ret = ops->build_txdesc(adapter, &info, buf, txd_len);
|
if (ret)
|
return ret;
|
|
return MACSUCCESS;
|
}
|
|
static inline void __fwcmd_wq_insert(struct h2c_buf *new_h2cb,
|
struct h2c_buf *prev, struct h2c_buf *next,
|
struct fwcmd_wkb_head *list)
|
{
|
new_h2cb->next = next;
|
new_h2cb->prev = prev;
|
next->prev = new_h2cb;
|
prev->next = new_h2cb;
|
list->qlen++;
|
}
|
|
static inline void __fwcmd_wq_before(struct fwcmd_wkb_head *list,
|
struct h2c_buf *next,
|
struct h2c_buf *new_h2cb)
|
{
|
__fwcmd_wq_insert(new_h2cb, next->prev, next, list);
|
}
|
|
static inline void __fwcmd_wq_tail(struct fwcmd_wkb_head *list,
|
struct h2c_buf *new_h2cb)
|
{
|
__fwcmd_wq_before(list, (struct h2c_buf *)list, new_h2cb);
|
}
|
|
u32 fwcmd_wq_enqueue(struct mac_ax_adapter *adapter, struct h2c_buf *h2cb)
|
{
|
struct fwcmd_wkb_head *list_head = &fwcmd_wq_head;
|
|
if (list_head->qlen > FWCMD_WQ_MAX_JOB_NUM) {
|
PLTFM_MSG_WARN("[WARN]fwcmd work queue full\n");
|
return MACBUFALLOC;
|
}
|
|
/* worq queue doesn't need wd body */
|
h2cb_pull(h2cb, WD_BODY_LEN);
|
PLTFM_MUTEX_LOCK(&list_head->lock);
|
__fwcmd_wq_tail(list_head, h2cb);
|
PLTFM_MUTEX_UNLOCK(&list_head->lock);
|
|
return MACSUCCESS;
|
}
|
|
static inline void __fwcmd_wq_unlink(struct h2c_buf *h2cb,
|
struct fwcmd_wkb_head *list)
|
{
|
struct h2c_buf *next, *prev;
|
|
list->qlen--;
|
next = h2cb->next;
|
prev = h2cb->prev;
|
h2cb->prev = NULL;
|
h2cb->next = NULL;
|
next->prev = prev;
|
prev->next = next;
|
}
|
|
struct h2c_buf *fwcmd_wq_dequeue(struct mac_ax_adapter *adapter, u32 id)
|
{
|
struct fwcmd_wkb_head *list_head = &fwcmd_wq_head;
|
struct h2c_buf *h2cb;
|
u32 hdr0;
|
u16 type = GET_FWCMD_TYPE(id);
|
u16 cat = GET_FWCMD_CAT(id);
|
u16 _class_ = GET_FWCMD_CLASS(id);
|
u16 func = GET_FWCMD_FUNC(id);
|
|
PLTFM_MUTEX_LOCK(&list_head->lock);
|
|
for (h2cb = list_head->next; h2cb->next != list_head->next;
|
h2cb = h2cb->next) {
|
hdr0 = ((struct fwcmd_hdr *)h2cb->data)->hdr0;
|
hdr0 = le32_to_cpu(hdr0);
|
if (type == GET_FIELD(hdr0, H2C_HDR_DEL_TYPE) &&
|
cat == GET_FIELD(hdr0, H2C_HDR_CAT) &&
|
_class_ == GET_FIELD(hdr0, H2C_HDR_CLASS) &&
|
func == GET_FIELD(hdr0, H2C_HDR_FUNC)) {
|
__fwcmd_wq_unlink(h2cb, list_head);
|
PLTFM_MUTEX_UNLOCK(&list_head->lock);
|
return h2cb;
|
}
|
}
|
|
PLTFM_MUTEX_UNLOCK(&list_head->lock);
|
|
PLTFM_MSG_ERR("[ERR]cannot find wq item: %X\n", id);
|
|
return NULL;
|
}
|
|
u32 fwcmd_wq_idle(struct mac_ax_adapter *adapter, u32 id)
|
{
|
struct fwcmd_wkb_head *list_head = &fwcmd_wq_head;
|
struct h2c_buf *h2cb;
|
|
PLTFM_MUTEX_LOCK(&list_head->lock);
|
|
for (h2cb = list_head->next; h2cb->next != list_head->next;
|
h2cb = h2cb->next) {
|
if (h2cb->id == id) {
|
PLTFM_MUTEX_UNLOCK(&list_head->lock);
|
return MACWQBUSY;
|
}
|
}
|
|
PLTFM_MUTEX_UNLOCK(&list_head->lock);
|
|
return MACSUCCESS;
|
}
|
#endif
|
|
static u32 c2h_fwi_cmd_log(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
#if MAC_AX_FEATURE_DBGDEC
|
u8 syntax_1 = 0, syntax_2 = 0;
|
|
if ((len - FWCMD_HDR_LEN) >= 11) {
|
syntax_1 = *(buf + FWCMD_HDR_LEN);
|
syntax_2 = *(buf + FWCMD_HDR_LEN + 1);
|
}
|
//PLTFM_MSG_WARN("C2H encoded log syntax_1 %x, syntax_2 %x", syntax_1, syntax_2);
|
if (syntax_1 == 0xa5 && syntax_2 == 0xa5) {
|
//PLTFM_MSG_WARN("C2H encoded log");
|
fw_log_dump(adapter, buf, len, info);
|
} else {
|
if (buf[len - 1] != '\0')
|
buf[len - 1] = '\0';
|
PLTFM_MSG_WARN("C2H log: %s", (char *)(buf + FWCMD_HDR_LEN));
|
}
|
#else
|
if (buf[len - 1] != '\0')
|
buf[len - 1] = '\0';
|
PLTFM_MSG_WARN("C2H log: %s", (char *)(buf + FWCMD_HDR_LEN));
|
#endif
|
return MACSUCCESS;
|
}
|
|
static u32 c2h_wow_rcv_ack_hdl(struct mac_ax_adapter *adapter,
|
struct rtw_c2h_info *info)
|
{
|
u8 *state;
|
|
switch (info->c2h_func) {
|
case FWCMD_H2C_FUNC_AOAC_REPORT_REQ:
|
state = &adapter->sm.aoac_rpt;
|
break;
|
|
default:
|
return MACSUCCESS;
|
}
|
|
if (*state == MAC_AX_AOAC_RPT_H2C_SENDING)
|
*state = MAC_AX_AOAC_RPT_H2C_RCVD;
|
|
return MACSUCCESS;
|
}
|
|
static u32 c2h_fwofld_rcv_ack_hdl(struct mac_ax_adapter *adapter,
|
struct rtw_c2h_info *info)
|
{
|
u8 *state;
|
|
switch (info->c2h_func) {
|
case FWCMD_H2C_FUNC_WRITE_OFLD:
|
state = &adapter->sm.write_h2c;
|
break;
|
|
case FWCMD_H2C_FUNC_CONF_OFLD:
|
state = &adapter->sm.conf_h2c;
|
break;
|
|
case FWCMD_H2C_FUNC_PACKET_OFLD:
|
state = &adapter->sm.pkt_ofld;
|
break;
|
|
case FWCMD_H2C_FUNC_READ_OFLD:
|
state = &adapter->sm.read_h2c;
|
break;
|
|
case FWCMD_H2C_FUNC_DUMP_EFUSE:
|
state = &adapter->sm.efuse_ofld;
|
break;
|
case FWCMD_H2C_FUNC_CH_SWITCH:
|
state = &adapter->sm.ch_switch;
|
break;
|
|
default:
|
return MACSUCCESS;
|
}
|
|
if (*state == MAC_AX_OFLD_H2C_SENDING)
|
*state = MAC_AX_OFLD_H2C_RCVD;
|
|
return MACSUCCESS;
|
}
|
|
static u32 c2h_fwi_rev_ack(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
u32 data = *(u32 *)(buf + FWCMD_HDR_LEN);
|
u32 ret;
|
u32 cat;
|
|
data = le32_to_cpu(data);
|
|
cat = GET_FIELD(data, FWCMD_C2H_REC_ACK_CAT);
|
if (cat == FWCMD_H2C_CAT_OUTSRC)
|
return MACSUCCESS;
|
|
info->c2h_cat = GET_FIELD(data, FWCMD_C2H_REC_ACK_CAT);
|
info->c2h_class = GET_FIELD(data, FWCMD_C2H_REC_ACK_CLASS);
|
info->c2h_func = GET_FIELD(data, FWCMD_C2H_REC_ACK_FUNC);
|
info->h2c_seq = GET_FIELD(data, FWCMD_C2H_REC_ACK_H2C_SEQ);
|
adapter->fw_info.rec_seq = info->h2c_seq;
|
info->type_rec_ack = 1;
|
|
if (info->c2h_cat == FWCMD_H2C_CAT_MAC) {
|
switch (info->c2h_class) {
|
case FWCMD_H2C_CL_WOW:
|
ret = c2h_wow_rcv_ack_hdl(adapter, info);
|
if (ret)
|
return ret;
|
break;
|
|
case FWCMD_H2C_CL_FW_OFLD:
|
ret = c2h_fwofld_rcv_ack_hdl(adapter, info);
|
if (ret)
|
return ret;
|
break;
|
|
default:
|
return MACSUCCESS;
|
}
|
}
|
|
return MACSUCCESS;
|
}
|
|
static u32 c2h_fwofld_done_ack_hdl(struct mac_ax_adapter *adapter,
|
struct rtw_c2h_info *info)
|
{
|
struct mac_ax_state_mach *sm = &adapter->sm;
|
struct mac_ax_pkt_ofld_info *ofld_info = &adapter->pkt_ofld_info;
|
struct mac_ax_scanofld_info *scanofld_info = &adapter->scanofld_info;
|
|
switch (info->c2h_func) {
|
case FWCMD_H2C_FUNC_WRITE_OFLD:
|
if (sm->write_h2c == MAC_AX_OFLD_H2C_RCVD) {
|
if (info->h2c_return == MACSUCCESS)
|
sm->write_h2c = MAC_AX_OFLD_H2C_IDLE;
|
else
|
sm->write_h2c = MAC_AX_OFLD_H2C_ERROR;
|
}
|
break;
|
|
case FWCMD_H2C_FUNC_CONF_OFLD:
|
if (sm->conf_h2c == MAC_AX_OFLD_H2C_RCVD) {
|
if (info->h2c_return == MACSUCCESS)
|
sm->conf_h2c = MAC_AX_OFLD_H2C_IDLE;
|
else
|
sm->conf_h2c = MAC_AX_OFLD_H2C_ERROR;
|
}
|
break;
|
|
case FWCMD_H2C_FUNC_PACKET_OFLD:
|
if (sm->pkt_ofld == MAC_AX_OFLD_H2C_RCVD) {
|
if (info->h2c_return == MACSUCCESS) {
|
if (ofld_info->last_op == PKT_OFLD_OP_READ)
|
sm->pkt_ofld = MAC_AX_OFLD_H2C_DONE;
|
else
|
sm->pkt_ofld = MAC_AX_OFLD_H2C_IDLE;
|
} else {
|
sm->pkt_ofld = MAC_AX_OFLD_H2C_ERROR;
|
}
|
} else {
|
PLTFM_MSG_ERR("cant set pkt ofld state since no recv ack is received.");
|
}
|
break;
|
|
case FWCMD_H2C_FUNC_READ_OFLD:
|
if (sm->read_h2c == MAC_AX_OFLD_H2C_RCVD) {
|
if (info->h2c_return == MACSUCCESS)
|
sm->read_h2c = MAC_AX_OFLD_H2C_DONE;
|
else
|
sm->read_h2c = MAC_AX_OFLD_H2C_ERROR;
|
}
|
break;
|
|
case FWCMD_H2C_FUNC_DUMP_EFUSE:
|
if (sm->efuse_ofld == MAC_AX_OFLD_H2C_RCVD) {
|
if (info->h2c_return == MACSUCCESS)
|
sm->efuse_ofld = MAC_AX_OFLD_H2C_DONE;
|
else
|
sm->efuse_ofld = MAC_AX_OFLD_H2C_ERROR;
|
}
|
break;
|
case FWCMD_H2C_FUNC_ADD_SCANOFLD_CH:
|
if (scanofld_info->clear_drv_ch_list && scanofld_info->list->head)
|
mac_scanofld_ch_list_clear(adapter, scanofld_info->list);
|
PLTFM_MSG_TRACE("[scan] got add scanofld done ack. clear chlist busy\n");
|
PLTFM_MUTEX_LOCK(&scanofld_info->drv_chlist_state_lock);
|
adapter->scanofld_info.drv_chlist_busy = 0;
|
PLTFM_MUTEX_UNLOCK(&scanofld_info->drv_chlist_state_lock);
|
PLTFM_MUTEX_LOCK(&scanofld_info->fw_chlist_state_lock);
|
adapter->scanofld_info.fw_chlist_busy = 0;
|
PLTFM_MUTEX_UNLOCK(&scanofld_info->fw_chlist_state_lock);
|
PLTFM_MSG_TRACE("[scan] drv_chlist_state = %d, fw_chlist_state = %d\n",
|
adapter->scanofld_info.drv_chlist_busy,
|
adapter->scanofld_info.fw_chlist_busy);
|
break;
|
case FWCMD_H2C_FUNC_SCANOFLD:
|
if (info->h2c_return != MACSUCCESS) {
|
PLTFM_MSG_TRACE("[scan]scan func fail, revert fwchlist and fw status\n");
|
PLTFM_MUTEX_LOCK(&scanofld_info->fw_chlist_state_lock);
|
scanofld_info->fw_chlist_busy = !scanofld_info->fw_chlist_busy;
|
PLTFM_MUTEX_UNLOCK(&scanofld_info->fw_chlist_state_lock);
|
scanofld_info->fw_scan_busy = !scanofld_info->fw_scan_busy;
|
}
|
PLTFM_MSG_TRACE("[scan] fw_scan_busy = %d, fw_chlist_state = %d\n",
|
scanofld_info->fw_scan_busy,
|
scanofld_info->fw_chlist_busy);
|
break;
|
default:
|
break;
|
}
|
return MACSUCCESS;
|
}
|
|
static u32 c2h_role_done_ack_hdl(struct mac_ax_adapter *adapter,
|
struct rtw_c2h_info *info)
|
{
|
struct mac_ax_state_mach *sm = &adapter->sm;
|
|
if (info->c2h_class == FWCMD_H2C_CL_MEDIA_RPT &&
|
info->c2h_func == FWCMD_H2C_FUNC_FWROLE_MAINTAIN) {
|
if (info->h2c_return == MACSUCCESS) {
|
sm->role_stat = MAC_AX_ROLE_ALOC_SUCC;
|
} else {
|
PLTFM_MSG_ERR("[ERR]role_maintain: alloc failed\n");
|
sm->role_stat = MAC_AX_ROLE_ALOC_FAIL;
|
return MACROLEALOCFL;
|
}
|
} else if (info->c2h_class == FWCMD_H2C_CL_MEDIA_RPT &&
|
info->c2h_func == FWCMD_H2C_FUNC_JOININFO) {
|
if (info->h2c_return == MACSUCCESS) {
|
sm->role_stat = MAC_AX_ROLE_INIT_SUCC;
|
} else {
|
PLTFM_MSG_ERR("[ERR]role_join: init failed\n");
|
sm->role_stat = MAC_AX_ROLE_INIT_FAIL;
|
return MACROLEINITFL;
|
}
|
} else if (info->c2h_class == FWCMD_H2C_CL_ADDR_CAM_UPDATE &&
|
info->c2h_func == FWCMD_H2C_FUNC_ADDRCAM_INFO) {
|
if (info->h2c_return == MACSUCCESS) {
|
sm->role_stat = MAC_AX_ROLE_HW_UPD_SUCC;
|
} else {
|
PLTFM_MSG_ERR("[ERR]ADDR_CAM: upd failed\n");
|
sm->role_stat = MAC_AX_ROLE_HW_UPD_FAIL;
|
return MACROLEHWUPDFL;
|
}
|
}
|
return MACSUCCESS;
|
}
|
|
static u32 c2h_ps_done_ack_hdl(struct mac_ax_adapter *adapter,
|
struct rtw_c2h_info *info)
|
{
|
struct mac_ax_state_mach *sm = &adapter->sm;
|
u8 p2pid;
|
u32 ret;
|
|
switch (info->c2h_func) {
|
case FWCMD_H2C_FUNC_P2P_ACT:
|
if (sm->p2p_stat != MAC_AX_P2P_ACT_BUSY) {
|
PLTFM_MSG_ERR("[ERR]p2p act dack stat err %d\n",
|
sm->p2p_stat);
|
return MACPROCERR;
|
}
|
|
if (info->h2c_return != MACSUCCESS) {
|
PLTFM_MSG_ERR("[ERR]p2p act dack ret %d\n",
|
info->h2c_return);
|
sm->p2p_stat = MAC_AX_P2P_ACT_FAIL;
|
break;
|
}
|
|
p2pid = P2PID_INVALID;
|
ret = get_wait_dack_p2pid(adapter, &p2pid);
|
if (ret != MACSUCCESS) {
|
PLTFM_MSG_ERR("[ERR]p2p act dack get wait id %d\n", ret);
|
return ret;
|
}
|
if (p2pid != P2PID_INVALID) {
|
if (adapter->p2p_info[p2pid].run) {
|
PLTFM_MEMSET(&adapter->p2p_info[p2pid], 0,
|
sizeof(struct mac_ax_p2p_info));
|
} else {
|
adapter->p2p_info[p2pid].run = 1;
|
adapter->p2p_info[p2pid].wait_dack = 0;
|
}
|
} else {
|
PLTFM_MSG_ERR("[ERR]p2p act dack no wait id\n");
|
}
|
sm->p2p_stat = MAC_AX_P2P_ACT_IDLE;
|
break;
|
case FWCMD_H2C_FUNC_P2P_MACID_CTRL:
|
if (sm->p2p_stat != MAC_AX_P2P_ACT_BUSY) {
|
PLTFM_MSG_ERR("[ERR]p2p macid ctrl dack stat err %d\n",
|
sm->p2p_stat);
|
return MACPROCERR;
|
}
|
|
if (info->h2c_return != MACSUCCESS) {
|
PLTFM_MSG_ERR("[ERR]p2p macid ctrl dack ret %d\n",
|
info->h2c_return);
|
sm->p2p_stat = MAC_AX_P2P_ACT_FAIL;
|
break;
|
}
|
|
p2pid = P2PID_INVALID;
|
ret = get_wait_dack_p2pid(adapter, &p2pid);
|
if (ret != MACSUCCESS) {
|
PLTFM_MSG_ERR("[ERR]p2p macid ctrl dack get wait id %d\n",
|
ret);
|
return ret;
|
}
|
if (p2pid != P2PID_INVALID) {
|
if (adapter->p2p_info[p2pid].run) {
|
adapter->p2p_info[p2pid].wait_dack = 0;
|
} else {
|
PLTFM_MSG_ERR("[ERR]p2p%d macid ctrl dack not run\n",
|
p2pid);
|
}
|
} else {
|
PLTFM_MSG_ERR("[ERR]p2p macid ctrl dack no wait id\n");
|
}
|
sm->p2p_stat = MAC_AX_P2P_ACT_IDLE;
|
break;
|
case FWCMD_H2C_FUNC_IPS_CFG:
|
if (info->h2c_return != MACSUCCESS)
|
PLTFM_MSG_ERR("[ERR]fwips dack ret %d\n", info->h2c_return);
|
break;
|
case FWCMD_H2C_FUNC_PS_ADVANCE_PARM:
|
if (info->h2c_return != MACSUCCESS)
|
PLTFM_MSG_ERR("[ERR]ps advanced parm dack ret %d\n", info->h2c_return);
|
break;
|
default:
|
break;
|
}
|
|
return MACSUCCESS;
|
}
|
|
static u32 c2h_fwi_done_ack(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
u32 data = *(u32 *)(buf + FWCMD_HDR_LEN);
|
u32 ret;
|
u32 cat;
|
|
data = le32_to_cpu(data);
|
|
cat = GET_FIELD(data, FWCMD_C2H_REC_ACK_CAT);
|
if (cat == FWCMD_H2C_CAT_OUTSRC)
|
return MACSUCCESS;
|
|
info->c2h_cat = GET_FIELD(data, FWCMD_C2H_DONE_ACK_CAT);
|
info->c2h_class = GET_FIELD(data, FWCMD_C2H_DONE_ACK_CLASS);
|
info->c2h_func = GET_FIELD(data, FWCMD_C2H_DONE_ACK_FUNC);
|
info->h2c_return = GET_FIELD(data, FWCMD_C2H_DONE_ACK_H2C_RETURN);
|
info->h2c_seq = GET_FIELD(data, FWCMD_C2H_DONE_ACK_H2C_SEQ);
|
info->type_done_ack = 1;
|
|
if (info->c2h_cat == FWCMD_H2C_CAT_MAC) {
|
if (info->c2h_class == FWCMD_H2C_CL_FW_OFLD) {
|
ret = c2h_fwofld_done_ack_hdl(adapter, info);
|
if (ret != MACSUCCESS)
|
return ret;
|
} else if (info->c2h_class == FWCMD_H2C_CL_PS) {
|
ret = c2h_ps_done_ack_hdl(adapter, info);
|
if (ret != MACSUCCESS)
|
return ret;
|
} else if (info->c2h_class == FWCMD_H2C_CL_MEDIA_RPT ||
|
info->c2h_class == FWCMD_H2C_CL_ADDR_CAM_UPDATE) {
|
ret = c2h_role_done_ack_hdl(adapter, info);
|
if (ret != MACSUCCESS)
|
return ret;
|
}
|
}
|
|
return MACSUCCESS;
|
}
|
|
static u32 c2h_fwi_bcn_stats(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
return MACSUCCESS;
|
}
|
|
static u32 c2h_fwi_bcn_csazero(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
return MACSUCCESS;
|
}
|
|
static struct c2h_proc_func c2h_proc_fw_info_cmd[] = {
|
{FWCMD_C2H_FUNC_REC_ACK, c2h_fwi_rev_ack},
|
{FWCMD_C2H_FUNC_DONE_ACK, c2h_fwi_done_ack},
|
{FWCMD_C2H_FUNC_C2H_LOG, c2h_fwi_cmd_log},
|
{FWCMD_C2H_FUNC_BCN_CNT, c2h_fwi_bcn_stats},
|
{FWCMD_C2H_FUNC_BCN_CSAZERO, c2h_fwi_bcn_csazero},
|
{FWCMD_C2H_FUNC_NULL, NULL},
|
};
|
|
u32 c2h_fw_info(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
struct c2h_proc_func *proc = c2h_proc_fw_info_cmd;
|
u32 (*handler)(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info) = NULL;
|
u32 hdr0;
|
u32 func;
|
|
hdr0 = ((struct fwcmd_hdr *)buf)->hdr0;
|
hdr0 = le32_to_cpu(hdr0);
|
|
func = GET_FIELD(hdr0, C2H_HDR_FUNC);
|
|
while (proc->id != FWCMD_C2H_FUNC_NULL) {
|
if (func == proc->id) {
|
handler = proc->handler;
|
break;
|
}
|
proc++;
|
}
|
|
if (!handler) {
|
PLTFM_MSG_ERR("[ERR]null func handler id: %X", func);
|
return MACNOITEM;
|
}
|
|
return handler(adapter, buf, len, info);
|
}
|
|
static u32 c2h_dump_efuse_hdl(struct mac_ax_adapter *adapter, u8 *buf,
|
u32 len, struct rtw_c2h_info *info)
|
{
|
struct mac_ax_efuse_ofld_info *ofld_info = &adapter->efuse_ofld_info;
|
u32 size;
|
|
if (adapter->sm.efuse_ofld != MAC_AX_OFLD_H2C_RCVD) {
|
PLTFM_MSG_ERR("[ERR]not cmd sending\n");
|
return MACPROCERR;
|
}
|
|
size = adapter->hw_info->efuse_size;
|
|
if (!ofld_info->buf) {
|
ofld_info->buf = (u8 *)PLTFM_MALLOC(size);
|
if (!ofld_info->buf) {
|
adapter->sm.efuse = MAC_AX_EFUSE_IDLE;
|
return MACBUFALLOC;
|
}
|
}
|
|
PLTFM_MEMCPY(ofld_info->buf, buf + FWCMD_HDR_LEN, size);
|
|
adapter->sm.efuse_ofld = MAC_AX_OFLD_H2C_DONE;
|
|
return MACSUCCESS;
|
}
|
|
static u32 c2h_read_rsp_hdl(struct mac_ax_adapter *adapter, u8 *buf,
|
u32 len, struct rtw_c2h_info *info)
|
{
|
struct mac_ax_read_ofld_value *value_info = &adapter->read_ofld_value;
|
u32 hdr1;
|
u16 read_len;
|
u8 *read_buff;
|
|
if (value_info->buf)
|
PLTFM_FREE(value_info->buf, value_info->len);
|
|
hdr1 = ((struct fwcmd_hdr *)buf)->hdr1;
|
hdr1 = le32_to_cpu(hdr1);
|
|
read_len = GET_FIELD(hdr1, C2H_HDR_TOTAL_LEN) - FWCMD_HDR_LEN;
|
|
read_buff = (u8 *)PLTFM_MALLOC(read_len);
|
if (!read_buff)
|
return MACBUFALLOC;
|
|
PLTFM_MEMCPY(read_buff, buf + FWCMD_HDR_LEN, read_len);
|
|
value_info->len = read_len;
|
value_info->buf = read_buff;
|
|
return MACSUCCESS;
|
}
|
|
static u32 c2h_pkt_ofld_rsp_hdl(struct mac_ax_adapter *adapter, u8 *buf,
|
u32 len, struct rtw_c2h_info *info)
|
{
|
struct mac_ax_pkt_ofld_info *ofld_info = &adapter->pkt_ofld_info;
|
struct mac_ax_pkt_ofld_pkt *ofld_pkt = &adapter->pkt_ofld_pkt;
|
u32 c2h_content = *(u32 *)(buf + FWCMD_HDR_LEN);
|
u16 pkt_len;
|
u8 id, pkt_op;
|
u8 *pkt_buff;
|
u8 *pkt_content;
|
|
c2h_content = le32_to_cpu(c2h_content);
|
|
pkt_op = GET_FIELD(c2h_content, FWCMD_C2H_PKT_OFLD_RSP_PKT_OP);
|
pkt_len = GET_FIELD(c2h_content, FWCMD_C2H_PKT_OFLD_RSP_PKT_LENGTH);
|
id = GET_FIELD(c2h_content, FWCMD_C2H_PKT_OFLD_RSP_PKT_ID);
|
|
PLTFM_MSG_TRACE("get pkt ofld rsp. pkt_op: %d, pkt_len: %d, id: %d\n", pkt_op, pkt_len, id);
|
|
switch (pkt_op) {
|
case PKT_OFLD_OP_ADD:
|
if (pkt_len != 0) {
|
ofld_info->id_bitmap[id >> 3] |= (1 << (id & 7));
|
ofld_info->free_id_count--;
|
ofld_info->used_id_count++;
|
}
|
|
break;
|
|
case PKT_OFLD_OP_DEL:
|
if (pkt_len != 0) {
|
ofld_info->id_bitmap[id >> 3] &= ~(1 << (id & 7));
|
ofld_info->free_id_count++;
|
ofld_info->used_id_count--;
|
}
|
|
break;
|
|
case PKT_OFLD_OP_READ:
|
if (pkt_len != 0) {
|
if (ofld_pkt->pkt)
|
PLTFM_FREE(ofld_pkt->pkt, ofld_pkt->pkt_len);
|
|
pkt_buff = (u8 *)PLTFM_MALLOC(pkt_len);
|
if (!pkt_buff)
|
return MACBUFALLOC;
|
|
pkt_content = buf + FWCMD_HDR_LEN;
|
pkt_content += sizeof(struct mac_ax_pkt_ofld_hdr);
|
PLTFM_MEMCPY(pkt_buff, pkt_content, pkt_len);
|
ofld_pkt->pkt_id = id;
|
ofld_pkt->pkt_len = pkt_len;
|
ofld_pkt->pkt = pkt_buff;
|
}
|
break;
|
|
default:
|
PLTFM_MSG_ERR("[ERR]invalid packet offload op: %d", pkt_op);
|
break;
|
}
|
|
return MACSUCCESS;
|
}
|
|
static u32 c2h_beacon_resend_hdl(struct mac_ax_adapter *adapter, u8 *buf,
|
u32 len, struct rtw_c2h_info *info)
|
{
|
return MACSUCCESS;
|
}
|
|
static u32 c2h_macid_pause_hdl(struct mac_ax_adapter *adapter, u8 *buf,
|
u32 len, struct rtw_c2h_info *info)
|
{
|
return MACSUCCESS;
|
}
|
|
static u32 c2h_tx_duty_hdl(struct mac_ax_adapter *adapter, u8 *buf,
|
u32 len, struct rtw_c2h_info *info)
|
{
|
u32 content = *(u32 *)(buf + FWCMD_HDR_LEN);
|
struct mac_ax_tx_duty_ofld_info ofld_info;
|
|
content = le32_to_cpu(content);
|
|
ofld_info.timer_err =
|
GET_FIELD(content, FWCMD_C2H_TX_DUTY_RPT_TIMER_ERR);
|
|
if (ofld_info.timer_err)
|
PLTFM_MSG_ERR("[ERR]Tx duty FW timer error\n");
|
|
return MACSUCCESS;
|
}
|
|
static u32 c2h_tsf32_togl_rpt_hdl(struct mac_ax_adapter *adapter, u8 *buf,
|
u32 len, struct rtw_c2h_info *info)
|
{
|
struct fwcmd_tsf32_togl_rpt rpt;
|
struct mac_ax_t32_togl_rpt *out_rpt;
|
u8 band, port;
|
|
if (!buf) {
|
PLTFM_MSG_ERR("[ERR]tsf32 togl rpt no buf\n");
|
return MACNPTR;
|
}
|
|
rpt.dword0 = le32_to_cpu(*(u32 *)(buf + FWCMD_HDR_LEN));
|
rpt.dword1 = le32_to_cpu(*(u32 *)(buf + FWCMD_HDR_LEN + 4));
|
rpt.dword2 = le32_to_cpu(*(u32 *)(buf + FWCMD_HDR_LEN + 8));
|
|
band = rpt.dword0 & FWCMD_C2H_TSF32_TOGL_RPT_BAND;
|
if (band >= MAC_AX_BAND_NUM) {
|
PLTFM_MSG_ERR("[ERR]invalid band %d in tsf32 togl rpt\n", band);
|
return MACNOITEM;
|
}
|
|
port = GET_FIELD(rpt.dword0, FWCMD_C2H_TSF32_TOGL_RPT_PORT);
|
if (port >= MAC_AX_PORT_NUM) {
|
PLTFM_MSG_ERR("[ERR]invalid port %d in tsf32 togl rpt\n", port);
|
return MACNOITEM;
|
}
|
|
out_rpt = &adapter->t32_togl_rpt[get_bp_idx(band, port)];
|
out_rpt->band = band;
|
out_rpt->port = port;
|
out_rpt->status = GET_FIELD(rpt.dword0, FWCMD_C2H_TSF32_TOGL_RPT_STATUS);
|
out_rpt->early = GET_FIELD(rpt.dword0, FWCMD_C2H_TSF32_TOGL_RPT_EARLY);
|
out_rpt->tsf_l = GET_FIELD(rpt.dword1, FWCMD_C2H_TSF32_TOGL_RPT_TSF_L);
|
out_rpt->tsf_h = GET_FIELD(rpt.dword2, FWCMD_C2H_TSF32_TOGL_RPT_TSF_H);
|
out_rpt->valid = 1;
|
|
return MACSUCCESS;
|
}
|
|
static u32 c2h_cmd_ofld_rsp_hdl(struct mac_ax_adapter *adapter, u8 *buf,
|
u32 len, struct rtw_c2h_info *info)
|
{
|
struct fwcmd_cmd_ofld_rsp rsp;
|
struct mac_ax_cmd_ofld_info *ofld_info = &adapter->cmd_ofld_info;
|
struct mac_ax_state_mach *sm = &adapter->sm;
|
|
if (!buf) {
|
PLTFM_MSG_ERR("[ERR]tsf32 togl rpt no buf\n");
|
return MACNPTR;
|
}
|
|
rsp.dword0 = le32_to_cpu(*(u32 *)(buf + FWCMD_HDR_LEN));
|
|
ofld_info->result = rsp.dword0 & FWCMD_C2H_CMD_OFLD_RSP_RESULT;
|
if (ofld_info->result) {
|
PLTFM_MSG_ERR("%s: IO offload fail!!!\n", __func__);
|
rsp.dword1 = le32_to_cpu(*(u32 *)(buf + FWCMD_HDR_LEN + 4));
|
rsp.dword2 = le32_to_cpu(*(u32 *)(buf + FWCMD_HDR_LEN + 8));
|
rsp.dword3 = le32_to_cpu(*(u32 *)(buf + FWCMD_HDR_LEN + 12));
|
PLTFM_MSG_ERR("offset = %x\n", rsp.dword1);
|
PLTFM_MSG_ERR("expected val = %x\n", rsp.dword2);
|
PLTFM_MSG_ERR("read val = %x\n", rsp.dword3);
|
}
|
|
if (sm->cmd_state != MAC_AX_CMD_OFLD_SENDING)
|
PLTFM_MSG_ERR("%s: IO offload stat err\n", __func__);
|
else
|
sm->cmd_state = MAC_AX_CMD_OFLD_RCVD;
|
|
return MACSUCCESS;
|
}
|
|
static u32 c2h_scanofld_rsp_hdl(struct mac_ax_adapter *adapter, u8 *buf,
|
u32 len, struct rtw_c2h_info *info)
|
{
|
struct fwcmd_scanofld_rsp rsp;
|
u32 *c2h_content = (u32 *)(buf + FWCMD_HDR_LEN);
|
// u8 central_ch;
|
// u8 scanned_ch;
|
u8 notify_reason;
|
// u8 status;
|
// u32 tsf_low;
|
// u32 tsf_high;
|
// u32 spent_low;
|
// u32 spent_high;
|
|
rsp.dword0 = le32_to_cpu(*c2h_content);
|
// central_ch = GET_FIELD(rsp.dword0, FWCMD_C2H_SCANOFLD_RSP_CENTRAL_CH);
|
// scanned_ch = GET_FIELD(rsp.dword0, FWCMD_C2H_SCANOFLD_RSP_SCANNED_CH);
|
notify_reason = GET_FIELD(rsp.dword0, FWCMD_C2H_SCANOFLD_RSP_NOTIFY_REASON);
|
// status = GET_FIELD(rsp.dword0, FWCMD_C2H_SCANOFLD_RSP_STATUS);
|
// tsf_low = le32_to_cpu(*(c2h_content + 1));
|
// tsf_high = le32_to_cpu(*(c2h_content + 2));
|
// spent_low = le32_to_cpu(*(c2h_content + 3));
|
// spent_high = le32_to_cpu(*(c2h_content + 4));
|
if (notify_reason == MAC_AX_SCAN_END_SCAN_NOTIFY) {
|
PLTFM_MUTEX_LOCK(&adapter->scanofld_info.fw_chlist_state_lock);
|
adapter->scanofld_info.fw_chlist_busy = 0;
|
PLTFM_MUTEX_UNLOCK(&adapter->scanofld_info.fw_chlist_state_lock);
|
adapter->scanofld_info.fw_scan_busy = 0;
|
}
|
return 0;
|
}
|
|
static u32 c2h_ch_switch_rpt_hdl(struct mac_ax_adapter *adapter, u8 *buf,
|
u32 len, struct rtw_c2h_info *info)
|
{
|
u32 *content = (u32 *)(buf + FWCMD_HDR_LEN);
|
u8 *state;
|
u32 rpt_size;
|
struct mac_ax_ch_switch_rpt *rpt;
|
|
state = &adapter->sm.ch_switch;
|
if (*state != MAC_AX_OFLD_H2C_SENDING && *state != MAC_AX_OFLD_H2C_RCVD)
|
return MACPROCERR;
|
rpt_size = sizeof(struct mac_ax_ch_switch_rpt);
|
if (!adapter->ch_switch_rpt)
|
adapter->ch_switch_rpt = (struct mac_ax_ch_switch_rpt *)PLTFM_MALLOC(rpt_size);
|
if (!adapter->ch_switch_rpt)
|
return MACPROCERR;
|
rpt = adapter->ch_switch_rpt;
|
rpt->result = (u8)GET_FIELD(le32_to_cpu(*content), FWCMD_C2H_CH_SWITCH_RPT_RESULT);
|
*state = MAC_AX_CH_SWITCH_GET_RPT;
|
return MACSUCCESS;
|
}
|
|
static u32 c2h_bcn_filter_rpt_hdl(struct mac_ax_adapter *adapter, u8 *buf,
|
u32 len, struct rtw_c2h_info *info)
|
{
|
struct fwcmd_bcnfltr_rpt *rpt = (struct fwcmd_bcnfltr_rpt *)(buf + FWCMD_HDR_LEN);
|
u32 dword;
|
u8 macid, type, rssi_evt, rssi_ma;
|
|
dword = le32_to_cpu(rpt->dword0);
|
macid = GET_FIELD(dword, FWCMD_C2H_BCNFLTR_RPT_MACID);
|
type = GET_FIELD(dword, FWCMD_C2H_BCNFLTR_RPT_TYPE);
|
rssi_evt = GET_FIELD(dword, FWCMD_C2H_BCNFLTR_RPT_RSSI_EVT);
|
rssi_ma = GET_FIELD(dword, FWCMD_C2H_BCNFLTR_RPT_RSSI_MA);
|
|
switch (type) {
|
case BCNFLTR_NOTI_BCN_LOSS:
|
PLTFM_MSG_TRACE("[BCNFLTR] bcn loss\n");
|
break;
|
case BCNFLTR_NOTI_DENY_SCAN:
|
PLTFM_MSG_TRACE("[BCNFLTR] deny scan\n");
|
break;
|
case BCNFLTR_NOTI_RSSI:
|
PLTFM_MSG_TRACE("[BCNFLTR] rssi: ma=%d, evt=%d\n", rssi_ma, rssi_evt);
|
break;
|
}
|
return MACSUCCESS;
|
}
|
|
static struct c2h_proc_func c2h_proc_fw_ofld_cmd[] = {
|
{FWCMD_C2H_FUNC_EFUSE_DUMP, c2h_dump_efuse_hdl},
|
{FWCMD_C2H_FUNC_READ_RSP, c2h_read_rsp_hdl},
|
{FWCMD_C2H_FUNC_PKT_OFLD_RSP, c2h_pkt_ofld_rsp_hdl},
|
{FWCMD_C2H_FUNC_BEACON_RESEND, c2h_beacon_resend_hdl},
|
{FWCMD_C2H_FUNC_MACID_PAUSE, c2h_macid_pause_hdl},
|
{FWCMD_C2H_FUNC_TSF32_TOGL_RPT, c2h_tsf32_togl_rpt_hdl},
|
{FWCMD_C2H_FUNC_CMD_OFLD_RSP, c2h_cmd_ofld_rsp_hdl},
|
{FWCMD_C2H_FUNC_TX_DUTY_RPT, c2h_tx_duty_hdl},
|
{FWCMD_C2H_FUNC_SCANOFLD_RSP, c2h_scanofld_rsp_hdl},
|
{FWCMD_C2H_FUNC_CH_SWITCH_RPT, c2h_ch_switch_rpt_hdl},
|
{FWCMD_C2H_FUNC_BCNFLTR_RPT, c2h_bcn_filter_rpt_hdl},
|
{FWCMD_C2H_FUNC_NULL, NULL},
|
};
|
|
u32 c2h_fw_ofld(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
struct c2h_proc_func *proc = c2h_proc_fw_ofld_cmd;
|
u32 (*handler)(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info) = NULL;
|
u32 hdr0;
|
u32 func;
|
|
hdr0 = ((struct fwcmd_hdr *)buf)->hdr0;
|
hdr0 = le32_to_cpu(hdr0);
|
|
func = GET_FIELD(hdr0, C2H_HDR_FUNC);
|
|
while (proc->id != FWCMD_C2H_FUNC_NULL) {
|
if (func == proc->id) {
|
handler = proc->handler;
|
break;
|
}
|
proc++;
|
}
|
|
if (!handler) {
|
PLTFM_MSG_ERR("[ERR]null func handler id: %X", func);
|
return MACNOITEM;
|
}
|
|
return handler(adapter, buf, len, info);
|
}
|
|
u32 c2h_twt(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
return MACSUCCESS;
|
}
|
|
u32 c2h_wow_aoac_report_hdl(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
struct mac_ax_wowlan_info *wowlan_info = &adapter->wowlan_info;
|
u8 *c2h_content = buf + FWCMD_HDR_LEN;
|
|
if (adapter->sm.aoac_rpt != MAC_AX_AOAC_RPT_H2C_RCVD)
|
return MACPROCERR;
|
|
if (!wowlan_info->aoac_report)
|
return MACBUFALLOC;
|
|
PLTFM_MEMCPY(wowlan_info->aoac_report, c2h_content, sizeof(struct mac_ax_aoac_report));
|
|
adapter->sm.aoac_rpt = MAC_AX_AOAC_RPT_H2C_DONE;
|
|
return MACSUCCESS;
|
}
|
|
static struct c2h_proc_func c2h_proc_wow_cmd[] = {
|
{FWCMD_C2H_FUNC_AOAC_REPORT, c2h_wow_aoac_report_hdl},
|
{FWCMD_C2H_FUNC_NULL, NULL},
|
};
|
|
u32 c2h_wow(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
struct c2h_proc_func *proc = c2h_proc_wow_cmd;
|
u32 (*handler)(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info) = NULL;
|
u32 hdr0;
|
u32 func;
|
|
hdr0 = ((struct fwcmd_hdr *)buf)->hdr0;
|
hdr0 = le32_to_cpu(hdr0);
|
|
func = GET_FIELD(hdr0, C2H_HDR_FUNC);
|
|
while (proc->id != FWCMD_C2H_FUNC_NULL) {
|
if (func == proc->id) {
|
handler = proc->handler;
|
break;
|
}
|
proc++;
|
}
|
|
if (!handler) {
|
PLTFM_MSG_ERR("[ERR]null func handler id: %X", func);
|
return MACNOITEM;
|
}
|
|
return handler(adapter, buf, len, info);
|
}
|
|
u32 c2h_mcc_rcv_ack_hdl(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
struct mac_ax_state_mach *sm = &adapter->sm;
|
u32 c2h_content = *(u32 *)(buf + FWCMD_HDR_LEN);
|
u8 group, h2c_func;
|
|
c2h_content = le32_to_cpu(c2h_content);
|
group = GET_FIELD(c2h_content, FWCMD_C2H_MCC_RCV_ACK_GROUP);
|
h2c_func = GET_FIELD(c2h_content, FWCMD_C2H_MCC_RCV_ACK_H2C_FUNC);
|
|
if (h2c_func <= FWCMD_H2C_FUNC_RESET_MCC_GROUP) {
|
PLTFM_MSG_TRACE("[TRACE]%s: MCC group H2C rcv ack\n",
|
__func__);
|
|
if (sm->mcc_group[group] == MAC_AX_MCC_STATE_H2C_SENT) {
|
sm->mcc_group[group] = MAC_AX_MCC_STATE_H2C_RCVD;
|
|
PLTFM_MSG_TRACE("[TRACE]%s: MCC group %d state: %d\n",
|
__func__, group,
|
MAC_AX_MCC_STATE_H2C_RCVD);
|
}
|
} else if (h2c_func <= FWCMD_H2C_FUNC_MCC_SET_DURATION) {
|
PLTFM_MSG_TRACE("[TRACE]%s: MCC request H2C rcv ack\n",
|
__func__);
|
|
if (sm->mcc_request[group] == MAC_AX_MCC_REQ_H2C_SENT) {
|
sm->mcc_request[group] = MAC_AX_MCC_REQ_H2C_RCVD;
|
|
PLTFM_MSG_TRACE("[TRACE]%s: MCC group %d state: %d\n",
|
__func__, group,
|
MAC_AX_MCC_REQ_H2C_RCVD);
|
}
|
} else {
|
PLTFM_MSG_ERR("[ERR]%s: invalid MCC H2C func %d\n",
|
__func__, h2c_func);
|
return MACNOITEM;
|
}
|
|
return MACSUCCESS;
|
}
|
|
u32 c2h_mcc_req_ack_hdl(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
struct mac_ax_state_mach *sm = &adapter->sm;
|
u32 c2h_content = *(u32 *)(buf + FWCMD_HDR_LEN);
|
u8 group, h2c_func, h2c_return;
|
|
c2h_content = le32_to_cpu(c2h_content);
|
group = GET_FIELD(c2h_content, FWCMD_C2H_MCC_REQ_ACK_GROUP);
|
h2c_func = GET_FIELD(c2h_content, FWCMD_C2H_MCC_REQ_ACK_H2C_FUNC);
|
h2c_return = GET_FIELD(c2h_content, FWCMD_C2H_MCC_REQ_ACK_H2C_RETURN);
|
|
PLTFM_MSG_TRACE("[TRACE]%s: group: %d, h2c_func: %d, h2c_return: %d\n",
|
__func__, group, h2c_func, h2c_return);
|
|
if (h2c_func < FWCMD_H2C_FUNC_MCC_REQ_TSF) {
|
PLTFM_MSG_ERR("[ERR]%s: invalid MCC H2C func: %d\n",
|
__func__, h2c_func);
|
return MACNOITEM;
|
}
|
|
PLTFM_MSG_TRACE("[TRACE]%s: group %d curr req state: %d\n",
|
__func__, group, sm->mcc_request[group]);
|
|
if (sm->mcc_request[group] == MAC_AX_MCC_REQ_H2C_RCVD) {
|
if (h2c_return == 0) {
|
if (h2c_func == FWCMD_H2C_FUNC_MCC_REQ_TSF)
|
sm->mcc_request[group] = MAC_AX_MCC_REQ_DONE;
|
else
|
sm->mcc_request[group] = MAC_AX_MCC_REQ_IDLE;
|
} else {
|
sm->mcc_request[group] = MAC_AX_MCC_REQ_FAIL;
|
PLTFM_MSG_ERR("[ERR]%s: MCC H2C func %d fail: %d\n",
|
__func__, h2c_func, h2c_return);
|
}
|
}
|
|
return MACSUCCESS;
|
}
|
|
u32 c2h_mcc_tsf_rpt_hdl(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
struct mac_ax_mcc_group_info *mcc_info = &adapter->mcc_group_info;
|
struct fwcmd_mcc_tsf_rpt *tsf_rpt;
|
u32 c2h_content;
|
u32 tsf;
|
u8 macid_x, macid_y, group;
|
|
PLTFM_MSG_TRACE("[TRACE]%s: mcc tsf report received\n", __func__);
|
|
tsf_rpt = (struct fwcmd_mcc_tsf_rpt *)(buf + FWCMD_HDR_LEN);
|
|
c2h_content = tsf_rpt->dword0;
|
c2h_content = le32_to_cpu(c2h_content);
|
group = GET_FIELD(c2h_content, FWCMD_C2H_MCC_TSF_RPT_GROUP);
|
macid_x = GET_FIELD(c2h_content, FWCMD_C2H_MCC_TSF_RPT_MACID_X);
|
macid_y = GET_FIELD(c2h_content, FWCMD_C2H_MCC_TSF_RPT_MACID_Y);
|
|
PLTFM_MSG_TRACE("[TRACE]%s: group: %d, macid_x: %d, macid_y: %d\n",
|
__func__, group, macid_x, macid_y);
|
|
mcc_info->groups[group].macid_x = macid_x;
|
mcc_info->groups[group].macid_y = macid_y;
|
|
tsf = tsf_rpt->dword1;
|
tsf = le32_to_cpu(tsf);
|
mcc_info->groups[group].tsf_x_low = tsf;
|
|
tsf = tsf_rpt->dword2;
|
tsf = le32_to_cpu(tsf);
|
mcc_info->groups[group].tsf_x_high = tsf;
|
|
tsf = tsf_rpt->dword3;
|
tsf = le32_to_cpu(tsf);
|
mcc_info->groups[group].tsf_y_low = tsf;
|
|
tsf = tsf_rpt->dword4;
|
tsf = le32_to_cpu(tsf);
|
mcc_info->groups[group].tsf_y_high = tsf;
|
|
PLTFM_MSG_TRACE("[TRACE]%s: tsf_x_high: 0x%x, tsf_x_low: 0x%x\n",
|
__func__, mcc_info->groups[group].tsf_x_high,
|
mcc_info->groups[group].tsf_x_low);
|
|
PLTFM_MSG_TRACE("[TRACE]%s: tsf_y_high: 0x%x, tsf_y_low: 0x%x\n",
|
__func__, mcc_info->groups[group].tsf_y_high,
|
mcc_info->groups[group].tsf_y_low);
|
|
return MACSUCCESS;
|
}
|
|
u32 c2h_mcc_status_rpt_hdl(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
struct mac_ax_mcc_group_info *mcc_info = &adapter->mcc_group_info;
|
struct mac_ax_state_mach *sm = &adapter->sm;
|
struct fwcmd_mcc_status_rpt *mcc_rpt;
|
u32 c2h_content;
|
u32 tsf_low;
|
u32 tsf_high;
|
u8 group, status, macid;
|
|
PLTFM_MSG_TRACE("[TRACE]%s: mcc status report received\n", __func__);
|
|
mcc_rpt = (struct fwcmd_mcc_status_rpt *)(buf + FWCMD_HDR_LEN);
|
|
c2h_content = mcc_rpt->dword0;
|
tsf_low = mcc_rpt->dword1;
|
tsf_high = mcc_rpt->dword2;
|
|
c2h_content = le32_to_cpu(c2h_content);
|
group = GET_FIELD(c2h_content, FWCMD_C2H_MCC_STATUS_RPT_GROUP);
|
macid = GET_FIELD(c2h_content, FWCMD_C2H_MCC_STATUS_RPT_MACID);
|
status = GET_FIELD(c2h_content, FWCMD_C2H_MCC_STATUS_RPT_STATUS);
|
|
PLTFM_MSG_TRACE("[TRACE]%s: mcc group: %d, macid: %d, status: %d\n",
|
__func__, group, macid, status);
|
|
switch (status) {
|
case MAC_AX_MCC_ADD_ROLE_OK:
|
if (sm->mcc_group[group] == MAC_AX_MCC_STATE_H2C_RCVD) {
|
sm->mcc_group[group] = MAC_AX_MCC_ADD_DONE;
|
PLTFM_MSG_TRACE("[TRACE]%s: mcc group %d add done\n",
|
__func__, group);
|
}
|
break;
|
|
case MAC_AX_MCC_START_GROUP_OK:
|
if (sm->mcc_group[group] == MAC_AX_MCC_STATE_H2C_RCVD) {
|
sm->mcc_group[group] = MAC_AX_MCC_START_DONE;
|
PLTFM_MSG_TRACE("[TRACE]%s: mcc group %d start done\n",
|
__func__, group);
|
}
|
break;
|
|
case MAC_AX_MCC_STOP_GROUP_OK:
|
sm->mcc_group[group] = MAC_AX_MCC_STOP_DONE;
|
PLTFM_MSG_TRACE("[TRACE]%s: mcc group %d stop done\n",
|
__func__, group);
|
break;
|
|
case MAC_AX_MCC_DEL_GROUP_OK:
|
sm->mcc_group[group] = MAC_AX_MCC_EMPTY;
|
PLTFM_MSG_TRACE("[TRACE]%s: mcc group %d empty\n",
|
__func__, group);
|
break;
|
|
case MAC_AX_MCC_RESET_GROUP_OK:
|
if (sm->mcc_group[group] == MAC_AX_MCC_STATE_H2C_RCVD) {
|
sm->mcc_group[group] = MAC_AX_MCC_EMPTY;
|
PLTFM_MSG_TRACE("[TRACE]%s: mcc group %d empty\n",
|
__func__, group);
|
}
|
break;
|
|
case MAC_AX_MCC_ADD_ROLE_FAIL:
|
case MAC_AX_MCC_START_GROUP_FAIL:
|
case MAC_AX_MCC_STOP_GROUP_FAIL:
|
case MAC_AX_MCC_DEL_GROUP_FAIL:
|
case MAC_AX_MCC_RESET_GROUP_FAIL:
|
if (sm->mcc_group[group] == MAC_AX_MCC_STATE_H2C_RCVD) {
|
PLTFM_MSG_ERR("[ERR]%s: mcc group %d fail status: %d\n",
|
__func__, group, status);
|
sm->mcc_group[group] = MAC_AX_MCC_STATE_ERROR;
|
}
|
break;
|
|
default:
|
break;
|
}
|
|
tsf_low = le32_to_cpu(tsf_low);
|
tsf_high = le32_to_cpu(tsf_high);
|
|
mcc_info->groups[group].rpt_status = status;
|
mcc_info->groups[group].rpt_macid = macid;
|
mcc_info->groups[group].rpt_tsf_low = tsf_low;
|
mcc_info->groups[group].rpt_tsf_high = tsf_high;
|
|
PLTFM_MSG_TRACE("[TRACE]%s: tsf_high: 0x%x, tsf_low: 0x%x\n",
|
__func__, tsf_high, tsf_low);
|
|
return MACSUCCESS;
|
}
|
|
static struct c2h_proc_func c2h_proc_mcc_cmd[] = {
|
{FWCMD_C2H_FUNC_MCC_RCV_ACK, c2h_mcc_rcv_ack_hdl},
|
{FWCMD_C2H_FUNC_MCC_REQ_ACK, c2h_mcc_req_ack_hdl},
|
{FWCMD_C2H_FUNC_MCC_TSF_RPT, c2h_mcc_tsf_rpt_hdl},
|
{FWCMD_C2H_FUNC_MCC_STATUS_RPT, c2h_mcc_status_rpt_hdl},
|
{FWCMD_C2H_FUNC_NULL, NULL},
|
};
|
|
u32 c2h_mcc(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
struct c2h_proc_func *proc = c2h_proc_mcc_cmd;
|
u32 (*handler)(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info) = NULL;
|
u32 hdr0;
|
u32 func;
|
|
hdr0 = ((struct fwcmd_hdr *)buf)->hdr0;
|
hdr0 = le32_to_cpu(hdr0);
|
|
func = GET_FIELD(hdr0, C2H_HDR_FUNC);
|
|
PLTFM_MSG_TRACE("[TRACE]%s: func: %d\n", __func__, func);
|
|
while (proc->id != FWCMD_C2H_FUNC_NULL) {
|
if (func == proc->id) {
|
handler = proc->handler;
|
break;
|
}
|
proc++;
|
}
|
|
if (!handler) {
|
PLTFM_MSG_ERR("[ERR]%s: null func handler id: %X",
|
__func__, func);
|
return MACNOITEM;
|
}
|
|
return handler(adapter, buf, len, info);
|
}
|
|
u32 c2h_rx_dbg_hdl(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
PLTFM_MSG_ERR("[ERR]%s: FW encounter Rx problem!\n", __func__);
|
|
return MACSUCCESS;
|
}
|
|
static struct c2h_proc_func c2h_proc_fw_dbg_cmd[] = {
|
{FWCMD_C2H_FUNC_RX_DBG, c2h_rx_dbg_hdl},
|
{FWCMD_C2H_FUNC_NULL, NULL},
|
};
|
|
u32 c2h_fw_dbg(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
struct c2h_proc_func *proc = c2h_proc_fw_dbg_cmd;
|
u32 (*handler)(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info) = NULL;
|
u32 hdr0;
|
u32 func;
|
|
hdr0 = ((struct fwcmd_hdr *)buf)->hdr0;
|
hdr0 = le32_to_cpu(hdr0);
|
|
func = GET_FIELD(hdr0, C2H_HDR_FUNC);
|
|
PLTFM_MSG_TRACE("[TRACE]%s: func: %d\n", __func__, func);
|
|
while (proc->id != FWCMD_C2H_FUNC_NULL) {
|
if (func == proc->id) {
|
handler = proc->handler;
|
break;
|
}
|
proc++;
|
}
|
|
if (!handler) {
|
PLTFM_MSG_ERR("[ERR]%s: null func handler id: %X",
|
__func__, func);
|
return MACNOITEM;
|
}
|
|
return handler(adapter, buf, len, info);
|
}
|
|
u32 c2h_wps_rpt(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
PLTFM_MSG_TRACE("recevied wps report\n");
|
return MACSUCCESS;
|
}
|
|
static u32 c2h_misc_ccxrpt(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
return MACSUCCESS;
|
}
|
|
static struct c2h_proc_func c2h_proc_misc[] = {
|
{FWCMD_C2H_FUNC_WPS_RPT, c2h_wps_rpt},
|
{FWCMD_C2H_FUNC_CCXRPT, c2h_misc_ccxrpt},
|
{FWCMD_C2H_FUNC_NULL, NULL},
|
};
|
|
static u32 c2h_cl_misc(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
struct c2h_proc_func *proc = c2h_proc_misc;
|
u32 (*handler)(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info) = NULL;
|
u32 hdr0;
|
u32 func;
|
|
hdr0 = ((struct fwcmd_hdr *)buf)->hdr0;
|
hdr0 = le32_to_cpu(hdr0);
|
|
func = GET_FIELD(hdr0, C2H_HDR_FUNC);
|
|
while (proc->id != FWCMD_C2H_FUNC_NULL) {
|
if (func == proc->id) {
|
handler = proc->handler;
|
break;
|
}
|
proc++;
|
}
|
|
if (!handler) {
|
PLTFM_MSG_ERR("[ERR]null func handler id: %X", func);
|
return MACNOITEM;
|
}
|
|
return handler(adapter, buf, len, info);
|
}
|
|
u32 c2h_fast_ch_sw_rpt_hdl(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
u32 *c2h_content;
|
u32 *rpt_status;
|
|
PLTFM_MSG_TRACE("[HM][C2H][FCS] get rpt func\n");
|
adapter->fast_ch_sw_info.busy = 0;
|
c2h_content = (u32 *)(buf + FWCMD_HDR_LEN);
|
rpt_status = &adapter->fast_ch_sw_info.status;
|
PLTFM_MEMCPY(rpt_status, c2h_content, sizeof(u32));
|
PLTFM_MSG_TRACE("[HM][C2H][FCS] Report Status: 0x%x\n", adapter->fast_ch_sw_info.status);
|
|
return MACSUCCESS;
|
}
|
|
static struct c2h_proc_func c2h_proc_fast_ch_sw_cmd[] = {
|
{FWCMD_C2H_FUNC_FCS_RPT, c2h_fast_ch_sw_rpt_hdl},
|
{FWCMD_C2H_FUNC_NULL, NULL},
|
};
|
|
u32 c2h_fast_ch_sw(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
u32 hdr0;
|
u32 func;
|
u32 (*handler)(struct mac_ax_adapter *adpater, u8 *buf,
|
u32 len, struct rtw_c2h_info *info);
|
struct c2h_proc_func *proc;
|
|
proc = c2h_proc_fast_ch_sw_cmd;
|
handler = NULL;
|
hdr0 = ((struct fwcmd_hdr *)buf)->hdr0;
|
hdr0 = le32_to_cpu(hdr0);
|
|
func = GET_FIELD(hdr0, C2H_HDR_FUNC);
|
|
while (proc->id != FWCMD_C2H_FUNC_NULL) {
|
if (func == proc->id) {
|
handler = proc->handler;
|
break;
|
}
|
proc++;
|
}
|
|
if (!handler) {
|
PLTFM_MSG_ERR("[ERR][%s]: sent id = %x", __func__, func);
|
return MACNOITEM;
|
}
|
|
return handler(adapter, buf, len, info);
|
}
|
|
u32 c2h_port_init_stat(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
struct fwcmd_port_init_stat stat;
|
struct mac_ax_port_info *pinfo;
|
u8 band, port;
|
u32 ret, tmp32;
|
|
stat.dword0 = le32_to_cpu(*(u32 *)(buf + FWCMD_HDR_LEN));
|
stat.dword1 = le32_to_cpu(*(u32 *)(buf + FWCMD_HDR_LEN + 4));
|
stat.dword2 = le32_to_cpu(*(u32 *)(buf + FWCMD_HDR_LEN + 8));
|
|
band = stat.dword0 & FWCMD_C2H_PORT_INIT_STAT_BAND;
|
if (band >= MAC_AX_BAND_NUM) {
|
PLTFM_MSG_ERR("[ERR]invalid band %d in port init stat\n", band);
|
return MACNOITEM;
|
}
|
|
port = GET_FIELD(stat.dword0, FWCMD_C2H_PORT_INIT_STAT_PORT);
|
if (port >= MAC_AX_PORT_NUM) {
|
PLTFM_MSG_ERR("[ERR]invalid port %d in port init stat\n", port);
|
return MACNOITEM;
|
}
|
|
pinfo = &adapter->port_info[get_bp_idx(band, port)];
|
|
ret = GET_FIELD(stat.dword2, FWCMD_C2H_PORT_INIT_STAT_RET);
|
if (ret != C2H_MPORT_RET_SUCCESS) {
|
PLTFM_MSG_ERR("[ERR]B%dP%d init fail: ret %d\n",
|
band, port, ret);
|
tmp32 = GET_FIELD(stat.dword0, FWCMD_C2H_PORT_INIT_STAT_STEP);
|
PLTFM_MSG_ERR("[ERR]B%dP%d init fail: step %d\n",
|
band, port, tmp32);
|
tmp32 = GET_FIELD(stat.dword0, FWCMD_C2H_PORT_INIT_STAT_CFG_MBID_IDX);
|
PLTFM_MSG_ERR("[ERR]B%dP%d init fail: cfg mbid %d\n",
|
band, port, tmp32);
|
tmp32 = GET_FIELD(stat.dword0, FWCMD_C2H_PORT_INIT_STAT_CFG_TYPE);
|
PLTFM_MSG_ERR("[ERR]B%dP%d init fail: cfg type %d\n",
|
band, port, tmp32);
|
tmp32 = GET_FIELD(stat.dword1, FWCMD_C2H_PORT_INIT_STAT_CFG_VAL);
|
PLTFM_MSG_ERR("[ERR]B%dP%d init fail: cfg val %d\n",
|
band, port, tmp32);
|
pinfo->h2c_sm = MAC_AX_PORT_H2C_FAIL;
|
} else {
|
pinfo->h2c_sm = MAC_AX_PORT_H2C_IDLE;
|
}
|
|
return MACSUCCESS;
|
}
|
|
u32 c2h_port_cfg_stat(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
struct fwcmd_port_cfg_stat stat;
|
struct mac_ax_port_info *pinfo;
|
u8 band, port, mbssid;
|
u32 ret, tmp32;
|
|
stat.dword0 = le32_to_cpu(*(u32 *)(buf + FWCMD_HDR_LEN));
|
stat.dword1 = le32_to_cpu(*(u32 *)(buf + FWCMD_HDR_LEN + 4));
|
stat.dword2 = le32_to_cpu(*(u32 *)(buf + FWCMD_HDR_LEN + 8));
|
|
band = stat.dword0 & FWCMD_C2H_PORT_CFG_STAT_BAND;
|
if (band >= MAC_AX_BAND_NUM) {
|
PLTFM_MSG_ERR("[ERR]invalid band %d in port cfg stat\n", band);
|
return MACNOITEM;
|
}
|
|
port = GET_FIELD(stat.dword0, FWCMD_C2H_PORT_CFG_STAT_PORT);
|
if (port >= MAC_AX_PORT_NUM) {
|
PLTFM_MSG_ERR("[ERR]invalid port %d in port cfg stat\n", port);
|
return MACNOITEM;
|
}
|
|
pinfo = &adapter->port_info[get_bp_idx(band, port)];
|
mbssid = GET_FIELD(stat.dword0, FWCMD_C2H_PORT_CFG_STAT_MBSSID_IDX);
|
|
ret = GET_FIELD(stat.dword2, FWCMD_C2H_PORT_CFG_STAT_RET);
|
if (ret != C2H_MPORT_RET_SUCCESS) {
|
PLTFM_MSG_ERR("[ERR]B%dP%dMB%d cfg fail: ret %d\n",
|
band, port, mbssid, ret);
|
tmp32 = GET_FIELD(stat.dword0, FWCMD_C2H_PORT_CFG_STAT_TYPE);
|
PLTFM_MSG_ERR("[ERR]B%dP%dMB%d cfg fail: type %d\n",
|
band, port, mbssid, tmp32);
|
tmp32 = GET_FIELD(stat.dword1, FWCMD_C2H_PORT_CFG_STAT_VAL);
|
PLTFM_MSG_ERR("[ERR]B%dP%dMB%d cfg fail: val %d\n",
|
band, port, mbssid, tmp32);
|
pinfo->h2c_sm = MAC_AX_PORT_H2C_FAIL;
|
} else {
|
pinfo->h2c_sm = MAC_AX_PORT_H2C_IDLE;
|
}
|
|
return MACSUCCESS;
|
}
|
|
static struct c2h_proc_func c2h_proc_mport[] = {
|
{FWCMD_C2H_FUNC_PORT_INIT_STAT, c2h_port_init_stat},
|
{FWCMD_C2H_FUNC_PORT_CFG_STAT, c2h_port_cfg_stat},
|
{FWCMD_C2H_FUNC_NULL, NULL},
|
};
|
|
static u32 c2h_cl_mport(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info)
|
{
|
struct c2h_proc_func *proc = c2h_proc_mport;
|
u32 (*handler)(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info) = NULL;
|
u32 hdr0;
|
u32 func;
|
|
hdr0 = ((struct fwcmd_hdr *)buf)->hdr0;
|
hdr0 = le32_to_cpu(hdr0);
|
|
func = GET_FIELD(hdr0, C2H_HDR_FUNC);
|
|
while (proc->id != FWCMD_C2H_FUNC_NULL) {
|
if (func == proc->id) {
|
handler = proc->handler;
|
break;
|
}
|
proc++;
|
}
|
|
if (!handler) {
|
PLTFM_MSG_ERR("[ERR]null func handler id: %X", func);
|
return MACNOITEM;
|
}
|
|
return handler(adapter, buf, len, info);
|
}
|
|
static struct c2h_proc_class c2h_proc_sys[] = {
|
#if MAC_AX_FEATURE_DBGPKG
|
{FWCMD_C2H_CL_CMD_PATH, c2h_sys_cmd_path},
|
{FWCMD_H2C_CL_PLAT_AUTO_TEST, c2h_sys_plat_autotest},
|
#if MAC_AX_FEATURE_HV
|
{FWCMD_C2H_CL_FW_AUTO, c2h_sys_fw_autotest},
|
#endif
|
#endif
|
{FWCMD_C2H_CL_FW_STATUS, c2h_fw_status},
|
{FWCMD_C2H_CL_NULL, NULL},
|
};
|
|
static struct c2h_proc_class c2h_proc_mac[] = {
|
{FWCMD_C2H_CL_FW_INFO, c2h_fw_info},
|
{FWCMD_C2H_CL_FW_OFLD, c2h_fw_ofld},
|
{FWCMD_C2H_CL_TWT, c2h_twt},
|
{FWCMD_C2H_CL_WOW, c2h_wow},
|
{FWCMD_C2H_CL_MCC, c2h_mcc},
|
{FWCMD_C2H_CL_FW_DBG, c2h_fw_dbg},
|
{FWCMD_C2H_CL_FLASH, c2h_sys_flash_pkt},
|
{FWCMD_C2H_CL_MISC, c2h_cl_misc},
|
{FWCMD_C2H_CL_FCS, c2h_fast_ch_sw},
|
{FWCMD_C2H_CL_MPORT, c2h_cl_mport},
|
{FWCMD_C2H_CL_NULL, NULL},
|
};
|
|
static inline struct c2h_proc_class *c2h_proc_sel(u8 cat)
|
{
|
struct c2h_proc_class *proc;
|
|
switch (cat) {
|
case FWCMD_C2H_CAT_TEST:
|
proc = c2h_proc_sys;
|
break;
|
case FWCMD_C2H_CAT_MAC:
|
proc = c2h_proc_mac;
|
break;
|
default:
|
proc = NULL;
|
break;
|
}
|
|
return proc;
|
}
|
|
u8 c2h_field_parsing(struct fwcmd_hdr *hdr, struct rtw_c2h_info *info)
|
{
|
u32 val;
|
|
val = le32_to_cpu(hdr->hdr0);
|
info->c2h_cat = GET_FIELD(val, C2H_HDR_CAT);
|
info->c2h_class = GET_FIELD(val, C2H_HDR_CLASS);
|
info->c2h_func = GET_FIELD(val, C2H_HDR_FUNC);
|
|
val = le32_to_cpu(hdr->hdr1);
|
info->content_len = GET_FIELD(val, C2H_HDR_TOTAL_LEN) -
|
FWCMD_HDR_LEN;
|
info->content = (u8 *)(hdr + 1);
|
|
return MACSUCCESS;
|
}
|
|
u32 mac_process_c2h(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
u8 *ret)
|
{
|
u8 _class_, result;
|
struct c2h_proc_class *proc;
|
struct fwcmd_hdr *hdr;
|
struct rtw_c2h_info *info;
|
u32 (*handler)(struct mac_ax_adapter *adapter, u8 *buf, u32 len,
|
struct rtw_c2h_info *info) = NULL;
|
u8 cat;
|
u32 val;
|
|
hdr = (struct fwcmd_hdr *)buf;
|
|
info = (struct rtw_c2h_info *)ret;
|
val = le32_to_cpu(hdr->hdr0);
|
|
result = c2h_field_parsing(hdr, info);
|
if (result) {
|
PLTFM_MSG_ERR("[ERR]parsing c2h hdr error: %X\n", val);
|
return MACNOITEM;
|
}
|
|
if (GET_FIELD(val, C2H_HDR_DEL_TYPE) != FWCMD_TYPE_C2H) {
|
PLTFM_MSG_ERR("[ERR]wrong fwcmd type: %X\n", val);
|
return MACNOITEM;
|
}
|
|
cat = (u8)GET_FIELD(val, C2H_HDR_CAT);
|
|
if (cat == FWCMD_C2H_CAT_OUTSRC)
|
return MACSUCCESS;
|
|
proc = c2h_proc_sel(cat);
|
if (!proc) {
|
PLTFM_MSG_ERR("[ERR]wrong fwcmd cat: %X\n", val);
|
return MACNOITEM;
|
}
|
|
_class_ = GET_FIELD(val, C2H_HDR_CLASS);
|
|
for (; proc->id != FWCMD_C2H_CL_NULL; proc++) {
|
if (_class_ == proc->id) {
|
handler = proc->handler;
|
break;
|
}
|
}
|
|
if (!handler) {
|
PLTFM_MSG_ERR("[ERR]null class handler id: %X", proc->id);
|
return MACNOITEM;
|
}
|
|
return handler(adapter, buf, len, info);
|
}
|
|
u32 mac_outsrc_h2c_common(struct mac_ax_adapter *adapter,
|
struct rtw_g6_h2c_hdr *hdr, u32 *pvalue)
|
{
|
u32 ret = 0;
|
u8 *buf;
|
#if MAC_AX_PHL_H2C
|
struct rtw_h2c_pkt *h2cb;
|
#else
|
struct h2c_buf *h2cb;
|
#endif
|
struct fwcmd_outsrc_info *info;
|
|
/*temp workaround for h2cb no functionality and outsrc has its timer*/
|
if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) {
|
PLTFM_MSG_ERR("FW is not ready\n");
|
return MACFWNONRDY;
|
}
|
|
h2cb = h2cb_alloc(adapter, (enum h2c_buf_class)hdr->type);
|
if (!h2cb)
|
return MACNPTR;
|
|
buf = h2cb_put(h2cb, hdr->content_len);
|
if (!buf) {
|
ret = MACNOBUF;
|
goto fail;
|
}
|
info = (struct fwcmd_outsrc_info *)buf;
|
PLTFM_MEMCPY(info->dword0, pvalue, hdr->content_len);
|
|
ret = h2c_pkt_set_hdr(adapter, h2cb,
|
FWCMD_TYPE_H2C,
|
FWCMD_H2C_CAT_OUTSRC,
|
hdr->h2c_class,
|
hdr->h2c_func,
|
hdr->rec_ack,
|
hdr->done_ack);
|
if (ret)
|
goto fail;
|
|
// return MACSUCCESS if h2c aggregation is enabled and enqueued successfully.
|
// H2C shall be sent by mac_h2c_agg_tx.
|
ret = h2c_agg_enqueue(adapter, h2cb);
|
if (ret == MACSUCCESS)
|
return MACSUCCESS;
|
|
ret = h2c_pkt_build_txd(adapter, h2cb);
|
if (ret)
|
goto fail;
|
|
#if MAC_AX_PHL_H2C
|
ret = PLTFM_TX(h2cb);
|
#else
|
ret = PLTFM_TX(h2cb->data, h2cb->len);
|
#endif
|
if (ret)
|
goto fail;
|
|
h2cb_free(adapter, h2cb);
|
|
h2c_end_flow(adapter);
|
|
return MACSUCCESS;
|
fail:
|
h2cb_free(adapter, h2cb);
|
|
return ret;
|
}
|
|
u32 mac_fw_log_cfg(struct mac_ax_adapter *adapter,
|
struct mac_ax_fw_log *log_cfg)
|
{
|
u32 ret = 0;
|
u8 *buf;
|
#if MAC_AX_PHL_H2C
|
struct rtw_h2c_pkt *h2cb;
|
#else
|
struct h2c_buf *h2cb;
|
#endif
|
struct fwcmd_log_cfg *log;
|
|
h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD);
|
if (!h2cb)
|
return MACNPTR;
|
|
buf = h2cb_put(h2cb, sizeof(struct fwcmd_log_cfg));
|
if (!buf) {
|
ret = MACNOBUF;
|
goto fail;
|
}
|
PLTFM_MEMSET(buf, 0, sizeof(struct fwcmd_log_cfg));
|
|
log = (struct fwcmd_log_cfg *)buf;
|
|
log->dword0 = cpu_to_le32(SET_WORD(log_cfg->level,
|
FWCMD_H2C_LOG_CFG_DBG_LV) |
|
SET_WORD(log_cfg->output,
|
FWCMD_H2C_LOG_CFG_PATH));
|
log->dword1 = cpu_to_le32(log_cfg->comp);
|
|
log->dword2 = cpu_to_le32(log_cfg->comp_ext);
|
|
ret = h2c_pkt_set_hdr(adapter, h2cb,
|
FWCMD_TYPE_H2C,
|
FWCMD_H2C_CAT_MAC,
|
FWCMD_H2C_CL_FW_INFO,
|
FWCMD_H2C_FUNC_LOG_CFG,
|
0,
|
1);
|
if (ret)
|
goto fail;
|
|
ret = h2c_pkt_build_txd(adapter, h2cb);
|
if (ret)
|
goto fail;
|
|
#if MAC_AX_PHL_H2C
|
ret = PLTFM_TX(h2cb);
|
#else
|
ret = PLTFM_TX(h2cb->data, h2cb->len);
|
#endif
|
if (ret)
|
goto fail;
|
|
h2cb_free(adapter, h2cb);
|
|
h2c_end_flow(adapter);
|
|
return MACSUCCESS;
|
fail:
|
h2cb_free(adapter, h2cb);
|
|
return ret;
|
}
|
|
u32 mac_send_bcn_h2c(struct mac_ax_adapter *adapter,
|
struct mac_ax_bcn_info *info)
|
{
|
#if MAC_AX_PHL_H2C
|
struct rtw_h2c_pkt *h2cb;
|
#else
|
struct h2c_buf *h2cb;
|
#endif
|
u8 *buf;
|
struct fwcmd_bcn_upd *hdr;
|
u32 ret = MACSUCCESS;
|
|
h2cb = h2cb_alloc(adapter, H2CB_CLASS_LONG_DATA);
|
if (!h2cb)
|
return MACNPTR;
|
|
hdr = (struct fwcmd_bcn_upd *)
|
h2cb_put(h2cb, sizeof(struct fwcmd_bcn_upd));
|
if (!hdr) {
|
ret = MACNOBUF;
|
goto fail;
|
}
|
|
info->grp_ie_ofst |= info->grp_ie_ofst ? BCN_GRPIE_OFST_EN : 0;
|
|
hdr->dword0 =
|
cpu_to_le32(SET_WORD(info->port,
|
FWCMD_H2C_BCN_UPD_PORT) |
|
SET_WORD(info->mbssid,
|
FWCMD_H2C_BCN_UPD_MBSSID) |
|
SET_WORD(info->band,
|
FWCMD_H2C_BCN_UPD_BAND) |
|
SET_WORD(info->grp_ie_ofst,
|
FWCMD_H2C_BCN_UPD_GRP_IE_OFST));
|
|
hdr->dword1 =
|
cpu_to_le32(SET_WORD(info->macid,
|
FWCMD_H2C_BCN_UPD_MACID) |
|
SET_WORD(info->ssn_sel,
|
FWCMD_H2C_BCN_UPD_SSN_SEL) |
|
SET_WORD(info->ssn_mode,
|
FWCMD_H2C_BCN_UPD_SSN_MODE) |
|
SET_WORD(info->rate_sel,
|
FWCMD_H2C_BCN_UPD_RATE) |
|
SET_WORD(info->txpwr,
|
FWCMD_H2C_BCN_UPD_TXPWR));
|
|
hdr->dword2 =
|
cpu_to_le32((info->txinfo_ctrl_en ?
|
FWCMD_H2C_BCN_UPD_TXINFO_CTRL_EN : 0) |
|
SET_WORD(info->ntx_path_en,
|
FWCMD_H2C_BCN_UPD_NTX_PATH_EN) |
|
SET_WORD(info->path_map_a,
|
FWCMD_H2C_BCN_UPD_PATH_MAP_A) |
|
SET_WORD(info->path_map_b,
|
FWCMD_H2C_BCN_UPD_PATH_MAP_B) |
|
SET_WORD(info->path_map_c,
|
FWCMD_H2C_BCN_UPD_PATH_MAP_C) |
|
SET_WORD(info->path_map_d,
|
FWCMD_H2C_BCN_UPD_PATH_MAP_D) |
|
(info->antsel_a ?
|
FWCMD_H2C_BCN_UPD_ANTSEL_A : 0) |
|
(info->antsel_b ?
|
FWCMD_H2C_BCN_UPD_ANTSEL_B : 0) |
|
(info->antsel_c ?
|
FWCMD_H2C_BCN_UPD_ANTSEL_C : 0) |
|
(info->antsel_d ?
|
FWCMD_H2C_BCN_UPD_ANTSEL_D : 0) |
|
SET_WORD(info->csa_ofst,
|
FWCMD_H2C_BCN_UPD_CSA_OFST));
|
|
buf = h2cb_put(h2cb, info->pld_len);
|
if (!buf) {
|
ret = MACNOBUF;
|
goto fail;
|
}
|
|
PLTFM_MEMCPY(buf, info->pld_buf, info->pld_len);
|
|
ret = h2c_pkt_set_hdr(adapter, h2cb,
|
FWCMD_TYPE_H2C,
|
FWCMD_H2C_CAT_MAC,
|
FWCMD_H2C_CL_FR_EXCHG,
|
FWCMD_H2C_FUNC_BCN_UPD,
|
0,
|
0);
|
if (ret)
|
goto fail;
|
|
ret = h2c_pkt_build_txd(adapter, h2cb);
|
if (ret)
|
goto fail;
|
|
#if MAC_AX_PHL_H2C
|
ret = PLTFM_TX(h2cb);
|
#else
|
ret = PLTFM_TX(h2cb->data, h2cb->len);
|
#endif
|
if (ret)
|
goto fail;
|
|
h2cb_free(adapter, h2cb);
|
|
h2c_end_flow(adapter);
|
|
return MACSUCCESS;
|
fail:
|
h2cb_free(adapter, h2cb);
|
|
return ret;
|
}
|
|
u32 mac_host_getpkt_h2c(struct mac_ax_adapter *adapter, u8 macid, u8 pkttype)
|
{
|
//temp patch, wait for h2creg api
|
u32 content = 0;
|
u32 ret;
|
|
content |= FWCMD_H2CREG_FUNC_GETPKT_INFORM;
|
content |= (1 << 8);
|
content |= (macid << 16);
|
content |= (pkttype << 24);
|
|
ret = mac_send_h2creg(adapter, &content, 1);
|
|
return ret;
|
}
|
|
#if MAC_AX_PHL_H2C
|
u32 __ie_cam_set_cmd(struct mac_ax_adapter *adapter, struct rtw_h2c_pkt *h2cb,
|
struct mac_ax_ie_cam_cmd_info *info)
|
{
|
struct fwcmd_ie_cam *cmd;
|
u8 *buf;
|
u32 ret = MACSUCCESS;
|
|
buf = h2cb_put(h2cb, sizeof(struct fwcmd_ie_cam));
|
if (!buf) {
|
ret = MACNOBUF;
|
return ret;
|
}
|
|
cmd = (struct fwcmd_ie_cam *)buf;
|
cmd->dword0 =
|
cpu_to_le32((info->en ? FWCMD_H2C_IE_CAM_CAM_EN : 0) |
|
(info->band ? FWCMD_H2C_IE_CAM_BAND : 0) |
|
(info->hit_en ? FWCMD_H2C_IE_CAM_HIT_FRWD_EN : 0) |
|
(info->miss_en ?
|
FWCMD_H2C_IE_CAM_MISS_FRWD_EN : 0) |
|
(info->rst ? FWCMD_H2C_IE_CAM_RST : 0) |
|
SET_WORD(info->port, FWCMD_H2C_IE_CAM_PORT) |
|
SET_WORD(info->hit_sel, FWCMD_H2C_IE_CAM_HIT_FRWD) |
|
SET_WORD(info->miss_sel,
|
FWCMD_H2C_IE_CAM_MISS_FRWD) |
|
SET_WORD(info->num, FWCMD_H2C_IE_CAM_UPD_NUM));
|
|
buf = h2cb_put(h2cb, info->buf_len);
|
if (!buf) {
|
ret = MACNOBUF;
|
return ret;
|
}
|
|
PLTFM_MEMCPY(buf, info->buf, info->buf_len);
|
|
return ret;
|
}
|
|
#else
|
u32 __ie_cam_set_cmd(struct mac_ax_adapter *adapter, struct h2c_buf *h2cb,
|
struct mac_ax_ie_cam_cmd_info *info)
|
{
|
struct fwcmd_ie_cam *cmd;
|
u8 *buf;
|
u32 ret = MACSUCCESS;
|
|
buf = h2cb_put(h2cb, sizeof(struct fwcmd_ie_cam));
|
if (!buf) {
|
ret = MACNOBUF;
|
return ret;
|
}
|
|
cmd = (struct fwcmd_ie_cam *)buf;
|
cmd->dword0 =
|
cpu_to_le32((info->en ? FWCMD_H2C_IE_CAM_CAM_EN : 0) |
|
(info->band ? FWCMD_H2C_IE_CAM_BAND : 0) |
|
(info->hit_en ? FWCMD_H2C_IE_CAM_HIT_FRWD_EN : 0) |
|
(info->miss_en ?
|
FWCMD_H2C_IE_CAM_MISS_FRWD_EN : 0) |
|
(info->rst ? FWCMD_H2C_IE_CAM_RST : 0) |
|
SET_WORD(info->port, FWCMD_H2C_IE_CAM_PORT) |
|
SET_WORD(info->hit_sel, FWCMD_H2C_IE_CAM_HIT_FRWD) |
|
SET_WORD(info->miss_sel,
|
FWCMD_H2C_IE_CAM_MISS_FRWD) |
|
SET_WORD(info->num, FWCMD_H2C_IE_CAM_UPD_NUM));
|
|
buf = h2cb_put(h2cb, info->buf_len);
|
if (!buf) {
|
ret = MACNOBUF;
|
return ret;
|
}
|
|
PLTFM_MEMCPY(buf, info->buf, info->buf_len);
|
|
return ret;
|
}
|
#endif
|
u32 mac_ie_cam_upd(struct mac_ax_adapter *adapter,
|
struct mac_ax_ie_cam_cmd_info *info)
|
{
|
#if MAC_AX_PHL_H2C
|
struct rtw_h2c_pkt *h2cb;
|
#else
|
struct h2c_buf *h2cb;
|
#endif
|
u32 ret;
|
|
h2cb = h2cb_alloc(adapter, H2CB_CLASS_DATA);
|
if (!h2cb)
|
return MACNPTR;
|
|
ret = __ie_cam_set_cmd(adapter, h2cb, info);
|
if (ret) {
|
PLTFM_MSG_ERR("H2C IE CAM set cmd fail %d\n", ret);
|
goto fail;
|
}
|
|
ret = h2c_pkt_set_hdr(adapter, h2cb,
|
FWCMD_TYPE_H2C,
|
FWCMD_H2C_CAT_MAC,
|
FWCMD_H2C_CL_IE_CAM,
|
FWCMD_H2C_FUNC_IE_CAM, 0, 1);
|
if (ret) {
|
PLTFM_MSG_ERR("H2C IE CAM set hdr fail %d\n", ret);
|
goto fail;
|
}
|
|
ret = h2c_pkt_build_txd(adapter, h2cb);
|
if (ret) {
|
PLTFM_MSG_ERR("H2C IE CAM build txd fail %d\n", ret);
|
goto fail;
|
}
|
|
#if MAC_AX_PHL_H2C
|
ret = PLTFM_TX(h2cb);
|
#else
|
ret = PLTFM_TX(h2cb->data, h2cb->len);
|
#endif
|
if (ret) {
|
PLTFM_MSG_ERR("H2C IE CAM tx fail %d\n", ret);
|
goto fail;
|
}
|
|
fail:
|
h2cb_free(adapter, h2cb);
|
|
if (!ret)
|
h2c_end_flow(adapter);
|
|
return ret;
|
}
|
|
u32 _mac_send_h2creg(struct mac_ax_adapter *adapter,
|
struct mac_ax_h2creg_info *h2c)
|
{
|
#define MAC_AX_H2CREG_CNT 100
|
#define MAC_AX_H2CREG_US 200
|
u32 cnt = MAC_AX_H2CREG_CNT;
|
u8 len, byte0, byte1, val;
|
struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
|
struct fwcmd_h2creg h2creg;
|
|
if (!h2c)
|
return MACSUCCESS;
|
|
if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) {
|
PLTFM_MSG_ERR("FW is not ready\n");
|
return MACFWNONRDY;
|
}
|
|
if (adapter->sm.mac_rdy != MAC_AX_MAC_RDY) {
|
PLTFM_MSG_TRACE("MAC is not ready\n");
|
adapter->stats.h2c_reg_uninit++;
|
}
|
|
do {
|
if (!(MAC_REG_R8(R_AX_H2CREG_CTRL) & B_AX_H2CREG_TRIGGER))
|
break;
|
PLTFM_DELAY_US(MAC_AX_H2CREG_US);
|
cnt--;
|
} while (cnt);
|
|
if (!cnt) {
|
PLTFM_MSG_ERR("FW does not process H2CREG\n");
|
return MACPOLLTO;
|
}
|
|
if (h2c->content_len > H2CREG_CONTENT_LEN) {
|
PLTFM_MSG_ERR("%s: h2creg len is TOO large\n", __func__);
|
return MACFUNCINPUT;
|
}
|
|
len = h2c->content_len + H2CREG_HDR_LEN;
|
if ((h2c->content_len + H2CREG_HDR_LEN) & 3)
|
len = ((h2c->content_len + H2CREG_HDR_LEN) >> 2) + 1;
|
else
|
len = (h2c->content_len + H2CREG_HDR_LEN) >> 2;
|
|
byte0 = (u8)GET_FIELD(h2c->h2c_content.dword0, FWCMD_H2CREG_BYTE2);
|
byte1 = (u8)GET_FIELD(h2c->h2c_content.dword0, FWCMD_H2CREG_BYTE3);
|
|
h2creg.dword0 = SET_WORD(h2c->id, FWCMD_H2CREG_H2CREG_HDR_FUNC) |
|
SET_WORD(len, FWCMD_H2CREG_H2CREG_HDR_TOTAL_LEN) |
|
SET_WORD(byte0, FWCMD_H2CREG_BYTE2) |
|
SET_WORD(byte1, FWCMD_H2CREG_BYTE3);
|
|
h2creg.dword1 = h2c->h2c_content.dword1;
|
h2creg.dword2 = h2c->h2c_content.dword2;
|
h2creg.dword3 = h2c->h2c_content.dword3;
|
|
MAC_REG_W32(R_AX_H2CREG_DATA0, h2creg.dword0);
|
MAC_REG_W32(R_AX_H2CREG_DATA1, h2creg.dword1);
|
MAC_REG_W32(R_AX_H2CREG_DATA2, h2creg.dword2);
|
MAC_REG_W32(R_AX_H2CREG_DATA3, h2creg.dword3);
|
H2CRegIncreaseCounter(adapter);
|
val = MAC_REG_R8(R_AX_H2CREG_CTRL);
|
MAC_REG_W8(R_AX_H2CREG_CTRL, val | B_AX_H2CREG_TRIGGER);
|
|
return MACSUCCESS;
|
}
|
|
u32 mac_send_h2creg(struct mac_ax_adapter *adapter, u32 *content, u8 len)
|
{
|
#define MAC_AX_H2CREG_PCNT 5
|
u32 cnt = MAC_AX_H2CREG_PCNT;
|
u8 i;
|
struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
|
|
if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) {
|
PLTFM_MSG_ERR("FW is not ready\n");
|
return MACFWNONRDY;
|
}
|
|
if (adapter->sm.mac_rdy != MAC_AX_MAC_RDY) {
|
PLTFM_MSG_TRACE("MAC is not ready\n");
|
adapter->stats.h2c_reg_uninit++;
|
}
|
|
if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852C) ||
|
is_chip_id(adapter, MAC_AX_CHIP_ID_8192XB)) {
|
do {
|
if (!MAC_REG_R8(R_AX_H2CREG_CTRL_V1))
|
break;
|
PLTFM_DELAY_US(1000);
|
cnt--;
|
} while (cnt);
|
} else {
|
do {
|
if (!MAC_REG_R8(R_AX_H2CREG_CTRL))
|
break;
|
PLTFM_DELAY_US(1000);
|
cnt--;
|
} while (cnt);
|
}
|
|
if (!cnt) {
|
PLTFM_MSG_ERR("FW does not process H2CREG\n");
|
return MACPOLLTO;
|
}
|
|
for (i = 0; i < len; i++)
|
MAC_REG_W32(R_AX_H2CREG_DATA0 + i * 4, content[i]);
|
|
if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852C) ||
|
is_chip_id(adapter, MAC_AX_CHIP_ID_8192XB))
|
MAC_REG_W8(R_AX_H2CREG_CTRL_V1, 1);
|
else
|
MAC_REG_W8(R_AX_H2CREG_CTRL, 1);
|
|
return MACSUCCESS;
|
}
|
|
u32 __recv_c2hreg(struct mac_ax_adapter *adapter, struct fwcmd_c2hreg *c2h)
|
{
|
struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
|
u8 val;
|
|
if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852C) ||
|
is_chip_id(adapter, MAC_AX_CHIP_ID_8192XB)) {
|
if (!(MAC_REG_R8(R_AX_C2HREG_CTRL_V1) & B_AX_C2HREG_TRIGGER))
|
return MACC2HREGEMP;
|
|
c2h->dword0 = MAC_REG_R32(R_AX_C2HREG_DATA0_V1);
|
c2h->dword1 = MAC_REG_R32(R_AX_C2HREG_DATA1_V1);
|
c2h->dword2 = MAC_REG_R32(R_AX_C2HREG_DATA2_V1);
|
c2h->dword3 = MAC_REG_R32(R_AX_C2HREG_DATA3_V1);
|
|
val = MAC_REG_R8(R_AX_C2HREG_CTRL_V1);
|
MAC_REG_W8(R_AX_C2HREG_CTRL_V1, val & ~B_AX_C2HREG_TRIGGER);
|
} else {
|
if (!(MAC_REG_R8(R_AX_C2HREG_CTRL) & B_AX_C2HREG_TRIGGER))
|
return MACC2HREGEMP;
|
|
c2h->dword0 = MAC_REG_R32(R_AX_C2HREG_DATA0);
|
c2h->dword1 = MAC_REG_R32(R_AX_C2HREG_DATA1);
|
c2h->dword2 = MAC_REG_R32(R_AX_C2HREG_DATA2);
|
c2h->dword3 = MAC_REG_R32(R_AX_C2HREG_DATA3);
|
|
val = MAC_REG_R8(R_AX_C2HREG_CTRL);
|
MAC_REG_W8(R_AX_C2HREG_CTRL, val & ~B_AX_C2HREG_TRIGGER);
|
}
|
C2HRegIncreaseCounter(adapter);
|
return MACSUCCESS;
|
}
|
|
u32 _recv_c2hreg(struct mac_ax_adapter *adapter, u8 *buf)
|
{
|
struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
|
u8 i;
|
|
if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852C) ||
|
is_chip_id(adapter, MAC_AX_CHIP_ID_8192XB)) {
|
if (!(MAC_REG_R8(R_AX_C2HREG_CTRL_V1) & B_AX_C2HREG_TRIGGER))
|
return MACC2HREGEMP;
|
} else {
|
if (!(MAC_REG_R8(R_AX_C2HREG_CTRL) & B_AX_C2HREG_TRIGGER))
|
return MACC2HREGEMP;
|
}
|
|
if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852C) ||
|
is_chip_id(adapter, MAC_AX_CHIP_ID_8192XB)) {
|
for (i = 0; i < C2HREG_LEN; i = i + 4)
|
*(u32 *)(buf + i) = MAC_REG_R32(R_AX_C2HREG_DATA0_V1 + i);
|
} else {
|
for (i = 0; i < C2HREG_LEN; i = i + 4)
|
*(u32 *)(buf + i) = MAC_REG_R32(R_AX_C2HREG_DATA0 + i);
|
}
|
|
if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852C) ||
|
is_chip_id(adapter, MAC_AX_CHIP_ID_8192XB))
|
MAC_REG_W8(R_AX_C2HREG_CTRL_V1, 0);
|
else
|
MAC_REG_W8(R_AX_C2HREG_CTRL, 0);
|
|
return MACSUCCESS;
|
}
|
|
u32 mac_process_c2hreg(struct mac_ax_adapter *adapter,
|
struct mac_ax_c2hreg_info *info)
|
{
|
u32 ret;
|
struct fwcmd_c2hreg_hdr *hdr;
|
|
info->id = FWCMD_C2H_FUNC_NULL;
|
|
if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) {
|
PLTFM_MSG_ERR("FW is not ready\n");
|
return MACFWNONRDY;
|
}
|
|
if (adapter->sm.mac_rdy != MAC_AX_MAC_RDY) {
|
PLTFM_MSG_TRACE("MAC is not ready\n");
|
adapter->stats.c2h_reg_uninit++;
|
}
|
|
ret = _recv_c2hreg(adapter, info->c2hreg);
|
if (ret == MACC2HREGEMP) {
|
return ret;
|
} else if (ret != MACSUCCESS) {
|
PLTFM_MSG_ERR("[ERR]Get C2H REG fail %d\n", ret);
|
return ret;
|
}
|
|
hdr = (struct fwcmd_c2hreg_hdr *)info->c2hreg;
|
info->id = GET_FIELD(hdr->dword0, FWCMD_C2HREG_C2HREG_HDR_FUNC);
|
info->content = info->c2hreg + C2HREG_HDR_LEN;
|
info->content_len = GET_FIELD(hdr->dword0,
|
FWCMD_C2HREG_C2HREG_HDR_TOTAL_LEN);
|
info->content_len = (info->content_len << 2) - C2HREG_HDR_LEN;
|
|
return MACSUCCESS;
|
}
|
|
u32 mac_recv_c2hreg(struct mac_ax_adapter *adapter,
|
struct mac_ax_c2hreg_cont *cont)
|
{
|
u32 ret;
|
|
cont->id = FWCMD_C2H_FUNC_NULL;
|
|
if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) {
|
PLTFM_MSG_ERR("FW is not ready\n");
|
return MACFWNONRDY;
|
}
|
|
if (adapter->sm.mac_rdy != MAC_AX_MAC_RDY) {
|
PLTFM_MSG_TRACE("MAC is not ready\n");
|
adapter->stats.c2h_reg_uninit++;
|
}
|
|
ret = __recv_c2hreg(adapter, &cont->c2h_content);
|
if (ret == MACC2HREGEMP) {
|
return ret;
|
} else if (ret != MACSUCCESS) {
|
PLTFM_MSG_ERR("[ERR]Get C2H REG fail %d\n", ret);
|
return ret;
|
}
|
|
cont->id = GET_FIELD(cont->c2h_content.dword0,
|
FWCMD_C2HREG_C2HREG_HDR_FUNC);
|
cont->content_len = GET_FIELD(cont->c2h_content.dword0,
|
FWCMD_C2HREG_C2HREG_HDR_TOTAL_LEN);
|
cont->content_len = (cont->content_len << 2) - C2HREG_HDR_LEN;
|
|
return MACSUCCESS;
|
}
|
|
u32 mac_notify_fw_dbcc(struct mac_ax_adapter *adapter, u8 en)
|
{
|
#if MAC_AX_PHL_H2C
|
struct rtw_h2c_pkt *h2cb;
|
#else
|
struct h2c_buf *h2cb;
|
#endif
|
u32 ret;
|
struct fwcmd_notify_dbcc *dbcc;
|
|
h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD);
|
if (!h2cb)
|
return MACNPTR;
|
|
dbcc = (struct fwcmd_notify_dbcc *)
|
h2cb_put(h2cb, sizeof(struct fwcmd_notify_dbcc));
|
if (!dbcc) {
|
ret = MACNPTR;
|
PLTFM_MSG_ERR("%s: h2c put fail\n", __func__);
|
goto fail;
|
}
|
|
dbcc->dword0 = en ? FWCMD_H2C_NOTIFY_DBCC_EN : 0;
|
|
ret = h2c_pkt_set_hdr(adapter, h2cb,
|
FWCMD_TYPE_H2C,
|
FWCMD_H2C_CAT_MAC,
|
FWCMD_H2C_CL_MEDIA_RPT,
|
FWCMD_H2C_FUNC_NOTIFY_DBCC, 0, 0);
|
if (ret) {
|
PLTFM_MSG_ERR("H2C IE CAM set hdr fail %d\n", ret);
|
goto fail;
|
}
|
|
ret = h2c_pkt_build_txd(adapter, h2cb);
|
if (ret) {
|
PLTFM_MSG_ERR("H2C IE CAM build txd fail %d\n", ret);
|
goto fail;
|
}
|
|
#if MAC_AX_PHL_H2C
|
ret = PLTFM_TX(h2cb);
|
#else
|
ret = PLTFM_TX(h2cb->data, h2cb->len);
|
#endif
|
if (ret) {
|
PLTFM_MSG_ERR("H2C IE CAM tx fail %d\n", ret);
|
goto fail;
|
}
|
|
fail:
|
h2cb_free(adapter, h2cb);
|
|
if (!ret)
|
h2c_end_flow(adapter);
|
|
return ret;
|
}
|
|
u32 poll_c2hreg(struct mac_ax_adapter *adapter,
|
struct mac_ax_c2hreg_poll *c2h)
|
{
|
u32 cnt, poll_us, ret;
|
struct mac_ax_c2hreg_cont *c2hreg_cont;
|
struct mac_ax_drv_stats *drv_stats = &adapter->drv_stats;
|
|
if (!c2h)
|
return MACSUCCESS;
|
|
cnt = c2h->retry_cnt;
|
poll_us = c2h->retry_wait_us;
|
c2hreg_cont = &c2h->c2hreg_cont;
|
do {
|
ret = mac_recv_c2hreg(adapter, c2hreg_cont);
|
if (cnt == 0 || ret == MACSUCCESS)
|
break;
|
|
if (drv_stats->drv_rm) {
|
PLTFM_MSG_ERR("%s: driver removed\n", __func__);
|
return MACDRVRM;
|
}
|
|
if (ret != MACSUCCESS) {
|
if (ret == MACC2HREGEMP) {
|
PLTFM_DELAY_US(poll_us);
|
cnt--;
|
} else {
|
PLTFM_MSG_ERR("%s: c2hreg fail\n", __func__);
|
return ret;
|
}
|
}
|
} while (cnt);
|
|
PLTFM_MSG_TRACE("%s: cnt = %d, us = %d\n",
|
__func__, cnt, poll_us);
|
|
if (ret == MACSUCCESS) {
|
if (c2h->polling_id != FWCMD_C2H_FUNC_NULL &&
|
c2h->polling_id != c2hreg_cont->id) {
|
PLTFM_MSG_ERR("%s: surprised c2h\n", __func__);
|
PLTFM_MSG_ERR("rev: %x\n", c2h->polling_id);
|
PLTFM_MSG_ERR("exp: %x\n", c2hreg_cont->id);
|
ret = MACBADC2HREG;
|
}
|
} else {
|
PLTFM_MSG_ERR("%s: polling c2hreg timeout\n", __func__);
|
PLTFM_MSG_ERR("c2h->polling_id: %x\n", c2h->polling_id);
|
PLTFM_MSG_ERR("c2hreg_cont->id: %x\n", c2hreg_cont->id);
|
}
|
|
return ret;
|
}
|
|
u32 proc_msg_reg(struct mac_ax_adapter *adapter,
|
struct mac_ax_h2creg_info *h2c,
|
struct mac_ax_c2hreg_poll *c2h)
|
{
|
struct mac_ax_dbgpkg_en en = {0};
|
u32 ret = MACSUCCESS;
|
|
if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) {
|
PLTFM_MSG_ERR("FW is not ready\n");
|
return MACFWNONRDY;
|
}
|
|
PLTFM_MUTEX_LOCK(&adapter->fw_info.msg_reg);
|
|
ret = _mac_send_h2creg(adapter, h2c);
|
if (ret != MACSUCCESS) {
|
PLTFM_MSG_ERR("%s: send h2c reg fail: %d\n", __func__, ret);
|
goto END;
|
}
|
|
ret = poll_c2hreg(adapter, c2h);
|
if (ret != MACSUCCESS)
|
PLTFM_MSG_ERR("%s: poll c2h reg fail: %d\n", __func__, ret);
|
|
END:
|
PLTFM_MUTEX_UNLOCK(&adapter->fw_info.msg_reg);
|
if (ret != MACSUCCESS) {
|
en.plersvd_dbg = 1;
|
mac_dbg_status_dump(adapter, NULL, &en);
|
}
|
return ret;
|
}
|
|
static u32 get_wps_rpt_event_id(struct mac_ax_adapter *adapter,
|
struct rtw_c2h_info *c2h,
|
enum phl_msg_evt_id *id,
|
u8 *c2h_info)
|
{
|
struct fwcmd_wps_rpt *rpt = (struct fwcmd_wps_rpt *)c2h->content;
|
u32 state, val;
|
|
val = le32_to_cpu(rpt->dword0);
|
state = GET_FIELD(val, FWCMD_C2H_WPS_RPT_STATE);
|
|
if (!state)
|
*id = MSG_EVT_WPS_RELEASED;
|
else
|
*id = MSG_EVT_WPS_PRESSED;
|
|
return MACSUCCESS;
|
}
|
|
static u32 get_bcn_resend_event(struct mac_ax_adapter *adapter,
|
struct rtw_c2h_info *c2h,
|
enum phl_msg_evt_id *id,
|
u8 *c2h_info)
|
{
|
*id = MSG_EVT_BCN_RESEND;
|
|
return MACSUCCESS;
|
}
|
|
static u32 get_tsf32_togl_rpt_event(struct mac_ax_adapter *adapter,
|
struct rtw_c2h_info *c2h,
|
enum phl_msg_evt_id *id,
|
u8 *c2h_info)
|
{
|
*id = MSG_EVT_TSF32_TOG;
|
|
return MACSUCCESS;
|
}
|
|
static u32 get_fw_rx_dbg_event(struct mac_ax_adapter *adapter,
|
struct rtw_c2h_info *c2h,
|
enum phl_msg_evt_id *id,
|
u8 *c2h_info)
|
{
|
*id = MSG_EVT_DBG_RX_DUMP;
|
|
return MACSUCCESS;
|
}
|
|
static struct c2h_event_id_proc event_proc[] = {
|
/* cat, class, func, hdl */
|
{FWCMD_C2H_CAT_MAC, FWCMD_C2H_CL_MISC,
|
FWCMD_C2H_FUNC_WPS_RPT, get_wps_rpt_event_id},
|
{FWCMD_C2H_CAT_MAC, FWCMD_C2H_CL_FW_OFLD,
|
FWCMD_C2H_FUNC_BEACON_RESEND, get_bcn_resend_event},
|
{FWCMD_C2H_CAT_MAC, FWCMD_C2H_CL_FW_OFLD,
|
FWCMD_C2H_FUNC_TSF32_TOGL_RPT, get_tsf32_togl_rpt_event},
|
{FWCMD_C2H_CAT_MAC, FWCMD_C2H_CL_MISC,
|
FWCMD_C2H_FUNC_CCXRPT, get_ccxrpt_event},
|
{FWCMD_C2H_CAT_MAC, FWCMD_C2H_CL_FW_DBG,
|
FWCMD_C2H_FUNC_RX_DBG, get_fw_rx_dbg_event},
|
{FWCMD_C2H_CAT_NULL, FWCMD_C2H_CL_NULL,
|
FWCMD_C2H_FUNC_NULL, NULL},
|
};
|
|
u32 mac_get_c2h_event(struct mac_ax_adapter *adapter,
|
struct rtw_c2h_info *c2h,
|
enum phl_msg_evt_id *id,
|
u8 *c2h_info)
|
{
|
struct c2h_event_id_proc *proc;
|
u32 (*hdl)(struct mac_ax_adapter *adapter, struct rtw_c2h_info *c2h,
|
enum phl_msg_evt_id *id, u8 *c2h_info) = NULL;
|
|
/*for C2H ack bit no need to process*/
|
if (c2h->type_done_ack == 1 || c2h->type_rec_ack == 1)
|
return MACSUCCESS;
|
|
proc = event_proc;
|
while (proc->cat != FWCMD_C2H_CAT_NULL) {
|
if (proc->cat == c2h->c2h_cat &&
|
proc->cls == c2h->c2h_class &&
|
proc->func == c2h->c2h_func) {
|
hdl = proc->hdl;
|
return hdl(adapter, c2h, id, c2h_info);
|
}
|
proc++;
|
}
|
|
return MACSUCCESS;
|
}
|
|
void H2CRegIncreaseCounter(struct mac_ax_adapter *adapter)
|
{
|
u8 val, low;
|
struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
|
|
val = MAC_REG_R8(R_AX_UDM1 + 1);
|
low = val & B_AX_UDM1_WCPU_H2C_DEQ_CNT_MSK;
|
low++;
|
if (low > 15)
|
low = 0; //we just use 4 bit as counter
|
val = val & 0xf0;
|
val = val | low;
|
MAC_REG_W8(R_AX_UDM1 + 1, val);
|
}
|
|
void C2HRegIncreaseCounter(struct mac_ax_adapter *adapter)
|
{
|
u8 val, high;
|
struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
|
|
val = MAC_REG_R8(R_AX_UDM1 + 1);
|
high = (val >> B_AX_UDM1_WCPU_C2H_ENQ_CNT_SH) & B_AX_UDM1_WCPU_C2H_ENQ_CNT_MSK;
|
high++;
|
if (high > 15)
|
high = 0;//we just use 4 bit as counter
|
val = val & 0x0f;
|
val = val | (high << B_AX_UDM1_WCPU_C2H_ENQ_CNT_SH);
|
MAC_REG_W8(R_AX_UDM1 + 1, val);
|
}
|