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