xref: /titanic_52/usr/src/uts/sun4v/io/cnex.c (revision d14abf155341d55053c76eeec58b787a456b753b)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23   * Use is subject to license terms.
24   */
25  
26  
27  /*
28   * Logical domain channel devices are devices implemented entirely
29   * in software; cnex is the nexus for channel-devices. They use
30   * the HV channel interfaces via the LDC transport module to send
31   * and receive data and to register callbacks.
32   */
33  
34  #include <sys/types.h>
35  #include <sys/cmn_err.h>
36  #include <sys/conf.h>
37  #include <sys/ddi.h>
38  #include <sys/ddi_impldefs.h>
39  #include <sys/devops.h>
40  #include <sys/instance.h>
41  #include <sys/modctl.h>
42  #include <sys/open.h>
43  #include <sys/stat.h>
44  #include <sys/sunddi.h>
45  #include <sys/sunndi.h>
46  #include <sys/systm.h>
47  #include <sys/mkdev.h>
48  #include <sys/machsystm.h>
49  #include <sys/intreg.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  #include <sys/hsvc.h>
58  #include <sys/sdt.h>
59  
60  /*
61   * Internal functions/information
62   */
63  static struct cnex_intr_map cnex_class_to_intr[] = {
64  	{LDC_DEV_GENERIC,	PIL_3,	 0},
65  	{LDC_DEV_BLK,		PIL_4,	10},
66  	{LDC_DEV_BLK_SVC,	PIL_3,	10},
67  	{LDC_DEV_NT,		PIL_6,	35},
68  	{LDC_DEV_NT_SVC,	PIL_4,	35},
69  	{LDC_DEV_SERIAL,	PIL_6,	 0}
70  };
71  #define	CNEX_MAX_DEVS (sizeof (cnex_class_to_intr) / \
72  				sizeof (cnex_class_to_intr[0]))
73  
74  #define	CNEX_TX_INTR_WEIGHT	0
75  
76  #define	SUN4V_REG_SPEC2CFG_HDL(x)	((x >> 32) & ~(0xfull << 28))
77  
78  static clock_t cnex_wait_usecs = 1000; /* wait time in usecs */
79  static int cnex_wait_retries = 3;
80  static void *cnex_state;
81  
82  static uint_t cnex_intr_wrapper(caddr_t arg);
83  static dev_info_t *cnex_find_chan_dip(dev_info_t *dip, uint64_t chan_id,
84      md_t *mdp, mde_cookie_t mde);
85  
86  /*
87   * Channel Interrupt Distribution
88   *
89   * In order to balance interrupts among available CPUs, we use
90   * the intr_dist_cpuid_{add,remove}_device_weight() interface to
91   * assign weights to channel interrupts. These weights, which are
92   * defined in the cnex_intr_map structure, influence which CPU
93   * is returned by intr_dist_cpuid() when called via the cnex
94   * interrupt redistribution callback cnex_intr_redist().
95   * Interrupts for VIO devclass channels are given more weight than
96   * other interrupts because they are expected to occur more
97   * frequently and have a larger impact on overall performance.
98   * Transmit interrupts are given a zero weight because they are
99   * not used.
100   *
101   * The interrupt weights influence the target CPU selection when
102   * interrupts are redistributed and when they are added. However,
103   * removal of interrupts can unbalance the distribution even if
104   * they are removed in converse order--compared to the order they
105   * are added. This can occur when interrupts are removed after
106   * redistribution occurs.
107   *
108   * Channel interrupt weights affect interrupt-CPU distribution
109   * relative to other weighted interrupts on the system. For VIO
110   * devclass channels, values are chosen to match those used by
111   * the PCI express nexus driver for net and storage devices.
112   */
113  static void cnex_intr_redist(void *arg, int32_t weight_max, int32_t weight);
114  static int cnex_intr_new_cpu(cnex_soft_state_t *ssp, cnex_intr_t *iinfo);
115  static int cnex_intr_dis_wait(cnex_soft_state_t *ssp, cnex_intr_t *iinfo);
116  static int32_t cnex_class_weight(ldc_dev_t devclass);
117  
118  /*
119   * Debug info
120   */
121  #ifdef DEBUG
122  
123  /*
124   * Print debug messages
125   *
126   * set cnexdbg to 0xf for enabling all msgs
127   * 0x8 - Errors
128   * 0x4 - Warnings
129   * 0x2 - All debug messages
130   * 0x1 - Minimal debug messages
131   */
132  
133  int cnexdbg = 0x8;
134  
135  static void
136  cnexdebug(const char *fmt, ...)
137  {
138  	char buf[512];
139  	va_list ap;
140  
141  	va_start(ap, fmt);
142  	(void) vsprintf(buf, fmt, ap);
143  	va_end(ap);
144  
145  	cmn_err(CE_CONT, "%s\n", buf);
146  }
147  
148  #define	D1		\
149  if (cnexdbg & 0x01)	\
150  	cnexdebug
151  
152  #define	D2		\
153  if (cnexdbg & 0x02)	\
154  	cnexdebug
155  
156  #define	DWARN		\
157  if (cnexdbg & 0x04)	\
158  	cnexdebug
159  
160  #define	DERR		\
161  if (cnexdbg & 0x08)	\
162  	cnexdebug
163  
164  #else
165  
166  #define	D1
167  #define	D2
168  #define	DWARN
169  #define	DERR
170  
171  #endif
172  
173  /*
174   * Config information
175   */
176  static int cnex_attach(dev_info_t *, ddi_attach_cmd_t);
177  static int cnex_detach(dev_info_t *, ddi_detach_cmd_t);
178  static int cnex_open(dev_t *, int, int, cred_t *);
179  static int cnex_close(dev_t, int, int, cred_t *);
180  static int cnex_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
181  static int cnex_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *,
182      void *);
183  
184  static struct bus_ops cnex_bus_ops = {
185  	BUSO_REV,
186  	nullbusmap,		/* bus_map */
187  	NULL,			/* bus_get_intrspec */
188  	NULL,			/* bus_add_intrspec */
189  	NULL,			/* bus_remove_intrspec */
190  	i_ddi_map_fault,	/* bus_map_fault */
191  	ddi_no_dma_map,		/* bus_dma_map */
192  	ddi_no_dma_allochdl,	/* bus_dma_allochdl */
193  	NULL,			/* bus_dma_freehdl */
194  	NULL,			/* bus_dma_bindhdl */
195  	NULL,			/* bus_dma_unbindhdl */
196  	NULL,			/* bus_dma_flush */
197  	NULL,			/* bus_dma_win */
198  	NULL,			/* bus_dma_ctl */
199  	cnex_ctl,		/* bus_ctl */
200  	ddi_bus_prop_op,	/* bus_prop_op */
201  	0,			/* bus_get_eventcookie */
202  	0,			/* bus_add_eventcall */
203  	0,			/* bus_remove_eventcall	*/
204  	0,			/* bus_post_event */
205  	NULL,			/* bus_intr_ctl */
206  	NULL,			/* bus_config */
207  	NULL,			/* bus_unconfig */
208  	NULL,			/* bus_fm_init */
209  	NULL,			/* bus_fm_fini */
210  	NULL,			/* bus_fm_access_enter */
211  	NULL,			/* bus_fm_access_exit */
212  	NULL,			/* bus_power */
213  	NULL			/* bus_intr_op */
214  };
215  
216  static struct cb_ops cnex_cb_ops = {
217  	cnex_open,			/* open */
218  	cnex_close,			/* close */
219  	nodev,				/* strategy */
220  	nodev,				/* print */
221  	nodev,				/* dump */
222  	nodev,				/* read */
223  	nodev,				/* write */
224  	cnex_ioctl,			/* ioctl */
225  	nodev,				/* devmap */
226  	nodev,				/* mmap */
227  	nodev,				/* segmap */
228  	nochpoll,			/* poll */
229  	ddi_prop_op,			/* cb_prop_op */
230  	0,				/* streamtab  */
231  	D_MP | D_NEW | D_HOTPLUG	/* Driver compatibility flag */
232  };
233  
234  static struct dev_ops cnex_ops = {
235  	DEVO_REV,		/* devo_rev, */
236  	0,			/* refcnt  */
237  	ddi_getinfo_1to1,	/* info */
238  	nulldev,		/* identify */
239  	nulldev,		/* probe */
240  	cnex_attach,		/* attach */
241  	cnex_detach,		/* detach */
242  	nodev,			/* reset */
243  	&cnex_cb_ops,		/* driver operations */
244  	&cnex_bus_ops,		/* bus operations */
245  	nulldev,		/* power */
246  	ddi_quiesce_not_needed,		/* quiesce */
247  };
248  
249  /*
250   * Module linkage information for the kernel.
251   */
252  static struct modldrv modldrv = {
253  	&mod_driverops,
254  	"sun4v channel-devices nexus",
255  	&cnex_ops,
256  };
257  
258  static struct modlinkage modlinkage = {
259  	MODREV_1, (void *)&modldrv, NULL
260  };
261  
262  int
263  _init(void)
264  {
265  	int err;
266  	uint64_t majornum;
267  	uint64_t minornum;
268  
269  	/*
270  	 * Check HV intr group api versioning.
271  	 * Note that cnex assumes interrupt cookies is
272  	 * in version 1.0 of the intr group api.
273  	 */
274  	if ((err = hsvc_version(HSVC_GROUP_INTR, &majornum, &minornum)) != 0) {
275  		cmn_err(CE_WARN, "cnex: failed to get intr api "
276  		    "group versioning errno=%d", err);
277  		return (err);
278  	} else if ((majornum != 1) && (majornum != 2)) {
279  		cmn_err(CE_WARN, "cnex: unsupported intr api group: "
280  		    "maj:0x%lx, min:0x%lx", majornum, minornum);
281  		return (ENOTSUP);
282  	}
283  
284  	if ((err = ddi_soft_state_init(&cnex_state,
285  	    sizeof (cnex_soft_state_t), 0)) != 0) {
286  		return (err);
287  	}
288  	if ((err = mod_install(&modlinkage)) != 0) {
289  		ddi_soft_state_fini(&cnex_state);
290  		return (err);
291  	}
292  	return (0);
293  }
294  
295  int
296  _fini(void)
297  {
298  	int err;
299  
300  	if ((err = mod_remove(&modlinkage)) != 0)
301  		return (err);
302  	ddi_soft_state_fini(&cnex_state);
303  	return (0);
304  }
305  
306  int
307  _info(struct modinfo *modinfop)
308  {
309  	return (mod_info(&modlinkage, modinfop));
310  }
311  
312  /*
313   * Callback function invoked by the interrupt redistribution
314   * framework. This will redirect interrupts at CPUs that are
315   * currently available in the system.
316   *
317   * Note: any interrupts with weight greater than or equal to
318   * weight_max must be redistributed when this callback is
319   * invoked with (weight == weight_max) which will be once per
320   * redistribution.
321   */
322  /*ARGSUSED*/
323  static void
324  cnex_intr_redist(void *arg, int32_t weight_max, int32_t weight)
325  {
326  	cnex_ldc_t		*cldcp;
327  	cnex_soft_state_t	*cnex_ssp = arg;
328  
329  	ASSERT(cnex_ssp != NULL);
330  	mutex_enter(&cnex_ssp->clist_lock);
331  
332  	cldcp = cnex_ssp->clist;
333  	while (cldcp != NULL) {
334  
335  		mutex_enter(&cldcp->lock);
336  
337  		if (cldcp->tx.hdlr && (cldcp->tx.weight == weight ||
338  		    (weight_max == weight && cldcp->tx.weight > weight))) {
339  			(void) cnex_intr_new_cpu(cnex_ssp, &cldcp->tx);
340  		}
341  
342  		if (cldcp->rx.hdlr && (cldcp->rx.weight == weight ||
343  		    (weight_max == weight && cldcp->rx.weight > weight))) {
344  			(void) cnex_intr_new_cpu(cnex_ssp, &cldcp->rx);
345  		}
346  
347  		mutex_exit(&cldcp->lock);
348  
349  		/* next channel */
350  		cldcp = cldcp->next;
351  	}
352  
353  	mutex_exit(&cnex_ssp->clist_lock);
354  }
355  
356  /*
357   * Internal function to replace the CPU used by an interrupt
358   * during interrupt redistribution.
359   */
360  static int
361  cnex_intr_new_cpu(cnex_soft_state_t *ssp, cnex_intr_t *iinfo)
362  {
363  	int	intr_state;
364  	int 	rv;
365  
366  	/* Determine if the interrupt is enabled */
367  	rv = hvldc_intr_getvalid(ssp->cfghdl, iinfo->ino, &intr_state);
368  	if (rv) {
369  		DWARN("cnex_intr_new_cpu: rx ino=0x%llx, can't get valid\n",
370  		    iinfo->ino);
371  		return (rv);
372  	}
373  
374  	/* If it is enabled, disable it */
375  	if (intr_state == HV_INTR_VALID) {
376  		rv = cnex_intr_dis_wait(ssp, iinfo);
377  		if (rv) {
378  			return (rv);
379  		}
380  	}
381  
382  	/* Target the interrupt at a new CPU. */
383  	iinfo->cpuid = intr_dist_cpuid();
384  	(void) hvldc_intr_settarget(ssp->cfghdl, iinfo->ino, iinfo->cpuid);
385  	intr_dist_cpuid_add_device_weight(iinfo->cpuid, iinfo->dip,
386  	    iinfo->weight);
387  
388  	/* Re-enable the interrupt if it was enabled */
389  	if (intr_state == HV_INTR_VALID) {
390  		(void) hvldc_intr_setvalid(ssp->cfghdl, iinfo->ino,
391  		    HV_INTR_VALID);
392  	}
393  
394  	return (0);
395  }
396  
397  /*
398   * Internal function to disable an interrupt and wait
399   * for any pending interrupts to finish.
400   */
401  static int
402  cnex_intr_dis_wait(cnex_soft_state_t *ssp, cnex_intr_t *iinfo)
403  {
404  	int rv, intr_state, retries;
405  
406  	/* disable interrupts */
407  	rv = hvldc_intr_setvalid(ssp->cfghdl, iinfo->ino, HV_INTR_NOTVALID);
408  	if (rv) {
409  		DWARN("cnex_intr_dis_wait: ino=0x%llx, can't set valid\n",
410  		    iinfo->ino);
411  		return (ENXIO);
412  	}
413  
414  	/*
415  	 * Make a best effort to wait for pending interrupts
416  	 * to finish. There is not much we can do if we timeout.
417  	 */
418  	retries = 0;
419  
420  	do {
421  		rv = hvldc_intr_getstate(ssp->cfghdl, iinfo->ino, &intr_state);
422  		if (rv) {
423  			DWARN("cnex_intr_dis_wait: ino=0x%llx, can't get "
424  			    "state\n", iinfo->ino);
425  			return (ENXIO);
426  		}
427  
428  		if (intr_state != HV_INTR_DELIVERED_STATE)
429  			break;
430  
431  		drv_usecwait(cnex_wait_usecs);
432  
433  	} while (!panicstr && ++retries <= cnex_wait_retries);
434  
435  	return (0);
436  }
437  
438  /*
439   * Returns the interrupt weight to use for the specified devclass.
440   */
441  static int32_t
442  cnex_class_weight(ldc_dev_t devclass)
443  {
444  	int idx;
445  
446  	for (idx = 0; idx < CNEX_MAX_DEVS; idx++) {
447  		if (devclass == cnex_class_to_intr[idx].devclass) {
448  			return (cnex_class_to_intr[idx].weight);
449  		}
450  	}
451  
452  	/*
453  	 * If this code is reached, the specified devclass is
454  	 * invalid. New devclasses should be added to
455  	 * cnex_class_to_intr.
456  	 */
457  	ASSERT(0);
458  
459  	return (0);
460  }
461  
462  /*
463   * Exported interface to register a LDC endpoint with
464   * the channel nexus
465   */
466  static int
467  cnex_reg_chan(dev_info_t *dip, uint64_t id, ldc_dev_t devclass)
468  {
469  	int		idx;
470  	cnex_ldc_t	*cldcp;
471  	cnex_ldc_t	*new_cldcp;
472  	int		listsz, num_nodes, num_channels;
473  	md_t		*mdp = NULL;
474  	mde_cookie_t	rootnode, *listp = NULL;
475  	uint64_t	tmp_id;
476  	uint64_t	rxino = (uint64_t)-1;
477  	uint64_t	txino = (uint64_t)-1;
478  	cnex_soft_state_t *cnex_ssp;
479  	int		status, instance;
480  	dev_info_t	*chan_dip = NULL;
481  
482  	/* Get device instance and structure */
483  	instance = ddi_get_instance(dip);
484  	cnex_ssp = ddi_get_soft_state(cnex_state, instance);
485  
486  	/* Check to see if channel is already registered */
487  	mutex_enter(&cnex_ssp->clist_lock);
488  	cldcp = cnex_ssp->clist;
489  	while (cldcp) {
490  		if (cldcp->id == id) {
491  			DWARN("cnex_reg_chan: channel 0x%llx exists\n", id);
492  			mutex_exit(&cnex_ssp->clist_lock);
493  			return (EINVAL);
494  		}
495  		cldcp = cldcp->next;
496  	}
497  	mutex_exit(&cnex_ssp->clist_lock);
498  
499  	/* Get the Tx/Rx inos from the MD */
500  	if ((mdp = md_get_handle()) == NULL) {
501  		DWARN("cnex_reg_chan: cannot init MD\n");
502  		return (ENXIO);
503  	}
504  	num_nodes = md_node_count(mdp);
505  	ASSERT(num_nodes > 0);
506  
507  	listsz = num_nodes * sizeof (mde_cookie_t);
508  	listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP);
509  
510  	rootnode = md_root_node(mdp);
511  
512  	/* search for all channel_endpoint nodes */
513  	num_channels = md_scan_dag(mdp, rootnode,
514  	    md_find_name(mdp, "channel-endpoint"),
515  	    md_find_name(mdp, "fwd"), listp);
516  	if (num_channels <= 0) {
517  		DWARN("cnex_reg_chan: invalid channel id\n");
518  		kmem_free(listp, listsz);
519  		(void) md_fini_handle(mdp);
520  		return (EINVAL);
521  	}
522  
523  	for (idx = 0; idx < num_channels; idx++) {
524  
525  		/* Get the channel ID */
526  		status = md_get_prop_val(mdp, listp[idx], "id", &tmp_id);
527  		if (status) {
528  			DWARN("cnex_reg_chan: cannot read LDC ID\n");
529  			kmem_free(listp, listsz);
530  			(void) md_fini_handle(mdp);
531  			return (ENXIO);
532  		}
533  		if (tmp_id != id)
534  			continue;
535  
536  		/* Get the Tx and Rx ino */
537  		status = md_get_prop_val(mdp, listp[idx], "tx-ino", &txino);
538  		if (status) {
539  			DWARN("cnex_reg_chan: cannot read Tx ino\n");
540  			kmem_free(listp, listsz);
541  			(void) md_fini_handle(mdp);
542  			return (ENXIO);
543  		}
544  		status = md_get_prop_val(mdp, listp[idx], "rx-ino", &rxino);
545  		if (status) {
546  			DWARN("cnex_reg_chan: cannot read Rx ino\n");
547  			kmem_free(listp, listsz);
548  			(void) md_fini_handle(mdp);
549  			return (ENXIO);
550  		}
551  		chan_dip = cnex_find_chan_dip(dip, id, mdp, listp[idx]);
552  		ASSERT(chan_dip != NULL);
553  	}
554  	kmem_free(listp, listsz);
555  	(void) md_fini_handle(mdp);
556  
557  	/*
558  	 * check to see if we looped through the list of channel IDs without
559  	 * matching one (i.e. an 'ino' has not been initialised).
560  	 */
561  	if ((rxino == -1) || (txino == -1)) {
562  		DERR("cnex_reg_chan: no ID matching '%llx' in MD\n", id);
563  		return (ENOENT);
564  	}
565  
566  	/* Allocate a new channel structure */
567  	new_cldcp = kmem_zalloc(sizeof (*new_cldcp), KM_SLEEP);
568  
569  	/* Initialize the channel */
570  	mutex_init(&new_cldcp->lock, NULL, MUTEX_DRIVER, NULL);
571  
572  	new_cldcp->id = id;
573  	new_cldcp->tx.ino = txino;
574  	new_cldcp->rx.ino = rxino;
575  	new_cldcp->devclass = devclass;
576  	new_cldcp->tx.weight = CNEX_TX_INTR_WEIGHT;
577  	new_cldcp->rx.weight = cnex_class_weight(devclass);
578  	new_cldcp->dip = chan_dip;
579  
580  	/*
581  	 * Add channel to nexus channel list.
582  	 * Check again to see if channel is already registered since
583  	 * clist_lock was dropped above.
584  	 */
585  	mutex_enter(&cnex_ssp->clist_lock);
586  	cldcp = cnex_ssp->clist;
587  	while (cldcp) {
588  		if (cldcp->id == id) {
589  			DWARN("cnex_reg_chan: channel 0x%llx exists\n", id);
590  			mutex_exit(&cnex_ssp->clist_lock);
591  			mutex_destroy(&new_cldcp->lock);
592  			kmem_free(new_cldcp, sizeof (*new_cldcp));
593  			return (EINVAL);
594  		}
595  		cldcp = cldcp->next;
596  	}
597  	new_cldcp->next = cnex_ssp->clist;
598  	cnex_ssp->clist = new_cldcp;
599  	mutex_exit(&cnex_ssp->clist_lock);
600  
601  	return (0);
602  }
603  
604  /*
605   * Add Tx/Rx interrupt handler for the channel
606   */
607  static int
608  cnex_add_intr(dev_info_t *dip, uint64_t id, cnex_intrtype_t itype,
609      uint_t (*hdlr)(), caddr_t arg1, caddr_t arg2)
610  {
611  	int		rv, idx, pil;
612  	cnex_ldc_t	*cldcp;
613  	cnex_intr_t	*iinfo;
614  	cnex_soft_state_t *cnex_ssp;
615  	int		instance;
616  
617  	/* Get device instance and structure */
618  	instance = ddi_get_instance(dip);
619  	cnex_ssp = ddi_get_soft_state(cnex_state, instance);
620  
621  	/* get channel info */
622  	mutex_enter(&cnex_ssp->clist_lock);
623  	cldcp = cnex_ssp->clist;
624  	while (cldcp) {
625  		if (cldcp->id == id)
626  			break;
627  		cldcp = cldcp->next;
628  	}
629  	if (cldcp == NULL) {
630  		DWARN("cnex_add_intr: channel 0x%llx does not exist\n", id);
631  		mutex_exit(&cnex_ssp->clist_lock);
632  		return (EINVAL);
633  	}
634  	mutex_exit(&cnex_ssp->clist_lock);
635  
636  	/* get channel lock */
637  	mutex_enter(&cldcp->lock);
638  
639  	/* get interrupt type */
640  	if (itype == CNEX_TX_INTR) {
641  		iinfo = &(cldcp->tx);
642  	} else if (itype == CNEX_RX_INTR) {
643  		iinfo = &(cldcp->rx);
644  	} else {
645  		DWARN("cnex_add_intr: invalid interrupt type\n", id);
646  		mutex_exit(&cldcp->lock);
647  		return (EINVAL);
648  	}
649  
650  	/* check if a handler is already added */
651  	if (iinfo->hdlr != 0) {
652  		DWARN("cnex_add_intr: interrupt handler exists\n");
653  		mutex_exit(&cldcp->lock);
654  		return (EINVAL);
655  	}
656  
657  	/* save interrupt handler info */
658  	iinfo->hdlr = hdlr;
659  	iinfo->arg1 = arg1;
660  	iinfo->arg2 = arg2;
661  
662  	/* save data for DTrace probes used by intrstat(1m) */
663  	iinfo->dip = cldcp->dip;
664  	iinfo->id = cldcp->id;
665  
666  	iinfo->icookie = MINVINTR_COOKIE + iinfo->ino;
667  
668  	/*
669  	 * Verify that the ino does not generate a cookie which
670  	 * is outside the (MINVINTR_COOKIE, MAXIVNUM) range of the
671  	 * system interrupt table.
672  	 */
673  	if (iinfo->icookie >= MAXIVNUM || iinfo->icookie < MINVINTR_COOKIE) {
674  		DWARN("cnex_add_intr: invalid cookie %x ino %x\n",
675  		    iinfo->icookie, iinfo->ino);
676  		mutex_exit(&cldcp->lock);
677  		return (EINVAL);
678  	}
679  
680  	D1("cnex_add_intr: add hdlr, cfghdl=0x%llx, ino=0x%llx, "
681  	    "cookie=0x%llx\n", cnex_ssp->cfghdl, iinfo->ino, iinfo->icookie);
682  
683  	/* Pick a PIL on the basis of the channel's devclass */
684  	for (idx = 0, pil = PIL_3; idx < CNEX_MAX_DEVS; idx++) {
685  		if (cldcp->devclass == cnex_class_to_intr[idx].devclass) {
686  			pil = cnex_class_to_intr[idx].pil;
687  			break;
688  		}
689  	}
690  
691  	/* add interrupt to solaris ivec table */
692  	if (add_ivintr(iinfo->icookie, pil, (intrfunc)cnex_intr_wrapper,
693  	    (caddr_t)iinfo, NULL, NULL) != 0) {
694  		DWARN("cnex_add_intr: add_ivintr fail cookie %x ino %x\n",
695  		    iinfo->icookie, iinfo->ino);
696  		mutex_exit(&cldcp->lock);
697  		return (EINVAL);
698  	}
699  
700  	/* set the cookie in the HV */
701  	rv = hvldc_intr_setcookie(cnex_ssp->cfghdl, iinfo->ino, iinfo->icookie);
702  
703  	/* pick next CPU in the domain for this channel */
704  	iinfo->cpuid = intr_dist_cpuid();
705  
706  	/* set the target CPU and then enable interrupts */
707  	rv = hvldc_intr_settarget(cnex_ssp->cfghdl, iinfo->ino, iinfo->cpuid);
708  	if (rv) {
709  		DWARN("cnex_add_intr: ino=0x%llx, cannot set target cpu\n",
710  		    iinfo->ino);
711  		goto hv_error;
712  	}
713  	rv = hvldc_intr_setstate(cnex_ssp->cfghdl, iinfo->ino,
714  	    HV_INTR_IDLE_STATE);
715  	if (rv) {
716  		DWARN("cnex_add_intr: ino=0x%llx, cannot set state\n",
717  		    iinfo->ino);
718  		goto hv_error;
719  	}
720  	rv = hvldc_intr_setvalid(cnex_ssp->cfghdl, iinfo->ino, HV_INTR_VALID);
721  	if (rv) {
722  		DWARN("cnex_add_intr: ino=0x%llx, cannot set valid\n",
723  		    iinfo->ino);
724  		goto hv_error;
725  	}
726  
727  	intr_dist_cpuid_add_device_weight(iinfo->cpuid, iinfo->dip,
728  	    iinfo->weight);
729  
730  	mutex_exit(&cldcp->lock);
731  	return (0);
732  
733  hv_error:
734  	(void) rem_ivintr(iinfo->icookie, pil);
735  	mutex_exit(&cldcp->lock);
736  	return (ENXIO);
737  }
738  
739  
740  /*
741   * Exported interface to unregister a LDC endpoint with
742   * the channel nexus
743   */
744  static int
745  cnex_unreg_chan(dev_info_t *dip, uint64_t id)
746  {
747  	cnex_ldc_t	*cldcp, *prev_cldcp;
748  	cnex_soft_state_t *cnex_ssp;
749  	int		instance;
750  
751  	/* Get device instance and structure */
752  	instance = ddi_get_instance(dip);
753  	cnex_ssp = ddi_get_soft_state(cnex_state, instance);
754  
755  	/* find and remove channel from list */
756  	mutex_enter(&cnex_ssp->clist_lock);
757  	prev_cldcp = NULL;
758  	cldcp = cnex_ssp->clist;
759  	while (cldcp) {
760  		if (cldcp->id == id)
761  			break;
762  		prev_cldcp = cldcp;
763  		cldcp = cldcp->next;
764  	}
765  
766  	if (cldcp == 0) {
767  		DWARN("cnex_unreg_chan: invalid channel %d\n", id);
768  		mutex_exit(&cnex_ssp->clist_lock);
769  		return (EINVAL);
770  	}
771  
772  	if (cldcp->tx.hdlr || cldcp->rx.hdlr) {
773  		DWARN("cnex_unreg_chan: handlers still exist: chan %lx\n", id);
774  		mutex_exit(&cnex_ssp->clist_lock);
775  		return (ENXIO);
776  	}
777  
778  	if (prev_cldcp)
779  		prev_cldcp->next = cldcp->next;
780  	else
781  		cnex_ssp->clist = cldcp->next;
782  
783  	mutex_exit(&cnex_ssp->clist_lock);
784  
785  	/* destroy mutex */
786  	mutex_destroy(&cldcp->lock);
787  
788  	/* free channel */
789  	kmem_free(cldcp, sizeof (*cldcp));
790  
791  	return (0);
792  }
793  
794  /*
795   * Remove Tx/Rx interrupt handler for the channel
796   */
797  static int
798  cnex_rem_intr(dev_info_t *dip, uint64_t id, cnex_intrtype_t itype)
799  {
800  	int			rv, idx, pil;
801  	cnex_ldc_t		*cldcp;
802  	cnex_intr_t		*iinfo;
803  	cnex_soft_state_t	*cnex_ssp;
804  	int			instance, istate;
805  
806  	/* Get device instance and structure */
807  	instance = ddi_get_instance(dip);
808  	cnex_ssp = ddi_get_soft_state(cnex_state, instance);
809  
810  	/* get channel info */
811  	mutex_enter(&cnex_ssp->clist_lock);
812  	cldcp = cnex_ssp->clist;
813  	while (cldcp) {
814  		if (cldcp->id == id)
815  			break;
816  		cldcp = cldcp->next;
817  	}
818  	if (cldcp == NULL) {
819  		DWARN("cnex_rem_intr: channel 0x%llx does not exist\n", id);
820  		mutex_exit(&cnex_ssp->clist_lock);
821  		return (EINVAL);
822  	}
823  	mutex_exit(&cnex_ssp->clist_lock);
824  
825  	/* get rid of the channel intr handler */
826  	mutex_enter(&cldcp->lock);
827  
828  	/* get interrupt type */
829  	if (itype == CNEX_TX_INTR) {
830  		iinfo = &(cldcp->tx);
831  	} else if (itype == CNEX_RX_INTR) {
832  		iinfo = &(cldcp->rx);
833  	} else {
834  		DWARN("cnex_rem_intr: invalid interrupt type\n");
835  		mutex_exit(&cldcp->lock);
836  		return (EINVAL);
837  	}
838  
839  	D1("cnex_rem_intr: interrupt ino=0x%x\n", iinfo->ino);
840  
841  	/* check if a handler is already added */
842  	if (iinfo->hdlr == 0) {
843  		DWARN("cnex_rem_intr: interrupt handler does not exist\n");
844  		mutex_exit(&cldcp->lock);
845  		return (EINVAL);
846  	}
847  
848  	D1("cnex_rem_intr: set intr to invalid ino=0x%x\n", iinfo->ino);
849  	rv = hvldc_intr_setvalid(cnex_ssp->cfghdl,
850  	    iinfo->ino, HV_INTR_NOTVALID);
851  	if (rv) {
852  		DWARN("cnex_rem_intr: cannot set valid ino=%x\n", iinfo->ino);
853  		mutex_exit(&cldcp->lock);
854  		return (ENXIO);
855  	}
856  
857  	/*
858  	 * Check if there are pending interrupts. If interrupts are
859  	 * pending return EAGAIN.
860  	 */
861  	rv = hvldc_intr_getstate(cnex_ssp->cfghdl, iinfo->ino, &istate);
862  	if (rv) {
863  		DWARN("cnex_rem_intr: ino=0x%llx, cannot get state\n",
864  		    iinfo->ino);
865  		mutex_exit(&cldcp->lock);
866  		return (ENXIO);
867  	}
868  
869  	/* if interrupts are still pending print warning */
870  	if (istate != HV_INTR_IDLE_STATE) {
871  		DWARN("cnex_rem_intr: cannot remove intr busy ino=%x\n",
872  		    iinfo->ino);
873  		mutex_exit(&cldcp->lock);
874  		return (EAGAIN);
875  	}
876  
877  	/* Pick a PIL on the basis of the channel's devclass */
878  	for (idx = 0, pil = PIL_3; idx < CNEX_MAX_DEVS; idx++) {
879  		if (cldcp->devclass == cnex_class_to_intr[idx].devclass) {
880  			pil = cnex_class_to_intr[idx].pil;
881  			break;
882  		}
883  	}
884  
885  	intr_dist_cpuid_rem_device_weight(iinfo->cpuid, iinfo->dip);
886  
887  	/* remove interrupt */
888  	(void) rem_ivintr(iinfo->icookie, pil);
889  
890  	/* clear interrupt info */
891  	bzero(iinfo, sizeof (*iinfo));
892  
893  	mutex_exit(&cldcp->lock);
894  
895  	return (0);
896  }
897  
898  
899  /*
900   * Clear pending Tx/Rx interrupt
901   */
902  static int
903  cnex_clr_intr(dev_info_t *dip, uint64_t id, cnex_intrtype_t itype)
904  {
905  	int			rv;
906  	cnex_ldc_t		*cldcp;
907  	cnex_intr_t		*iinfo;
908  	cnex_soft_state_t	*cnex_ssp;
909  	int			instance;
910  
911  	/* Get device instance and structure */
912  	instance = ddi_get_instance(dip);
913  	cnex_ssp = ddi_get_soft_state(cnex_state, instance);
914  
915  	/* get channel info */
916  	mutex_enter(&cnex_ssp->clist_lock);
917  	cldcp = cnex_ssp->clist;
918  	while (cldcp) {
919  		if (cldcp->id == id)
920  			break;
921  		cldcp = cldcp->next;
922  	}
923  	if (cldcp == NULL) {
924  		DWARN("cnex_clr_intr: channel 0x%llx does not exist\n", id);
925  		mutex_exit(&cnex_ssp->clist_lock);
926  		return (EINVAL);
927  	}
928  	mutex_exit(&cnex_ssp->clist_lock);
929  
930  	mutex_enter(&cldcp->lock);
931  
932  	/* get interrupt type */
933  	if (itype == CNEX_TX_INTR) {
934  		iinfo = &(cldcp->tx);
935  	} else if (itype == CNEX_RX_INTR) {
936  		iinfo = &(cldcp->rx);
937  	} else {
938  		DWARN("cnex_clr_intr: invalid interrupt type\n");
939  		mutex_exit(&cldcp->lock);
940  		return (EINVAL);
941  	}
942  
943  	D1("%s: interrupt ino=0x%x\n", __func__, iinfo->ino);
944  
945  	/* check if a handler is already added */
946  	if (iinfo->hdlr == 0) {
947  		DWARN("cnex_clr_intr: interrupt handler does not exist\n");
948  		mutex_exit(&cldcp->lock);
949  		return (EINVAL);
950  	}
951  
952  	rv = hvldc_intr_setstate(cnex_ssp->cfghdl, iinfo->ino,
953  	    HV_INTR_IDLE_STATE);
954  	if (rv) {
955  		DWARN("cnex_clr_intr: cannot clear interrupt state\n");
956  		mutex_exit(&cldcp->lock);
957  		return (ENXIO);
958  	}
959  
960  	mutex_exit(&cldcp->lock);
961  
962  	return (0);
963  }
964  
965  /*
966   * Channel nexus interrupt handler wrapper
967   */
968  static uint_t
969  cnex_intr_wrapper(caddr_t arg)
970  {
971  	int 			res;
972  	uint_t 			(*handler)();
973  	caddr_t 		handler_arg1;
974  	caddr_t 		handler_arg2;
975  	cnex_intr_t 		*iinfo = (cnex_intr_t *)arg;
976  
977  	ASSERT(iinfo != NULL);
978  
979  	handler = iinfo->hdlr;
980  	handler_arg1 = iinfo->arg1;
981  	handler_arg2 = iinfo->arg2;
982  
983  	/*
984  	 * The 'interrupt__start' and 'interrupt__complete' probes
985  	 * are provided to support 'intrstat' command. These probes
986  	 * help monitor the interrupts on a per device basis only.
987  	 * In order to provide the ability to monitor the
988  	 * activity on a per channel basis, two additional
989  	 * probes('channelintr__start','channelintr__complete')
990  	 * are provided here.
991  	 */
992  	DTRACE_PROBE4(channelintr__start, uint64_t, iinfo->id,
993  	    cnex_intr_t *, iinfo, void *, handler, caddr_t, handler_arg1);
994  
995  	DTRACE_PROBE4(interrupt__start, dev_info_t, iinfo->dip,
996  	    void *, handler, caddr_t, handler_arg1, caddr_t, handler_arg2);
997  
998  	D1("cnex_intr_wrapper:ino=0x%llx invoke client handler\n", iinfo->ino);
999  	res = (*handler)(handler_arg1, handler_arg2);
1000  
1001  	DTRACE_PROBE4(interrupt__complete, dev_info_t, iinfo->dip,
1002  	    void *, handler, caddr_t, handler_arg1, int, res);
1003  
1004  	DTRACE_PROBE4(channelintr__complete, uint64_t, iinfo->id,
1005  	    cnex_intr_t *, iinfo, void *, handler, caddr_t, handler_arg1);
1006  
1007  	return (res);
1008  }
1009  
1010  /*ARGSUSED*/
1011  static int
1012  cnex_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
1013  {
1014  	int 		rv, instance, reglen;
1015  	cnex_regspec_t	*reg_p;
1016  	ldc_cnex_t	cinfo;
1017  	cnex_soft_state_t *cnex_ssp;
1018  
1019  	switch (cmd) {
1020  	case DDI_ATTACH:
1021  		break;
1022  	case DDI_RESUME:
1023  		return (DDI_SUCCESS);
1024  	default:
1025  		return (DDI_FAILURE);
1026  	}
1027  
1028  	/*
1029  	 * Get the instance specific soft state structure.
1030  	 * Save the devi for this instance in the soft_state data.
1031  	 */
1032  	instance = ddi_get_instance(devi);
1033  	if (ddi_soft_state_zalloc(cnex_state, instance) != DDI_SUCCESS)
1034  		return (DDI_FAILURE);
1035  	cnex_ssp = ddi_get_soft_state(cnex_state, instance);
1036  
1037  	cnex_ssp->devi = devi;
1038  	cnex_ssp->clist = NULL;
1039  
1040  	if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
1041  	    "reg", (caddr_t)&reg_p, &reglen) != DDI_SUCCESS) {
1042  		return (DDI_FAILURE);
1043  	}
1044  
1045  	/* get the sun4v config handle for this device */
1046  	cnex_ssp->cfghdl = SUN4V_REG_SPEC2CFG_HDL(reg_p->physaddr);
1047  	kmem_free(reg_p, reglen);
1048  
1049  	D1("cnex_attach: cfghdl=0x%llx\n", cnex_ssp->cfghdl);
1050  
1051  	/* init channel list mutex */
1052  	mutex_init(&cnex_ssp->clist_lock, NULL, MUTEX_DRIVER, NULL);
1053  
1054  	/* Register with LDC module */
1055  	cinfo.dip = devi;
1056  	cinfo.reg_chan = cnex_reg_chan;
1057  	cinfo.unreg_chan = cnex_unreg_chan;
1058  	cinfo.add_intr = cnex_add_intr;
1059  	cinfo.rem_intr = cnex_rem_intr;
1060  	cinfo.clr_intr = cnex_clr_intr;
1061  
1062  	/*
1063  	 * LDC register will fail if an nexus instance had already
1064  	 * registered with the LDC framework
1065  	 */
1066  	rv = ldc_register(&cinfo);
1067  	if (rv) {
1068  		DWARN("cnex_attach: unable to register with LDC\n");
1069  		ddi_soft_state_free(cnex_state, instance);
1070  		mutex_destroy(&cnex_ssp->clist_lock);
1071  		return (DDI_FAILURE);
1072  	}
1073  
1074  	if (ddi_create_minor_node(devi, "devctl", S_IFCHR, instance,
1075  	    DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
1076  		ddi_remove_minor_node(devi, NULL);
1077  		ddi_soft_state_free(cnex_state, instance);
1078  		mutex_destroy(&cnex_ssp->clist_lock);
1079  		return (DDI_FAILURE);
1080  	}
1081  
1082  	/* Add interrupt redistribution callback. */
1083  	intr_dist_add_weighted(cnex_intr_redist, cnex_ssp);
1084  
1085  	ddi_report_dev(devi);
1086  	return (DDI_SUCCESS);
1087  }
1088  
1089  /*ARGSUSED*/
1090  static int
1091  cnex_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
1092  {
1093  	int 		instance;
1094  	ldc_cnex_t	cinfo;
1095  	cnex_soft_state_t *cnex_ssp;
1096  
1097  	switch (cmd) {
1098  	case DDI_DETACH:
1099  		break;
1100  	case DDI_SUSPEND:
1101  		return (DDI_SUCCESS);
1102  	default:
1103  		return (DDI_FAILURE);
1104  	}
1105  
1106  	instance = ddi_get_instance(devi);
1107  	cnex_ssp = ddi_get_soft_state(cnex_state, instance);
1108  
1109  	/* check if there are any channels still registered */
1110  	if (cnex_ssp->clist) {
1111  		cmn_err(CE_WARN, "?cnex_dettach: channels registered %d\n",
1112  		    ddi_get_instance(devi));
1113  		return (DDI_FAILURE);
1114  	}
1115  
1116  	/* Unregister with LDC module */
1117  	cinfo.dip = devi;
1118  	(void) ldc_unregister(&cinfo);
1119  
1120  	/* Remove interrupt redistribution callback. */
1121  	intr_dist_rem_weighted(cnex_intr_redist, cnex_ssp);
1122  
1123  	/* destroy mutex */
1124  	mutex_destroy(&cnex_ssp->clist_lock);
1125  
1126  	/* free soft state structure */
1127  	ddi_soft_state_free(cnex_state, instance);
1128  
1129  	return (DDI_SUCCESS);
1130  }
1131  
1132  /*ARGSUSED*/
1133  static int
1134  cnex_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1135  {
1136  	int instance;
1137  
1138  	if (otyp != OTYP_CHR)
1139  		return (EINVAL);
1140  
1141  	instance = getminor(*devp);
1142  	if (ddi_get_soft_state(cnex_state, instance) == NULL)
1143  		return (ENXIO);
1144  
1145  	return (0);
1146  }
1147  
1148  /*ARGSUSED*/
1149  static int
1150  cnex_close(dev_t dev, int flags, int otyp, cred_t *credp)
1151  {
1152  	int instance;
1153  
1154  	if (otyp != OTYP_CHR)
1155  		return (EINVAL);
1156  
1157  	instance = getminor(dev);
1158  	if (ddi_get_soft_state(cnex_state, instance) == NULL)
1159  		return (ENXIO);
1160  
1161  	return (0);
1162  }
1163  
1164  /*ARGSUSED*/
1165  static int
1166  cnex_ioctl(dev_t dev,
1167      int cmd, intptr_t arg, int mode, cred_t *cred_p, int *rval_p)
1168  {
1169  	int instance;
1170  	cnex_soft_state_t *cnex_ssp;
1171  
1172  	instance = getminor(dev);
1173  	if ((cnex_ssp = ddi_get_soft_state(cnex_state, instance)) == NULL)
1174  		return (ENXIO);
1175  	ASSERT(cnex_ssp->devi);
1176  	return (ndi_devctl_ioctl(cnex_ssp->devi, cmd, arg, mode, 0));
1177  }
1178  
1179  static int
1180  cnex_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
1181      void *arg, void *result)
1182  {
1183  	char		name[MAXNAMELEN];
1184  	uint32_t	reglen;
1185  	int		*cnex_regspec;
1186  
1187  	switch (ctlop) {
1188  	case DDI_CTLOPS_REPORTDEV:
1189  		if (rdip == NULL)
1190  			return (DDI_FAILURE);
1191  		cmn_err(CE_CONT, "?channel-device: %s%d\n",
1192  		    ddi_driver_name(rdip), ddi_get_instance(rdip));
1193  		return (DDI_SUCCESS);
1194  
1195  	case DDI_CTLOPS_INITCHILD:
1196  	{
1197  		dev_info_t *child = (dev_info_t *)arg;
1198  
1199  		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child,
1200  		    DDI_PROP_DONTPASS, "reg",
1201  		    &cnex_regspec, &reglen) != DDI_SUCCESS) {
1202  			return (DDI_FAILURE);
1203  		}
1204  
1205  		(void) snprintf(name, sizeof (name), "%x", *cnex_regspec);
1206  		ddi_set_name_addr(child, name);
1207  		ddi_set_parent_data(child, NULL);
1208  		ddi_prop_free(cnex_regspec);
1209  		return (DDI_SUCCESS);
1210  	}
1211  
1212  	case DDI_CTLOPS_UNINITCHILD:
1213  	{
1214  		dev_info_t *child = (dev_info_t *)arg;
1215  
1216  		NDI_CONFIG_DEBUG((CE_NOTE,
1217  		    "DDI_CTLOPS_UNINITCHILD(%s, instance=%d)",
1218  		    ddi_driver_name(child), DEVI(child)->devi_instance));
1219  
1220  		ddi_set_name_addr(child, NULL);
1221  
1222  		return (DDI_SUCCESS);
1223  	}
1224  
1225  	case DDI_CTLOPS_DMAPMAPC:
1226  	case DDI_CTLOPS_REPORTINT:
1227  	case DDI_CTLOPS_REGSIZE:
1228  	case DDI_CTLOPS_NREGS:
1229  	case DDI_CTLOPS_SIDDEV:
1230  	case DDI_CTLOPS_SLAVEONLY:
1231  	case DDI_CTLOPS_AFFINITY:
1232  	case DDI_CTLOPS_POKE:
1233  	case DDI_CTLOPS_PEEK:
1234  		/*
1235  		 * These ops correspond to functions that "shouldn't" be called
1236  		 * by a channel-device driver.  So we whine when we're called.
1237  		 */
1238  		cmn_err(CE_WARN, "%s%d: invalid op (%d) from %s%d\n",
1239  		    ddi_driver_name(dip), ddi_get_instance(dip), ctlop,
1240  		    ddi_driver_name(rdip), ddi_get_instance(rdip));
1241  		return (DDI_FAILURE);
1242  
1243  	case DDI_CTLOPS_ATTACH:
1244  	case DDI_CTLOPS_BTOP:
1245  	case DDI_CTLOPS_BTOPR:
1246  	case DDI_CTLOPS_DETACH:
1247  	case DDI_CTLOPS_DVMAPAGESIZE:
1248  	case DDI_CTLOPS_IOMIN:
1249  	case DDI_CTLOPS_POWER:
1250  	case DDI_CTLOPS_PTOB:
1251  	default:
1252  		/*
1253  		 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
1254  		 */
1255  		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
1256  	}
1257  }
1258  
1259  /*
1260   * cnex_find_chan_dip -- Find the dip of a device that is corresponding
1261   * 	to the specific channel. Below are the details on how the dip
1262   *	is derived.
1263   *
1264   *	- In the MD, the cfg-handle is expected to be unique for
1265   *	  virtual-device nodes that have the same 'name' property value.
1266   *	  This value is expected to be the same as that of "reg" property
1267   *	  of the corresponding OBP device node.
1268   *
1269   *	- The value of the 'name' property of a virtual-device node
1270   *	  in the MD is expected to be the same for the corresponding
1271   *	  OBP device node.
1272   *
1273   *	- Find the virtual-device node corresponding to a channel-endpoint
1274   *	  by walking backwards. Then obtain the values for the 'name' and
1275   *	  'cfg-handle' properties.
1276   *
1277   *	- Walk all the children of the cnex, find a matching dip which
1278   *	  has the same 'name' and 'reg' property values.
1279   *
1280   *	- The channels that have no corresponding device driver are
1281   *	  treated as if they  correspond to the cnex driver,
1282   *	  that is, return cnex dip for them. This means, the
1283   *	  cnex acts as an umbrella device driver. Note, this is
1284   *	  for 'intrstat' statistics purposes only. As a result of this,
1285   *	  the 'intrstat' shows cnex as the device that is servicing the
1286   *	  interrupts corresponding to these channels.
1287   *
1288   *	  For now, only one such case is known, that is, the channels that
1289   *	  are used by the "domain-services".
1290   */
1291  static dev_info_t *
1292  cnex_find_chan_dip(dev_info_t *dip, uint64_t chan_id,
1293      md_t *mdp, mde_cookie_t mde)
1294  {
1295  	int listsz;
1296  	int num_nodes;
1297  	int num_devs;
1298  	uint64_t cfghdl;
1299  	char *md_name;
1300  	mde_cookie_t *listp;
1301  	dev_info_t *cdip = NULL;
1302  
1303  	num_nodes = md_node_count(mdp);
1304  	ASSERT(num_nodes > 0);
1305  	listsz = num_nodes * sizeof (mde_cookie_t);
1306  	listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP);
1307  
1308  	num_devs = md_scan_dag(mdp, mde, md_find_name(mdp, "virtual-device"),
1309  	    md_find_name(mdp, "back"), listp);
1310  	ASSERT(num_devs <= 1);
1311  	if (num_devs <= 0) {
1312  		DWARN("cnex_find_chan_dip:channel(0x%llx): "
1313  		    "No virtual-device found\n", chan_id);
1314  		goto fdip_exit;
1315  	}
1316  	if (md_get_prop_str(mdp, listp[0], "name", &md_name) != 0) {
1317  		DWARN("cnex_find_chan_dip:channel(0x%llx): "
1318  		    "name property not found\n", chan_id);
1319  		goto fdip_exit;
1320  	}
1321  
1322  	D1("cnex_find_chan_dip: channel(0x%llx): virtual-device "
1323  	    "name property value = %s\n", chan_id, md_name);
1324  
1325  	if (md_get_prop_val(mdp, listp[0], "cfg-handle", &cfghdl) != 0) {
1326  		DWARN("cnex_find_chan_dip:channel(0x%llx): virtual-device's "
1327  		    "cfg-handle property not found\n", chan_id);
1328  		goto fdip_exit;
1329  	}
1330  
1331  	D1("cnex_find_chan_dip:channel(0x%llx): virtual-device cfg-handle "
1332  	    " property value = 0x%x\n", chan_id, cfghdl);
1333  
1334  	for (cdip = ddi_get_child(dip); cdip != NULL;
1335  	    cdip = ddi_get_next_sibling(cdip)) {
1336  
1337  		int *cnex_regspec;
1338  		uint32_t reglen;
1339  		char	*dev_name;
1340  
1341  		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, cdip,
1342  		    DDI_PROP_DONTPASS, "name",
1343  		    &dev_name) != DDI_PROP_SUCCESS) {
1344  			DWARN("cnex_find_chan_dip: name property not"
1345  			    " found for dip(0x%p)\n", cdip);
1346  			continue;
1347  		}
1348  		if (strcmp(md_name, dev_name) != 0) {
1349  			ddi_prop_free(dev_name);
1350  			continue;
1351  		}
1352  		ddi_prop_free(dev_name);
1353  		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip,
1354  		    DDI_PROP_DONTPASS, "reg",
1355  		    &cnex_regspec, &reglen) != DDI_SUCCESS) {
1356  			DWARN("cnex_find_chan_dip: reg property not"
1357  			    " found for dip(0x%p)\n", cdip);
1358  			continue;
1359  		}
1360  		if (*cnex_regspec == cfghdl) {
1361  			D1("cnex_find_chan_dip:channel(0x%llx): found "
1362  			    "dip(0x%p) drvname=%s\n", chan_id, cdip,
1363  			    ddi_driver_name(cdip));
1364  			ddi_prop_free(cnex_regspec);
1365  			break;
1366  		}
1367  		ddi_prop_free(cnex_regspec);
1368  	}
1369  
1370  fdip_exit:
1371  	if (cdip == NULL) {
1372  		/*
1373  		 * If a virtual-device node exists but no dip found,
1374  		 * then for now print a DEBUG error message only.
1375  		 */
1376  		if (num_devs > 0) {
1377  			DERR("cnex_find_chan_dip:channel(0x%llx): "
1378  			    "No device found\n", chan_id);
1379  		}
1380  
1381  		/* If no dip was found, return cnex device's dip. */
1382  		cdip = dip;
1383  	}
1384  
1385  	kmem_free(listp, listsz);
1386  	D1("cnex_find_chan_dip:channel(0x%llx): returning dip=0x%p\n",
1387  	    chan_id, cdip);
1388  	return (cdip);
1389  }
1390  
1391  /* -------------------------------------------------------------------------- */
1392