mwifiex: add SDIO rx single port aggregation
[deliverable/linux.git] / drivers / net / wireless / mwifiex / sdio.c
index 91e36cda9543e4cd20e1755572f8a31a24774b88..fdeeb67f790ac4c42f4bac793aef65d0075a9737 100644 (file)
@@ -105,8 +105,8 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
                card->tx_buf_size = data->tx_buf_size;
                card->mp_tx_agg_buf_size = data->mp_tx_agg_buf_size;
                card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size;
-               card->supports_fw_dump = data->supports_fw_dump;
-               card->auto_tdls = data->auto_tdls;
+               card->can_dump_fw = data->can_dump_fw;
+               card->can_auto_tdls = data->can_auto_tdls;
                card->can_ext_scan = data->can_ext_scan;
        }
 
@@ -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;
 
-       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) {
@@ -1133,6 +1203,7 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
        s32 f_do_rx_aggr = 0;
        s32 f_do_rx_cur = 0;
        s32 f_aggr_cur = 0;
+       s32 f_post_aggr_cur = 0;
        struct sk_buff *skb_deaggr;
        u32 pind;
        u32 pkt_len, pkt_type, mport;
@@ -1169,7 +1240,7 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
                        } else {
                                /* No room in Aggr buf, do rx aggr now */
                                f_do_rx_aggr = 1;
-                               f_do_rx_cur = 1;
+                               f_post_aggr_cur = 1;
                        }
                } else {
                        /* Rx aggr not in progress */
@@ -1246,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);
 
@@ -1257,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:"
-                                       " 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);
@@ -1277,12 +1352,23 @@ rx_curr_single:
                                              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);
        }
+       if (f_post_aggr_cur) {
+               dev_dbg(adapter->dev, "info: current packet aggregation\n");
+               /* Curr pkt can be aggregated */
+               mp_rx_aggr_setup(card, skb, port);
+       }
 
        return 0;
-
 error:
        if (MP_RX_AGGR_IN_PROGRESS(card)) {
                /* Multiport-aggregation transfer failed - cleanup */
@@ -1357,7 +1443,7 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
                        return -1;
                rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE);
 
-               skb = dev_alloc_skb(rx_len);
+               skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL | GFP_DMA);
                if (!skb)
                        return -1;
 
@@ -1447,14 +1533,16 @@ 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;
                        }
                        rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE);
 
-                       skb = dev_alloc_skb(rx_len);
+                       skb = mwifiex_alloc_dma_align_buf(rx_len,
+                                                         GFP_KERNEL |
+                                                         GFP_DMA);
 
                        if (!skb) {
                                dev_err(adapter->dev, "%s: failed to alloc skb",
@@ -1735,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);
@@ -1745,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) {
@@ -1887,7 +1978,7 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
                return -1;
        }
 
-       adapter->auto_tdls = card->auto_tdls;
+       adapter->auto_tdls = card->can_auto_tdls;
        adapter->ext_scan = card->can_ext_scan;
        return ret;
 }
@@ -2032,7 +2123,7 @@ static void mwifiex_sdio_fw_dump_work(struct work_struct *work)
 
        mwifiex_dump_drv_info(adapter);
 
-       if (!card->supports_fw_dump)
+       if (!card->can_dump_fw)
                return;
 
        for (idx = 0; idx < ARRAY_SIZE(mem_type_mapping_tbl); idx++) {
@@ -2291,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,
 };
 
 /*
This page took 0.026677 seconds and 5 git commands to generate.