drm/amdgpu: Remove second moot switch to set EEPROM I2C address
[platform/kernel/linux-starfive.git] / kernel / workqueue.c
index 7cd5f5e..f3b6ac2 100644 (file)
@@ -326,7 +326,7 @@ static struct rcuwait manager_wait = __RCUWAIT_INITIALIZER(manager_wait);
 static LIST_HEAD(workqueues);          /* PR: list of all workqueues */
 static bool workqueue_freezing;                /* PL: have wqs started freezing? */
 
-/* PL: allowable cpus for unbound wqs and work items */
+/* PL&A: allowable cpus for unbound wqs and work items */
 static cpumask_var_t wq_unbound_cpumask;
 
 /* CPU where unbound work was last round robin scheduled from this CPU */
@@ -698,12 +698,17 @@ static void clear_work_data(struct work_struct *work)
        set_work_data(work, WORK_STRUCT_NO_POOL, 0);
 }
 
+static inline struct pool_workqueue *work_struct_pwq(unsigned long data)
+{
+       return (struct pool_workqueue *)(data & WORK_STRUCT_WQ_DATA_MASK);
+}
+
 static struct pool_workqueue *get_work_pwq(struct work_struct *work)
 {
        unsigned long data = atomic_long_read(&work->data);
 
        if (data & WORK_STRUCT_PWQ)
-               return (void *)(data & WORK_STRUCT_WQ_DATA_MASK);
+               return work_struct_pwq(data);
        else
                return NULL;
 }
@@ -731,8 +736,7 @@ static struct worker_pool *get_work_pool(struct work_struct *work)
        assert_rcu_or_pool_mutex();
 
        if (data & WORK_STRUCT_PWQ)
-               return ((struct pool_workqueue *)
-                       (data & WORK_STRUCT_WQ_DATA_MASK))->pool;
+               return work_struct_pwq(data)->pool;
 
        pool_id = data >> WORK_OFFQ_POOL_SHIFT;
        if (pool_id == WORK_OFFQ_POOL_NONE)
@@ -753,8 +757,7 @@ static int get_work_pool_id(struct work_struct *work)
        unsigned long data = atomic_long_read(&work->data);
 
        if (data & WORK_STRUCT_PWQ)
-               return ((struct pool_workqueue *)
-                       (data & WORK_STRUCT_WQ_DATA_MASK))->pool->id;
+               return work_struct_pwq(data)->pool->id;
 
        return data >> WORK_OFFQ_POOL_SHIFT;
 }
