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
ac_kpm_err_cvt(int err)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
ac_add_bank(struct bd_list * add,ac_cfga_pkt_t * pkt)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
ac_add_memory(ac_cfga_pkt_t * pkt)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