summaryrefslogtreecommitdiffstats
path: root/arch/m68k/q40
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
commitd6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch)
treee2be02f33984c48ec019c654051d27964e42c441 /arch/m68k/q40
parent609d1e803baf519487233b765eb487f9ec227a18 (diff)
Merge with 2.3.19.
Diffstat (limited to 'arch/m68k/q40')
-rw-r--r--arch/m68k/q40/README30
-rw-r--r--arch/m68k/q40/config.c30
-rw-r--r--arch/m68k/q40/q40ints.c179
3 files changed, 171 insertions, 68 deletions
diff --git a/arch/m68k/q40/README b/arch/m68k/q40/README
index 5433796cb..60134d9de 100644
--- a/arch/m68k/q40/README
+++ b/arch/m68k/q40/README
@@ -7,7 +7,7 @@ available from this place and ftp.uni-erlangen.de/linux/680x0/q40/
and mirrors.
Hints to documentation usually refer to the linux source tree in
-/usr/src/linux unless URL given.
+/usr/src/linux/Documentation unless URL given.
It seems IRQ unmasking can't be safely done on a Q40. Autoprobing is
not yet implemented - do not try it! (See below)
@@ -18,8 +18,8 @@ particular device drivers.
The floppy imposes a very high interrupt load on the CPU, approx 30K/s.
When something blocks interrupts (HD) it will loose some of them, so far
this is not known to have caused any data loss. On hihgly loaded systems
-it can make the floppy very slow. Other Q40 OS' simply poll the floppy
-for this reason - something that can't be done in Linux.
+it can make the floppy very slow or practicaly stop. Other Q40 OS' simply
+poll the floppy for this reason - something that can't be done in Linux.
Only possible cure is getting a 82072 contoler with fifo instead of
the 8272A
@@ -48,7 +48,7 @@ Debugging
Upon startup the kernel will usually output "ABCQGHIJ" into the SRAM,
preceded by the booter signature. This is a trace just in case something
went wrong during earliest setup stages.
-*Changed* to preserve SRAM contents by default, this is only done when
+**Changed** to preserve SRAM contents by default, this is only done when
requested - SRAM must start with '%LX$' signature to do this. '-d' option
to 'lxx' loader enables this.
@@ -92,12 +92,22 @@ Interrupts
==========
q40 master chip handles only level triggered interrupts :-((
-further limitation is no disabling etc. Unless someone finds
-some ingenious clue this means autoprobing will never work.
-Parallel port interrupts cause most trouble..
-
-IRQ sharing is not yet implemented.
-
+further limitation is no disabling etc. There is NO WAY to remove
+an ISA irq request other than serve the HW specific control register,
+the ISA irq lines are connected straight to the CPU ipl1 pin..
+
+IRQ sharing is not yet implemented but this should be only a minor
+problem..
+
+Linux has some requirements wrt interrupt architecture, these are
+to my knowledge:
+ (a) interrupt handler must not be reentered even when sti() is called
+ (b) working enable/disable_irq
+
+Luckily these requirements are only important for drivers shared
+with other architectures - ide,serial,parallel, ethernet..
+q40ints.c now contains a trivial hack for (a), however (b) could
+be only solved by driver-specific code
Keyboard
========
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
index 0c6871f88..df0a57762 100644
--- a/arch/m68k/q40/config.c
+++ b/arch/m68k/q40/config.c
@@ -1,18 +1,17 @@
/*
* arch/m68k/q40/config.c
*
+ * Copyright (C) 1999 Richard Zidlicky
+ *
* originally based on:
*
* linux/bvme/config.c
*
- * Copyright (C) 1993 Hamish Macdonald
- *
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file README.legal in the main directory of this archive
* for more details.
*/
-#include <stdarg.h>
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -24,6 +23,7 @@
#include <linux/init.h>
#include <linux/major.h>
+#include <asm/rtc.h>
#include <asm/bootinfo.h>
#include <asm/system.h>
#include <asm/pgtable.h>
@@ -135,12 +135,11 @@ int q40_kbdrate (struct kbd_repeat *k)
void q40_reset()
{
- printk ("\n\n*******************************************\n"
- "Called q40_reset : press the RESET button!! \n");
- printk( "*******************************************\n");
-
- while(1)
- ;
+ printk ("\n\n*******************************************\n"
+ "Called q40_reset : press the RESET button!! \n"
+ "*******************************************\n");
+
+ while(1) ;
}
static void q40_get_model(char *model)
@@ -158,7 +157,7 @@ static int q40_get_hardware_list(char *buffer)
}
-__initfunc(void config_q40(void))
+void __init config_q40(void)
{
mach_sched_init = q40_sched_init; /* ok */
/*mach_kbdrate = q40_kbdrate;*/ /* unneeded ?*/
@@ -233,6 +232,9 @@ void q40_mksound(unsigned int hz, unsigned int ticks)
}
static void (*q40_timer_routine)(int, void *, struct pt_regs *);
+static short rtc_oldsecs=0;
+unsigned rtc_irq_flags=0;
+unsigned rtc_irq_ctrl=0;
static void q40_timer_int (int irq, void *dev_id, struct pt_regs *fp)
{
@@ -251,6 +253,14 @@ static void q40_timer_int (int irq, void *dev_id, struct pt_regs *fp)
*DAC_LEFT=sval;
*DAC_RIGHT=sval;
}
+#ifdef CONFIG_Q40RTC
+ if (rtc_irq_ctrl && (rtc_oldsecs != RTC_SECS))
+ {
+ rtc_oldsecs = RTC_SECS;
+ rtc_irq_flags = RTC_UIE;
+ rtc_interrupt();
+ }
+#endif
if (ql_ticks) return;
#endif
q40_timer_routine(irq, dev_id, fp);
diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c
index e9b5a5b1f..c6625aad8 100644
--- a/arch/m68k/q40/q40ints.c
+++ b/arch/m68k/q40/q40ints.c
@@ -29,7 +29,7 @@
* 3,4,5,6,7,10,11,14,15 : ISA dev IRQs
* 16-31: reserved
* 32 : keyboard int
- * 33 : frame int (50 Hz periodic timer)
+ * 33 : frame int (50/200 Hz periodic timer)
* 34 : sample int (10/20 KHz periodic timer)
*
*/
@@ -45,20 +45,21 @@ extern void (*q40_sys_default_handler[]) (int, void *, struct pt_regs *); /* ad
static void q40_defhand (int irq, void *dev_id, struct pt_regs *fp);
static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs);
-/*
- * This should ideally be 4 elements only, for speed.
- */
#define DEVNAME_SIZE 24
-static struct {
+static struct q40_irq_node {
void (*handler)(int, void *, struct pt_regs *);
unsigned long flags;
void *dev_id;
+ /* struct q40_irq_node *next;*/
char devname[DEVNAME_SIZE];
unsigned count;
+ unsigned short state;
} irq_tab[Q40_IRQ_MAX+1];
+short unsigned q40_ablecount[Q40_IRQ_MAX+1];
+
/*
* void q40_init_IRQ (void)
*
@@ -78,8 +79,11 @@ void q40_init_IRQ (void)
irq_tab[i].handler = q40_defhand;
irq_tab[i].flags = IRQ_FLG_STD;
irq_tab[i].dev_id = NULL;
+ /* irq_tab[i].next = NULL;*/
irq_tab[i].devname[0] = 0;
irq_tab[i].count = 0;
+ irq_tab[i].state =0;
+ q40_ablecount[i]=0; /* all enabled */
}
/* setup handler for ISA ints */
@@ -108,23 +112,20 @@ int q40_request_irq(unsigned int irq,
}
/* test for ISA ints not implemented by HW */
- if (irq<15)
+ switch (irq)
{
- switch (irq){
- case 1: case 2: case 8: case 9:
- case 12: case 13:
- printk("%s: ISA IRQ %d from %s not implemented by HW\n", __FUNCTION__, irq, devname);
- return -ENXIO;
- default:
- }
+ case 1: case 2: case 8: case 9:
+ case 12: case 13:
+ printk("%s: ISA IRQ %d from %s not implemented by HW\n", __FUNCTION__, irq, devname);
+ return -ENXIO;
+ case 11:
+ printk("warning IRQ 10 and 11 not distinguishable\n");
+ irq=10;
+ default:
}
if (irq<Q40_IRQ_TIMER)
{
- if (irq==11) {
- printk("warning IRQ 10 and 11 not distinguishable\n");
- irq=10;
- }
if (!(irq_tab[irq].flags & IRQ_FLG_STD))
{
if (irq_tab[irq].flags & IRQ_FLG_LOCK)
@@ -145,6 +146,7 @@ int q40_request_irq(unsigned int irq,
irq_tab[irq].flags = flags;
irq_tab[irq].dev_id = dev_id;
strncpy(irq_tab[irq].devname,devname,DEVNAME_SIZE);
+ irq_tab[irq].state = 0;
return 0;
}
else {
@@ -163,30 +165,33 @@ void q40_free_irq(unsigned int irq, void *dev_id)
}
/* test for ISA ints not implemented by HW */
- if (irq<15) {
- switch (irq){
+ switch (irq)
+ {
case 1: case 2: case 8: case 9:
case 12: case 13:
- printk("%s: ISA IRQ %d from %x illegal\n", __FUNCTION__, irq, (unsigned)dev_id);
- return;
+ printk("%s: ISA IRQ %d from %x illegal\n", __FUNCTION__, irq, (unsigned)dev_id);
+ return;
+ case 11: irq=10;
default:
- }
- }
+ }
- if (irq<Q40_IRQ_TIMER){
- if (irq==11) irq=10;
- if (irq_tab[irq].dev_id != dev_id)
- printk("%s: Removing probably wrong IRQ %d from %s\n",
- __FUNCTION__, irq, irq_tab[irq].devname);
-
- irq_tab[irq].handler = q40_defhand;
- irq_tab[irq].flags = IRQ_FLG_STD;
- irq_tab[irq].dev_id = NULL;
- /* irq_tab[irq].devname = NULL; */
- } else { /* == Q40_IRQ_TIMER */
- sys_free_irq(4,dev_id);
- sys_free_irq(6,dev_id);
- }
+ if (irq<Q40_IRQ_TIMER)
+ {
+ if (irq_tab[irq].dev_id != dev_id)
+ printk("%s: Removing probably wrong IRQ %d from %s\n",
+ __FUNCTION__, irq, irq_tab[irq].devname);
+
+ irq_tab[irq].handler = q40_defhand;
+ irq_tab[irq].flags = IRQ_FLG_STD;
+ irq_tab[irq].dev_id = NULL;
+ /* irq_tab[irq].devname = NULL; */
+ /* do not reset state !! */
+ }
+ else
+ { /* == Q40_IRQ_TIMER */
+ sys_free_irq(4,dev_id);
+ sys_free_irq(6,dev_id);
+ }
}
#if 1
@@ -224,11 +229,16 @@ static struct IRQ_TABLE eirqs[]={
{0,0}};
-/* complaiun only this many times about spurious ints : */
+/* complain only this many times about spurious ints : */
static int ccleirq=60; /* ISA dev IRQ's*/
static int cclirq=60; /* internal */
-/* FIX: add IRQ_INPROGRESS,mask,unmask,probing.... */
+/* FIX: add shared ints,mask,unmask,probing.... */
+
+/* this is an awfull hack.. */
+#define IRQ_INPROGRESS 1
+static int disabled=0;
+/*static unsigned short saved_mask;*/
void q40_irq2_handler (int vec, void *devname, struct pt_regs *fp)
{
@@ -238,11 +248,6 @@ void q40_irq2_handler (int vec, void *devname, struct pt_regs *fp)
unsigned mer;
int irq,i;
- /*
- * more than 1 bit might be set, must handle atmost 1 int source,
- * - handle only those with explicitly set handler
- */
-
if ((mir&IRQ_SER_MASK) || (mir&IRQ_EXT_MASK))
{
@@ -257,9 +262,37 @@ void q40_irq2_handler (int vec, void *devname, struct pt_regs *fp)
irq=eirqs[i].irq;
irq_tab[irq].count++;
if (irq_tab[irq].handler == q40_defhand )
- continue; /* ignore uninited INTs :-( */
-
+ {
+ printk("handler for IRQ %d not defined\n",irq);
+ continue; /* ignore uninited INTs :-( */
+ }
+
+ if ( irq_tab[irq].state & IRQ_INPROGRESS )
+ {
+ /*printk("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n",irq,disabled ? "already" : "not yet"); */
+
+ /*saved_mask = fp->sr;*/
+ fp->sr = (fp->sr & (~0x700))+0x200;
+ disabled=1;
+ return;
+ }
+ irq_tab[irq].state |= IRQ_INPROGRESS;
irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp);
+
+ /* naively enable everything, if that fails than */
+ /* this function will be reentered immediately thus */
+ /* getting another chance to disable the IRQ */
+
+ irq_tab[irq].state &= ~IRQ_INPROGRESS;
+ if ( disabled )
+ {
+ /*printk("reenabling irq %d\n",irq); */
+ fp->sr = (fp->sr & (~0x700)); /*saved_mask; */
+ disabled=0;
+ }
+ else if ( fp->sr &0x200 )
+ printk("exiting irq handler: fp->sr &0x200 !!\n");
+
return;
}
}
@@ -279,7 +312,17 @@ void q40_irq2_handler (int vec, void *devname, struct pt_regs *fp)
if (irq_tab[irq].handler == q40_defhand )
continue; /* ignore uninited INTs :-( */
+ /* the INPROGRESS stuff should be completely useless*/
+ /* for internal ints, nevertheless test it..*/
+ if ( irq_tab[irq].state & IRQ_INPROGRESS )
+ {
+ /*disable_irq(irq);
+ return;*/
+ printk("rentering handler for IRQ %d !!\n",irq);
+ }
irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp);
+ irq_tab[irq].state &= ~IRQ_INPROGRESS;
+ /*enable_irq(irq);*/ /* better not try luck !*/
return;
}
}
@@ -327,19 +370,59 @@ static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs)
sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler
};
+int irq_disabled=0;
void q40_enable_irq (unsigned int irq)
{
+ /* enable ISA iqs */
+ if ( irq>=0 && irq<=15 ) /* the moderately bad case */
+ master_outb(1,EXT_ENABLE_REG);
+#if 0
+ unsigned long flags;
+ int i;
+
+ if (irq>=10 && irq <= 15)
+ {
+ if ( !(--q40_ablecount[irq]))
+ for (i=10,irq_disabled=0; i<=15; i++)
+ {
+ irq_disabled |= (q40_ablecount[irq] !=0);
+ }
+ if ( !irq_disabled )
+ {
+ save_flags(flags);
+ restore_flags(flags & (~0x700));
+ }
+ }
+#endif
}
void q40_disable_irq (unsigned int irq)
{
+ /* disable ISA iqs : only do something if the driver has been
+ * verified to be Q40 "compatible" - right now only IDE
+ * Any driver should not attempt to sleep accross disable_irq !!
+ */
+
+ if ( irq>=10 && irq<=15 ) /* the moderately bad case */
+ master_outb(0,EXT_ENABLE_REG);
+#if 0
+ unsigned long flags;
+
+ if (irq>=10 && irq <= 15)
+ {
+ save_flags(flags);
+ restore_flags(flags | 0x200 );
+ irq_disabled=1;
+ q40_ablecount[irq]++;
+ }
+#endif
}
unsigned long q40_probe_irq_on (void)
{
- printk("sorry, irq probing not yet implemented - reconfigure the driver to avoid this\n");
- return 0;
+ printk("irq probing not working - reconfigure the driver to avoid this\n");
+ return -1;
}
int q40_probe_irq_off (unsigned long irqs)
{