1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28 /*
29 * PCI SBBC Device Driver that provides interfaces into
30 * EPLD and IO-SRAM
31 *
32 */
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <sys/errno.h>
36 #include <sys/file.h>
37 #include <sys/cmn_err.h>
38 #include <sys/stropts.h>
39 #include <sys/kmem.h>
40 #include <sys/sunndi.h>
41 #include <sys/conf.h> /* req. by dev_ops flags MTSAFE etc. */
42 #include <sys/modctl.h> /* for modldrv */
43 #include <sys/promif.h>
44 #include <sys/stat.h>
45 #include <sys/ddi.h>
46
47 #include <sys/serengeti.h>
48 #include <sys/sgsbbc_priv.h>
49 #include <sys/sgsbbc_iosram_priv.h>
50 #include <sys/sgsbbc_mailbox_priv.h>
51
52 #ifdef DEBUG
53 /* debug flag */
54 uint_t sgsbbc_debug = 0;
55 #endif /* DEBUG */
56
57 /* driver entry point fn definitions */
58 static int sbbc_attach(dev_info_t *, ddi_attach_cmd_t);
59 static int sbbc_detach(dev_info_t *, ddi_detach_cmd_t);
60
61 /*
62 * SBBC soft state hook
63 */
64 static void *sbbcp;
65
66 /*
67 * Chosen IOSRAM
68 */
69 struct chosen_iosram *master_iosram = NULL;
70
71 /*
72 * define new iosram's sbbc and liked list of sbbc.
73 */
74 struct sbbc_softstate *sgsbbc_instances = NULL;
75
76 /*
77 * At attach time, check if the device is the 'chosen' node
78 * if it is, set up the IOSRAM Solaris<->SC Comm tunnel
79 * Its like 'Highlander' - there can be only one !
80 */
81 static int master_chosen = FALSE;
82 kmutex_t chosen_lock;
83
84 /*
85 * Local variable to save intr_in_enabled when the driver is suspended
86 */
87 static uint32_t intr_in_enabled;
88
89 /*
90 * Local declarations
91 */
92 static void softsp_init(sbbc_softstate_t *, dev_info_t *);
93 static void sbbc_chosen_init(sbbc_softstate_t *);
94 static void sbbc_add_instance(sbbc_softstate_t *);
95 static void sbbc_remove_instance(sbbc_softstate_t *);
96 static int sbbc_find_dip(dev_info_t *, void *);
97 static void sbbc_unmap_regs(sbbc_softstate_t *);
98
99 /*
100 * ops stuff.
101 */
102 static struct cb_ops sbbc_cb_ops = {
103 nodev, /* cb_open */
104 nodev, /* cb_close */
105 nodev, /* cb_strategy */
106 nodev, /* cb_print */
107 nodev, /* cb_dump */
108 nodev, /* cb_read */
109 nodev, /* cb_write */
110 nodev, /* cb_ioctl */
111 nodev, /* cb_devmap */
112 nodev, /* cb_mmap */
113 nodev, /* cb_segmap */
114 nochpoll, /* cb_chpoll */
115 ddi_prop_op, /* cb_prop_op */
116 NULL, /* cb_stream */
117 D_NEW | D_MP /* cb_flag */
118 };
119
120 /*
121 * Declare ops vectors for auto configuration.
122 */
123 struct dev_ops sbbc_ops = {
124 DEVO_REV, /* devo_rev */
125 0, /* devo_refcnt */
126 ddi_getinfo_1to1, /* devo_getinfo */
127 nulldev, /* devo_identify */
128 nulldev, /* devo_probe */
129 sbbc_attach, /* devo_attach */
130 sbbc_detach, /* devo_detach */
131 nodev, /* devo_reset */
132 &sbbc_cb_ops, /* devo_cb_ops */
133 (struct bus_ops *)NULL, /* devo_bus_ops */
134 nulldev, /* devo_power */
135 ddi_quiesce_not_supported, /* devo_quiesce */
136 };
137
138 /*
139 * Loadable module support.
140 */
141 extern struct mod_ops mod_driverops;
142
143 static struct modldrv modldrv = {
144 &mod_driverops, /* type of module - driver */
145 "PCI SBBC",
146 &sbbc_ops,
147 };
148
149 static struct modlinkage modlinkage = {
150 MODREV_1,
151 (void *)&modldrv,
152 NULL
153 };
154
155 int
_init(void)156 _init(void)
157 {
158 int error;
159
160 if ((error = ddi_soft_state_init(&sbbcp,
161 sizeof (sbbc_softstate_t), 1)) != 0)
162 return (error);
163
164 if ((error = mod_install(&modlinkage)) != 0) {
165 ddi_soft_state_fini(&sbbcp);
166 return (error);
167 }
168
169 /*
170 * Initialise the global 'chosen' IOSRAM mutex
171 */
172 mutex_init(&chosen_lock, NULL, MUTEX_DEFAULT, NULL);
173
174 /*
175 * Initialise the iosram driver
176 */
177 iosram_init();
178
179 /*
180 * Initialize the mailbox
181 */
182 sbbc_mbox_init();
183
184 return (error);
185
186 }
187
188 int
_fini(void)189 _fini(void)
190 {
191 int error;
192
193 if ((error = mod_remove(&modlinkage)) == 0)
194 ddi_soft_state_fini(&sbbcp);
195
196 master_chosen = FALSE;
197
198 mutex_destroy(&chosen_lock);
199
200 /*
201 * remove the mailbox
202 */
203 sbbc_mbox_fini();
204
205 /*
206 * remove the iosram driver
207 */
208 iosram_fini();
209
210 return (error);
211 }
212
213 int
_info(struct modinfo * modinfop)214 _info(struct modinfo *modinfop)
215 {
216 return (mod_info(&modlinkage, modinfop));
217 }
218
219 static int
sbbc_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)220 sbbc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
221 {
222 int instance;
223 sbbc_softstate_t *softsp;
224 uint32_t *pci_intr_enable_reg;
225 int len;
226 #ifdef DEBUG
227 char name[8];
228 #endif /* DEBUG */
229
230 instance = ddi_get_instance(devi);
231
232 switch (cmd) {
233 case DDI_ATTACH:
234
235 if (ddi_soft_state_zalloc(sbbcp, instance) != 0)
236 return (DDI_FAILURE);
237
238 softsp = ddi_get_soft_state(sbbcp, instance);
239 softsp->sbbc_instance = instance;
240
241 /*
242 * Set the dip in the soft state
243 * And get interrupt cookies and initialize the
244 * per instance mutex.
245 */
246 softsp_init(softsp, devi);
247
248
249 /*
250 * Verify that an 'interrupts' property exists for
251 * this device. If not, this instance will be ignored.
252 */
253 if (ddi_getproplen(DDI_DEV_T_ANY, softsp->dip,
254 DDI_PROP_DONTPASS, "interrupts",
255 &len) != DDI_PROP_SUCCESS) {
256 SBBC_ERR1(CE_WARN, "No 'interrupts' property for the "
257 "SBBC instance %d\n", instance);
258 return (DDI_FAILURE);
259 }
260 /*
261 * Add this instance to the sbbc chosen iosram list
262 * so that it can be used for tunnel switch.
263 */
264 mutex_enter(&chosen_lock);
265 softsp->sbbc_state = SBBC_STATE_INIT;
266 sbbc_add_instance(softsp);
267
268 /*
269 * If this is the chosen IOSRAM and there is no master IOSRAM
270 * yet, then let's set this instance as the master.
271 * if there is a master alreay due to the previous tunnel switch
272 * then keep as is even though this is the chosen.
273 */
274 if (sgsbbc_iosram_is_chosen(softsp)) {
275 ASSERT(master_iosram);
276 softsp->iosram = master_iosram;
277 master_iosram->sgsbbc = softsp;
278
279 /* Do 'chosen' init only */
280 sbbc_chosen_init(softsp);
281 }
282
283 mutex_exit(&chosen_lock);
284 #ifdef DEBUG
285 (void) sprintf(name, "sbbc%d", instance);
286
287 if (ddi_create_minor_node(devi, name, S_IFCHR, instance,
288 NULL, NULL) == DDI_FAILURE) {
289 mutex_destroy(&softsp->sbbc_lock);
290 ddi_remove_minor_node(devi, NULL);
291 ddi_soft_state_free(sbbcp, instance);
292 return (DDI_FAILURE);
293 }
294 #endif /* DEBUG */
295
296 ddi_report_dev(devi);
297
298 return (DDI_SUCCESS);
299
300 case DDI_RESUME:
301
302 if (!(softsp = ddi_get_soft_state(sbbcp, instance)))
303 return (DDI_FAILURE);
304
305 mutex_enter(&softsp->sbbc_lock);
306 if ((softsp->suspended == TRUE) && (softsp->chosen == TRUE)) {
307 /*
308 * Enable Interrupts now, turn on both INT#A lines
309 */
310 pci_intr_enable_reg = (uint32_t *)
311 ((char *)softsp->sbbc_regs +
312 SBBC_PCI_INT_ENABLE);
313
314 ddi_put32(softsp->sbbc_reg_handle1,
315 pci_intr_enable_reg,
316 (uint32_t)SBBC_PCI_ENABLE_INT_A);
317
318 /*
319 * Reset intr_in_enabled to the original value
320 * so the SC can send us interrupt.
321 */
322 if (iosram_write(SBBC_SC_INTR_ENABLED_KEY,
323 0, (caddr_t)&intr_in_enabled,
324 sizeof (intr_in_enabled))) {
325
326 mutex_exit(&softsp->sbbc_lock);
327 return (DDI_FAILURE);
328 }
329 }
330 softsp->suspended = FALSE;
331
332 mutex_exit(&softsp->sbbc_lock);
333
334 return (DDI_SUCCESS);
335
336 default:
337 return (DDI_FAILURE);
338 }
339 }
340
341 static int
sbbc_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)342 sbbc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
343 {
344 sbbc_softstate_t *softsp;
345 int instance;
346 uint32_t *pci_intr_enable_reg;
347 int rc = DDI_SUCCESS;
348
349 instance = ddi_get_instance(devi);
350
351 if (!(softsp = ddi_get_soft_state(sbbcp, instance)))
352 return (DDI_FAILURE);
353
354 switch (cmd) {
355 case DDI_DETACH:
356 mutex_enter(&chosen_lock);
357 softsp->sbbc_state |= SBBC_STATE_DETACH;
358 mutex_exit(&chosen_lock);
359
360 /* only tunnel switch the instance with iosram chosen */
361 if (softsp->chosen == TRUE) {
362 if (sgsbbc_iosram_switchfrom(softsp) == DDI_FAILURE) {
363 SBBC_ERR(CE_WARN, "Cannot unconfigure: "
364 "tunnel switch failed\n");
365 return (DDI_FAILURE);
366 }
367 }
368
369 /* Adjust linked list */
370 mutex_enter(&chosen_lock);
371 sbbc_remove_instance(softsp);
372 mutex_exit(&chosen_lock);
373
374 sbbc_unmap_regs(softsp);
375 mutex_destroy(&softsp->sbbc_lock);
376 ddi_soft_state_free(sbbcp, instance);
377
378 return (DDI_SUCCESS);
379
380 case DDI_SUSPEND:
381
382 mutex_enter(&softsp->sbbc_lock);
383
384 if ((softsp->suspended == FALSE) && (softsp->chosen == TRUE)) {
385 uint32_t tmp_intr_enabled = 0;
386
387 /*
388 * Disable Interrupts now, turn OFF both INT#A lines
389 */
390 pci_intr_enable_reg = (uint32_t *)
391 ((char *)softsp->sbbc_regs +
392 SBBC_PCI_INT_ENABLE);
393
394 ddi_put32(softsp->sbbc_reg_handle1,
395 pci_intr_enable_reg, 0);
396
397 /*
398 * Set intr_in_enabled to 0 so the SC won't send
399 * us interrupt.
400 */
401 rc = iosram_read(SBBC_SC_INTR_ENABLED_KEY,
402 0, (caddr_t)&intr_in_enabled,
403 sizeof (intr_in_enabled));
404
405 if (rc) {
406 mutex_exit(&softsp->sbbc_lock);
407 return (DDI_FAILURE);
408 }
409
410 rc = iosram_write(SBBC_SC_INTR_ENABLED_KEY,
411 0, (caddr_t)&tmp_intr_enabled,
412 sizeof (tmp_intr_enabled));
413
414 if (rc) {
415 mutex_exit(&softsp->sbbc_lock);
416 return (DDI_FAILURE);
417 }
418 }
419 softsp->suspended = TRUE;
420
421 mutex_exit(&softsp->sbbc_lock);
422
423 return (DDI_SUCCESS);
424
425 default:
426 return (DDI_FAILURE);
427 }
428
429 }
430
431 static void
softsp_init(sbbc_softstate_t * softsp,dev_info_t * devi)432 softsp_init(sbbc_softstate_t *softsp, dev_info_t *devi)
433 {
434 softsp->dip = devi;
435
436 /*
437 * XXXX
438 * ddi_get_iblock_cookie() here because we need
439 * to initialise the mutex regardless of whether
440 * or not this SBBC will eventually
441 * register an interrupt handler
442 */
443
444 (void) ddi_get_iblock_cookie(devi, 0, &softsp->iblock);
445
446 mutex_init(&softsp->sbbc_lock, NULL, MUTEX_DRIVER,
447 (void *)softsp->iblock);
448
449 softsp->suspended = FALSE;
450 softsp->chosen = FALSE;
451 }
452
453 static int
sbbc_find_dip(dev_info_t * dip,void * arg)454 sbbc_find_dip(dev_info_t *dip, void *arg)
455 {
456 char *node_name;
457 sbbc_find_dip_t *dip_struct = (sbbc_find_dip_t *)arg;
458 char status[OBP_MAXPROPNAME];
459
460 /*
461 * Need to find a node named "bootbus-controller" that is neither
462 * disabled nor failed. If a node is not ok, there will be an
463 * OBP status property. Therefore, we will look for a node
464 * without the status property.
465 */
466 node_name = ddi_node_name(dip);
467 if (strcmp(node_name, "bootbus-controller") == 0 && DDI_CF2(dip) &&
468 (prom_getprop(ddi_get_nodeid(dip),
469 "status", (caddr_t)status) == -1) &&
470 (prom_getprop(ddi_get_nodeid(ddi_get_parent(dip)),
471 "status", (caddr_t)status) == -1)) {
472
473 if (dip != dip_struct->cur_dip) {
474 dip_struct->new_dip = (void *)dip;
475 return (DDI_WALK_TERMINATE);
476 }
477 }
478
479 return (DDI_WALK_CONTINUE);
480 }
481
482 /*
483 * SBBC Interrupt Handler
484 *
485 * Check the SBBC Port Interrupt Status
486 * register to verify that its our interrupt.
487 * If yes, clear the register.
488 *
489 * Then read the 'interrupt reason' field from SRAM,
490 * this triggers the appropriate soft_intr handler
491 */
492 uint_t
sbbc_intr_handler(caddr_t arg)493 sbbc_intr_handler(caddr_t arg)
494 {
495 sbbc_softstate_t *softsp = (sbbc_softstate_t *)arg;
496 uint32_t *port_int_reg;
497 volatile uint32_t port_int_status;
498 volatile uint32_t intr_reason;
499 uint32_t intr_enabled;
500 sbbc_intrs_t *intr;
501 int i, intr_mask;
502 struct tunnel_key tunnel_key;
503 ddi_acc_handle_t intr_in_handle;
504 uint32_t *intr_in_reason;
505
506 if (softsp == (sbbc_softstate_t *)NULL) {
507
508 return (DDI_INTR_UNCLAIMED);
509 }
510
511 mutex_enter(&softsp->sbbc_lock);
512
513 if (softsp->port_int_regs == NULL) {
514 mutex_exit(&softsp->sbbc_lock);
515 return (DDI_INTR_UNCLAIMED);
516 }
517
518 /*
519 * Normally if port_int_status is 0, we assume it is not
520 * our interrupt. However, we don't want to miss the
521 * ones that come in during tunnel switch. Therefore,
522 * we always check the interrupt reason bits in IOSRAM
523 * to be sure.
524 */
525 port_int_reg = softsp->port_int_regs;
526
527 port_int_status = ddi_get32(softsp->sbbc_reg_handle1, port_int_reg);
528
529 /*
530 * Generate a softint for each interrupt
531 * bit set in the intr_in_reason field in SRAM
532 * that has a corresponding bit set in the
533 * intr_in_enabled field in SRAM
534 */
535
536 if (iosram_read(SBBC_SC_INTR_ENABLED_KEY, 0,
537 (caddr_t)&intr_enabled, sizeof (intr_enabled))) {
538
539 goto intr_handler_exit;
540 }
541
542 tunnel_key = master_iosram->tunnel->tunnel_keys[SBBC_SC_INTR_KEY];
543 intr_in_reason = (uint32_t *)tunnel_key.base;
544 intr_in_handle = tunnel_key.reg_handle;
545
546 intr_reason = ddi_get32(intr_in_handle, intr_in_reason);
547
548 SGSBBC_DBG_INTR(CE_CONT, "intr_reason = %x\n", intr_reason);
549
550 intr_reason &= intr_enabled;
551
552 for (i = 0; i < SBBC_MAX_INTRS; i++) {
553 intr_mask = (1 << i);
554 if (intr_reason & intr_mask) {
555 intr = &softsp->intr_hdlrs[i];
556 if ((intr != NULL) &&
557 (intr->sbbc_intr_id != 0)) {
558 /*
559 * XXXX
560 * The model we agree with a handler
561 * is that they run until they have
562 * exhausted all work. To avoid
563 * triggering them again, they pass
564 * a state flag and lock when registering.
565 * We check the flag, if they are idle,
566 * we trigger.
567 * The interrupt handler should so
568 * intr_func()
569 * mutex_enter(sbbc_intr_lock);
570 * sbbc_intr_state = RUNNING;
571 * mutex_exit(sbbc_intr_lock);
572 * ..........
573 * ..........
574 * ..........
575 * mutex_enter(sbbc_intr_lock);
576 * sbbc_intr_state = IDLE;
577 * mutex_exit(sbbc_intr_lock);
578 *
579 * XXXX
580 */
581 mutex_enter(intr->sbbc_intr_lock);
582 if (*(intr->sbbc_intr_state) ==
583 SBBC_INTR_IDLE) {
584 mutex_exit(intr->sbbc_intr_lock);
585 ddi_trigger_softintr(
586 intr->sbbc_intr_id);
587 } else {
588 /*
589 * The handler is running
590 */
591 mutex_exit(intr->sbbc_intr_lock);
592 }
593 intr_reason &= ~intr_mask;
594 /*
595 * Clear the corresponding reason bit in SRAM
596 *
597 * Since there is no interlocking between
598 * Solaris and the SC when writing to SRAM,
599 * it is possible for the SC to set another
600 * bit in the interrupt reason field while
601 * we are handling the current interrupt.
602 * To minimize the window in which an
603 * additional bit can be set, reading
604 * and writing the interrupt reason
605 * in SRAM must be as close as possible.
606 */
607 ddi_put32(intr_in_handle, intr_in_reason,
608 ddi_get32(intr_in_handle,
609 intr_in_reason) & ~intr_mask);
610 }
611 }
612 if (intr_reason == 0) /* No more interrupts to be processed */
613 break;
614 }
615
616 /*
617 * Clear the Interrupt Status Register (RW1C)
618 */
619 ddi_put32(softsp->sbbc_reg_handle1, port_int_reg, port_int_status);
620
621 port_int_status = ddi_get32(softsp->sbbc_reg_handle1, port_int_reg);
622
623 intr_handler_exit:
624
625 mutex_exit(&softsp->sbbc_lock);
626
627 return (DDI_INTR_CLAIMED);
628
629 }
630
631 /*
632 * If we don't already have a master SBBC selected,
633 * get the <sbbc> property from the /chosen node. If
634 * the pathname matches, this is the master SBBC and
635 * we set up the console/TOD SRAM mapping here.
636 */
637 static void
sbbc_chosen_init(sbbc_softstate_t * softsp)638 sbbc_chosen_init(sbbc_softstate_t *softsp)
639 {
640 char master_sbbc[MAXNAMELEN];
641 char pn[MAXNAMELEN];
642 int nodeid, len;
643 pnode_t dnode;
644
645 if (master_chosen != FALSE) {
646 /*
647 * We've got one already
648 */
649 return;
650 }
651
652 /*
653 * Get /chosen node info. prom interface will handle errors.
654 */
655 dnode = prom_chosennode();
656
657 /*
658 * Look for the "iosram" property on the chosen node with a prom
659 * interface as ddi_find_devinfo() couldn't be used (calls
660 * ddi_walk_devs() that creates one extra lock on the device tree).
661 */
662 if (prom_getprop(dnode, IOSRAM_CHOSEN_PROP, (caddr_t)&nodeid) <= 0) {
663 /*
664 * No I/O Board SBBC set up as console, what to do ?
665 */
666 SBBC_ERR(CE_PANIC, "No SBBC found for Console/TOD \n");
667 }
668
669 if (prom_getprop(dnode, IOSRAM_TOC_PROP,
670 (caddr_t)&softsp->sram_toc) <= 0) {
671 /*
672 * SRAM TOC Offset defaults to 0
673 */
674 SBBC_ERR(CE_WARN, "No SBBC TOC Offset found\n");
675 softsp->sram_toc = 0;
676 }
677
678 /*
679 * get the full OBP pathname of this node
680 */
681 if (prom_phandle_to_path((phandle_t)nodeid, master_sbbc,
682 sizeof (master_sbbc)) < 0) {
683
684 SBBC_ERR1(CE_PANIC, "prom_phandle_to_path(%d) failed\n",
685 nodeid);
686 }
687 SGSBBC_DBG_ALL("chosen pathname : %s\n", master_sbbc);
688 SGSBBC_DBG_ALL("device pathname : %s\n", ddi_pathname(softsp->dip, pn));
689 if (strcmp(master_sbbc, ddi_pathname(softsp->dip, pn)) == 0) {
690
691 /*
692 * map in the SBBC regs
693 */
694
695 if (sbbc_map_regs(softsp) != DDI_SUCCESS) {
696 SBBC_ERR(CE_PANIC, "Can't map the SBBC regs \n");
697 }
698 /*
699 * Only the 'chosen' node is used for iosram_read()/_write()
700 * Must initialise the tunnel before the console/tod
701 *
702 */
703 if (iosram_tunnel_init(softsp) == DDI_FAILURE) {
704 SBBC_ERR(CE_PANIC, "Can't create the SRAM <-> SC "
705 "comm. tunnel \n");
706 }
707
708 master_chosen = TRUE;
709
710 /*
711 * Verify that an 'interrupts' property
712 * exists for this device
713 */
714
715 if (ddi_getproplen(DDI_DEV_T_ANY, softsp->dip,
716 DDI_PROP_DONTPASS, "interrupts",
717 &len) != DDI_PROP_SUCCESS) {
718
719 SBBC_ERR(CE_PANIC, "No 'interrupts' property for the "
720 "'chosen' SBBC \n");
721 }
722
723 /*
724 * add the interrupt handler
725 * NB
726 * should this be a high-level interrupt ?
727 * NB
728 */
729 if (sbbc_add_intr(softsp) == DDI_FAILURE) {
730 SBBC_ERR(CE_PANIC, "Can't add interrupt handler for "
731 "'chosen' SBBC \n");
732 }
733
734 sbbc_enable_intr(softsp);
735
736 /*
737 * Create the mailbox
738 */
739 if (sbbc_mbox_create(softsp) != 0) {
740 cmn_err(CE_WARN, "No IOSRAM MailBox created!\n");
741 }
742
743 }
744 }
745 /*
746 * sbbc_add_instance
747 * Must be called to hold chosen_lock.
748 */
749 static void
sbbc_add_instance(sbbc_softstate_t * softsp)750 sbbc_add_instance(sbbc_softstate_t *softsp)
751 {
752 #ifdef DEBUG
753 struct sbbc_softstate *sp;
754 #endif
755
756 ASSERT(mutex_owned(&chosen_lock));
757
758 #if defined(DEBUG)
759 /* Verify that this instance is not in the list yet */
760 for (sp = sgsbbc_instances; sp != NULL; sp = sp->next) {
761 ASSERT(sp != softsp);
762 }
763 #endif
764
765 /*
766 * Add this instance to the front of the list.
767 */
768 if (sgsbbc_instances != NULL) {
769 sgsbbc_instances->prev = softsp;
770 }
771
772 softsp->next = sgsbbc_instances;
773 softsp->prev = NULL;
774 sgsbbc_instances = softsp;
775 }
776
777 static void
sbbc_remove_instance(sbbc_softstate_t * softsp)778 sbbc_remove_instance(sbbc_softstate_t *softsp)
779 {
780 struct sbbc_softstate *sp;
781
782 for (sp = sgsbbc_instances; sp != NULL; sp = sp->next) {
783 if (sp == softsp) {
784 if (sp->next != NULL) {
785 sp->next->prev = sp->prev;
786 }
787 if (sp->prev != NULL) {
788 sp->prev->next = sp->next;
789 }
790 if (sgsbbc_instances == softsp) {
791 sgsbbc_instances = sp->next;
792 }
793 break;
794 }
795 }
796 }
797
798 /*
799 * Generate an SBBC interrupt to the SC
800 * Called from iosram_send_intr()
801 *
802 * send_intr == 0, check if EPLD register clear
803 * for sync'ing SC/OS
804 * send_intr == 1, send the interrupt
805 */
806 int
sbbc_send_intr(sbbc_softstate_t * softsp,int send_intr)807 sbbc_send_intr(sbbc_softstate_t *softsp, int send_intr)
808 {
809
810 uchar_t *epld_int;
811 volatile uchar_t epld_status;
812
813 ASSERT(MUTEX_HELD(&master_iosram->iosram_lock));
814
815 if ((softsp == (sbbc_softstate_t *)NULL) ||
816 (softsp->epld_regs == (struct sbbc_epld_regs *)NULL))
817 return (ENXIO);
818
819 /*
820 * Check the L1 EPLD Interrupt register. If the
821 * interrupt bit is set, theres an interrupt outstanding
822 * (we assume) so return (EBUSY).
823 */
824
825 epld_int = &softsp->epld_regs->epld_reg[EPLD_INTERRUPT];
826
827 epld_status = ddi_get8(softsp->sbbc_reg_handle2, epld_int);
828
829 if (epld_status & INTERRUPT_ON)
830 return (EBUSY);
831
832 if (send_intr == TRUE)
833 ddi_put8(softsp->sbbc_reg_handle2, epld_int,
834 (epld_status | INTERRUPT_ON));
835
836 return (0);
837 }
838
839 /*
840 * Map SBBC Internal registers
841 *
842 * The call to function should be protected by
843 * chosen_lock or master_iosram->iosram_lock
844 * to make sure a tunnel switch will not occur
845 * in a middle of mapping.
846 */
847 int
sbbc_map_regs(sbbc_softstate_t * softsp)848 sbbc_map_regs(sbbc_softstate_t *softsp)
849 {
850 struct ddi_device_acc_attr attr;
851
852 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
853 attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
854 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
855
856 /*
857 * Map in register set 1, Common Device Regs
858 * SBCC offset 0x0
859 */
860 if (ddi_regs_map_setup(softsp->dip, RNUM_SBBC_REGS,
861 (caddr_t *)&softsp->sbbc_regs,
862 SBBC_REGS_OFFSET, SBBC_REGS_SIZE,
863 &attr, &softsp->sbbc_reg_handle1) != DDI_SUCCESS) {
864
865 cmn_err(CE_WARN, "sbbc%d: unable to map interrupt "
866 "registers", ddi_get_instance(softsp->dip));
867 return (DDI_FAILURE);
868 }
869 /*
870 * Map in using register set 1, EPLD
871 * SBCC offset 0xe000
872 */
873 if (ddi_regs_map_setup(softsp->dip, RNUM_SBBC_REGS,
874 (caddr_t *)&softsp->epld_regs,
875 SBBC_EPLD_OFFSET, SBBC_EPLD_SIZE,
876 &attr, &softsp->sbbc_reg_handle2) != DDI_SUCCESS) {
877
878 cmn_err(CE_WARN, "sbbc%d: unable to map EPLD "
879 "registers", ddi_get_instance(softsp->dip));
880 return (DDI_FAILURE);
881 }
882
883 /*
884 * Set up pointers for registers
885 */
886 softsp->port_int_regs = (uint32_t *)((char *)softsp->sbbc_regs +
887 SBBC_PCI_INT_STATUS);
888
889 map_regs_exit:
890 return (DDI_SUCCESS);
891 }
892
893
894 /*
895 * Unmap SBBC Internal registers
896 */
897 static void
sbbc_unmap_regs(sbbc_softstate_t * softsp)898 sbbc_unmap_regs(sbbc_softstate_t *softsp)
899 {
900 if (softsp == NULL)
901 return;
902
903 mutex_enter(&master_iosram->iosram_lock);
904
905 if (softsp->sbbc_regs) {
906 ddi_regs_map_free(&softsp->sbbc_reg_handle1);
907 softsp->sbbc_regs = NULL;
908 softsp->port_int_regs = NULL;
909 }
910
911 if (softsp->epld_regs) {
912 ddi_regs_map_free(&softsp->sbbc_reg_handle2);
913 softsp->epld_regs = NULL;
914 }
915
916 mutex_exit(&master_iosram->iosram_lock);
917
918 return;
919
920 }
921 /*
922 * This is here to allow the IOSRAM driver get the softstate
923 * for a chosen node when doing a tunnel switch. Just enables
924 * us to avoid exporting the sbbcp softstate hook
925 */
926 sbbc_softstate_t *
sbbc_get_soft_state(int instance)927 sbbc_get_soft_state(int instance)
928 {
929 return (ddi_get_soft_state(sbbcp, instance));
930 }
931
932 /*
933 * Add interrupt handlers
934 */
935 int
sbbc_add_intr(sbbc_softstate_t * softsp)936 sbbc_add_intr(sbbc_softstate_t *softsp)
937 {
938 int rc = DDI_SUCCESS;
939
940 /*
941 * map in the SBBC interrupts
942 * Note that the iblock_cookie was initialised
943 * in the 'attach' routine
944 */
945
946 if (ddi_add_intr(softsp->dip, 0, &softsp->iblock,
947 &softsp->idevice, sbbc_intr_handler,
948 (caddr_t)softsp) != DDI_SUCCESS) {
949
950 cmn_err(CE_WARN, "Can't register SBBC "
951 " interrupt handler\n");
952 rc = DDI_FAILURE;
953 }
954
955 return (rc);
956 }
957
958 void
sbbc_enable_intr(sbbc_softstate_t * softsp)959 sbbc_enable_intr(sbbc_softstate_t *softsp)
960 {
961 uint32_t *pci_intr_enable_reg;
962
963 /*
964 * Enable Interrupts now, turn on both INT#A lines
965 */
966 pci_intr_enable_reg = (uint32_t *)((char *)softsp->sbbc_regs +
967 SBBC_PCI_INT_ENABLE);
968 ddi_put32(softsp->sbbc_reg_handle1, pci_intr_enable_reg,
969 (uint32_t)SBBC_PCI_ENABLE_INT_A);
970 }
971
972 void
sbbc_disable_intr(sbbc_softstate_t * softsp)973 sbbc_disable_intr(sbbc_softstate_t *softsp)
974 {
975 uint32_t *pci_intr_enable_reg;
976
977 /*
978 * Disable Interrupts now, turn off both INT#A lines
979 */
980 pci_intr_enable_reg = (uint32_t *)((char *)softsp->sbbc_regs +
981 SBBC_PCI_INT_ENABLE);
982 ddi_put32(softsp->sbbc_reg_handle1, pci_intr_enable_reg, 0);
983 }
984