Get rid of bus_{disable,enable}_intr(), it wasn't generic enough for
[dragonfly.git] / sys / net / altq / altq_subr.c
1 /*      $KAME: altq_subr.c,v 1.23 2004/04/20 16:10:06 itojun Exp $      */
2 /*      $DragonFly: src/sys/net/altq/altq_subr.c,v 1.3 2005/05/24 20:59:05 dillon Exp $ */
3
4 /*
5  * Copyright (C) 1997-2003
6  *      Sony Computer Science Laboratories Inc.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include "opt_altq.h"
31 #include "opt_inet.h"
32 #include "opt_inet6.h"
33
34 #include <sys/param.h>
35 #include <sys/malloc.h>
36 #include <sys/mbuf.h>
37 #include <sys/systm.h>
38 #include <sys/proc.h>
39 #include <sys/socket.h>
40 #include <sys/socketvar.h>
41 #include <sys/kernel.h>
42 #include <sys/callout.h>
43 #include <sys/errno.h>
44 #include <sys/syslog.h>
45 #include <sys/sysctl.h>
46 #include <sys/queue.h>
47
48 #include <net/if.h>
49 #include <net/if_dl.h>
50 #include <net/if_types.h>
51 #include <net/ifq_var.h>
52
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/ip.h>
56 #ifdef INET6
57 #include <netinet/ip6.h>
58 #endif
59 #include <netinet/tcp.h>
60 #include <netinet/udp.h>
61
62 #include <net/pf/pfvar.h>
63 #include <net/altq/altq.h>
64
65 /* machine dependent clock related includes */
66 #if defined(__i386__)
67 #include <machine/clock.h>              /* for tsc_freq */
68 #include <machine/md_var.h>             /* for cpu_feature */
69 #include <machine/specialreg.h>         /* for CPUID_TSC */
70 #endif /* __i386__ */
71
72 /*
73  * internal function prototypes
74  */
75 static void     tbr_timeout(void *);
76 int (*altq_input)(struct mbuf *, int) = NULL;
77 static int tbr_timer = 0;       /* token bucket regulator timer */
78 static struct callout tbr_callout;
79
80 int pfaltq_running;     /* keep track of running state */
81
82 MALLOC_DEFINE(M_ALTQ, "altq", "ALTQ structures");
83
84 /*
85  * alternate queueing support routines
86  */
87
88 /* look up the queue state by the interface name and the queueing type. */
89 void *
90 altq_lookup(const char *name, int type)
91 {
92         struct ifnet *ifp;
93
94         if ((ifp = ifunit(name)) != NULL) {
95                 if (type != ALTQT_NONE && ifp->if_snd.altq_type == type)
96                         return (ifp->if_snd.altq_disc);
97         }
98
99         return (NULL);
100 }
101
102 int
103 altq_attach(struct ifaltq *ifq, int type, void *discipline,
104             int (*enqueue)(struct ifaltq *, struct mbuf *, struct altq_pktattr *),
105             struct mbuf *(*dequeue)(struct ifaltq *, int),
106             int (*request)(struct ifaltq *, int, void *),
107             void *clfier,
108             void *(*classify)(struct ifaltq *, struct mbuf *,
109                               struct altq_pktattr *))
110 {
111         if (!ifq_is_ready(ifq))
112                 return ENXIO;
113
114         ifq->altq_type     = type;
115         ifq->altq_disc     = discipline;
116         ifq->altq_enqueue  = enqueue;
117         ifq->altq_dequeue  = dequeue;
118         ifq->altq_request  = request;
119         ifq->altq_clfier   = clfier;
120         ifq->altq_classify = classify;
121         ifq->altq_flags &= (ALTQF_CANTCHANGE|ALTQF_ENABLED);
122         return 0;
123 }
124
125 int
126 altq_detach(struct ifaltq *ifq)
127 {
128         if (!ifq_is_ready(ifq))
129                 return ENXIO;
130         if (ifq_is_enabled(ifq))
131                 return EBUSY;
132         if (!ifq_is_attached(ifq))
133                 return (0);
134
135         ifq_set_classic(ifq);
136         ifq->altq_type     = ALTQT_NONE;
137         ifq->altq_disc     = NULL;
138         ifq->altq_clfier   = NULL;
139         ifq->altq_classify = NULL;
140         ifq->altq_flags &= ALTQF_CANTCHANGE;
141         return 0;
142 }
143
144 int
145 altq_enable(struct ifaltq *ifq)
146 {
147         int s;
148
149         if (!ifq_is_ready(ifq))
150                 return ENXIO;
151         if (ifq_is_enabled(ifq))
152                 return 0;
153
154         s = splimp();
155         ifq_purge(ifq);
156         KKASSERT(ifq->ifq_len == 0);
157         ifq->altq_flags |= ALTQF_ENABLED;
158         if (ifq->altq_clfier != NULL)
159                 ifq->altq_flags |= ALTQF_CLASSIFY;
160         splx(s);
161
162         return 0;
163 }
164
165 int
166 altq_disable(struct ifaltq *ifq)
167 {
168         int s;
169
170         if (!ifq_is_enabled(ifq))
171                 return 0;
172
173         s = splimp();
174         ifq_purge(ifq);
175         KKASSERT(ifq->ifq_len == 0);
176         ifq->altq_flags &= ~(ALTQF_ENABLED|ALTQF_CLASSIFY);
177         splx(s);
178         return 0;
179 }
180
181 /*
182  * internal representation of token bucket parameters
183  *      rate:   byte_per_unittime << 32
184  *              (((bits_per_sec) / 8) << 32) / machclk_freq
185  *      depth:  byte << 32
186  *
187  */
188 #define TBR_SHIFT       32
189 #define TBR_SCALE(x)    ((int64_t)(x) << TBR_SHIFT)
190 #define TBR_UNSCALE(x)  ((x) >> TBR_SHIFT)
191
192 struct mbuf *
193 tbr_dequeue(struct ifaltq *ifq, int op)
194 {
195         struct tb_regulator *tbr;
196         struct mbuf *m;
197         int64_t interval;
198         uint64_t now;
199         int s;
200
201         s = splimp();
202         tbr = ifq->altq_tbr;
203         if (op == ALTDQ_REMOVE && tbr->tbr_lastop == ALTDQ_POLL) {
204                 /* if this is a remove after poll, bypass tbr check */
205         } else {
206                 /* update token only when it is negative */
207                 if (tbr->tbr_token <= 0) {
208                         now = read_machclk();
209                         interval = now - tbr->tbr_last;
210                         if (interval >= tbr->tbr_filluptime)
211                                 tbr->tbr_token = tbr->tbr_depth;
212                         else {
213                                 tbr->tbr_token += interval * tbr->tbr_rate;
214                                 if (tbr->tbr_token > tbr->tbr_depth)
215                                         tbr->tbr_token = tbr->tbr_depth;
216                         }
217                         tbr->tbr_last = now;
218                 }
219                 /* if token is still negative, don't allow dequeue */
220                 if (tbr->tbr_token <= 0) {
221                         splx(s);
222                         return (NULL);
223                 }
224         }
225
226         if (ifq_is_enabled(ifq))
227                 m = (*ifq->altq_dequeue)(ifq, op);
228         else if (op == ALTDQ_POLL)
229                 IF_POLL(ifq, m);
230         else
231                 IF_DEQUEUE(ifq, m);
232
233         if (m != NULL && op == ALTDQ_REMOVE)
234                 tbr->tbr_token -= TBR_SCALE(m_pktlen(m));
235         tbr->tbr_lastop = op;
236         splx(s);
237         return (m);
238 }
239
240 /*
241  * set a token bucket regulator.
242  * if the specified rate is zero, the token bucket regulator is deleted.
243  */
244 int
245 tbr_set(struct ifaltq *ifq, struct tb_profile *profile)
246 {
247         struct tb_regulator *tbr, *otbr;
248
249         if (machclk_freq == 0)
250                 init_machclk();
251         if (machclk_freq == 0) {
252                 printf("tbr_set: no cpu clock available!\n");
253                 return (ENXIO);
254         }
255
256         if (profile->rate == 0) {
257                 /* delete this tbr */
258                 if ((tbr = ifq->altq_tbr) == NULL)
259                         return (ENOENT);
260                 ifq->altq_tbr = NULL;
261                 free(tbr, M_ALTQ);
262                 return (0);
263         }
264
265         tbr = malloc(sizeof(*tbr), M_ALTQ, M_WAITOK | M_ZERO);
266         tbr->tbr_rate = TBR_SCALE(profile->rate / 8) / machclk_freq;
267         tbr->tbr_depth = TBR_SCALE(profile->depth);
268         if (tbr->tbr_rate > 0)
269                 tbr->tbr_filluptime = tbr->tbr_depth / tbr->tbr_rate;
270         else
271                 tbr->tbr_filluptime = 0xffffffffffffffffLL;
272         tbr->tbr_token = tbr->tbr_depth;
273         tbr->tbr_last = read_machclk();
274         tbr->tbr_lastop = ALTDQ_REMOVE;
275
276         otbr = ifq->altq_tbr;
277         ifq->altq_tbr = tbr;    /* set the new tbr */
278
279         if (otbr != NULL)
280                 free(otbr, M_ALTQ);
281         else if (tbr_timer == 0) {
282                 callout_reset(&tbr_callout, 1, tbr_timeout, NULL);
283                 tbr_timer = 1;
284         }
285         return (0);
286 }
287
288 /*
289  * tbr_timeout goes through the interface list, and kicks the drivers
290  * if necessary.
291  */
292 static void
293 tbr_timeout(void *arg)
294 {
295         struct ifnet *ifp;
296         int active, s;
297
298         active = 0;
299         s = splimp();
300         for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
301                 if (ifp->if_snd.altq_tbr == NULL)
302                         continue;
303                 active++;
304                 if (!ifq_is_empty(&ifp->if_snd) && ifp->if_start != NULL)
305                         (*ifp->if_start)(ifp);
306         }
307         splx(s);
308         if (active > 0)
309                 callout_reset(&tbr_callout, 1, tbr_timeout, NULL);
310         else
311                 tbr_timer = 0;  /* don't need tbr_timer anymore */
312 }
313
314 /*
315  * get token bucket regulator profile
316  */
317 int
318 tbr_get(struct ifaltq *ifq, struct tb_profile *profile)
319 {
320         struct tb_regulator *tbr;
321
322         if ((tbr = ifq->altq_tbr) == NULL) {
323                 profile->rate = 0;
324                 profile->depth = 0;
325         } else {
326                 profile->rate =
327                     (u_int)TBR_UNSCALE(tbr->tbr_rate * 8 * machclk_freq);
328                 profile->depth = (u_int)TBR_UNSCALE(tbr->tbr_depth);
329         }
330         return (0);
331 }
332
333 /*
334  * attach a discipline to the interface.  if one already exists, it is
335  * overridden.
336  */
337 int
338 altq_pfattach(struct pf_altq *a)
339 {
340         struct ifnet *ifp;
341         struct tb_profile tb;
342         int s, error = 0;
343
344         switch (a->scheduler) {
345         case ALTQT_NONE:
346                 break;
347 #ifdef ALTQ_CBQ
348         case ALTQT_CBQ:
349                 error = cbq_pfattach(a);
350                 break;
351 #endif
352 #ifdef ALTQ_PRIQ
353         case ALTQT_PRIQ:
354                 error = priq_pfattach(a);
355                 break;
356 #endif
357 #ifdef ALTQ_HFSC
358         case ALTQT_HFSC:
359                 error = hfsc_pfattach(a);
360                 break;
361 #endif
362         default:
363                 error = ENXIO;
364         }
365
366         ifp = ifunit(a->ifname);
367
368         /* if the state is running, enable altq */
369         if (error == 0 && pfaltq_running &&
370             ifp != NULL && ifp->if_snd.altq_type != ALTQT_NONE &&
371             !ifq_is_enabled(&ifp->if_snd))
372                         error = altq_enable(&ifp->if_snd);
373
374         /* if altq is already enabled, reset set tokenbucket regulator */
375         if (error == 0 && ifp != NULL && ifq_is_enabled(&ifp->if_snd)) {
376                 tb.rate = a->ifbandwidth;
377                 tb.depth = a->tbrsize;
378                 s = splimp();
379                 error = tbr_set(&ifp->if_snd, &tb);
380                 splx(s);
381         }
382
383         return (error);
384 }
385
386 /*
387  * detach a discipline from the interface.
388  * it is possible that the discipline was already overridden by another
389  * discipline.
390  */
391 int
392 altq_pfdetach(struct pf_altq *a)
393 {
394         struct ifnet *ifp;
395         int s, error = 0;
396
397         if ((ifp = ifunit(a->ifname)) == NULL)
398                 return (EINVAL);
399
400         /* if this discipline is no longer referenced, just return */
401         if (a->altq_disc == NULL || a->altq_disc != ifp->if_snd.altq_disc)
402                 return (0);
403
404         s = splimp();
405         if (ifq_is_enabled(&ifp->if_snd))
406                 error = altq_disable(&ifp->if_snd);
407         if (error == 0)
408                 error = altq_detach(&ifp->if_snd);
409         splx(s);
410
411         return (error);
412 }
413
414 /*
415  * add a discipline or a queue
416  */
417 int
418 altq_add(struct pf_altq *a)
419 {
420         int error = 0;
421
422         if (a->qname[0] != 0)
423                 return (altq_add_queue(a));
424
425         if (machclk_freq == 0)
426                 init_machclk();
427         if (machclk_freq == 0)
428                 panic("altq_add: no cpu clock");
429
430         switch (a->scheduler) {
431 #ifdef ALTQ_CBQ
432         case ALTQT_CBQ:
433                 error = cbq_add_altq(a);
434                 break;
435 #endif
436 #ifdef ALTQ_PRIQ
437         case ALTQT_PRIQ:
438                 error = priq_add_altq(a);
439                 break;
440 #endif
441 #ifdef ALTQ_HFSC
442         case ALTQT_HFSC:
443                 error = hfsc_add_altq(a);
444                 break;
445 #endif
446         default:
447                 error = ENXIO;
448         }
449
450         return (error);
451 }
452
453 /*
454  * remove a discipline or a queue
455  */
456 int
457 altq_remove(struct pf_altq *a)
458 {
459         int error = 0;
460
461         if (a->qname[0] != 0)
462                 return (altq_remove_queue(a));
463
464         switch (a->scheduler) {
465 #ifdef ALTQ_CBQ
466         case ALTQT_CBQ:
467                 error = cbq_remove_altq(a);
468                 break;
469 #endif
470 #ifdef ALTQ_PRIQ
471         case ALTQT_PRIQ:
472                 error = priq_remove_altq(a);
473                 break;
474 #endif
475 #ifdef ALTQ_HFSC
476         case ALTQT_HFSC:
477                 error = hfsc_remove_altq(a);
478                 break;
479 #endif
480         default:
481                 error = ENXIO;
482         }
483
484         return (error);
485 }
486
487 /*
488  * add a queue to the discipline
489  */
490 int
491 altq_add_queue(struct pf_altq *a)
492 {
493         int error = 0;
494
495         switch (a->scheduler) {
496 #ifdef ALTQ_CBQ
497         case ALTQT_CBQ:
498                 error = cbq_add_queue(a);
499                 break;
500 #endif
501 #ifdef ALTQ_PRIQ
502         case ALTQT_PRIQ:
503                 error = priq_add_queue(a);
504                 break;
505 #endif
506 #ifdef ALTQ_HFSC
507         case ALTQT_HFSC:
508                 error = hfsc_add_queue(a);
509                 break;
510 #endif
511         default:
512                 error = ENXIO;
513         }
514
515         return (error);
516 }
517
518 /*
519  * remove a queue from the discipline
520  */
521 int
522 altq_remove_queue(struct pf_altq *a)
523 {
524         int error = 0;
525
526         switch (a->scheduler) {
527 #ifdef ALTQ_CBQ
528         case ALTQT_CBQ:
529                 error = cbq_remove_queue(a);
530                 break;
531 #endif
532 #ifdef ALTQ_PRIQ
533         case ALTQT_PRIQ:
534                 error = priq_remove_queue(a);
535                 break;
536 #endif
537 #ifdef ALTQ_HFSC
538         case ALTQT_HFSC:
539                 error = hfsc_remove_queue(a);
540                 break;
541 #endif
542         default:
543                 error = ENXIO;
544         }
545
546         return (error);
547 }
548
549 /*
550  * get queue statistics
551  */
552 int
553 altq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
554 {
555         int error = 0;
556
557         switch (a->scheduler) {
558 #ifdef ALTQ_CBQ
559         case ALTQT_CBQ:
560                 error = cbq_getqstats(a, ubuf, nbytes);
561                 break;
562 #endif
563 #ifdef ALTQ_PRIQ
564         case ALTQT_PRIQ:
565                 error = priq_getqstats(a, ubuf, nbytes);
566                 break;
567 #endif
568 #ifdef ALTQ_HFSC
569         case ALTQT_HFSC:
570                 error = hfsc_getqstats(a, ubuf, nbytes);
571                 break;
572 #endif
573         default:
574                 error = ENXIO;
575         }
576
577         return (error);
578 }
579
580 /*
581  * read and write diffserv field in IPv4 or IPv6 header
582  */
583 uint8_t
584 read_dsfield(struct mbuf *m, struct altq_pktattr *pktattr)
585 {
586         struct mbuf *m0;
587         uint8_t ds_field = 0;
588
589         if (pktattr == NULL ||
590             (pktattr->pattr_af != AF_INET && pktattr->pattr_af != AF_INET6))
591                 return ((uint8_t)0);
592
593         /* verify that pattr_hdr is within the mbuf data */
594         for (m0 = m; m0 != NULL; m0 = m0->m_next) {
595                 if ((pktattr->pattr_hdr >= m0->m_data) &&
596                     (pktattr->pattr_hdr < m0->m_data + m0->m_len))
597                         break;
598         }
599         if (m0 == NULL) {
600                 /* ick, pattr_hdr is stale */
601                 pktattr->pattr_af = AF_UNSPEC;
602 #ifdef ALTQ_DEBUG
603                 printf("read_dsfield: can't locate header!\n");
604 #endif
605                 return ((uint8_t)0);
606         }
607
608         if (pktattr->pattr_af == AF_INET) {
609                 struct ip *ip = (struct ip *)pktattr->pattr_hdr;
610
611                 if (ip->ip_v != 4)
612                         return ((uint8_t)0);    /* version mismatch! */
613                 ds_field = ip->ip_tos;
614         }
615 #ifdef INET6
616         else if (pktattr->pattr_af == AF_INET6) {
617                 struct ip6_hdr *ip6 = (struct ip6_hdr *)pktattr->pattr_hdr;
618                 uint32_t flowlabel;
619
620                 flowlabel = ntohl(ip6->ip6_flow);
621                 if ((flowlabel >> 28) != 6)
622                         return ((uint8_t)0);    /* version mismatch! */
623                 ds_field = (flowlabel >> 20) & 0xff;
624         }
625 #endif
626         return (ds_field);
627 }
628
629 void
630 write_dsfield(struct mbuf *m, struct altq_pktattr *pktattr, uint8_t dsfield)
631 {
632         struct mbuf *m0;
633
634         if (pktattr == NULL ||
635             (pktattr->pattr_af != AF_INET && pktattr->pattr_af != AF_INET6))
636                 return;
637
638         /* verify that pattr_hdr is within the mbuf data */
639         for (m0 = m; m0 != NULL; m0 = m0->m_next) {
640                 if ((pktattr->pattr_hdr >= m0->m_data) &&
641                     (pktattr->pattr_hdr < m0->m_data + m0->m_len))
642                         break;
643         }
644         if (m0 == NULL) {
645                 /* ick, pattr_hdr is stale */
646                 pktattr->pattr_af = AF_UNSPEC;
647 #ifdef ALTQ_DEBUG
648                 printf("write_dsfield: can't locate header!\n");
649 #endif
650                 return;
651         }
652
653         if (pktattr->pattr_af == AF_INET) {
654                 struct ip *ip = (struct ip *)pktattr->pattr_hdr;
655                 uint8_t old;
656                 int32_t sum;
657
658                 if (ip->ip_v != 4)
659                         return;         /* version mismatch! */
660                 old = ip->ip_tos;
661                 dsfield |= old & 3;     /* leave CU bits */
662                 if (old == dsfield)
663                         return;
664                 ip->ip_tos = dsfield;
665                 /*
666                  * update checksum (from RFC1624)
667                  *         HC' = ~(~HC + ~m + m')
668                  */
669                 sum = ~ntohs(ip->ip_sum) & 0xffff;
670                 sum += 0xff00 + (~old & 0xff) + dsfield;
671                 sum = (sum >> 16) + (sum & 0xffff);
672                 sum += (sum >> 16);  /* add carry */
673
674                 ip->ip_sum = htons(~sum & 0xffff);
675         }
676 #ifdef INET6
677         else if (pktattr->pattr_af == AF_INET6) {
678                 struct ip6_hdr *ip6 = (struct ip6_hdr *)pktattr->pattr_hdr;
679                 uint32_t flowlabel;
680
681                 flowlabel = ntohl(ip6->ip6_flow);
682                 if ((flowlabel >> 28) != 6)
683                         return;         /* version mismatch! */
684                 flowlabel = (flowlabel & 0xf03fffff) | (dsfield << 20);
685                 ip6->ip6_flow = htonl(flowlabel);
686         }
687 #endif
688 }
689
690 /*
691  * high resolution clock support taking advantage of a machine dependent
692  * high resolution time counter (e.g., timestamp counter of intel pentium).
693  * we assume
694  *  - 64-bit-long monotonically-increasing counter
695  *  - frequency range is 100M-4GHz (CPU speed)
696  */
697 /* if pcc is not available or disabled, emulate 256MHz using microtime() */
698 #define MACHCLK_SHIFT   8
699
700 int machclk_usepcc;
701 uint32_t machclk_freq = 0;
702 uint32_t machclk_per_tick = 0;
703
704 void
705 init_machclk(void)
706 {
707         callout_init(&tbr_callout);
708
709         machclk_usepcc = 1;
710
711 #if !defined(__i386__) || defined(ALTQ_NOPCC)
712         machclk_usepcc = 0;
713 #elif defined(__DragonFly__) && defined(SMP)
714         machclk_usepcc = 0;
715 #elif defined(__i386__)
716         /* check if TSC is available */
717         if (machclk_usepcc == 1 && (cpu_feature & CPUID_TSC) == 0)
718                 machclk_usepcc = 0;
719 #endif
720
721         if (machclk_usepcc == 0) {
722                 /* emulate 256MHz using microtime() */
723                 machclk_freq = 1000000 << MACHCLK_SHIFT;
724                 machclk_per_tick = machclk_freq / hz;
725 #ifdef ALTQ_DEBUG
726                 printf("altq: emulate %uHz cpu clock\n", machclk_freq);
727 #endif
728                 return;
729         }
730
731         /*
732          * if the clock frequency (of Pentium TSC or Alpha PCC) is
733          * accessible, just use it.
734          */
735 #ifdef __i386__
736         machclk_freq = tsc_freq;
737 #else
738 #error "machclk_freq interface not implemented"
739 #endif
740
741         /*
742          * if we don't know the clock frequency, measure it.
743          */
744         if (machclk_freq == 0) {
745                 static int      wait;
746                 struct timeval  tv_start, tv_end;
747                 uint64_t        start, end, diff;
748                 int             timo;
749
750                 microtime(&tv_start);
751                 start = read_machclk();
752                 timo = hz;      /* 1 sec */
753                 tsleep(&wait, PCATCH, "init_machclk", timo);
754                 microtime(&tv_end);
755                 end = read_machclk();
756                 diff = (uint64_t)(tv_end.tv_sec - tv_start.tv_sec) * 1000000
757                     + tv_end.tv_usec - tv_start.tv_usec;
758                 if (diff != 0)
759                         machclk_freq = (u_int)((end - start) * 1000000 / diff);
760         }
761
762         machclk_per_tick = machclk_freq / hz;
763
764 #ifdef ALTQ_DEBUG
765         printf("altq: CPU clock: %uHz\n", machclk_freq);
766 #endif
767 }
768
769 uint64_t
770 read_machclk(void)
771 {
772         uint64_t val;
773
774         if (machclk_usepcc) {
775 #if defined(__i386__)
776                 val = rdtsc();
777 #else
778                 panic("read_machclk");
779 #endif
780         } else {
781                 struct timeval tv;
782
783                 microtime(&tv);
784                 val = (((uint64_t)(tv.tv_sec - boottime.tv_sec) * 1000000
785                     + tv.tv_usec) << MACHCLK_SHIFT);
786         }
787         return (val);
788 }