1*25cf1a30Sjl139090 /*
2*25cf1a30Sjl139090 * CDDL HEADER START
3*25cf1a30Sjl139090 *
4*25cf1a30Sjl139090 * The contents of this file are subject to the terms of the
5*25cf1a30Sjl139090 * Common Development and Distribution License (the "License").
6*25cf1a30Sjl139090 * You may not use this file except in compliance with the License.
7*25cf1a30Sjl139090 *
8*25cf1a30Sjl139090 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*25cf1a30Sjl139090 * or http://www.opensolaris.org/os/licensing.
10*25cf1a30Sjl139090 * See the License for the specific language governing permissions
11*25cf1a30Sjl139090 * and limitations under the License.
12*25cf1a30Sjl139090 *
13*25cf1a30Sjl139090 * When distributing Covered Code, include this CDDL HEADER in each
14*25cf1a30Sjl139090 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*25cf1a30Sjl139090 * If applicable, add the following below this CDDL HEADER, with the
16*25cf1a30Sjl139090 * fields enclosed by brackets "[]" replaced with your own identifying
17*25cf1a30Sjl139090 * information: Portions Copyright [yyyy] [name of copyright owner]
18*25cf1a30Sjl139090 *
19*25cf1a30Sjl139090 * CDDL HEADER END
20*25cf1a30Sjl139090 */
21*25cf1a30Sjl139090 /*
22*25cf1a30Sjl139090 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23*25cf1a30Sjl139090 * Use is subject to license terms.
24*25cf1a30Sjl139090 */
25*25cf1a30Sjl139090
26*25cf1a30Sjl139090 #pragma ident "%Z%%M% %I% %E% SMI"
27*25cf1a30Sjl139090
28*25cf1a30Sjl139090 /*
29*25cf1a30Sjl139090 * CMU-CH Control Block object
30*25cf1a30Sjl139090 */
31*25cf1a30Sjl139090 #include <sys/types.h>
32*25cf1a30Sjl139090 #include <sys/kmem.h>
33*25cf1a30Sjl139090 #include <sys/systm.h>
34*25cf1a30Sjl139090 #include <sys/async.h>
35*25cf1a30Sjl139090 #include <sys/sunddi.h>
36*25cf1a30Sjl139090 #include <sys/ddi_impldefs.h>
37*25cf1a30Sjl139090 #include <sys/pcicmu/pcicmu.h>
38*25cf1a30Sjl139090 #include <sys/machsystm.h>
39*25cf1a30Sjl139090
40*25cf1a30Sjl139090 extern uint64_t xc_tick_jump_limit;
41*25cf1a30Sjl139090
42*25cf1a30Sjl139090 void
pcmu_cb_create(pcmu_t * pcmu_p)43*25cf1a30Sjl139090 pcmu_cb_create(pcmu_t *pcmu_p)
44*25cf1a30Sjl139090 {
45*25cf1a30Sjl139090 pcmu_cb_t *pcb_p = (pcmu_cb_t *)
46*25cf1a30Sjl139090 kmem_zalloc(sizeof (pcmu_cb_t), KM_SLEEP);
47*25cf1a30Sjl139090 mutex_init(&pcb_p->pcb_intr_lock, NULL, MUTEX_DRIVER, NULL);
48*25cf1a30Sjl139090 pcmu_p->pcmu_cb_p = pcb_p;
49*25cf1a30Sjl139090 pcb_p->pcb_pcmu_p = pcmu_p;
50*25cf1a30Sjl139090 pcmu_cb_setup(pcmu_p);
51*25cf1a30Sjl139090 }
52*25cf1a30Sjl139090
53*25cf1a30Sjl139090 void
pcmu_cb_destroy(pcmu_t * pcmu_p)54*25cf1a30Sjl139090 pcmu_cb_destroy(pcmu_t *pcmu_p)
55*25cf1a30Sjl139090 {
56*25cf1a30Sjl139090 pcmu_cb_t *pcb_p = pcmu_p->pcmu_cb_p;
57*25cf1a30Sjl139090
58*25cf1a30Sjl139090 intr_dist_rem(pcmu_cb_intr_dist, pcb_p);
59*25cf1a30Sjl139090 pcmu_cb_teardown(pcmu_p);
60*25cf1a30Sjl139090 pcmu_p->pcmu_cb_p = NULL;
61*25cf1a30Sjl139090 mutex_destroy(&pcb_p->pcb_intr_lock);
62*25cf1a30Sjl139090 kmem_free(pcb_p, sizeof (pcmu_cb_t));
63*25cf1a30Sjl139090 }
64*25cf1a30Sjl139090
65*25cf1a30Sjl139090 uint64_t
pcmu_cb_ino_to_map_pa(pcmu_cb_t * pcb_p,pcmu_ib_ino_t ino)66*25cf1a30Sjl139090 pcmu_cb_ino_to_map_pa(pcmu_cb_t *pcb_p, pcmu_ib_ino_t ino)
67*25cf1a30Sjl139090 {
68*25cf1a30Sjl139090 return (pcb_p->pcb_map_pa + ((ino & 0x1f) << 3));
69*25cf1a30Sjl139090 }
70*25cf1a30Sjl139090
71*25cf1a30Sjl139090 uint64_t
pcmu_cb_ino_to_clr_pa(pcmu_cb_t * pcb_p,pcmu_ib_ino_t ino)72*25cf1a30Sjl139090 pcmu_cb_ino_to_clr_pa(pcmu_cb_t *pcb_p, pcmu_ib_ino_t ino)
73*25cf1a30Sjl139090 {
74*25cf1a30Sjl139090 return (pcb_p->pcb_clr_pa + ((ino & 0x1f) << 3));
75*25cf1a30Sjl139090 }
76*25cf1a30Sjl139090
77*25cf1a30Sjl139090 static void
pcmu_cb_set_nintr_reg(pcmu_cb_t * pcb_p,pcmu_ib_ino_t ino,uint64_t value)78*25cf1a30Sjl139090 pcmu_cb_set_nintr_reg(pcmu_cb_t *pcb_p, pcmu_ib_ino_t ino, uint64_t value)
79*25cf1a30Sjl139090 {
80*25cf1a30Sjl139090 uint64_t pa = pcmu_cb_ino_to_clr_pa(pcb_p, ino);
81*25cf1a30Sjl139090
82*25cf1a30Sjl139090 PCMU_DBG3(PCMU_DBG_CB|PCMU_DBG_CONT, NULL,
83*25cf1a30Sjl139090 "pci-%x pcmu_cb_set_nintr_reg: ino=%x PA=%016llx\n",
84*25cf1a30Sjl139090 pcb_p->pcb_pcmu_p->pcmu_id, ino, pa);
85*25cf1a30Sjl139090
86*25cf1a30Sjl139090 stdphysio(pa, value);
87*25cf1a30Sjl139090 (void) lddphysio(pa); /* flush the previous write */
88*25cf1a30Sjl139090 }
89*25cf1a30Sjl139090
90*25cf1a30Sjl139090 /*
91*25cf1a30Sjl139090 * enable an internal interrupt source:
92*25cf1a30Sjl139090 * if an interrupt is shared by both sides, record it in pcb_inos[] and
93*25cf1a30Sjl139090 * cb will own its distribution.
94*25cf1a30Sjl139090 */
95*25cf1a30Sjl139090 void
pcmu_cb_enable_nintr(pcmu_t * pcmu_p,pcmu_cb_nintr_index_t idx)96*25cf1a30Sjl139090 pcmu_cb_enable_nintr(pcmu_t *pcmu_p, pcmu_cb_nintr_index_t idx)
97*25cf1a30Sjl139090 {
98*25cf1a30Sjl139090 pcmu_cb_t *pcb_p = pcmu_p->pcmu_cb_p;
99*25cf1a30Sjl139090 pcmu_ib_ino_t ino = PCMU_IB_MONDO_TO_INO(pcmu_p->pcmu_inos[idx]);
100*25cf1a30Sjl139090 pcmu_ib_mondo_t mondo = PCMU_CB_INO_TO_MONDO(pcb_p, ino);
101*25cf1a30Sjl139090 uint32_t cpu_id;
102*25cf1a30Sjl139090 uint64_t reg, pa;
103*25cf1a30Sjl139090 pcmu_ib_t *pib_p = pcb_p->pcb_pcmu_p->pcmu_ib_p;
104*25cf1a30Sjl139090 volatile uint64_t *imr_p = ib_intr_map_reg_addr(pib_p, ino);
105*25cf1a30Sjl139090
106*25cf1a30Sjl139090 ASSERT(idx < CBNINTR_MAX);
107*25cf1a30Sjl139090 pa = pcmu_cb_ino_to_map_pa(pcb_p, ino);
108*25cf1a30Sjl139090
109*25cf1a30Sjl139090 mutex_enter(&pcb_p->pcb_intr_lock);
110*25cf1a30Sjl139090 cpu_id = intr_dist_cpuid();
111*25cf1a30Sjl139090
112*25cf1a30Sjl139090 cpu_id = u2u_translate_tgtid(pib_p->pib_pcmu_p, cpu_id, imr_p);
113*25cf1a30Sjl139090
114*25cf1a30Sjl139090 reg = ib_get_map_reg(mondo, cpu_id);
115*25cf1a30Sjl139090 stdphysio(pa, reg);
116*25cf1a30Sjl139090
117*25cf1a30Sjl139090 ASSERT(pcb_p->pcb_inos[idx] == 0);
118*25cf1a30Sjl139090 pcb_p->pcb_inos[idx] = ino;
119*25cf1a30Sjl139090
120*25cf1a30Sjl139090 pcmu_cb_set_nintr_reg(pcb_p, ino, PCMU_CLEAR_INTR_REG_IDLE);
121*25cf1a30Sjl139090 mutex_exit(&pcb_p->pcb_intr_lock);
122*25cf1a30Sjl139090
123*25cf1a30Sjl139090 PCMU_DBG3(PCMU_DBG_CB|PCMU_DBG_CONT, NULL,
124*25cf1a30Sjl139090 "pci-%x pcmu_cb_enable_nintr: ino=%x cpu_id=%x\n",
125*25cf1a30Sjl139090 pcmu_p->pcmu_id, ino, cpu_id);
126*25cf1a30Sjl139090 PCMU_DBG2(PCMU_DBG_CB|PCMU_DBG_CONT, NULL,
127*25cf1a30Sjl139090 "\tPA=%016llx data=%016llx\n", pa, reg);
128*25cf1a30Sjl139090 }
129*25cf1a30Sjl139090
130*25cf1a30Sjl139090 static void
pcmu_cb_disable_nintr_reg(pcmu_cb_t * pcb_p,pcmu_ib_ino_t ino,int wait)131*25cf1a30Sjl139090 pcmu_cb_disable_nintr_reg(pcmu_cb_t *pcb_p, pcmu_ib_ino_t ino, int wait)
132*25cf1a30Sjl139090 {
133*25cf1a30Sjl139090 uint64_t tmp, map_reg_pa = pcmu_cb_ino_to_map_pa(pcb_p, ino);
134*25cf1a30Sjl139090 ASSERT(MUTEX_HELD(&pcb_p->pcb_intr_lock));
135*25cf1a30Sjl139090
136*25cf1a30Sjl139090 /* mark interrupt invalid in mapping register */
137*25cf1a30Sjl139090 tmp = lddphysio(map_reg_pa) & ~PCMU_INTR_MAP_REG_VALID;
138*25cf1a30Sjl139090 stdphysio(map_reg_pa, tmp);
139*25cf1a30Sjl139090 (void) lddphysio(map_reg_pa); /* flush previous write */
140*25cf1a30Sjl139090
141*25cf1a30Sjl139090 if (wait) {
142*25cf1a30Sjl139090 hrtime_t start_time;
143*25cf1a30Sjl139090 hrtime_t prev, curr, interval, jump;
144*25cf1a30Sjl139090 hrtime_t intr_timeout;
145*25cf1a30Sjl139090 uint64_t state_reg_pa = pcb_p->pcb_obsta_pa;
146*25cf1a30Sjl139090 uint_t shift = (ino & 0x1f) << 1;
147*25cf1a30Sjl139090
148*25cf1a30Sjl139090 /* busy wait if there is interrupt being processed */
149*25cf1a30Sjl139090 /* unless panic or timeout for interrupt pending is reached */
150*25cf1a30Sjl139090
151*25cf1a30Sjl139090 intr_timeout = pcmu_intrpend_timeout;
152*25cf1a30Sjl139090 jump = TICK_TO_NSEC(xc_tick_jump_limit);
153*25cf1a30Sjl139090 start_time = curr = gethrtime();
154*25cf1a30Sjl139090 while ((((lddphysio(state_reg_pa) >> shift) &
155*25cf1a30Sjl139090 PCMU_CLEAR_INTR_REG_MASK) ==
156*25cf1a30Sjl139090 PCMU_CLEAR_INTR_REG_PENDING) && !panicstr) {
157*25cf1a30Sjl139090 /*
158*25cf1a30Sjl139090 * If we have a really large jump in hrtime, it is most
159*25cf1a30Sjl139090 * probably because we entered the debugger (or OBP,
160*25cf1a30Sjl139090 * in general). So, we adjust the timeout accordingly
161*25cf1a30Sjl139090 * to prevent declaring an interrupt timeout. The
162*25cf1a30Sjl139090 * master-interrupt mechanism in OBP should deliver
163*25cf1a30Sjl139090 * the interrupts properly.
164*25cf1a30Sjl139090 */
165*25cf1a30Sjl139090 prev = curr;
166*25cf1a30Sjl139090 curr = gethrtime();
167*25cf1a30Sjl139090 interval = curr - prev;
168*25cf1a30Sjl139090 if (interval > jump)
169*25cf1a30Sjl139090 intr_timeout += interval;
170*25cf1a30Sjl139090 if (curr - start_time > intr_timeout) {
171*25cf1a30Sjl139090 cmn_err(CE_WARN, "pcmu@%x "
172*25cf1a30Sjl139090 "pcmu_cb_disable_nintr_reg(%lx,%x) timeout",
173*25cf1a30Sjl139090 pcb_p->pcb_pcmu_p->pcmu_id, map_reg_pa,
174*25cf1a30Sjl139090 PCMU_CB_INO_TO_MONDO(pcb_p, ino));
175*25cf1a30Sjl139090 break;
176*25cf1a30Sjl139090 }
177*25cf1a30Sjl139090 }
178*25cf1a30Sjl139090 }
179*25cf1a30Sjl139090 }
180*25cf1a30Sjl139090
181*25cf1a30Sjl139090 void
pcmu_cb_disable_nintr(pcmu_cb_t * pcb_p,pcmu_cb_nintr_index_t idx,int wait)182*25cf1a30Sjl139090 pcmu_cb_disable_nintr(pcmu_cb_t *pcb_p, pcmu_cb_nintr_index_t idx, int wait)
183*25cf1a30Sjl139090 {
184*25cf1a30Sjl139090 pcmu_ib_t *pib_p = pcb_p->pcb_pcmu_p->pcmu_ib_p;
185*25cf1a30Sjl139090 volatile uint64_t *imr_p;
186*25cf1a30Sjl139090 pcmu_ib_ino_t ino = pcb_p->pcb_inos[idx];
187*25cf1a30Sjl139090 ASSERT(idx < CBNINTR_MAX);
188*25cf1a30Sjl139090 ASSERT(ino);
189*25cf1a30Sjl139090
190*25cf1a30Sjl139090 imr_p = ib_intr_map_reg_addr(pib_p, ino);
191*25cf1a30Sjl139090 mutex_enter(&pcb_p->pcb_intr_lock);
192*25cf1a30Sjl139090 pcmu_cb_disable_nintr_reg(pcb_p, ino, wait);
193*25cf1a30Sjl139090 pcmu_cb_set_nintr_reg(pcb_p, ino, PCMU_CLEAR_INTR_REG_PENDING);
194*25cf1a30Sjl139090 pcb_p->pcb_inos[idx] = 0;
195*25cf1a30Sjl139090 mutex_exit(&pcb_p->pcb_intr_lock);
196*25cf1a30Sjl139090 u2u_ittrans_cleanup((u2u_ittrans_data_t *)(pcb_p->pcb_ittrans_cookie),
197*25cf1a30Sjl139090 imr_p);
198*25cf1a30Sjl139090 }
199*25cf1a30Sjl139090
200*25cf1a30Sjl139090 void
pcmu_cb_clear_nintr(pcmu_cb_t * pcb_p,pcmu_cb_nintr_index_t idx)201*25cf1a30Sjl139090 pcmu_cb_clear_nintr(pcmu_cb_t *pcb_p, pcmu_cb_nintr_index_t idx)
202*25cf1a30Sjl139090 {
203*25cf1a30Sjl139090 pcmu_ib_ino_t ino = pcb_p->pcb_inos[idx];
204*25cf1a30Sjl139090 ASSERT(idx < CBNINTR_MAX);
205*25cf1a30Sjl139090 ASSERT(ino);
206*25cf1a30Sjl139090 pcmu_cb_set_nintr_reg(pcb_p, ino, PCMU_CLEAR_INTR_REG_IDLE);
207*25cf1a30Sjl139090 }
208*25cf1a30Sjl139090
209*25cf1a30Sjl139090 void
pcmu_cb_intr_dist(void * arg)210*25cf1a30Sjl139090 pcmu_cb_intr_dist(void *arg)
211*25cf1a30Sjl139090 {
212*25cf1a30Sjl139090 int i;
213*25cf1a30Sjl139090 pcmu_cb_t *pcb_p = (pcmu_cb_t *)arg;
214*25cf1a30Sjl139090
215*25cf1a30Sjl139090 mutex_enter(&pcb_p->pcb_intr_lock);
216*25cf1a30Sjl139090 for (i = 0; i < pcb_p->pcb_no_of_inos; i++) {
217*25cf1a30Sjl139090 uint64_t mr_pa;
218*25cf1a30Sjl139090 volatile uint64_t imr;
219*25cf1a30Sjl139090 pcmu_ib_mondo_t mondo;
220*25cf1a30Sjl139090 uint32_t cpu_id;
221*25cf1a30Sjl139090 pcmu_ib_t *pib_p = pcb_p->pcb_pcmu_p->pcmu_ib_p;
222*25cf1a30Sjl139090 volatile uint64_t *imr_p;
223*25cf1a30Sjl139090
224*25cf1a30Sjl139090 pcmu_ib_ino_t ino = pcb_p->pcb_inos[i];
225*25cf1a30Sjl139090 if (!ino) /* skip non-shared interrupts */
226*25cf1a30Sjl139090 continue;
227*25cf1a30Sjl139090
228*25cf1a30Sjl139090 mr_pa = pcmu_cb_ino_to_map_pa(pcb_p, ino);
229*25cf1a30Sjl139090 imr = lddphysio(mr_pa);
230*25cf1a30Sjl139090 if (!PCMU_IB_INO_INTR_ISON(imr))
231*25cf1a30Sjl139090 continue;
232*25cf1a30Sjl139090
233*25cf1a30Sjl139090 mondo = PCMU_CB_INO_TO_MONDO(pcb_p, ino);
234*25cf1a30Sjl139090 cpu_id = intr_dist_cpuid();
235*25cf1a30Sjl139090 imr_p = ib_intr_map_reg_addr(pib_p, ino);
236*25cf1a30Sjl139090
237*25cf1a30Sjl139090 cpu_id = u2u_translate_tgtid(pib_p->pib_pcmu_p, cpu_id, imr_p);
238*25cf1a30Sjl139090
239*25cf1a30Sjl139090 pcmu_cb_disable_nintr_reg(pcb_p, ino, PCMU_IB_INTR_WAIT);
240*25cf1a30Sjl139090 stdphysio(mr_pa, ib_get_map_reg(mondo, cpu_id));
241*25cf1a30Sjl139090 (void) lddphysio(mr_pa); /* flush previous write */
242*25cf1a30Sjl139090 }
243*25cf1a30Sjl139090 mutex_exit(&pcb_p->pcb_intr_lock);
244*25cf1a30Sjl139090 }
245*25cf1a30Sjl139090
246*25cf1a30Sjl139090 void
pcmu_cb_suspend(pcmu_cb_t * pcb_p)247*25cf1a30Sjl139090 pcmu_cb_suspend(pcmu_cb_t *pcb_p)
248*25cf1a30Sjl139090 {
249*25cf1a30Sjl139090 int i, inos = pcb_p->pcb_no_of_inos;
250*25cf1a30Sjl139090 ASSERT(!pcb_p->pcb_imr_save);
251*25cf1a30Sjl139090 pcb_p->pcb_imr_save = kmem_alloc(inos * sizeof (uint64_t), KM_SLEEP);
252*25cf1a30Sjl139090
253*25cf1a30Sjl139090 /*
254*25cf1a30Sjl139090 * save the internal interrupts' mapping registers content
255*25cf1a30Sjl139090 *
256*25cf1a30Sjl139090 * The PBM IMR really doesn't need to be saved, as it is
257*25cf1a30Sjl139090 * different per side and is handled by pcmu_pbm_suspend/resume.
258*25cf1a30Sjl139090 * But it complicates the logic.
259*25cf1a30Sjl139090 */
260*25cf1a30Sjl139090 for (i = 0; i < inos; i++) {
261*25cf1a30Sjl139090 uint64_t pa;
262*25cf1a30Sjl139090 pcmu_ib_ino_t ino = pcb_p->pcb_inos[i];
263*25cf1a30Sjl139090 if (!ino)
264*25cf1a30Sjl139090 continue;
265*25cf1a30Sjl139090 pa = pcmu_cb_ino_to_map_pa(pcb_p, ino);
266*25cf1a30Sjl139090 pcb_p->pcb_imr_save[i] = lddphysio(pa);
267*25cf1a30Sjl139090 }
268*25cf1a30Sjl139090 }
269*25cf1a30Sjl139090
270*25cf1a30Sjl139090 void
pcmu_cb_resume(pcmu_cb_t * pcb_p)271*25cf1a30Sjl139090 pcmu_cb_resume(pcmu_cb_t *pcb_p)
272*25cf1a30Sjl139090 {
273*25cf1a30Sjl139090 int i;
274*25cf1a30Sjl139090 for (i = 0; i < pcb_p->pcb_no_of_inos; i++) {
275*25cf1a30Sjl139090 uint64_t pa;
276*25cf1a30Sjl139090 pcmu_ib_ino_t ino = pcb_p->pcb_inos[i];
277*25cf1a30Sjl139090 if (!ino)
278*25cf1a30Sjl139090 continue;
279*25cf1a30Sjl139090 pa = pcmu_cb_ino_to_map_pa(pcb_p, ino);
280*25cf1a30Sjl139090 pcmu_cb_set_nintr_reg(pcb_p, ino, PCMU_CLEAR_INTR_REG_IDLE);
281*25cf1a30Sjl139090 stdphysio(pa, pcb_p->pcb_imr_save[i]); /* restore IMR */
282*25cf1a30Sjl139090 }
283*25cf1a30Sjl139090 kmem_free(pcb_p->pcb_imr_save,
284*25cf1a30Sjl139090 pcb_p->pcb_no_of_inos * sizeof (uint64_t));
285*25cf1a30Sjl139090 pcb_p->pcb_imr_save = NULL;
286*25cf1a30Sjl139090 }
287