sun3ints.c 5.85 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
 /*
Linus Torvalds's avatar
Linus Torvalds committed
2
 * linux/arch/m68k/sun3/sun3ints.c -- Sun-3(x) Linux interrupt handling code
Linus Torvalds's avatar
Linus Torvalds committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 */

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
#include <linux/interrupt.h>
#include <asm/segment.h>
#include <asm/intersil.h>
#include <asm/oplib.h>
#include <asm/sun3ints.h>
Linus Torvalds's avatar
Linus Torvalds committed
18
#include <linux/seq_file.h>
Linus Torvalds's avatar
Linus Torvalds committed
19 20

extern void sun3_leds (unsigned char);
21
static irqreturn_t sun3_inthandle(int irq, void *dev_id, struct pt_regs *fp);
Linus Torvalds's avatar
Linus Torvalds committed
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39

void sun3_disable_interrupts(void)
{
	sun3_disable_irq(0);
}

void sun3_enable_interrupts(void)
{
	sun3_enable_irq(0);
}	

int led_pattern[8] = {
       ~(0x80), ~(0x01),
       ~(0x40), ~(0x02),
       ~(0x20), ~(0x04),
       ~(0x10), ~(0x08)
};

Linus Torvalds's avatar
Linus Torvalds committed
40
volatile unsigned char* sun3_intreg;
Linus Torvalds's avatar
Linus Torvalds committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61

void sun3_insert_irq(irq_node_t **list, irq_node_t *node)
{
}

void sun3_delete_irq(irq_node_t **list, void *dev_id)
{
}

void sun3_enable_irq(unsigned int irq)
{
	*sun3_intreg |=  (1<<irq);
}

void sun3_disable_irq(unsigned int irq)
{
	*sun3_intreg &= ~(1<<irq);
}

inline void sun3_do_irq(int irq, struct pt_regs *fp)
{
62
	kstat_cpu(0).irqs[SYS_IRQS + irq]++;
Linus Torvalds's avatar
Linus Torvalds committed
63 64 65 66
	*sun3_intreg &= ~(1<<irq);
	*sun3_intreg |=  (1<<irq);
}

67
static irqreturn_t sun3_int7(int irq, void *dev_id, struct pt_regs *fp)
Linus Torvalds's avatar
Linus Torvalds committed
68 69
{
	sun3_do_irq(irq,fp);
70 71 72
	if(!(kstat_cpu(0).irqs[SYS_IRQS + irq] % 2000)) 
		sun3_leds(led_pattern[(kstat_cpu(0).irqs[SYS_IRQS+irq]%16000)
			  /2000]);
73
	return IRQ_HANDLED;
Linus Torvalds's avatar
Linus Torvalds committed
74 75
}

76
static irqreturn_t sun3_int5(int irq, void *dev_id, struct pt_regs *fp)
Linus Torvalds's avatar
Linus Torvalds committed
77
{
78
        kstat_cpu(0).irqs[SYS_IRQS + irq]++;
Linus Torvalds's avatar
Linus Torvalds committed
79
#ifdef CONFIG_SUN3
Linus Torvalds's avatar
Linus Torvalds committed
80
	intersil_clear();
Linus Torvalds's avatar
Linus Torvalds committed
81 82
#endif
        *sun3_intreg &= ~(1<<irq);
Linus Torvalds's avatar
Linus Torvalds committed
83
        *sun3_intreg |=  (1<<irq);
Linus Torvalds's avatar
Linus Torvalds committed
84 85 86
#ifdef CONFIG_SUN3
	intersil_clear();
#endif
Linus Torvalds's avatar
Linus Torvalds committed
87
        do_timer(fp);
88 89
        if(!(kstat_cpu(0).irqs[SYS_IRQS + irq] % 20))
                sun3_leds(led_pattern[(kstat_cpu(0).irqs[SYS_IRQS+irq]%160)
Linus Torvalds's avatar
Linus Torvalds committed
90
                /20]);
91
	return IRQ_HANDLED;
Linus Torvalds's avatar
Linus Torvalds committed
92 93 94 95
}

/* handle requested ints, excepting 5 and 7, which always do the same
   thing */
96
irqreturn_t (*sun3_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
97 98 99 100 101 102 103 104
	[0] = sun3_inthandle,
	[1] = sun3_inthandle,
	[2] = sun3_inthandle,
	[3] = sun3_inthandle,
	[4] = sun3_inthandle,
	[5] = sun3_int5,
	[6] = sun3_inthandle,
	[7] = sun3_int7
105 106
};

107 108 109 110
static const char *dev_names[SYS_IRQS] = {
	[5] = "timer",
	[7] = "int7 handler"
};
Linus Torvalds's avatar
Linus Torvalds committed
111
static void *dev_ids[SYS_IRQS];
112
static irqreturn_t (*sun3_inthandler[SYS_IRQS])(int, void *, struct pt_regs *) = {
113 114
	[5] = sun3_int5,
	[7] = sun3_int7
Linus Torvalds's avatar
Linus Torvalds committed
115
};
116
static irqreturn_t (*sun3_vechandler[SUN3_INT_VECS])(int, void *, struct pt_regs *);
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
static void *vec_ids[SUN3_INT_VECS];
static const char *vec_names[SUN3_INT_VECS];
static int vec_ints[SUN3_INT_VECS];


int show_sun3_interrupts(struct seq_file *p, void *v)
{
	int i;

	for(i = 0; i < (SUN3_INT_VECS-1); i++) {
		if(sun3_vechandler[i] != NULL) {
			seq_printf(p, "vec %3d: %10u %s\n", i+64, 
				   vec_ints[i],
				   (vec_names[i]) ? vec_names[i] :
				   "sun3_vechandler");
		}
	}

	return 0;
}
Linus Torvalds's avatar
Linus Torvalds committed
137

