Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 92263a84 authored by Zhaoyang Liu's avatar Zhaoyang Liu Committed by Kalle Valo
Browse files

mwifiex: add SDIO rx single port aggregation



This patch brings in support for SDIO single port rx aggregation
to mwifiex.
Maximum read size support by SDIO cmd53 is 64K.
Based on multi port aggregation which is already part of mwifiex, idea here
is multiple packets received in FW can be aggregated into single buffer.
A separate upload type is defined for such packet aggregated to single port.
Packets from this single buffer are later deaggregated into individual packets.
This way, driver can receive more packets each time through single SDIO cmd53;
thereby reducing no of times MMC bus is accessed.

SDIO SP aggregation support is advertised by FW during load time and driver
would get FW block size in command response of HostCmd_CMD_SDIO_SP_RX_AGGR_CFG.

Signed-off-by: default avatarZhaoyang Liu <liuzy@marvell.com>
Signed-off-by: default avatarMarc Yang <yangyang@marvell.com>
Reviewed-by: default avatarAmitkumar Karwar <akarwar@marvell.com>
Reviewed-by: default avatarCathy Luo <cluo@marvell.com>
Reviewed-by: default avatarAvinash Patil <patila@marvell.com>
Signed-off-by: default avatarAvinash Patil <patila@marvell.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent e35000ea
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -112,6 +112,11 @@

#define MWIFIEX_A_BAND_START_FREQ	5000

/* SDIO Aggr data packet special info */
#define SDIO_MAX_AGGR_BUF_SIZE		(256 * 255)
#define BLOCK_NUMBER_OFFSET		15
#define SDIO_HEADER_OFFSET		28

