* Initialize a new timecounter and possibly use it. */
| 1153 | * Initialize a new timecounter and possibly use it. |
| 1154 | */ |
| 1155 | void |
| 1156 | tc_init(struct timecounter *tc) |
| 1157 | { |
| 1158 | u_int u; |
| 1159 | struct sysctl_oid *tc_root; |
| 1160 | |
| 1161 | u = tc->tc_frequency / tc->tc_counter_mask; |
| 1162 | /* XXX: We need some margin here, 10% is a guess */ |
| 1163 | u *= 11; |
| 1164 | u /= 10; |
| 1165 | if (u > hz && tc->tc_quality >= 0) { |
| 1166 | tc->tc_quality = -2000; |
| 1167 | if (bootverbose) { |
| 1168 | printf("Timecounter \"%s\" frequency %ju Hz", |
| 1169 | tc->tc_name, (uintmax_t)tc->tc_frequency); |
| 1170 | printf(" -- Insufficient hz, needs at least %u\n", u); |
| 1171 | } |
| 1172 | } else if (tc->tc_quality >= 0 || bootverbose) { |
| 1173 | printf("Timecounter \"%s\" frequency %ju Hz quality %d\n", |
| 1174 | tc->tc_name, (uintmax_t)tc->tc_frequency, |
| 1175 | tc->tc_quality); |
| 1176 | } |
| 1177 | |
| 1178 | tc->tc_next = timecounters; |
| 1179 | timecounters = tc; |
| 1180 | /* |
| 1181 | * Set up sysctl tree for this counter. |
| 1182 | */ |
| 1183 | tc_root = SYSCTL_ADD_NODE_WITH_LABEL(NULL, |
| 1184 | SYSCTL_STATIC_CHILDREN(_kern_timecounter_tc), OID_AUTO, tc->tc_name, |
| 1185 | CTLFLAG_RW | CTLFLAG_MPSAFE, 0, |
| 1186 | "timecounter description", "timecounter"); |
| 1187 | SYSCTL_ADD_UINT(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO, |
| 1188 | "mask", CTLFLAG_RD, &(tc->tc_counter_mask), 0, |
| 1189 | "mask for implemented bits"); |
| 1190 | SYSCTL_ADD_PROC(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO, |
| 1191 | "counter", CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_MPSAFE, tc, |
| 1192 | sizeof(*tc), sysctl_kern_timecounter_get, "IU", |
| 1193 | "current timecounter value"); |
| 1194 | SYSCTL_ADD_PROC(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO, |
| 1195 | "frequency", CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_MPSAFE, tc, |
| 1196 | sizeof(*tc), sysctl_kern_timecounter_freq, "QU", |
| 1197 | "timecounter frequency"); |
| 1198 | SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO, |
| 1199 | "quality", CTLFLAG_RD, &(tc->tc_quality), 0, |
| 1200 | "goodness of time counter"); |
| 1201 | /* |
| 1202 | * Do not automatically switch if the current tc was specifically |
| 1203 | * chosen. Never automatically use a timecounter with negative quality. |
| 1204 | * Even though we run on the dummy counter, switching here may be |
| 1205 | * worse since this timecounter may not be monotonic. |
| 1206 | */ |
| 1207 | if (tc_chosen) |
| 1208 | return; |
| 1209 | if (tc->tc_quality < 0) |
| 1210 | return; |
| 1211 | if (tc->tc_quality < timecounter->tc_quality) |
| 1212 | return; |
no test coverage detected