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