提交 5e6e3a92 编写于 作者: B Bing Zhao 提交者: John W. Linville

wireless: mwifiex: initial commit for Marvell mwifiex driver

This driver adds WiFi support for Marvell 802.11n based chipsets
with SDIO interface. Currently only SD8787 is supported. More
chipsets will be supported later.

drivers/net/wireless/mwifiex/
Signed-off-by: NNishant Sarmukadam <nishants@marvell.com>
Signed-off-by: NAmitkumar Karwar <akarwar@marvell.com>
Signed-off-by: NKiran Divekar <dkiran@marvell.com>
Signed-off-by: NBing Zhao <bzhao@marvell.com>
Signed-off-by: NYogesh Ashok Powar <yogeshp@marvell.com>
Signed-off-by: NMarc Yang <yangyang@marvell.com>
Signed-off-by: NRamesh Radhakrishnan <rramesh@marvell.com>
Signed-off-by: NFrank Huang <frankh@marvell.com>
Signed-off-by: NJohn W. Linville <linville@tuxdriver.com>
上级 903946e6
......@@ -284,5 +284,6 @@ source "drivers/net/wireless/rtlwifi/Kconfig"
source "drivers/net/wireless/wl1251/Kconfig"
source "drivers/net/wireless/wl12xx/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig"
source "drivers/net/wireless/mwifiex/Kconfig"
endif # WLAN
......@@ -56,3 +56,5 @@ obj-$(CONFIG_WL12XX) += wl12xx/
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/
obj-$(CONFIG_IWM) += iwmc3200wifi/
obj-$(CONFIG_MWIFIEX) += mwifiex/
此差异已折叠。
/*
* Marvell Wireless LAN device driver: 802.11n
*
* Copyright (C) 2011, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*/
#ifndef _MWIFIEX_11N_H_
#define _MWIFIEX_11N_H_
#include "11n_aggr.h"
#include "11n_rxreorder.h"
#include "wmm.h"
void mwifiex_show_dot_11n_dev_cap(struct mwifiex_adapter *adapter, u32 cap);
void mwifiex_show_dev_mcs_support(struct mwifiex_adapter *adapter, u8 support);
int mwifiex_ret_11n_delba(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp);
int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp);
int mwifiex_ret_11n_cfg(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp,
void *data_buf);
int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd,
u16 cmd_action, void *data_buf);
int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd,
u16 cmd_action, void *data_buf);
int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
struct mwifiex_bssdescriptor *bss_desc,
u8 **buffer);
void mwifiex_cfg_tx_buf(struct mwifiex_private *priv,
struct mwifiex_bssdescriptor *bss_desc);
void mwifiex_fill_cap_info(struct mwifiex_private *,
struct mwifiex_ie_types_htcap *);
int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv,
u16 action, int *htcap_cfg);
void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv,
struct mwifiex_tx_ba_stream_tbl
*tx_tbl);
void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv);
struct mwifiex_tx_ba_stream_tbl *mwifiex_11n_get_tx_ba_stream_tbl(struct
mwifiex_private
*priv, int tid,
u8 *ra);
void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv, u8 *ra,
int tid,
enum mwifiex_ba_status ba_status);
int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac);
int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
int initiator);
void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba);
int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv,
struct mwifiex_ds_rx_reorder_tbl *buf);
int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
struct mwifiex_ds_tx_ba_stream_tbl *buf);
int mwifiex_ret_amsdu_aggr_ctrl(struct mwifiex_private *priv,
struct host_cmd_ds_command
*resp,
void *data_buf);
int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd,
int cmd_action, void *data_buf);
int mwifiex_cmd_amsdu_aggr_ctrl(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd,
int cmd_action,
void *data_buf);
/*
* This function checks whether AMPDU is allowed or not for a particular TID.
*/
static inline u8
mwifiex_is_ampdu_allowed(struct mwifiex_private *priv,
struct mwifiex_ra_list_tbl *ptr, int tid)
{
return ((priv->aggr_prio_tbl[tid].ampdu_ap != BA_STREAM_NOT_ALLOWED)
? true : false);
}
/*
* This function checks whether AMSDU is allowed or not for a particular TID.
*/
static inline u8
mwifiex_is_amsdu_allowed(struct mwifiex_private *priv,
struct mwifiex_ra_list_tbl *ptr, int tid)
{
return (((priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED)
&& ((priv->is_data_rate_auto)
|| !((priv->bitmap_rates[2]) & 0x03)))
? true : false);
}
/*
* This function checks whether a BA stream is available or not.
*/
static inline u8
mwifiex_is_ba_stream_avail(struct mwifiex_private *priv)
{
struct mwifiex_private *pmpriv = NULL;
u8 i = 0;
u32 ba_stream_num = 0;
for (i = 0; i < priv->adapter->priv_num; i++) {
pmpriv = priv->adapter->priv[i];
if (pmpriv)
ba_stream_num +=
mwifiex_wmm_list_len(priv->adapter,
(struct list_head
*) &pmpriv->
tx_ba_stream_tbl_ptr);
}
return ((ba_stream_num <
MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) ? true : false);
}
/*
* This function finds the correct Tx BA stream to delete.
*
* Upon successfully locating, both the TID and the RA are returned.
*/
static inline u8
mwifiex_find_stream_to_delete(struct mwifiex_private *priv,
struct mwifiex_ra_list_tbl *ptr, int ptr_tid,
int *ptid, u8 *ra)
{
int tid;
u8 ret = false;
struct mwifiex_tx_ba_stream_tbl *tx_tbl;
unsigned long flags;
tid = priv->aggr_prio_tbl[ptr_tid].ampdu_user;
spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
list_for_each_entry(tx_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
if (tid > priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user) {
tid = priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user;
*ptid = tx_tbl->tid;
memcpy(ra, tx_tbl->ra, ETH_ALEN);
ret = true;
}
}
spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
return ret;
}
/*
* This function checks whether BA stream is set up or not.
*/
static inline int
mwifiex_is_ba_stream_setup(struct mwifiex_private *priv,
struct mwifiex_ra_list_tbl *ptr, int tid)
{
struct mwifiex_tx_ba_stream_tbl *tx_tbl;
tx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ptr->ra);
if (tx_tbl && IS_BASTREAM_SETUP(tx_tbl))
return true;
return false;
}
#endif /* !_MWIFIEX_11N_H_ */
/*
* Marvell Wireless LAN device driver: 802.11n Aggregation
*
* Copyright (C) 2011, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*/
#include "decl.h"
#include "ioctl.h"
#include "util.h"
#include "fw.h"
#include "main.h"
#include "wmm.h"
#include "11n.h"
#include "11n_aggr.h"
/*
* Creates an AMSDU subframe for aggregation into one AMSDU packet.
*
* The resultant AMSDU subframe format is -
*
* +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+
* | DA | SA | Length | SNAP header | MSDU |
* | data[0..5] | data[6..11] | | | data[14..] |
* +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+
* <--6-bytes--> <--6-bytes--> <--2-bytes--><--8-bytes--> <--n-bytes-->
*
* This function also computes the amount of padding required to make the
* buffer length multiple of 4 bytes.
*
* Data => |DA|SA|SNAP-TYPE|........ .|
* MSDU => |DA|SA|Length|SNAP|...... ..|
*/
static int
mwifiex_11n_form_amsdu_pkt(struct mwifiex_adapter *adapter,
struct sk_buff *skb_aggr,
struct sk_buff *skb_src, int *pad)
{
int dt_offset;
struct rfc_1042_hdr snap = {
0xaa, /* LLC DSAP */
0xaa, /* LLC SSAP */
0x03, /* LLC CTRL */
{0x00, 0x00, 0x00}, /* SNAP OUI */
0x0000 /* SNAP type */
/*
* This field will be overwritten
* later with ethertype
*/
};
struct tx_packet_hdr *tx_header = NULL;
skb_put(skb_aggr, sizeof(*tx_header));
tx_header = (struct tx_packet_hdr *) skb_aggr->data;
/* Copy DA and SA */
dt_offset = 2 * ETH_ALEN;
memcpy(&tx_header->eth803_hdr, skb_src->data, dt_offset);
/* Copy SNAP header */
snap.snap_type = *(u16 *) ((u8 *)skb_src->data + dt_offset);
dt_offset += sizeof(u16);
memcpy(&tx_header->rfc1042_hdr, &snap, sizeof(struct rfc_1042_hdr));
skb_pull(skb_src, dt_offset);
/* Update Length field */
tx_header->eth803_hdr.h_proto = htons(skb_src->len + LLC_SNAP_LEN);
/* Add payload */
skb_put(skb_aggr, skb_src->len);
memcpy(skb_aggr->data + sizeof(*tx_header), skb_src->data,
skb_src->len);
*pad = (((skb_src->len + LLC_SNAP_LEN) & 3)) ? (4 - (((skb_src->len +
LLC_SNAP_LEN)) & 3)) : 0;
skb_put(skb_aggr, *pad);
return skb_aggr->len + *pad;
}
/*
* Adds TxPD to AMSDU header.
*
* Each AMSDU packet will contain one TxPD at the beginning,
* followed by multiple AMSDU subframes.
*/
static void
mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv,
struct sk_buff *skb)
{
struct txpd *local_tx_pd;
skb_push(skb, sizeof(*local_tx_pd));
local_tx_pd = (struct txpd *) skb->data;
memset(local_tx_pd, 0, sizeof(struct txpd));
/* Original priority has been overwritten */
local_tx_pd->priority = (u8) skb->priority;
local_tx_pd->pkt_delay_2ms =
mwifiex_wmm_compute_drv_pkt_delay(priv, skb);
local_tx_pd->bss_num = priv->bss_num;
local_tx_pd->bss_type = priv->bss_type;
/* Always zero as the data is followed by struct txpd */
local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd));
local_tx_pd->tx_pkt_type = cpu_to_le16(PKT_TYPE_AMSDU);
local_tx_pd->tx_pkt_length = cpu_to_le16(skb->len -
sizeof(*local_tx_pd));
if (local_tx_pd->tx_control == 0)
/* TxCtrl set by user or default */
local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl);
if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
(priv->adapter->pps_uapsd_mode)) {
if (true == mwifiex_check_last_packet_indication(priv)) {
priv->adapter->tx_lock_flag = true;
local_tx_pd->flags =
MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET;
}
}
}
/*
* Counts the number of subframes in an aggregate packet.
*
* This function parses an aggregate packet buffer, looking for
* subframes and counting the number of such subframe found. The
* function automatically skips the DA/SA fields at the beginning
* of each subframe and padding at the end.
*/
static int
mwifiex_11n_get_num_aggr_pkts(u8 *data, int total_pkt_len)
{
int pkt_count = 0, pkt_len, pad;
while (total_pkt_len > 0) {
/* Length will be in network format, change it to host */
pkt_len = ntohs((*(__be16 *)(data + 2 * ETH_ALEN)));
pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ?
(4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0;
data += pkt_len + pad + sizeof(struct ethhdr);
total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr);
++pkt_count;
}
return pkt_count;
}
/*
* De-aggregate received packets.
*
* This function parses the received aggregate buffer, extracts each subframe,
* strips off the SNAP header from them and sends the data portion for further
* processing.
*
* Each subframe body is copied onto a separate buffer, which are freed by
* upper layer after processing. The function also performs sanity tests on
* the received buffer.
*/
int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv,
struct sk_buff *skb)
{
u16 pkt_len;
int total_pkt_len;
u8 *data;
int pad;
struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
struct rxpd *local_rx_pd = (struct rxpd *) skb->data;
struct sk_buff *skb_daggr;
struct mwifiex_rxinfo *rx_info_daggr = NULL;
int ret = -1;
struct rx_packet_hdr *rx_pkt_hdr;
struct mwifiex_adapter *adapter = priv->adapter;
u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
data = (u8 *) (local_rx_pd + local_rx_pd->rx_pkt_offset);
total_pkt_len = local_rx_pd->rx_pkt_length;
/* Sanity test */
if (total_pkt_len > MWIFIEX_RX_DATA_BUF_SIZE) {
dev_err(adapter->dev, "total pkt len greater than buffer"
" size %d\n", total_pkt_len);
return -1;
}
rx_info->use_count = mwifiex_11n_get_num_aggr_pkts(data, total_pkt_len);
while (total_pkt_len > 0) {
rx_pkt_hdr = (struct rx_packet_hdr *) data;
/* Length will be in network format, change it to host */
pkt_len = ntohs((*(__be16 *) (data + 2 * ETH_ALEN)));
if (pkt_len > total_pkt_len) {
dev_err(adapter->dev, "pkt_len %d > total_pkt_len %d\n",
total_pkt_len, pkt_len);
break;
}
pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ?
(4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0;
total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr);
if (memcmp(&rx_pkt_hdr->rfc1042_hdr,
rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
memmove(data + LLC_SNAP_LEN, data, 2 * ETH_ALEN);
data += LLC_SNAP_LEN;
pkt_len += sizeof(struct ethhdr) - LLC_SNAP_LEN;
} else {
*(u16 *) (data + 2 * ETH_ALEN) = (u16) 0;
pkt_len += sizeof(struct ethhdr);
}
skb_daggr = dev_alloc_skb(pkt_len);
if (!skb_daggr) {
dev_err(adapter->dev, "%s: failed to alloc skb_daggr\n",
__func__);
return -1;
}
rx_info_daggr = MWIFIEX_SKB_RXCB(skb_daggr);
rx_info_daggr->bss_index = rx_info->bss_index;
skb_daggr->tstamp = skb->tstamp;
rx_info_daggr->parent = skb;
skb_daggr->priority = skb->priority;
skb_put(skb_daggr, pkt_len);
memcpy(skb_daggr->data, data, pkt_len);
ret = mwifiex_recv_packet(adapter, skb_daggr);
switch (ret) {
case -EINPROGRESS:
break;
case -1:
dev_err(adapter->dev, "deaggr: host_to_card failed\n");
case 0:
mwifiex_recv_packet_complete(adapter, skb_daggr, ret);
break;
default:
break;
}
data += pkt_len + pad;
}
return ret;
}
/*
* Create aggregated packet.
*
* This function creates an aggregated MSDU packet, by combining buffers
* from the RA list. Each individual buffer is encapsulated as an AMSDU
* subframe and all such subframes are concatenated together to form the
* AMSDU packet.
*
* A TxPD is also added to the front of the resultant AMSDU packets for
* transmission. The resultant packets format is -
*
* +---- ~ ----+------ ~ ------+------ ~ ------+-..-+------ ~ ------+
* | TxPD |AMSDU sub-frame|AMSDU sub-frame| .. |AMSDU sub-frame|
* | | 1 | 2 | .. | n |
* +---- ~ ----+------ ~ ------+------ ~ ------+ .. +------ ~ ------+
*/
int
mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
struct mwifiex_ra_list_tbl *pra_list, int headroom,
int ptrindex, unsigned long ra_list_flags)
__releases(&priv->wmm.ra_list_spinlock)
{
struct mwifiex_adapter *adapter = priv->adapter;
struct sk_buff *skb_aggr, *skb_src;
struct mwifiex_txinfo *tx_info_aggr, *tx_info_src;
int pad = 0;
int ret = 0;
struct mwifiex_tx_param tx_param;
struct txpd *ptx_pd = NULL;
if (skb_queue_empty(&pra_list->skb_head)) {
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
return 0;
}
skb_src = skb_peek(&pra_list->skb_head);
tx_info_src = MWIFIEX_SKB_TXCB(skb_src);
skb_aggr = dev_alloc_skb(adapter->tx_buf_size);
if (!skb_aggr) {
dev_err(adapter->dev, "%s: alloc skb_aggr\n", __func__);
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
return -1;
}
skb_reserve(skb_aggr, headroom + sizeof(struct txpd));
tx_info_aggr = MWIFIEX_SKB_TXCB(skb_aggr);
tx_info_aggr->bss_index = tx_info_src->bss_index;
skb_aggr->priority = skb_src->priority;
while (skb_src && ((skb_headroom(skb_aggr) + skb_src->len
+ LLC_SNAP_LEN)
<= adapter->tx_buf_size)) {
if (!skb_queue_empty(&pra_list->skb_head))
skb_src = skb_dequeue(&pra_list->skb_head);
else
skb_src = NULL;
pra_list->total_pkts_size -= skb_src->len;
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
mwifiex_11n_form_amsdu_pkt(adapter, skb_aggr, skb_src, &pad);
mwifiex_write_data_complete(adapter, skb_src, 0);
spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
return -1;
}
if (!skb_queue_empty(&pra_list->skb_head))
skb_src = skb_peek(&pra_list->skb_head);
else
skb_src = NULL;
}
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags);
/* Last AMSDU packet does not need padding */
skb_trim(skb_aggr, skb_aggr->len - pad);
/* Form AMSDU */
mwifiex_11n_form_amsdu_txpd(priv, skb_aggr);
if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
ptx_pd = (struct txpd *)skb_aggr->data;
skb_push(skb_aggr, headroom);
tx_param.next_pkt_len = ((pra_list->total_pkts_size) ?
(((pra_list->total_pkts_size) >
adapter->tx_buf_size) ? adapter->
tx_buf_size : pra_list->total_pkts_size +
LLC_SNAP_LEN + sizeof(struct txpd)) : 0);
ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
skb_aggr->data,
skb_aggr->len, &tx_param);
switch (ret) {
case -EBUSY:
spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
mwifiex_write_data_complete(adapter, skb_aggr, -1);
return -1;
}
if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
(adapter->pps_uapsd_mode) &&
(adapter->tx_lock_flag)) {
priv->adapter->tx_lock_flag = false;
ptx_pd->flags = 0;
}
skb_queue_tail(&pra_list->skb_head, skb_aggr);
pra_list->total_pkts_size += skb_aggr->len;
tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
break;
case -1:
adapter->data_sent = false;
dev_err(adapter->dev, "%s: host_to_card failed: %#x\n",
__func__, ret);
adapter->dbg.num_tx_host_to_card_failure++;
mwifiex_write_data_complete(adapter, skb_aggr, ret);
return 0;
case -EINPROGRESS:
adapter->data_sent = false;
break;
case 0:
mwifiex_write_data_complete(adapter, skb_aggr, ret);
break;
default:
break;
}
if (ret != -EBUSY) {
spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
if (mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
priv->wmm.packets_out[ptrindex]++;
priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list;
}
/* Now bss_prio_cur pointer points to next node */
adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
list_first_entry(
&adapter->bss_prio_tbl[priv->bss_priority]
.bss_prio_cur->list,
struct mwifiex_bss_prio_node, list);
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
}
return 0;
}
/*
* Marvell Wireless LAN device driver: 802.11n Aggregation
*
* Copyright (C) 2011, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*/
#ifndef _MWIFIEX_11N_AGGR_H_
#define _MWIFIEX_11N_AGGR_H_
#define PKT_TYPE_AMSDU 0xE6
int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv,
struct sk_buff *skb);
int mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
struct mwifiex_ra_list_tbl *ptr, int headroom,
int ptr_index, unsigned long flags)
__releases(&priv->wmm.ra_list_spinlock);
#endif /* !_MWIFIEX_11N_AGGR_H_ */
/*
* Marvell Wireless LAN device driver: 802.11n RX Re-ordering
*
* Copyright (C) 2011, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*/
#include "decl.h"
#include "ioctl.h"
#include "util.h"
#include "fw.h"
#include "main.h"
#include "wmm.h"
#include "11n.h"
#include "11n_rxreorder.h"
/*
* This function processes a received packet and forwards
* it to the kernel/upper layer.
*/
static int mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, void *payload)
{
int ret = 0;
struct mwifiex_adapter *adapter = priv->adapter;
ret = mwifiex_process_rx_packet(adapter, (struct sk_buff *) payload);
return ret;
}
/*
* This function dispatches all packets in the Rx reorder table.
*
* There could be holes in the buffer, which are skipped by the function.
* Since the buffer is linear, the function uses rotation to simulate
* circular buffer.
*/
static int
mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
struct mwifiex_rx_reorder_tbl
*rx_reor_tbl_ptr, int start_win)
{
int no_pkt_to_send, i, xchg;
void *rx_tmp_ptr = NULL;
unsigned long flags;
no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ?
min((start_win - rx_reor_tbl_ptr->start_win),
rx_reor_tbl_ptr->win_size) : rx_reor_tbl_ptr->win_size;
for (i = 0; i < no_pkt_to_send; ++i) {
spin_lock_irqsave(&priv->rx_pkt_lock, flags);
rx_tmp_ptr = NULL;
if (rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL;
}
spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
if (rx_tmp_ptr)
mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr);
}
spin_lock_irqsave(&priv->rx_pkt_lock, flags);
/*
* We don't have a circular buffer, hence use rotation to simulate
* circular buffer
*/
xchg = rx_reor_tbl_ptr->win_size - no_pkt_to_send;
for (i = 0; i < xchg; ++i) {
rx_reor_tbl_ptr->rx_reorder_ptr[i] =
rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i];
rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = NULL;
}
rx_reor_tbl_ptr->start_win = start_win;
spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
return 0;
}
/*
* This function dispatches all packets in the Rx reorder table until
* a hole is found.
*
* The start window is adjusted automatically when a hole is located.
* Since the buffer is linear, the function uses rotation to simulate
* circular buffer.
*/
static int
mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr)
{
int i, j, xchg;
void *rx_tmp_ptr = NULL;
unsigned long flags;
for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) {
spin_lock_irqsave(&priv->rx_pkt_lock, flags);
if (!rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
break;
}
rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL;
spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr);
}
spin_lock_irqsave(&priv->rx_pkt_lock, flags);
/*
* We don't have a circular buffer, hence use rotation to simulate
* circular buffer
*/
if (i > 0) {
xchg = rx_reor_tbl_ptr->win_size - i;
for (j = 0; j < xchg; ++j) {
rx_reor_tbl_ptr->rx_reorder_ptr[j] =
rx_reor_tbl_ptr->rx_reorder_ptr[i + j];
rx_reor_tbl_ptr->rx_reorder_ptr[i + j] = NULL;
}
}
rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i)
&(MAX_TID_VALUE - 1);
spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
return 0;
}
/*
* This function deletes the Rx reorder table and frees the memory.
*
* The function stops the associated timer and dispatches all the
* pending packets in the Rx reorder table before deletion.
*/
static void
mwifiex_11n_delete_rx_reorder_tbl_entry(struct mwifiex_private *priv,
struct mwifiex_rx_reorder_tbl
*rx_reor_tbl_ptr)
{
unsigned long flags;
if (!rx_reor_tbl_ptr)
return;
mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr,
(rx_reor_tbl_ptr->start_win +
rx_reor_tbl_ptr->win_size)
&(MAX_TID_VALUE - 1));
del_timer(&rx_reor_tbl_ptr->timer_context.timer);
spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
list_del(&rx_reor_tbl_ptr->list);
spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
kfree(rx_reor_tbl_ptr->rx_reorder_ptr);
kfree(rx_reor_tbl_ptr);
}
/*
* This function returns the pointer to an entry in Rx reordering
* table which matches the given TA/TID pair.
*/
static struct mwifiex_rx_reorder_tbl *
mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
{
struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
unsigned long flags;
spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) {
if ((!memcmp(rx_reor_tbl_ptr->ta, ta, ETH_ALEN))
&& (rx_reor_tbl_ptr->tid == tid)) {
spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
flags);
return rx_reor_tbl_ptr;
}
}
spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
return NULL;
}
/*
* This function finds the last sequence number used in the packets
* buffered in Rx reordering table.
*/
static int
mwifiex_11n_find_last_seq_num(struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr)
{
int i;
for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i)
if (rx_reorder_tbl_ptr->rx_reorder_ptr[i])
return i;
return -1;
}
/*
* This function flushes all the packets in Rx reordering table.
*
* The function checks if any packets are currently buffered in the
* table or not. In case there are packets available, it dispatches
* them and then dumps the Rx reordering table.
*/
static void
mwifiex_flush_data(unsigned long context)
{
struct reorder_tmr_cnxt *reorder_cnxt =
(struct reorder_tmr_cnxt *) context;
int start_win;
start_win = mwifiex_11n_find_last_seq_num(reorder_cnxt->ptr);
if (start_win >= 0) {
dev_dbg(reorder_cnxt->priv->adapter->dev,
"info: flush data %d\n", start_win);
mwifiex_11n_dispatch_pkt_until_start_win(reorder_cnxt->priv,
reorder_cnxt->ptr,
((reorder_cnxt->ptr->start_win +
start_win + 1) & (MAX_TID_VALUE - 1)));
}
}
/*
* This function creates an entry in Rx reordering table for the
* given TA/TID.
*
* The function also initializes the entry with sequence number, window
* size as well as initializes the timer.
*
* If the received TA/TID pair is already present, all the packets are
* dispatched and the window size is moved until the SSN.
*/
static void
mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
int tid, int win_size, int seq_num)
{
int i;
struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr, *new_node;
u16 last_seq = 0;
unsigned long flags;
/*
* If we get a TID, ta pair which is already present dispatch all the
* the packets and move the window size until the ssn
*/
rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
if (rx_reor_tbl_ptr) {
mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr,
seq_num);
return;
}
/* if !rx_reor_tbl_ptr then create one */
new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL);
if (!new_node) {
dev_err(priv->adapter->dev, "%s: failed to alloc new_node\n",
__func__);
return;
}
INIT_LIST_HEAD(&new_node->list);
new_node->tid = tid;
memcpy(new_node->ta, ta, ETH_ALEN);
new_node->start_win = seq_num;
if (mwifiex_queuing_ra_based(priv))
/* TODO for adhoc */
dev_dbg(priv->adapter->dev,
"info: ADHOC:last_seq=%d start_win=%d\n",
last_seq, new_node->start_win);
else
last_seq = priv->rx_seq[tid];
if (last_seq >= new_node->start_win)
new_node->start_win = last_seq + 1;
new_node->win_size = win_size;
new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size,
GFP_KERNEL);
if (!new_node->rx_reorder_ptr) {
kfree((u8 *) new_node);
dev_err(priv->adapter->dev,
"%s: failed to alloc reorder_ptr\n", __func__);
return;
}
new_node->timer_context.ptr = new_node;
new_node->timer_context.priv = priv;
init_timer(&new_node->timer_context.timer);
new_node->timer_context.timer.function = mwifiex_flush_data;
new_node->timer_context.timer.data =
(unsigned long) &new_node->timer_context;
for (i = 0; i < win_size; ++i)
new_node->rx_reorder_ptr[i] = NULL;
spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr);
spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
return;
}
/*
* This function prepares command for adding a BA request.
*
* Preparation includes -
* - Setting command ID and proper size
* - Setting add BA request buffer
* - Ensuring correct endian-ness
*/
int mwifiex_cmd_11n_addba_req(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd, void *data_buf)
{
struct host_cmd_ds_11n_addba_req *add_ba_req =
(struct host_cmd_ds_11n_addba_req *)
&cmd->params.add_ba_req;
cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ);
cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN);
memcpy(add_ba_req, data_buf, sizeof(*add_ba_req));
return 0;
}
/*
* This function prepares command for adding a BA response.
*
* Preparation includes -
* - Setting command ID and proper size
* - Setting add BA response buffer
* - Ensuring correct endian-ness
*/
int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd,
void *data_buf)
{
struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
(struct host_cmd_ds_11n_addba_rsp *)
&cmd->params.add_ba_rsp;
struct host_cmd_ds_11n_addba_req *cmd_addba_req =
(struct host_cmd_ds_11n_addba_req *) data_buf;
u8 tid = 0;
int win_size = 0;
uint16_t block_ack_param_set;
cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN);
memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr,
ETH_ALEN);
add_ba_rsp->dialog_token = cmd_addba_req->dialog_token;
add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo;
add_ba_rsp->ssn = cmd_addba_req->ssn;
block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set);
tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
>> BLOCKACKPARAM_TID_POS;
add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT);
block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
/* We donot support AMSDU inside AMPDU, hence reset the bit */
block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
block_ack_param_set |= (priv->add_ba_param.rx_win_size <<
BLOCKACKPARAM_WINSIZE_POS);
add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set);
win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
& IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
>> BLOCKACKPARAM_WINSIZE_POS;
cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set);
mwifiex_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr,
tid, win_size, le16_to_cpu(cmd_addba_req->ssn));
return 0;
}
/*
* This function prepares command for deleting a BA request.
*
* Preparation includes -
* - Setting command ID and proper size
* - Setting del BA request buffer
* - Ensuring correct endian-ness
*/
int mwifiex_cmd_11n_delba(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd, void *data_buf)
{
struct host_cmd_ds_11n_delba *del_ba = (struct host_cmd_ds_11n_delba *)
&cmd->params.del_ba;
cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA);
cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN);
memcpy(del_ba, data_buf, sizeof(*del_ba));
return 0;
}
/*
* This function identifies if Rx reordering is needed for a received packet.
*
* In case reordering is required, the function will do the reordering
* before sending it to kernel.
*
* The Rx reorder table is checked first with the received TID/TA pair. If
* not found, the received packet is dispatched immediately. But if found,
* the packet is reordered and all the packets in the updated Rx reordering
* table is dispatched until a hole is found.
*
* For sequence number less than the starting window, the packet is dropped.
*/
int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
u16 seq_num, u16 tid,
u8 *ta, u8 pkt_type, void *payload)
{
struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
int start_win, end_win, win_size;
int ret = 0;
u16 pkt_index = 0;
rx_reor_tbl_ptr =
mwifiex_11n_get_rx_reorder_tbl((struct mwifiex_private *) priv,
tid, ta);
if (!rx_reor_tbl_ptr) {
if (pkt_type != PKT_TYPE_BAR)
mwifiex_11n_dispatch_pkt(priv, payload);
return 0;
}
start_win = rx_reor_tbl_ptr->start_win;
win_size = rx_reor_tbl_ptr->win_size;
end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
del_timer(&rx_reor_tbl_ptr->timer_context.timer);
mod_timer(&rx_reor_tbl_ptr->timer_context.timer, jiffies
+ (MIN_FLUSH_TIMER_MS * win_size * HZ) / 1000);
/*
* If seq_num is less then starting win then ignore and drop the
* packet
*/
if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {/* Wrap */
if (seq_num >= ((start_win + (TWOPOW11)) & (MAX_TID_VALUE - 1))
&& (seq_num < start_win))
return -1;
} else if ((seq_num < start_win)
|| (seq_num > (start_win + (TWOPOW11)))) {
return -1;
}
/*
* If this packet is a BAR we adjust seq_num as
* WinStart = seq_num
*/
if (pkt_type == PKT_TYPE_BAR)
seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1);
if (((end_win < start_win)
&& (seq_num < (TWOPOW11 - (MAX_TID_VALUE - start_win)))
&& (seq_num > end_win)) || ((end_win > start_win)
&& ((seq_num > end_win) || (seq_num < start_win)))) {
end_win = seq_num;
if (((seq_num - win_size) + 1) >= 0)
start_win = (end_win - win_size) + 1;
else
start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1;
ret = mwifiex_11n_dispatch_pkt_until_start_win(priv,
rx_reor_tbl_ptr, start_win);
if (ret)
return ret;
}
if (pkt_type != PKT_TYPE_BAR) {
if (seq_num >= start_win)
pkt_index = seq_num - start_win;
else
pkt_index = (seq_num+MAX_TID_VALUE) - start_win;
if (rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index])
return -1;
rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index] = payload;
}
/*
* Dispatch all packets sequentially from start_win until a
* hole is found and adjust the start_win appropriately
*/
ret = mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr);
return ret;
}
/*
* This function deletes an entry for a given TID/TA pair.
*
* The TID/TA are taken from del BA event body.
*/
void
mwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int tid,
u8 *peer_mac, u8 type, int initiator)
{
struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
struct mwifiex_tx_ba_stream_tbl *ptx_tbl;
u8 cleanup_rx_reorder_tbl;
unsigned long flags;
if (type == TYPE_DELBA_RECEIVE)
cleanup_rx_reorder_tbl = (initiator) ? true : false;
else
cleanup_rx_reorder_tbl = (initiator) ? false : true;
dev_dbg(priv->adapter->dev, "event: DELBA: %pM tid=%d, "
"initiator=%d\n", peer_mac, tid, initiator);
if (cleanup_rx_reorder_tbl) {
rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
peer_mac);
if (!rx_reor_tbl_ptr) {
dev_dbg(priv->adapter->dev,
"event: TID, TA not found in table\n");
return;
}
mwifiex_11n_delete_rx_reorder_tbl_entry(priv, rx_reor_tbl_ptr);
} else {
ptx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, peer_mac);
if (!ptx_tbl) {
dev_dbg(priv->adapter->dev,
"event: TID, RA not found in table\n");
return;
}
spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl);
spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
}
}
/*
* This function handles the command response of an add BA response.
*
* Handling includes changing the header fields into CPU format and
* creating the stream, provided the add BA is accepted.
*/
int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp)
{
struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
(struct host_cmd_ds_11n_addba_rsp *)
&resp->params.add_ba_rsp;
int tid, win_size;
struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr = NULL;
uint16_t block_ack_param_set;
block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set);
tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
>> BLOCKACKPARAM_TID_POS;
/*
* Check if we had rejected the ADDBA, if yes then do not create
* the stream
*/
if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) {
win_size = (block_ack_param_set &
IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
>> BLOCKACKPARAM_WINSIZE_POS;
dev_dbg(priv->adapter->dev, "cmd: ADDBA RSP: %pM"
" tid=%d ssn=%d win_size=%d\n",
add_ba_rsp->peer_mac_addr,
tid, add_ba_rsp->ssn, win_size);
} else {
dev_err(priv->adapter->dev, "ADDBA RSP: failed %pM tid=%d)\n",
add_ba_rsp->peer_mac_addr, tid);
rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv,
tid, add_ba_rsp->peer_mac_addr);
if (rx_reor_tbl_ptr)
mwifiex_11n_delete_rx_reorder_tbl_entry(priv,
rx_reor_tbl_ptr);
}
return 0;
}
/*
* This function handles BA stream timeout event by preparing and sending
* a command to the firmware.
*/
void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv,
struct host_cmd_ds_11n_batimeout *event)
{
struct host_cmd_ds_11n_delba delba;
memset(&delba, 0, sizeof(struct host_cmd_ds_11n_delba));
memcpy(delba.peer_mac_addr, event->peer_mac_addr, ETH_ALEN);
delba.del_ba_param_set |=
cpu_to_le16((u16) event->tid << DELBA_TID_POS);
delba.del_ba_param_set |= cpu_to_le16(
(u16) event->origninator << DELBA_INITIATOR_POS);
delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT);
mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, NULL, &delba);
return;
}
/*
* This function cleans up the Rx reorder table by deleting all the entries
* and re-initializing.
*/
void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv)
{
struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node;
unsigned long flags;
spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
list_for_each_entry_safe(del_tbl_ptr, tmp_node,
&priv->rx_reorder_tbl_ptr, list) {
spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
mwifiex_11n_delete_rx_reorder_tbl_entry(priv, del_tbl_ptr);
spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
}
spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
memset(priv->rx_seq, 0, sizeof(priv->rx_seq));
}
/*
* Marvell Wireless LAN device driver: 802.11n RX Re-ordering
*
* Copyright (C) 2011, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*/
#ifndef _MWIFIEX_11N_RXREORDER_H_
#define _MWIFIEX_11N_RXREORDER_H_
#define MIN_FLUSH_TIMER_MS 50
#define PKT_TYPE_BAR 0xE7
#define MAX_TID_VALUE (2 << 11)
#define TWOPOW11 (2 << 10)
#define BLOCKACKPARAM_TID_POS 2
#define BLOCKACKPARAM_AMSDU_SUPP_MASK 0x1
#define BLOCKACKPARAM_WINSIZE_POS 6
#define DELBA_TID_POS 12
#define DELBA_INITIATOR_POS 11
#define TYPE_DELBA_SENT 1
#define TYPE_DELBA_RECEIVE 2
#define IMMEDIATE_BLOCK_ACK 0x2
#define ADDBA_RSP_STATUS_ACCEPT 0
int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *,
u16 seqNum,
u16 tid, u8 *ta,
u8 pkttype, void *payload);
void mwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int Tid,
u8 *PeerMACAddr, u8 type,
int initiator);
void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv,
struct host_cmd_ds_11n_batimeout *event);
int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
struct host_cmd_ds_command
*resp);
int mwifiex_cmd_11n_delba(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd,
void *data_buf);
int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
struct host_cmd_ds_command
*cmd, void *data_buf);
int mwifiex_cmd_11n_addba_req(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd,
void *data_buf);
void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv);
struct mwifiex_rx_reorder_tbl *mwifiex_11n_get_rxreorder_tbl(struct
mwifiex_private
*priv, int tid,
u8 *ta);
#endif /* _MWIFIEX_11N_RXREORDER_H_ */
config MWIFIEX
tristate "Marvell WiFi-Ex Driver"
depends on CFG80211
select LIB80211
---help---
This adds support for wireless adapters based on Marvell
802.11n chipsets.
If you choose to build it as a module, it will be called
mwifiex.
config MWIFIEX_SDIO
tristate "Marvell WiFi-Ex Driver for SD8787"
depends on MWIFIEX && MMC
select FW_LOADER
---help---
This adds support for wireless adapters based on Marvell
8787 chipset with SDIO interface.
If you choose to build it as a module, it will be called
mwifiex_sdio.
#
# Copyright (C) 2011, Marvell International Ltd.
#
# This software file (the "File") is distributed by Marvell International
# Ltd. under the terms of the GNU General Public License Version 2, June 1991
# (the "License"). You may use, redistribute and/or modify this File in
# accordance with the terms and conditions of the License, a copy of which
# is available by writing to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
# worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
#
# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
# ARE EXPRESSLY DISCLAIMED. The License provides additional details about
# this warranty disclaimer.
mwifiex-y += main.o
mwifiex-y += init.o
mwifiex-y += cfp.o
mwifiex-y += cmdevt.o
mwifiex-y += util.o
mwifiex-y += txrx.o
mwifiex-y += wmm.o
mwifiex-y += 11n.o
mwifiex-y += 11n_aggr.o
mwifiex-y += 11n_rxreorder.o
mwifiex-y += scan.o
mwifiex-y += join.o
mwifiex-y += sta_ioctl.o
mwifiex-y += sta_cmd.o
mwifiex-y += sta_cmdresp.o
mwifiex-y += sta_event.o
mwifiex-y += sta_tx.o
mwifiex-y += sta_rx.o
mwifiex-y += cfg80211.o
mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o
obj-$(CONFIG_MWIFIEX) += mwifiex.o
mwifiex_sdio-y += sdio.o
obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o
# Copyright (C) 2011, Marvell International Ltd.
#
# This software file (the "File") is distributed by Marvell International
# Ltd. under the terms of the GNU General Public License Version 2, June 1991
# (the "License"). You may use, redistribute and/or modify this File in
# accordance with the terms and conditions of the License, a copy of which
# is available by writing to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
# worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
#
# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
# ARE EXPRESSLY DISCLAIMED. The License provides additional details about
# this warranty disclaimer.
===============================================================================
U S E R M A N U A L
1) FOR DRIVER INSTALL
a) Copy sd8787.bin to /lib/firmware/mrvl/ directory,
create the directory if it doesn't exist.
b) Install WLAN driver,
insmod mwifiex.ko
c) Uninstall WLAN driver,
ifconfig mlanX down
rmmod mwifiex
2) FOR DRIVER CONFIGURATION AND INFO
The configurations can be done either using the 'iw' user space
utility or debugfs.
a) 'iw' utility commands
Following are some useful iw commands:-
iw dev mlan0 scan
This command will trigger a scan.
The command will then display the scan table entries
iw dev mlan0 connect -w <SSID> [<freq in MHz>] [<bssid>] [key 0:abcde d:1123456789a]
The above command can be used to connect to an AP with a particular SSID.
Ap's operating frequency can be specified or even the bssid. If the AP is using
WEP encryption, wep keys can be specified in the command.
Note: Every time before connecting to an AP scan command (iw dev mlan0 scan) should be used by user.
iw dev mlan0 disconnect
This command will be used to disconnect from an AP.
iw dev mlan0 ibss join <SSID> <freq in MHz> [fixed-freq] [fixed-bssid] [key 0:abcde]
The command will be used to join or create an ibss. Optionally, operating frequency,
bssid and the security related parameters can be specified while joining/creating
and ibss.
iw dev mlan0 ibss leave
The command will be used to leave an ibss network.
iw dev mlan0 link
The command will be used to get the connection status. The command will return parameters
such as SSID, operating frequency, rx/tx packets, signal strength, tx bitrate.
Apart from the iw utility all standard configurations using the 'iwconfig' utility are also supported.
b) Debugfs interface
The debugfs interface can be used for configurations and for getting
some useful information from the driver.
The section below explains the configurations that can be
done.
Mount debugfs to /debugfs mount point:
mkdir /debugfs
mount -t debugfs debugfs /debugfs
The information is provided in /debugfs/mwifiex/mlanX/:
iw reg set <country code>
The command will be used to change the regulatory domain.
iw reg get
The command will be used to get current regulatory domain.
info
This command is used to get driver info.
Usage:
cat info
driver_name = "mwifiex"
driver_version = <driver_name, driver_version, (firmware_version)>
interface_name = "mlanX"
bss_mode = "Ad-hoc" | "Managed" | "Auto" | "Unknown"
media_state = "Disconnected" | "Connected"
mac_address = <6-byte adapter MAC address>
multicase_count = <multicast address count>
essid = <current SSID>
bssid = <current BSSID>
channel = <current channel>
region_code = <current region code>
multicasr_address[n] = <multicast address>
num_tx_bytes = <number of bytes sent to device>
num_rx_bytes = <number of bytes received from device and sent to kernel>
num_tx_pkts = <number of packets sent to device>
num_rx_pkts = <number of packets received from device and sent to kernel>
num_tx_pkts_dropped = <number of Tx packets dropped by driver>
num_rx_pkts_dropped = <number of Rx packets dropped by driver>
num_tx_pkts_err = <number of Tx packets failed to send to device>
num_rx_pkts_err = <number of Rx packets failed to receive from device>
carrier "on" | "off"
tx queue "stopped" | "started"
The following debug info are provided in /debugfs/mwifiex/mlanX/debug:
int_counter = <interrupt count, cleared when interrupt handled>
wmm_ac_vo = <number of packets sent to device from WMM AcVo queue>
wmm_ac_vi = <number of packets sent to device from WMM AcVi queue>
wmm_ac_be = <number of packets sent to device from WMM AcBE queue>
wmm_ac_bk = <number of packets sent to device from WMM AcBK queue>
max_tx_buf_size = <maximum Tx buffer size>
tx_buf_size = <current Tx buffer size>
curr_tx_buf_size = <current Tx buffer size>
ps_mode = <0/1, CAM mode/PS mode>
ps_state = <0/1/2/3, full power state/awake state/pre-sleep state/sleep state>
is_deep_sleep = <0/1, not deep sleep state/deep sleep state>
wakeup_dev_req = <0/1, wakeup device not required/required>
wakeup_tries = <wakeup device count, cleared when device awake>
hs_configured = <0/1, host sleep not configured/configured>
hs_activated = <0/1, extended host sleep not activated/activated>
num_tx_timeout = <number of Tx timeout>
num_cmd_timeout = <number of timeout commands>
timeout_cmd_id = <command id of the last timeout command>
timeout_cmd_act = <command action of the last timeout command>
last_cmd_id = <command id of the last several commands sent to device>
last_cmd_act = <command action of the last several commands sent to device>
last_cmd_index = <0 based last command index>
last_cmd_resp_id = <command id of the last several command responses received from device>
last_cmd_resp_index = <0 based last command response index>
last_event = <event id of the last several events received from device>
last_event_index = <0 based last event index>
num_cmd_h2c_fail = <number of commands failed to send to device>
num_cmd_sleep_cfm_fail = <number of sleep confirm failed to send to device>
num_tx_h2c_fail = <number of data packets failed to send to device>
num_evt_deauth = <number of deauthenticated events received from device>
num_evt_disassoc = <number of disassociated events received from device>
num_evt_link_lost = <number of link lost events received from device>
num_cmd_deauth = <number of deauthenticate commands sent to device>
num_cmd_assoc_ok = <number of associate commands with success return>
num_cmd_assoc_fail = <number of associate commands with failure return>
cmd_sent = <0/1, send command resources available/sending command to device>
data_sent = <0/1, send data resources available/sending data to device>
mp_rd_bitmap = <SDIO multi-port read bitmap>
mp_wr_bitmap = <SDIO multi-port write bitmap>
cmd_resp_received = <0/1, no cmd response to process/response received and yet to process>
event_received = <0/1, no event to process/event received and yet to process>
ioctl_pending = <number of ioctl pending>
tx_pending = <number of Tx packet pending>
rx_pending = <number of Rx packet pending>
3) FOR DRIVER CONFIGURATION
regrdwr
This command is used to read/write the adapter register.
Usage:
echo " <type> <offset> [value]" > regrdwr
cat regrdwr
where the parameters are,
<type>: 1:MAC/SOC, 2:BBP, 3:RF, 4:PMIC, 5:CAU
<offset>: offset of register
[value]: value to be written
Examples:
echo "1 0xa060" > regrdwr : Read the MAC register
echo "1 0xa060 0x12" > regrdwr : Write the MAC register
echo "1 0xa794 0x80000000" > regrdwr
: Write 0x80000000 to MAC register
rdeeprom
This command is used to read the EEPROM contents of the card.
Usage:
echo "<offset> <length>" > rdeeprom
cat rdeeprom
where the parameters are,
<offset>: multiples of 4
<length>: 4-20, multiples of 4
Example:
echo "0 20" > rdeeprom : Read 20 bytes of EEPROM data from offset 0
getlog
This command is used to get the statistics available in the station.
Usage:
cat getlog
===============================================================================
此差异已折叠。
/*
* Marvell Wireless LAN device driver: CFG80211
*
* Copyright (C) 2011, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*/
#ifndef __MWIFIEX_CFG80211__
#define __MWIFIEX_CFG80211__
#include <net/cfg80211.h>
#include "main.h"
int mwifiex_register_cfg80211(struct net_device *, u8 *,
struct mwifiex_private *);
void mwifiex_cfg80211_results(struct work_struct *work);
#endif
/*
* Marvell Wireless LAN device driver: Channel, Frequence and Power
*
* Copyright (C) 2011, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*/
#include "decl.h"
#include "ioctl.h"
#include "util.h"
#include "fw.h"
#include "main.h"
#include "cfg80211.h"
/* 100mW */
#define MWIFIEX_TX_PWR_DEFAULT 20
/* 100mW */
#define MWIFIEX_TX_PWR_US_DEFAULT 20
/* 50mW */
#define MWIFIEX_TX_PWR_JP_DEFAULT 16
/* 100mW */
#define MWIFIEX_TX_PWR_FR_100MW 20
/* 10mW */
#define MWIFIEX_TX_PWR_FR_10MW 10
/* 100mW */
#define MWIFIEX_TX_PWR_EMEA_DEFAULT 20
static u8 adhoc_rates_b[B_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, 0 };
static u8 adhoc_rates_g[G_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24,
0xb0, 0x48, 0x60, 0x6c, 0 };
static u8 adhoc_rates_bg[BG_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96,
0x0c, 0x12, 0x18, 0x24,
0x30, 0x48, 0x60, 0x6c, 0 };
static u8 adhoc_rates_a[A_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24,
0xb0, 0x48, 0x60, 0x6c, 0 };
u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
0xb0, 0x48, 0x60, 0x6c, 0 };
static u16 mwifiex_data_rates[MWIFIEX_SUPPORTED_RATES_EXT] = { 0x02, 0x04,
0x0B, 0x16, 0x00, 0x0C, 0x12, 0x18,
0x24, 0x30, 0x48, 0x60, 0x6C, 0x90,
0x0D, 0x1A, 0x27, 0x34, 0x4E, 0x68,
0x75, 0x82, 0x0C, 0x1B, 0x36, 0x51,
0x6C, 0xA2, 0xD8, 0xF3, 0x10E, 0x00 };
u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 };
u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
0x30, 0x48, 0x60, 0x6c, 0 };
u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c,
0x12, 0x16, 0x18, 0x24, 0x30, 0x48,
0x60, 0x6c, 0 };
u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x10, 0x20, 0x30,
0x32, 0x40, 0x41, 0xff };
u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 };
/*
* This function maps an index in supported rates table into
* the corresponding data rate.
*/
u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index,
u8 ht_info)
{
u16 mcs_rate[4][8] = {
{0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e}
, /* LG 40M */
{0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c}
, /* SG 40M */
{0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82}
, /* LG 20M */
{0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90}
}; /* SG 20M */
u32 rate;
if (ht_info & BIT(0)) {
if (index == MWIFIEX_RATE_BITMAP_MCS0) {
if (ht_info & BIT(2))
rate = 0x0D; /* MCS 32 SGI rate */
else
rate = 0x0C; /* MCS 32 LGI rate */
} else if (index < 8) {
if (ht_info & BIT(1)) {
if (ht_info & BIT(2))
/* SGI, 40M */
rate = mcs_rate[1][index];
else
/* LGI, 40M */
rate = mcs_rate[0][index];
} else {
if (ht_info & BIT(2))
/* SGI, 20M */
rate = mcs_rate[3][index];
else
/* LGI, 20M */
rate = mcs_rate[2][index];
}
} else
rate = mwifiex_data_rates[0];
} else {
if (index >= MWIFIEX_SUPPORTED_RATES_EXT)
index = 0;
rate = mwifiex_data_rates[index];
}
return rate;
}
/*
* This function maps a data rate value into corresponding index in supported
* rates table.
*/
u8 mwifiex_data_rate_to_index(struct mwifiex_adapter *adapter, u32 rate)
{
u16 *ptr;
if (rate) {
ptr = memchr(mwifiex_data_rates, rate,
sizeof(mwifiex_data_rates));
if (ptr)
return (u8) (ptr - mwifiex_data_rates);
}
return 0;
}
/*
* This function returns the current active data rates.
*
* The result may vary depending upon connection status.
*/
u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, u8 *rates)
{
u32 k;
if (!priv->media_connected)
k = mwifiex_get_supported_rates(priv, rates);
else
k = mwifiex_copy_rates(rates, 0,
priv->curr_bss_params.data_rates,
priv->curr_bss_params.num_of_rates);
return k;
}
/*
* This function locates the Channel-Frequency-Power triplet based upon
* band and channel parameters.
*/
struct mwifiex_chan_freq_power *
mwifiex_get_cfp_by_band_and_channel_from_cfg80211(struct mwifiex_private
*priv, u8 band, u16 channel)
{
struct mwifiex_chan_freq_power *cfp = NULL;
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
int i;
if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG)
sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ];
else
sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ];
if (!sband) {
dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
" & channel %d\n", __func__, band, channel);
return cfp;
}
for (i = 0; i < sband->n_channels; i++) {
ch = &sband->channels[i];
if (((ch->hw_value == channel) ||
(channel == FIRST_VALID_CHANNEL))
&& !(ch->flags & IEEE80211_CHAN_DISABLED)) {
priv->cfp.channel = channel;
priv->cfp.freq = ch->center_freq;
priv->cfp.max_tx_power = ch->max_power;
cfp = &priv->cfp;
break;
}
}
if (i == sband->n_channels)
dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
" & channel %d\n", __func__, band, channel);
return cfp;
}
/*
* This function locates the Channel-Frequency-Power triplet based upon
* band and frequency parameters.
*/
struct mwifiex_chan_freq_power *
mwifiex_get_cfp_by_band_and_freq_from_cfg80211(struct mwifiex_private *priv,
u8 band, u32 freq)
{
struct mwifiex_chan_freq_power *cfp = NULL;
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
int i;
if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG)
sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ];
else
sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ];
if (!sband) {
dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
" & freq %d\n", __func__, band, freq);
return cfp;
}
for (i = 0; i < sband->n_channels; i++) {
ch = &sband->channels[i];
if ((ch->center_freq == freq) &&
!(ch->flags & IEEE80211_CHAN_DISABLED)) {
priv->cfp.channel = ch->hw_value;
priv->cfp.freq = freq;
priv->cfp.max_tx_power = ch->max_power;
cfp = &priv->cfp;
break;
}
}
if (i == sband->n_channels)
dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
" & freq %d\n", __func__, band, freq);
return cfp;
}
/*
* This function checks if the data rate is set to auto.
*/
u8
mwifiex_is_rate_auto(struct mwifiex_private *priv)
{
u32 i;
int rate_num = 0;
for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates); i++)
if (priv->bitmap_rates[i])
rate_num++;
if (rate_num > 1)
return true;
else
return false;
}
/*
* This function converts rate bitmap into rate index.
*/
int
mwifiex_get_rate_index(struct mwifiex_adapter *adapter, u16 *rate_bitmap,
int size)
{
int i;
for (i = 0; i < size * 8; i++)
if (rate_bitmap[i / 16] & (1 << (i % 16)))
return i;
return 0;
}
/*
* This function gets the supported data rates.
*
* The function works in both Ad-Hoc and infra mode by printing the
* band and returning the data rates.
*/
u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
{
u32 k = 0;
struct mwifiex_adapter *adapter = priv->adapter;
if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA) {
/* Infra. mode */
switch (adapter->config_bands) {
case BAND_B:
dev_dbg(adapter->dev, "info: infra band=%d "
"supported_rates_b\n", adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_b,
sizeof(supported_rates_b));
break;
case BAND_G:
case BAND_G | BAND_GN:
dev_dbg(adapter->dev, "info: infra band=%d "
"supported_rates_g\n", adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_g,
sizeof(supported_rates_g));
break;
case BAND_B | BAND_G:
case BAND_A | BAND_B | BAND_G:
case BAND_A | BAND_B:
case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN:
case BAND_B | BAND_G | BAND_GN:
dev_dbg(adapter->dev, "info: infra band=%d "
"supported_rates_bg\n", adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_bg,
sizeof(supported_rates_bg));
break;
case BAND_A:
case BAND_A | BAND_G:
dev_dbg(adapter->dev, "info: infra band=%d "
"supported_rates_a\n", adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_a,
sizeof(supported_rates_a));
break;
case BAND_A | BAND_AN:
case BAND_A | BAND_G | BAND_AN | BAND_GN:
dev_dbg(adapter->dev, "info: infra band=%d "
"supported_rates_a\n", adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_a,
sizeof(supported_rates_a));
break;
case BAND_GN:
dev_dbg(adapter->dev, "info: infra band=%d "
"supported_rates_n\n", adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_n,
sizeof(supported_rates_n));
break;
}
} else {
/* Ad-hoc mode */
switch (adapter->adhoc_start_band) {
case BAND_B:
dev_dbg(adapter->dev, "info: adhoc B\n");
k = mwifiex_copy_rates(rates, k, adhoc_rates_b,
sizeof(adhoc_rates_b));
break;
case BAND_G:
case BAND_G | BAND_GN:
dev_dbg(adapter->dev, "info: adhoc G only\n");
k = mwifiex_copy_rates(rates, k, adhoc_rates_g,
sizeof(adhoc_rates_g));
break;
case BAND_B | BAND_G:
case BAND_B | BAND_G | BAND_GN:
dev_dbg(adapter->dev, "info: adhoc BG\n");
k = mwifiex_copy_rates(rates, k, adhoc_rates_bg,
sizeof(adhoc_rates_bg));
break;
case BAND_A:
case BAND_A | BAND_AN:
dev_dbg(adapter->dev, "info: adhoc A\n");
k = mwifiex_copy_rates(rates, k, adhoc_rates_a,
sizeof(adhoc_rates_a));
break;
}
}
return k;
}
此差异已折叠。
此差异已折叠。
/*
* Marvell Wireless LAN device driver: generic data structures and APIs
*
* Copyright (C) 2011, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*/
#ifndef _MWIFIEX_DECL_H_
#define _MWIFIEX_DECL_H_
#undef pr_fmt
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/wait.h>
#include <linux/timer.h>
#include <linux/ieee80211.h>
#define MWIFIEX_MAX_BSS_NUM (1)
#define MWIFIEX_MIN_DATA_HEADER_LEN 32 /* (sizeof(mwifiex_txpd)) */
#define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2
#define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16
#define MWIFIEX_AMPDU_DEF_TXWINSIZE 32
#define MWIFIEX_AMPDU_DEF_RXWINSIZE 16
#define MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff
#define MWIFIEX_RATE_INDEX_HRDSSS0 0
#define MWIFIEX_RATE_INDEX_HRDSSS3 3
#define MWIFIEX_RATE_INDEX_OFDM0 4
#define MWIFIEX_RATE_INDEX_OFDM7 11
#define MWIFIEX_RATE_INDEX_MCS0 12
#define MWIFIEX_RATE_BITMAP_OFDM0 16
#define MWIFIEX_RATE_BITMAP_OFDM7 23
#define MWIFIEX_RATE_BITMAP_MCS0 32
#define MWIFIEX_RATE_BITMAP_MCS127 159
#define MWIFIEX_RX_DATA_BUF_SIZE (4 * 1024)
#define MWIFIEX_RX_CMD_BUF_SIZE (2 * 1024)
#define MWIFIEX_RTS_MIN_VALUE (0)
#define MWIFIEX_RTS_MAX_VALUE (2347)
#define MWIFIEX_FRAG_MIN_VALUE (256)
#define MWIFIEX_FRAG_MAX_VALUE (2346)
#define MWIFIEX_SDIO_BLOCK_SIZE 256
#define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0)
enum mwifiex_error_code {
MWIFIEX_ERROR_NO_ERROR = 0,
MWIFIEX_ERROR_FW_NOT_READY = 0x00000001,
MWIFIEX_ERROR_FW_BUSY,
MWIFIEX_ERROR_FW_CMDRESP,
MWIFIEX_ERROR_PKT_SIZE_INVALID = 0x80000001,
MWIFIEX_ERROR_PKT_TIMEOUT,
MWIFIEX_ERROR_CMD_INVALID,
MWIFIEX_ERROR_CMD_TIMEOUT,
MWIFIEX_ERROR_CMD_DNLD_FAIL,
MWIFIEX_ERROR_CMD_CANCEL,
MWIFIEX_ERROR_CMD_RESP_FAIL,
MWIFIEX_ERROR_ASSOC_FAIL,
MWIFIEX_ERROR_EVENT_UNKNOWN,
MWIFIEX_ERROR_INVALID_PARAMETER,
};
enum mwifiex_bss_type {
MWIFIEX_BSS_TYPE_STA = 0,
MWIFIEX_BSS_TYPE_UAP = 1,
MWIFIEX_BSS_TYPE_ANY = 0xff,
};
enum mwifiex_bss_role {
MWIFIEX_BSS_ROLE_STA = 0,
MWIFIEX_BSS_ROLE_UAP = 1,
MWIFIEX_BSS_ROLE_ANY = 0xff,
};
#define BSS_ROLE_BIT_MASK BIT(0)
#define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_BIT_MASK)
enum mwifiex_data_frame_type {
MWIFIEX_DATA_FRAME_TYPE_ETH_II = 0,
MWIFIEX_DATA_FRAME_TYPE_802_11,
};
struct mwifiex_fw_image {
u8 *helper_buf;
u32 helper_len;
u8 *fw_buf;
u32 fw_len;
};
struct mwifiex_802_11_ssid {
u32 ssid_len;
u8 ssid[IEEE80211_MAX_SSID_LEN];
};
struct mwifiex_wait_queue {
u32 bss_index;
wait_queue_head_t *wait;
u16 *condition;
u32 start_time;
int status;
u32 enabled;
};
struct mwifiex_rxinfo {
u8 bss_index;
struct sk_buff *parent;
u8 use_count;
};
struct mwifiex_txinfo {
u32 status_code;
u8 flags;
u8 bss_index;
};
struct mwifiex_bss_attr {
u32 bss_type;
u32 frame_type;
u32 active;
u32 bss_priority;
u32 bss_num;
};
enum mwifiex_cmd_result_e {
MWIFIEX_CMD_RESULT_SUCCESS = 0,
MWIFIEX_CMD_RESULT_FAILURE = 1,
MWIFIEX_CMD_RESULT_TIMEOUT = 2,
MWIFIEX_CMD_RESULT_INVALID_DATA = 3
} __packed;
enum mwifiex_wmm_ac_e {
WMM_AC_BK,
WMM_AC_BE,
WMM_AC_VI,
WMM_AC_VO
} __packed;
enum mwifiex_wmm_queue_config_action_e {
MWIFIEX_WMM_QUEUE_CONFIG_ACTION_GET = 0,
MWIFIEX_WMM_QUEUE_CONFIG_ACTION_SET = 1,
MWIFIEX_WMM_QUEUE_CONFIG_ACTION_DEFAULT = 2,
MWIFIEX_WMM_QUEUE_CONFIG_ACTION_MAX
} __packed;
enum mwifiex_wmm_queue_stats_action_e {
MWIFIEX_WMM_STATS_ACTION_START = 0,
MWIFIEX_WMM_STATS_ACTION_STOP = 1,
MWIFIEX_WMM_STATS_ACTION_GET_CLR = 2,
MWIFIEX_WMM_STATS_ACTION_SET_CFG = 3, /* Not currently used */
MWIFIEX_WMM_STATS_ACTION_GET_CFG = 4, /* Not currently used */
MWIFIEX_WMM_STATS_ACTION_MAX
} __packed;
struct mwifiex_device {
struct mwifiex_bss_attr bss_attr[MWIFIEX_MAX_BSS_NUM];
};
#endif /* !_MWIFIEX_DECL_H_ */
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
* Marvell Wireless LAN device driver: SDIO specific definitions
*
* Copyright (C) 2011, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*/
#ifndef _MWIFIEX_SDIO_H
#define _MWIFIEX_SDIO_H
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/card.h>
#include "main.h"
#define BLOCK_MODE 1
#define BYTE_MODE 0
#define REG_PORT 0
#define RD_BITMAP_L 0x04
#define RD_BITMAP_U 0x05
#define WR_BITMAP_L 0x06
#define WR_BITMAP_U 0x07
#define RD_LEN_P0_L 0x08
#define RD_LEN_P0_U 0x09
#define MWIFIEX_SDIO_IO_PORT_MASK 0xfffff
#define MWIFIEX_SDIO_BYTE_MODE_MASK 0x80000000
#define CTRL_PORT 0
#define CTRL_PORT_MASK 0x0001
#define DATA_PORT_MASK 0xfffe
#define MAX_MP_REGS 64
#define MAX_PORT 16
#define SDIO_MP_AGGR_DEF_PKT_LIMIT 8
#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (4096) /* 4K */
/* Multi port RX aggregation buffer size */
#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE (4096) /* 4K */
/* Misc. Config Register : Auto Re-enable interrupts */
#define AUTO_RE_ENABLE_INT BIT(4)
/* Host Control Registers */
/* Host Control Registers : I/O port 0 */
#define IO_PORT_0_REG 0x78
/* Host Control Registers : I/O port 1 */
#define IO_PORT_1_REG 0x79
/* Host Control Registers : I/O port 2 */
#define IO_PORT_2_REG 0x7A
/* Host Control Registers : Configuration */
#define CONFIGURATION_REG 0x00
/* Host Control Registers : Host without Command 53 finish host*/
#define HOST_TO_CARD_EVENT (0x1U << 3)
/* Host Control Registers : Host without Command 53 finish host */
#define HOST_WO_CMD53_FINISH_HOST (0x1U << 2)
/* Host Control Registers : Host power up */
#define HOST_POWER_UP (0x1U << 1)
/* Host Control Registers : Host power down */
#define HOST_POWER_DOWN (0x1U << 0)
/* Host Control Registers : Host interrupt mask */
#define HOST_INT_MASK_REG 0x02
/* Host Control Registers : Upload host interrupt mask */
#define UP_LD_HOST_INT_MASK (0x1U)
/* Host Control Registers : Download host interrupt mask */
#define DN_LD_HOST_INT_MASK (0x2U)
/* Enable Host interrupt mask */
#define HOST_INT_ENABLE (UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK)
/* Disable Host interrupt mask */
#define HOST_INT_DISABLE 0xff
/* Host Control Registers : Host interrupt status */
#define HOST_INTSTATUS_REG 0x03
/* Host Control Registers : Upload host interrupt status */
#define UP_LD_HOST_INT_STATUS (0x1U)
/* Host Control Registers : Download host interrupt status */
#define DN_LD_HOST_INT_STATUS (0x2U)
/* Host Control Registers : Host interrupt RSR */
#define HOST_INT_RSR_REG 0x01
/* Host Control Registers : Upload host interrupt RSR */
#define UP_LD_HOST_INT_RSR (0x1U)
#define SDIO_INT_MASK 0x3F
/* Host Control Registers : Host interrupt status */
#define HOST_INT_STATUS_REG 0x28
/* Host Control Registers : Upload CRC error */
#define UP_LD_CRC_ERR (0x1U << 2)
/* Host Control Registers : Upload restart */
#define UP_LD_RESTART (0x1U << 1)
/* Host Control Registers : Download restart */
#define DN_LD_RESTART (0x1U << 0)
/* Card Control Registers : Card status register */
#define CARD_STATUS_REG 0x30
/* Card Control Registers : Card I/O ready */
#define CARD_IO_READY (0x1U << 3)
/* Card Control Registers : CIS card ready */
#define CIS_CARD_RDY (0x1U << 2)
/* Card Control Registers : Upload card ready */
#define UP_LD_CARD_RDY (0x1U << 1)
/* Card Control Registers : Download card ready */
#define DN_LD_CARD_RDY (0x1U << 0)
/* Card Control Registers : Host interrupt mask register */
#define HOST_INTERRUPT_MASK_REG 0x34
/* Card Control Registers : Host power interrupt mask */
#define HOST_POWER_INT_MASK (0x1U << 3)
/* Card Control Registers : Abort card interrupt mask */
#define ABORT_CARD_INT_MASK (0x1U << 2)
/* Card Control Registers : Upload card interrupt mask */
#define UP_LD_CARD_INT_MASK (0x1U << 1)
/* Card Control Registers : Download card interrupt mask */
#define DN_LD_CARD_INT_MASK (0x1U << 0)
/* Card Control Registers : Card interrupt status register */
#define CARD_INTERRUPT_STATUS_REG 0x38
/* Card Control Registers : Power up interrupt */
#define POWER_UP_INT (0x1U << 4)
/* Card Control Registers : Power down interrupt */
#define POWER_DOWN_INT (0x1U << 3)
/* Card Control Registers : Card interrupt RSR register */
#define CARD_INTERRUPT_RSR_REG 0x3c
/* Card Control Registers : Power up RSR */
#define POWER_UP_RSR (0x1U << 4)
/* Card Control Registers : Power down RSR */
#define POWER_DOWN_RSR (0x1U << 3)
/* Card Control Registers : Miscellaneous Configuration Register */
#define CARD_MISC_CFG_REG 0x6C
/* Host F1 read base 0 */
#define HOST_F1_RD_BASE_0 0x0040
/* Host F1 read base 1 */
#define HOST_F1_RD_BASE_1 0x0041
/* Host F1 card ready */
#define HOST_F1_CARD_RDY 0x0020
/* Firmware status 0 register */
#define CARD_FW_STATUS0_REG 0x60
/* Firmware status 1 register */
#define CARD_FW_STATUS1_REG 0x61
/* Rx length register */
#define CARD_RX_LEN_REG 0x62
/* Rx unit register */
#define CARD_RX_UNIT_REG 0x63
/* Event header Len*/
#define MWIFIEX_EVENT_HEADER_LEN 8
/* Max retry number of CMD53 write */
#define MAX_WRITE_IOMEM_RETRY 2
/* SDIO Tx aggregation in progress ? */
#define MP_TX_AGGR_IN_PROGRESS(a) (a->mpa_tx.pkt_cnt > 0)
/* SDIO Tx aggregation buffer room for next packet ? */
#define MP_TX_AGGR_BUF_HAS_ROOM(a, len) ((a->mpa_tx.buf_len+len) \
<= a->mpa_tx.buf_size)
/* Copy current packet (SDIO Tx aggregation buffer) to SDIO buffer */
#define MP_TX_AGGR_BUF_PUT(a, payload, pkt_len, port) do { \
memmove(&a->mpa_tx.buf[a->mpa_tx.buf_len], \
payload, pkt_len); \
a->mpa_tx.buf_len += pkt_len; \
if (!a->mpa_tx.pkt_cnt) \
a->mpa_tx.start_port = port; \
if (a->mpa_tx.start_port <= port) \
a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt)); \
else \
a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt+1+(MAX_PORT - \
a->mp_end_port))); \
a->mpa_tx.pkt_cnt++; \
} while (0);
/* SDIO Tx aggregation limit ? */
#define MP_TX_AGGR_PKT_LIMIT_REACHED(a) \
(a->mpa_tx.pkt_cnt == a->mpa_tx.pkt_aggr_limit)
/* SDIO Tx aggregation port limit ? */
#define MP_TX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_wr_port < \
a->mpa_tx.start_port) && (((MAX_PORT - \
a->mpa_tx.start_port) + a->curr_wr_port) >= \
SDIO_MP_AGGR_DEF_PKT_LIMIT))
/* Reset SDIO Tx aggregation buffer parameters */
#define MP_TX_AGGR_BUF_RESET(a) do { \
a->mpa_tx.pkt_cnt = 0; \
a->mpa_tx.buf_len = 0; \
a->mpa_tx.ports = 0; \
a->mpa_tx.start_port = 0; \
} while (0);
/* SDIO Rx aggregation limit ? */
#define MP_RX_AGGR_PKT_LIMIT_REACHED(a) \
(a->mpa_rx.pkt_cnt == a->mpa_rx.pkt_aggr_limit)
/* SDIO Tx aggregation port limit ? */
#define MP_RX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_rd_port < \
a->mpa_rx.start_port) && (((MAX_PORT - \
a->mpa_rx.start_port) + a->curr_rd_port) >= \
SDIO_MP_AGGR_DEF_PKT_LIMIT))
/* SDIO Rx aggregation in progress ? */
#define MP_RX_AGGR_IN_PROGRESS(a) (a->mpa_rx.pkt_cnt > 0)
/* SDIO Rx aggregation buffer room for next packet ? */
#define MP_RX_AGGR_BUF_HAS_ROOM(a, rx_len) \
((a->mpa_rx.buf_len+rx_len) <= a->mpa_rx.buf_size)
/* Prepare to copy current packet from card to SDIO Rx aggregation buffer */
#define MP_RX_AGGR_SETUP(a, skb, port) do { \
a->mpa_rx.buf_len += skb->len; \
if (!a->mpa_rx.pkt_cnt) \
a->mpa_rx.start_port = port; \
if (a->mpa_rx.start_port <= port) \
a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt)); \
else \
a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt+1)); \
a->mpa_rx.skb_arr[a->mpa_rx.pkt_cnt] = skb; \
a->mpa_rx.len_arr[a->mpa_rx.pkt_cnt] = skb->len; \
a->mpa_rx.pkt_cnt++; \
} while (0);
/* Reset SDIO Rx aggregation buffer parameters */
#define MP_RX_AGGR_BUF_RESET(a) do { \
a->mpa_rx.pkt_cnt = 0; \
a->mpa_rx.buf_len = 0; \
a->mpa_rx.ports = 0; \
a->mpa_rx.start_port = 0; \
} while (0);
/* data structure for SDIO MPA TX */
struct mwifiex_sdio_mpa_tx {
/* multiport tx aggregation buffer pointer */
u8 *buf;
u32 buf_len;
u32 pkt_cnt;
u16 ports;
u16 start_port;
u8 enabled;
u32 buf_size;
u32 pkt_aggr_limit;
};
struct mwifiex_sdio_mpa_rx {
u8 *buf;
u32 buf_len;
u32 pkt_cnt;
u16 ports;
u16 start_port;
struct sk_buff *skb_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT];
u32 len_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT];
u8 enabled;
u32 buf_size;
u32 pkt_aggr_limit;
};
int mwifiex_bus_register(void);
void mwifiex_bus_unregister(void);
struct sdio_mmc_card {
struct sdio_func *func;
struct mwifiex_adapter *adapter;
u16 mp_rd_bitmap;
u16 mp_wr_bitmap;
u16 mp_end_port;
u16 mp_data_port_mask;
u8 curr_rd_port;
u8 curr_wr_port;
u8 *mp_regs;
struct mwifiex_sdio_mpa_tx mpa_tx;
struct mwifiex_sdio_mpa_rx mpa_rx;
};
#endif /* _MWIFIEX_SDIO_H */
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
* Marvell Wireless LAN device driver: utility functions
*
* Copyright (C) 2011, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*/
#ifndef _MWIFIEX_UTIL_H_
#define _MWIFIEX_UTIL_H_
static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb)
{
return (struct mwifiex_rxinfo *)skb->cb;
}
static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb)
{
return (struct mwifiex_txinfo *)skb->cb;
}
#endif /* !_MWIFIEX_UTIL_H_ */
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册