blob: 16bcb50ae64eed9750372ffb1108d0bdda894e71 [file] [log] [blame]
/**
******************************************************************************
*
* @file rwnx_tx.h
*
* Copyright (C) RivieraWaves 2012-2019
*
******************************************************************************
*/
#ifndef _RWNX_TX_H_
#define _RWNX_TX_H_
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
#include <linux/netdevice.h>
#include "lmac_types.h"
#include "ipc_shared.h"
#include "rwnx_txq.h"
#include "hal_desc.h"
#include "rwnx_utils.h"
#define RWNX_HWQ_BK 0
#define RWNX_HWQ_BE 1
#define RWNX_HWQ_VI 2
#define RWNX_HWQ_VO 3
#define RWNX_HWQ_BCMC 4
#define RWNX_HWQ_NB NX_TXQ_CNT
#define RWNX_HWQ_ALL_ACS (RWNX_HWQ_BK | RWNX_HWQ_BE | RWNX_HWQ_VI | RWNX_HWQ_VO)
#define RWNX_HWQ_ALL_ACS_BIT (BIT(RWNX_HWQ_BK) | BIT(RWNX_HWQ_BE) | \
BIT(RWNX_HWQ_VI) | BIT(RWNX_HWQ_VO))
#define RWNX_TX_LIFETIME_MS 1000
#define RWNX_TX_MAX_RATES NX_TX_MAX_RATES
#define RWNX_SWTXHDR_ALIGN_SZ 4
#define RWNX_SWTXHDR_ALIGN_MSK (RWNX_SWTXHDR_ALIGN_SZ - 1)
#define RWNX_SWTXHDR_ALIGN_PADS(x) \
((RWNX_SWTXHDR_ALIGN_SZ - ((x) & RWNX_SWTXHDR_ALIGN_MSK)) \
& RWNX_SWTXHDR_ALIGN_MSK)
#if RWNX_SWTXHDR_ALIGN_SZ & RWNX_SWTXHDR_ALIGN_MSK
#error bad RWNX_SWTXHDR_ALIGN_SZ
#endif
#define AMSDU_PADDING(x) ((4 - ((x) & 0x3)) & 0x3)
#define TXU_CNTRL_RETRY BIT(0)
#define TXU_CNTRL_MORE_DATA BIT(2)
#define TXU_CNTRL_MGMT BIT(3)
#define TXU_CNTRL_MGMT_NO_CCK BIT(4)
#define TXU_CNTRL_AMSDU BIT(6)
#define TXU_CNTRL_MGMT_ROBUST BIT(7)
#define TXU_CNTRL_USE_4ADDR BIT(8)
#define TXU_CNTRL_EOSP BIT(9)
#define TXU_CNTRL_MESH_FWD BIT(10)
#define TXU_CNTRL_TDLS BIT(11)
#define TXU_CNTRL_REUSE_SN BIT(15)
extern const int rwnx_tid2hwq[IEEE80211_NUM_TIDS];
/**
* struct rwnx_amsdu_txhdr - Structure added in skb headroom (instead of
* rwnx_txhdr) for amsdu subframe buffer (except for the first subframe
* that has a normal rwnx_txhdr)
*
* @list List of other amsdu subframe (rwnx_sw_txhdr.amsdu.hdrs)
* @ipc_data: IPC buffer for the A-MSDU subframe
* @skb skb
* @pad padding added before this subframe
* (only use when amsdu must be dismantled)
* @msdu_len Size, in bytes, of the MSDU (without padding nor amsdu header)
*/
struct rwnx_amsdu_txhdr {
struct list_head list;
struct rwnx_ipc_buf ipc_data;
struct sk_buff *skb;
u16 pad;
u16 msdu_len;
};
/**
* struct rwnx_amsdu - Structure to manage creation of an A-MSDU, updated
* only In the first subframe of an A-MSDU
*
* @hdrs List of subframe of rwnx_amsdu_txhdr
* @len Current size for this A-MDSU (doesn't take padding into account)
* 0 means that no amsdu is in progress
* @nb Number of subframe in the amsdu
* @pad Padding to add before adding a new subframe
*/
struct rwnx_amsdu {
struct list_head hdrs;
u16 len;
u8 nb;
u8 pad;
};
/**
* struct rwnx_sw_txhdr - Software part of tx header
*
* @rwnx_sta: sta to which this buffer is addressed
* @rwnx_vif: vif that send the buffer
* @txq: pointer to TXQ used to send the buffer
* @hw_queue: Index of the HWQ used to push the buffer.
* May be different than txq->hwq->id on confirmation.
* @frame_len: Size of the frame (doesn't not include mac header)
* (Only used to update stat, can't we use skb->len instead ?)
* @amsdu: Description of amsdu whose first subframe is this buffer
* (amsdu.nb = 0 means this buffer is not part of amsdu)
* @skb: skb received from transmission
* @ipc_data: IPC buffer for the frame
* @ipc_desc: IPC buffer for the TX descriptor
* @jiffies: Jiffies when this buffer has been pushed to the driver
* @desc: TX descriptor downloaded by firmware
*/
struct rwnx_sw_txhdr {
struct rwnx_sta *rwnx_sta;
struct rwnx_vif *rwnx_vif;
struct rwnx_txq *txq;
u8 hw_queue;
u16 frame_len;
u16 headroom;
#ifdef CONFIG_RWNX_AMSDUS_TX
struct rwnx_amsdu amsdu;
#endif
#ifndef AICWF_PCIE_SUPPORT
u32 need_cfm;
#else
u16 need_cfm;
u16 cfmd;
u16 idx;
#endif
struct sk_buff *skb;
struct rwnx_ipc_buf ipc_data;
struct rwnx_ipc_buf ipc_desc;
struct rwnx_ipc_buf ipc_hostdesc;
unsigned long jiffies;
struct txdesc_host desc;
u8 raw_frame;
u8 fixed_rate;
u16 rate_config;
};
/**
* struct rwnx_txhdr - Structure to control transmission of packet
* (Added in skb headroom)
*
* @sw_hdr: Information from driver
* @cache_guard:
* @hw_hdr: Information for/from hardware
*/
struct rwnx_txhdr {
struct rwnx_sw_txhdr *sw_hdr;
char cache_guard[L1_CACHE_BYTES];
struct rwnx_hw_txhdr hw_hdr;
};
/**
* RWNX_TX_HEADROOM - Headroom to use to store struct rwnx_txhdr
*/
#define RWNX_TX_HEADROOM sizeof(struct rwnx_txhdr)
/**
* RWNX_TX_AMSDU_HEADROOM - Maximum headroom need for an A-MSDU sub frame
* Need to store struct rwnx_amsdu_txhdr, A-MSDU header (14)
* optional padding (4) and LLC/SNAP header (8)
*/
#define RWNX_TX_AMSDU_HEADROOM (sizeof(struct rwnx_amsdu_txhdr) + 14 + 4 + 8)
/**
* RWNX_TX_MAX_HEADROOM - Maximum size needed in skb headroom to prepare a buffer
* for transmission
*/
#define RWNX_TX_MAX_HEADROOM max(RWNX_TX_HEADROOM, RWNX_TX_AMSDU_HEADROOM)
/**
* RWNX_TX_DMA_MAP_LEN - Length, in bytes, to map for DMA transfer
* To be called with skb BEFORE reserving headroom to store struct rwnx_txhdr.
*/
#define RWNX_TX_DMA_MAP_LEN(skb) (skb->len - sizeof(struct ethhdr))
/**
* SKB buffer format before it is pushed to MACSW
*
* For DATA frame
* |--------------------|
* | headroom |
* skb->data ----> |--------------------|
* | struct rwnx_txhdr |
* | * rwnx_sw_txhdr * |
* | * [L1 guard] |
* |--------------------|
* | 802.3 Header |
* +--> |--------------------| <---- desc.host.packet_addr[0]
* memory : | Data |
* mapped : | |
* for DMA : | |
* : | |
* +--> |--------------------|
* | tailroom |
* |--------------------|
*
*
* For MGMT frame (skb is created by the driver so buffer is always aligned
* with no headroom/tailroom)
*
* skb->data ----> |--------------------|
* | struct rwnx_txhdr |
* | * rwnx_sw_txhdr * |
* | * [L1 guard] |
* | |
* +--> |--------------------| <---- desc.host.packet_addr[0]
* memory : | 802.11 HDR |
* mapped : |--------------------|
* for DMA : | Data |
* : | |
* +--> |--------------------|
*
*/
u16 rwnx_select_txq(struct rwnx_vif *rwnx_vif, struct sk_buff *skb);
netdev_tx_t rwnx_start_xmit(struct sk_buff *skb, struct net_device *dev);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta,
struct cfg80211_mgmt_tx_params *params, bool offchan,
u64 *cookie);
#else
int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta,
struct ieee80211_channel *channel, bool offchan,
unsigned int wait, const u8 *buf, size_t len,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
bool no_cck,
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
bool dont_wait_for_ack,
#endif
u64 *cookie);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
int rwnx_txdatacfm(void *pthis, void *host_id,u8 free);
struct rwnx_hw;
struct rwnx_sta;
void rwnx_set_traffic_status(struct rwnx_hw *rwnx_hw,
struct rwnx_sta *sta,
bool available,
u8 ps_id);
void rwnx_ps_bh_enable(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
bool enable);
void rwnx_ps_bh_traffic_req(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
u16 pkt_req, u8 ps_id);
void rwnx_switch_vif_sta_txq(struct rwnx_sta *sta, struct rwnx_vif *old_vif,
struct rwnx_vif *new_vif);
int rwnx_dbgfs_print_sta(char *buf, size_t size, struct rwnx_sta *sta,
struct rwnx_hw *rwnx_hw);
void rwnx_txq_credit_update(struct rwnx_hw *rwnx_hw, int sta_idx, u8 tid,
s8 update);
void rwnx_tx_push(struct rwnx_hw *rwnx_hw, struct rwnx_txhdr *txhdr, int flags);
#endif /* _RWNX_TX_H_ */