1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 1998 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <sys/types.h>
30 #include <sys/systm.h>
31 #include <sys/ddi.h>
32 #include <sys/sunddi.h>
33 #include <sys/ddi_impldefs.h>
34 #include <sys/obpdefs.h>
35 #include <sys/cmn_err.h>
36 #include <sys/errno.h>
37 #include <sys/kmem.h>
38 #include <sys/debug.h>
39 #include <sys/sysmacros.h>
40 #include <sys/machsystm.h>
41 #include <sys/machparam.h>
42 #include <sys/modctl.h>
43 #include <sys/fhc.h>
44 #include <sys/ac.h>
45 #include <sys/vm.h>
46 #include <sys/cpu_module.h>
47 #include <vm/hat_sfmmu.h>
48 #include <sys/mem_config.h>
49 #include <sys/mem_cage.h>
50
51 extern ac_err_t ac_kpm_err_cvt(int);
52
53 #ifdef DEBUG
54 static void query_checker(pfn_t, pgcnt_t, memquery_t *);
55 static int ac_do_query_check = 0;
56 #endif /* DEBUG */
57
58 int
ac_mem_stat(ac_cfga_pkt_t * pkt,int flag)59 ac_mem_stat(ac_cfga_pkt_t *pkt, int flag)
60 {
61 ac_stat_t *statp;
62 memquery_t memq;
63 struct ac_mem_info *mem_info;
64 struct bd_list *board;
65 struct ac_soft_state *ac;
66 uint64_t decode;
67 uint64_t base_pa;
68 uint64_t bank_size;
69 pfn_t base;
70 pgcnt_t npgs;
71 int ret;
72 int retval;
73
74 /*
75 * Is the specified bank present?
76 */
77
78 board = fhc_bdlist_lock(pkt->softsp->board);
79 if (board == NULL || board->ac_softsp == NULL) {
80 fhc_bdlist_unlock();
81 AC_ERR_SET(pkt, AC_ERR_BD);
82 return (EINVAL);
83 }
84
85 /* verify the board is of the correct type */
86 switch (board->sc.type) {
87 case CPU_BOARD:
88 case MEM_BOARD:
89 break;
90 default:
91 fhc_bdlist_unlock();
92 AC_ERR_SET(pkt, AC_ERR_BD_TYPE);
93 return (EINVAL);
94 }
95 ASSERT(pkt->softsp == board->ac_softsp);
96
97 ac = pkt->softsp;
98 mem_info = &ac->bank[pkt->bank];
99
100 statp = kmem_zalloc(sizeof (ac_stat_t), KM_SLEEP);
101
102 statp->rstate = mem_info->rstate;
103 statp->ostate = mem_info->ostate;
104 statp->condition = mem_info->condition;
105 statp->status_time = mem_info->status_change;
106 statp->board = ac->board;
107 statp->real_size = mem_info->real_size;
108 statp->use_size = mem_info->use_size;
109 statp->ac_memctl = *(ac->ac_memctl);
110 statp->ac_decode0 = *(ac->ac_memdecode0);
111 statp->ac_decode1 = *(ac->ac_memdecode1);
112
113 statp->page_size = PAGESIZE;
114
115 /*
116 * Busy could also be set for fhc_bd_busy(ac->board)
117 * however, this is just advisory information so limit it
118 * to memory operation in progress.
119 */
120 statp->busy = (mem_info->busy != FALSE);
121
122 /*
123 * Determine the physical location of the selected bank
124 */
125 decode = (pkt->bank == Bank0) ?
126 *(ac->ac_memdecode0) : *(ac->ac_memdecode1);
127 base_pa = GRP_REALBASE(decode);
128 bank_size = GRP_UK2SPAN(decode);
129
130 base = base_pa >> PAGESHIFT;
131 npgs = bank_size >> PAGESHIFT;
132
133 if (mem_info->ostate == SYSC_CFGA_OSTATE_CONFIGURED) {
134 bzero(&memq, sizeof (memq));
135
136 ret = kphysm_del_span_query(base, npgs, &memq);
137
138 if (ret != KPHYSM_OK) {
139 fhc_bdlist_unlock();
140 AC_ERR_SET(pkt, ac_kpm_err_cvt(ret));
141 retval = EINVAL;
142 goto out;
143 }
144 #ifdef DEBUG
145 if (ac_do_query_check) {
146 query_checker(base, npgs, &memq);
147 if (memq.phys_pages != npgs) {
148 /*
149 * This can happen in normal concurrent
150 * operation.
151 */
152 cmn_err(CE_WARN, "ac_mem_stat(): "
153 "memq.phys_pages != npgs (%ld != %ld)",
154 (u_long)memq.phys_pages, (u_long)npgs);
155 }
156 }
157 #endif /* DEBUG */
158
159 statp->phys_pages = memq.phys_pages;
160 statp->managed = memq.managed;
161 if (!kcage_on)
162 statp->nonrelocatable = memq.phys_pages;
163 else
164 statp->nonrelocatable = memq.nonrelocatable;
165 } else
166 if (mem_info->rstate == SYSC_CFGA_RSTATE_CONNECTED) {
167 /* Bank is in state Spare */
168 statp->phys_pages = npgs;
169 }
170
171 fhc_bdlist_unlock();
172
173 retval = DDI_SUCCESS;
174 /* return the information to the user */
175 #ifdef _MULTI_DATAMODEL
176 switch (ddi_model_convert_from(flag & FMODELS)) {
177 case DDI_MODEL_ILP32: {
178 ac_stat32_t *stat32p;
179
180 stat32p = kmem_zalloc(sizeof (ac_stat32_t), KM_SLEEP);
181
182 stat32p->rstate = statp->rstate;
183 stat32p->ostate = statp->ostate;
184 stat32p->condition = statp->condition;
185 stat32p->status_time = (time32_t)statp->status_time;
186 stat32p->board = statp->board;
187 stat32p->real_size = statp->real_size;
188 stat32p->use_size = statp->use_size;
189 stat32p->busy = statp->busy;
190 stat32p->page_size = statp->page_size;
191 stat32p->phys_pages = statp->phys_pages;
192 stat32p->managed = statp->managed;
193 stat32p->nonrelocatable = statp->nonrelocatable;
194 stat32p->ac_memctl = statp->ac_memctl;
195 stat32p->ac_decode0 = statp->ac_decode0;
196 stat32p->ac_decode1 = statp->ac_decode1;
197
198 if (ddi_copyout(stat32p, pkt->cmd_cfga.private,
199 sizeof (ac_stat32_t), flag) != 0) {
200 retval = EFAULT;
201 }
202 kmem_free(stat32p, sizeof (ac_stat32_t));
203 break;
204 }
205 case DDI_MODEL_NONE:
206 if (ddi_copyout(statp, pkt->cmd_cfga.private,
207 sizeof (ac_stat_t), flag) != 0) {
208 retval = EFAULT;
209 }
210 break;
211 }
212 #else /* _MULTI_DATAMODEL */
213 if (ddi_copyout(statp, pkt->cmd_cfga.private,
214 sizeof (ac_stat_t), flag) != 0) {
215 retval = EFAULT;
216 }
217 #endif /* _MULTI_DATAMODEL */
218
219 out:
220 kmem_free(statp, sizeof (ac_stat_t));
221
222 return (retval);
223 }
224
225 #ifdef DEBUG
226
227 static void
query_checker(pfn_t base,pgcnt_t npgs,memquery_t * mqp)228 query_checker(
229 pfn_t base,
230 pgcnt_t npgs,
231 memquery_t *mqp)
232 {
233 memquery_t memq;
234 memquery_t amemq;
235 int done_first_nonreloc;
236 int all_pop;
237 pfn_t abase;
238 pgcnt_t n;
239 int ret;
240
241 all_pop = (mqp->phys_pages == npgs);
242 memq.phys_pages = 0;
243 memq.managed = 0;
244 memq.nonrelocatable = 0;
245 memq.first_nonrelocatable = 0;
246 memq.last_nonrelocatable = 0;
247 done_first_nonreloc = 0;
248 for (abase = base, n = npgs; n != 0; abase++, n--) {
249 ret = kphysm_del_span_query(abase, 1, &amemq);
250 if (ret != KPHYSM_OK) {
251 printf("%ld: ret = %d\n", abase, ret);
252 continue;
253 }
254 if (all_pop && amemq.phys_pages != 1) {
255 printf("%ld: phys_pages = %ld, expected 1\n",
256 abase, amemq.phys_pages);
257 } else
258 if (amemq.phys_pages != 0 && amemq.phys_pages != 1) {
259 printf("%ld: phys_pages = %ld, expected 0 or 1\n",
260 abase, amemq.phys_pages);
261 }
262 memq.phys_pages += amemq.phys_pages;
263 if (amemq.managed != 0 && amemq.managed != 1) {
264 printf("%ld: managed = %ld, expected 0 or 1\n",
265 abase, amemq.managed);
266 }
267 memq.managed += amemq.managed;
268 if (amemq.nonrelocatable != 0 && amemq.nonrelocatable != 1) {
269 printf("%ld: nonrelocatable = %ld, expected 0 or 1\n",
270 abase, amemq.nonrelocatable);
271 }
272 memq.nonrelocatable += amemq.nonrelocatable;
273 if (amemq.nonrelocatable != 0) {
274 if (amemq.first_nonrelocatable != abase) {
275 printf("%ld: first_nonrelocatable = %ld\n",
276 abase, amemq.first_nonrelocatable);
277 }
278 if (amemq.last_nonrelocatable != abase) {
279 printf("%ld: last_nonrelocatable = %ld\n",
280 abase, amemq.last_nonrelocatable);
281 }
282 if (!done_first_nonreloc) {
283 memq.first_nonrelocatable = abase;
284 done_first_nonreloc = 1;
285 }
286 memq.last_nonrelocatable = abase;
287 }
288 }
289 if (mqp->phys_pages != memq.phys_pages) {
290 printf("query phys_pages: %ld != %ld\n",
291 mqp->phys_pages, memq.phys_pages);
292 }
293 if (mqp->managed != memq.managed) {
294 printf("query managed: %ld != %ld\n",
295 mqp->managed, memq.managed);
296 }
297 if (mqp->nonrelocatable != memq.nonrelocatable) {
298 printf("query nonrelocatable: %ld != %ld\n",
299 mqp->nonrelocatable, memq.nonrelocatable);
300 }
301 if (mqp->first_nonrelocatable != memq.first_nonrelocatable) {
302 printf("query first_nonrelocatable: %ld != %ld\n",
303 mqp->first_nonrelocatable, memq.first_nonrelocatable);
304 }
305 if (mqp->last_nonrelocatable != memq.last_nonrelocatable) {
306 printf("query last_nonrelocatable: %ld != %ld\n",
307 mqp->last_nonrelocatable, memq.last_nonrelocatable);
308 }
309 }
310 #endif /* DEBUG */
311