4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/types.h>
30 #include <sys/systm.h>
32 #include <sys/sunddi.h>
33 #include <sys/ddi_impldefs.h>
34 #include <sys/obpdefs.h>
35 #include <sys/errno.h>
38 #include <sys/debug.h>
39 #include <sys/sysmacros.h>
40 #include <sys/machsystm.h>
41 #include <sys/machparam.h>
42 #include <sys/modctl.h>
46 #include <sys/cpu_module.h>
47 #include <vm/seg_kmem.h>
48 #include <vm/hat_sfmmu.h>
49 #include <sys/mem_config.h>
50 #include <sys/mem_cage.h>
52 extern ac_err_t
ac_kpm_err_cvt(int);
57 * Default timeout, in seconds, for delete.
58 * Time is counted when no progress is being made.
60 static int ac_del_timeout
= 60;
62 #define DEL_PAGESIZE MMU_PAGESIZE
65 struct del_status
*next
;
67 volatile int its_done
;
74 pgcnt_t last_collected
;
76 static struct del_status
*ac_del_list
;
77 static kmutex_t ac_del_mutex
;
79 static struct del_status
*
82 struct del_status
*dsp
;
84 dsp
= kmem_zalloc(sizeof (*dsp
), KM_SLEEP
);
85 mutex_enter(&ac_del_mutex
);
86 dsp
->next
= ac_del_list
;
88 mutex_exit(&ac_del_mutex
);
94 ac_del_free_status(struct del_status
*dsp
)
96 struct del_status
**dspp
;
98 mutex_enter(&ac_del_mutex
);
100 while (*dspp
!= NULL
) {
103 dspp
= &(*dspp
)->next
;
105 ASSERT(*dspp
== dsp
);
109 mutex_exit(&ac_del_mutex
);
110 kmem_free((void *)dsp
, sizeof (*dsp
));
114 del_comp(void *arg
, int error
)
116 struct del_status
*dsp
;
118 dsp
= (struct del_status
*)arg
;
119 mutex_enter(&ac_del_mutex
);
122 struct del_status
*adsp
;
123 for (adsp
= ac_del_list
; adsp
!= NULL
; adsp
= adsp
->next
) {
127 ASSERT(adsp
!= NULL
);
131 dsp
->done_error
= error
;
132 cv_signal(&dsp
->ac_del_cv
);
133 mutex_exit(&ac_del_mutex
);
138 del_to_scan(void *arg
)
140 struct del_status
*dsp
;
149 struct del_status
*adsp
;
151 mutex_enter(&ac_del_mutex
);
152 for (adsp
= ac_del_list
; adsp
!= NULL
; adsp
= adsp
->next
) {
156 ASSERT(adsp
!= NULL
);
157 mutex_exit(&ac_del_mutex
);
161 err
= kphysm_del_status(dsp
->handle
, &dstat
);
162 mutex_enter(&ac_del_mutex
);
164 mutex_exit(&ac_del_mutex
);
167 if ((err
== KPHYSM_OK
) &&
168 (dsp
->last_collected
!= dstat
.collected
)) {
169 dsp
->del_noprogress
= 0;
170 dsp
->last_collected
= dstat
.collected
;
172 dsp
->del_noprogress
++;
173 if (dsp
->del_noprogress
>= dsp
->del_timeout
) {
174 if (dsp
->cancel_code
== 0)
175 dsp
->cancel_code
= AC_ERR_TIMEOUT
;
180 dsp
->to_id
= timeout(del_to_scan
, arg
, hz
);
183 mutex_exit(&ac_del_mutex
);
185 (void) kphysm_del_cancel(dsp
->handle
);
189 del_to_start(struct del_status
*dsp
)
191 if (dsp
->del_timeout
!= 0)
192 dsp
->to_id
= timeout(del_to_scan
, dsp
, hz
);
196 del_to_stop(struct del_status
*dsp
)
200 while ((tid
= dsp
->to_id
) != 0) {
202 mutex_exit(&ac_del_mutex
);
203 (void) untimeout(tid
);
204 mutex_enter(&ac_del_mutex
);
209 ac_del_bank_add_span(
220 struct ac_soft_state
*asp
= pkt
->softsp
;
224 * Cannot delete interleaved banks at the moment.
226 ilv
= (pkt
->bank
== Bank0
) ?
227 INTLV0(*asp
->ac_memctl
) : INTLV1(*asp
->ac_memctl
);
229 AC_ERR_SET(pkt
, AC_ERR_MEM_DEINTLV
);
233 * Determine the physical location of the selected bank
235 decode
= (pkt
->bank
== Bank0
) ?
236 *asp
->ac_memdecode0
: *asp
->ac_memdecode1
;
237 base_pa
= GRP_REALBASE(decode
);
238 bank_size
= GRP_UK2SPAN(decode
);
240 base
= base_pa
>> PAGESHIFT
;
241 npgs
= bank_size
>> PAGESHIFT
;
244 * Delete the pages from the cage growth list.
246 ret
= kcage_range_delete(base
, npgs
);
248 /* TODO: Should this be a separate error? */
249 AC_ERR_SET(pkt
, AC_ERR_KPM_NONRELOC
);
254 * Add to delete memory list.
257 if ((errs
= kphysm_del_span(handle
, base
, npgs
)) != KPHYSM_OK
) {
258 AC_ERR_SET(pkt
, ac_kpm_err_cvt(errs
));
260 * Restore the pages to the cage growth list.
261 * TODO: We should not unconditionally add back
262 * if we conditionally add at memory add time.
264 errs
= kcage_range_add(base
, npgs
, KCAGE_DOWN
);
265 /* TODO: deal with error return. */
267 AC_ERR_SET(pkt
, ac_kpm_err_cvt(errs
));
268 cmn_err(CE_NOTE
, "ac_del_bank_add_span(): "
269 "board %d, bank %d, "
270 "kcage_range_add() returned %d",
271 pkt
->softsp
->board
, pkt
->bank
, errs
);
279 ac_del_bank_add_cage(
281 enum ac_bank_id bank
)
289 struct ac_soft_state
*asp
= (struct ac_soft_state
*)(del
->ac_softsp
);
292 * Determine the physical location of the selected bank
294 decode
= (bank
== Bank0
) ? *asp
->ac_memdecode0
: *asp
->ac_memdecode1
;
295 base_pa
= GRP_REALBASE(decode
);
296 bank_size
= GRP_UK2SPAN(decode
);
298 base
= base_pa
>> PAGESHIFT
;
299 npgs
= bank_size
>> PAGESHIFT
;
302 * Restore the pages to the cage growth list.
303 * TODO: We should not unconditionally add back
304 * if we conditionally add at memory add time.
306 errs
= kcage_range_add(base
, npgs
, KCAGE_DOWN
);
307 /* TODO: deal with error return. */
309 cmn_err(CE_NOTE
, "ac_del_bank_add_cage(): "
310 "board %d, bank %d, "
311 "kcage_range_add() returned %d",
312 del
->sc
.board
, bank
, errs
);
316 ac_del_bank_run(struct del_status
*dsp
, ac_cfga_pkt_t
*pkt
)
321 if ((errs
= kphysm_del_start(dsp
->handle
, del_comp
, (void *)dsp
)) !=
323 AC_ERR_SET(pkt
, ac_kpm_err_cvt(errs
));
326 /* Wait for it to complete. */
327 mutex_enter(&ac_del_mutex
);
329 while (!dsp
->its_done
) {
330 if (!cv_wait_sig(&dsp
->ac_del_cv
, &ac_del_mutex
)) {
331 if (dsp
->cancel_code
== 0)
332 dsp
->cancel_code
= AC_ERR_INTR
;
333 mutex_exit(&ac_del_mutex
);
334 errs
= kphysm_del_cancel(dsp
->handle
);
335 mutex_enter(&ac_del_mutex
);
336 if (errs
!= KPHYSM_OK
) {
337 ASSERT(errs
== KPHYSM_ENOTRUNNING
);
343 * If the loop exited due to a signal, we must continue to wait
344 * using cv_wait() as the signal is pending until syscall exit.
346 while (!dsp
->its_done
) {
347 cv_wait(&dsp
->ac_del_cv
, &ac_del_mutex
);
349 if (dsp
->done_error
!= KPHYSM_OK
) {
350 AC_ERR_SET(pkt
, ac_kpm_err_cvt(dsp
->done_error
));
351 if ((dsp
->done_error
== KPHYSM_ECANCELLED
) ||
352 (dsp
->done_error
== KPHYSM_EREFUSED
)) {
354 if (dsp
->cancel_code
!= 0) {
355 AC_ERR_SET(pkt
, dsp
->cancel_code
);
363 mutex_exit(&ac_del_mutex
);
370 * set the memory to known state for debugging
373 ac_bank_write_pattern(struct bd_list
*del
, enum ac_bank_id bank
)
382 struct ac_soft_state
*asp
= (struct ac_soft_state
*)(del
->ac_softsp
);
386 * Determine the physical location of the selected bank
388 decode
= (bank
== Bank0
) ? *asp
->ac_memdecode0
: *asp
->ac_memdecode1
;
389 base_pa
= GRP_REALBASE(decode
);
390 bank_size
= GRP_UK2SPAN(decode
);
391 limit_pa
= base_pa
+ bank_size
;
392 linesize
= cpunodes
[CPU
->cpu_id
].ecache_linesize
;
395 * We need a page_va and a fill buffer for this operation
397 base_va
= vmem_alloc(heap_arena
, PAGESIZE
, VM_SLEEP
);
398 fill_buf
= kmem_zalloc(DEL_PAGESIZE
, KM_SLEEP
);
400 typedef uint32_t patt_t
;
401 patt_t
*bf
, *bfe
, patt
;
403 bf
= (patt_t
*)fill_buf
;
404 bfe
= (patt_t
*)((char *)fill_buf
+ DEL_PAGESIZE
);
414 for (current_pa
= base_pa
; current_pa
< limit_pa
;
415 current_pa
+= DEL_PAGESIZE
) {
418 ac_mapin(current_pa
, base_va
);
420 /* fill the target page */
421 ac_blkcopy(fill_buf
, base_va
,
422 DEL_PAGESIZE
/linesize
, linesize
);
424 /* tear down translation */
430 * clean up temporary resources
433 /* Distinguish the fill buf from memory deleted! */
434 typedef uint32_t patt_t
;
435 patt_t
*bf
, *bfe
, patt
;
437 bf
= (patt_t
*)fill_buf
;
438 bfe
= (patt_t
*)((char *)fill_buf
+ DEL_PAGESIZE
);
443 kmem_free(fill_buf
, DEL_PAGESIZE
);
444 vmem_free(heap_arena
, base_va
, PAGESIZE
);
448 ac_del_memory(ac_cfga_pkt_t
*pkt
)
450 struct bd_list
*board
;
451 struct ac_mem_info
*mem_info
;
453 struct del_status
*dsp
;
457 struct ac_soft_state
*asp
;
460 static int cage_msg_done
= 0;
462 if (!cage_msg_done
) {
464 cmn_err(CE_NOTE
, "ac: memory delete"
465 " refused: cage is off");
467 AC_ERR_SET(pkt
, ac_kpm_err_cvt(KPHYSM_ENONRELOC
));
471 dsp
= ac_del_alloc_status();
472 if ((retval
= kphysm_del_gethandle(&dsp
->handle
)) != KPHYSM_OK
) {
473 ac_del_free_status(dsp
);
474 AC_ERR_SET(pkt
, ac_kpm_err_cvt(retval
));
480 board
= fhc_bdlist_lock(pkt
->softsp
->board
);
481 if (board
== NULL
|| board
->ac_softsp
== NULL
) {
483 AC_ERR_SET(pkt
, AC_ERR_BD
);
487 ASSERT(pkt
->softsp
== board
->ac_softsp
);
490 /* verify the board is of the correct type */
491 switch (board
->sc
.type
) {
497 AC_ERR_SET(pkt
, AC_ERR_BD_TYPE
);
502 /* verify the memory condition is acceptable */
503 mem_info
= &asp
->bank
[pkt
->bank
];
504 if (!MEM_BOARD_VISIBLE(board
) || mem_info
->busy
||
505 fhc_bd_busy(pkt
->softsp
->board
) ||
506 mem_info
->rstate
!= SYSC_CFGA_RSTATE_CONNECTED
||
507 mem_info
->ostate
!= SYSC_CFGA_OSTATE_CONFIGURED
) {
509 AC_ERR_SET(pkt
, AC_ERR_BD_STATE
);
514 if ((dsp
->del_timeout
= pkt
->cmd_cfga
.arg
) == -1)
515 dsp
->del_timeout
= ac_del_timeout
;
518 * at this point, we have an available bank to del.
519 * mark it busy and initiate the del function.
521 mem_info
->busy
= TRUE
;
526 retval
= ac_del_bank_add_span(dsp
->handle
, pkt
);
529 r_errs
= kphysm_del_release(dsp
->handle
);
530 ASSERT(r_errs
== KPHYSM_OK
);
533 board
= fhc_bdlist_lock(pkt
->softsp
->board
);
534 ASSERT(board
!= NULL
&& board
->ac_softsp
!= NULL
);
536 ASSERT(board
->sc
.type
== CPU_BOARD
||
537 board
->sc
.type
== MEM_BOARD
);
539 (struct ac_soft_state
*)(board
->ac_softsp
));
540 mem_info
= &asp
->bank
[pkt
->bank
];
541 ASSERT(mem_info
->busy
!= FALSE
);
542 ASSERT(mem_info
->ostate
== SYSC_CFGA_OSTATE_CONFIGURED
);
543 mem_info
->busy
= FALSE
;
547 ac_del_free_status(dsp
);
551 (void) kphysm_del_status(dsp
->handle
, &dstat
);
553 retval
= ac_del_bank_run(dsp
, pkt
);
555 r_errs
= kphysm_del_release(dsp
->handle
);
556 ASSERT(r_errs
== KPHYSM_OK
);
558 board
= fhc_bdlist_lock(pkt
->softsp
->board
);
559 ASSERT(board
!= NULL
&& board
->ac_softsp
!= NULL
);
561 ASSERT(board
->sc
.type
== CPU_BOARD
|| board
->sc
.type
== MEM_BOARD
);
562 ASSERT(asp
== (struct ac_soft_state
*)(board
->ac_softsp
));
563 mem_info
= &asp
->bank
[pkt
->bank
];
564 ASSERT(mem_info
->busy
!= FALSE
);
565 ASSERT(mem_info
->ostate
== SYSC_CFGA_OSTATE_CONFIGURED
);
566 mem_info
->busy
= FALSE
;
568 mem_info
->ostate
= SYSC_CFGA_OSTATE_UNCONFIGURED
;
569 mem_info
->status_change
= ddi_get_time();
572 /* DEBUG - set memory to known state */
573 ac_bank_write_pattern(board
, pkt
->bank
);
577 * Restore the pages to the cage growth list.
579 ac_del_bank_add_cage(board
, pkt
->bank
);
583 ac_del_free_status(dsp
);