129949e86Sstevel /* 229949e86Sstevel * CDDL HEADER START 329949e86Sstevel * 429949e86Sstevel * The contents of this file are subject to the terms of the 529949e86Sstevel * Common Development and Distribution License (the "License"). 629949e86Sstevel * You may not use this file except in compliance with the License. 729949e86Sstevel * 829949e86Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 929949e86Sstevel * or http://www.opensolaris.org/os/licensing. 1029949e86Sstevel * See the License for the specific language governing permissions 1129949e86Sstevel * and limitations under the License. 1229949e86Sstevel * 1329949e86Sstevel * When distributing Covered Code, include this CDDL HEADER in each 1429949e86Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1529949e86Sstevel * If applicable, add the following below this CDDL HEADER, with the 1629949e86Sstevel * fields enclosed by brackets "[]" replaced with your own identifying 1729949e86Sstevel * information: Portions Copyright [yyyy] [name of copyright owner] 1829949e86Sstevel * 1929949e86Sstevel * CDDL HEADER END 2029949e86Sstevel */ 2129949e86Sstevel 2229949e86Sstevel /* 23*85f58038Sdp78419 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 2429949e86Sstevel * Use is subject to license terms. 2529949e86Sstevel */ 2629949e86Sstevel 2729949e86Sstevel #pragma ident "%Z%%M% %I% %E% SMI" 2829949e86Sstevel 2929949e86Sstevel #include <sys/types.h> 3029949e86Sstevel #include <sys/systm.h> 3129949e86Sstevel #include <sys/ddi.h> 3229949e86Sstevel #include <sys/sunddi.h> 3329949e86Sstevel #include <sys/ddi_impldefs.h> 3429949e86Sstevel #include <sys/obpdefs.h> 3529949e86Sstevel #include <sys/errno.h> 3629949e86Sstevel #include <sys/kmem.h> 3729949e86Sstevel #include <sys/vmem.h> 3829949e86Sstevel #include <sys/debug.h> 3929949e86Sstevel #include <sys/sysmacros.h> 4029949e86Sstevel #include <sys/machsystm.h> 4129949e86Sstevel #include <sys/machparam.h> 4229949e86Sstevel #include <sys/modctl.h> 4329949e86Sstevel #include <sys/fhc.h> 4429949e86Sstevel #include <sys/ac.h> 4529949e86Sstevel #include <sys/vm.h> 4629949e86Sstevel #include <sys/cpu_module.h> 4729949e86Sstevel #include <vm/seg_kmem.h> 4829949e86Sstevel #include <vm/hat_sfmmu.h> 4929949e86Sstevel #include <sys/mem_config.h> 5029949e86Sstevel #include <sys/mem_cage.h> 5129949e86Sstevel 5229949e86Sstevel /* 5329949e86Sstevel * Default to always clean memory on add to reduce chance 5429949e86Sstevel * of uncorrectable errors. 5529949e86Sstevel */ 5629949e86Sstevel int ac_add_clean = 1; 5729949e86Sstevel 5829949e86Sstevel #define ADD_PAGESIZE MMU_PAGESIZE 5929949e86Sstevel 6029949e86Sstevel ac_err_t 6129949e86Sstevel ac_kpm_err_cvt(int err) 6229949e86Sstevel { 6329949e86Sstevel switch (err) { 6429949e86Sstevel case KPHYSM_ESPAN: 6529949e86Sstevel return (AC_ERR_KPM_SPAN); 6629949e86Sstevel case KPHYSM_EFAULT: 6729949e86Sstevel return (AC_ERR_KPM_FAULT); 6829949e86Sstevel case KPHYSM_ERESOURCE: 6929949e86Sstevel return (AC_ERR_KPM_RESOURCE); 7029949e86Sstevel case KPHYSM_ENOTSUP: 7129949e86Sstevel return (AC_ERR_KPM_NOTSUP); 7229949e86Sstevel case KPHYSM_ENOHANDLES: 7329949e86Sstevel return (AC_ERR_KPM_NOHANDLES); 7429949e86Sstevel case KPHYSM_ENONRELOC: 7529949e86Sstevel return (AC_ERR_KPM_NONRELOC); 7629949e86Sstevel case KPHYSM_EHANDLE: 7729949e86Sstevel return (AC_ERR_KPM_HANDLE); 7829949e86Sstevel case KPHYSM_EBUSY: 7929949e86Sstevel return (AC_ERR_KPM_BUSY); 8029949e86Sstevel case KPHYSM_ENOTVIABLE: 8129949e86Sstevel return (AC_ERR_KPM_NOTVIABLE); 8229949e86Sstevel case KPHYSM_ESEQUENCE: 8329949e86Sstevel return (AC_ERR_KPM_SEQUENCE); 8429949e86Sstevel case KPHYSM_ENOWORK: 8529949e86Sstevel return (AC_ERR_KPM_NOWORK); 8629949e86Sstevel case KPHYSM_ECANCELLED: 8729949e86Sstevel return (AC_ERR_KPM_CANCELLED); 8829949e86Sstevel case KPHYSM_ENOTFINISHED: 8929949e86Sstevel return (AC_ERR_KPM_NOTFINISHED); 9029949e86Sstevel case KPHYSM_ENOTRUNNING: 9129949e86Sstevel return (AC_ERR_KPM_NOTRUNNING); 9229949e86Sstevel case KPHYSM_EREFUSED: 9329949e86Sstevel return (AC_ERR_KPM_REFUSED); 9429949e86Sstevel case KPHYSM_EDUP: 9529949e86Sstevel return (AC_ERR_KPM_DUP); 9629949e86Sstevel default: 9729949e86Sstevel return (AC_ERR_DEFAULT); 9829949e86Sstevel } 9929949e86Sstevel } 10029949e86Sstevel 10129949e86Sstevel static int 10229949e86Sstevel ac_add_bank(struct bd_list *add, ac_cfga_pkt_t *pkt) 10329949e86Sstevel { 10429949e86Sstevel uint64_t decode; 10529949e86Sstevel uint64_t base_pa; 10629949e86Sstevel uint64_t limit_pa; 10729949e86Sstevel uint64_t current_pa; 10829949e86Sstevel int errs; 10929949e86Sstevel uint64_t bank_size; 11029949e86Sstevel struct ac_mem_info *mem_info; 11129949e86Sstevel struct ac_soft_state *asp = pkt->softsp; 11229949e86Sstevel uint_t ilv; 11329949e86Sstevel 11429949e86Sstevel /* 11529949e86Sstevel * Cannot add interleaved banks at the moment. 11629949e86Sstevel */ 11729949e86Sstevel ilv = (pkt->bank == Bank0) ? 11829949e86Sstevel INTLV0(*asp->ac_memctl) : INTLV1(*asp->ac_memctl); 11929949e86Sstevel if (ilv != 1) { 12029949e86Sstevel AC_ERR_SET(pkt, AC_ERR_MEM_DEINTLV); 12129949e86Sstevel return (EINVAL); 12229949e86Sstevel } 12329949e86Sstevel /* 12429949e86Sstevel * Determine the physical location of the selected bank 12529949e86Sstevel */ 12629949e86Sstevel decode = (pkt->bank == Bank0) ? 12729949e86Sstevel *asp->ac_memdecode0 : *asp->ac_memdecode1; 12829949e86Sstevel base_pa = GRP_REALBASE(decode); 12929949e86Sstevel bank_size = GRP_UK2SPAN(decode); 13029949e86Sstevel limit_pa = base_pa + bank_size; 13129949e86Sstevel 13229949e86Sstevel mem_info = &asp->bank[pkt->bank]; 13329949e86Sstevel if (ac_add_clean || mem_info->condition != SYSC_CFGA_COND_OK) { 13429949e86Sstevel caddr_t base_va; 13529949e86Sstevel caddr_t fill_buf; 13629949e86Sstevel int linesize; 13729949e86Sstevel 13829949e86Sstevel /* 13929949e86Sstevel * We need a page_va and a fill buffer for this operation 14029949e86Sstevel */ 14129949e86Sstevel base_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP); 14229949e86Sstevel fill_buf = kmem_zalloc(ADD_PAGESIZE, KM_SLEEP); 14329949e86Sstevel linesize = cpunodes[CPU->cpu_id].ecache_linesize; 14429949e86Sstevel 14529949e86Sstevel /* 14629949e86Sstevel * zero fill the memory -- indirectly initializes the ECC 14729949e86Sstevel */ 14829949e86Sstevel kpreempt_disable(); 14929949e86Sstevel for (current_pa = base_pa; current_pa < limit_pa; 15029949e86Sstevel current_pa += ADD_PAGESIZE) { 15129949e86Sstevel 15229949e86Sstevel /* map current pa */ 15329949e86Sstevel ac_mapin(current_pa, base_va); 15429949e86Sstevel 15529949e86Sstevel /* fill the target page */ 15629949e86Sstevel ac_blkcopy(fill_buf, base_va, 15729949e86Sstevel ADD_PAGESIZE/linesize, linesize); 15829949e86Sstevel 15929949e86Sstevel /* tear down translation */ 16029949e86Sstevel ac_unmap(base_va); 16129949e86Sstevel } 16229949e86Sstevel kpreempt_enable(); 16329949e86Sstevel 16429949e86Sstevel /* 16529949e86Sstevel * clean up temporary resources 16629949e86Sstevel */ 16729949e86Sstevel kmem_free(fill_buf, ADD_PAGESIZE); 16829949e86Sstevel vmem_free(heap_arena, base_va, PAGESIZE); 16929949e86Sstevel } 17029949e86Sstevel 17129949e86Sstevel /* 17229949e86Sstevel * give the memory to Solaris 17329949e86Sstevel */ 17429949e86Sstevel errs = kphysm_add_memory_dynamic(base_pa >> PAGESHIFT, 17529949e86Sstevel bank_size >> PAGESHIFT); 17629949e86Sstevel 17729949e86Sstevel if (errs != KPHYSM_OK) { 17829949e86Sstevel AC_ERR_SET(pkt, ac_kpm_err_cvt(errs)); 17929949e86Sstevel return (EINVAL); 18029949e86Sstevel } 18129949e86Sstevel 18229949e86Sstevel /* 18329949e86Sstevel * Add the board to the cage growth list. 18429949e86Sstevel */ 185*85f58038Sdp78419 errs = kcage_range_add(btop(base_pa), btop(bank_size), KCAGE_DOWN); 18629949e86Sstevel /* TODO: deal with error return. */ 18729949e86Sstevel if (errs != 0) 18829949e86Sstevel cmn_err(CE_NOTE, "ac_add_bank(): board %d, bank %d, " 18929949e86Sstevel "kcage_range_add() returned %d", 19029949e86Sstevel add->sc.board, pkt->bank, errs); 19129949e86Sstevel 19229949e86Sstevel return (0); 19329949e86Sstevel } 19429949e86Sstevel 19529949e86Sstevel int 19629949e86Sstevel ac_add_memory(ac_cfga_pkt_t *pkt) 19729949e86Sstevel { 19829949e86Sstevel struct bd_list *board; 19929949e86Sstevel struct ac_mem_info *mem_info; 20029949e86Sstevel int force = pkt->cmd_cfga.force; 20129949e86Sstevel int retval; 20229949e86Sstevel 20329949e86Sstevel board = fhc_bdlist_lock(pkt->softsp->board); 20429949e86Sstevel if (board == NULL || board->ac_softsp == NULL) { 20529949e86Sstevel fhc_bdlist_unlock(); 20629949e86Sstevel AC_ERR_SET(pkt, AC_ERR_BD); 20729949e86Sstevel return (EINVAL); 20829949e86Sstevel } 20929949e86Sstevel ASSERT(pkt->softsp == board->ac_softsp); 21029949e86Sstevel 21129949e86Sstevel /* verify the board is of the correct type */ 21229949e86Sstevel switch (board->sc.type) { 21329949e86Sstevel case CPU_BOARD: 21429949e86Sstevel case MEM_BOARD: 21529949e86Sstevel break; 21629949e86Sstevel default: 21729949e86Sstevel fhc_bdlist_unlock(); 21829949e86Sstevel AC_ERR_SET(pkt, AC_ERR_BD_TYPE); 21929949e86Sstevel return (EINVAL); 22029949e86Sstevel } 22129949e86Sstevel 22229949e86Sstevel /* verify the memory condition is acceptable */ 22329949e86Sstevel mem_info = &pkt->softsp->bank[pkt->bank]; 22429949e86Sstevel if (!MEM_BOARD_VISIBLE(board) || mem_info->busy || 22529949e86Sstevel fhc_bd_busy(pkt->softsp->board) || 22629949e86Sstevel mem_info->rstate != SYSC_CFGA_RSTATE_CONNECTED || 22729949e86Sstevel mem_info->ostate != SYSC_CFGA_OSTATE_UNCONFIGURED || 22829949e86Sstevel (!force && mem_info->condition != SYSC_CFGA_COND_OK)) { 22929949e86Sstevel fhc_bdlist_unlock(); 23029949e86Sstevel AC_ERR_SET(pkt, AC_ERR_BD_STATE); 23129949e86Sstevel return (EINVAL); 23229949e86Sstevel } 23329949e86Sstevel 23429949e86Sstevel /* 23529949e86Sstevel * at this point, we have an available bank to add. 23629949e86Sstevel * mark it busy and initiate the add function. 23729949e86Sstevel */ 23829949e86Sstevel mem_info->busy = TRUE; 23929949e86Sstevel fhc_bdlist_unlock(); 24029949e86Sstevel 24129949e86Sstevel retval = ac_add_bank(board, pkt); 24229949e86Sstevel 24329949e86Sstevel /* 24429949e86Sstevel * We made it! Update the status and get out of here. 24529949e86Sstevel */ 24629949e86Sstevel (void) fhc_bdlist_lock(-1); 24729949e86Sstevel mem_info->busy = FALSE; 24829949e86Sstevel if (retval == 0) { 24929949e86Sstevel mem_info->ostate = SYSC_CFGA_OSTATE_CONFIGURED; 25029949e86Sstevel mem_info->status_change = ddi_get_time(); 25129949e86Sstevel } 25229949e86Sstevel 25329949e86Sstevel fhc_bdlist_unlock(); 25429949e86Sstevel 25529949e86Sstevel if (retval != 0) { 25629949e86Sstevel return (retval); 25729949e86Sstevel } 25829949e86Sstevel return (DDI_SUCCESS); 25929949e86Sstevel } 260