remove version in all files
[dpdk.git] / lib / librte_eal / linuxapp / eal / eal_hpet.c
1 /*-
2  *   BSD LICENSE
3  * 
4  *   Copyright(c) 2010-2012 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  * 
7  *   Redistribution and use in source and binary forms, with or without 
8  *   modification, are permitted provided that the following conditions 
9  *   are met:
10  * 
11  *     * Redistributions of source code must retain the above copyright 
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright 
14  *       notice, this list of conditions and the following disclaimer in 
15  *       the documentation and/or other materials provided with the 
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its 
18  *       contributors may be used to endorse or promote products derived 
19  *       from this software without specific prior written permission.
20  * 
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  * 
33  */
34
35 #include <string.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <stdarg.h>
39 #include <stdint.h>
40 #include <fcntl.h>
41 #include <inttypes.h>
42 #include <sys/mman.h>
43 #include <sys/queue.h>
44 #include <unistd.h>
45 #include <pthread.h>
46 #include <errno.h>
47
48 #include <rte_common.h>
49 #include <rte_log.h>
50 #include <rte_cycles.h>
51 #include <rte_tailq.h>
52 #include <rte_memory.h>
53 #include <rte_memzone.h>
54 #include <rte_eal.h>
55
56 #include "eal_private.h"
57 #include "eal_internal_cfg.h"
58
59 #define DEV_HPET "/dev/hpet"
60
61 /* Maximum number of counters. */
62 #define HPET_TIMER_NUM 3
63
64 /* General capabilities register */
65 #define CLK_PERIOD_SHIFT     32 /* Clock period shift. */
66 #define CLK_PERIOD_MASK      0xffffffff00000000ULL /* Clock period mask. */
67 #define COUNT_SIZE_CAP_SHIFT 13 /* Count size capa. shift. */
68 #define COUNT_SIZE_CAP_MASK 0x0000000000002000ULL /* Count size capa. mask. */
69
70 /**
71  * HPET timer registers. From the Intel IA-PC HPET (High Precision Event
72  * Timers) Specification.
73  */
74 struct eal_hpet_regs {
75         /* Memory-mapped, software visible registers */
76         uint64_t capabilities;      /**< RO General Capabilities Register. */
77         uint64_t reserved0;         /**< Reserved for future use. */
78         uint64_t config;            /**< RW General Configuration Register. */
79         uint64_t reserved1;         /**< Reserved for future use. */
80         uint64_t isr;               /**< RW Clear General Interrupt Status. */
81         uint64_t reserved2[25];     /**< Reserved for future use. */
82         union {
83                 uint64_t counter;   /**< RW Main Counter Value Register. */
84                 struct {
85                         uint32_t counter_l; /**< RW Main Counter Low. */
86                         uint32_t counter_h; /**< RW Main Counter High. */
87                 };
88         };
89         uint64_t reserved3;         /**< Reserved for future use. */
90         struct {
91                 uint64_t config;    /**< RW Timer Config and Capability Reg. */
92                 uint64_t comp;      /**< RW Timer Comparator Value Register. */
93                 uint64_t fsb;       /**< RW FSB Interrupt Route Register. */
94                 uint64_t reserved4; /**< Reserved for future use. */
95         } timers[HPET_TIMER_NUM]; /**< Set of HPET timers. */
96 };
97
98 /* Mmap'd hpet registers */
99 static volatile struct eal_hpet_regs *eal_hpet = NULL;
100
101 /* Period at which the counter increments in femtoseconds (10^-15 seconds). */
102 static uint32_t eal_hpet_resolution_fs = 0;
103
104 /* Frequency of the counter in Hz */
105 static uint64_t eal_hpet_resolution_hz = 0;
106
107 /* Incremented 4 times during one 32bits hpet full count */
108 static uint32_t eal_hpet_msb;
109
110 static pthread_t msb_inc_thread_id;
111
112 /*
113  * This function runs on a specific thread to update a global variable
114  * containing used to process MSB of the HPET (unfortunatelly, we need
115  * this because hpet is 32 bits by default under linux).
116  */
117 static __attribute__((noreturn)) void *
118 hpet_msb_inc(__attribute__((unused)) void *arg)
119 {
120         uint32_t t;
121
122         while (1) {
123                 t = (eal_hpet->counter_l >> 30);
124                 if (t != (eal_hpet_msb & 3))
125                         eal_hpet_msb ++;
126                 sleep(10);
127         }
128 }
129
130 static inline void
131 set_rdtsc_freq(void)
132 {
133         uint64_t start;
134
135         start = rte_rdtsc();
136         sleep(1);
137         eal_hpet_resolution_hz = rte_rdtsc() - start;
138         eal_hpet_resolution_fs = (uint32_t)
139                         ((1.0 / eal_hpet_resolution_hz) / 1e-15);
140 }
141
142 /*
143  * Open and mmap /dev/hpet (high precision event timer) that will
144  * provide our time reference.
145  */
146 int
147 rte_eal_hpet_init(void)
148 {
149         int fd, ret;
150
151         if (internal_config.no_hpet) {
152                 goto use_rdtsc;
153         }
154
155         fd = open(DEV_HPET, O_RDONLY);
156         if (fd < 0) {
157                 RTE_LOG(WARNING, EAL, "WARNING: Cannot open "DEV_HPET": %s! "
158                                 "The TSC will be used instead.\n",
159                         strerror(errno));
160                 goto use_rdtsc;
161         }
162         eal_hpet = mmap(NULL, 1024, PROT_READ, MAP_SHARED, fd, 0);
163         if (eal_hpet == MAP_FAILED) {
164                 RTE_LOG(WARNING, EAL, "WARNING: Cannot mmap "DEV_HPET"! "
165                                 "The TSC will be used instead.\n");
166                 close(fd);
167                 goto use_rdtsc;
168         }
169         close(fd);
170
171         eal_hpet_resolution_fs = (uint32_t)((eal_hpet->capabilities &
172                                         CLK_PERIOD_MASK) >>
173                                         CLK_PERIOD_SHIFT);
174
175         eal_hpet_resolution_hz = (1000ULL*1000ULL*1000ULL*1000ULL*1000ULL) /
176                 (uint64_t)eal_hpet_resolution_fs;
177
178         eal_hpet_msb = (eal_hpet->counter_l >> 30);
179
180         /* create a thread that will increment a global variable for
181          * msb (hpet is 32 bits by default under linux) */
182         ret = pthread_create(&msb_inc_thread_id, NULL, hpet_msb_inc, NULL);
183         if (ret < 0) {
184                 RTE_LOG(WARNING, EAL, "WARNING: Cannot create HPET timer thread! "
185                                 "The TSC will be used instead.\n");
186                 goto use_rdtsc;
187         }
188
189         return 0;
190
191 use_rdtsc:
192         internal_config.no_hpet = 1;
193         set_rdtsc_freq();
194         return 0;
195 }
196
197 uint64_t
198 rte_get_hpet_hz(void)
199 {
200         return eal_hpet_resolution_hz;
201 }
202
203 uint64_t
204 rte_get_hpet_cycles(void)
205 {
206         uint32_t t, msb;
207         uint64_t ret;
208
209         if(internal_config.no_hpet)
210                 /* fallback to rdtsc */
211                 return rte_rdtsc();
212
213         t = eal_hpet->counter_l;
214         msb = eal_hpet_msb;
215         ret = (msb + 2 - (t >> 30)) / 4;
216         ret <<= 32;
217         ret += t;
218         return ret;
219 }
220
221 void
222 rte_delay_us(unsigned us)
223 {
224         uint64_t start;
225         uint64_t ticks;
226         ticks = (uint64_t)us * 1000ULL * 1000ULL * 1000ULL;
227         ticks /= eal_hpet_resolution_fs;
228         start = rte_get_hpet_cycles();
229         while ((rte_get_hpet_cycles() - start) < ticks)
230                 rte_pause();
231 }