Print this page
XXXX introduce drv_sectohz
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/sun4u/serengeti/io/sgsbbc_mailbox.c
+++ new/usr/src/uts/sun4u/serengeti/io/sgsbbc_mailbox.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 28 * Interface for Serengeti IOSRAM mailbox
29 29 * OS <-> SC communication protocol
30 30 */
31 31
32 32 #include <sys/types.h>
33 33 #include <sys/systm.h>
34 34 #include <sys/ddi.h>
35 35 #include <sys/sunddi.h>
36 36 #include <sys/kmem.h>
37 37 #include <sys/uadmin.h>
38 38 #include <sys/machsystm.h>
39 39 #include <sys/disp.h>
40 40 #include <sys/taskq.h>
41 41
42 42 #include <sys/sgevents.h>
43 43 #include <sys/sgsbbc_priv.h>
44 44 #include <sys/sgsbbc_iosram_priv.h>
45 45 #include <sys/sgsbbc_mailbox_priv.h>
46 46 #include <sys/plat_ecc_unum.h>
47 47 #include <sys/plat_ecc_dimm.h>
48 48 #include <sys/serengeti.h>
49 49 #include <sys/fm/util.h>
50 50 #include <sys/promif.h>
51 51 #include <sys/plat_datapath.h>
52 52
53 53 sbbc_mailbox_t *master_mbox = NULL;
54 54
55 55 /*
56 56 * Panic Shutdown event support
57 57 */
58 58 static kmutex_t panic_hdlr_lock;
59 59
60 60 /*
61 61 * The ID of the soft interrupt which triggers the bringing down of a Domain
62 62 * when a PANIC_SHUTDOWN event is received.
63 63 */
64 64 static ddi_softintr_t panic_softintr_id = 0;
65 65
66 66 static sg_panic_shutdown_t panic_payload;
67 67 static sbbc_msg_t panic_payload_msg;
68 68
69 69 /*
70 70 * A queue for making sure outgoing messages are in order as ScApp
71 71 * does not support interleaving messages.
72 72 */
73 73 static kcondvar_t outbox_queue;
74 74 static kmutex_t outbox_queue_lock;
75 75
76 76 /*
77 77 * Handle unsolicited capability message.
78 78 */
79 79 static plat_capability_data_t cap_payload;
80 80 static sbbc_msg_t cap_payload_msg;
81 81 static kmutex_t cap_msg_hdlr_lock;
82 82
83 83 /*
84 84 * Datapath error and fault messages arrive unsolicited. The message data
85 85 * is contained in a plat_datapath_info_t structure.
86 86 */
87 87 typedef struct {
88 88 uint8_t type; /* CDS, DX, CP */
89 89 uint8_t pad; /* for alignment */
90 90 uint16_t cpuid; /* Safari ID of base CPU */
91 91 uint32_t t_value; /* SERD timeout threshold (seconds) */
92 92 } plat_datapath_info_t;
93 93
94 94 /*
95 95 * Unsolicited datapath error messages are processed via a soft interrupt,
96 96 * triggered in unsolicited interrupt processing.
97 97 */
98 98 static ddi_softintr_t dp_softintr_id = 0;
99 99 static kmutex_t dp_hdlr_lock;
100 100
101 101 static plat_datapath_info_t dp_payload;
102 102 static sbbc_msg_t dp_payload_msg;
103 103
104 104 static char *dperrtype[] = {
105 105 DP_ERROR_CDS,
106 106 DP_ERROR_DX,
107 107 DP_ERROR_RP
108 108 };
109 109
110 110 /*
111 111 * Variable indicating if we are already processing requests.
112 112 * Setting this value must be protected by outbox_queue_lock.
113 113 */
114 114 static int outbox_busy = 0;
115 115
116 116 /*
117 117 * local stuff
118 118 */
119 119 static int sbbc_mbox_send_msg(sbbc_msg_t *, int, uint_t, time_t, clock_t);
120 120 static int sbbc_mbox_recv_msg();
121 121 static int mbox_write(struct sbbc_mbox_header *,
122 122 struct sbbc_fragment *, sbbc_msg_t *);
123 123 static int mbox_read(struct sbbc_mbox_header *, struct sbbc_fragment *,
124 124 sbbc_msg_t *);
125 125 static int mbox_has_free_space(struct sbbc_mbox_header *);
126 126 static void mbox_skip_next_msg(struct sbbc_mbox_header *);
127 127 static int mbox_read_header(uint32_t, struct sbbc_mbox_header *);
128 128 static void mbox_update_header(uint32_t, struct sbbc_mbox_header *);
129 129 static int mbox_read_frag(struct sbbc_mbox_header *, struct sbbc_fragment *);
130 130 static struct sbbc_msg_waiter *mbox_find_waiter(uint16_t, uint32_t);
131 131 static void wakeup_next(void);
132 132 static uint_t sbbc_panic_shutdown_handler(char *arg);
133 133 static uint_t sbbc_do_fast_shutdown(char *arg);
134 134 static void sbbc_mbox_post_reg(sbbc_softstate_t *softsp);
135 135 static uint_t cap_ecc_msg_handler(char *);
136 136 static uint_t sbbc_datapath_error_msg_handler(char *arg);
137 137 static uint_t sbbc_datapath_fault_msg_handler(char *arg);
138 138 static uint_t sbbc_dp_trans_event(char *arg);
139 139
140 140
141 141 /*
142 142 * Interrupt handlers
143 143 */
144 144 static int sbbc_mbox_msgin(void);
145 145 static int sbbc_mbox_msgout(void);
146 146 static int sbbc_mbox_spacein(void);
147 147 static int sbbc_mbox_spaceout(void);
148 148
149 149 /*
150 150 * ECC event mailbox message taskq and parameters
151 151 */
152 152 static taskq_t *sbbc_ecc_mbox_taskq = NULL;
153 153 static int sbbc_ecc_mbox_taskq_errs = 0;
154 154 static int sbbc_ecc_mbox_send_errs = 0;
155 155 static int sbbc_ecc_mbox_inval_errs = 0;
156 156 static int sbbc_ecc_mbox_other_errs = 0;
157 157 int sbbc_ecc_mbox_err_throttle = ECC_MBOX_TASKQ_ERR_THROTTLE;
158 158
159 159 /*
160 160 * Called when SBBC driver is loaded
161 161 * Initialise global mailbox stuff, etc
162 162 */
163 163 void
164 164 sbbc_mbox_init()
165 165 {
166 166 int i;
167 167
168 168 master_mbox = kmem_zalloc(sizeof (sbbc_mailbox_t), KM_NOSLEEP);
169 169 if (master_mbox == NULL) {
170 170 cmn_err(CE_PANIC, "Can't allocate memory for mailbox\n");
171 171 }
172 172
173 173 /*
174 174 * mutex'es for the wait-lists
175 175 */
176 176 for (i = 0; i < SBBC_MBOX_MSG_TYPES; i++) {
177 177 mutex_init(&master_mbox->mbox_wait_lock[i],
178 178 NULL, MUTEX_DEFAULT, NULL);
179 179 master_mbox->mbox_wait_list[i] = NULL;
180 180 }
181 181
182 182 for (i = 0; i < SBBC_MBOX_MSG_TYPES; i++)
183 183 master_mbox->intrs[i] = NULL;
184 184
185 185 /*
186 186 * Two mailbox channels SC -> OS , read-only
187 187 * OS -> SC, read/write
188 188 */
189 189 master_mbox->mbox_in = kmem_zalloc(sizeof (sbbc_mbox_t), KM_NOSLEEP);
190 190 if (master_mbox->mbox_in == NULL) {
191 191 cmn_err(CE_PANIC,
192 192 "Can't allocate memory for inbound mailbox\n");
193 193 }
194 194
195 195 master_mbox->mbox_out = kmem_zalloc(sizeof (sbbc_mbox_t), KM_NOSLEEP);
196 196 if (master_mbox->mbox_out == NULL) {
197 197 cmn_err(CE_PANIC,
198 198 "Can't allocate memory for outbound mailbox\n");
199 199 }
200 200
201 201 mutex_init(&master_mbox->mbox_in->mb_lock, NULL,
202 202 MUTEX_DEFAULT, NULL);
203 203 mutex_init(&master_mbox->mbox_out->mb_lock, NULL,
204 204 MUTEX_DEFAULT, NULL);
205 205
206 206 /*
207 207 * Add PANIC_SHUTDOWN Event mutex
208 208 */
209 209 mutex_init(&panic_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
210 210
211 211 /* Initialize datapath error message handler mutex */
212 212 mutex_init(&dp_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
213 213
214 214 /* Initialize capability message handler event mutex */
215 215 mutex_init(&cap_msg_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
216 216
217 217 /*
218 218 * NOT USED YET
219 219 */
220 220 master_mbox->mbox_in->mb_type =
221 221 master_mbox->mbox_out->mb_type = 0;
222 222
223 223 cv_init(&outbox_queue, NULL, CV_DEFAULT, NULL);
224 224 mutex_init(&outbox_queue_lock, NULL, MUTEX_DEFAULT, NULL);
225 225
226 226 }
227 227
228 228 /*
229 229 * called when the SBBC driver is unloaded
230 230 */
231 231 void
232 232 sbbc_mbox_fini()
233 233 {
234 234 int i;
235 235 int err;
236 236
237 237 /*
238 238 * destroy ECC event mailbox taskq
239 239 */
240 240 if (sbbc_ecc_mbox_taskq != NULL) {
241 241 taskq_destroy(sbbc_ecc_mbox_taskq);
242 242 sbbc_ecc_mbox_taskq = NULL;
243 243 sbbc_ecc_mbox_taskq_errs = 0;
244 244 }
245 245
246 246 /*
247 247 * unregister interrupts
248 248 */
249 249 (void) iosram_unreg_intr(SBBC_MAILBOX_IN);
250 250 (void) iosram_unreg_intr(SBBC_MAILBOX_IN);
251 251 (void) iosram_unreg_intr(SBBC_MAILBOX_SPACE_IN);
252 252 (void) iosram_unreg_intr(SBBC_MAILBOX_SPACE_OUT);
253 253
254 254 /*
255 255 * Remove Panic Shutdown and Datapath Error event support.
256 256 *
257 257 * NOTE: If we have not added the soft interrupt handlers for these
258 258 * then we know that we have not registered the event handlers either.
259 259 */
260 260 if (panic_softintr_id != 0) {
261 261 ddi_remove_softintr(panic_softintr_id);
262 262
263 263 err = sbbc_mbox_unreg_intr(MBOX_EVENT_PANIC_SHUTDOWN,
264 264 sbbc_panic_shutdown_handler);
265 265 if (err != 0) {
266 266 cmn_err(CE_WARN, "Failed to unreg Panic Shutdown "
267 267 "handler. Err=%d", err);
268 268 }
269 269 }
270 270 if (dp_softintr_id != 0) {
271 271 ddi_remove_softintr(dp_softintr_id);
272 272
273 273 err = sbbc_mbox_unreg_intr(MBOX_EVENT_DP_ERROR,
274 274 sbbc_datapath_error_msg_handler);
275 275 err |= sbbc_mbox_unreg_intr(MBOX_EVENT_DP_FAULT,
276 276 sbbc_datapath_fault_msg_handler);
277 277 if (err != 0) {
278 278 cmn_err(CE_WARN, "Failed to unreg Datapath Error "
279 279 "handler. Err=%d", err);
280 280 }
281 281 }
282 282
283 283 /*
284 284 * destroy all its mutex'es, lists etc
285 285 */
286 286
287 287 /*
288 288 * mutex'es for the wait-lists
289 289 */
290 290 for (i = 0; i < SBBC_MBOX_MSG_TYPES; i++) {
291 291 mutex_destroy(&master_mbox->mbox_wait_lock[i]);
292 292 }
293 293
294 294 mutex_destroy(&master_mbox->mbox_in->mb_lock);
295 295 mutex_destroy(&master_mbox->mbox_out->mb_lock);
296 296
297 297 mutex_destroy(&panic_hdlr_lock);
298 298 mutex_destroy(&dp_hdlr_lock);
299 299
300 300 kmem_free(master_mbox->mbox_in, sizeof (sbbc_mbox_t));
301 301 kmem_free(master_mbox->mbox_out, sizeof (sbbc_mbox_t));
302 302 kmem_free(master_mbox, sizeof (sbbc_mailbox_t));
303 303
304 304 cv_destroy(&outbox_queue);
305 305 mutex_destroy(&outbox_queue_lock);
306 306
307 307 err = sbbc_mbox_unreg_intr(INFO_MBOX, cap_ecc_msg_handler);
308 308 if (err != 0) {
309 309 cmn_err(CE_WARN, "Failed to unregister capability message "
310 310 "handler. Err=%d", err);
311 311 }
312 312
313 313 mutex_destroy(&cap_msg_hdlr_lock);
314 314 }
315 315
316 316 /*
317 317 * Update iosram_sbbc to the new softstate after a tunnel switch.
318 318 * Move software interrupts from the old dip to the new dip.
319 319 */
320 320 int
321 321 sbbc_mbox_switch(sbbc_softstate_t *softsp)
322 322 {
323 323 sbbc_intrs_t *intr;
324 324 int msg_type;
325 325 int rc = 0;
326 326 int err;
327 327
328 328 if (master_mbox == NULL)
329 329 return (ENXIO);
330 330
331 331 ASSERT(MUTEX_HELD(&master_iosram->iosram_lock));
332 332
333 333 for (msg_type = 0; msg_type < SBBC_MBOX_MSG_TYPES; msg_type++) {
334 334
335 335 for (intr = master_mbox->intrs[msg_type]; intr != NULL;
336 336 intr = intr->sbbc_intr_next) {
337 337
338 338 if (intr->sbbc_intr_id) {
339 339 ddi_remove_softintr(intr->sbbc_intr_id);
340 340
341 341 if (ddi_add_softintr(softsp->dip,
342 342 DDI_SOFTINT_HIGH,
343 343 &intr->sbbc_intr_id, NULL, NULL,
344 344 intr->sbbc_handler, intr->sbbc_arg)
345 345 != DDI_SUCCESS) {
346 346
347 347 cmn_err(CE_WARN,
348 348 "Can't add SBBC mailbox "
349 349 "softint for msg_type %x\n",
350 350 msg_type);
351 351 rc = ENXIO;
352 352 }
353 353 }
354 354 }
355 355 }
356 356
357 357 /*
358 358 * Add PANIC_SHUTDOWN Event handler
359 359 */
360 360 if (panic_softintr_id) {
361 361 ddi_remove_softintr(panic_softintr_id);
362 362
363 363 err = ddi_add_softintr(softsp->dip, DDI_SOFTINT_LOW,
364 364 &panic_softintr_id, NULL, NULL,
365 365 sbbc_do_fast_shutdown, NULL);
366 366
367 367 if (err != DDI_SUCCESS) {
368 368 cmn_err(CE_WARN, "Failed to register Panic "
369 369 "Shutdown handler. Err=%d", err);
370 370 (void) sbbc_mbox_unreg_intr(MBOX_EVENT_PANIC_SHUTDOWN,
371 371 sbbc_panic_shutdown_handler);
372 372 rc = ENXIO;
373 373 }
374 374
375 375 }
376 376 /*
377 377 * Add Datapath Error Event handler
378 378 */
379 379 if (dp_softintr_id) {
380 380 ddi_remove_softintr(dp_softintr_id);
381 381
382 382 err = ddi_add_softintr(softsp->dip, DDI_SOFTINT_LOW,
383 383 &dp_softintr_id, NULL, NULL,
384 384 sbbc_dp_trans_event, NULL);
385 385
386 386 if (err != DDI_SUCCESS) {
387 387 cmn_err(CE_WARN, "Failed to register Datapath "
388 388 "Error Event handler. Err=%d", err);
389 389 (void) sbbc_mbox_unreg_intr(MBOX_EVENT_DP_ERROR,
390 390 sbbc_datapath_error_msg_handler);
391 391 (void) sbbc_mbox_unreg_intr(MBOX_EVENT_DP_FAULT,
392 392 sbbc_datapath_fault_msg_handler);
393 393 rc = ENXIO;
394 394 }
395 395
396 396 }
397 397
398 398 return (rc);
399 399 }
400 400
401 401 /*
402 402 * Called when the IOSRAM tunnel is created for the 'chosen' node.
403 403 *
404 404 * Read the mailbox header from the IOSRAM
405 405 * tunnel[SBBC_MAILBOX_KEY]
406 406 * Register the mailbox interrupt handlers
407 407 * for messages in/space etc
408 408 */
409 409 int
410 410 sbbc_mbox_create(sbbc_softstate_t *softsp)
411 411 {
412 412 struct sbbc_mbox_header header;
413 413
414 414 int i;
415 415 int err;
416 416 int rc = 0;
417 417
418 418 /*
419 419 * This function should only be called once when
420 420 * the chosen node is initialized.
421 421 */
422 422 ASSERT(MUTEX_HELD(&chosen_lock));
423 423
424 424 if (master_mbox == NULL)
425 425 return (ENXIO);
426 426
427 427 /*
428 428 * read the header at offset 0
429 429 * check magic/version etc
430 430 */
431 431 if (rc = iosram_read(SBBC_MAILBOX_KEY, 0, (caddr_t)&header,
432 432 sizeof (struct sbbc_mbox_header))) {
433 433
434 434 return (rc);
435 435 }
436 436
437 437 /*
438 438 * add the interrupt handlers for the mailbox
439 439 * interrupts
440 440 */
441 441 for (i = 0; i < MBOX_INTRS; i++) {
442 442 sbbc_intrfunc_t intr_handler;
443 443 uint_t *state;
444 444 kmutex_t *lock;
445 445 uint32_t intr_num;
446 446
447 447 switch (i) {
448 448 case MBOX_MSGIN_INTR:
449 449 intr_handler = (sbbc_intrfunc_t)sbbc_mbox_msgin;
450 450 intr_num = SBBC_MAILBOX_IN;
451 451 break;
452 452 case MBOX_MSGOUT_INTR:
453 453 intr_handler = (sbbc_intrfunc_t)sbbc_mbox_msgout;
454 454 intr_num = SBBC_MAILBOX_OUT;
455 455 break;
456 456 case MBOX_SPACEIN_INTR:
457 457 intr_handler = (sbbc_intrfunc_t)sbbc_mbox_spacein;
458 458 intr_num = SBBC_MAILBOX_SPACE_IN;
459 459 break;
460 460 case MBOX_SPACEOUT_INTR:
461 461 intr_handler = (sbbc_intrfunc_t)sbbc_mbox_spaceout;
462 462 intr_num = SBBC_MAILBOX_SPACE_OUT;
463 463 break;
464 464 }
465 465 state = (uint_t *)&master_mbox->intr_state[i].mbox_intr_state;
466 466 lock = &master_mbox->intr_state[i].mbox_intr_lock;
467 467 if (iosram_reg_intr(intr_num, intr_handler, (caddr_t)NULL,
468 468 state, lock)) {
469 469
470 470 cmn_err(CE_WARN,
471 471 "Can't register Mailbox interrupts \n");
472 472 }
473 473 }
474 474
475 475 /*
476 476 * Add PANIC_SHUTDOWN Event handler
477 477 */
478 478 panic_payload_msg.msg_buf = (caddr_t)&panic_payload;
479 479 panic_payload_msg.msg_len = sizeof (panic_payload);
480 480
481 481 err = ddi_add_softintr(softsp->dip, DDI_SOFTINT_LOW, &panic_softintr_id,
482 482 NULL, NULL, sbbc_do_fast_shutdown, NULL);
483 483
484 484 if (err == DDI_SUCCESS) {
485 485 err = sbbc_mbox_reg_intr(MBOX_EVENT_PANIC_SHUTDOWN,
486 486 sbbc_panic_shutdown_handler, &panic_payload_msg,
487 487 NULL, &panic_hdlr_lock);
488 488 if (err != 0) {
489 489 cmn_err(CE_WARN, "Failed to register Panic "
490 490 "Shutdown handler. Err=%d", err);
491 491 }
492 492
493 493 } else {
494 494 cmn_err(CE_WARN, "Failed to add Panic Shutdown "
495 495 "softintr handler");
496 496 }
497 497
498 498 /*
499 499 * Add Unsolicited Datapath Error Events handler
500 500 */
501 501 dp_payload_msg.msg_buf = (caddr_t)&dp_payload;
502 502 dp_payload_msg.msg_len = sizeof (dp_payload);
503 503
504 504 err = ddi_add_softintr(softsp->dip, DDI_SOFTINT_LOW, &dp_softintr_id,
505 505 NULL, NULL, sbbc_dp_trans_event, NULL);
506 506
507 507 if (err == DDI_SUCCESS) {
508 508 err = sbbc_mbox_reg_intr(MBOX_EVENT_DP_ERROR,
509 509 sbbc_datapath_error_msg_handler, &dp_payload_msg,
510 510 NULL, &dp_hdlr_lock);
511 511 err |= sbbc_mbox_reg_intr(MBOX_EVENT_DP_FAULT,
512 512 sbbc_datapath_fault_msg_handler, &dp_payload_msg,
513 513 NULL, &dp_hdlr_lock);
514 514 if (err != 0) {
515 515 cmn_err(CE_WARN, "Failed to register Datapath "
516 516 "error handler. Err=%d", err);
517 517 }
518 518
519 519 } else {
520 520 cmn_err(CE_WARN, "Failed to add Datapath error "
521 521 "softintr handler");
522 522 }
523 523
524 524 /*
525 525 * Register an interrupt handler with the sgbbc driver for the
526 526 * unsolicited INFO_MBOX response for the capability bitmap.
527 527 * This message is expected whenever the SC is (re)booted or
528 528 * failed over.
529 529 */
530 530 cap_payload_msg.msg_buf = (caddr_t)&cap_payload;
531 531 cap_payload_msg.msg_len = sizeof (cap_payload);
532 532
533 533 err = sbbc_mbox_reg_intr(INFO_MBOX, cap_ecc_msg_handler,
534 534 &cap_payload_msg, NULL, &cap_msg_hdlr_lock);
535 535 if (err != 0) {
536 536 cmn_err(CE_WARN, "Failed to register capability message"
537 537 " handler with Err=%d", err);
538 538 }
539 539
540 540 /*
541 541 * Now is the opportunity to register
542 542 * the deferred mbox intrs.
543 543 */
544 544 sbbc_mbox_post_reg(softsp);
545 545
546 546 return (rc);
547 547 }
548 548
549 549 /*
550 550 * Called when chosen IOSRAM is initialized
551 551 * to register the deferred mbox intrs.
552 552 */
553 553 static void
554 554 sbbc_mbox_post_reg(sbbc_softstate_t *softsp)
555 555 {
556 556 uint32_t msg_type;
557 557 sbbc_intrs_t *intr;
558 558
559 559 ASSERT(master_mbox);
560 560 for (msg_type = 0; msg_type < SBBC_MBOX_MSG_TYPES; msg_type++) {
561 561 intr = master_mbox->intrs[msg_type];
562 562 while (intr != NULL) {
563 563 if (!intr->registered) {
564 564 SGSBBC_DBG_INTR(CE_CONT, "sbbc_mbox_post_reg: "
565 565 "postreg for msgtype=%x\n", msg_type);
566 566 if (ddi_add_softintr(softsp->dip,
567 567 DDI_SOFTINT_HIGH, &intr->sbbc_intr_id,
568 568 NULL, NULL, intr->sbbc_handler,
569 569 (caddr_t)intr->sbbc_arg)
570 570 != DDI_SUCCESS) {
571 571 cmn_err(CE_WARN, "Can't add SBBC "
572 572 "deferred mailbox softint \n");
573 573 } else
574 574 intr->registered = 1;
575 575 }
576 576 intr = intr->sbbc_intr_next;
577 577 }
578 578 }
579 579 }
580 580
581 581 /*
582 582 * Register a handler for a message type
583 583 * NB NB NB
584 584 * arg must be either NULL or the address of a sbbc_fragment
585 585 * pointer
586 586 */
587 587 int
588 588 sbbc_mbox_reg_intr(uint32_t msg_type, sbbc_intrfunc_t intr_handler,
589 589 sbbc_msg_t *arg, uint_t *state, kmutex_t *lock)
590 590 {
591 591 sbbc_intrs_t *intr, *previntr;
592 592 int rc = 0;
593 593
594 594 /*
595 595 * Validate arguments
596 596 */
597 597 if (msg_type >= SBBC_MBOX_MSG_TYPES)
598 598 return (EINVAL);
599 599
600 600 /*
601 601 * Verify that we have already set up the master sbbc
602 602 */
603 603 if (master_iosram == NULL || master_mbox == NULL)
604 604 return (ENXIO);
605 605
606 606 mutex_enter(&master_iosram->iosram_lock);
607 607 msg_type &= SBBC_MSG_TYPE_MASK;
608 608 previntr = intr = master_mbox->intrs[msg_type];
609 609
610 610 /* Find the end of the link list */
611 611 while (intr != NULL && intr->sbbc_handler != intr_handler) {
612 612
613 613 previntr = intr;
614 614 intr = intr->sbbc_intr_next;
615 615 }
616 616
617 617 /* Return if the handler has been registered */
618 618 if (intr != NULL) {
619 619 mutex_exit(&master_iosram->iosram_lock);
620 620 return (EBUSY);
621 621 }
622 622
623 623 /*
624 624 * The requested handler has not been installed.
625 625 * Allocate some memory.
626 626 */
627 627 intr = kmem_zalloc(sizeof (sbbc_intrs_t), KM_SLEEP);
628 628
629 629 intr->sbbc_handler = intr_handler;
630 630 intr->sbbc_arg = (caddr_t)arg;
631 631 intr->sbbc_intr_state = state;
632 632 intr->sbbc_intr_lock = lock;
633 633 intr->sbbc_intr_next = NULL;
634 634 /* not registered yet */
635 635 intr->registered = 0;
636 636
637 637 if (previntr != NULL)
638 638 previntr->sbbc_intr_next = intr;
639 639 else
640 640 master_mbox->intrs[msg_type] = intr;
641 641
642 642 /*
643 643 * register only if the chosen IOSRAM is
644 644 * initialized, otherwise defer the registration
645 645 * until IOSRAM initialization.
646 646 */
647 647 if (master_iosram->iosram_sbbc) {
648 648 if (ddi_add_softintr(master_iosram->iosram_sbbc->dip,
649 649 DDI_SOFTINT_HIGH,
650 650 &intr->sbbc_intr_id, NULL, NULL,
651 651 intr_handler, (caddr_t)arg) != DDI_SUCCESS) {
652 652 cmn_err(CE_WARN, "Can't add SBBC mailbox softint \n");
653 653 rc = ENXIO;
654 654 } else
655 655 intr->registered = 1;
656 656 } else {
657 657 SGSBBC_DBG_INTR(CE_CONT, "sbbc_mbox_reg_intr: "
658 658 "deferring msg=%x registration\n", msg_type);
659 659 }
660 660
661 661 mutex_exit(&master_iosram->iosram_lock);
662 662
663 663 return (rc);
664 664 }
665 665
666 666 /*
667 667 * Unregister a handler for a message type
668 668 */
669 669 int
670 670 sbbc_mbox_unreg_intr(uint32_t msg_type, sbbc_intrfunc_t intr_handler)
671 671 {
672 672 sbbc_intrs_t *intr, *previntr, *nextintr;
673 673
674 674 /*
675 675 * Verify that we have already set up the master sbbc
676 676 */
677 677 if (master_iosram == NULL || master_mbox == NULL)
678 678 return (ENXIO);
679 679
680 680 msg_type &= SBBC_MSG_TYPE_MASK;
681 681
682 682 if (msg_type >= SBBC_MBOX_MSG_TYPES ||
683 683 intr_handler == (sbbc_intrfunc_t)NULL) {
684 684
685 685 return (EINVAL);
686 686 }
687 687
688 688 mutex_enter(&master_iosram->iosram_lock);
689 689
690 690 previntr = intr = master_mbox->intrs[msg_type];
691 691
692 692 /*
693 693 * No handlers installed
694 694 */
695 695 if (intr == NULL) {
696 696 mutex_exit(&master_iosram->iosram_lock);
697 697 return (EINVAL);
698 698 }
699 699
700 700 while (intr != NULL) {
701 701
702 702 /* Save the next pointer */
703 703 nextintr = intr->sbbc_intr_next;
704 704
705 705 /* Found a match. Remove it from the link list */
706 706 if (intr->sbbc_handler == intr_handler) {
707 707
708 708 if (intr->sbbc_intr_id)
709 709 ddi_remove_softintr(intr->sbbc_intr_id);
710 710
711 711 kmem_free(intr, sizeof (sbbc_intrs_t));
712 712
713 713 if (previntr != master_mbox->intrs[msg_type])
714 714 previntr->sbbc_intr_next = nextintr;
715 715 else
716 716 master_mbox->intrs[msg_type] = nextintr;
717 717
718 718 break;
719 719 }
720 720
721 721 /* update pointers */
722 722 previntr = intr;
723 723 intr = nextintr;
724 724 }
725 725
726 726 mutex_exit(&master_iosram->iosram_lock);
727 727
728 728 return (0);
729 729 }
730 730 /*
731 731 * Interrupt handlers - one for each mailbox
732 732 * interrupt type
733 733 */
734 734
735 735 /*
736 736 * mailbox message received
737 737 */
738 738 static int
739 739 sbbc_mbox_msgin()
740 740 {
741 741 mutex_enter(&master_mbox->intr_state[MBOX_MSGIN_INTR].mbox_intr_lock);
742 742 master_mbox->intr_state[MBOX_MSGIN_INTR].mbox_intr_state =
743 743 SBBC_INTR_RUNNING;
744 744 mutex_exit(&master_mbox->intr_state[MBOX_MSGIN_INTR].mbox_intr_lock);
745 745
746 746 /*
747 747 * We are only locking the InBox here, not the whole
748 748 * mailbox. This is based on the assumption of
749 749 * complete separation of mailboxes - outbox is
750 750 * read/write, inbox is read-only.
751 751 * We only ever update the producer for the
752 752 * outbox and the consumer for the inbox.
753 753 */
754 754 mutex_enter(&master_mbox->mbox_in->mb_lock);
755 755
756 756 for (;;) {
757 757 /*
758 758 * Get as many incoming messages as possible
759 759 */
760 760 while (sbbc_mbox_recv_msg() == 0)
761 761 /* empty */;
762 762
763 763 /*
764 764 * send interrupt to SC to let it know that
765 765 * space is available over here
766 766 */
767 767 (void) iosram_send_intr(SBBC_MAILBOX_SPACE_IN);
768 768
769 769 mutex_enter(&master_mbox->intr_state[MBOX_MSGIN_INTR].
770 770 mbox_intr_lock);
771 771 /*
772 772 * Read the inbox one more time to see if new messages
773 773 * has come in after we exit the loop.
774 774 */
775 775 if (sbbc_mbox_recv_msg() == 0) {
776 776 mutex_exit(&master_mbox->intr_state[MBOX_MSGIN_INTR].
777 777 mbox_intr_lock);
778 778 } else {
779 779 master_mbox->intr_state[MBOX_MSGIN_INTR].
780 780 mbox_intr_state = SBBC_INTR_IDLE;
781 781 mutex_exit(&master_mbox->intr_state[MBOX_MSGIN_INTR].
782 782 mbox_intr_lock);
783 783 break;
784 784 }
785 785 }
786 786
787 787 mutex_exit(&master_mbox->mbox_in->mb_lock);
788 788
789 789 return (DDI_INTR_CLAIMED);
790 790 }
791 791
792 792 /*
793 793 * mailbox message sent
794 794 */
795 795 static int
796 796 sbbc_mbox_msgout()
797 797 {
798 798 /*
799 799 * Should never get this
800 800 */
801 801
802 802 return (DDI_INTR_CLAIMED);
803 803 }
804 804
805 805 /*
806 806 * space in the inbox
807 807 */
808 808 static int
809 809 sbbc_mbox_spacein()
810 810 {
811 811 /*
812 812 * Should never get this
813 813 */
814 814
815 815 return (DDI_INTR_CLAIMED);
816 816 }
817 817
818 818 /*
819 819 * space in the outbox
820 820 */
821 821 static int
822 822 sbbc_mbox_spaceout()
823 823 {
824 824 /*
825 825 * cv_broadcast() the threads waiting on the
826 826 * outbox's mb_full
827 827 */
828 828
829 829 mutex_enter(&master_mbox->mbox_out->mb_lock);
830 830
831 831 cv_broadcast(&master_mbox->mbox_out->mb_full);
832 832
833 833 mutex_exit(&master_mbox->mbox_out->mb_lock);
834 834
835 835 return (DDI_INTR_CLAIMED);
836 836 }
837 837
838 838 /*
839 839 * Client Interface
840 840 *
841 841 * The main interface will be
842 842 *
843 843 * sbbc_mbox_request_response(sbbc_msg_t *request,
844 844 * sbbc_msg_t *response, time_t wait_time)
845 845 *
846 846 * 1) the client calls request_response
847 847 * 2) a new unique msg ID is assigned for that msg
848 848 * 3) if there is space available in the outbox
849 849 * - the request msg is written to the mbox_out mailbox
850 850 * and the mailbox info updated.
851 851 * - allocate a sbbc_msg_waiter struct for this
852 852 * message, initialise the w_cv condvar.
853 853 * - get the mailbox mbox_wait_lock mutex for this
854 854 * message type
855 855 * - the response msg is put on the mbox_wait_list for
856 856 * that message type to await the SC's response
857 857 * - wait on the w_cv condvar protected by the
858 858 * mbox_wait_lock
859 859 * - SBBC_MAILBOX_OUT interrupt is sent to the SC
860 860 *
861 861 * 4) if no space in the outbox,
862 862 * - the request message blocks waiting
863 863 * for a SBBC_MAILBOX_SPACE_OUT interrupt
864 864 * It will block on the mailbox mb_full condvar.
865 865 * - go to (3) above
866 866 * 5) When we get a SBBC_MAILBOX_IN interrupt.
867 867 * - read the message ID of the next message (FIFO)
868 868 * - find that ID on the wait list
869 869 * - no wait list entry => unsolicited message. If theres
870 870 * a handler, trigger it
871 871 * - if someone is waiting, read the message in from
872 872 * SRAM, handling fragmentation, wraparound, etc
873 873 * - if the whole message has been read, signal
874 874 * the waiter
875 875 * - read next message until mailbox empty
876 876 * - send SBBC_MAILBOX_SPACE_IN interrupt to the SC
877 877 *
878 878 * 6) If a response is required and none is received, the client
879 879 * will timeout after <wait_time> seconds and the message
880 880 * status will be set to ETIMEDOUT.
881 881 */
882 882 int
883 883 sbbc_mbox_request_response(sbbc_msg_t *request,
884 884 sbbc_msg_t *response, time_t wait_time)
885 885 {
886 886
887 887 struct sbbc_msg_waiter *waiter;
888 888 uint_t msg_id;
889 889 int rc = 0;
890 890 int flags;
891 891 uint16_t msg_type;
892 892 clock_t stop_time;
893 893 clock_t clockleft;
894 894 kmutex_t *mbox_wait_lock;
895 895 kmutex_t *mb_lock;
896 896 static fn_t f = "sbbc_mbox_request_response";
897 897
898 898 if ((request == NULL) ||
899 899 (request->msg_type.type >= SBBC_MBOX_MSG_TYPES) ||
900 900 ((response != NULL) &&
901 901 (response->msg_type.type >= SBBC_MBOX_MSG_TYPES)))
902 902 return (EINVAL);
903 903
904 904 msg_type = request->msg_type.type;
905 905
906 906 /*
907 907 * Verify that we have already set up the master sbbc
908 908 */
909 909 if (master_mbox == NULL)
910 910 return (ENXIO);
911 911 mbox_wait_lock = &master_mbox->mbox_wait_lock[msg_type];
912 912
↓ open down ↓ |
912 lines elided |
↑ open up ↑ |
913 913 flags = WAIT_FOR_REPLY|WAIT_FOR_SPACE;
914 914
915 915 /*
916 916 * We want to place a lower limit on the shortest amount of time we
917 917 * will wait before timing out while communicating with the SC via
918 918 * the mailbox.
919 919 */
920 920 if (wait_time < sbbc_mbox_min_timeout)
921 921 wait_time = sbbc_mbox_default_timeout;
922 922
923 - stop_time = ddi_get_lbolt() + wait_time * drv_usectohz(MICROSEC);
923 + stop_time = ddi_get_lbolt() + drv_sectohz(wait_time);
924 924
925 925 /*
926 926 * If there is a message being processed, sleep until it is our turn.
927 927 */
928 928 mutex_enter(&outbox_queue_lock);
929 929
930 930 /*
931 931 * allocate an ID for this message, let it wrap
932 932 * around transparently.
933 933 * msg_id == 0 is unsolicited message
934 934 */
935 935 msg_id = ++(master_mbox->mbox_msg_id);
936 936 if (msg_id == 0)
937 937 msg_id = ++(master_mbox->mbox_msg_id);
938 938
939 939 SGSBBC_DBG_MBOX("%s: msg_id = 0x%x, msg_len = 0x%x\n",
940 940 f, msg_id, request->msg_len);
941 941
942 942 /*
943 943 * A new message can actually grab the lock before the thread
944 944 * that has just been signaled. Therefore, we need to double
945 945 * check to make sure that outbox_busy is not already set
946 946 * after we wake up.
947 947 *
948 948 * Potentially this could mean starvation for certain unfortunate
949 949 * threads that keep getting woken up and putting back to sleep.
950 950 * But the window of such contention is very small to begin with.
951 951 */
952 952 while (outbox_busy) {
953 953
954 954 clockleft = cv_timedwait(&outbox_queue, &outbox_queue_lock,
955 955 stop_time);
956 956
957 957 SGSBBC_DBG_MBOX("%s: msg_id = 0x%x is woken up\n", f, msg_id);
958 958
959 959 /*
960 960 * If we have timed out, set status to ETIMEOUT and return.
961 961 */
962 962 if (clockleft < 0) {
963 963 SGSBBC_DBG_MBOX("%s: msg_id = 0x%x has timed out\n",
964 964 f, msg_id);
965 965 cmn_err(CE_NOTE,
966 966 "Timed out obtaining SBBC outbox lock");
967 967 request->msg_status = ETIMEDOUT;
968 968 if (response != NULL)
969 969 response->msg_status = ETIMEDOUT;
970 970 mutex_exit(&outbox_queue_lock);
971 971 return (ETIMEDOUT);
972 972 }
973 973 }
974 974
975 975 outbox_busy = 1;
976 976 mutex_exit(&outbox_queue_lock);
977 977
978 978 /*
979 979 * We are only locking the OutBox from here, not the whole
980 980 * mailbox. This is based on the assumption of
981 981 * complete separation of mailboxes - outbox is
982 982 * read/write, inbox is read-only.
983 983 * We only ever update the producer for the
984 984 * outbox and the consumer for the inbox.
985 985 */
986 986 mb_lock = &master_mbox->mbox_out->mb_lock;
987 987 mutex_enter(mb_lock);
988 988
989 989 /*
990 990 * No response expected ? Just send the message and return
991 991 */
992 992 if (response == NULL) {
993 993 rc = sbbc_mbox_send_msg(request, flags, msg_id, wait_time,
994 994 stop_time);
995 995 SGSBBC_DBG_MBOX("%s: msg_id = 0x%x send rc = %d\n",
996 996 f, msg_id, rc);
997 997
998 998 wakeup_next();
999 999
1000 1000 mutex_exit(mb_lock);
1001 1001 request->msg_status = rc;
1002 1002 return (rc);
1003 1003 }
1004 1004
1005 1005 /*
1006 1006 * allocate/initialise a waiter
1007 1007 */
1008 1008 waiter = kmem_zalloc(sizeof (struct sbbc_msg_waiter), KM_NOSLEEP);
1009 1009
1010 1010 if (waiter == (struct sbbc_msg_waiter *)NULL) {
1011 1011 cmn_err(CE_WARN, "SBBC Mailbox can't allocate waiter\n");
1012 1012
1013 1013 wakeup_next();
1014 1014
1015 1015 mutex_exit(mb_lock);
1016 1016 return (ENOMEM);
1017 1017 }
1018 1018
1019 1019 waiter->w_id = 0; /* Until we get an ID from the send */
1020 1020 waiter->w_msg = response;
1021 1021 waiter->w_msg->msg_status = EINPROGRESS;
1022 1022
1023 1023 cv_init(&waiter->w_cv, NULL, CV_DEFAULT, NULL);
1024 1024
1025 1025 rc = sbbc_mbox_send_msg(request, flags, msg_id, wait_time, stop_time);
1026 1026
1027 1027 wakeup_next();
1028 1028
1029 1029 if (rc != 0) {
1030 1030
1031 1031 request->msg_status = response->msg_status = rc;
1032 1032 mutex_exit(mb_lock);
1033 1033
1034 1034 /* Free the waiter */
1035 1035 cv_destroy(&waiter->w_cv);
1036 1036 kmem_free(waiter, sizeof (struct sbbc_msg_waiter));
1037 1037
1038 1038 SGSBBC_DBG_MBOX("%s: msg_id = 0x%x send rc = %d\n",
1039 1039 f, msg_id, rc);
1040 1040
1041 1041 return (rc);
1042 1042 }
1043 1043
1044 1044 waiter->w_id = msg_id;
1045 1045
1046 1046 /*
1047 1047 * Lock this waiter list and add the waiter
1048 1048 */
1049 1049 mutex_enter(mbox_wait_lock);
1050 1050
1051 1051 if (master_mbox->mbox_wait_list[msg_type] == NULL) {
1052 1052 master_mbox->mbox_wait_list[msg_type] = waiter;
1053 1053 waiter->w_next = NULL;
1054 1054 } else {
1055 1055 struct sbbc_msg_waiter *tmp;
1056 1056 tmp = master_mbox->mbox_wait_list[msg_type];
1057 1057 master_mbox->mbox_wait_list[msg_type] = waiter;
1058 1058 waiter->w_next = tmp;
1059 1059 }
1060 1060
1061 1061 mutex_exit(mb_lock);
1062 1062
1063 1063 /*
1064 1064 * wait here for a response to our message
1065 1065 * holding the mbox_wait_lock for the list ensures
1066 1066 * that the interrupt handler can't get in before
1067 1067 * we block.
1068 1068 * NOTE: We use the request msg_type for the
1069 1069 * the wait_list. This ensures that the
1070 1070 * msg_type won't change.
1071 1071 */
1072 1072 clockleft = cv_timedwait(&waiter->w_cv, mbox_wait_lock, stop_time);
1073 1073
1074 1074 SGSBBC_DBG_MBOX("%s: msg_id = 0x%x is woken up for response\n",
1075 1075 f, msg_id);
1076 1076
1077 1077 /*
1078 1078 * If we have timed out, set msg_status to ETIMEDOUT,
1079 1079 * and remove the waiter from the waiter list.
1080 1080 */
1081 1081 if (clockleft < 0) {
1082 1082 /*
1083 1083 * Remove the waiter from the waiter list.
1084 1084 * If we can't find the waiter in the list,
1085 1085 * 1. msg_status == EINPROGRESS
1086 1086 * It is being processed. We will give it
1087 1087 * a chance to finish.
1088 1088 * 2. msg_status != EINPROGRESS
1089 1089 * It is done processing. We can safely
1090 1090 * remove it.
1091 1091 * If we can find the waiter, it has timed out.
1092 1092 */
1093 1093 SGSBBC_DBG_MBOX("%s: msg_id = 0x%x has timed out\n",
1094 1094 f, msg_id);
1095 1095 if (mbox_find_waiter(msg_type, msg_id) == NULL) {
1096 1096 if (waiter->w_msg->msg_status == EINPROGRESS) {
1097 1097 SGSBBC_DBG_MBOX("%s: Waiting for msg_id = 0x%x "
1098 1098 "complete.\n", f, msg_id);
1099 1099 cv_wait(&waiter->w_cv, mbox_wait_lock);
1100 1100 }
1101 1101 } else {
1102 1102 SGSBBC_DBG_MBOX("%s: setting msg_id = 0x%x "
1103 1103 "to ETIMEDOUT\n", f, msg_id);
1104 1104 cmn_err(CE_NOTE, "Timed out waiting for SC response");
1105 1105 rc = waiter->w_msg->msg_status = ETIMEDOUT;
1106 1106 }
1107 1107 }
1108 1108
1109 1109 /*
1110 1110 * lose the waiter
1111 1111 */
1112 1112 cv_destroy(&waiter->w_cv);
1113 1113 kmem_free(waiter, sizeof (struct sbbc_msg_waiter));
1114 1114
1115 1115 mutex_exit(mbox_wait_lock);
1116 1116
1117 1117 return (rc);
1118 1118
1119 1119 }
1120 1120
1121 1121 static void
1122 1122 wakeup_next()
1123 1123 {
1124 1124 /*
1125 1125 * Done sending the current message or encounter an error.
1126 1126 * Wake up the one request in the outbox_queue.
1127 1127 */
1128 1128 mutex_enter(&outbox_queue_lock);
1129 1129 outbox_busy = 0;
1130 1130 cv_signal(&outbox_queue);
1131 1131 mutex_exit(&outbox_queue_lock);
1132 1132 }
1133 1133
1134 1134
1135 1135 /* ARGSUSED */
1136 1136 int
1137 1137 sbbc_mbox_send_msg(sbbc_msg_t *msg, int flags, uint_t msg_id,
1138 1138 time_t wait_time, clock_t stop_time)
1139 1139 {
1140 1140 struct sbbc_mbox_header header;
1141 1141 struct sbbc_fragment frag;
1142 1142 int rc = 0;
1143 1143 int bytes_written;
1144 1144 uint32_t intr_enabled;
1145 1145 clock_t clockleft;
1146 1146 static fn_t f = "sbbc_mbox_send_msg";
1147 1147
1148 1148 /*
1149 1149 * First check that the SC has enabled its mailbox
1150 1150 */
1151 1151 rc = iosram_read(SBBC_INTR_SC_ENABLED_KEY, 0,
1152 1152 (caddr_t)&intr_enabled, sizeof (intr_enabled));
1153 1153
1154 1154 if (rc)
1155 1155 return (rc);
1156 1156
1157 1157 if (!(intr_enabled & SBBC_MAILBOX_OUT))
1158 1158 return (ENOTSUP);
1159 1159
1160 1160 /*
1161 1161 * read the mailbox header
1162 1162 */
1163 1163 if (rc = mbox_read_header(SBBC_OUTBOX, &header))
1164 1164 return (rc);
1165 1165
1166 1166 /*
1167 1167 * Allocate/initialise a fragment for this message
1168 1168 */
1169 1169 frag.f_id = msg_id;
1170 1170 frag.f_type = msg->msg_type;
1171 1171 frag.f_status = 0;
1172 1172 frag.f_total_len = msg->msg_len;
1173 1173 frag.f_frag_offset = 0;
1174 1174 /*
1175 1175 * Throw in the message data
1176 1176 */
1177 1177 bcopy(&msg->msg_data, &frag.f_data, sizeof (msg->msg_data));
1178 1178
1179 1179 /*
1180 1180 * If not enough space is available
1181 1181 * write what we can and wait for
1182 1182 * an interrupt to tell us that more
1183 1183 * space is available
1184 1184 */
1185 1185
1186 1186 bytes_written = 0;
1187 1187 do {
1188 1188 rc = mbox_write(&header, &frag, msg);
1189 1189
1190 1190 if (rc != 0 && rc != ENOSPC) {
1191 1191 return (rc);
1192 1192 }
1193 1193
1194 1194 if (rc == 0) {
1195 1195 /*
1196 1196 * Always tell the SC when there is a message.
1197 1197 * Ignore returned value as not being able to
1198 1198 * signal the SC about space available does
1199 1199 * not stop the SC from processing input.
1200 1200 */
1201 1201 (void) iosram_send_intr(SBBC_MAILBOX_OUT);
1202 1202 }
1203 1203
1204 1204 bytes_written += frag.f_frag_len;
1205 1205 frag.f_frag_offset += frag.f_frag_len;
1206 1206 if ((bytes_written < msg->msg_len) || (rc == ENOSPC)) {
1207 1207
1208 1208 if (mbox_has_free_space(&header) <=
1209 1209 sizeof (struct sbbc_fragment)) {
1210 1210
1211 1211 int tmprc;
1212 1212
1213 1213 clockleft = cv_timedwait(
1214 1214 &master_mbox->mbox_out->mb_full,
1215 1215 &master_mbox->mbox_out->mb_lock,
1216 1216 stop_time);
1217 1217
1218 1218 /* Return ETIMEDOUT if we timed out */
1219 1219 if (clockleft < 0) {
1220 1220 SGSBBC_DBG_MBOX("%s: msg_id = 0x%x "
1221 1221 "has timed out\n", f, msg_id);
1222 1222 cmn_err(CE_NOTE,
1223 1223 "Timed out sending message "
1224 1224 "to SC");
1225 1225 return (ETIMEDOUT);
1226 1226 }
1227 1227
1228 1228 /* Read updated header from IOSRAM */
1229 1229 if (tmprc = mbox_read_header(SBBC_OUTBOX,
1230 1230 &header)) {
1231 1231
1232 1232 return (tmprc);
1233 1233 }
1234 1234 }
1235 1235 }
1236 1236
1237 1237 SGSBBC_DBG_MBOX("%s: msg_id = 0x%x, bytes_written = 0x%x, "
1238 1238 "msg_len = 0x%x\n", f,
1239 1239 msg_id, bytes_written, msg->msg_len);
1240 1240 } while ((bytes_written < msg->msg_len) || (rc == ENOSPC));
1241 1241
1242 1242 /*
1243 1243 * this could be a spurious interrupt
1244 1244 * as the SC may be merrily readings its
1245 1245 * mail even as send, but what can you do ? No
1246 1246 * synchronization method between SC <-> OS
1247 1247 * SRAM data eaters means that this is inevitable.
1248 1248 * It would take a bigger brain to fix this.
1249 1249 *
1250 1250 */
1251 1251 (void) iosram_send_intr(SBBC_MAILBOX_OUT);
1252 1252
1253 1253 return (rc);
1254 1254 }
1255 1255
1256 1256
1257 1257 /*
1258 1258 * get next message
1259 1259 * Read the next message from SRAM
1260 1260 * Check if theres an entry on the wait queue
1261 1261 * for this message
1262 1262 * If yes, read the message in and signal
1263 1263 * the waiter (if all the message has been received)
1264 1264 * No, its unsolicited, if theres a handler installed for
1265 1265 * this message type trigger it, otherwise toss
1266 1266 * the message
1267 1267 */
1268 1268 int
1269 1269 sbbc_mbox_recv_msg()
1270 1270 {
1271 1271 struct sbbc_mbox_header header;
1272 1272 struct sbbc_fragment frag;
1273 1273 sbbc_msg_t tmpmsg; /* Temporary msg storage */
1274 1274 int rc = 0, i, first_hdlr, last_hdlr;
1275 1275 uint32_t intr_enabled;
1276 1276 sbbc_intrs_t *intr;
1277 1277 struct sbbc_msg_waiter *waiter;
1278 1278 uint16_t type; /* frag.f_type.type */
1279 1279 uint32_t f_id; /* frag.f_id */
1280 1280 uint32_t f_frag_offset, f_frag_len;
1281 1281 kmutex_t *mbox_wait_lock;
1282 1282 static fn_t f = "sbbc_mbox_recv_msg";
1283 1283
1284 1284 /*
1285 1285 * First check that the OS has enabled its mailbox
1286 1286 */
1287 1287 rc = iosram_read(SBBC_SC_INTR_ENABLED_KEY, 0,
1288 1288 (caddr_t)&intr_enabled, sizeof (intr_enabled));
1289 1289
1290 1290 if (rc) {
1291 1291 return (rc);
1292 1292 }
1293 1293
1294 1294 if (!(intr_enabled & SBBC_MAILBOX_IN))
1295 1295 return (ENOTSUP);
1296 1296
1297 1297 /*
1298 1298 * read the mailbox header
1299 1299 */
1300 1300 if (rc = mbox_read_header(SBBC_INBOX, &header))
1301 1301 return (rc);
1302 1302
1303 1303 /*
1304 1304 * check if any messages available. If
1305 1305 * consumer == producer then no more
1306 1306 * messages
1307 1307 */
1308 1308 if ((header.mailboxes[SBBC_INBOX].mbox_consumer ==
1309 1309 header.mailboxes[SBBC_INBOX].mbox_producer)) {
1310 1310
1311 1311 return (-1);
1312 1312 }
1313 1313
1314 1314 /*
1315 1315 * read the fragment header for this message
1316 1316 */
1317 1317 if (rc = mbox_read_frag(&header, &frag)) {
1318 1318
1319 1319 return (rc);
1320 1320 }
1321 1321
1322 1322 /* Save to local variable for easy reading */
1323 1323 type = frag.f_type.type;
1324 1324 f_id = frag.f_id;
1325 1325
1326 1326 SGSBBC_DBG_MBOX("%s: f_id = 0x%x\n", f, f_id);
1327 1327
1328 1328 /*
1329 1329 * check the message type. If its invalid, we will
1330 1330 * just toss the message
1331 1331 */
1332 1332 if (type >= SBBC_MBOX_MSG_TYPES) {
1333 1333 goto done;
1334 1334 }
1335 1335
1336 1336 /*
1337 1337 * if theres no waiters for this message type, and theres
1338 1338 * no message handler installed, toss it.
1339 1339 *
1340 1340 * Unsolicited messages (f_id == 0) are tricky because we won't know
1341 1341 * when the handler has finished so that we can
1342 1342 * remove the message, so, given the small brains in operation
1343 1343 * here, what we do is restrict junk mail to zero-length
1344 1344 * messages, then we allocate a fragment using kmem,
1345 1345 * make a copy of the fragment in this memory,
1346 1346 * pass this pointer to the fragment, then skip the message.
1347 1347 * So even if there is data associated with the junkmail,
1348 1348 * the message handler doesn't get to see it
1349 1349 * We expect the mesaage handler to free the memory.
1350 1350 */
1351 1351 if (type == SBBC_BROADCAST_MSG) {
1352 1352 /*
1353 1353 * Broadcast message, trigger all handlers
1354 1354 */
1355 1355 first_hdlr = 0;
1356 1356 last_hdlr = SBBC_MBOX_MSG_TYPES - 1;
1357 1357 } else if ((master_mbox->mbox_wait_list[type] == NULL) || (f_id == 0)) {
1358 1358 /*
1359 1359 * Theres no waiters, or its unsolicited anyway
1360 1360 */
1361 1361 first_hdlr = last_hdlr = type;
1362 1362 } else {
1363 1363 /*
1364 1364 * check the fragment message type, look at the wait list for
1365 1365 * that type to find its associated message
1366 1366 *
1367 1367 * First find the message. If we get it, take it off
1368 1368 * the waiter list and read the data. We will
1369 1369 * put it back on the list if necessary.
1370 1370 * This avoids the problem of a second message-in
1371 1371 * interrupt playing with this waiter.
1372 1372 * This will cut down on mutex spinning on the wait
1373 1373 * list locks, also, expect the next fragment to be
1374 1374 * for this messageso we might as well have it at the
1375 1375 * start of the list.
1376 1376 *
1377 1377 * its possible that a return message has a different type,
1378 1378 * (possible but not recommended!). So, if we don't find
1379 1379 * it on the list pointed to by the request type,
1380 1380 * go look at all the other lists
1381 1381 */
1382 1382
1383 1383 mbox_wait_lock = &master_mbox->mbox_wait_lock[type];
1384 1384
1385 1385 mutex_enter(mbox_wait_lock);
1386 1386 if ((waiter = mbox_find_waiter(type, f_id)) == NULL) {
1387 1387 for (i = 0; i < SBBC_MBOX_MSG_TYPES; i++) {
1388 1388 if (i == type)
1389 1389 continue;
1390 1390 if ((waiter = mbox_find_waiter(i, f_id))
1391 1391 != NULL)
1392 1392 break;
1393 1393 }
1394 1394 }
1395 1395 mutex_exit(mbox_wait_lock);
1396 1396
1397 1397 if (waiter == NULL) {
1398 1398 rc = -1;
1399 1399 /*
1400 1400 * there's no waiter for this message, but that
1401 1401 * could mean that this message is the start of
1402 1402 * a send/receive to us, and every 'first' request
1403 1403 * must by definition be unsolicited,
1404 1404 * so trigger the handler
1405 1405 */
1406 1406 first_hdlr = last_hdlr = type;
1407 1407 } else {
1408 1408 SGSBBC_DBG_MBOX("%s: f_id = 0x%x, msg_id = 0x%x, "
1409 1409 "msg_len = 0x%x\n",
1410 1410 f, f_id, waiter->w_id,
1411 1411 waiter->w_msg->msg_len);
1412 1412
1413 1413 rc = mbox_read(&header, &frag, waiter->w_msg);
1414 1414
1415 1415 SGSBBC_DBG_MBOX("%s: f_id = 0x%x, offset = 0x%x, "
1416 1416 "len = 0x%x, total_len = 0x%x\n",
1417 1417 f, frag.f_id, frag.f_frag_offset,
1418 1418 frag.f_frag_len, frag.f_total_len);
1419 1419
1420 1420 if (rc || ((frag.f_frag_offset + frag.f_frag_len) ==
1421 1421 frag.f_total_len)) {
1422 1422 /*
1423 1423 * failed or all the message has been read in
1424 1424 */
1425 1425 mutex_enter(mbox_wait_lock);
1426 1426 waiter->w_msg->msg_status = (rc == ENOMEM)?
1427 1427 rc : frag.f_status;
1428 1428 SGSBBC_DBG_MBOX("%s: msg_status = %d\n",
1429 1429 f, waiter->w_msg->msg_status);
1430 1430 cv_signal(&waiter->w_cv);
1431 1431 mutex_exit(mbox_wait_lock);
1432 1432
1433 1433 } else {
1434 1434 /*
1435 1435 * back on the wait list
1436 1436 */
1437 1437 mutex_enter(mbox_wait_lock);
1438 1438 if (waiter->w_msg->msg_status == ETIMEDOUT) {
1439 1439 cv_signal(&waiter->w_cv);
1440 1440 mutex_exit(mbox_wait_lock);
1441 1441 goto done;
1442 1442 }
1443 1443
1444 1444 if (master_mbox->mbox_wait_list[type] == NULL) {
1445 1445 master_mbox->mbox_wait_list[type] =
1446 1446 waiter;
1447 1447 waiter->w_next = NULL;
1448 1448 } else {
1449 1449 struct sbbc_msg_waiter *tmp;
1450 1450 tmp = master_mbox->mbox_wait_list[type];
1451 1451 master_mbox->mbox_wait_list[type] =
1452 1452 waiter;
1453 1453 waiter->w_next = tmp;
1454 1454 }
1455 1455 mutex_exit(mbox_wait_lock);
1456 1456 }
1457 1457 goto done;
1458 1458 }
1459 1459 }
1460 1460
1461 1461 /*
1462 1462 * Set msg_len to f_frag_len so msg_buf will be large enough
1463 1463 * to contain what is in the fragment.
1464 1464 */
1465 1465 f_frag_len = tmpmsg.msg_len = frag.f_frag_len;
1466 1466 /*
1467 1467 * Save the f_frag_offset for copying into client's space.
1468 1468 * Set frag.f_frag_offset to 0 so we don't have to allocate
1469 1469 * too much space for reading in the message.
1470 1470 */
1471 1471 f_frag_offset = frag.f_frag_offset;
1472 1472 frag.f_frag_offset = 0;
1473 1473
1474 1474 /* Allocate space for msg_buf */
1475 1475 if (f_frag_len != 0 && (tmpmsg.msg_buf =
1476 1476 kmem_alloc(f_frag_len, KM_NOSLEEP)) == NULL) {
1477 1477
1478 1478 rc = ENOMEM;
1479 1479 cmn_err(CE_WARN, "Can't allocate memory"
1480 1480 " for unsolicited messages\n");
1481 1481 } else {
1482 1482 /* Save the incoming message in tmpmsg */
1483 1483 rc = mbox_read(&header, &frag, &tmpmsg);
1484 1484
1485 1485 for (i = first_hdlr; rc == 0 && i <= last_hdlr; i++) {
1486 1486
1487 1487 intr = master_mbox->intrs[i];
1488 1488 if ((intr == NULL) || (intr->sbbc_intr_id == 0)) {
1489 1489 continue;
1490 1490 }
1491 1491
1492 1492 while (intr != NULL) {
1493 1493 /*
1494 1494 * If the client has allocated enough space
1495 1495 * for incoming message, copy into the
1496 1496 * client buffer.
1497 1497 */
1498 1498 sbbc_msg_t *arg = (sbbc_msg_t *)intr->sbbc_arg;
1499 1499 if (arg != (void *)NULL) {
1500 1500 if (arg->msg_len >= frag.f_total_len) {
1501 1501 if (f_frag_len > 0)
1502 1502 bcopy(tmpmsg.msg_buf,
1503 1503 arg->msg_buf +
1504 1504 f_frag_offset,
1505 1505 f_frag_len);
1506 1506 } else {
1507 1507 arg->msg_status = ENOMEM;
1508 1508 }
1509 1509 }
1510 1510
1511 1511 /*
1512 1512 * Only trigger the interrupt when we
1513 1513 * have received the whole message.
1514 1514 */
1515 1515 if (f_frag_offset + f_frag_len ==
1516 1516 frag.f_total_len) {
1517 1517
1518 1518 ddi_trigger_softintr(
1519 1519 intr->sbbc_intr_id);
1520 1520 }
1521 1521 intr = intr->sbbc_intr_next;
1522 1522 }
1523 1523 }
1524 1524
1525 1525 if (f_frag_len != 0) {
1526 1526 /* Don't forget to free the buffer */
1527 1527 kmem_free(tmpmsg.msg_buf, f_frag_len);
1528 1528 }
1529 1529 }
1530 1530 done:
1531 1531 mbox_skip_next_msg(&header);
1532 1532 return (rc);
1533 1533 }
1534 1534
1535 1535 /*
1536 1536 * available free space in the outbox
1537 1537 */
1538 1538 static int
1539 1539 mbox_has_free_space(struct sbbc_mbox_header *header)
1540 1540 {
1541 1541 uint32_t space = 0;
1542 1542
1543 1543 ASSERT(MUTEX_HELD(&master_mbox->mbox_out->mb_lock));
1544 1544
1545 1545 if (header->mailboxes[SBBC_OUTBOX].mbox_producer ==
1546 1546 header->mailboxes[SBBC_OUTBOX].mbox_consumer) {
1547 1547 /*
1548 1548 * mailbox is empty
1549 1549 */
1550 1550 space += header->mailboxes[SBBC_OUTBOX].mbox_len -
1551 1551 header->mailboxes[SBBC_OUTBOX].mbox_producer;
1552 1552 space +=
1553 1553 header->mailboxes[SBBC_OUTBOX].mbox_producer;
1554 1554 } else if (header->mailboxes[SBBC_OUTBOX].mbox_producer >
1555 1555 header->mailboxes[SBBC_OUTBOX].mbox_consumer) {
1556 1556 space += header->mailboxes[SBBC_OUTBOX].mbox_len -
1557 1557 header->mailboxes[SBBC_OUTBOX].mbox_producer;
1558 1558 space += header->mailboxes[SBBC_OUTBOX].mbox_consumer;
1559 1559 } else {
1560 1560 /*
1561 1561 * mailbox wrapped around
1562 1562 */
1563 1563 space += header->mailboxes[SBBC_OUTBOX].mbox_consumer -
1564 1564 header->mailboxes[SBBC_OUTBOX].mbox_producer;
1565 1565 }
1566 1566
1567 1567 /*
1568 1568 * Need to make sure that the mailbox never
1569 1569 * gets completely full, as consumer == producer is
1570 1570 * our test for empty, so we drop MBOX_ALIGN_BYTES.
1571 1571 */
1572 1572
1573 1573 if (space >= MBOX_ALIGN_BYTES)
1574 1574 space -= MBOX_ALIGN_BYTES;
1575 1575 else
1576 1576 space = 0;
1577 1577
1578 1578 return (space);
1579 1579
1580 1580 }
1581 1581 /*
1582 1582 * Write the data to IOSRAM
1583 1583 * Update the SRAM mailbox header
1584 1584 * Update the local mailbox pointers
1585 1585 * Only write a single fragment. If possible,
1586 1586 * put the whole message into a fragment.
1587 1587 *
1588 1588 * Note: We assume that there is no 'max' message
1589 1589 * size. We will just keep fragmenting.
1590 1590 * Note: We always write to SBBC_OUTBOX and
1591 1591 * read from SBBC_INBOX
1592 1592 *
1593 1593 * If we get an error at any time, return immediately
1594 1594 * without updating the mailbox header in SRAM
1595 1595 */
1596 1596 static int
1597 1597 mbox_write(struct sbbc_mbox_header *header,
1598 1598 struct sbbc_fragment *frag, sbbc_msg_t *msg)
1599 1599 {
1600 1600 int bytes_written, bytes_remaining, free_space;
1601 1601 int rc = 0;
1602 1602 caddr_t src;
1603 1603 uint32_t sram_dst;
1604 1604 int space_at_end, space_at_start;
1605 1605 uint32_t mbox_offset, mbox_len;
1606 1606 uint32_t mbox_producer, mbox_consumer;
1607 1607 uint32_t f_total_len, f_frag_offset;
1608 1608 uint32_t frag_header_size;
1609 1609 static fn_t f = "mbox_write";
1610 1610
1611 1611 ASSERT(MUTEX_HELD(&master_mbox->mbox_out->mb_lock));
1612 1612
1613 1613 /*
1614 1614 * Save to local variables to make code more readable
1615 1615 */
1616 1616 mbox_offset = header->mailboxes[SBBC_OUTBOX].mbox_offset;
1617 1617 mbox_len = header->mailboxes[SBBC_OUTBOX].mbox_len;
1618 1618 mbox_producer = header->mailboxes[SBBC_OUTBOX].mbox_producer;
1619 1619 mbox_consumer = header->mailboxes[SBBC_OUTBOX].mbox_consumer;
1620 1620 f_total_len = frag->f_total_len;
1621 1621 f_frag_offset = frag->f_frag_offset;
1622 1622 frag_header_size = sizeof (struct sbbc_fragment);
1623 1623
1624 1624 SGSBBC_DBG_MBOX("%s: mbox_consumer = 0x%x, "
1625 1625 "mbox_producer = 0x%x\n", f, mbox_consumer, mbox_producer);
1626 1626
1627 1627 /*
1628 1628 * Write pointer in SRAM
1629 1629 */
1630 1630 sram_dst = mbox_offset + mbox_producer;
1631 1631
1632 1632 /*
1633 1633 * NB We assume that the consumer stays constant
1634 1634 * during the write. It may not necessarily
1635 1635 * be the case but it won't cause us any problems, just means
1636 1636 * we fragment more than is absolutely necessary
1637 1637 *
1638 1638 * possible cases
1639 1639 * 1) consumer == producer, mailbox empty
1640 1640 * space_at_end == mailbox end - producer
1641 1641 * space_at_start == producer - MBOX_ALIGN_BYTES
1642 1642 * 2) producer < consumer
1643 1643 * space_at_end = (consumer - producer - MBOX_ALIGN_BYTES)
1644 1644 * space_at_start == 0
1645 1645 * 3) producer > consumer
1646 1646 * space_at_end = mailbox end - producer
1647 1647 * space_at_start = consumer - MBOX_ALIGN_BYTES
1648 1648 *
1649 1649 * (space - MBOX_ALIGN_BYTES) because we need to avoid the
1650 1650 * scenario where the producer wraps around completely and
1651 1651 * producer == consumer, as this is our test for 'empty'.
1652 1652 * Also we want it to be 8-byte aligned.
1653 1653 * Note: start is assumed = 0
1654 1654 */
1655 1655 if (mbox_producer < mbox_consumer) {
1656 1656 space_at_end = mbox_consumer - mbox_producer - MBOX_ALIGN_BYTES;
1657 1657 if (space_at_end < 0)
1658 1658 space_at_end = 0;
1659 1659 space_at_start = 0;
1660 1660 } else {
1661 1661 space_at_end = mbox_len - mbox_producer;
1662 1662 if (mbox_consumer == 0)
1663 1663 space_at_end -= MBOX_ALIGN_BYTES;
1664 1664 space_at_start = mbox_consumer - MBOX_ALIGN_BYTES;
1665 1665 if (space_at_start < 0)
1666 1666 space_at_start = 0;
1667 1667 }
1668 1668
1669 1669 SGSBBC_DBG_MBOX("%s: space_at_end = 0x%x, space_at_start = 0x%x\n",
1670 1670 f, space_at_end, space_at_start);
1671 1671
1672 1672 free_space = space_at_end + space_at_start;
1673 1673
1674 1674 if (free_space < frag_header_size) {
1675 1675 /*
1676 1676 * can't even write a fragment header, so just return
1677 1677 * the caller will block waiting for space
1678 1678 */
1679 1679 frag->f_frag_len = 0;
1680 1680 return (ENOSPC);
1681 1681 }
1682 1682
1683 1683 /*
1684 1684 * How many bytes will be in the fragment ?
1685 1685 */
1686 1686 bytes_remaining = f_total_len - f_frag_offset;
1687 1687 frag->f_frag_len = min(bytes_remaining, free_space - frag_header_size);
1688 1688
1689 1689 SGSBBC_DBG_MBOX("%s: writing header:sram_dst = 0x%x\n",
1690 1690 f, sram_dst);
1691 1691
1692 1692 /*
1693 1693 * we can write the fragment header and some data
1694 1694 * First, the fragment header
1695 1695 */
1696 1696 if (space_at_end >= frag_header_size) {
1697 1697 rc = iosram_write(SBBC_MAILBOX_KEY, sram_dst, (caddr_t)frag,
1698 1698 frag_header_size);
1699 1699 if (rc)
1700 1700 return (rc);
1701 1701
1702 1702 sram_dst = (uint32_t)(sram_dst + frag_header_size);
1703 1703 /*
1704 1704 * Wrap around if we reach the end
1705 1705 */
1706 1706 if (sram_dst >= (mbox_len + mbox_offset)) {
1707 1707 sram_dst = mbox_offset;
1708 1708 }
1709 1709 space_at_end -= frag_header_size;
1710 1710 } else {
1711 1711 /* wraparound */
1712 1712 if (space_at_end) {
1713 1713 rc = iosram_write(SBBC_MAILBOX_KEY, sram_dst,
1714 1714 (caddr_t)frag, space_at_end);
1715 1715 if (rc)
1716 1716 return (rc);
1717 1717 sram_dst = (uint32_t)mbox_offset;
1718 1718 }
1719 1719 rc = iosram_write(SBBC_MAILBOX_KEY, sram_dst,
1720 1720 (caddr_t)((caddr_t)frag + space_at_end),
1721 1721 (frag_header_size - space_at_end));
1722 1722 if (rc)
1723 1723 return (rc);
1724 1724 sram_dst += frag_header_size - space_at_end;
1725 1725 space_at_start -= (frag_header_size - space_at_end);
1726 1726 space_at_end = 0;
1727 1727 }
1728 1728
1729 1729 SGSBBC_DBG_MBOX("%s: space_at_end = 0x%x, space_at_start = 0x%x\n",
1730 1730 f, space_at_end, space_at_start);
1731 1731
1732 1732 /*
1733 1733 * Now the fragment data
1734 1734 */
1735 1735 free_space -= frag_header_size;
1736 1736 src = (caddr_t)(msg->msg_buf + f_frag_offset);
1737 1737 bytes_written = 0;
1738 1738 if (space_at_end) {
1739 1739 SGSBBC_DBG_MBOX("%s: writing data:sram_dst = 0x%x, "
1740 1740 "bytes_remaining = 0x%x\n",
1741 1741 f, sram_dst, bytes_remaining);
1742 1742
1743 1743 if (space_at_end < bytes_remaining)
1744 1744 bytes_written = space_at_end;
1745 1745 else
1746 1746 bytes_written = bytes_remaining;
1747 1747 rc = iosram_write(SBBC_MAILBOX_KEY, sram_dst, src,
1748 1748 bytes_written);
1749 1749 if (rc)
1750 1750 return (rc);
1751 1751
1752 1752 sram_dst = (uint32_t)(sram_dst + bytes_written);
1753 1753 /*
1754 1754 * Wrap around if we reach the end
1755 1755 */
1756 1756 if (sram_dst >= (mbox_len + mbox_offset)) {
1757 1757 sram_dst = mbox_offset;
1758 1758 }
1759 1759 src = (caddr_t)(src + bytes_written);
1760 1760 bytes_remaining -= bytes_written;
1761 1761 }
1762 1762
1763 1763 if ((bytes_remaining > 0) && space_at_start) {
1764 1764 SGSBBC_DBG_MBOX("%s: writing the rest:sram_dst = 0x%x, "
1765 1765 "bytes_remaining = 0x%x\n",
1766 1766 f, sram_dst, bytes_remaining);
1767 1767 if (space_at_start < bytes_remaining) {
1768 1768 rc = iosram_write(SBBC_MAILBOX_KEY, sram_dst, src,
1769 1769 space_at_start);
1770 1770 bytes_written += space_at_start;
1771 1771 } else {
1772 1772 rc = iosram_write(SBBC_MAILBOX_KEY, sram_dst, src,
1773 1773 bytes_remaining);
1774 1774 bytes_written += bytes_remaining;
1775 1775 }
1776 1776 if (rc)
1777 1777 return (rc);
1778 1778 }
1779 1779
1780 1780 frag->f_frag_len = bytes_written;
1781 1781
1782 1782 /*
1783 1783 * update header->mbox_producer (bytes_written + frag_size)
1784 1784 */
1785 1785 sram_dst = mbox_producer + bytes_written + frag_header_size;
1786 1786 if (sram_dst >= mbox_len) {
1787 1787 sram_dst = sram_dst % mbox_len;
1788 1788 }
1789 1789
1790 1790 SGSBBC_DBG_MBOX("%s: after writing data:sram_dst = 0x%x, "
1791 1791 "bytes_written = 0x%x\n", f, sram_dst, bytes_written);
1792 1792
1793 1793 header->mailboxes[SBBC_OUTBOX].mbox_producer = sram_dst;
1794 1794
1795 1795 mbox_update_header(SBBC_OUTBOX, header);
1796 1796
1797 1797
1798 1798 return (rc);
1799 1799 }
1800 1800
1801 1801
1802 1802 /*
1803 1803 * Get the next frag from IOSRAM.
1804 1804 * Write it to the corresponding msg buf.
1805 1805 * The caller must update the SRAM pointers etc.
1806 1806 */
1807 1807 static int
1808 1808 mbox_read(struct sbbc_mbox_header *header,
1809 1809 struct sbbc_fragment *frag, sbbc_msg_t *msg)
1810 1810 {
1811 1811 int rc = 0;
1812 1812 uint32_t sram_src, sram_end;
1813 1813 caddr_t msg_buf;
1814 1814 int bytes_at_start, bytes_at_end;
1815 1815 int bytes_to_read;
1816 1816 uint32_t frag_header_size, frag_total_size;
1817 1817 uint32_t f_frag_offset, f_frag_len;
1818 1818 uint32_t mbox_producer, mbox_consumer;
1819 1819 uint32_t mbox_len, mbox_offset;
1820 1820 static fn_t f = "mbox_read";
1821 1821
1822 1822 ASSERT(MUTEX_HELD(&master_mbox->mbox_in->mb_lock));
1823 1823
1824 1824 /*
1825 1825 * Save to local variables to make code more readable
1826 1826 */
1827 1827 mbox_producer = header->mailboxes[SBBC_INBOX].mbox_producer;
1828 1828 mbox_consumer = header->mailboxes[SBBC_INBOX].mbox_consumer;
1829 1829 mbox_len = header->mailboxes[SBBC_INBOX].mbox_len;
1830 1830 mbox_offset = header->mailboxes[SBBC_INBOX].mbox_offset;
1831 1831 frag_header_size = sizeof (struct sbbc_fragment);
1832 1832 f_frag_offset = frag->f_frag_offset;
1833 1833 f_frag_len = frag->f_frag_len;
1834 1834 frag_total_size = frag_header_size + f_frag_len;
1835 1835
1836 1836 /*
1837 1837 * If the message buffer size is smaller than the fragment
1838 1838 * size, return an error.
1839 1839 */
1840 1840 if (msg->msg_len < f_frag_len) {
1841 1841 rc = ENOMEM;
1842 1842 goto done;
1843 1843 }
1844 1844
1845 1845 msg_buf = (caddr_t)(msg->msg_buf + f_frag_offset);
1846 1846
1847 1847 /*
1848 1848 * Throw in the message data
1849 1849 */
1850 1850 bcopy(&frag->f_data, &msg->msg_data, sizeof (msg->msg_data));
1851 1851
1852 1852 /*
1853 1853 * We have it all, waiter, message, so lets
1854 1854 * go get that puppy!
1855 1855 * Message could be in one or two chunks -
1856 1856 * consumer < producer: 1 chunk, (producer - consumer)
1857 1857 * consumer > producer: 2 chunks, (end - consumer)
1858 1858 * (producer - start)
1859 1859 */
1860 1860 sram_end = (uint32_t)(mbox_offset + mbox_len);
1861 1861 sram_src = (uint32_t)(mbox_offset + mbox_consumer + frag_header_size);
1862 1862
1863 1863 /*
1864 1864 * wraparound
1865 1865 */
1866 1866 if (sram_src >= sram_end)
1867 1867 sram_src -= mbox_len;
1868 1868
1869 1869 /*
1870 1870 * find where the data is
1871 1871 * possible cases
1872 1872 * 1) consumer == producer, mailbox empty
1873 1873 * error
1874 1874 * 2) producer < consumer
1875 1875 * bytes_at_end = mailbox end - consumer
1876 1876 * bytes_at_start = producer
1877 1877 * 3) producer > consumer
1878 1878 * bytes_at_end = producer - consumer
1879 1879 * bytes_at_start = 0
1880 1880 */
1881 1881
1882 1882 SGSBBC_DBG_MBOX("%s: mbox_consumer = 0x%x, mbox_producer = 0x%x, "
1883 1883 "frag_len = 0x%x\n",
1884 1884 f, mbox_consumer, mbox_producer, f_frag_len);
1885 1885
1886 1886 if (mbox_producer == mbox_consumer) {
1887 1887 bytes_at_end = bytes_at_start = 0;
1888 1888 } else if (mbox_producer < mbox_consumer) {
1889 1889 bytes_at_end = mbox_len - mbox_consumer;
1890 1890 bytes_at_start = mbox_producer;
1891 1891 } else {
1892 1892 bytes_at_end = mbox_producer - mbox_consumer;
1893 1893 bytes_at_start = 0;
1894 1894 }
1895 1895
1896 1896 SGSBBC_DBG_MBOX("%s: bytes_at_end = 0x%x, "
1897 1897 "bytes_at_start = 0x%x\n", f, bytes_at_end, bytes_at_start);
1898 1898
1899 1899 if ((bytes_at_end + bytes_at_start) < frag_total_size) {
1900 1900
1901 1901 /*
1902 1902 * mailbox is corrupt
1903 1903 * but what to do ?
1904 1904 */
1905 1905 cmn_err(CE_PANIC, "Corrupt INBOX!\n"
1906 1906 "producer = %x, consumer = %x, bytes_at_start = %x, "
1907 1907 "bytes_at_end = %x\n", mbox_producer, mbox_consumer,
1908 1908 bytes_at_start, bytes_at_end);
1909 1909 }
1910 1910
1911 1911 /*
1912 1912 * If bytes_at_end is greater than header size, read the
1913 1913 * part at the end of the mailbox, and then update the
1914 1914 * pointers and bytes_to_read.
1915 1915 */
1916 1916 if (bytes_at_end > frag_header_size) {
1917 1917 /*
1918 1918 * We are only interested in the data segment.
1919 1919 */
1920 1920 bytes_at_end -= frag_header_size;
1921 1921 bytes_to_read = (bytes_at_end >= f_frag_len)?
1922 1922 f_frag_len : bytes_at_end;
1923 1923 SGSBBC_DBG_MBOX("%s: reading data: sram_src = 0x%x, "
1924 1924 "bytes_to_read = 0x%x\n", f, sram_src, bytes_to_read);
1925 1925 rc = iosram_read(SBBC_MAILBOX_KEY, sram_src, msg_buf,
1926 1926 bytes_to_read);
1927 1927 if (rc) {
1928 1928 goto done;
1929 1929 }
1930 1930
1931 1931 /*
1932 1932 * Update pointers in SRAM and message buffer.
1933 1933 */
1934 1934 sram_src = (uint32_t)mbox_offset;
1935 1935 msg_buf = (caddr_t)(msg_buf + bytes_to_read);
1936 1936 bytes_to_read = f_frag_len - bytes_to_read;
1937 1937 } else {
1938 1938 bytes_to_read = f_frag_len;
1939 1939 }
1940 1940
1941 1941 /*
1942 1942 * wraparound to start of mailbox
1943 1943 */
1944 1944 if (bytes_to_read > 0) {
1945 1945 SGSBBC_DBG_MBOX("%s: reading the rest: sram_src = 0x%x, "
1946 1946 "bytes_to_read = 0x%x\n", f, sram_src, bytes_to_read);
1947 1947 rc = iosram_read(SBBC_MAILBOX_KEY, sram_src, msg_buf,
1948 1948 bytes_to_read);
1949 1949 }
1950 1950
1951 1951 done:
1952 1952 msg->msg_bytes += f_frag_len;
1953 1953
1954 1954 return (rc);
1955 1955 }
1956 1956
1957 1957 /*
1958 1958 * move past the next message in the inbox
1959 1959 */
1960 1960 static void
1961 1961 mbox_skip_next_msg(struct sbbc_mbox_header *header)
1962 1962 {
1963 1963 struct sbbc_fragment frag;
1964 1964 uint32_t next_msg;
1965 1965
1966 1966 ASSERT(MUTEX_HELD(&master_mbox->mbox_in->mb_lock));
1967 1967
1968 1968 if (mbox_read_frag(header, &frag)) {
1969 1969 cmn_err(CE_PANIC, "INBOX is Corrupt !\n");
1970 1970 }
1971 1971
1972 1972 /*
1973 1973 * Move on to the next message
1974 1974 */
1975 1975 next_msg = header->mailboxes[SBBC_INBOX].mbox_consumer;
1976 1976 next_msg += sizeof (struct sbbc_fragment);
1977 1977 next_msg += frag.f_frag_len;
1978 1978 if (next_msg >= header->mailboxes[SBBC_INBOX].mbox_len) {
1979 1979 next_msg = (next_msg +
1980 1980 header->mailboxes[SBBC_INBOX].mbox_len) %
1981 1981 header->mailboxes[SBBC_INBOX].mbox_len;
1982 1982 }
1983 1983 header->mailboxes[SBBC_INBOX].mbox_consumer =
1984 1984 next_msg;
1985 1985
1986 1986 mbox_update_header(SBBC_INBOX, header);
1987 1987
1988 1988 return;
1989 1989
1990 1990 }
1991 1991
1992 1992 static struct sbbc_msg_waiter *
1993 1993 mbox_find_waiter(uint16_t msg_type, uint32_t msg_id)
1994 1994 {
1995 1995 struct sbbc_msg_waiter *waiter, *prev;
1996 1996
1997 1997 prev = NULL;
1998 1998 for (waiter = master_mbox->mbox_wait_list[msg_type];
1999 1999 waiter != NULL; waiter = waiter->w_next) {
2000 2000
2001 2001 if (waiter->w_id == msg_id) {
2002 2002 if (prev != NULL) {
2003 2003 prev->w_next = waiter->w_next;
2004 2004 } else {
2005 2005 master_mbox->mbox_wait_list[msg_type] =
2006 2006 waiter->w_next;
2007 2007 }
2008 2008 break;
2009 2009 }
2010 2010 prev = waiter;
2011 2011 }
2012 2012
2013 2013 return (waiter);
2014 2014 }
2015 2015
2016 2016 static int
2017 2017 mbox_read_header(uint32_t mailbox, struct sbbc_mbox_header *header)
2018 2018 {
2019 2019 struct sbbc_mbox_header *hd;
2020 2020 uint32_t offset;
2021 2021 int rc;
2022 2022
2023 2023 /*
2024 2024 * Initialize a sbbc_mbox_header pointer to 0 so that we
2025 2025 * can use it to calculate the offsets of fields inside
2026 2026 * the structure.
2027 2027 */
2028 2028 hd = (struct sbbc_mbox_header *)0;
2029 2029
2030 2030 if (rc = iosram_read(SBBC_MAILBOX_KEY, 0, (caddr_t)header,
2031 2031 sizeof (struct sbbc_mbox_header)))
2032 2032 return (rc);
2033 2033
2034 2034 /*
2035 2035 * Since the header is read in a byte-by-byte fashion
2036 2036 * using ddi_rep_get8, we need to re-read the producer
2037 2037 * or consumer pointer as integer in case it has changed
2038 2038 * after part of the previous value has been read.
2039 2039 */
2040 2040 switch (mailbox) {
2041 2041
2042 2042 case SBBC_INBOX:
2043 2043 offset = (uint32_t)(uintptr_t)
2044 2044 (&hd->mailboxes[SBBC_INBOX].mbox_producer);
2045 2045 rc = iosram_read(SBBC_MAILBOX_KEY, offset,
2046 2046 (caddr_t)&header->mailboxes[SBBC_INBOX].mbox_producer,
2047 2047 sizeof (uint32_t));
2048 2048 break;
2049 2049 case SBBC_OUTBOX:
2050 2050 offset = (uint32_t)(uintptr_t)
2051 2051 (&hd->mailboxes[SBBC_OUTBOX].mbox_consumer);
2052 2052 rc = iosram_read(SBBC_MAILBOX_KEY, offset,
2053 2053 (caddr_t)&header->mailboxes[SBBC_OUTBOX].mbox_consumer,
2054 2054 sizeof (uint32_t));
2055 2055 break;
2056 2056 default:
2057 2057 cmn_err(CE_PANIC, "Invalid Mbox header type\n");
2058 2058 break;
2059 2059
2060 2060 }
2061 2061
2062 2062 return (rc);
2063 2063 }
2064 2064
2065 2065 /*
2066 2066 * There are only two fields updated by the domain,
2067 2067 * the inbox consumer field and the outbox producer
2068 2068 * field. These fields are protected by the respective
2069 2069 * mbox_{in|out}->mb_lock so that accesses will
2070 2070 * be serialised. The only coherency issue is writing
2071 2071 * back the header, so we do it here after grabbing
2072 2072 * the global mailbox lock.
2073 2073 */
2074 2074 static void
2075 2075 mbox_update_header(uint32_t mailbox, struct sbbc_mbox_header *header)
2076 2076 {
2077 2077 struct sbbc_mbox_header *hd;
2078 2078 uint32_t value, offset, mbox_len;
2079 2079
2080 2080 /*
2081 2081 * Initialize a sbbc_mbox_header pointer to 0 so that we
2082 2082 * can use it to calculate the offsets of fields inside
2083 2083 * the structure.
2084 2084 */
2085 2085 hd = (struct sbbc_mbox_header *)0;
2086 2086
2087 2087 switch (mailbox) {
2088 2088
2089 2089 case SBBC_INBOX:
2090 2090 value = header->mailboxes[SBBC_INBOX].mbox_consumer;
2091 2091 offset = (uint32_t)(uintptr_t)
2092 2092 (&hd->mailboxes[SBBC_INBOX].mbox_consumer);
2093 2093
2094 2094 mbox_len = header->mailboxes[SBBC_INBOX].mbox_len;
2095 2095 break;
2096 2096 case SBBC_OUTBOX:
2097 2097 value = header->mailboxes[SBBC_OUTBOX].mbox_producer;
2098 2098 offset = (uint32_t)(uintptr_t)
2099 2099 (&hd->mailboxes[SBBC_OUTBOX].mbox_producer);
2100 2100 mbox_len = header->mailboxes[SBBC_OUTBOX].mbox_len;
2101 2101 break;
2102 2102 default:
2103 2103 cmn_err(CE_PANIC, "Invalid Mbox header type\n");
2104 2104 break;
2105 2105
2106 2106 }
2107 2107
2108 2108 /*
2109 2109 * If the last read/write would cause the next read/write
2110 2110 * to be unaligned, we skip on modulo MBOX_ALIGN_BYTES.
2111 2111 * This is OK because all the mailbox handlers will
2112 2112 * conform to this.
2113 2113 */
2114 2114 if (value % MBOX_ALIGN_BYTES) {
2115 2115 value += (MBOX_ALIGN_BYTES - (value % MBOX_ALIGN_BYTES));
2116 2116 value %= mbox_len;
2117 2117 }
2118 2118
2119 2119 if (iosram_write(SBBC_MAILBOX_KEY, offset, (caddr_t)&value,
2120 2120 sizeof (uint32_t))) {
2121 2121 cmn_err(CE_PANIC, "Mailbox Corrupt ! \n");
2122 2122 }
2123 2123
2124 2124 /*
2125 2125 * Update internal pointers so they won't be out of sync with
2126 2126 * the values in IOSRAM.
2127 2127 */
2128 2128 switch (mailbox) {
2129 2129
2130 2130 case SBBC_INBOX:
2131 2131 header->mailboxes[SBBC_INBOX].mbox_consumer = value;
2132 2132 break;
2133 2133 case SBBC_OUTBOX:
2134 2134 header->mailboxes[SBBC_OUTBOX].mbox_producer = value;
2135 2135 break;
2136 2136 }
2137 2137 }
2138 2138
2139 2139 static int
2140 2140 mbox_read_frag(struct sbbc_mbox_header *header,
2141 2141 struct sbbc_fragment *frag)
2142 2142 {
2143 2143 int rc = 0;
2144 2144 uint32_t sram_src, bytes;
2145 2145 caddr_t dst;
2146 2146
2147 2147 ASSERT(MUTEX_HELD(&master_mbox->mbox_in->mb_lock));
2148 2148 /*
2149 2149 * read the fragment header for this message
2150 2150 */
2151 2151 sram_src = (uint32_t)(header->mailboxes[SBBC_INBOX].mbox_offset +
2152 2152 header->mailboxes[SBBC_INBOX].mbox_consumer);
2153 2153
2154 2154 /*
2155 2155 * wraparound ?
2156 2156 */
2157 2157 if ((header->mailboxes[SBBC_INBOX].mbox_consumer +
2158 2158 sizeof (struct sbbc_fragment)) >=
2159 2159 header->mailboxes[SBBC_INBOX].mbox_len) {
2160 2160
2161 2161 dst = (caddr_t)frag;
2162 2162 bytes = header->mailboxes[SBBC_INBOX].mbox_len -
2163 2163 header->mailboxes[SBBC_INBOX].mbox_consumer;
2164 2164
2165 2165 if (rc = iosram_read(SBBC_MAILBOX_KEY, sram_src, dst, bytes)) {
2166 2166 return (rc);
2167 2167 }
2168 2168
2169 2169 dst += bytes;
2170 2170 sram_src = header->mailboxes[SBBC_INBOX].mbox_offset;
2171 2171 bytes = (header->mailboxes[SBBC_INBOX].mbox_consumer +
2172 2172 sizeof (struct sbbc_fragment)) %
2173 2173 header->mailboxes[SBBC_INBOX].mbox_len;
2174 2174
2175 2175 if (rc = iosram_read(SBBC_MAILBOX_KEY, sram_src,
2176 2176 dst, bytes)) {
2177 2177 return (rc);
2178 2178 }
2179 2179 } else {
2180 2180 if (rc = iosram_read(SBBC_MAILBOX_KEY, sram_src, (caddr_t)frag,
2181 2181 sizeof (struct sbbc_fragment))) {
2182 2182 return (rc);
2183 2183 }
2184 2184 }
2185 2185
2186 2186 return (0);
2187 2187 }
2188 2188
2189 2189
2190 2190 /*
2191 2191 * This function is triggered by a soft interrupt and it's purpose is to call
2192 2192 * to kadmin() to shutdown the Domain.
2193 2193 */
2194 2194 /*ARGSUSED0*/
2195 2195 static uint_t
2196 2196 sbbc_do_fast_shutdown(char *arg)
2197 2197 {
2198 2198 (void) kadmin(A_SHUTDOWN, AD_POWEROFF, NULL, kcred);
2199 2199
2200 2200 /*
2201 2201 * If kadmin fails for some reason then we bring the system down
2202 2202 * via power_down(), or failing that using halt().
2203 2203 */
2204 2204 power_down("kadmin() failed, trying power_down()");
2205 2205
2206 2206 halt("power_down() failed, trying halt()");
2207 2207
2208 2208 /*
2209 2209 * We should never make it this far, so something must have gone
2210 2210 * horribly, horribly wrong.
2211 2211 */
2212 2212 /*NOTREACHED*/
2213 2213 return (DDI_INTR_UNCLAIMED);
2214 2214 }
2215 2215
2216 2216
2217 2217 /*
2218 2218 * This function handles unsolicited PANIC_SHUTDOWN events
2219 2219 */
2220 2220 static uint_t
2221 2221 sbbc_panic_shutdown_handler(char *arg)
2222 2222 {
2223 2223 static fn_t f = "sbbc_panic_shutdown_handler()";
2224 2224
2225 2225 sg_panic_shutdown_t *payload = NULL;
2226 2226 sbbc_msg_t *msg = NULL;
2227 2227
2228 2228 if (arg == NULL) {
2229 2229 SGSBBC_DBG_EVENT(CE_NOTE, "%s: arg == NULL", f);
2230 2230 return (DDI_INTR_UNCLAIMED);
2231 2231 }
2232 2232
2233 2233 msg = (sbbc_msg_t *)arg;
2234 2234
2235 2235 if (msg->msg_buf == NULL) {
2236 2236 SGSBBC_DBG_EVENT(CE_NOTE, "%s: msg_buf == NULL", f);
2237 2237 return (DDI_INTR_UNCLAIMED);
2238 2238 }
2239 2239
2240 2240 payload = (sg_panic_shutdown_t *)msg->msg_buf;
2241 2241
2242 2242 switch (*payload) {
2243 2243 case SC_EVENT_PANIC_ENV:
2244 2244
2245 2245 /*
2246 2246 * Let the user know why the domain is going down.
2247 2247 */
2248 2248 cmn_err(CE_WARN, "%s", PANIC_ENV_EVENT_MSG);
2249 2249
2250 2250 /*
2251 2251 * trigger sbbc_do_fast_shutdown().
2252 2252 */
2253 2253 ddi_trigger_softintr(panic_softintr_id);
2254 2254
2255 2255 /*NOTREACHED*/
2256 2256 break;
2257 2257
2258 2258 case SC_EVENT_PANIC_KEYSWITCH:
2259 2259 /*
2260 2260 * The SC warns a user if they try a destructive keyswitch
2261 2261 * command on a Domain which is currently running Solaris.
2262 2262 * If the user chooses to continue despite our best advise
2263 2263 * then we bring down the Domain immediately without trying
2264 2264 * to shut the system down gracefully.
2265 2265 */
2266 2266 break;
2267 2267
2268 2268 default:
2269 2269 SGSBBC_DBG_EVENT(CE_NOTE, "%s: Unknown payload:%d", f,
2270 2270 *payload);
2271 2271 return (DDI_INTR_UNCLAIMED);
2272 2272 }
2273 2273
2274 2274 return (DDI_INTR_CLAIMED);
2275 2275 }
2276 2276
2277 2277 /*
2278 2278 * dp_get_cores()
2279 2279 *
2280 2280 * Checks cpu implementation for the input cpuid and returns
2281 2281 * the number of cores.
2282 2282 * If implementation cannot be determined, returns 1
2283 2283 */
2284 2284 static int
2285 2285 dp_get_cores(uint16_t cpuid)
2286 2286 {
2287 2287 int bd, ii, impl, nc;
2288 2288
2289 2289 bd = cpuid / 4;
2290 2290 nc = SG_MAX_CPUS_PER_BD;
2291 2291
2292 2292 /* find first with valid implementation */
2293 2293 for (ii = 0; ii < nc; ii++)
2294 2294 if (cpu[MAKE_CPUID(bd, ii)]) {
2295 2295 impl = cpunodes[MAKE_CPUID(bd, ii)].implementation;
2296 2296 break;
2297 2297 }
2298 2298
2299 2299 if (IS_JAGUAR(impl) || IS_PANTHER(impl))
2300 2300 return (2);
2301 2301 else
2302 2302 return (1);
2303 2303 }
2304 2304
2305 2305 /*
2306 2306 * dp_payload_add_cpus()
2307 2307 *
2308 2308 * From datapath mailbox message, determines the number of and safari IDs
2309 2309 * for affected cpus, then adds this info to the datapath ereport.
2310 2310 *
2311 2311 */
2312 2312 static int
2313 2313 dp_payload_add_cpus(plat_datapath_info_t *dpmsg, nvlist_t *erp)
2314 2314 {
2315 2315 int jj = 0, numcpus = 0;
2316 2316 int bd, procpos, ii, num, ncores, ret;
2317 2317 uint16_t *dparray, cpuid;
2318 2318 uint64_t *snarray;
2319 2319
2320 2320 /* check for multiple core architectures */
2321 2321 ncores = dp_get_cores(dpmsg->cpuid);
2322 2322
2323 2323 switch (dpmsg->type) {
2324 2324 case DP_CDS_TYPE:
2325 2325 numcpus = ncores;
2326 2326 break;
2327 2327
2328 2328 case DP_DX_TYPE:
2329 2329 numcpus = 2 * ncores;
2330 2330 break;
2331 2331
2332 2332 case DP_RP_TYPE:
2333 2333 numcpus = SG_MAX_CPUS_PER_BD;
2334 2334 break;
2335 2335
2336 2336 default:
2337 2337 ASSERT(0);
2338 2338 return (-1);
2339 2339 }
2340 2340
2341 2341 num = numcpus;
2342 2342
2343 2343 /*
2344 2344 * populate dparray with impacted cores (only those present)
2345 2345 */
2346 2346 dparray = kmem_zalloc(num * sizeof (uint16_t *), KM_SLEEP);
2347 2347 bd = SG_PORTID_TO_BOARD_NUM(SG_CPUID_TO_PORTID(dpmsg->cpuid));
2348 2348 procpos = SG_CPUID_TO_PORTID(dpmsg->cpuid) & 0x3;
2349 2349
2350 2350 mutex_enter(&cpu_lock);
2351 2351
2352 2352 switch (dpmsg->type) {
2353 2353
2354 2354 case DP_CDS_TYPE:
2355 2355 /*
2356 2356 * For a CDS error, it's the reporting cpuid
2357 2357 * and it's other core (if present)
2358 2358 */
2359 2359 cpuid = dpmsg->cpuid & 0x1FF; /* core 0 */
2360 2360 if (cpu[cpuid])
2361 2361 dparray[jj++] = cpuid;
2362 2362
2363 2363 cpuid = dpmsg->cpuid | SG_CORE_ID_MASK; /* core 1 */
2364 2364 if (cpu[cpuid])
2365 2365 dparray[jj++] = cpuid;
2366 2366 break;
2367 2367
2368 2368 case DP_DX_TYPE:
2369 2369 /*
2370 2370 * For a DX error, it's the reporting cpuid (all
2371 2371 * cores) and the other CPU sharing the same
2372 2372 * DX<-->DCDS interface (all cores)
2373 2373 */
2374 2374
2375 2375 /* reporting cpuid */
2376 2376 cpuid = dpmsg->cpuid & 0x1FF; /* core 0 */
2377 2377 if (cpu[cpuid])
2378 2378 dparray[jj++] = cpuid;
2379 2379
2380 2380 cpuid = dpmsg->cpuid | SG_CORE_ID_MASK; /* core 1 */
2381 2381 if (cpu[cpuid])
2382 2382 dparray[jj++] = cpuid;
2383 2383
2384 2384 /* find partner cpuid */
2385 2385 if (procpos == 0 || procpos == 2)
2386 2386 cpuid = dpmsg->cpuid + 1;
2387 2387 else
2388 2388 cpuid = dpmsg->cpuid - 1;
2389 2389
2390 2390 /* add partner cpuid */
2391 2391 cpuid &= 0x1FF; /* core 0 */
2392 2392 if (cpu[cpuid])
2393 2393 dparray[jj++] = cpuid;
2394 2394
2395 2395 cpuid |= SG_CORE_ID_MASK; /* core 1 */
2396 2396 if (cpu[cpuid])
2397 2397 dparray[jj++] = cpuid;
2398 2398 break;
2399 2399
2400 2400 case DP_RP_TYPE:
2401 2401 /*
2402 2402 * For a RP error, it's all cpuids (all cores) on
2403 2403 * the reporting board
2404 2404 */
2405 2405 for (ii = 0; ii < SG_MAX_CMPS_PER_BD; ii++) {
2406 2406 cpuid = MAKE_CPUID(bd, ii);
2407 2407 if (cpu[cpuid]) /* core 0 */
2408 2408 dparray[jj++] = cpuid;
2409 2409 cpuid |= SG_CORE_ID_MASK;
2410 2410 if (cpu[cpuid]) /* core 1 */
2411 2411 dparray[jj++] = cpuid;
2412 2412 }
2413 2413 break;
2414 2414 }
2415 2415
2416 2416 mutex_exit(&cpu_lock);
2417 2417
2418 2418 /*
2419 2419 * The datapath message could not be associated with any
2420 2420 * configured CPU.
2421 2421 */
2422 2422 if (!jj) {
2423 2423 kmem_free(dparray, num * sizeof (uint16_t *));
2424 2424 ret = nvlist_add_uint32(erp, DP_LIST_SIZE, jj);
2425 2425 ASSERT(ret == 0);
2426 2426 return (-1);
2427 2427 }
2428 2428
2429 2429 snarray = kmem_zalloc(jj * sizeof (uint64_t), KM_SLEEP);
2430 2430 for (ii = 0; ii < jj; ii++)
2431 2431 snarray[ii] = cpunodes[dparray[ii]].device_id;
2432 2432
2433 2433 ret = nvlist_add_uint32(erp, DP_LIST_SIZE, jj);
2434 2434 ret |= nvlist_add_uint16_array(erp, DP_LIST, dparray, jj);
2435 2435 ret |= nvlist_add_uint64_array(erp, SN_LIST, snarray, jj);
2436 2436 ASSERT(ret == 0);
2437 2437
2438 2438 kmem_free(dparray, num * sizeof (uint16_t *));
2439 2439 kmem_free(snarray, jj * sizeof (uint64_t *));
2440 2440
2441 2441 return (0);
2442 2442 }
2443 2443
2444 2444 /*
2445 2445 * sbbc_dp_trans_event() - datapath message handler.
2446 2446 *
2447 2447 * Process datapath error and fault messages received from the SC. Checks
2448 2448 * for, and disregards, messages associated with I/O boards. Otherwise,
2449 2449 * extracts message info to produce a datapath ereport.
2450 2450 */
2451 2451 /*ARGSUSED*/
2452 2452 static uint_t
2453 2453 sbbc_dp_trans_event(char *arg)
2454 2454 {
2455 2455 const char *f = "sbbc_dp_trans_event()";
2456 2456 nvlist_t *erp, *detector, *hcelem;
2457 2457 char buf[FM_MAX_CLASS];
2458 2458 int board;
2459 2459 plat_datapath_info_t *dpmsg;
2460 2460 sbbc_msg_t *msg;
2461 2461 int msgtype;
2462 2462
2463 2463 /* set i/f message and payload pointers */
2464 2464 msg = &dp_payload_msg;
2465 2465 dpmsg = &dp_payload;
2466 2466 msgtype = msg->msg_type.type;
2467 2467
2468 2468 cmn_err(CE_NOTE, "%s: msgtype=0x%x\n", f, msgtype);
2469 2469 cmn_err(CE_NOTE, "type=0x%x cpuid=0x%x t_value=0x%x\n", dpmsg->type,
2470 2470 dpmsg->cpuid, dpmsg->t_value);
2471 2471
2472 2472 /* check for valid type */
2473 2473 if (dpmsg->type > DP_RP_TYPE) {
2474 2474 cmn_err(CE_WARN, "%s: dpmsg type 0x%x invalid\n",
2475 2475 f, dpmsg->type);
2476 2476 return (DDI_INTR_CLAIMED);
2477 2477 }
2478 2478
2479 2479 /* check for I/O board message - Schizo AIDs are 25 - 30 */
2480 2480 if (dpmsg->cpuid > 23) {
2481 2481 cmn_err(CE_NOTE, "%s: ignore I/O board msg\n", f);
2482 2482 return (DDI_INTR_CLAIMED);
2483 2483 }
2484 2484
2485 2485 /* allocate space for ereport */
2486 2486 erp = fm_nvlist_create(NULL);
2487 2487
2488 2488 /*
2489 2489 * Member Name Data Type Comments
2490 2490 * ----------- --------- -----------
2491 2491 * version uint8 0
2492 2492 * class string "asic"
2493 2493 * ENA uint64 ENA Format 1
2494 2494 * detector fmri aggregated ID data for SC-DE
2495 2495 *
2496 2496 * Datapath ereport subclasses and data payloads:
2497 2497 * There will be two types of ereports (error and fault) which will be
2498 2498 * identified by the "type" member.
2499 2499 *
2500 2500 * ereport.asic.serengeti.cds.cds-dp
2501 2501 * ereport.asic.serengeti.dx.dx-dp (board)
2502 2502 * ereport.asic.serengeti.rp.rp-dp (centerplane)
2503 2503 *
2504 2504 * Member Name Data Type Comments
2505 2505 * ----------- --------- -----------
2506 2506 * erptype uint16 derived from message type: error or
2507 2507 * fault
2508 2508 * t-value uint32 SC's datapath SERD timeout threshold
2509 2509 * dp-list-sz uint8 number of dp-list array elements
2510 2510 * dp-list array of uint16 Safari IDs of affected cpus
2511 2511 * sn-list array of uint64 Serial numbers of affected cpus
2512 2512 */
2513 2513
2514 2514 /* compose common ereport elements */
2515 2515 detector = fm_nvlist_create(NULL);
2516 2516
2517 2517 /*
2518 2518 * Create legacy FMRI for the detector
2519 2519 */
2520 2520 board = SG_PORTID_TO_BOARD_NUM(SG_CPUID_TO_PORTID(dpmsg->cpuid));
2521 2521 switch (dpmsg->type) {
2522 2522 case DP_CDS_TYPE:
2523 2523 case DP_DX_TYPE:
2524 2524 (void) snprintf(buf, FM_MAX_CLASS, "SB%d", board);
2525 2525 break;
2526 2526 case DP_RP_TYPE:
2527 2527 (void) snprintf(buf, FM_MAX_CLASS, "RP");
2528 2528 break;
2529 2529 default:
2530 2530 (void) snprintf(buf, FM_MAX_CLASS, "UNKNOWN");
2531 2531 break;
2532 2532 }
2533 2533
2534 2534 hcelem = fm_nvlist_create(NULL);
2535 2535
2536 2536 (void) nvlist_add_string(hcelem, FM_FMRI_HC_NAME, FM_FMRI_LEGACY_HC);
2537 2537 (void) nvlist_add_string(hcelem, FM_FMRI_HC_ID, buf);
2538 2538
2539 2539 (void) nvlist_add_uint8(detector, FM_VERSION, FM_HC_SCHEME_VERSION);
2540 2540 (void) nvlist_add_string(detector, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC);
2541 2541 (void) nvlist_add_string(detector, FM_FMRI_HC_ROOT, "");
2542 2542 (void) nvlist_add_uint32(detector, FM_FMRI_HC_LIST_SZ, 1);
2543 2543 (void) nvlist_add_nvlist_array(detector, FM_FMRI_HC_LIST, &hcelem, 1);
2544 2544
2545 2545 /* build ereport class name */
2546 2546 (void) snprintf(buf, FM_MAX_CLASS, "asic.serengeti.%s.%s-%s",
2547 2547 dperrtype[dpmsg->type], dperrtype[dpmsg->type],
2548 2548 FM_ERROR_DATAPATH);
2549 2549
2550 2550 fm_ereport_set(erp, FM_EREPORT_VERSION, buf,
2551 2551 fm_ena_generate(0, FM_ENA_FMT1), detector, NULL);
2552 2552
2553 2553 /* add payload elements */
2554 2554 if (msgtype == MBOX_EVENT_DP_ERROR)
2555 2555 fm_payload_set(erp,
2556 2556 DP_EREPORT_TYPE, DATA_TYPE_UINT16, DP_ERROR, NULL);
2557 2557 else
2558 2558 fm_payload_set(erp,
2559 2559 DP_EREPORT_TYPE, DATA_TYPE_UINT16, DP_FAULT, NULL);
2560 2560
2561 2561 fm_payload_set(erp, DP_TVALUE, DATA_TYPE_UINT32, dpmsg->t_value, NULL);
2562 2562
2563 2563 (void) dp_payload_add_cpus(dpmsg, erp);
2564 2564
2565 2565 /* post ereport */
2566 2566 fm_ereport_post(erp, EVCH_SLEEP);
2567 2567
2568 2568 /* free ereport memory */
2569 2569 fm_nvlist_destroy(erp, FM_NVA_FREE);
2570 2570 fm_nvlist_destroy(detector, FM_NVA_FREE);
2571 2571
2572 2572 return (DDI_INTR_CLAIMED);
2573 2573 }
2574 2574
2575 2575 static uint_t
2576 2576 sbbc_datapath_error_msg_handler(char *arg)
2577 2577 {
2578 2578 static fn_t f = "sbbc_datapath_error_msg_handler()";
2579 2579 sbbc_msg_t *msg = NULL;
2580 2580
2581 2581 if (arg == NULL) {
2582 2582 SGSBBC_DBG_EVENT(CE_NOTE, "%s: arg == NULL", f);
2583 2583 return (DDI_INTR_UNCLAIMED);
2584 2584 }
2585 2585
2586 2586 msg = (sbbc_msg_t *)arg;
2587 2587
2588 2588 if (msg->msg_buf == NULL) {
2589 2589 SGSBBC_DBG_EVENT(CE_NOTE, "%s: msg_buf == NULL", f);
2590 2590 return (DDI_INTR_UNCLAIMED);
2591 2591 }
2592 2592
2593 2593 msg->msg_type.type = MBOX_EVENT_DP_ERROR;
2594 2594
2595 2595 /* trigger sbbc_dp_trans_event() */
2596 2596 ddi_trigger_softintr(dp_softintr_id);
2597 2597
2598 2598 return (DDI_INTR_CLAIMED);
2599 2599 }
2600 2600
2601 2601 static uint_t
2602 2602 sbbc_datapath_fault_msg_handler(char *arg)
2603 2603 {
2604 2604
2605 2605 static fn_t f = "sbbc_datapath_fault_msg_handler()";
2606 2606
2607 2607 sbbc_msg_t *msg = NULL;
2608 2608
2609 2609 if (arg == NULL) {
2610 2610 SGSBBC_DBG_EVENT(CE_NOTE, "%s: arg == NULL", f);
2611 2611 return (DDI_INTR_UNCLAIMED);
2612 2612 }
2613 2613
2614 2614 msg = (sbbc_msg_t *)arg;
2615 2615
2616 2616 if (msg->msg_buf == NULL) {
2617 2617 SGSBBC_DBG_EVENT(CE_NOTE, "%s: msg_buf == NULL", f);
2618 2618 return (DDI_INTR_UNCLAIMED);
2619 2619 }
2620 2620
2621 2621 msg->msg_type.type = MBOX_EVENT_DP_FAULT;
2622 2622
2623 2623 /* trigger sbbc_dp_trans_event() */
2624 2624 ddi_trigger_softintr(dp_softintr_id);
2625 2625
2626 2626 return (DDI_INTR_CLAIMED);
2627 2627 }
2628 2628
2629 2629 /*
2630 2630 * Log an ECC event message to the SC. This is called from the
2631 2631 * sbbc_ecc_mbox_taskq or directly from plat_send_ecc_mailbox_msg
2632 2632 * for indictment messages.
2633 2633 */
2634 2634 int
2635 2635 sbbc_mbox_ecc_output(sbbc_ecc_mbox_t *msgp)
2636 2636 {
2637 2637 int rv;
2638 2638 plat_capability_data_t *cap;
2639 2639 plat_dimm_sid_board_data_t *ddata;
2640 2640 plat_ecc_msg_hdr_t *hdr;
2641 2641
2642 2642 rv = sbbc_mbox_request_response(&msgp->ecc_req, &msgp->ecc_resp,
2643 2643 sbbc_mbox_default_timeout);
2644 2644
2645 2645 if (rv != 0) {
2646 2646 /*
2647 2647 * Indictment messages use the return value to indicate a
2648 2648 * problem in the mailbox. For Error mailbox messages, we'll
2649 2649 * have to use a syslog message.
2650 2650 */
2651 2651 if (msgp->ecc_log_error) {
2652 2652 if (sbbc_ecc_mbox_send_errs == 0) {
2653 2653 cmn_err(CE_NOTE, "!Solaris failed to send a "
2654 2654 "message (0x%x/0x%x) to the System "
2655 2655 "Controller. Error: %d, Message Status: %d",
2656 2656 msgp->ecc_resp.msg_type.type,
2657 2657 msgp->ecc_resp.msg_type.sub_type,
2658 2658 rv, msgp->ecc_resp.msg_status);
2659 2659 }
2660 2660
2661 2661 if (++sbbc_ecc_mbox_send_errs >=
2662 2662 sbbc_ecc_mbox_err_throttle) {
2663 2663 sbbc_ecc_mbox_send_errs = 0;
2664 2664 }
2665 2665 }
2666 2666
2667 2667 } else if (msgp->ecc_resp.msg_status != 0) {
2668 2668 if (msgp->ecc_resp.msg_type.type == INFO_MBOX) {
2669 2669 switch (msgp->ecc_resp.msg_type.sub_type) {
2670 2670 case INFO_MBOX_ECC:
2671 2671 hdr = (plat_ecc_msg_hdr_t *)
2672 2672 msgp->ecc_req.msg_buf;
2673 2673 if (hdr->emh_msg_type ==
2674 2674 PLAT_ECC_DIMM_SID_MESSAGE) {
2675 2675 rv = msgp->ecc_resp.msg_status;
2676 2676 break;
2677 2677 }
2678 2678 /*FALLTHROUGH*/
2679 2679 case INFO_MBOX_ECC_CAP:
2680 2680 /*
2681 2681 * The positive response comes only
2682 2682 * from the AVL FS1 updated SC.
2683 2683 * If the firmware is either downgraded
2684 2684 * or failover to an older version, then
2685 2685 * lets reset the SC capability to
2686 2686 * default.
2687 2687 */
2688 2688 plat_ecc_capability_sc_set
2689 2689 (PLAT_ECC_CAPABILITY_SC_DEFAULT);
2690 2690 break;
2691 2691 default:
2692 2692 break;
2693 2693 }
2694 2694 }
2695 2695 if (msgp->ecc_log_error) {
2696 2696 if (sbbc_ecc_mbox_inval_errs == 0) {
2697 2697 cmn_err(CE_NOTE, "!An internal error (%d) "
2698 2698 "occurred in the System Controller while "
2699 2699 "processing this message (0x%x/0x%x)",
2700 2700 msgp->ecc_resp.msg_status,
2701 2701 msgp->ecc_resp.msg_type.type,
2702 2702 msgp->ecc_resp.msg_type.sub_type);
2703 2703 }
2704 2704 if (msgp->ecc_resp.msg_status == EINVAL) {
2705 2705 if (++sbbc_ecc_mbox_inval_errs >=
2706 2706 sbbc_ecc_mbox_err_throttle) {
2707 2707 sbbc_ecc_mbox_inval_errs = 0;
2708 2708 }
2709 2709 rv = ENOMSG;
2710 2710 } else {
2711 2711 if (++sbbc_ecc_mbox_other_errs >=
2712 2712 sbbc_ecc_mbox_err_throttle) {
2713 2713 sbbc_ecc_mbox_other_errs = 0;
2714 2714 }
2715 2715 rv = msgp->ecc_resp.msg_status;
2716 2716 }
2717 2717 }
2718 2718
2719 2719 } else {
2720 2720 if (msgp->ecc_resp.msg_type.type == INFO_MBOX) {
2721 2721 switch (msgp->ecc_resp.msg_type.sub_type) {
2722 2722 case INFO_MBOX_ECC_CAP:
2723 2723 /*
2724 2724 * Successfully received the response
2725 2725 * for the capability message, so updating
2726 2726 * the SC ECC messaging capability.
2727 2727 */
2728 2728 cap = (plat_capability_data_t *)
2729 2729 msgp->ecc_resp.msg_buf;
2730 2730 plat_ecc_capability_sc_set
2731 2731 (cap->capd_capability);
2732 2732 break;
2733 2733
2734 2734 case INFO_MBOX_ECC:
2735 2735 hdr = (plat_ecc_msg_hdr_t *)
2736 2736 msgp->ecc_resp.msg_buf;
2737 2737 if (hdr && (hdr->emh_msg_type ==
2738 2738 PLAT_ECC_DIMM_SID_MESSAGE)) {
2739 2739 /*
2740 2740 * Successfully received a response
2741 2741 * to a request for DIMM serial ids.
2742 2742 */
2743 2743 ddata = (plat_dimm_sid_board_data_t *)
2744 2744 msgp->ecc_resp.msg_buf;
2745 2745 (void) plat_store_mem_sids(ddata);
2746 2746 }
2747 2747 break;
2748 2748
2749 2749 default:
2750 2750 break;
2751 2751 }
2752 2752 }
2753 2753 }
2754 2754
2755 2755 if (msgp->ecc_resp.msg_buf)
2756 2756 kmem_free((void *)msgp->ecc_resp.msg_buf,
2757 2757 (size_t)msgp->ecc_resp.msg_len);
2758 2758
2759 2759 kmem_free((void *)msgp->ecc_req.msg_buf, (size_t)msgp->ecc_req.msg_len);
2760 2760 kmem_free(msgp, sizeof (sbbc_ecc_mbox_t));
2761 2761 return (rv);
2762 2762 }
2763 2763
2764 2764 /*
2765 2765 * Enqueue ECC event message on taskq to SC. This is invoked from
2766 2766 * plat_send_ecc_mailbox_msg() for each ECC event generating a message.
2767 2767 */
2768 2768 void
2769 2769 sbbc_mbox_queue_ecc_event(sbbc_ecc_mbox_t *sbbc_ecc_msgp)
2770 2770 {
2771 2771 /*
2772 2772 * Create the ECC event mailbox taskq, if it does not yet exist.
2773 2773 * This must be done here rather than in sbbc_mbox_init(). The
2774 2774 * sgsbbc driver is loaded very early in the boot flow. Calling
2775 2775 * taskq_create() from sbbc_mbox_init could lead to a boot deadlock.
2776 2776 *
2777 2777 * There might be a tiny probability that two ECC handlers on
2778 2778 * different processors could arrive here simultaneously. If
2779 2779 * the taskq has not been created previously, then these two
2780 2780 * simultaneous events could cause the creation of an extra taskq.
2781 2781 * Given the extremely small likelihood (if not outright impossibility)
2782 2782 * of this occurrence, sbbc_ecc_mbox_taskq is not protected by a lock.
2783 2783 */
2784 2784
2785 2785 if (sbbc_ecc_mbox_taskq == NULL) {
2786 2786 sbbc_ecc_mbox_taskq = taskq_create("ECC_event_mailbox", 1,
2787 2787 minclsyspri, ECC_MBOX_TASKQ_MIN, ECC_MBOX_TASKQ_MAX,
2788 2788 TASKQ_PREPOPULATE);
2789 2789 if (sbbc_ecc_mbox_taskq == NULL) {
2790 2790 if (sbbc_ecc_mbox_taskq_errs == 0) {
2791 2791 cmn_err(CE_NOTE, "Unable to create mailbox "
2792 2792 "task queue for ECC event logging to "
2793 2793 "System Controller");
2794 2794 }
2795 2795 if (++sbbc_ecc_mbox_taskq_errs >=
2796 2796 sbbc_ecc_mbox_err_throttle) {
2797 2797 sbbc_ecc_mbox_taskq_errs = 0;
2798 2798 }
2799 2799
2800 2800 kmem_free((void *)sbbc_ecc_msgp->ecc_req.msg_buf,
2801 2801 (size_t)sbbc_ecc_msgp->ecc_req.msg_len);
2802 2802 kmem_free((void *)sbbc_ecc_msgp,
2803 2803 sizeof (sbbc_ecc_mbox_t));
2804 2804 return;
2805 2805 }
2806 2806
2807 2807 /*
2808 2808 * Reset error counter so that first taskq_dispatch
2809 2809 * error will be output
2810 2810 */
2811 2811 sbbc_ecc_mbox_taskq_errs = 0;
2812 2812 }
2813 2813
2814 2814 /*
2815 2815 * Enqueue the message
2816 2816 */
2817 2817
2818 2818 if (taskq_dispatch(sbbc_ecc_mbox_taskq,
2819 2819 (task_func_t *)sbbc_mbox_ecc_output, sbbc_ecc_msgp,
2820 2820 TQ_NOSLEEP) == NULL) {
2821 2821
2822 2822 if (sbbc_ecc_mbox_taskq_errs == 0) {
2823 2823 cmn_err(CE_NOTE, "Unable to send ECC event "
2824 2824 "message to System Controller");
2825 2825 }
2826 2826 if (++sbbc_ecc_mbox_taskq_errs >= sbbc_ecc_mbox_err_throttle) {
2827 2827 sbbc_ecc_mbox_taskq_errs = 0;
2828 2828 }
2829 2829
2830 2830 kmem_free((void *)sbbc_ecc_msgp->ecc_req.msg_buf,
2831 2831 (size_t)sbbc_ecc_msgp->ecc_req.msg_len);
2832 2832 kmem_free((void *)sbbc_ecc_msgp, sizeof (sbbc_ecc_mbox_t));
2833 2833 }
2834 2834 }
2835 2835
2836 2836 static uint_t
2837 2837 cap_ecc_msg_handler(char *addr)
2838 2838 {
2839 2839 sbbc_msg_t *msg = NULL;
2840 2840 plat_capability_data_t *cap = NULL;
2841 2841 static fn_t f = "cap_ecc_msg_handler";
2842 2842
2843 2843 msg = (sbbc_msg_t *)addr;
2844 2844
2845 2845 if (msg == NULL) {
2846 2846 SGSBBC_DBG_EVENT(CE_WARN, "cap_ecc_msg_handler() called with "
2847 2847 "null addr");
2848 2848 return (DDI_INTR_CLAIMED);
2849 2849 }
2850 2850
2851 2851 if (msg->msg_buf == NULL) {
2852 2852 SGSBBC_DBG_EVENT(CE_WARN, "cap_ecc_msg_handler() called with "
2853 2853 "null data buffer");
2854 2854 return (DDI_INTR_CLAIMED);
2855 2855 }
2856 2856
2857 2857 cap = (plat_capability_data_t *)msg->msg_buf;
2858 2858 switch (cap->capd_msg_type) {
2859 2859 case PLAT_ECC_CAPABILITY_MESSAGE:
2860 2860 SGSBBC_DBG_MBOX("%s: capability 0x%x\n", f,
2861 2861 cap->capd_capability);
2862 2862 plat_ecc_capability_sc_set(cap->capd_capability);
2863 2863 break;
2864 2864 default:
2865 2865 SGSBBC_DBG_MBOX("%s: Unknown message type = 0x%x\n", f,
2866 2866 cap->capd_msg_type);
2867 2867 break;
2868 2868 }
2869 2869
2870 2870 return (DDI_INTR_CLAIMED);
2871 2871 }
↓ open down ↓ |
1938 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX