18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Fast batching percpu counters.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/percpu_counter.h>
78c2ecf20Sopenharmony_ci#include <linux/mutex.h>
88c2ecf20Sopenharmony_ci#include <linux/init.h>
98c2ecf20Sopenharmony_ci#include <linux/cpu.h>
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/debugobjects.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU
148c2ecf20Sopenharmony_cistatic LIST_HEAD(percpu_counters);
158c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(percpu_counters_lock);
168c2ecf20Sopenharmony_ci#endif
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic const struct debug_obj_descr percpu_counter_debug_descr;
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic bool percpu_counter_fixup_free(void *addr, enum debug_obj_state state)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	struct percpu_counter *fbc = addr;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	switch (state) {
278c2ecf20Sopenharmony_ci	case ODEBUG_STATE_ACTIVE:
288c2ecf20Sopenharmony_ci		percpu_counter_destroy(fbc);
298c2ecf20Sopenharmony_ci		debug_object_free(fbc, &percpu_counter_debug_descr);
308c2ecf20Sopenharmony_ci		return true;
318c2ecf20Sopenharmony_ci	default:
328c2ecf20Sopenharmony_ci		return false;
338c2ecf20Sopenharmony_ci	}
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic const struct debug_obj_descr percpu_counter_debug_descr = {
378c2ecf20Sopenharmony_ci	.name		= "percpu_counter",
388c2ecf20Sopenharmony_ci	.fixup_free	= percpu_counter_fixup_free,
398c2ecf20Sopenharmony_ci};
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic inline void debug_percpu_counter_activate(struct percpu_counter *fbc)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	debug_object_init(fbc, &percpu_counter_debug_descr);
448c2ecf20Sopenharmony_ci	debug_object_activate(fbc, &percpu_counter_debug_descr);
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic inline void debug_percpu_counter_deactivate(struct percpu_counter *fbc)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	debug_object_deactivate(fbc, &percpu_counter_debug_descr);
508c2ecf20Sopenharmony_ci	debug_object_free(fbc, &percpu_counter_debug_descr);
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#else	/* CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER */
548c2ecf20Sopenharmony_cistatic inline void debug_percpu_counter_activate(struct percpu_counter *fbc)
558c2ecf20Sopenharmony_ci{ }
568c2ecf20Sopenharmony_cistatic inline void debug_percpu_counter_deactivate(struct percpu_counter *fbc)
578c2ecf20Sopenharmony_ci{ }
588c2ecf20Sopenharmony_ci#endif	/* CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER */
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_civoid percpu_counter_set(struct percpu_counter *fbc, s64 amount)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	int cpu;
638c2ecf20Sopenharmony_ci	unsigned long flags;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&fbc->lock, flags);
668c2ecf20Sopenharmony_ci	for_each_possible_cpu(cpu) {
678c2ecf20Sopenharmony_ci		s32 *pcount = per_cpu_ptr(fbc->counters, cpu);
688c2ecf20Sopenharmony_ci		*pcount = 0;
698c2ecf20Sopenharmony_ci	}
708c2ecf20Sopenharmony_ci	fbc->count = amount;
718c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&fbc->lock, flags);
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(percpu_counter_set);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci/**
768c2ecf20Sopenharmony_ci * This function is both preempt and irq safe. The former is due to explicit
778c2ecf20Sopenharmony_ci * preemption disable. The latter is guaranteed by the fact that the slow path
788c2ecf20Sopenharmony_ci * is explicitly protected by an irq-safe spinlock whereas the fast patch uses
798c2ecf20Sopenharmony_ci * this_cpu_add which is irq-safe by definition. Hence there is no need muck
808c2ecf20Sopenharmony_ci * with irq state before calling this one
818c2ecf20Sopenharmony_ci */
828c2ecf20Sopenharmony_civoid percpu_counter_add_batch(struct percpu_counter *fbc, s64 amount, s32 batch)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	s64 count;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	preempt_disable();
878c2ecf20Sopenharmony_ci	count = __this_cpu_read(*fbc->counters) + amount;
888c2ecf20Sopenharmony_ci	if (abs(count) >= batch) {
898c2ecf20Sopenharmony_ci		unsigned long flags;
908c2ecf20Sopenharmony_ci		raw_spin_lock_irqsave(&fbc->lock, flags);
918c2ecf20Sopenharmony_ci		fbc->count += count;
928c2ecf20Sopenharmony_ci		__this_cpu_sub(*fbc->counters, count - amount);
938c2ecf20Sopenharmony_ci		raw_spin_unlock_irqrestore(&fbc->lock, flags);
948c2ecf20Sopenharmony_ci	} else {
958c2ecf20Sopenharmony_ci		this_cpu_add(*fbc->counters, amount);
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci	preempt_enable();
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(percpu_counter_add_batch);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci/*
1028c2ecf20Sopenharmony_ci * For percpu_counter with a big batch, the devication of its count could
1038c2ecf20Sopenharmony_ci * be big, and there is requirement to reduce the deviation, like when the
1048c2ecf20Sopenharmony_ci * counter's batch could be runtime decreased to get a better accuracy,
1058c2ecf20Sopenharmony_ci * which can be achieved by running this sync function on each CPU.
1068c2ecf20Sopenharmony_ci */
1078c2ecf20Sopenharmony_civoid percpu_counter_sync(struct percpu_counter *fbc)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	unsigned long flags;
1108c2ecf20Sopenharmony_ci	s64 count;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&fbc->lock, flags);
1138c2ecf20Sopenharmony_ci	count = __this_cpu_read(*fbc->counters);
1148c2ecf20Sopenharmony_ci	fbc->count += count;
1158c2ecf20Sopenharmony_ci	__this_cpu_sub(*fbc->counters, count);
1168c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&fbc->lock, flags);
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(percpu_counter_sync);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci/*
1218c2ecf20Sopenharmony_ci * Add up all the per-cpu counts, return the result.  This is a more accurate
1228c2ecf20Sopenharmony_ci * but much slower version of percpu_counter_read_positive()
1238c2ecf20Sopenharmony_ci */
1248c2ecf20Sopenharmony_cis64 __percpu_counter_sum(struct percpu_counter *fbc)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	s64 ret;
1278c2ecf20Sopenharmony_ci	int cpu;
1288c2ecf20Sopenharmony_ci	unsigned long flags;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&fbc->lock, flags);
1318c2ecf20Sopenharmony_ci	ret = fbc->count;
1328c2ecf20Sopenharmony_ci	for_each_online_cpu(cpu) {
1338c2ecf20Sopenharmony_ci		s32 *pcount = per_cpu_ptr(fbc->counters, cpu);
1348c2ecf20Sopenharmony_ci		ret += *pcount;
1358c2ecf20Sopenharmony_ci	}
1368c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&fbc->lock, flags);
1378c2ecf20Sopenharmony_ci	return ret;
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__percpu_counter_sum);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ciint __percpu_counter_init(struct percpu_counter *fbc, s64 amount, gfp_t gfp,
1428c2ecf20Sopenharmony_ci			  struct lock_class_key *key)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	unsigned long flags __maybe_unused;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	raw_spin_lock_init(&fbc->lock);
1478c2ecf20Sopenharmony_ci	lockdep_set_class(&fbc->lock, key);
1488c2ecf20Sopenharmony_ci	fbc->count = amount;
1498c2ecf20Sopenharmony_ci	fbc->counters = alloc_percpu_gfp(s32, gfp);
1508c2ecf20Sopenharmony_ci	if (!fbc->counters)
1518c2ecf20Sopenharmony_ci		return -ENOMEM;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	debug_percpu_counter_activate(fbc);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU
1568c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&fbc->list);
1578c2ecf20Sopenharmony_ci	spin_lock_irqsave(&percpu_counters_lock, flags);
1588c2ecf20Sopenharmony_ci	list_add(&fbc->list, &percpu_counters);
1598c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&percpu_counters_lock, flags);
1608c2ecf20Sopenharmony_ci#endif
1618c2ecf20Sopenharmony_ci	return 0;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__percpu_counter_init);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_civoid percpu_counter_destroy(struct percpu_counter *fbc)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	unsigned long flags __maybe_unused;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	if (!fbc->counters)
1708c2ecf20Sopenharmony_ci		return;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	debug_percpu_counter_deactivate(fbc);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU
1758c2ecf20Sopenharmony_ci	spin_lock_irqsave(&percpu_counters_lock, flags);
1768c2ecf20Sopenharmony_ci	list_del(&fbc->list);
1778c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&percpu_counters_lock, flags);
1788c2ecf20Sopenharmony_ci#endif
1798c2ecf20Sopenharmony_ci	free_percpu(fbc->counters);
1808c2ecf20Sopenharmony_ci	fbc->counters = NULL;
1818c2ecf20Sopenharmony_ci}
1828c2ecf20Sopenharmony_ciEXPORT_SYMBOL(percpu_counter_destroy);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ciint percpu_counter_batch __read_mostly = 32;
1858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(percpu_counter_batch);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic int compute_batch_value(unsigned int cpu)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	int nr = num_online_cpus();
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	percpu_counter_batch = max(32, nr*2);
1928c2ecf20Sopenharmony_ci	return 0;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic int percpu_counter_cpu_dead(unsigned int cpu)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU
1988c2ecf20Sopenharmony_ci	struct percpu_counter *fbc;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	compute_batch_value(cpu);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	spin_lock_irq(&percpu_counters_lock);
2038c2ecf20Sopenharmony_ci	list_for_each_entry(fbc, &percpu_counters, list) {
2048c2ecf20Sopenharmony_ci		s32 *pcount;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci		raw_spin_lock(&fbc->lock);
2078c2ecf20Sopenharmony_ci		pcount = per_cpu_ptr(fbc->counters, cpu);
2088c2ecf20Sopenharmony_ci		fbc->count += *pcount;
2098c2ecf20Sopenharmony_ci		*pcount = 0;
2108c2ecf20Sopenharmony_ci		raw_spin_unlock(&fbc->lock);
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci	spin_unlock_irq(&percpu_counters_lock);
2138c2ecf20Sopenharmony_ci#endif
2148c2ecf20Sopenharmony_ci	return 0;
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci/*
2188c2ecf20Sopenharmony_ci * Compare counter against given value.
2198c2ecf20Sopenharmony_ci * Return 1 if greater, 0 if equal and -1 if less
2208c2ecf20Sopenharmony_ci */
2218c2ecf20Sopenharmony_ciint __percpu_counter_compare(struct percpu_counter *fbc, s64 rhs, s32 batch)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	s64	count;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	count = percpu_counter_read(fbc);
2268c2ecf20Sopenharmony_ci	/* Check to see if rough count will be sufficient for comparison */
2278c2ecf20Sopenharmony_ci	if (abs(count - rhs) > (batch * num_online_cpus())) {
2288c2ecf20Sopenharmony_ci		if (count > rhs)
2298c2ecf20Sopenharmony_ci			return 1;
2308c2ecf20Sopenharmony_ci		else
2318c2ecf20Sopenharmony_ci			return -1;
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci	/* Need to use precise count */
2348c2ecf20Sopenharmony_ci	count = percpu_counter_sum(fbc);
2358c2ecf20Sopenharmony_ci	if (count > rhs)
2368c2ecf20Sopenharmony_ci		return 1;
2378c2ecf20Sopenharmony_ci	else if (count < rhs)
2388c2ecf20Sopenharmony_ci		return -1;
2398c2ecf20Sopenharmony_ci	else
2408c2ecf20Sopenharmony_ci		return 0;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__percpu_counter_compare);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic int __init percpu_counter_startup(void)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	int ret;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "lib/percpu_cnt:online",
2498c2ecf20Sopenharmony_ci				compute_batch_value, NULL);
2508c2ecf20Sopenharmony_ci	WARN_ON(ret < 0);
2518c2ecf20Sopenharmony_ci	ret = cpuhp_setup_state_nocalls(CPUHP_PERCPU_CNT_DEAD,
2528c2ecf20Sopenharmony_ci					"lib/percpu_cnt:dead", NULL,
2538c2ecf20Sopenharmony_ci					percpu_counter_cpu_dead);
2548c2ecf20Sopenharmony_ci	WARN_ON(ret < 0);
2558c2ecf20Sopenharmony_ci	return 0;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_cimodule_init(percpu_counter_startup);
258