mwifiex: fix driver init failure under memory pressure
authorXinming Hu <huxm@marvell.com>
Fri, 18 Sep 2015 13:32:06 +0000 (06:32 -0700)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 29 Sep 2015 07:47:31 +0000 (10:47 +0300)
64k Tx and Rx buffers are allocated during driver initialization
for SDIO level data aggregations. When host is under memory
pressure situation, kzalloc() request for 64k may fail.

We will try allocating 32k buffers and disable our rx single port
aggreagation feature in this situation.

If the allocation still fails, we will disable our sdio multport
aggregation feature as well. In this way, we will transmit and
receive packets one by one, thus reduce the demand for big
memory.

Signed-off-by: Xinming Hu <huxm@marvell.com>
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/sdio.c
drivers/net/wireless/mwifiex/sta_cmd.c

index 966632147079fa670cfd5e4dded885ac6775030e..2c2004e991e0edb06c5e79dedfa9ed7ffb314695 100644 (file)
@@ -860,6 +860,8 @@ struct mwifiex_adapter {
        u8 more_task_flag;
        u16 tx_buf_size;
        u16 curr_tx_buf_size;
+       /* sdio single port rx aggregation capability */
+       bool host_disable_sdio_rx_aggr;
        bool sdio_rx_aggr_enable;
        u16 sdio_rx_block_size;
        u32 ioport;
index d35210caa94b3a97f3346f7fa91cf324c71abf86..78a8474e1a3dce80ae83c42cb5feb67e0ff65020 100644 (file)
@@ -2058,16 +2058,26 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
        ret = mwifiex_alloc_sdio_mpa_buffers(adapter,
                                             card->mp_tx_agg_buf_size,
                                             card->mp_rx_agg_buf_size);
-       if (ret) {
-               mwifiex_dbg(adapter, ERROR,
-                           "failed to alloc sdio mp-a buffers\n");
-               kfree(card->mp_regs);
-               return -1;
+
+       /* Allocate 32k MPA Tx/Rx buffers if 64k memory allocation fails */
+       if (ret && (card->mp_tx_agg_buf_size == MWIFIEX_MP_AGGR_BUF_SIZE_MAX ||
+                   card->mp_rx_agg_buf_size == MWIFIEX_MP_AGGR_BUF_SIZE_MAX)) {
+               /* Disable rx single port aggregation */
+               adapter->host_disable_sdio_rx_aggr = true;
+
+               ret = mwifiex_alloc_sdio_mpa_buffers
+                       (adapter, MWIFIEX_MP_AGGR_BUF_SIZE_32K,
+                        MWIFIEX_MP_AGGR_BUF_SIZE_32K);
+               if (ret) {
+                       /* Disable multi port aggregation */
+                       card->mpa_tx.enabled = 0;
+                       card->mpa_rx.enabled = 0;
+               }
        }
 
        adapter->auto_tdls = card->can_auto_tdls;
        adapter->ext_scan = card->can_ext_scan;
-       return ret;
+       return 0;
 }
 
 /*
index a49a80dd773edbf02fe99d433d9eddee48349c76..504b321301ec46ce99bc986fe8792011194fcef2 100644 (file)
@@ -2125,7 +2125,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)
 
                /** Set SDIO Single Port RX Aggr Info */
                if (priv->adapter->iface_type == MWIFIEX_SDIO &&
-                   ISSUPP_SDIO_SPA_ENABLED(priv->adapter->fw_cap_info)) {
+                   ISSUPP_SDIO_SPA_ENABLED(priv->adapter->fw_cap_info) &&
+                   !priv->adapter->host_disable_sdio_rx_aggr) {
                        sdio_sp_rx_aggr_enable = true;
                        ret = mwifiex_send_cmd(priv,
                                               HostCmd_CMD_SDIO_SP_RX_AGGR_CFG,