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