1*25cf1a30Sjl /*
2*25cf1a30Sjl  * CDDL HEADER START
3*25cf1a30Sjl  *
4*25cf1a30Sjl  * The contents of this file are subject to the terms of the
5*25cf1a30Sjl  * Common Development and Distribution License (the "License").
6*25cf1a30Sjl  * You may not use this file except in compliance with the License.
7*25cf1a30Sjl  *
8*25cf1a30Sjl  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*25cf1a30Sjl  * or http://www.opensolaris.org/os/licensing.
10*25cf1a30Sjl  * See the License for the specific language governing permissions
11*25cf1a30Sjl  * and limitations under the License.
12*25cf1a30Sjl  *
13*25cf1a30Sjl  * When distributing Covered Code, include this CDDL HEADER in each
14*25cf1a30Sjl  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*25cf1a30Sjl  * If applicable, add the following below this CDDL HEADER, with the
16*25cf1a30Sjl  * fields enclosed by brackets "[]" replaced with your own identifying
17*25cf1a30Sjl  * information: Portions Copyright [yyyy] [name of copyright owner]
18*25cf1a30Sjl  *
19*25cf1a30Sjl  * CDDL HEADER END
20*25cf1a30Sjl  */
21*25cf1a30Sjl /*
22*25cf1a30Sjl  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*25cf1a30Sjl  * Use is subject to license terms.
24*25cf1a30Sjl  */
25*25cf1a30Sjl 
26*25cf1a30Sjl #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*25cf1a30Sjl 
28*25cf1a30Sjl /*
29*25cf1a30Sjl  * CMU-CH nexus interrupt handling:
30*25cf1a30Sjl  *	PCI device interrupt handler wrapper
31*25cf1a30Sjl  *	pil lookup routine
32*25cf1a30Sjl  *	PCI device interrupt related initchild code
33*25cf1a30Sjl  */
34*25cf1a30Sjl 
35*25cf1a30Sjl #include <sys/types.h>
36*25cf1a30Sjl #include <sys/kmem.h>
37*25cf1a30Sjl #include <sys/async.h>
38*25cf1a30Sjl #include <sys/spl.h>
39*25cf1a30Sjl #include <sys/sunddi.h>
40*25cf1a30Sjl #include <sys/machsystm.h>
41*25cf1a30Sjl #include <sys/ddi_impldefs.h>
42*25cf1a30Sjl #include <sys/pcicmu/pcicmu.h>
43*25cf1a30Sjl #include <sys/sdt.h>
44*25cf1a30Sjl 
45*25cf1a30Sjl uint_t pcmu_intr_wrapper(caddr_t arg);
46*25cf1a30Sjl 
47*25cf1a30Sjl /*
48*25cf1a30Sjl  * interrupt jabber:
49*25cf1a30Sjl  *
50*25cf1a30Sjl  * When an interrupt line is jabbering, every time the state machine for the
51*25cf1a30Sjl  * associated ino is idled, a new mondo will be sent and the ino will go into
52*25cf1a30Sjl  * the pending state again. The mondo will cause a new call to
53*25cf1a30Sjl  * pcmu_intr_wrapper() which normally idles the ino's state machine which would
54*25cf1a30Sjl  * precipitate another trip round the loop.
55*25cf1a30Sjl  * The loop can be broken by preventing the ino's state machine from being
56*25cf1a30Sjl  * idled when an interrupt line is jabbering. See the comment at the
57*25cf1a30Sjl  * beginning of pcmu_intr_wrapper() explaining how the 'interrupt jabber
58*25cf1a30Sjl  * protection' code does this.
59*25cf1a30Sjl  */
60*25cf1a30Sjl 
61*25cf1a30Sjl 
62*25cf1a30Sjl /*
63*25cf1a30Sjl  * If the unclaimed interrupt count has reached the limit set by
64*25cf1a30Sjl  * pcmu_unclaimed_intr_max within the time limit, then all interrupts
65*25cf1a30Sjl  * on this ino is blocked by not idling the interrupt state machine.
66*25cf1a30Sjl  */
67*25cf1a30Sjl static int
68*25cf1a30Sjl pcmu_spurintr(pcmu_ib_ino_info_t *ino_p) {
69*25cf1a30Sjl 	int i;
70*25cf1a30Sjl 	ih_t *ih_p = ino_p->pino_ih_start;
71*25cf1a30Sjl 	pcmu_t *pcmu_p = ino_p->pino_ib_p->pib_pcmu_p;
72*25cf1a30Sjl 	char *err_fmt_str;
73*25cf1a30Sjl 
74*25cf1a30Sjl 	if (ino_p->pino_unclaimed > pcmu_unclaimed_intr_max) {
75*25cf1a30Sjl 		return (DDI_INTR_CLAIMED);
76*25cf1a30Sjl 	}
77*25cf1a30Sjl 	if (!ino_p->pino_unclaimed) {
78*25cf1a30Sjl 		ino_p->pino_spurintr_begin = ddi_get_lbolt();
79*25cf1a30Sjl 	}
80*25cf1a30Sjl 	ino_p->pino_unclaimed++;
81*25cf1a30Sjl 	if (ino_p->pino_unclaimed <= pcmu_unclaimed_intr_max) {
82*25cf1a30Sjl 		goto clear;
83*25cf1a30Sjl 	}
84*25cf1a30Sjl 	if (drv_hztousec(ddi_get_lbolt() - ino_p->pino_spurintr_begin)
85*25cf1a30Sjl 	    > pcmu_spurintr_duration) {
86*25cf1a30Sjl 		ino_p->pino_unclaimed = 0;
87*25cf1a30Sjl 		goto clear;
88*25cf1a30Sjl 	}
89*25cf1a30Sjl 	err_fmt_str = "%s%d: ino 0x%x blocked";
90*25cf1a30Sjl 	goto warn;
91*25cf1a30Sjl clear:
92*25cf1a30Sjl 	/* clear the pending state */
93*25cf1a30Sjl 	PCMU_IB_INO_INTR_CLEAR(ino_p->pino_clr_reg);
94*25cf1a30Sjl 	err_fmt_str = "!%s%d: spurious interrupt from ino 0x%x";
95*25cf1a30Sjl warn:
96*25cf1a30Sjl 	cmn_err(CE_WARN, err_fmt_str, NAMEINST(pcmu_p->pcmu_dip),
97*25cf1a30Sjl 	    ino_p->pino_ino);
98*25cf1a30Sjl 	for (i = 0; i < ino_p->pino_ih_size; i++, ih_p = ih_p->ih_next) {
99*25cf1a30Sjl 		cmn_err(CE_CONT, "!%s-%d#%x ", NAMEINST(ih_p->ih_dip),
100*25cf1a30Sjl 		    ih_p->ih_inum);
101*25cf1a30Sjl 	}
102*25cf1a30Sjl 	cmn_err(CE_CONT, "!\n");
103*25cf1a30Sjl 	return (DDI_INTR_CLAIMED);
104*25cf1a30Sjl }
105*25cf1a30Sjl 
106*25cf1a30Sjl /*
107*25cf1a30Sjl  * pcmu_intr_wrapper
108*25cf1a30Sjl  *
109*25cf1a30Sjl  * This routine is used as wrapper around interrupt handlers installed by child
110*25cf1a30Sjl  * device drivers.  This routine invokes the driver interrupt handlers and
111*25cf1a30Sjl  * examines the return codes.
112*25cf1a30Sjl  * There is a count of unclaimed interrupts kept on a per-ino basis. If at
113*25cf1a30Sjl  * least one handler claims the interrupt then the counter is halved and the
114*25cf1a30Sjl  * interrupt state machine is idled. If no handler claims the interrupt then
115*25cf1a30Sjl  * the counter is incremented by one and the state machine is idled.
116*25cf1a30Sjl  * If the count ever reaches the limit value set by pcmu_unclaimed_intr_max
117*25cf1a30Sjl  * then the interrupt state machine is not idled thus preventing any further
118*25cf1a30Sjl  * interrupts on that ino. The state machine will only be idled again if a
119*25cf1a30Sjl  * handler is subsequently added or removed.
120*25cf1a30Sjl  *
121*25cf1a30Sjl  * return value: DDI_INTR_CLAIMED if any handlers claimed the interrupt,
122*25cf1a30Sjl  * DDI_INTR_UNCLAIMED otherwise.
123*25cf1a30Sjl  */
124*25cf1a30Sjl uint_t
125*25cf1a30Sjl pcmu_intr_wrapper(caddr_t arg)
126*25cf1a30Sjl {
127*25cf1a30Sjl 	pcmu_ib_ino_info_t *ino_p = (pcmu_ib_ino_info_t *)arg;
128*25cf1a30Sjl 	uint_t result = 0, r;
129*25cf1a30Sjl 	ih_t *ih_p = ino_p->pino_ih_start;
130*25cf1a30Sjl 	int i;
131*25cf1a30Sjl #ifdef	DEBUG
132*25cf1a30Sjl 	pcmu_t *pcmu_p = ino_p->pino_ib_p->pib_pcmu_p;
133*25cf1a30Sjl #endif
134*25cf1a30Sjl 
135*25cf1a30Sjl 
136*25cf1a30Sjl 	for (i = 0; i < ino_p->pino_ih_size; i++, ih_p = ih_p->ih_next) {
137*25cf1a30Sjl 		dev_info_t *dip = ih_p->ih_dip;
138*25cf1a30Sjl 		uint_t (*handler)() = ih_p->ih_handler;
139*25cf1a30Sjl 		caddr_t arg1 = ih_p->ih_handler_arg1;
140*25cf1a30Sjl 		caddr_t arg2 = ih_p->ih_handler_arg2;
141*25cf1a30Sjl 
142*25cf1a30Sjl 		if (ih_p->ih_intr_state == PCMU_INTR_STATE_DISABLE) {
143*25cf1a30Sjl 			PCMU_DBG3(PCMU_DBG_INTR, pcmu_p->pcmu_dip,
144*25cf1a30Sjl 			    "pcmu_intr_wrapper: %s%d interrupt %d is "
145*25cf1a30Sjl 			    "disabled\n", ddi_driver_name(dip),
146*25cf1a30Sjl 			    ddi_get_instance(dip), ino_p->pino_ino);
147*25cf1a30Sjl 			continue;
148*25cf1a30Sjl 		}
149*25cf1a30Sjl 
150*25cf1a30Sjl 		DTRACE_PROBE4(pcmu__interrupt__start, dev_info_t, dip,
151*25cf1a30Sjl 		    void *, handler, caddr_t, arg1, caddr_t, arg2);
152*25cf1a30Sjl 
153*25cf1a30Sjl 		r = (*handler)(arg1, arg2);
154*25cf1a30Sjl 		DTRACE_PROBE4(pcmu__interrupt__complete, dev_info_t, dip,
155*25cf1a30Sjl 		    void *, handler, caddr_t, arg1, int, r);
156*25cf1a30Sjl 
157*25cf1a30Sjl 		result += r;
158*25cf1a30Sjl 	}
159*25cf1a30Sjl 
160*25cf1a30Sjl 	if (!result) {
161*25cf1a30Sjl 		return (pcmu_spurintr(ino_p));
162*25cf1a30Sjl 	}
163*25cf1a30Sjl 	ino_p->pino_unclaimed = 0;
164*25cf1a30Sjl 	/* clear the pending state */
165*25cf1a30Sjl 	PCMU_IB_INO_INTR_CLEAR(ino_p->pino_clr_reg);
166*25cf1a30Sjl 	return (DDI_INTR_CLAIMED);
167*25cf1a30Sjl }
168*25cf1a30Sjl 
169*25cf1a30Sjl int
170*25cf1a30Sjl pcmu_add_intr(dev_info_t *dip, dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp)
171*25cf1a30Sjl {
172*25cf1a30Sjl 	pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip));
173*25cf1a30Sjl 	pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p;
174*25cf1a30Sjl 	ih_t *ih_p;
175*25cf1a30Sjl 	pcmu_ib_ino_t ino;
176*25cf1a30Sjl 	pcmu_ib_ino_info_t *ino_p; /* pulse interrupts have no ino */
177*25cf1a30Sjl 	pcmu_ib_mondo_t mondo;
178*25cf1a30Sjl 	uint32_t cpu_id;
179*25cf1a30Sjl 	int ret;
180*25cf1a30Sjl 
181*25cf1a30Sjl 	ino = PCMU_IB_MONDO_TO_INO(hdlp->ih_vector);
182*25cf1a30Sjl 
183*25cf1a30Sjl 	PCMU_DBG3(PCMU_DBG_A_INTX, dip, "pcmu_add_intr: rdip=%s%d ino=%x\n",
184*25cf1a30Sjl 	    ddi_driver_name(rdip), ddi_get_instance(rdip), ino);
185*25cf1a30Sjl 
186*25cf1a30Sjl 	if (ino > pib_p->pib_max_ino) {
187*25cf1a30Sjl 		PCMU_DBG1(PCMU_DBG_A_INTX, dip, "ino %x is invalid\n", ino);
188*25cf1a30Sjl 		return (DDI_INTR_NOTFOUND);
189*25cf1a30Sjl 	}
190*25cf1a30Sjl 
191*25cf1a30Sjl 	if ((mondo = PCMU_IB_INO_TO_MONDO(pcmu_p->pcmu_ib_p, ino)) == 0)
192*25cf1a30Sjl 		goto fail1;
193*25cf1a30Sjl 
194*25cf1a30Sjl 	ino = PCMU_IB_MONDO_TO_INO(mondo);
195*25cf1a30Sjl 
196*25cf1a30Sjl 	mutex_enter(&pib_p->pib_ino_lst_mutex);
197*25cf1a30Sjl 	ih_p = pcmu_ib_alloc_ih(rdip, hdlp->ih_inum,
198*25cf1a30Sjl 	    hdlp->ih_cb_func, hdlp->ih_cb_arg1, hdlp->ih_cb_arg2);
199*25cf1a30Sjl 
200*25cf1a30Sjl 	if (ino_p = pcmu_ib_locate_ino(pib_p, ino)) {	/* sharing ino */
201*25cf1a30Sjl 		uint32_t intr_index = hdlp->ih_inum;
202*25cf1a30Sjl 		if (pcmu_ib_ino_locate_intr(ino_p, rdip, intr_index)) {
203*25cf1a30Sjl 			PCMU_DBG1(PCMU_DBG_A_INTX, dip,
204*25cf1a30Sjl 			    "dup intr #%d\n", intr_index);
205*25cf1a30Sjl 			goto fail3;
206*25cf1a30Sjl 		}
207*25cf1a30Sjl 
208*25cf1a30Sjl 		/*
209*25cf1a30Sjl 		 * add default weight(0) to the cpu that we are
210*25cf1a30Sjl 		 * already targeting
211*25cf1a30Sjl 		 */
212*25cf1a30Sjl 		cpu_id = ino_p->pino_cpuid;
213*25cf1a30Sjl 		intr_dist_cpuid_add_device_weight(cpu_id, rdip, 0);
214*25cf1a30Sjl 		pcmu_ib_ino_add_intr(pcmu_p, ino_p, ih_p);
215*25cf1a30Sjl 		goto ino_done;
216*25cf1a30Sjl 	}
217*25cf1a30Sjl 
218*25cf1a30Sjl 	ino_p = pcmu_ib_new_ino(pib_p, ino, ih_p);
219*25cf1a30Sjl 	hdlp->ih_vector = mondo;
220*25cf1a30Sjl 
221*25cf1a30Sjl 	PCMU_DBG2(PCMU_DBG_A_INTX, dip, "pcmu_add_intr:  pil=0x%x mondo=0x%x\n",
222*25cf1a30Sjl 	    hdlp->ih_pri, hdlp->ih_vector);
223*25cf1a30Sjl 
224*25cf1a30Sjl 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp,
225*25cf1a30Sjl 	    (ddi_intr_handler_t *)pcmu_intr_wrapper, (caddr_t)ino_p, NULL);
226*25cf1a30Sjl 
227*25cf1a30Sjl 	ret = i_ddi_add_ivintr(hdlp);
228*25cf1a30Sjl 
229*25cf1a30Sjl 	/*
230*25cf1a30Sjl 	 * Restore original interrupt handler
231*25cf1a30Sjl 	 * and arguments in interrupt handle.
232*25cf1a30Sjl 	 */
233*25cf1a30Sjl 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_handler,
234*25cf1a30Sjl 	    ih_p->ih_handler_arg1, ih_p->ih_handler_arg2);
235*25cf1a30Sjl 
236*25cf1a30Sjl 	if (ret != DDI_SUCCESS) {
237*25cf1a30Sjl 		goto fail4;
238*25cf1a30Sjl 	}
239*25cf1a30Sjl 	/* Save the pil for this ino */
240*25cf1a30Sjl 	ino_p->pino_pil = hdlp->ih_pri;
241*25cf1a30Sjl 
242*25cf1a30Sjl 	/* clear and enable interrupt */
243*25cf1a30Sjl 	PCMU_IB_INO_INTR_CLEAR(ino_p->pino_clr_reg);
244*25cf1a30Sjl 
245*25cf1a30Sjl 	/* select cpu for sharing and removal */
246*25cf1a30Sjl 	cpu_id = pcmu_intr_dist_cpuid(pib_p, ino_p);
247*25cf1a30Sjl 	ino_p->pino_cpuid = cpu_id;
248*25cf1a30Sjl 	ino_p->pino_established = 1;
249*25cf1a30Sjl 	intr_dist_cpuid_add_device_weight(cpu_id, rdip, 0);
250*25cf1a30Sjl 
251*25cf1a30Sjl 	cpu_id = u2u_translate_tgtid(pib_p->pib_pcmu_p,
252*25cf1a30Sjl 	    cpu_id, ino_p->pino_map_reg);
253*25cf1a30Sjl 	*ino_p->pino_map_reg = ib_get_map_reg(mondo, cpu_id);
254*25cf1a30Sjl 	*ino_p->pino_map_reg;
255*25cf1a30Sjl ino_done:
256*25cf1a30Sjl 	mutex_exit(&pib_p->pib_ino_lst_mutex);
257*25cf1a30Sjl done:
258*25cf1a30Sjl 	PCMU_DBG2(PCMU_DBG_A_INTX, dip, "done! Interrupt 0x%x pil=%x\n",
259*25cf1a30Sjl 		hdlp->ih_vector, hdlp->ih_pri);
260*25cf1a30Sjl 	return (DDI_SUCCESS);
261*25cf1a30Sjl fail4:
262*25cf1a30Sjl 	pcmu_ib_delete_ino(pib_p, ino_p);
263*25cf1a30Sjl fail3:
264*25cf1a30Sjl 	if (ih_p->ih_config_handle)
265*25cf1a30Sjl 		pci_config_teardown(&ih_p->ih_config_handle);
266*25cf1a30Sjl 	mutex_exit(&pib_p->pib_ino_lst_mutex);
267*25cf1a30Sjl 	kmem_free(ih_p, sizeof (ih_t));
268*25cf1a30Sjl fail1:
269*25cf1a30Sjl 	PCMU_DBG2(PCMU_DBG_A_INTX, dip, "Failed! Interrupt 0x%x pil=%x\n",
270*25cf1a30Sjl 		hdlp->ih_vector, hdlp->ih_pri);
271*25cf1a30Sjl 	return (DDI_FAILURE);
272*25cf1a30Sjl }
273*25cf1a30Sjl 
274*25cf1a30Sjl int
275*25cf1a30Sjl pcmu_remove_intr(dev_info_t *dip, dev_info_t *rdip,
276*25cf1a30Sjl     ddi_intr_handle_impl_t *hdlp)
277*25cf1a30Sjl {
278*25cf1a30Sjl 	pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip));
279*25cf1a30Sjl 	pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p;
280*25cf1a30Sjl 	pcmu_ib_ino_t ino;
281*25cf1a30Sjl 	pcmu_ib_mondo_t mondo;
282*25cf1a30Sjl 	pcmu_ib_ino_info_t *ino_p;	/* non-pulse only */
283*25cf1a30Sjl 	ih_t *ih_p;			/* non-pulse only */
284*25cf1a30Sjl 
285*25cf1a30Sjl 	ino = PCMU_IB_MONDO_TO_INO(hdlp->ih_vector);
286*25cf1a30Sjl 
287*25cf1a30Sjl 	PCMU_DBG3(PCMU_DBG_R_INTX, dip, "pcmu_rem_intr: rdip=%s%d ino=%x\n",
288*25cf1a30Sjl 	    ddi_driver_name(rdip), ddi_get_instance(rdip), ino);
289*25cf1a30Sjl 
290*25cf1a30Sjl 	/* Translate the interrupt property */
291*25cf1a30Sjl 	mondo = PCMU_IB_INO_TO_MONDO(pcmu_p->pcmu_ib_p, ino);
292*25cf1a30Sjl 	if (mondo == 0) {
293*25cf1a30Sjl 		PCMU_DBG1(PCMU_DBG_R_INTX, dip,
294*25cf1a30Sjl 		    "can't get mondo for ino %x\n", ino);
295*25cf1a30Sjl 		return (DDI_FAILURE);
296*25cf1a30Sjl 	}
297*25cf1a30Sjl 	ino = PCMU_IB_MONDO_TO_INO(mondo);
298*25cf1a30Sjl 
299*25cf1a30Sjl 	mutex_enter(&pib_p->pib_ino_lst_mutex);
300*25cf1a30Sjl 	ino_p = pcmu_ib_locate_ino(pib_p, ino);
301*25cf1a30Sjl 	if (!ino_p) {
302*25cf1a30Sjl 		mutex_exit(&pib_p->pib_ino_lst_mutex);
303*25cf1a30Sjl 		return (DDI_SUCCESS);
304*25cf1a30Sjl 	}
305*25cf1a30Sjl 
306*25cf1a30Sjl 	ih_p = pcmu_ib_ino_locate_intr(ino_p, rdip, hdlp->ih_inum);
307*25cf1a30Sjl 	pcmu_ib_ino_rem_intr(pcmu_p, ino_p, ih_p);
308*25cf1a30Sjl 	intr_dist_cpuid_rem_device_weight(ino_p->pino_cpuid, rdip);
309*25cf1a30Sjl 	if (ino_p->pino_ih_size == 0) {
310*25cf1a30Sjl 		PCMU_IB_INO_INTR_PEND(ib_clear_intr_reg_addr(pib_p, ino));
311*25cf1a30Sjl 		hdlp->ih_vector = mondo;
312*25cf1a30Sjl 		i_ddi_rem_ivintr(hdlp);
313*25cf1a30Sjl 		pcmu_ib_delete_ino(pib_p, ino_p);
314*25cf1a30Sjl 	}
315*25cf1a30Sjl 
316*25cf1a30Sjl 	/* re-enable interrupt only if mapping register still shared */
317*25cf1a30Sjl 	if (ino_p->pino_ih_size) {
318*25cf1a30Sjl 		PCMU_IB_INO_INTR_ON(ino_p->pino_map_reg);
319*25cf1a30Sjl 		*ino_p->pino_map_reg;
320*25cf1a30Sjl 	}
321*25cf1a30Sjl 	mutex_exit(&pib_p->pib_ino_lst_mutex);
322*25cf1a30Sjl 	if (ino_p->pino_ih_size == 0) {
323*25cf1a30Sjl 		kmem_free(ino_p, sizeof (pcmu_ib_ino_info_t));
324*25cf1a30Sjl 	}
325*25cf1a30Sjl 	PCMU_DBG1(PCMU_DBG_R_INTX, dip, "success! mondo=%x\n", mondo);
326*25cf1a30Sjl 	return (DDI_SUCCESS);
327*25cf1a30Sjl }
328*25cf1a30Sjl 
329*25cf1a30Sjl /*
330*25cf1a30Sjl  * free the pcmu_inos array allocated during pcmu_intr_setup. the actual
331*25cf1a30Sjl  * interrupts are torn down by their respective block destroy routines:
332*25cf1a30Sjl  * cb_destroy, pcmu_pbm_destroy, and ib_destroy.
333*25cf1a30Sjl  */
334*25cf1a30Sjl void
335*25cf1a30Sjl pcmu_intr_teardown(pcmu_t *pcmu_p)
336*25cf1a30Sjl {
337*25cf1a30Sjl 	kmem_free(pcmu_p->pcmu_inos, pcmu_p->pcmu_inos_len);
338*25cf1a30Sjl 	pcmu_p->pcmu_inos = NULL;
339*25cf1a30Sjl 	pcmu_p->pcmu_inos_len = 0;
340*25cf1a30Sjl }
341