xref: /onnv-gate/usr/src/uts/sun4u/io/pci/pci_cb.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * PCI Control Block object
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate #include <sys/types.h>
33*0Sstevel@tonic-gate #include <sys/kmem.h>
34*0Sstevel@tonic-gate #include <sys/systm.h>		/* timeout() */
35*0Sstevel@tonic-gate #include <sys/async.h>
36*0Sstevel@tonic-gate #include <sys/sunddi.h>
37*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
38*0Sstevel@tonic-gate #include <sys/pci/pci_obj.h>
39*0Sstevel@tonic-gate #include <sys/machsystm.h>
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate #ifdef _STARFIRE
42*0Sstevel@tonic-gate #include <sys/starfire.h>
43*0Sstevel@tonic-gate #endif /* _STARFIRE */
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate /*LINTLIBRARY*/
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate void
48*0Sstevel@tonic-gate cb_create(pci_t *pci_p)
49*0Sstevel@tonic-gate {
50*0Sstevel@tonic-gate 	cb_t *cb_p = (cb_t *)kmem_zalloc(sizeof (cb_t), KM_SLEEP);
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate 	mutex_init(&cb_p->cb_intr_lock, NULL, MUTEX_DRIVER, NULL);
53*0Sstevel@tonic-gate 	pci_p->pci_cb_p = cb_p;
54*0Sstevel@tonic-gate 	cb_p->cb_pci_cmn_p = pci_p->pci_common_p;
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate 	pci_cb_setup(pci_p);
57*0Sstevel@tonic-gate }
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate void
60*0Sstevel@tonic-gate cb_destroy(pci_t *pci_p)
61*0Sstevel@tonic-gate {
62*0Sstevel@tonic-gate 	cb_t *cb_p = pci_p->pci_cb_p;
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate 	intr_dist_rem(cb_intr_dist, cb_p);
65*0Sstevel@tonic-gate 	pci_cb_teardown(pci_p);
66*0Sstevel@tonic-gate 	pci_p->pci_cb_p = NULL;
67*0Sstevel@tonic-gate 	mutex_destroy(&cb_p->cb_intr_lock);
68*0Sstevel@tonic-gate 	kmem_free(cb_p, sizeof (cb_t));
69*0Sstevel@tonic-gate }
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate static void
72*0Sstevel@tonic-gate cb_set_nintr_reg(cb_t *cb_p, ib_ino_t ino, uint64_t value)
73*0Sstevel@tonic-gate {
74*0Sstevel@tonic-gate 	uint64_t pa = cb_ino_to_clr_pa(cb_p, ino);
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate 	DEBUG3(DBG_CB|DBG_CONT, NULL,
77*0Sstevel@tonic-gate 		"pci-%x cb_set_nintr_reg: ino=%x PA=%016llx\n",
78*0Sstevel@tonic-gate 		cb_p->cb_pci_cmn_p->pci_common_id, ino, pa);
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate 	stdphysio(pa, value);
81*0Sstevel@tonic-gate 	(void) lddphysio(pa);	/* flush the previous write */
82*0Sstevel@tonic-gate }
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate /*
85*0Sstevel@tonic-gate  * enable an internal interrupt source:
86*0Sstevel@tonic-gate  * if an interrupt is shared by both sides, record it in cb_inos[] and
87*0Sstevel@tonic-gate  * cb will own its distribution.
88*0Sstevel@tonic-gate  */
89*0Sstevel@tonic-gate void
90*0Sstevel@tonic-gate cb_enable_nintr(pci_t *pci_p, enum cb_nintr_index idx)
91*0Sstevel@tonic-gate {
92*0Sstevel@tonic-gate 	cb_t *cb_p = pci_p->pci_cb_p;
93*0Sstevel@tonic-gate 	ib_ino_t ino = IB_MONDO_TO_INO(pci_p->pci_inos[idx]);
94*0Sstevel@tonic-gate 	ib_mondo_t mondo = CB_INO_TO_MONDO(cb_p, ino);
95*0Sstevel@tonic-gate 	uint32_t cpu_id;
96*0Sstevel@tonic-gate 	uint64_t reg, pa;
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate 	ASSERT(idx < CBNINTR_MAX);
99*0Sstevel@tonic-gate 	pa = cb_ino_to_map_pa(cb_p, ino);
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 	mutex_enter(&cb_p->cb_intr_lock);
102*0Sstevel@tonic-gate 	cpu_id = intr_dist_cpuid();
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate #ifdef _STARFIRE
105*0Sstevel@tonic-gate 	cpu_id = pc_translate_tgtid(cb_p->cb_ittrans_cookie, cpu_id,
106*0Sstevel@tonic-gate 		IB_GET_MAPREG_INO(ino));
107*0Sstevel@tonic-gate #endif /* _STARFIRE */
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 	reg = ib_get_map_reg(mondo, cpu_id);
110*0Sstevel@tonic-gate 	stdphysio(pa, reg);
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate 	ASSERT(cb_p->cb_inos[idx] == 0);
113*0Sstevel@tonic-gate 	cb_p->cb_inos[idx] = ino;
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate 	cb_set_nintr_reg(cb_p, ino, COMMON_CLEAR_INTR_REG_IDLE);
116*0Sstevel@tonic-gate 	mutex_exit(&cb_p->cb_intr_lock);
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 	DEBUG3(DBG_CB|DBG_CONT, NULL,
119*0Sstevel@tonic-gate 		"pci-%x cb_enable_nintr: ino=%x cpu_id=%x\n",
120*0Sstevel@tonic-gate 		pci_p->pci_id, ino, cpu_id);
121*0Sstevel@tonic-gate 	DEBUG2(DBG_CB|DBG_CONT, NULL, "\tPA=%016llx data=%016llx\n", pa, reg);
122*0Sstevel@tonic-gate }
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate static void
125*0Sstevel@tonic-gate cb_disable_nintr_reg(cb_t *cb_p, ib_ino_t ino, int wait)
126*0Sstevel@tonic-gate {
127*0Sstevel@tonic-gate 	uint64_t tmp, map_reg_pa = cb_ino_to_map_pa(cb_p, ino);
128*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cb_p->cb_intr_lock));
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 	/* mark interrupt invalid in mapping register */
131*0Sstevel@tonic-gate 	tmp = lddphysio(map_reg_pa) & ~COMMON_INTR_MAP_REG_VALID;
132*0Sstevel@tonic-gate 	stdphysio(map_reg_pa, tmp);
133*0Sstevel@tonic-gate 	(void) lddphysio(map_reg_pa);   /* flush previous write */
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate 	if (wait) {
136*0Sstevel@tonic-gate 		hrtime_t start_time;
137*0Sstevel@tonic-gate 		uint64_t state_reg_pa = cb_p->cb_obsta_pa;
138*0Sstevel@tonic-gate 		uint_t shift = (ino & 0x1f) << 1;
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 		/* busy wait if there is interrupt being processed */
141*0Sstevel@tonic-gate 		/* unless panic or timeout for interrupt pending is reached */
142*0Sstevel@tonic-gate 		start_time = gethrtime();
143*0Sstevel@tonic-gate 		while ((((lddphysio(state_reg_pa) >> shift) &
144*0Sstevel@tonic-gate 			COMMON_CLEAR_INTR_REG_MASK) ==
145*0Sstevel@tonic-gate 			COMMON_CLEAR_INTR_REG_PENDING) && !panicstr) {
146*0Sstevel@tonic-gate 			if (gethrtime() - start_time > pci_intrpend_timeout) {
147*0Sstevel@tonic-gate 				cmn_err(CE_WARN,
148*0Sstevel@tonic-gate 				"pci@%x cb_disable_nintr_reg(%p,%x) timeout",
149*0Sstevel@tonic-gate 					cb_p->cb_pci_cmn_p->pci_common_id,
150*0Sstevel@tonic-gate 					map_reg_pa,
151*0Sstevel@tonic-gate 					CB_INO_TO_MONDO(cb_p, ino));
152*0Sstevel@tonic-gate 				break;
153*0Sstevel@tonic-gate 			}
154*0Sstevel@tonic-gate 		}
155*0Sstevel@tonic-gate 	}
156*0Sstevel@tonic-gate }
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate void
159*0Sstevel@tonic-gate cb_disable_nintr(cb_t *cb_p, enum cb_nintr_index idx, int wait)
160*0Sstevel@tonic-gate {
161*0Sstevel@tonic-gate 	ib_ino_t ino = cb_p->cb_inos[idx];
162*0Sstevel@tonic-gate 	ASSERT(idx < CBNINTR_MAX);
163*0Sstevel@tonic-gate 	ASSERT(ino);
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	mutex_enter(&cb_p->cb_intr_lock);
166*0Sstevel@tonic-gate 	cb_disable_nintr_reg(cb_p, ino, wait);
167*0Sstevel@tonic-gate 	cb_set_nintr_reg(cb_p, ino, COMMON_CLEAR_INTR_REG_PENDING);
168*0Sstevel@tonic-gate 	cb_p->cb_inos[idx] = 0;
169*0Sstevel@tonic-gate 	mutex_exit(&cb_p->cb_intr_lock);
170*0Sstevel@tonic-gate #ifdef _STARFIRE
171*0Sstevel@tonic-gate 	pc_ittrans_cleanup(cb_p->cb_ittrans_cookie, (volatile uint64_t *)ino);
172*0Sstevel@tonic-gate #endif /* _STARFIRE */
173*0Sstevel@tonic-gate }
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate void
176*0Sstevel@tonic-gate cb_clear_nintr(cb_t *cb_p, enum cb_nintr_index idx)
177*0Sstevel@tonic-gate {
178*0Sstevel@tonic-gate 	ib_ino_t ino = cb_p->cb_inos[idx];
179*0Sstevel@tonic-gate 	ASSERT(idx < CBNINTR_MAX);
180*0Sstevel@tonic-gate 	ASSERT(ino);
181*0Sstevel@tonic-gate 	cb_set_nintr_reg(cb_p, ino, COMMON_CLEAR_INTR_REG_IDLE);
182*0Sstevel@tonic-gate }
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate void
185*0Sstevel@tonic-gate cb_intr_dist(void *arg)
186*0Sstevel@tonic-gate {
187*0Sstevel@tonic-gate 	int i;
188*0Sstevel@tonic-gate 	cb_t *cb_p = (cb_t *)arg;
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 	mutex_enter(&cb_p->cb_intr_lock);
191*0Sstevel@tonic-gate 	for (i = 0; i < cb_p->cb_no_of_inos; i++) {
192*0Sstevel@tonic-gate 		uint64_t mr_pa;
193*0Sstevel@tonic-gate 		volatile uint64_t imr;
194*0Sstevel@tonic-gate 		ib_mondo_t mondo;
195*0Sstevel@tonic-gate 		uint32_t cpu_id;
196*0Sstevel@tonic-gate 
197*0Sstevel@tonic-gate 		ib_ino_t ino = cb_p->cb_inos[i];
198*0Sstevel@tonic-gate 		if (!ino)	/* skip non-shared interrupts */
199*0Sstevel@tonic-gate 			continue;
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate 		mr_pa = cb_ino_to_map_pa(cb_p, ino);
202*0Sstevel@tonic-gate 		imr = lddphysio(mr_pa);
203*0Sstevel@tonic-gate 		if (!IB_INO_INTR_ISON(imr))
204*0Sstevel@tonic-gate 			continue;
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 		mondo = CB_INO_TO_MONDO(cb_p, ino);
207*0Sstevel@tonic-gate 		cpu_id = intr_dist_cpuid();
208*0Sstevel@tonic-gate #ifdef _STARFIRE
209*0Sstevel@tonic-gate 		cpu_id = pc_translate_tgtid(cb_p->cb_ittrans_cookie, cpu_id,
210*0Sstevel@tonic-gate 			IB_GET_MAPREG_INO(ino));
211*0Sstevel@tonic-gate #else
212*0Sstevel@tonic-gate 		if (ib_map_reg_get_cpu(imr) == cpu_id)
213*0Sstevel@tonic-gate 			continue;	/* same cpu target, no re-program */
214*0Sstevel@tonic-gate #endif
215*0Sstevel@tonic-gate 		cb_disable_nintr_reg(cb_p, ino, IB_INTR_WAIT);
216*0Sstevel@tonic-gate 		stdphysio(mr_pa, ib_get_map_reg(mondo, cpu_id));
217*0Sstevel@tonic-gate 		(void) lddphysio(mr_pa);	/* flush previous write */
218*0Sstevel@tonic-gate 	}
219*0Sstevel@tonic-gate 	mutex_exit(&cb_p->cb_intr_lock);
220*0Sstevel@tonic-gate }
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate void
223*0Sstevel@tonic-gate cb_suspend(cb_t *cb_p)
224*0Sstevel@tonic-gate {
225*0Sstevel@tonic-gate 	int i, inos = cb_p->cb_no_of_inos;
226*0Sstevel@tonic-gate 	ASSERT(!cb_p->cb_imr_save);
227*0Sstevel@tonic-gate 	cb_p->cb_imr_save = kmem_alloc(inos * sizeof (uint64_t), KM_SLEEP);
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 	/*
230*0Sstevel@tonic-gate 	 * save the internal interrupts' mapping registers content
231*0Sstevel@tonic-gate 	 *
232*0Sstevel@tonic-gate 	 * The PBM IMR really doesn't need to be saved, as it is
233*0Sstevel@tonic-gate 	 * different per side and is handled by pbm_suspend/resume.
234*0Sstevel@tonic-gate 	 * But it complicates the logic.
235*0Sstevel@tonic-gate 	 */
236*0Sstevel@tonic-gate 	for (i = 0; i < inos; i++) {
237*0Sstevel@tonic-gate 		uint64_t pa;
238*0Sstevel@tonic-gate 		ib_ino_t ino = cb_p->cb_inos[i];
239*0Sstevel@tonic-gate 		if (!ino)
240*0Sstevel@tonic-gate 			continue;
241*0Sstevel@tonic-gate 		pa = cb_ino_to_map_pa(cb_p, ino);
242*0Sstevel@tonic-gate 		cb_p->cb_imr_save[i] = lddphysio(pa);
243*0Sstevel@tonic-gate 	}
244*0Sstevel@tonic-gate }
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate void
247*0Sstevel@tonic-gate cb_resume(cb_t *cb_p)
248*0Sstevel@tonic-gate {
249*0Sstevel@tonic-gate 	int i;
250*0Sstevel@tonic-gate 	for (i = 0; i < cb_p->cb_no_of_inos; i++) {
251*0Sstevel@tonic-gate 		uint64_t pa;
252*0Sstevel@tonic-gate 		ib_ino_t ino = cb_p->cb_inos[i];
253*0Sstevel@tonic-gate 		if (!ino)
254*0Sstevel@tonic-gate 			continue;
255*0Sstevel@tonic-gate 		pa = cb_ino_to_map_pa(cb_p, ino);
256*0Sstevel@tonic-gate 		cb_set_nintr_reg(cb_p, ino, COMMON_CLEAR_INTR_REG_IDLE);
257*0Sstevel@tonic-gate 		stdphysio(pa, cb_p->cb_imr_save[i]);	/* restore IMR */
258*0Sstevel@tonic-gate 	}
259*0Sstevel@tonic-gate 	kmem_free(cb_p->cb_imr_save, cb_p->cb_no_of_inos * sizeof (uint64_t));
260*0Sstevel@tonic-gate 	cb_p->cb_imr_save = NULL;
261*0Sstevel@tonic-gate }
262