17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*e824d57fSjohnlev * Common Development and Distribution License (the "License"). 6*e824d57fSjohnlev * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22d045b987Smasputra * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * Squeues - TCP/IP serialization mechanism. 307c478bd9Sstevel@tonic-gate * 317c478bd9Sstevel@tonic-gate * This is a general purpose high-performance serialization mechanism. It is 327c478bd9Sstevel@tonic-gate * similar to a taskq with a single worker thread, the difference is that it 337c478bd9Sstevel@tonic-gate * does not imply a context switch - the thread placing a request may actually 347c478bd9Sstevel@tonic-gate * process it. It is also biased for processing requests in interrupt context. 357c478bd9Sstevel@tonic-gate * 367c478bd9Sstevel@tonic-gate * Each squeue has a worker thread which may optionally be bound to a CPU. 377c478bd9Sstevel@tonic-gate * 387c478bd9Sstevel@tonic-gate * Only one thread may process requests from a given squeue at any time. This is 397c478bd9Sstevel@tonic-gate * called "entering" squeue. 407c478bd9Sstevel@tonic-gate * 417c478bd9Sstevel@tonic-gate * Each dispatched request is processed either by 427c478bd9Sstevel@tonic-gate * 437c478bd9Sstevel@tonic-gate * a) Dispatching thread or 447c478bd9Sstevel@tonic-gate * b) Some other thread that is currently processing squeue at the time of 457c478bd9Sstevel@tonic-gate * request or 467c478bd9Sstevel@tonic-gate * c) worker thread. 477c478bd9Sstevel@tonic-gate * 487c478bd9Sstevel@tonic-gate * INTERFACES: 497c478bd9Sstevel@tonic-gate * 507c478bd9Sstevel@tonic-gate * squeue_t *squeue_create(name, bind, wait, pri) 517c478bd9Sstevel@tonic-gate * 527c478bd9Sstevel@tonic-gate * name: symbolic name for squeue. 537c478bd9Sstevel@tonic-gate * wait: time to wait before waiking the worker thread after queueing 547c478bd9Sstevel@tonic-gate * request. 557c478bd9Sstevel@tonic-gate * bind: preferred CPU binding for the worker thread. 567c478bd9Sstevel@tonic-gate * pri: thread priority for the worker thread. 577c478bd9Sstevel@tonic-gate * 587c478bd9Sstevel@tonic-gate * This function never fails and may sleep. It returns a transparent pointer 597c478bd9Sstevel@tonic-gate * to the squeue_t structure that is passed to all other squeue operations. 607c478bd9Sstevel@tonic-gate * 617c478bd9Sstevel@tonic-gate * void squeue_bind(sqp, bind) 627c478bd9Sstevel@tonic-gate * 637c478bd9Sstevel@tonic-gate * Bind squeue worker thread to a CPU specified by the 'bind' argument. The 647c478bd9Sstevel@tonic-gate * 'bind' value of -1 binds to the preferred thread specified for 657c478bd9Sstevel@tonic-gate * squeue_create. 667c478bd9Sstevel@tonic-gate * 677c478bd9Sstevel@tonic-gate * NOTE: Any value of 'bind' other then -1 is not supported currently, but the 687c478bd9Sstevel@tonic-gate * API is present - in the future it may be useful to specify different 697c478bd9Sstevel@tonic-gate * binding. 707c478bd9Sstevel@tonic-gate * 717c478bd9Sstevel@tonic-gate * void squeue_unbind(sqp) 727c478bd9Sstevel@tonic-gate * 737c478bd9Sstevel@tonic-gate * Unbind the worker thread from its preferred CPU. 747c478bd9Sstevel@tonic-gate * 757c478bd9Sstevel@tonic-gate * void squeue_enter(*sqp, *mp, proc, arg, tag) 767c478bd9Sstevel@tonic-gate * 777c478bd9Sstevel@tonic-gate * Post a single request for processing. Each request consists of mblock 'mp', 787c478bd9Sstevel@tonic-gate * function 'proc' to execute and an argument 'arg' to pass to this 797c478bd9Sstevel@tonic-gate * function. The function is called as (*proc)(arg, mp, sqp); The tag is an 807c478bd9Sstevel@tonic-gate * arbitrary number from 0 to 255 which will be stored in mp to track exact 817c478bd9Sstevel@tonic-gate * caller of squeue_enter. The combination of function name and the tag should 827c478bd9Sstevel@tonic-gate * provide enough information to identify the caller. 837c478bd9Sstevel@tonic-gate * 847c478bd9Sstevel@tonic-gate * If no one is processing the squeue, squeue_enter() will call the function 857c478bd9Sstevel@tonic-gate * immediately. Otherwise it will add the request to the queue for later 867c478bd9Sstevel@tonic-gate * processing. Once the function is executed, the thread may continue 877c478bd9Sstevel@tonic-gate * executing all other requests pending on the queue. 887c478bd9Sstevel@tonic-gate * 897c478bd9Sstevel@tonic-gate * NOTE: The tagging information is only used when SQUEUE_DEBUG is set to 1. 907c478bd9Sstevel@tonic-gate * NOTE: The argument can be conn_t only. Ideally we'd like to have generic 917c478bd9Sstevel@tonic-gate * argument, but we want to drop connection reference count here - this 927c478bd9Sstevel@tonic-gate * improves tail-call optimizations. 937c478bd9Sstevel@tonic-gate * XXX: The arg should have type conn_t. 947c478bd9Sstevel@tonic-gate * 957c478bd9Sstevel@tonic-gate * void squeue_enter_nodrain(*sqp, *mp, proc, arg, tag) 967c478bd9Sstevel@tonic-gate * 977c478bd9Sstevel@tonic-gate * Same as squeue_enter(), but the entering thread will only try to execute a 987c478bd9Sstevel@tonic-gate * single request. It will not continue executing any pending requests. 997c478bd9Sstevel@tonic-gate * 1007c478bd9Sstevel@tonic-gate * void squeue_fill(*sqp, *mp, proc, arg, tag) 1017c478bd9Sstevel@tonic-gate * 1027c478bd9Sstevel@tonic-gate * Just place the request on the queue without trying to execute it. Arrange 1037c478bd9Sstevel@tonic-gate * for the worker thread to process the request. 1047c478bd9Sstevel@tonic-gate * 1057c478bd9Sstevel@tonic-gate * void squeue_profile_enable(sqp) 1067c478bd9Sstevel@tonic-gate * void squeue_profile_disable(sqp) 1077c478bd9Sstevel@tonic-gate * 1087c478bd9Sstevel@tonic-gate * Enable or disable profiling for specified 'sqp'. Profiling is only 1097c478bd9Sstevel@tonic-gate * available when SQUEUE_PROFILE is set. 1107c478bd9Sstevel@tonic-gate * 1117c478bd9Sstevel@tonic-gate * void squeue_profile_reset(sqp) 1127c478bd9Sstevel@tonic-gate * 1137c478bd9Sstevel@tonic-gate * Reset all profiling information to zero. Profiling is only 1147c478bd9Sstevel@tonic-gate * available when SQUEUE_PROFILE is set. 1157c478bd9Sstevel@tonic-gate * 1167c478bd9Sstevel@tonic-gate * void squeue_profile_start() 1177c478bd9Sstevel@tonic-gate * void squeue_profile_stop() 1187c478bd9Sstevel@tonic-gate * 1197c478bd9Sstevel@tonic-gate * Globally enable or disabled profiling for all squeues. 1207c478bd9Sstevel@tonic-gate * 1217c478bd9Sstevel@tonic-gate * uintptr_t *squeue_getprivate(sqp, p) 1227c478bd9Sstevel@tonic-gate * 1237c478bd9Sstevel@tonic-gate * Each squeue keeps small amount of private data space available for various 1247c478bd9Sstevel@tonic-gate * consumers. Current consumers include TCP and NCA. Other consumers need to 1257c478bd9Sstevel@tonic-gate * add their private tag to the sqprivate_t enum. The private information is 1267c478bd9Sstevel@tonic-gate * limited to an uintptr_t value. The squeue has no knowledge of its content 1277c478bd9Sstevel@tonic-gate * and does not manage it in any way. 1287c478bd9Sstevel@tonic-gate * 1297c478bd9Sstevel@tonic-gate * The typical use may be a breakdown of data structures per CPU (since 1307c478bd9Sstevel@tonic-gate * squeues are usually per CPU). See NCA for examples of use. 1317c478bd9Sstevel@tonic-gate * Currently 'p' may have one legal value SQPRIVATE_TCP. 1327c478bd9Sstevel@tonic-gate * 1337c478bd9Sstevel@tonic-gate * processorid_t squeue_binding(sqp) 1347c478bd9Sstevel@tonic-gate * 1357c478bd9Sstevel@tonic-gate * Returns the CPU binding for a given squeue. 1367c478bd9Sstevel@tonic-gate * 1377c478bd9Sstevel@tonic-gate * TUNABALES: 1387c478bd9Sstevel@tonic-gate * 1397c478bd9Sstevel@tonic-gate * squeue_intrdrain_ms: Maximum time in ms interrupts spend draining any 1407c478bd9Sstevel@tonic-gate * squeue. Note that this is approximation - squeues have no control on the 1417c478bd9Sstevel@tonic-gate * time it takes to process each request. This limit is only checked 1427c478bd9Sstevel@tonic-gate * between processing individual messages. 1437c478bd9Sstevel@tonic-gate * Default: 20 ms. 1447c478bd9Sstevel@tonic-gate * 1457c478bd9Sstevel@tonic-gate * squeue_writerdrain_ms: Maximum time in ms non-interrupts spend draining any 1467c478bd9Sstevel@tonic-gate * squeue. Note that this is approximation - squeues have no control on the 1477c478bd9Sstevel@tonic-gate * time it takes to process each request. This limit is only checked 1487c478bd9Sstevel@tonic-gate * between processing individual messages. 1497c478bd9Sstevel@tonic-gate * Default: 10 ms. 1507c478bd9Sstevel@tonic-gate * 1517c478bd9Sstevel@tonic-gate * squeue_workerdrain_ms: Maximum time in ms worker thread spends draining any 1527c478bd9Sstevel@tonic-gate * squeue. Note that this is approximation - squeues have no control on the 1537c478bd9Sstevel@tonic-gate * time it takes to process each request. This limit is only checked 1547c478bd9Sstevel@tonic-gate * between processing individual messages. 1557c478bd9Sstevel@tonic-gate * Default: 10 ms. 1567c478bd9Sstevel@tonic-gate * 1577c478bd9Sstevel@tonic-gate * squeue_workerwait_ms: When worker thread is interrupted because workerdrain 1587c478bd9Sstevel@tonic-gate * expired, how much time to wait before waking worker thread again. 1597c478bd9Sstevel@tonic-gate * Default: 10 ms. 1607c478bd9Sstevel@tonic-gate */ 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate #include <sys/types.h> 1637c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 1647c478bd9Sstevel@tonic-gate #include <sys/debug.h> 1657c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 1667c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 1677c478bd9Sstevel@tonic-gate #include <sys/condvar_impl.h> 1687c478bd9Sstevel@tonic-gate #include <sys/systm.h> 1697c478bd9Sstevel@tonic-gate #include <sys/callb.h> 1707c478bd9Sstevel@tonic-gate #include <sys/sdt.h> 1717c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h> 174d045b987Smasputra #include <inet/udp_impl.h> 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate /* 1777c478bd9Sstevel@tonic-gate * State flags. 1787c478bd9Sstevel@tonic-gate * Note: The MDB IP module depends on the values of these flags. 1797c478bd9Sstevel@tonic-gate */ 1807c478bd9Sstevel@tonic-gate #define SQS_PROC 0x0001 /* being processed */ 1817c478bd9Sstevel@tonic-gate #define SQS_WORKER 0x0002 /* worker thread */ 1827c478bd9Sstevel@tonic-gate #define SQS_ENTER 0x0004 /* enter thread */ 1837c478bd9Sstevel@tonic-gate #define SQS_FAST 0x0008 /* enter-fast thread */ 1847c478bd9Sstevel@tonic-gate #define SQS_USER 0x0010 /* A non interrupt user */ 1857c478bd9Sstevel@tonic-gate #define SQS_BOUND 0x0020 /* Worker thread is bound */ 1867c478bd9Sstevel@tonic-gate #define SQS_PROFILE 0x0040 /* Enable profiling */ 1877c478bd9Sstevel@tonic-gate #define SQS_REENTER 0x0080 /* Re entered thread */ 1887c478bd9Sstevel@tonic-gate #define SQS_TMO_PROG 0x0100 /* Timeout is being set */ 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate #include <sys/squeue_impl.h> 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate static void squeue_fire(void *); 193d19d6468Sbw static void squeue_drain(squeue_t *, uint_t, hrtime_t); 1947c478bd9Sstevel@tonic-gate static void squeue_worker(squeue_t *sqp); 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 1977c478bd9Sstevel@tonic-gate static kmutex_t squeue_kstat_lock; 1987c478bd9Sstevel@tonic-gate static int squeue_kstat_update(kstat_t *, int); 1997c478bd9Sstevel@tonic-gate #endif 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate kmem_cache_t *squeue_cache; 2027c478bd9Sstevel@tonic-gate 203d19d6468Sbw #define SQUEUE_MSEC_TO_NSEC 1000000 204d19d6468Sbw 2057c478bd9Sstevel@tonic-gate int squeue_intrdrain_ms = 20; 2067c478bd9Sstevel@tonic-gate int squeue_writerdrain_ms = 10; 2077c478bd9Sstevel@tonic-gate int squeue_workerdrain_ms = 10; 2087c478bd9Sstevel@tonic-gate int squeue_workerwait_ms = 10; 2097c478bd9Sstevel@tonic-gate 210d19d6468Sbw /* The values above converted to ticks or nano seconds */ 211d19d6468Sbw static int squeue_intrdrain_ns = 0; 212d19d6468Sbw static int squeue_writerdrain_ns = 0; 213d19d6468Sbw static int squeue_workerdrain_ns = 0; 2147c478bd9Sstevel@tonic-gate static int squeue_workerwait_tick = 0; 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate /* 2177c478bd9Sstevel@tonic-gate * The minimum packet queued when worker thread doing the drain triggers 2187c478bd9Sstevel@tonic-gate * polling (if squeue allows it). The choice of 3 is arbitrary. You 2197c478bd9Sstevel@tonic-gate * definitely don't want it to be 1 since that will trigger polling 2207c478bd9Sstevel@tonic-gate * on very low loads as well (ssh seems to do be one such example 2217c478bd9Sstevel@tonic-gate * where packet flow was very low yet somehow 1 packet ended up getting 2227c478bd9Sstevel@tonic-gate * queued and worker thread fires every 10ms and blanking also gets 2237c478bd9Sstevel@tonic-gate * triggered. 2247c478bd9Sstevel@tonic-gate */ 2257c478bd9Sstevel@tonic-gate int squeue_worker_poll_min = 3; 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 2287c478bd9Sstevel@tonic-gate /* 2297c478bd9Sstevel@tonic-gate * Set to B_TRUE to enable profiling. 2307c478bd9Sstevel@tonic-gate */ 2317c478bd9Sstevel@tonic-gate static int squeue_profile = B_FALSE; 2327c478bd9Sstevel@tonic-gate #define SQ_PROFILING(sqp) (squeue_profile && ((sqp)->sq_state & SQS_PROFILE)) 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate #define SQSTAT(sqp, x) ((sqp)->sq_stats.x++) 2357c478bd9Sstevel@tonic-gate #define SQDELTA(sqp, x, d) ((sqp)->sq_stats.x += (d)) 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate struct squeue_kstat { 2387c478bd9Sstevel@tonic-gate kstat_named_t sq_count; 2397c478bd9Sstevel@tonic-gate kstat_named_t sq_max_qlen; 2407c478bd9Sstevel@tonic-gate kstat_named_t sq_npackets_worker; 2417c478bd9Sstevel@tonic-gate kstat_named_t sq_npackets_intr; 2427c478bd9Sstevel@tonic-gate kstat_named_t sq_npackets_other; 2437c478bd9Sstevel@tonic-gate kstat_named_t sq_nqueued_intr; 2447c478bd9Sstevel@tonic-gate kstat_named_t sq_nqueued_other; 2457c478bd9Sstevel@tonic-gate kstat_named_t sq_ndrains_worker; 2467c478bd9Sstevel@tonic-gate kstat_named_t sq_ndrains_intr; 2477c478bd9Sstevel@tonic-gate kstat_named_t sq_ndrains_other; 2487c478bd9Sstevel@tonic-gate kstat_named_t sq_time_worker; 2497c478bd9Sstevel@tonic-gate kstat_named_t sq_time_intr; 2507c478bd9Sstevel@tonic-gate kstat_named_t sq_time_other; 2517c478bd9Sstevel@tonic-gate } squeue_kstat = { 2527c478bd9Sstevel@tonic-gate { "count", KSTAT_DATA_UINT64 }, 2537c478bd9Sstevel@tonic-gate { "max_qlen", KSTAT_DATA_UINT64 }, 2547c478bd9Sstevel@tonic-gate { "packets_worker", KSTAT_DATA_UINT64 }, 2557c478bd9Sstevel@tonic-gate { "packets_intr", KSTAT_DATA_UINT64 }, 2567c478bd9Sstevel@tonic-gate { "packets_other", KSTAT_DATA_UINT64 }, 2577c478bd9Sstevel@tonic-gate { "queued_intr", KSTAT_DATA_UINT64 }, 2587c478bd9Sstevel@tonic-gate { "queued_other", KSTAT_DATA_UINT64 }, 2597c478bd9Sstevel@tonic-gate { "ndrains_worker", KSTAT_DATA_UINT64 }, 2607c478bd9Sstevel@tonic-gate { "ndrains_intr", KSTAT_DATA_UINT64 }, 2617c478bd9Sstevel@tonic-gate { "ndrains_other", KSTAT_DATA_UINT64 }, 2627c478bd9Sstevel@tonic-gate { "time_worker", KSTAT_DATA_UINT64 }, 2637c478bd9Sstevel@tonic-gate { "time_intr", KSTAT_DATA_UINT64 }, 2647c478bd9Sstevel@tonic-gate { "time_other", KSTAT_DATA_UINT64 }, 2657c478bd9Sstevel@tonic-gate }; 2667c478bd9Sstevel@tonic-gate #endif 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate #define SQUEUE_WORKER_WAKEUP(sqp) { \ 2697c478bd9Sstevel@tonic-gate timeout_id_t tid = (sqp)->sq_tid; \ 2707c478bd9Sstevel@tonic-gate \ 2717c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&(sqp)->sq_lock)); \ 2727c478bd9Sstevel@tonic-gate /* \ 2737c478bd9Sstevel@tonic-gate * Queue isn't being processed, so take \ 2747c478bd9Sstevel@tonic-gate * any post enqueue actions needed before leaving. \ 2757c478bd9Sstevel@tonic-gate */ \ 2767c478bd9Sstevel@tonic-gate if (tid != 0) { \ 2777c478bd9Sstevel@tonic-gate /* \ 2787c478bd9Sstevel@tonic-gate * Waiting for an enter() to process mblk(s). \ 2797c478bd9Sstevel@tonic-gate */ \ 2807c478bd9Sstevel@tonic-gate clock_t waited = lbolt - (sqp)->sq_awaken; \ 2817c478bd9Sstevel@tonic-gate \ 2827c478bd9Sstevel@tonic-gate if (TICK_TO_MSEC(waited) >= (sqp)->sq_wait) { \ 2837c478bd9Sstevel@tonic-gate /* \ 2847c478bd9Sstevel@tonic-gate * Times up and have a worker thread \ 2857c478bd9Sstevel@tonic-gate * waiting for work, so schedule it. \ 2867c478bd9Sstevel@tonic-gate */ \ 2877c478bd9Sstevel@tonic-gate (sqp)->sq_tid = 0; \ 2887c478bd9Sstevel@tonic-gate (sqp)->sq_awaken = lbolt; \ 2897c478bd9Sstevel@tonic-gate cv_signal(&(sqp)->sq_async); \ 2907c478bd9Sstevel@tonic-gate mutex_exit(&(sqp)->sq_lock); \ 2917c478bd9Sstevel@tonic-gate (void) untimeout(tid); \ 2927c478bd9Sstevel@tonic-gate return; \ 2937c478bd9Sstevel@tonic-gate } \ 2947c478bd9Sstevel@tonic-gate mutex_exit(&(sqp)->sq_lock); \ 2957c478bd9Sstevel@tonic-gate return; \ 2967c478bd9Sstevel@tonic-gate } else if ((sqp)->sq_state & SQS_TMO_PROG) { \ 2977c478bd9Sstevel@tonic-gate mutex_exit(&(sqp)->sq_lock); \ 2987c478bd9Sstevel@tonic-gate return; \ 2997c478bd9Sstevel@tonic-gate } else if ((sqp)->sq_wait != 0) { \ 3007c478bd9Sstevel@tonic-gate clock_t wait = (sqp)->sq_wait; \ 3017c478bd9Sstevel@tonic-gate /* \ 3027c478bd9Sstevel@tonic-gate * Wait up to sqp->sq_wait ms for an \ 3037c478bd9Sstevel@tonic-gate * enter() to process this queue. We \ 3047c478bd9Sstevel@tonic-gate * don't want to contend on timeout locks \ 3057c478bd9Sstevel@tonic-gate * with sq_lock held for performance reasons, \ 3067c478bd9Sstevel@tonic-gate * so drop the sq_lock before calling timeout \ 3077c478bd9Sstevel@tonic-gate * but we need to check if timeout is required \ 3087c478bd9Sstevel@tonic-gate * after re acquiring the sq_lock. Once \ 3097c478bd9Sstevel@tonic-gate * the sq_lock is dropped, someone else could \ 3107c478bd9Sstevel@tonic-gate * have processed the packet or the timeout could \ 3117c478bd9Sstevel@tonic-gate * have already fired. \ 3127c478bd9Sstevel@tonic-gate */ \ 3137c478bd9Sstevel@tonic-gate (sqp)->sq_state |= SQS_TMO_PROG; \ 3147c478bd9Sstevel@tonic-gate mutex_exit(&(sqp)->sq_lock); \ 3157c478bd9Sstevel@tonic-gate tid = timeout(squeue_fire, (sqp), wait); \ 3167c478bd9Sstevel@tonic-gate mutex_enter(&(sqp)->sq_lock); \ 3177c478bd9Sstevel@tonic-gate /* Check again if we still need the timeout */ \ 3187c478bd9Sstevel@tonic-gate if ((((sqp)->sq_state & (SQS_PROC|SQS_TMO_PROG)) == \ 3197c478bd9Sstevel@tonic-gate SQS_TMO_PROG) && ((sqp)->sq_tid == 0) && \ 3207c478bd9Sstevel@tonic-gate ((sqp)->sq_first != NULL)) { \ 3217c478bd9Sstevel@tonic-gate (sqp)->sq_state &= ~SQS_TMO_PROG; \ 3227c478bd9Sstevel@tonic-gate (sqp)->sq_awaken = lbolt; \ 3237c478bd9Sstevel@tonic-gate (sqp)->sq_tid = tid; \ 3247c478bd9Sstevel@tonic-gate mutex_exit(&(sqp)->sq_lock); \ 3257c478bd9Sstevel@tonic-gate return; \ 3267c478bd9Sstevel@tonic-gate } else { \ 3277c478bd9Sstevel@tonic-gate if ((sqp)->sq_state & SQS_TMO_PROG) { \ 3287c478bd9Sstevel@tonic-gate (sqp)->sq_state &= ~SQS_TMO_PROG; \ 3297c478bd9Sstevel@tonic-gate mutex_exit(&(sqp)->sq_lock); \ 3307c478bd9Sstevel@tonic-gate (void) untimeout(tid); \ 3317c478bd9Sstevel@tonic-gate } else { \ 3327c478bd9Sstevel@tonic-gate /* \ 3337c478bd9Sstevel@tonic-gate * The timer fired before we could \ 3347c478bd9Sstevel@tonic-gate * reacquire the sq_lock. squeue_fire \ 3357c478bd9Sstevel@tonic-gate * removes the SQS_TMO_PROG flag \ 3367c478bd9Sstevel@tonic-gate * and we don't need to do anything \ 3377c478bd9Sstevel@tonic-gate * else. \ 3387c478bd9Sstevel@tonic-gate */ \ 3397c478bd9Sstevel@tonic-gate mutex_exit(&(sqp)->sq_lock); \ 3407c478bd9Sstevel@tonic-gate } \ 3417c478bd9Sstevel@tonic-gate } \ 3427c478bd9Sstevel@tonic-gate } else { \ 3437c478bd9Sstevel@tonic-gate /* \ 3447c478bd9Sstevel@tonic-gate * Schedule the worker thread. \ 3457c478bd9Sstevel@tonic-gate */ \ 3467c478bd9Sstevel@tonic-gate (sqp)->sq_awaken = lbolt; \ 3477c478bd9Sstevel@tonic-gate cv_signal(&(sqp)->sq_async); \ 3487c478bd9Sstevel@tonic-gate mutex_exit(&(sqp)->sq_lock); \ 3497c478bd9Sstevel@tonic-gate } \ 3507c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&(sqp)->sq_lock)); \ 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate #define ENQUEUE_MP(sqp, mp, proc, arg) { \ 3547c478bd9Sstevel@tonic-gate /* \ 3557c478bd9Sstevel@tonic-gate * Enque our mblk. \ 3567c478bd9Sstevel@tonic-gate */ \ 3577c478bd9Sstevel@tonic-gate (mp)->b_queue = NULL; \ 3587c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&(sqp)->sq_lock)); \ 3597c478bd9Sstevel@tonic-gate ASSERT((mp)->b_prev == NULL && (mp)->b_next == NULL); \ 3607c478bd9Sstevel@tonic-gate (mp)->b_queue = (queue_t *)(proc); \ 3617c478bd9Sstevel@tonic-gate (mp)->b_prev = (mblk_t *)(arg); \ 3627c478bd9Sstevel@tonic-gate \ 3637c478bd9Sstevel@tonic-gate if ((sqp)->sq_last != NULL) \ 3647c478bd9Sstevel@tonic-gate (sqp)->sq_last->b_next = (mp); \ 3657c478bd9Sstevel@tonic-gate else \ 3667c478bd9Sstevel@tonic-gate (sqp)->sq_first = (mp); \ 3677c478bd9Sstevel@tonic-gate (sqp)->sq_last = (mp); \ 3687c478bd9Sstevel@tonic-gate (sqp)->sq_count++; \ 3697c478bd9Sstevel@tonic-gate ASSERT((sqp)->sq_count > 0); \ 3707c478bd9Sstevel@tonic-gate DTRACE_PROBE2(squeue__enqueue, squeue_t *, sqp, \ 3717c478bd9Sstevel@tonic-gate mblk_t *, mp); \ 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate #define ENQUEUE_CHAIN(sqp, mp, tail, cnt) { \ 3767c478bd9Sstevel@tonic-gate /* \ 3777c478bd9Sstevel@tonic-gate * Enqueue our mblk chain. \ 3787c478bd9Sstevel@tonic-gate */ \ 3797c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&(sqp)->sq_lock)); \ 3807c478bd9Sstevel@tonic-gate \ 3817c478bd9Sstevel@tonic-gate if ((sqp)->sq_last != NULL) \ 3827c478bd9Sstevel@tonic-gate (sqp)->sq_last->b_next = (mp); \ 3837c478bd9Sstevel@tonic-gate else \ 3847c478bd9Sstevel@tonic-gate (sqp)->sq_first = (mp); \ 3857c478bd9Sstevel@tonic-gate (sqp)->sq_last = (tail); \ 3867c478bd9Sstevel@tonic-gate (sqp)->sq_count += (cnt); \ 3877c478bd9Sstevel@tonic-gate ASSERT((sqp)->sq_count > 0); \ 3887c478bd9Sstevel@tonic-gate DTRACE_PROBE4(squeue__enqueuechain, squeue_t *, sqp, \ 3897c478bd9Sstevel@tonic-gate mblk_t *, mp, mblk_t *, tail, int, cnt); \ 3907c478bd9Sstevel@tonic-gate \ 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate #define SQS_POLLING_ON(sqp, rx_ring) { \ 3947c478bd9Sstevel@tonic-gate ASSERT(rx_ring != NULL); \ 3957c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&(sqp)->sq_lock)); \ 3967c478bd9Sstevel@tonic-gate rx_ring->rr_blank(rx_ring->rr_handle, \ 3977c478bd9Sstevel@tonic-gate MIN((sqp->sq_avg_drain_time * sqp->sq_count), \ 3987c478bd9Sstevel@tonic-gate rx_ring->rr_max_blank_time), \ 3997c478bd9Sstevel@tonic-gate rx_ring->rr_max_pkt_cnt); \ 4007c478bd9Sstevel@tonic-gate rx_ring->rr_poll_state |= ILL_POLLING; \ 4017c478bd9Sstevel@tonic-gate rx_ring->rr_poll_time = lbolt; \ 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate #define SQS_POLLING_OFF(sqp, rx_ring) { \ 4067c478bd9Sstevel@tonic-gate ASSERT(rx_ring != NULL); \ 4077c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&(sqp)->sq_lock)); \ 4087c478bd9Sstevel@tonic-gate rx_ring->rr_blank(rx_ring->rr_handle, \ 4097c478bd9Sstevel@tonic-gate rx_ring->rr_min_blank_time, \ 4107c478bd9Sstevel@tonic-gate rx_ring->rr_min_pkt_cnt); \ 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate void 4147c478bd9Sstevel@tonic-gate squeue_init(void) 4157c478bd9Sstevel@tonic-gate { 4167c478bd9Sstevel@tonic-gate squeue_cache = kmem_cache_create("squeue_cache", 4177c478bd9Sstevel@tonic-gate sizeof (squeue_t), 64, NULL, NULL, NULL, NULL, NULL, 0); 4187c478bd9Sstevel@tonic-gate 419d19d6468Sbw squeue_intrdrain_ns = squeue_intrdrain_ms * SQUEUE_MSEC_TO_NSEC; 420d19d6468Sbw squeue_writerdrain_ns = squeue_writerdrain_ms * SQUEUE_MSEC_TO_NSEC; 421d19d6468Sbw squeue_workerdrain_ns = squeue_workerdrain_ms * SQUEUE_MSEC_TO_NSEC; 4227c478bd9Sstevel@tonic-gate squeue_workerwait_tick = MSEC_TO_TICK_ROUNDUP(squeue_workerwait_ms); 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4267c478bd9Sstevel@tonic-gate squeue_t * 4277c478bd9Sstevel@tonic-gate squeue_create(char *name, processorid_t bind, clock_t wait, pri_t pri) 4287c478bd9Sstevel@tonic-gate { 4297c478bd9Sstevel@tonic-gate squeue_t *sqp = kmem_cache_alloc(squeue_cache, KM_SLEEP); 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate bzero(sqp, sizeof (squeue_t)); 4327c478bd9Sstevel@tonic-gate (void) strncpy(sqp->sq_name, name, SQ_NAMELEN + 1); 4337c478bd9Sstevel@tonic-gate sqp->sq_name[SQ_NAMELEN] = '\0'; 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate sqp->sq_bind = bind; 4367c478bd9Sstevel@tonic-gate sqp->sq_wait = MSEC_TO_TICK(wait); 4377c478bd9Sstevel@tonic-gate sqp->sq_avg_drain_time = 438d19d6468Sbw drv_hztousec(NSEC_TO_TICK_ROUNDUP(squeue_intrdrain_ns)) / 439d19d6468Sbw NSEC_TO_TICK_ROUNDUP(squeue_intrdrain_ns); 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 4427c478bd9Sstevel@tonic-gate if ((sqp->sq_kstat = kstat_create("ip", bind, name, 4437c478bd9Sstevel@tonic-gate "net", KSTAT_TYPE_NAMED, 4447c478bd9Sstevel@tonic-gate sizeof (squeue_kstat) / sizeof (kstat_named_t), 4457c478bd9Sstevel@tonic-gate KSTAT_FLAG_VIRTUAL)) != NULL) { 4467c478bd9Sstevel@tonic-gate sqp->sq_kstat->ks_lock = &squeue_kstat_lock; 4477c478bd9Sstevel@tonic-gate sqp->sq_kstat->ks_data = &squeue_kstat; 4487c478bd9Sstevel@tonic-gate sqp->sq_kstat->ks_update = squeue_kstat_update; 4497c478bd9Sstevel@tonic-gate sqp->sq_kstat->ks_private = sqp; 4507c478bd9Sstevel@tonic-gate kstat_install(sqp->sq_kstat); 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate #endif 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate sqp->sq_worker = thread_create(NULL, 0, squeue_worker, 4557c478bd9Sstevel@tonic-gate sqp, 0, &p0, TS_RUN, pri); 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate return (sqp); 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4617c478bd9Sstevel@tonic-gate void 4627c478bd9Sstevel@tonic-gate squeue_bind(squeue_t *sqp, processorid_t bind) 4637c478bd9Sstevel@tonic-gate { 4647c478bd9Sstevel@tonic-gate ASSERT(bind == -1); 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate mutex_enter(&sqp->sq_lock); 4677c478bd9Sstevel@tonic-gate if (sqp->sq_state & SQS_BOUND) { 4687c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 4697c478bd9Sstevel@tonic-gate return; 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate sqp->sq_state |= SQS_BOUND; 4737c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate thread_affinity_set(sqp->sq_worker, sqp->sq_bind); 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate void 4797c478bd9Sstevel@tonic-gate squeue_unbind(squeue_t *sqp) 4807c478bd9Sstevel@tonic-gate { 4817c478bd9Sstevel@tonic-gate mutex_enter(&sqp->sq_lock); 4827c478bd9Sstevel@tonic-gate if (!(sqp->sq_state & SQS_BOUND)) { 4837c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 4847c478bd9Sstevel@tonic-gate return; 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate sqp->sq_state &= ~SQS_BOUND; 4887c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate thread_affinity_clear(sqp->sq_worker); 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate /* 4947c478bd9Sstevel@tonic-gate * squeue_enter() - enter squeue sqp with mblk mp (which can be 4957c478bd9Sstevel@tonic-gate * a chain), while tail points to the end and cnt in number of 4967c478bd9Sstevel@tonic-gate * mblks in the chain. 4977c478bd9Sstevel@tonic-gate * 4987c478bd9Sstevel@tonic-gate * For a chain of single packet (i.e. mp == tail), go through the 4997c478bd9Sstevel@tonic-gate * fast path if no one is processing the squeue and nothing is queued. 5007c478bd9Sstevel@tonic-gate * 5017c478bd9Sstevel@tonic-gate * The proc and arg for each mblk is already stored in the mblk in 5027c478bd9Sstevel@tonic-gate * appropriate places. 5037c478bd9Sstevel@tonic-gate */ 5047c478bd9Sstevel@tonic-gate void 5057c478bd9Sstevel@tonic-gate squeue_enter_chain(squeue_t *sqp, mblk_t *mp, mblk_t *tail, 5067c478bd9Sstevel@tonic-gate uint32_t cnt, uint8_t tag) 5077c478bd9Sstevel@tonic-gate { 5087c478bd9Sstevel@tonic-gate int interrupt = servicing_interrupt(); 5097c478bd9Sstevel@tonic-gate void *arg; 5107c478bd9Sstevel@tonic-gate sqproc_t proc; 511d19d6468Sbw hrtime_t now; 5127c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 5137c478bd9Sstevel@tonic-gate hrtime_t start, delta; 5147c478bd9Sstevel@tonic-gate #endif 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate ASSERT(sqp != NULL); 5177c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 5187c478bd9Sstevel@tonic-gate ASSERT(tail != NULL); 5197c478bd9Sstevel@tonic-gate ASSERT(cnt > 0); 5207c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&sqp->sq_lock)); 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate mutex_enter(&sqp->sq_lock); 5237c478bd9Sstevel@tonic-gate if (!(sqp->sq_state & SQS_PROC)) { 5247c478bd9Sstevel@tonic-gate /* 5257c478bd9Sstevel@tonic-gate * See if anything is already queued. If we are the 5267c478bd9Sstevel@tonic-gate * first packet, do inline processing else queue the 5277c478bd9Sstevel@tonic-gate * packet and do the drain. 5287c478bd9Sstevel@tonic-gate */ 5297c478bd9Sstevel@tonic-gate sqp->sq_run = curthread; 5307c478bd9Sstevel@tonic-gate if (sqp->sq_first == NULL && cnt == 1) { 5317c478bd9Sstevel@tonic-gate /* 5327c478bd9Sstevel@tonic-gate * Fast-path, ok to process and nothing queued. 5337c478bd9Sstevel@tonic-gate */ 5347c478bd9Sstevel@tonic-gate sqp->sq_state |= (SQS_PROC|SQS_FAST); 5357c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate /* 5387c478bd9Sstevel@tonic-gate * We are the chain of 1 packet so 5397c478bd9Sstevel@tonic-gate * go through this fast path. 5407c478bd9Sstevel@tonic-gate */ 5417c478bd9Sstevel@tonic-gate arg = mp->b_prev; 5427c478bd9Sstevel@tonic-gate mp->b_prev = NULL; 5437c478bd9Sstevel@tonic-gate proc = (sqproc_t)mp->b_queue; 5447c478bd9Sstevel@tonic-gate mp->b_queue = NULL; 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate ASSERT(proc != NULL); 5477c478bd9Sstevel@tonic-gate ASSERT(arg != NULL); 5487c478bd9Sstevel@tonic-gate ASSERT(mp->b_next == NULL); 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 5517c478bd9Sstevel@tonic-gate sqp->sq_isintr = interrupt; 5527c478bd9Sstevel@tonic-gate sqp->sq_curmp = mp; 5537c478bd9Sstevel@tonic-gate sqp->sq_curproc = proc; 5547c478bd9Sstevel@tonic-gate sqp->sq_connp = arg; 5557c478bd9Sstevel@tonic-gate mp->b_tag = sqp->sq_tag = tag; 5567c478bd9Sstevel@tonic-gate #endif 5577c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 5587c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 5597c478bd9Sstevel@tonic-gate if (interrupt) 5607c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_npackets_intr); 5617c478bd9Sstevel@tonic-gate else 5627c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_npackets_other); 5637c478bd9Sstevel@tonic-gate start = gethrtime(); 5647c478bd9Sstevel@tonic-gate } 5657c478bd9Sstevel@tonic-gate #endif 5667c478bd9Sstevel@tonic-gate ((conn_t *)arg)->conn_on_sqp = B_TRUE; 5677c478bd9Sstevel@tonic-gate DTRACE_PROBE3(squeue__proc__start, squeue_t *, 5687c478bd9Sstevel@tonic-gate sqp, mblk_t *, mp, conn_t *, arg); 5697c478bd9Sstevel@tonic-gate (*proc)(arg, mp, sqp); 5707c478bd9Sstevel@tonic-gate DTRACE_PROBE2(squeue__proc__end, squeue_t *, 5717c478bd9Sstevel@tonic-gate sqp, conn_t *, arg); 5727c478bd9Sstevel@tonic-gate ((conn_t *)arg)->conn_on_sqp = B_FALSE; 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 5757c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 5767c478bd9Sstevel@tonic-gate delta = gethrtime() - start; 5777c478bd9Sstevel@tonic-gate if (interrupt) 5787c478bd9Sstevel@tonic-gate SQDELTA(sqp, sq_time_intr, delta); 5797c478bd9Sstevel@tonic-gate else 5807c478bd9Sstevel@tonic-gate SQDELTA(sqp, sq_time_other, delta); 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate #endif 5837c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 5847c478bd9Sstevel@tonic-gate sqp->sq_curmp = NULL; 5857c478bd9Sstevel@tonic-gate sqp->sq_curproc = NULL; 5867c478bd9Sstevel@tonic-gate sqp->sq_connp = NULL; 5877c478bd9Sstevel@tonic-gate sqp->sq_isintr = 0; 5887c478bd9Sstevel@tonic-gate #endif 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate CONN_DEC_REF((conn_t *)arg); 5917c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&sqp->sq_lock)); 5927c478bd9Sstevel@tonic-gate mutex_enter(&sqp->sq_lock); 5937c478bd9Sstevel@tonic-gate sqp->sq_state &= ~(SQS_PROC|SQS_FAST); 5947c478bd9Sstevel@tonic-gate if (sqp->sq_first == NULL) { 5957c478bd9Sstevel@tonic-gate /* 5967c478bd9Sstevel@tonic-gate * We processed inline our packet and 5977c478bd9Sstevel@tonic-gate * nothing new has arrived. We are done. 5987c478bd9Sstevel@tonic-gate */ 5997c478bd9Sstevel@tonic-gate sqp->sq_run = NULL; 6007c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 6017c478bd9Sstevel@tonic-gate return; 6027c478bd9Sstevel@tonic-gate } else if (sqp->sq_bind != CPU->cpu_id) { 6037c478bd9Sstevel@tonic-gate /* 6047c478bd9Sstevel@tonic-gate * If the current thread is not running 6057c478bd9Sstevel@tonic-gate * on the CPU to which this squeue is bound, 6067c478bd9Sstevel@tonic-gate * then don't allow it to drain. 6077c478bd9Sstevel@tonic-gate */ 6087c478bd9Sstevel@tonic-gate sqp->sq_run = NULL; 6097c478bd9Sstevel@tonic-gate SQUEUE_WORKER_WAKEUP(sqp); 6107c478bd9Sstevel@tonic-gate return; 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate } else { 6137c478bd9Sstevel@tonic-gate ENQUEUE_CHAIN(sqp, mp, tail, cnt); 6147c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 6157c478bd9Sstevel@tonic-gate mp->b_tag = tag; 6167c478bd9Sstevel@tonic-gate #endif 6177c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 6187c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 6197c478bd9Sstevel@tonic-gate if (servicing_interrupt()) 6207c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_nqueued_intr); 6217c478bd9Sstevel@tonic-gate else 6227c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_nqueued_other); 6237c478bd9Sstevel@tonic-gate if (sqp->sq_stats.sq_max_qlen < sqp->sq_count) 6247c478bd9Sstevel@tonic-gate sqp->sq_stats.sq_max_qlen = 6257c478bd9Sstevel@tonic-gate sqp->sq_count; 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate #endif 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate /* 6317c478bd9Sstevel@tonic-gate * We are here because either we couldn't do inline 6327c478bd9Sstevel@tonic-gate * processing (because something was already queued), 6337c478bd9Sstevel@tonic-gate * or we had a chanin of more than one packet, 6347c478bd9Sstevel@tonic-gate * or something else arrived after we were done with 6357c478bd9Sstevel@tonic-gate * inline processing. 6367c478bd9Sstevel@tonic-gate */ 6377c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sqp->sq_lock)); 6387c478bd9Sstevel@tonic-gate ASSERT(sqp->sq_first != NULL); 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 6417c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 6427c478bd9Sstevel@tonic-gate start = gethrtime(); 6437c478bd9Sstevel@tonic-gate } 6447c478bd9Sstevel@tonic-gate #endif 6457c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 6467c478bd9Sstevel@tonic-gate sqp->sq_isintr = interrupt; 6477c478bd9Sstevel@tonic-gate #endif 6487c478bd9Sstevel@tonic-gate 649d19d6468Sbw now = gethrtime(); 6507c478bd9Sstevel@tonic-gate if (interrupt) { 651d19d6468Sbw squeue_drain(sqp, SQS_ENTER, now + 652d19d6468Sbw squeue_intrdrain_ns); 6537c478bd9Sstevel@tonic-gate } else { 654d19d6468Sbw squeue_drain(sqp, SQS_USER, now + 655d19d6468Sbw squeue_writerdrain_ns); 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 6597c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 6607c478bd9Sstevel@tonic-gate delta = gethrtime() - start; 6617c478bd9Sstevel@tonic-gate if (interrupt) 6627c478bd9Sstevel@tonic-gate SQDELTA(sqp, sq_time_intr, delta); 6637c478bd9Sstevel@tonic-gate else 6647c478bd9Sstevel@tonic-gate SQDELTA(sqp, sq_time_other, delta); 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate #endif 6677c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 6687c478bd9Sstevel@tonic-gate sqp->sq_isintr = 0; 6697c478bd9Sstevel@tonic-gate #endif 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate /* 6727c478bd9Sstevel@tonic-gate * If we didn't do a complete drain, the worker 6737c478bd9Sstevel@tonic-gate * thread was already signalled by squeue_drain. 6747c478bd9Sstevel@tonic-gate */ 6757c478bd9Sstevel@tonic-gate sqp->sq_run = NULL; 6767c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 6777c478bd9Sstevel@tonic-gate return; 6787c478bd9Sstevel@tonic-gate } else { 6797c478bd9Sstevel@tonic-gate ASSERT(sqp->sq_run != NULL); 6807c478bd9Sstevel@tonic-gate /* 6817c478bd9Sstevel@tonic-gate * Queue is already being processed. Just enqueue 6827c478bd9Sstevel@tonic-gate * the packet and go away. 6837c478bd9Sstevel@tonic-gate */ 6847c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 6857c478bd9Sstevel@tonic-gate mp->b_tag = tag; 6867c478bd9Sstevel@tonic-gate #endif 6877c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 6887c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 6897c478bd9Sstevel@tonic-gate if (servicing_interrupt()) 6907c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_nqueued_intr); 6917c478bd9Sstevel@tonic-gate else 6927c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_nqueued_other); 6937c478bd9Sstevel@tonic-gate if (sqp->sq_stats.sq_max_qlen < sqp->sq_count) 6947c478bd9Sstevel@tonic-gate sqp->sq_stats.sq_max_qlen = sqp->sq_count; 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate #endif 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate ENQUEUE_CHAIN(sqp, mp, tail, cnt); 6997c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 7007c478bd9Sstevel@tonic-gate return; 7017c478bd9Sstevel@tonic-gate } 7027c478bd9Sstevel@tonic-gate } 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate /* 7057c478bd9Sstevel@tonic-gate * squeue_enter() - enter squeue *sqp with mblk *mp with argument of *arg. 7067c478bd9Sstevel@tonic-gate */ 7077c478bd9Sstevel@tonic-gate void 7087c478bd9Sstevel@tonic-gate squeue_enter(squeue_t *sqp, mblk_t *mp, sqproc_t proc, void *arg, 7097c478bd9Sstevel@tonic-gate uint8_t tag) 7107c478bd9Sstevel@tonic-gate { 7117c478bd9Sstevel@tonic-gate int interrupt = servicing_interrupt(); 712d19d6468Sbw hrtime_t now; 7137c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 7147c478bd9Sstevel@tonic-gate hrtime_t start, delta; 7157c478bd9Sstevel@tonic-gate #endif 7167c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 7177c478bd9Sstevel@tonic-gate conn_t *connp = (conn_t *)arg; 718ff550d0eSmasputra ASSERT(!IPCL_IS_TCP(connp) || connp->conn_tcp->tcp_connp == connp); 719ff550d0eSmasputra ASSERT(!IPCL_IS_UDP(connp) || connp->conn_udp->udp_connp == connp); 7207c478bd9Sstevel@tonic-gate #endif 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate ASSERT(proc != NULL); 7237c478bd9Sstevel@tonic-gate ASSERT(sqp != NULL); 7247c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 7257c478bd9Sstevel@tonic-gate ASSERT(mp->b_next == NULL); 7267c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&sqp->sq_lock)); 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate mutex_enter(&sqp->sq_lock); 7297c478bd9Sstevel@tonic-gate if (!(sqp->sq_state & SQS_PROC)) { 7307c478bd9Sstevel@tonic-gate /* 7317c478bd9Sstevel@tonic-gate * See if anything is already queued. If we are the 7327c478bd9Sstevel@tonic-gate * first packet, do inline processing else queue the 7337c478bd9Sstevel@tonic-gate * packet and do the drain. 7347c478bd9Sstevel@tonic-gate */ 7357c478bd9Sstevel@tonic-gate sqp->sq_run = curthread; 7367c478bd9Sstevel@tonic-gate if (sqp->sq_first == NULL) { 7377c478bd9Sstevel@tonic-gate /* 7387c478bd9Sstevel@tonic-gate * Fast-path, ok to process and nothing queued. 7397c478bd9Sstevel@tonic-gate */ 7407c478bd9Sstevel@tonic-gate sqp->sq_state |= (SQS_PROC|SQS_FAST); 7417c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 7447c478bd9Sstevel@tonic-gate sqp->sq_isintr = interrupt; 7457c478bd9Sstevel@tonic-gate sqp->sq_curmp = mp; 7467c478bd9Sstevel@tonic-gate sqp->sq_curproc = proc; 7477c478bd9Sstevel@tonic-gate sqp->sq_connp = connp; 7487c478bd9Sstevel@tonic-gate mp->b_tag = sqp->sq_tag = tag; 7497c478bd9Sstevel@tonic-gate #endif 7507c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 7517c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 7527c478bd9Sstevel@tonic-gate if (interrupt) 7537c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_npackets_intr); 7547c478bd9Sstevel@tonic-gate else 7557c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_npackets_other); 7567c478bd9Sstevel@tonic-gate start = gethrtime(); 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate #endif 7597c478bd9Sstevel@tonic-gate ((conn_t *)arg)->conn_on_sqp = B_TRUE; 7607c478bd9Sstevel@tonic-gate DTRACE_PROBE3(squeue__proc__start, squeue_t *, 7617c478bd9Sstevel@tonic-gate sqp, mblk_t *, mp, conn_t *, arg); 7627c478bd9Sstevel@tonic-gate (*proc)(arg, mp, sqp); 7637c478bd9Sstevel@tonic-gate DTRACE_PROBE2(squeue__proc__end, squeue_t *, 7647c478bd9Sstevel@tonic-gate sqp, conn_t *, arg); 7657c478bd9Sstevel@tonic-gate ((conn_t *)arg)->conn_on_sqp = B_FALSE; 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 7687c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 7697c478bd9Sstevel@tonic-gate delta = gethrtime() - start; 7707c478bd9Sstevel@tonic-gate if (interrupt) 7717c478bd9Sstevel@tonic-gate SQDELTA(sqp, sq_time_intr, delta); 7727c478bd9Sstevel@tonic-gate else 7737c478bd9Sstevel@tonic-gate SQDELTA(sqp, sq_time_other, delta); 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate #endif 7767c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 7777c478bd9Sstevel@tonic-gate sqp->sq_curmp = NULL; 7787c478bd9Sstevel@tonic-gate sqp->sq_curproc = NULL; 7797c478bd9Sstevel@tonic-gate sqp->sq_connp = NULL; 7807c478bd9Sstevel@tonic-gate sqp->sq_isintr = 0; 7817c478bd9Sstevel@tonic-gate #endif 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate CONN_DEC_REF((conn_t *)arg); 7847c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&sqp->sq_lock)); 7857c478bd9Sstevel@tonic-gate mutex_enter(&sqp->sq_lock); 7867c478bd9Sstevel@tonic-gate sqp->sq_state &= ~(SQS_PROC|SQS_FAST); 7877c478bd9Sstevel@tonic-gate if (sqp->sq_first == NULL) { 7887c478bd9Sstevel@tonic-gate /* 7897c478bd9Sstevel@tonic-gate * We processed inline our packet and 7907c478bd9Sstevel@tonic-gate * nothing new has arrived. We are done. 7917c478bd9Sstevel@tonic-gate */ 7927c478bd9Sstevel@tonic-gate sqp->sq_run = NULL; 7937c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 7947c478bd9Sstevel@tonic-gate return; 7957c478bd9Sstevel@tonic-gate } else if (sqp->sq_bind != CPU->cpu_id) { 7967c478bd9Sstevel@tonic-gate /* 7977c478bd9Sstevel@tonic-gate * If the current thread is not running 7987c478bd9Sstevel@tonic-gate * on the CPU to which this squeue is bound, 7997c478bd9Sstevel@tonic-gate * then don't allow it to drain. 8007c478bd9Sstevel@tonic-gate */ 8017c478bd9Sstevel@tonic-gate sqp->sq_run = NULL; 8027c478bd9Sstevel@tonic-gate SQUEUE_WORKER_WAKEUP(sqp); 8037c478bd9Sstevel@tonic-gate return; 8047c478bd9Sstevel@tonic-gate } 8057c478bd9Sstevel@tonic-gate } else { 8067c478bd9Sstevel@tonic-gate ENQUEUE_MP(sqp, mp, proc, arg); 8077c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 8087c478bd9Sstevel@tonic-gate mp->b_tag = tag; 8097c478bd9Sstevel@tonic-gate #endif 8107c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 8117c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 8127c478bd9Sstevel@tonic-gate if (servicing_interrupt()) 8137c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_nqueued_intr); 8147c478bd9Sstevel@tonic-gate else 8157c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_nqueued_other); 8167c478bd9Sstevel@tonic-gate if (sqp->sq_stats.sq_max_qlen < sqp->sq_count) 8177c478bd9Sstevel@tonic-gate sqp->sq_stats.sq_max_qlen = 8187c478bd9Sstevel@tonic-gate sqp->sq_count; 8197c478bd9Sstevel@tonic-gate } 8207c478bd9Sstevel@tonic-gate #endif 8217c478bd9Sstevel@tonic-gate } 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate /* 8247c478bd9Sstevel@tonic-gate * We are here because either we couldn't do inline 8257c478bd9Sstevel@tonic-gate * processing (because something was already queued) 8267c478bd9Sstevel@tonic-gate * or something else arrived after we were done with 8277c478bd9Sstevel@tonic-gate * inline processing. 8287c478bd9Sstevel@tonic-gate */ 8297c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sqp->sq_lock)); 8307c478bd9Sstevel@tonic-gate ASSERT(sqp->sq_first != NULL); 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 8337c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 8347c478bd9Sstevel@tonic-gate start = gethrtime(); 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate #endif 8377c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 8387c478bd9Sstevel@tonic-gate sqp->sq_isintr = interrupt; 8397c478bd9Sstevel@tonic-gate #endif 8407c478bd9Sstevel@tonic-gate 841d19d6468Sbw now = gethrtime(); 8427c478bd9Sstevel@tonic-gate if (interrupt) { 843d19d6468Sbw squeue_drain(sqp, SQS_ENTER, now + 844d19d6468Sbw squeue_intrdrain_ns); 8457c478bd9Sstevel@tonic-gate } else { 846d19d6468Sbw squeue_drain(sqp, SQS_USER, now + 847d19d6468Sbw squeue_writerdrain_ns); 8487c478bd9Sstevel@tonic-gate } 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 8517c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 8527c478bd9Sstevel@tonic-gate delta = gethrtime() - start; 8537c478bd9Sstevel@tonic-gate if (interrupt) 8547c478bd9Sstevel@tonic-gate SQDELTA(sqp, sq_time_intr, delta); 8557c478bd9Sstevel@tonic-gate else 8567c478bd9Sstevel@tonic-gate SQDELTA(sqp, sq_time_other, delta); 8577c478bd9Sstevel@tonic-gate } 8587c478bd9Sstevel@tonic-gate #endif 8597c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 8607c478bd9Sstevel@tonic-gate sqp->sq_isintr = 0; 8617c478bd9Sstevel@tonic-gate #endif 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate /* 8647c478bd9Sstevel@tonic-gate * If we didn't do a complete drain, the worker 8657c478bd9Sstevel@tonic-gate * thread was already signalled by squeue_drain. 8667c478bd9Sstevel@tonic-gate */ 8677c478bd9Sstevel@tonic-gate sqp->sq_run = NULL; 8687c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 8697c478bd9Sstevel@tonic-gate return; 8707c478bd9Sstevel@tonic-gate } else { 8717c478bd9Sstevel@tonic-gate ASSERT(sqp->sq_run != NULL); 8727c478bd9Sstevel@tonic-gate /* 8737c478bd9Sstevel@tonic-gate * We let a thread processing a squeue reenter only 8747c478bd9Sstevel@tonic-gate * once. This helps the case of incoming connection 8757c478bd9Sstevel@tonic-gate * where a SYN-ACK-ACK that triggers the conn_ind 8767c478bd9Sstevel@tonic-gate * doesn't have to queue the packet if listener and 8777c478bd9Sstevel@tonic-gate * eager are on the same squeue. Also helps the 8787c478bd9Sstevel@tonic-gate * loopback connection where the two ends are bound 8797c478bd9Sstevel@tonic-gate * to the same squeue (which is typical on single 8807c478bd9Sstevel@tonic-gate * CPU machines). 8817c478bd9Sstevel@tonic-gate * We let the thread reenter only once for the fear 8827c478bd9Sstevel@tonic-gate * of stack getting blown with multiple traversal. 8837c478bd9Sstevel@tonic-gate */ 8847c478bd9Sstevel@tonic-gate if (!(sqp->sq_state & SQS_REENTER) && 8857c478bd9Sstevel@tonic-gate (sqp->sq_run == curthread) && 8867c478bd9Sstevel@tonic-gate (((conn_t *)arg)->conn_on_sqp == B_FALSE)) { 8877c478bd9Sstevel@tonic-gate sqp->sq_state |= SQS_REENTER; 8887c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate ((conn_t *)arg)->conn_on_sqp = B_TRUE; 8917c478bd9Sstevel@tonic-gate DTRACE_PROBE3(squeue__proc__start, squeue_t *, 8927c478bd9Sstevel@tonic-gate sqp, mblk_t *, mp, conn_t *, arg); 8937c478bd9Sstevel@tonic-gate (*proc)(arg, mp, sqp); 8947c478bd9Sstevel@tonic-gate DTRACE_PROBE2(squeue__proc__end, squeue_t *, 8957c478bd9Sstevel@tonic-gate sqp, conn_t *, arg); 8967c478bd9Sstevel@tonic-gate ((conn_t *)arg)->conn_on_sqp = B_FALSE; 8977c478bd9Sstevel@tonic-gate CONN_DEC_REF((conn_t *)arg); 8987c478bd9Sstevel@tonic-gate 8997c478bd9Sstevel@tonic-gate mutex_enter(&sqp->sq_lock); 9007c478bd9Sstevel@tonic-gate sqp->sq_state &= ~SQS_REENTER; 9017c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 9027c478bd9Sstevel@tonic-gate return; 9037c478bd9Sstevel@tonic-gate } 9047c478bd9Sstevel@tonic-gate /* 9057c478bd9Sstevel@tonic-gate * Queue is already being processed. Just enqueue 9067c478bd9Sstevel@tonic-gate * the packet and go away. 9077c478bd9Sstevel@tonic-gate */ 9087c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 9097c478bd9Sstevel@tonic-gate mp->b_tag = tag; 9107c478bd9Sstevel@tonic-gate #endif 9117c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 9127c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 9137c478bd9Sstevel@tonic-gate if (servicing_interrupt()) 9147c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_nqueued_intr); 9157c478bd9Sstevel@tonic-gate else 9167c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_nqueued_other); 9177c478bd9Sstevel@tonic-gate if (sqp->sq_stats.sq_max_qlen < sqp->sq_count) 9187c478bd9Sstevel@tonic-gate sqp->sq_stats.sq_max_qlen = sqp->sq_count; 9197c478bd9Sstevel@tonic-gate } 9207c478bd9Sstevel@tonic-gate #endif 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate ENQUEUE_MP(sqp, mp, proc, arg); 9237c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 9247c478bd9Sstevel@tonic-gate return; 9257c478bd9Sstevel@tonic-gate } 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate void 9297c478bd9Sstevel@tonic-gate squeue_enter_nodrain(squeue_t *sqp, mblk_t *mp, sqproc_t proc, void *arg, 9307c478bd9Sstevel@tonic-gate uint8_t tag) 9317c478bd9Sstevel@tonic-gate { 9327c478bd9Sstevel@tonic-gate int interrupt = servicing_interrupt(); 9337c478bd9Sstevel@tonic-gate boolean_t being_processed; 9347c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 9357c478bd9Sstevel@tonic-gate conn_t *connp = (conn_t *)arg; 9367c478bd9Sstevel@tonic-gate #endif 9377c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 9387c478bd9Sstevel@tonic-gate hrtime_t start, delta; 9397c478bd9Sstevel@tonic-gate #endif 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate ASSERT(proc != NULL); 9427c478bd9Sstevel@tonic-gate ASSERT(sqp != NULL); 9437c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 9447c478bd9Sstevel@tonic-gate ASSERT(mp->b_next == NULL); 945ff550d0eSmasputra ASSERT(!IPCL_IS_TCP(connp) || connp->conn_tcp->tcp_connp == connp); 946ff550d0eSmasputra ASSERT(!IPCL_IS_UDP(connp) || connp->conn_udp->udp_connp == connp); 9477c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&sqp->sq_lock)); 948ff550d0eSmasputra 9497c478bd9Sstevel@tonic-gate mutex_enter(&sqp->sq_lock); 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate being_processed = (sqp->sq_state & SQS_PROC); 9527c478bd9Sstevel@tonic-gate if (!being_processed && (sqp->sq_first == NULL)) { 9537c478bd9Sstevel@tonic-gate /* 9547c478bd9Sstevel@tonic-gate * Fast-path, ok to process and nothing queued. 9557c478bd9Sstevel@tonic-gate */ 9567c478bd9Sstevel@tonic-gate sqp->sq_state |= (SQS_PROC|SQS_FAST); 9577c478bd9Sstevel@tonic-gate sqp->sq_run = curthread; 9587c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 9617c478bd9Sstevel@tonic-gate sqp->sq_isintr = interrupt; 9627c478bd9Sstevel@tonic-gate sqp->sq_curmp = mp; 9637c478bd9Sstevel@tonic-gate sqp->sq_curproc = proc; 9647c478bd9Sstevel@tonic-gate sqp->sq_connp = connp; 9657c478bd9Sstevel@tonic-gate mp->b_tag = sqp->sq_tag = tag; 9667c478bd9Sstevel@tonic-gate #endif 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 9697c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 9707c478bd9Sstevel@tonic-gate if (interrupt) 9717c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_npackets_intr); 9727c478bd9Sstevel@tonic-gate else 9737c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_npackets_other); 9747c478bd9Sstevel@tonic-gate start = gethrtime(); 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate #endif 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate ((conn_t *)arg)->conn_on_sqp = B_TRUE; 9797c478bd9Sstevel@tonic-gate DTRACE_PROBE3(squeue__proc__start, squeue_t *, 9807c478bd9Sstevel@tonic-gate sqp, mblk_t *, mp, conn_t *, arg); 9817c478bd9Sstevel@tonic-gate (*proc)(arg, mp, sqp); 9827c478bd9Sstevel@tonic-gate DTRACE_PROBE2(squeue__proc__end, squeue_t *, 9837c478bd9Sstevel@tonic-gate sqp, conn_t *, arg); 9847c478bd9Sstevel@tonic-gate ((conn_t *)arg)->conn_on_sqp = B_FALSE; 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 9877c478bd9Sstevel@tonic-gate sqp->sq_curmp = NULL; 9887c478bd9Sstevel@tonic-gate sqp->sq_curproc = NULL; 9897c478bd9Sstevel@tonic-gate sqp->sq_connp = NULL; 9907c478bd9Sstevel@tonic-gate sqp->sq_isintr = 0; 9917c478bd9Sstevel@tonic-gate #endif 9927c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 9937c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 9947c478bd9Sstevel@tonic-gate delta = gethrtime() - start; 9957c478bd9Sstevel@tonic-gate if (interrupt) 9967c478bd9Sstevel@tonic-gate SQDELTA(sqp, sq_time_intr, delta); 9977c478bd9Sstevel@tonic-gate else 9987c478bd9Sstevel@tonic-gate SQDELTA(sqp, sq_time_other, delta); 9997c478bd9Sstevel@tonic-gate } 10007c478bd9Sstevel@tonic-gate #endif 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate CONN_DEC_REF((conn_t *)arg); 10037c478bd9Sstevel@tonic-gate mutex_enter(&sqp->sq_lock); 10047c478bd9Sstevel@tonic-gate sqp->sq_state &= ~(SQS_PROC|SQS_FAST); 10057c478bd9Sstevel@tonic-gate sqp->sq_run = NULL; 10067c478bd9Sstevel@tonic-gate if (sqp->sq_first == NULL) { 10077c478bd9Sstevel@tonic-gate /* 10087c478bd9Sstevel@tonic-gate * We processed inline our packet and 10097c478bd9Sstevel@tonic-gate * nothing new has arrived. We are done. 10107c478bd9Sstevel@tonic-gate */ 10117c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 10127c478bd9Sstevel@tonic-gate } else { 10137c478bd9Sstevel@tonic-gate SQUEUE_WORKER_WAKEUP(sqp); 10147c478bd9Sstevel@tonic-gate } 10157c478bd9Sstevel@tonic-gate return; 10167c478bd9Sstevel@tonic-gate } else { 10177c478bd9Sstevel@tonic-gate /* 10187c478bd9Sstevel@tonic-gate * We let a thread processing a squeue reenter only 10197c478bd9Sstevel@tonic-gate * once. This helps the case of incoming connection 10207c478bd9Sstevel@tonic-gate * where a SYN-ACK-ACK that triggers the conn_ind 10217c478bd9Sstevel@tonic-gate * doesn't have to queue the packet if listener and 10227c478bd9Sstevel@tonic-gate * eager are on the same squeue. Also helps the 10237c478bd9Sstevel@tonic-gate * loopback connection where the two ends are bound 10247c478bd9Sstevel@tonic-gate * to the same squeue (which is typical on single 10257c478bd9Sstevel@tonic-gate * CPU machines). 10267c478bd9Sstevel@tonic-gate * We let the thread reenter only once for the fear 10277c478bd9Sstevel@tonic-gate * of stack getting blown with multiple traversal. 10287c478bd9Sstevel@tonic-gate */ 10297c478bd9Sstevel@tonic-gate if (being_processed && !(sqp->sq_state & SQS_REENTER) && 10307c478bd9Sstevel@tonic-gate (sqp->sq_run == curthread) && 10317c478bd9Sstevel@tonic-gate (((conn_t *)arg)->conn_on_sqp == B_FALSE)) { 10327c478bd9Sstevel@tonic-gate sqp->sq_state |= SQS_REENTER; 10337c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate ((conn_t *)arg)->conn_on_sqp = B_TRUE; 10367c478bd9Sstevel@tonic-gate DTRACE_PROBE3(squeue__proc__start, squeue_t *, 10377c478bd9Sstevel@tonic-gate sqp, mblk_t *, mp, conn_t *, arg); 10387c478bd9Sstevel@tonic-gate (*proc)(arg, mp, sqp); 10397c478bd9Sstevel@tonic-gate DTRACE_PROBE2(squeue__proc__end, squeue_t *, 10407c478bd9Sstevel@tonic-gate sqp, conn_t *, arg); 10417c478bd9Sstevel@tonic-gate ((conn_t *)arg)->conn_on_sqp = B_FALSE; 10427c478bd9Sstevel@tonic-gate CONN_DEC_REF((conn_t *)arg); 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate mutex_enter(&sqp->sq_lock); 10457c478bd9Sstevel@tonic-gate sqp->sq_state &= ~SQS_REENTER; 10467c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 10477c478bd9Sstevel@tonic-gate return; 10487c478bd9Sstevel@tonic-gate } 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 10517c478bd9Sstevel@tonic-gate mp->b_tag = tag; 10527c478bd9Sstevel@tonic-gate #endif 10537c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 10547c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 10557c478bd9Sstevel@tonic-gate if (servicing_interrupt()) 10567c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_nqueued_intr); 10577c478bd9Sstevel@tonic-gate else 10587c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_nqueued_other); 10597c478bd9Sstevel@tonic-gate if (sqp->sq_stats.sq_max_qlen < sqp->sq_count) 10607c478bd9Sstevel@tonic-gate sqp->sq_stats.sq_max_qlen = sqp->sq_count; 10617c478bd9Sstevel@tonic-gate } 10627c478bd9Sstevel@tonic-gate #endif 10637c478bd9Sstevel@tonic-gate ENQUEUE_MP(sqp, mp, proc, arg); 10647c478bd9Sstevel@tonic-gate if (being_processed) { 10657c478bd9Sstevel@tonic-gate /* 10667c478bd9Sstevel@tonic-gate * Queue is already being processed. 10677c478bd9Sstevel@tonic-gate * No need to do anything. 10687c478bd9Sstevel@tonic-gate */ 10697c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 10707c478bd9Sstevel@tonic-gate return; 10717c478bd9Sstevel@tonic-gate } 10727c478bd9Sstevel@tonic-gate SQUEUE_WORKER_WAKEUP(sqp); 10737c478bd9Sstevel@tonic-gate } 10747c478bd9Sstevel@tonic-gate } 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate /* 10777c478bd9Sstevel@tonic-gate * squeue_fill() - fill squeue *sqp with mblk *mp with argument of *arg 10787c478bd9Sstevel@tonic-gate * without processing the squeue. 10797c478bd9Sstevel@tonic-gate */ 10807c478bd9Sstevel@tonic-gate /* ARGSUSED */ 10817c478bd9Sstevel@tonic-gate void 10827c478bd9Sstevel@tonic-gate squeue_fill(squeue_t *sqp, mblk_t *mp, sqproc_t proc, void * arg, 10837c478bd9Sstevel@tonic-gate uint8_t tag) 10847c478bd9Sstevel@tonic-gate { 10857c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 10867c478bd9Sstevel@tonic-gate conn_t *connp = (conn_t *)arg; 10877c478bd9Sstevel@tonic-gate #endif 10887c478bd9Sstevel@tonic-gate ASSERT(proc != NULL); 10897c478bd9Sstevel@tonic-gate ASSERT(sqp != NULL); 10907c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 10917c478bd9Sstevel@tonic-gate ASSERT(mp->b_next == NULL); 1092ff550d0eSmasputra ASSERT(!IPCL_IS_TCP(connp) || connp->conn_tcp->tcp_connp == connp); 1093ff550d0eSmasputra ASSERT(!IPCL_IS_UDP(connp) || connp->conn_udp->udp_connp == connp); 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&sqp->sq_lock)); 10967c478bd9Sstevel@tonic-gate mutex_enter(&sqp->sq_lock); 10977c478bd9Sstevel@tonic-gate ENQUEUE_MP(sqp, mp, proc, arg); 10987c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 10997c478bd9Sstevel@tonic-gate mp->b_tag = tag; 11007c478bd9Sstevel@tonic-gate #endif 11017c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 11027c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 11037c478bd9Sstevel@tonic-gate if (servicing_interrupt()) 11047c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_nqueued_intr); 11057c478bd9Sstevel@tonic-gate else 11067c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_nqueued_other); 11077c478bd9Sstevel@tonic-gate if (sqp->sq_stats.sq_max_qlen < sqp->sq_count) 11087c478bd9Sstevel@tonic-gate sqp->sq_stats.sq_max_qlen = sqp->sq_count; 11097c478bd9Sstevel@tonic-gate } 11107c478bd9Sstevel@tonic-gate #endif 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate /* 11137c478bd9Sstevel@tonic-gate * If queue is already being processed. No need to do anything. 11147c478bd9Sstevel@tonic-gate */ 11157c478bd9Sstevel@tonic-gate if (sqp->sq_state & SQS_PROC) { 11167c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 11177c478bd9Sstevel@tonic-gate return; 11187c478bd9Sstevel@tonic-gate } 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate SQUEUE_WORKER_WAKEUP(sqp); 11217c478bd9Sstevel@tonic-gate } 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate /* 11257c478bd9Sstevel@tonic-gate * PRIVATE FUNCTIONS 11267c478bd9Sstevel@tonic-gate */ 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate static void 11297c478bd9Sstevel@tonic-gate squeue_fire(void *arg) 11307c478bd9Sstevel@tonic-gate { 11317c478bd9Sstevel@tonic-gate squeue_t *sqp = arg; 11327c478bd9Sstevel@tonic-gate uint_t state; 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate mutex_enter(&sqp->sq_lock); 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate state = sqp->sq_state; 11377c478bd9Sstevel@tonic-gate if (sqp->sq_tid == 0 && !(state & SQS_TMO_PROG)) { 11387c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 11397c478bd9Sstevel@tonic-gate return; 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate sqp->sq_tid = 0; 11437c478bd9Sstevel@tonic-gate /* 11447c478bd9Sstevel@tonic-gate * The timeout fired before we got a chance to set it. 11457c478bd9Sstevel@tonic-gate * Process it anyway but remove the SQS_TMO_PROG so that 11467c478bd9Sstevel@tonic-gate * the guy trying to set the timeout knows that it has 11477c478bd9Sstevel@tonic-gate * already been processed. 11487c478bd9Sstevel@tonic-gate */ 11497c478bd9Sstevel@tonic-gate if (state & SQS_TMO_PROG) 11507c478bd9Sstevel@tonic-gate sqp->sq_state &= ~SQS_TMO_PROG; 11517c478bd9Sstevel@tonic-gate 11527c478bd9Sstevel@tonic-gate if (!(state & SQS_PROC)) { 11537c478bd9Sstevel@tonic-gate sqp->sq_awaken = lbolt; 11547c478bd9Sstevel@tonic-gate cv_signal(&sqp->sq_async); 11557c478bd9Sstevel@tonic-gate } 11567c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 11577c478bd9Sstevel@tonic-gate } 11587c478bd9Sstevel@tonic-gate 11597c478bd9Sstevel@tonic-gate static void 1160d19d6468Sbw squeue_drain(squeue_t *sqp, uint_t proc_type, hrtime_t expire) 11617c478bd9Sstevel@tonic-gate { 11627c478bd9Sstevel@tonic-gate mblk_t *mp; 11637c478bd9Sstevel@tonic-gate mblk_t *head; 11647c478bd9Sstevel@tonic-gate sqproc_t proc; 11657c478bd9Sstevel@tonic-gate conn_t *connp; 11667c478bd9Sstevel@tonic-gate clock_t start = lbolt; 11677c478bd9Sstevel@tonic-gate clock_t drain_time; 11687c478bd9Sstevel@tonic-gate timeout_id_t tid; 11697c478bd9Sstevel@tonic-gate uint_t cnt; 11707c478bd9Sstevel@tonic-gate uint_t total_cnt = 0; 11717c478bd9Sstevel@tonic-gate ill_rx_ring_t *sq_rx_ring = sqp->sq_rx_ring; 11727c478bd9Sstevel@tonic-gate int interrupt = servicing_interrupt(); 11737c478bd9Sstevel@tonic-gate boolean_t poll_on = B_FALSE; 1174d19d6468Sbw hrtime_t now; 11757c478bd9Sstevel@tonic-gate 11767c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&sqp->sq_lock)); 11777c478bd9Sstevel@tonic-gate ASSERT(!(sqp->sq_state & SQS_PROC)); 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 11807c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 11817c478bd9Sstevel@tonic-gate if (interrupt) 11827c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_ndrains_intr); 11837c478bd9Sstevel@tonic-gate else if (!(proc_type & SQS_WORKER)) 11847c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_ndrains_other); 11857c478bd9Sstevel@tonic-gate else 11867c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_ndrains_worker); 11877c478bd9Sstevel@tonic-gate } 11887c478bd9Sstevel@tonic-gate #endif 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate if ((tid = sqp->sq_tid) != 0) 11917c478bd9Sstevel@tonic-gate sqp->sq_tid = 0; 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate sqp->sq_state |= SQS_PROC | proc_type; 11947c478bd9Sstevel@tonic-gate head = sqp->sq_first; 11957c478bd9Sstevel@tonic-gate sqp->sq_first = NULL; 11967c478bd9Sstevel@tonic-gate sqp->sq_last = NULL; 11977c478bd9Sstevel@tonic-gate cnt = sqp->sq_count; 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate /* 12007c478bd9Sstevel@tonic-gate * We have backlog built up. Switch to polling mode if the 12017c478bd9Sstevel@tonic-gate * device underneath allows it. Need to do it only for 12027c478bd9Sstevel@tonic-gate * drain by non-interrupt thread so interrupts don't 12037c478bd9Sstevel@tonic-gate * come and disrupt us in between. If its a interrupt thread, 12047c478bd9Sstevel@tonic-gate * no need because most devices will not issue another 12057c478bd9Sstevel@tonic-gate * interrupt till this one returns. 12067c478bd9Sstevel@tonic-gate */ 12077c478bd9Sstevel@tonic-gate if ((sqp->sq_state & SQS_POLL_CAPAB) && !(proc_type & SQS_ENTER) && 12087c478bd9Sstevel@tonic-gate (sqp->sq_count > squeue_worker_poll_min)) { 12097c478bd9Sstevel@tonic-gate ASSERT(sq_rx_ring != NULL); 12107c478bd9Sstevel@tonic-gate SQS_POLLING_ON(sqp, sq_rx_ring); 12117c478bd9Sstevel@tonic-gate poll_on = B_TRUE; 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate if (tid != 0) 12177c478bd9Sstevel@tonic-gate (void) untimeout(tid); 12187c478bd9Sstevel@tonic-gate again: 12197c478bd9Sstevel@tonic-gate while ((mp = head) != NULL) { 12207c478bd9Sstevel@tonic-gate head = mp->b_next; 12217c478bd9Sstevel@tonic-gate mp->b_next = NULL; 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate proc = (sqproc_t)mp->b_queue; 12247c478bd9Sstevel@tonic-gate mp->b_queue = NULL; 12257c478bd9Sstevel@tonic-gate connp = (conn_t *)mp->b_prev; 12267c478bd9Sstevel@tonic-gate mp->b_prev = NULL; 12277c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 12287c478bd9Sstevel@tonic-gate sqp->sq_curmp = mp; 12297c478bd9Sstevel@tonic-gate sqp->sq_curproc = proc; 12307c478bd9Sstevel@tonic-gate sqp->sq_connp = connp; 12317c478bd9Sstevel@tonic-gate sqp->sq_tag = mp->b_tag; 12327c478bd9Sstevel@tonic-gate #endif 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 12357c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 12367c478bd9Sstevel@tonic-gate if (interrupt) 12377c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_npackets_intr); 12387c478bd9Sstevel@tonic-gate else if (!(proc_type & SQS_WORKER)) 12397c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_npackets_other); 12407c478bd9Sstevel@tonic-gate else 12417c478bd9Sstevel@tonic-gate SQSTAT(sqp, sq_npackets_worker); 12427c478bd9Sstevel@tonic-gate } 12437c478bd9Sstevel@tonic-gate #endif 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate connp->conn_on_sqp = B_TRUE; 12467c478bd9Sstevel@tonic-gate DTRACE_PROBE3(squeue__proc__start, squeue_t *, 12477c478bd9Sstevel@tonic-gate sqp, mblk_t *, mp, conn_t *, connp); 12487c478bd9Sstevel@tonic-gate (*proc)(connp, mp, sqp); 12497c478bd9Sstevel@tonic-gate DTRACE_PROBE2(squeue__proc__end, squeue_t *, 12507c478bd9Sstevel@tonic-gate sqp, conn_t *, connp); 12517c478bd9Sstevel@tonic-gate connp->conn_on_sqp = B_FALSE; 12527c478bd9Sstevel@tonic-gate CONN_DEC_REF(connp); 12537c478bd9Sstevel@tonic-gate } 12547c478bd9Sstevel@tonic-gate 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 12577c478bd9Sstevel@tonic-gate sqp->sq_curmp = NULL; 12587c478bd9Sstevel@tonic-gate sqp->sq_curproc = NULL; 12597c478bd9Sstevel@tonic-gate sqp->sq_connp = NULL; 12607c478bd9Sstevel@tonic-gate #endif 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate mutex_enter(&sqp->sq_lock); 12637c478bd9Sstevel@tonic-gate sqp->sq_count -= cnt; 12647c478bd9Sstevel@tonic-gate total_cnt += cnt; 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate if (sqp->sq_first != NULL) { 1267d19d6468Sbw 1268d19d6468Sbw now = gethrtime(); 1269d19d6468Sbw if (!expire || (now < expire)) { 12707c478bd9Sstevel@tonic-gate /* More arrived and time not expired */ 12717c478bd9Sstevel@tonic-gate head = sqp->sq_first; 12727c478bd9Sstevel@tonic-gate sqp->sq_first = NULL; 12737c478bd9Sstevel@tonic-gate sqp->sq_last = NULL; 12747c478bd9Sstevel@tonic-gate cnt = sqp->sq_count; 12757c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 12767c478bd9Sstevel@tonic-gate goto again; 12777c478bd9Sstevel@tonic-gate } 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate /* 12807c478bd9Sstevel@tonic-gate * If we are not worker thread and we 12817c478bd9Sstevel@tonic-gate * reached our time limit to do drain, 12827c478bd9Sstevel@tonic-gate * signal the worker thread to pick 12837c478bd9Sstevel@tonic-gate * up the work. 12847c478bd9Sstevel@tonic-gate * If we were the worker thread, then 12857c478bd9Sstevel@tonic-gate * we take a break to allow an interrupt 12867c478bd9Sstevel@tonic-gate * or writer to pick up the load. 12877c478bd9Sstevel@tonic-gate */ 12887c478bd9Sstevel@tonic-gate if (proc_type != SQS_WORKER) { 12897c478bd9Sstevel@tonic-gate sqp->sq_awaken = lbolt; 12907c478bd9Sstevel@tonic-gate cv_signal(&sqp->sq_async); 12917c478bd9Sstevel@tonic-gate } 12927c478bd9Sstevel@tonic-gate } 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate /* 12957c478bd9Sstevel@tonic-gate * Try to see if we can get a time estimate to process a packet. 12967c478bd9Sstevel@tonic-gate * Do it only in interrupt context since less chance of context 12977c478bd9Sstevel@tonic-gate * switch or pinning etc. to get a better estimate. 12987c478bd9Sstevel@tonic-gate */ 12997c478bd9Sstevel@tonic-gate if (interrupt && ((drain_time = (lbolt - start)) > 0)) 13007c478bd9Sstevel@tonic-gate sqp->sq_avg_drain_time = ((80 * sqp->sq_avg_drain_time) + 13017c478bd9Sstevel@tonic-gate (20 * (drv_hztousec(drain_time)/total_cnt)))/100; 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate sqp->sq_state &= ~(SQS_PROC | proc_type); 13047c478bd9Sstevel@tonic-gate 13057c478bd9Sstevel@tonic-gate /* 13067c478bd9Sstevel@tonic-gate * If polling was turned on, turn it off and reduce the default 13077c478bd9Sstevel@tonic-gate * interrupt blank interval as well to bring new packets in faster 13087c478bd9Sstevel@tonic-gate * (reduces the latency when there is no backlog). 13097c478bd9Sstevel@tonic-gate */ 13107c478bd9Sstevel@tonic-gate if (poll_on && (sqp->sq_state & SQS_POLL_CAPAB)) { 13117c478bd9Sstevel@tonic-gate ASSERT(sq_rx_ring != NULL); 13127c478bd9Sstevel@tonic-gate SQS_POLLING_OFF(sqp, sq_rx_ring); 13137c478bd9Sstevel@tonic-gate } 13147c478bd9Sstevel@tonic-gate } 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate static void 13177c478bd9Sstevel@tonic-gate squeue_worker(squeue_t *sqp) 13187c478bd9Sstevel@tonic-gate { 13197c478bd9Sstevel@tonic-gate kmutex_t *lock = &sqp->sq_lock; 13207c478bd9Sstevel@tonic-gate kcondvar_t *async = &sqp->sq_async; 13217c478bd9Sstevel@tonic-gate callb_cpr_t cprinfo; 1322d19d6468Sbw hrtime_t now; 13237c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 13247c478bd9Sstevel@tonic-gate hrtime_t start; 13257c478bd9Sstevel@tonic-gate #endif 13267c478bd9Sstevel@tonic-gate 13277c478bd9Sstevel@tonic-gate CALLB_CPR_INIT(&cprinfo, lock, callb_generic_cpr, "nca"); 13287c478bd9Sstevel@tonic-gate mutex_enter(lock); 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate for (;;) { 13317c478bd9Sstevel@tonic-gate while (sqp->sq_first == NULL || (sqp->sq_state & SQS_PROC)) { 13327c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cprinfo); 13337c478bd9Sstevel@tonic-gate still_wait: 13347c478bd9Sstevel@tonic-gate cv_wait(async, lock); 13357c478bd9Sstevel@tonic-gate if (sqp->sq_state & SQS_PROC) { 13367c478bd9Sstevel@tonic-gate goto still_wait; 13377c478bd9Sstevel@tonic-gate } 13387c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cprinfo, lock); 13397c478bd9Sstevel@tonic-gate } 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 13427c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 13437c478bd9Sstevel@tonic-gate start = gethrtime(); 13447c478bd9Sstevel@tonic-gate } 13457c478bd9Sstevel@tonic-gate #endif 13467c478bd9Sstevel@tonic-gate 1347d19d6468Sbw ASSERT(squeue_workerdrain_ns != 0); 1348d19d6468Sbw now = gethrtime(); 13497c478bd9Sstevel@tonic-gate sqp->sq_run = curthread; 1350d19d6468Sbw squeue_drain(sqp, SQS_WORKER, now + squeue_workerdrain_ns); 13517c478bd9Sstevel@tonic-gate sqp->sq_run = NULL; 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate if (sqp->sq_first != NULL) { 13547c478bd9Sstevel@tonic-gate /* 13557c478bd9Sstevel@tonic-gate * Doing too much processing by worker thread 13567c478bd9Sstevel@tonic-gate * in presense of interrupts can be sub optimal. 13577c478bd9Sstevel@tonic-gate * Instead, once a drain is done by worker thread 1358d19d6468Sbw * for squeue_writerdrain_ns (the reason we are 13597c478bd9Sstevel@tonic-gate * here), we force wait for squeue_workerwait_tick 13607c478bd9Sstevel@tonic-gate * before doing more processing even if sq_wait is 13617c478bd9Sstevel@tonic-gate * set to 0. 13627c478bd9Sstevel@tonic-gate * 13637c478bd9Sstevel@tonic-gate * This can be counterproductive for performance 13647c478bd9Sstevel@tonic-gate * if worker thread is the only means to process 13657c478bd9Sstevel@tonic-gate * the packets (interrupts or writers are not 13667c478bd9Sstevel@tonic-gate * allowed inside the squeue). 13677c478bd9Sstevel@tonic-gate */ 13687c478bd9Sstevel@tonic-gate if (sqp->sq_tid == 0 && 13697c478bd9Sstevel@tonic-gate !(sqp->sq_state & SQS_TMO_PROG)) { 13707c478bd9Sstevel@tonic-gate timeout_id_t tid; 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate sqp->sq_state |= SQS_TMO_PROG; 13737c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 13747c478bd9Sstevel@tonic-gate tid = timeout(squeue_fire, sqp, 13757c478bd9Sstevel@tonic-gate squeue_workerwait_tick); 13767c478bd9Sstevel@tonic-gate mutex_enter(&sqp->sq_lock); 13777c478bd9Sstevel@tonic-gate /* 13787c478bd9Sstevel@tonic-gate * Check again if we still need 13797c478bd9Sstevel@tonic-gate * the timeout 13807c478bd9Sstevel@tonic-gate */ 13817c478bd9Sstevel@tonic-gate if (((sqp->sq_state & (SQS_TMO_PROG|SQS_PROC)) 13827c478bd9Sstevel@tonic-gate == SQS_TMO_PROG) && (sqp->sq_tid == 0) && 13837c478bd9Sstevel@tonic-gate (sqp->sq_first != NULL)) { 13847c478bd9Sstevel@tonic-gate sqp->sq_state &= ~SQS_TMO_PROG; 13857c478bd9Sstevel@tonic-gate sqp->sq_awaken = lbolt; 13867c478bd9Sstevel@tonic-gate sqp->sq_tid = tid; 13877c478bd9Sstevel@tonic-gate } else if (sqp->sq_state & SQS_TMO_PROG) { 13887c478bd9Sstevel@tonic-gate /* timeout not needed */ 13897c478bd9Sstevel@tonic-gate sqp->sq_state &= ~SQS_TMO_PROG; 13907c478bd9Sstevel@tonic-gate mutex_exit(&(sqp)->sq_lock); 13917c478bd9Sstevel@tonic-gate (void) untimeout(tid); 13927c478bd9Sstevel@tonic-gate mutex_enter(&sqp->sq_lock); 13937c478bd9Sstevel@tonic-gate } 13947c478bd9Sstevel@tonic-gate } 13957c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cprinfo); 13967c478bd9Sstevel@tonic-gate cv_wait(async, lock); 13977c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cprinfo, lock); 13987c478bd9Sstevel@tonic-gate } 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 14027c478bd9Sstevel@tonic-gate if (SQ_PROFILING(sqp)) { 14037c478bd9Sstevel@tonic-gate SQDELTA(sqp, sq_time_worker, gethrtime() - start); 14047c478bd9Sstevel@tonic-gate } 14057c478bd9Sstevel@tonic-gate #endif 14067c478bd9Sstevel@tonic-gate } 14077c478bd9Sstevel@tonic-gate } 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 14107c478bd9Sstevel@tonic-gate static int 14117c478bd9Sstevel@tonic-gate squeue_kstat_update(kstat_t *ksp, int rw) 14127c478bd9Sstevel@tonic-gate { 14137c478bd9Sstevel@tonic-gate struct squeue_kstat *sqsp = &squeue_kstat; 14147c478bd9Sstevel@tonic-gate squeue_t *sqp = ksp->ks_private; 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate if (rw == KSTAT_WRITE) 14177c478bd9Sstevel@tonic-gate return (EACCES); 14187c478bd9Sstevel@tonic-gate 14197c478bd9Sstevel@tonic-gate #if SQUEUE_DEBUG 14207c478bd9Sstevel@tonic-gate sqsp->sq_count.value.ui64 = sqp->sq_count; 14217c478bd9Sstevel@tonic-gate sqsp->sq_max_qlen.value.ui64 = sqp->sq_stats.sq_max_qlen; 14227c478bd9Sstevel@tonic-gate #endif 14237c478bd9Sstevel@tonic-gate sqsp->sq_npackets_worker.value.ui64 = sqp->sq_stats.sq_npackets_worker; 14247c478bd9Sstevel@tonic-gate sqsp->sq_npackets_intr.value.ui64 = sqp->sq_stats.sq_npackets_intr; 14257c478bd9Sstevel@tonic-gate sqsp->sq_npackets_other.value.ui64 = sqp->sq_stats.sq_npackets_other; 14267c478bd9Sstevel@tonic-gate sqsp->sq_nqueued_intr.value.ui64 = sqp->sq_stats.sq_nqueued_intr; 14277c478bd9Sstevel@tonic-gate sqsp->sq_nqueued_other.value.ui64 = sqp->sq_stats.sq_nqueued_other; 14287c478bd9Sstevel@tonic-gate sqsp->sq_ndrains_worker.value.ui64 = sqp->sq_stats.sq_ndrains_worker; 14297c478bd9Sstevel@tonic-gate sqsp->sq_ndrains_intr.value.ui64 = sqp->sq_stats.sq_ndrains_intr; 14307c478bd9Sstevel@tonic-gate sqsp->sq_ndrains_other.value.ui64 = sqp->sq_stats.sq_ndrains_other; 14317c478bd9Sstevel@tonic-gate sqsp->sq_time_worker.value.ui64 = sqp->sq_stats.sq_time_worker; 14327c478bd9Sstevel@tonic-gate sqsp->sq_time_intr.value.ui64 = sqp->sq_stats.sq_time_intr; 14337c478bd9Sstevel@tonic-gate sqsp->sq_time_other.value.ui64 = sqp->sq_stats.sq_time_other; 14347c478bd9Sstevel@tonic-gate return (0); 14357c478bd9Sstevel@tonic-gate } 14367c478bd9Sstevel@tonic-gate #endif 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate void 14397c478bd9Sstevel@tonic-gate squeue_profile_enable(squeue_t *sqp) 14407c478bd9Sstevel@tonic-gate { 14417c478bd9Sstevel@tonic-gate mutex_enter(&sqp->sq_lock); 14427c478bd9Sstevel@tonic-gate sqp->sq_state |= SQS_PROFILE; 14437c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 14447c478bd9Sstevel@tonic-gate } 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate void 14477c478bd9Sstevel@tonic-gate squeue_profile_disable(squeue_t *sqp) 14487c478bd9Sstevel@tonic-gate { 14497c478bd9Sstevel@tonic-gate mutex_enter(&sqp->sq_lock); 14507c478bd9Sstevel@tonic-gate sqp->sq_state &= ~SQS_PROFILE; 14517c478bd9Sstevel@tonic-gate mutex_exit(&sqp->sq_lock); 14527c478bd9Sstevel@tonic-gate } 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate void 14557c478bd9Sstevel@tonic-gate squeue_profile_reset(squeue_t *sqp) 14567c478bd9Sstevel@tonic-gate { 14577c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 14587c478bd9Sstevel@tonic-gate bzero(&sqp->sq_stats, sizeof (sqstat_t)); 14597c478bd9Sstevel@tonic-gate #endif 14607c478bd9Sstevel@tonic-gate } 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate void 14637c478bd9Sstevel@tonic-gate squeue_profile_start(void) 14647c478bd9Sstevel@tonic-gate { 14657c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 14667c478bd9Sstevel@tonic-gate squeue_profile = B_TRUE; 14677c478bd9Sstevel@tonic-gate #endif 14687c478bd9Sstevel@tonic-gate } 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate void 14717c478bd9Sstevel@tonic-gate squeue_profile_stop(void) 14727c478bd9Sstevel@tonic-gate { 14737c478bd9Sstevel@tonic-gate #if SQUEUE_PROFILE 14747c478bd9Sstevel@tonic-gate squeue_profile = B_FALSE; 14757c478bd9Sstevel@tonic-gate #endif 14767c478bd9Sstevel@tonic-gate } 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate uintptr_t * 14797c478bd9Sstevel@tonic-gate squeue_getprivate(squeue_t *sqp, sqprivate_t p) 14807c478bd9Sstevel@tonic-gate { 14817c478bd9Sstevel@tonic-gate ASSERT(p < SQPRIVATE_MAX); 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate return (&sqp->sq_private[p]); 14847c478bd9Sstevel@tonic-gate } 14857c478bd9Sstevel@tonic-gate 14867c478bd9Sstevel@tonic-gate processorid_t 14877c478bd9Sstevel@tonic-gate squeue_binding(squeue_t *sqp) 14887c478bd9Sstevel@tonic-gate { 14897c478bd9Sstevel@tonic-gate return (sqp->sq_bind); 14907c478bd9Sstevel@tonic-gate } 1491