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