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 2005 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/iommutsb.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/mutex.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/platform_module.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate /* 40*7c478bd9Sstevel@tonic-gate * The interfaces provided by this file will eventually no longer 41*7c478bd9Sstevel@tonic-gate * be required once a physically contiguous memory allocator 42*7c478bd9Sstevel@tonic-gate * is available. 43*7c478bd9Sstevel@tonic-gate */ 44*7c478bd9Sstevel@tonic-gate 45*7c478bd9Sstevel@tonic-gate /* 46*7c478bd9Sstevel@tonic-gate * The TSB size and consequently the DVMA range is appropriated proportional 47*7c478bd9Sstevel@tonic-gate * to the physical memory size. 48*7c478bd9Sstevel@tonic-gate * 49*7c478bd9Sstevel@tonic-gate * phys_mem_size iommu TSB size DVMA size 50*7c478bd9Sstevel@tonic-gate * <= 32MB 64KB 64MB 51*7c478bd9Sstevel@tonic-gate * <= 128MB 256KB 256MB 52*7c478bd9Sstevel@tonic-gate * <= 512MB 512KB 512MB 53*7c478bd9Sstevel@tonic-gate * > 512MB 1MB 1GB 54*7c478bd9Sstevel@tonic-gate * 55*7c478bd9Sstevel@tonic-gate * NOTE: The original Solaris 8 FCS allocations must be used with 56*7c478bd9Sstevel@tonic-gate * 32-bit kernels. 57*7c478bd9Sstevel@tonic-gate * 58*7c478bd9Sstevel@tonic-gate */ 59*7c478bd9Sstevel@tonic-gate static uint_t 60*7c478bd9Sstevel@tonic-gate resolve_tsb_size(pgcnt_t phys_mem_size) 61*7c478bd9Sstevel@tonic-gate { 62*7c478bd9Sstevel@tonic-gate if (phys_mem_size <= 0x1000) 63*7c478bd9Sstevel@tonic-gate return (0x10000); 64*7c478bd9Sstevel@tonic-gate else if (phys_mem_size <= 0x4000) 65*7c478bd9Sstevel@tonic-gate return (0x40000); 66*7c478bd9Sstevel@tonic-gate else if (phys_mem_size <= 0x10000) 67*7c478bd9Sstevel@tonic-gate return (0x80000); 68*7c478bd9Sstevel@tonic-gate else 69*7c478bd9Sstevel@tonic-gate return (0x100000); 70*7c478bd9Sstevel@tonic-gate } 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate /* TSB size must be a power of 2 between the minimum and the maximum. */ 73*7c478bd9Sstevel@tonic-gate #define MIN_TSB_BYTES 0x2000 74*7c478bd9Sstevel@tonic-gate #define MAX_TSB_BYTES 0x100000 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate /* 77*7c478bd9Sstevel@tonic-gate * Use boot to allocate the physically contiguous memory needed for the 78*7c478bd9Sstevel@tonic-gate * IOMMU's TSB arrays until there is an interface for dynamically 79*7c478bd9Sstevel@tonic-gate * allocated, physically contiguous memory. 80*7c478bd9Sstevel@tonic-gate * The number IOMMUs at boot, niommu_tsbs, is set as a side effect 81*7c478bd9Sstevel@tonic-gate * of map_wellknown_devices(). The number of TSBs allocated is 82*7c478bd9Sstevel@tonic-gate * at least niommu_tsbs. On platforms supporting Dynamic Reconfiguration 83*7c478bd9Sstevel@tonic-gate * the platmod routine set_platform_tsb_spares() returns the 84*7c478bd9Sstevel@tonic-gate * maximum total number of TSBs expected. The final number of TSBs 85*7c478bd9Sstevel@tonic-gate * allocated is set in iommu_tsb_num. 86*7c478bd9Sstevel@tonic-gate * 87*7c478bd9Sstevel@tonic-gate * WARNING - since this routine uses boot to allocate memory, it MUST 88*7c478bd9Sstevel@tonic-gate * be called before the kernel takes over memory allocation from boot. 89*7c478bd9Sstevel@tonic-gate */ 90*7c478bd9Sstevel@tonic-gate #define MAX_IOMMU_PER_AGENT 2 91*7c478bd9Sstevel@tonic-gate #define MAX_TSB_ALLOC (MAX_UPA * MAX_IOMMU_PER_AGENT) 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate static kmutex_t iommu_tsb_avail_lock; 94*7c478bd9Sstevel@tonic-gate static uint16_t iommu_tsb_avail[MAX_TSB_ALLOC]; 95*7c478bd9Sstevel@tonic-gate #define IOMMU_TSB_INUSE 0x8000u 96*7c478bd9Sstevel@tonic-gate static uint_t iommu_tsb_num; 97*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 98*7c478bd9Sstevel@tonic-gate static uint_t iommu_tsb_nfree; 99*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate static caddr_t iommu_tsb_base; 102*7c478bd9Sstevel@tonic-gate static uint_t iommu_tsb_size; 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate uint_t niommu_tsbs; 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate /* 107*7c478bd9Sstevel@tonic-gate * The following variables can be patched to override the auto-selection 108*7c478bd9Sstevel@tonic-gate * of dvma space based on the amount of installed physical memory. 109*7c478bd9Sstevel@tonic-gate * Not settable via /etc/system as it is read after iommu_tsb_init() 110*7c478bd9Sstevel@tonic-gate * is called. 111*7c478bd9Sstevel@tonic-gate */ 112*7c478bd9Sstevel@tonic-gate uint_t iommu_tsb_size_min = MIN_TSB_BYTES; 113*7c478bd9Sstevel@tonic-gate uint_t iommu_tsb_size_max = MAX_TSB_BYTES; 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate caddr_t 116*7c478bd9Sstevel@tonic-gate iommu_tsb_init(caddr_t alloc_base) 117*7c478bd9Sstevel@tonic-gate { 118*7c478bd9Sstevel@tonic-gate size_t total_size; 119*7c478bd9Sstevel@tonic-gate caddr_t base = (caddr_t)roundup((uintptr_t)alloc_base, MMU_PAGESIZE); 120*7c478bd9Sstevel@tonic-gate uint_t tsb_min, tsb_max; 121*7c478bd9Sstevel@tonic-gate uint_t tsb_size; 122*7c478bd9Sstevel@tonic-gate uint_t ntsbs; 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate /* 125*7c478bd9Sstevel@tonic-gate * determine the amount of physical memory required for the TSB arrays 126*7c478bd9Sstevel@tonic-gate * 127*7c478bd9Sstevel@tonic-gate * assumes niommu_tsbs has already been initialized, i.e. 128*7c478bd9Sstevel@tonic-gate * map_wellknown_devices() 129*7c478bd9Sstevel@tonic-gate * 130*7c478bd9Sstevel@tonic-gate * TSB space is allocated proportional to memory size (see 131*7c478bd9Sstevel@tonic-gate * resolve_tsb_size) but later constained by the limit obtained 132*7c478bd9Sstevel@tonic-gate * from get_dvma_property_limit in the nexus attach. 133*7c478bd9Sstevel@tonic-gate */ 134*7c478bd9Sstevel@tonic-gate tsb_size = resolve_tsb_size(physinstalled); 135*7c478bd9Sstevel@tonic-gate 136*7c478bd9Sstevel@tonic-gate tsb_min = MAX(iommu_tsb_size_min, MIN_TSB_BYTES); 137*7c478bd9Sstevel@tonic-gate tsb_max = MIN(iommu_tsb_size_max, MAX_TSB_BYTES); 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate if (tsb_min <= tsb_max) { 140*7c478bd9Sstevel@tonic-gate uint_t sz; 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate /* Ensure that min and max are powers of two. */ 143*7c478bd9Sstevel@tonic-gate /* guaranteed min and max are both between MIN/MAX_TSB_BYTES */ 144*7c478bd9Sstevel@tonic-gate for (sz = MAX_TSB_BYTES; !(sz & tsb_min); sz >>= 1) 145*7c478bd9Sstevel@tonic-gate /* empty */; 146*7c478bd9Sstevel@tonic-gate tsb_min = sz; 147*7c478bd9Sstevel@tonic-gate for (sz = MAX_TSB_BYTES; !(sz & tsb_max); sz >>= 1) 148*7c478bd9Sstevel@tonic-gate /* empty */; 149*7c478bd9Sstevel@tonic-gate tsb_max = sz; 150*7c478bd9Sstevel@tonic-gate 151*7c478bd9Sstevel@tonic-gate /* guaranteed min still <= max */ 152*7c478bd9Sstevel@tonic-gate tsb_size = MIN(tsb_size, tsb_max); 153*7c478bd9Sstevel@tonic-gate tsb_size = MAX(tsb_size, tsb_min); 154*7c478bd9Sstevel@tonic-gate } else 155*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 156*7c478bd9Sstevel@tonic-gate "iommutsb: bad iommu_tsb_size_min/max value pair"); 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate iommu_tsb_size = tsb_size; 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate if (&set_platform_tsb_spares) 161*7c478bd9Sstevel@tonic-gate ntsbs = set_platform_tsb_spares(); 162*7c478bd9Sstevel@tonic-gate else 163*7c478bd9Sstevel@tonic-gate ntsbs = 0; 164*7c478bd9Sstevel@tonic-gate ntsbs = MAX(ntsbs, niommu_tsbs); 165*7c478bd9Sstevel@tonic-gate ntsbs = MIN(ntsbs, MAX_TSB_ALLOC); 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate total_size = ntsbs * tsb_size; 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate if (total_size == 0) 170*7c478bd9Sstevel@tonic-gate return (alloc_base); 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate /* 173*7c478bd9Sstevel@tonic-gate * allocate the physical memory for the TSB arrays 174*7c478bd9Sstevel@tonic-gate */ 175*7c478bd9Sstevel@tonic-gate if ((iommu_tsb_base = (caddr_t)BOP_ALLOC(bootops, base, 176*7c478bd9Sstevel@tonic-gate total_size, MMU_PAGESIZE)) == NULL) 177*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "Cannot allocate IOMMU TSB arrays"); 178*7c478bd9Sstevel@tonic-gate ASSERT(iommu_tsb_base == base); 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate iommu_tsb_num = ntsbs; 181*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 182*7c478bd9Sstevel@tonic-gate iommu_tsb_nfree = iommu_tsb_num; 183*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate return (base + total_size); 186*7c478bd9Sstevel@tonic-gate } 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate /* 189*7c478bd9Sstevel@tonic-gate * External allocation interface to the nexus drivers (sbus, pci). 190*7c478bd9Sstevel@tonic-gate * As an aid to debugging, the upaid or portid is recorded against 191*7c478bd9Sstevel@tonic-gate * an allocation. 192*7c478bd9Sstevel@tonic-gate */ 193*7c478bd9Sstevel@tonic-gate uint16_t 194*7c478bd9Sstevel@tonic-gate iommu_tsb_alloc(uint16_t id) 195*7c478bd9Sstevel@tonic-gate { 196*7c478bd9Sstevel@tonic-gate uint16_t tsbc; 197*7c478bd9Sstevel@tonic-gate uint_t i; 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate tsbc = IOMMU_TSB_COOKIE_NONE; 200*7c478bd9Sstevel@tonic-gate mutex_enter(&iommu_tsb_avail_lock); 201*7c478bd9Sstevel@tonic-gate for (i = 0; i < iommu_tsb_num; i++) { 202*7c478bd9Sstevel@tonic-gate if (iommu_tsb_avail[i] == 0) { 203*7c478bd9Sstevel@tonic-gate iommu_tsb_avail[i] = IOMMU_TSB_INUSE | id; 204*7c478bd9Sstevel@tonic-gate tsbc = (uint16_t)i; 205*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 206*7c478bd9Sstevel@tonic-gate ASSERT(iommu_tsb_nfree != 0); 207*7c478bd9Sstevel@tonic-gate iommu_tsb_nfree--; 208*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 209*7c478bd9Sstevel@tonic-gate break; 210*7c478bd9Sstevel@tonic-gate } 211*7c478bd9Sstevel@tonic-gate } 212*7c478bd9Sstevel@tonic-gate mutex_exit(&iommu_tsb_avail_lock); 213*7c478bd9Sstevel@tonic-gate return (tsbc); 214*7c478bd9Sstevel@tonic-gate } 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate void 217*7c478bd9Sstevel@tonic-gate iommu_tsb_free(uint16_t tsbc) 218*7c478bd9Sstevel@tonic-gate { 219*7c478bd9Sstevel@tonic-gate ASSERT(tsbc != IOMMU_TSB_COOKIE_NONE); 220*7c478bd9Sstevel@tonic-gate ASSERT(tsbc < iommu_tsb_num); 221*7c478bd9Sstevel@tonic-gate mutex_enter(&iommu_tsb_avail_lock); 222*7c478bd9Sstevel@tonic-gate if (iommu_tsb_avail[tsbc] == 0) { 223*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "iommu_tsb_free(%d): tsb not in use", tsbc); 224*7c478bd9Sstevel@tonic-gate } 225*7c478bd9Sstevel@tonic-gate iommu_tsb_avail[tsbc] = 0; 226*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 227*7c478bd9Sstevel@tonic-gate ASSERT(iommu_tsb_nfree < iommu_tsb_num); 228*7c478bd9Sstevel@tonic-gate iommu_tsb_nfree++; 229*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 230*7c478bd9Sstevel@tonic-gate mutex_exit(&iommu_tsb_avail_lock); 231*7c478bd9Sstevel@tonic-gate } 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 234*7c478bd9Sstevel@tonic-gate uint_t 235*7c478bd9Sstevel@tonic-gate iommu_tsb_cookie_to_size(uint16_t tsbc) 236*7c478bd9Sstevel@tonic-gate { 237*7c478bd9Sstevel@tonic-gate ASSERT(tsbc != IOMMU_TSB_COOKIE_NONE); 238*7c478bd9Sstevel@tonic-gate ASSERT(tsbc < iommu_tsb_num); 239*7c478bd9Sstevel@tonic-gate ASSERT(iommu_tsb_avail[tsbc] != 0); 240*7c478bd9Sstevel@tonic-gate return (iommu_tsb_size); 241*7c478bd9Sstevel@tonic-gate } 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate uint64_t * 244*7c478bd9Sstevel@tonic-gate iommu_tsb_cookie_to_va(uint16_t tsbc) 245*7c478bd9Sstevel@tonic-gate { 246*7c478bd9Sstevel@tonic-gate ASSERT(tsbc != IOMMU_TSB_COOKIE_NONE); 247*7c478bd9Sstevel@tonic-gate ASSERT(tsbc < iommu_tsb_num); 248*7c478bd9Sstevel@tonic-gate ASSERT(iommu_tsb_avail[tsbc] != 0); 249*7c478bd9Sstevel@tonic-gate return ((uint64_t *)(iommu_tsb_base + (tsbc * iommu_tsb_size))); 250*7c478bd9Sstevel@tonic-gate } 251