diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
commit | d6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch) | |
tree | e2be02f33984c48ec019c654051d27964e42c441 /arch/m68k/q40 | |
parent | 609d1e803baf519487233b765eb487f9ec227a18 (diff) |
Merge with 2.3.19.
Diffstat (limited to 'arch/m68k/q40')
-rw-r--r-- | arch/m68k/q40/README | 30 | ||||
-rw-r--r-- | arch/m68k/q40/config.c | 30 | ||||
-rw-r--r-- | arch/m68k/q40/q40ints.c | 179 |
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) { |