xref: /illumos-gate/usr/src/uts/sun4u/sunfire/io/ac_stat.c (revision bc1f688b4872ace323eaddbb1a6365d054e7bf56)
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
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
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