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