29949e866e40b95795203f3ee46f44a197c946e4stevel/*
29949e866e40b95795203f3ee46f44a197c946e4stevel * CDDL HEADER START
29949e866e40b95795203f3ee46f44a197c946e4stevel *
29949e866e40b95795203f3ee46f44a197c946e4stevel * The contents of this file are subject to the terms of the
29949e866e40b95795203f3ee46f44a197c946e4stevel * Common Development and Distribution License (the "License").
29949e866e40b95795203f3ee46f44a197c946e4stevel * You may not use this file except in compliance with the License.
29949e866e40b95795203f3ee46f44a197c946e4stevel *
29949e866e40b95795203f3ee46f44a197c946e4stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
29949e866e40b95795203f3ee46f44a197c946e4stevel * or http://www.opensolaris.org/os/licensing.
29949e866e40b95795203f3ee46f44a197c946e4stevel * See the License for the specific language governing permissions
29949e866e40b95795203f3ee46f44a197c946e4stevel * and limitations under the License.
29949e866e40b95795203f3ee46f44a197c946e4stevel *
29949e866e40b95795203f3ee46f44a197c946e4stevel * When distributing Covered Code, include this CDDL HEADER in each
29949e866e40b95795203f3ee46f44a197c946e4stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
29949e866e40b95795203f3ee46f44a197c946e4stevel * If applicable, add the following below this CDDL HEADER, with the
29949e866e40b95795203f3ee46f44a197c946e4stevel * fields enclosed by brackets "[]" replaced with your own identifying
29949e866e40b95795203f3ee46f44a197c946e4stevel * information: Portions Copyright [yyyy] [name of copyright owner]
29949e866e40b95795203f3ee46f44a197c946e4stevel *
29949e866e40b95795203f3ee46f44a197c946e4stevel * CDDL HEADER END
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel/*
85f5803819bea86c07827a9544494e4ad327d95ddp * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
29949e866e40b95795203f3ee46f44a197c946e4stevel * Use is subject to license terms.
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel#pragma ident "%Z%%M% %I% %E% SMI"
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/types.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/systm.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/ddi.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/sunddi.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/ddi_impldefs.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/obpdefs.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/errno.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/kmem.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/vmem.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/debug.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/sysmacros.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/machsystm.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/machparam.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/modctl.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/fhc.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/ac.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/vm.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/cpu_module.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <vm/seg_kmem.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <vm/hat_sfmmu.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/mem_config.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel#include <sys/mem_cage.h>
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel/*
29949e866e40b95795203f3ee46f44a197c946e4stevel * Default to always clean memory on add to reduce chance
29949e866e40b95795203f3ee46f44a197c946e4stevel * of uncorrectable errors.
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevelint ac_add_clean = 1;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel#define ADD_PAGESIZE MMU_PAGESIZE
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelac_err_t
29949e866e40b95795203f3ee46f44a197c946e4stevelac_kpm_err_cvt(int err)
29949e866e40b95795203f3ee46f44a197c946e4stevel{
29949e866e40b95795203f3ee46f44a197c946e4stevel switch (err) {
29949e866e40b95795203f3ee46f44a197c946e4stevel case KPHYSM_ESPAN:
29949e866e40b95795203f3ee46f44a197c946e4stevel return (AC_ERR_KPM_SPAN);
29949e866e40b95795203f3ee46f44a197c946e4stevel case KPHYSM_EFAULT:
29949e866e40b95795203f3ee46f44a197c946e4stevel return (AC_ERR_KPM_FAULT);
29949e866e40b95795203f3ee46f44a197c946e4stevel case KPHYSM_ERESOURCE:
29949e866e40b95795203f3ee46f44a197c946e4stevel return (AC_ERR_KPM_RESOURCE);
29949e866e40b95795203f3ee46f44a197c946e4stevel case KPHYSM_ENOTSUP:
29949e866e40b95795203f3ee46f44a197c946e4stevel return (AC_ERR_KPM_NOTSUP);
29949e866e40b95795203f3ee46f44a197c946e4stevel case KPHYSM_ENOHANDLES:
29949e866e40b95795203f3ee46f44a197c946e4stevel return (AC_ERR_KPM_NOHANDLES);
29949e866e40b95795203f3ee46f44a197c946e4stevel case KPHYSM_ENONRELOC:
29949e866e40b95795203f3ee46f44a197c946e4stevel return (AC_ERR_KPM_NONRELOC);
29949e866e40b95795203f3ee46f44a197c946e4stevel case KPHYSM_EHANDLE:
29949e866e40b95795203f3ee46f44a197c946e4stevel return (AC_ERR_KPM_HANDLE);
29949e866e40b95795203f3ee46f44a197c946e4stevel case KPHYSM_EBUSY:
29949e866e40b95795203f3ee46f44a197c946e4stevel return (AC_ERR_KPM_BUSY);
29949e866e40b95795203f3ee46f44a197c946e4stevel case KPHYSM_ENOTVIABLE:
29949e866e40b95795203f3ee46f44a197c946e4stevel return (AC_ERR_KPM_NOTVIABLE);
29949e866e40b95795203f3ee46f44a197c946e4stevel case KPHYSM_ESEQUENCE:
29949e866e40b95795203f3ee46f44a197c946e4stevel return (AC_ERR_KPM_SEQUENCE);
29949e866e40b95795203f3ee46f44a197c946e4stevel case KPHYSM_ENOWORK:
29949e866e40b95795203f3ee46f44a197c946e4stevel return (AC_ERR_KPM_NOWORK);
29949e866e40b95795203f3ee46f44a197c946e4stevel case KPHYSM_ECANCELLED:
29949e866e40b95795203f3ee46f44a197c946e4stevel return (AC_ERR_KPM_CANCELLED);
29949e866e40b95795203f3ee46f44a197c946e4stevel case KPHYSM_ENOTFINISHED:
29949e866e40b95795203f3ee46f44a197c946e4stevel return (AC_ERR_KPM_NOTFINISHED);
29949e866e40b95795203f3ee46f44a197c946e4stevel case KPHYSM_ENOTRUNNING:
29949e866e40b95795203f3ee46f44a197c946e4stevel return (AC_ERR_KPM_NOTRUNNING);
29949e866e40b95795203f3ee46f44a197c946e4stevel case KPHYSM_EREFUSED:
29949e866e40b95795203f3ee46f44a197c946e4stevel return (AC_ERR_KPM_REFUSED);
29949e866e40b95795203f3ee46f44a197c946e4stevel case KPHYSM_EDUP:
29949e866e40b95795203f3ee46f44a197c946e4stevel return (AC_ERR_KPM_DUP);
29949e866e40b95795203f3ee46f44a197c946e4stevel default:
29949e866e40b95795203f3ee46f44a197c946e4stevel return (AC_ERR_DEFAULT);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel}
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelstatic int
29949e866e40b95795203f3ee46f44a197c946e4stevelac_add_bank(struct bd_list *add, ac_cfga_pkt_t *pkt)
29949e866e40b95795203f3ee46f44a197c946e4stevel{
29949e866e40b95795203f3ee46f44a197c946e4stevel uint64_t decode;
29949e866e40b95795203f3ee46f44a197c946e4stevel uint64_t base_pa;
29949e866e40b95795203f3ee46f44a197c946e4stevel uint64_t limit_pa;
29949e866e40b95795203f3ee46f44a197c946e4stevel uint64_t current_pa;
29949e866e40b95795203f3ee46f44a197c946e4stevel int errs;
29949e866e40b95795203f3ee46f44a197c946e4stevel uint64_t bank_size;
29949e866e40b95795203f3ee46f44a197c946e4stevel struct ac_mem_info *mem_info;
29949e866e40b95795203f3ee46f44a197c946e4stevel struct ac_soft_state *asp = pkt->softsp;
29949e866e40b95795203f3ee46f44a197c946e4stevel uint_t ilv;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * Cannot add interleaved banks at the moment.
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel ilv = (pkt->bank == Bank0) ?
29949e866e40b95795203f3ee46f44a197c946e4stevel INTLV0(*asp->ac_memctl) : INTLV1(*asp->ac_memctl);
29949e866e40b95795203f3ee46f44a197c946e4stevel if (ilv != 1) {
29949e866e40b95795203f3ee46f44a197c946e4stevel AC_ERR_SET(pkt, AC_ERR_MEM_DEINTLV);
29949e866e40b95795203f3ee46f44a197c946e4stevel return (EINVAL);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * Determine the physical location of the selected bank
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel decode = (pkt->bank == Bank0) ?
29949e866e40b95795203f3ee46f44a197c946e4stevel *asp->ac_memdecode0 : *asp->ac_memdecode1;
29949e866e40b95795203f3ee46f44a197c946e4stevel base_pa = GRP_REALBASE(decode);
29949e866e40b95795203f3ee46f44a197c946e4stevel bank_size = GRP_UK2SPAN(decode);
29949e866e40b95795203f3ee46f44a197c946e4stevel limit_pa = base_pa + bank_size;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel mem_info = &asp->bank[pkt->bank];
29949e866e40b95795203f3ee46f44a197c946e4stevel if (ac_add_clean || mem_info->condition != SYSC_CFGA_COND_OK) {
29949e866e40b95795203f3ee46f44a197c946e4stevel caddr_t base_va;
29949e866e40b95795203f3ee46f44a197c946e4stevel caddr_t fill_buf;
29949e866e40b95795203f3ee46f44a197c946e4stevel int linesize;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * We need a page_va and a fill buffer for this operation
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel base_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
29949e866e40b95795203f3ee46f44a197c946e4stevel fill_buf = kmem_zalloc(ADD_PAGESIZE, KM_SLEEP);
29949e866e40b95795203f3ee46f44a197c946e4stevel linesize = cpunodes[CPU->cpu_id].ecache_linesize;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * zero fill the memory -- indirectly initializes the ECC
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel kpreempt_disable();
29949e866e40b95795203f3ee46f44a197c946e4stevel for (current_pa = base_pa; current_pa < limit_pa;
29949e866e40b95795203f3ee46f44a197c946e4stevel current_pa += ADD_PAGESIZE) {
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* map current pa */
29949e866e40b95795203f3ee46f44a197c946e4stevel ac_mapin(current_pa, base_va);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* fill the target page */
29949e866e40b95795203f3ee46f44a197c946e4stevel ac_blkcopy(fill_buf, base_va,
29949e866e40b95795203f3ee46f44a197c946e4stevel ADD_PAGESIZE/linesize, linesize);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* tear down translation */
29949e866e40b95795203f3ee46f44a197c946e4stevel ac_unmap(base_va);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel kpreempt_enable();
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * clean up temporary resources
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel kmem_free(fill_buf, ADD_PAGESIZE);
29949e866e40b95795203f3ee46f44a197c946e4stevel vmem_free(heap_arena, base_va, PAGESIZE);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * give the memory to Solaris
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel errs = kphysm_add_memory_dynamic(base_pa >> PAGESHIFT,
29949e866e40b95795203f3ee46f44a197c946e4stevel bank_size >> PAGESHIFT);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel if (errs != KPHYSM_OK) {
29949e866e40b95795203f3ee46f44a197c946e4stevel AC_ERR_SET(pkt, ac_kpm_err_cvt(errs));
29949e866e40b95795203f3ee46f44a197c946e4stevel return (EINVAL);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * Add the board to the cage growth list.
29949e866e40b95795203f3ee46f44a197c946e4stevel */
85f5803819bea86c07827a9544494e4ad327d95ddp errs = kcage_range_add(btop(base_pa), btop(bank_size), KCAGE_DOWN);
29949e866e40b95795203f3ee46f44a197c946e4stevel /* TODO: deal with error return. */
29949e866e40b95795203f3ee46f44a197c946e4stevel if (errs != 0)
29949e866e40b95795203f3ee46f44a197c946e4stevel cmn_err(CE_NOTE, "ac_add_bank(): board %d, bank %d, "
29949e866e40b95795203f3ee46f44a197c946e4stevel "kcage_range_add() returned %d",
29949e866e40b95795203f3ee46f44a197c946e4stevel add->sc.board, pkt->bank, errs);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel return (0);
29949e866e40b95795203f3ee46f44a197c946e4stevel}
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevelint
29949e866e40b95795203f3ee46f44a197c946e4stevelac_add_memory(ac_cfga_pkt_t *pkt)
29949e866e40b95795203f3ee46f44a197c946e4stevel{
29949e866e40b95795203f3ee46f44a197c946e4stevel struct bd_list *board;
29949e866e40b95795203f3ee46f44a197c946e4stevel struct ac_mem_info *mem_info;
29949e866e40b95795203f3ee46f44a197c946e4stevel int force = pkt->cmd_cfga.force;
29949e866e40b95795203f3ee46f44a197c946e4stevel int retval;
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel board = fhc_bdlist_lock(pkt->softsp->board);
29949e866e40b95795203f3ee46f44a197c946e4stevel if (board == NULL || board->ac_softsp == NULL) {
29949e866e40b95795203f3ee46f44a197c946e4stevel fhc_bdlist_unlock();
29949e866e40b95795203f3ee46f44a197c946e4stevel AC_ERR_SET(pkt, AC_ERR_BD);
29949e866e40b95795203f3ee46f44a197c946e4stevel return (EINVAL);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel ASSERT(pkt->softsp == board->ac_softsp);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* verify the board is of the correct type */
29949e866e40b95795203f3ee46f44a197c946e4stevel switch (board->sc.type) {
29949e866e40b95795203f3ee46f44a197c946e4stevel case CPU_BOARD:
29949e866e40b95795203f3ee46f44a197c946e4stevel case MEM_BOARD:
29949e866e40b95795203f3ee46f44a197c946e4stevel break;
29949e866e40b95795203f3ee46f44a197c946e4stevel default:
29949e866e40b95795203f3ee46f44a197c946e4stevel fhc_bdlist_unlock();
29949e866e40b95795203f3ee46f44a197c946e4stevel AC_ERR_SET(pkt, AC_ERR_BD_TYPE);
29949e866e40b95795203f3ee46f44a197c946e4stevel return (EINVAL);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /* verify the memory condition is acceptable */
29949e866e40b95795203f3ee46f44a197c946e4stevel mem_info = &pkt->softsp->bank[pkt->bank];
29949e866e40b95795203f3ee46f44a197c946e4stevel if (!MEM_BOARD_VISIBLE(board) || mem_info->busy ||
29949e866e40b95795203f3ee46f44a197c946e4stevel fhc_bd_busy(pkt->softsp->board) ||
29949e866e40b95795203f3ee46f44a197c946e4stevel mem_info->rstate != SYSC_CFGA_RSTATE_CONNECTED ||
29949e866e40b95795203f3ee46f44a197c946e4stevel mem_info->ostate != SYSC_CFGA_OSTATE_UNCONFIGURED ||
29949e866e40b95795203f3ee46f44a197c946e4stevel (!force && mem_info->condition != SYSC_CFGA_COND_OK)) {
29949e866e40b95795203f3ee46f44a197c946e4stevel fhc_bdlist_unlock();
29949e866e40b95795203f3ee46f44a197c946e4stevel AC_ERR_SET(pkt, AC_ERR_BD_STATE);
29949e866e40b95795203f3ee46f44a197c946e4stevel return (EINVAL);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * at this point, we have an available bank to add.
29949e866e40b95795203f3ee46f44a197c946e4stevel * mark it busy and initiate the add function.
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel mem_info->busy = TRUE;
29949e866e40b95795203f3ee46f44a197c946e4stevel fhc_bdlist_unlock();
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel retval = ac_add_bank(board, pkt);
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel /*
29949e866e40b95795203f3ee46f44a197c946e4stevel * We made it! Update the status and get out of here.
29949e866e40b95795203f3ee46f44a197c946e4stevel */
29949e866e40b95795203f3ee46f44a197c946e4stevel (void) fhc_bdlist_lock(-1);
29949e866e40b95795203f3ee46f44a197c946e4stevel mem_info->busy = FALSE;
29949e866e40b95795203f3ee46f44a197c946e4stevel if (retval == 0) {
29949e866e40b95795203f3ee46f44a197c946e4stevel mem_info->ostate = SYSC_CFGA_OSTATE_CONFIGURED;
29949e866e40b95795203f3ee46f44a197c946e4stevel mem_info->status_change = ddi_get_time();
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel fhc_bdlist_unlock();
29949e866e40b95795203f3ee46f44a197c946e4stevel
29949e866e40b95795203f3ee46f44a197c946e4stevel if (retval != 0) {
29949e866e40b95795203f3ee46f44a197c946e4stevel return (retval);
29949e866e40b95795203f3ee46f44a197c946e4stevel }
29949e866e40b95795203f3ee46f44a197c946e4stevel return (DDI_SUCCESS);
29949e866e40b95795203f3ee46f44a197c946e4stevel}