patch-2.4.26 linux-2.4.26/arch/ia64/kernel/salinfo.c

Next file: linux-2.4.26/arch/ia64/kernel/signal.c
Previous file: linux-2.4.26/arch/ia64/kernel/ptrace.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.25/arch/ia64/kernel/salinfo.c linux-2.4.26/arch/ia64/kernel/salinfo.c
@@ -16,6 +16,13 @@
  *   Cache the record across multi-block reads from user space.
  *   Support > 64 cpus.
  *   Delete module_exit and MOD_INC/DEC_COUNT, salinfo cannot be a module.
+ *
+ * Jan 28 2004	kaos@sgi.com
+ *   Periodically check for outstanding MCA or INIT records.
+ *
+ * Feb 21 2004	kaos@sgi.com
+ *   Copy record contents rather than relying on the mca.c buffers, to cope with
+ *   interrupts arriving in mca.c faster than salinfo.c can process them.
  */
 
 #include <linux/types.h>
@@ -23,6 +30,7 @@
 #include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/timer.h>
 #include <linux/vmalloc.h>
 
 #include <asm/semaphore.h>
@@ -83,6 +91,7 @@
 	u64			size;
 	u64			id;
 	int			cpu;
+	int			kmalloced :1;	/* buffer was kmalloc'ed */
 };
 
 /* State transitions.  Actions are :-
@@ -178,6 +187,8 @@
 static void
 shift1_data_saved (struct salinfo_data *data, int shift)
 {
+	if (data->data_saved[shift].kmalloced)
+		kfree(data->data_saved[shift].buffer);
 	memcpy(data->data_saved+shift, data->data_saved+shift+1,
 	       (ARRAY_SIZE(data->data_saved) - (shift+1)) * sizeof(data->data_saved[0]));
 	memset(data->data_saved + ARRAY_SIZE(data->data_saved) - 1, 0,
@@ -187,6 +198,8 @@
 /* This routine is invoked in interrupt context.  Note: mca.c enables
  * interrupts before calling this code for CMC/CPE.  MCA and INIT events are
  * not irq safe, do not call any routines that use spinlocks, they may deadlock.
+ * MCA and INIT records are recorded, a timer event will look for any
+ * outstanding events and wake up the user space code.
  *
  * The buffer passed from mca.c points to the output from ia64_log_get. This is
  * a persistent buffer but its contents can change between the interrupt and
@@ -194,12 +207,12 @@
  * changes.
  */
 void
-salinfo_log_wakeup(int type, u8 *buffer, u64 size)
+salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe)
 {
 	struct salinfo_data *data = salinfo_data + type;
 	struct salinfo_data_saved *data_saved;
 	unsigned long flags = 0;
-	int i, irqsafe = type != SAL_INFO_TYPE_MCA && type != SAL_INFO_TYPE_INIT;
+	int i;
 	int saved_size = ARRAY_SIZE(data->data_saved);
 
 	BUG_ON(type >= ARRAY_SIZE(salinfo_log_name));
@@ -221,7 +234,13 @@
 		data_saved->cpu = smp_processor_id();
 		data_saved->id = ((sal_log_record_header_t *)buffer)->id;
 		data_saved->size = size;
-		data_saved->buffer = buffer;
+		if (irqsafe && (data_saved->buffer = kmalloc(size, GFP_ATOMIC))) {
+			memcpy(data_saved->buffer, buffer, size);
+			data_saved->kmalloced = 1;
+		} else {
+			data_saved->buffer = buffer;
+			data_saved->kmalloced = 0;
+		}
 	}
 	if (irqsafe)
 		spin_unlock_irqrestore(&data_saved_lock, flags);
@@ -232,6 +251,35 @@
 	}
 }
 
+/* Check for outstanding MCA/INIT records every 5 minutes (arbitrary) */
+#define SALINFO_TIMER_DELAY (5*60*HZ)
+static struct timer_list salinfo_timer;
+
+static void
+salinfo_timeout_check(struct salinfo_data *data)
+{
+	int i;
+	if (!data->open)
+		return;
+	for (i = 0; i < NR_CPUS; ++i) {
+		if (test_bit(i, &data->cpu_event)) {
+			/* double up() is not a problem, user space will see no
+			 * records for the additional "events".
+			 */
+			up(&data->sem);
+		}
+	}
+}
+
+static void 
+salinfo_timeout (unsigned long arg)
+{
+	salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_MCA);
+	salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_INIT);
+	salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY;
+	add_timer(&salinfo_timer);
+}
+
 static int
 salinfo_event_open(struct inode *inode, struct file *file)
 {
@@ -571,6 +619,11 @@
 
 	*sdir++ = salinfo_dir;
 
+	init_timer(&salinfo_timer);
+	salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY;
+	salinfo_timer.function = &salinfo_timeout;
+	add_timer(&salinfo_timer);
+
 	return 0;
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)