@@ -3952,7 +3955,8 @@ static void apply_wqattrs_cleanup(struct apply_wqattrs_ctx *ctx)
 /* allocate the attrs and pwqs for later installation */
 static struct apply_wqattrs_ctx *
 apply_wqattrs_prepare(struct workqueue_struct *wq,
-                     const struct workqueue_attrs *attrs)
+                     const struct workqueue_attrs *attrs,
+                     const cpumask_var_t unbound_cpumask)
 {
        struct apply_wqattrs_ctx *ctx;
        struct workqueue_attrs *new_attrs, *tmp_attrs;
@@ -3968,14 +3972,15 @@ apply_wqattrs_prepare(struct workqueue_struct *wq,
                goto out_free;
 
        /*
-        * Calculate the attrs of the default pwq.
+        * Calculate the attrs of the default pwq with unbound_cpumask
+        * which is wq_unbound_cpumask or to set to wq_unbound_cpumask.
         * If the user configured cpumask doesn't overlap with the
         * wq_unbound_cpumask, we fallback to the wq_unbound_cpumask.
         */
        copy_workqueue_attrs(new_attrs, attrs);
-       cpumask_and(new_attrs->cpumask, new_attrs->cpumask, wq_unbound_cpumask);
+       cpumask_and(new_attrs->cpumask, new_attrs->cpumask, unbound_cpumask);
        if (unlikely(cpumask_empty(new_attrs->cpumask)))
-               cpumask_copy(new_attrs->cpumask, wq_unbound_cpumask);
+               cpumask_copy(new_attrs->cpumask, unbound_cpumask);
 
        /*
         * We may create multiple pwqs with differing cpumasks.  Make a
@@ -4072,7 +4077,7 @@ static int apply_workqueue_attrs_locked(struct workqueue_struct *wq,
                wq->flags &= ~__WQ_ORDERED;
        }
 
-       ctx = apply_wqattrs_prepare(wq, attrs);
+       ctx = apply_wqattrs_prepare(wq, attrs, wq_unbound_cpumask);
        if (!ctx)
                return -ENOMEM;
 
@@ -4848,10 +4853,16 @@ static void show_one_worker_pool(struct worker_pool *pool)
        struct worker *worker;
        bool first = true;
        unsigned long flags;
+       unsigned long hung = 0;
 
        raw_spin_lock_irqsave(&pool->lock, flags);
        if (pool->nr_workers == pool->nr_idle)
                goto next_pool;
+
+       /* How long the first pending work is waiting for a worker. */
+       if (!list_empty(&pool->worklist))
+               hung = jiffies_to_msecs(jiffies - pool->watchdog_ts) / 1000;
+
        /*
         * Defer printing to avoid deadlocks in console drivers that
         * queue work while holding locks also taken in their write
@@ -4860,9 +4871,7 @@ static void show_one_worker_pool(struct worker_pool *pool)
        printk_deferred_enter();
        pr_info("pool %d:", pool->id);
        pr_cont_pool_info(pool);
-       pr_cont(" hung=%us workers=%d",
-               jiffies_to_msecs(jiffies - pool->watchdog_ts) / 1000,
-               pool->nr_workers);
+       pr_cont(" hung=%lus workers=%d", hung, pool->nr_workers);
        if (pool->manager)
                pr_cont(" manager: %d",
                        task_pid_nr(pool->manager->task));
@@ -5176,50 +5185,54 @@ static void work_for_cpu_fn(struct work_struct *work)
 }
 
 /**
- * work_on_cpu - run a function in thread context on a particular cpu
+ * work_on_cpu_key - run a function in thread context on a particular cpu
  * @cpu: the cpu to run on
  * @fn: the function to run
  * @arg: the function arg
+ * @key: The lock class key for lock debugging purposes
  *
  * It is up to the caller to ensure that the cpu doesn't go offline.
  * The caller must not hold any locks which would prevent @fn from completing.
  *
  * Return: The value @fn returns.
  */
-long work_on_cpu(int cpu, long (*fn)(void *), void *arg)
+long work_on_cpu_key(int cpu, long (*fn)(void *),
+                    void *arg, struct lock_class_key *key)
 {
        struct work_for_cpu wfc = { .fn = fn, .arg = arg };
 
-       INIT_WORK_ONSTACK(&wfc.work, work_for_cpu_fn);
+       INIT_WORK_ONSTACK_KEY(&wfc.work, work_for_cpu_fn, key);
        schedule_work_on(cpu, &wfc.work);
        flush_work(&wfc.work);
        destroy_work_on_stack(&wfc.work);
        return wfc.ret;
 }
-EXPORT_SYMBOL_GPL(work_on_cpu);
+EXPORT_SYMBOL_GPL(work_on_cpu_key);
 
 /**
- * work_on_cpu_safe - run a function in thread context on a particular cpu
+ * work_on_cpu_safe_key - run a function in thread context on a particular cpu
  * @cpu: the cpu to run on
  * @fn:  the function to run
  * @arg: the function argument
+ * @key: The lock class key for lock debugging purposes
  *
  * Disables CPU hotplug and calls work_on_cpu(). The caller must not hold
  * any locks which would prevent @fn from completing.
  *
  * Return: The value @fn returns.
  */
-long work_on_cpu_safe(int cpu, long (*fn)(void *), void *arg)
+long work_on_cpu_safe_key(int cpu, long (*fn)(void *),
+                         void *arg, struct lock_class_key *key)
 {
        long ret = -ENODEV;
 
        cpus_read_lock();
        if (cpu_online(cpu))
-               ret = work_on_cpu(cpu, fn, arg);
+               ret = work_on_cpu_key(cpu, fn, arg, key);
        cpus_read_unlock();
        return ret;
 }
-EXPORT_SYMBOL_GPL(work_on_cpu_safe);
+EXPORT_SYMBOL_GPL(work_on_cpu_safe_key);
 #endif /* CONFIG_SMP */
 
 #ifdef CONFIG_FREEZER
@@ -5334,7 +5347,7 @@ out_unlock:
 }
 #endif /* CONFIG_FREEZER */
 
-static int workqueue_apply_unbound_cpumask(void)
+static int workqueue_apply_unbound_cpumask(const cpumask_var_t unbound_cpumask)
 {
        LIST_HEAD(ctxs);
        int ret = 0;
@@ -5346,11 +5359,15 @@ static int workqueue_apply_unbound_cpumask(void)
        list_for_each_entry(wq, &workqueues, list) {
                if (!(wq->flags & WQ_UNBOUND))
                        continue;
+
                /* creating multiple pwqs breaks ordering guarantee */
-               if (wq->flags & __WQ_ORDERED)
-                       continue;
+               if (!list_empty(&wq->pwqs)) {
+                       if (wq->flags & __WQ_ORDERED_EXPLICIT)
+                               continue;
+                       wq->flags &= ~__WQ_ORDERED;
+               }
 
-               ctx = apply_wqattrs_prepare(wq, wq->unbound_attrs);
+               ctx = apply_wqattrs_prepare(wq, wq->unbound_attrs, unbound_cpumask);
                if (!ctx) {
                        ret = -ENOMEM;
                        break;
@@ -5365,6 +5382,11 @@ static int workqueue_apply_unbound_cpumask(void)
                apply_wqattrs_cleanup(ctx);
        }
 
+       if (!ret) {
+               mutex_lock(&wq_pool_attach_mutex);
+               cpumask_copy(wq_unbound_cpumask, unbound_cpumask);
+               mutex_unlock(&wq_pool_attach_mutex);
+       }
        return ret;
 }
 
@@ -5383,7 +5405,6 @@ static int workqueue_apply_unbound_cpumask(void)
 int workqueue_set_unbound_cpumask(cpumask_var_t cpumask)
 {
        int ret = -EINVAL;
-       cpumask_var_t saved_cpumask;
 
        /*
         * Not excluding isolated cpus on purpose.
@@ -5397,23 +5418,8 @@ int workqueue_set_unbound_cpumask(cpumask_var_t cpumask)
                        goto out_unlock;
                }
 
-               if (!zalloc_cpumask_var(&saved_cpumask, GFP_KERNEL)) {
-                       ret = -ENOMEM;
-                       goto out_unlock;
-               }
-
-               /* save the old wq_unbound_cpumask. */
-               cpumask_copy(saved_cpumask, wq_unbound_cpumask);
-
-               /* update wq_unbound_cpumask at first and apply it to wqs. */
-               cpumask_copy(wq_unbound_cpumask, cpumask);
-               ret = workqueue_apply_unbound_cpumask();
-
-               /* restore the wq_unbound_cpumask when failed. */
-               if (ret < 0)
-                       cpumask_copy(wq_unbound_cpumask, saved_cpumask);
+               ret = workqueue_apply_unbound_cpumask(cpumask);
 
-               free_cpumask_var(saved_cpumask);
 out_unlock:
                apply_wqattrs_unlock();
        }