17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*8793b36bSNick Todd * Common Development and Distribution License (the "License"). 6*8793b36bSNick Todd * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*8793b36bSNick Todd * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <sys/types.h> 277c478bd9Sstevel@tonic-gate #include <sys/conf.h> 287c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 297c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 307c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 317c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 327c478bd9Sstevel@tonic-gate #include <vm/hat_sfmmu.h> 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <sys/iommu.h> 357c478bd9Sstevel@tonic-gate #include <sys/iocache.h> 367c478bd9Sstevel@tonic-gate #include <sys/sysiosbus.h> 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate #include <sys/nexusdebug.h> 397c478bd9Sstevel@tonic-gate #include <sys/debug.h> 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #define IOCACHE_REGISTERS_DEBUG 0x1 427c478bd9Sstevel@tonic-gate #define IOCACHE_SYNC_DEBUG 0x2 437c478bd9Sstevel@tonic-gate #define IOCACHE_DIAG_REG_DEBUG 0x4 447c478bd9Sstevel@tonic-gate #define IOCACHE_SYNC_FAIL_DEBUG 0x8 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate #define MAX_RETRY 10 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate /* Flag which enables the streaming buffer */ 497c478bd9Sstevel@tonic-gate int stream_buf_on = 1; 507c478bd9Sstevel@tonic-gate /* 517c478bd9Sstevel@tonic-gate * This is the number of pages that a mapping request needs before we force 527c478bd9Sstevel@tonic-gate * the streaming buffer sync code to use diagnostic registers. This value 537c478bd9Sstevel@tonic-gate * was determined through a series of test runs measuring dma mapping 547c478bd9Sstevel@tonic-gate * setup performance. 557c478bd9Sstevel@tonic-gate */ 567c478bd9Sstevel@tonic-gate int stream_buf_sync_using_diag = 36; 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate int 597c478bd9Sstevel@tonic-gate stream_buf_init(struct sbus_soft_state *softsp, caddr_t address) 607c478bd9Sstevel@tonic-gate { 617c478bd9Sstevel@tonic-gate uchar_t version; 627c478bd9Sstevel@tonic-gate #ifdef DEBUG 637c478bd9Sstevel@tonic-gate debug_info = 1; 647c478bd9Sstevel@tonic-gate debug_print_level = 0; 657c478bd9Sstevel@tonic-gate #endif 667c478bd9Sstevel@tonic-gate version = (uchar_t)(*softsp->sysio_ctrl_reg >> SYSIO_VER_SHIFT); 677c478bd9Sstevel@tonic-gate version &= 0xf; 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate if (stream_buf_on == 0 || version == 0) { 707c478bd9Sstevel@tonic-gate softsp->stream_buf_off = STREAM_BUF_OFF; 717c478bd9Sstevel@tonic-gate if (version == 0) 727c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "Disabling streaming buffer due to " 737c478bd9Sstevel@tonic-gate "SYSIO Rev %d.\n", version); 747c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 757c478bd9Sstevel@tonic-gate } 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate /* 787c478bd9Sstevel@tonic-gate * Simply add each registers offset to the base address 797c478bd9Sstevel@tonic-gate * to calculate the already mapped virtual address of 807c478bd9Sstevel@tonic-gate * the device register... 817c478bd9Sstevel@tonic-gate * 827c478bd9Sstevel@tonic-gate * define a macro for the pointer arithmetic; all registers 837c478bd9Sstevel@tonic-gate * are 64 bits wide and are defined as uint64_t's. 847c478bd9Sstevel@tonic-gate */ 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate #define REG_ADDR(b, o) (uint64_t *)((caddr_t)(b) + (o)) 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate softsp->str_buf_ctrl_reg = REG_ADDR(address, OFF_STR_BUF_CTRL_REG); 897c478bd9Sstevel@tonic-gate softsp->str_buf_flush_reg = REG_ADDR(address, OFF_STR_BUF_FLUSH_REG); 907c478bd9Sstevel@tonic-gate softsp->str_buf_sync_reg = REG_ADDR(address, OFF_STR_BUF_SYNC_REG); 917c478bd9Sstevel@tonic-gate softsp->str_buf_pg_tag_diag = REG_ADDR(address, STR_BUF_PAGE_TAG_DIAG); 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate #undef REG_ADDR 947c478bd9Sstevel@tonic-gate 95ffadc26eSmike_s DPRINTF(IOCACHE_REGISTERS_DEBUG, ("Streaming buffer control reg: 0x%p, " 96ffadc26eSmike_s "Streaming buffer flush reg: 0x%p, Streaming buffer sync reg: 0x%p", 97*8793b36bSNick Todd (void *)softsp->str_buf_ctrl_reg, (void *)softsp->str_buf_flush_reg, 98*8793b36bSNick Todd (void *)softsp->str_buf_sync_reg)); 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate /* Initialize stream buffer sync reg mutex */ 1017c478bd9Sstevel@tonic-gate mutex_init(&softsp->sync_reg_lock, NULL, MUTEX_DEFAULT, NULL); 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate /* Turn on per instance streaming buffer flag */ 1047c478bd9Sstevel@tonic-gate softsp->stream_buf_off = 0; 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate /* Set the hardware registers */ 1077c478bd9Sstevel@tonic-gate (void) stream_buf_resume_init(softsp); 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate int 1137c478bd9Sstevel@tonic-gate stream_buf_uninit(struct sbus_soft_state *softsp) 1147c478bd9Sstevel@tonic-gate { 1157c478bd9Sstevel@tonic-gate /* Turn off per instance streaming buffer flag */ 1167c478bd9Sstevel@tonic-gate softsp->stream_buf_off = 1; 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate /* Turn off the streaming buffer */ 1197c478bd9Sstevel@tonic-gate *softsp->str_buf_ctrl_reg = STREAM_BUF_DISABLE; 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1227c478bd9Sstevel@tonic-gate } 1237c478bd9Sstevel@tonic-gate /* 1247c478bd9Sstevel@tonic-gate * Initialize stream buf hardware when the system is being resumed. 1257c478bd9Sstevel@tonic-gate * (Subset of stream_buf_init()) 1267c478bd9Sstevel@tonic-gate */ 1277c478bd9Sstevel@tonic-gate int 1287c478bd9Sstevel@tonic-gate stream_buf_resume_init(struct sbus_soft_state *softsp) 1297c478bd9Sstevel@tonic-gate { 1307c478bd9Sstevel@tonic-gate uchar_t version; 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate version = (uchar_t)(*softsp->sysio_ctrl_reg >> SYSIO_VER_SHIFT); 1337c478bd9Sstevel@tonic-gate version &= 0xf; 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate if (stream_buf_on == 0 || version == 0) { 1367c478bd9Sstevel@tonic-gate softsp->stream_buf_off = STREAM_BUF_OFF; 1377c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate /* Turn on the streaming buffer */ 1417c478bd9Sstevel@tonic-gate *softsp->str_buf_ctrl_reg = STREAM_BUF_ENABLE; 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1447c478bd9Sstevel@tonic-gate } 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate /* 1477c478bd9Sstevel@tonic-gate * The SYSIO spec says that it will get back to us within 0.5 seconds, 1487c478bd9Sstevel@tonic-gate * but loaded systems have seen response times over 1.5 seconds. We 1497c478bd9Sstevel@tonic-gate * err on the side of caution and set the timeout to be 10 seconds. 1507c478bd9Sstevel@tonic-gate */ 1517c478bd9Sstevel@tonic-gate #define SCACHE_NSEC_WAIT (10ull * NANOSEC) 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate /* 1547c478bd9Sstevel@tonic-gate * We want to avoid using gethrtime every time we check sync_flag, 1557c478bd9Sstevel@tonic-gate * so we take SCACHE_SPIN laps before beginning to use gethrtime. 1567c478bd9Sstevel@tonic-gate */ 1577c478bd9Sstevel@tonic-gate #define SCACHE_SPIN 10000000 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate void 1607c478bd9Sstevel@tonic-gate sync_stream_buf(struct sbus_soft_state *softsp, ioaddr_t addr, uint_t npages, 1617c478bd9Sstevel@tonic-gate int *sync_flag, uint64_t phys_sync_flag) 1627c478bd9Sstevel@tonic-gate { 1637c478bd9Sstevel@tonic-gate #ifndef lint 1647c478bd9Sstevel@tonic-gate volatile uint64_t tmp; 1657c478bd9Sstevel@tonic-gate #endif 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate int cntr = 0; 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate if (softsp->stream_buf_off != 0) 1707c478bd9Sstevel@tonic-gate return; 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate DPRINTF(IOCACHE_SYNC_DEBUG, ("sync_stream_buf: ioaddr 0x%x, page cnt " 173ffadc26eSmike_s "0x%x, sync flag 0x%p, sync flag pf 0x%lx\n", addr, npages, 174*8793b36bSNick Todd (void *)sync_flag, phys_sync_flag)); 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate ASSERT(npages > (uint_t)0); 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate /* Acquire the sync lock */ 1797c478bd9Sstevel@tonic-gate mutex_enter(&softsp->sync_reg_lock); 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate *sync_flag = 0; 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate if (npages > stream_buf_sync_using_diag) { 1847c478bd9Sstevel@tonic-gate int i; 1857c478bd9Sstevel@tonic-gate volatile uint64_t *reg_addr; 1867c478bd9Sstevel@tonic-gate uint64_t reg; 1877c478bd9Sstevel@tonic-gate uint_t ioaddr; 1887c478bd9Sstevel@tonic-gate uint_t hiaddr = addr + (npages * IOMMU_PAGESIZE); 1897c478bd9Sstevel@tonic-gate int do_sync = 0; 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate for (i = 0, reg_addr = softsp->str_buf_pg_tag_diag; 1927c478bd9Sstevel@tonic-gate i < STREAM_CACHE_LINES; i++, reg_addr++) { 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate /* Read the page tag diag reg */ 1957c478bd9Sstevel@tonic-gate reg = *reg_addr; 1967c478bd9Sstevel@tonic-gate #ifdef DEBUG 1977c478bd9Sstevel@tonic-gate { 1987c478bd9Sstevel@tonic-gate uint_t hi, lo; 1997c478bd9Sstevel@tonic-gate hi = (uint_t)(reg >> 32); 2007c478bd9Sstevel@tonic-gate lo = (uint_t)(reg & 0xffffffff); 2017c478bd9Sstevel@tonic-gate DPRINTF(IOCACHE_DIAG_REG_DEBUG, 2027c478bd9Sstevel@tonic-gate ("IO cache line diag " 203ffadc26eSmike_s "reg addr 0x%p, hi0x%x lo0x%x\n", 204*8793b36bSNick Todd (void *)reg_addr, hi, lo)); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 2077c478bd9Sstevel@tonic-gate /* Check for a valid line */ 2087c478bd9Sstevel@tonic-gate if (reg & STR_PG_VALID) { 2097c478bd9Sstevel@tonic-gate ioaddr = (uint_t)reg << STR_PG_SHIFT; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate DPRINTF(IOCACHE_DIAG_REG_DEBUG, ("ioaddr 0x%x, " 2127c478bd9Sstevel@tonic-gate "range base 0x%x, range extent 0x%x\n", 2137c478bd9Sstevel@tonic-gate ioaddr, addr, 2147c478bd9Sstevel@tonic-gate addr + (npages * IOMMU_PAGESIZE))); 2157c478bd9Sstevel@tonic-gate if (ioaddr >= addr && ioaddr <= hiaddr) { 2167c478bd9Sstevel@tonic-gate *softsp->str_buf_flush_reg = (uint64_t) 2177c478bd9Sstevel@tonic-gate ioaddr; 2187c478bd9Sstevel@tonic-gate do_sync = 1; 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate } 2217c478bd9Sstevel@tonic-gate } 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate if (!do_sync) { 2247c478bd9Sstevel@tonic-gate mutex_exit(&softsp->sync_reg_lock); 2257c478bd9Sstevel@tonic-gate return; 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate } else { 2287c478bd9Sstevel@tonic-gate do { 2297c478bd9Sstevel@tonic-gate *softsp->str_buf_flush_reg = (uint64_t)addr; 2307c478bd9Sstevel@tonic-gate addr += IOMMU_PAGESIZE; 2317c478bd9Sstevel@tonic-gate npages--; 2327c478bd9Sstevel@tonic-gate } while (npages > (uint_t)0); 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate /* Ask the hardware to flag when the flush is complete */ 2367c478bd9Sstevel@tonic-gate *softsp->str_buf_sync_reg = phys_sync_flag; 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate #ifndef lint 2397c478bd9Sstevel@tonic-gate /* 2407c478bd9Sstevel@tonic-gate * Due to the sun4u memory models, this noncached load will sync the 2417c478bd9Sstevel@tonic-gate * order of all prior loads and stores regardless of cacheability. 2427c478bd9Sstevel@tonic-gate * No membar_stst() is needed after zeroing the flush sync flag. 2437c478bd9Sstevel@tonic-gate */ 2447c478bd9Sstevel@tonic-gate tmp = *softsp->sbus_ctrl_reg; 2457c478bd9Sstevel@tonic-gate #endif 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate /* 2487c478bd9Sstevel@tonic-gate * Begin spinning on the hardware sync register. We'll spin for 2497c478bd9Sstevel@tonic-gate * a while (SCACHE_SPIN) before using gethrtime, but once that time 2507c478bd9Sstevel@tonic-gate * is up we'll drop into an inner loop where we use gethrtime on 2517c478bd9Sstevel@tonic-gate * every iteration. Once SCACHE_NSEC_WAIT nanoseconds have 2527c478bd9Sstevel@tonic-gate * elapsed, we'll assume a Bad Thing has happened and toss. 2537c478bd9Sstevel@tonic-gate */ 2547c478bd9Sstevel@tonic-gate while (!*((volatile int *)sync_flag)) { 2557c478bd9Sstevel@tonic-gate if (cntr++ == SCACHE_SPIN) { 2567c478bd9Sstevel@tonic-gate /* 2577c478bd9Sstevel@tonic-gate * If we're here, then we've spun long enough 2587c478bd9Sstevel@tonic-gate * to justify use of gethrtime each iteration. 2597c478bd9Sstevel@tonic-gate */ 2607c478bd9Sstevel@tonic-gate hrtime_t nsec_start, nsectowait, nsec_current; 2617c478bd9Sstevel@tonic-gate nsectowait = SCACHE_NSEC_WAIT; 2627c478bd9Sstevel@tonic-gate nsec_current = nsec_start = gethrtime(); 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate while (!*((volatile int *)sync_flag)) { 2657c478bd9Sstevel@tonic-gate /* 2667c478bd9Sstevel@tonic-gate * Double check the sync flag again before 2677c478bd9Sstevel@tonic-gate * we panic in case we get preempted. 2687c478bd9Sstevel@tonic-gate * See bugid 4126896 2697c478bd9Sstevel@tonic-gate */ 2707c478bd9Sstevel@tonic-gate nsec_current = gethrtime(); 2717c478bd9Sstevel@tonic-gate if ((nsec_current - nsec_start) > nsectowait && 2727c478bd9Sstevel@tonic-gate !*((volatile int *)sync_flag)) { 2737c478bd9Sstevel@tonic-gate /* 2747c478bd9Sstevel@tonic-gate * Trouble. The SYSIO chip has 2757c478bd9Sstevel@tonic-gate * seemingly gone AWOL. Vomit. 2767c478bd9Sstevel@tonic-gate */ 2777c478bd9Sstevel@tonic-gate panic("streaming buffer timed out"); 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate /* Finally, drop the sync lock */ 2847c478bd9Sstevel@tonic-gate mutex_exit(&softsp->sync_reg_lock); 2857c478bd9Sstevel@tonic-gate } 286