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.
*
u8 *cmd_buf;
__le16 *curr_ptr = (__le16 *)skb->data;
u16 pkt_len = le16_to_cpu(*curr_ptr);
+ struct mwifiex_rxinfo *rx_info;
- skb_trim(skb, pkt_len);
- skb_pull(skb, INTF_HEADER_LEN);
+ 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) {
/* 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);
mwifiex_decode_rx_packet(adapter, skb_deaggr,
pkt_type);
} else {
- dev_err(adapter->dev, "wrong aggr pkt:"
- " type=%d len=%d max_len=%d\n",
+ 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);
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);
}
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;
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);
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) {
.iface_work = mwifiex_sdio_work,
.fw_dump = mwifiex_sdio_fw_dump,
.reg_dump = mwifiex_sdio_reg_dump,
+ .deaggr_pkt = mwifiex_deaggr_sdio_pkt,
};
/*
return 0;
}
+
+/* This function prepares command of sdio rx aggr info. */
+static int mwifiex_cmd_sdio_rx_aggr_cfg(struct host_cmd_ds_command *cmd,
+ u16 cmd_action, void *data_buf)
+{
+ struct host_cmd_sdio_sp_rx_aggr_cfg *cfg =
+ &cmd->params.sdio_rx_aggr_cfg;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_SDIO_SP_RX_AGGR_CFG);
+ cmd->size =
+ cpu_to_le16(sizeof(struct host_cmd_sdio_sp_rx_aggr_cfg) +
+ S_DS_GEN);
+ cfg->action = cmd_action;
+ if (cmd_action == HostCmd_ACT_GEN_SET)
+ cfg->enable = *(u8 *)data_buf;
+
+ return 0;
+}
+
/*
* This function prepares the commands before sending them to the firmware.
*
ret = mwifiex_cmd_issue_chan_report_request(priv, cmd_ptr,
data_buf);
break;
+ case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG:
+ ret = mwifiex_cmd_sdio_rx_aggr_cfg(cmd_ptr, cmd_action,
+ data_buf);
+ break;
default:
dev_err(priv->adapter->dev,
"PREP_CMD: unknown cmd- %#x\n", cmd_no);
struct mwifiex_ds_auto_ds auto_ds;
enum state_11d_t state_11d;
struct mwifiex_ds_11n_tx_cfg tx_cfg;
+ u8 sdio_sp_rx_aggr_enable;
if (first_sta) {
if (priv->adapter->iface_type == MWIFIEX_PCIE) {
if (ret)
return -1;
+ /** Set SDIO Single Port RX Aggr Info */
+ if (priv->adapter->iface_type == MWIFIEX_SDIO &&
+ ISSUPP_SDIO_SPA_ENABLED(priv->adapter->fw_cap_info)) {
+ sdio_sp_rx_aggr_enable = true;
+ ret = mwifiex_send_cmd(priv,
+ HostCmd_CMD_SDIO_SP_RX_AGGR_CFG,
+ HostCmd_ACT_GEN_SET, 0,
+ &sdio_sp_rx_aggr_enable,
+ true);
+ if (ret) {
+ dev_err(priv->adapter->dev,
+ "error while enabling SP aggregation..disable it");
+ adapter->sdio_rx_aggr_enable = false;
+ }
+ }
+
/* Reconfigure tx buf size */
ret = mwifiex_send_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
HostCmd_ACT_GEN_SET, 0,