[parisc-linux-cvs] pa19, convert the led interrupt-func to a tasklet

Helge Deller deller@gmx.de
Sun, 15 Jul 2001 20:51:34 +0200


Index: Makefile
===================================================================
RCS file: /home/cvs/parisc/linux/Makefile,v
retrieving revision 1.103
diff -u -r1.103 Makefile
--- Makefile	2001/07/14 21:17:01	1.103
+++ Makefile	2001/07/15 18:44:13
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 6
-EXTRAVERSION = -pa18
+EXTRAVERSION = -pa19
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
Index: include/asm-parisc/led.h
===================================================================
RCS file: /home/cvs/parisc/linux/include/asm-parisc/led.h,v
retrieving revision 1.5
diff -u -r1.5 led.h
--- led.h	2000/12/14 17:33:28	1.5
+++ led.h	2001/07/15 18:44:13
@@ -23,19 +23,19 @@
 
 #define LED_CMD_REG_NONE NULL		/* NULL == no addr for the cmd register */
 
-/* irq function */
-extern void led_interrupt_func(void);	
+/* led tasklet struct */
+struct tasklet_struct led_tasklet;
 
 /* register_led_driver() */
-extern int __init register_led_driver( int model, char *cmd_reg, char *data_reg );
+int __init register_led_driver( int model, char *cmd_reg, char *data_reg );
 
 /* registers the LED regions for procfs */
-extern void __init register_led_regions(void);
+void __init register_led_regions(void);
 
-/* writes a string to the LCD display (if available) */
-extern int lcd_print(char *str);
+/* writes a string to the LCD display (if possible on this h/w) */
+int lcd_print(char *str);
 
 /* main LED initialization function (uses PDC) */ 
-extern int __init led_init(void);
+int __init led_init(void);
 
 #endif /* LED_H */
Index: arch/parisc/kernel/led.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/led.c,v
retrieving revision 1.20
diff -u -r1.20 led.c
--- led.c	2001/06/30 23:47:53	1.20
+++ led.c	2001/07/15 18:44:13
@@ -2,7 +2,8 @@
  *    Chassis LCD/LED driver for HP-PARISC workstations
  *
  *      (c) Copyright 2000 Red Hat Software
- *      (c) Copyright 2000-2001 Helge Deller <hdeller@redhat.com>
+ *      (c) Copyright 2000 Helge Deller <hdeller@redhat.com>
+ *      (c) Copyright 2001 Helge Deller <deller@gmx.de>
  *
  *      This program is free software; you can redistribute it and/or modify
  *      it under the terms of the GNU General Public License as published by
@@ -10,7 +11,7 @@
  *      (at your option) any later version.
  *
  * TODO:
