138ff87f7SStephen Boyd /* 238ff87f7SStephen Boyd * sched_clock.c: support for extending counters to full 64-bit ns counter 338ff87f7SStephen Boyd * 438ff87f7SStephen Boyd * This program is free software; you can redistribute it and/or modify 538ff87f7SStephen Boyd * it under the terms of the GNU General Public License version 2 as 638ff87f7SStephen Boyd * published by the Free Software Foundation. 738ff87f7SStephen Boyd */ 838ff87f7SStephen Boyd #include <linux/clocksource.h> 938ff87f7SStephen Boyd #include <linux/init.h> 1038ff87f7SStephen Boyd #include <linux/jiffies.h> 11a08ca5d1SStephen Boyd #include <linux/ktime.h> 1238ff87f7SStephen Boyd #include <linux/kernel.h> 1338ff87f7SStephen Boyd #include <linux/moduleparam.h> 1438ff87f7SStephen Boyd #include <linux/sched.h> 1538ff87f7SStephen Boyd #include <linux/syscore_ops.h> 16a08ca5d1SStephen Boyd #include <linux/hrtimer.h> 1738ff87f7SStephen Boyd #include <linux/sched_clock.h> 1885c3d2ddSStephen Boyd #include <linux/seqlock.h> 19e7e3ff1bSStephen Boyd #include <linux/bitops.h> 2038ff87f7SStephen Boyd 21cf7c9c17SDaniel Thompson /** 22cf7c9c17SDaniel Thompson * struct clock_read_data - data required to read from sched_clock 23cf7c9c17SDaniel Thompson * 24cf7c9c17SDaniel Thompson * @epoch_ns: sched_clock value at last update 25cf7c9c17SDaniel Thompson * @epoch_cyc: Clock cycle value at last update 26cf7c9c17SDaniel Thompson * @sched_clock_mask: Bitmask for two's complement subtraction of non 64bit 27cf7c9c17SDaniel Thompson * clocks 28cf7c9c17SDaniel Thompson * @read_sched_clock: Current clock source (or dummy source when suspended) 29cf7c9c17SDaniel Thompson * @mult: Multipler for scaled math conversion 30cf7c9c17SDaniel Thompson * @shift: Shift value for scaled math conversion 31cf7c9c17SDaniel Thompson * 32cf7c9c17SDaniel Thompson * Care must be taken when updating this structure; it is read by 3313dbeb38SDaniel Thompson * some very hot code paths. It occupies <=40 bytes and, when combined 34cf7c9c17SDaniel Thompson * with the seqcount used to synchronize access, comfortably fits into 35cf7c9c17SDaniel Thompson * a 64 byte cache line. 36cf7c9c17SDaniel Thompson */ 37cf7c9c17SDaniel Thompson struct clock_read_data { 3838ff87f7SStephen Boyd u64 epoch_ns; 39e7e3ff1bSStephen Boyd u64 epoch_cyc; 40cf7c9c17SDaniel Thompson u64 sched_clock_mask; 41cf7c9c17SDaniel Thompson u64 (*read_sched_clock)(void); 4238ff87f7SStephen Boyd u32 mult; 4338ff87f7SStephen Boyd u32 shift; 4438ff87f7SStephen Boyd }; 4538ff87f7SStephen Boyd 46cf7c9c17SDaniel Thompson /** 47cf7c9c17SDaniel Thompson * struct clock_data - all data needed for sched_clock (including 48cf7c9c17SDaniel Thompson * registration of a new clock source) 49cf7c9c17SDaniel Thompson * 50cf7c9c17SDaniel Thompson * @seq: Sequence counter for protecting updates. 51cf7c9c17SDaniel Thompson * @read_data: Data required to read from sched_clock. 52cf7c9c17SDaniel Thompson * @wrap_kt: Duration for which clock can run before wrapping 53cf7c9c17SDaniel Thompson * @rate: Tick rate of the registered clock 54cf7c9c17SDaniel Thompson * @actual_read_sched_clock: Registered clock read function 55cf7c9c17SDaniel Thompson * 56cf7c9c17SDaniel Thompson * The ordering of this structure has been chosen to optimize cache 57cf7c9c17SDaniel Thompson * performance. In particular seq and read_data (combined) should fit 58cf7c9c17SDaniel Thompson * into a single 64 byte cache line. 59cf7c9c17SDaniel Thompson */ 60cf7c9c17SDaniel Thompson struct clock_data { 61cf7c9c17SDaniel Thompson seqcount_t seq; 62cf7c9c17SDaniel Thompson struct clock_read_data read_data; 63cf7c9c17SDaniel Thompson ktime_t wrap_kt; 64cf7c9c17SDaniel Thompson unsigned long rate; 6513dbeb38SDaniel Thompson u64 (*actual_read_sched_clock)(void); 66cf7c9c17SDaniel Thompson }; 67cf7c9c17SDaniel Thompson 68a08ca5d1SStephen Boyd static struct hrtimer sched_clock_timer; 6938ff87f7SStephen Boyd static int irqtime = -1; 7038ff87f7SStephen Boyd 7138ff87f7SStephen Boyd core_param(irqtime, irqtime, int, 0400); 7238ff87f7SStephen Boyd 73e7e3ff1bSStephen Boyd static u64 notrace jiffy_sched_clock_read(void) 7438ff87f7SStephen Boyd { 75e7e3ff1bSStephen Boyd /* 76e7e3ff1bSStephen Boyd * We don't need to use get_jiffies_64 on 32-bit arches here 77e7e3ff1bSStephen Boyd * because we register with BITS_PER_LONG 78e7e3ff1bSStephen Boyd */ 79e7e3ff1bSStephen Boyd return (u64)(jiffies - INITIAL_JIFFIES); 8038ff87f7SStephen Boyd } 8138ff87f7SStephen Boyd 82cf7c9c17SDaniel Thompson static struct clock_data cd ____cacheline_aligned = { 83cf7c9c17SDaniel Thompson .read_data = { .mult = NSEC_PER_SEC / HZ, 84cf7c9c17SDaniel Thompson .read_sched_clock = jiffy_sched_clock_read, }, 8513dbeb38SDaniel Thompson .actual_read_sched_clock = jiffy_sched_clock_read, 8613dbeb38SDaniel Thompson 87cf7c9c17SDaniel Thompson }; 8838ff87f7SStephen Boyd 8938ff87f7SStephen Boyd static inline u64 notrace cyc_to_ns(u64 cyc, u32 mult, u32 shift) 9038ff87f7SStephen Boyd { 9138ff87f7SStephen Boyd return (cyc * mult) >> shift; 9238ff87f7SStephen Boyd } 9338ff87f7SStephen Boyd 94b4042ceaSStephen Boyd unsigned long long notrace sched_clock(void) 9538ff87f7SStephen Boyd { 968710e914SDaniel Thompson u64 cyc, res; 9785c3d2ddSStephen Boyd unsigned long seq; 98cf7c9c17SDaniel Thompson struct clock_read_data *rd = &cd.read_data; 99336ae118SStephen Boyd 10038ff87f7SStephen Boyd do { 1017a06c41cSJohn Stultz seq = raw_read_seqcount_begin(&cd.seq); 1028710e914SDaniel Thompson 10313dbeb38SDaniel Thompson cyc = (rd->read_sched_clock() - rd->epoch_cyc) & 10413dbeb38SDaniel Thompson rd->sched_clock_mask; 10513dbeb38SDaniel Thompson res = rd->epoch_ns + cyc_to_ns(cyc, rd->mult, rd->shift); 10685c3d2ddSStephen Boyd } while (read_seqcount_retry(&cd.seq, seq)); 10738ff87f7SStephen Boyd 1088710e914SDaniel Thompson return res; 10938ff87f7SStephen Boyd } 11038ff87f7SStephen Boyd 11138ff87f7SStephen Boyd /* 11238ff87f7SStephen Boyd * Atomically update the sched_clock epoch. 11338ff87f7SStephen Boyd */ 114*9fee69a8SDaniel Thompson static void update_sched_clock(void) 11538ff87f7SStephen Boyd { 11638ff87f7SStephen Boyd unsigned long flags; 117e7e3ff1bSStephen Boyd u64 cyc; 11838ff87f7SStephen Boyd u64 ns; 119cf7c9c17SDaniel Thompson struct clock_read_data *rd = &cd.read_data; 12038ff87f7SStephen Boyd 12113dbeb38SDaniel Thompson cyc = cd.actual_read_sched_clock(); 122cf7c9c17SDaniel Thompson ns = rd->epoch_ns + 123cf7c9c17SDaniel Thompson cyc_to_ns((cyc - rd->epoch_cyc) & rd->sched_clock_mask, 124cf7c9c17SDaniel Thompson rd->mult, rd->shift); 12585c3d2ddSStephen Boyd 12638ff87f7SStephen Boyd raw_local_irq_save(flags); 1277a06c41cSJohn Stultz raw_write_seqcount_begin(&cd.seq); 128cf7c9c17SDaniel Thompson rd->epoch_ns = ns; 129cf7c9c17SDaniel Thompson rd->epoch_cyc = cyc; 1307a06c41cSJohn Stultz raw_write_seqcount_end(&cd.seq); 13138ff87f7SStephen Boyd raw_local_irq_restore(flags); 13238ff87f7SStephen Boyd } 13338ff87f7SStephen Boyd 134a08ca5d1SStephen Boyd static enum hrtimer_restart sched_clock_poll(struct hrtimer *hrt) 13538ff87f7SStephen Boyd { 13638ff87f7SStephen Boyd update_sched_clock(); 137a08ca5d1SStephen Boyd hrtimer_forward_now(hrt, cd.wrap_kt); 138a08ca5d1SStephen Boyd return HRTIMER_RESTART; 13938ff87f7SStephen Boyd } 14038ff87f7SStephen Boyd 141e7e3ff1bSStephen Boyd void __init sched_clock_register(u64 (*read)(void), int bits, 142e7e3ff1bSStephen Boyd unsigned long rate) 14338ff87f7SStephen Boyd { 1445ae8aabeSStephen Boyd u64 res, wrap, new_mask, new_epoch, cyc, ns; 1455ae8aabeSStephen Boyd u32 new_mult, new_shift; 146a08ca5d1SStephen Boyd unsigned long r; 14738ff87f7SStephen Boyd char r_unit; 148cf7c9c17SDaniel Thompson struct clock_read_data *rd = &cd.read_data; 14938ff87f7SStephen Boyd 15038ff87f7SStephen Boyd if (cd.rate > rate) 15138ff87f7SStephen Boyd return; 15238ff87f7SStephen Boyd 15338ff87f7SStephen Boyd WARN_ON(!irqs_disabled()); 15438ff87f7SStephen Boyd 15538ff87f7SStephen Boyd /* calculate the mult/shift to convert counter ticks to ns. */ 1565ae8aabeSStephen Boyd clocks_calc_mult_shift(&new_mult, &new_shift, rate, NSEC_PER_SEC, 3600); 1575ae8aabeSStephen Boyd 1585ae8aabeSStephen Boyd new_mask = CLOCKSOURCE_MASK(bits); 1598710e914SDaniel Thompson cd.rate = rate; 1605ae8aabeSStephen Boyd 161362fde04SJohn Stultz /* calculate how many nanosecs until we risk wrapping */ 162fb82fe2fSJohn Stultz wrap = clocks_calc_max_nsecs(new_mult, new_shift, 0, new_mask, NULL); 1638710e914SDaniel Thompson cd.wrap_kt = ns_to_ktime(wrap); 1645ae8aabeSStephen Boyd 1655ae8aabeSStephen Boyd /* update epoch for new counter and update epoch_ns from old counter*/ 1665ae8aabeSStephen Boyd new_epoch = read(); 16713dbeb38SDaniel Thompson cyc = cd.actual_read_sched_clock(); 168cf7c9c17SDaniel Thompson ns = rd->epoch_ns + 169cf7c9c17SDaniel Thompson cyc_to_ns((cyc - rd->epoch_cyc) & rd->sched_clock_mask, 170cf7c9c17SDaniel Thompson rd->mult, rd->shift); 17113dbeb38SDaniel Thompson cd.actual_read_sched_clock = read; 1725ae8aabeSStephen Boyd 1735ae8aabeSStephen Boyd raw_write_seqcount_begin(&cd.seq); 174cf7c9c17SDaniel Thompson rd->read_sched_clock = read; 175cf7c9c17SDaniel Thompson rd->sched_clock_mask = new_mask; 176cf7c9c17SDaniel Thompson rd->mult = new_mult; 177cf7c9c17SDaniel Thompson rd->shift = new_shift; 178cf7c9c17SDaniel Thompson rd->epoch_cyc = new_epoch; 179cf7c9c17SDaniel Thompson rd->epoch_ns = ns; 1805ae8aabeSStephen Boyd raw_write_seqcount_end(&cd.seq); 18138ff87f7SStephen Boyd 18238ff87f7SStephen Boyd r = rate; 18338ff87f7SStephen Boyd if (r >= 4000000) { 18438ff87f7SStephen Boyd r /= 1000000; 18538ff87f7SStephen Boyd r_unit = 'M'; 18638ff87f7SStephen Boyd } else if (r >= 1000) { 18738ff87f7SStephen Boyd r /= 1000; 18838ff87f7SStephen Boyd r_unit = 'k'; 18938ff87f7SStephen Boyd } else 19038ff87f7SStephen Boyd r_unit = ' '; 19138ff87f7SStephen Boyd 19238ff87f7SStephen Boyd /* calculate the ns resolution of this counter */ 1935ae8aabeSStephen Boyd res = cyc_to_ns(1ULL, new_mult, new_shift); 1945ae8aabeSStephen Boyd 195a08ca5d1SStephen Boyd pr_info("sched_clock: %u bits at %lu%cHz, resolution %lluns, wraps every %lluns\n", 196a08ca5d1SStephen Boyd bits, r, r_unit, res, wrap); 19738ff87f7SStephen Boyd 19838ff87f7SStephen Boyd /* Enable IRQ time accounting if we have a fast enough sched_clock */ 19938ff87f7SStephen Boyd if (irqtime > 0 || (irqtime == -1 && rate >= 1000000)) 20038ff87f7SStephen Boyd enable_sched_clock_irqtime(); 20138ff87f7SStephen Boyd 20238ff87f7SStephen Boyd pr_debug("Registered %pF as sched_clock source\n", read); 20338ff87f7SStephen Boyd } 20438ff87f7SStephen Boyd 20538ff87f7SStephen Boyd void __init sched_clock_postinit(void) 20638ff87f7SStephen Boyd { 20738ff87f7SStephen Boyd /* 20838ff87f7SStephen Boyd * If no sched_clock function has been provided at that point, 20938ff87f7SStephen Boyd * make it the final one one. 21038ff87f7SStephen Boyd */ 21113dbeb38SDaniel Thompson if (cd.actual_read_sched_clock == jiffy_sched_clock_read) 212e7e3ff1bSStephen Boyd sched_clock_register(jiffy_sched_clock_read, BITS_PER_LONG, HZ); 21338ff87f7SStephen Boyd 214a08ca5d1SStephen Boyd update_sched_clock(); 215a08ca5d1SStephen Boyd 216a08ca5d1SStephen Boyd /* 217a08ca5d1SStephen Boyd * Start the timer to keep sched_clock() properly updated and 218a08ca5d1SStephen Boyd * sets the initial epoch. 219a08ca5d1SStephen Boyd */ 220a08ca5d1SStephen Boyd hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 221a08ca5d1SStephen Boyd sched_clock_timer.function = sched_clock_poll; 222a08ca5d1SStephen Boyd hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL); 22338ff87f7SStephen Boyd } 22438ff87f7SStephen Boyd 22513dbeb38SDaniel Thompson /* 22613dbeb38SDaniel Thompson * Clock read function for use when the clock is suspended. 22713dbeb38SDaniel Thompson * 22813dbeb38SDaniel Thompson * This function makes it appear to sched_clock() as if the clock 22913dbeb38SDaniel Thompson * stopped counting at its last update. 23013dbeb38SDaniel Thompson */ 23113dbeb38SDaniel Thompson static u64 notrace suspended_sched_clock_read(void) 23213dbeb38SDaniel Thompson { 23313dbeb38SDaniel Thompson return cd.read_data.epoch_cyc; 23413dbeb38SDaniel Thompson } 23513dbeb38SDaniel Thompson 23638ff87f7SStephen Boyd static int sched_clock_suspend(void) 23738ff87f7SStephen Boyd { 238cf7c9c17SDaniel Thompson struct clock_read_data *rd = &cd.read_data; 239cf7c9c17SDaniel Thompson 240f723aa18SStephen Boyd update_sched_clock(); 241f723aa18SStephen Boyd hrtimer_cancel(&sched_clock_timer); 24213dbeb38SDaniel Thompson rd->read_sched_clock = suspended_sched_clock_read; 24338ff87f7SStephen Boyd return 0; 24438ff87f7SStephen Boyd } 24538ff87f7SStephen Boyd 24638ff87f7SStephen Boyd static void sched_clock_resume(void) 24738ff87f7SStephen Boyd { 248cf7c9c17SDaniel Thompson struct clock_read_data *rd = &cd.read_data; 249cf7c9c17SDaniel Thompson 25013dbeb38SDaniel Thompson rd->epoch_cyc = cd.actual_read_sched_clock(); 251f723aa18SStephen Boyd hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL); 25213dbeb38SDaniel Thompson rd->read_sched_clock = cd.actual_read_sched_clock; 25338ff87f7SStephen Boyd } 25438ff87f7SStephen Boyd 25538ff87f7SStephen Boyd static struct syscore_ops sched_clock_ops = { 25638ff87f7SStephen Boyd .suspend = sched_clock_suspend, 25738ff87f7SStephen Boyd .resume = sched_clock_resume, 25838ff87f7SStephen Boyd }; 25938ff87f7SStephen Boyd 26038ff87f7SStephen Boyd static int __init sched_clock_syscore_init(void) 26138ff87f7SStephen Boyd { 26238ff87f7SStephen Boyd register_syscore_ops(&sched_clock_ops); 26338ff87f7SStephen Boyd return 0; 26438ff87f7SStephen Boyd } 26538ff87f7SStephen Boyd device_initcall(sched_clock_syscore_init); 266