xref: /onnv-gate/usr/src/uts/sun4u/sunfire/io/ac_add.c (revision 4266:c151d8b35988)
11341Sstevel /*
21341Sstevel  * CDDL HEADER START
31341Sstevel  *
41341Sstevel  * The contents of this file are subject to the terms of the
51341Sstevel  * Common Development and Distribution License (the "License").
61341Sstevel  * You may not use this file except in compliance with the License.
71341Sstevel  *
81341Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91341Sstevel  * or http://www.opensolaris.org/os/licensing.
101341Sstevel  * See the License for the specific language governing permissions
111341Sstevel  * and limitations under the License.
121341Sstevel  *
131341Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141341Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151341Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161341Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171341Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181341Sstevel  *
191341Sstevel  * CDDL HEADER END
201341Sstevel  */
211341Sstevel 
221341Sstevel /*
23*4266Sdp78419  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
241341Sstevel  * Use is subject to license terms.
251341Sstevel  */
261341Sstevel 
271341Sstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
281341Sstevel 
291341Sstevel #include <sys/types.h>
301341Sstevel #include <sys/systm.h>
311341Sstevel #include <sys/ddi.h>
321341Sstevel #include <sys/sunddi.h>
331341Sstevel #include <sys/ddi_impldefs.h>
341341Sstevel #include <sys/obpdefs.h>
351341Sstevel #include <sys/errno.h>
361341Sstevel #include <sys/kmem.h>
371341Sstevel #include <sys/vmem.h>
381341Sstevel #include <sys/debug.h>
391341Sstevel #include <sys/sysmacros.h>
401341Sstevel #include <sys/machsystm.h>
411341Sstevel #include <sys/machparam.h>
421341Sstevel #include <sys/modctl.h>
431341Sstevel #include <sys/fhc.h>
441341Sstevel #include <sys/ac.h>
451341Sstevel #include <sys/vm.h>
461341Sstevel #include <sys/cpu_module.h>
471341Sstevel #include <vm/seg_kmem.h>
481341Sstevel #include <vm/hat_sfmmu.h>
491341Sstevel #include <sys/mem_config.h>
501341Sstevel #include <sys/mem_cage.h>
511341Sstevel 
521341Sstevel /*
531341Sstevel  * Default to always clean memory on add to reduce chance
541341Sstevel  * of uncorrectable errors.
551341Sstevel  */
561341Sstevel int ac_add_clean = 1;
571341Sstevel 
581341Sstevel #define	ADD_PAGESIZE	MMU_PAGESIZE
591341Sstevel 
601341Sstevel ac_err_t
ac_kpm_err_cvt(int err)611341Sstevel ac_kpm_err_cvt(int err)
621341Sstevel {
631341Sstevel 	switch (err) {
641341Sstevel 	case KPHYSM_ESPAN:
651341Sstevel 		return (AC_ERR_KPM_SPAN);
661341Sstevel 	case KPHYSM_EFAULT:
671341Sstevel 		return (AC_ERR_KPM_FAULT);
681341Sstevel 	case KPHYSM_ERESOURCE:
691341Sstevel 		return (AC_ERR_KPM_RESOURCE);
701341Sstevel 	case KPHYSM_ENOTSUP:
711341Sstevel 		return (AC_ERR_KPM_NOTSUP);
721341Sstevel 	case KPHYSM_ENOHANDLES:
731341Sstevel 		return (AC_ERR_KPM_NOHANDLES);
741341Sstevel 	case KPHYSM_ENONRELOC:
751341Sstevel 		return (AC_ERR_KPM_NONRELOC);
761341Sstevel 	case KPHYSM_EHANDLE:
771341Sstevel 		return (AC_ERR_KPM_HANDLE);
781341Sstevel 	case KPHYSM_EBUSY:
791341Sstevel 		return (AC_ERR_KPM_BUSY);
801341Sstevel 	case KPHYSM_ENOTVIABLE:
811341Sstevel 		return (AC_ERR_KPM_NOTVIABLE);
821341Sstevel 	case KPHYSM_ESEQUENCE:
831341Sstevel 		return (AC_ERR_KPM_SEQUENCE);
841341Sstevel 	case KPHYSM_ENOWORK:
851341Sstevel 		return (AC_ERR_KPM_NOWORK);
861341Sstevel 	case KPHYSM_ECANCELLED:
871341Sstevel 		return (AC_ERR_KPM_CANCELLED);
881341Sstevel 	case KPHYSM_ENOTFINISHED:
891341Sstevel 		return (AC_ERR_KPM_NOTFINISHED);
901341Sstevel 	case KPHYSM_ENOTRUNNING:
911341Sstevel 		return (AC_ERR_KPM_NOTRUNNING);
921341Sstevel 	case KPHYSM_EREFUSED:
931341Sstevel 		return (AC_ERR_KPM_REFUSED);
941341Sstevel 	case KPHYSM_EDUP:
951341Sstevel 		return (AC_ERR_KPM_DUP);
961341Sstevel 	default:
971341Sstevel 		return (AC_ERR_DEFAULT);
981341Sstevel 	}
991341Sstevel }
1001341Sstevel 
1011341Sstevel static int
ac_add_bank(struct bd_list * add,ac_cfga_pkt_t * pkt)1021341Sstevel ac_add_bank(struct bd_list *add, ac_cfga_pkt_t *pkt)
1031341Sstevel {
1041341Sstevel 	uint64_t		decode;
1051341Sstevel 	uint64_t		base_pa;
1061341Sstevel 	uint64_t		limit_pa;
1071341Sstevel 	uint64_t		current_pa;
1081341Sstevel 	int			errs;
1091341Sstevel 	uint64_t		bank_size;
1101341Sstevel 	struct ac_mem_info	*mem_info;
1111341Sstevel 	struct ac_soft_state	*asp = pkt->softsp;
1121341Sstevel 	uint_t			ilv;
1131341Sstevel 
1141341Sstevel 	/*
1151341Sstevel 	 * Cannot add interleaved banks at the moment.
1161341Sstevel 	 */
1171341Sstevel 	ilv = (pkt->bank == Bank0) ?
1181341Sstevel 	    INTLV0(*asp->ac_memctl) : INTLV1(*asp->ac_memctl);
1191341Sstevel 	if (ilv != 1) {
1201341Sstevel 		AC_ERR_SET(pkt, AC_ERR_MEM_DEINTLV);
1211341Sstevel 		return (EINVAL);
1221341Sstevel 	}
1231341Sstevel 	/*
1241341Sstevel 	 * Determine the physical location of the selected bank
1251341Sstevel 	 */
1261341Sstevel 	decode = (pkt->bank == Bank0) ?
1271341Sstevel 	    *asp->ac_memdecode0 : *asp->ac_memdecode1;
1281341Sstevel 	base_pa = GRP_REALBASE(decode);
1291341Sstevel 	bank_size = GRP_UK2SPAN(decode);
1301341Sstevel 	limit_pa = base_pa + bank_size;
1311341Sstevel 
1321341Sstevel 	mem_info = &asp->bank[pkt->bank];
1331341Sstevel 	if (ac_add_clean || mem_info->condition != SYSC_CFGA_COND_OK) {
1341341Sstevel 		caddr_t			base_va;
1351341Sstevel 		caddr_t			fill_buf;
1361341Sstevel 		int			linesize;
1371341Sstevel 
1381341Sstevel 		/*
1391341Sstevel 		 * We need a page_va and a fill buffer for this operation
1401341Sstevel 		 */
1411341Sstevel 		base_va = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
1421341Sstevel 		fill_buf = kmem_zalloc(ADD_PAGESIZE, KM_SLEEP);
1431341Sstevel 		linesize = cpunodes[CPU->cpu_id].ecache_linesize;
1441341Sstevel 
1451341Sstevel 		/*
1461341Sstevel 		 * zero fill the memory -- indirectly initializes the ECC
1471341Sstevel 		 */
1481341Sstevel 		kpreempt_disable();
1491341Sstevel 		for (current_pa = base_pa; current_pa < limit_pa;
1501341Sstevel 		    current_pa += ADD_PAGESIZE) {
1511341Sstevel 
1521341Sstevel 			/* map current pa */
1531341Sstevel 			ac_mapin(current_pa, base_va);
1541341Sstevel 
1551341Sstevel 			/* fill the target page */
1561341Sstevel 			ac_blkcopy(fill_buf, base_va,
1571341Sstevel 				ADD_PAGESIZE/linesize, linesize);
1581341Sstevel 
1591341Sstevel 			/* tear down translation */
1601341Sstevel 			ac_unmap(base_va);
1611341Sstevel 		}
1621341Sstevel 		kpreempt_enable();
1631341Sstevel 
1641341Sstevel 		/*
1651341Sstevel 		 * clean up temporary resources
1661341Sstevel 		 */
1671341Sstevel 		kmem_free(fill_buf, ADD_PAGESIZE);
1681341Sstevel 		vmem_free(heap_arena, base_va, PAGESIZE);
1691341Sstevel 	}
1701341Sstevel 
1711341Sstevel 	/*
1721341Sstevel 	 * give the memory to Solaris
1731341Sstevel 	 */
1741341Sstevel 	errs = kphysm_add_memory_dynamic(base_pa >> PAGESHIFT,
1751341Sstevel 	    bank_size >> PAGESHIFT);
1761341Sstevel 
1771341Sstevel 	if (errs != KPHYSM_OK) {
1781341Sstevel 		AC_ERR_SET(pkt, ac_kpm_err_cvt(errs));
1791341Sstevel 		return (EINVAL);
1801341Sstevel 	}
1811341Sstevel 
1821341Sstevel 	/*
1831341Sstevel 	 * Add the board to the cage growth list.
1841341Sstevel 	 */
185*4266Sdp78419 	errs = kcage_range_add(btop(base_pa), btop(bank_size), KCAGE_DOWN);
1861341Sstevel 	/* TODO: deal with error return. */
1871341Sstevel 	if (errs != 0)
1881341Sstevel 		cmn_err(CE_NOTE, "ac_add_bank(): board %d, bank %d, "
1891341Sstevel 		    "kcage_range_add() returned %d",
1901341Sstevel 		    add->sc.board, pkt->bank, errs);
1911341Sstevel 
1921341Sstevel 	return (0);
1931341Sstevel }
1941341Sstevel 
1951341Sstevel int
ac_add_memory(ac_cfga_pkt_t * pkt)1961341Sstevel ac_add_memory(ac_cfga_pkt_t *pkt)
1971341Sstevel {
1981341Sstevel 	struct bd_list *board;
1991341Sstevel 	struct ac_mem_info *mem_info;
2001341Sstevel 	int force = pkt->cmd_cfga.force;
2011341Sstevel 	int retval;
2021341Sstevel 
2031341Sstevel 	board = fhc_bdlist_lock(pkt->softsp->board);
2041341Sstevel 	if (board == NULL || board->ac_softsp == NULL) {
2051341Sstevel 		fhc_bdlist_unlock();
2061341Sstevel 		AC_ERR_SET(pkt, AC_ERR_BD);
2071341Sstevel 		return (EINVAL);
2081341Sstevel 	}
2091341Sstevel 	ASSERT(pkt->softsp == board->ac_softsp);
2101341Sstevel 
2111341Sstevel 	/* verify the board is of the correct type */
2121341Sstevel 	switch (board->sc.type) {
2131341Sstevel 	case CPU_BOARD:
2141341Sstevel 	case MEM_BOARD:
2151341Sstevel 		break;
2161341Sstevel 	default:
2171341Sstevel 		fhc_bdlist_unlock();
2181341Sstevel 		AC_ERR_SET(pkt, AC_ERR_BD_TYPE);
2191341Sstevel 		return (EINVAL);
2201341Sstevel 	}
2211341Sstevel 
2221341Sstevel 	/* verify the memory condition is acceptable */
2231341Sstevel 	mem_info = &pkt->softsp->bank[pkt->bank];
2241341Sstevel 	if (!MEM_BOARD_VISIBLE(board) || mem_info->busy ||
2251341Sstevel 	    fhc_bd_busy(pkt->softsp->board) ||
2261341Sstevel 	    mem_info->rstate != SYSC_CFGA_RSTATE_CONNECTED ||
2271341Sstevel 	    mem_info->ostate != SYSC_CFGA_OSTATE_UNCONFIGURED ||
2281341Sstevel 	    (!force && mem_info->condition != SYSC_CFGA_COND_OK)) {
2291341Sstevel 		fhc_bdlist_unlock();
2301341Sstevel 		AC_ERR_SET(pkt, AC_ERR_BD_STATE);
2311341Sstevel 		return (EINVAL);
2321341Sstevel 	}
2331341Sstevel 
2341341Sstevel 	/*
2351341Sstevel 	 * at this point, we have an available bank to add.
2361341Sstevel 	 * mark it busy and initiate the add function.
2371341Sstevel 	 */
2381341Sstevel 	mem_info->busy = TRUE;
2391341Sstevel 	fhc_bdlist_unlock();
2401341Sstevel 
2411341Sstevel 	retval = ac_add_bank(board, pkt);
2421341Sstevel 
2431341Sstevel 	/*
2441341Sstevel 	 * We made it!  Update the status and get out of here.
2451341Sstevel 	 */
2461341Sstevel 	(void) fhc_bdlist_lock(-1);
2471341Sstevel 	mem_info->busy = FALSE;
2481341Sstevel 	if (retval == 0) {
2491341Sstevel 		mem_info->ostate = SYSC_CFGA_OSTATE_CONFIGURED;
2501341Sstevel 		mem_info->status_change = ddi_get_time();
2511341Sstevel 	}
2521341Sstevel 
2531341Sstevel 	fhc_bdlist_unlock();
2541341Sstevel 
2551341Sstevel 	if (retval != 0) {
2561341Sstevel 		return (retval);
2571341Sstevel 	}
2581341Sstevel 	return (DDI_SUCCESS);
2591341Sstevel }
260