Date: Tue, 13 Apr 2010 22:20:12 +0000 (UTC) From: Marcel Moolenaar <marcel@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r206570 - in head/sys/ia64: ia64 include Message-ID: <201004132220.o3DMKCxf081383@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: marcel Date: Tue Apr 13 22:20:12 2010 New Revision: 206570 URL: http://svn.freebsd.org/changeset/base/206570 Log: Populate the sysctl tree with any MCA records we collected. The sequence number is used as the name of a sysctl node, under which we add the MCA records using the CPU id as the leaf name. Add the hw.mca.inject sysctl to provide a way to inject MC errors and trigger machine checks. PR: ia64/113102 Modified: head/sys/ia64/ia64/mca.c head/sys/ia64/include/mca.h Modified: head/sys/ia64/ia64/mca.c ============================================================================== --- head/sys/ia64/ia64/mca.c Tue Apr 13 21:32:06 2010 (r206569) +++ head/sys/ia64/ia64/mca.c Tue Apr 13 22:20:12 2010 (r206570) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2002 Marcel Moolenaar + * Copyright (c) 2002-2010 Marcel Moolenaar * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,6 +37,7 @@ #include <vm/vm.h> #include <vm/vm_kern.h> #include <machine/mca.h> +#include <machine/pal.h> #include <machine/sal.h> #include <machine/smp.h> @@ -44,19 +45,19 @@ MALLOC_DEFINE(M_MCA, "MCA", "Machine Che struct mca_info { STAILQ_ENTRY(mca_info) mi_link; - char mi_name[32]; + u_long mi_seqnr; + u_int mi_cpuid; size_t mi_recsz; char mi_record[0]; }; -static STAILQ_HEAD(, mca_info) mca_records = - STAILQ_HEAD_INITIALIZER(mca_records); +STAILQ_HEAD(mca_info_list, mca_info); -int64_t mca_info_size[SAL_INFO_TYPES]; -vm_offset_t mca_info_block; -struct mtx mca_info_block_lock; +static int64_t mca_info_size[SAL_INFO_TYPES]; +static vm_offset_t mca_info_block; +static struct mtx mca_info_block_lock; -SYSCTL_NODE(_hw, OID_AUTO, mca, CTLFLAG_RW, 0, "MCA container"); +SYSCTL_NODE(_hw, OID_AUTO, mca, CTLFLAG_RW, NULL, "MCA container"); static int mca_count; /* Number of records stored. */ static int mca_first; /* First (lowest) record ID. */ @@ -69,6 +70,32 @@ SYSCTL_INT(_hw_mca, OID_AUTO, first, CTL SYSCTL_INT(_hw_mca, OID_AUTO, last, CTLFLAG_RD, &mca_last, 0, "Last record id"); +static struct mtx mca_sysctl_lock; + +static int +mca_sysctl_inject(SYSCTL_HANDLER_ARGS) +{ + struct ia64_pal_result res; + u_int val; + int error; + + val = 0; + error = sysctl_wire_old_buffer(req, sizeof(u_int)); + if (!error) + error = sysctl_handle_int(oidp, &val, 0, req); + + if (error != 0 || req->newptr == NULL) + return (error); + + /* For example: val=137 causes a fatal CPU error. */ + res = ia64_call_pal_stacked(PAL_MC_ERROR_INJECT, val, 0, 0); + printf("%s: %#lx, %#lx, %#lx, %#lx\n", __func__, res.pal_status, + res.pal_result[0], res.pal_result[1], res.pal_result[2]); + return (0); +} +SYSCTL_PROC(_hw_mca, OID_AUTO, inject, CTLTYPE_INT | CTLFLAG_RW, NULL, 0, + mca_sysctl_inject, "I", "set to trigger a MCA"); + static int mca_sysctl_handler(SYSCTL_HANDLER_ARGS) { @@ -85,27 +112,8 @@ mca_sysctl_handler(SYSCTL_HANDLER_ARGS) return (error); } -void -ia64_mca_populate(void) -{ - struct mca_info *rec; - - mtx_lock_spin(&mca_info_block_lock); - while (!STAILQ_EMPTY(&mca_records)) { - rec = STAILQ_FIRST(&mca_records); - STAILQ_REMOVE_HEAD(&mca_records, mi_link); - mtx_unlock_spin(&mca_info_block_lock); - (void)SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), - OID_AUTO, rec->mi_name, CTLTYPE_OPAQUE | CTLFLAG_RD, - rec->mi_record, rec->mi_recsz, mca_sysctl_handler, "S,MCA", - "Error record"); - mtx_lock_spin(&mca_info_block_lock); - } - mtx_unlock_spin(&mca_info_block_lock); -} - -void -ia64_mca_save_state(int type) +static void +ia64_mca_collect_state(int type, struct mca_info_list *reclst) { struct ia64_sal_result result; struct mca_record_header *hdr; @@ -123,13 +131,13 @@ ia64_mca_save_state(int type) if (mca_info_block == 0) return; - mtx_lock_spin(&mca_info_block_lock); while (1) { + mtx_lock_spin(&mca_info_block_lock); result = ia64_sal_entry(SAL_GET_STATE_INFO, type, 0, mca_info_block, 0, 0, 0, 0); if (result.sal_status < 0) { mtx_unlock_spin(&mca_info_block_lock); - return; + break; } hdr = (struct mca_record_header *)mca_info_block; @@ -142,9 +150,10 @@ ia64_mca_save_state(int type) M_NOWAIT | M_ZERO); if (rec == NULL) /* XXX: Not sure what to do. */ - return; + break; - sprintf(rec->mi_name, "%lld", (long long)seqnr); + rec->mi_seqnr = seqnr; + rec->mi_cpuid = PCPU_GET(cpuid); mtx_lock_spin(&mca_info_block_lock); @@ -163,7 +172,6 @@ ia64_mca_save_state(int type) if (seqnr != hdr->rh_seqnr) { mtx_unlock_spin(&mca_info_block_lock); free(rec, M_MCA); - mtx_lock_spin(&mca_info_block_lock); continue; } } @@ -171,23 +179,51 @@ ia64_mca_save_state(int type) rec->mi_recsz = recsz; bcopy((char*)mca_info_block, rec->mi_record, recsz); - if (mca_count > 0) { - if (seqnr < mca_first) - mca_first = seqnr; - else if (seqnr > mca_last) - mca_last = seqnr; - } else - mca_first = mca_last = seqnr; - - mca_count++; - STAILQ_INSERT_TAIL(&mca_records, rec, mi_link); - /* * Clear the state so that we get any other records when * they exist. */ result = ia64_sal_entry(SAL_CLEAR_STATE_INFO, type, 0, 0, 0, 0, 0, 0); + + mtx_unlock_spin(&mca_info_block_lock); + + STAILQ_INSERT_TAIL(reclst, rec, mi_link); + } +} + +void +ia64_mca_save_state(int type) +{ + char name[64]; + struct mca_info_list reclst = STAILQ_HEAD_INITIALIZER(reclst); + struct mca_info *rec; + struct sysctl_oid *oid; + + ia64_mca_collect_state(type, &reclst); + + STAILQ_FOREACH(rec, &reclst, mi_link) { + sprintf(name, "%lu", rec->mi_seqnr); + oid = SYSCTL_ADD_NODE(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), + OID_AUTO, name, CTLFLAG_RW, NULL, name); + if (oid == NULL) + continue; + + mtx_lock(&mca_sysctl_lock); + if (mca_count > 0) { + if (rec->mi_seqnr < mca_first) + mca_first = rec->mi_seqnr; + else if (rec->mi_seqnr > mca_last) + mca_last = rec->mi_seqnr; + } else + mca_first = mca_last = rec->mi_seqnr; + mca_count++; + mtx_unlock(&mca_sysctl_lock); + + sprintf(name, "%u", rec->mi_cpuid); + SYSCTL_ADD_PROC(NULL, SYSCTL_CHILDREN(oid), rec->mi_cpuid, + name, CTLTYPE_OPAQUE | CTLFLAG_RD, rec->mi_record, + rec->mi_recsz, mca_sysctl_handler, "S,MCA", "MCA record"); } } @@ -237,7 +273,14 @@ ia64_mca_init(void) * should be rare. On top of that, performance is not an issue when * dealing with machine checks... */ - mtx_init(&mca_info_block_lock, "MCA spin lock", NULL, MTX_SPIN); + mtx_init(&mca_info_block_lock, "MCA info lock", NULL, MTX_SPIN); + + /* + * Serialize sysctl operations with a sleep lock. Note that this + * implies that we update the sysctl tree in a context that allows + * sleeping. + */ + mtx_init(&mca_sysctl_lock, "MCA sysctl lock", NULL, MTX_DEF); /* * Get and save any processor and platfom error records. Note that in Modified: head/sys/ia64/include/mca.h ============================================================================== --- head/sys/ia64/include/mca.h Tue Apr 13 21:32:06 2010 (r206569) +++ head/sys/ia64/include/mca.h Tue Apr 13 22:20:12 2010 (r206570) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2002 Marcel Moolenaar + * Copyright (c) 2002-2010 Marcel Moolenaar * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -240,7 +240,6 @@ struct mca_pcidev_reg { #ifdef _KERNEL void ia64_mca_init(void); -void ia64_mca_populate(void); void ia64_mca_save_state(int); #endif /* _KERNEL */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201004132220.o3DMKCxf081383>