[NEUS7920-133][9610] wlbt: Use single threaded wq in hip4 bh
authorAlbert Cano <a.canocamps@samsung.com>
Thu, 14 Feb 2019 10:39:50 +0000 (10:39 +0000)
committerYoungmin Nam <youngmin.nam@samsung.com>
Tue, 21 May 2019 10:45:21 +0000 (19:45 +0900)
We have recently (A50 project) observed several issues to schedule
hip4_wq work, most likely because the kernel is blocked and is not
granting us CPU cycles.

In current implementation the work is added in the systemwq. Systemwq
might be easily affected by other subsystems adding batch works that
might eventually block our pending work.

In order to avoid using systemwq, the patch creates a new singlethread
workqueue and adds the non-napi process context bottom half works in there.

Change-Id: I0cc69779aa91c26777f00a2e7b1cd840336f553d
SCSC-Bug-Id: SSB-50566
Signed-off-by: Albert Cano <a.canocamps@samsung.com>
drivers/net/wireless/scsc/hip4.c
drivers/net/wireless/scsc/hip4.h

index 86a4a425030d3892db1632824c3e9f3a3ab9c412..0af531180e727f2ac017fd29b52d3fa37b0db039 100755 (executable)
 
 #include "debug.h"
 
+static bool hip4_system_wq;
+module_param(hip4_system_wq, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(hip4_system_wq, "Use system wq instead of named workqueue. (default: N)");
+
 #ifdef CONFIG_SCSC_LOGRING
 static bool hip4_dynamic_logging = true;
 module_param(hip4_dynamic_logging, bool, S_IRUGO | S_IWUSR);
@@ -1146,7 +1150,10 @@ static void hip4_irq_handler_fb(int irq, void *data)
        set_bit(HIP4_MIF_Q_FH_RFB, hip->hip_priv->irq_bitmap);
 
        scsc_service_mifintrbit_bit_mask(sdev->service, irq);
-       schedule_work(&hip->hip_priv->intr_wq_fb);
+       if (hip4_system_wq)
+               schedule_work(&hip->hip_priv->intr_wq_fb);
+       else
+               queue_work(hip->hip_priv->hip4_workq, &hip->hip_priv->intr_wq_fb);
        /* Clear interrupt */
        scsc_service_mifintrbit_bit_clear(sdev->service, irq);
        SCSC_HIP4_SAMPLER_INT_OUT(hip->hip_priv->minor, 2);
@@ -1320,7 +1327,10 @@ static void hip4_irq_handler_ctrl(int irq, void *data)
 
        scsc_service_mifintrbit_bit_mask(sdev->service, irq);
 
-       schedule_work(&hip->hip_priv->intr_wq_ctrl);
+       if (hip4_system_wq)
+               schedule_work(&hip->hip_priv->intr_wq_ctrl);
+       else
+               queue_work(hip->hip_priv->hip4_workq, &hip->hip_priv->intr_wq_ctrl);
        /* Clear interrupt */
        scsc_service_mifintrbit_bit_clear(sdev->service, irq);
        SCSC_HIP4_SAMPLER_INT_OUT(hip->hip_priv->minor, 1);
@@ -2014,7 +2024,11 @@ static void hip4_irq_handler(int irq, void *data)
        }
 
        atomic_inc(&hip->hip_priv->stats.irqs);
-       schedule_work(&hip->hip_priv->intr_wq);
+
+       if (hip4_system_wq)
+               schedule_work(&hip->hip_priv->intr_wq);
+       else
+               queue_work(hip->hip_priv->hip4_workq, &hip->hip_priv->intr_wq);
 end:
        /* Clear interrupt */
        scsc_service_mifintrbit_bit_clear(sdev->service, hip->hip_priv->intr_tohost);
@@ -2341,6 +2355,11 @@ int hip4_init(struct slsi_hip4 *hip)
        atomic_set(&hip->hip_priv->in_tx, 0);
 
        /* Init work structs */
+       hip->hip_priv->hip4_workq = create_singlethread_workqueue("hip4_work");
+       if (!hip->hip_priv->hip4_workq) {
+               SLSI_ERR_NODEV("Error creating singlethread_workqueue\n");
+               return -ENOMEM;
+       }
 #ifdef CONFIG_SCSC_WLAN_RX_NAPI
        tasklet_init(&hip->hip_priv->intr_tasklet, hip4_irq_data_tasklet, (unsigned long)hip);
        INIT_WORK(&hip->hip_priv->intr_wq_ctrl, hip4_wq_ctrl);
@@ -2733,6 +2752,8 @@ void hip4_freeze(struct slsi_hip4 *hip)
        scsc_service_mifintrbit_bit_mask(service, hip->hip_priv->intr_tohost);
        cancel_work_sync(&hip->hip_priv->intr_wq);
 #endif
+       flush_workqueue(hip->hip_priv->hip4_workq);
+       destroy_workqueue(hip->hip_priv->hip4_workq);
        atomic_set(&hip->hip_priv->rx_ready, 0);
        atomic_set(&hip->hip_priv->watchdog_timer_active, 0);
 
@@ -2803,6 +2824,9 @@ void hip4_deinit(struct slsi_hip4 *hip)
        cancel_work_sync(&hip->hip_priv->intr_wq);
        scsc_service_mifintrbit_unregister_tohost(service, hip->hip_priv->intr_tohost);
 
+       flush_workqueue(hip->hip_priv->hip4_workq);
+       destroy_workqueue(hip->hip_priv->hip4_workq);
+
        scsc_service_mifintrbit_free_fromhost(service, hip->hip_priv->intr_fromhost, SCSC_MIFINTR_TARGET_R4);
 
        /* If we get to that point with rx_lock/tx_lock claimed, trigger BUG() */
index 519c307f5262d20d6084be41ba14977bf88c8363..4700e928b21925808ea9a6bff1284d4e8675c6e2 100755 (executable)
@@ -349,6 +349,8 @@ struct hip4_priv {
        u16                          mib_sz;
        /* Mutex to protect hcf file collection if a tear down is triggered */
        struct mutex                 in_collection;
+
+       struct workqueue_struct *hip4_workq;
 };
 
 struct scsc_service;