ba20341e70
Source: https://github.com/cringeops/bes2600 Source: https://github.com/cringeops/bes2600/pull/14 Source: https://github.com/cringeops/bes2600/pull/17 Source: https://github.com/cringeops/bes2600/pull/20
538 lines
20 KiB
C
538 lines
20 KiB
C
/*
|
|
* Mac80211 driver for BES2600 device
|
|
*
|
|
* Copyright (c) 2022, Bestechnic
|
|
* Author:
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
#include "bes2600.h"
|
|
#include "wsm.h"
|
|
#include "queue.h"
|
|
#include "bes_log.h"
|
|
|
|
struct tx_loop_table
|
|
{
|
|
u16 cmd;
|
|
void (*proc)(struct bes2600_common *hw_priv, u8 *buf, u32 len);
|
|
};
|
|
|
|
static void bes2600_tx_loop_build_lmac_tx_cfm(struct bes2600_common *hw_priv, u8 *buf, u32 len);
|
|
static void bes2600_tx_loop_build_scan_compl_ind(struct bes2600_common *hw_priv);
|
|
static void bes2600_tx_loop_build_pm_ind(struct bes2600_common *hw_priv);
|
|
|
|
void bes2600_tx_loop_init(struct bes2600_common *hw_priv)
|
|
{
|
|
hw_priv->tx_loop.enabled = false;
|
|
hw_priv->tx_loop.start_lmac_seq = 0;
|
|
hw_priv->tx_loop.start_mcu_seq = 0;
|
|
INIT_LIST_HEAD(&hw_priv->tx_loop.pending_record_list);
|
|
spin_lock_init(&hw_priv->tx_loop.pending_record_lock);
|
|
spin_lock_init(&hw_priv->tx_loop.tx_loop_lock);
|
|
skb_queue_head_init(&hw_priv->tx_loop.rx_queue);
|
|
}
|
|
|
|
struct sk_buff *bes2600_tx_loop_read(struct bes2600_common *hw_priv)
|
|
{
|
|
struct sk_buff *skb;
|
|
struct wsm_hdr *wsm;
|
|
|
|
if(hw_priv == NULL)
|
|
return NULL;
|
|
|
|
skb = skb_dequeue(&hw_priv->tx_loop.rx_queue);
|
|
if(skb != NULL) {
|
|
wsm = (struct wsm_hdr *)skb->data;
|
|
bes_devel("tx loop pipe read msg_id:0x%04x seq:%d\n",
|
|
WSM_MSG_ID_GET(wsm->id), WSM_MSG_SEQ_GET(wsm->id));
|
|
}
|
|
|
|
return skb;
|
|
}
|
|
|
|
static void bes2600_tx_loop_item_pending_item(struct bes2600_common *hw_priv, struct sk_buff *skb)
|
|
{
|
|
bes_devel("tx loop confirm pending skb.\n");
|
|
bes2600_tx_loop_build_lmac_tx_cfm(hw_priv, skb->data, skb->data_len);
|
|
}
|
|
|
|
void bes2600_tx_loop_record_wsm_cmd(struct bes2600_common *hw_priv, u8 *wsm_cmd)
|
|
{
|
|
hw_priv->tx_loop.wsm_cmd_ptr = wsm_cmd;
|
|
}
|
|
|
|
void bes2600_tx_loop_clear_wsm_cmd(struct bes2600_common *hw_priv)
|
|
{
|
|
hw_priv->tx_loop.wsm_cmd_ptr = NULL;
|
|
}
|
|
|
|
void bes2600_tx_loop_set_enable(struct bes2600_common *hw_priv, bool need_warn)
|
|
{
|
|
int i = 0;
|
|
u16 cmd_id = -1;
|
|
|
|
if(hw_priv == NULL)
|
|
return;
|
|
|
|
if(hw_priv->tx_loop.enabled)
|
|
return;
|
|
|
|
WARN_ON(need_warn);
|
|
|
|
hw_priv->tx_loop.enabled = true;
|
|
hw_priv->tx_loop.start_lmac_seq = hw_priv->wsm_rx_seq[0];
|
|
hw_priv->tx_loop.start_mcu_seq = hw_priv->wsm_rx_seq[1];
|
|
|
|
if(hw_priv->tx_loop.wsm_cmd_ptr) {
|
|
struct wsm_hdr *tx_wsm = (struct wsm_hdr *)hw_priv->tx_loop.wsm_cmd_ptr;
|
|
cmd_id = tx_wsm->id & WSM_MSG_ID_MASK;
|
|
|
|
if(cmd_id == 0x0005 || cmd_id == 0x0006){
|
|
struct wsm_mib *mib = (struct wsm_mib *)hw_priv->wsm_cmd.arg;
|
|
u16 mib_id = mib->mibId;
|
|
bes_devel("pending cmd:0x%04x seq:%d mib_id:0x%04x\n",
|
|
cmd_id, WSM_MSG_SEQ_GET(tx_wsm->id), mib_id);
|
|
} else {
|
|
bes_devel("pending cmd:0x%04x seq:%d\n",
|
|
cmd_id, WSM_MSG_SEQ_GET(tx_wsm->id));
|
|
}
|
|
|
|
bes2600_tx_loop_pipe_send(hw_priv, hw_priv->tx_loop.wsm_cmd_ptr, 8);
|
|
}
|
|
|
|
if (atomic_read(&hw_priv->scan.in_progress) && cmd_id != 0x0007) {
|
|
bes2600_tx_loop_build_scan_compl_ind(hw_priv);
|
|
} else if (atomic_read(&hw_priv->bes_power.pm_set_in_process) && cmd_id != 0x0010) {
|
|
bes2600_tx_loop_build_pm_ind(hw_priv);
|
|
}
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
bes2600_queue_iterate_pending_packet(&hw_priv->tx_queue[i],
|
|
bes2600_tx_loop_item_pending_item);
|
|
}
|
|
spin_lock(&hw_priv->tx_loop.pending_record_lock);
|
|
bes2600_queue_iterate_record_pending_packet(hw_priv, bes2600_tx_loop_item_pending_item);
|
|
spin_unlock(&hw_priv->tx_loop.pending_record_lock);
|
|
|
|
if (atomic_read(&hw_priv->bh_rx) > 0)
|
|
wake_up(&hw_priv->bh_wq);
|
|
|
|
}
|
|
|
|
static void bes2600_tx_loop_build_lmac_generic_cfm(struct bes2600_common *hw_priv, u8 *buf, u32 len)
|
|
{
|
|
struct sk_buff *out_skb;
|
|
struct wsm_hdr *rx_wsm, *tx_wsm;
|
|
u32 msg_len = sizeof(struct wsm_hdr) + 4;
|
|
u16 msg_id = 0;
|
|
|
|
tx_wsm = (struct wsm_hdr *)buf;
|
|
|
|
out_skb = dev_alloc_skb(msg_len);
|
|
if(IS_ERR_OR_NULL(out_skb)) {
|
|
bes_err("%s, alloc mem fail.\n", __func__);
|
|
return;
|
|
}
|
|
|
|
bes_devel("%s cmd 0x%04x len:%d\n",
|
|
__func__, (tx_wsm->id & WSM_MSG_ID_MASK), msg_len);
|
|
skb_put(out_skb, msg_len);
|
|
rx_wsm = (struct wsm_hdr *)out_skb->data;
|
|
msg_id = (tx_wsm->id & WSM_MSG_ID_MASK);
|
|
msg_id |= 0x400; // set confirm flag
|
|
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_lmac_seq);
|
|
rx_wsm->id = __cpu_to_le16(msg_id);
|
|
rx_wsm->len = __cpu_to_le16(msg_len);
|
|
*((u32 *)&rx_wsm[1]) = __cpu_to_le32(WSM_STATUS_SUCCESS);
|
|
|
|
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
|
|
hw_priv->tx_loop.start_lmac_seq = (hw_priv->tx_loop.start_lmac_seq + 1) & 7;
|
|
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
|
|
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
|
|
|
|
atomic_add_return(1, &hw_priv->bh_rx);
|
|
}
|
|
|
|
static void bes2600_tx_loop_build_lmac_tx_cfm(struct bes2600_common *hw_priv, u8 *buf, u32 len)
|
|
{
|
|
struct sk_buff *out_skb;
|
|
struct wsm_hdr *rx_wsm;
|
|
struct wsm_tx *tx_wsm;
|
|
struct wsm_tx_confirm *cfm;
|
|
u32 msg_len = sizeof(struct wsm_hdr) + sizeof(struct wsm_tx_confirm);
|
|
u16 msg_id = 0;
|
|
|
|
tx_wsm = (struct wsm_tx *)buf;
|
|
|
|
out_skb = dev_alloc_skb(msg_len);
|
|
if(IS_ERR_OR_NULL(out_skb)) {
|
|
bes_err("%s, alloc mem fail.\n", __func__);
|
|
return;
|
|
}
|
|
|
|
bes_devel("%s cmd 0x%04x len:%d\n",
|
|
__func__, (tx_wsm->hdr.id & WSM_MSG_ID_MASK), msg_len);
|
|
skb_put(out_skb, msg_len);
|
|
rx_wsm = (struct wsm_hdr *)out_skb->data;
|
|
msg_id = (tx_wsm->hdr.id & WSM_MSG_ID_MASK);
|
|
msg_id |= 0x400; // set confirm flag
|
|
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_lmac_seq);
|
|
rx_wsm->id = __cpu_to_le16(msg_id);
|
|
rx_wsm->len = __cpu_to_le16(msg_len);
|
|
|
|
cfm = (struct wsm_tx_confirm *)&rx_wsm[1];
|
|
cfm->packetID = tx_wsm->packetID;
|
|
cfm->status = WSM_STATUS_SUCCESS;
|
|
cfm->txedRate = tx_wsm->maxTxRate;
|
|
cfm->ackFailures = 0;
|
|
cfm->flags = WSM_TX_STATUS_NORMAL_ACK;
|
|
cfm->txQueueDelay = 5;
|
|
cfm->mediaDelay = 3;
|
|
|
|
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
|
|
hw_priv->tx_loop.start_lmac_seq = (hw_priv->tx_loop.start_lmac_seq + 1) & 7;
|
|
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
|
|
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
|
|
|
|
atomic_add_return(1, &hw_priv->bh_rx);
|
|
}
|
|
|
|
static void bes2600_tx_loop_build_config_cfm(struct bes2600_common *hw_priv, u8 *buf, u32 len)
|
|
{
|
|
struct sk_buff *out_skb;
|
|
struct wsm_hdr *rx_wsm;
|
|
struct wsm_hdr *tx_wsm = (struct wsm_hdr *)buf;
|
|
u32 msg_len = sizeof(struct wsm_hdr) + sizeof(struct wsm_configuration) + 4;
|
|
u16 msg_id = 0;
|
|
|
|
out_skb = dev_alloc_skb(msg_len);
|
|
if(IS_ERR_OR_NULL(out_skb)) {
|
|
bes_err("%s, alloc mem fail.\n", __func__);
|
|
return;
|
|
}
|
|
|
|
bes_devel("%s cmd 0x%04x len:%d\n",
|
|
__func__, (tx_wsm->id & WSM_MSG_ID_MASK), msg_len);
|
|
skb_put(out_skb, msg_len);
|
|
rx_wsm = (struct wsm_hdr *)out_skb->data;
|
|
msg_id = (tx_wsm->id & WSM_MSG_ID_MASK);
|
|
msg_id |= 0x400; // set confirm flag
|
|
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_lmac_seq);
|
|
rx_wsm->id = __cpu_to_le16(msg_id);
|
|
rx_wsm->len = __cpu_to_le16(msg_len);
|
|
*(u32 *)&rx_wsm[1] = WSM_STATUS_SUCCESS;
|
|
|
|
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
|
|
hw_priv->tx_loop.start_lmac_seq = (hw_priv->tx_loop.start_lmac_seq + 1) & 7;
|
|
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
|
|
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
|
|
|
|
atomic_add_return(1, &hw_priv->bh_rx);
|
|
}
|
|
|
|
static void bes2600_tx_loop_build_read_mib_cfm(struct bes2600_common *hw_priv, u8 *buf, u32 len)
|
|
{
|
|
struct sk_buff *out_skb;
|
|
struct wsm_hdr *rx_wsm;
|
|
struct wsm_hdr *tx_wsm = (struct wsm_hdr *)buf;
|
|
struct wsm_mib *mib = (struct wsm_mib *)hw_priv->wsm_cmd.arg;
|
|
u32 *status;
|
|
u16 *mib_id, *size;
|
|
u32 msg_len = sizeof(struct wsm_hdr) + 4 /* status */ + 2 /* mib_id */ + mib->buf_size;
|
|
u16 msg_id = 0;
|
|
|
|
out_skb = dev_alloc_skb(msg_len);
|
|
if(IS_ERR_OR_NULL(out_skb)) {
|
|
bes_err("%s, alloc mem fail.\n", __func__);
|
|
return;
|
|
}
|
|
|
|
bes_devel("%s cmd 0x%04x len:%d\n",
|
|
__func__, (tx_wsm->id & WSM_MSG_ID_MASK), msg_len);
|
|
skb_put(out_skb, msg_len);
|
|
rx_wsm = (struct wsm_hdr *)out_skb->data;
|
|
msg_id = (tx_wsm->id & WSM_MSG_ID_MASK);
|
|
msg_id |= 0x400; // set confirm flag
|
|
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_lmac_seq);
|
|
rx_wsm->id = __cpu_to_le16(msg_id);
|
|
rx_wsm->len = __cpu_to_le16(msg_len);
|
|
|
|
status = (u32 *)&rx_wsm[1];
|
|
*status = WSM_STATUS_SUCCESS;
|
|
|
|
mib_id = (u16 *)&status[1];
|
|
*mib_id = mib->mibId;
|
|
|
|
size = (u16 *)&mib_id[1];
|
|
*size = mib->buf_size;
|
|
|
|
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
|
|
hw_priv->tx_loop.start_lmac_seq = (hw_priv->tx_loop.start_lmac_seq + 1) & 7;
|
|
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
|
|
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
|
|
|
|
atomic_add_return(1, &hw_priv->bh_rx);
|
|
}
|
|
|
|
static void bes2600_tx_loop_build_join_cfm(struct bes2600_common *hw_priv, u8 *buf, u32 len)
|
|
{
|
|
struct sk_buff *out_skb;
|
|
struct wsm_hdr *rx_wsm;
|
|
struct wsm_hdr *tx_wsm = (struct wsm_hdr *)buf;
|
|
u16 msg_id = 0;
|
|
u32 msg_len = sizeof(struct wsm_hdr) + 4 /* status */ + 8 /* power_level */;
|
|
|
|
out_skb = dev_alloc_skb(msg_len);
|
|
if(IS_ERR_OR_NULL(out_skb)) {
|
|
bes_err("%s, alloc mem fail.\n", __func__);
|
|
return;
|
|
}
|
|
|
|
bes_devel("%s cmd 0x%04x len:%d\n",
|
|
__func__, (tx_wsm->id & WSM_MSG_ID_MASK), msg_len);
|
|
skb_put(out_skb, msg_len);
|
|
rx_wsm = (struct wsm_hdr *)out_skb->data;
|
|
msg_id = (tx_wsm->id & WSM_MSG_ID_MASK);
|
|
msg_id |= 0x400; // set confirm flag
|
|
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_lmac_seq);
|
|
rx_wsm->id = __cpu_to_le16(msg_id);
|
|
rx_wsm->len = __cpu_to_le16(msg_len);
|
|
*(u32 *)&rx_wsm[1] = WSM_STATUS_SUCCESS;
|
|
|
|
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
|
|
hw_priv->tx_loop.start_lmac_seq = (hw_priv->tx_loop.start_lmac_seq + 1) & 7;
|
|
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
|
|
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
|
|
|
|
atomic_add_return(1, &hw_priv->bh_rx);
|
|
}
|
|
|
|
static void bes2600_tx_loop_build_rfcmd_cfm(struct bes2600_common *hw_priv, u8 *buf, u32 len)
|
|
{
|
|
struct sk_buff *out_skb;
|
|
struct wsm_mcu_hdr *rx_wsm;
|
|
struct wsm_hdr *tx_wsm = (struct wsm_hdr *)buf;
|
|
u16 msg_id = 0;
|
|
u32 msg_len = sizeof(struct wsm_mcu_hdr);
|
|
|
|
out_skb = dev_alloc_skb(msg_len);
|
|
if(IS_ERR_OR_NULL(out_skb)) {
|
|
bes_err("%s, alloc mem fail.\n", __func__);
|
|
return;
|
|
}
|
|
|
|
bes_devel("%s cmd 0x%04x len:%d\n",
|
|
__func__, (tx_wsm->id & WSM_MSG_ID_MASK), msg_len);
|
|
skb_put(out_skb, msg_len);
|
|
rx_wsm = (struct wsm_mcu_hdr *)out_skb->data;
|
|
msg_id = (tx_wsm->id & WSM_MSG_ID_MASK);
|
|
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_mcu_seq);
|
|
rx_wsm->hdr.id = __cpu_to_le16(msg_id);
|
|
rx_wsm->hdr.len = __cpu_to_le16(msg_len);
|
|
rx_wsm->handle_label = WSM_TO_MCU_CMD_CONFIRM_LABEL;
|
|
rx_wsm->cmd_type = (tx_wsm->id & WSM_MSG_ID_MASK);
|
|
|
|
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
|
|
hw_priv->tx_loop.start_mcu_seq = (hw_priv->tx_loop.start_mcu_seq + 1) & 7;
|
|
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
|
|
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
|
|
|
|
atomic_add_return(1, &hw_priv->bh_rx);
|
|
}
|
|
|
|
static void bes2600_tx_loop_build_driver_cmd_cfm(struct bes2600_common *hw_priv, u8 *buf, u32 len)
|
|
{
|
|
struct sk_buff *out_skb;
|
|
struct wsm_mcu_hdr *rx_wsm;
|
|
struct wsm_hdr *tx_wsm = (struct wsm_hdr *)buf;
|
|
u16 msg_id = 0;
|
|
u32 msg_len = sizeof(struct wsm_mcu_hdr) + 4;
|
|
|
|
out_skb = dev_alloc_skb(msg_len);
|
|
if(IS_ERR_OR_NULL(out_skb)) {
|
|
bes_err("%s, alloc mem fail.\n", __func__);
|
|
return;
|
|
}
|
|
|
|
bes_devel("%s cmd 0x%04x len:%d\n",
|
|
__func__, (tx_wsm->id & WSM_MSG_ID_MASK), msg_len);
|
|
skb_put(out_skb, msg_len);
|
|
rx_wsm = (struct wsm_mcu_hdr *)out_skb->data;
|
|
msg_id = (tx_wsm->id & WSM_MSG_ID_MASK);
|
|
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_mcu_seq);
|
|
rx_wsm->hdr.id = __cpu_to_le16(msg_id);
|
|
rx_wsm->hdr.len = __cpu_to_le16(msg_len);
|
|
rx_wsm->handle_label = WSM_TO_MCU_CMD_CONFIRM_LABEL;
|
|
rx_wsm->cmd_type = (tx_wsm->id & WSM_MSG_ID_MASK);
|
|
*(uint32_t *)(rx_wsm + 1) = 0;
|
|
|
|
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
|
|
hw_priv->tx_loop.start_mcu_seq = (hw_priv->tx_loop.start_mcu_seq + 1) & 7;
|
|
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
|
|
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
|
|
|
|
atomic_add_return(1, &hw_priv->bh_rx);
|
|
}
|
|
|
|
static struct tx_loop_table tx_loop_tbl[] = {
|
|
{.cmd = 0x0004, .proc = bes2600_tx_loop_build_lmac_tx_cfm},
|
|
{.cmd = 0x0009, .proc = bes2600_tx_loop_build_config_cfm},
|
|
{.cmd = 0x0005, .proc = bes2600_tx_loop_build_read_mib_cfm},
|
|
{.cmd = 0x0006, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
|
|
{.cmd = 0x000B, .proc = bes2600_tx_loop_build_join_cfm},
|
|
{.cmd = 0x0007, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
|
|
{.cmd = 0x0008, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
|
|
{.cmd = 0x000A, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
|
|
{.cmd = 0x000C, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
|
|
{.cmd = 0x000D, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
|
|
{.cmd = 0x0010, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
|
|
{.cmd = 0x0011, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
|
|
{.cmd = 0x0012, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
|
|
{.cmd = 0x0013, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
|
|
{.cmd = 0x0016, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
|
|
{.cmd = 0x0017, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
|
|
{.cmd = 0x0018, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
|
|
{.cmd = 0x0019, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
|
|
{.cmd = 0x001A, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
|
|
{.cmd = 0x001B, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
|
|
{.cmd = 0x001C, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
|
|
{.cmd = 0x0029, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
|
|
{.cmd = 0x0C25, .proc = bes2600_tx_loop_build_rfcmd_cfm},
|
|
{.cmd = 0x0C27, .proc = bes2600_tx_loop_build_driver_cmd_cfm},
|
|
};
|
|
|
|
static void bes2600_tx_loop_build_scan_compl_ind(struct bes2600_common *hw_priv)
|
|
{
|
|
struct sk_buff *out_skb;
|
|
struct wsm_hdr *rx_wsm;
|
|
struct wsm_scan_complete *scan_compl;
|
|
u16 msg_id = 0;
|
|
u32 msg_len = sizeof(struct wsm_hdr) + sizeof(struct wsm_scan_complete);
|
|
|
|
out_skb = dev_alloc_skb(msg_len);
|
|
if(IS_ERR_OR_NULL(out_skb)) {
|
|
bes_devel("%s, alloc mem fail.\n", __func__);
|
|
return;
|
|
}
|
|
|
|
bes_devel("%s len:%d\n", __func__, msg_len);
|
|
skb_put(out_skb, msg_len);
|
|
rx_wsm = (struct wsm_hdr *)out_skb->data;
|
|
msg_id |= 0x806; // set indication flag
|
|
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_lmac_seq);
|
|
rx_wsm->id = __cpu_to_le16(msg_id);
|
|
rx_wsm->len = __cpu_to_le16(msg_len);
|
|
|
|
scan_compl = (struct wsm_scan_complete *)&rx_wsm[1];
|
|
scan_compl->status = WSM_STATUS_SUCCESS;
|
|
scan_compl->psm = WSM_PSM_PS;
|
|
scan_compl->numChannels = 2;
|
|
|
|
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
|
|
hw_priv->tx_loop.start_lmac_seq = (hw_priv->tx_loop.start_lmac_seq + 1) & 7;
|
|
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
|
|
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
|
|
|
|
atomic_add_return(1, &hw_priv->bh_rx);
|
|
}
|
|
|
|
static void bes2600_tx_loop_build_pm_ind(struct bes2600_common *hw_priv)
|
|
{
|
|
struct sk_buff *out_skb;
|
|
struct wsm_hdr *rx_wsm;
|
|
struct wsm_set_pm_complete *pm_compl;
|
|
u16 msg_id = 0;
|
|
u32 msg_len = sizeof(struct wsm_hdr) + sizeof(struct wsm_set_pm_complete);
|
|
|
|
out_skb = dev_alloc_skb(msg_len);
|
|
if(IS_ERR_OR_NULL(out_skb)) {
|
|
bes_devel("%s, alloc mem fail.\n", __func__);
|
|
return;
|
|
}
|
|
|
|
bes_devel("%s len:%d\n", __func__, msg_len);
|
|
skb_put(out_skb, msg_len);
|
|
rx_wsm = (struct wsm_hdr *)out_skb->data;
|
|
msg_id |= 0x809; // set indication flag
|
|
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_lmac_seq);
|
|
rx_wsm->id = __cpu_to_le16(msg_id);
|
|
rx_wsm->len = __cpu_to_le16(msg_len);
|
|
|
|
pm_compl = (struct wsm_set_pm_complete *)&rx_wsm[1];
|
|
pm_compl->status = WSM_STATUS_SUCCESS;
|
|
pm_compl->psm = WSM_PSM_PS;
|
|
|
|
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
|
|
hw_priv->tx_loop.start_lmac_seq = (hw_priv->tx_loop.start_lmac_seq + 1) & 7;
|
|
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
|
|
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
|
|
|
|
atomic_add_return(1, &hw_priv->bh_rx);
|
|
}
|
|
|
|
static void bes2600_tx_loop_build_rfcmd_ind(struct bes2600_common *hw_priv, u8 *buf, u32 len)
|
|
{
|
|
struct sk_buff *out_skb;
|
|
struct wsm_mcu_hdr *rx_wsm;
|
|
struct wsm_hdr *tx_wsm = (struct wsm_hdr *)buf;
|
|
u16 msg_id = 0;
|
|
u32 msg_len = sizeof(struct wsm_mcu_hdr);
|
|
|
|
out_skb = dev_alloc_skb(msg_len);
|
|
if(IS_ERR_OR_NULL(out_skb)) {
|
|
bes_err("%s, alloc mem fail.\n", __func__);
|
|
return;
|
|
}
|
|
|
|
bes_devel("%s len:%d\n",__func__, msg_len);
|
|
skb_put(out_skb, msg_len);
|
|
rx_wsm = (struct wsm_mcu_hdr *)out_skb->data;
|
|
msg_id = (tx_wsm->id & WSM_MSG_ID_MASK);
|
|
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_mcu_seq);
|
|
rx_wsm->hdr.id = __cpu_to_le16(msg_id);
|
|
rx_wsm->hdr.len = __cpu_to_le16(msg_len);
|
|
rx_wsm->handle_label = WSM_TO_MCU_CMD_INDICATION_LABEL;
|
|
rx_wsm->cmd_type = (tx_wsm->id & WSM_MSG_ID_MASK);
|
|
|
|
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
|
|
hw_priv->tx_loop.start_mcu_seq = (hw_priv->tx_loop.start_mcu_seq + 1) & 7;
|
|
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
|
|
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
|
|
|
|
atomic_add_return(1, &hw_priv->bh_rx);
|
|
}
|
|
|
|
void bes2600_tx_loop_pipe_send(struct bes2600_common *hw_priv, u8 *buf, u32 len)
|
|
{
|
|
int i = 0;
|
|
int tbl_size = ARRAY_SIZE(tx_loop_tbl);
|
|
struct wsm_hdr *tx_wsm = (struct wsm_hdr *)buf;
|
|
u16 cmd_id = tx_wsm->id & WSM_MSG_ID_MASK;
|
|
|
|
/* don't need to tx loop if wifi is unregistered */
|
|
if(hw_priv == NULL)
|
|
return;
|
|
|
|
bes_devel("tx loop pipe send cmd:0x%04x seq:%d\n",
|
|
cmd_id, WSM_MSG_SEQ_GET(tx_wsm->id));
|
|
|
|
/* select build confirm function based on command id */
|
|
for(i = 0; i < tbl_size; i++) {
|
|
if(cmd_id == tx_loop_tbl[i].cmd) {
|
|
tx_loop_tbl[i].proc(hw_priv, buf, len);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* build indication for special command */
|
|
if(cmd_id == 0x0007) {
|
|
bes2600_tx_loop_build_scan_compl_ind(hw_priv);
|
|
} else if(cmd_id == 0x0010) {
|
|
bes2600_tx_loop_build_pm_ind(hw_priv);
|
|
} else if(cmd_id == 0x0C25) {
|
|
bes2600_tx_loop_build_rfcmd_ind(hw_priv, buf, len);
|
|
}
|
|
}
|