xref: /onnv-gate/usr/src/uts/sun4u/io/iocache.c (revision 7632:91aa3d8541b5)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7632SNick.Todd@Sun.COM  * Common Development and Distribution License (the "License").
6*7632SNick.Todd@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*7632SNick.Todd@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <sys/conf.h>
280Sstevel@tonic-gate #include <sys/ddi.h>
290Sstevel@tonic-gate #include <sys/sunddi.h>
300Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
310Sstevel@tonic-gate #include <sys/cmn_err.h>
320Sstevel@tonic-gate #include <vm/hat_sfmmu.h>
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #include <sys/iommu.h>
350Sstevel@tonic-gate #include <sys/iocache.h>
360Sstevel@tonic-gate #include <sys/sysiosbus.h>
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include <sys/nexusdebug.h>
390Sstevel@tonic-gate #include <sys/debug.h>
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #define	IOCACHE_REGISTERS_DEBUG		0x1
420Sstevel@tonic-gate #define	IOCACHE_SYNC_DEBUG		0x2
430Sstevel@tonic-gate #define	IOCACHE_DIAG_REG_DEBUG		0x4
440Sstevel@tonic-gate #define	IOCACHE_SYNC_FAIL_DEBUG		0x8
450Sstevel@tonic-gate 
460Sstevel@tonic-gate #define	MAX_RETRY			10
470Sstevel@tonic-gate 
480Sstevel@tonic-gate /* Flag which enables the streaming buffer */
490Sstevel@tonic-gate int stream_buf_on = 1;
500Sstevel@tonic-gate /*
510Sstevel@tonic-gate  * This is the number of pages that a mapping request needs before we force
520Sstevel@tonic-gate  * the streaming buffer sync code to use diagnostic registers.  This value
530Sstevel@tonic-gate  * was determined through a series of test runs measuring dma mapping
540Sstevel@tonic-gate  * setup performance.
550Sstevel@tonic-gate  */
560Sstevel@tonic-gate int stream_buf_sync_using_diag = 36;
570Sstevel@tonic-gate 
580Sstevel@tonic-gate int
stream_buf_init(struct sbus_soft_state * softsp,caddr_t address)590Sstevel@tonic-gate stream_buf_init(struct sbus_soft_state *softsp, caddr_t address)
600Sstevel@tonic-gate {
610Sstevel@tonic-gate 	uchar_t version;
620Sstevel@tonic-gate #ifdef DEBUG
630Sstevel@tonic-gate 	debug_info = 1;
640Sstevel@tonic-gate 	debug_print_level = 0;
650Sstevel@tonic-gate #endif
660Sstevel@tonic-gate 	version = (uchar_t)(*softsp->sysio_ctrl_reg >> SYSIO_VER_SHIFT);
670Sstevel@tonic-gate 	version &= 0xf;
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	if (stream_buf_on == 0 || version == 0) {
700Sstevel@tonic-gate 		softsp->stream_buf_off = STREAM_BUF_OFF;
710Sstevel@tonic-gate 		if (version == 0)
720Sstevel@tonic-gate 			cmn_err(CE_CONT, "Disabling streaming buffer due to "
730Sstevel@tonic-gate 			    "SYSIO Rev %d.\n", version);
740Sstevel@tonic-gate 		return (DDI_SUCCESS);
750Sstevel@tonic-gate 	}
760Sstevel@tonic-gate 
770Sstevel@tonic-gate 	/*
780Sstevel@tonic-gate 	 * Simply add each registers offset to the base address
790Sstevel@tonic-gate 	 * to calculate the already mapped virtual address of
800Sstevel@tonic-gate 	 * the device register...
810Sstevel@tonic-gate 	 *
820Sstevel@tonic-gate 	 * define a macro for the pointer arithmetic; all registers
830Sstevel@tonic-gate 	 * are 64 bits wide and are defined as uint64_t's.
840Sstevel@tonic-gate 	 */
850Sstevel@tonic-gate 
860Sstevel@tonic-gate #define	REG_ADDR(b, o)	(uint64_t *)((caddr_t)(b) + (o))
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	softsp->str_buf_ctrl_reg = REG_ADDR(address, OFF_STR_BUF_CTRL_REG);
890Sstevel@tonic-gate 	softsp->str_buf_flush_reg = REG_ADDR(address, OFF_STR_BUF_FLUSH_REG);
900Sstevel@tonic-gate 	softsp->str_buf_sync_reg = REG_ADDR(address, OFF_STR_BUF_SYNC_REG);
910Sstevel@tonic-gate 	softsp->str_buf_pg_tag_diag = REG_ADDR(address, STR_BUF_PAGE_TAG_DIAG);
920Sstevel@tonic-gate 
930Sstevel@tonic-gate #undef	REG_ADDR
940Sstevel@tonic-gate 
951035Smike_s 	DPRINTF(IOCACHE_REGISTERS_DEBUG, ("Streaming buffer control reg: 0x%p, "
961035Smike_s 	    "Streaming buffer flush reg: 0x%p, Streaming buffer sync reg: 0x%p",
97*7632SNick.Todd@Sun.COM 	    (void *)softsp->str_buf_ctrl_reg, (void *)softsp->str_buf_flush_reg,
98*7632SNick.Todd@Sun.COM 	    (void *)softsp->str_buf_sync_reg));
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 	/* Initialize stream buffer sync reg mutex */
1010Sstevel@tonic-gate 	mutex_init(&softsp->sync_reg_lock, NULL, MUTEX_DEFAULT, NULL);
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 	/* Turn on per instance streaming buffer flag */
1040Sstevel@tonic-gate 	softsp->stream_buf_off = 0;
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 	/* Set the hardware registers */
1070Sstevel@tonic-gate 	(void) stream_buf_resume_init(softsp);
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	return (DDI_SUCCESS);
1100Sstevel@tonic-gate }
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate int
stream_buf_uninit(struct sbus_soft_state * softsp)1130Sstevel@tonic-gate stream_buf_uninit(struct sbus_soft_state *softsp)
1140Sstevel@tonic-gate {
1150Sstevel@tonic-gate 	/* Turn off per instance streaming buffer flag */
1160Sstevel@tonic-gate 	softsp->stream_buf_off = 1;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	/* Turn off the streaming buffer */
1190Sstevel@tonic-gate 	*softsp->str_buf_ctrl_reg = STREAM_BUF_DISABLE;
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	return (DDI_SUCCESS);
1220Sstevel@tonic-gate }
1230Sstevel@tonic-gate /*
1240Sstevel@tonic-gate  * Initialize stream buf hardware when the system is being resumed.
1250Sstevel@tonic-gate  * (Subset of stream_buf_init())
1260Sstevel@tonic-gate  */
1270Sstevel@tonic-gate int
stream_buf_resume_init(struct sbus_soft_state * softsp)1280Sstevel@tonic-gate stream_buf_resume_init(struct sbus_soft_state *softsp)
1290Sstevel@tonic-gate {
1300Sstevel@tonic-gate 	uchar_t version;
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate 	version = (uchar_t)(*softsp->sysio_ctrl_reg >> SYSIO_VER_SHIFT);
1330Sstevel@tonic-gate 	version &= 0xf;
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	if (stream_buf_on == 0 || version == 0) {
1360Sstevel@tonic-gate 		softsp->stream_buf_off = STREAM_BUF_OFF;
1370Sstevel@tonic-gate 		return (DDI_SUCCESS);
1380Sstevel@tonic-gate 	}
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 	/* Turn on the streaming buffer */
1410Sstevel@tonic-gate 	*softsp->str_buf_ctrl_reg = STREAM_BUF_ENABLE;
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	return (DDI_SUCCESS);
1440Sstevel@tonic-gate }
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate /*
1470Sstevel@tonic-gate  * The SYSIO spec says that it will get back to us within 0.5 seconds,
1480Sstevel@tonic-gate  * but loaded systems have seen response times over 1.5 seconds.  We
1490Sstevel@tonic-gate  * err on the side of caution and set the timeout to be 10 seconds.
1500Sstevel@tonic-gate  */
1510Sstevel@tonic-gate #define	SCACHE_NSEC_WAIT	(10ull * NANOSEC)
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate /*
1540Sstevel@tonic-gate  * We want to avoid using gethrtime every time we check sync_flag,
1550Sstevel@tonic-gate  * so we take SCACHE_SPIN laps before beginning to use gethrtime.
1560Sstevel@tonic-gate  */
1570Sstevel@tonic-gate #define	SCACHE_SPIN		10000000
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate void
sync_stream_buf(struct sbus_soft_state * softsp,ioaddr_t addr,uint_t npages,int * sync_flag,uint64_t phys_sync_flag)1600Sstevel@tonic-gate sync_stream_buf(struct sbus_soft_state *softsp, ioaddr_t addr, uint_t npages,
1610Sstevel@tonic-gate 	int *sync_flag, uint64_t phys_sync_flag)
1620Sstevel@tonic-gate {
1630Sstevel@tonic-gate #ifndef lint
1640Sstevel@tonic-gate 	volatile uint64_t tmp;
1650Sstevel@tonic-gate #endif
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	int cntr = 0;
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	if (softsp->stream_buf_off != 0)
1700Sstevel@tonic-gate 		return;
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 	DPRINTF(IOCACHE_SYNC_DEBUG, ("sync_stream_buf: ioaddr 0x%x, page cnt "
1731035Smike_s 	    "0x%x, sync flag 0x%p, sync flag pf 0x%lx\n", addr, npages,
174*7632SNick.Todd@Sun.COM 	    (void *)sync_flag, phys_sync_flag));
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	ASSERT(npages > (uint_t)0);
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	/* Acquire the sync lock */
1790Sstevel@tonic-gate 	mutex_enter(&softsp->sync_reg_lock);
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	*sync_flag = 0;
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	if (npages > stream_buf_sync_using_diag) {
1840Sstevel@tonic-gate 		int i;
1850Sstevel@tonic-gate 		volatile uint64_t *reg_addr;
1860Sstevel@tonic-gate 		uint64_t reg;
1870Sstevel@tonic-gate 		uint_t ioaddr;
1880Sstevel@tonic-gate 		uint_t hiaddr = addr + (npages * IOMMU_PAGESIZE);
1890Sstevel@tonic-gate 		int do_sync = 0;
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 		for (i = 0, reg_addr = softsp->str_buf_pg_tag_diag;
1920Sstevel@tonic-gate 		    i < STREAM_CACHE_LINES; i++, reg_addr++) {
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 			/* Read the page tag diag reg */
1950Sstevel@tonic-gate 			reg = *reg_addr;
1960Sstevel@tonic-gate #ifdef DEBUG
1970Sstevel@tonic-gate 			{
1980Sstevel@tonic-gate 				uint_t hi, lo;
1990Sstevel@tonic-gate 				hi = (uint_t)(reg >> 32);
2000Sstevel@tonic-gate 				lo = (uint_t)(reg & 0xffffffff);
2010Sstevel@tonic-gate 				DPRINTF(IOCACHE_DIAG_REG_DEBUG,
2020Sstevel@tonic-gate 				    ("IO cache line diag "
2031035Smike_s 				    "reg addr 0x%p, hi0x%x lo0x%x\n",
204*7632SNick.Todd@Sun.COM 				    (void *)reg_addr, hi, lo));
2050Sstevel@tonic-gate 			}
2060Sstevel@tonic-gate #endif /* DEBUG */
2070Sstevel@tonic-gate 			/* Check for a valid line */
2080Sstevel@tonic-gate 			if (reg & STR_PG_VALID) {
2090Sstevel@tonic-gate 				ioaddr = (uint_t)reg << STR_PG_SHIFT;
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 				DPRINTF(IOCACHE_DIAG_REG_DEBUG, ("ioaddr 0x%x, "
2120Sstevel@tonic-gate 				    "range base 0x%x, range extent 0x%x\n",
2130Sstevel@tonic-gate 				    ioaddr, addr,
2140Sstevel@tonic-gate 				    addr + (npages * IOMMU_PAGESIZE)));
2150Sstevel@tonic-gate 				if (ioaddr >= addr && ioaddr <= hiaddr) {
2160Sstevel@tonic-gate 					*softsp->str_buf_flush_reg = (uint64_t)
2170Sstevel@tonic-gate 					    ioaddr;
2180Sstevel@tonic-gate 					do_sync = 1;
2190Sstevel@tonic-gate 				}
2200Sstevel@tonic-gate 			}
2210Sstevel@tonic-gate 		}
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 		if (!do_sync) {
2240Sstevel@tonic-gate 			mutex_exit(&softsp->sync_reg_lock);
2250Sstevel@tonic-gate 			return;
2260Sstevel@tonic-gate 		}
2270Sstevel@tonic-gate 	} else {
2280Sstevel@tonic-gate 		do {
2290Sstevel@tonic-gate 			*softsp->str_buf_flush_reg = (uint64_t)addr;
2300Sstevel@tonic-gate 			addr += IOMMU_PAGESIZE;
2310Sstevel@tonic-gate 			npages--;
2320Sstevel@tonic-gate 		} while (npages > (uint_t)0);
2330Sstevel@tonic-gate 	}
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	/* Ask the hardware to flag when the flush is complete */
2360Sstevel@tonic-gate 	*softsp->str_buf_sync_reg = phys_sync_flag;
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate #ifndef lint
2390Sstevel@tonic-gate 	/*
2400Sstevel@tonic-gate 	 * Due to the sun4u memory models, this noncached load will sync the
2410Sstevel@tonic-gate 	 * order of all prior loads and stores regardless of cacheability.
2420Sstevel@tonic-gate 	 * No membar_stst() is needed after zeroing the flush sync flag.
2430Sstevel@tonic-gate 	 */
2440Sstevel@tonic-gate 	tmp = *softsp->sbus_ctrl_reg;
2450Sstevel@tonic-gate #endif
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	/*
2480Sstevel@tonic-gate 	 * Begin spinning on the hardware sync register.  We'll spin for
2490Sstevel@tonic-gate 	 * a while (SCACHE_SPIN) before using gethrtime, but once that time
2500Sstevel@tonic-gate 	 * is up we'll drop into an inner loop where we use gethrtime on
2510Sstevel@tonic-gate 	 * every iteration.  Once SCACHE_NSEC_WAIT nanoseconds have
2520Sstevel@tonic-gate 	 * elapsed, we'll assume a Bad Thing has happened and toss.
2530Sstevel@tonic-gate 	 */
2540Sstevel@tonic-gate 	while (!*((volatile int *)sync_flag)) {
2550Sstevel@tonic-gate 		if (cntr++ == SCACHE_SPIN) {
2560Sstevel@tonic-gate 			/*
2570Sstevel@tonic-gate 			 * If we're here, then we've spun long enough
2580Sstevel@tonic-gate 			 * to justify use of gethrtime each iteration.
2590Sstevel@tonic-gate 			 */
2600Sstevel@tonic-gate 			hrtime_t nsec_start, nsectowait, nsec_current;
2610Sstevel@tonic-gate 			nsectowait = SCACHE_NSEC_WAIT;
2620Sstevel@tonic-gate 			nsec_current = nsec_start = gethrtime();
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 			while (!*((volatile int *)sync_flag)) {
2650Sstevel@tonic-gate 				/*
2660Sstevel@tonic-gate 				 * Double check the sync flag again before
2670Sstevel@tonic-gate 				 * we panic in case we get preempted.
2680Sstevel@tonic-gate 				 * See bugid 4126896
2690Sstevel@tonic-gate 				 */
2700Sstevel@tonic-gate 				nsec_current = gethrtime();
2710Sstevel@tonic-gate 				if ((nsec_current - nsec_start) > nsectowait &&
272*7632SNick.Todd@Sun.COM 				    !*((volatile int *)sync_flag)) {
2730Sstevel@tonic-gate 					/*
2740Sstevel@tonic-gate 					 * Trouble.  The SYSIO chip has
2750Sstevel@tonic-gate 					 * seemingly gone AWOL.  Vomit.
2760Sstevel@tonic-gate 					 */
2770Sstevel@tonic-gate 					panic("streaming buffer timed out");
2780Sstevel@tonic-gate 				}
2790Sstevel@tonic-gate 			}
2800Sstevel@tonic-gate 		}
2810Sstevel@tonic-gate 	}
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	/* Finally, drop the sync lock */
2840Sstevel@tonic-gate 	mutex_exit(&softsp->sync_reg_lock);
2850Sstevel@tonic-gate }
286