- *	- LCD functionality is completely untested (lack of hardware :-() 
+ *	- LCD functionality is mostly untested (lack of hardware :-() 
  *	- add procfs entry to (maybe partially) enable & disable LEDs
  *	- speed-up calculations with inlined assembler
  */
@@ -36,14 +37,14 @@
 #include <asm/pdc.h>
 
 /* The control of the LEDs and LCDs on PARISC-machines have to be done 
-   completely in software. The necessary calculations are done during every
-   interrupt and since the calculations may consume relatively much CPU-time
-   some of the calculations can be turned off with the following defines */
+   completely in software. The necessary calculations are done in a tasklet
+   which is scheduled at every timer interrupt and since the calculations 
+   may consume relatively much CPU-time some of the calculations can be 
+   turned off with the following defines */
 #undef NO_HEARTBEAT
 #undef NO_DISKIO
 #undef NO_LAN_RXTX
 
-
 #if 0
 #define DPRINTK(x)	printk x
 #else
@@ -148,11 +149,10 @@
    ** 
    ** led_LCD_driver()
    ** 
-   ** The logic of the LCD driver is, that we write at every interrupt
+   ** The logic of the LCD driver is, that we write at every scheduled call
    ** only to one of LCD_CMD_REG _or_ LCD_DATA_REG - registers.
-   ** That way we don't need to let this interrupt routine busywait
-   ** the "min_cmd_delay", since idlewaiting in an interrupt-routine is
-   ** allways a BAD IDEA !
+   ** That way we don't need to let this tasklet busywait for min_cmd_delay
+   ** milliseconds.
    **
    ** TODO: check the value of "min_cmd_delay" against the value of HZ.
    **   
@@ -204,6 +204,8 @@
    ** 
    ** calculate the TX- & RX-troughput on the network interfaces in
    ** the system for usage in the LED code
+   **
+   ** (analog to dev_get_info() from net/core/dev.c)
    **   
  */
 #ifndef NO_LAN_RXTX
@@ -218,10 +220,11 @@
 
 	rx_total = tx_total = 0;
 	
-	/* are we really allowed to lock dev during the interrupt this way ? */
+	/* we are running as a tasklet, so locking dev_base 
+	 * for reading should be OK */
 	read_lock(&dev_base_lock);
 	for (dev = dev_base; dev != NULL; dev = dev->next) {
-	    if (dev->get_stats) { /* && dev->if_port!=IF_PORT_UNKNOWN */
+	    if (dev->get_stats) { 
 	        stats = dev->get_stats(dev);
 		rx_total += stats->rx_packets;
 		tx_total += stats->tx_packets;
@@ -282,31 +285,29 @@
 
 
 /*
-   ** led_interrupt_func()
+   ** led_tasklet_func()
    ** 
-   ** is called at every timer interrupt from time.c,
+   ** is scheduled at every timer interrupt from time.c and
    ** updates the chassis LCD/LED 
 
     TODO:
-    - display load average (older machines like 715/64 have 4 "free" LED's for that!) 
-    - optimizations (we are still in an interrupt-function !!!)  
-
+    - display load average (older machines like 715/64 have 4 "free" LED's for that)
+    - optimizations
  */
 
 static unsigned char currentleds;	/* stores current value of the LEDs */
-static unsigned char led_stop;		/* stop LED activity at system shutdown */
 
 #define HEARTBEAT_LEN (HZ*6/100)
 #define HEARTBEAT_2ND_RANGE_START (HZ*22/100)
 #define HEARTBEAT_2ND_RANGE_END   (HEARTBEAT_2ND_RANGE_START + HEARTBEAT_LEN)
 
-void led_interrupt_func(void)
+static void led_tasket_func(unsigned long unused)
 {
 	static unsigned int count, count_HZ;
 	static unsigned char lastleds;
 
-	/* exit, if not initialized */
-	if (led_stop || !led_func_ptr)
+	/* exit if not initialized */
+	if (!led_func_ptr)
 	    return;
 
 	/* increment the local counters */
@@ -364,7 +365,10 @@
 	}
 }
 
+/* main led tasklet struct (scheduled from time.c) */
+DECLARE_TASKLET_DISABLED(led_tasklet, led_tasket_func, 0);
 
+
 /*
    ** led_halt()
    ** 
@@ -393,9 +397,8 @@
 	default:		return NOTIFY_DONE;
 	}
 	
-	/* stop the LED/LCD interrupt handler */
-	led_stop = 1;
-	mdelay(1 + 999 / HZ);
+	/* completely stop the LED/LCD tasklet */
+	tasklet_disable(&led_tasklet);
 
 	if (lcd_info.model == DISPLAY_MODEL_LCD)
 		lcd_print(txt);
@@ -430,10 +433,8 @@
 		LCD_DATA_REG = data_reg;
 		printk(KERN_INFO "LCD display at %p,%p registered\n", 
 			LCD_CMD_REG , LCD_DATA_REG);
-		led_stop = 1;
 		led_func_ptr = led_LCD_driver;
 		lcd_print( "Linux " UTS_RELEASE );
-		led_stop = 0;
 		break;
 
 	case DISPLAY_MODEL_LASI:
@@ -459,6 +460,9 @@
 	 * register to the reboot notifier chain */
 	initialized++;
 	register_reboot_notifier(&led_notifier);
+
+	/* start the led tasklet for the first time */
+	tasklet_enable(&led_tasklet);
 	
 	return 0;
 }
@@ -494,8 +498,8 @@
    ** lcd_print()
    ** 
    ** Displays the given string on the LCD-Display of newer machines.
-   ** lcd_print() ensures to not be interrupted by the interrupt handler
-   ** led_interrupt_func() with usage of the led_stop variable.
+   ** lcd_print() disables the timer-based led tasklet during its 
+   ** execution and enables it afterwards again.
    **
  */
 int lcd_print( char *str )
@@ -505,9 +509,8 @@
 	if (!led_func_ptr || lcd_info.model != DISPLAY_MODEL_LCD)
 	    return 0;
 	
-	/* temporarily disable the interrupt handler */
-	led_stop++;
-	mdelay(1 + 999 / HZ);
+	/* temporarily disable the led tasklet */
+	tasklet_disable(&led_tasklet);
 
 	/* Set LCD Cursor to 1st character */
 	gsc_writeb(lcd_info.reset_cmd1, LCD_CMD_REG);
@@ -522,8 +525,8 @@
 	    udelay(lcd_info.min_cmd_delay);
 	}
 	
-	/* re-enable the interrupt handler */
-	led_stop--;
+	/* re-enable the led tasklet */
+	tasklet_enable(&led_tasklet);
 
 	return lcd_info.lcd_width;
 }
Index: arch/parisc/kernel/time.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/time.c,v
retrieving revision 1.13
diff -u -r1.13 time.c
--- time.c	2001/07/07 00:23:44	1.13
+++ time.c	2001/07/15 18:44:13
@@ -73,7 +73,7 @@
 	do_timer(regs);
     
 #ifdef CONFIG_CHASSIS_LCD_LED
-	led_interrupt_func();
+	tasklet_schedule(&led_tasklet);
 #endif
 }