diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-06-17 13:25:08 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-06-17 13:25:08 +0000 |
commit | 59223edaa18759982db0a8aced0e77457d10c68e (patch) | |
tree | 89354903b01fa0a447bffeefe00df3044495db2e /arch/sparc/kernel | |
parent | db7d4daea91e105e3859cf461d7e53b9b77454b2 (diff) |
Merge with Linux 2.3.6. Sorry, this isn't tested on silicon, I don't
have a MIPS box at hand.
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r-- | arch/sparc/kernel/ebus.c | 92 | ||||
-rw-r--r-- | arch/sparc/kernel/entry.S | 50 | ||||
-rw-r--r-- | arch/sparc/kernel/head.S | 12 | ||||
-rw-r--r-- | arch/sparc/kernel/init_task.c | 6 | ||||
-rw-r--r-- | arch/sparc/kernel/irq.c | 8 | ||||
-rw-r--r-- | arch/sparc/kernel/pcic.c | 419 | ||||
-rw-r--r-- | arch/sparc/kernel/ptrace.c | 21 | ||||
-rw-r--r-- | arch/sparc/kernel/setup.c | 4 | ||||
-rw-r--r-- | arch/sparc/kernel/sys_sunos.c | 10 |
9 files changed, 472 insertions, 150 deletions
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c index 7c3eda88e..ae84dde6b 100644 --- a/arch/sparc/kernel/ebus.c +++ b/arch/sparc/kernel/ebus.c @@ -1,9 +1,10 @@ -/* $Id: ebus.c,v 1.2 1998/10/07 11:35:16 jj Exp $ +/* $Id: ebus.c,v 1.3 1999/06/03 15:02:09 davem Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) * * Adopted for sparc by V. Roganov and G. Raiko. + * Fixes for different platforms by Pete Zaitcev. */ #include <linux/config.h> @@ -25,9 +26,9 @@ #undef DEBUG_FILL_EBUS_DEV #ifdef PROM_DEBUG -#define dprintf prom_printf +#define dprintk prom_printf #else -#define dprintf printk +#define dprintk printk #endif struct linux_ebus *ebus_chain = 0; @@ -48,6 +49,9 @@ extern int flash_init(void); extern int envctrl_init(void); #endif +/* We are together with pcic.c under CONFIG_PCI. */ +extern unsigned int pcic_pin_to_irq(unsigned int, char *name); + static inline unsigned long ebus_alloc(size_t size) { return (unsigned long)kmalloc(size, GFP_ATOMIC); @@ -66,6 +70,7 @@ __initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg, strcpy(dev->prom_name, lbuf); len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs)); + if (len == -1) len = 0; dev->num_addrs = len / sizeof(regs[0]); for (i = 0; i < dev->num_addrs; i++) { @@ -77,22 +82,36 @@ __initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg, dev->base_address[i] = dev->parent->base_address[regs[i]]; } + /* + * Houston, we have a problem... + * Sometimes PROM supplies absolutely meaningless properties. + * Still, we take what it gives since we have nothing better. + * Children of ebus may be wired on any input pin of PCIC. + */ len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs)); if ((len == -1) || (len == 0)) { dev->num_irqs = 0; - /* - * Oh, well, some PROMs don't export interrupts - * property to children of EBus devices... - * - * Be smart about PS/2 keyboard and mouse. - */ - if (!strcmp(dev->parent->prom_name, "8042")) { + dev->irqs[0] = 0; + if (dev->parent->num_irqs != 0) { dev->num_irqs = 1; dev->irqs[0] = dev->parent->irqs[0]; +/* P3 remove */ printk("EBUS: dev %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); } } else { dev->num_irqs = len / sizeof(irqs[0]); - printk("FIXME: %s irq(%d)\n", dev->prom_name, irqs[0]); + if (irqs[0] == 0 || irqs[0] >= 8) { + /* + * XXX Zero is a valid pin number... + * This works as long as Ebus is not wired to INTA#. + */ + printk("EBUS: %s got bad irq %d from PROM\n", + dev->prom_name, irqs[0]); + dev->num_irqs = 0; + dev->irqs[0] = 0; + } else { + dev->irqs[0] = pcic_pin_to_irq(irqs[0], dev->prom_name); +/* P3 remove */ printk("EBUS: dev %s irq %d from PROM\n", dev->prom_name, dev->irqs[0]); + } } #ifdef DEBUG_FILL_EBUS_DEV @@ -131,7 +150,30 @@ __initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev)) dev->num_addrs = len / sizeof(struct linux_prom_registers); for (i = 0; i < dev->num_addrs; i++) { - n = (regs[i].which_io - 0x10) >> 2; + /* + * XXX Collect JE-1 PROM + * + * Example - JS-E with 3.11: + * /ebus + * regs + * 0x00000000, 0x0, 0x00000000, 0x0, 0x00000000, + * 0x82000010, 0x0, 0xf0000000, 0x0, 0x01000000, + * 0x82000014, 0x0, 0x38800000, 0x0, 0x00800000, + * ranges + * 0x00, 0x00000000, 0x02000010, 0x0, 0x0, 0x01000000, + * 0x01, 0x01000000, 0x02000014, 0x0, 0x0, 0x00800000, + * /ebus/8042 + * regs + * 0x00000001, 0x00300060, 0x00000008, + * 0x00000001, 0x00300060, 0x00000008, + */ + n = regs[i].which_io; + if (n >= 4) { + /* XXX This is copied from old JE-1 by Gleb. */ + n = (regs[i].which_io - 0x10) >> 2; + } else { + ; + } dev->base_address[i] = dev->bus->self->base_address[n]; dev->base_address[i] += regs[i].phys_addr; @@ -141,8 +183,14 @@ __initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev)) (unsigned long)sparc_alloc_io (dev->base_address[i], 0, regs[i].reg_size, dev->prom_name, 0, 0); +#if 0 +/* + * This release_region() screwes those who do sparc_alloc_io(). + * Change drivers which do check_region(). See drivers/block/floppy.c. + */ /* Some drivers call 'check_region', so we release it */ release_region(dev->base_address[i] & PAGE_MASK, PAGE_SIZE); +#endif if (dev->base_address[i] == 0 ) { panic("ebus: unable sparc_alloc_io for dev %s", @@ -154,12 +202,22 @@ __initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev)) len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs)); if ((len == -1) || (len == 0)) { dev->num_irqs = 0; + if ((dev->irqs[0] = dev->bus->self->irq) != 0) { + dev->num_irqs = 1; +/* P3 remove */ printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); + } } else { - dev->num_irqs = len / sizeof(irqs[0]); - -#define IRQ_8042 7 - if (irqs[0] == 4) dev->irqs[0] = IRQ_8042; - printk("FIXME: %s irq(%d)\n", dev->prom_name, irqs[0]); + dev->num_irqs = 1; /* dev->num_irqs = len / sizeof(irqs[0]); */ + if (irqs[0] == 0 || irqs[0] >= 8) { + /* See above for the parent. XXX */ + printk("EBUS: %s got bad irq %d from PROM\n", + dev->prom_name, irqs[0]); + dev->num_irqs = 0; + dev->irqs[0] = 0; + } else { + dev->irqs[0] = pcic_pin_to_irq(irqs[0], dev->prom_name); +/* P3 remove */ printk("EBUS: child %s irq %d from PROM\n", dev->prom_name, dev->irqs[0]); + } } #ifdef DEBUG_FILL_EBUS_DEV diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index 8eeac72b0..ff1ac2497 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.159 1999/05/08 03:00:03 davem Exp $ +/* $Id: entry.S,v 1.160 1999/06/03 15:02:11 davem Exp $ * arch/sparc/kernel/entry.S: Sparc trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1889,4 +1889,52 @@ C_LABEL(restore_current): retl nop +#ifdef CONFIG_PCI +#include <asm/pcic.h> + + .align 4 + .globl linux_trap_ipi15_pcic +linux_trap_ipi15_pcic: + rd %wim, %l3 + SAVE_ALL + + /* + * First deactivate NMI + * or we cannot drop ET, cannot get window spill traps. + * The busy loop is necessary because the PIO error + * sometimes does not go away quickly and we trap again. + */ + sethi %hi(C_LABEL(pcic_regs)), %o1 + ld [%o1 + %lo(C_LABEL(pcic_regs))], %o2 + + ! Get pending status for printouts later. + ld [%o2 + PCI_SYS_INT_PENDING], %o0 + + mov PCI_SYS_INT_PENDING_CLEAR_ALL, %o1 + stb %o1, [%o2 + PCI_SYS_INT_PENDING_CLEAR] +1: + ld [%o2 + PCI_SYS_INT_PENDING], %o1 + andcc %o1, ((PCI_SYS_INT_PENDING_PIO|PCI_SYS_INT_PENDING_PCI)>>24), %g0 + bne 1b + nop + + or %l0, PSR_PIL, %l4 + wr %l4, 0x0, %psr + WRITE_PAUSE + wr %l4, PSR_ET, %psr + WRITE_PAUSE + + call C_LABEL(pcic_nmi) + add %sp, REGWIN_SZ, %o1 ! struct pt_regs *regs + RESTORE_ALL + + .globl C_LABEL(pcic_nmi_trap_patch) +C_LABEL(pcic_nmi_trap_patch): + sethi %hi(linux_trap_ipi15_pcic), %l3 + jmpl %l3 + %lo(linux_trap_ipi15_pcic), %g0 + rd %psr, %l0 + .word 0 + +#endif /* CONFIG_PCI */ + /* End of entry.S */ diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S index 0020770e0..ac78b1407 100644 --- a/arch/sparc/kernel/head.S +++ b/arch/sparc/kernel/head.S @@ -1,11 +1,13 @@ -/* $Id: head.S,v 1.95 1999/04/13 07:40:34 anton Exp $ +/* $Id: head.S,v 1.96 1999/06/03 15:02:15 davem Exp $ * head.S: The initial boot code for the Sparc port of Linux. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1995 Peter Zaitcev (Zaitcev@ipmce.su) + * Copyright (C) 1995,1999 Pete Zaitcev (zaitcev@metabyte.com) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1997 Michael A. Griffith (grif@acm.org) + * + * CompactPCI platform by Eric Brower, 1999. */ #include <linux/version.h> @@ -116,10 +118,10 @@ t_irq11:TRAP_ENTRY_INTERRUPT(11) /* IRQ Floppy Intr. */ t_irq12:TRAP_ENTRY_INTERRUPT(12) /* IRQ Zilog serial chip */ t_irq13:TRAP_ENTRY_INTERRUPT(13) /* IRQ Audio Intr. */ t_irq14:TRAP_ENTRY_INTERRUPT(14) /* IRQ Timer #2 */ + .globl t_nmi #ifndef __SMP__ t_nmi: NMI_TRAP /* Level 15 (NMI) */ #else - .globl t_nmi t_nmi: TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m) #endif t_racc: TRAP_ENTRY(0x20, do_reg_access) /* General Register Access Error */ @@ -842,6 +844,8 @@ got_prop: be 1f cmp %l1, 'm' be 1f + cmp %l1, 's' + be 1f cmp %l1, 'd' be 1f cmp %l1, 'e' @@ -854,6 +858,8 @@ got_prop: ldub [%l1 + 0x4], %l1 cmp %l1, 'm' ! Test for sun4d, sun4e ? be sun4m_init + cmp %l1, 's' ! Treat sun4s as sun4m + be sun4m_init cmp %l1, 'd' ! Let us see how the beast will die be sun4d_init nop diff --git a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c index 156ed4337..dc2bc9171 100644 --- a/arch/sparc/kernel/init_task.c +++ b/arch/sparc/kernel/init_task.c @@ -9,11 +9,13 @@ static struct fs_struct init_fs = INIT_FS; static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; -struct mm_struct init_mm = INIT_MM; +struct mm_struct init_mm = INIT_MM(init_mm); /* .text section in head.S is aligned at 8k boundry and this gets linked * right after that so that the init_task_union is aligned properly as well. * If this is not aligned on a 8k boundry, then you should change code * in etrap.S which assumes it. */ -union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK }; +union task_union init_task_union + __attribute__((__section__(".text"))) = + { INIT_TASK(init_task_union.task) }; diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c index 26f3194bd..1ab0ccbce 100644 --- a/arch/sparc/kernel/irq.c +++ b/arch/sparc/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.93 1999/04/21 06:15:45 anton Exp $ +/* $Id: irq.c,v 1.94 1999/05/28 14:59:20 anton Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device @@ -491,15 +491,13 @@ void handler_irq(int irq, struct pt_regs * regs) extern void smp4m_irq_rotate(int cpu); #endif + irq_enter(cpu, irq); disable_pil_irq(irq); -#if 0 /* FIXME: rotating IRQs halts the machine during SCSI probe. -ecd */ #ifdef __SMP__ /* Only rotate on lower priority IRQ's (scsi, ethernet, etc.). */ if(irq < 10) smp4m_irq_rotate(cpu); #endif -#endif - irq_enter(cpu, irq); action = *(irq + irq_action); kstat.irqs[cpu][irq]++; do { @@ -508,8 +506,8 @@ void handler_irq(int irq, struct pt_regs * regs) action->handler(irq, action->dev_id, regs); action = action->next; } while (action); - irq_exit(cpu, irq); enable_pil_irq(irq); + irq_exit(cpu, irq); } #ifdef CONFIG_BLK_DEV_FD diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index a2beedbf1..a4ae9497e 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -1,10 +1,13 @@ -/* $Id: pcic.c,v 1.5 1999/03/16 00:15:20 davem Exp $ +/* $Id: pcic.c,v 1.6 1999/06/03 15:02:18 davem Exp $ * pcic.c: Sparc/PCI controller support * * Copyright (C) 1998 V. Roganov and G. Raiko * * Code is derived from Ultra/PCI PSYCHO controller support, see that * for author info. + * + * Support for diverse IIep based platforms by Pete Zaitcev. + * CP-1200 by Eric Brower. */ #include <linux/config.h> @@ -16,6 +19,7 @@ #include <asm/ebus.h> #include <asm/sbus.h> /* for sanity check... */ +#include <asm/swift.h> /* for cache flushing. */ #include <asm/io.h> @@ -69,9 +73,99 @@ asmlinkage int sys_pciconfig_write(unsigned long bus, #else +unsigned int pcic_pin_to_irq(unsigned int pin, char *name); + +/* + * I studied different documents and many live PROMs both from 2.30 + * family and 3.xx versions. I came to the amazing conclusion: there is + * absolutely no way to route interrupts in IIep systems relying on + * information which PROM presents. We must hardcode interrupt routing + * schematics. And this actually sucks. -- zaitcev 1999/05/12 + * + * To find irq for a device we determine which routing map + * is in effect or, in other words, on which machine we are running. + * We use PROM name for this although other techniques may be used + * in special cases (Gleb reports a PROMless IIep based system). + * Once we know the map we take device configuration address and + * find PCIC pin number where INT line goes. Then we may either program + * preferred irq into the PCIC or supply the preexisting irq to the device. + * + * XXX Entries for JE-1 are completely bogus. Gleb, Vladimir, please fill them. + */ +struct pcic_ca2irq { + unsigned char busno; /* PCI bus number */ + unsigned char devfn; /* Configuration address */ + unsigned char pin; /* PCIC external interrupt pin */ + unsigned char irq; /* Preferred IRQ (mappable in PCIC) */ + unsigned int force; /* Enforce preferred IRQ */ +}; + +struct pcic_sn2list { + char *sysname; + struct pcic_ca2irq *intmap; + int mapdim; +}; + +/* + * XXX JE-1 is a little known beast. + * One rumor has the map this way: pin 0 - parallel, audio; + * pin 1 - Ethernet; pin 2 - su; pin 3 - PS/2 kbd and mouse. + * All other comparable systems tie serial and keyboard together, + * so we do not code this rumor just yet. + */ +static struct pcic_ca2irq pcic_i_je1[] = { + { 0, 0x01, 1, 6, 1 }, /* Happy Meal */ +}; + +/* XXX JS-E entry is incomplete - PCI Slot 2 address (pin 7)? */ +static struct pcic_ca2irq pcic_i_jse[] = { + { 0, 0x00, 0, 13, 0 }, /* Ebus - serial and keyboard */ + { 0, 0x01, 1, 6, 0 }, /* hme */ + { 0, 0x08, 2, 9, 0 }, /* VGA - we hope not used :) */ + { 0, 0x18, 6, 8, 0 }, /* PCI INTA# in Slot 1 */ + { 0, 0x38, 4, 9, 0 }, /* All ISA devices. Read 8259. */ + { 0, 0x80, 5, 11, 0 }, /* EIDE */ + /* {0,0x88, 0,0,0} - unknown device... PMU? Probably no interrupt. */ + { 0, 0xA0, 4, 9, 0 }, /* USB */ + /* + * Some pins belong to non-PCI devices, we hardcode them in drivers. + * sun4m timers - irq 10, 14 + * PC style RTC - pin 7, irq 4 ? + * Smart card, Parallel - pin 4 shared with USB, ISA + * audio - pin 3, irq 5 ? + */ +}; + +/* SPARCengine-6 was the original release name of CP1200. + * The documentation differs between the two versions + */ +static struct pcic_ca2irq pcic_i_se6[] = { + { 0, 0x08, 0, 2, 0 }, /* SCSI */ + { 0, 0x01, 1, 6, 0 }, /* HME */ + { 0, 0x00, 3, 13, 0 }, /* EBus */ +}; + +/* + * Several entries in this list may point to the same routing map + * as several PROMs may be installed on the same physical board. + */ +#define SN2L_INIT(name, map) \ + { name, map, sizeof(map)/sizeof(struct pcic_ca2irq) } + +static struct pcic_sn2list pcic_known_sysnames[] = { + SN2L_INIT("JE-1-name", pcic_i_je1), /* XXX Gleb, put name here, pls */ + SN2L_INIT("SUNW,JS-E", pcic_i_jse), /* PROLL JavaStation-E */ + SN2L_INIT("SUNW,SPARCengine-6", pcic_i_se6), /* SPARCengine-6/CP-1200 */ + { NULL, NULL, 0 } +}; + static struct linux_pcic PCIC; static struct linux_pcic *pcic = NULL; +unsigned int pcic_regs; +volatile int pcic_speculative; +volatile int pcic_trapped; + static void pci_do_gettimeofday(struct timeval *tv); static void pci_do_settimeofday(struct timeval *tv); @@ -149,6 +243,37 @@ __initfunc(void pcic_probe(void)) pbm->prom_node = node; prom_getstring(node, "name", namebuf, sizeof(namebuf)); strcpy(pbm->prom_name, namebuf); + + { + extern volatile int t_nmi[1]; + extern int pcic_nmi_trap_patch[1]; + + t_nmi[0] = pcic_nmi_trap_patch[0]; + t_nmi[1] = pcic_nmi_trap_patch[1]; + t_nmi[2] = pcic_nmi_trap_patch[2]; + t_nmi[3] = pcic_nmi_trap_patch[3]; + swift_flush_dcache(); + pcic_regs = pcic->pcic_regs; + } + + prom_getstring(prom_root_node, "name", namebuf, sizeof(namebuf)); + { + struct pcic_sn2list *p; + + for (p = pcic_known_sysnames; p->sysname != NULL; p++) { + if (strcmp(namebuf, p->sysname) == 0) + break; + } + pcic->pcic_imap = p->intmap; + pcic->pcic_imdim = p->mapdim; + } + if (pcic->pcic_imap == NULL) { + /* + * We do not panic here for the sake of embedded systems. + */ + printk("PCIC: System %s is unknown, cannot route interrupts\n", + namebuf); + } } __initfunc(void pcibios_init(void)) @@ -166,20 +291,15 @@ __initfunc(void pcibios_init(void)) pcic->pcic_regs, pcic->pcic_io); /* - * FIXME: * Switch off IOTLB translation. - * It'll be great to use IOMMU to handle HME's rings - * but we couldn't. Thus, we have to flush CPU cache - * in HME. */ writeb(PCI_DVMA_CONTROL_IOTLB_DISABLE, pcic->pcic_regs+PCI_DVMA_CONTROL); /* - * FIXME: * Increase mapped size for PCI memory space (DMA access). * Should be done in that order (size first, address second). - * Why we couldn't set up 4GB and forget about it ? + * Why we couldn't set up 4GB and forget about it? XXX */ writel(0xF0000000UL, pcic->pcic_regs+PCI_SIZE_0); writel(0+PCI_BASE_ADDRESS_SPACE_MEMORY, @@ -204,7 +324,7 @@ __initfunc(static int pdev_to_pnode(struct linux_pbm_info *pbm, if(err != 0 && err != -1) { unsigned long devfn = (regs[0].which_io >> 8) & 0xff; if(devfn == pdev->devfn) - return node; /* Match */ + return node; } node = prom_getsibling(node); } @@ -216,9 +336,9 @@ static inline struct pcidev_cookie *pci_devcookie_alloc(void) return kmalloc(sizeof(struct pcidev_cookie), GFP_ATOMIC); } - -static void pcic_map_pci_device (struct pci_dev *dev) { - int node, pcinode; +static void pcic_map_pci_device (struct pci_dev *dev, int node) { + struct linux_prom_pci_assigned_addresses addrs[6]; + int addrlen; int i, j; /* Is any valid address present ? */ @@ -227,74 +347,132 @@ static void pcic_map_pci_device (struct pci_dev *dev) { if (dev->base_address[j]) i++; if (!i) return; /* nothing to do */ + if (node == 0 || node == -1) { + printk("PCIC: no prom node for device ID (%x,%x)\n", + dev->device, dev->vendor); + return; + } + /* * find related address and get it's window length */ - pcinode = prom_getchild(prom_root_node); - pcinode = prom_searchsiblings(pcinode, "pci"); - if (!pcinode) - panic("PCIC: failed to locate 'pci' node"); - - - for (node = prom_getchild(pcinode); node; - node = prom_getsibling(node)) { - struct linux_prom_pci_assigned_addresses addrs[6]; - int addrlen = prom_getproperty(node,"assigned-addresses", + addrlen = prom_getproperty(node,"assigned-addresses", (char*)addrs, sizeof(addrs)); - if (addrlen == -1) - continue; + if (addrlen == -1) { + printk("PCIC: no \"assigned-addresses\" for device (%x,%x)\n", + dev->device, dev->vendor); + return; + } - addrlen /= sizeof(struct linux_prom_pci_assigned_addresses); - for (i = 0; i < addrlen; i++ ) - for (j = 0; j < 6; j++) { - if (!dev->base_address[j] || !addrs[i].phys_lo) - continue; - if (addrs[i].phys_lo == dev->base_address[j]) { - unsigned long address = dev->base_address[j]; - int length = addrs[i].size_lo; - char namebuf[128] = { 0, }; - unsigned long mapaddr, addrflags; - - prom_getstring(node, "name", - namebuf, sizeof(namebuf)); - - /* FIXME: - * failure in allocation too large space - */ - if (length > 0x200000) { + addrlen /= sizeof(struct linux_prom_pci_assigned_addresses); + for (i = 0; i < addrlen; i++ ) + for (j = 0; j < 6; j++) { + if (!dev->base_address[j] || !addrs[i].phys_lo) + continue; + if (addrs[i].phys_lo == dev->base_address[j]) { + unsigned long address = dev->base_address[j]; + int length = addrs[i].size_lo; + char namebuf[128] = { 0, }; + unsigned long mapaddr, addrflags; + + prom_getstring(node, "name", namebuf, sizeof(namebuf)); + + /* + * failure in allocation too large space + */ + if (length > 0x200000) { length = 0x200000; prom_printf("PCIC: map window for device '%s' " "reduced to 2MB !\n", namebuf); - } + } - /* - * Be careful with MEM/IO address flags - */ - if ((address & PCI_BASE_ADDRESS_SPACE) == + /* + * Be careful with MEM/IO address flags + */ + if ((address & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { mapaddr = address & PCI_BASE_ADDRESS_IO_MASK; - } else { + } else { mapaddr = address & PCI_BASE_ADDRESS_MEM_MASK; - } - addrflags = address ^ mapaddr; + } + addrflags = address ^ mapaddr; - dev->base_address[j] = + dev->base_address[j] = (unsigned long)sparc_alloc_io(address, 0, length, namebuf, 0, 0); - if ( dev->base_address[j] == 0 ) + if ( dev->base_address[j] == 0 ) panic("PCIC: failed make mapping for " "pci device '%s' with address %lx\n", namebuf, address); - dev->base_address[j] ^= addrflags; - return; - } + dev->base_address[j] ^= addrflags; + return; } + } + + printk("PCIC: unable to match addresses for device (%x,%x)\n", + dev->device, dev->vendor); +} + +static void pcic_fill_irq(struct pci_dev *dev, int node) { + struct pcic_ca2irq *p; + int i, ivec; + char namebuf[64]; /* P3 remove */ + + if (node == -1) { + strcpy(namebuf, "???"); + } else { + prom_getstring(node, "name", namebuf, sizeof(namebuf)); /* P3 remove */ } - panic("PCIC: unable to locate prom node for pci device (%x,%x) \n", - dev->device, dev->vendor); + if ((p = pcic->pcic_imap) == 0) { + dev->irq = 0; + return; + } + for (i = 0; i < pcic->pcic_imdim; i++) { + if (p->busno == dev->bus->number && p->devfn == dev->devfn) + break; + p++; + } + if (i >= pcic->pcic_imdim) { + printk("PCIC: device %s devfn %02x:%02x not found in %d\n", + namebuf, dev->bus->number, dev->devfn, pcic->pcic_imdim); + dev->irq = 0; + return; + } + + i = p->pin; + if (i >= 0 && i < 4) { + ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_LO); + dev->irq = ivec >> (i << 2) & 0xF; + } else if (i >= 4 && i < 8) { + ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_HI); + dev->irq = ivec >> ((i-4) << 2) & 0xF; + } else { /* Corrupted map */ + printk("PCIC: BAD PIN %d\n", i); for (;;) {} + } +/* P3 remove later */ printk("PCIC: device %s pin %d ivec 0x%x irq %x\n", namebuf, i, ivec, dev->irq); + + /* + * dev->irq=0 means PROM did not bothered to program the upper + * half of PCIC. This happens on JS-E with PROM 3.11, for instance. + */ + if (dev->irq == 0 || p->force) { + if (p->irq == 0 || p->irq >= 15) { /* Corrupted map */ + printk("PCIC: BAD IRQ %d\n", p->irq); for (;;) {} + } + printk("PCIC: setting irq %x for device (%x,%x)\n", + p->irq, dev->device, dev->vendor); + dev->irq = p->irq; + + ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_HI); + ivec &= ~(0xF << ((p->pin - 4) << 2)); + ivec |= p->irq << ((p->pin - 4) << 2); + writew(ivec, pcic->pcic_regs+PCI_INT_SELECT_HI); + } + + return; } /* @@ -317,9 +495,10 @@ unsigned long pcic_alloc_io( unsigned long* addr ) writeb((pcic->pcic_io_phys>>24) & PCI_SIBAR_ADDRESS_MASK, pcic->pcic_regs+PCI_SIBAR); writeb(PCI_ISIZE_16M, pcic->pcic_regs+PCI_ISIZE); + } if(paddr < pcic->pcic_mapped_io || - paddr > pcic->pcic_mapped_io + PCI_SPACE_SIZE) + paddr >= pcic->pcic_mapped_io + 0x10000) return 0; offset = paddr - pcic->pcic_mapped_io; *addr = pcic->pcic_io_phys + offset; @@ -334,6 +513,9 @@ __initfunc(void pcibios_fixup(void)) struct pci_dev *dev; int i, has_io, has_mem; unsigned short cmd; + struct linux_pbm_info* pbm = &pcic->pbm; + int node; + struct pcidev_cookie *pcp; if(pcic == NULL) { prom_printf("PCI: Error, PCIC not found.\n"); @@ -359,47 +541,61 @@ __initfunc(void pcibios_fixup(void)) } pci_read_config_word(dev, PCI_COMMAND, &cmd); if (has_io && !(cmd & PCI_COMMAND_IO)) { - printk("PCI: Enabling I/O for device %02x:%02x\n", + printk("PCIC: Enabling I/O for device %02x:%02x\n", dev->bus->number, dev->devfn); cmd |= PCI_COMMAND_IO; pci_write_config_word(dev, PCI_COMMAND, cmd); } if (has_mem && !(cmd & PCI_COMMAND_MEMORY)) { - printk("PCI: Enabling memory for device %02x:%02x\n", + printk("PCIC: Enabling memory for device %02x:%02x\n", dev->bus->number, dev->devfn); cmd |= PCI_COMMAND_MEMORY; pci_write_config_word(dev, PCI_COMMAND, cmd); } + node = pdev_to_pnode(pbm, dev); + if(node == 0) + node = -1; + /* cookies */ - { - struct pcidev_cookie *pcp; - struct linux_pbm_info* pbm = &pcic->pbm; - int node = pdev_to_pnode(pbm, dev); - - if(node == 0) - node = -1; - pcp = pci_devcookie_alloc(); - pcp->pbm = pbm; - pcp->prom_node = node; - dev->sysdata = pcp; - } + pcp = pci_devcookie_alloc(); + pcp->pbm = pbm; + pcp->prom_node = node; + dev->sysdata = pcp; /* memory mapping */ - if (!(dev->vendor == PCI_VENDOR_ID_SUN && - dev->device == PCI_DEVICE_ID_SUN_EBUS)) { - pcic_map_pci_device(dev); - } - - /* irq */ -#define SETIRQ(vend,devid,irqn) \ - if (dev->vendor==vend && dev->device==devid) dev->irq = irqn; + if ((dev->class>>16) != PCI_BASE_CLASS_BRIDGE) + pcic_map_pci_device(dev, node); - SETIRQ(PCI_VENDOR_ID_SUN,PCI_DEVICE_ID_SUN_HAPPYMEAL,3); + pcic_fill_irq(dev, node); } + ebus_init(); } +/* + * pcic_pin_to_irq() is exported to ebus.c. + */ +unsigned int +pcic_pin_to_irq(unsigned int pin, char *name) +{ + unsigned int irq; + unsigned int ivec; + + if (pin < 4) { + ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_LO); + irq = ivec >> (pin << 2) & 0xF; + } else if (pin < 8) { + ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_HI); + irq = ivec >> ((pin-4) << 2) & 0xF; + } else { /* Corrupted map */ + printk("PCIC: BAD PIN %d FOR %s\n", pin, name); + for (;;) {} /* XXX Cannot panic properly in case of PROLL */ + } +/* P3 remove later */ printk("PCIC: dev %s pin %d ivec 0x%x irq %x\n", name, pin, ivec, irq); + return irq; +} + /* Makes compiler happy */ static volatile int pcic_timer_dummy; @@ -539,26 +735,38 @@ int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned int *value) { unsigned long flags; - if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER; - if (bus != 0 || - (device_fn != 0 && device_fn != 1 && device_fn != 0x80)) { - *value = 0xffffffff; - return PCIBIOS_SUCCESSFUL; - } - /* FIXME: IGA haven't got high config memory addresses !!! */ - if (device_fn == 0x80 && where > PCI_INTERRUPT_LINE) { - *value = 0xffffffff; - return PCIBIOS_SUCCESSFUL; - } + if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER; save_and_cli(flags); +#if 0 + pcic_speculative = 1; + pcic_trapped = 0; +#endif writel(CONFIG_CMD(bus,device_fn,where), pcic->pcic_config_space_addr); +#if 0 + nop(); + if (pcic_trapped) { + restore_flags(flags); + *value = ~0; + return PCIBIOS_SUCCESSFUL; + } +#endif + pcic_speculative = 2; + pcic_trapped = 0; *value = readl(pcic->pcic_config_space_data + (where&4)); + nop(); + if (pcic_trapped) { + pcic_speculative = 0; + restore_flags(flags); + *value = ~0; + return PCIBIOS_SUCCESSFUL; + } + pcic_speculative = 0; restore_flags(flags); return PCIBIOS_SUCCESSFUL; } - + int pcibios_write_config_byte (unsigned char bus, unsigned char devfn, unsigned char where, unsigned char value) { @@ -586,8 +794,8 @@ int pcibios_write_config_dword (unsigned char bus, unsigned char devfn, unsigned char where, unsigned int value) { unsigned long flags; - if ((where&3) || bus != 0 || (devfn != 0 && devfn != 1 && devfn != 0x80)) - return PCIBIOS_BAD_REGISTER_NUMBER; + + if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER; save_and_cli(flags); writel(CONFIG_CMD(bus,devfn,where),pcic->pcic_config_space_addr); @@ -602,6 +810,29 @@ __initfunc(char *pcibios_setup(char *str)) } /* + * NMI + */ +void pcic_nmi(unsigned int pend, struct pt_regs *regs) +{ + + pend = flip_dword(pend); + + if (!pcic_speculative || (pend & PCI_SYS_INT_PENDING_PIO) == 0) { + /* + * XXX On CP-1200 PCI #SERR may happen, we do not know + * what to do about it yet. + */ + printk("Aiee, NMI pend 0x%x pc 0x%x spec %d, hanging\n", + pend, (int)regs->pc, pcic_speculative); + for (;;) { } + } + pcic_speculative = 0; + pcic_trapped = 1; + regs->pc = regs->npc; + regs->npc += 4; +} + +/* * Following code added to handle extra PCI-related system calls */ asmlinkage int sys_pciconfig_read(unsigned long bus, diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index 7f6ec54f9..92c8c464f 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c @@ -134,26 +134,6 @@ repeat: flush_tlb_page(vma, addr); } -static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, - unsigned long addr) -{ - struct vm_area_struct * vma; - - addr &= PAGE_MASK; - vma = find_vma(tsk->mm,addr); - if (!vma) - return NULL; - if (vma->vm_start <= addr) - return vma; - if (!(vma->vm_flags & VM_GROWSDOWN)) - return NULL; - if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur) - return NULL; - vma->vm_offset -= vma->vm_start - addr; - vma->vm_start = addr; - return vma; -} - /* * This routine checks the page boundaries, and that the offset is * within the task area. It then calls get_long() to read a long. @@ -540,6 +520,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) if((!child->dumpable || (current->uid != child->euid) || (current->uid != child->uid) || + (current->uid != child->suid) || (current->gid != child->egid) || (current->gid != child->sgid) || (!cap_issubset(child->cap_permitted, current->cap_permitted)) || diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c index d29c1cb66..1e22e086e 100644 --- a/arch/sparc/kernel/setup.c +++ b/arch/sparc/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.105 1999/04/13 14:17:08 jj Exp $ +/* $Id: setup.c,v 1.107 1999/06/03 15:02:20 davem Exp $ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -313,6 +313,7 @@ __initfunc(void setup_arch(char **cmdline_p, if(!strcmp(&cputypval,"sun4 ")) { sparc_cpu_model=sun4; } if(!strcmp(&cputypval,"sun4c")) { sparc_cpu_model=sun4c; } if(!strcmp(&cputypval,"sun4m")) { sparc_cpu_model=sun4m; } + if(!strcmp(&cputypval,"sun4s")) { sparc_cpu_model=sun4m; } /* CP-1200 with PROM 2.30 -E */ if(!strcmp(&cputypval,"sun4d")) { sparc_cpu_model=sun4d; } if(!strcmp(&cputypval,"sun4e")) { sparc_cpu_model=sun4e; } if(!strcmp(&cputypval,"sun4u")) { sparc_cpu_model=sun4u; } @@ -456,6 +457,7 @@ __initfunc(void setup_arch(char **cmdline_p, prom_printf("MrCoffee keyboard\n"); } else { prom_printf("Inconsistent or unknown console\n"); + prom_printf("You cannot mix serial and non serial input/output devices\n"); prom_halt(); } } diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c index 086a473e3..050ba65db 100644 --- a/arch/sparc/kernel/sys_sunos.c +++ b/arch/sparc/kernel/sys_sunos.c @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.94 1998/10/12 06:15:04 jj Exp $ +/* $Id: sys_sunos.c,v 1.98 1999/06/09 08:23:39 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -150,7 +150,6 @@ asmlinkage int sunos_brk(unsigned long brk) unsigned long newbrk, oldbrk; down(¤t->mm->mmap_sem); - lock_kernel(); if(ARCH_SUN4C_SUN4) { if(brk >= 0x20000000 && brk < 0xe0000000) { goto out; @@ -210,12 +209,9 @@ asmlinkage int sunos_brk(unsigned long brk) * Ok, we have probably got enough memory - let it rip. */ current->mm->brk = brk; - do_mmap(NULL, oldbrk, newbrk-oldbrk, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE, 0); + do_brk(oldbrk, newbrk-oldbrk) retval = 0; out: - unlock_kernel(); up(¤t->mm->mmap_sem); return retval; } @@ -1198,7 +1194,7 @@ asmlinkage int sunos_readv(unsigned long fd, const struct iovec * vector, long c lock_kernel(); ret = check_nonblock(sys_readv(fd,vector,count),fd); - lock_kernel(); + unlock_kernel(); return ret; } |