/* Tasklets --- multithreaded analogue of BHs.
 
+   This API is deprecated. Please consider using threaded IRQs instead:
+   https://lore.kernel.org/lkml/20200716081538.2sivhkj4hcyrusem@linutronix.de
+
    Main feature differing them of generic softirqs: tasklet
    is running only on one CPU simultaneously.
 
        struct tasklet_struct *next;
        unsigned long state;
        atomic_t count;
-       void (*func)(unsigned long);
+       bool use_callback;
+       union {
+               void (*func)(unsigned long data);
+               void (*callback)(struct tasklet_struct *t);
+       };
        unsigned long data;
 };
 
+#define DECLARE_TASKLET(name, _callback)               \
+struct tasklet_struct name = {                         \
+       .count = ATOMIC_INIT(0),                        \
+       .callback = _callback,                          \
+       .use_callback = true,                           \
+}
+
+#define DECLARE_TASKLET_DISABLED(name, _callback)      \
+struct tasklet_struct name = {                         \
+       .count = ATOMIC_INIT(1),                        \
+       .callback = _callback,                          \
+       .use_callback = true,                           \
+}
+
+#define from_tasklet(var, callback_tasklet, tasklet_fieldname) \
+       container_of(callback_tasklet, typeof(*var), tasklet_fieldname)
+
 #define DECLARE_TASKLET_OLD(name, _func)               \
 struct tasklet_struct name = {                         \
        .count = ATOMIC_INIT(0),                        \
 extern void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu);
 extern void tasklet_init(struct tasklet_struct *t,
                         void (*func)(unsigned long), unsigned long data);
+extern void tasklet_setup(struct tasklet_struct *t,
+                         void (*callback)(struct tasklet_struct *));
 
 /*
  * Autoprobing for irqs:
 
                                if (!test_and_clear_bit(TASKLET_STATE_SCHED,
                                                        &t->state))
                                        BUG();
-                               t->func(t->data);
+                               if (t->use_callback)
+                                       t->callback(t);
+                               else
+                                       t->func(t->data);
                                tasklet_unlock(t);
                                continue;
                        }
        tasklet_action_common(a, this_cpu_ptr(&tasklet_hi_vec), HI_SOFTIRQ);
 }
 
+void tasklet_setup(struct tasklet_struct *t,
+                  void (*callback)(struct tasklet_struct *))
+{
+       t->next = NULL;
+       t->state = 0;
+       atomic_set(&t->count, 0);
+       t->callback = callback;
+       t->use_callback = true;
+       t->data = 0;
+}
+EXPORT_SYMBOL(tasklet_setup);
+
 void tasklet_init(struct tasklet_struct *t,
                  void (*func)(unsigned long), unsigned long data)
 {
        t->state = 0;
        atomic_set(&t->count, 0);
        t->func = func;
+       t->use_callback = false;
        t->data = data;
 }
 EXPORT_SYMBOL(tasklet_init);