xref: /illumos-gate/usr/src/uts/sun4v/io/cnex.c (revision a86b630751e645f5c8cdc1ac7f5acee522cf9ba0)
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  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Logical domain channel devices are devices implemented entirely
30  * in software; cnex is the nexus for channel-devices. They use
31  * the HV channel interfaces via the LDC transport module to send
32  * and receive data and to register callbacks.
33  */
34 
35 #include <sys/types.h>
36 #include <sys/cmn_err.h>
37 #include <sys/conf.h>
38 #include <sys/ddi.h>
39 #include <sys/ddi_impldefs.h>
40 #include <sys/devops.h>
41 #include <sys/instance.h>
42 #include <sys/modctl.h>
43 #include <sys/open.h>
44 #include <sys/stat.h>
45 #include <sys/sunddi.h>
46 #include <sys/sunndi.h>
47 #include <sys/systm.h>
48 #include <sys/mkdev.h>
49 #include <sys/machsystm.h>
50 #include <sys/intr.h>
51 #include <sys/ddi_intr_impl.h>
52 #include <sys/ivintr.h>
53 #include <sys/hypervisor_api.h>
54 #include <sys/ldc.h>
55 #include <sys/cnex.h>
56 #include <sys/mach_descrip.h>
57 
58 /*
59  * Internal functions/information
60  */
61 static struct cnex_pil_map cnex_class_to_pil[] = {
62 	{LDC_DEV_GENERIC,	PIL_3},
63 	{LDC_DEV_BLK,		PIL_4},
64 	{LDC_DEV_BLK_SVC,	PIL_3},
65 	{LDC_DEV_NT,		PIL_6},
66 	{LDC_DEV_NT_SVC,	PIL_4},
67 	{LDC_DEV_SERIAL,	PIL_6}
68 };
69 #define	CNEX_MAX_DEVS (sizeof (cnex_class_to_pil) / \
70 				sizeof (cnex_class_to_pil[0]))
71 
72 #define	SUN4V_REG_SPEC2CFG_HDL(x)	((x >> 32) & ~(0xfull << 28))
73 
74 static clock_t cnex_wait_usecs = 1000; /* wait time in usecs */
75 static hrtime_t cnex_pending_tmout = 2ull * NANOSEC; /* 2 secs in nsecs */
76 static void *cnex_state;
77 
78 static void cnex_intr_redist(void *arg);
79 static uint_t cnex_intr_wrapper(caddr_t arg);
80 
81 /*
82  * Debug info
83  */
84 #ifdef DEBUG
85 
86 /*
87  * Print debug messages
88  *
89  * set cnexdbg to 0xf for enabling all msgs
90  * 0x8 - Errors
91  * 0x4 - Warnings
92  * 0x2 - All debug messages
93  * 0x1 - Minimal debug messages
94  */
95 
96 int cnexdbg = 0x8;
97 
98 static void
99 cnexdebug(const char *fmt, ...)
100 {
101 	char buf[512];
102 	va_list ap;
103 
104 	va_start(ap, fmt);
105 	(void) vsprintf(buf, fmt, ap);
106 	va_end(ap);
107 
108 	cmn_err(CE_CONT, "%s\n", buf);
109 }
110 
111 #define	D1		\
112 if (cnexdbg & 0x01)	\
113 	cnexdebug
114 
115 #define	D2		\
116 if (cnexdbg & 0x02)	\
117 	cnexdebug
118 
119 #define	DWARN		\
120 if (cnexdbg & 0x04)	\
121 	cnexdebug
122 
123 #define	DERR		\
124 if (cnexdbg & 0x08)	\
125 	cnexdebug
126 
127 #else
128 
129 #define	D1
130 #define	D2
131 #define	DWARN
132 #define	DERR
133 
134 #endif
135 
136 /*
137  * Config information
138  */
139 static int cnex_attach(dev_info_t *, ddi_attach_cmd_t);
140 static int cnex_detach(dev_info_t *, ddi_detach_cmd_t);
141 static int cnex_open(dev_t *, int, int, cred_t *);
142 static int cnex_close(dev_t, int, int, cred_t *);
143 static int cnex_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
144 static int cnex_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *,
145     void *);
146 
147 static struct bus_ops cnex_bus_ops = {
148 	BUSO_REV,
149 	nullbusmap,		/* bus_map */
150 	NULL,			/* bus_get_intrspec */
151 	NULL,			/* bus_add_intrspec */
152 	NULL,			/* bus_remove_intrspec */
153 	i_ddi_map_fault,	/* bus_map_fault */
154 	ddi_no_dma_map,		/* bus_dma_map */
155 	ddi_no_dma_allochdl,	/* bus_dma_allochdl */
156 	NULL,			/* bus_dma_freehdl */
157 	NULL,			/* bus_dma_bindhdl */
158 	NULL,			/* bus_dma_unbindhdl */
159 	NULL,			/* bus_dma_flush */
160 	NULL,			/* bus_dma_win */
161 	NULL,			/* bus_dma_ctl */
162 	cnex_ctl,		/* bus_ctl */
163 	ddi_bus_prop_op,	/* bus_prop_op */
164 	0,			/* bus_get_eventcookie */
165 	0,			/* bus_add_eventcall */
166 	0,			/* bus_remove_eventcall	*/
167 	0,			/* bus_post_event */
168 	NULL,			/* bus_intr_ctl */
169 	NULL,			/* bus_config */
170 	NULL,			/* bus_unconfig */
171 	NULL,			/* bus_fm_init */
172 	NULL,			/* bus_fm_fini */
173 	NULL,			/* bus_fm_access_enter */
174 	NULL,			/* bus_fm_access_exit */
175 	NULL,			/* bus_power */
176 	NULL			/* bus_intr_op */
177 };
178 
179 static struct cb_ops cnex_cb_ops = {
180 	cnex_open,			/* open */
181 	cnex_close,			/* close */
182 	nodev,				/* strategy */
183 	nodev,				/* print */
184 	nodev,				/* dump */
185 	nodev,				/* read */
186 	nodev,				/* write */
187 	cnex_ioctl,			/* ioctl */
188 	nodev,				/* devmap */
189 	nodev,				/* mmap */
190 	nodev,				/* segmap */
191 	nochpoll,			/* poll */
192 	ddi_prop_op,			/* cb_prop_op */
193 	0,				/* streamtab  */
194 	D_MP | D_NEW | D_HOTPLUG	/* Driver compatibility flag */
195 };
196 
197 static struct dev_ops cnex_ops = {
198 	DEVO_REV,		/* devo_rev, */
199 	0,			/* refcnt  */
200 	ddi_getinfo_1to1,	/* info */
201 	nulldev,		/* identify */
202 	nulldev,		/* probe */
203 	cnex_attach,		/* attach */
204 	cnex_detach,		/* detach */
205 	nodev,			/* reset */
206 	&cnex_cb_ops,		/* driver operations */
207 	&cnex_bus_ops,		/* bus operations */
208 	nulldev			/* power */
209 };
210 
211 /*
212  * Module linkage information for the kernel.
213  */
214 static struct modldrv modldrv = {
215 	&mod_driverops,
216 	"sun4v channel-devices nexus %I%",
217 	&cnex_ops,
218 };
219 
220 static struct modlinkage modlinkage = {
221 	MODREV_1, (void *)&modldrv, NULL
222 };
223 
224 int
225 _init(void)
226 {
227 	int err;
228 
229 	if ((err = ddi_soft_state_init(&cnex_state,
230 		sizeof (cnex_soft_state_t), 0)) != 0) {
231 		return (err);
232 	}
233 	if ((err = mod_install(&modlinkage)) != 0) {
234 		ddi_soft_state_fini(&cnex_state);
235 		return (err);
236 	}
237 	return (0);
238 }
239 
240 int
241 _fini(void)
242 {
243 	int err;
244 
245 	if ((err = mod_remove(&modlinkage)) != 0)
246 		return (err);
247 	ddi_soft_state_fini(&cnex_state);
248 	return (0);
249 }
250 
251 int
252 _info(struct modinfo *modinfop)
253 {
254 	return (mod_info(&modlinkage, modinfop));
255 }
256 
257 /*
258  * Callback function invoked by the interrupt redistribution
259  * framework. This will redirect interrupts at CPUs that are
260  * currently available in the system.
261  */
262 static void
263 cnex_intr_redist(void *arg)
264 {
265 	cnex_ldc_t		*cldcp;
266 	cnex_soft_state_t	*cnex_ssp = arg;
267 	int			intr_state;
268 	hrtime_t 		start;
269 	uint64_t		cpuid;
270 	int 			rv;
271 
272 	ASSERT(cnex_ssp != NULL);
273 	mutex_enter(&cnex_ssp->clist_lock);
274 
275 	cldcp = cnex_ssp->clist;
276 	while (cldcp != NULL) {
277 
278 		mutex_enter(&cldcp->lock);
279 
280 		if (cldcp->tx.hdlr) {
281 			/*
282 			 * Don't do anything for disabled interrupts.
283 			 */
284 			rv = hvldc_intr_getvalid(cnex_ssp->cfghdl,
285 			    cldcp->tx.ino, &intr_state);
286 			if (rv) {
287 				DWARN("cnex_intr_redist: tx ino=0x%llx, "
288 				    "can't get valid\n", cldcp->tx.ino);
289 				mutex_exit(&cldcp->lock);
290 				mutex_exit(&cnex_ssp->clist_lock);
291 				return;
292 			}
293 			if (intr_state == HV_INTR_NOTVALID) {
294 				mutex_exit(&cldcp->lock);
295 				cldcp = cldcp->next;
296 				continue;
297 			}
298 
299 			cpuid = intr_dist_cpuid();
300 
301 			/* disable interrupts */
302 			rv = hvldc_intr_setvalid(cnex_ssp->cfghdl,
303 			    cldcp->tx.ino, HV_INTR_NOTVALID);
304 			if (rv) {
305 				DWARN("cnex_intr_redist: tx ino=0x%llx, "
306 				    "can't set valid\n", cldcp->tx.ino);
307 				mutex_exit(&cldcp->lock);
308 				mutex_exit(&cnex_ssp->clist_lock);
309 				return;
310 			}
311 
312 			/*
313 			 * Make a best effort to wait for pending interrupts
314 			 * to finish. There is not much we can do if we timeout.
315 			 */
316 			start = gethrtime();
317 
318 			do {
319 				rv = hvldc_intr_getstate(cnex_ssp->cfghdl,
320 				    cldcp->tx.ino, &intr_state);
321 				if (rv) {
322 					DWARN("cnex_intr_redist: tx ino=0x%llx,"
323 					    "can't get state\n", cldcp->tx.ino);
324 					mutex_exit(&cldcp->lock);
325 					mutex_exit(&cnex_ssp->clist_lock);
326 					return;
327 				}
328 
329 				if ((gethrtime() - start) > cnex_pending_tmout)
330 					break;
331 				else
332 					drv_usecwait(cnex_wait_usecs);
333 
334 			} while (!panicstr &&
335 			    intr_state == HV_INTR_DELIVERED_STATE);
336 
337 			(void) hvldc_intr_settarget(cnex_ssp->cfghdl,
338 			    cldcp->tx.ino, cpuid);
339 			(void) hvldc_intr_setvalid(cnex_ssp->cfghdl,
340 			    cldcp->tx.ino, HV_INTR_VALID);
341 		}
342 
343 		if (cldcp->rx.hdlr) {
344 			/*
345 			 * Don't do anything for disabled interrupts.
346 			 */
347 			rv = hvldc_intr_getvalid(cnex_ssp->cfghdl,
348 			    cldcp->rx.ino, &intr_state);
349 			if (rv) {
350 				DWARN("cnex_intr_redist: rx ino=0x%llx, "
351 				    "can't get valid\n", cldcp->rx.ino);
352 				mutex_exit(&cldcp->lock);
353 				mutex_exit(&cnex_ssp->clist_lock);
354 				return;
355 			}
356 			if (intr_state == HV_INTR_NOTVALID) {
357 				mutex_exit(&cldcp->lock);
358 				cldcp = cldcp->next;
359 				continue;
360 			}
361 
362 			cpuid = intr_dist_cpuid();
363 
364 			/* disable interrupts */
365 			rv = hvldc_intr_setvalid(cnex_ssp->cfghdl,
366 			    cldcp->rx.ino, HV_INTR_NOTVALID);
367 			if (rv) {
368 				DWARN("cnex_intr_redist: rx ino=0x%llx, "
369 				    "can't set valid\n", cldcp->rx.ino);
370 				mutex_exit(&cldcp->lock);
371 				mutex_exit(&cnex_ssp->clist_lock);
372 				return;
373 			}
374 
375 			/*
376 			 * Make a best effort to wait for pending interrupts
377 			 * to finish. There is not much we can do if we timeout.
378 			 */
379 			start = gethrtime();
380 
381 			do {
382 				rv = hvldc_intr_getstate(cnex_ssp->cfghdl,
383 				    cldcp->rx.ino, &intr_state);
384 				if (rv) {
385 					DWARN("cnex_intr_redist: rx ino=0x%llx,"
386 					    "can't set state\n", cldcp->rx.ino);
387 					mutex_exit(&cldcp->lock);
388 					mutex_exit(&cnex_ssp->clist_lock);
389 					return;
390 				}
391 
392 				if ((gethrtime() - start) > cnex_pending_tmout)
393 					break;
394 				else
395 					drv_usecwait(cnex_wait_usecs);
396 
397 			} while (!panicstr &&
398 			    intr_state == HV_INTR_DELIVERED_STATE);
399 
400 			(void) hvldc_intr_settarget(cnex_ssp->cfghdl,
401 			    cldcp->rx.ino, cpuid);
402 			(void) hvldc_intr_setvalid(cnex_ssp->cfghdl,
403 			    cldcp->rx.ino, HV_INTR_VALID);
404 		}
405 
406 		mutex_exit(&cldcp->lock);
407 
408 		/* next channel */
409 		cldcp = cldcp->next;
410 	}
411 
412 	mutex_exit(&cnex_ssp->clist_lock);
413 }
414 
415 /*
416  * Exported interface to register a LDC endpoint with
417  * the channel nexus
418  */
419 static int
420 cnex_reg_chan(dev_info_t *dip, uint64_t id, ldc_dev_t devclass)
421 {
422 	int		idx;
423 	cnex_ldc_t	*cldcp;
424 	int		listsz, num_nodes, num_channels;
425 	md_t		*mdp = NULL;
426 	mde_cookie_t	rootnode, *listp = NULL;
427 	uint64_t	tmp_id;
428 	uint64_t	rxino = (uint64_t)-1;
429 	uint64_t	txino = (uint64_t)-1;
430 	cnex_soft_state_t *cnex_ssp;
431 	int		status, instance;
432 
433 	/* Get device instance and structure */
434 	instance = ddi_get_instance(dip);
435 	cnex_ssp = ddi_get_soft_state(cnex_state, instance);
436 
437 	/* Check to see if channel is already registered */
438 	mutex_enter(&cnex_ssp->clist_lock);
439 	cldcp = cnex_ssp->clist;
440 	while (cldcp) {
441 		if (cldcp->id == id) {
442 			DWARN("cnex_reg_chan: channel 0x%llx exists\n", id);
443 			mutex_exit(&cnex_ssp->clist_lock);
444 			return (EINVAL);
445 		}
446 		cldcp = cldcp->next;
447 	}
448 
449 	/* Get the Tx/Rx inos from the MD */
450 	if ((mdp = md_get_handle()) == NULL) {
451 		DWARN("cnex_reg_chan: cannot init MD\n");
452 		mutex_exit(&cnex_ssp->clist_lock);
453 		return (ENXIO);
454 	}
455 	num_nodes = md_node_count(mdp);
456 	ASSERT(num_nodes > 0);
457 
458 	listsz = num_nodes * sizeof (mde_cookie_t);
459 	listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP);
460 
461 	rootnode = md_root_node(mdp);
462 
463 	/* search for all channel_endpoint nodes */
464 	num_channels = md_scan_dag(mdp, rootnode,
465 	    md_find_name(mdp, "channel-endpoint"),
466 	    md_find_name(mdp, "fwd"), listp);
467 	if (num_channels <= 0) {
468 		DWARN("cnex_reg_chan: invalid channel id\n");
469 		kmem_free(listp, listsz);
470 		(void) md_fini_handle(mdp);
471 		mutex_exit(&cnex_ssp->clist_lock);
472 		return (EINVAL);
473 	}
474 
475 	for (idx = 0; idx < num_channels; idx++) {
476 
477 		/* Get the channel ID */
478 		status = md_get_prop_val(mdp, listp[idx], "id", &tmp_id);
479 		if (status) {
480 			DWARN("cnex_reg_chan: cannot read LDC ID\n");
481 			kmem_free(listp, listsz);
482 			(void) md_fini_handle(mdp);
483 			mutex_exit(&cnex_ssp->clist_lock);
484 			return (ENXIO);
485 		}
486 		if (tmp_id != id)
487 			continue;
488 
489 		/* Get the Tx and Rx ino */
490 		status = md_get_prop_val(mdp, listp[idx], "tx-ino", &txino);
491 		if (status) {
492 			DWARN("cnex_reg_chan: cannot read Tx ino\n");
493 			kmem_free(listp, listsz);
494 			(void) md_fini_handle(mdp);
495 			mutex_exit(&cnex_ssp->clist_lock);
496 			return (ENXIO);
497 		}
498 		status = md_get_prop_val(mdp, listp[idx], "rx-ino", &rxino);
499 		if (status) {
500 			DWARN("cnex_reg_chan: cannot read Rx ino\n");
501 			kmem_free(listp, listsz);
502 			(void) md_fini_handle(mdp);
503 			mutex_exit(&cnex_ssp->clist_lock);
504 			return (ENXIO);
505 		}
506 	}
507 	kmem_free(listp, listsz);
508 	(void) md_fini_handle(mdp);
509 
510 	/*
511 	 * check to see if we looped through the list of channel IDs without
512 	 * matching one (i.e. an 'ino' has not been initialised).
513 	 */
514 	if ((rxino == -1) || (txino == -1)) {
515 		DERR("cnex_reg_chan: no ID matching '%llx' in MD\n", id);
516 		mutex_exit(&cnex_ssp->clist_lock);
517 		return (ENOENT);
518 	}
519 
520 	/* Allocate a new channel structure */
521 	cldcp = kmem_zalloc(sizeof (*cldcp), KM_SLEEP);
522 
523 	/* Initialize the channel */
524 	mutex_init(&cldcp->lock, NULL, MUTEX_DRIVER, NULL);
525 
526 	cldcp->id = id;
527 	cldcp->tx.ino = txino;
528 	cldcp->rx.ino = rxino;
529 	cldcp->devclass = devclass;
530 
531 	/* add channel to nexus channel list */
532 	cldcp->next = cnex_ssp->clist;
533 	cnex_ssp->clist = cldcp;
534 
535 	mutex_exit(&cnex_ssp->clist_lock);
536 
537 	return (0);
538 }
539 
540 /*
541  * Add Tx/Rx interrupt handler for the channel
542  */
543 static int
544 cnex_add_intr(dev_info_t *dip, uint64_t id, cnex_intrtype_t itype,
545     uint_t (*hdlr)(), caddr_t arg1, caddr_t arg2)
546 {
547 	int		rv, idx, pil;
548 	cnex_ldc_t	*cldcp;
549 	cnex_intr_t	*iinfo;
550 	uint64_t	cpuid;
551 	cnex_soft_state_t *cnex_ssp;
552 	int		instance;
553 
554 	/* Get device instance and structure */
555 	instance = ddi_get_instance(dip);
556 	cnex_ssp = ddi_get_soft_state(cnex_state, instance);
557 
558 	/* get channel info */
559 	mutex_enter(&cnex_ssp->clist_lock);
560 	cldcp = cnex_ssp->clist;
561 	while (cldcp) {
562 		if (cldcp->id == id)
563 			break;
564 		cldcp = cldcp->next;
565 	}
566 	if (cldcp == NULL) {
567 		DWARN("cnex_add_intr: channel 0x%llx does not exist\n", id);
568 		mutex_exit(&cnex_ssp->clist_lock);
569 		return (EINVAL);
570 	}
571 	mutex_exit(&cnex_ssp->clist_lock);
572 
573 	/* get channel lock */
574 	mutex_enter(&cldcp->lock);
575 
576 	/* get interrupt type */
577 	if (itype == CNEX_TX_INTR) {
578 		iinfo = &(cldcp->tx);
579 	} else if (itype == CNEX_RX_INTR) {
580 		iinfo = &(cldcp->rx);
581 	} else {
582 		DWARN("cnex_add_intr: invalid interrupt type\n", id);
583 		mutex_exit(&cldcp->lock);
584 		return (EINVAL);
585 	}
586 
587 	/* check if a handler is already added */
588 	if (iinfo->hdlr != 0) {
589 		DWARN("cnex_add_intr: interrupt handler exists\n");
590 		mutex_exit(&cldcp->lock);
591 		return (EINVAL);
592 	}
593 
594 	/* save interrupt handler info */
595 	iinfo->hdlr = hdlr;
596 	iinfo->arg1 = arg1;
597 	iinfo->arg2 = arg2;
598 
599 	iinfo->ssp = cnex_ssp;
600 
601 	/*
602 	 * FIXME - generate the interrupt cookie
603 	 * using the interrupt registry
604 	 */
605 	iinfo->icookie = cnex_ssp->cfghdl | iinfo->ino;
606 
607 	D1("cnex_add_intr: add hdlr, cfghdl=0x%llx, ino=0x%llx, "
608 	    "cookie=0x%llx\n", cnex_ssp->cfghdl, iinfo->ino, iinfo->icookie);
609 
610 	/* Pick a PIL on the basis of the channel's devclass */
611 	for (idx = 0, pil = PIL_3; idx < CNEX_MAX_DEVS; idx++) {
612 		if (cldcp->devclass == cnex_class_to_pil[idx].devclass) {
613 			pil = cnex_class_to_pil[idx].pil;
614 			break;
615 		}
616 	}
617 
618 	/* add interrupt to solaris ivec table */
619 	VERIFY(add_ivintr(iinfo->icookie, pil, (intrfunc)cnex_intr_wrapper,
620 	    (caddr_t)iinfo, NULL, NULL) == 0);
621 
622 	/* set the cookie in the HV */
623 	rv = hvldc_intr_setcookie(cnex_ssp->cfghdl, iinfo->ino, iinfo->icookie);
624 
625 	/* pick next CPU in the domain for this channel */
626 	cpuid = intr_dist_cpuid();
627 
628 	/* set the target CPU and then enable interrupts */
629 	rv = hvldc_intr_settarget(cnex_ssp->cfghdl, iinfo->ino, cpuid);
630 	if (rv) {
631 		DWARN("cnex_add_intr: ino=0x%llx, cannot set target cpu\n",
632 		    iinfo->ino);
633 		goto hv_error;
634 	}
635 	rv = hvldc_intr_setstate(cnex_ssp->cfghdl, iinfo->ino,
636 	    HV_INTR_IDLE_STATE);
637 	if (rv) {
638 		DWARN("cnex_add_intr: ino=0x%llx, cannot set state\n",
639 		    iinfo->ino);
640 		goto hv_error;
641 	}
642 	rv = hvldc_intr_setvalid(cnex_ssp->cfghdl, iinfo->ino, HV_INTR_VALID);
643 	if (rv) {
644 		DWARN("cnex_add_intr: ino=0x%llx, cannot set valid\n",
645 		    iinfo->ino);
646 		goto hv_error;
647 	}
648 
649 	mutex_exit(&cldcp->lock);
650 	return (0);
651 
652 hv_error:
653 	(void) rem_ivintr(iinfo->icookie, pil);
654 	mutex_exit(&cldcp->lock);
655 	return (ENXIO);
656 }
657 
658 
659 /*
660  * Exported interface to unregister a LDC endpoint with
661  * the channel nexus
662  */
663 static int
664 cnex_unreg_chan(dev_info_t *dip, uint64_t id)
665 {
666 	cnex_ldc_t	*cldcp, *prev_cldcp;
667 	cnex_soft_state_t *cnex_ssp;
668 	int		instance;
669 
670 	/* Get device instance and structure */
671 	instance = ddi_get_instance(dip);
672 	cnex_ssp = ddi_get_soft_state(cnex_state, instance);
673 
674 	/* find and remove channel from list */
675 	mutex_enter(&cnex_ssp->clist_lock);
676 	prev_cldcp = NULL;
677 	cldcp = cnex_ssp->clist;
678 	while (cldcp) {
679 		if (cldcp->id == id)
680 			break;
681 		prev_cldcp = cldcp;
682 		cldcp = cldcp->next;
683 	}
684 
685 	if (cldcp == 0) {
686 		DWARN("cnex_unreg_chan: invalid channel %d\n", id);
687 		mutex_exit(&cnex_ssp->clist_lock);
688 		return (EINVAL);
689 	}
690 
691 	if (cldcp->tx.hdlr || cldcp->rx.hdlr) {
692 		DWARN("cnex_unreg_chan: handlers still exist: chan %lx\n", id);
693 		mutex_exit(&cnex_ssp->clist_lock);
694 		return (ENXIO);
695 	}
696 
697 	if (prev_cldcp)
698 		prev_cldcp->next = cldcp->next;
699 	else
700 		cnex_ssp->clist = cldcp->next;
701 
702 	mutex_exit(&cnex_ssp->clist_lock);
703 
704 	/* destroy mutex */
705 	mutex_destroy(&cldcp->lock);
706 
707 	/* free channel */
708 	kmem_free(cldcp, sizeof (*cldcp));
709 
710 	return (0);
711 }
712 
713 /*
714  * Remove Tx/Rx interrupt handler for the channel
715  */
716 static int
717 cnex_rem_intr(dev_info_t *dip, uint64_t id, cnex_intrtype_t itype)
718 {
719 	int			rv, idx, pil;
720 	cnex_ldc_t		*cldcp;
721 	cnex_intr_t		*iinfo;
722 	cnex_soft_state_t	*cnex_ssp;
723 	int			instance, istate;
724 
725 	/* Get device instance and structure */
726 	instance = ddi_get_instance(dip);
727 	cnex_ssp = ddi_get_soft_state(cnex_state, instance);
728 
729 	/* get channel info */
730 	mutex_enter(&cnex_ssp->clist_lock);
731 	cldcp = cnex_ssp->clist;
732 	while (cldcp) {
733 		if (cldcp->id == id)
734 			break;
735 		cldcp = cldcp->next;
736 	}
737 	if (cldcp == NULL) {
738 		DWARN("cnex_rem_intr: channel 0x%llx does not exist\n", id);
739 		mutex_exit(&cnex_ssp->clist_lock);
740 		return (EINVAL);
741 	}
742 	mutex_exit(&cnex_ssp->clist_lock);
743 
744 	/* get rid of the channel intr handler */
745 	mutex_enter(&cldcp->lock);
746 
747 	/* get interrupt type */
748 	if (itype == CNEX_TX_INTR) {
749 		iinfo = &(cldcp->tx);
750 	} else if (itype == CNEX_RX_INTR) {
751 		iinfo = &(cldcp->rx);
752 	} else {
753 		DWARN("cnex_rem_intr: invalid interrupt type\n");
754 		mutex_exit(&cldcp->lock);
755 		return (EINVAL);
756 	}
757 
758 	D1("cnex_rem_intr: interrupt ino=0x%x\n", iinfo->ino);
759 
760 	/* check if a handler is already added */
761 	if (iinfo->hdlr == 0) {
762 		DWARN("cnex_rem_intr: interrupt handler does not exist\n");
763 		mutex_exit(&cldcp->lock);
764 		return (EINVAL);
765 	}
766 
767 	D1("cnex_rem_intr: set intr to invalid ino=0x%x\n", iinfo->ino);
768 	rv = hvldc_intr_setvalid(cnex_ssp->cfghdl,
769 	    iinfo->ino, HV_INTR_NOTVALID);
770 	if (rv) {
771 		DWARN("cnex_rem_intr: cannot set valid ino=%x\n", iinfo->ino);
772 		mutex_exit(&cldcp->lock);
773 		return (ENXIO);
774 	}
775 
776 	/*
777 	 * Check if there are pending interrupts. If interrupts are
778 	 * pending return EAGAIN.
779 	 */
780 	rv = hvldc_intr_getstate(cnex_ssp->cfghdl, iinfo->ino, &istate);
781 	if (rv) {
782 		DWARN("cnex_rem_intr: ino=0x%llx, cannot get state\n",
783 		    iinfo->ino);
784 		mutex_exit(&cldcp->lock);
785 		return (ENXIO);
786 	}
787 
788 	/* if interrupts are still pending print warning */
789 	if (istate != HV_INTR_IDLE_STATE) {
790 		DWARN("cnex_rem_intr: cannot remove intr busy ino=%x\n",
791 		    iinfo->ino);
792 		mutex_exit(&cldcp->lock);
793 		return (EAGAIN);
794 	}
795 
796 	/* Pick a PIL on the basis of the channel's devclass */
797 	for (idx = 0, pil = PIL_3; idx < CNEX_MAX_DEVS; idx++) {
798 		if (cldcp->devclass == cnex_class_to_pil[idx].devclass) {
799 			pil = cnex_class_to_pil[idx].pil;
800 			break;
801 		}
802 	}
803 
804 	/* remove interrupt */
805 	(void) rem_ivintr(iinfo->icookie, pil);
806 
807 	/* clear interrupt info */
808 	bzero(iinfo, sizeof (*iinfo));
809 
810 	mutex_exit(&cldcp->lock);
811 
812 	return (0);
813 }
814 
815 
816 /*
817  * Clear pending Tx/Rx interrupt
818  */
819 static int
820 cnex_clr_intr(dev_info_t *dip, uint64_t id, cnex_intrtype_t itype)
821 {
822 	int			rv;
823 	cnex_ldc_t		*cldcp;
824 	cnex_intr_t		*iinfo;
825 	cnex_soft_state_t	*cnex_ssp;
826 	int			instance;
827 
828 	/* Get device instance and structure */
829 	instance = ddi_get_instance(dip);
830 	cnex_ssp = ddi_get_soft_state(cnex_state, instance);
831 
832 	/* get channel info */
833 	mutex_enter(&cnex_ssp->clist_lock);
834 	cldcp = cnex_ssp->clist;
835 	while (cldcp) {
836 		if (cldcp->id == id)
837 			break;
838 		cldcp = cldcp->next;
839 	}
840 	if (cldcp == NULL) {
841 		DWARN("cnex_clr_intr: channel 0x%llx does not exist\n", id);
842 		mutex_exit(&cnex_ssp->clist_lock);
843 		return (EINVAL);
844 	}
845 	mutex_exit(&cnex_ssp->clist_lock);
846 
847 	mutex_enter(&cldcp->lock);
848 
849 	/* get interrupt type */
850 	if (itype == CNEX_TX_INTR) {
851 		iinfo = &(cldcp->tx);
852 	} else if (itype == CNEX_RX_INTR) {
853 		iinfo = &(cldcp->rx);
854 	} else {
855 		DWARN("cnex_clr_intr: invalid interrupt type\n");
856 		mutex_exit(&cldcp->lock);
857 		return (EINVAL);
858 	}
859 
860 	D1("cnex_rem_intr: interrupt ino=0x%x\n", iinfo->ino);
861 
862 	/* check if a handler is already added */
863 	if (iinfo->hdlr == 0) {
864 		DWARN("cnex_clr_intr: interrupt handler does not exist\n");
865 		mutex_exit(&cldcp->lock);
866 		return (EINVAL);
867 	}
868 
869 	rv = hvldc_intr_setstate(cnex_ssp->cfghdl, iinfo->ino,
870 	    HV_INTR_IDLE_STATE);
871 	if (rv) {
872 		DWARN("cnex_clr_intr: cannot clear interrupt state\n");
873 		mutex_exit(&cldcp->lock);
874 		return (ENXIO);
875 	}
876 
877 	mutex_exit(&cldcp->lock);
878 
879 	return (0);
880 }
881 
882 /*
883  * Channel nexus interrupt handler wrapper
884  */
885 static uint_t
886 cnex_intr_wrapper(caddr_t arg)
887 {
888 	int 			res;
889 	uint_t 			(*handler)();
890 	caddr_t 		handler_arg1;
891 	caddr_t 		handler_arg2;
892 	cnex_intr_t 		*iinfo = (cnex_intr_t *)arg;
893 
894 	ASSERT(iinfo != NULL);
895 
896 	handler = iinfo->hdlr;
897 	handler_arg1 = iinfo->arg1;
898 	handler_arg2 = iinfo->arg2;
899 
900 	D1("cnex_intr_wrapper: ino=0x%llx invoke client handler\n", iinfo->ino);
901 	res = (*handler)(handler_arg1, handler_arg2);
902 
903 	return (res);
904 }
905 
906 /*ARGSUSED*/
907 static int
908 cnex_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
909 {
910 	int 		rv, instance, reglen;
911 	cnex_regspec_t	*reg_p;
912 	ldc_cnex_t	cinfo;
913 	cnex_soft_state_t *cnex_ssp;
914 
915 	switch (cmd) {
916 	case DDI_ATTACH:
917 		break;
918 	case DDI_RESUME:
919 		return (DDI_SUCCESS);
920 	default:
921 		return (DDI_FAILURE);
922 	}
923 
924 	/*
925 	 * Get the instance specific soft state structure.
926 	 * Save the devi for this instance in the soft_state data.
927 	 */
928 	instance = ddi_get_instance(devi);
929 	if (ddi_soft_state_zalloc(cnex_state, instance) != DDI_SUCCESS)
930 		return (DDI_FAILURE);
931 	cnex_ssp = ddi_get_soft_state(cnex_state, instance);
932 
933 	cnex_ssp->devi = devi;
934 	cnex_ssp->clist = NULL;
935 
936 	if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
937 		"reg", (caddr_t)&reg_p, &reglen) != DDI_SUCCESS) {
938 		return (DDI_FAILURE);
939 	}
940 
941 	/* get the sun4v config handle for this device */
942 	cnex_ssp->cfghdl = SUN4V_REG_SPEC2CFG_HDL(reg_p->physaddr);
943 	kmem_free(reg_p, reglen);
944 
945 	D1("cnex_attach: cfghdl=0x%llx\n", cnex_ssp->cfghdl);
946 
947 	/* init channel list mutex */
948 	mutex_init(&cnex_ssp->clist_lock, NULL, MUTEX_DRIVER, NULL);
949 
950 	/* Register with LDC module */
951 	cinfo.dip = devi;
952 	cinfo.reg_chan = cnex_reg_chan;
953 	cinfo.unreg_chan = cnex_unreg_chan;
954 	cinfo.add_intr = cnex_add_intr;
955 	cinfo.rem_intr = cnex_rem_intr;
956 	cinfo.clr_intr = cnex_clr_intr;
957 
958 	/*
959 	 * LDC register will fail if an nexus instance had already
960 	 * registered with the LDC framework
961 	 */
962 	rv = ldc_register(&cinfo);
963 	if (rv) {
964 		DWARN("cnex_attach: unable to register with LDC\n");
965 		ddi_soft_state_free(cnex_state, instance);
966 		mutex_destroy(&cnex_ssp->clist_lock);
967 		return (DDI_FAILURE);
968 	}
969 
970 	if (ddi_create_minor_node(devi, "devctl", S_IFCHR, instance,
971 	    DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
972 		ddi_remove_minor_node(devi, NULL);
973 		ddi_soft_state_free(cnex_state, instance);
974 		mutex_destroy(&cnex_ssp->clist_lock);
975 		return (DDI_FAILURE);
976 	}
977 
978 	/* Add interrupt redistribution callback. */
979 	intr_dist_add(cnex_intr_redist, cnex_ssp);
980 
981 	ddi_report_dev(devi);
982 	return (DDI_SUCCESS);
983 }
984 
985 /*ARGSUSED*/
986 static int
987 cnex_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
988 {
989 	int 		instance;
990 	ldc_cnex_t	cinfo;
991 	cnex_soft_state_t *cnex_ssp;
992 
993 	switch (cmd) {
994 	case DDI_DETACH:
995 		break;
996 	case DDI_SUSPEND:
997 		return (DDI_SUCCESS);
998 	default:
999 		return (DDI_FAILURE);
1000 	}
1001 
1002 	instance = ddi_get_instance(devi);
1003 	cnex_ssp = ddi_get_soft_state(cnex_state, instance);
1004 
1005 	/* check if there are any channels still registered */
1006 	if (cnex_ssp->clist) {
1007 		cmn_err(CE_WARN, "?cnex_dettach: channels registered %d\n",
1008 		    ddi_get_instance(devi));
1009 		return (DDI_FAILURE);
1010 	}
1011 
1012 	/* Unregister with LDC module */
1013 	cinfo.dip = devi;
1014 	(void) ldc_unregister(&cinfo);
1015 
1016 	/* Remove interrupt redistribution callback. */
1017 	intr_dist_rem(cnex_intr_redist, cnex_ssp);
1018 
1019 	/* destroy mutex */
1020 	mutex_destroy(&cnex_ssp->clist_lock);
1021 
1022 	/* free soft state structure */
1023 	ddi_soft_state_free(cnex_state, instance);
1024 
1025 	return (DDI_SUCCESS);
1026 }
1027 
1028 /*ARGSUSED*/
1029 static int
1030 cnex_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1031 {
1032 	int instance;
1033 
1034 	if (otyp != OTYP_CHR)
1035 		return (EINVAL);
1036 
1037 	instance = getminor(*devp);
1038 	if (ddi_get_soft_state(cnex_state, instance) == NULL)
1039 		return (ENXIO);
1040 
1041 	return (0);
1042 }
1043 
1044 /*ARGSUSED*/
1045 static int
1046 cnex_close(dev_t dev, int flags, int otyp, cred_t *credp)
1047 {
1048 	int instance;
1049 
1050 	if (otyp != OTYP_CHR)
1051 		return (EINVAL);
1052 
1053 	instance = getminor(dev);
1054 	if (ddi_get_soft_state(cnex_state, instance) == NULL)
1055 		return (ENXIO);
1056 
1057 	return (0);
1058 }
1059 
1060 /*ARGSUSED*/
1061 static int
1062 cnex_ioctl(dev_t dev,
1063     int cmd, intptr_t arg, int mode, cred_t *cred_p, int *rval_p)
1064 {
1065 	int instance;
1066 	cnex_soft_state_t *cnex_ssp;
1067 
1068 	instance = getminor(dev);
1069 	if ((cnex_ssp = ddi_get_soft_state(cnex_state, instance)) == NULL)
1070 		return (ENXIO);
1071 	ASSERT(cnex_ssp->devi);
1072 	return (ndi_devctl_ioctl(cnex_ssp->devi, cmd, arg, mode, 0));
1073 }
1074 
1075 static int
1076 cnex_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
1077     void *arg, void *result)
1078 {
1079 	char		name[MAXNAMELEN];
1080 	uint32_t	reglen;
1081 	int		*cnex_regspec;
1082 
1083 	switch (ctlop) {
1084 	case DDI_CTLOPS_REPORTDEV:
1085 		if (rdip == NULL)
1086 			return (DDI_FAILURE);
1087 		cmn_err(CE_CONT, "?channel-device: %s%d\n",
1088 		    ddi_driver_name(rdip), ddi_get_instance(rdip));
1089 		return (DDI_SUCCESS);
1090 
1091 	case DDI_CTLOPS_INITCHILD:
1092 	{
1093 		dev_info_t *child = (dev_info_t *)arg;
1094 
1095 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child,
1096 			DDI_PROP_DONTPASS, "reg",
1097 			&cnex_regspec, &reglen) != DDI_SUCCESS) {
1098 			return (DDI_FAILURE);
1099 		}
1100 
1101 		(void) snprintf(name, sizeof (name), "%x", *cnex_regspec);
1102 		ddi_set_name_addr(child, name);
1103 		ddi_set_parent_data(child, NULL);
1104 		ddi_prop_free(cnex_regspec);
1105 		return (DDI_SUCCESS);
1106 	}
1107 
1108 	case DDI_CTLOPS_UNINITCHILD:
1109 	{
1110 		dev_info_t *child = (dev_info_t *)arg;
1111 
1112 		NDI_CONFIG_DEBUG((CE_NOTE,
1113 		    "DDI_CTLOPS_UNINITCHILD(%s, instance=%d)",
1114 		    ddi_driver_name(child), DEVI(child)->devi_instance));
1115 
1116 		ddi_set_name_addr(child, NULL);
1117 
1118 		return (DDI_SUCCESS);
1119 	}
1120 
1121 	case DDI_CTLOPS_DMAPMAPC:
1122 	case DDI_CTLOPS_REPORTINT:
1123 	case DDI_CTLOPS_REGSIZE:
1124 	case DDI_CTLOPS_NREGS:
1125 	case DDI_CTLOPS_SIDDEV:
1126 	case DDI_CTLOPS_SLAVEONLY:
1127 	case DDI_CTLOPS_AFFINITY:
1128 	case DDI_CTLOPS_POKE:
1129 	case DDI_CTLOPS_PEEK:
1130 		/*
1131 		 * These ops correspond to functions that "shouldn't" be called
1132 		 * by a channel-device driver.  So we whine when we're called.
1133 		 */
1134 		cmn_err(CE_WARN, "%s%d: invalid op (%d) from %s%d\n",
1135 		    ddi_driver_name(dip), ddi_get_instance(dip), ctlop,
1136 		    ddi_driver_name(rdip), ddi_get_instance(rdip));
1137 		return (DDI_FAILURE);
1138 
1139 	case DDI_CTLOPS_ATTACH:
1140 	case DDI_CTLOPS_BTOP:
1141 	case DDI_CTLOPS_BTOPR:
1142 	case DDI_CTLOPS_DETACH:
1143 	case DDI_CTLOPS_DVMAPAGESIZE:
1144 	case DDI_CTLOPS_IOMIN:
1145 	case DDI_CTLOPS_POWER:
1146 	case DDI_CTLOPS_PTOB:
1147 	default:
1148 		/*
1149 		 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
1150 		 */
1151 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
1152 	}
1153 }
1154 
1155 /* -------------------------------------------------------------------------- */
1156