18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file contains functions which manage clock event devices. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright(C) 2005-2006, Thomas Gleixner <tglx@linutronix.de> 68c2ecf20Sopenharmony_ci * Copyright(C) 2005-2007, Red Hat, Inc., Ingo Molnar 78c2ecf20Sopenharmony_ci * Copyright(C) 2006-2007, Timesys Corp., Thomas Gleixner 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/clockchips.h> 118c2ecf20Sopenharmony_ci#include <linux/hrtimer.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/smp.h> 158c2ecf20Sopenharmony_ci#include <linux/device.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "tick-internal.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* The registered clock event devices */ 208c2ecf20Sopenharmony_cistatic LIST_HEAD(clockevent_devices); 218c2ecf20Sopenharmony_cistatic LIST_HEAD(clockevents_released); 228c2ecf20Sopenharmony_ci/* Protection for the above */ 238c2ecf20Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(clockevents_lock); 248c2ecf20Sopenharmony_ci/* Protection for unbind operations */ 258c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(clockevents_mutex); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct ce_unbind { 288c2ecf20Sopenharmony_ci struct clock_event_device *ce; 298c2ecf20Sopenharmony_ci int res; 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic u64 cev_delta2ns(unsigned long latch, struct clock_event_device *evt, 338c2ecf20Sopenharmony_ci bool ismax) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci u64 clc = (u64) latch << evt->shift; 368c2ecf20Sopenharmony_ci u64 rnd; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci if (WARN_ON(!evt->mult)) 398c2ecf20Sopenharmony_ci evt->mult = 1; 408c2ecf20Sopenharmony_ci rnd = (u64) evt->mult - 1; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci /* 438c2ecf20Sopenharmony_ci * Upper bound sanity check. If the backwards conversion is 448c2ecf20Sopenharmony_ci * not equal latch, we know that the above shift overflowed. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_ci if ((clc >> evt->shift) != (u64)latch) 478c2ecf20Sopenharmony_ci clc = ~0ULL; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* 508c2ecf20Sopenharmony_ci * Scaled math oddities: 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * For mult <= (1 << shift) we can safely add mult - 1 to 538c2ecf20Sopenharmony_ci * prevent integer rounding loss. So the backwards conversion 548c2ecf20Sopenharmony_ci * from nsec to device ticks will be correct. 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * For mult > (1 << shift), i.e. device frequency is > 1GHz we 578c2ecf20Sopenharmony_ci * need to be careful. Adding mult - 1 will result in a value 588c2ecf20Sopenharmony_ci * which when converted back to device ticks can be larger 598c2ecf20Sopenharmony_ci * than latch by up to (mult - 1) >> shift. For the min_delta 608c2ecf20Sopenharmony_ci * calculation we still want to apply this in order to stay 618c2ecf20Sopenharmony_ci * above the minimum device ticks limit. For the upper limit 628c2ecf20Sopenharmony_ci * we would end up with a latch value larger than the upper 638c2ecf20Sopenharmony_ci * limit of the device, so we omit the add to stay below the 648c2ecf20Sopenharmony_ci * device upper boundary. 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * Also omit the add if it would overflow the u64 boundary. 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_ci if ((~0ULL - clc > rnd) && 698c2ecf20Sopenharmony_ci (!ismax || evt->mult <= (1ULL << evt->shift))) 708c2ecf20Sopenharmony_ci clc += rnd; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci do_div(clc, evt->mult); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* Deltas less than 1usec are pointless noise */ 758c2ecf20Sopenharmony_ci return clc > 1000 ? clc : 1000; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/** 798c2ecf20Sopenharmony_ci * clockevents_delta2ns - Convert a latch value (device ticks) to nanoseconds 808c2ecf20Sopenharmony_ci * @latch: value to convert 818c2ecf20Sopenharmony_ci * @evt: pointer to clock event device descriptor 828c2ecf20Sopenharmony_ci * 838c2ecf20Sopenharmony_ci * Math helper, returns latch value converted to nanoseconds (bound checked) 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ciu64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci return cev_delta2ns(latch, evt, false); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clockevent_delta2ns); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int __clockevents_switch_state(struct clock_event_device *dev, 928c2ecf20Sopenharmony_ci enum clock_event_state state) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci if (dev->features & CLOCK_EVT_FEAT_DUMMY) 958c2ecf20Sopenharmony_ci return 0; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* Transition with new state-specific callbacks */ 988c2ecf20Sopenharmony_ci switch (state) { 998c2ecf20Sopenharmony_ci case CLOCK_EVT_STATE_DETACHED: 1008c2ecf20Sopenharmony_ci /* The clockevent device is getting replaced. Shut it down. */ 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci case CLOCK_EVT_STATE_SHUTDOWN: 1038c2ecf20Sopenharmony_ci if (dev->set_state_shutdown) 1048c2ecf20Sopenharmony_ci return dev->set_state_shutdown(dev); 1058c2ecf20Sopenharmony_ci return 0; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci case CLOCK_EVT_STATE_PERIODIC: 1088c2ecf20Sopenharmony_ci /* Core internal bug */ 1098c2ecf20Sopenharmony_ci if (!(dev->features & CLOCK_EVT_FEAT_PERIODIC)) 1108c2ecf20Sopenharmony_ci return -ENOSYS; 1118c2ecf20Sopenharmony_ci if (dev->set_state_periodic) 1128c2ecf20Sopenharmony_ci return dev->set_state_periodic(dev); 1138c2ecf20Sopenharmony_ci return 0; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci case CLOCK_EVT_STATE_ONESHOT: 1168c2ecf20Sopenharmony_ci /* Core internal bug */ 1178c2ecf20Sopenharmony_ci if (!(dev->features & CLOCK_EVT_FEAT_ONESHOT)) 1188c2ecf20Sopenharmony_ci return -ENOSYS; 1198c2ecf20Sopenharmony_ci if (dev->set_state_oneshot) 1208c2ecf20Sopenharmony_ci return dev->set_state_oneshot(dev); 1218c2ecf20Sopenharmony_ci return 0; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci case CLOCK_EVT_STATE_ONESHOT_STOPPED: 1248c2ecf20Sopenharmony_ci /* Core internal bug */ 1258c2ecf20Sopenharmony_ci if (WARN_ONCE(!clockevent_state_oneshot(dev), 1268c2ecf20Sopenharmony_ci "Current state: %d\n", 1278c2ecf20Sopenharmony_ci clockevent_get_state(dev))) 1288c2ecf20Sopenharmony_ci return -EINVAL; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (dev->set_state_oneshot_stopped) 1318c2ecf20Sopenharmony_ci return dev->set_state_oneshot_stopped(dev); 1328c2ecf20Sopenharmony_ci else 1338c2ecf20Sopenharmony_ci return -ENOSYS; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci default: 1368c2ecf20Sopenharmony_ci return -ENOSYS; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/** 1418c2ecf20Sopenharmony_ci * clockevents_switch_state - set the operating state of a clock event device 1428c2ecf20Sopenharmony_ci * @dev: device to modify 1438c2ecf20Sopenharmony_ci * @state: new state 1448c2ecf20Sopenharmony_ci * 1458c2ecf20Sopenharmony_ci * Must be called with interrupts disabled ! 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_civoid clockevents_switch_state(struct clock_event_device *dev, 1488c2ecf20Sopenharmony_ci enum clock_event_state state) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci if (clockevent_get_state(dev) != state) { 1518c2ecf20Sopenharmony_ci if (__clockevents_switch_state(dev, state)) 1528c2ecf20Sopenharmony_ci return; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci clockevent_set_state(dev, state); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* 1578c2ecf20Sopenharmony_ci * A nsec2cyc multiplicator of 0 is invalid and we'd crash 1588c2ecf20Sopenharmony_ci * on it, so fix it up and emit a warning: 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_ci if (clockevent_state_oneshot(dev)) { 1618c2ecf20Sopenharmony_ci if (WARN_ON(!dev->mult)) 1628c2ecf20Sopenharmony_ci dev->mult = 1; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci/** 1688c2ecf20Sopenharmony_ci * clockevents_shutdown - shutdown the device and clear next_event 1698c2ecf20Sopenharmony_ci * @dev: device to shutdown 1708c2ecf20Sopenharmony_ci */ 1718c2ecf20Sopenharmony_civoid clockevents_shutdown(struct clock_event_device *dev) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci clockevents_switch_state(dev, CLOCK_EVT_STATE_SHUTDOWN); 1748c2ecf20Sopenharmony_ci dev->next_event = KTIME_MAX; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci/** 1788c2ecf20Sopenharmony_ci * clockevents_tick_resume - Resume the tick device before using it again 1798c2ecf20Sopenharmony_ci * @dev: device to resume 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_ciint clockevents_tick_resume(struct clock_event_device *dev) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci int ret = 0; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (dev->tick_resume) 1868c2ecf20Sopenharmony_ci ret = dev->tick_resume(dev); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return ret; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci#ifdef CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/* Limit min_delta to a jiffie */ 1948c2ecf20Sopenharmony_ci#define MIN_DELTA_LIMIT (NSEC_PER_SEC / HZ) 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/** 1978c2ecf20Sopenharmony_ci * clockevents_increase_min_delta - raise minimum delta of a clock event device 1988c2ecf20Sopenharmony_ci * @dev: device to increase the minimum delta 1998c2ecf20Sopenharmony_ci * 2008c2ecf20Sopenharmony_ci * Returns 0 on success, -ETIME when the minimum delta reached the limit. 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_cistatic int clockevents_increase_min_delta(struct clock_event_device *dev) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci /* Nothing to do if we already reached the limit */ 2058c2ecf20Sopenharmony_ci if (dev->min_delta_ns >= MIN_DELTA_LIMIT) { 2068c2ecf20Sopenharmony_ci printk_deferred(KERN_WARNING 2078c2ecf20Sopenharmony_ci "CE: Reprogramming failure. Giving up\n"); 2088c2ecf20Sopenharmony_ci dev->next_event = KTIME_MAX; 2098c2ecf20Sopenharmony_ci return -ETIME; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (dev->min_delta_ns < 5000) 2138c2ecf20Sopenharmony_ci dev->min_delta_ns = 5000; 2148c2ecf20Sopenharmony_ci else 2158c2ecf20Sopenharmony_ci dev->min_delta_ns += dev->min_delta_ns >> 1; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (dev->min_delta_ns > MIN_DELTA_LIMIT) 2188c2ecf20Sopenharmony_ci dev->min_delta_ns = MIN_DELTA_LIMIT; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci printk_deferred(KERN_WARNING 2218c2ecf20Sopenharmony_ci "CE: %s increased min_delta_ns to %llu nsec\n", 2228c2ecf20Sopenharmony_ci dev->name ? dev->name : "?", 2238c2ecf20Sopenharmony_ci (unsigned long long) dev->min_delta_ns); 2248c2ecf20Sopenharmony_ci return 0; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci/** 2288c2ecf20Sopenharmony_ci * clockevents_program_min_delta - Set clock event device to the minimum delay. 2298c2ecf20Sopenharmony_ci * @dev: device to program 2308c2ecf20Sopenharmony_ci * 2318c2ecf20Sopenharmony_ci * Returns 0 on success, -ETIME when the retry loop failed. 2328c2ecf20Sopenharmony_ci */ 2338c2ecf20Sopenharmony_cistatic int clockevents_program_min_delta(struct clock_event_device *dev) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci unsigned long long clc; 2368c2ecf20Sopenharmony_ci int64_t delta; 2378c2ecf20Sopenharmony_ci int i; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci for (i = 0;;) { 2408c2ecf20Sopenharmony_ci delta = dev->min_delta_ns; 2418c2ecf20Sopenharmony_ci dev->next_event = ktime_add_ns(ktime_get(), delta); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (clockevent_state_shutdown(dev)) 2448c2ecf20Sopenharmony_ci return 0; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci dev->retries++; 2478c2ecf20Sopenharmony_ci clc = ((unsigned long long) delta * dev->mult) >> dev->shift; 2488c2ecf20Sopenharmony_ci if (dev->set_next_event((unsigned long) clc, dev) == 0) 2498c2ecf20Sopenharmony_ci return 0; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (++i > 2) { 2528c2ecf20Sopenharmony_ci /* 2538c2ecf20Sopenharmony_ci * We tried 3 times to program the device with the 2548c2ecf20Sopenharmony_ci * given min_delta_ns. Try to increase the minimum 2558c2ecf20Sopenharmony_ci * delta, if that fails as well get out of here. 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_ci if (clockevents_increase_min_delta(dev)) 2588c2ecf20Sopenharmony_ci return -ETIME; 2598c2ecf20Sopenharmony_ci i = 0; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci#else /* CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST */ 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci/** 2678c2ecf20Sopenharmony_ci * clockevents_program_min_delta - Set clock event device to the minimum delay. 2688c2ecf20Sopenharmony_ci * @dev: device to program 2698c2ecf20Sopenharmony_ci * 2708c2ecf20Sopenharmony_ci * Returns 0 on success, -ETIME when the retry loop failed. 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_cistatic int clockevents_program_min_delta(struct clock_event_device *dev) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci unsigned long long clc; 2758c2ecf20Sopenharmony_ci int64_t delta = 0; 2768c2ecf20Sopenharmony_ci int i; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 2798c2ecf20Sopenharmony_ci delta += dev->min_delta_ns; 2808c2ecf20Sopenharmony_ci dev->next_event = ktime_add_ns(ktime_get(), delta); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (clockevent_state_shutdown(dev)) 2838c2ecf20Sopenharmony_ci return 0; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci dev->retries++; 2868c2ecf20Sopenharmony_ci clc = ((unsigned long long) delta * dev->mult) >> dev->shift; 2878c2ecf20Sopenharmony_ci if (dev->set_next_event((unsigned long) clc, dev) == 0) 2888c2ecf20Sopenharmony_ci return 0; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci return -ETIME; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci#endif /* CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST */ 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci/** 2968c2ecf20Sopenharmony_ci * clockevents_program_event - Reprogram the clock event device. 2978c2ecf20Sopenharmony_ci * @dev: device to program 2988c2ecf20Sopenharmony_ci * @expires: absolute expiry time (monotonic clock) 2998c2ecf20Sopenharmony_ci * @force: program minimum delay if expires can not be set 3008c2ecf20Sopenharmony_ci * 3018c2ecf20Sopenharmony_ci * Returns 0 on success, -ETIME when the event is in the past. 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_ciint clockevents_program_event(struct clock_event_device *dev, ktime_t expires, 3048c2ecf20Sopenharmony_ci bool force) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci unsigned long long clc; 3078c2ecf20Sopenharmony_ci int64_t delta; 3088c2ecf20Sopenharmony_ci int rc; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(expires < 0)) 3118c2ecf20Sopenharmony_ci return -ETIME; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci dev->next_event = expires; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (clockevent_state_shutdown(dev)) 3168c2ecf20Sopenharmony_ci return 0; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* We must be in ONESHOT state here */ 3198c2ecf20Sopenharmony_ci WARN_ONCE(!clockevent_state_oneshot(dev), "Current state: %d\n", 3208c2ecf20Sopenharmony_ci clockevent_get_state(dev)); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* Shortcut for clockevent devices that can deal with ktime. */ 3238c2ecf20Sopenharmony_ci if (dev->features & CLOCK_EVT_FEAT_KTIME) 3248c2ecf20Sopenharmony_ci return dev->set_next_ktime(expires, dev); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci delta = ktime_to_ns(ktime_sub(expires, ktime_get())); 3278c2ecf20Sopenharmony_ci if (delta <= 0) 3288c2ecf20Sopenharmony_ci return force ? clockevents_program_min_delta(dev) : -ETIME; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci delta = min(delta, (int64_t) dev->max_delta_ns); 3318c2ecf20Sopenharmony_ci delta = max(delta, (int64_t) dev->min_delta_ns); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci clc = ((unsigned long long) delta * dev->mult) >> dev->shift; 3348c2ecf20Sopenharmony_ci rc = dev->set_next_event((unsigned long) clc, dev); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci return (rc && force) ? clockevents_program_min_delta(dev) : rc; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci/* 3408c2ecf20Sopenharmony_ci * Called after a notify add to make devices available which were 3418c2ecf20Sopenharmony_ci * released from the notifier call. 3428c2ecf20Sopenharmony_ci */ 3438c2ecf20Sopenharmony_cistatic void clockevents_notify_released(void) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct clock_event_device *dev; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci while (!list_empty(&clockevents_released)) { 3488c2ecf20Sopenharmony_ci dev = list_entry(clockevents_released.next, 3498c2ecf20Sopenharmony_ci struct clock_event_device, list); 3508c2ecf20Sopenharmony_ci list_del(&dev->list); 3518c2ecf20Sopenharmony_ci list_add(&dev->list, &clockevent_devices); 3528c2ecf20Sopenharmony_ci tick_check_new_device(dev); 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci/* 3578c2ecf20Sopenharmony_ci * Try to install a replacement clock event device 3588c2ecf20Sopenharmony_ci */ 3598c2ecf20Sopenharmony_cistatic int clockevents_replace(struct clock_event_device *ced) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci struct clock_event_device *dev, *newdev = NULL; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci list_for_each_entry(dev, &clockevent_devices, list) { 3648c2ecf20Sopenharmony_ci if (dev == ced || !clockevent_state_detached(dev)) 3658c2ecf20Sopenharmony_ci continue; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (!tick_check_replacement(newdev, dev)) 3688c2ecf20Sopenharmony_ci continue; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (!try_module_get(dev->owner)) 3718c2ecf20Sopenharmony_ci continue; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (newdev) 3748c2ecf20Sopenharmony_ci module_put(newdev->owner); 3758c2ecf20Sopenharmony_ci newdev = dev; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci if (newdev) { 3788c2ecf20Sopenharmony_ci tick_install_replacement(newdev); 3798c2ecf20Sopenharmony_ci list_del_init(&ced->list); 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci return newdev ? 0 : -EBUSY; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci/* 3858c2ecf20Sopenharmony_ci * Called with clockevents_mutex and clockevents_lock held 3868c2ecf20Sopenharmony_ci */ 3878c2ecf20Sopenharmony_cistatic int __clockevents_try_unbind(struct clock_event_device *ced, int cpu) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci /* Fast track. Device is unused */ 3908c2ecf20Sopenharmony_ci if (clockevent_state_detached(ced)) { 3918c2ecf20Sopenharmony_ci list_del_init(&ced->list); 3928c2ecf20Sopenharmony_ci return 0; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci return ced == per_cpu(tick_cpu_device, cpu).evtdev ? -EAGAIN : -EBUSY; 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci/* 3998c2ecf20Sopenharmony_ci * SMP function call to unbind a device 4008c2ecf20Sopenharmony_ci */ 4018c2ecf20Sopenharmony_cistatic void __clockevents_unbind(void *arg) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct ce_unbind *cu = arg; 4048c2ecf20Sopenharmony_ci int res; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci raw_spin_lock(&clockevents_lock); 4078c2ecf20Sopenharmony_ci res = __clockevents_try_unbind(cu->ce, smp_processor_id()); 4088c2ecf20Sopenharmony_ci if (res == -EAGAIN) 4098c2ecf20Sopenharmony_ci res = clockevents_replace(cu->ce); 4108c2ecf20Sopenharmony_ci cu->res = res; 4118c2ecf20Sopenharmony_ci raw_spin_unlock(&clockevents_lock); 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci/* 4158c2ecf20Sopenharmony_ci * Issues smp function call to unbind a per cpu device. Called with 4168c2ecf20Sopenharmony_ci * clockevents_mutex held. 4178c2ecf20Sopenharmony_ci */ 4188c2ecf20Sopenharmony_cistatic int clockevents_unbind(struct clock_event_device *ced, int cpu) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci struct ce_unbind cu = { .ce = ced, .res = -ENODEV }; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci smp_call_function_single(cpu, __clockevents_unbind, &cu, 1); 4238c2ecf20Sopenharmony_ci return cu.res; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci/* 4278c2ecf20Sopenharmony_ci * Unbind a clockevents device. 4288c2ecf20Sopenharmony_ci */ 4298c2ecf20Sopenharmony_ciint clockevents_unbind_device(struct clock_event_device *ced, int cpu) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci int ret; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci mutex_lock(&clockevents_mutex); 4348c2ecf20Sopenharmony_ci ret = clockevents_unbind(ced, cpu); 4358c2ecf20Sopenharmony_ci mutex_unlock(&clockevents_mutex); 4368c2ecf20Sopenharmony_ci return ret; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clockevents_unbind_device); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci/** 4418c2ecf20Sopenharmony_ci * clockevents_register_device - register a clock event device 4428c2ecf20Sopenharmony_ci * @dev: device to register 4438c2ecf20Sopenharmony_ci */ 4448c2ecf20Sopenharmony_civoid clockevents_register_device(struct clock_event_device *dev) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci unsigned long flags; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci /* Initialize state to DETACHED */ 4498c2ecf20Sopenharmony_ci clockevent_set_state(dev, CLOCK_EVT_STATE_DETACHED); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (!dev->cpumask) { 4528c2ecf20Sopenharmony_ci WARN_ON(num_possible_cpus() > 1); 4538c2ecf20Sopenharmony_ci dev->cpumask = cpumask_of(smp_processor_id()); 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (dev->cpumask == cpu_all_mask) { 4578c2ecf20Sopenharmony_ci WARN(1, "%s cpumask == cpu_all_mask, using cpu_possible_mask instead\n", 4588c2ecf20Sopenharmony_ci dev->name); 4598c2ecf20Sopenharmony_ci dev->cpumask = cpu_possible_mask; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&clockevents_lock, flags); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci list_add(&dev->list, &clockevent_devices); 4658c2ecf20Sopenharmony_ci tick_check_new_device(dev); 4668c2ecf20Sopenharmony_ci clockevents_notify_released(); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&clockevents_lock, flags); 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clockevents_register_device); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic void clockevents_config(struct clock_event_device *dev, u32 freq) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci u64 sec; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (!(dev->features & CLOCK_EVT_FEAT_ONESHOT)) 4778c2ecf20Sopenharmony_ci return; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci /* 4808c2ecf20Sopenharmony_ci * Calculate the maximum number of seconds we can sleep. Limit 4818c2ecf20Sopenharmony_ci * to 10 minutes for hardware which can program more than 4828c2ecf20Sopenharmony_ci * 32bit ticks so we still get reasonable conversion values. 4838c2ecf20Sopenharmony_ci */ 4848c2ecf20Sopenharmony_ci sec = dev->max_delta_ticks; 4858c2ecf20Sopenharmony_ci do_div(sec, freq); 4868c2ecf20Sopenharmony_ci if (!sec) 4878c2ecf20Sopenharmony_ci sec = 1; 4888c2ecf20Sopenharmony_ci else if (sec > 600 && dev->max_delta_ticks > UINT_MAX) 4898c2ecf20Sopenharmony_ci sec = 600; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci clockevents_calc_mult_shift(dev, freq, sec); 4928c2ecf20Sopenharmony_ci dev->min_delta_ns = cev_delta2ns(dev->min_delta_ticks, dev, false); 4938c2ecf20Sopenharmony_ci dev->max_delta_ns = cev_delta2ns(dev->max_delta_ticks, dev, true); 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci/** 4978c2ecf20Sopenharmony_ci * clockevents_config_and_register - Configure and register a clock event device 4988c2ecf20Sopenharmony_ci * @dev: device to register 4998c2ecf20Sopenharmony_ci * @freq: The clock frequency 5008c2ecf20Sopenharmony_ci * @min_delta: The minimum clock ticks to program in oneshot mode 5018c2ecf20Sopenharmony_ci * @max_delta: The maximum clock ticks to program in oneshot mode 5028c2ecf20Sopenharmony_ci * 5038c2ecf20Sopenharmony_ci * min/max_delta can be 0 for devices which do not support oneshot mode. 5048c2ecf20Sopenharmony_ci */ 5058c2ecf20Sopenharmony_civoid clockevents_config_and_register(struct clock_event_device *dev, 5068c2ecf20Sopenharmony_ci u32 freq, unsigned long min_delta, 5078c2ecf20Sopenharmony_ci unsigned long max_delta) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci dev->min_delta_ticks = min_delta; 5108c2ecf20Sopenharmony_ci dev->max_delta_ticks = max_delta; 5118c2ecf20Sopenharmony_ci clockevents_config(dev, freq); 5128c2ecf20Sopenharmony_ci clockevents_register_device(dev); 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clockevents_config_and_register); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ciint __clockevents_update_freq(struct clock_event_device *dev, u32 freq) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci clockevents_config(dev, freq); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (clockevent_state_oneshot(dev)) 5218c2ecf20Sopenharmony_ci return clockevents_program_event(dev, dev->next_event, false); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (clockevent_state_periodic(dev)) 5248c2ecf20Sopenharmony_ci return __clockevents_switch_state(dev, CLOCK_EVT_STATE_PERIODIC); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci return 0; 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci/** 5308c2ecf20Sopenharmony_ci * clockevents_update_freq - Update frequency and reprogram a clock event device. 5318c2ecf20Sopenharmony_ci * @dev: device to modify 5328c2ecf20Sopenharmony_ci * @freq: new device frequency 5338c2ecf20Sopenharmony_ci * 5348c2ecf20Sopenharmony_ci * Reconfigure and reprogram a clock event device in oneshot 5358c2ecf20Sopenharmony_ci * mode. Must be called on the cpu for which the device delivers per 5368c2ecf20Sopenharmony_ci * cpu timer events. If called for the broadcast device the core takes 5378c2ecf20Sopenharmony_ci * care of serialization. 5388c2ecf20Sopenharmony_ci * 5398c2ecf20Sopenharmony_ci * Returns 0 on success, -ETIME when the event is in the past. 5408c2ecf20Sopenharmony_ci */ 5418c2ecf20Sopenharmony_ciint clockevents_update_freq(struct clock_event_device *dev, u32 freq) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci unsigned long flags; 5448c2ecf20Sopenharmony_ci int ret; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci local_irq_save(flags); 5478c2ecf20Sopenharmony_ci ret = tick_broadcast_update_freq(dev, freq); 5488c2ecf20Sopenharmony_ci if (ret == -ENODEV) 5498c2ecf20Sopenharmony_ci ret = __clockevents_update_freq(dev, freq); 5508c2ecf20Sopenharmony_ci local_irq_restore(flags); 5518c2ecf20Sopenharmony_ci return ret; 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci/* 5558c2ecf20Sopenharmony_ci * Noop handler when we shut down an event device 5568c2ecf20Sopenharmony_ci */ 5578c2ecf20Sopenharmony_civoid clockevents_handle_noop(struct clock_event_device *dev) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci/** 5628c2ecf20Sopenharmony_ci * clockevents_exchange_device - release and request clock devices 5638c2ecf20Sopenharmony_ci * @old: device to release (can be NULL) 5648c2ecf20Sopenharmony_ci * @new: device to request (can be NULL) 5658c2ecf20Sopenharmony_ci * 5668c2ecf20Sopenharmony_ci * Called from various tick functions with clockevents_lock held and 5678c2ecf20Sopenharmony_ci * interrupts disabled. 5688c2ecf20Sopenharmony_ci */ 5698c2ecf20Sopenharmony_civoid clockevents_exchange_device(struct clock_event_device *old, 5708c2ecf20Sopenharmony_ci struct clock_event_device *new) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci /* 5738c2ecf20Sopenharmony_ci * Caller releases a clock event device. We queue it into the 5748c2ecf20Sopenharmony_ci * released list and do a notify add later. 5758c2ecf20Sopenharmony_ci */ 5768c2ecf20Sopenharmony_ci if (old) { 5778c2ecf20Sopenharmony_ci module_put(old->owner); 5788c2ecf20Sopenharmony_ci clockevents_switch_state(old, CLOCK_EVT_STATE_DETACHED); 5798c2ecf20Sopenharmony_ci list_del(&old->list); 5808c2ecf20Sopenharmony_ci list_add(&old->list, &clockevents_released); 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (new) { 5848c2ecf20Sopenharmony_ci BUG_ON(!clockevent_state_detached(new)); 5858c2ecf20Sopenharmony_ci clockevents_shutdown(new); 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci/** 5908c2ecf20Sopenharmony_ci * clockevents_suspend - suspend clock devices 5918c2ecf20Sopenharmony_ci */ 5928c2ecf20Sopenharmony_civoid clockevents_suspend(void) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci struct clock_event_device *dev; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci list_for_each_entry_reverse(dev, &clockevent_devices, list) 5978c2ecf20Sopenharmony_ci if (dev->suspend && !clockevent_state_detached(dev)) 5988c2ecf20Sopenharmony_ci dev->suspend(dev); 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci/** 6028c2ecf20Sopenharmony_ci * clockevents_resume - resume clock devices 6038c2ecf20Sopenharmony_ci */ 6048c2ecf20Sopenharmony_civoid clockevents_resume(void) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci struct clock_event_device *dev; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci list_for_each_entry(dev, &clockevent_devices, list) 6098c2ecf20Sopenharmony_ci if (dev->resume && !clockevent_state_detached(dev)) 6108c2ecf20Sopenharmony_ci dev->resume(dev); 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci# ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 6168c2ecf20Sopenharmony_ci/** 6178c2ecf20Sopenharmony_ci * tick_offline_cpu - Take CPU out of the broadcast mechanism 6188c2ecf20Sopenharmony_ci * @cpu: The outgoing CPU 6198c2ecf20Sopenharmony_ci * 6208c2ecf20Sopenharmony_ci * Called on the outgoing CPU after it took itself offline. 6218c2ecf20Sopenharmony_ci */ 6228c2ecf20Sopenharmony_civoid tick_offline_cpu(unsigned int cpu) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci raw_spin_lock(&clockevents_lock); 6258c2ecf20Sopenharmony_ci tick_broadcast_offline(cpu); 6268c2ecf20Sopenharmony_ci raw_spin_unlock(&clockevents_lock); 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci# endif 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci/** 6318c2ecf20Sopenharmony_ci * tick_cleanup_dead_cpu - Cleanup the tick and clockevents of a dead cpu 6328c2ecf20Sopenharmony_ci */ 6338c2ecf20Sopenharmony_civoid tick_cleanup_dead_cpu(int cpu) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci struct clock_event_device *dev, *tmp; 6368c2ecf20Sopenharmony_ci unsigned long flags; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&clockevents_lock, flags); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci tick_shutdown(cpu); 6418c2ecf20Sopenharmony_ci /* 6428c2ecf20Sopenharmony_ci * Unregister the clock event devices which were 6438c2ecf20Sopenharmony_ci * released from the users in the notify chain. 6448c2ecf20Sopenharmony_ci */ 6458c2ecf20Sopenharmony_ci list_for_each_entry_safe(dev, tmp, &clockevents_released, list) 6468c2ecf20Sopenharmony_ci list_del(&dev->list); 6478c2ecf20Sopenharmony_ci /* 6488c2ecf20Sopenharmony_ci * Now check whether the CPU has left unused per cpu devices 6498c2ecf20Sopenharmony_ci */ 6508c2ecf20Sopenharmony_ci list_for_each_entry_safe(dev, tmp, &clockevent_devices, list) { 6518c2ecf20Sopenharmony_ci if (cpumask_test_cpu(cpu, dev->cpumask) && 6528c2ecf20Sopenharmony_ci cpumask_weight(dev->cpumask) == 1 && 6538c2ecf20Sopenharmony_ci !tick_is_broadcast_device(dev)) { 6548c2ecf20Sopenharmony_ci BUG_ON(!clockevent_state_detached(dev)); 6558c2ecf20Sopenharmony_ci list_del(&dev->list); 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&clockevents_lock, flags); 6598c2ecf20Sopenharmony_ci} 6608c2ecf20Sopenharmony_ci#endif 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci#ifdef CONFIG_SYSFS 6638c2ecf20Sopenharmony_cistatic struct bus_type clockevents_subsys = { 6648c2ecf20Sopenharmony_ci .name = "clockevents", 6658c2ecf20Sopenharmony_ci .dev_name = "clockevent", 6668c2ecf20Sopenharmony_ci}; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct device, tick_percpu_dev); 6698c2ecf20Sopenharmony_cistatic struct tick_device *tick_get_tick_dev(struct device *dev); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic ssize_t sysfs_show_current_tick_dev(struct device *dev, 6728c2ecf20Sopenharmony_ci struct device_attribute *attr, 6738c2ecf20Sopenharmony_ci char *buf) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci struct tick_device *td; 6768c2ecf20Sopenharmony_ci ssize_t count = 0; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci raw_spin_lock_irq(&clockevents_lock); 6798c2ecf20Sopenharmony_ci td = tick_get_tick_dev(dev); 6808c2ecf20Sopenharmony_ci if (td && td->evtdev) 6818c2ecf20Sopenharmony_ci count = snprintf(buf, PAGE_SIZE, "%s\n", td->evtdev->name); 6828c2ecf20Sopenharmony_ci raw_spin_unlock_irq(&clockevents_lock); 6838c2ecf20Sopenharmony_ci return count; 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_cistatic DEVICE_ATTR(current_device, 0444, sysfs_show_current_tick_dev, NULL); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci/* We don't support the abomination of removable broadcast devices */ 6888c2ecf20Sopenharmony_cistatic ssize_t sysfs_unbind_tick_dev(struct device *dev, 6898c2ecf20Sopenharmony_ci struct device_attribute *attr, 6908c2ecf20Sopenharmony_ci const char *buf, size_t count) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci char name[CS_NAME_LEN]; 6938c2ecf20Sopenharmony_ci ssize_t ret = sysfs_get_uname(buf, name, count); 6948c2ecf20Sopenharmony_ci struct clock_event_device *ce; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (ret < 0) 6978c2ecf20Sopenharmony_ci return ret; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci ret = -ENODEV; 7008c2ecf20Sopenharmony_ci mutex_lock(&clockevents_mutex); 7018c2ecf20Sopenharmony_ci raw_spin_lock_irq(&clockevents_lock); 7028c2ecf20Sopenharmony_ci list_for_each_entry(ce, &clockevent_devices, list) { 7038c2ecf20Sopenharmony_ci if (!strcmp(ce->name, name)) { 7048c2ecf20Sopenharmony_ci ret = __clockevents_try_unbind(ce, dev->id); 7058c2ecf20Sopenharmony_ci break; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci raw_spin_unlock_irq(&clockevents_lock); 7098c2ecf20Sopenharmony_ci /* 7108c2ecf20Sopenharmony_ci * We hold clockevents_mutex, so ce can't go away 7118c2ecf20Sopenharmony_ci */ 7128c2ecf20Sopenharmony_ci if (ret == -EAGAIN) 7138c2ecf20Sopenharmony_ci ret = clockevents_unbind(ce, dev->id); 7148c2ecf20Sopenharmony_ci mutex_unlock(&clockevents_mutex); 7158c2ecf20Sopenharmony_ci return ret ? ret : count; 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_cistatic DEVICE_ATTR(unbind_device, 0200, NULL, sysfs_unbind_tick_dev); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 7208c2ecf20Sopenharmony_cistatic struct device tick_bc_dev = { 7218c2ecf20Sopenharmony_ci .init_name = "broadcast", 7228c2ecf20Sopenharmony_ci .id = 0, 7238c2ecf20Sopenharmony_ci .bus = &clockevents_subsys, 7248c2ecf20Sopenharmony_ci}; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistatic struct tick_device *tick_get_tick_dev(struct device *dev) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci return dev == &tick_bc_dev ? tick_get_broadcast_device() : 7298c2ecf20Sopenharmony_ci &per_cpu(tick_cpu_device, dev->id); 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cistatic __init int tick_broadcast_init_sysfs(void) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci int err = device_register(&tick_bc_dev); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if (!err) 7378c2ecf20Sopenharmony_ci err = device_create_file(&tick_bc_dev, &dev_attr_current_device); 7388c2ecf20Sopenharmony_ci return err; 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci#else 7418c2ecf20Sopenharmony_cistatic struct tick_device *tick_get_tick_dev(struct device *dev) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci return &per_cpu(tick_cpu_device, dev->id); 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_cistatic inline int tick_broadcast_init_sysfs(void) { return 0; } 7468c2ecf20Sopenharmony_ci#endif 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cistatic int __init tick_init_sysfs(void) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci int cpu; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 7538c2ecf20Sopenharmony_ci struct device *dev = &per_cpu(tick_percpu_dev, cpu); 7548c2ecf20Sopenharmony_ci int err; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci dev->id = cpu; 7578c2ecf20Sopenharmony_ci dev->bus = &clockevents_subsys; 7588c2ecf20Sopenharmony_ci err = device_register(dev); 7598c2ecf20Sopenharmony_ci if (!err) 7608c2ecf20Sopenharmony_ci err = device_create_file(dev, &dev_attr_current_device); 7618c2ecf20Sopenharmony_ci if (!err) 7628c2ecf20Sopenharmony_ci err = device_create_file(dev, &dev_attr_unbind_device); 7638c2ecf20Sopenharmony_ci if (err) 7648c2ecf20Sopenharmony_ci return err; 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci return tick_broadcast_init_sysfs(); 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_cistatic int __init clockevents_init_sysfs(void) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci int err = subsys_system_register(&clockevents_subsys, NULL); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if (!err) 7748c2ecf20Sopenharmony_ci err = tick_init_sysfs(); 7758c2ecf20Sopenharmony_ci return err; 7768c2ecf20Sopenharmony_ci} 7778c2ecf20Sopenharmony_cidevice_initcall(clockevents_init_sysfs); 7788c2ecf20Sopenharmony_ci#endif /* SYSFS */ 779