]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/pktsched/pktsched.c
xnu-2782.1.97.tar.gz
[apple/xnu.git] / bsd / net / pktsched / pktsched.c
1 /*
2 * Copyright (c) 2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <sys/cdefs.h>
30
31 #include <sys/param.h>
32 #include <sys/malloc.h>
33 #include <sys/mbuf.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/errno.h>
37 #include <sys/mcache.h>
38 #include <sys/sysctl.h>
39
40 #include <net/if.h>
41 #include <net/if_var.h>
42 #include <net/if_dl.h>
43 #include <net/if_types.h>
44 #include <net/net_osdep.h>
45 #include <net/pktsched/pktsched.h>
46 #include <net/pktsched/pktsched_tcq.h>
47 #include <net/pktsched/pktsched_qfq.h>
48 #if PKTSCHED_PRIQ
49 #include <net/pktsched/pktsched_priq.h>
50 #endif /* PKTSCHED_PRIQ */
51 #if PKTSCHED_FAIRQ
52 #include <net/pktsched/pktsched_fairq.h>
53 #endif /* PKTSCHED_FAIRQ */
54 #if PKTSCHED_CBQ
55 #include <net/pktsched/pktsched_cbq.h>
56 #endif /* PKTSCHED_CBQ */
57 #if PKTSCHED_HFSC
58 #include <net/pktsched/pktsched_hfsc.h>
59 #endif /* PKTSCHED_HFSC */
60
61 #include <pexpert/pexpert.h>
62
63 u_int32_t machclk_freq = 0;
64 u_int64_t machclk_per_sec = 0;
65 u_int32_t pktsched_verbose; /* more noise if greater than 1 */
66
67 static void init_machclk(void);
68
69 SYSCTL_NODE(_net, OID_AUTO, pktsched, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "pktsched");
70
71 SYSCTL_UINT(_net_pktsched, OID_AUTO, verbose, CTLFLAG_RW|CTLFLAG_LOCKED,
72 &pktsched_verbose, 0, "Packet scheduler verbosity level");
73
74 void
75 pktsched_init(void)
76 {
77 init_machclk();
78 if (machclk_freq == 0) {
79 panic("%s: no CPU clock available!\n", __func__);
80 /* NOTREACHED */
81 }
82
83 tcq_init();
84 qfq_init();
85 #if PKTSCHED_PRIQ
86 priq_init();
87 #endif /* PKTSCHED_PRIQ */
88 #if PKTSCHED_FAIRQ
89 fairq_init();
90 #endif /* PKTSCHED_FAIRQ */
91 #if PKTSCHED_CBQ
92 cbq_init();
93 #endif /* PKTSCHED_CBQ */
94 #if PKTSCHED_HFSC
95 hfsc_init();
96 #endif /* PKTSCHED_HFSC */
97 }
98
99 static void
100 init_machclk(void)
101 {
102 /*
103 * Initialize machclk_freq using the timerbase frequency
104 * value from device specific info.
105 */
106 machclk_freq = gPEClockFrequencyInfo.timebase_frequency_hz;
107
108 clock_interval_to_absolutetime_interval(1, NSEC_PER_SEC,
109 &machclk_per_sec);
110 }
111
112 u_int64_t
113 pktsched_abs_to_nsecs(u_int64_t abstime)
114 {
115 u_int64_t nsecs;
116
117 absolutetime_to_nanoseconds(abstime, &nsecs);
118 return (nsecs);
119 }
120
121 u_int64_t
122 pktsched_nsecs_to_abstime(u_int64_t nsecs)
123 {
124 u_int64_t abstime;
125
126 nanoseconds_to_absolutetime(nsecs, &abstime);
127 return (abstime);
128 }
129
130 int
131 pktsched_setup(struct ifclassq *ifq, u_int32_t scheduler, u_int32_t sflags)
132 {
133 int error = 0;
134 u_int32_t qflags = sflags;
135 u_int32_t rflags;
136
137 IFCQ_LOCK_ASSERT_HELD(ifq);
138
139 VERIFY(machclk_freq != 0);
140
141 /* Nothing to do unless the scheduler type changes */
142 if (ifq->ifcq_type == scheduler)
143 return (0);
144
145 qflags &= (PKTSCHEDF_QALG_RED | PKTSCHEDF_QALG_RIO |
146 PKTSCHEDF_QALG_BLUE | PKTSCHEDF_QALG_SFB);
147
148 /* These are mutually exclusive */
149 if (qflags != 0 &&
150 qflags != PKTSCHEDF_QALG_RED && qflags != PKTSCHEDF_QALG_RIO &&
151 qflags != PKTSCHEDF_QALG_BLUE && qflags != PKTSCHEDF_QALG_SFB) {
152 panic("%s: RED|RIO|BLUE|SFB mutually exclusive\n", __func__);
153 /* NOTREACHED */
154 }
155
156 /*
157 * Remember the flags that need to be restored upon success, as
158 * they may be cleared when we tear down existing scheduler.
159 */
160 rflags = (ifq->ifcq_flags & IFCQF_ENABLED);
161
162 if (ifq->ifcq_type != PKTSCHEDT_NONE) {
163 (void) pktsched_teardown(ifq);
164
165 /* Teardown should have succeeded */
166 VERIFY(ifq->ifcq_type == PKTSCHEDT_NONE);
167 VERIFY(ifq->ifcq_disc == NULL);
168 VERIFY(ifq->ifcq_enqueue == NULL);
169 VERIFY(ifq->ifcq_dequeue == NULL);
170 VERIFY(ifq->ifcq_dequeue_sc == NULL);
171 VERIFY(ifq->ifcq_request == NULL);
172 }
173
174 switch (scheduler) {
175 #if PKTSCHED_PRIQ
176 case PKTSCHEDT_PRIQ:
177 error = priq_setup_ifclassq(ifq, sflags);
178 break;
179 #endif /* PKTSCHED_PRIQ */
180
181 case PKTSCHEDT_TCQ:
182 error = tcq_setup_ifclassq(ifq, sflags);
183 break;
184
185 case PKTSCHEDT_QFQ:
186 error = qfq_setup_ifclassq(ifq, sflags);
187 break;
188
189 default:
190 error = ENXIO;
191 break;
192 }
193
194 if (error == 0)
195 ifq->ifcq_flags |= rflags;
196
197 return (error);
198 }
199
200 int
201 pktsched_teardown(struct ifclassq *ifq)
202 {
203 int error = 0;
204
205 IFCQ_LOCK_ASSERT_HELD(ifq);
206
207 if_qflush(ifq->ifcq_ifp, 1);
208 VERIFY(IFCQ_IS_EMPTY(ifq));
209
210 ifq->ifcq_flags &= ~IFCQF_ENABLED;
211
212 switch (ifq->ifcq_type) {
213 case PKTSCHEDT_NONE:
214 break;
215
216 #if PKTSCHED_PRIQ
217 case PKTSCHEDT_PRIQ:
218 error = priq_teardown_ifclassq(ifq);
219 break;
220 #endif /* PKTSCHED_PRIQ */
221
222 case PKTSCHEDT_TCQ:
223 error = tcq_teardown_ifclassq(ifq);
224 break;
225
226 case PKTSCHEDT_QFQ:
227 error = qfq_teardown_ifclassq(ifq);
228 break;
229
230 default:
231 error = ENXIO;
232 break;
233 }
234
235 return (error);
236 }
237
238 int
239 pktsched_getqstats(struct ifclassq *ifq, u_int32_t qid,
240 struct if_ifclassq_stats *ifqs)
241 {
242 int error;
243
244 IFCQ_LOCK_ASSERT_HELD(ifq);
245
246 switch (ifq->ifcq_type) {
247 #if PKTSCHED_PRIQ
248 case PKTSCHEDT_PRIQ:
249 error = priq_getqstats_ifclassq(ifq, qid, ifqs);
250 break;
251 #endif /* PKTSCHED_PRIQ */
252
253 case PKTSCHEDT_TCQ:
254 error = tcq_getqstats_ifclassq(ifq, qid, ifqs);
255 break;
256
257 case PKTSCHEDT_QFQ:
258 error = qfq_getqstats_ifclassq(ifq, qid, ifqs);
259 break;
260
261 default:
262 error = ENXIO;
263 break;
264 }
265
266 return (error);
267 }