1*29949e86Sstevel /* 2*29949e86Sstevel * CDDL HEADER START 3*29949e86Sstevel * 4*29949e86Sstevel * The contents of this file are subject to the terms of the 5*29949e86Sstevel * Common Development and Distribution License (the "License"). 6*29949e86Sstevel * You may not use this file except in compliance with the License. 7*29949e86Sstevel * 8*29949e86Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*29949e86Sstevel * or http://www.opensolaris.org/os/licensing. 10*29949e86Sstevel * See the License for the specific language governing permissions 11*29949e86Sstevel * and limitations under the License. 12*29949e86Sstevel * 13*29949e86Sstevel * When distributing Covered Code, include this CDDL HEADER in each 14*29949e86Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*29949e86Sstevel * If applicable, add the following below this CDDL HEADER, with the 16*29949e86Sstevel * fields enclosed by brackets "[]" replaced with your own identifying 17*29949e86Sstevel * information: Portions Copyright [yyyy] [name of copyright owner] 18*29949e86Sstevel * 19*29949e86Sstevel * CDDL HEADER END 20*29949e86Sstevel */ 21*29949e86Sstevel 22*29949e86Sstevel /* 23*29949e86Sstevel * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*29949e86Sstevel * Use is subject to license terms. 25*29949e86Sstevel */ 26*29949e86Sstevel 27*29949e86Sstevel #pragma ident "%Z%%M% %I% %E% SMI" 28*29949e86Sstevel 29*29949e86Sstevel #include <sys/types.h> 30*29949e86Sstevel #include <sys/systm.h> 31*29949e86Sstevel #include <sys/ddi.h> 32*29949e86Sstevel #include <sys/sunddi.h> 33*29949e86Sstevel #include <sys/ddi_impldefs.h> 34*29949e86Sstevel #include <sys/obpdefs.h> 35*29949e86Sstevel #include <sys/errno.h> 36*29949e86Sstevel #include <sys/kmem.h> 37*29949e86Sstevel #include <sys/vmem.h> 38*29949e86Sstevel #include <sys/debug.h> 39*29949e86Sstevel #include <sys/sysmacros.h> 40*29949e86Sstevel #include <sys/machsystm.h> 41*29949e86Sstevel #include <sys/machparam.h> 42*29949e86Sstevel #include <sys/modctl.h> 43*29949e86Sstevel #include <sys/fhc.h> 44*29949e86Sstevel #include <sys/ac.h> 45*29949e86Sstevel #include <sys/vm.h> 46*29949e86Sstevel #include <sys/cpu_module.h> 47*29949e86Sstevel #include <vm/seg_kmem.h> 48*29949e86Sstevel #include <vm/hat_sfmmu.h> 49*29949e86Sstevel #include <sys/mem_config.h> 50*29949e86Sstevel #include <sys/mem_cage.h> 51*29949e86Sstevel 52*29949e86Sstevel /* 53*29949e86Sstevel * Default to always clean memory on add to reduce chance 54*29949e86Sstevel * of uncorrectable errors. 55*29949e86Sstevel */ 56*29949e86Sstevel int ac_add_clean = 1; 57*29949e86Sstevel 58*29949e86Sstevel #define ADD_PAGESIZE MMU_PAGESIZE 59*29949e86Sstevel 60*29949e86Sstevel ac_err_t 61*29949e86Sstevel ac_kpm_err_cvt(int err) 62*29949e86Sstevel { 63*29949e86Sstevel switch (err) { 64*29949e86Sstevel case KPHYSM_ESPAN: 65*29949e86Sstevel return (AC_ERR_KPM_SPAN); 66*29949e86Sstevel case KPHYSM_EFAULT: 67*29949e86Sstevel return (AC_ERR_KPM_FAULT); 68*29949e86Sstevel case KPHYSM_ERESOURCE: 69*29949e86Sstevel return (AC_ERR_KPM_RESOURCE); 70*29949e86Sstevel case KPHYSM_ENOTSUP: 71*29949e86Sstevel return (AC_ERR_KPM_NOTSUP); 72*29949e86Sstevel case KPHYSM_ENOHANDLES: 73*29949e86Sstevel return (AC_ERR_KPM_NOHANDLES); 74*29949e86Sstevel case KPHYSM_ENONRELOC: 75*29949e86Sstevel return (AC_ERR_KPM_NONRELOC); 76*29949e86Sstevel case KPHYSM_EHANDLE: 77*29949e86Sstevel return (AC_ERR_KPM_HANDLE); 78*29949e86Sstevel case KPHYSM_EBUSY: 79*29949e86Sstevel return (AC_ERR_KPM_BUSY); 80*29949e86Sstevel case KPHYSM_ENOTVIABLE: 81*29949e86Sstevel return (AC_ERR_KPM_NOTVIABLE); 82*29949e86Sstevel case KPHYSM_ESEQUENCE: 83*29949e86Sstevel return (AC_ERR_KPM_SEQUENCE); 84*29949e86Sstevel case KPHYSM_ENOWORK: 85*29949e86Sstevel return (AC_ERR_KPM_NOWORK); 86*29949e86Sstevel case KPHYSM_ECANCELLED: 87*29949e86Sstevel return (AC_ERR_KPM_CANCELLED); 88*29949e86Sstevel case KPHYSM_ENOTFINISHED: 89*29949e86Sstevel return (AC_ERR_KPM_NOTFINISHED); 90*29949e86Sstevel case KPHYSM_ENOTRUNNING: 91*29949e86Sstevel return (AC_ERR_KPM_NOTRUNNING); 92*29949e86Sstevel case KPHYSM_EREFUSED: 93*29949e86Sstevel return (AC_ERR_KPM_REFUSED); 94*29949e86Sstevel case KPHYSM_EDUP: 95*29949e86Sstevel return (AC_ERR_KPM_DUP); 96*29949e86Sstevel default: 97*29949e86Sstevel return (AC_ERR_DEFAULT); 98*29949e86Sstevel } 99*29949e86Sstevel } 100*29949e86Sstevel 101*29949e86Sstevel static int 102*29949e86Sstevel ac_add_bank(struct bd_list *add, ac_cfga_pkt_t *pkt) 103*29949e86Sstevel { 104*29949e86Sstevel uint64_t decode; 105*29949e86Sstevel uint64_t base_pa; 106*29949e86Sstevel uint64_t limit_pa; 107*29949e86Sstevel uint64_t current_pa; 108*29949e86Sstevel int errs; 109*29949e86Sstevel uint64_t bank_size; 110*29949e86Sstevel struct ac_mem_info *mem_info; 111*29949e86Sstevel struct ac_soft_state *asp = pkt->softsp; 112*29949e86Sstevel uint_t ilv; 113*29949e86Sstevel 114*29949e86Sstevel /* 115*29949e86Sstevel * Cannot add interleaved banks at the moment. 116*29949e86Sstevel */ 117*29949e86Sstevel ilv = (pkt->bank == Bank0) ? 118*29949e86Sstevel INTLV0(*asp->ac_memctl) : INTLV1(*asp->ac_memctl); 119*29949e86Sstevel if (ilv != 1) { 120*29949e86Sstevel AC_ERR_SET(pkt, AC_ERR_MEM_DEINTLV); 121*29949e86Sstevel return (EINVAL); 122*29949e86Sstevel } 123*29949e86Sstevel /* 124*29949e86Sstevel * Determine the physical location of the selected bank 125*29949e86Sstevel */ 126*29949e86Sstevel decode = (pkt->bank == Bank0) ? 127*29949e86Sstevel *asp->ac_memdecode0 : *asp->ac_memdecode1; 128*29949e86Sstevel base_pa = GRP_REALBASE(decode); 129*29949e86Sstevel bank_size = GRP_UK2SPAN(decode); 130*29949e86Sstevel limit_pa = base_pa + bank_size; 131*29949e86Sstevel 132*29949e86Sstevel mem_info = &asp->bank[pkt->bank]; 133*29949e86Sstevel if (ac_add_clean || mem_info->condition != SYSC_CFGA_COND_OK) { 134*29949e86Sstevel caddr_t base_va; 135*29949e86Sstevel caddr_t fill_buf; 136*29949e86Sstevel int linesize; 137*29949e86Sstevel 138*29949e86Sstevel /* 139*29949e86Sstevel * We need a page_va and a fill buffer for this operation 140*29949e86Sstevel */ 141*29949e86Sstevel base_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP); 142*29949e86Sstevel fill_buf = kmem_zalloc(ADD_PAGESIZE, KM_SLEEP); 143*29949e86Sstevel linesize = cpunodes[CPU->cpu_id].ecache_linesize; 144*29949e86Sstevel 145*29949e86Sstevel /* 146*29949e86Sstevel * zero fill the memory -- indirectly initializes the ECC 147*29949e86Sstevel */ 148*29949e86Sstevel kpreempt_disable(); 149*29949e86Sstevel for (current_pa = base_pa; current_pa < limit_pa; 150*29949e86Sstevel current_pa += ADD_PAGESIZE) { 151*29949e86Sstevel 152*29949e86Sstevel /* map current pa */ 153*29949e86Sstevel ac_mapin(current_pa, base_va); 154*29949e86Sstevel 155*29949e86Sstevel /* fill the target page */ 156*29949e86Sstevel ac_blkcopy(fill_buf, base_va, 157*29949e86Sstevel ADD_PAGESIZE/linesize, linesize); 158*29949e86Sstevel 159*29949e86Sstevel /* tear down translation */ 160*29949e86Sstevel ac_unmap(base_va); 161*29949e86Sstevel } 162*29949e86Sstevel kpreempt_enable(); 163*29949e86Sstevel 164*29949e86Sstevel /* 165*29949e86Sstevel * clean up temporary resources 166*29949e86Sstevel */ 167*29949e86Sstevel kmem_free(fill_buf, ADD_PAGESIZE); 168*29949e86Sstevel vmem_free(heap_arena, base_va, PAGESIZE); 169*29949e86Sstevel } 170*29949e86Sstevel 171*29949e86Sstevel /* 172*29949e86Sstevel * give the memory to Solaris 173*29949e86Sstevel */ 174*29949e86Sstevel errs = kphysm_add_memory_dynamic(base_pa >> PAGESHIFT, 175*29949e86Sstevel bank_size >> PAGESHIFT); 176*29949e86Sstevel 177*29949e86Sstevel if (errs != KPHYSM_OK) { 178*29949e86Sstevel AC_ERR_SET(pkt, ac_kpm_err_cvt(errs)); 179*29949e86Sstevel return (EINVAL); 180*29949e86Sstevel } 181*29949e86Sstevel 182*29949e86Sstevel /* 183*29949e86Sstevel * Add the board to the cage growth list. 184*29949e86Sstevel */ 185*29949e86Sstevel kcage_range_lock(); 186*29949e86Sstevel errs = kcage_range_add(base_pa >> PAGESHIFT, bank_size >> PAGESHIFT, 1); 187*29949e86Sstevel /* TODO: deal with error return. */ 188*29949e86Sstevel if (errs != 0) 189*29949e86Sstevel cmn_err(CE_NOTE, "ac_add_bank(): board %d, bank %d, " 190*29949e86Sstevel "kcage_range_add() returned %d", 191*29949e86Sstevel add->sc.board, pkt->bank, errs); 192*29949e86Sstevel kcage_range_unlock(); 193*29949e86Sstevel 194*29949e86Sstevel return (0); 195*29949e86Sstevel } 196*29949e86Sstevel 197*29949e86Sstevel int 198*29949e86Sstevel ac_add_memory(ac_cfga_pkt_t *pkt) 199*29949e86Sstevel { 200*29949e86Sstevel struct bd_list *board; 201*29949e86Sstevel struct ac_mem_info *mem_info; 202*29949e86Sstevel int force = pkt->cmd_cfga.force; 203*29949e86Sstevel int retval; 204*29949e86Sstevel 205*29949e86Sstevel board = fhc_bdlist_lock(pkt->softsp->board); 206*29949e86Sstevel if (board == NULL || board->ac_softsp == NULL) { 207*29949e86Sstevel fhc_bdlist_unlock(); 208*29949e86Sstevel AC_ERR_SET(pkt, AC_ERR_BD); 209*29949e86Sstevel return (EINVAL); 210*29949e86Sstevel } 211*29949e86Sstevel ASSERT(pkt->softsp == board->ac_softsp); 212*29949e86Sstevel 213*29949e86Sstevel /* verify the board is of the correct type */ 214*29949e86Sstevel switch (board->sc.type) { 215*29949e86Sstevel case CPU_BOARD: 216*29949e86Sstevel case MEM_BOARD: 217*29949e86Sstevel break; 218*29949e86Sstevel default: 219*29949e86Sstevel fhc_bdlist_unlock(); 220*29949e86Sstevel AC_ERR_SET(pkt, AC_ERR_BD_TYPE); 221*29949e86Sstevel return (EINVAL); 222*29949e86Sstevel } 223*29949e86Sstevel 224*29949e86Sstevel /* verify the memory condition is acceptable */ 225*29949e86Sstevel mem_info = &pkt->softsp->bank[pkt->bank]; 226*29949e86Sstevel if (!MEM_BOARD_VISIBLE(board) || mem_info->busy || 227*29949e86Sstevel fhc_bd_busy(pkt->softsp->board) || 228*29949e86Sstevel mem_info->rstate != SYSC_CFGA_RSTATE_CONNECTED || 229*29949e86Sstevel mem_info->ostate != SYSC_CFGA_OSTATE_UNCONFIGURED || 230*29949e86Sstevel (!force && mem_info->condition != SYSC_CFGA_COND_OK)) { 231*29949e86Sstevel fhc_bdlist_unlock(); 232*29949e86Sstevel AC_ERR_SET(pkt, AC_ERR_BD_STATE); 233*29949e86Sstevel return (EINVAL); 234*29949e86Sstevel } 235*29949e86Sstevel 236*29949e86Sstevel /* 237*29949e86Sstevel * at this point, we have an available bank to add. 238*29949e86Sstevel * mark it busy and initiate the add function. 239*29949e86Sstevel */ 240*29949e86Sstevel mem_info->busy = TRUE; 241*29949e86Sstevel fhc_bdlist_unlock(); 242*29949e86Sstevel 243*29949e86Sstevel retval = ac_add_bank(board, pkt); 244*29949e86Sstevel 245*29949e86Sstevel /* 246*29949e86Sstevel * We made it! Update the status and get out of here. 247*29949e86Sstevel */ 248*29949e86Sstevel (void) fhc_bdlist_lock(-1); 249*29949e86Sstevel mem_info->busy = FALSE; 250*29949e86Sstevel if (retval == 0) { 251*29949e86Sstevel mem_info->ostate = SYSC_CFGA_OSTATE_CONFIGURED; 252*29949e86Sstevel mem_info->status_change = ddi_get_time(); 253*29949e86Sstevel } 254*29949e86Sstevel 255*29949e86Sstevel fhc_bdlist_unlock(); 256*29949e86Sstevel 257*29949e86Sstevel if (retval != 0) { 258*29949e86Sstevel return (retval); 259*29949e86Sstevel } 260*29949e86Sstevel return (DDI_SUCCESS); 261*29949e86Sstevel } 262