enum mwifiex_bss_type {
	MWIFIEX_BSS_TYPE_STA = 0,
	MWIFIEX_BSS_TYPE_UAP = 1,
@@ -169,10 +174,11 @@ struct mwifiex_wait_queue {
};

struct mwifiex_rxinfo {
	struct sk_buff *parent;
	u8 bss_num;
	u8 bss_type;
	struct sk_buff *parent;
	u8 use_count;
	u8 buf_type;
};

struct mwifiex_txinfo {
+9 −0
Original line number Diff line number Diff line
@@ -197,6 +197,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {

#define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11))
#define ISSUPP_TDLS_ENABLED(FwCapInfo) (FwCapInfo & BIT(14))
#define ISSUPP_SDIO_SPA_ENABLED(FwCapInfo) (FwCapInfo & BIT(16))

#define MWIFIEX_DEF_HT_CAP	(IEEE80211_HT_CAP_DSSSCCK40 | \
				 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) | \
@@ -353,6 +354,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_REMAIN_ON_CHAN                    0x010d
#define HostCmd_CMD_11AC_CFG			      0x0112
#define HostCmd_CMD_TDLS_OPER                         0x0122
#define HostCmd_CMD_SDIO_SP_RX_AGGR_CFG               0x0223

#define PROTOCOL_NO_SECURITY        0x01
#define PROTOCOL_STATIC_WEP         0x02
@@ -1242,6 +1244,12 @@ struct host_cmd_ds_chan_rpt_event {
	u8 tlvbuf[0];
} __packed;

struct host_cmd_sdio_sp_rx_aggr_cfg {
	u8 action;
	u8 enable;
	__le16 block_size;
} __packed;

struct mwifiex_fixed_bcn_param {
	__le64 timestamp;
	__le16 beacon_period;
@@ -1964,6 +1972,7 @@ struct host_cmd_ds_command {
		struct host_cmd_ds_coalesce_cfg coalesce_cfg;
		struct host_cmd_ds_tdls_oper tdls_oper;
		struct host_cmd_ds_chan_rpt_req chan_rpt_req;
		struct host_cmd_sdio_sp_rx_aggr_cfg sdio_rx_aggr_cfg;
	} params;
} __packed;

+9 −1
Original line number Diff line number Diff line
@@ -163,6 +163,7 @@ static int mwifiex_process_rx(struct mwifiex_adapter *adapter)
{
	unsigned long flags;
	struct sk_buff *skb;
	struct mwifiex_rxinfo *rx_info;

	spin_lock_irqsave(&adapter->rx_proc_lock, flags);
	if (adapter->rx_processing || adapter->rx_locked) {
@@ -184,8 +185,15 @@ static int mwifiex_process_rx(struct mwifiex_adapter *adapter)
			adapter->delay_main_work = false;
			mwifiex_queue_main_work(adapter);
		}
		rx_info = MWIFIEX_SKB_RXCB(skb);
		if (rx_info->buf_type == MWIFIEX_TYPE_AGGR_DATA) {
			if (adapter->if_ops.deaggr_pkt)
				adapter->if_ops.deaggr_pkt(adapter, skb);
			dev_kfree_skb_any(skb);
		} else {
			mwifiex_handle_rx_packet(adapter, skb);
		}
	}
	spin_lock_irqsave(&adapter->rx_proc_lock, flags);
	adapter->rx_processing = false;
	spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
+4 −0
Original line number Diff line number Diff line
@@ -121,6 +121,7 @@ enum {

#define MWIFIEX_TYPE_CMD				1
#define MWIFIEX_TYPE_DATA				0
#define MWIFIEX_TYPE_AGGR_DATA				10
#define MWIFIEX_TYPE_EVENT				3

#define MAX_BITMAP_RATES_SIZE			18
@@ -744,6 +745,7 @@ struct mwifiex_if_ops {
	int (*clean_pcie_ring) (struct mwifiex_adapter *adapter);
	void (*iface_work)(struct work_struct *work);
	void (*submit_rem_rx_urbs)(struct mwifiex_adapter *adapter);
	void (*deaggr_pkt)(struct mwifiex_adapter *, struct sk_buff *);
};

struct mwifiex_adapter {
@@ -787,6 +789,8 @@ struct mwifiex_adapter {
	u8 more_task_flag;
	u16 tx_buf_size;
	u16 curr_tx_buf_size;
	bool sdio_rx_aggr_enable;
	u16 sdio_rx_block_size;
	u32 ioport;
	enum MWIFIEX_HARDWARE_STATUS hw_status;
	u16 number_of_antenna;
+94 −9
Original line number Diff line number Diff line
@@ -1042,6 +1042,59 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
	return ret;
}

/*
 * This function decode sdio aggreation pkt.
 *
 * Based on the the data block size and pkt_len,
 * skb data will be decoded to few packets.
 */
static void mwifiex_deaggr_sdio_pkt(struct mwifiex_adapter *adapter,
				    struct sk_buff *skb)
{
	u32 total_pkt_len, pkt_len;
	struct sk_buff *skb_deaggr;
	u32 pkt_type;
	u16 blk_size;
	u8 blk_num;
	u8 *data;

	data = skb->data;
	total_pkt_len = skb->len;

	while (total_pkt_len >= (SDIO_HEADER_OFFSET + INTF_HEADER_LEN)) {
		if (total_pkt_len < adapter->sdio_rx_block_size)
			break;
		blk_num = *(data + BLOCK_NUMBER_OFFSET);
		blk_size = adapter->sdio_rx_block_size * blk_num;
		if (blk_size > total_pkt_len) {
			dev_err(adapter->dev, "%s: error in pkt,\t"
				"blk_num=%d, blk_size=%d, total_pkt_len=%d\n",
				__func__, blk_num, blk_size, total_pkt_len);
			break;
		}
		pkt_len = le16_to_cpu(*(__le16 *)(data + SDIO_HEADER_OFFSET));
		pkt_type = le16_to_cpu(*(__le16 *)(data + SDIO_HEADER_OFFSET +
					 2));
		if ((pkt_len + SDIO_HEADER_OFFSET) > blk_size) {
			dev_err(adapter->dev, "%s: error in pkt,\t"
				"pkt_len=%d, blk_size=%d\n",
				__func__, pkt_len, blk_size);
			break;
		}
		skb_deaggr = mwifiex_alloc_dma_align_buf(pkt_len,
							 GFP_KERNEL | GFP_DMA);
		if (!skb_deaggr)
			break;
		skb_put(skb_deaggr, pkt_len);
		memcpy(skb_deaggr->data, data + SDIO_HEADER_OFFSET, pkt_len);
		skb_pull(skb_deaggr, INTF_HEADER_LEN);

		mwifiex_handle_rx_packet(adapter, skb_deaggr);
		data += blk_size;
		total_pkt_len -= blk_size;
	}
}

/*
 * This function decodes a received packet.
 *
@@ -1055,11 +1108,28 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
	u8 *cmd_buf;
	__le16 *curr_ptr = (__le16 *)skb->data;
	u16 pkt_len = le16_to_cpu(*curr_ptr);
	struct mwifiex_rxinfo *rx_info;

	if (upld_typ != MWIFIEX_TYPE_AGGR_DATA) {
		skb_trim(skb, pkt_len);
		skb_pull(skb, INTF_HEADER_LEN);
	}

	switch (upld_typ) {
	case MWIFIEX_TYPE_AGGR_DATA:
		dev_dbg(adapter->dev, "info: --- Rx: Aggr Data packet ---\n");
		rx_info = MWIFIEX_SKB_RXCB(skb);
		rx_info->buf_type = MWIFIEX_TYPE_AGGR_DATA;
		if (adapter->rx_work_enabled) {
			skb_queue_tail(&adapter->rx_data_q, skb);
			atomic_inc(&adapter->rx_pending);
			adapter->data_received = true;
		} else {
			mwifiex_deaggr_sdio_pkt(adapter, skb);
			dev_kfree_skb_any(skb);
		}
		break;

	case MWIFIEX_TYPE_DATA:
		dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n");
		if (adapter->rx_work_enabled) {
@@ -1247,8 +1317,10 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
			/* copy pkt to deaggr buf */
			skb_deaggr = card->mpa_rx.skb_arr[pind];

			if ((pkt_type == MWIFIEX_TYPE_DATA) && (pkt_len <=
					 card->mpa_rx.len_arr[pind])) {
			if ((pkt_type == MWIFIEX_TYPE_DATA ||
			     (pkt_type == MWIFIEX_TYPE_AGGR_DATA &&
			      adapter->sdio_rx_aggr_enable)) &&
			    (pkt_len <= card->mpa_rx.len_arr[pind])) {

				memcpy(skb_deaggr->data, curr_ptr, pkt_len);

@@ -1258,8 +1330,10 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
				mwifiex_decode_rx_packet(adapter, skb_deaggr,
							 pkt_type);
			} else {
				dev_err(adapter->dev, "wrong aggr pkt:"
				dev_err(adapter->dev, "wrong aggr pkt:\t"
					"sdio_single_port_rx_aggr=%d\t"
					"type=%d len=%d max_len=%d\n",
					adapter->sdio_rx_aggr_enable,
					pkt_type, pkt_len,
					card->mpa_rx.len_arr[pind]);
				dev_kfree_skb_any(skb_deaggr);
@@ -1278,6 +1352,13 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
					      skb->data, skb->len,
					      adapter->ioport + port))
			goto error;
		if (!adapter->sdio_rx_aggr_enable &&
		    pkt_type == MWIFIEX_TYPE_AGGR_DATA) {
			dev_err(adapter->dev, "Wrong pkt type %d\t"
				"Current SDIO RX Aggr not enabled\n",
				pkt_type);
			goto error;
		}

		mwifiex_decode_rx_packet(adapter, skb, pkt_type);
	}
@@ -1452,7 +1533,7 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
				 1) / MWIFIEX_SDIO_BLOCK_SIZE;
			if (rx_len <= INTF_HEADER_LEN ||
			    (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) >
			     MWIFIEX_RX_DATA_BUF_SIZE) {
			     card->mpa_rx.buf_size) {
				dev_err(adapter->dev, "invalid rx_len=%d\n",
					rx_len);
				return -1;
@@ -1742,6 +1823,7 @@ static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter,
				   u32 mpa_tx_buf_size, u32 mpa_rx_buf_size)
{
	struct sdio_mmc_card *card = adapter->card;
	u32 rx_buf_size;
	int ret = 0;

	card->mpa_tx.buf = kzalloc(mpa_tx_buf_size, GFP_KERNEL);
@@ -1752,13 +1834,15 @@ static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter,

	card->mpa_tx.buf_size = mpa_tx_buf_size;

	card->mpa_rx.buf = kzalloc(mpa_rx_buf_size, GFP_KERNEL);
	rx_buf_size = max_t(u32, mpa_rx_buf_size,
			    (u32)SDIO_MAX_AGGR_BUF_SIZE);
	card->mpa_rx.buf = kzalloc(rx_buf_size, GFP_KERNEL);
	if (!card->mpa_rx.buf) {
		ret = -1;
		goto error;
	}

	card->mpa_rx.buf_size = mpa_rx_buf_size;
	card->mpa_rx.buf_size = rx_buf_size;

error:
	if (ret) {
@@ -2298,6 +2382,7 @@ static struct mwifiex_if_ops sdio_ops = {
	.iface_work = mwifiex_sdio_work,
	.fw_dump = mwifiex_sdio_fw_dump,
	.reg_dump = mwifiex_sdio_reg_dump,
	.deaggr_pkt = mwifiex_deaggr_sdio_pkt,
};

/*
Loading