xref: /titanic_52/usr/src/uts/sun4/os/iommutsb.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 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