138
static irqreturn_t sun3_inthandle(int irq, void *dev_id, struct pt_regs *fp)
Linus Torvalds's avatar
Linus Torvalds committed
139
{
Linus Torvalds's avatar
Linus Torvalds committed
140
	if(sun3_inthandler[irq] == NULL)
Linus Torvalds's avatar
Linus Torvalds committed
141 142
		panic ("bad interrupt %d received (id %p)\n",irq, dev_id);

143
        kstat_cpu(0).irqs[SYS_IRQS + irq]++;
Linus Torvalds's avatar
Linus Torvalds committed
144 145
        *sun3_intreg &= ~(1<<irq);

Linus Torvalds's avatar
Linus Torvalds committed
146
	sun3_inthandler[irq](irq, dev_ids[irq], fp);
147
	return IRQ_HANDLED;
Linus Torvalds's avatar
Linus Torvalds committed
148 149
}

150
static irqreturn_t sun3_vec255(int irq, void *dev_id, struct pt_regs *fp)
Linus Torvalds's avatar
Linus Torvalds committed
151 152
{
//	intersil_clear();
153
	return IRQ_HANDLED;
Linus Torvalds's avatar
Linus Torvalds committed
154 155 156 157 158 159
}

void sun3_init_IRQ(void)
{
	int i;

Linus Torvalds's avatar
Linus Torvalds committed
160 161
	*sun3_intreg = 1;

Linus Torvalds's avatar
Linus Torvalds committed
162 163 164
	for(i = 0; i < SYS_IRQS; i++)
	{
		if(dev_names[i])
165 166
			cpu_request_irq(i, sun3_default_handler[i], 0,
					dev_names[i], NULL);
Linus Torvalds's avatar
Linus Torvalds committed
167 168
	}

Linus Torvalds's avatar
Linus Torvalds committed
169 170 171 172
	for(i = 0; i < 192; i++) 
		sun3_vechandler[i] = NULL;
	
	sun3_vechandler[191] = sun3_vec255;
Linus Torvalds's avatar
Linus Torvalds committed
173 174
}
                                
175
int sun3_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
Linus Torvalds's avatar
Linus Torvalds committed
176 177 178
                      unsigned long flags, const char *devname, void *dev_id)
{

Linus Torvalds's avatar
Linus Torvalds committed
179 180 181 182 183 184 185 186 187 188 189
	if(irq < SYS_IRQS) {
		if(sun3_inthandler[irq] != NULL) {
			printk("sun3_request_irq: request for irq %d -- already taken!\n", irq);
			return 1;
		}
		
		sun3_inthandler[irq] = handler;
		dev_ids[irq] = dev_id;
		dev_names[irq] = devname;
		
		/* setting devname would be nice */
190 191
		cpu_request_irq(irq, sun3_default_handler[irq], 0, devname,
				NULL);
Linus Torvalds's avatar
Linus Torvalds committed
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206

		return 0;
	} else {
		if((irq >= 64) && (irq <= 255)) {
		        int vec;

			vec = irq - 64;
			if(sun3_vechandler[vec] != NULL) {
				printk("sun3_request_irq: request for vec %d -- already taken!\n", irq);
				return 1;
			}

			sun3_vechandler[vec] = handler;
			vec_ids[vec] = dev_id;
			vec_names[vec] = devname;
207
			vec_ints[vec] = 0;
Linus Torvalds's avatar
Linus Torvalds committed
208 209 210 211
			
			return 0;
		}
	}
Linus Torvalds's avatar
Linus Torvalds committed
212

Linus Torvalds's avatar
Linus Torvalds committed
213 214
	printk("sun3_request_irq: invalid irq %d\n", irq);
	return 1;
Linus Torvalds's avatar
Linus Torvalds committed
215 216 217

}
                        
Linus Torvalds's avatar
Linus Torvalds committed
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
void sun3_free_irq(unsigned int irq, void *dev_id)
{

	if(irq < SYS_IRQS) {
		if(sun3_inthandler[irq] == NULL) 
			panic("sun3_free_int: attempt to free unused irq %d\n", irq);
		if(dev_ids[irq] != dev_id)
			panic("sun3_free_int: incorrect dev_id for irq %d\n", irq);
		
		sun3_inthandler[irq] = NULL;
		return;
	} else if((irq >= 64) && (irq <= 255)) {
		int vec;

		vec = irq - 64;
		if(sun3_vechandler[vec] == NULL)
			panic("sun3_free_int: attempt to free unused vector %d\n", irq);
		if(vec_ids[irq] != dev_id)
			panic("sun3_free_int: incorrect dev_id for vec %d\n", irq);
		
		sun3_vechandler[vec] = NULL;
		return;
	} else {
		panic("sun3_free_irq: invalid irq %d\n", irq);
	}		
}

245
irqreturn_t sun3_process_int(int irq, struct pt_regs *regs)
Linus Torvalds's avatar
Linus Torvalds committed
246 247 248 249 250 251 252 253
{

	if((irq >= 64) && (irq <= 255)) {
		int vec;

		vec = irq - 64;
		if(sun3_vechandler[vec] == NULL) 
			panic ("bad interrupt vector %d received\n",irq);
254 255

		vec_ints[vec]++;
256
		return sun3_vechandler[vec](irq, vec_ids[vec], regs);
Linus Torvalds's avatar
Linus Torvalds committed
257 258 259 260 261
	} else {
		panic("sun3_process_int: unable to handle interrupt vector %d\n",
		      irq);
	}
}