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
51extern ac_err_t ac_kpm_err_cvt(int);
52
53#ifdef DEBUG
54static void query_checker(pfn_t, pgcnt_t, memquery_t *);
55static int ac_do_query_check = 0;
56#endif /* DEBUG */
57
58int
59ac_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
219out:
220	kmem_free(statp, sizeof (ac_stat_t));
221
222	return (retval);
223}
224
225#ifdef DEBUG
226
227static void
228query_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