diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-06-19 22:45:37 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-06-19 22:45:37 +0000 |
commit | 6d403070f28cd44860fdb3a53be5da0275c65cf4 (patch) | |
tree | 0d0e7fe7b5fb7568d19e11d7d862b77a866ce081 /arch/alpha | |
parent | ecf1bf5f6c2e668d03b0a9fb026db7aa41e292e1 (diff) |
Merge with 2.4.0-test1-ac21 + pile of MIPS cleanups to make merging
possible. Chainsawed RM200 kernel to compile again. Jazz machine
status unknown.
Diffstat (limited to 'arch/alpha')
40 files changed, 2992 insertions, 307 deletions
diff --git a/arch/alpha/boot/bootp.c b/arch/alpha/boot/bootp.c index bb892ba3c..3be5fd6b6 100644 --- a/arch/alpha/boot/bootp.c +++ b/arch/alpha/boot/bootp.c @@ -93,7 +93,7 @@ pal_init(void) i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB); if (i) { srm_printk("failed, code %ld\n", i); - halt(); + __halt(); } percpu = (struct percpu_struct *) @@ -171,8 +171,7 @@ start_kernel(void) srm_printk("Initrd positioned at %#lx\n", initrd_start); #endif - nbytes = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS, - envval, sizeof(envval)); + nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval)); if (nbytes < 0 || nbytes >= sizeof(envval)) { nbytes = 0; } @@ -181,18 +180,17 @@ start_kernel(void) /* NOTE: *no* callbacks or printouts from here on out!!! */ - /* - * This is a hack, as some consoles seem to get virtual 20000000 - * (ie where the SRM console puts the kernel bootp image) memory - * overlapping physical 310000 memory, which causes real problems - * when attempting to copy the former to the latter... :-( + /* This is a hack, as some consoles seem to get virtual 20000000 (ie + * where the SRM console puts the kernel bootp image) memory + * overlapping physical memory where the kernel wants to be put, + * which causes real problems when attempting to copy the former to + * the latter... :-( * * So, we first move the kernel virtual-to-physical way above where * we physically want the kernel to end up, then copy it from there * to its final resting place... ;-} * - * Sigh... - */ + * Sigh... */ #ifdef INITRD_SIZE load(initrd_start, KERNEL_ORIGIN+KERNEL_SIZE, INITRD_SIZE); diff --git a/arch/alpha/boot/main.c b/arch/alpha/boot/main.c index 07913d899..78c9b0b6e 100644 --- a/arch/alpha/boot/main.c +++ b/arch/alpha/boot/main.c @@ -90,7 +90,7 @@ pal_init(void) i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB); if (i) { srm_printk("failed, code %ld\n", i); - halt(); + __halt(); } percpu = (struct percpu_struct *) @@ -107,15 +107,15 @@ static inline long openboot(void) char bootdev[256]; long result; - result = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_DEV, bootdev, 255); + result = callback_getenv(ENV_BOOTED_DEV, bootdev, 255); if (result < 0) return result; - return srm_dispatch(CCB_OPEN, bootdev, result & 255); + return callback_open(bootdev, result & 255); } static inline long close(long dev) { - return srm_dispatch(CCB_CLOSE, dev); + return callback_close(dev); } static inline long load(long dev, unsigned long addr, unsigned long count) @@ -124,7 +124,7 @@ static inline long load(long dev, unsigned long addr, unsigned long count) extern char _end; long result, boot_size = &_end - (char *) BOOT_ADDR; - result = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_FILE, bootfile, 255); + result = callback_getenv(ENV_BOOTED_FILE, bootfile, 255); if (result < 0) return result; result &= 255; @@ -132,7 +132,7 @@ static inline long load(long dev, unsigned long addr, unsigned long count) if (result) srm_printk("Boot file specification (%s) not implemented\n", bootfile); - return srm_dispatch(CCB_READ, dev, count, addr, boot_size/512 + 1); + return callback_read(dev, count, addr, boot_size/512 + 1); } /* @@ -176,8 +176,7 @@ void start_kernel(void) return; } - nbytes = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS, - envval, sizeof(envval)); + nbytes = callback_getenv(ENV_BOOTED_OSFLAGS, envval, sizeof(envval)); if (nbytes < 0) { nbytes = 0; } @@ -188,5 +187,5 @@ void start_kernel(void) runkernel(); for (i = 0 ; i < 0x100000000 ; i++) /* nothing */; - halt(); + __halt(); } diff --git a/arch/alpha/config.in b/arch/alpha/config.in index 6053ae25c..5f344e0f5 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -1,6 +1,6 @@ # # For a description of the syntax of this configuration file, -# see the Configure script. +# see Documentation/kbuild/config-language.txt. # define_bool CONFIG_UID16 n @@ -51,7 +51,9 @@ choice 'Alpha system type' \ RX164 CONFIG_ALPHA_RX164 \ SX164 CONFIG_ALPHA_SX164 \ Sable CONFIG_ALPHA_SABLE \ - Takara CONFIG_ALPHA_TAKARA" Generic + Takara CONFIG_ALPHA_TAKARA \ + Titan CONFIG_ALPHA_TITAN \ + Wildfire CONFIG_ALPHA_WILDFIRE" Generic # clear all implied options (don't want default values for those): unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5 CONFIG_ALPHA_EV6 @@ -131,6 +133,16 @@ then define_bool CONFIG_ALPHA_EV6 y define_bool CONFIG_ALPHA_TSUNAMI y fi +if [ "$CONFIG_ALPHA_WILDFIRE" = "y" ] +then + define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV6 y +fi +if [ "$CONFIG_ALPHA_TITAN" = "y" ] +then + define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV6 y +fi if [ "$CONFIG_ALPHA_RAWHIDE" = "y" ] then define_bool CONFIG_ALPHA_EV5 y @@ -151,18 +163,23 @@ then define_bool CONFIG_ALPHA_IRONGATE y fi +if [ "$CONFIG_ALPHA_JENSEN" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \ + -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" \ + -o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \ + -o "$CONFIG_ALPHA_EIGER" = "y" -o "$CONFIG_ALPHA_WILDFIRE" = "y" \ + -o "$CONFIG_ALPHA_TITAN" = "y" ] +then + define_bool CONFIG_ALPHA_SRM y +fi if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \ - -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \ + -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \ -o "$CONFIG_ALPHA_TAKARA" = "y" -o "$CONFIG_ALPHA_EB164" = "y" \ - -o "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_ALCOR" = "y" \ - -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_MIATA" = "y" \ - -o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \ - -o "$CONFIG_ALPHA_LX164" = "y" -o "$CONFIG_ALPHA_SX164" = "y" \ - -o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \ - -o "$CONFIG_ALPHA_EIGER" = "y" ] + -o "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_MIATA" = "y" \ + -o "$CONFIG_ALPHA_LX164" = "y" -o "$CONFIG_ALPHA_SX164" = "y" ] then bool 'Use SRM as bootloader' CONFIG_ALPHA_SRM fi + if [ "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \ -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" \ -o "$CONFIG_ALPHA_RAWHIDE" = "y" ] @@ -179,7 +196,8 @@ then fi if [ "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \ - -o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_GENERIC" = "y" ] + -o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_WILDFIRE" = "y" \ + -o "$CONFIG_ALPHA_TITAN" = "y" -o "$CONFIG_ALPHA_GENERIC" = "y" ] then bool 'Symmetric multi-processing support' CONFIG_SMP fi @@ -286,6 +304,12 @@ if [ "$CONFIG_VT" = "y" ]; then mainmenu_option next_comment comment 'Console drivers' bool 'VGA text console' CONFIG_VGA_CONSOLE +# if [ "$CONFIG_PCI" = "y" -a "$CONFIG_VGA_CONSOLE" = "y" ]; then +# bool ' Allow VGA on any bus?' CONFIG_VGA_HOSE +# if [ "$CONFIG_VGA_HOSE" = "y" ]; then +# define_bool CONFIG_DUMMY_CONSOLE y +# fi +# fi source drivers/video/Config.in if [ "$CONFIG_FB" = "y" ]; then define_bool CONFIG_PCI_CONSOLE y diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig index 37d7a8630..f7bf7b2a0 100644 --- a/arch/alpha/defconfig +++ b/arch/alpha/defconfig @@ -45,6 +45,8 @@ CONFIG_ALPHA_GENERIC=y # CONFIG_ALPHA_SX164 is not set # CONFIG_ALPHA_SABLE is not set # CONFIG_ALPHA_TAKARA is not set +# CONFIG_ALPHA_TITAN is not set +# CONFIG_ALPHA_WILDFIRE is not set CONFIG_ISA=y # CONFIG_SBUS is not set CONFIG_PCI=y @@ -83,10 +85,6 @@ CONFIG_BLK_DEV_FD=y # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_DEV_DAC960 is not set - -# -# Additional Block Devices -# # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile index 3a0a4ec0b..3b8d98bd2 100644 --- a/arch/alpha/kernel/Makefile +++ b/arch/alpha/kernel/Makefile @@ -26,17 +26,22 @@ O_OBJS += smp.o irq_smp.o endif ifdef CONFIG_PCI -L_OBJS += pci.o pci_iommu.o +O_OBJS += pci.o pci_iommu.o +endif + +ifdef CONFIG_VGA_HOSE +L_OBJS += console.o endif ifdef CONFIG_ALPHA_GENERIC O_OBJS += core_apecs.o core_cia.o core_irongate.o core_lca.o core_mcpcia.o \ - core_polaris.o core_t2.o core_tsunami.o \ + core_polaris.o core_t2.o core_tsunami.o core_titan.o \ sys_alcor.o sys_cabriolet.o sys_dp264.o sys_eb64p.o sys_eiger.o \ - sys_jensen.o sys_miata.o sys_mikasa.o sys_nautilus.o \ + sys_jensen.o sys_miata.o sys_mikasa.o sys_nautilus.o sys_titan.o \ sys_noritake.o sys_rawhide.o sys_ruffian.o sys_rx164.o \ - sys_sable.o sys_sio.o sys_sx164.o sys_takara.o sys_rx164.o + sys_sable.o sys_sio.o sys_sx164.o sys_takara.o sys_rx164.o \ + sys_wildfire.o core_wildfire.o else @@ -62,9 +67,15 @@ endif ifdef CONFIG_ALPHA_TSUNAMI O_OBJS += core_tsunami.o endif +ifdef CONFIG_ALPHA_TITAN +O_OBJS += core_titan.o +endif ifdef CONFIG_ALPHA_POLARIS O_OBJS += core_polaris.o endif +ifdef CONFIG_ALPHA_WILDFIRE +O_OBJS += core_wildfire.o +endif # Board support ifneq ($(CONFIG_ALPHA_ALCOR)$(CONFIG_ALPHA_XLT),) @@ -76,6 +87,9 @@ endif ifdef CONFIG_ALPHA_DP264 O_OBJS += sys_dp264.o endif +ifdef CONFIG_ALPHA_TITAN +O_OBJS += sys_titan.o +endif ifneq ($(CONFIG_ALPHA_EB64P)$(CONFIG_ALPHA_EB66),) O_OBJS += sys_eb64p.o endif @@ -118,6 +132,9 @@ endif ifdef CONFIG_ALPHA_TAKARA O_OBJS += sys_takara.o endif +ifdef CONFIG_ALPHA_WILDFIRE +O_OBJS += sys_wildfire.o +endif endif # GENERIC diff --git a/arch/alpha/kernel/console.c b/arch/alpha/kernel/console.c new file mode 100644 index 000000000..ac2e49817 --- /dev/null +++ b/arch/alpha/kernel/console.c @@ -0,0 +1,65 @@ +/* + * linux/arch/alpha/kernel/console.c + * + * Architecture-specific specific support for VGA device on + * non-0 I/O hose + */ + +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/tty.h> +#include <linux/console.h> +#include <asm/vga.h> +#include <asm/machvec.h> + +#ifdef CONFIG_VGA_HOSE + +/* + * Externally-visible vga hose bases + */ +unsigned long __vga_hose_io_base = 0; /* base for default hose */ +unsigned long __vga_hose_mem_base = 0; /* base for default hose */ + +static struct pci_controler * __init +default_vga_hose_select(struct pci_controler *h1, struct pci_controler *h2) +{ + if (h2->index < h1->index) + return h2; + + return h1; +} + +void __init +set_vga_hose(struct pci_controler *hose) +{ + if (hose) { + __vga_hose_io_base = hose->io_space->start; + __vga_hose_mem_base = hose->mem_space->start; + } +} + +void __init +locate_and_init_vga(void *(*sel_func)(void *, void *)) +{ + struct pci_controler *hose = NULL; + struct pci_dev *dev = NULL; + + if (!sel_func) sel_func = (void *)default_vga_hose_select; + + for(dev=NULL; (dev=pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, dev));) { + if (!hose) hose = dev->sysdata; + else hose = sel_func(hose, dev->sysdata); + } + + /* Did we already inititialize the correct one? */ + if (conswitchp == &vga_con && + __vga_hose_io_base == hose->io_space->start && + __vga_hose_mem_base == hose->mem_space->start) + return; + + /* Set the VGA hose and init the new console */ + set_vga_hose(hose); + take_over_console(&vga_con, 0, MAX_NR_CONSOLES-1, 1); +} + +#endif diff --git a/arch/alpha/kernel/core_mcpcia.c b/arch/alpha/kernel/core_mcpcia.c index 527c4f5eb..648090d24 100644 --- a/arch/alpha/kernel/core_mcpcia.c +++ b/arch/alpha/kernel/core_mcpcia.c @@ -45,6 +45,8 @@ #define MCPCIA_MAX_HOSES 4 +static int mcpcia_hose_count; /* Actual number found. */ + /* * Given a bus, device, and function number, compute resulting * configuration space address and setup the MCPCIA_HAXR2 register @@ -308,6 +310,7 @@ mcpcia_probe_hose(int h) mb(); draina(); wrmces(7); + mcheck_expected(cpu) = 2; /* indicates probing */ mcheck_taken(cpu) = 0; mcheck_extra(cpu) = mid; @@ -410,18 +413,19 @@ mcpcia_startup_hose(struct pci_controler *hose) * ??? We ought to scale window 1 with memory. */ - hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0); - hose->sg_pci = iommu_arena_new(hose, 0x40000000, 0x08000000, 0); + /* Make sure to align the arenas. */ + hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 1); + hose->sg_pci = iommu_arena_new(hose, 0x40000000, 0x08000000, 1); __direct_map_base = 0x80000000; __direct_map_size = 0x80000000; *(vuip)MCPCIA_W0_BASE(mid) = hose->sg_isa->dma_base | 3; *(vuip)MCPCIA_W0_MASK(mid) = (hose->sg_isa->size - 1) & 0xfff00000; - *(vuip)MCPCIA_T0_BASE(mid) = virt_to_phys(hose->sg_isa->ptes) >> 2; + *(vuip)MCPCIA_T0_BASE(mid) = virt_to_phys(hose->sg_isa->ptes) >> 8; *(vuip)MCPCIA_W1_BASE(mid) = hose->sg_pci->dma_base | 3; *(vuip)MCPCIA_W1_MASK(mid) = (hose->sg_pci->size - 1) & 0xfff00000; - *(vuip)MCPCIA_T1_BASE(mid) = virt_to_phys(hose->sg_pci->ptes) >> 2; + *(vuip)MCPCIA_T1_BASE(mid) = virt_to_phys(hose->sg_pci->ptes) >> 8; *(vuip)MCPCIA_W2_BASE(mid) = __direct_map_base | 1; *(vuip)MCPCIA_W2_MASK(mid) = (__direct_map_size - 1) & 0xfff00000; @@ -464,18 +468,20 @@ void __init mcpcia_init_hoses(void) { struct pci_controler *hose; - int h, hose_count = 0; + int h; + + mcpcia_hose_count = 0; /* First, find how many hoses we have. */ for (h = 0; h < MCPCIA_MAX_HOSES; ++h) { if (mcpcia_probe_hose(h)) { if (h != 0) mcpcia_new_hose(h); - hose_count++; + mcpcia_hose_count++; } } - printk("mcpcia_init_hoses: found %d hoses\n", hose_count); + printk("mcpcia_init_hoses: found %d hoses\n", mcpcia_hose_count); /* Now do init for each hose. */ for (hose = hose_head; hose; hose = hose->next) @@ -554,6 +560,65 @@ mcpcia_print_uncorrectable(struct el_MCPCIA_uncorrected_frame_mcheck *logout) frame->ld_lock); } +static void +mcpcia_print_system_area(unsigned long la_ptr) +{ + struct el_common *frame; + int i; + + struct IOD_subpacket { + unsigned long base; + unsigned int whoami; + unsigned int rsvd1; + unsigned int pci_rev; + unsigned int cap_ctrl; + unsigned int hae_mem; + unsigned int hae_io; + unsigned int int_ctl; + unsigned int int_reg; + unsigned int int_mask0; + unsigned int int_mask1; + unsigned int mc_err0; + unsigned int mc_err1; + unsigned int cap_err; + unsigned int rsvd2; + unsigned int pci_err1; + unsigned int mdpa_stat; + unsigned int mdpa_syn; + unsigned int mdpb_stat; + unsigned int mdpb_syn; + unsigned int rsvd3; + unsigned int rsvd4; + unsigned int rsvd5; + } *iodpp; + + frame = (struct el_common *)la_ptr; + + iodpp = (struct IOD_subpacket *) (la_ptr + frame->sys_offset); + + for (i = 0; i < mcpcia_hose_count; i++, iodpp++) { + printk("IOD %d Register Subpacket - Bridge Base Address %16lx\n", + i, iodpp->base); + printk(" WHOAMI = %8x\n", iodpp->whoami); + printk(" PCI_REV = %8x\n", iodpp->pci_rev); + printk(" CAP_CTRL = %8x\n", iodpp->cap_ctrl); + printk(" HAE_MEM = %8x\n", iodpp->hae_mem); + printk(" HAE_IO = %8x\n", iodpp->hae_io); + printk(" INT_CTL = %8x\n", iodpp->int_ctl); + printk(" INT_REG = %8x\n", iodpp->int_reg); + printk(" INT_MASK0 = %8x\n", iodpp->int_mask0); + printk(" INT_MASK1 = %8x\n", iodpp->int_mask1); + printk(" MC_ERR0 = %8x\n", iodpp->mc_err0); + printk(" MC_ERR1 = %8x\n", iodpp->mc_err1); + printk(" CAP_ERR = %8x\n", iodpp->cap_err); + printk(" PCI_ERR1 = %8x\n", iodpp->pci_err1); + printk(" MDPA_STAT = %8x\n", iodpp->mdpa_stat); + printk(" MDPA_SYN = %8x\n", iodpp->mdpa_syn); + printk(" MDPB_STAT = %8x\n", iodpp->mdpb_stat); + printk(" MDPB_SYN = %8x\n", iodpp->mdpb_syn); + } +} + void mcpcia_machine_check(unsigned long vector, unsigned long la_ptr, struct pt_regs * regs) @@ -594,6 +659,8 @@ mcpcia_machine_check(unsigned long vector, unsigned long la_ptr, mb(); process_mcheck_info(vector, la_ptr, regs, "MCPCIA", expected != 0); - if (!expected && vector != 0x620 && vector != 0x630) + if (!expected && vector != 0x620 && vector != 0x630) { mcpcia_print_uncorrectable(mchk_logout); + mcpcia_print_system_area(la_ptr); + } } diff --git a/arch/alpha/kernel/core_titan.c b/arch/alpha/kernel/core_titan.c new file mode 100644 index 000000000..65bcc8651 --- /dev/null +++ b/arch/alpha/kernel/core_titan.c @@ -0,0 +1,486 @@ +/* + * linux/arch/alpha/kernel/core_titan.c + * + * Code common to all TITAN core logic chips. + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/sched.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/smp.h> + +#define __EXTERN_INLINE inline +#include <asm/io.h> +#include <asm/core_titan.h> +#undef __EXTERN_INLINE + +#include "proto.h" +#include "pci_impl.h" + +int TITAN_bootcpu; +unsigned TITAN_agp = 0; + +static struct +{ + unsigned long wsba[4]; + unsigned long wsm[4]; + unsigned long tba[4]; +} saved_pachip_port[4]; + +/* + * BIOS32-style PCI interface: + */ + +#define DEBUG_MCHECK 0 /* 0 = minimum, 1 = debug, 2 = dump+dump */ +#define DEBUG_CONFIG 0 + +#if DEBUG_CONFIG +# define DBG_CFG(args) printk args +#else +# define DBG_CFG(args) +#endif + +/* + * Given a bus, device, and function number, compute resulting + * configuration space address + * accordingly. It is therefore not safe to have concurrent + * invocations to configuration space access routines, but there + * really shouldn't be any need for this. + * + * Note that all config space accesses use Type 1 address format. + * + * Note also that type 1 is determined by non-zero bus number. + * + * Type 1: + * + * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 31:24 reserved + * 23:16 bus number (8 bits = 128 possible buses) + * 15:11 Device number (5 bits) + * 10:8 function number + * 7:2 register number + * + * Notes: + * The function number selects which function of a multi-function device + * (e.g., SCSI and Ethernet). + * + * The register selects a DWORD (32 bit) register offset. Hence it + * doesn't get shifted by 2 bits as we want to "drop" the bottom two + * bits. + */ + +static int +mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, + unsigned char *type1) +{ + struct pci_controler *hose = dev->sysdata; + unsigned long addr; + u8 bus = dev->bus->number; + u8 device_fn = dev->devfn; + + DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, " + "pci_addr=0x%p, type1=0x%p)\n", + bus, device_fn, where, pci_addr, type1)); + + if (hose->first_busno == dev->bus->number) + bus = 0; + *type1 = (bus != 0); + + addr = (bus << 16) | (device_fn << 8) | where; + addr |= hose->config_space_base; + + *pci_addr = addr; + DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); + return 0; +} + +static int +titan_read_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = __kernel_ldbu(*(vucp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +titan_read_config_word(struct pci_dev *dev, int where, u16 *value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = __kernel_ldwu(*(vusp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +titan_read_config_dword(struct pci_dev *dev, int where, u32 *value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = *(vuip)addr; + return PCIBIOS_SUCCESSFUL; +} + +static int +titan_write_config_byte(struct pci_dev *dev, int where, u8 value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + __kernel_stb(value, *(vucp)addr); + mb(); + __kernel_ldbu(*(vucp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +titan_write_config_word(struct pci_dev *dev, int where, u16 value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + __kernel_stw(value, *(vusp)addr); + mb(); + __kernel_ldwu(*(vusp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +titan_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *(vuip)addr = value; + mb(); + *(vuip)addr; + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops titan_pci_ops = +{ + read_byte: titan_read_config_byte, + read_word: titan_read_config_word, + read_dword: titan_read_config_dword, + write_byte: titan_write_config_byte, + write_word: titan_write_config_word, + write_dword: titan_write_config_dword +}; + + +void +titan_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) +{ + titan_pachip *pachip = + (hose->index & 1) ? TITAN_pachip1 : TITAN_pachip0; + titan_pachip_port *port; + volatile unsigned long *csr; + unsigned long value; + + /* Get the right hose */ + port = &pachip->g_port; + if (hose->index & 2) + port = &pachip->a_port; + + /* We can invalidate up to 8 tlb entries in a go. The flush + matches against <31:16> in the pci address. */ + csr = &port->port_specific.g.gtlbia.csr; + if (((start ^ end) & 0xffff0000) == 0) + csr = &port->port_specific.g.gtlbiv.csr; + + /* For TBIA, it doesn't matter what value we write. For TBI, + it's the shifted tag bits. */ + value = (start & 0xffff0000) >> 12; + + wmb(); + *csr = value; + mb(); + *csr; +} + +#define FN __FUNCTION__ + +static int __init +titan_query_agp(titan_pachip_port *port) +{ + union TPAchipPCTL pctl; + + /* set up APCTL */ + pctl.pctl_q_whole = port->pctl.csr; + + return pctl.pctl_r_bits.apctl_v_agp_present; + +} +static void __init +titan_init_agp(titan_pachip_port *port, struct pci_controler *hose) +{ + union TPAchipPCTL pctl; + + if (!titan_query_agp(port)) + return; + + printk("AGP present on hose %d\n", hose->index); + + /* get APCTL */ + pctl.pctl_q_whole = port->pctl.csr; + + + pctl.pctl_r_bits.apctl_v_agp_en = 1; /* enable AGP */ + pctl.pctl_r_bits.apctl_v_agp_lp_rd = 0; + pctl.pctl_r_bits.apctl_v_agp_hp_rd = 0; + + port->pctl.csr = pctl.pctl_q_whole; + + TITAN_agp |= 1 << hose->index; + +#ifdef CONFIG_VGA_HOSE + /* is a graphics card on the AGP? (always device 5) */ + if (hose != NULL && + __kernel_ldwu(*(vusp)(hose->config_space_base + 0x280a)) == + PCI_CLASS_DISPLAY_VGA) + set_vga_hose(hose); +#endif +} + +static void __init +titan_init_one_pachip_port(titan_pachip_port *port, int index) +{ + struct pci_controler *hose; + + hose = alloc_pci_controler(); + if (index == 0) + pci_isa_hose = hose; + hose->io_space = alloc_resource(); + hose->mem_space = alloc_resource(); + + hose->config_space_base = TITAN_CONF(index); + hose->index = index; + + hose->io_space->start = TITAN_IO(index) - TITAN_IO_BIAS; + hose->io_space->end = hose->io_space->start + TITAN_IO_SPACE - 1; + hose->io_space->name = pci_io_names[index]; + hose->io_space->flags = IORESOURCE_IO; + + hose->mem_space->start = TITAN_MEM(index) - TITAN_MEM_BIAS; + hose->mem_space->end = hose->mem_space->start + 0xffffffff; + hose->mem_space->name = pci_mem_names[index]; + hose->mem_space->flags = IORESOURCE_MEM; + + if (request_resource(&ioport_resource, hose->io_space) < 0) + printk(KERN_ERR "Failed to request IO on hose %d\n", index); + if (request_resource(&iomem_resource, hose->mem_space) < 0) + printk(KERN_ERR "Failed to request MEM on hose %d\n", index); + + /* It's safe to call this for both G-Ports and A-Ports */ + titan_init_agp(port, hose); + + /* + * Save the existing PCI window translations. SRM will + * need them when we go to reboot. + */ + saved_pachip_port[index].wsba[0] = port->wsba[0].csr; + saved_pachip_port[index].wsm[0] = port->wsm[0].csr; + saved_pachip_port[index].tba[0] = port->tba[0].csr; + + saved_pachip_port[index].wsba[1] = port->wsba[1].csr; + saved_pachip_port[index].wsm[1] = port->wsm[1].csr; + saved_pachip_port[index].tba[1] = port->tba[1].csr; + + saved_pachip_port[index].wsba[2] = port->wsba[2].csr; + saved_pachip_port[index].wsm[2] = port->wsm[2].csr; + saved_pachip_port[index].tba[2] = port->tba[2].csr; + + saved_pachip_port[index].wsba[3] = port->wsba[3].csr; + saved_pachip_port[index].wsm[3] = port->wsm[3].csr; + saved_pachip_port[index].tba[3] = port->tba[3].csr; + + /* + * Set up the PCI to main memory translation windows. + * + * Note: Window 3 on Titan is Scatter-Gather ONLY + * + * Window 0 is scatter-gather 8MB at 8MB (for isa) + * Window 1 is direct access 1GB at 1GB + * Window 2 is direct access 1GB at 2GB + * Window 3 is scatter-gather 128MB at 3GB + * ??? We ought to scale window 3 memory. + * + * We must actually use 2 windows to direct-map the 2GB space, + * because of an idiot-syncrasy of the CYPRESS chip. It may + * respond to a PCI bus address in the last 1MB of the 4GB + * address range. + */ + hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0); + hose->sg_pci = iommu_arena_new(hose, 0xc0000000, 0x08000000, 0); + __direct_map_base = 0x40000000; + __direct_map_size = 0x80000000; + + port->wsba[0].csr = hose->sg_isa->dma_base | 3; + port->wsm[0].csr = (hose->sg_isa->size - 1) & 0xfff00000; + port->tba[0].csr = virt_to_phys(hose->sg_isa->ptes); + + port->wsba[1].csr = 0x40000000 | 1; + port->wsm[1].csr = (0x40000000 - 1) & 0xfff00000; + port->tba[1].csr = 0; + + port->wsba[2].csr = 0x80000000 | 1; + port->wsm[2].csr = (0x40000000 - 1) & 0xfff00000; + port->tba[2].csr = 0x40000000; + + port->wsba[3].csr = hose->sg_pci->dma_base | 3; + port->wsm[3].csr = (hose->sg_pci->size - 1) & 0xfff00000; + port->tba[3].csr = virt_to_phys(hose->sg_pci->ptes); + + titan_pci_tbi(hose, 0, -1); +} + +static void __init +titan_init_pachips(titan_pachip *pachip0, titan_pachip *pachip1) +{ + int pchip1_present = TITAN_cchip->csc.csr & 1L<<14; + + /* Init the ports in hose order... */ + titan_init_one_pachip_port(&pachip0->g_port, 0); /* hose 0 */ + if (pchip1_present) + titan_init_one_pachip_port(&pachip1->g_port, 1);/* hose 1 */ + titan_init_one_pachip_port(&pachip0->a_port, 2); /* hose 2 */ + if (pchip1_present) + titan_init_one_pachip_port(&pachip1->a_port, 3);/* hose 3 */ +} + +void __init +titan_init_arch(void) +{ +#if 0 + printk("%s: titan_init_arch()\n", FN); + printk("%s: CChip registers:\n", FN); + printk("%s: CSR_CSC 0x%lx\n", FN, TITAN_cchip->csc.csr); + printk("%s: CSR_MTR 0x%lx\n", FN, TITAN_cchip->mtr.csr); + printk("%s: CSR_MISC 0x%lx\n", FN, TITAN_cchip->misc.csr); + printk("%s: CSR_DIM0 0x%lx\n", FN, TITAN_cchip->dim0.csr); + printk("%s: CSR_DIM1 0x%lx\n", FN, TITAN_cchip->dim1.csr); + printk("%s: CSR_DIR0 0x%lx\n", FN, TITAN_cchip->dir0.csr); + printk("%s: CSR_DIR1 0x%lx\n", FN, TITAN_cchip->dir1.csr); + printk("%s: CSR_DRIR 0x%lx\n", FN, TITAN_cchip->drir.csr); + + printk("%s: DChip registers:\n", FN); + printk("%s: CSR_DSC 0x%lx\n", FN, TITAN_dchip->dsc.csr); + printk("%s: CSR_STR 0x%lx\n", FN, TITAN_dchip->str.csr); + printk("%s: CSR_DREV 0x%lx\n", FN, TITAN_dchip->drev.csr); +#endif + + TITAN_bootcpu = __hard_smp_processor_id(); + + /* With multiple PCI busses, we play with I/O as physical addrs. */ + ioport_resource.end = ~0UL; + iomem_resource.end = ~0UL; + + /* Init the PA chip(s) */ + titan_init_pachips(TITAN_pachip0, TITAN_pachip1); +} + +static void +titan_kill_one_pachip_port(titan_pachip_port *port, int index) +{ + port->wsba[0].csr = saved_pachip_port[index].wsba[0]; + port->wsm[0].csr = saved_pachip_port[index].wsm[0]; + port->tba[0].csr = saved_pachip_port[index].tba[0]; + + port->wsba[1].csr = saved_pachip_port[index].wsba[1]; + port->wsm[1].csr = saved_pachip_port[index].wsm[1]; + port->tba[1].csr = saved_pachip_port[index].tba[1]; + + port->wsba[2].csr = saved_pachip_port[index].wsba[2]; + port->wsm[2].csr = saved_pachip_port[index].wsm[2]; + port->tba[2].csr = saved_pachip_port[index].tba[2]; + + port->wsba[3].csr = saved_pachip_port[index].wsba[3]; + port->wsm[3].csr = saved_pachip_port[index].wsm[3]; + port->tba[3].csr = saved_pachip_port[index].tba[3]; +} + +static void +titan_kill_pachips(titan_pachip *pachip0, titan_pachip *pachip1) +{ + int pchip1_present = TITAN_cchip->csc.csr & 1L<<14; + + if (pchip1_present) { + titan_kill_one_pachip_port(&pachip0->g_port, 1); + titan_kill_one_pachip_port(&pachip0->a_port, 3); + } + titan_kill_one_pachip_port(&pachip0->g_port, 0); + titan_kill_one_pachip_port(&pachip0->a_port, 2); +} + +void +titan_kill_arch(int mode) +{ + titan_kill_pachips(TITAN_pachip0, TITAN_pachip1); +} + +static inline void +titan_pci_clr_err_1(titan_pachip *pachip) +{ + unsigned int jd; + + jd = pachip->g_port.port_specific.g.gperror.csr; + pachip->g_port.port_specific.g.gperror.csr = jd; + mb(); + pachip->g_port.port_specific.g.gperror.csr; +} + +static inline void +titan_pci_clr_err(void) +{ + titan_pci_clr_err_1(TITAN_pachip0); + + if (TITAN_cchip->csc.csr & 1L<<14) + titan_pci_clr_err_1(TITAN_pachip1); +} + +void +titan_machine_check(unsigned long vector, unsigned long la_ptr, + struct pt_regs * regs) +{ + /* clear error before any reporting. */ + mb(); + draina(); + titan_pci_clr_err(); + wrmces(0x7); + mb(); + + process_mcheck_info(vector, la_ptr, regs, "TITAN", + mcheck_expected(smp_processor_id())); +} + diff --git a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c index 5e3943fec..45ff9bb12 100644 --- a/arch/alpha/kernel/core_tsunami.c +++ b/arch/alpha/kernel/core_tsunami.c @@ -344,11 +344,13 @@ tsunami_init_one_pchip(tsunami_pchip *pchip, int index) /* * Set up the PCI to main memory translation windows. * + * Note: Window 3 is scatter-gather only + * * Window 0 is scatter-gather 8MB at 8MB (for isa) - * Window 1 is scatter-gather 128MB at 3GB - * Window 2 is direct access 1GB at 1GB - * Window 3 is direct access 1GB at 2GB - * ??? We ought to scale window 1 memory. + * Window 1 is direct access 1GB at 1GB + * Window 2 is direct access 1GB at 2GB + * Window 3 is scatter-gather 128MB at 3GB + * ??? We ought to scale window 3 memory. * * We must actually use 2 windows to direct-map the 2GB space, * because of an idiot-syncrasy of the CYPRESS chip. It may @@ -364,17 +366,17 @@ tsunami_init_one_pchip(tsunami_pchip *pchip, int index) pchip->wsm[0].csr = (hose->sg_isa->size - 1) & 0xfff00000; pchip->tba[0].csr = virt_to_phys(hose->sg_isa->ptes); - pchip->wsba[1].csr = hose->sg_pci->dma_base | 3; - pchip->wsm[1].csr = (hose->sg_pci->size - 1) & 0xfff00000; - pchip->tba[1].csr = virt_to_phys(hose->sg_pci->ptes); + pchip->wsba[1].csr = 0x40000000 | 1; + pchip->wsm[1].csr = (0x40000000 - 1) & 0xfff00000; + pchip->tba[1].csr = 0; - pchip->wsba[2].csr = 0x40000000 | 1; + pchip->wsba[2].csr = 0x80000000 | 1; pchip->wsm[2].csr = (0x40000000 - 1) & 0xfff00000; - pchip->tba[2].csr = 0; + pchip->tba[2].csr = 0x40000000; - pchip->wsba[3].csr = 0x80000000 | 1; - pchip->wsm[3].csr = (0x40000000 - 1) & 0xfff00000; - pchip->tba[3].csr = 0x40000000; + pchip->wsba[3].csr = hose->sg_pci->dma_base | 3; + pchip->wsm[3].csr = (hose->sg_pci->size - 1) & 0xfff00000; + pchip->tba[3].csr = virt_to_phys(hose->sg_pci->ptes); tsunami_pci_tbi(hose, 0, -1); } diff --git a/arch/alpha/kernel/core_wildfire.c b/arch/alpha/kernel/core_wildfire.c new file mode 100644 index 000000000..9b4f28c10 --- /dev/null +++ b/arch/alpha/kernel/core_wildfire.c @@ -0,0 +1,668 @@ +/* + * linux/arch/alpha/kernel/core_wildfire.c + * + * Wildfire support. + * + * Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/sched.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/smp.h> + +#define __EXTERN_INLINE inline +#include <asm/io.h> +#include <asm/core_wildfire.h> +#undef __EXTERN_INLINE + +#include "proto.h" +#include "pci_impl.h" + +#define DEBUG_MCHECK 0 /* 0 = minimal, 1 = debug, 2 = debug+dump. */ +#define DEBUG_CONFIG 0 +#define DEBUG_DUMP_REGS 0 +#define DEBUG_DUMP_CONFIG 1 + +#if DEBUG_CONFIG +# define DBG_CFG(args) printk args +#else +# define DBG_CFG(args) +#endif + +#if DEBUG_DUMP_REGS +static void wildfire_dump_pci_regs(int qbbno, int hoseno); +static void wildfire_dump_pca_regs(int qbbno, int pcano); +static void wildfire_dump_qsa_regs(int qbbno); +static void wildfire_dump_qsd_regs(int qbbno); +static void wildfire_dump_iop_regs(int qbbno); +static void wildfire_dump_gp_regs(int qbbno); +#endif +#if DEBUG_DUMP_CONFIG +static void wildfire_dump_hardware_config(void); +#endif + +unsigned char wildfire_hard_qbb_map[WILDFIRE_MAX_QBB]; +unsigned char wildfire_soft_qbb_map[WILDFIRE_MAX_QBB]; +#define QBB_MAP_EMPTY 0xff + +unsigned long wildfire_hard_qbb_mask; +unsigned long wildfire_soft_qbb_mask; +unsigned long wildfire_gp_mask; +unsigned long wildfire_hs_mask; +unsigned long wildfire_iop_mask; +unsigned long wildfire_ior_mask; +unsigned long wildfire_pca_mask; +unsigned long wildfire_cpu_mask; +unsigned long wildfire_mem_mask; + +void __init +wildfire_init_hose(int qbbno, int hoseno) +{ + struct pci_controler *hose; + wildfire_pci *pci; + + hose = alloc_pci_controler(); + hose->io_space = alloc_resource(); + hose->mem_space = alloc_resource(); + + /* This is for userland consumption. */ + hose->sparse_mem_base = 0; + hose->sparse_io_base = 0; + hose->dense_mem_base = WILDFIRE_MEM(qbbno, hoseno); + hose->dense_io_base = WILDFIRE_IO(qbbno, hoseno); + + hose->config_space_base = WILDFIRE_CONF(qbbno, hoseno); + hose->index = (qbbno << 3) + hoseno; + + hose->io_space->start = WILDFIRE_IO(qbbno, hoseno) - WILDFIRE_IO_BIAS; + hose->io_space->end = hose->io_space->start + WILDFIRE_IO_SPACE - 1; + hose->io_space->name = pci_io_names[hoseno]; + hose->io_space->flags = IORESOURCE_IO; + + hose->mem_space->start = WILDFIRE_MEM(qbbno, hoseno)-WILDFIRE_MEM_BIAS; + hose->mem_space->end = hose->mem_space->start + 0xffffffff; + hose->mem_space->name = pci_mem_names[hoseno]; + hose->mem_space->flags = IORESOURCE_MEM; + + if (request_resource(&ioport_resource, hose->io_space) < 0) + printk(KERN_ERR "Failed to request IO on qbb %d hose %d\n", + qbbno, hoseno); + if (request_resource(&iomem_resource, hose->mem_space) < 0) + printk(KERN_ERR "Failed to request MEM on qbb %d hose %d\n", + qbbno, hoseno); + +#if DEBUG_DUMP_REGS + wildfire_dump_pci_regs(qbbno, hoseno); +#endif + + /* + * Set up the PCI to main memory translation windows. + * + * Note: Window 3 is scatter-gather only + * + * Window 0 is scatter-gather 8MB at 8MB (for isa) + * Window 1 is direct access 1GB at 1GB + * Window 2 is direct access 1GB at 2GB + * Window 3 is scatter-gather 128MB at 3GB + * ??? We ought to scale window 3 memory. + * + */ + hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0); + hose->sg_pci = iommu_arena_new(hose, 0xc0000000, 0x08000000, 0); + + pci = WILDFIRE_pci(qbbno, hoseno); + + pci->pci_window[0].wbase.csr = hose->sg_isa->dma_base | 3; + pci->pci_window[0].wmask.csr = (hose->sg_isa->size - 1) & 0xfff00000; + pci->pci_window[0].tbase.csr = virt_to_phys(hose->sg_isa->ptes); + + pci->pci_window[1].wbase.csr = 0x40000000 | 1; + pci->pci_window[1].wmask.csr = (0x40000000 -1) & 0xfff00000; + pci->pci_window[1].tbase.csr = 0; + + pci->pci_window[2].wbase.csr = 0x80000000 | 1; + pci->pci_window[2].wmask.csr = (0x40000000 -1) & 0xfff00000; + pci->pci_window[2].tbase.csr = 0x40000000; + + pci->pci_window[3].wbase.csr = hose->sg_pci->dma_base | 3; + pci->pci_window[3].wmask.csr = (hose->sg_pci->size - 1) & 0xfff00000; + pci->pci_window[3].tbase.csr = virt_to_phys(hose->sg_pci->ptes); + + wildfire_pci_tbi(hose, 0, 0); /* Flush TLB at the end. */ +} + +void __init +wildfire_init_pca(int qbbno, int pcano) +{ + + /* Test for PCA existence first. */ + if (!WILDFIRE_PCA_EXISTS(qbbno, pcano)) + return; + +#if DEBUG_DUMP_REGS + wildfire_dump_pca_regs(qbbno, pcano); +#endif + + /* Do both hoses of the PCA. */ + wildfire_init_hose(qbbno, (pcano << 1) + 0); + wildfire_init_hose(qbbno, (pcano << 1) + 1); +} + +void __init +wildfire_init_qbb(int qbbno) +{ + int pcano; + + /* Test for QBB existence first. */ + if (!WILDFIRE_QBB_EXISTS(qbbno)) + return; + +#if DEBUG_DUMP_REGS + wildfire_dump_qsa_regs(qbbno); + wildfire_dump_qsd_regs(qbbno); + wildfire_dump_iop_regs(qbbno); + wildfire_dump_gp_regs(qbbno); +#endif + + /* Init all PCAs here. */ + for (pcano = 0; pcano < WILDFIRE_PCA_PER_QBB; pcano++) { + wildfire_init_pca(qbbno, pcano); + } +} + +void __init +wildfire_hardware_probe(void) +{ + unsigned long temp; + unsigned int hard_qbb, soft_qbb; + wildfire_fast_qsd *fast = WILDFIRE_fast_qsd(); + wildfire_qsd *qsd; + wildfire_qsa *qsa; + wildfire_iop *iop; + wildfire_gp *gp; + wildfire_ne *ne; + wildfire_fe *fe; + int i; + + temp = fast->qsd_whami.csr; +#if 0 + printk(KERN_ERR "fast QSD_WHAMI at base %p is 0x%lx\n", fast, temp); +#endif + + hard_qbb = (temp >> 8) & 7; + soft_qbb = (temp >> 4) & 7; + + /* Init the HW configuration variables. */ + wildfire_hard_qbb_mask = (1 << hard_qbb); + wildfire_soft_qbb_mask = (1 << soft_qbb); + + wildfire_gp_mask = 0; + wildfire_hs_mask = 0; + wildfire_iop_mask = 0; + wildfire_ior_mask = 0; + wildfire_pca_mask = 0; + + wildfire_cpu_mask = 0; + wildfire_mem_mask = 0; + + memset(wildfire_hard_qbb_map, QBB_MAP_EMPTY, WILDFIRE_MAX_QBB); + memset(wildfire_soft_qbb_map, QBB_MAP_EMPTY, WILDFIRE_MAX_QBB); + + /* First, determine which QBBs are present. */ + qsa = WILDFIRE_qsa(soft_qbb); + + temp = qsa->qsa_qbb_id.csr; +#if 0 + printk(KERN_ERR "QSA_QBB_ID at base %p is 0x%lx\n", qsa, temp); +#endif + + if (temp & 0x40) /* Is there an HS? */ + wildfire_hs_mask = 1; + + if (temp & 0x20) { /* Is there a GP? */ + gp = WILDFIRE_gp(soft_qbb); + temp = 0; + for (i = 0; i < 4; i++) { + temp |= gp->gpa_qbb_map[i].csr << (i * 8); +#if 0 + printk(KERN_ERR "GPA_QBB_MAP[%d] at base %p is 0x%lx\n", + i, gp, temp); +#endif + } + + for (hard_qbb = 0; hard_qbb < WILDFIRE_MAX_QBB; hard_qbb++) { + if (temp & 8) { /* Is there a QBB? */ + soft_qbb = temp & 7; + wildfire_hard_qbb_mask |= (1 << hard_qbb); + wildfire_soft_qbb_mask |= (1 << soft_qbb); + } + temp >>= 4; + } + wildfire_gp_mask = wildfire_soft_qbb_mask; + } + + /* Next determine each QBBs resources. */ + for (soft_qbb = 0; soft_qbb < WILDFIRE_MAX_QBB; soft_qbb++) { + if (WILDFIRE_QBB_EXISTS(soft_qbb)) { + qsd = WILDFIRE_qsd(soft_qbb); + temp = qsd->qsd_whami.csr; +#if 0 + printk(KERN_ERR "QSD_WHAMI at base %p is 0x%lx\n", qsd, temp); +#endif + hard_qbb = (temp >> 8) & 7; + wildfire_hard_qbb_map[hard_qbb] = soft_qbb; + wildfire_soft_qbb_map[soft_qbb] = hard_qbb; + + qsa = WILDFIRE_qsa(soft_qbb); + temp = qsa->qsa_qbb_pop[0].csr; +#if 0 + printk(KERN_ERR "QSA_QBB_POP_0 at base %p is 0x%lx\n", qsa, temp); +#endif + wildfire_cpu_mask |= ((temp >> 0) & 0xf) << (soft_qbb << 2); + wildfire_mem_mask |= ((temp >> 4) & 0xf) << (soft_qbb << 2); + + temp = qsa->qsa_qbb_pop[1].csr; +#if 0 + printk(KERN_ERR "QSA_QBB_POP_1 at base %p is 0x%lx\n", qsa, temp); +#endif + wildfire_iop_mask |= (1 << soft_qbb); + wildfire_ior_mask |= ((temp >> 4) & 0xf) << (soft_qbb << 2); + + temp = qsa->qsa_qbb_id.csr; +#if 0 + printk(KERN_ERR "QSA_QBB_ID at %p is 0x%lx\n", qsa, temp); +#endif + if (temp & 0x20) + wildfire_gp_mask |= (1 << soft_qbb); + + /* Probe for PCA existence here. */ + for (i = 0; i < WILDFIRE_PCA_PER_QBB; i++) { + iop = WILDFIRE_iop(soft_qbb); + ne = WILDFIRE_ne(soft_qbb, i); + fe = WILDFIRE_fe(soft_qbb, i); + + if ((iop->iop_hose[i].init.csr & 1) == 1 && + ((ne->ne_what_am_i.csr & 0xf00000300) == 0x100000300) && + ((fe->fe_what_am_i.csr & 0xf00000300) == 0x100000200)) + { + wildfire_pca_mask |= 1 << ((soft_qbb << 2) + i); + } + } + + } + } +#if DEBUG_DUMP_CONFIG + wildfire_dump_hardware_config(); +#endif +} + +void __init +wildfire_init_arch(void) +{ + int qbbno; + + /* With multiple PCI buses, we play with I/O as physical addrs. */ + ioport_resource.end = ~0UL; + iomem_resource.end = ~0UL; + + + /* Probe the hardware for info about configuration. */ + wildfire_hardware_probe(); + + /* Now init all the found QBBs. */ + for (qbbno = 0; qbbno < WILDFIRE_MAX_QBB; qbbno++) { + wildfire_init_qbb(qbbno); + } + + /* Normal direct PCI DMA mapping. */ + __direct_map_base = 0x40000000UL; + __direct_map_size = 0x80000000UL; +} + +void +wildfire_machine_check(unsigned long vector, unsigned long la_ptr, + struct pt_regs * regs) +{ + mb(); + mb(); /* magic */ + draina(); + /* FIXME: clear pci errors */ + wrmces(0x7); + mb(); + + process_mcheck_info(vector, la_ptr, regs, "WILDFIRE", + mcheck_expected(smp_processor_id())); +} + +void +wildfire_kill_arch(int mode) +{ +} + +void +wildfire_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) +{ + int qbbno = hose->index >> 3; + int hoseno = hose->index & 7; + wildfire_pci *pci = WILDFIRE_pci(qbbno, hoseno); + + mb(); + pci->pci_flush_tlb.csr; /* reading does the trick */ +} + +static int +mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, + unsigned char *type1) +{ + struct pci_controler *hose = dev->sysdata; + unsigned long addr; + u8 bus = dev->bus->number; + u8 device_fn = dev->devfn; + + DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, " + "pci_addr=0x%p, type1=0x%p)\n", + bus, device_fn, where, pci_addr, type1)); + + if (hose->first_busno == dev->bus->number) + bus = 0; + *type1 = (bus != 0); + + addr = (bus << 16) | (device_fn << 8) | where; + addr |= hose->config_space_base; + + *pci_addr = addr; + DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); + return 0; +} + +static int +wildfire_read_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = __kernel_ldbu(*(vucp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +wildfire_read_config_word(struct pci_dev *dev, int where, u16 *value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = __kernel_ldwu(*(vusp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +wildfire_read_config_dword(struct pci_dev *dev, int where, u32 *value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = *(vuip)addr; + return PCIBIOS_SUCCESSFUL; +} + +static int +wildfire_write_config_byte(struct pci_dev *dev, int where, u8 value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + __kernel_stb(value, *(vucp)addr); + mb(); + __kernel_ldbu(*(vucp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +wildfire_write_config_word(struct pci_dev *dev, int where, u16 value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + __kernel_stw(value, *(vusp)addr); + mb(); + __kernel_ldwu(*(vusp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +wildfire_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *(vuip)addr = value; + mb(); + *(vuip)addr; + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops wildfire_pci_ops = +{ + read_byte: wildfire_read_config_byte, + read_word: wildfire_read_config_word, + read_dword: wildfire_read_config_dword, + write_byte: wildfire_write_config_byte, + write_word: wildfire_write_config_word, + write_dword: wildfire_write_config_dword +}; + +#if DEBUG_DUMP_REGS + +static void __init +wildfire_dump_pci_regs(int qbbno, int hoseno) +{ + wildfire_pci *pci = WILDFIRE_pci(qbbno, hoseno); + int i; + + printk(KERN_ERR "PCI registers for QBB %d hose %d (%p)\n", + qbbno, hoseno, pci); + + printk(KERN_ERR " PCI_IO_ADDR_EXT: 0x%16lx\n", + pci->pci_io_addr_ext.csr); + printk(KERN_ERR " PCI_CTRL: 0x%16lx\n", pci->pci_ctrl.csr); + printk(KERN_ERR " PCI_ERR_SUM: 0x%16lx\n", pci->pci_err_sum.csr); + printk(KERN_ERR " PCI_ERR_ADDR: 0x%16lx\n", pci->pci_err_addr.csr); + printk(KERN_ERR " PCI_STALL_CNT: 0x%16lx\n", pci->pci_stall_cnt.csr); + printk(KERN_ERR " PCI_PEND_INT: 0x%16lx\n", pci->pci_pend_int.csr); + printk(KERN_ERR " PCI_SENT_INT: 0x%16lx\n", pci->pci_sent_int.csr); + + printk(KERN_ERR " DMA window registers for QBB %d hose %d (%p)\n", + qbbno, hoseno, pci); + for (i = 0; i < 4; i++) { + printk(KERN_ERR " window %d: 0x%16lx 0x%16lx 0x%16lx\n", i, + pci->pci_window[i].wbase.csr, + pci->pci_window[i].wmask.csr, + pci->pci_window[i].tbase.csr); + } + printk(KERN_ERR "\n"); +} + +static void __init +wildfire_dump_pca_regs(int qbbno, int pcano) +{ + wildfire_pca *pca = WILDFIRE_pca(qbbno, pcano); + int i; + + printk(KERN_ERR "PCA registers for QBB %d PCA %d (%p)\n", + qbbno, pcano, pca); + + printk(KERN_ERR " PCA_WHAT_AM_I: 0x%16lx\n", pca->pca_what_am_i.csr); + printk(KERN_ERR " PCA_ERR_SUM: 0x%16lx\n", pca->pca_err_sum.csr); + printk(KERN_ERR " PCA_PEND_INT: 0x%16lx\n", pca->pca_pend_int.csr); + printk(KERN_ERR " PCA_SENT_INT: 0x%16lx\n", pca->pca_sent_int.csr); + printk(KERN_ERR " PCA_STDIO_EL: 0x%16lx\n", + pca->pca_stdio_edge_level.csr); + + printk(KERN_ERR " PCA target registers for QBB %d PCA %d (%p)\n", + qbbno, pcano, pca); + for (i = 0; i < 4; i++) { + printk(KERN_ERR " target %d: 0x%16lx 0x%16lx\n", i, + pca->pca_int[i].target.csr, + pca->pca_int[i].enable.csr); + } + + printk(KERN_ERR "\n"); +} + +static void __init +wildfire_dump_qsa_regs(int qbbno) +{ + wildfire_qsa *qsa = WILDFIRE_qsa(qbbno); + int i; + + printk(KERN_ERR "QSA registers for QBB %d (%p)\n", qbbno, qsa); + + printk(KERN_ERR " QSA_QBB_ID: 0x%16lx\n", qsa->qsa_qbb_id.csr); + printk(KERN_ERR " QSA_PORT_ENA: 0x%16lx\n", qsa->qsa_port_ena.csr); + printk(KERN_ERR " QSA_REF_INT: 0x%16lx\n", qsa->qsa_ref_int.csr); + + for (i = 0; i < 5; i++) + printk(KERN_ERR " QSA_CONFIG_%d: 0x%16lx\n", + i, qsa->qsa_config[i].csr); + + for (i = 0; i < 2; i++) + printk(KERN_ERR " QSA_QBB_POP_%d: 0x%16lx\n", + i, qsa->qsa_qbb_pop[0].csr); + + printk(KERN_ERR "\n"); +} + +static void __init +wildfire_dump_qsd_regs(int qbbno) +{ + wildfire_qsd *qsd = WILDFIRE_qsd(qbbno); + + printk(KERN_ERR "QSD registers for QBB %d (%p)\n", qbbno, qsd); + + printk(KERN_ERR " QSD_WHAMI: 0x%16lx\n", qsd->qsd_whami.csr); + printk(KERN_ERR " QSD_REV: 0x%16lx\n", qsd->qsd_rev.csr); + printk(KERN_ERR " QSD_PORT_PRESENT: 0x%16lx\n", + qsd->qsd_port_present.csr); + printk(KERN_ERR " QSD_PORT_ACTUVE: 0x%16lx\n", + qsd->qsd_port_active.csr); + printk(KERN_ERR " QSD_FAULT_ENA: 0x%16lx\n", + qsd->qsd_fault_ena.csr); + printk(KERN_ERR " QSD_CPU_INT_ENA: 0x%16lx\n", + qsd->qsd_cpu_int_ena.csr); + printk(KERN_ERR " QSD_MEM_CONFIG: 0x%16lx\n", + qsd->qsd_mem_config.csr); + printk(KERN_ERR " QSD_ERR_SUM: 0x%16lx\n", + qsd->qsd_err_sum.csr); + + printk(KERN_ERR "\n"); +} + +static void __init +wildfire_dump_iop_regs(int qbbno) +{ + wildfire_iop *iop = WILDFIRE_iop(qbbno); + int i; + + printk(KERN_ERR "IOP registers for QBB %d (%p)\n", qbbno, iop); + + printk(KERN_ERR " IOA_CONFIG: 0x%16lx\n", iop->ioa_config.csr); + printk(KERN_ERR " IOD_CONFIG: 0x%16lx\n", iop->iod_config.csr); + printk(KERN_ERR " IOP_SWITCH_CREDITS: 0x%16lx\n", + iop->iop_switch_credits.csr); + printk(KERN_ERR " IOP_HOSE_CREDITS: 0x%16lx\n", + iop->iop_hose_credits.csr); + + for (i = 0; i < 4; i++) + printk(KERN_ERR " IOP_HOSE_%d_INIT: 0x%16lx\n", + i, iop->iop_hose[i].init.csr); + for (i = 0; i < 4; i++) + printk(KERN_ERR " IOP_DEV_INT_TARGET_%d: 0x%16lx\n", + i, iop->iop_dev_int[i].target.csr); + + printk(KERN_ERR "\n"); +} + +static void __init +wildfire_dump_gp_regs(int qbbno) +{ + wildfire_gp *gp = WILDFIRE_gp(qbbno); + int i; + + printk(KERN_ERR "GP registers for QBB %d (%p)\n", qbbno, gp); + for (i = 0; i < 4; i++) + printk(KERN_ERR " GPA_QBB_MAP_%d: 0x%16lx\n", + i, gp->gpa_qbb_map[i].csr); + + printk(KERN_ERR " GPA_MEM_POP_MAP: 0x%16lx\n", + gp->gpa_mem_pop_map.csr); + printk(KERN_ERR " GPA_SCRATCH: 0x%16lx\n", gp->gpa_scratch.csr); + printk(KERN_ERR " GPA_DIAG: 0x%16lx\n", gp->gpa_diag.csr); + printk(KERN_ERR " GPA_CONFIG_0: 0x%16lx\n", gp->gpa_config_0.csr); + printk(KERN_ERR " GPA_INIT_ID: 0x%16lx\n", gp->gpa_init_id.csr); + printk(KERN_ERR " GPA_CONFIG_2: 0x%16lx\n", gp->gpa_config_2.csr); + + printk(KERN_ERR "\n"); +} +#endif /* DUMP_REGS */ + +#if DEBUG_DUMP_CONFIG +static void __init +wildfire_dump_hardware_config(void) +{ + int i; + + printk(KERN_ERR "Probed Hardware Configuration\n"); + + printk(KERN_ERR " hard_qbb_mask: 0x%16lx\n", wildfire_hard_qbb_mask); + printk(KERN_ERR " soft_qbb_mask: 0x%16lx\n", wildfire_soft_qbb_mask); + + printk(KERN_ERR " gp_mask: 0x%16lx\n", wildfire_gp_mask); + printk(KERN_ERR " hs_mask: 0x%16lx\n", wildfire_hs_mask); + printk(KERN_ERR " iop_mask: 0x%16lx\n", wildfire_iop_mask); + printk(KERN_ERR " ior_mask: 0x%16lx\n", wildfire_ior_mask); + printk(KERN_ERR " pca_mask: 0x%16lx\n", wildfire_pca_mask); + + printk(KERN_ERR " cpu_mask: 0x%16lx\n", wildfire_cpu_mask); + printk(KERN_ERR " mem_mask: 0x%16lx\n", wildfire_mem_mask); + + printk(" hard_qbb_map: "); + for (i = 0; i < WILDFIRE_MAX_QBB; i++) + if (wildfire_hard_qbb_map[i] == QBB_MAP_EMPTY) + printk("--- "); + else + printk("%3d ", wildfire_hard_qbb_map[i]); + printk("\n"); + + printk(" soft_qbb_map: "); + for (i = 0; i < WILDFIRE_MAX_QBB; i++) + if (wildfire_soft_qbb_map[i] == QBB_MAP_EMPTY) + printk("--- "); + else + printk("%3d ", wildfire_soft_qbb_map[i]); + printk("\n"); +} +#endif /* DUMP_CONFIG */ diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index 33d5eead1..6f73ff9f9 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -34,11 +34,12 @@ #define TASK_EXEC_DOMAIN 32 #define TASK_NEED_RESCHED 40 #define TASK_PROCESSOR 100 +#define TASK_PTRACE 104 /* * task flags (must match include/linux/sched.h): */ -#define PF_PTRACED 0x00000010 +#define PT_PTRACED 0x00000001 #define CLONE_VM 0x00000100 @@ -557,10 +558,10 @@ entSys: lda $5,sys_call_table lda $27,sys_ni_syscall cmpult $0,$4,$4 - ldq $3,TASK_FLAGS($8) + ldq $3,TASK_PTRACE($8) stq $17,SP_OFF+32($30) s8addq $0,$5,$5 - and $3,PF_PTRACED,$3 + and $3,PT_PTRACED,$3 stq $18,SP_OFF+40($30) bne $3,strace beq $4,1f diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c index e47fcd3ca..dc665fbfb 100644 --- a/arch/alpha/kernel/irq.c +++ b/arch/alpha/kernel/irq.c @@ -233,14 +233,14 @@ static unsigned long irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; static void select_smp_affinity(int irq) { - static int last_cpu; + static int last_cpu = 0; int cpu = last_cpu + 1; if (! irq_desc[irq].handler->set_affinity || irq_user_affinity[irq]) return; while (((cpu_present_mask >> cpu) & 1) == 0) - cpu = (cpu < NR_CPUS ? cpu + 1 : 0); + cpu = (cpu < (NR_CPUS-1) ? cpu + 1 : 0); last_cpu = cpu; irq_affinity[irq] = 1UL << cpu; @@ -520,8 +520,10 @@ get_irq_list(char *buf) p += sprintf(p, " "); for (i = 0; i < smp_num_cpus; i++) p += sprintf(p, "CPU%d ", i); +#ifdef DO_BROADCAST_INTS for (i = 0; i < smp_num_cpus; i++) p += sprintf(p, "TRY%d ", i); +#endif *p++ = '\n'; #endif @@ -536,10 +538,12 @@ get_irq_list(char *buf) for (j = 0; j < smp_num_cpus; j++) p += sprintf(p, "%10u ", kstat.irqs[cpu_logical_map(j)][i]); +#ifdef DO_BROADCAST_INTS for (j = 0; j < smp_num_cpus; j++) p += sprintf(p, "%10lu ", irq_attempt(cpu_logical_map(j), i)); #endif +#endif p += sprintf(p, " %14s", irq_desc[i].handler->typename); p += sprintf(p, " %c%s", (action->flags & SA_INTERRUPT)?'+':' ', diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c index 774fcf8a6..ff1570406 100644 --- a/arch/alpha/kernel/irq_alpha.c +++ b/arch/alpha/kernel/irq_alpha.c @@ -105,8 +105,18 @@ common_init_isa_dma(void) void __init init_IRQ(void) { - alpha_mv.init_irq(); + /* Uh, this really MUST come first, just in case + * the platform init_irq() causes interrupts/mchecks + * (as is the case with RAWHIDE, at least). + */ wrent(entInt, 0); + + alpha_mv.init_irq(); + + /* If we had wanted SRM console printk echoing early, undo it now. */ + if (alpha_using_srm && srmcons_output) { + unregister_srm_console(); + } } /* diff --git a/arch/alpha/kernel/irq_i8259.c b/arch/alpha/kernel/irq_i8259.c index 79a1c4fb5..42029b33f 100644 --- a/arch/alpha/kernel/irq_i8259.c +++ b/arch/alpha/kernel/irq_i8259.c @@ -126,6 +126,8 @@ init_i8259a_irqs(void) # define IACK_SC CIA_IACK_SC #elif defined(CONFIG_ALPHA_PYXIS) # define IACK_SC PYXIS_IACK_SC +#elif defined(CONFIG_ALPHA_TITAN) +# define IACK_SC TITAN_IACK_SC #elif defined(CONFIG_ALPHA_TSUNAMI) # define IACK_SC TSUNAMI_IACK_SC #elif defined(CONFIG_ALPHA_POLARIS) diff --git a/arch/alpha/kernel/machvec_impl.h b/arch/alpha/kernel/machvec_impl.h index bc9c0d3de..454950c1b 100644 --- a/arch/alpha/kernel/machvec_impl.h +++ b/arch/alpha/kernel/machvec_impl.h @@ -9,12 +9,14 @@ #include <linux/config.h> #include <asm/pgalloc.h> -/* Whee. IRONGATE, POLARIS and TSUNAMI don't have an HAE. Fix things up for - the GENERIC kernel by defining the HAE address to be that of the cache. - Now we can read and write it as we like. ;-) */ +/* Whee. IRONGATE, POLARIS, TSUNAMI, TITAN, and WILDFIRE don't have an HAE. + Fix things up for the GENERIC kernel by defining the HAE address + to be that of the cache. Now we can read and write it as we like. ;-) */ #define IRONGATE_HAE_ADDRESS (&alpha_mv.hae_cache) #define POLARIS_HAE_ADDRESS (&alpha_mv.hae_cache) #define TSUNAMI_HAE_ADDRESS (&alpha_mv.hae_cache) +#define TITAN_HAE_ADDRESS (&alpha_mv.hae_cache) +#define WILDFIRE_HAE_ADDRESS (&alpha_mv.hae_cache) #if CIA_ONE_HAE_WINDOW #define CIA_HAE_ADDRESS (&alpha_mv.hae_cache) @@ -28,6 +30,7 @@ seems like such a pain. Define this to get things to compile. */ #define JENSEN_IACK_SC 1 #define T2_IACK_SC 1 +#define WILDFIRE_IACK_SC 1 /* FIXME */ /* @@ -91,6 +94,8 @@ #define DO_POLARIS_IO IO(POLARIS,polaris) #define DO_T2_IO IO(T2,t2) #define DO_TSUNAMI_IO IO(TSUNAMI,tsunami) +#define DO_TITAN_IO IO(TITAN,titan) +#define DO_WILDFIRE_IO IO(WILDFIRE,wildfire) #define DO_PYXIS_IO IO_LITE(CIA,cia_bwx), \ pci_ops: &CAT(cia,_pci_ops) @@ -107,6 +112,8 @@ #define DO_POLARIS_BUS BUS(polaris) #define DO_T2_BUS BUS(t2) #define DO_TSUNAMI_BUS BUS(tsunami) +#define DO_TITAN_BUS BUS(titan) +#define DO_WILDFIRE_BUS BUS(wildfire) /* diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 238b4004f..d55af89c6 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -230,7 +230,6 @@ asmlinkage unsigned long osf_mmap(unsigned long addr, unsigned long len, struct file *file = NULL; unsigned long ret = -EBADF; - down(¤t->mm->mmap_sem); lock_kernel(); #if 0 if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED)) @@ -243,12 +242,13 @@ asmlinkage unsigned long osf_mmap(unsigned long addr, unsigned long len, goto out; } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + down(¤t->mm->mmap_sem); ret = do_mmap(file, addr, len, prot, flags, off); + up(¤t->mm->mmap_sem); if (file) fput(file); out: unlock_kernel(); - up(¤t->mm->mmap_sem); return ret; } diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c index f9a79c1d6..39de16465 100644 --- a/arch/alpha/kernel/pci.c +++ b/arch/alpha/kernel/pci.c @@ -25,11 +25,13 @@ */ const char *const pci_io_names[] = { - "PCI IO bus 0", "PCI IO bus 1", "PCI IO bus 2", "PCI IO bus 3" + "PCI IO bus 0", "PCI IO bus 1", "PCI IO bus 2", "PCI IO bus 3", + "PCI IO bus 4", "PCI IO bus 5", "PCI IO bus 6", "PCI IO bus 7" }; const char *const pci_mem_names[] = { - "PCI mem bus 0", "PCI mem bus 1", "PCI mem bus 2", "PCI mem bus 3" + "PCI mem bus 0", "PCI mem bus 1", "PCI mem bus 2", "PCI mem bus 3", + "PCI mem bus 4", "PCI mem bus 5", "PCI mem bus 6", "PCI mem bus 7" }; const char pci_hae0_name[] = "HAE0"; @@ -266,6 +268,7 @@ pcibios_fixup_bus(struct pci_bus *bus) struct pci_controler *hose = (struct pci_controler *) bus->sysdata; struct list_head *ln; + /* ???? */ bus->resource[0] = hose->io_space; bus->resource[1] = hose->mem_space; @@ -291,15 +294,14 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root, u32 reg; if (resource < PCI_ROM_RESOURCE) - where = PCI_BASE_ADDRESS_0 + (resource * 4); + where = PCI_BASE_ADDRESS_0 + (resource * 4); else if (resource == PCI_ROM_RESOURCE) where = dev->rom_base_reg; else { - /* Don't update non-standard resources here */ - return; + return; /* Don't update non-standard resources here. */ } - /* Point root at the hose root */ + /* Point root at the hose root. */ if (res->flags & IORESOURCE_IO) root = hose->io_space; if (res->flags & IORESOURCE_MEM) @@ -431,6 +433,11 @@ pcibios_size_bridge(struct pci_bus *bus, struct pbus_set_ranges_data *outer) bridge->resource[0].end = bridge->resource[0].start + inner.io_end; bridge->resource[1].end = bridge->resource[1].start + inner.mem_end; + bridge->resource[PCI_BRIDGE_RESOURCES].end = + bridge->resource[PCI_BRIDGE_RESOURCES].start + inner.io_end; + bridge->resource[PCI_BRIDGE_RESOURCES+1].end = + bridge->resource[PCI_BRIDGE_RESOURCES+1].start + inner.mem_end; + /* adjust parent's resource requirements */ if (outer) { outer->io_end = ROUND_UP(outer->io_end, 4*1024); diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c index 5a36aa578..cadf69b58 100644 --- a/arch/alpha/kernel/pci_iommu.c +++ b/arch/alpha/kernel/pci_iommu.c @@ -97,10 +97,6 @@ iommu_arena_alloc(struct pci_iommu_arena *arena, long n) } if (i < n) { - /* Reached the end. Flush the TLB and restart the - search from the beginning. */ - alpha_mv.mv_pci_tbi(arena->hose, 0, -1); - p = 0, i = 0; while (i < n && p+i < nent) { if (ptes[p+i]) @@ -139,7 +135,7 @@ iommu_arena_free(struct pci_iommu_arena *arena, long ofs, long n) p[i] = 0; } -/* Map a single buffer of the indicate size for PCI DMA in streaming +/* Map a single buffer of the indicated size for PCI DMA in streaming mode. The 32-bit PCI bus mastering address to use is returned. Once the device is given the dma address, the device owns this memory until either pci_unmap_single or pci_dma_sync_single is performed. */ @@ -201,6 +197,7 @@ pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size, int direction) DBGA("pci_map_single: [%p,%lx] np %ld -> sg %x from %p\n", cpu_addr, size, npages, ret, __builtin_return_address(0)); + alpha_mv.mv_pci_tbi(hose, ret, ret + size - 1); return ret; } @@ -250,10 +247,6 @@ pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size, npages = calc_npages((dma_addr & ~PAGE_MASK) + size); iommu_arena_free(arena, dma_ofs, npages); - /* If we're freeing ptes above the `next_entry' pointer, they - may have snuck back into the TLB since the last wrap flush. - We need to flush the TLB before reallocating these. */ - if (dma_ofs >= arena->next_entry) alpha_mv.mv_pci_tbi(hose, dma_addr, dma_addr + size - 1); DBGA("pci_unmap_single: sg [%x,%lx] np %ld from %p\n", @@ -441,6 +434,8 @@ sg_fill(struct scatterlist *leader, struct scatterlist *end, #endif } while (++sg < end && (int) sg->dma_address < 0); + alpha_mv.mv_pci_tbi(arena->hose, out->dma_address, + out->dma_address+out->dma_length-1); return 1; } @@ -574,10 +569,6 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, if (fend < tend) fend = tend; } - /* If we're freeing ptes above the `next_entry' pointer, they - may have snuck back into the TLB since the last wrap flush. - We need to flush the TLB before reallocating these. */ - if ((fend - arena->dma_base) >> PAGE_SHIFT >= arena->next_entry) alpha_mv.mv_pci_tbi(hose, fbeg, fend); DBGA("pci_unmap_sg: %d entries\n", nents - (end - sg)); diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h index e141df202..5463c9fec 100644 --- a/arch/alpha/kernel/proto.h +++ b/arch/alpha/kernel/proto.h @@ -61,6 +61,13 @@ extern void t2_init_arch(void); extern void t2_machine_check(u64, u64, struct pt_regs *); #define t2_pci_tbi ((void *)0) +/* core_titan.c */ +extern struct pci_ops titan_pci_ops; +extern void titan_init_arch(void); +extern void titan_kill_arch(int); +extern void titan_machine_check(u64, u64, struct pt_regs *); +extern void titan_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); + /* core_tsunami.c */ extern struct pci_ops tsunami_pci_ops; extern void tsunami_init_arch(void); @@ -68,9 +75,19 @@ extern void tsunami_kill_arch(int); extern void tsunami_machine_check(u64, u64, struct pt_regs *); extern void tsunami_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); +/* core_wildfire.c */ +extern struct pci_ops wildfire_pci_ops; +extern void wildfire_init_arch(void); +extern void wildfire_kill_arch(int); +extern void wildfire_machine_check(u64, u64, struct pt_regs *); +extern void wildfire_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); + /* setup.c */ extern unsigned long srm_hae; extern int boot_cpuid; +extern int srmcons_output; +extern void register_srm_console(void); +extern void unregister_srm_console(void); /* smp.c */ extern void setup_smp(void); @@ -129,7 +146,8 @@ extern void dik_show_regs(struct pt_regs *regs, unsigned long *r9_15); extern void die_if_kernel(char *, struct pt_regs *, long, unsigned long *); /* ../mm/init.c */ -void srm_paging_stop(void); +extern void switch_to_system_map(void); +extern void srm_paging_stop(void); /* irq.c */ diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index b79d42257..09fcfd787 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c @@ -246,18 +246,23 @@ sys_ptrace(long request, long pid, long addr, long data, ret = -EPERM; if (request == PTRACE_TRACEME) { /* are we already being traced? */ - if (current->flags & PF_PTRACED) - goto out; - /* set the ptrace bit in the process flags. */ - current->flags |= PF_PTRACED; + if (current->ptrace & PT_PTRACED) + goto out_notsk; + /* set the ptrace bit in the process ptrace flags. */ + current->ptrace |= PT_PTRACED; ret = 0; - goto out; + goto out_notsk; } if (pid == 1) /* you may not mess with init */ - goto out; + goto out_notsk; ret = -ESRCH; - if (!(child = find_task_by_pid(pid))) - goto out; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) + goto out_notsk; if (request == PTRACE_ATTACH) { ret = -EPERM; if (child == current) @@ -273,20 +278,22 @@ sys_ptrace(long request, long pid, long addr, long data, && !capable(CAP_SYS_PTRACE)) goto out; /* the same process cannot be attached many times */ - if (child->flags & PF_PTRACED) + if (child->ptrace & PT_PTRACED) goto out; - child->flags |= PF_PTRACED; + child->ptrace |= PT_PTRACED; + write_lock_irq(&tasklist_lock); if (child->p_pptr != current) { REMOVE_LINKS(child); child->p_pptr = current; SET_LINKS(child); } + write_unlock_irq(&tasklist_lock); send_sig(SIGSTOP, child, 1); ret = 0; goto out; } ret = -ESRCH; - if (!(child->flags & PF_PTRACED)) { + if (!(child->ptrace & PT_PTRACED)) { DBG(DBG_MEM, ("child not traced\n")); goto out; } @@ -343,9 +350,9 @@ sys_ptrace(long request, long pid, long addr, long data, if ((unsigned long) data > _NSIG) goto out; if (request == PTRACE_SYSCALL) - child->flags |= PF_TRACESYS; + child->ptrace |= PT_TRACESYS; else - child->flags &= ~PF_TRACESYS; + child->ptrace &= ~PT_TRACESYS; child->exit_code = data; wake_up_process(child); /* make sure single-step breakpoint is gone. */ @@ -373,7 +380,7 @@ sys_ptrace(long request, long pid, long addr, long data, if ((unsigned long) data > _NSIG) goto out; child->thread.bpt_nsaved = -1; /* mark single-stepping */ - child->flags &= ~PF_TRACESYS; + child->ptrace &= ~PT_TRACESYS; wake_up_process(child); child->exit_code = data; /* give it a chance to run. */ @@ -384,12 +391,14 @@ sys_ptrace(long request, long pid, long addr, long data, ret = -EIO; if ((unsigned long) data > _NSIG) goto out; - child->flags &= ~(PF_PTRACED|PF_TRACESYS); + child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); wake_up_process(child); child->exit_code = data; + write_lock_irq(&tasklist_lock); REMOVE_LINKS(child); child->p_pptr = child->p_opptr; SET_LINKS(child); + write_unlock_irq(&tasklist_lock); /* make sure single-step breakpoint is gone. */ ptrace_cancel_bpt(child); ret = 0; @@ -400,6 +409,8 @@ sys_ptrace(long request, long pid, long addr, long data, goto out; } out: + free_task_struct(child); + out_notsk: unlock_kernel(); return ret; } @@ -407,8 +418,8 @@ sys_ptrace(long request, long pid, long addr, long data, asmlinkage void syscall_trace(void) { - if ((current->flags & (PF_PTRACED|PF_TRACESYS)) - != (PF_PTRACED|PF_TRACESYS)) + if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) + != (PT_PTRACED|PT_TRACESYS)) return; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index 1eab8fc5b..988c3cbec 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -34,6 +34,15 @@ #include <linux/blk.h> #endif +#include <linux/notifier.h> +extern struct notifier_block *panic_notifier_list; +static int alpha_panic_event(struct notifier_block *, unsigned long, void *); +static struct notifier_block alpha_panic_block = { + alpha_panic_event, + NULL, + INT_MAX /* try to do it first */ +}; + #include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/system.h> @@ -42,6 +51,7 @@ #include <asm/io.h> #include <asm/pci.h> #include <asm/mmu_context.h> +#include <asm/console.h> #include "proto.h" #include "pci_impl.h" @@ -53,6 +63,17 @@ unsigned long srm_hae; /* Which processor we booted from. */ int boot_cpuid; +/* Using SRM callbacks for initial console output. This works from + setup_arch() time through the end of init_IRQ(), as those places + are under our control. + + By default, OFF; set it with a bootcommand arg of "srmcons". +*/ +int srmcons_output = 0; + +/* Enforce a memory size limit; useful for testing. By default, none. */ +unsigned long mem_size_limit = 0; + #ifdef CONFIG_ALPHA_GENERIC struct alpha_machine_vector alpha_mv; int alpha_using_srm; @@ -139,6 +160,7 @@ WEAK(noritake_mv); WEAK(noritake_primo_mv); WEAK(p2k_mv); WEAK(pc164_mv); +WEAK(privateer_mv); WEAK(rawhide_mv); WEAK(ruffian_mv); WEAK(rx164_mv); @@ -147,6 +169,7 @@ WEAK(sable_gamma_mv); WEAK(sx164_mv); WEAK(takara_mv); WEAK(webbrick_mv); +WEAK(wildfire_mv); WEAK(xl_mv); WEAK(xlt_mv); @@ -202,14 +225,33 @@ reserve_std_resources(void) for ((cluster) = (memdesc)->cluster, (i) = 0; \ (i) < (memdesc)->numclusters; (i)++, (cluster)++) +static unsigned long __init +get_mem_size_limit(char *s) +{ + unsigned long end = 0; + char *from = s; + + end = simple_strtoul(from, &from, 0); + if ( *from == 'K' || *from == 'k' ) { + end = end << 10; + from++; + } else if ( *from == 'M' || *from == 'm' ) { + end = end << 20; + from++; + } else if ( *from == 'G' || *from == 'g' ) { + end = end << 30; + from++; + } + return end >> PAGE_SHIFT; /* Return the PFN of the limit. */ +} + static void __init -setup_memory(void) +setup_memory(void * kernel_end) { struct memclust_struct * cluster; struct memdesc_struct * memdesc; unsigned long start_pfn, bootmap_size, bootmap_pages, bootmap_start; unsigned long start, end; - extern char _end[]; int i; /* Find free clusters, and init and free the bootmem accordingly. */ @@ -232,15 +274,23 @@ setup_memory(void) max_low_pfn = end; } - /* Find the end of the kernel memory. */ - start_pfn = PFN_UP(virt_to_phys(_end)); + if (mem_size_limit && max_low_pfn >= mem_size_limit) + { + printk("setup: forcing memory size to %ldK (from %ldK).\n", + mem_size_limit << (PAGE_SHIFT - 10), + max_low_pfn << (PAGE_SHIFT - 10)); + max_low_pfn = mem_size_limit; + } + + /* Find the end of the memory used by the kernel. */ + start_pfn = PFN_UP(virt_to_phys(kernel_end)); bootmap_start = -1; try_again: if (max_low_pfn <= start_pfn) panic("not enough memory to boot"); - /* We need to know how many physically contigous pages + /* We need to know how many physically contiguous pages we'll need for the bootmap. */ bootmap_pages = bootmem_bootmap_pages(max_low_pfn); @@ -307,14 +357,14 @@ setup_memory(void) printk("Initial ramdisk at: 0x%p (%lu bytes)\n", (void *) initrd_start, INITRD_SIZE); - if (initrd_end > phys_to_virt(PFN_PHYS(max_low_pfn))) { + if ((void *)initrd_end > phys_to_virt(PFN_PHYS(max_low_pfn))) { printk("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + "(0x%08lx > 0x%p)\ndisabling initrd\n", initrd_end, phys_to_virt(PFN_PHYS(max_low_pfn))); initrd_start = initrd_end = 0; } else { - reserve_bootmem(virt_to_phys(initrd_start), + reserve_bootmem(virt_to_phys((void *)initrd_start), INITRD_SIZE); } } @@ -346,20 +396,98 @@ page_is_ram(unsigned long pfn) #undef PFN_PHYS #undef PFN_MAX +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM) +/* + * Manage the SRM callbacks as a "console". + */ +static struct console srmcons; + +void __init register_srm_console(void) +{ + register_console(&srmcons); +} + +void __init unregister_srm_console(void) +{ + unregister_console(&srmcons); +} + +static void srm_console_write(struct console *co, const char *s, + unsigned count) +{ + srm_printk(s); +} + +static kdev_t srm_console_device(struct console *c) +{ + /* Huh? */ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +static int srm_console_wait_key(struct console *co) +{ + /* Huh? */ + return 1; +} + +static int __init srm_console_setup(struct console *co, char *options) +{ + return 1; +} + +static struct console srmcons = { + "srm0", + srm_console_write, + NULL, + srm_console_device, + srm_console_wait_key, + NULL, + srm_console_setup, + CON_PRINTBUFFER | CON_ENABLED, /* fake it out */ + -1, + 0, + NULL +}; + +#else +void __init register_srm_console(void) +{ +} +void __init unregister_srm_console(void) +{ +} +#endif + void __init setup_arch(char **cmdline_p) { struct alpha_machine_vector *vec = NULL; struct percpu_struct *cpu; char *type_name, *var_name, *p; + extern char _end; + void * kernel_end = &_end; /* end of kernel */ hwrpb = (struct hwrpb_struct*) __va(INIT_HWRPB->phys_addr); boot_cpuid = hard_smp_processor_id(); + /* Register a call for panic conditions. */ + notifier_chain_register(&panic_notifier_list, &alpha_panic_block); + +#ifdef CONFIG_ALPHA_GENERIC + /* Assume that we've booted from SRM if we havn't booted from MILO. + Detect the later by looking for "MILO" in the system serial nr. */ + alpha_using_srm = strncmp((const char *)hwrpb->ssn, "MILO", 4) != 0; +#endif + + /* If we are using SRM, we want to allow callbacks + as early as possible, so do this NOW, and then + they should work immediately thereafter. + */ + kernel_end = callback_init(kernel_end); + /* * Locate the command line. */ - /* Hack for Jensen... since we're restricted to 8 or 16 chars for boot flags depending on the boot mode, we need some shorthand. This should do for installation. */ @@ -375,7 +503,6 @@ setup_arch(char **cmdline_p) /* * Process command-line arguments. */ - for (p = strtok(command_line, " \t"); p ; p = strtok(NULL, " \t")) { if (strncmp(p, "alpha_mv=", 9) == 0) { vec = get_sysvec_byname(p+9); @@ -385,15 +512,27 @@ setup_arch(char **cmdline_p) est_cycle_freq = simple_strtol(p+6, NULL, 0); continue; } + if (strncmp(p, "mem=", 4) == 0) { + mem_size_limit = get_mem_size_limit(p+4); + continue; + } + if (strncmp(p, "srmcons", 7) == 0) { + srmcons_output = 1; + continue; + } } - /* Replace the command line, not that we've killed it with strtok. */ + /* Replace the command line, now that we've killed it with strtok. */ strcpy(command_line, saved_command_line); + /* If we want SRM console printk echoing early, do it now. */ + if (alpha_using_srm && srmcons_output) { + register_srm_console(); + } + /* * Indentify and reconfigure for the current system. */ - get_sysnames(hwrpb->sys_type, hwrpb->sys_variation, &type_name, &var_name); if (*var_name == '0') @@ -415,12 +554,6 @@ setup_arch(char **cmdline_p) alpha_mv = *vec; } -#ifdef CONFIG_ALPHA_GENERIC - /* Assume that we've booted from SRM if we havn't booted from MILO. - Detect the later by looking for "MILO" in the system serial nr. */ - alpha_using_srm = strncmp((const char *)hwrpb->ssn, "MILO", 4) != 0; -#endif - printk("Booting " #ifdef CONFIG_ALPHA_GENERIC "GENERIC " @@ -433,10 +566,9 @@ setup_arch(char **cmdline_p) printk("Command line: %s\n", command_line); /* - * Sync with the HAE + * Sync up the HAE. + * Save the SRM's current value for restoration. */ - - /* Save the SRM's current value for restoration. */ srm_hae = *alpha_mv.hae_register; __set_hae(alpha_mv.hae_cache); @@ -444,7 +576,7 @@ setup_arch(char **cmdline_p) wrmces(0x7); /* Find our memory. */ - setup_memory(); + setup_memory(kernel_end); /* Initialize the machine. Usually has to do with setting up DMA windows and the like. */ @@ -499,7 +631,7 @@ static char systype_names[][16] = { "Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1", "Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake", "Cortex", "29", "Miata", "XXM", "Takara", "Yukon", - "Tsunami", "Wildfire", "CUSCO", "Eiger" + "Tsunami", "Wildfire", "CUSCO", "Eiger", "Titan" }; static char unofficial_names[][8] = {"100", "Ruffian"}; @@ -523,6 +655,11 @@ static char rawhide_names[][16] = { }; static int rawhide_indices[] = {0,0,0,1,1,2,2,3,3,4,4}; +static char titan_names[][16] = { + "0", "Privateer" +}; +static int titan_indices[] = {0,1}; + static char tsunami_names[][16] = { "0", "DP264", "Warhol", "Windjammer", "Monet", "Clipper", "Goldrush", "Webbrick", "Catamaran" @@ -569,9 +706,10 @@ get_sysvec(long type, long variation, long cpu) &takara_mv, NULL, /* Yukon */ NULL, /* Tsunami -- see variation. */ - NULL, /* Wildfire */ + &wildfire_mv, /* Wildfire */ NULL, /* CUSCO */ &eiger_mv, /* Eiger */ + NULL, /* Titan */ }; static struct alpha_machine_vector *unofficial_vecs[] __initlocaldata = @@ -609,6 +747,12 @@ get_sysvec(long type, long variation, long cpu) &eb66p_mv }; + static struct alpha_machine_vector *titan_vecs[] __initlocaldata = + { + NULL, + &privateer_mv, /* privateer */ + }; + static struct alpha_machine_vector *tsunami_vecs[] __initlocaldata = { NULL, @@ -665,6 +809,10 @@ get_sysvec(long type, long variation, long cpu) if (member < N(eb66_indices)) vec = eb66_vecs[eb66_indices[member]]; break; + case ST_DEC_TITAN: + if (member < N(titan_indices)) + vec = titan_vecs[titan_indices[member]]; + break; case ST_DEC_TSUNAMI: if (member < N(tsunami_indices)) vec = tsunami_vecs[tsunami_indices[member]]; @@ -723,6 +871,7 @@ get_sysvec_byname(const char *name) &noritake_primo_mv, &p2k_mv, &pc164_mv, + &privateer_mv, &rawhide_mv, &ruffian_mv, &rx164_mv, @@ -731,6 +880,7 @@ get_sysvec_byname(const char *name) &sx164_mv, &takara_mv, &webbrick_mv, + &wildfire_mv, &xl_mv, &xlt_mv }; @@ -801,6 +951,10 @@ get_sysnames(long type, long variation, if (member < N(rawhide_indices)) *variation_name = rawhide_names[rawhide_indices[member]]; break; + case ST_DEC_TITAN: + if (member < N(titan_indices)) + *variation_name = titan_names[titan_indices[member]]; + break; case ST_DEC_TSUNAMI: if (member < N(tsunami_indices)) *variation_name = tsunami_names[tsunami_indices[member]]; @@ -873,7 +1027,7 @@ int get_cpuinfo(char *buffer) static char cpu_names[][8] = { "EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56", - "EV6", "PCA56", "PCA57", "EV67" + "EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL" }; struct percpu_struct *cpu; @@ -936,3 +1090,16 @@ int get_cpuinfo(char *buffer) return len; } + +static int alpha_panic_event(struct notifier_block *this, + unsigned long event, + void *ptr) +{ +#if 1 + /* FIXME FIXME FIXME */ + /* If we are using SRM and serial console, just hard halt here. */ + if (alpha_using_srm && srmcons_output) + __halt(); +#endif + return NOTIFY_DONE; +} diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index 1f70c98e6..db8cacbc9 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -651,7 +651,7 @@ do_signal(sigset_t *oldset, struct pt_regs * regs, struct switch_stack * sw, if (!signr) break; - if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { /* Let the debugger run. */ current->exit_code = signr; current->state = TASK_STOPPED; diff --git a/arch/alpha/kernel/smc37c669.c b/arch/alpha/kernel/smc37c669.c index caab7accc..0b2db18ab 100644 --- a/arch/alpha/kernel/smc37c669.c +++ b/arch/alpha/kernel/smc37c669.c @@ -2588,6 +2588,9 @@ void __init SMC669_Init ( int index ) ); SMC37c669_enable_device( FLOPPY_0 ); + /* Wake up sometimes forgotten floppy, especially on DP264. */ + outb(0xc, 0x3f2); + SMC37c669_disable_device( IDE_0 ); #if SMC_DEBUG diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index 1ddaaf74d..b812e2c64 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -212,8 +212,19 @@ smp_tune_scheduling (void) freq = hwrpb->cycle_freq ? : est_cycle_freq; +#if 0 /* Magic estimation stolen from x86 port. */ - cacheflush_time = freq / 1024 * on_chip_cache / 5000; + cacheflush_time = freq / 1024L * on_chip_cache / 5000L; + + printk("Using heuristic of %d cycles.\n", + cacheflush_time); +#else + /* Magic value to force potential preemption of other CPUs. */ + cacheflush_time = INT_MAX; + + printk("Using heuristic of %d cycles.\n", + cacheflush_time); +#endif } /* @@ -325,8 +336,8 @@ recv_secondary_console_msg(void) } } - printk(KERN_INFO "recv_secondary_console_msg: on %d " - "message is '%s'\n", mycpu, buf); + DBGS((KERN_INFO "recv_secondary_console_msg: on %d " + "message is '%s'\n", mycpu, buf)); } hwrpb->txrdy = 0; @@ -361,8 +372,10 @@ secondary_cpu_start(int cpuid, struct task_struct *idle) hwpcb->flags = idle->thread.pal_flags; hwpcb->res1 = hwpcb->res2 = 0; +#if 0 DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx UNIQUE 0x%lx\n", hwpcb->ksp, hwpcb->ptbr, hwrpb->vptb, hwcpb->unique)); +#endif DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n", cpuid, idle->state, idle->thread.pal_flags)); @@ -738,8 +751,10 @@ handle_ipi(struct pt_regs *regs) unsigned long *pending_ipis = &ipi_data[this_cpu].bits; unsigned long ops; - DBGS(("handle_ipi: on CPU %d ops 0x%x PC 0x%lx\n", +#if 0 + DBGS(("handle_ipi: on CPU %d ops 0x%lx PC 0x%lx\n", this_cpu, *pending_ipis, regs->pc)); +#endif mb(); /* Order interrupt and bit testing. */ while ((ops = xchg(pending_ipis, 0)) != 0) { diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c index c10018fff..475b477bd 100644 --- a/arch/alpha/kernel/sys_dp264.c +++ b/arch/alpha/kernel/sys_dp264.c @@ -36,7 +36,7 @@ /* Note mask bit is true for ENABLED irqs. */ static unsigned long cached_irq_mask; /* dp264 boards handle at max four CPUs */ -static unsigned long cpu_irq_affinity[4] = { ~0UL, ~0UL, ~0UL, ~0UL }; +static unsigned long cpu_irq_affinity[4] = { 0UL, 0UL, 0UL, 0UL }; spinlock_t dp264_irq_lock = SPIN_LOCK_UNLOCKED; @@ -52,6 +52,7 @@ tsunami_update_irq_hw(unsigned long mask) volatile unsigned long *dim0, *dim1, *dim2, *dim3; unsigned long mask0, mask1, mask2, mask3, dummy; + mask &= ~isa_enable; mask0 = mask & cpu_irq_affinity[0]; mask1 = mask & cpu_irq_affinity[1]; mask2 = mask & cpu_irq_affinity[2]; @@ -170,7 +171,6 @@ cpu_set_irq_affinity(unsigned int irq, unsigned long affinity) aff &= ~(1UL << irq); cpu_irq_affinity[cpu] = aff; } - } static void @@ -275,7 +275,12 @@ clipper_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) irq = (vector - 0x800) >> 4; - /* +#if 0 + printk("clipper_srm_device_interrupt: vector 0x%lx IRQ %d cpu %d\n", + vector, irq, smp_processor_id()); +#endif + +/* * The SRM console reports PCI interrupts with a vector calculated by: * * 0x900 + (0x10 * DRIR-bit) diff --git a/arch/alpha/kernel/sys_mikasa.c b/arch/alpha/kernel/sys_mikasa.c index f436b4902..d939b2c21 100644 --- a/arch/alpha/kernel/sys_mikasa.c +++ b/arch/alpha/kernel/sys_mikasa.c @@ -185,8 +185,8 @@ static void mikasa_apecs_machine_check(unsigned long vector, unsigned long la_ptr, struct pt_regs * regs) { -#define MCHK_NO_DEVSEL 0x205L -#define MCHK_NO_TABT 0x204L +#define MCHK_NO_DEVSEL 0x205U +#define MCHK_NO_TABT 0x204U struct el_common *mchk_header; unsigned int code; diff --git a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c new file mode 100644 index 000000000..5b3011d07 --- /dev/null +++ b/arch/alpha/kernel/sys_titan.c @@ -0,0 +1,392 @@ +/* + * linux/arch/alpha/kernel/sys_titan.c + * + * Copyright (C) 1995 David A Rusling + * Copyright (C) 1996, 1999 Jay A Estabrook + * Copyright (C) 1998, 1999 Richard Henderson + * Copyright (C) 1999, 2000 Jeff Wiedemeier + * + * Code supporting TITAN systems (EV6+TITAN), currently: + * Privateer + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/dma.h> +#include <asm/irq.h> +#include <asm/bitops.h> +#include <asm/mmu_context.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/core_titan.h> +#include <asm/hwrpb.h> + +#include "proto.h" +#include "irq_impl.h" +#include "pci_impl.h" +#include "machvec_impl.h" + +/* Note mask bit is true for ENABLED irqs. */ +static unsigned long cached_irq_mask; +/* Titan boards handle at most four CPUs. */ +static unsigned long cpu_irq_affinity[4] = { ~0UL, ~0UL, ~0UL, ~0UL }; + +spinlock_t titan_irq_lock = SPIN_LOCK_UNLOCKED; + +static void +titan_update_irq_hw(unsigned long mask) +{ + register titan_cchip *cchip = TITAN_cchip; + unsigned long isa_enable = 1UL << 55; + register int bcpu = boot_cpuid; + +#ifdef CONFIG_SMP + register unsigned long cpm = cpu_present_mask; + volatile unsigned long *dim0, *dim1, *dim2, *dim3; + unsigned long mask0, mask1, mask2, mask3, dummy; + + mask &= ~isa_enable; + mask0 = mask & cpu_irq_affinity[0]; + mask1 = mask & cpu_irq_affinity[1]; + mask2 = mask & cpu_irq_affinity[2]; + mask3 = mask & cpu_irq_affinity[3]; + + if (bcpu == 0) mask0 |= isa_enable; + else if (bcpu == 1) mask1 |= isa_enable; + else if (bcpu == 2) mask2 |= isa_enable; + else mask3 |= isa_enable; + + dim0 = &cchip->dim0.csr; + dim1 = &cchip->dim1.csr; + dim2 = &cchip->dim2.csr; + dim3 = &cchip->dim3.csr; + if ((cpm & 1) == 0) dim0 = &dummy; + if ((cpm & 2) == 0) dim1 = &dummy; + if ((cpm & 4) == 0) dim2 = &dummy; + if ((cpm & 8) == 0) dim3 = &dummy; + + *dim0 = mask0; + *dim1 = mask1; + *dim2 = mask2; + *dim3 = mask3; + mb(); + *dim0; + *dim1; + *dim2; + *dim3; +#else + volatile unsigned long *dimB; + if (bcpu == 0) dimB = &cchip->dim0.csr; + else if (bcpu == 1) dimB = &cchip->dim1.csr; + else if (bcpu == 2) dimB = &cchip->dim2.csr; + else if (bcpu == 3) dimB = &cchip->dim3.csr; + + *dimB = mask | isa_enable; + mb(); + *dimB; +#endif +} + +static inline void +privateer_enable_irq(unsigned int irq) +{ + spin_lock(&titan_irq_lock); + cached_irq_mask |= 1UL << (irq - 16); + titan_update_irq_hw(cached_irq_mask); + spin_unlock(&titan_irq_lock); +} + +static inline void +privateer_disable_irq(unsigned int irq) +{ + spin_lock(&titan_irq_lock); + cached_irq_mask &= ~(1UL << (irq - 16)); + titan_update_irq_hw(cached_irq_mask); + spin_unlock(&titan_irq_lock); +} + +static unsigned int +privateer_startup_irq(unsigned int irq) +{ + privateer_enable_irq(irq); + return 0; /* never anything pending */ +} + +static void +privateer_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + privateer_enable_irq(irq); +} + +static void +cpu_set_irq_affinity(unsigned int irq, unsigned long affinity) +{ + int cpu; + + for (cpu = 0; cpu < 4; cpu++) { + if (affinity & (1UL << cpu)) + cpu_irq_affinity[cpu] |= 1UL << irq; + else + cpu_irq_affinity[cpu] &= ~(1UL << irq); + } + +} + +static void +privateer_set_affinity(unsigned int irq, unsigned long affinity) +{ + spin_lock(&titan_irq_lock); + cpu_set_irq_affinity(irq - 16, affinity); + titan_update_irq_hw(cached_irq_mask); + spin_unlock(&titan_irq_lock); +} + +static struct hw_interrupt_type privateer_irq_type = { + typename: "PRIVATEER", + startup: privateer_startup_irq, + shutdown: privateer_disable_irq, + enable: privateer_enable_irq, + disable: privateer_disable_irq, + ack: privateer_disable_irq, + end: privateer_end_irq, + set_affinity: privateer_set_affinity, +}; + +static void +privateer_device_interrupt(unsigned long vector, struct pt_regs * regs) +{ + printk("privateer_device_interrupt: NOT IMPLEMENTED YET!! \n"); +} + +static void +privateer_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +{ + int irq; + + irq = (vector - 0x800) >> 4; + handle_irq(irq, regs); +} + + +static void __init +init_titan_irqs(struct hw_interrupt_type * ops, int imin, int imax) +{ + long i; + for(i = imin; i <= imax; ++i) { + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i].handler = ops; + } +} + +static void __init +privateer_init_irq(void) +{ + extern asmlinkage void entInt(void); + int cpu; + + outb(0, DMA1_RESET_REG); + outb(0, DMA2_RESET_REG); + outb(DMA_MODE_CASCADE, DMA2_MODE_REG); + outb(0, DMA2_MASK_REG); + + if (alpha_using_srm) + alpha_mv.device_interrupt = privateer_srm_device_interrupt; + + titan_update_irq_hw(0UL); + + init_i8259a_irqs(); + init_titan_irqs(&privateer_irq_type, 16, 63 + 16); +} + +/* + * Privateer PCI Fixup configuration. + * + * PCHIP 0 BUS 0 (Hose 0) + * + * IDSEL Dev What + * ----- --- ---- + * 18 7 Embedded Southbridge + * 19 8 Slot 0 + * 20 9 Slot 1 + * 21 10 Slot 2 + * 22 11 Slot 3 + * 23 12 Embedded HotPlug controller + * 27 16 Embedded Southbridge IDE + * 29 18 Embedded Southbridge PMU + * 31 20 Embedded Southbridge USB + * + * PCHIP 1 BUS 0 (Hose 1) + * + * IDSEL Dev What + * ----- --- ---- + * 12 1 Slot 0 + * 13 2 Slot 1 + * 17 6 Embedded hotPlug controller + * + * PCHIP 0 BUS 1 (Hose 2) + * + * IDSEL What + * ----- ---- + * NONE AGP + * + * PCHIP 1 BUS 1 (Hose 3) + * + * IDSEL Dev What + * ----- --- ---- + * 12 1 Slot 0 + * 13 2 Slot 1 + * 17 6 Embedded hotPlug controller + * + * Summary @ TITAN_CSR_DIM0: + * Bit Meaning + * 0-7 Unused + * 8 PCHIP 0 BUS 1 YUKON (if present) + * 9 PCHIP 1 BUS 1 YUKON + * 10 PCHIP 1 BUS 0 YUKON + * 11 PCHIP 0 BUS 0 YUKON + * 12 PCHIP 0 BUS 0 SLOT 2 INT A + * 13 PCHIP 0 BUS 0 SLOT 2 INT B + * 14 PCHIP 0 BUS 0 SLOT 2 INT C + * 15 PCHIP 0 BUS 0 SLOT 2 INT D + * 16 PCHIP 0 BUS 0 SLOT 3 INT A + * 17 PCHIP 0 BUS 0 SLOT 3 INT B + * 18 PCHIP 0 BUS 0 SLOT 3 INT C + * 19 PCHIP 0 BUS 0 SLOT 3 INT D + * 20 PCHIP 0 BUS 0 SLOT 0 INT A + * 21 PCHIP 0 BUS 0 SLOT 0 INT B + * 22 PCHIP 0 BUS 0 SLOT 0 INT C + * 23 PCHIP 0 BUS 0 SLOT 0 INT D + * 24 PCHIP 0 BUS 0 SLOT 1 INT A + * 25 PCHIP 0 BUS 0 SLOT 1 INT B + * 26 PCHIP 0 BUS 0 SLOT 1 INT C + * 27 PCHIP 0 BUS 0 SLOT 1 INT D + * 28 PCHIP 1 BUS 0 SLOT 0 INT A + * 29 PCHIP 1 BUS 0 SLOT 0 INT B + * 30 PCHIP 1 BUS 0 SLOT 0 INT C + * 31 PCHIP 1 BUS 0 SLOT 0 INT D + * 32 PCHIP 1 BUS 0 SLOT 1 INT A + * 33 PCHIP 1 BUS 0 SLOT 1 INT B + * 34 PCHIP 1 BUS 0 SLOT 1 INT C + * 35 PCHIP 1 BUS 0 SLOT 1 INT D + * 36 PCHIP 1 BUS 1 SLOT 0 INT A + * 37 PCHIP 1 BUS 1 SLOT 0 INT B + * 38 PCHIP 1 BUS 1 SLOT 0 INT C + * 39 PCHIP 1 BUS 1 SLOT 0 INT D + * 40 PCHIP 1 BUS 1 SLOT 1 INT A + * 41 PCHIP 1 BUS 1 SLOT 1 INT B + * 42 PCHIP 1 BUS 1 SLOT 1 INT C + * 43 PCHIP 1 BUS 1 SLOT 1 INT D + * 44 AGP INT A + * 45 AGP INT B + * 46-47 Unused + * 49 Reserved for Sleep mode + * 50 Temperature Warning (optional) + * 51 Power Warning (optional) + * 52 Reserved + * 53 South Bridge NMI + * 54 South Bridge SMI INT + * 55 South Bridge ISA Interrupt + * 56-58 Unused + * 59 PCHIP1_C_ERROR + * 60 PCHIP0_C_ERROR + * 61 PCHIP1_H_ERROR + * 62 PCHIP0_H_ERROR + * 63 Reserved + * + */ +static int __init +privateer_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + u8 irq; + + pcibios_read_config_byte(dev->bus->number, + dev->devfn, + PCI_INTERRUPT_LINE, + &irq); + + /* is it routed through ISA? */ + if ((irq & 0xF0) == 0xE0) + return (int)irq; + + return (int)irq + 16; /* HACK -- this better only be called once */ +} + +#ifdef CONFIG_VGA_HOSE +static struct pci_controler * __init +privateer_vga_hose_select(struct pci_controler *h1, struct pci_controler *h2) +{ + struct pci_controler *hose = h1; + int agp1, agp2; + + /* which hose(s) are agp? */ + agp1 = (0 != (TITAN_agp & (1 << h1->index))); + agp2 = (0 != (TITAN_agp & (1 << h2->index))); + + hose = h1; /* default to h1 */ + if (agp1 ^ agp2) { + if (agp2) hose = h2; /* take agp if only one */ + } else if (h2->index < h1->index) + hose = h2; /* first hose if 2xpci or 2xagp */ + + return hose; +} +#endif + +static void __init +privateer_init_pci(void) +{ + common_init_pci(); + SMC669_Init(0); +#ifdef CONFIG_VGA_HOSE + locate_and_init_vga(privateer_vga_hose_select); +#endif +} + +void +privateer_machine_check(unsigned long vector, unsigned long la_ptr, + struct pt_regs * regs) +{ + /* only handle system events here */ + if (vector != SCB_Q_SYSEVENT) + return titan_machine_check(vector, la_ptr, regs); + + /* it's a system event, handle it here */ + printk("PRIVATEER 680 Machine Check on CPU %d\n", smp_processor_id()); +} + + +/* + * The System Vectors + */ + +struct alpha_machine_vector privateer_mv __initmv = { + vector_name: "PRIVATEER", + DO_EV6_MMU, + DO_DEFAULT_RTC, + DO_TITAN_IO, + DO_TITAN_BUS, + machine_check: privateer_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: DEFAULT_MEM_BASE, + + nr_irqs: 80, /* 64 + 16 */ + device_interrupt: privateer_device_interrupt, + + init_arch: titan_init_arch, + init_irq: privateer_init_irq, + init_rtc: common_init_rtc, + init_pci: privateer_init_pci, + kill_arch: titan_kill_arch, + pci_map_irq: privateer_map_irq, + pci_swizzle: common_swizzle, +}; +ALIAS_MV(privateer) diff --git a/arch/alpha/kernel/sys_wildfire.c b/arch/alpha/kernel/sys_wildfire.c new file mode 100644 index 000000000..7aa49f50b --- /dev/null +++ b/arch/alpha/kernel/sys_wildfire.c @@ -0,0 +1,362 @@ +/* + * linux/arch/alpha/kernel/sys_wildfire.c + * + * Wildfire support. + * + * Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/dma.h> +#include <asm/irq.h> +#include <asm/bitops.h> +#include <asm/mmu_context.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/core_wildfire.h> +#include <asm/hwrpb.h> + +#include "proto.h" +#include "irq_impl.h" +#include "pci_impl.h" +#include "machvec_impl.h" + +static unsigned long cached_irq_mask[WILDFIRE_NR_IRQS/(sizeof(long)*8)]; + +spinlock_t wildfire_irq_lock = SPIN_LOCK_UNLOCKED; + +static int doing_init_irq_hw = 0; + +static void +wildfire_update_irq_hw(unsigned int irq) +{ + int qbbno = (irq >> 8) & (WILDFIRE_MAX_QBB - 1); + int pcano = (irq >> 6) & (WILDFIRE_PCA_PER_QBB - 1); + wildfire_pca *pca; + volatile unsigned long * enable0; + + if (!WILDFIRE_PCA_EXISTS(qbbno, pcano)) { + if (!doing_init_irq_hw) { + printk(KERN_ERR "wildfire_update_irq_hw:" + " got irq %d for non-existent PCA %d" + " on QBB %d.\n", + irq, pcano, qbbno); + } + return; + } + + pca = WILDFIRE_pca(qbbno, pcano); + enable0 = (unsigned long *) &pca->pca_int[0].enable; /* ??? */ + + *enable0 = cached_irq_mask[qbbno * WILDFIRE_PCA_PER_QBB + pcano]; + mb(); + *enable0; +} + +static void __init +wildfire_init_irq_hw(void) +{ +#if 0 + register wildfire_pca * pca = WILDFIRE_pca(0, 0); + volatile unsigned long * enable0, * enable1, * enable2, *enable3; + volatile unsigned long * target0, * target1, * target2, *target3; + + enable0 = (unsigned long *) &pca->pca_int[0].enable; + enable1 = (unsigned long *) &pca->pca_int[1].enable; + enable2 = (unsigned long *) &pca->pca_int[2].enable; + enable3 = (unsigned long *) &pca->pca_int[3].enable; + + target0 = (unsigned long *) &pca->pca_int[0].target; + target1 = (unsigned long *) &pca->pca_int[1].target; + target2 = (unsigned long *) &pca->pca_int[2].target; + target3 = (unsigned long *) &pca->pca_int[3].target; + + *enable0 = *enable1 = *enable2 = *enable3 = 0; + + *target0 = (1UL<<8) | WILDFIRE_QBB(0); + *target1 = *target2 = *target3 = 0; + + mb(); + + *enable0; *enable1; *enable2; *enable3; + *target0; *target1; *target2; *target3; + +#else + int i; + + doing_init_irq_hw = 1; + + /* Need to update only once for every possible PCA. */ + for (i = 0; i < WILDFIRE_NR_IRQS; i+=WILDFIRE_IRQ_PER_PCA) + wildfire_update_irq_hw(i); + + doing_init_irq_hw = 0; +#endif +} + +static void +wildfire_enable_irq(unsigned int irq) +{ + if (irq < 16) + i8259a_enable_irq(irq); + + spin_lock(&wildfire_irq_lock); + set_bit(irq, &cached_irq_mask); + wildfire_update_irq_hw(irq); + spin_unlock(&wildfire_irq_lock); +} + +static void +wildfire_disable_irq(unsigned int irq) +{ + if (irq < 16) + i8259a_disable_irq(irq); + + spin_lock(&wildfire_irq_lock); + clear_bit(irq, &cached_irq_mask); + wildfire_update_irq_hw(irq); + spin_unlock(&wildfire_irq_lock); +} + +static void +wildfire_mask_and_ack_irq(unsigned int irq) +{ + if (irq < 16) + i8259a_mask_and_ack_irq(irq); + + spin_lock(&wildfire_irq_lock); + clear_bit(irq, &cached_irq_mask); + wildfire_update_irq_hw(irq); + spin_unlock(&wildfire_irq_lock); +} + +static unsigned int +wildfire_startup_irq(unsigned int irq) +{ + wildfire_enable_irq(irq); + return 0; /* never anything pending */ +} + +static void +wildfire_end_irq(unsigned int irq) +{ +#if 0 + if (!irq_desc[irq].action) + printk("got irq %d\n", irq); +#endif + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + wildfire_enable_irq(irq); +} + +static struct hw_interrupt_type wildfire_irq_type = { + typename: "WILDFIRE", + startup: wildfire_startup_irq, + shutdown: wildfire_disable_irq, + enable: wildfire_enable_irq, + disable: wildfire_disable_irq, + ack: wildfire_mask_and_ack_irq, + end: wildfire_end_irq, +}; + +static void __init +wildfire_init_irq_per_pca(int qbbno, int pcano) +{ + int i, irq_bias; + unsigned long io_bias; + static struct irqaction isa_enable = { + handler: no_action, + name: "isa_enable", + }; + + irq_bias = qbbno * (WILDFIRE_PCA_PER_QBB * WILDFIRE_IRQ_PER_PCA) + + pcano * WILDFIRE_IRQ_PER_PCA; + + /* Only need the following for first PCI bus per PCA. */ + io_bias = WILDFIRE_IO(qbbno, pcano<<1) - WILDFIRE_IO_BIAS; + +#if 0 + outb(0, DMA1_RESET_REG + io_bias); + outb(0, DMA2_RESET_REG + io_bias); + outb(DMA_MODE_CASCADE, DMA2_MODE_REG + io_bias); + outb(0, DMA2_MASK_REG + io_bias); +#endif + +#if 0 + /* ??? Not sure how to do this, yet... */ + init_i8259a_irqs(); /* ??? */ +#endif + + for (i = 0; i < 16; ++i) { + if (i == 2) + continue; + irq_desc[i+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i+irq_bias].handler = &wildfire_irq_type; + } + + irq_desc[36+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[36+irq_bias].handler = &wildfire_irq_type; + for (i = 40; i < 64; ++i) { + irq_desc[i+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i+irq_bias].handler = &wildfire_irq_type; + } + + setup_irq(32+irq_bias, &isa_enable); +} + +static void __init +wildfire_init_irq(void) +{ + int qbbno, pcano; + +#if 1 + wildfire_init_irq_hw(); + init_i8259a_irqs(); +#endif + + for (qbbno = 0; qbbno < WILDFIRE_MAX_QBB; qbbno++) { + if (WILDFIRE_QBB_EXISTS(qbbno)) { + for (pcano = 0; pcano < WILDFIRE_PCA_PER_QBB; pcano++) { + if (WILDFIRE_PCA_EXISTS(qbbno, pcano)) { + wildfire_init_irq_per_pca(qbbno, pcano); + } + } + } + } +} + +static void +wildfire_device_interrupt(unsigned long vector, struct pt_regs * regs) +{ + int irq; + + irq = (vector - 0x800) >> 4; + + /* + * bits 10-8: source QBB ID + * bits 7-6: PCA + * bits 5-0: irq in PCA + */ + + handle_irq(irq, regs); + return; +} + +/* + * PCI Fixup configuration. + * + * Summary per PCA (2 PCI or HIPPI buses): + * + * Bit Meaning + * 0-15 ISA + * + *32 ISA summary + *33 SMI + *34 NMI + *36 builtin QLogic SCSI (or slot 0 if no IO module) + *40 Interrupt Line A from slot 2 PCI0 + *41 Interrupt Line B from slot 2 PCI0 + *42 Interrupt Line C from slot 2 PCI0 + *43 Interrupt Line D from slot 2 PCI0 + *44 Interrupt Line A from slot 3 PCI0 + *45 Interrupt Line B from slot 3 PCI0 + *46 Interrupt Line C from slot 3 PCI0 + *47 Interrupt Line D from slot 3 PCI0 + * + *48 Interrupt Line A from slot 4 PCI1 + *49 Interrupt Line B from slot 4 PCI1 + *50 Interrupt Line C from slot 4 PCI1 + *51 Interrupt Line D from slot 4 PCI1 + *52 Interrupt Line A from slot 5 PCI1 + *53 Interrupt Line B from slot 5 PCI1 + *54 Interrupt Line C from slot 5 PCI1 + *55 Interrupt Line D from slot 5 PCI1 + *56 Interrupt Line A from slot 6 PCI1 + *57 Interrupt Line B from slot 6 PCI1 + *58 Interrupt Line C from slot 6 PCI1 + *50 Interrupt Line D from slot 6 PCI1 + *60 Interrupt Line A from slot 7 PCI1 + *61 Interrupt Line B from slot 7 PCI1 + *62 Interrupt Line C from slot 7 PCI1 + *63 Interrupt Line D from slot 7 PCI1 + * + * + * IdSel + * 0 Cypress Bridge I/O (ISA summary interrupt) + * 1 64 bit PCI 0 option slot 1 (SCSI QLogic builtin) + * 2 64 bit PCI 0 option slot 2 + * 3 64 bit PCI 0 option slot 3 + * 4 64 bit PCI 1 option slot 4 + * 5 64 bit PCI 1 option slot 5 + * 6 64 bit PCI 1 option slot 6 + * 7 64 bit PCI 1 option slot 7 + */ + +static int __init +wildfire_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + static char irq_tab[8][5] __initlocaldata = { + /*INT INTA INTB INTC INTD */ + { -1, -1, -1, -1, -1}, /* IdSel 0 ISA Bridge */ + { 36, 36, 36+1, 36+2, 36+3}, /* IdSel 1 SCSI builtin */ + { 40, 40, 40+1, 40+2, 40+3}, /* IdSel 2 PCI 0 slot 2 */ + { 44, 44, 44+1, 44+2, 44+3}, /* IdSel 3 PCI 0 slot 3 */ + { 48, 48, 48+1, 48+2, 48+3}, /* IdSel 4 PCI 1 slot 4 */ + { 52, 52, 52+1, 52+2, 52+3}, /* IdSel 5 PCI 1 slot 5 */ + { 56, 56, 56+1, 56+2, 56+3}, /* IdSel 6 PCI 1 slot 6 */ + { 60, 60, 60+1, 60+2, 60+3}, /* IdSel 7 PCI 1 slot 7 */ + }; + const long min_idsel = 0, max_idsel = 7, irqs_per_slot = 5; + + struct pci_controler *hose = dev->sysdata; + int irq = COMMON_TABLE_LOOKUP; + + if (irq > 0) { + int qbbno = hose->index >> 3; + int pcano = (hose->index >> 1) & 3; + irq += (qbbno << 8) + (pcano << 6); + } + return irq; +} + +static void __init +wildfire_init_pci(void) +{ + common_init_pci(); +} + +/* + * The System Vectors + */ + +struct alpha_machine_vector wildfire_mv __initmv = { + vector_name: "WILDFIRE", + DO_EV6_MMU, + DO_DEFAULT_RTC, + DO_WILDFIRE_IO, + DO_WILDFIRE_BUS, + machine_check: wildfire_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + min_io_address: DEFAULT_IO_BASE, + min_mem_address: DEFAULT_MEM_BASE, + + nr_irqs: WILDFIRE_NR_IRQS, + device_interrupt: wildfire_device_interrupt, + + init_arch: wildfire_init_arch, + init_irq: wildfire_init_irq, + init_rtc: common_init_rtc, + init_pci: wildfire_init_pci, + kill_arch: wildfire_kill_arch, + pci_map_irq: wildfire_map_irq, + pci_swizzle: common_swizzle, +}; +ALIAS_MV(wildfire) diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index 8edfef27d..7b2f8be03 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -27,30 +27,234 @@ dik_show_regs(struct pt_regs *regs, unsigned long *r9_15) { printk("pc = [<%016lx>] ra = [<%016lx>] ps = %04lx\n", regs->pc, regs->r26, regs->ps); - printk("r0 = %016lx r1 = %016lx r2 = %016lx\n", + printk("v0 = %016lx t0 = %016lx t1 = %016lx\n", regs->r0, regs->r1, regs->r2); - printk("r3 = %016lx r4 = %016lx r5 = %016lx\n", + printk("t2 = %016lx t3 = %016lx t4 = %016lx\n", regs->r3, regs->r4, regs->r5); - printk("r6 = %016lx r7 = %016lx r8 = %016lx\n", + printk("t5 = %016lx t6 = %016lx t7 = %016lx\n", regs->r6, regs->r7, regs->r8); if (r9_15) { - printk("r9 = %016lx r10= %016lx r11= %016lx\n", + printk("s0 = %016lx s1 = %016lx s2 = %016lx\n", r9_15[9], r9_15[10], r9_15[11]); - printk("r12= %016lx r13= %016lx r14= %016lx\n", + printk("s3 = %016lx s4 = %016lx s5 = %016lx\n", r9_15[12], r9_15[13], r9_15[14]); - printk("r15= %016lx\n", r9_15[15]); + printk("s6 = %016lx\n", r9_15[15]); } - printk("r16= %016lx r17= %016lx r18= %016lx\n", + printk("a0 = %016lx a1 = %016lx a2 = %016lx\n", regs->r16, regs->r17, regs->r18); - printk("r19= %016lx r20= %016lx r21= %016lx\n", + printk("a3 = %016lx a4 = %016lx a5 = %016lx\n", regs->r19, regs->r20, regs->r21); - printk("r22= %016lx r23= %016lx r24= %016lx\n", + printk("t8 = %016lx t9 = %016lx t10= %016lx\n", regs->r22, regs->r23, regs->r24); - printk("r25= %016lx r27= %016lx r28= %016lx\n", + printk("t11= %016lx pv = %016lx at = %016lx\n", regs->r25, regs->r27, regs->r28); printk("gp = %016lx sp = %p\n", regs->gp, regs+1); +#if 0 +__halt(); +#endif +} + +static char * ireg_name[] = {"v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", + "t7", "s0", "s1", "s2", "s3", "s4", "s5", "s6", + "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9", + "t10", "t11", "ra", "pv", "at", "gp", "sp", "zero"}; + +static char * inst_name[] = {"call_pal", "", "", "", "", "", "", "", + "lda", "ldah", "ldbu", "ldq_u", "ldwu", "stw", "stb", "stq_u", + "ALU", "ALU", "ALU", "ALU", "SQRT", "FVAX", "FIEEE", "FLOAT", + "MISC", "PAL19", "JMP", "PAL1B", "GRAPH", "PAL1D", "PAL1E", "PAL1F", + "ldf", "ldg", "lds", "ldt", "stf", "stg", "sts", "stt", + "ldl", "ldq", "ldl_l", "ldq_l", "stl", "stq", "stl_c", "stq_c", + "br", "fbeq", "fblt", "fble", "bsr", "fbne", "fbge", "fbgt" + "blbc", "beq", "blt", "ble", "blbs", "bne", "bge", "bgt" +}; + +static char * jump_name[] = {"jmp", "jsr", "ret", "jsr_coroutine"}; + +typedef struct {int func; char * text;} alist; + +static alist inta_name[] = {{0, "addl"}, {2, "s4addl"}, {9, "subl"}, + {0xb, "s4subl"}, {0xf, "cmpbge"}, {0x12, "s8addl"}, {0x1b, "s8subl"}, + {0x1d, "cmpult"}, {0x20, "addq"}, {0x22, "s4addq"}, {0x29, "subq"}, + {0x2b, "s4subq"}, {0x2d, "cmpeq"}, {0x32, "s8addq"}, {0x3b, "s8subq"}, + {0x3d, "cmpule"}, {0x40, "addl/v"}, {0x49, "subl/v"}, {0x4d, "cmplt"}, + {0x60, "addq/v"}, {0x69, "subq/v"}, {0x6d, "cmple"}, {-1, 0}}; + +static alist intl_name[] = {{0, "and"}, {8, "andnot"}, {0x14, "cmovlbs"}, + {0x16, "cmovlbc"}, {0x20, "or"}, {0x24, "cmoveq"}, {0x26, "cmovne"}, + {0x28, "ornot"}, {0x40, "xor"}, {0x44, "cmovlt"}, {0x46, "cmovge"}, + {0x48, "eqv"}, {0x61, "amask"}, {0x64, "cmovle"}, {0x66, "cmovgt"}, + {0x6c, "implver"}, {-1, 0}}; + +static alist ints_name[] = {{2, "mskbl"}, {6, "extbl"}, {0xb, "insbl"}, + {0x12, "mskwl"}, {0x16, "extwl"}, {0x1b, "inswl"}, {0x22, "mskll"}, + {0x26, "extll"}, {0x2b, "insll"}, {0x30, "zap"}, {0x31, "zapnot"}, + {0x32, "mskql"}, {0x34, "srl"}, {0x36, "extql"}, {0x39, "sll"}, + {0x3b, "insql"}, {0x3c, "sra"}, {0x52, "mskwh"}, {0x57, "inswh"}, + {0x5a, "extwh"}, {0x62, "msklh"}, {0x67, "inslh"}, {0x6a, "extlh"}, + {0x72, "mskqh"}, {0x77, "insqh"}, {0x7a, "extqh"}, {-1, 0}}; + +static alist intm_name[] = {{0, "mull"}, {0x20, "mulq"}, {0x30, "umulh"}, + {0x40, "mull/v"}, {0x60, "mulq/v"}, {-1, 0}}; + +static alist * int_name[] = {inta_name, intl_name, ints_name, intm_name}; + +static char * +assoc(int fcode, alist * a) +{ + while ((fcode != a->func) && (a->func != -1)) + ++a; + return a->text; +} + +static char * +iname(unsigned int instr) +{ + int opcode = instr >> 26; + char * name = inst_name[opcode]; + + switch (opcode) { + default: + break; + + case 0x10: + case 0x11: + case 0x12: + case 0x13: { + char * specific_name + = assoc((instr >> 5) & 0x3f, int_name[opcode - 0x10]); + if (specific_name) + name = specific_name; + break; + } + + case 0x1a: + name = jump_name[(instr >> 14) & 3]; + break; + } + + return name; +} + +static enum {NOT_INST, PAL, BRANCH, MEMORY, JUMP, OPERATE, FOPERATE, MISC} +iformat(int opcode) +{ + if (opcode >= 0x30) + return BRANCH; + if (opcode >= 0x20) + return MEMORY; + if (opcode == 0) + return PAL; + if (opcode < 8) + return NOT_INST; + if (opcode < 0x10) + return MEMORY; + if (opcode < 0x14) + return OPERATE; + if (opcode < 0x18) + return FOPERATE; + switch (opcode) { + case 0x18: + return MISC; + case 0x1A: + return JUMP; + case 0x1C: + return OPERATE; + default: + return NOT_INST; + } +} + +/* + * The purpose here is to provide useful clues about a kernel crash, so + * less likely instructions, e.g. floating point, aren't fully decoded. + */ +static void +disassemble(unsigned int instr) +{ + int optype = instr >> 26; + char buf[40], *s = buf; + + s += sprintf(buf, "%08x %s ", instr, iname(instr)); + switch (iformat(optype)) { + default: + case NOT_INST: + case MISC: + break; + + case PAL: + s += sprintf(s, "%d", instr); + break; + + case BRANCH: { + int reg = (instr >> 21) & 0x1f; + int offset = instr & 0x1fffff; + + if (offset >= 0x100000) + offset -= 0x200000; + if (((optype & 3) == 0) || (optype >= 0x38)) { + if ((optype != 0x30) || (reg != 0x1f)) + s += sprintf(s, "%s,", ireg_name[reg]); + } else + s += sprintf(s, "f%d,", reg); + s += sprintf(s, ".%+d", (offset + 1) << 2); + break; + } + + case MEMORY: { + int addr_reg = (instr >> 16) & 0x1f; + int value_reg = (instr >> 21) & 0x1f; + int offset = instr & 0xffff; + + if (offset >= 0x8000) + offset -= 0x10000; + if ((optype >= 0x20) && (optype < 0x28)) + s += sprintf(s, "f%d", value_reg); + else + s += sprintf(s, "%s", ireg_name[value_reg]); + + s += sprintf(s, ",%d(%s)", offset, ireg_name[addr_reg]); + break; + } + + case JUMP: { + int target_reg = (instr >> 16) & 0x1f; + int return_reg = (instr >> 21) & 0x1f; + + s += sprintf(s, "%s,", ireg_name[return_reg]); + s += sprintf(s, "(%s)", ireg_name[target_reg]); + break; + } + + case OPERATE: { + int areg = (instr >> 21) & 0x1f; + int breg = (instr >> 16) & 0x1f; + int creg = instr & 0x1f; + int litflag = instr & (1<<12); + int lit = (instr >> 13) & 0xff; + + s += sprintf(s, "%s,", ireg_name[areg]); + if (litflag) + s += sprintf(s, "%d", lit); + else + s += sprintf(s, "%s", ireg_name[breg]); + s += sprintf(s, ",%s", ireg_name[creg]); + break; + } + + case FOPERATE: { + int areg = (instr >> 21) & 0x1f; + int breg = (instr >> 16) & 0x1f; + int creg = instr & 0x1f; + + s += sprintf(s, "f%d,f%d,f%d", areg, breg, creg); + break; + } + } + buf[s-buf] = 0; + printk("%s\n", buf); } static void @@ -59,11 +263,12 @@ dik_show_code(unsigned int *pc) long i; printk("Code:"); - for (i = -3; i < 6; i++) { + for (i = -6; i < 2; i++) { unsigned int insn; if (__get_user(insn, pc+i)) break; - printk("%c%08x%c",i?' ':'<',insn,i?' ':'>'); + printk("%c", i ? ' ' : '*'); + disassemble(insn); } printk("\n"); } @@ -81,8 +286,12 @@ dik_show_trace(unsigned long *sp) continue; if (tmp >= (unsigned long) &_etext) continue; - printk(" [<%lx>]", tmp); - if (++i > 40) { + /* + * Assume that only the low 24-bits of a kernel text address + * is interesting. + */ + printk("%6x%c", (int)tmp & 0xffffff, (++i % 11) ? ' ' : '\n'); + if (i > 40) { printk(" ..."); break; } @@ -450,7 +659,7 @@ do_entUna(void * va, unsigned long opcode, unsigned long reg, got_exception: /* Ok, we caught the exception, but we don't want it. Is there someone to pass it along to? */ - if ((fixup = search_exception_table(pc)) != 0) { + if ((fixup = search_exception_table(pc, regs.gp)) != 0) { unsigned long newpc; newpc = fixup_exception(una_reg, fixup, pc); diff --git a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile index 52571557b..b6cf88e3d 100644 --- a/arch/alpha/lib/Makefile +++ b/arch/alpha/lib/Makefile @@ -2,13 +2,18 @@ # Makefile for alpha-specific library files.. # +.S.s: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $< +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $< + OBJS = __divqu.o __remqu.o __divlu.o __remlu.o memset.o memcpy.o io.o \ checksum.o csum_partial_copy.o strlen.o \ strcat.o strcpy.o strncat.o strncpy.o stxcpy.o stxncpy.o \ strchr.o strrchr.o memchr.o \ copy_user.o clear_user.o strncpy_from_user.o strlen_user.o \ csum_ipv6_magic.o strcasecmp.o semaphore.o fpreg.o \ - srm_dispatch.o srm_fixup.o srm_puts.o srm_printk.o + callback_srm.o callback_init.o srm_puts.o srm_printk.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) diff --git a/arch/alpha/lib/callback_init.c b/arch/alpha/lib/callback_init.c new file mode 100644 index 000000000..fe643ccfc --- /dev/null +++ b/arch/alpha/lib/callback_init.c @@ -0,0 +1,79 @@ +#include <linux/init.h> +#include <linux/sched.h> + +#include <asm/page.h> +#include <asm/hwrpb.h> +#include <asm/console.h> +#include <asm/pgtable.h> + +#include "../kernel/proto.h" + +extern struct hwrpb_struct *hwrpb; + +/* This is the SRM version. Maybe there will be a DBM version. */ + +int callback_init_done = 0; + +void * __init callback_init(void * kernel_end) +{ + int i, j; + unsigned long vaddr = CONSOLE_REMAP_START; + struct crb_struct * crb; + pgd_t * pgd = pgd_offset_k(vaddr); + pmd_t * pmd; + unsigned long two_pte_pages; + + if (!alpha_using_srm) { + switch_to_system_map(); + return kernel_end; + } + + /* Allocate some memory for the pages. */ + two_pte_pages = ((unsigned long)kernel_end + ~PAGE_MASK) & PAGE_MASK; + kernel_end = (void *)(two_pte_pages + 2*PAGE_SIZE); + memset((void *)two_pte_pages, 0, 2*PAGE_SIZE); + + /* Starting at the HWRPB, locate the CRB. */ + crb = (struct crb_struct *)((char *)hwrpb + hwrpb->crb_offset); + + /* Tell the console whither the console is to be remapped. */ + if (srm_fixup(vaddr, (unsigned long)hwrpb)) + __halt(); /* "We're boned." --Bender */ + + /* Edit the procedure descriptors for DISPATCH and FIXUP. */ + crb->dispatch_va = (struct procdesc_struct *) + (vaddr + (unsigned long)crb->dispatch_va - crb->map[0].va); + crb->fixup_va = (struct procdesc_struct *) + (vaddr + (unsigned long)crb->fixup_va - crb->map[0].va); + + switch_to_system_map(); + + /* + * Set up the first and second level PTEs for console callbacks. + * There is an assumption here that only one of each is needed, + * and this allows for 8MB. Currently (late 1999), big consoles + * are still under 4MB. + */ + pgd_set(pgd, (pmd_t *)two_pte_pages); + pmd = pmd_offset(pgd, vaddr); + pmd_set(pmd, (pte_t *)(two_pte_pages + PAGE_SIZE)); + + /* + * Set up the third level PTEs and update the virtual addresses + * of the CRB entries. + */ + for (i = 0; i < crb->map_entries; ++i) { + unsigned long paddr = crb->map[i].pa; + crb->map[i].va = vaddr; + for (j = 0; j < crb->map[i].count; ++j) { + set_pte(pte_offset(pmd, vaddr), + mk_pte_phys(paddr, PAGE_KERNEL)); + paddr += PAGE_SIZE; + vaddr += PAGE_SIZE; + } + } + + callback_init_done = 1; + return kernel_end; +} + diff --git a/arch/alpha/lib/callback_srm.S b/arch/alpha/lib/callback_srm.S new file mode 100644 index 000000000..de2edebb1 --- /dev/null +++ b/arch/alpha/lib/callback_srm.S @@ -0,0 +1,102 @@ +/* + * arch/alpha/lib/callback_srm.S + */ + +#include <linux/config.h> +#include <asm/console.h> + +.text +#define HWRPB_CRB_OFFSET 0xc0 + +#if defined(CONFIG_ALPHA_SRM) || defined(CONFIG_ALPHA_GENERIC) +.align 4 +srm_dispatch: +#if defined(CONFIG_ALPHA_GENERIC) + ldl $4,alpha_using_srm + beq $4,nosrm +#endif + ldq $0,hwrpb # gp is set up by CALLBACK macro. + ldl $25,0($25) # Pick up the wrapper data. + mov $20,$21 # Shift arguments right. + mov $19,$20 + ldq $1,HWRPB_CRB_OFFSET($0) + mov $18,$19 + mov $17,$18 + mov $16,$17 + addq $0,$1,$2 # CRB address + ldq $27,0($2) # DISPATCH procedure descriptor (VMS call std) + extwl $25,0,$16 # SRM callback function code + ldq $3,8($27) # call address + extwl $25,2,$25 # argument information (VMS calling std) + jmp ($3) # Return directly to caller of wrapper. + +.align 4 +.globl srm_fixup +.ent srm_fixup +srm_fixup: + ldgp $29,0($27) +#if defined(CONFIG_ALPHA_GENERIC) + ldl $4,alpha_using_srm + beq $4,nosrm +#endif + ldq $0,hwrpb + ldq $1,HWRPB_CRB_OFFSET($0) + addq $0,$1,$2 # CRB address + ldq $27,16($2) # VA of FIXUP procedure descriptor + ldq $3,8($27) # call address + lda $25,2($31) # two integer arguments + jmp ($3) # Return directly to caller of srm_fixup. +.end srm_fixup + +#if defined(CONFIG_ALPHA_GENERIC) +.align 3 +nosrm: + lda $0,-1($31) + ret +#endif + +#define CALLBACK(NAME, CODE, ARG_CNT) \ +.align 4; .globl callback_##NAME; .ent callback_##NAME; callback_##NAME##: \ +ldgp $29,0($27); br $25,srm_dispatch; .word CODE, ARG_CNT; .end callback_##NAME + +#else /* defined(CONFIG_ALPHA_SRM) || defined(CONFIG_ALPHA_GENERIC) */ + +#define CALLBACK(NAME, CODE, ARG_CNT) \ +.align 3; .globl callback_##NAME; .ent callback_##NAME; callback_##NAME##: \ +lda $0,-1($31); ret; .end callback_##NAME + +.align 3 +.globl srm_fixup +.ent srm_fixup +srm_fixup: + lda $0,-1($31) + ret +.end srm_fixup +#endif /* defined(CONFIG_ALPHA_SRM) || defined(CONFIG_ALPHA_GENERIC) */ + +CALLBACK(puts, CCB_PUTS, 4) +CALLBACK(open, CCB_OPEN, 3) +CALLBACK(close, CCB_CLOSE, 2) +CALLBACK(read, CCB_READ, 5) +CALLBACK(getenv, CCB_GET_ENV, 4) +CALLBACK(setenv, CCB_SET_ENV, 4) +CALLBACK(getc, CCB_GETC, 2) +CALLBACK(reset_term, CCB_RESET_TERM, 2) +CALLBACK(term_int, CCB_SET_TERM_INT, 3) +CALLBACK(term_ctl, CCB_SET_TERM_CTL, 3) +CALLBACK(process_keycode, CCB_PROCESS_KEYCODE, 3) +CALLBACK(ioctl, CCB_IOCTL, 6) +CALLBACK(write, CCB_WRITE, 5) +CALLBACK(reset_env, CCB_RESET_ENV, 4) +CALLBACK(save_env, CCB_SAVE_ENV, 1) +CALLBACK(pswitch, CCB_PSWITCH, 3) +CALLBACK(bios_emul, CCB_BIOS_EMUL, 5) + +.data +__alpha_using_srm: # For use by bootpheader + .long 7 # value is not 1 for link debugging + .weak alpha_using_srm; alpha_using_srm = __alpha_using_srm +__callback_init_done: # For use by bootpheader + .long 7 # value is not 1 for link debugging + .weak callback_init_done; callback_init_done = __callback_init_done + diff --git a/arch/alpha/lib/srm_dispatch.S b/arch/alpha/lib/srm_dispatch.S deleted file mode 100644 index 2bcea3073..000000000 --- a/arch/alpha/lib/srm_dispatch.S +++ /dev/null @@ -1,43 +0,0 @@ -/* - * arch/alpha/lib/srm_dispatch.S - */ - -.globl srm_dispatch -.ent srm_dispatch -srm_dispatch: - .frame $30,30,$26 - subq $30,80,$30 - stq $26,0($30) - stq $8,8($30) - stq $9,16($30) - stq $10,24($30) - stq $11,32($30) - stq $12,40($30) - stq $13,48($30) - stq $14,56($30) - stq $15,64($30) - stq $29,72($30) - .mask 0x2400FF00, -80 - .prologue 0 - - ldq $1,hwrpb - ldq $2,0xc0($1) /* crb offset */ - addq $2,$1,$2 /* crb */ - ldq $27,0($2) /* dispatch procedure value */ - - ldq $2,8($27) /* dispatch call address */ - jsr $26,($2) /* call it (weird VMS call seq) */ - - ldq $26,0($30) - ldq $8,8($30) - ldq $9,16($30) - ldq $10,24($30) - ldq $11,32($30) - ldq $12,40($30) - ldq $13,48($30) - ldq $14,56($30) - ldq $15,64($30) - ldq $29,72($30) - addq $30,80,$30 - ret $31,($26),1 -.end srm_dispatch diff --git a/arch/alpha/lib/srm_fixup.S b/arch/alpha/lib/srm_fixup.S deleted file mode 100644 index 9cf2d78c2..000000000 --- a/arch/alpha/lib/srm_fixup.S +++ /dev/null @@ -1,42 +0,0 @@ -/* - * arch/alpha/lib/srm_fixup.S - */ - -.globl srm_fixup -.ent srm_fixup -srm_fixup: - .frame $30,30,$26 - subq $30,80,$30 - stq $26,0($30) - stq $8,8($30) - stq $9,16($30) - stq $10,24($30) - stq $11,32($30) - stq $12,40($30) - stq $13,48($30) - stq $14,56($30) - stq $15,64($30) - stq $29,72($30) - .mask 0x2400FF00, -80 - .prologue 0 - - ldq $2,0xc0($17) /* crb offset */ - addq $2,$1,$2 /* crb */ - ldq $27,16($2) /* fixup procedure value */ - - ldq $2,8($27) /* dispatch call address */ - jsr $26,($2) /* call it (weird VMS call seq) */ - - ldq $26,0($30) - ldq $8,8($30) - ldq $9,16($30) - ldq $10,24($30) - ldq $11,32($30) - ldq $12,40($30) - ldq $13,48($30) - ldq $14,56($30) - ldq $15,64($30) - ldq $29,72($30) - addq $30,80,$30 - ret $31,($26),1 -.end srm_fixup diff --git a/arch/alpha/lib/srm_printk.c b/arch/alpha/lib/srm_printk.c index b5baee15f..31b53c494 100644 --- a/arch/alpha/lib/srm_printk.c +++ b/arch/alpha/lib/srm_printk.c @@ -9,13 +9,33 @@ long srm_printk(const char *fmt, ...) { static char buf[1024]; - va_list args; - long i; + va_list args; + long len, num_lf; + char *src, *dst; - va_start(args, fmt); - i = vsprintf(buf,fmt,args); - va_end(args); + va_start(args, fmt); + len = vsprintf(buf, fmt, args); + va_end(args); - srm_puts(buf); - return i; + /* count number of linefeeds in string: */ + + num_lf = 0; + for (src = buf; *src; ++src) { + if (*src == '\n') { + ++num_lf; + } + } + + if (num_lf) { + /* expand each linefeed into carriage-return/linefeed: */ + for (dst = src + num_lf; src >= buf; ) { + if (*src == '\n') { + *dst-- = '\r'; + } + *dst-- = *src--; + } + } + + srm_puts(buf, num_lf+len); + return len; } diff --git a/arch/alpha/lib/srm_puts.c b/arch/alpha/lib/srm_puts.c index 87b1d1155..7b60a6f75 100644 --- a/arch/alpha/lib/srm_puts.c +++ b/arch/alpha/lib/srm_puts.c @@ -5,30 +5,19 @@ #include <linux/string.h> #include <asm/console.h> -void -srm_puts(const char *str) +long +srm_puts(const char *str, long len) { - /* Expand \n to \r\n as we go. */ + long remaining, written; - while (*str) { - long len; - const char *e = str; + if (!callback_init_done) + return len; - if (*str == '\n') { - if (srm_dispatch(CCB_PUTS, 0, "\r", 1) < 0) - return; - ++e; - } - - e = strchr(e, '\n') ? : strchr(e, '\0'); - len = e - str; - - while (len > 0) { - long written = srm_dispatch(CCB_PUTS, 0, str, len); - if (written < 0) - return; - len -= written & 0xffffffff; - str += written & 0xffffffff; - } + for (remaining = len; remaining > 0; remaining -= written) + { + written = callback_puts(0, str, remaining); + written &= 0xffffffff; + str += written; } + return len; } diff --git a/arch/alpha/mm/extable.c b/arch/alpha/mm/extable.c index 12a1f4803..d3a02fe27 100644 --- a/arch/alpha/mm/extable.c +++ b/arch/alpha/mm/extable.c @@ -36,12 +36,12 @@ search_one_table(const struct exception_table_entry *first, register unsigned long gp __asm__("$29"); -unsigned -search_exception_table(unsigned long addr) +static unsigned +search_exception_table_without_gp(unsigned long addr) { unsigned ret; -#ifndef CONFIG_MODULE +#ifndef CONFIG_MODULES /* There is only the kernel to search. */ ret = search_one_table(__start___ex_table, __stop___ex_table - 1, addr - gp); @@ -60,3 +60,39 @@ search_exception_table(unsigned long addr) return 0; } + +unsigned +search_exception_table(unsigned long addr, unsigned long exc_gp) +{ + unsigned ret; + +#ifndef CONFIG_MODULES + ret = search_one_table(__start___ex_table, __stop___ex_table - 1, + addr - exc_gp); + if (ret) return ret; +#else + /* The kernel is the last "module" -- no need to treat it special. */ + struct module *mp; + for (mp = module_list; mp ; mp = mp->next) { + if (!mp->ex_table_start) + continue; + ret = search_one_table(mp->ex_table_start, + mp->ex_table_end - 1, addr - exc_gp); + if (ret) return ret; + } +#endif + + /* + * The search failed with the exception gp. To be safe, try the + * old method before giving up. + */ + ret = search_exception_table_without_gp(addr); + if (ret) { + printk(KERN_ALERT, "%s: [%lx] EX_TABLE search fail with" + "exc frame GP, success with raw GP\n", + current->comm, addr); + return ret; + } + + return 0; +} diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c index 1639972db..bf4839b8f 100644 --- a/arch/alpha/mm/fault.c +++ b/arch/alpha/mm/fault.c @@ -164,11 +164,13 @@ bad_area: no_context: /* Are we prepared to handle this fault as an exception? */ - if ((fixup = search_exception_table(regs->pc)) != 0) { + if ((fixup = search_exception_table(regs->pc, regs->gp)) != 0) { unsigned long newpc; newpc = fixup_exception(dpf_reg, fixup, regs->pc); - printk("%s: Exception at [<%lx>] (%lx)\n", +#if 1 + printk("%s: Exception at [<%lx>] (%lx) handled successfully\n", current->comm, regs->pc, newpc); +#endif regs->pc = newpc; return; } diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c index 2cbe9bb0f..84b608f45 100644 --- a/arch/alpha/mm/init.c +++ b/arch/alpha/mm/init.c @@ -182,43 +182,15 @@ load_PCB(struct thread_struct * pcb) return __reload_thread(pcb); } -/* - * paging_init() sets up the page tables: in the alpha version this actually - * unmaps the bootup page table (as we're now in KSEG, so we don't need it). - */ +/* switch_to_system_map() sets up some necessary page tables. */ void -paging_init(void) +switch_to_system_map(void) { unsigned long newptbr; unsigned long original_pcb_ptr; - unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; - unsigned long dma_pfn, high_pfn; - - dma_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; - high_pfn = max_low_pfn; - -#define ORDER_MASK (~((1 << (MAX_ORDER-1))-1)) -#define ORDER_ALIGN(n) (((n) + ~ORDER_MASK) & ORDER_MASK) - - dma_pfn = ORDER_ALIGN(dma_pfn); - high_pfn = ORDER_ALIGN(high_pfn); - -#undef ORDER_MASK -#undef ORDER_ALIGN - - if (dma_pfn > high_pfn) - zones_size[ZONE_DMA] = high_pfn; - else { - zones_size[ZONE_DMA] = dma_pfn; - zones_size[ZONE_NORMAL] = high_pfn - dma_pfn; - } - - /* Initialize mem_map[]. */ - free_area_init(zones_size); /* Initialize the kernel's page tables. Linux puts the vptb in the last slot of the L1 page table. */ - memset((void *)ZERO_PGE, 0, PAGE_SIZE); memset(swapper_pg_dir, 0, PAGE_SIZE); newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT; pgd_val(swapper_pg_dir[1023]) = @@ -253,6 +225,41 @@ paging_init(void) original_pcb = *(struct thread_struct *) original_pcb_ptr; } +/* + * paging_init() sets up the memory map. + */ +void +paging_init(void) +{ + unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; + unsigned long dma_pfn, high_pfn; + + dma_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; + high_pfn = max_low_pfn; + +#define ORDER_MASK (~((1L << (MAX_ORDER-1))-1)) +#define ORDER_ALIGN(n) (((n) + ~ORDER_MASK) & ORDER_MASK) + + dma_pfn = ORDER_ALIGN(dma_pfn); + high_pfn = ORDER_ALIGN(high_pfn); + +#undef ORDER_MASK +#undef ORDER_ALIGN + + if (dma_pfn > high_pfn) + zones_size[ZONE_DMA] = high_pfn; + else { + zones_size[ZONE_DMA] = dma_pfn; + zones_size[ZONE_NORMAL] = high_pfn - dma_pfn; + } + + /* Initialize mem_map[]. */ + free_area_init(zones_size); + + /* Initialize the kernel's ZERO_PGE. */ + memset((void *)ZERO_PGE, 0, PAGE_SIZE); +} + #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM) void srm_paging_stop (void) diff --git a/arch/alpha/vmlinux.lds b/arch/alpha/vmlinux.lds index 4eaac4e42..f64a926b6 100644 --- a/arch/alpha/vmlinux.lds +++ b/arch/alpha/vmlinux.lds @@ -2,7 +2,7 @@ OUTPUT_FORMAT("elf64-alpha") ENTRY(__start) SECTIONS { - . = 0xfffffc0000310000; + . = 0xfffffc0000810000; _text = .; .text : { *(.text) } _etext = .; @@ -50,9 +50,11 @@ SECTIONS .got : { *(.got) } .sdata : { *(.sdata) } _edata = .; - _bss = .; + + __bss_start = .; .sbss : { *(.sbss) *(.scommon) } .bss : { *(.bss) *(COMMON) } + __bss_stop = .; _end = .; .mdebug 0 : { *(.mdebug) } |