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 63u_int32_t machclk_freq = 0; 64u_int64_t machclk_per_sec = 0; 65u_int32_t pktsched_verbose; /* more noise if greater than 1 */ 66 67static void init_machclk(void); 68 69SYSCTL_NODE(_net, OID_AUTO, pktsched, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "pktsched"); 70 71SYSCTL_UINT(_net_pktsched, OID_AUTO, verbose, CTLFLAG_RW|CTLFLAG_LOCKED, 72 &pktsched_verbose, 0, "Packet scheduler verbosity level"); 73 74void 75pktsched_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 99static void 100init_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 112u_int64_t 113pktsched_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 121u_int64_t 122pktsched_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 130int 131pktsched_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 200int 201pktsched_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 238int 239pktsched_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} 268