xref: /titanic_44/usr/src/uts/sun4u/io/iocache.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 1995-1998, 2002 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
35*7c478bd9Sstevel@tonic-gate #include <vm/hat_sfmmu.h>
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #include <sys/iommu.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/iocache.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/sysiosbus.h>
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #include <sys/nexusdebug.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate #define	IOCACHE_REGISTERS_DEBUG		0x1
45*7c478bd9Sstevel@tonic-gate #define	IOCACHE_SYNC_DEBUG		0x2
46*7c478bd9Sstevel@tonic-gate #define	IOCACHE_DIAG_REG_DEBUG		0x4
47*7c478bd9Sstevel@tonic-gate #define	IOCACHE_SYNC_FAIL_DEBUG		0x8
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate #define	MAX_RETRY			10
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate /* Flag which enables the streaming buffer */
52*7c478bd9Sstevel@tonic-gate int stream_buf_on = 1;
53*7c478bd9Sstevel@tonic-gate /*
54*7c478bd9Sstevel@tonic-gate  * This is the number of pages that a mapping request needs before we force
55*7c478bd9Sstevel@tonic-gate  * the streaming buffer sync code to use diagnostic registers.  This value
56*7c478bd9Sstevel@tonic-gate  * was determined through a series of test runs measuring dma mapping
57*7c478bd9Sstevel@tonic-gate  * setup performance.
58*7c478bd9Sstevel@tonic-gate  */
59*7c478bd9Sstevel@tonic-gate int stream_buf_sync_using_diag = 36;
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate int
62*7c478bd9Sstevel@tonic-gate stream_buf_init(struct sbus_soft_state *softsp, caddr_t address)
63*7c478bd9Sstevel@tonic-gate {
64*7c478bd9Sstevel@tonic-gate 	uchar_t version;
65*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
66*7c478bd9Sstevel@tonic-gate 	debug_info = 1;
67*7c478bd9Sstevel@tonic-gate 	debug_print_level = 0;
68*7c478bd9Sstevel@tonic-gate #endif
69*7c478bd9Sstevel@tonic-gate 	version = (uchar_t)(*softsp->sysio_ctrl_reg >> SYSIO_VER_SHIFT);
70*7c478bd9Sstevel@tonic-gate 	version &= 0xf;
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate 	if (stream_buf_on == 0 || version == 0) {
73*7c478bd9Sstevel@tonic-gate 		softsp->stream_buf_off = STREAM_BUF_OFF;
74*7c478bd9Sstevel@tonic-gate 		if (version == 0)
75*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "Disabling streaming buffer due to "
76*7c478bd9Sstevel@tonic-gate 			    "SYSIO Rev %d.\n", version);
77*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
78*7c478bd9Sstevel@tonic-gate 	}
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate 	/*
81*7c478bd9Sstevel@tonic-gate 	 * Simply add each registers offset to the base address
82*7c478bd9Sstevel@tonic-gate 	 * to calculate the already mapped virtual address of
83*7c478bd9Sstevel@tonic-gate 	 * the device register...
84*7c478bd9Sstevel@tonic-gate 	 *
85*7c478bd9Sstevel@tonic-gate 	 * define a macro for the pointer arithmetic; all registers
86*7c478bd9Sstevel@tonic-gate 	 * are 64 bits wide and are defined as uint64_t's.
87*7c478bd9Sstevel@tonic-gate 	 */
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate #define	REG_ADDR(b, o)	(uint64_t *)((caddr_t)(b) + (o))
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate 	softsp->str_buf_ctrl_reg = REG_ADDR(address, OFF_STR_BUF_CTRL_REG);
92*7c478bd9Sstevel@tonic-gate 	softsp->str_buf_flush_reg = REG_ADDR(address, OFF_STR_BUF_FLUSH_REG);
93*7c478bd9Sstevel@tonic-gate 	softsp->str_buf_sync_reg = REG_ADDR(address, OFF_STR_BUF_SYNC_REG);
94*7c478bd9Sstevel@tonic-gate 	softsp->str_buf_pg_tag_diag = REG_ADDR(address, STR_BUF_PAGE_TAG_DIAG);
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate #undef	REG_ADDR
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate 	DPRINTF(IOCACHE_REGISTERS_DEBUG, ("Streaming buffer control reg: 0x%x, "
99*7c478bd9Sstevel@tonic-gate 	    "Streaming buffer flush reg: 0x%x, Streaming buffer sync reg: 0x%x",
100*7c478bd9Sstevel@tonic-gate 	    softsp->str_buf_ctrl_reg, softsp->str_buf_flush_reg,
101*7c478bd9Sstevel@tonic-gate 	    softsp->str_buf_sync_reg));
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate 	/* Initialize stream buffer sync reg mutex */
104*7c478bd9Sstevel@tonic-gate 	mutex_init(&softsp->sync_reg_lock, NULL, MUTEX_DEFAULT, NULL);
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate 	/* Turn on per instance streaming buffer flag */
107*7c478bd9Sstevel@tonic-gate 	softsp->stream_buf_off = 0;
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 	/* Set the hardware registers */
110*7c478bd9Sstevel@tonic-gate 	(void) stream_buf_resume_init(softsp);
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
113*7c478bd9Sstevel@tonic-gate }
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate int
116*7c478bd9Sstevel@tonic-gate stream_buf_uninit(struct sbus_soft_state *softsp)
117*7c478bd9Sstevel@tonic-gate {
118*7c478bd9Sstevel@tonic-gate 	/* Turn off per instance streaming buffer flag */
119*7c478bd9Sstevel@tonic-gate 	softsp->stream_buf_off = 1;
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate 	/* Turn off the streaming buffer */
122*7c478bd9Sstevel@tonic-gate 	*softsp->str_buf_ctrl_reg = STREAM_BUF_DISABLE;
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
125*7c478bd9Sstevel@tonic-gate }
126*7c478bd9Sstevel@tonic-gate /*
127*7c478bd9Sstevel@tonic-gate  * Initialize stream buf hardware when the system is being resumed.
128*7c478bd9Sstevel@tonic-gate  * (Subset of stream_buf_init())
129*7c478bd9Sstevel@tonic-gate  */
130*7c478bd9Sstevel@tonic-gate int
131*7c478bd9Sstevel@tonic-gate stream_buf_resume_init(struct sbus_soft_state *softsp)
132*7c478bd9Sstevel@tonic-gate {
133*7c478bd9Sstevel@tonic-gate 	uchar_t version;
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 	version = (uchar_t)(*softsp->sysio_ctrl_reg >> SYSIO_VER_SHIFT);
136*7c478bd9Sstevel@tonic-gate 	version &= 0xf;
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 	if (stream_buf_on == 0 || version == 0) {
139*7c478bd9Sstevel@tonic-gate 		softsp->stream_buf_off = STREAM_BUF_OFF;
140*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
141*7c478bd9Sstevel@tonic-gate 	}
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate 	/* Turn on the streaming buffer */
144*7c478bd9Sstevel@tonic-gate 	*softsp->str_buf_ctrl_reg = STREAM_BUF_ENABLE;
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
147*7c478bd9Sstevel@tonic-gate }
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate /*
150*7c478bd9Sstevel@tonic-gate  * The SYSIO spec says that it will get back to us within 0.5 seconds,
151*7c478bd9Sstevel@tonic-gate  * but loaded systems have seen response times over 1.5 seconds.  We
152*7c478bd9Sstevel@tonic-gate  * err on the side of caution and set the timeout to be 10 seconds.
153*7c478bd9Sstevel@tonic-gate  */
154*7c478bd9Sstevel@tonic-gate #define	SCACHE_NSEC_WAIT	(10ull * NANOSEC)
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate /*
157*7c478bd9Sstevel@tonic-gate  * We want to avoid using gethrtime every time we check sync_flag,
158*7c478bd9Sstevel@tonic-gate  * so we take SCACHE_SPIN laps before beginning to use gethrtime.
159*7c478bd9Sstevel@tonic-gate  */
160*7c478bd9Sstevel@tonic-gate #define	SCACHE_SPIN		10000000
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate void
163*7c478bd9Sstevel@tonic-gate sync_stream_buf(struct sbus_soft_state *softsp, ioaddr_t addr, uint_t npages,
164*7c478bd9Sstevel@tonic-gate 	int *sync_flag, uint64_t phys_sync_flag)
165*7c478bd9Sstevel@tonic-gate {
166*7c478bd9Sstevel@tonic-gate #ifndef lint
167*7c478bd9Sstevel@tonic-gate 	volatile uint64_t tmp;
168*7c478bd9Sstevel@tonic-gate #endif
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	int cntr = 0;
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 	if (softsp->stream_buf_off != 0)
173*7c478bd9Sstevel@tonic-gate 		return;
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 	DPRINTF(IOCACHE_SYNC_DEBUG, ("sync_stream_buf: ioaddr 0x%x, page cnt "
176*7c478bd9Sstevel@tonic-gate 	    "0x%x, sync flag 0x%x, sync flag pf 0x%xll\n", addr, npages,
177*7c478bd9Sstevel@tonic-gate 	    sync_flag, phys_sync_flag));
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 	ASSERT(npages > (uint_t)0);
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	/* Acquire the sync lock */
182*7c478bd9Sstevel@tonic-gate 	mutex_enter(&softsp->sync_reg_lock);
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate 	*sync_flag = 0;
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 	if (npages > stream_buf_sync_using_diag) {
187*7c478bd9Sstevel@tonic-gate 		int i;
188*7c478bd9Sstevel@tonic-gate 		volatile uint64_t *reg_addr;
189*7c478bd9Sstevel@tonic-gate 		uint64_t reg;
190*7c478bd9Sstevel@tonic-gate 		uint_t ioaddr;
191*7c478bd9Sstevel@tonic-gate 		uint_t hiaddr = addr + (npages * IOMMU_PAGESIZE);
192*7c478bd9Sstevel@tonic-gate 		int do_sync = 0;
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 		for (i = 0, reg_addr = softsp->str_buf_pg_tag_diag;
195*7c478bd9Sstevel@tonic-gate 		    i < STREAM_CACHE_LINES; i++, reg_addr++) {
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate 			/* Read the page tag diag reg */
198*7c478bd9Sstevel@tonic-gate 			reg = *reg_addr;
199*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
200*7c478bd9Sstevel@tonic-gate 			{
201*7c478bd9Sstevel@tonic-gate 				uint_t hi, lo;
202*7c478bd9Sstevel@tonic-gate 				hi = (uint_t)(reg >> 32);
203*7c478bd9Sstevel@tonic-gate 				lo = (uint_t)(reg & 0xffffffff);
204*7c478bd9Sstevel@tonic-gate 				DPRINTF(IOCACHE_DIAG_REG_DEBUG,
205*7c478bd9Sstevel@tonic-gate 				    ("IO cache line diag "
206*7c478bd9Sstevel@tonic-gate 				    "reg addr 0x%x, hi0x%x lo0x%x\n",
207*7c478bd9Sstevel@tonic-gate 				    reg_addr, hi, lo));
208*7c478bd9Sstevel@tonic-gate 			}
209*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
210*7c478bd9Sstevel@tonic-gate 			/* Check for a valid line */
211*7c478bd9Sstevel@tonic-gate 			if (reg & STR_PG_VALID) {
212*7c478bd9Sstevel@tonic-gate 				ioaddr = (uint_t)reg << STR_PG_SHIFT;
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate 				DPRINTF(IOCACHE_DIAG_REG_DEBUG, ("ioaddr 0x%x, "
215*7c478bd9Sstevel@tonic-gate 				    "range base 0x%x, range extent 0x%x\n",
216*7c478bd9Sstevel@tonic-gate 				    ioaddr, addr,
217*7c478bd9Sstevel@tonic-gate 				    addr + (npages * IOMMU_PAGESIZE)));
218*7c478bd9Sstevel@tonic-gate 				if (ioaddr >= addr && ioaddr <= hiaddr) {
219*7c478bd9Sstevel@tonic-gate 					*softsp->str_buf_flush_reg = (uint64_t)
220*7c478bd9Sstevel@tonic-gate 					    ioaddr;
221*7c478bd9Sstevel@tonic-gate 					do_sync = 1;
222*7c478bd9Sstevel@tonic-gate 				}
223*7c478bd9Sstevel@tonic-gate 			}
224*7c478bd9Sstevel@tonic-gate 		}
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 		if (!do_sync) {
227*7c478bd9Sstevel@tonic-gate 			mutex_exit(&softsp->sync_reg_lock);
228*7c478bd9Sstevel@tonic-gate 			return;
229*7c478bd9Sstevel@tonic-gate 		}
230*7c478bd9Sstevel@tonic-gate 	} else {
231*7c478bd9Sstevel@tonic-gate 		do {
232*7c478bd9Sstevel@tonic-gate 			*softsp->str_buf_flush_reg = (uint64_t)addr;
233*7c478bd9Sstevel@tonic-gate 			addr += IOMMU_PAGESIZE;
234*7c478bd9Sstevel@tonic-gate 			npages--;
235*7c478bd9Sstevel@tonic-gate 		} while (npages > (uint_t)0);
236*7c478bd9Sstevel@tonic-gate 	}
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	/* Ask the hardware to flag when the flush is complete */
239*7c478bd9Sstevel@tonic-gate 	*softsp->str_buf_sync_reg = phys_sync_flag;
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate #ifndef lint
242*7c478bd9Sstevel@tonic-gate 	/*
243*7c478bd9Sstevel@tonic-gate 	 * Due to the sun4u memory models, this noncached load will sync the
244*7c478bd9Sstevel@tonic-gate 	 * order of all prior loads and stores regardless of cacheability.
245*7c478bd9Sstevel@tonic-gate 	 * No membar_stst() is needed after zeroing the flush sync flag.
246*7c478bd9Sstevel@tonic-gate 	 */
247*7c478bd9Sstevel@tonic-gate 	tmp = *softsp->sbus_ctrl_reg;
248*7c478bd9Sstevel@tonic-gate #endif
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 	/*
251*7c478bd9Sstevel@tonic-gate 	 * Begin spinning on the hardware sync register.  We'll spin for
252*7c478bd9Sstevel@tonic-gate 	 * a while (SCACHE_SPIN) before using gethrtime, but once that time
253*7c478bd9Sstevel@tonic-gate 	 * is up we'll drop into an inner loop where we use gethrtime on
254*7c478bd9Sstevel@tonic-gate 	 * every iteration.  Once SCACHE_NSEC_WAIT nanoseconds have
255*7c478bd9Sstevel@tonic-gate 	 * elapsed, we'll assume a Bad Thing has happened and toss.
256*7c478bd9Sstevel@tonic-gate 	 */
257*7c478bd9Sstevel@tonic-gate 	while (!*((volatile int *)sync_flag)) {
258*7c478bd9Sstevel@tonic-gate 		if (cntr++ == SCACHE_SPIN) {
259*7c478bd9Sstevel@tonic-gate 			/*
260*7c478bd9Sstevel@tonic-gate 			 * If we're here, then we've spun long enough
261*7c478bd9Sstevel@tonic-gate 			 * to justify use of gethrtime each iteration.
262*7c478bd9Sstevel@tonic-gate 			 */
263*7c478bd9Sstevel@tonic-gate 			hrtime_t nsec_start, nsectowait, nsec_current;
264*7c478bd9Sstevel@tonic-gate 			nsectowait = SCACHE_NSEC_WAIT;
265*7c478bd9Sstevel@tonic-gate 			nsec_current = nsec_start = gethrtime();
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 			while (!*((volatile int *)sync_flag)) {
268*7c478bd9Sstevel@tonic-gate 				/*
269*7c478bd9Sstevel@tonic-gate 				 * Double check the sync flag again before
270*7c478bd9Sstevel@tonic-gate 				 * we panic in case we get preempted.
271*7c478bd9Sstevel@tonic-gate 				 * See bugid 4126896
272*7c478bd9Sstevel@tonic-gate 				 */
273*7c478bd9Sstevel@tonic-gate 				nsec_current = gethrtime();
274*7c478bd9Sstevel@tonic-gate 				if ((nsec_current - nsec_start) > nsectowait &&
275*7c478bd9Sstevel@tonic-gate 				!*((volatile int *)sync_flag)) {
276*7c478bd9Sstevel@tonic-gate 					/*
277*7c478bd9Sstevel@tonic-gate 					 * Trouble.  The SYSIO chip has
278*7c478bd9Sstevel@tonic-gate 					 * seemingly gone AWOL.  Vomit.
279*7c478bd9Sstevel@tonic-gate 					 */
280*7c478bd9Sstevel@tonic-gate 					panic("streaming buffer timed out");
281*7c478bd9Sstevel@tonic-gate 				}
282*7c478bd9Sstevel@tonic-gate 			}
283*7c478bd9Sstevel@tonic-gate 		}
284*7c478bd9Sstevel@tonic-gate 	}
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 	/* Finally, drop the sync lock */
287*7c478bd9Sstevel@tonic-gate 	mutex_exit(&softsp->sync_reg_lock);
288*7c478bd9Sstevel@tonic-gate }
289