1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright 2017 Joyent, Inc. 25 */ 26 27 /* 28 * General Soft rings - Simulating Rx rings in S/W. 29 * 30 * Soft ring is a data abstraction containing a queue and a worker 31 * thread and represents a hardware Rx ring in software. Each soft 32 * ring set can have a collection of soft rings for separating 33 * L3/L4 specific traffic (IPv4 from IPv6 or TCP from UDP) or for 34 * allowing a higher degree of parallelism by sending traffic to 35 * one of the soft rings for a SRS (using a hash on src IP or port). 36 * Each soft ring worker thread can be bound to a different CPU 37 * allowing the processing for each soft ring to happen in parallel 38 * and independent from each other. 39 * 40 * Protocol soft rings: 41 * 42 * Each SRS has at an minimum 3 softrings. One each for IPv4 TCP, 43 * IPv4 UDP and rest (OTH - for IPv6 and everything else). The 44 * SRS does dynamic polling and enforces link level bandwidth but 45 * it does so for all traffic (IPv4 and IPv6 and all protocols) on 46 * that link. However, each protocol layer wants a different 47 * behaviour. For instance IPv4 TCP has per CPU squeues which 48 * enforce their own polling and flow control so IPv4 TCP traffic 49 * needs to go to a separate soft ring which can be polled by the 50 * TCP squeue. It also allows TCP squeue to push back flow control 51 * all the way to NIC hardware (if it puts its corresponding soft 52 * ring in the poll mode and soft ring queue builds up, the 53 * shared srs_poll_pkt_cnt goes up and SRS automatically stops 54 * more packets from entering the system). 55 * 56 * Similarly, the UDP benefits from a DLS bypass and packet chaining 57 * so sending it to a separate soft ring is desired. All the rest of 58 * the traffic (including IPv6 is sent to OTH softring). The IPv6 59 * traffic current goes through OTH softring and via DLS because 60 * it need more processing to be done. Irrespective of the sap 61 * (IPv4 or IPv6) or the transport, the dynamic polling, B/W enforcement, 62 * cpu assignment, fanout, etc apply to all traffic since they 63 * are implement by the SRS which is agnostic to sap or transport. 64 * 65 * Fanout soft rings: 66 * 67 * On a multithreaded system, we can assign more CPU and multi thread 68 * the stack by creating a soft ring per CPU and spreading traffic 69 * based on a hash computed on src IP etc. Since we still need to 70 * keep the protocol separation, we create a set of 3 soft ring per 71 * CPU (specified by cpu list or degree of fanout). 72 * 73 * NOTE: See the block level comment on top of mac_sched.c 74 */ 75 76 #include <sys/types.h> 77 #include <sys/callb.h> 78 #include <sys/sdt.h> 79 #include <sys/strsubr.h> 80 #include <sys/strsun.h> 81 #include <sys/vlan.h> 82 #include <inet/ipsec_impl.h> 83 #include <inet/ip_impl.h> 84 #include <inet/sadb.h> 85 #include <inet/ipsecesp.h> 86 #include <inet/ipsecah.h> 87 88 #include <sys/mac_impl.h> 89 #include <sys/mac_client_impl.h> 90 #include <sys/mac_soft_ring.h> 91 #include <sys/mac_flow_impl.h> 92 #include <sys/mac_stat.h> 93 94 static void mac_rx_soft_ring_drain(mac_soft_ring_t *); 95 static void mac_soft_ring_fire(void *); 96 static void mac_soft_ring_worker(mac_soft_ring_t *); 97 static void mac_tx_soft_ring_drain(mac_soft_ring_t *); 98 99 uint32_t mac_tx_soft_ring_max_q_cnt = 100000; 100 uint32_t mac_tx_soft_ring_hiwat = 1000; 101 102 extern kmem_cache_t *mac_soft_ring_cache; 103 104 #define ADD_SOFTRING_TO_SET(mac_srs, softring) { \ 105 if (mac_srs->srs_soft_ring_head == NULL) { \ 106 mac_srs->srs_soft_ring_head = softring; \ 107 mac_srs->srs_soft_ring_tail = softring; \ 108 } else { \ 109 /* ADD to the list */ \ 110 softring->s_ring_prev = \ 111 mac_srs->srs_soft_ring_tail; \ 112 mac_srs->srs_soft_ring_tail->s_ring_next = softring; \ 113 mac_srs->srs_soft_ring_tail = softring; \ 114 } \ 115 mac_srs->srs_soft_ring_count++; \ 116 } 117 118 /* 119 * mac_soft_ring_worker_wakeup 120 * 121 * Wake up the soft ring worker thread to process the queue as long 122 * as no one else is processing it and upper layer (client) is still 123 * ready to receive packets. 124 */ 125 void 126 mac_soft_ring_worker_wakeup(mac_soft_ring_t *ringp) 127 { 128 ASSERT(MUTEX_HELD(&ringp->s_ring_lock)); 129 if (!(ringp->s_ring_state & S_RING_PROC) && 130 !(ringp->s_ring_state & S_RING_BLANK) && 131 (ringp->s_ring_tid == NULL)) { 132 if (ringp->s_ring_wait != 0) { 133 ringp->s_ring_tid = 134 timeout(mac_soft_ring_fire, ringp, 135 ringp->s_ring_wait); 136 } else { 137 /* Schedule the worker thread. */ 138 cv_signal(&ringp->s_ring_async); 139 } 140 } 141 } 142 143 /* 144 * mac_soft_ring_create 145 * 146 * Create a soft ring, do the necessary setup and bind the worker 147 * thread to the assigned CPU. 148 */ 149 mac_soft_ring_t * 150 mac_soft_ring_create(int id, clock_t wait, uint16_t type, 151 pri_t pri, mac_client_impl_t *mcip, mac_soft_ring_set_t *mac_srs, 152 processorid_t cpuid, mac_direct_rx_t rx_func, void *x_arg1, 153 mac_resource_handle_t x_arg2) 154 { 155 mac_soft_ring_t *ringp; 156 char name[S_RING_NAMELEN]; 157 158 bzero(name, 64); 159 ringp = kmem_cache_alloc(mac_soft_ring_cache, KM_SLEEP); 160 161 if (type & ST_RING_TCP) { 162 (void) snprintf(name, sizeof (name), 163 "mac_tcp_soft_ring_%d_%p", id, (void *)mac_srs); 164 } else if (type & ST_RING_UDP) { 165 (void) snprintf(name, sizeof (name), 166 "mac_udp_soft_ring_%d_%p", id, (void *)mac_srs); 167 } else if (type & ST_RING_OTH) { 168 (void) snprintf(name, sizeof (name), 169 "mac_oth_soft_ring_%d_%p", id, (void *)mac_srs); 170 } else { 171 ASSERT(type & ST_RING_TX); 172 (void) snprintf(name, sizeof (name), 173 "mac_tx_soft_ring_%d_%p", id, (void *)mac_srs); 174 } 175 176 bzero(ringp, sizeof (mac_soft_ring_t)); 177 (void) strncpy(ringp->s_ring_name, name, S_RING_NAMELEN + 1); 178 ringp->s_ring_name[S_RING_NAMELEN] = '\0'; 179 mutex_init(&ringp->s_ring_lock, NULL, MUTEX_DEFAULT, NULL); 180 ringp->s_ring_notify_cb_info.mcbi_lockp = &ringp->s_ring_lock; 181 182 ringp->s_ring_type = type; 183 ringp->s_ring_wait = MSEC_TO_TICK(wait); 184 ringp->s_ring_mcip = mcip; 185 ringp->s_ring_set = mac_srs; 186 187 /* 188 * Protect against access from DR callbacks (mac_walk_srs_bind/unbind) 189 * which can't grab the mac perimeter 190 */ 191 mutex_enter(&mac_srs->srs_lock); 192 ADD_SOFTRING_TO_SET(mac_srs, ringp); 193 mutex_exit(&mac_srs->srs_lock); 194 195 /* 196 * set the bind CPU to -1 to indicate 197 * no thread affinity set 198 */ 199 ringp->s_ring_cpuid = ringp->s_ring_cpuid_save = -1; 200 ringp->s_ring_worker = thread_create(NULL, 0, 201 mac_soft_ring_worker, ringp, 0, &p0, TS_RUN, pri); 202 if (type & ST_RING_TX) { 203 ringp->s_ring_drain_func = mac_tx_soft_ring_drain; 204 ringp->s_ring_tx_arg1 = x_arg1; 205 ringp->s_ring_tx_arg2 = x_arg2; 206 ringp->s_ring_tx_max_q_cnt = mac_tx_soft_ring_max_q_cnt; 207 ringp->s_ring_tx_hiwat = 208 (mac_tx_soft_ring_hiwat > mac_tx_soft_ring_max_q_cnt) ? 209 mac_tx_soft_ring_max_q_cnt : mac_tx_soft_ring_hiwat; 210 if (mcip->mci_state_flags & MCIS_IS_AGGR) { 211 mac_srs_tx_t *tx = &mac_srs->srs_tx; 212 213 ASSERT(tx->st_soft_rings[ 214 ((mac_ring_t *)x_arg2)->mr_index] == NULL); 215 tx->st_soft_rings[((mac_ring_t *)x_arg2)->mr_index] = 216 ringp; 217 } 218 } else { 219 ringp->s_ring_drain_func = mac_rx_soft_ring_drain; 220 ringp->s_ring_rx_func = rx_func; 221 ringp->s_ring_rx_arg1 = x_arg1; 222 ringp->s_ring_rx_arg2 = x_arg2; 223 if (mac_srs->srs_state & SRS_SOFTRING_QUEUE) 224 ringp->s_ring_type |= ST_RING_WORKER_ONLY; 225 } 226 if (cpuid != -1) 227 (void) mac_soft_ring_bind(ringp, cpuid); 228 229 mac_soft_ring_stat_create(ringp); 230 231 return (ringp); 232 } 233 234 /* 235 * mac_soft_ring_free 236 * 237 * Free the soft ring once we are done with it. 238 */ 239 void 240 mac_soft_ring_free(mac_soft_ring_t *softring) 241 { 242 ASSERT((softring->s_ring_state & 243 (S_RING_CONDEMNED | S_RING_CONDEMNED_DONE | S_RING_PROC)) == 244 (S_RING_CONDEMNED | S_RING_CONDEMNED_DONE)); 245 mac_pkt_drop(NULL, NULL, softring->s_ring_first, B_FALSE); 246 softring->s_ring_tx_arg2 = NULL; 247 mac_soft_ring_stat_delete(softring); 248 mac_callback_free(softring->s_ring_notify_cb_list); 249 kmem_cache_free(mac_soft_ring_cache, softring); 250 } 251 252 int mac_soft_ring_thread_bind = 1; 253 254 /* 255 * mac_soft_ring_bind 256 * 257 * Bind a soft ring worker thread to supplied CPU. 258 */ 259 cpu_t * 260 mac_soft_ring_bind(mac_soft_ring_t *ringp, processorid_t cpuid) 261 { 262 cpu_t *cp; 263 boolean_t clear = B_FALSE; 264 265 ASSERT(MUTEX_HELD(&cpu_lock)); 266 267 if (mac_soft_ring_thread_bind == 0) { 268 DTRACE_PROBE1(mac__soft__ring__no__cpu__bound, 269 mac_soft_ring_t *, ringp); 270 return (NULL); 271 } 272 273 cp = cpu_get(cpuid); 274 if (cp == NULL || !cpu_is_online(cp)) 275 return (NULL); 276 277 mutex_enter(&ringp->s_ring_lock); 278 ringp->s_ring_state |= S_RING_BOUND; 279 if (ringp->s_ring_cpuid != -1) 280 clear = B_TRUE; 281 ringp->s_ring_cpuid = cpuid; 282 mutex_exit(&ringp->s_ring_lock); 283 284 if (clear) 285 thread_affinity_clear(ringp->s_ring_worker); 286 287 DTRACE_PROBE2(mac__soft__ring__cpu__bound, mac_soft_ring_t *, 288 ringp, processorid_t, cpuid); 289 290 thread_affinity_set(ringp->s_ring_worker, cpuid); 291 292 return (cp); 293 } 294 295 /* 296 * mac_soft_ring_unbind 297 * 298 * Un Bind a soft ring worker thread. 299 */ 300 void 301 mac_soft_ring_unbind(mac_soft_ring_t *ringp) 302 { 303 ASSERT(MUTEX_HELD(&cpu_lock)); 304 305 mutex_enter(&ringp->s_ring_lock); 306 if (!(ringp->s_ring_state & S_RING_BOUND)) { 307 ASSERT(ringp->s_ring_cpuid == -1); 308 mutex_exit(&ringp->s_ring_lock); 309 return; 310 } 311 312 ringp->s_ring_cpuid = -1; 313 ringp->s_ring_state &= ~S_RING_BOUND; 314 thread_affinity_clear(ringp->s_ring_worker); 315 mutex_exit(&ringp->s_ring_lock); 316 } 317 318 /* 319 * PRIVATE FUNCTIONS 320 */ 321 322 static void 323 mac_soft_ring_fire(void *arg) 324 { 325 mac_soft_ring_t *ringp = arg; 326 327 mutex_enter(&ringp->s_ring_lock); 328 if (ringp->s_ring_tid == NULL) { 329 mutex_exit(&ringp->s_ring_lock); 330 return; 331 } 332 333 ringp->s_ring_tid = NULL; 334 335 if (!(ringp->s_ring_state & S_RING_PROC)) { 336 cv_signal(&ringp->s_ring_async); 337 } 338 mutex_exit(&ringp->s_ring_lock); 339 } 340 341 /* 342 * mac_rx_soft_ring_drain 343 * 344 * Called when worker thread model (ST_RING_WORKER_ONLY) of processing 345 * incoming packets is used. s_ring_first contain the queued packets. 346 * s_ring_rx_func contains the upper level (client) routine where the 347 * packets are destined and s_ring_rx_arg1/s_ring_rx_arg2 are the 348 * cookie meant for the client. 349 */ 350 /* ARGSUSED */ 351 static void 352 mac_rx_soft_ring_drain(mac_soft_ring_t *ringp) 353 { 354 mblk_t *mp; 355 void *arg1; 356 mac_resource_handle_t arg2; 357 timeout_id_t tid; 358 mac_direct_rx_t proc; 359 size_t sz; 360 int cnt; 361 mac_soft_ring_set_t *mac_srs = ringp->s_ring_set; 362 363 ringp->s_ring_run = curthread; 364 ASSERT(mutex_owned(&ringp->s_ring_lock)); 365 ASSERT(!(ringp->s_ring_state & S_RING_PROC)); 366 367 if ((tid = ringp->s_ring_tid) != NULL) 368 ringp->s_ring_tid = NULL; 369 370 ringp->s_ring_state |= S_RING_PROC; 371 372 proc = ringp->s_ring_rx_func; 373 arg1 = ringp->s_ring_rx_arg1; 374 arg2 = ringp->s_ring_rx_arg2; 375 376 while ((ringp->s_ring_first != NULL) && 377 !(ringp->s_ring_state & S_RING_PAUSE)) { 378 mp = ringp->s_ring_first; 379 ringp->s_ring_first = NULL; 380 ringp->s_ring_last = NULL; 381 cnt = ringp->s_ring_count; 382 ringp->s_ring_count = 0; 383 sz = ringp->s_ring_size; 384 ringp->s_ring_size = 0; 385 mutex_exit(&ringp->s_ring_lock); 386 387 if (tid != NULL) { 388 (void) untimeout(tid); 389 tid = NULL; 390 } 391 392 (*proc)(arg1, arg2, mp, NULL); 393 394 /* 395 * If we have a soft ring set which is doing 396 * bandwidth control, we need to decrement its 397 * srs_size so it can have a accurate idea of 398 * what is the real data queued between SRS and 399 * its soft rings. We decrement the size for a 400 * packet only when it gets processed by both 401 * SRS and the soft ring. 402 */ 403 mutex_enter(&mac_srs->srs_lock); 404 MAC_UPDATE_SRS_COUNT_LOCKED(mac_srs, cnt); 405 MAC_UPDATE_SRS_SIZE_LOCKED(mac_srs, sz); 406 mutex_exit(&mac_srs->srs_lock); 407 408 mutex_enter(&ringp->s_ring_lock); 409 } 410 ringp->s_ring_state &= ~S_RING_PROC; 411 if (ringp->s_ring_state & S_RING_CLIENT_WAIT) 412 cv_signal(&ringp->s_ring_client_cv); 413 ringp->s_ring_run = NULL; 414 } 415 416 /* 417 * mac_soft_ring_worker 418 * 419 * The soft ring worker routine to process any queued packets. In 420 * normal case, the worker thread is bound to a CPU. It the soft 421 * ring is dealing with TCP packets, then the worker thread will 422 * be bound to the same CPU as the TCP squeue. 423 */ 424 static void 425 mac_soft_ring_worker(mac_soft_ring_t *ringp) 426 { 427 kmutex_t *lock = &ringp->s_ring_lock; 428 kcondvar_t *async = &ringp->s_ring_async; 429 mac_soft_ring_set_t *srs = ringp->s_ring_set; 430 callb_cpr_t cprinfo; 431 432 CALLB_CPR_INIT(&cprinfo, lock, callb_generic_cpr, "mac_soft_ring"); 433 mutex_enter(lock); 434 start: 435 for (;;) { 436 while (((ringp->s_ring_first == NULL || 437 (ringp->s_ring_state & (S_RING_BLOCK|S_RING_BLANK))) && 438 !(ringp->s_ring_state & S_RING_PAUSE)) || 439 (ringp->s_ring_state & S_RING_PROC)) { 440 441 CALLB_CPR_SAFE_BEGIN(&cprinfo); 442 cv_wait(async, lock); 443 CALLB_CPR_SAFE_END(&cprinfo, lock); 444 } 445 446 /* 447 * Either we have work to do, or we have been asked to 448 * shutdown temporarily or permanently 449 */ 450 if (ringp->s_ring_state & S_RING_PAUSE) 451 goto done; 452 453 ringp->s_ring_drain_func(ringp); 454 } 455 done: 456 mutex_exit(lock); 457 mutex_enter(&srs->srs_lock); 458 mutex_enter(lock); 459 460 ringp->s_ring_state |= S_RING_QUIESCE_DONE; 461 if (!(ringp->s_ring_state & S_RING_CONDEMNED)) { 462 srs->srs_soft_ring_quiesced_count++; 463 cv_broadcast(&srs->srs_async); 464 mutex_exit(&srs->srs_lock); 465 while (!(ringp->s_ring_state & 466 (S_RING_RESTART | S_RING_CONDEMNED))) 467 cv_wait(&ringp->s_ring_async, &ringp->s_ring_lock); 468 mutex_exit(lock); 469 mutex_enter(&srs->srs_lock); 470 mutex_enter(lock); 471 srs->srs_soft_ring_quiesced_count--; 472 if (ringp->s_ring_state & S_RING_RESTART) { 473 ASSERT(!(ringp->s_ring_state & S_RING_CONDEMNED)); 474 ringp->s_ring_state &= ~(S_RING_RESTART | 475 S_RING_QUIESCE | S_RING_QUIESCE_DONE); 476 cv_broadcast(&srs->srs_async); 477 mutex_exit(&srs->srs_lock); 478 goto start; 479 } 480 } 481 ASSERT(ringp->s_ring_state & S_RING_CONDEMNED); 482 ringp->s_ring_state |= S_RING_CONDEMNED_DONE; 483 CALLB_CPR_EXIT(&cprinfo); 484 srs->srs_soft_ring_condemned_count++; 485 cv_broadcast(&srs->srs_async); 486 mutex_exit(&srs->srs_lock); 487 thread_exit(); 488 } 489 490 /* 491 * mac_soft_ring_intr_enable and mac_soft_ring_intr_disable 492 * 493 * these functions are called to toggle the sending of packets to the 494 * client. They are called by the client. the client gets the name 495 * of these routine and corresponding cookie (pointing to softring) 496 * during capability negotiation at setup time. 497 * 498 * Enabling is allow the processing thread to send packets to the 499 * client while disabling does the opposite. 500 */ 501 void 502 mac_soft_ring_intr_enable(void *arg) 503 { 504 mac_soft_ring_t *ringp = (mac_soft_ring_t *)arg; 505 mutex_enter(&ringp->s_ring_lock); 506 ringp->s_ring_state &= ~S_RING_BLANK; 507 if (ringp->s_ring_first != NULL) 508 mac_soft_ring_worker_wakeup(ringp); 509 mutex_exit(&ringp->s_ring_lock); 510 } 511 512 boolean_t 513 mac_soft_ring_intr_disable(void *arg) 514 { 515 mac_soft_ring_t *ringp = (mac_soft_ring_t *)arg; 516 boolean_t sring_blanked = B_FALSE; 517 /* 518 * Stop worker thread from sending packets above. 519 * Squeue will poll soft ring when it needs packets. 520 */ 521 mutex_enter(&ringp->s_ring_lock); 522 if (!(ringp->s_ring_state & S_RING_PROC)) { 523 ringp->s_ring_state |= S_RING_BLANK; 524 sring_blanked = B_TRUE; 525 } 526 mutex_exit(&ringp->s_ring_lock); 527 return (sring_blanked); 528 } 529 530 /* 531 * mac_soft_ring_poll 532 * 533 * This routine is called by the client to poll for packets from 534 * the soft ring. The function name and cookie corresponding to 535 * the soft ring is exchanged during capability negotiation during 536 * setup. 537 */ 538 mblk_t * 539 mac_soft_ring_poll(mac_soft_ring_t *ringp, size_t bytes_to_pickup) 540 { 541 mblk_t *head, *tail; 542 mblk_t *mp; 543 size_t sz = 0; 544 int cnt = 0; 545 mac_soft_ring_set_t *mac_srs = ringp->s_ring_set; 546 547 ASSERT(mac_srs != NULL); 548 549 mutex_enter(&ringp->s_ring_lock); 550 head = tail = mp = ringp->s_ring_first; 551 if (head == NULL) { 552 mutex_exit(&ringp->s_ring_lock); 553 return (NULL); 554 } 555 556 if (ringp->s_ring_size <= bytes_to_pickup) { 557 head = ringp->s_ring_first; 558 ringp->s_ring_first = NULL; 559 ringp->s_ring_last = NULL; 560 cnt = ringp->s_ring_count; 561 ringp->s_ring_count = 0; 562 sz = ringp->s_ring_size; 563 ringp->s_ring_size = 0; 564 } else { 565 while (mp && sz <= bytes_to_pickup) { 566 sz += msgdsize(mp); 567 cnt++; 568 tail = mp; 569 mp = mp->b_next; 570 } 571 ringp->s_ring_count -= cnt; 572 ringp->s_ring_size -= sz; 573 tail->b_next = NULL; 574 if (mp == NULL) { 575 ringp->s_ring_first = NULL; 576 ringp->s_ring_last = NULL; 577 ASSERT(ringp->s_ring_count == 0); 578 } else { 579 ringp->s_ring_first = mp; 580 } 581 } 582 583 mutex_exit(&ringp->s_ring_lock); 584 /* 585 * Update the shared count and size counters so 586 * that SRS has a accurate idea of queued packets. 587 */ 588 mutex_enter(&mac_srs->srs_lock); 589 MAC_UPDATE_SRS_COUNT_LOCKED(mac_srs, cnt); 590 MAC_UPDATE_SRS_SIZE_LOCKED(mac_srs, sz); 591 mutex_exit(&mac_srs->srs_lock); 592 return (head); 593 } 594 595 /* 596 * mac_soft_ring_dls_bypass 597 * 598 * Enable direct client (IP) callback function from the softrings. 599 * Callers need to make sure they don't need any DLS layer processing 600 */ 601 void 602 mac_soft_ring_dls_bypass(void *arg, mac_direct_rx_t rx_func, void *rx_arg1) 603 { 604 mac_soft_ring_t *softring = arg; 605 mac_soft_ring_set_t *srs; 606 607 ASSERT(rx_func != NULL); 608 609 mutex_enter(&softring->s_ring_lock); 610 softring->s_ring_rx_func = rx_func; 611 softring->s_ring_rx_arg1 = rx_arg1; 612 mutex_exit(&softring->s_ring_lock); 613 614 srs = softring->s_ring_set; 615 mutex_enter(&srs->srs_lock); 616 srs->srs_type |= SRST_DLS_BYPASS; 617 mutex_exit(&srs->srs_lock); 618 } 619 620 /* 621 * mac_soft_ring_signal 622 * 623 * Typically used to set the soft ring state to QUIESCE, CONDEMNED, or 624 * RESTART. 625 * 626 * In the Rx side, the quiescing is done bottom up. After the Rx upcalls 627 * from the driver are done, then the Rx SRS is quiesced and only then can 628 * we signal the soft rings. Thus this function can't be called arbitrarily 629 * without satisfying the prerequisites. On the Tx side, the threads from 630 * top need to quiesced, then the Tx SRS and only then can we signal the 631 * Tx soft rings. 632 */ 633 void 634 mac_soft_ring_signal(mac_soft_ring_t *softring, uint_t sr_flag) 635 { 636 mutex_enter(&softring->s_ring_lock); 637 softring->s_ring_state |= sr_flag; 638 cv_signal(&softring->s_ring_async); 639 mutex_exit(&softring->s_ring_lock); 640 } 641 642 /* 643 * mac_tx_soft_ring_drain 644 * 645 * The transmit side drain routine in case the soft ring was being 646 * used to transmit packets. 647 */ 648 static void 649 mac_tx_soft_ring_drain(mac_soft_ring_t *ringp) 650 { 651 mblk_t *mp; 652 void *arg1; 653 void *arg2; 654 mblk_t *tail; 655 uint_t saved_pkt_count, saved_size; 656 mac_tx_stats_t stats; 657 mac_soft_ring_set_t *mac_srs = ringp->s_ring_set; 658 659 saved_pkt_count = saved_size = 0; 660 ringp->s_ring_run = curthread; 661 ASSERT(mutex_owned(&ringp->s_ring_lock)); 662 ASSERT(!(ringp->s_ring_state & S_RING_PROC)); 663 664 ringp->s_ring_state |= S_RING_PROC; 665 arg1 = ringp->s_ring_tx_arg1; 666 arg2 = ringp->s_ring_tx_arg2; 667 668 while (ringp->s_ring_first != NULL) { 669 mp = ringp->s_ring_first; 670 tail = ringp->s_ring_last; 671 saved_pkt_count = ringp->s_ring_count; 672 saved_size = ringp->s_ring_size; 673 ringp->s_ring_first = NULL; 674 ringp->s_ring_last = NULL; 675 ringp->s_ring_count = 0; 676 ringp->s_ring_size = 0; 677 mutex_exit(&ringp->s_ring_lock); 678 679 mp = mac_tx_send(arg1, arg2, mp, &stats); 680 681 mutex_enter(&ringp->s_ring_lock); 682 if (mp != NULL) { 683 /* Device out of tx desc, set block */ 684 tail->b_next = ringp->s_ring_first; 685 ringp->s_ring_first = mp; 686 ringp->s_ring_count += 687 (saved_pkt_count - stats.mts_opackets); 688 ringp->s_ring_size += (saved_size - stats.mts_obytes); 689 if (ringp->s_ring_last == NULL) 690 ringp->s_ring_last = tail; 691 692 if (ringp->s_ring_tx_woken_up) { 693 ringp->s_ring_tx_woken_up = B_FALSE; 694 } else { 695 ringp->s_ring_state |= S_RING_BLOCK; 696 ringp->s_st_stat.mts_blockcnt++; 697 } 698 699 ringp->s_ring_state &= ~S_RING_PROC; 700 ringp->s_ring_run = NULL; 701 return; 702 } else { 703 ringp->s_ring_tx_woken_up = B_FALSE; 704 SRS_TX_STATS_UPDATE(mac_srs, &stats); 705 SOFTRING_TX_STATS_UPDATE(ringp, &stats); 706 } 707 } 708 709 if (ringp->s_ring_count == 0 && ringp->s_ring_state & 710 (S_RING_TX_HIWAT | S_RING_WAKEUP_CLIENT | S_RING_ENQUEUED)) { 711 mac_client_impl_t *mcip = ringp->s_ring_mcip; 712 boolean_t wakeup_required = B_FALSE; 713 714 if (ringp->s_ring_state & 715 (S_RING_TX_HIWAT|S_RING_WAKEUP_CLIENT)) { 716 wakeup_required = B_TRUE; 717 } 718 ringp->s_ring_state &= 719 ~(S_RING_TX_HIWAT | S_RING_WAKEUP_CLIENT | S_RING_ENQUEUED); 720 mutex_exit(&ringp->s_ring_lock); 721 if (wakeup_required) { 722 mac_tx_invoke_callbacks(mcip, (mac_tx_cookie_t)ringp); 723 /* 724 * If the client is not the primary MAC client, then we 725 * need to send the notification to the clients upper 726 * MAC, i.e. mci_upper_mip. 727 */ 728 mac_tx_notify(mcip->mci_upper_mip != NULL ? 729 mcip->mci_upper_mip : mcip->mci_mip); 730 } 731 mutex_enter(&ringp->s_ring_lock); 732 } 733 ringp->s_ring_state &= ~S_RING_PROC; 734 ringp->s_ring_run = NULL; 735 } 736