44#include <sys/resourcevar.h> 45#include <sys/sched.h> 46#include <sys/unistd.h> 47#include <sys/sysctl.h> 48#include <sys/malloc.h> 49 50#include <machine/reg.h> 51#include <machine/cpu.h> 52#include <machine/hwfunc.h> 53#include <machine/mips_opcode.h> 54 55#include <machine/param.h> 56#include <machine/intr_machdep.h> 57#include <mips/rmi/interrupt.h> 58#include <mips/rmi/msgring.h> 59#include <mips/rmi/pic.h> 60#include <mips/rmi/board.h> 61 62#define MSGRNG_CC_INIT_CPU_DEST(dest, counter) \ 63do { \ 64 msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][0], 0 ); \ 65 msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][1], 1 ); \ 66 msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][2], 2 ); \ 67 msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][3], 3 ); \ 68 msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][4], 4 ); \ 69 msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][5], 5 ); \ 70 msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][6], 6 ); \ 71 msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][7], 7 ); \ 72} while(0) 73 74 75/* 76 * Keep track of our message ring handler threads, each core has a 77 * different message station. Ideally we will need to start a few 78 * message handling threads every core, and wake them up depending on 79 * load 80 */ 81struct msgring_thread { 82 struct { 83 struct thread *thread; /* msgring handler threads */ 84 int needed; /* thread needs to wake up */ 85 } threads[XLR_NTHREADS]; 86 int running; /* number of threads running */ 87 int nthreads; /* number of threads started */ 88 struct mtx lock; /* for changing running/active */ 89}; 90static struct msgring_thread msgring_threads[XLR_MAX_CORES]; 91static struct proc *msgring_proc; /* all threads are under a proc */ 92 93/* 94 * The maximum number of software message handler threads to be started 95 * per core. Default is 3 per core 96 */ 97static int msgring_maxthreads = 3; 98TUNABLE_INT("hw.fmn.maxthreads", &msgring_maxthreads); 99 100/* 101 * The device drivers can register a handler for the messages sent 102 * from a station (corresponding to the device). 103 */ 104struct tx_stn_handler { 105 msgring_handler action; 106 void *arg; 107}; 108static struct tx_stn_handler msgmap[MSGRNG_NSTATIONS]; 109static struct mtx msgmap_lock; 110 111/* 112 * Initialize the messaging subsystem. 113 * 114 * Message Stations are shared among all threads in a cpu core, this 115 * has to be called once from every core which is online. 116 */ 117void 118xlr_msgring_cpu_init(void) 119{ 120 struct stn_cc *cc_config; 121 struct bucket_size *bucket_sizes; 122 uint32_t flags; 123 int id; 124 125 KASSERT(xlr_thr_id() == 0, 126 ("xlr_msgring_cpu_init from non-zero thread")); 127 id = xlr_core_id(); 128 bucket_sizes = xlr_board_info.bucket_sizes; 129 cc_config = xlr_board_info.credit_configs[id]; 130 131 flags = msgrng_access_enable(); 132 133 /* 134 * FMN messages are received in 8 buckets per core, set up 135 * the bucket sizes for each bucket 136 */ 137 msgrng_write_bucksize(0, bucket_sizes->bucket[id * 8 + 0]); 138 msgrng_write_bucksize(1, bucket_sizes->bucket[id * 8 + 1]); 139 msgrng_write_bucksize(2, bucket_sizes->bucket[id * 8 + 2]); 140 msgrng_write_bucksize(3, bucket_sizes->bucket[id * 8 + 3]); 141 msgrng_write_bucksize(4, bucket_sizes->bucket[id * 8 + 4]); 142 msgrng_write_bucksize(5, bucket_sizes->bucket[id * 8 + 5]); 143 msgrng_write_bucksize(6, bucket_sizes->bucket[id * 8 + 6]); 144 msgrng_write_bucksize(7, bucket_sizes->bucket[id * 8 + 7]); 145 146 /* 147 * For sending FMN messages, we need credits on the destination 148 * bucket. Program the credits this core has on the 128 possible 149 * destination buckets. 150 * We cannot use a loop here, because the first argument has 151 * to be a constant integer value. 152 */ 153 MSGRNG_CC_INIT_CPU_DEST(0, cc_config->counters); 154 MSGRNG_CC_INIT_CPU_DEST(1, cc_config->counters); 155 MSGRNG_CC_INIT_CPU_DEST(2, cc_config->counters); 156 MSGRNG_CC_INIT_CPU_DEST(3, cc_config->counters); 157 MSGRNG_CC_INIT_CPU_DEST(4, cc_config->counters); 158 MSGRNG_CC_INIT_CPU_DEST(5, cc_config->counters); 159 MSGRNG_CC_INIT_CPU_DEST(6, cc_config->counters); 160 MSGRNG_CC_INIT_CPU_DEST(7, cc_config->counters); 161 MSGRNG_CC_INIT_CPU_DEST(8, cc_config->counters); 162 MSGRNG_CC_INIT_CPU_DEST(9, cc_config->counters); 163 MSGRNG_CC_INIT_CPU_DEST(10, cc_config->counters); 164 MSGRNG_CC_INIT_CPU_DEST(11, cc_config->counters); 165 MSGRNG_CC_INIT_CPU_DEST(12, cc_config->counters); 166 MSGRNG_CC_INIT_CPU_DEST(13, cc_config->counters); 167 MSGRNG_CC_INIT_CPU_DEST(14, cc_config->counters); 168 MSGRNG_CC_INIT_CPU_DEST(15, cc_config->counters); 169 msgrng_restore(flags); 170} 171 172/* 173 * Boot time init, called only once 174 */ 175void 176xlr_msgring_config(void) 177{ 178 mtx_init(&msgmap_lock, "msgring", NULL, MTX_SPIN); 179 180 /* check value */ 181 if (msgring_maxthreads < 0 || msgring_maxthreads > XLR_NTHREADS) 182 msgring_maxthreads = XLR_NTHREADS; 183} 184 185/* 186 * Drain out max_messages for the buckets set in the bucket mask. 187 * Use max_messages = 0 to drain out all messages. 188 */ 189uint32_t 190xlr_msgring_handler(uint8_t bucket_mask, uint32_t max_messages) 191{ 192 int bucket = 0; 193 int size = 0, code = 0, rx_stid = 0; 194 struct msgrng_msg msg; 195 struct tx_stn_handler *he; 196 unsigned int status = 0; 197 unsigned long mflags; 198 uint32_t n_msgs; 199 uint32_t msgbuckets; 200 201 n_msgs = 0; 202 mflags = msgrng_access_enable(); 203 for (;;) { 204 msgbuckets = (~msgrng_read_status() >> 24) & bucket_mask; 205 206 /* all buckets empty, break */ 207 if (msgbuckets == 0) 208 break; 209 210 for (bucket = 0; bucket < 8; bucket++) { 211 if ((msgbuckets & (1 << bucket)) == 0) /* empty */ 212 continue; 213 214 status = message_receive(bucket, &size, &code, 215 &rx_stid, &msg); 216 if (status != 0) 217 continue; 218 n_msgs++; 219 he = &msgmap[rx_stid]; 220 if (he->action == NULL) { 221 printf("[%s]: No Handler for message from " 222 "stn_id=%d, bucket=%d, size=%d, msg0=%jx\n", 223 __func__, rx_stid, bucket, size, 224 (uintmax_t)msg.msg0); 225 } else { 226 msgrng_restore(mflags); 227 (*he->action)(bucket, size, code, rx_stid, 228 &msg, he->arg); 229 mflags = msgrng_access_enable(); 230 } 231 if (max_messages > 0 && n_msgs >= max_messages) 232 goto done; 233 } 234 } 235 236done: 237 msgrng_restore(mflags); 238 return (n_msgs); 239} 240 241/* 242 * XLR COP2 supports watermark interrupts based on the number of 243 * messages pending in all the buckets in the core. We increase 244 * the watermark until all the possible handler threads in the core 245 * are woken up. 246 */ 247static void 248msgrng_setconfig(int running, int nthr) 249{ 250 uint32_t config, mflags; 251 int watermark = 1; /* non zero needed */ 252 int wm_intr_value; 253 254 KASSERT(nthr >= 0 && nthr <= msgring_maxthreads, 255 ("Bad value of nthr %d", nthr)); 256 KASSERT(running <= nthr, ("Bad value of running %d", running)); 257 258 if (running == nthr) { 259 wm_intr_value = 0; 260 } else { 261 switch (running) { 262 case 0: break; /* keep default */ 263 case 1: 264 watermark = 32; break; 265 case 2: 266 watermark = 48; break; 267 case 3: 268 watermark = 56; break; 269 } 270 wm_intr_value = 0x2; /* set watermark enable interrupt */ 271 } 272 mflags = msgrng_access_enable(); 273 config = (watermark << 24) | (IRQ_MSGRING << 16) | (1 << 8) | 274 wm_intr_value; 275 /* clear pending interrupts, they will get re-raised if still valid */ 276 write_c0_eirr64(1ULL << IRQ_MSGRING); 277 msgrng_write_config(config); 278 msgrng_restore(mflags); 279} 280 281/* Debug counters */ 282static int msgring_nintr[XLR_MAX_CORES]; 283static int msgring_badintr[XLR_MAX_CORES]; 284static int msgring_wakeup_sleep[XLR_MAX_CORES * XLR_NTHREADS]; 285static int msgring_wakeup_nosleep[XLR_MAX_CORES * XLR_NTHREADS]; 286static int msgring_nmsgs[XLR_MAX_CORES * XLR_NTHREADS]; 287 288static int 289msgring_process_fast_intr(void *arg) 290{ 291 struct msgring_thread *mthd; 292 struct thread *td; 293 uint32_t mflags; 294 int core, nt; 295 296 core = xlr_core_id(); 297 mthd = &msgring_threads[core]; 298 msgring_nintr[core]++; 299 mtx_lock_spin(&mthd->lock); 300 nt = mthd->running; 301 if(nt >= mthd->nthreads) { 302 msgring_badintr[core]++; 303 mtx_unlock_spin(&mthd->lock); 304 return (FILTER_HANDLED); 305 } 306 307 td = mthd->threads[nt].thread; 308 mflags = msgrng_access_enable(); 309 310 /* default value with interrupts disabled */ 311 msgrng_write_config((1 << 24) | (IRQ_MSGRING << 16) | (1 << 8)); 312 /* clear pending interrupts */ 313 write_c0_eirr64(1ULL << IRQ_MSGRING); 314 msgrng_restore(mflags); 315 mtx_unlock_spin(&mthd->lock); 316 317 /* wake up the target thread */ 318 mthd->threads[nt].needed = 1; 319 thread_lock(td); 320 if (TD_AWAITING_INTR(td)) { 321 msgring_wakeup_sleep[core*4+nt]++; 322 TD_CLR_IWAIT(td); 323 sched_add(td, SRQ_INTR); 324 } else 325 msgring_wakeup_nosleep[core*4+nt]++; 326 thread_unlock(td); 327 return (FILTER_HANDLED); 328} 329 330static void 331msgring_process(void *arg) 332{ 333 struct msgring_thread *mthd; 334 struct thread *td; 335 int hwtid, tid, core; 336 int nmsgs; 337 338 hwtid = (intptr_t)arg; 339 core = hwtid / 4; 340 tid = hwtid % 4; 341 mthd = &msgring_threads[core]; 342 td = mthd->threads[tid].thread; 343 KASSERT(curthread == td, 344 ("Incorrect thread core %d, thread %d", core, hwtid)); 345 346 /* First bind this thread to the right CPU */ 347 thread_lock(td); 348 sched_bind(td, xlr_hwtid_to_cpuid[hwtid]); 349 thread_unlock(td); 350 351 mtx_lock_spin(&mthd->lock); 352 ++mthd->nthreads; /* Active thread count */ 353 mtx_unlock_spin(&mthd->lock); 354 355 /* start processing messages */ 356 for(;;) { 357 mtx_lock_spin(&mthd->lock); 358 ++mthd->running; 359 msgrng_setconfig(mthd->running, mthd->nthreads); 360 mtx_unlock_spin(&mthd->lock); 361 362 atomic_store_rel_int(&mthd->threads[tid].needed, 0); 363 nmsgs = xlr_msgring_handler(0xff, 0); 364 msgring_nmsgs[hwtid] += nmsgs; 365 366 mtx_lock_spin(&mthd->lock); 367 --mthd->running; 368 msgrng_setconfig(mthd->running, mthd->nthreads); 369 mtx_unlock_spin(&mthd->lock); 370 371 /* sleep */ 372 thread_lock(td); 373 if (mthd->threads[tid].needed) { 374 thread_unlock(td); 375 continue; 376 } 377 sched_class(td, PRI_ITHD); 378 TD_SET_IWAIT(td); 379 mi_switch(SW_VOL, NULL); 380 thread_unlock(td); 381 } 382} 383 384static void 385create_msgring_thread(int hwtid) 386{ 387 struct msgring_thread *mthd; 388 struct thread *td; 389 int tid, core; 390 int error; 391 392 core = hwtid / 4; 393 tid = hwtid % 4; 394 mthd = &msgring_threads[core]; 395 if (tid == 0) { 396 mtx_init(&mthd->lock, "msgrngcore", NULL, MTX_SPIN); 397 mthd->running = mthd->nthreads = 0; 398 } 399 error = kproc_kthread_add(msgring_process, (void *)(uintptr_t)hwtid, 400 &msgring_proc, &td, RFSTOPPED, 2, "msgrngproc", 401 "msgthr%d", hwtid); 402 if (error) 403 panic("kproc_kthread_add() failed with %d", error); 404 mthd->threads[tid].thread = td; 405 406 thread_lock(td); 407 sched_class(td, PRI_ITHD); 408 sched_add(td, SRQ_INTR); 409 thread_unlock(td); 410 CTR2(KTR_INTR, "%s: created %s", __func__, td->td_name); 411} 412 413int 414register_msgring_handler(int startb, int endb, msgring_handler action, 415 void *arg) 416{ 417 void *cookie; 418 int i; 419 static int msgring_int_enabled = 0; 420 421 KASSERT(startb >= 0 && startb <= endb && endb < MSGRNG_NSTATIONS, 422 ("Invalid value for for bucket range %d,%d", startb, endb)); 423 424 mtx_lock_spin(&msgmap_lock); 425 for (i = startb; i <= endb; i++) { 426 KASSERT(msgmap[i].action == NULL, 427 ("Bucket %d already used [action %p]", i, msgmap[i].action)); 428 msgmap[i].action = action; 429 msgmap[i].arg = arg; 430 } 431 mtx_unlock_spin(&msgmap_lock); 432 433 if (xlr_test_and_set(&msgring_int_enabled)) { 434 create_msgring_thread(0); 435 if (msgring_maxthreads > xlr_threads_per_core) 436 msgring_maxthreads = xlr_threads_per_core; 437 cpu_establish_hardintr("msgring", msgring_process_fast_intr, 438 NULL, NULL, IRQ_MSGRING, 439 INTR_TYPE_NET, &cookie); 440 } 441 return (0); 442} 443 444/* 445 * Start message ring processing threads on other CPUs, after SMP start 446 */ 447static void 448start_msgring_threads(void *arg) 449{ 450 int hwt, tid; 451 452 for (hwt = 1; hwt < XLR_MAX_CORES * XLR_NTHREADS; hwt++) { 453 if ((xlr_hw_thread_mask & (1 << hwt)) == 0) 454 continue; 455 tid = hwt % XLR_NTHREADS; 456 if (tid >= msgring_maxthreads) 457 continue; 458 create_msgring_thread(hwt); 459 } 460} 461 462SYSINIT(start_msgring_threads, SI_SUB_SMP, SI_ORDER_MIDDLE, 463 start_msgring_threads, NULL); 464 465/* 466 * DEBUG support, XXX: static buffer, not locked 467 */ 468static int 469sys_print_debug(SYSCTL_HANDLER_ARGS) 470{ 471 int error, nb, i, fs; 472 static char xprintb[4096], *buf; 473 474 buf = xprintb; 475 fs = sizeof(xprintb); 476 nb = snprintf(buf, fs, 477 "\nID INTR ER WU-SLP WU-ERR MSGS\n"); 478 buf += nb; 479 fs -= nb; 480 for (i = 0; i < 32; i++) { 481 if ((xlr_hw_thread_mask & (1 << i)) == 0) 482 continue; 483 nb = snprintf(buf, fs, 484 "%2d: %8d %4d %8d %8d %8d\n", i, 485 msgring_nintr[i/4], msgring_badintr[i/4], 486 msgring_wakeup_sleep[i], msgring_wakeup_nosleep[i], 487 msgring_nmsgs[i]); 488 buf += nb; 489 fs -= nb; 490 } 491 error = SYSCTL_OUT(req, xprintb, buf - xprintb); 492 return (error); 493} 494 495SYSCTL_PROC(_debug, OID_AUTO, msgring, CTLTYPE_STRING | CTLFLAG_RD, 0, 0, 496 sys_print_debug, "A", "msgring debug info");
|