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