[RAMEN9610-13159][common][MODAP-20690][9610] wlbt: NAPI: do not use GRO path in BA...
authorDebabrata Purohit <d.purohit@samsung.com>
Mon, 11 Mar 2019 19:13:53 +0000 (19:13 +0000)
committerhskang <hs1218.kang@samsung.com>
Wed, 13 Mar 2019 13:00:01 +0000 (22:00 +0900)
When releasing frames from BA timer context, do not use
napi_gro_receive() as that can corrupt the kernel GRO lists.

Resolution:
Use non-NAPI path when releasing frames from BA timer context.

Change-Id: I9ac803e0a69d6eca3bb8c69e1be8bdfb152b4058
SCSC-Bug-Id: SSB-50448
Signed-off-by: Debabrata Purohit <d.purohit@samsung.com>
drivers/net/wireless/scsc/ba.c
drivers/net/wireless/scsc/ba.h
drivers/net/wireless/scsc/dev.h
drivers/net/wireless/scsc/sap_ma.c

index b268562ce354436039a31b410b2ae43a4f1dff0e..40bb616da6afc10849fce991b2fa20d198357c6a 100755 (executable)
@@ -92,14 +92,13 @@ static void slsi_rx_ba_free_buffer(struct net_device *dev, struct slsi_peer *pee
  * is called in the data workqueue context with the
  * netdev_vif mutex held.
  */
-void slsi_ba_process_complete(struct net_device *dev)
+void slsi_ba_process_complete(struct net_device *dev, bool from_ba_timer)
 {
        struct netdev_vif *ndev_vif = netdev_priv(dev);
        struct sk_buff    *skb;
 
-       while ((skb = slsi_skb_dequeue(&ndev_vif->ba_complete)) != NULL) {
-               slsi_rx_data_deliver_skb(ndev_vif->sdev, dev, skb);
-       }
+       while ((skb = slsi_skb_dequeue(&ndev_vif->ba_complete)) != NULL)
+               slsi_rx_data_deliver_skb(ndev_vif->sdev, dev, skb, from_ba_timer);
 }
 
 static void slsi_ba_signal_process_complete(struct net_device *dev)
@@ -320,7 +319,7 @@ static void slsi_ba_aging_timeout_handler(unsigned long data)
 #ifdef CONFIG_SCSC_WLAN_RX_NAPI
                conf_hip4_ver = scsc_wifi_get_hip_config_version(&sdev->hip4_inst.hip_control->init);
                if (conf_hip4_ver == 4)
-                       slsi_ba_process_complete(dev);
+                       slsi_ba_process_complete(dev, true);
                else
                        slsi_ba_signal_process_complete(dev);
 #else
index 0f977c3199a696b76b17b893f382d5b3db110b77..af442233ad7abd33d2301449572864556042793c 100755 (executable)
@@ -1,6 +1,6 @@
 /*****************************************************************************
  *
- * Copyright (c) 2012 - 2016 Samsung Electronics Co., Ltd. All rights reserved
+ * Copyright (c) 2012 - 2019 Samsung Electronics Co., Ltd. All rights reserved
  *
  ****************************************************************************/
 
@@ -16,7 +16,7 @@ void slsi_handle_blockack(struct net_device *dev, struct slsi_peer *peer,
 int slsi_ba_process_frame(struct net_device *dev, struct slsi_peer *peer,
                          struct sk_buff *skb, u16 sequence_number, u16 tid);
 
-void slsi_ba_process_complete(struct net_device *dev);
+void slsi_ba_process_complete(struct net_device *dev, bool from_ba_timer);
 
 bool slsi_ba_check(struct slsi_peer *peer, u16 tid);
 
index 186e6efc1e3326c98a74f734993c56dd79f58523..a73754f19a397f574f4ba8fde8f86eccb7ee031b 100755 (executable)
@@ -1135,7 +1135,7 @@ struct llc_snap_hdr {
        u16 snap_type;
 } __packed;
 
-void slsi_rx_data_deliver_skb(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb);
+void slsi_rx_data_deliver_skb(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb, bool from_ba_timer);
 void slsi_rx_dbg_sap_work(struct work_struct *work);
 void slsi_rx_netdev_data_work(struct work_struct *work);
 void slsi_rx_netdev_mlme_work(struct work_struct *work);
index 26fa07b8aad85b36c0f92f96ccba880592637be5..4a09c1302ef6006b96adada4c5cff5bd254695f5 100755 (executable)
@@ -190,7 +190,7 @@ static inline bool slsi_rx_is_amsdu(struct sk_buff *skb)
        return (fapi_get_u16(skb, u.ma_unitdata_ind.data_unit_descriptor) == FAPI_DATAUNITDESCRIPTOR_AMSDU);
 }
 
-void slsi_rx_data_deliver_skb(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb)
+void slsi_rx_data_deliver_skb(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb, bool from_ba_timer)
 {
        struct netdev_vif *ndev_vif = netdev_priv(dev);
        struct sk_buff_head msdu_list;
@@ -321,7 +321,10 @@ void slsi_rx_data_deliver_skb(struct slsi_dev *sdev, struct net_device *dev, str
                conf_hip4_ver = scsc_wifi_get_hip_config_version(&sdev->hip4_inst.hip_control->init);
                if (conf_hip4_ver == 4) {
 #ifdef CONFIG_SCSC_WLAN_RX_NAPI_GRO
-                       napi_gro_receive(&sdev->hip4_inst.hip_priv->napi, rx_skb);
+                       if (!from_ba_timer)
+                               napi_gro_receive(&sdev->hip4_inst.hip_priv->napi, rx_skb);
+                       else
+                               netif_receive_skb(rx_skb);
 #else
                        netif_receive_skb(rx_skb);
 #endif
@@ -412,7 +415,7 @@ static void slsi_rx_data_ind(struct slsi_dev *sdev, struct net_device *dev, stru
                        SLSI_NET_WARN(dev, "Packet received from TDLS but no TDLS exists (seq: %x) Skip BA\n", seq_num);
 
                /* Skip BA reorder and pass the frames Up */
-               slsi_rx_data_deliver_skb(sdev, dev, skb);
+               slsi_rx_data_deliver_skb(sdev, dev, skb, false);
                return;
        }
 
@@ -434,7 +437,7 @@ static void slsi_rx_data_ind(struct slsi_dev *sdev, struct net_device *dev, stru
                        return;
 
        /* Pass to next receive process */
-       slsi_rx_data_deliver_skb(sdev, dev, skb);
+       slsi_rx_data_deliver_skb(sdev, dev, skb, false);
 }
 
 static int slsi_rx_data_cfm(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb)
@@ -484,7 +487,7 @@ static int slsi_rx_napi_process(struct slsi_dev *sdev, struct sk_buff *skb)
                /* SKBs in a BA session are not passed yet */
                if (atomic_read(&ndev_vif->ba_flush)) {
                        atomic_set(&ndev_vif->ba_flush, 0);
-                       slsi_ba_process_complete(dev);
+                       slsi_ba_process_complete(dev, false);
                }
                break;
        case MA_UNITDATA_CFM:
@@ -521,7 +524,7 @@ void slsi_rx_netdev_data_work(struct work_struct *work)
 
                if (atomic_read(&ndev_vif->ba_flush)) {
                        atomic_set(&ndev_vif->ba_flush, 0);
-                       slsi_ba_process_complete(dev);
+                       slsi_ba_process_complete(dev, false);
                }
 
                skb = slsi_skb_work_dequeue(w);