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 2006 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/conf.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/vmem.h> 39*1341Sstevel #include <sys/debug.h> 40*1341Sstevel #include <sys/sysmacros.h> 41*1341Sstevel #include <sys/machsystm.h> 42*1341Sstevel #include <sys/machparam.h> 43*1341Sstevel #include <sys/modctl.h> 44*1341Sstevel #include <sys/atomic.h> 45*1341Sstevel #include <sys/fhc.h> 46*1341Sstevel #include <sys/ac.h> 47*1341Sstevel #include <sys/jtag.h> 48*1341Sstevel #include <sys/cpu_module.h> 49*1341Sstevel #include <sys/spitregs.h> 50*1341Sstevel #include <sys/vm.h> 51*1341Sstevel #include <vm/seg_kmem.h> 52*1341Sstevel #include <vm/hat_sfmmu.h> 53*1341Sstevel 54*1341Sstevel /* memory setup parameters */ 55*1341Sstevel #define TEST_PAGESIZE MMU_PAGESIZE 56*1341Sstevel 57*1341Sstevel struct test_info { 58*1341Sstevel struct test_info *next; /* linked list of tests */ 59*1341Sstevel struct ac_mem_info *mem_info; 60*1341Sstevel uint_t board; 61*1341Sstevel uint_t bank; 62*1341Sstevel caddr_t bufp; /* pointer to buffer page */ 63*1341Sstevel caddr_t va; /* test target VA */ 64*1341Sstevel ac_mem_test_start_t info; 65*1341Sstevel uint_t in_test; /* count of threads in test */ 66*1341Sstevel }; 67*1341Sstevel 68*1341Sstevel /* list of tests in progress (list protected test_mutex) */ 69*1341Sstevel static struct test_info *test_base = NULL; 70*1341Sstevel static kmutex_t test_mutex; 71*1341Sstevel static int test_mutex_initialized = FALSE; 72*1341Sstevel 73*1341Sstevel static mem_test_handle_t mem_test_sequence_id = 0; 74*1341Sstevel 75*1341Sstevel void 76*1341Sstevel ac_mapin(uint64_t pa, caddr_t va) 77*1341Sstevel { 78*1341Sstevel pfn_t pfn; 79*1341Sstevel tte_t tte; 80*1341Sstevel 81*1341Sstevel pfn = pa >> MMU_PAGESHIFT; 82*1341Sstevel tte.tte_inthi = TTE_VALID_INT | TTE_SZ_INT(TTE8K) | 83*1341Sstevel TTE_PFN_INTHI(pfn); 84*1341Sstevel tte.tte_intlo = TTE_PFN_INTLO(pfn) | TTE_CP_INT | 85*1341Sstevel TTE_PRIV_INT | TTE_LCK_INT | TTE_HWWR_INT; 86*1341Sstevel sfmmu_dtlb_ld(va, KCONTEXT, &tte); 87*1341Sstevel 88*1341Sstevel } 89*1341Sstevel 90*1341Sstevel void 91*1341Sstevel ac_unmap(caddr_t va) 92*1341Sstevel { 93*1341Sstevel vtag_flushpage(va, KCONTEXT); 94*1341Sstevel } 95*1341Sstevel 96*1341Sstevel int 97*1341Sstevel ac_mem_test_start(ac_cfga_pkt_t *pkt, int flag) 98*1341Sstevel { 99*1341Sstevel struct ac_soft_state *softsp; 100*1341Sstevel struct ac_mem_info *mem_info; 101*1341Sstevel struct bd_list *board; 102*1341Sstevel struct test_info *test; 103*1341Sstevel uint64_t decode; 104*1341Sstevel 105*1341Sstevel /* XXX if ac ever detaches... */ 106*1341Sstevel if (test_mutex_initialized == FALSE) { 107*1341Sstevel mutex_init(&test_mutex, NULL, MUTEX_DEFAULT, NULL); 108*1341Sstevel test_mutex_initialized = TRUE; 109*1341Sstevel } 110*1341Sstevel 111*1341Sstevel /* 112*1341Sstevel * Is the specified bank testable? 113*1341Sstevel */ 114*1341Sstevel 115*1341Sstevel board = fhc_bdlist_lock(pkt->softsp->board); 116*1341Sstevel if (board == NULL || board->ac_softsp == NULL) { 117*1341Sstevel fhc_bdlist_unlock(); 118*1341Sstevel AC_ERR_SET(pkt, AC_ERR_BD); 119*1341Sstevel return (EINVAL); 120*1341Sstevel } 121*1341Sstevel ASSERT(pkt->softsp == board->ac_softsp); 122*1341Sstevel 123*1341Sstevel /* verify the board is of the correct type */ 124*1341Sstevel switch (board->sc.type) { 125*1341Sstevel case CPU_BOARD: 126*1341Sstevel case MEM_BOARD: 127*1341Sstevel break; 128*1341Sstevel default: 129*1341Sstevel fhc_bdlist_unlock(); 130*1341Sstevel AC_ERR_SET(pkt, AC_ERR_BD_TYPE); 131*1341Sstevel return (EINVAL); 132*1341Sstevel } 133*1341Sstevel 134*1341Sstevel /* 135*1341Sstevel * Memory must be in the spare state to be testable. 136*1341Sstevel * However, spare memory that is testing can't be tested 137*1341Sstevel * again, instead return the current test info. 138*1341Sstevel */ 139*1341Sstevel softsp = pkt->softsp; 140*1341Sstevel mem_info = &softsp->bank[pkt->bank]; 141*1341Sstevel if (!MEM_BOARD_VISIBLE(board) || 142*1341Sstevel fhc_bd_busy(softsp->board) || 143*1341Sstevel mem_info->rstate != SYSC_CFGA_RSTATE_CONNECTED || 144*1341Sstevel mem_info->ostate != SYSC_CFGA_OSTATE_UNCONFIGURED) { 145*1341Sstevel fhc_bdlist_unlock(); 146*1341Sstevel AC_ERR_SET(pkt, AC_ERR_BD_STATE); 147*1341Sstevel return (EINVAL); 148*1341Sstevel } 149*1341Sstevel if (mem_info->busy) { /* oops, testing? */ 150*1341Sstevel /* 151*1341Sstevel * find the test entry 152*1341Sstevel */ 153*1341Sstevel ASSERT(test_mutex_initialized); 154*1341Sstevel mutex_enter(&test_mutex); 155*1341Sstevel for (test = test_base; test != NULL; test = test->next) { 156*1341Sstevel if (test->board == softsp->board && 157*1341Sstevel test->bank == pkt->bank) 158*1341Sstevel break; 159*1341Sstevel } 160*1341Sstevel if (test == NULL) { 161*1341Sstevel mutex_exit(&test_mutex); 162*1341Sstevel fhc_bdlist_unlock(); 163*1341Sstevel /* Not busy testing. */ 164*1341Sstevel AC_ERR_SET(pkt, AC_ERR_BD_STATE); 165*1341Sstevel return (EINVAL); 166*1341Sstevel } 167*1341Sstevel 168*1341Sstevel /* 169*1341Sstevel * return the current test information to the new caller 170*1341Sstevel */ 171*1341Sstevel if (ddi_copyout(&test->info, pkt->cmd_cfga.private, 172*1341Sstevel sizeof (ac_mem_test_start_t), flag) != 0) { 173*1341Sstevel mutex_exit(&test_mutex); 174*1341Sstevel fhc_bdlist_unlock(); 175*1341Sstevel return (EFAULT); /* !broken user app */ 176*1341Sstevel } 177*1341Sstevel mutex_exit(&test_mutex); 178*1341Sstevel fhc_bdlist_unlock(); 179*1341Sstevel AC_ERR_SET(pkt, AC_ERR_MEM_BK); 180*1341Sstevel return (EBUSY); /* signal bank in use */ 181*1341Sstevel } 182*1341Sstevel 183*1341Sstevel /* 184*1341Sstevel * at this point, we have an available bank to test. 185*1341Sstevel * create a test buffer 186*1341Sstevel */ 187*1341Sstevel test = kmem_zalloc(sizeof (struct test_info), KM_SLEEP); 188*1341Sstevel test->va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP); 189*1341Sstevel 190*1341Sstevel /* fill in all the test info details now */ 191*1341Sstevel test->mem_info = mem_info; 192*1341Sstevel test->board = softsp->board; 193*1341Sstevel test->bank = pkt->bank; 194*1341Sstevel test->bufp = kmem_alloc(TEST_PAGESIZE, KM_SLEEP); 195*1341Sstevel test->info.handle = atomic_add_32_nv(&mem_test_sequence_id, 1); 196*1341Sstevel (void) drv_getparm(PPID, (ulong_t *)(&(test->info.tester_pid))); 197*1341Sstevel test->info.prev_condition = mem_info->condition; 198*1341Sstevel test->info.page_size = TEST_PAGESIZE; 199*1341Sstevel /* If Blackbird ever gets a variable line size, this will change. */ 200*1341Sstevel test->info.line_size = cpunodes[CPU->cpu_id].ecache_linesize; 201*1341Sstevel decode = (pkt->bank == Bank0) ? 202*1341Sstevel *softsp->ac_memdecode0 : *softsp->ac_memdecode1; 203*1341Sstevel test->info.afar_base = GRP_REALBASE(decode); 204*1341Sstevel test->info.bank_size = GRP_UK2SPAN(decode); 205*1341Sstevel 206*1341Sstevel /* return the information to the user */ 207*1341Sstevel if (ddi_copyout(&test->info, pkt->cmd_cfga.private, 208*1341Sstevel sizeof (ac_mem_test_start_t), flag) != 0) { 209*1341Sstevel 210*1341Sstevel /* oh well, tear down the test now */ 211*1341Sstevel kmem_free(test->bufp, TEST_PAGESIZE); 212*1341Sstevel vmem_free(heap_arena, test->va, PAGESIZE); 213*1341Sstevel kmem_free(test, sizeof (struct test_info)); 214*1341Sstevel 215*1341Sstevel fhc_bdlist_unlock(); 216*1341Sstevel return (EFAULT); 217*1341Sstevel } 218*1341Sstevel 219*1341Sstevel mem_info->busy = TRUE; 220*1341Sstevel 221*1341Sstevel /* finally link us into the test database */ 222*1341Sstevel mutex_enter(&test_mutex); 223*1341Sstevel test->next = test_base; 224*1341Sstevel test_base = test; 225*1341Sstevel mutex_exit(&test_mutex); 226*1341Sstevel 227*1341Sstevel fhc_bdlist_unlock(); 228*1341Sstevel 229*1341Sstevel #ifdef DEBUG 230*1341Sstevel cmn_err(CE_NOTE, "!memtest: start test[%u]: board %d, bank %d", 231*1341Sstevel test->info.handle, test->board, test->bank); 232*1341Sstevel #endif /* DEBUG */ 233*1341Sstevel return (DDI_SUCCESS); 234*1341Sstevel } 235*1341Sstevel 236*1341Sstevel int 237*1341Sstevel ac_mem_test_stop(ac_cfga_pkt_t *pkt, int flag) 238*1341Sstevel { 239*1341Sstevel struct test_info *test, **prev; 240*1341Sstevel ac_mem_test_stop_t stop; 241*1341Sstevel 242*1341Sstevel /* get test result information */ 243*1341Sstevel if (ddi_copyin(pkt->cmd_cfga.private, &stop, 244*1341Sstevel sizeof (ac_mem_test_stop_t), flag) != 0) 245*1341Sstevel return (EFAULT); 246*1341Sstevel 247*1341Sstevel /* bdlist protects all state changes... */ 248*1341Sstevel (void) fhc_bdlist_lock(-1); 249*1341Sstevel 250*1341Sstevel /* find the test */ 251*1341Sstevel mutex_enter(&test_mutex); 252*1341Sstevel prev = &test_base; 253*1341Sstevel for (test = test_base; test != NULL; test = test->next) { 254*1341Sstevel if (test->info.handle == stop.handle) 255*1341Sstevel break; /* found the test */ 256*1341Sstevel prev = &test->next; 257*1341Sstevel } 258*1341Sstevel if (test == NULL) { 259*1341Sstevel mutex_exit(&test_mutex); 260*1341Sstevel fhc_bdlist_unlock(); 261*1341Sstevel AC_ERR_SET(pkt, AC_ERR_MEM_TEST); 262*1341Sstevel return (EINVAL); 263*1341Sstevel } 264*1341Sstevel 265*1341Sstevel #ifdef DEBUG 266*1341Sstevel cmn_err(CE_NOTE, 267*1341Sstevel "!memtest: stop test[%u]: board %d, bank %d," 268*1341Sstevel " condition %d", 269*1341Sstevel test->info.handle, test->board, 270*1341Sstevel test->bank, stop.condition); 271*1341Sstevel #endif /* DEBUG */ 272*1341Sstevel 273*1341Sstevel /* first unlink us from the test list (to allow no more entries) */ 274*1341Sstevel *prev = test->next; 275*1341Sstevel 276*1341Sstevel /* then, wait for current tests to complete */ 277*1341Sstevel while (test->in_test != 0) 278*1341Sstevel delay(1); 279*1341Sstevel 280*1341Sstevel mutex_exit(&test_mutex); 281*1341Sstevel 282*1341Sstevel /* clean up the test related allocations */ 283*1341Sstevel vmem_free(heap_arena, test->va, PAGESIZE); 284*1341Sstevel kmem_free(test->bufp, TEST_PAGESIZE); 285*1341Sstevel 286*1341Sstevel /* update the bank condition accordingly */ 287*1341Sstevel test->mem_info->condition = stop.condition; 288*1341Sstevel test->mem_info->status_change = ddi_get_time(); 289*1341Sstevel 290*1341Sstevel test->mem_info->busy = FALSE; 291*1341Sstevel 292*1341Sstevel /* finally, delete the test element */ 293*1341Sstevel kmem_free(test, sizeof (struct test_info)); 294*1341Sstevel 295*1341Sstevel fhc_bdlist_unlock(); 296*1341Sstevel 297*1341Sstevel return (DDI_SUCCESS); 298*1341Sstevel } 299*1341Sstevel 300*1341Sstevel void 301*1341Sstevel ac_mem_test_stop_on_close(uint_t board, uint_t bank) 302*1341Sstevel { 303*1341Sstevel struct test_info *test, **prev; 304*1341Sstevel sysc_cfga_cond_t condition = SYSC_CFGA_COND_UNKNOWN; 305*1341Sstevel 306*1341Sstevel /* bdlist protects all state changes... */ 307*1341Sstevel (void) fhc_bdlist_lock(-1); 308*1341Sstevel 309*1341Sstevel /* find the test */ 310*1341Sstevel mutex_enter(&test_mutex); 311*1341Sstevel prev = &test_base; 312*1341Sstevel for (test = test_base; test != NULL; test = test->next) { 313*1341Sstevel if (test->board == board && test->bank == bank) 314*1341Sstevel break; /* found the test */ 315*1341Sstevel prev = &test->next; 316*1341Sstevel } 317*1341Sstevel if (test == NULL) { 318*1341Sstevel /* No test running, nothing to do. */ 319*1341Sstevel mutex_exit(&test_mutex); 320*1341Sstevel fhc_bdlist_unlock(); 321*1341Sstevel return; 322*1341Sstevel } 323*1341Sstevel 324*1341Sstevel #ifdef DEBUG 325*1341Sstevel cmn_err(CE_NOTE, "!memtest: stop test[%u] on close: " 326*1341Sstevel "board %d, bank %d, condition %d", test->info.handle, 327*1341Sstevel test->board, test->bank, condition); 328*1341Sstevel #endif /* DEBUG */ 329*1341Sstevel 330*1341Sstevel /* first unlink us from the test list (to allow no more entries) */ 331*1341Sstevel *prev = test->next; 332*1341Sstevel 333*1341Sstevel ASSERT(test->in_test == 0); 334*1341Sstevel 335*1341Sstevel mutex_exit(&test_mutex); 336*1341Sstevel 337*1341Sstevel /* clean up the test related allocations */ 338*1341Sstevel vmem_free(heap_arena, test->va, PAGESIZE); 339*1341Sstevel kmem_free(test->bufp, TEST_PAGESIZE); 340*1341Sstevel 341*1341Sstevel /* update the bank condition accordingly */ 342*1341Sstevel test->mem_info->condition = condition; 343*1341Sstevel test->mem_info->status_change = ddi_get_time(); 344*1341Sstevel 345*1341Sstevel test->mem_info->busy = FALSE; 346*1341Sstevel 347*1341Sstevel /* finally, delete the test element */ 348*1341Sstevel kmem_free(test, sizeof (struct test_info)); 349*1341Sstevel 350*1341Sstevel fhc_bdlist_unlock(); 351*1341Sstevel } 352*1341Sstevel 353*1341Sstevel int 354*1341Sstevel ac_mem_test_read(ac_cfga_pkt_t *pkt, int flag) 355*1341Sstevel { 356*1341Sstevel struct test_info *test; 357*1341Sstevel uint_t page_offset; 358*1341Sstevel uint64_t page_pa; 359*1341Sstevel uint_t pstate_save; 360*1341Sstevel caddr_t src_va, dst_va; 361*1341Sstevel uint64_t orig_err; 362*1341Sstevel int retval = DDI_SUCCESS; 363*1341Sstevel sunfire_processor_error_regs_t error_buf; 364*1341Sstevel int error_found; 365*1341Sstevel ac_mem_test_read_t t_read; 366*1341Sstevel 367*1341Sstevel #ifdef _MULTI_DATAMODEL 368*1341Sstevel switch (ddi_model_convert_from(flag & FMODELS)) { 369*1341Sstevel case DDI_MODEL_ILP32: { 370*1341Sstevel ac_mem_test_read32_t t_read32; 371*1341Sstevel 372*1341Sstevel if (ddi_copyin(pkt->cmd_cfga.private, &t_read32, 373*1341Sstevel sizeof (ac_mem_test_read32_t), flag) != 0) 374*1341Sstevel return (EFAULT); 375*1341Sstevel t_read.handle = t_read32.handle; 376*1341Sstevel t_read.page_buf = (void *)(uintptr_t)t_read32.page_buf; 377*1341Sstevel t_read.address = t_read32.address; 378*1341Sstevel t_read.error_buf = (sunfire_processor_error_regs_t *) 379*1341Sstevel (uintptr_t)t_read32.error_buf; 380*1341Sstevel break; 381*1341Sstevel } 382*1341Sstevel case DDI_MODEL_NONE: 383*1341Sstevel if (ddi_copyin(pkt->cmd_cfga.private, &t_read, 384*1341Sstevel sizeof (ac_mem_test_read_t), flag) != 0) 385*1341Sstevel return (EFAULT); 386*1341Sstevel break; 387*1341Sstevel } 388*1341Sstevel #else /* _MULTI_DATAMODEL */ 389*1341Sstevel if (ddi_copyin(pkt->cmd_cfga.private, &t_read, 390*1341Sstevel sizeof (ac_mem_test_read_t), flag) != 0) 391*1341Sstevel return (EFAULT); 392*1341Sstevel #endif /* _MULTI_DATAMODEL */ 393*1341Sstevel 394*1341Sstevel /* verify the handle */ 395*1341Sstevel mutex_enter(&test_mutex); 396*1341Sstevel for (test = test_base; test != NULL; test = test->next) { 397*1341Sstevel if (test->info.handle == t_read.handle) 398*1341Sstevel break; 399*1341Sstevel } 400*1341Sstevel if (test == NULL) { 401*1341Sstevel mutex_exit(&test_mutex); 402*1341Sstevel AC_ERR_SET(pkt, AC_ERR_MEM_TEST); 403*1341Sstevel return (EINVAL); 404*1341Sstevel } 405*1341Sstevel 406*1341Sstevel /* bump the busy bit */ 407*1341Sstevel atomic_add_32(&test->in_test, 1); 408*1341Sstevel mutex_exit(&test_mutex); 409*1341Sstevel 410*1341Sstevel /* verify the remaining parameters */ 411*1341Sstevel if ((t_read.address.page_num >= 412*1341Sstevel test->info.bank_size / test->info.page_size) || 413*1341Sstevel (t_read.address.line_count == 0) || 414*1341Sstevel (t_read.address.line_count > 415*1341Sstevel test->info.page_size / test->info.line_size) || 416*1341Sstevel (t_read.address.line_offset >= 417*1341Sstevel test->info.page_size / test->info.line_size) || 418*1341Sstevel ((t_read.address.line_offset + t_read.address.line_count) > 419*1341Sstevel test->info.page_size / test->info.line_size)) { 420*1341Sstevel AC_ERR_SET(pkt, AC_ERR_MEM_TEST_PAR); 421*1341Sstevel retval = EINVAL; 422*1341Sstevel goto read_done; 423*1341Sstevel } 424*1341Sstevel 425*1341Sstevel page_offset = t_read.address.line_offset * test->info.line_size; 426*1341Sstevel page_pa = test->info.afar_base + 427*1341Sstevel t_read.address.page_num * test->info.page_size; 428*1341Sstevel dst_va = test->bufp + page_offset; 429*1341Sstevel src_va = test->va + page_offset; 430*1341Sstevel 431*1341Sstevel /* time to go quiet */ 432*1341Sstevel kpreempt_disable(); 433*1341Sstevel 434*1341Sstevel /* we need a va for the block instructions */ 435*1341Sstevel ac_mapin(page_pa, test->va); 436*1341Sstevel 437*1341Sstevel pstate_save = disable_vec_intr(); 438*1341Sstevel 439*1341Sstevel /* disable errors */ 440*1341Sstevel orig_err = get_error_enable(); 441*1341Sstevel set_error_enable(orig_err & ~(EER_CEEN | EER_NCEEN)); 442*1341Sstevel 443*1341Sstevel /* copy the data again (using our very special copy) */ 444*1341Sstevel ac_blkcopy(src_va, dst_va, t_read.address.line_count, 445*1341Sstevel test->info.line_size); 446*1341Sstevel 447*1341Sstevel /* process errors (if any) */ 448*1341Sstevel error_buf.module_id = CPU->cpu_id; 449*1341Sstevel get_asyncflt(&(error_buf.afsr)); 450*1341Sstevel get_asyncaddr(&(error_buf.afar)); 451*1341Sstevel get_udb_errors(&(error_buf.udbh_error_reg), 452*1341Sstevel &(error_buf.udbl_error_reg)); 453*1341Sstevel 454*1341Sstevel /* 455*1341Sstevel * clean up after our no-error copy but before enabling ints. 456*1341Sstevel * XXX what to do about other error types? 457*1341Sstevel */ 458*1341Sstevel if (error_buf.afsr & (P_AFSR_CE | P_AFSR_UE)) { 459*1341Sstevel extern void clr_datapath(void); /* XXX */ 460*1341Sstevel 461*1341Sstevel clr_datapath(); 462*1341Sstevel set_asyncflt(error_buf.afsr); 463*1341Sstevel retval = EIO; 464*1341Sstevel error_found = TRUE; 465*1341Sstevel } else { 466*1341Sstevel error_found = FALSE; 467*1341Sstevel } 468*1341Sstevel 469*1341Sstevel /* errors back on */ 470*1341Sstevel set_error_enable(orig_err); 471*1341Sstevel 472*1341Sstevel enable_vec_intr(pstate_save); 473*1341Sstevel 474*1341Sstevel /* tear down translation (who needs an mmu) */ 475*1341Sstevel ac_unmap(test->va); 476*1341Sstevel 477*1341Sstevel /* we're back! */ 478*1341Sstevel kpreempt_enable(); 479*1341Sstevel 480*1341Sstevel /* 481*1341Sstevel * If there was a data error, attempt to return the error_buf 482*1341Sstevel * to the user. 483*1341Sstevel */ 484*1341Sstevel if (error_found) { 485*1341Sstevel if (ddi_copyout(&error_buf, t_read.error_buf, 486*1341Sstevel sizeof (sunfire_processor_error_regs_t), flag) != 0) { 487*1341Sstevel retval = EFAULT; 488*1341Sstevel /* Keep going */ 489*1341Sstevel } 490*1341Sstevel } 491*1341Sstevel 492*1341Sstevel /* 493*1341Sstevel * Then, return the page to the user (always) 494*1341Sstevel */ 495*1341Sstevel if (ddi_copyout(dst_va, (caddr_t)(t_read.page_buf) + page_offset, 496*1341Sstevel t_read.address.line_count * test->info.line_size, flag) != 0) { 497*1341Sstevel retval = EFAULT; 498*1341Sstevel } 499*1341Sstevel 500*1341Sstevel read_done: 501*1341Sstevel atomic_add_32(&test->in_test, -1); 502*1341Sstevel return (retval); 503*1341Sstevel } 504*1341Sstevel 505*1341Sstevel int 506*1341Sstevel ac_mem_test_write(ac_cfga_pkt_t *pkt, int flag) 507*1341Sstevel { 508*1341Sstevel struct test_info *test; 509*1341Sstevel uint_t page_offset; 510*1341Sstevel uint64_t page_pa; 511*1341Sstevel uint_t pstate_save; 512*1341Sstevel caddr_t src_va, dst_va; 513*1341Sstevel int retval = DDI_SUCCESS; 514*1341Sstevel ac_mem_test_write_t t_write; 515*1341Sstevel 516*1341Sstevel #ifdef _MULTI_DATAMODEL 517*1341Sstevel switch (ddi_model_convert_from(flag & FMODELS)) { 518*1341Sstevel case DDI_MODEL_ILP32: { 519*1341Sstevel ac_mem_test_write32_t t_write32; 520*1341Sstevel 521*1341Sstevel if (ddi_copyin(pkt->cmd_cfga.private, &t_write32, 522*1341Sstevel sizeof (ac_mem_test_write32_t), flag) != 0) 523*1341Sstevel return (EFAULT); 524*1341Sstevel t_write.handle = t_write32.handle; 525*1341Sstevel t_write.page_buf = (void *)(uintptr_t)t_write32.page_buf; 526*1341Sstevel t_write.address = t_write32.address; 527*1341Sstevel break; 528*1341Sstevel } 529*1341Sstevel case DDI_MODEL_NONE: 530*1341Sstevel if (ddi_copyin(pkt->cmd_cfga.private, &t_write, 531*1341Sstevel sizeof (ac_mem_test_write_t), flag) != 0) 532*1341Sstevel return (EFAULT); 533*1341Sstevel break; 534*1341Sstevel } 535*1341Sstevel #else /* _MULTI_DATAMODEL */ 536*1341Sstevel if (ddi_copyin(pkt->cmd_cfga.private, &t_write, 537*1341Sstevel sizeof (ac_mem_test_write_t), flag) != 0) 538*1341Sstevel return (EFAULT); 539*1341Sstevel #endif /* _MULTI_DATAMODEL */ 540*1341Sstevel 541*1341Sstevel /* verify the handle */ 542*1341Sstevel mutex_enter(&test_mutex); 543*1341Sstevel for (test = test_base; test != NULL; test = test->next) { 544*1341Sstevel if (test->info.handle == t_write.handle) 545*1341Sstevel break; 546*1341Sstevel } 547*1341Sstevel if (test == NULL) { 548*1341Sstevel mutex_exit(&test_mutex); 549*1341Sstevel return (EINVAL); 550*1341Sstevel } 551*1341Sstevel 552*1341Sstevel /* bump the busy bit */ 553*1341Sstevel atomic_add_32(&test->in_test, 1); 554*1341Sstevel mutex_exit(&test_mutex); 555*1341Sstevel 556*1341Sstevel /* verify the remaining parameters */ 557*1341Sstevel if ((t_write.address.page_num >= 558*1341Sstevel test->info.bank_size / test->info.page_size) || 559*1341Sstevel (t_write.address.line_count == 0) || 560*1341Sstevel (t_write.address.line_count > 561*1341Sstevel test->info.page_size / test->info.line_size) || 562*1341Sstevel (t_write.address.line_offset >= 563*1341Sstevel test->info.page_size / test->info.line_size) || 564*1341Sstevel ((t_write.address.line_offset + t_write.address.line_count) > 565*1341Sstevel test->info.page_size / test->info.line_size)) { 566*1341Sstevel AC_ERR_SET(pkt, AC_ERR_MEM_TEST_PAR); 567*1341Sstevel retval = EINVAL; 568*1341Sstevel goto write_done; 569*1341Sstevel } 570*1341Sstevel 571*1341Sstevel page_offset = t_write.address.line_offset * test->info.line_size; 572*1341Sstevel page_pa = test->info.afar_base + 573*1341Sstevel t_write.address.page_num * test->info.page_size; 574*1341Sstevel src_va = test->bufp + page_offset; 575*1341Sstevel dst_va = test->va + page_offset; 576*1341Sstevel 577*1341Sstevel /* copy in the specified user data */ 578*1341Sstevel if (ddi_copyin((caddr_t)(t_write.page_buf) + page_offset, src_va, 579*1341Sstevel t_write.address.line_count * test->info.line_size, flag) != 0) { 580*1341Sstevel retval = EFAULT; 581*1341Sstevel goto write_done; 582*1341Sstevel } 583*1341Sstevel 584*1341Sstevel /* time to go quiet */ 585*1341Sstevel kpreempt_disable(); 586*1341Sstevel 587*1341Sstevel /* we need a va for the block instructions */ 588*1341Sstevel ac_mapin(page_pa, test->va); 589*1341Sstevel 590*1341Sstevel pstate_save = disable_vec_intr(); 591*1341Sstevel 592*1341Sstevel /* copy the data again (using our very special copy) */ 593*1341Sstevel ac_blkcopy(src_va, dst_va, t_write.address.line_count, 594*1341Sstevel test->info.line_size); 595*1341Sstevel 596*1341Sstevel enable_vec_intr(pstate_save); 597*1341Sstevel 598*1341Sstevel /* tear down translation (who needs an mmu) */ 599*1341Sstevel ac_unmap(test->va); 600*1341Sstevel 601*1341Sstevel /* we're back! */ 602*1341Sstevel kpreempt_enable(); 603*1341Sstevel 604*1341Sstevel write_done: 605*1341Sstevel atomic_add_32(&test->in_test, -1); 606*1341Sstevel return (retval); 607*1341Sstevel } 608