[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
}