summaryrefslogtreecommitdiffstats
path: root/sys/ia64
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2009-02-04 18:44:29 +0000
committerjhb <jhb@FreeBSD.org>2009-02-04 18:44:29 +0000
commit91ab06bc89c8b1ebcef65d274d75619329bb0119 (patch)
tree619758d9b4cc116f238dd07a625c8cad152df1d3 /sys/ia64
parent38f4b2a9a8835ed31f275273f37ce9bd291db451 (diff)
downloadFreeBSD-src-91ab06bc89c8b1ebcef65d274d75619329bb0119.zip
FreeBSD-src-91ab06bc89c8b1ebcef65d274d75619329bb0119.tar.gz
Tweak the ia64 machine check handling code to not register new sysctl nodes
while holding a spin mutex. Instead, it now shoves the machine check records onto a queue that is later drained to add sysctl nodes for each record. While a routine to drain the queue is present, it is not currently called. Reviewed by: marcel
Diffstat (limited to 'sys/ia64')
-rw-r--r--sys/ia64/ia64/mca.c70
-rw-r--r--sys/ia64/include/mca.h1
2 files changed, 45 insertions, 26 deletions
diff --git a/sys/ia64/ia64/mca.c b/sys/ia64/ia64/mca.c
index bba0bfb..e25031d 100644
--- a/sys/ia64/ia64/mca.c
+++ b/sys/ia64/ia64/mca.c
@@ -42,6 +42,16 @@
MALLOC_DEFINE(M_MCA, "MCA", "Machine Check Architecture");
+struct mca_info {
+ STAILQ_ENTRY(mca_info) mi_link;
+ char mi_name[32];
+ size_t mi_recsz;
+ char mi_record[0];
+};
+
+static STAILQ_HEAD(, mca_info) mca_records =
+ STAILQ_HEAD_INITIALIZER(mca_records);
+
int64_t mca_info_size[SAL_INFO_TYPES];
vm_offset_t mca_info_block;
struct mtx mca_info_block_lock;
@@ -76,14 +86,32 @@ mca_sysctl_handler(SYSCTL_HANDLER_ARGS)
}
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)
{
struct ia64_sal_result result;
struct mca_record_header *hdr;
- struct sysctl_oid *oidp;
- char *name, *state;
+ struct mca_info *rec;
uint64_t seqnr;
- size_t recsz, totsz;
+ size_t recsz;
/*
* Don't try to get the state if we couldn't get the size of
@@ -95,9 +123,8 @@ 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) {
@@ -111,11 +138,13 @@ ia64_mca_save_state(int type)
mtx_unlock_spin(&mca_info_block_lock);
- totsz = sizeof(struct sysctl_oid) + recsz + 32;
- oidp = malloc(totsz, M_MCA, M_NOWAIT|M_ZERO);
- state = (char*)(oidp + 1);
- name = state + recsz;
- sprintf(name, "%lld", (long long)seqnr);
+ rec = malloc(sizeof(struct mca_info) + recsz, M_MCA,
+ M_NOWAIT | M_ZERO);
+ if (rec == NULL)
+ /* XXX: Not sure what to do. */
+ return;
+
+ sprintf(rec->mi_name, "%lld", (long long)seqnr);
mtx_lock_spin(&mca_info_block_lock);
@@ -133,24 +162,14 @@ ia64_mca_save_state(int type)
mca_info_block, 0, 0, 0, 0);
if (seqnr != hdr->rh_seqnr) {
mtx_unlock_spin(&mca_info_block_lock);
- free(oidp, M_MCA);
+ free(rec, M_MCA);
+ mtx_lock_spin(&mca_info_block_lock);
continue;
}
}
- bcopy((char*)mca_info_block, state, recsz);
-
- oidp->oid_parent = &sysctl__hw_mca_children;
- oidp->oid_number = OID_AUTO;
- oidp->oid_kind = CTLTYPE_OPAQUE|CTLFLAG_RD|CTLFLAG_DYN;
- oidp->oid_arg1 = state;
- oidp->oid_arg2 = recsz;
- oidp->oid_name = name;
- oidp->oid_handler = mca_sysctl_handler;
- oidp->oid_fmt = "S,MCA";
- oidp->oid_descr = "Error record";
-
- sysctl_register_oid(oidp);
+ rec->mi_recsz = recsz;
+ bcopy((char*)mca_info_block, rec->mi_record, recsz);
if (mca_count > 0) {
if (seqnr < mca_first)
@@ -161,6 +180,7 @@ ia64_mca_save_state(int type)
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
@@ -168,8 +188,6 @@ ia64_mca_save_state(int type)
*/
result = ia64_sal_entry(SAL_CLEAR_STATE_INFO, type, 0, 0, 0,
0, 0, 0);
-
- mtx_unlock_spin(&mca_info_block_lock);
}
}
diff --git a/sys/ia64/include/mca.h b/sys/ia64/include/mca.h
index 997c221..75831c7 100644
--- a/sys/ia64/include/mca.h
+++ b/sys/ia64/include/mca.h
@@ -239,6 +239,7 @@ struct mca_pcidev_reg {
#ifdef _KERNEL
void ia64_mca_init(void);
+void ia64_mca_populate(void);
void ia64_mca_save_state(int);
#endif /* _KERNEL */
OpenPOWER on IntegriCloud