1211809Sjchandra/*- 2198160Srrs * Copyright (c) 2003-2009 RMI Corporation 3198160Srrs * All rights reserved. 4198160Srrs * 5198160Srrs * Redistribution and use in source and binary forms, with or without 6198160Srrs * modification, are permitted provided that the following conditions 7198160Srrs * are met: 8198160Srrs * 1. Redistributions of source code must retain the above copyright 9198160Srrs * notice, this list of conditions and the following disclaimer. 10198160Srrs * 2. Redistributions in binary form must reproduce the above copyright 11198160Srrs * notice, this list of conditions and the following disclaimer in the 12198160Srrs * documentation and/or other materials provided with the distribution. 13198160Srrs * 3. Neither the name of RMI Corporation, nor the names of its contributors, 14198160Srrs * may be used to endorse or promote products derived from this software 15198160Srrs * without specific prior written permission. 16198160Srrs * 17198160Srrs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18198160Srrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19198160Srrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20198160Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21198160Srrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22198160Srrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23198160Srrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24198160Srrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25198160Srrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26198160Srrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27198160Srrs * SUCH DAMAGE. 28198160Srrs * 29198160Srrs * RMI_BSD */ 30203112Srrs#include <sys/cdefs.h> 31203112Srrs__FBSDID("$FreeBSD$"); 32198160Srrs#include <sys/types.h> 33198160Srrs#include <sys/systm.h> 34198160Srrs#include <sys/param.h> 35198160Srrs#include <sys/lock.h> 36198160Srrs#include <sys/mutex.h> 37198160Srrs#include <sys/proc.h> 38198160Srrs#include <sys/limits.h> 39198160Srrs#include <sys/bus.h> 40280013Sian#include <sys/sbuf.h> 41198160Srrs 42208165Srrs#include <sys/ktr.h> 43208165Srrs#include <sys/kernel.h> 44208165Srrs#include <sys/kthread.h> 45208165Srrs#include <sys/resourcevar.h> 46208165Srrs#include <sys/sched.h> 47208165Srrs#include <sys/unistd.h> 48208165Srrs#include <sys/sysctl.h> 49208165Srrs#include <sys/malloc.h> 50208165Srrs 51198160Srrs#include <machine/reg.h> 52198160Srrs#include <machine/cpu.h> 53208165Srrs#include <machine/hwfunc.h> 54198160Srrs#include <machine/mips_opcode.h> 55198160Srrs 56198160Srrs#include <machine/intr_machdep.h> 57198607Srrs#include <mips/rmi/interrupt.h> 58198607Srrs#include <mips/rmi/msgring.h> 59198607Srrs#include <mips/rmi/pic.h> 60198607Srrs#include <mips/rmi/board.h> 61198160Srrs 62198160Srrs#define MSGRNG_CC_INIT_CPU_DEST(dest, counter) \ 63198160Srrsdo { \ 64198160Srrs msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][0], 0 ); \ 65198160Srrs msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][1], 1 ); \ 66198160Srrs msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][2], 2 ); \ 67198160Srrs msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][3], 3 ); \ 68198160Srrs msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][4], 4 ); \ 69198160Srrs msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][5], 5 ); \ 70198160Srrs msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][6], 6 ); \ 71198160Srrs msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][7], 7 ); \ 72198160Srrs} while(0) 73198160Srrs 74198160Srrs 75213377Sjchandra/* 76213377Sjchandra * Keep track of our message ring handler threads, each core has a 77213377Sjchandra * different message station. Ideally we will need to start a few 78213377Sjchandra * message handling threads every core, and wake them up depending on 79213377Sjchandra * load 80213377Sjchandra */ 81213377Sjchandrastruct msgring_thread { 82213377Sjchandra struct { 83213377Sjchandra struct thread *thread; /* msgring handler threads */ 84213377Sjchandra int needed; /* thread needs to wake up */ 85213377Sjchandra } threads[XLR_NTHREADS]; 86213377Sjchandra int running; /* number of threads running */ 87213377Sjchandra int nthreads; /* number of threads started */ 88213377Sjchandra struct mtx lock; /* for changing running/active */ 89213377Sjchandra}; 90213377Sjchandrastatic struct msgring_thread msgring_threads[XLR_MAX_CORES]; 91213377Sjchandrastatic struct proc *msgring_proc; /* all threads are under a proc */ 92198160Srrs 93213377Sjchandra/* 94213377Sjchandra * The maximum number of software message handler threads to be started 95213443Sjchandra * per core. Default is 3 per core 96213377Sjchandra */ 97213443Sjchandrastatic int msgring_maxthreads = 3; 98213377SjchandraTUNABLE_INT("hw.fmn.maxthreads", &msgring_maxthreads); 99213377Sjchandra 100213377Sjchandra/* 101218909Sbrucec * The device drivers can register a handler for the messages sent 102213377Sjchandra * from a station (corresponding to the device). 103213377Sjchandra */ 104213377Sjchandrastruct tx_stn_handler { 105213377Sjchandra msgring_handler action; 106213377Sjchandra void *arg; 107213377Sjchandra}; 108213377Sjchandrastatic struct tx_stn_handler msgmap[MSGRNG_NSTATIONS]; 109213377Sjchandrastatic struct mtx msgmap_lock; 110213377Sjchandra 111213377Sjchandra/* 112213377Sjchandra * Initialize the messaging subsystem. 113213377Sjchandra * 114213377Sjchandra * Message Stations are shared among all threads in a cpu core, this 115213377Sjchandra * has to be called once from every core which is online. 116213377Sjchandra */ 117198625Srrsvoid 118198625Srrsxlr_msgring_cpu_init(void) 119198160Srrs{ 120198160Srrs struct stn_cc *cc_config; 121198160Srrs struct bucket_size *bucket_sizes; 122213377Sjchandra uint32_t flags; 123198160Srrs int id; 124198160Srrs 125208165Srrs KASSERT(xlr_thr_id() == 0, 126213377Sjchandra ("xlr_msgring_cpu_init from non-zero thread")); 127208165Srrs id = xlr_core_id(); 128198160Srrs bucket_sizes = xlr_board_info.bucket_sizes; 129198160Srrs cc_config = xlr_board_info.credit_configs[id]; 130198160Srrs 131213377Sjchandra flags = msgrng_access_enable(); 132198625Srrs 133198625Srrs /* 134213377Sjchandra * FMN messages are received in 8 buckets per core, set up 135213377Sjchandra * the bucket sizes for each bucket 136198160Srrs */ 137198625Srrs msgrng_write_bucksize(0, bucket_sizes->bucket[id * 8 + 0]); 138198625Srrs msgrng_write_bucksize(1, bucket_sizes->bucket[id * 8 + 1]); 139198625Srrs msgrng_write_bucksize(2, bucket_sizes->bucket[id * 8 + 2]); 140198625Srrs msgrng_write_bucksize(3, bucket_sizes->bucket[id * 8 + 3]); 141198625Srrs msgrng_write_bucksize(4, bucket_sizes->bucket[id * 8 + 4]); 142198625Srrs msgrng_write_bucksize(5, bucket_sizes->bucket[id * 8 + 5]); 143198625Srrs msgrng_write_bucksize(6, bucket_sizes->bucket[id * 8 + 6]); 144198625Srrs msgrng_write_bucksize(7, bucket_sizes->bucket[id * 8 + 7]); 145198160Srrs 146213377Sjchandra /* 147213377Sjchandra * For sending FMN messages, we need credits on the destination 148213377Sjchandra * bucket. Program the credits this core has on the 128 possible 149213377Sjchandra * destination buckets. 150218909Sbrucec * We cannot use a loop here, because the first argument has 151213443Sjchandra * to be a constant integer value. 152213377Sjchandra */ 153213377Sjchandra MSGRNG_CC_INIT_CPU_DEST(0, cc_config->counters); 154213377Sjchandra MSGRNG_CC_INIT_CPU_DEST(1, cc_config->counters); 155213377Sjchandra MSGRNG_CC_INIT_CPU_DEST(2, cc_config->counters); 156213377Sjchandra MSGRNG_CC_INIT_CPU_DEST(3, cc_config->counters); 157213377Sjchandra MSGRNG_CC_INIT_CPU_DEST(4, cc_config->counters); 158213377Sjchandra MSGRNG_CC_INIT_CPU_DEST(5, cc_config->counters); 159213377Sjchandra MSGRNG_CC_INIT_CPU_DEST(6, cc_config->counters); 160213377Sjchandra MSGRNG_CC_INIT_CPU_DEST(7, cc_config->counters); 161213377Sjchandra MSGRNG_CC_INIT_CPU_DEST(8, cc_config->counters); 162213377Sjchandra MSGRNG_CC_INIT_CPU_DEST(9, cc_config->counters); 163198160Srrs MSGRNG_CC_INIT_CPU_DEST(10, cc_config->counters); 164198160Srrs MSGRNG_CC_INIT_CPU_DEST(11, cc_config->counters); 165198160Srrs MSGRNG_CC_INIT_CPU_DEST(12, cc_config->counters); 166198160Srrs MSGRNG_CC_INIT_CPU_DEST(13, cc_config->counters); 167198160Srrs MSGRNG_CC_INIT_CPU_DEST(14, cc_config->counters); 168198160Srrs MSGRNG_CC_INIT_CPU_DEST(15, cc_config->counters); 169212321Sjchandra msgrng_restore(flags); 170198160Srrs} 171198160Srrs 172213377Sjchandra/* 173213377Sjchandra * Boot time init, called only once 174213377Sjchandra */ 175198625Srrsvoid 176198625Srrsxlr_msgring_config(void) 177198160Srrs{ 178213377Sjchandra mtx_init(&msgmap_lock, "msgring", NULL, MTX_SPIN); 179213377Sjchandra 180213377Sjchandra /* check value */ 181213377Sjchandra if (msgring_maxthreads < 0 || msgring_maxthreads > XLR_NTHREADS) 182213377Sjchandra msgring_maxthreads = XLR_NTHREADS; 183198160Srrs} 184198160Srrs 185212790Sjchandra/* 186212790Sjchandra * Drain out max_messages for the buckets set in the bucket mask. 187212790Sjchandra * Use max_messages = 0 to drain out all messages. 188212790Sjchandra */ 189212790Sjchandrauint32_t 190212790Sjchandraxlr_msgring_handler(uint8_t bucket_mask, uint32_t max_messages) 191198160Srrs{ 192198625Srrs int bucket = 0; 193213377Sjchandra int size = 0, code = 0, rx_stid = 0; 194198160Srrs struct msgrng_msg msg; 195213377Sjchandra struct tx_stn_handler *he; 196198625Srrs unsigned int status = 0; 197212790Sjchandra unsigned long mflags; 198213377Sjchandra uint32_t n_msgs; 199213377Sjchandra uint32_t msgbuckets; 200198160Srrs 201212790Sjchandra n_msgs = 0; 202212321Sjchandra mflags = msgrng_access_enable(); 203198625Srrs for (;;) { 204213377Sjchandra msgbuckets = (~msgrng_read_status() >> 24) & bucket_mask; 205198160Srrs 206198625Srrs /* all buckets empty, break */ 207213377Sjchandra if (msgbuckets == 0) 208198625Srrs break; 209198160Srrs 210213377Sjchandra for (bucket = 0; bucket < 8; bucket++) { 211213377Sjchandra if ((msgbuckets & (1 << bucket)) == 0) /* empty */ 212198625Srrs continue; 213198625Srrs 214213377Sjchandra status = message_receive(bucket, &size, &code, 215213377Sjchandra &rx_stid, &msg); 216213377Sjchandra if (status != 0) 217198625Srrs continue; 218212790Sjchandra n_msgs++; 219213377Sjchandra he = &msgmap[rx_stid]; 220213377Sjchandra if (he->action == NULL) { 221213377Sjchandra printf("[%s]: No Handler for message from " 222213377Sjchandra "stn_id=%d, bucket=%d, size=%d, msg0=%jx\n", 223213377Sjchandra __func__, rx_stid, bucket, size, 224213377Sjchandra (uintmax_t)msg.msg0); 225198625Srrs } else { 226212321Sjchandra msgrng_restore(mflags); 227213377Sjchandra (*he->action)(bucket, size, code, rx_stid, 228213377Sjchandra &msg, he->arg); 229212321Sjchandra mflags = msgrng_access_enable(); 230198625Srrs } 231212790Sjchandra if (max_messages > 0 && n_msgs >= max_messages) 232212790Sjchandra goto done; 233198160Srrs } 234198160Srrs } 235212790Sjchandra 236212790Sjchandradone: 237212321Sjchandra msgrng_restore(mflags); 238212790Sjchandra return (n_msgs); 239198160Srrs} 240198160Srrs 241213377Sjchandra/* 242213377Sjchandra * XLR COP2 supports watermark interrupts based on the number of 243213377Sjchandra * messages pending in all the buckets in the core. We increase 244213377Sjchandra * the watermark until all the possible handler threads in the core 245213377Sjchandra * are woken up. 246213377Sjchandra */ 247213377Sjchandrastatic void 248213377Sjchandramsgrng_setconfig(int running, int nthr) 249198160Srrs{ 250212321Sjchandra uint32_t config, mflags; 251213377Sjchandra int watermark = 1; /* non zero needed */ 252213377Sjchandra int wm_intr_value; 253198160Srrs 254213377Sjchandra KASSERT(nthr >= 0 && nthr <= msgring_maxthreads, 255213377Sjchandra ("Bad value of nthr %d", nthr)); 256213377Sjchandra KASSERT(running <= nthr, ("Bad value of running %d", running)); 257198160Srrs 258213377Sjchandra if (running == nthr) { 259213377Sjchandra wm_intr_value = 0; 260213377Sjchandra } else { 261213377Sjchandra switch (running) { 262213377Sjchandra case 0: break; /* keep default */ 263213377Sjchandra case 1: 264213443Sjchandra watermark = 32; break; 265213377Sjchandra case 2: 266213443Sjchandra watermark = 48; break; 267213377Sjchandra case 3: 268213443Sjchandra watermark = 56; break; 269213377Sjchandra } 270213377Sjchandra wm_intr_value = 0x2; /* set watermark enable interrupt */ 271213377Sjchandra } 272212321Sjchandra mflags = msgrng_access_enable(); 273213377Sjchandra config = (watermark << 24) | (IRQ_MSGRING << 16) | (1 << 8) | 274213377Sjchandra wm_intr_value; 275213443Sjchandra /* clear pending interrupts, they will get re-raised if still valid */ 276213377Sjchandra write_c0_eirr64(1ULL << IRQ_MSGRING); 277198160Srrs msgrng_write_config(config); 278212321Sjchandra msgrng_restore(mflags); 279198160Srrs} 280198160Srrs 281213443Sjchandra/* Debug counters */ 282213443Sjchandrastatic int msgring_nintr[XLR_MAX_CORES]; 283213443Sjchandrastatic int msgring_badintr[XLR_MAX_CORES]; 284213443Sjchandrastatic int msgring_wakeup_sleep[XLR_MAX_CORES * XLR_NTHREADS]; 285213443Sjchandrastatic int msgring_wakeup_nosleep[XLR_MAX_CORES * XLR_NTHREADS]; 286213443Sjchandrastatic int msgring_nmsgs[XLR_MAX_CORES * XLR_NTHREADS]; 287213443Sjchandra 288208165Srrsstatic int 289208165Srrsmsgring_process_fast_intr(void *arg) 290208165Srrs{ 291213377Sjchandra struct msgring_thread *mthd; 292213377Sjchandra struct thread *td; 293213377Sjchandra uint32_t mflags; 294213377Sjchandra int core, nt; 295198160Srrs 296213377Sjchandra core = xlr_core_id(); 297213377Sjchandra mthd = &msgring_threads[core]; 298213443Sjchandra msgring_nintr[core]++; 299213377Sjchandra mtx_lock_spin(&mthd->lock); 300213377Sjchandra nt = mthd->running; 301213377Sjchandra if(nt >= mthd->nthreads) { 302213443Sjchandra msgring_badintr[core]++; 303213377Sjchandra mtx_unlock_spin(&mthd->lock); 304213377Sjchandra return (FILTER_HANDLED); 305213377Sjchandra } 306213377Sjchandra 307213377Sjchandra td = mthd->threads[nt].thread; 308213377Sjchandra mflags = msgrng_access_enable(); 309213377Sjchandra 310213377Sjchandra /* default value with interrupts disabled */ 311213377Sjchandra msgrng_write_config((1 << 24) | (IRQ_MSGRING << 16) | (1 << 8)); 312213443Sjchandra /* clear pending interrupts */ 313213443Sjchandra write_c0_eirr64(1ULL << IRQ_MSGRING); 314213377Sjchandra msgrng_restore(mflags); 315213377Sjchandra mtx_unlock_spin(&mthd->lock); 316213377Sjchandra 317213377Sjchandra /* wake up the target thread */ 318213377Sjchandra mthd->threads[nt].needed = 1; 319208165Srrs thread_lock(td); 320208165Srrs if (TD_AWAITING_INTR(td)) { 321213443Sjchandra msgring_wakeup_sleep[core*4+nt]++; 322208165Srrs TD_CLR_IWAIT(td); 323208165Srrs sched_add(td, SRQ_INTR); 324213443Sjchandra } else 325213443Sjchandra msgring_wakeup_nosleep[core*4+nt]++; 326208165Srrs thread_unlock(td); 327213377Sjchandra return (FILTER_HANDLED); 328208165Srrs} 329208165Srrs 330208165Srrsstatic void 331208165Srrsmsgring_process(void *arg) 332208165Srrs{ 333213377Sjchandra struct msgring_thread *mthd; 334213377Sjchandra struct thread *td; 335213377Sjchandra int hwtid, tid, core; 336213377Sjchandra int nmsgs; 337208165Srrs 338213377Sjchandra hwtid = (intptr_t)arg; 339213377Sjchandra core = hwtid / 4; 340213377Sjchandra tid = hwtid % 4; 341213377Sjchandra mthd = &msgring_threads[core]; 342213377Sjchandra td = mthd->threads[tid].thread; 343213377Sjchandra KASSERT(curthread == td, 344213377Sjchandra ("Incorrect thread core %d, thread %d", core, hwtid)); 345208165Srrs 346208165Srrs /* First bind this thread to the right CPU */ 347208165Srrs thread_lock(td); 348213377Sjchandra sched_bind(td, xlr_hwtid_to_cpuid[hwtid]); 349208165Srrs thread_unlock(td); 350208165Srrs 351213377Sjchandra mtx_lock_spin(&mthd->lock); 352213443Sjchandra ++mthd->nthreads; /* Active thread count */ 353213377Sjchandra mtx_unlock_spin(&mthd->lock); 354213377Sjchandra 355213377Sjchandra /* start processing messages */ 356213377Sjchandra for(;;) { 357213377Sjchandra mtx_lock_spin(&mthd->lock); 358213377Sjchandra ++mthd->running; 359213377Sjchandra msgrng_setconfig(mthd->running, mthd->nthreads); 360213377Sjchandra mtx_unlock_spin(&mthd->lock); 361213377Sjchandra 362213377Sjchandra atomic_store_rel_int(&mthd->threads[tid].needed, 0); 363213377Sjchandra nmsgs = xlr_msgring_handler(0xff, 0); 364213443Sjchandra msgring_nmsgs[hwtid] += nmsgs; 365213377Sjchandra 366213377Sjchandra mtx_lock_spin(&mthd->lock); 367213377Sjchandra --mthd->running; 368213377Sjchandra msgrng_setconfig(mthd->running, mthd->nthreads); 369213377Sjchandra mtx_unlock_spin(&mthd->lock); 370213377Sjchandra 371213377Sjchandra /* sleep */ 372213377Sjchandra thread_lock(td); 373213377Sjchandra if (mthd->threads[tid].needed) { 374208165Srrs thread_unlock(td); 375213377Sjchandra continue; 376208165Srrs } 377213377Sjchandra sched_class(td, PRI_ITHD); 378213377Sjchandra TD_SET_IWAIT(td); 379213377Sjchandra mi_switch(SW_VOL, NULL); 380213377Sjchandra thread_unlock(td); 381208165Srrs } 382208165Srrs} 383208165Srrs 384208165Srrsstatic void 385213377Sjchandracreate_msgring_thread(int hwtid) 386208165Srrs{ 387213377Sjchandra struct msgring_thread *mthd; 388208165Srrs struct thread *td; 389213377Sjchandra int tid, core; 390213377Sjchandra int error; 391208165Srrs 392213377Sjchandra core = hwtid / 4; 393213377Sjchandra tid = hwtid % 4; 394213377Sjchandra mthd = &msgring_threads[core]; 395213377Sjchandra if (tid == 0) { 396213377Sjchandra mtx_init(&mthd->lock, "msgrngcore", NULL, MTX_SPIN); 397213377Sjchandra mthd->running = mthd->nthreads = 0; 398213377Sjchandra } 399213474Sjchandra error = kproc_kthread_add(msgring_process, (void *)(uintptr_t)hwtid, 400213377Sjchandra &msgring_proc, &td, RFSTOPPED, 2, "msgrngproc", 401213377Sjchandra "msgthr%d", hwtid); 402208165Srrs if (error) 403213377Sjchandra panic("kproc_kthread_add() failed with %d", error); 404213377Sjchandra mthd->threads[tid].thread = td; 405208165Srrs 406208165Srrs thread_lock(td); 407208165Srrs sched_class(td, PRI_ITHD); 408208165Srrs sched_add(td, SRQ_INTR); 409208165Srrs thread_unlock(td); 410210845Sjchandra CTR2(KTR_INTR, "%s: created %s", __func__, td->td_name); 411208165Srrs} 412208165Srrs 413198625Srrsint 414213377Sjchandraregister_msgring_handler(int startb, int endb, msgring_handler action, 415213377Sjchandra void *arg) 416198160Srrs{ 417213377Sjchandra void *cookie; 418213377Sjchandra int i; 419213377Sjchandra static int msgring_int_enabled = 0; 420198160Srrs 421213377Sjchandra KASSERT(startb >= 0 && startb <= endb && endb < MSGRNG_NSTATIONS, 422213377Sjchandra ("Invalid value for for bucket range %d,%d", startb, endb)); 423198160Srrs 424213377Sjchandra mtx_lock_spin(&msgmap_lock); 425213377Sjchandra for (i = startb; i <= endb; i++) { 426213377Sjchandra KASSERT(msgmap[i].action == NULL, 427213377Sjchandra ("Bucket %d already used [action %p]", i, msgmap[i].action)); 428213377Sjchandra msgmap[i].action = action; 429213377Sjchandra msgmap[i].arg = arg; 430213377Sjchandra } 431213377Sjchandra mtx_unlock_spin(&msgmap_lock); 432198625Srrs 433198160Srrs if (xlr_test_and_set(&msgring_int_enabled)) { 434213377Sjchandra create_msgring_thread(0); 435213377Sjchandra if (msgring_maxthreads > xlr_threads_per_core) 436213377Sjchandra msgring_maxthreads = xlr_threads_per_core; 437213377Sjchandra cpu_establish_hardintr("msgring", msgring_process_fast_intr, 438203112Srrs NULL, NULL, IRQ_MSGRING, 439217072Sjhb INTR_TYPE_NET, &cookie); 440198160Srrs } 441213377Sjchandra return (0); 442198160Srrs} 443198160Srrs 444213443Sjchandra/* 445213443Sjchandra * Start message ring processing threads on other CPUs, after SMP start 446213443Sjchandra */ 447208165Srrsstatic void 448208165Srrsstart_msgring_threads(void *arg) 449208165Srrs{ 450213377Sjchandra int hwt, tid; 451208165Srrs 452213377Sjchandra for (hwt = 1; hwt < XLR_MAX_CORES * XLR_NTHREADS; hwt++) { 453213377Sjchandra if ((xlr_hw_thread_mask & (1 << hwt)) == 0) 454213377Sjchandra continue; 455213377Sjchandra tid = hwt % XLR_NTHREADS; 456213377Sjchandra if (tid >= msgring_maxthreads) 457213377Sjchandra continue; 458213377Sjchandra create_msgring_thread(hwt); 459208369Sjchandra } 460198160Srrs} 461208165Srrs 462213443SjchandraSYSINIT(start_msgring_threads, SI_SUB_SMP, SI_ORDER_MIDDLE, 463213443Sjchandra start_msgring_threads, NULL); 464213443Sjchandra 465213443Sjchandra/* 466213443Sjchandra * DEBUG support, XXX: static buffer, not locked 467213443Sjchandra */ 468213443Sjchandrastatic int 469213443Sjchandrasys_print_debug(SYSCTL_HANDLER_ARGS) 470213443Sjchandra{ 471280013Sian struct sbuf sb; 472280013Sian int error, i; 473213443Sjchandra 474280013Sian sbuf_new_for_sysctl(&sb, NULL, 64, req); 475280013Sian sbuf_printf(&sb, 476213443Sjchandra "\nID INTR ER WU-SLP WU-ERR MSGS\n"); 477213443Sjchandra for (i = 0; i < 32; i++) { 478213443Sjchandra if ((xlr_hw_thread_mask & (1 << i)) == 0) 479213443Sjchandra continue; 480280013Sian sbuf_printf(&sb, "%2d: %8d %4d %8d %8d %8d\n", i, 481213443Sjchandra msgring_nintr[i/4], msgring_badintr[i/4], 482213443Sjchandra msgring_wakeup_sleep[i], msgring_wakeup_nosleep[i], 483213443Sjchandra msgring_nmsgs[i]); 484213443Sjchandra } 485280013Sian error = sbuf_finish(&sb); 486280013Sian sbuf_delete(&sb); 487213443Sjchandra return (error); 488213443Sjchandra} 489213443Sjchandra 490213443SjchandraSYSCTL_PROC(_debug, OID_AUTO, msgring, CTLTYPE_STRING | CTLFLAG_RD, 0, 0, 491213443Sjchandra sys_print_debug, "A", "msgring debug info"); 492