diff options
Diffstat (limited to 'arch')
258 files changed, 32466 insertions, 4401 deletions
diff --git a/arch/alpha/Makefile b/arch/alpha/Makefile index 44ae94a99..c07b25764 100644 --- a/arch/alpha/Makefile +++ b/arch/alpha/Makefile @@ -36,6 +36,10 @@ ifeq ($(have_mcpu),y) CFLAGS := $(CFLAGS) -mcpu=ev5 mcpu_done := y endif + ifeq ($(mcpu_done)$(CONFIG_ALPHA_SX164)$(have_mcpu_pca56),nyy) + CFLAGS := $(CFLAGS) -mcpu=pca56 + mcpu_done := y + endif ifeq ($(mcpu_done)$(CONFIG_ALPHA_PYXIS),ny) CFLAGS := $(CFLAGS) -mcpu=ev56 mcpu_done := y @@ -48,14 +52,14 @@ ifeq ($(have_mcpu),y) endif mcpu_done := y endif - ifeq ($(mcpu_done)$(CONFIG_ALPHA_NAUTILUS)$(have_mcpu_ev67),nyy) - CFLAGS := $(CFLAGS) -mcpu=ev67 - mcpu_done := y - endif ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV4),ny) CFLAGS := $(CFLAGS) -mcpu=ev4 mcpu_done := y endif + ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV67)$(have_mcpu_ev67),nyy) + CFLAGS := $(CFLAGS) -mcpu=ev67 + mcpu_done := y + endif ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV6),ny) ifeq ($(have_mcpu_ev6),y) CFLAGS := $(CFLAGS) -mcpu=ev6 diff --git a/arch/alpha/config.in b/arch/alpha/config.in index da5c361c9..649047e66 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -56,7 +56,7 @@ choice 'Alpha system type' \ 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 +unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5 CONFIG_ALPHA_EV6 CONFIG_ALPHA_EV67 unset CONFIG_ALPHA_EISA unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS @@ -138,16 +138,12 @@ if [ "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_EIGER" = "y" ] then define_bool CONFIG_ALPHA_EV6 y define_bool CONFIG_ALPHA_TSUNAMI y + bool 'EV67 (or later) CPU (speed > 600MHz)?' CONFIG_ALPHA_EV67 fi -if [ "$CONFIG_ALPHA_WILDFIRE" = "y" ] +if [ "$CONFIG_ALPHA_WILDFIRE" = "y" -o "$CONFIG_ALPHA_TITAN" = "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 + define_bool CONFIG_ALPHA_EV67 y fi if [ "$CONFIG_ALPHA_RAWHIDE" = "y" ] then @@ -165,8 +161,9 @@ then fi if [ "$CONFIG_ALPHA_NAUTILUS" = "y" ] then - define_bool CONFIG_ALPHA_EV6 y define_bool CONFIG_ALPHA_IRONGATE y + define_bool CONFIG_ALPHA_EV6 y + define_bool CONFIG_ALPHA_EV67 y fi if [ "$CONFIG_ALPHA_JENSEN" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \ diff --git a/arch/alpha/kernel/core_cia.c b/arch/alpha/kernel/core_cia.c index 1b1f46867..6203b0247 100644 --- a/arch/alpha/kernel/core_cia.c +++ b/arch/alpha/kernel/core_cia.c @@ -119,6 +119,7 @@ conf_read(unsigned long addr, unsigned char type1) stat0 = *(vip)CIA_IOC_CIA_ERR; *(vip)CIA_IOC_CIA_ERR = stat0; mb(); + *(vip)CIA_IOC_CIA_ERR; /* re-read to force write */ /* If Type1 access, must set CIA CFG. */ if (type1) { @@ -128,6 +129,7 @@ conf_read(unsigned long addr, unsigned char type1) *(vip)CIA_IOC_CFG; } + mb(); draina(); mcheck_expected(0) = 1; mcheck_taken(0) = 0; @@ -171,6 +173,7 @@ conf_write(unsigned long addr, unsigned int value, unsigned char type1) stat0 = *(vip)CIA_IOC_CIA_ERR; *(vip)CIA_IOC_CIA_ERR = stat0; mb(); + *(vip)CIA_IOC_CIA_ERR; /* re-read to force write */ /* If Type1 access, must set CIA CFG. */ if (type1) { @@ -180,6 +183,7 @@ conf_write(unsigned long addr, unsigned int value, unsigned char type1) *(vip)CIA_IOC_CFG; } + mb(); draina(); mcheck_expected(0) = 1; mcheck_taken(0) = 0; @@ -188,7 +192,7 @@ conf_write(unsigned long addr, unsigned int value, unsigned char type1) /* Access configuration space. */ *(vip)addr = value; mb(); - mb(); /* magic */ + *(vip)addr; /* read back to force the write */ mcheck_expected(0) = 0; mb(); @@ -606,7 +610,8 @@ do_init_arch(int is_pyxis) *(vip)CIA_IOC_ERR_MASK = temp; /* Clear all currently pending errors. */ - *(vip)CIA_IOC_CIA_ERR = 0; + temp = *(vip)CIA_IOC_CIA_ERR; + *(vip)CIA_IOC_CIA_ERR = temp; /* Turn on mchecks. */ temp = *(vip)CIA_IOC_CIA_CTRL; @@ -695,11 +700,11 @@ do_init_arch(int is_pyxis) *(vip)CIA_IOC_PCI_W1_BASE = 0x40000000 | 1; *(vip)CIA_IOC_PCI_W1_MASK = (0x40000000 - 1) & 0xfff00000; - *(vip)CIA_IOC_PCI_T1_BASE = 0; + *(vip)CIA_IOC_PCI_T1_BASE = 0 >> 2; *(vip)CIA_IOC_PCI_W2_BASE = 0x80000000 | 1; *(vip)CIA_IOC_PCI_W2_MASK = (0x40000000 - 1) & 0xfff00000; - *(vip)CIA_IOC_PCI_T2_BASE = 0x40000000; + *(vip)CIA_IOC_PCI_T2_BASE = 0x40000000 >> 2; *(vip)CIA_IOC_PCI_W3_BASE = 0; } diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c index 1b83bdfb9..ddf3d9755 100644 --- a/arch/alpha/kernel/pci.c +++ b/arch/alpha/kernel/pci.c @@ -8,6 +8,11 @@ /* 2.3.x PCI/resources, 1999 Andrea Arcangeli <andrea@suse.de> */ +/* + * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru> + * PCI-PCI bridges cleanup + */ + #include <linux/string.h> #include <linux/pci.h> #include <linux/init.h> @@ -51,13 +56,13 @@ struct pci_controler *pci_isa_hose; static void __init quirk_eisa_bridge(struct pci_dev *dev) { - dev->class = PCI_CLASS_BRIDGE_EISA; + dev->class = PCI_CLASS_BRIDGE_EISA << 8; } static void __init quirk_isa_bridge(struct pci_dev *dev) { - dev->class = PCI_CLASS_BRIDGE_ISA; + dev->class = PCI_CLASS_BRIDGE_ISA << 8; } static void __init @@ -71,6 +76,24 @@ quirk_ali_ide_ports(struct pci_dev *dev) dev->resource[3].end = dev->resource[3].start + 7; } +/* + * Notorious Cy82C693 chip. One of its numerous bugs: although + * Cypress IDE controller doesn't support native mode, it has + * programmable addresses of IDE command/control registers. + * This violates PCI specifications, confuses IDE subsystem + * and causes resource conflict between primary HD_CMD register + * and floppy controller. Ugh. + * Fix that. + */ +static void __init +quirk_cypress_ide_ports(struct pci_dev *dev) +{ + if (dev->class >> 8 != PCI_CLASS_STORAGE_IDE) + return; + dev->resource[0].flags = 0; + dev->resource[1].flags = 0; +} + static void __init quirk_vga_enable_rom(struct pci_dev *dev) { @@ -78,7 +101,6 @@ quirk_vga_enable_rom(struct pci_dev *dev) But if its a Cirrus 543x/544x DISABLE it, since enabling ROM disables the memory... */ if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA && - /* But if its a Cirrus 543x/544x DISABLE it */ (dev->vendor != PCI_VENDOR_ID_CIRRUS || (dev->device < 0x00a0) || (dev->device > 0x00ac))) { @@ -98,6 +120,8 @@ struct pci_fixup pcibios_fixups[] __initdata = { quirk_isa_bridge }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, quirk_ali_ide_ports }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, + quirk_cypress_ide_ports }, { PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, quirk_vga_enable_rom }, { 0 } }; @@ -122,18 +146,12 @@ pcibios_align_resource(void *data, struct resource *res, unsigned long size) start = PCIBIOS_MIN_IO + hose->io_space->start; /* - * Aligning to 0x800 rather than the minimum base of - * 0x400 is an attempt to avoid having devices in - * any 0x?C?? range, which is where the de4x5 driver - * probes for EISA cards. - * - * Adaptecs, especially, resent such intrusions. - * - * The de4x5 driver has the eisa probe conditionalized - * out for Alpha, so lower the minimum base back to 0x400. + * Put everything into 0x00-0xff region modulo 0x400 */ - alignto = MAX(0x400, size); - start = ALIGN(start, alignto); + if (start & 0x300) { + start = (start + 0x3ff) & ~0x3ff; + res->start = start; + } } else if (res->flags & IORESOURCE_MEM) { /* Make sure we start at our min on all hoses */ @@ -181,44 +199,6 @@ pcibios_align_resource(void *data, struct resource *res, unsigned long size) #undef MB #undef GB -/* - * Pre-layout host-independant device initialization. - */ - -static void __init -pcibios_assign_special(struct pci_dev * dev) -{ - int i; - - /* The first three resources of an IDE controler are often magic, - so leave them unchanged. This is true, for instance, of the - Contaq 82C693 as seen on SX164 and DP264. */ - - if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE) { - /* Resource 1 of IDE controller is the address of HD_CMD - register which actually occupies a single byte (0x3f6 - for ide0) in reported 0x3f4-3f7 range. We have to fix - that to avoid resource conflict with AT-style floppy - controller. */ - dev->resource[1].start += 2; - dev->resource[1].end = dev->resource[1].start; - for (i = 0; i < PCI_NUM_RESOURCES; i++) - if (dev->resource[i].flags && dev->resource[i].start) - pci_claim_resource(dev, i); - } - /* - * We don't have code that will init the CYPRESS bridge correctly - * so we do the next best thing, and depend on the previous - * console code to do the right thing, and ignore it here... :-\ - */ - else if (dev->vendor == PCI_VENDOR_ID_CONTAQ && - dev->device == PCI_DEVICE_ID_CONTAQ_82C693) - for (i = 0; i < PCI_NUM_RESOURCES; i++) - if (dev->resource[i].flags && dev->resource[i].start) - pci_claim_resource(dev, i); -} - - void __init pcibios_init(void) { @@ -257,7 +237,6 @@ pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus) pcibios_fixup_resource(&dev->resource[i], hose->mem_space); } - pcibios_assign_special(dev); } void __init @@ -265,17 +244,33 @@ pcibios_fixup_bus(struct pci_bus *bus) { /* Propogate hose info into the subordinate devices. */ - struct pci_controler *hose = (struct pci_controler *) bus->sysdata; + struct pci_controler *hose = bus->sysdata; struct list_head *ln; + struct pci_dev *dev = bus->self; - /* ???? */ - bus->resource[0] = hose->io_space; - bus->resource[1] = hose->mem_space; + if (!dev) { + /* Root bus */ + bus->resource[0] = hose->io_space; + bus->resource[1] = hose->mem_space; + } else { + /* This is a bridge. Do not care how it's initialized, + just link its resources to the bus ones */ + int i; - /* If this is a bridge, get the current bases */ - if (bus->self) { - pci_read_bridge_bases(bus); - pcibios_fixup_device_resources(bus->self, bus->parent); + for(i=0; i<3; i++) { + bus->resource[i] = + &dev->resource[PCI_BRIDGE_RESOURCES+i]; + bus->resource[i]->name = bus->name; + } + bus->resource[0]->flags |= pci_bridge_check_io(dev); + bus->resource[1]->flags |= IORESOURCE_MEM; + /* For now, propogate hose limits to the bus; + we'll adjust them later. */ + bus->resource[0]->end = hose->io_space->end; + bus->resource[1]->end = hose->mem_space->end; + /* Turn off downstream PF memory address range by default */ + bus->resource[2]->start = 1024*1024; + bus->resource[2]->end = bus->resource[2]->start - 1; } for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { @@ -285,7 +280,7 @@ pcibios_fixup_bus(struct pci_bus *bus) } } -void __init +void pcibios_update_resource(struct pci_dev *dev, struct resource *root, struct resource *res, int resource) { @@ -385,99 +380,6 @@ pcibios_set_master(struct pci_dev *dev) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); } -#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) - -static void __init -pcibios_size_bridge(struct pci_bus *bus, struct pbus_set_ranges_data *outer) -{ - struct pbus_set_ranges_data inner; - struct pci_dev *dev; - struct pci_dev *bridge = bus->self; - struct pci_controler *hose = bus->sysdata; - struct list_head *ln; - - if (!bridge) - return; /* host bridge, nothing to do */ - - /* set reasonable default locations for pcibios_align_resource */ - inner.io_start = hose->io_space->start + PCIBIOS_MIN_IO; - inner.mem_start = hose->mem_space->start + PCIBIOS_MIN_MEM; - inner.io_end = inner.io_start; - inner.mem_end = inner.mem_start; - - /* Collect information about how our direct children are layed out. */ - for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) { - int i; - dev = pci_dev_b(ln); - - /* Skip bridges for now */ - if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI) - continue; - - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource res; - unsigned long size; - - memcpy(&res, &dev->resource[i], sizeof(res)); - size = res.end - res.start + 1; - - if (res.flags & IORESOURCE_IO) { - res.start = inner.io_end; - pcibios_align_resource(dev, &res, size); - inner.io_end = res.start + size; - } else if (res.flags & IORESOURCE_MEM) { - res.start = inner.mem_end; - pcibios_align_resource(dev, &res, size); - inner.mem_end = res.start + size; - } - } - } - - /* And for all of the subordinate busses. */ - for (ln=bus->children.next; ln != &bus->children; ln=ln->next) - pcibios_size_bridge(pci_bus_b(ln), &inner); - - /* turn the ending locations into sizes (subtract start) */ - inner.io_end -= inner.io_start; - inner.mem_end -= inner.mem_start; - - /* Align the sizes up by bridge rules */ - inner.io_end = ROUND_UP(inner.io_end, 4*1024) - 1; - inner.mem_end = ROUND_UP(inner.mem_end, 1*1024*1024) - 1; - - /* Adjust the bridge's allocation requirements */ - 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); - outer->io_end += inner.io_end; - - outer->mem_end = ROUND_UP(outer->mem_end, 1*1024*1024); - outer->mem_end += inner.mem_end; - } -} - -#undef ROUND_UP - -static void __init -pcibios_size_bridges(void) -{ - struct list_head *ln1, *ln2; - - for(ln1=pci_root_buses.next; ln1 != &pci_root_buses; ln1=ln1->next) - for(ln2 = pci_bus_b(ln1)->children.next; - ln2 != &pci_bus_b(ln1)->children; - ln2 = ln2->next) - pcibios_size_bridge(pci_bus_b(ln2), NULL); -} - void __init common_init_pci(void) { @@ -495,10 +397,8 @@ common_init_pci(void) next_busno += 1; } - pcibios_size_bridges(); pci_assign_unassigned_resources(); pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq); - pci_set_bus_ranges(); } diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c index 3b727631a..d4eb6a5d9 100644 --- a/arch/alpha/kernel/pci_iommu.c +++ b/arch/alpha/kernel/pci_iommu.c @@ -613,10 +613,10 @@ pci_dma_supported(struct pci_dev *pdev, dma_addr_t mask) /* Check that we have a scatter-gather arena that fits. */ hose = pdev ? pdev->sysdata : pci_isa_hose; arena = hose->sg_isa; - if (arena && arena->dma_base + arena->size <= mask) + if (arena && arena->dma_base + arena->size - 1 <= mask) return 1; arena = hose->sg_pci; - if (arena && arena->dma_base + arena->size <= mask) + if (arena && arena->dma_base + arena->size - 1 <= mask) return 1; return 0; diff --git a/arch/alpha/kernel/sys_ruffian.c b/arch/alpha/kernel/sys_ruffian.c index 54fc93387..c9a2e79a4 100644 --- a/arch/alpha/kernel/sys_ruffian.c +++ b/arch/alpha/kernel/sys_ruffian.c @@ -56,9 +56,9 @@ ruffian_init_irq(void) init_i8259a_irqs(); - /* Not interested in the bogus interrupts (0,3,4,6), + /* Not interested in the bogus interrupts (0,3,6), NMI (1), HALT (2), flash (5), or 21142 (8). */ - init_pyxis_irqs(0x17f0000); + init_pyxis_irqs(0x16f0000); common_init_isa_dma(); } diff --git a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile index 913331a95..cb23a987d 100644 --- a/arch/alpha/lib/Makefile +++ b/arch/alpha/lib/Makefile @@ -3,32 +3,63 @@ # .S.s: - $(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $< + $(CPP) -D__ASSEMBLY__ $(CFLAGS) -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 fpreg.o \ + $(CC) -D__ASSEMBLY__ $(CFLAGS) -c -o $*.o $< + +# Many of these routines have implementations tuned for ev6. +# Choose them iff we're targeting ev6 specifically. +ev6 := +ifeq ($(CONFIG_ALPHA_EV6),y) + ev6 := ev6- +endif + +# Several make use of the cttz instruction introduced in ev67. +ev67 := +ifeq ($(CONFIG_ALPHA_EV67),y) + ev67 := ev67- +endif + +OBJS = __divqu.o __remqu.o __divlu.o __remlu.o \ + $(ev6)memset.o \ + $(ev6)memcpy.o \ + memmove.o \ + io.o \ + checksum.o \ + csum_partial_copy.o \ + $(ev67)strlen.o \ + $(ev67)strcat.o \ + strcpy.o \ + $(ev67)strncat.o \ + strncpy.o \ + $(ev6)stxcpy.o \ + $(ev6)stxncpy.o \ + $(ev67)strchr.o \ + strrchr.o \ + $(ev6)memchr.o \ + $(ev6)copy_user.o \ + $(ev6)clear_user.o \ + $(ev6)strncpy_from_user.o \ + $(ev67)strlen_user.o \ + $(ev6)csum_ipv6_magic.o \ + strcasecmp.o \ + fpreg.o \ callback_srm.o srm_puts.o srm_printk.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) -__divqu.o: divide.S - $(CC) $(AFLAGS) -DDIV -c -o __divqu.o divide.S +__divqu.o: $(ev6)divide.S + $(CC) $(AFLAGS) -DDIV -c -o __divqu.o $(ev6)divide.S -__remqu.o: divide.S - $(CC) $(AFLAGS) -DREM -c -o __remqu.o divide.S +__remqu.o: $(ev6)divide.S + $(CC) $(AFLAGS) -DREM -c -o __remqu.o $(ev6)divide.S -__divlu.o: divide.S - $(CC) $(AFLAGS) -DDIV -DINTSIZE -c -o __divlu.o divide.S +__divlu.o: $(ev6)divide.S + $(CC) $(AFLAGS) -DDIV -DINTSIZE -c -o __divlu.o $(ev6)divide.S -__remlu.o: divide.S - $(CC) $(AFLAGS) -DREM -DINTSIZE -c -o __remlu.o divide.S +__remlu.o: $(ev6)divide.S + $(CC) $(AFLAGS) -DREM -DINTSIZE -c -o __remlu.o $(ev6)divide.S dep: diff --git a/arch/alpha/lib/checksum.c b/arch/alpha/lib/checksum.c index 5165279f0..7f29ac81c 100644 --- a/arch/alpha/lib/checksum.c +++ b/arch/alpha/lib/checksum.c @@ -3,6 +3,10 @@ * * This file contains network checksum routines that are better done * in an architecture-specific manner due to speed.. + * Comments in other versions indicate that the algorithms are from RFC1071 + * + * accellerated versions (and 21264 assembly versions ) contributed by + * Rick Gorton <rick.gorton@alpha-processor.com> */ #include <linux/string.h> @@ -11,15 +15,25 @@ static inline unsigned short from64to16(unsigned long x) { - /* add up 32-bit words for 33 bits */ - x = (x & 0xffffffff) + (x >> 32); - /* add up 16-bit and 17-bit words for 17+c bits */ - x = (x & 0xffff) + (x >> 16); - /* add up 16-bit and 2-bit for 16+c bit */ - x = (x & 0xffff) + (x >> 16); - /* add up carry.. */ - x = (x & 0xffff) + (x >> 16); - return x; + /* Using extract instructions is a bit more efficient + than the original shift/bitmask version. */ + + union { + unsigned long ul; + unsigned int ui[2]; + unsigned short us[4]; + } in_v, tmp_v, out_v; + + in_v.ul = x; + tmp_v.ul = (unsigned long) in_v.ui[0] + (unsigned long) in_v.ui[1]; + + /* Since the bits of tmp_v.sh[3] are going to always be zero, + we don't have to bother to add that in. */ + out_v.ul = (unsigned long) tmp_v.us[0] + (unsigned long) tmp_v.us[1] + + (unsigned long) tmp_v.us[2]; + + /* Similarly, out_v.us[2] is always zero for the final add. */ + return out_v.us[0] + out_v.us[1]; } /* diff --git a/arch/alpha/lib/csum_partial_copy.c b/arch/alpha/lib/csum_partial_copy.c index 5638a1a0c..f8129b5f5 100644 --- a/arch/alpha/lib/csum_partial_copy.c +++ b/arch/alpha/lib/csum_partial_copy.c @@ -2,6 +2,8 @@ * csum_partial_copy - do IP checksumming and copy * * (C) Copyright 1996 Linus Torvalds + * accellerated versions (and 21264 assembly versions ) contributed by + * Rick Gorton <rick.gorton@alpha-processor.com> * * Don't look at this too closely - you'll go mad. The things * we do for performance.. @@ -68,6 +70,31 @@ __asm__ __volatile__("insqh %1,%2,%0":"=r" (z):"r" (x),"r" (y)) }) +static inline unsigned short from64to16(unsigned long x) +{ + /* Using extract instructions is a bit more efficient + than the original shift/bitmask version. */ + + union { + unsigned long ul; + unsigned int ui[2]; + unsigned short us[4]; + } in_v, tmp_v, out_v; + + in_v.ul = x; + tmp_v.ul = (unsigned long) in_v.ui[0] + (unsigned long) in_v.ui[1]; + + /* Since the bits of tmp_v.sh[3] are going to always be zero, + we don't have to bother to add that in. */ + out_v.ul = (unsigned long) tmp_v.us[0] + (unsigned long) tmp_v.us[1] + + (unsigned long) tmp_v.us[2]; + + /* Similarly, out_v.us[2] is always zero for the final add. */ + return out_v.us[0] + out_v.us[1]; +} + + + /* * Ok. This isn't fun, but this is the EASY case. */ @@ -335,13 +362,7 @@ do_csum_partial_copy_from_user(const char *src, char *dst, int len, soff, doff, len-8, checksum, partial_dest, errp); } - /* 64 -> 33 bits */ - checksum = (checksum & 0xffffffff) + (checksum >> 32); - /* 33 -> < 32 bits */ - checksum = (checksum & 0xffff) + (checksum >> 16); - /* 32 -> 16 bits */ - checksum = (checksum & 0xffff) + (checksum >> 16); - checksum = (checksum & 0xffff) + (checksum >> 16); + checksum = from64to16 (checksum); } return checksum; } diff --git a/arch/alpha/lib/ev6-clear_user.S b/arch/alpha/lib/ev6-clear_user.S new file mode 100644 index 000000000..090f06063 --- /dev/null +++ b/arch/alpha/lib/ev6-clear_user.S @@ -0,0 +1,228 @@ +/* + * arch/alpha/lib/ev6-clear_user.S + * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com> + * + * Zero user space, handling exceptions as we go. + * + * We have to make sure that $0 is always up-to-date and contains the + * right "bytes left to zero" value (and that it is updated only _after_ + * a successful copy). There is also some rather minor exception setup + * stuff. + * + * NOTE! This is not directly C-callable, because the calling semantics + * are different: + * + * Inputs: + * length in $0 + * destination address in $6 + * exception pointer in $7 + * return address in $28 (exceptions expect it there) + * + * Outputs: + * bytes left to copy in $0 + * + * Clobbers: + * $1,$2,$3,$4,$5,$6 + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * Try not to change the actual algorithm if possible for consistency. + * Determining actual stalls (other than slotting) doesn't appear to be easy to do. + * From perusing the source code context where this routine is called, it is + * a fair assumption that significant fractions of entire pages are zeroed, so + * it's going to be worth the effort to hand-unroll a big loop, and use wh64. + * ASSUMPTION: + * The believed purpose of only updating $0 after a store is that a signal + * may come along during the execution of this chunk of code, and we don't + * want to leave a hole (and we also want to avoid repeating lots of work) + */ + +/* Allow an exception for an insn; exit if we get one. */ +#define EX(x,y...) \ + 99: x,##y; \ + .section __ex_table,"a"; \ + .gprel32 99b; \ + lda $31, $exception-99b($31); \ + .previous + + .set noat + .set noreorder + .align 4 + + .globl __do_clear_user + .ent __do_clear_user + .frame $30, 0, $28 + .prologue 0 + + # Pipeline info : Slotting & Comments +__do_clear_user: + ldgp $29,0($27) # we do exceptions -- we need the gp. + # Macro instruction becomes ldah/lda + # .. .. E E : + and $6, 7, $4 # .. E .. .. : find dest head misalignment + beq $0, $zerolength # U .. .. .. : U L U L + + addq $0, $4, $1 # .. .. .. E : bias counter + and $1, 7, $2 # .. .. E .. : number of misaligned bytes in tail +# Note - we never actually use $2, so this is a moot computation +# and we can rewrite this later... + srl $1, 3, $1 # .. E .. .. : number of quadwords to clear + beq $4, $headalign # U .. .. .. : U L U L + +/* + * Head is not aligned. Write (8 - $4) bytes to head of destination + * This means $6 is known to be misaligned + */ + EX( ldq_u $5, 0($6) ) # .. .. .. L : load dst word to mask back in + beq $1, $onebyte # .. .. U .. : sub-word store? + mskql $5, $6, $5 # .. U .. .. : take care of misaligned head + addq $6, 8, $6 # E .. .. .. : L U U L + + EX( stq_u $5, -8($6) ) # .. .. .. L : + subq $1, 1, $1 # .. .. E .. : + addq $0, $4, $0 # .. E .. .. : bytes left -= 8 - misalignment + subq $0, 8, $0 # E .. .. .. : U L U L + + .align 4 +/* + * (The .align directive ought to be a moot point) + * values upon initial entry to the loop + * $1 is number of quadwords to clear (zero is a valid value) + * $2 is number of trailing bytes (0..7) ($2 never used...) + * $6 is known to be aligned 0mod8 + */ +$headalign: + subq $1, 16, $4 # .. .. .. E : If < 16, we can not use the huge loop + and $6, 0x3f, $2 # .. .. E .. : Forward work for huge loop + subq $2, 0x40, $3 # .. E .. .. : bias counter (huge loop) + blt $4, $trailquad # U .. .. .. : U L U L + +/* + * We know that we're going to do at least 16 quads, which means we are + * going to be able to use the large block clear loop at least once. + * Figure out how many quads we need to clear before we are 0mod64 aligned + * so we can use the wh64 instruction. + */ + + nop # .. .. .. E + nop # .. .. E .. + nop # .. E .. .. + beq $3, $bigalign # U .. .. .. : U L U L : Aligned 0mod64 + +$alignmod64: + EX( stq_u $31, 0($6) ) # .. .. .. L + addq $3, 8, $3 # .. .. E .. + subq $0, 8, $0 # .. E .. .. + nop # E .. .. .. : U L U L + + nop # .. .. .. E + subq $1, 1, $1 # .. .. E .. + addq $6, 8, $6 # .. E .. .. + blt $3, $alignmod64 # U .. .. .. : U L U L + +$bigalign: +/* + * $0 is the number of bytes left + * $1 is the number of quads left + * $6 is aligned 0mod64 + * we know that we'll be taking a minimum of one trip through + * CWG Section 3.7.6: do not expect a sustained store rate of > 1/cycle + * We are _not_ going to update $0 after every single store. That + * would be silly, because there will be cross-cluster dependencies + * no matter how the code is scheduled. By doing it in slightly + * staggered fashion, we can still do this loop in 5 fetches + * The worse case will be doing two extra quads in some future execution, + * in the event of an interrupted clear. + * Assumes the wh64 needs to be for 2 trips through the loop in the future + * The wh64 is issued on for the starting destination address for trip +2 + * through the loop, and if there are less than two trips left, the target + * address will be for the current trip. + */ + nop # E : + nop # E : + nop # E : + bis $6,$6,$3 # E : U L U L : Initial wh64 address is dest + /* This might actually help for the current trip... */ + +$do_wh64: + wh64 ($3) # .. .. .. L1 : memory subsystem hint + subq $1, 16, $4 # .. .. E .. : Forward calculation - repeat the loop? + EX( stq_u $31, 0($6) ) # .. L .. .. + subq $0, 8, $0 # E .. .. .. : U L U L + + addq $6, 128, $3 # E : Target address of wh64 + EX( stq_u $31, 8($6) ) # L : + EX( stq_u $31, 16($6) ) # L : + subq $0, 16, $0 # E : U L L U + + nop # E : + EX( stq_u $31, 24($6) ) # L : + EX( stq_u $31, 32($6) ) # L : + subq $0, 168, $5 # E : U L L U : two trips through the loop left? + /* 168 = 192 - 24, since we've already completed some stores */ + + subq $0, 16, $0 # E : + EX( stq_u $31, 40($6) ) # L : + EX( stq_u $31, 48($6) ) # L : + cmovlt $5, $6, $3 # E : U L L U : Latency 2, extra mapping cycle + + subq $1, 8, $1 # E : + subq $0, 16, $0 # E : + EX( stq_u $31, 56($6) ) # L : + nop # E : U L U L + + nop # E : + subq $0, 8, $0 # E : + addq $6, 64, $6 # E : + bge $4, $do_wh64 # U : U L U L + +$trailquad: + # zero to 16 quadwords left to store, plus any trailing bytes + # $1 is the number of quadwords left to go. + # + nop # .. .. .. E + nop # .. .. E .. + nop # .. E .. .. + beq $1, $trailbytes # U .. .. .. : U L U L : Only 0..7 bytes to go + +$onequad: + EX( stq_u $31, 0($6) ) # .. .. .. L + subq $1, 1, $1 # .. .. E .. + subq $0, 8, $0 # .. E .. .. + nop # E .. .. .. : U L U L + + nop # .. .. .. E + nop # .. .. E .. + addq $6, 8, $6 # .. E .. .. + bgt $1, $onequad # U .. .. .. : U L U L + + # We have an unknown number of bytes left to go. +$trailbytes: + nop # .. .. .. E + nop # .. .. E .. + nop # .. E .. .. + beq $0, $zerolength # U .. .. .. : U L U L + + # $0 contains the number of bytes left to copy (0..31) + # so we will use $0 as the loop counter + # We know for a fact that $0 > 0 zero due to previous context +$onebyte: + EX( stb $31, 0($6) ) # .. .. .. L + subq $0, 1, $0 # .. .. E .. : + addq $6, 1, $6 # .. E .. .. : + bgt $0, $onebyte # U .. .. .. : U L U L + +$zerolength: +$exception: # Destination for exception recovery(?) + nop # .. .. .. E : + nop # .. .. E .. : + nop # .. E .. .. : + ret $31, ($28), 1 # L0 .. .. .. : L U L U + .end __do_clear_user + diff --git a/arch/alpha/lib/ev6-copy_user.S b/arch/alpha/lib/ev6-copy_user.S new file mode 100644 index 000000000..a30f7324c --- /dev/null +++ b/arch/alpha/lib/ev6-copy_user.S @@ -0,0 +1,262 @@ +/* + * arch/alpha/lib/ev6-copy_user.S + * + * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com> + * + * Copy to/from user space, handling exceptions as we go.. This + * isn't exactly pretty. + * + * This is essentially the same as "memcpy()", but with a few twists. + * Notably, we have to make sure that $0 is always up-to-date and + * contains the right "bytes left to copy" value (and that it is updated + * only _after_ a successful copy). There is also some rather minor + * exception setup stuff.. + * + * NOTE! This is not directly C-callable, because the calling semantics are + * different: + * + * Inputs: + * length in $0 + * destination address in $6 + * source address in $7 + * return address in $28 + * + * Outputs: + * bytes left to copy in $0 + * + * Clobbers: + * $1,$2,$3,$4,$5,$6,$7 + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + */ + +/* Allow an exception for an insn; exit if we get one. */ +#define EXI(x,y...) \ + 99: x,##y; \ + .section __ex_table,"a"; \ + .gprel32 99b; \ + lda $31, $exitin-99b($31); \ + .previous + +#define EXO(x,y...) \ + 99: x,##y; \ + .section __ex_table,"a"; \ + .gprel32 99b; \ + lda $31, $exitout-99b($31); \ + .previous + + .set noat + .align 4 + .globl __copy_user + .ent __copy_user + # Pipeline info: Slotting & Comments +__copy_user: + ldgp $29,0($27) # we do exceptions -- we need the gp. + # Macro instruction becomes ldah/lda + # .. .. E E + .prologue 1 + subq $0, 32, $1 # .. E .. .. : Is this going to be a small copy? + beq $0, $zerolength # U .. .. .. : U L U L + + and $6,7,$3 # .. .. .. E : is leading dest misalignment + ble $1, $onebyteloop # .. .. U .. : 1st branch : small amount of data + beq $3, $destaligned # .. U .. .. : 2nd (one cycle fetcher stall) + subq $3, 8, $3 # E .. .. .. : L U U L : trip counter +/* + * The fetcher stall also hides the 1 cycle cross-cluster stall for $3 (L --> U) + * This loop aligns the destination a byte at a time + * We know we have at least one trip through this loop + */ +$aligndest: + EXI( ldbu $1,0($7) ) # .. .. .. L : Keep loads separate from stores + addq $6,1,$6 # .. .. E .. : Section 3.8 in the CWG + addq $3,1,$3 # .. E .. .. : + nop # E .. .. .. : U L U L + +/* + * the -1 is to compensate for the inc($6) done in a previous quadpack + * which allows us zero dependencies within either quadpack in the loop + */ + EXO( stb $1,-1($6) ) # .. .. .. L : + addq $7,1,$7 # .. .. E .. : Section 3.8 in the CWG + subq $0,1,$0 # .. E .. .. : + bne $3, $aligndest # U .. .. .. : U L U L + +/* + * If we fell through into here, we have a minimum of 33 - 7 bytes + * If we arrived via branch, we have a minimum of 32 bytes + */ +$destaligned: + and $7,7,$1 # .. .. .. E : Check _current_ source alignment + bic $0,7,$4 # .. .. E .. : number bytes as a quadword loop + EXI( ldq_u $3,0($7) ) # .. L .. .. : Forward fetch for fallthrough code + beq $1,$quadaligned # U .. .. .. : U L U L + +/* + * In the worst case, we've just executed an ldq_u here from 0($7) + * and we'll repeat it once if we take the branch + */ + +/* Misaligned quadword loop - not unrolled. Leave it that way. */ +$misquad: + EXI( ldq_u $2,8($7) ) # .. .. .. L : + subq $4,8,$4 # .. .. E .. : + extql $3,$7,$3 # .. U .. .. : + extqh $2,$7,$1 # U .. .. .. : U U L L + + bis $3,$1,$1 # .. .. .. E : + EXO( stq $1,0($6) ) # .. .. L .. : + addq $7,8,$7 # .. E .. .. : + subq $0,8,$0 # E .. .. .. : U L L U + + addq $6,8,$6 # .. .. .. E : + bis $2,$2,$3 # .. .. E .. : + nop # .. E .. .. : + bne $4,$misquad # U .. .. .. : U L U L + + nop # .. .. .. E + nop # .. .. E .. + nop # .. E .. .. + beq $0,$zerolength # U .. .. .. : U L U L + +/* We know we have at least one trip through the byte loop */ + EXI ( ldbu $2,0($7) ) # .. .. .. L : No loads in the same quad + addq $6,1,$6 # .. .. E .. : as the store (Section 3.8 in CWG) + nop # .. E .. .. : + br $31, $dirtyentry # L0 .. .. .. : L U U L +/* Do the trailing byte loop load, then hop into the store part of the loop */ + +/* + * A minimum of (33 - 7) bytes to do a quad at a time. + * Based upon the usage context, it's worth the effort to unroll this loop + * $0 - number of bytes to be moved + * $4 - number of bytes to move as quadwords + * $6 is current destination address + * $7 is current source address + */ +$quadaligned: + subq $4, 32, $2 # .. .. .. E : do not unroll for small stuff + nop # .. .. E .. + nop # .. E .. .. + blt $2, $onequad # U .. .. .. : U L U L + +/* + * There is a significant assumption here that the source and destination + * addresses differ by more than 32 bytes. In this particular case, a + * sparsity of registers further bounds this to be a minimum of 8 bytes. + * But if this isn't met, then the output result will be incorrect. + * Furthermore, due to a lack of available registers, we really can't + * unroll this to be an 8x loop (which would enable us to use the wh64 + * instruction memory hint instruction). + */ +$unroll4: + EXI( ldq $1,0($7) ) # .. .. .. L + EXI( ldq $2,8($7) ) # .. .. L .. + subq $4,32,$4 # .. E .. .. + nop # E .. .. .. : U U L L + + addq $7,16,$7 # .. .. .. E + EXO( stq $1,0($6) ) # .. .. L .. + EXO( stq $2,8($6) ) # .. L .. .. + subq $0,16,$0 # E .. .. .. : U L L U + + addq $6,16,$6 # .. .. .. E + EXI( ldq $1,0($7) ) # .. .. L .. + EXI( ldq $2,8($7) ) # .. L .. .. + subq $4, 32, $3 # E .. .. .. : U U L L : is there enough for another trip? + + EXO( stq $1,0($6) ) # .. .. .. L + EXO( stq $2,8($6) ) # .. .. L .. + subq $0,16,$0 # .. E .. .. + addq $7,16,$7 # E .. .. .. : U L L U + + nop # .. .. .. E + nop # .. .. E .. + addq $6,16,$6 # .. E .. .. + bgt $3,$unroll4 # U .. .. .. : U L U L + + nop + nop + nop + beq $4, $noquads + +$onequad: + EXI( ldq $1,0($7) ) + subq $4,8,$4 + addq $7,8,$7 + nop + + EXO( stq $1,0($6) ) + subq $0,8,$0 + addq $6,8,$6 + bne $4,$onequad + +$noquads: + nop + nop + nop + beq $0,$zerolength + +/* + * For small copies (or the tail of a larger copy), do a very simple byte loop. + * There's no point in doing a lot of complex alignment calculations to try to + * to quadword stuff for a small amount of data. + * $0 - remaining number of bytes left to copy + * $6 - current dest addr + * $7 - current source addr + */ + +$onebyteloop: + EXI ( ldbu $2,0($7) ) # .. .. .. L : No loads in the same quad + addq $6,1,$6 # .. .. E .. : as the store (Section 3.8 in CWG) + nop # .. E .. .. : + nop # E .. .. .. : U L U L + +$dirtyentry: +/* + * the -1 is to compensate for the inc($6) done in a previous quadpack + * which allows us zero dependencies within either quadpack in the loop + */ + EXO ( stb $2,-1($6) ) # .. .. .. L : + addq $7,1,$7 # .. .. E .. : quadpack as the load + subq $0,1,$0 # .. E .. .. : change count _after_ copy + bgt $0,$onebyteloop # U .. .. .. : U L U L + +$zerolength: +$exitout: # Destination for exception recovery(?) + nop # .. .. .. E + nop # .. .. E .. + nop # .. E .. .. + ret $31,($28),1 # L0 .. .. .. : L U L U + +$exitin: + + /* A stupid byte-by-byte zeroing of the rest of the output + buffer. This cures security holes by never leaving + random kernel data around to be copied elsewhere. */ + + nop + nop + nop + mov $0,$1 + +$101: + EXO ( stb $31,0($6) ) # L + subq $1,1,$1 # E + addq $6,1,$6 # E + bgt $1,$101 # U + + nop + nop + nop + ret $31,($28),1 # L0 + + .end __copy_user + diff --git a/arch/alpha/lib/ev6-csum_ipv6_magic.S b/arch/alpha/lib/ev6-csum_ipv6_magic.S new file mode 100644 index 000000000..de1948a69 --- /dev/null +++ b/arch/alpha/lib/ev6-csum_ipv6_magic.S @@ -0,0 +1,126 @@ +/* + * arch/alpha/lib/ev6-csum_ipv6_magic.S + * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com> + * + * unsigned short csum_ipv6_magic(struct in6_addr *saddr, + * struct in6_addr *daddr, + * __u32 len, + * unsigned short proto, + * unsigned int csum); + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * Try not to change the actual algorithm if possible for consistency. + * Determining actual stalls (other than slotting) doesn't appear to be easy to do. + * + * unsigned short csum_ipv6_magic(struct in6_addr *saddr, + * struct in6_addr *daddr, + * __u32 len, + * unsigned short proto, + * unsigned int csum); + * + * Swap <proto> (takes form 0xaabb) + * Then shift it left by 48, so result is: + * 0xbbaa0000 00000000 + * Then turn it back into a sign extended 32-bit item + * 0xbbaa0000 + * + * Swap <len> (an unsigned int) using Mike Burrows' 7-instruction sequence + * (we can't hide the 3-cycle latency of the unpkbw in the 6-instruction sequence) + * Assume input takes form 0xAABBCCDD + * + * Finally, original 'folding' approach is to split the long into 4 unsigned shorts + * add 4 ushorts, resulting in ushort/carry + * add carry bits + ushort --> ushort + * add carry bits + ushort --> ushort (in case the carry results in an overflow) + * Truncate to a ushort. (took 13 instructions) + * From doing some testing, using the approach in checksum.c:from64to16() + * results in the same outcome: + * split into 2 uints, add those, generating a ulong + * add the 3 low ushorts together, generating a uint + * a final add of the 2 lower ushorts + * truncating the result. + */ + + .globl csum_ipv6_magic + .align 4 + .ent csum_ipv6_magic + .frame $30,0,$26,0 +csum_ipv6_magic: + .prologue 0 + + ldq $0,0($16) # L : Latency: 3 + inslh $18,7,$4 # U : 0000000000AABBCC + ldq $1,8($16) # L : Latency: 3 + sll $19,8,$7 # U : U L U L : 0x00000000 00aabb00 + + zapnot $20,15,$20 # U : zero extend incoming csum + ldq $2,0($17) # L : Latency: 3 + sll $19,24,$19 # U : U L L U : 0x000000aa bb000000 + inswl $18,3,$18 # U : 000000CCDD000000 + + ldq $3,8($17) # L : Latency: 3 + bis $18,$4,$18 # E : 000000CCDDAABBCC + addl $19,$7,$19 # E : <sign bits>bbaabb00 + nop # E : U L U L + + addq $20,$0,$20 # E : begin summing the words + srl $18,16,$4 # U : 0000000000CCDDAA + zap $19,0x3,$19 # U : <sign bits>bbaa0000 + nop # E : L U U L + + cmpult $20,$0,$0 # E : + addq $20,$1,$20 # E : + zapnot $18,0xa,$18 # U : 00000000DD00BB00 + zap $4,0xa,$4 # U : U U L L : 0000000000CC00AA + + or $18,$4,$18 # E : 00000000DDCCBBAA + nop # E : + cmpult $20,$1,$1 # E : + addq $20,$2,$20 # E : U L U L + + cmpult $20,$2,$2 # E : + addq $20,$3,$20 # E : + cmpult $20,$3,$3 # E : (1 cycle stall on $20) + addq $20,$18,$20 # E : U L U L (1 cycle stall on $20) + + cmpult $20,$18,$18 # E : + addq $20,$19,$20 # E : (1 cycle stall on $20) + addq $0,$1,$0 # E : merge the carries back into the csum + addq $2,$3,$2 # E : + + cmpult $20,$19,$19 # E : + addq $18,$19,$18 # E : (1 cycle stall on $19) + addq $0,$2,$0 # E : + addq $20,$18,$20 # E : U L U L : + /* (1 cycle stall on $18, 2 cycles on $20) */ + + addq $0,$20,$0 # E : + zapnot $0,15,$1 # U : Start folding output (1 cycle stall on $0) + nop # E : + srl $0,32,$0 # U : U L U L : (1 cycle stall on $0) + + addq $1,$0,$1 # E : Finished generating ulong + extwl $1,2,$2 # U : ushort[1] (1 cycle stall on $1) + zapnot $1,3,$0 # U : ushort[0] (1 cycle stall on $1) + extwl $1,4,$1 # U : ushort[2] (1 cycle stall on $1) + + addq $0,$2,$0 # E + addq $0,$1,$3 # E : Finished generating uint + /* (1 cycle stall on $0) */ + extwl $3,2,$1 # U : ushort[1] (1 cycle stall on $3) + nop # E : L U L U + + addq $1,$3,$0 # E : Final carry + not $0,$4 # E : complement (1 cycle stall on $0) + zapnot $4,3,$0 # U : clear upper garbage bits + /* (1 cycle stall on $4) */ + ret # L0 : L U L U + + .end csum_ipv6_magic diff --git a/arch/alpha/lib/ev6-divide.S b/arch/alpha/lib/ev6-divide.S new file mode 100644 index 000000000..2a82b9be9 --- /dev/null +++ b/arch/alpha/lib/ev6-divide.S @@ -0,0 +1,259 @@ +/* + * arch/alpha/lib/ev6-divide.S + * + * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com> + * + * Alpha division.. + */ + +/* + * The alpha chip doesn't provide hardware division, so we have to do it + * by hand. The compiler expects the functions + * + * __divqu: 64-bit unsigned long divide + * __remqu: 64-bit unsigned long remainder + * __divqs/__remqs: signed 64-bit + * __divlu/__remlu: unsigned 32-bit + * __divls/__remls: signed 32-bit + * + * These are not normal C functions: instead of the normal + * calling sequence, these expect their arguments in registers + * $24 and $25, and return the result in $27. Register $28 may + * be clobbered (assembly temporary), anything else must be saved. + * + * In short: painful. + * + * This is a rather simple bit-at-a-time algorithm: it's very good + * at dividing random 64-bit numbers, but the more usual case where + * the divisor is small is handled better by the DEC algorithm + * using lookup tables. This uses much less memory, though, and is + * nicer on the cache.. Besides, I don't know the copyright status + * of the DEC code. + */ + +/* + * My temporaries: + * $0 - current bit + * $1 - shifted divisor + * $2 - modulus/quotient + * + * $23 - return address + * $24 - dividend + * $25 - divisor + * + * $27 - quotient/modulus + * $28 - compare status + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * Try not to change the actual algorithm if possible for consistency. + */ + +#define halt .long 0 + +/* + * Select function type and registers + */ +#define mask $0 +#define divisor $1 +#define compare $28 +#define tmp1 $3 +#define tmp2 $4 + +#ifdef DIV +#define DIV_ONLY(x,y...) x,##y +#define MOD_ONLY(x,y...) +#define func(x) __div##x +#define modulus $2 +#define quotient $27 +#define GETSIGN(x) xor $24,$25,x +#define STACK 48 +#else +#define DIV_ONLY(x,y...) +#define MOD_ONLY(x,y...) x,##y +#define func(x) __rem##x +#define modulus $27 +#define quotient $2 +#define GETSIGN(x) bis $24,$24,x +#define STACK 32 +#endif + +/* + * For 32-bit operations, we need to extend to 64-bit + */ +#ifdef INTSIZE +#define ufunction func(lu) +#define sfunction func(l) +#define LONGIFY(x) zapnot x,15,x +#define SLONGIFY(x) addl x,0,x +#else +#define ufunction func(qu) +#define sfunction func(q) +#define LONGIFY(x) +#define SLONGIFY(x) +#endif + +.set noat +.align 4 +.globl ufunction +.ent ufunction +ufunction: + subq $30,STACK,$30 # E : + .frame $30,STACK,$23 + .prologue 0 + +7: stq $1, 0($30) # L : + bis $25,$25,divisor # E : + stq $2, 8($30) # L : L U L U + + bis $24,$24,modulus # E : + stq $0,16($30) # L : + bis $31,$31,quotient # E : + LONGIFY(divisor) # E : U L L U + + stq tmp1,24($30) # L : + LONGIFY(modulus) # E : + bis $31,1,mask # E : + DIV_ONLY(stq tmp2,32($30)) # L : L U U L + + beq divisor, 9f /* div by zero */ + /* + * In spite of the DIV_ONLY being either a non-instruction + * or an actual stq, the addition of the .align directive + * below ensures that label 1 is going to be nicely aligned + */ + + .align 4 +#ifdef INTSIZE + /* + * shift divisor left, using 3-bit shifts for + * 32-bit divides as we can't overflow. Three-bit + * shifts will result in looping three times less + * here, but can result in two loops more later. + * Thus using a large shift isn't worth it (and + * s8add pairs better than a sll..) + */ +1: cmpult divisor,modulus,compare # E : + s8addq divisor,$31,divisor # E : + s8addq mask,$31,mask # E : + bne compare,1b # U : U L U L +#else +1: cmpult divisor,modulus,compare # E : + nop # E : + nop # E : + blt divisor, 2f # U : U L U L + + addq divisor,divisor,divisor # E : + addq mask,mask,mask # E : + unop # E : + bne compare,1b # U : U L U L +#endif + + /* ok, start to go right again.. */ +2: + /* + * Keep things nicely bundled... use a nop instead of not + * having an instruction for DIV_ONLY + */ +#ifdef DIV + DIV_ONLY(addq quotient,mask,tmp2) # E : +#else + nop # E : +#endif + srl mask,1,mask # U : + cmpule divisor,modulus,compare # E : + subq modulus,divisor,tmp1 # E : + +#ifdef DIV + DIV_ONLY(cmovne compare,tmp2,quotient) # E : Latency 2, extra map slot + nop # E : as part of the cmovne + srl divisor,1,divisor # U : + nop # E : L U L U + + nop # E : + cmovne compare,tmp1,modulus # E : Latency 2, extra map slot + nop # E : as part of the cmovne + bne mask,2b # U : U L U L +#else + srl divisor,1,divisor # U : + cmovne compare,tmp1,modulus # E : Latency 2, extra map slot + nop # E : as part of the cmovne + bne mask,2b # U : U L L U +#endif + +9: ldq $1, 0($30) # L : + ldq $2, 8($30) # L : + nop # E : + nop # E : U U L L + + ldq $0,16($30) # L : + ldq tmp1,24($30) # L : + nop # E : + nop # E : + +#ifdef DIV + DIV_ONLY(ldq tmp2,32($30)) # L : +#else + nop # E : +#endif + addq $30,STACK,$30 # E : + ret $31,($23),1 # L0 : L U U L + .end ufunction + +/* + * Uhh.. Ugly signed division. I'd rather not have it at all, but + * it's needed in some circumstances. There are different ways to + * handle this, really. This does: + * -a / b = a / -b = -(a / b) + * -a % b = -(a % b) + * a % -b = a % b + * which is probably not the best solution, but at least should + * have the property that (x/y)*y + (x%y) = x. + */ +.align 4 +.globl sfunction +.ent sfunction +sfunction: + subq $30,STACK,$30 # E : + .frame $30,STACK,$23 + .prologue 0 + bis $24,$25,$28 # E : + SLONGIFY($28) # E : + bge $28,7b # U : + + stq $24,0($30) # L : + subq $31,$24,$28 # E : + stq $25,8($30) # L : + nop # E : U L U L + + cmovlt $24,$28,$24 /* abs($24) */ # E : Latency 2, extra map slot + nop # E : as part of the cmov + stq $23,16($30) # L : + subq $31,$25,$28 # E : U L U L + + stq tmp1,24($30) # L : + cmovlt $25,$28,$25 /* abs($25) */ # E : Latency 2, extra map slot + nop # E : + bsr $23,ufunction # L0: L U L U + + ldq $24,0($30) # L : + ldq $25,8($30) # L : + GETSIGN($28) # E : + subq $31,$27,tmp1 # E : U U L L + + SLONGIFY($28) # E : + ldq $23,16($30) # L : + cmovlt $28,tmp1,$27 # E : Latency 2, extra map slot + nop # E : U L L U : as part of the cmov + + ldq tmp1,24($30) # L : + nop # E : as part of the cmov + addq $30,STACK,$30 # E : + ret $31,($23),1 # L0 : L U U L + .end sfunction diff --git a/arch/alpha/lib/ev6-memchr.S b/arch/alpha/lib/ev6-memchr.S new file mode 100644 index 000000000..a8e843dbc --- /dev/null +++ b/arch/alpha/lib/ev6-memchr.S @@ -0,0 +1,191 @@ +/* + * arch/alpha/lib/ev6-memchr.S + * + * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com> + * + * Finds characters in a memory area. Optimized for the Alpha: + * + * - memory accessed as aligned quadwords only + * - uses cmpbge to compare 8 bytes in parallel + * - does binary search to find 0 byte in last + * quadword (HAKMEM needed 12 instructions to + * do this instead of the 9 instructions that + * binary search needs). + * + * For correctness consider that: + * + * - only minimum number of quadwords may be accessed + * - the third argument is an unsigned long + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * Try not to change the actual algorithm if possible for consistency. + */ + + .set noreorder + .set noat + + .align 4 + .globl memchr + .ent memchr +memchr: + .frame $30,0,$26,0 + .prologue 0 + + # Hack -- if someone passes in (size_t)-1, hoping to just + # search til the end of the address space, we will overflow + # below when we find the address of the last byte. Given + # that we will never have a 56-bit address space, cropping + # the length is the easiest way to avoid trouble. + zap $18, 0x80, $5 # U : Bound length + beq $18, $not_found # U : + ldq_u $1, 0($16) # L : load first quadword Latency=3 + and $17, 0xff, $17 # E : L L U U : 00000000000000ch + + insbl $17, 1, $2 # U : 000000000000ch00 + cmpult $18, 9, $4 # E : small (< 1 quad) string? + or $2, $17, $17 # E : 000000000000chch + lda $3, -1($31) # E : U L L U + + sll $17, 16, $2 # U : 00000000chch0000 + addq $16, $5, $5 # E : Max search address + or $2, $17, $17 # E : 00000000chchchch + sll $17, 32, $2 # U : U L L U : chchchch00000000 + + or $2, $17, $17 # E : chchchchchchchch + extql $1, $16, $7 # U : $7 is upper bits + beq $4, $first_quad # U : + ldq_u $6, -1($5) # L : L U U L : eight or less bytes to search Latency=3 + + extqh $6, $16, $6 # U : 2 cycle stall for $6 + mov $16, $0 # E : + nop # E : + or $7, $6, $1 # E : L U L U $1 = quadword starting at $16 + + # Deal with the case where at most 8 bytes remain to be searched + # in $1. E.g.: + # $18 = 6 + # $1 = ????c6c5c4c3c2c1 +$last_quad: + negq $18, $6 # E : + xor $17, $1, $1 # E : + srl $3, $6, $6 # U : $6 = mask of $18 bits set + cmpbge $31, $1, $2 # E : L U L U + + nop + nop + and $2, $6, $2 # E : + beq $2, $not_found # U : U L U L + +$found_it: +#if defined(__alpha_fix__) && defined(__alpha_cix__) + /* + * Since we are guaranteed to have set one of the bits, we don't + * have to worry about coming back with a 0x40 out of cttz... + */ + cttz $2, $3 # U0 : + addq $0, $3, $0 # E : All done + nop # E : + ret # L0 : L U L U +#else + /* + * Slow and clunky. It can probably be improved. + * An exercise left for others. + */ + negq $2, $3 # E : + and $2, $3, $2 # E : + and $2, 0x0f, $1 # E : + addq $0, 4, $3 # E : + + cmoveq $1, $3, $0 # E : Latency 2, extra map cycle + nop # E : keep with cmov + and $2, 0x33, $1 # E : + addq $0, 2, $3 # E : U L U L : 2 cycle stall on $0 + + cmoveq $1, $3, $0 # E : Latency 2, extra map cycle + nop # E : keep with cmov + and $2, 0x55, $1 # E : + addq $0, 1, $3 # E : U L U L : 2 cycle stall on $0 + + cmoveq $1, $3, $0 # E : Latency 2, extra map cycle + nop + nop + ret # L0 : L U L U +#endif + + # Deal with the case where $18 > 8 bytes remain to be + # searched. $16 may not be aligned. + .align 4 +$first_quad: + andnot $16, 0x7, $0 # E : + insqh $3, $16, $2 # U : $2 = 0000ffffffffffff ($16<0:2> ff) + xor $1, $17, $1 # E : + or $1, $2, $1 # E : U L U L $1 = ====ffffffffffff + + cmpbge $31, $1, $2 # E : + bne $2, $found_it # U : + # At least one byte left to process. + ldq $1, 8($0) # L : + subq $5, 1, $18 # E : U L U L + + addq $0, 8, $0 # E : + # Make $18 point to last quad to be accessed (the + # last quad may or may not be partial). + andnot $18, 0x7, $18 # E : + cmpult $0, $18, $2 # E : + beq $2, $final # U : U L U L + + # At least two quads remain to be accessed. + + subq $18, $0, $4 # E : $4 <- nr quads to be processed + and $4, 8, $4 # E : odd number of quads? + bne $4, $odd_quad_count # U : + # At least three quads remain to be accessed + mov $1, $4 # E : L U L U : move prefetched value to correct reg + + .align 4 +$unrolled_loop: + ldq $1, 8($0) # L : prefetch $1 + xor $17, $4, $2 # E : + cmpbge $31, $2, $2 # E : + bne $2, $found_it # U : U L U L + + addq $0, 8, $0 # E : + nop # E : + nop # E : + nop # E : + +$odd_quad_count: + xor $17, $1, $2 # E : + ldq $4, 8($0) # L : prefetch $4 + cmpbge $31, $2, $2 # E : + addq $0, 8, $6 # E : + + bne $2, $found_it # U : + cmpult $6, $18, $6 # E : + addq $0, 8, $0 # E : + nop # E : + + bne $6, $unrolled_loop # U : + mov $4, $1 # E : move prefetched value into $1 + nop # E : + nop # E : + +$final: subq $5, $0, $18 # E : $18 <- number of bytes left to do + nop # E : + nop # E : + bne $18, $last_quad # U : + +$not_found: + mov $31, $0 # E : + nop # E : + nop # E : + ret # L0 : + + .end memchr diff --git a/arch/alpha/lib/ev6-memcpy.S b/arch/alpha/lib/ev6-memcpy.S new file mode 100644 index 000000000..7ebcbc27b --- /dev/null +++ b/arch/alpha/lib/ev6-memcpy.S @@ -0,0 +1,248 @@ +/* + * arch/alpha/lib/ev6-memcpy.S + * 21264 version by Rick Gorton <rick.gorton@alpha-processor.com> + * + * Reasonably optimized memcpy() routine for the Alpha 21264 + * + * - memory accessed as aligned quadwords only + * - uses bcmpge to compare 8 bytes in parallel + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * + * Temp usage notes: + * $1,$2, - scratch + */ + + .set noreorder + .set noat + + .align 4 + .globl memcpy + .ent memcpy +memcpy: + .frame $30,0,$26,0 + .prologue 0 + + mov $16, $0 # E : copy dest to return + ble $18, $nomoredata # U : done with the copy? + xor $16, $17, $1 # E : are source and dest alignments the same? + and $1, 7, $1 # E : are they the same mod 8? + + bne $1, $misaligned # U : Nope - gotta do this the slow way + /* source and dest are same mod 8 address */ + and $16, 7, $1 # E : Are both 0mod8? + beq $1, $both_0mod8 # U : Yes + nop # E : + + /* + * source and dest are same misalignment. move a byte at a time + * until a 0mod8 alignment for both is reached. + * At least one byte more to move + */ + +$head_align: + ldbu $1, 0($17) # L : grab a byte + subq $18, 1, $18 # E : count-- + addq $17, 1, $17 # E : src++ + stb $1, 0($16) # L : + addq $16, 1, $16 # E : dest++ + and $16, 7, $1 # E : Are we at 0mod8 yet? + ble $18, $nomoredata # U : done with the copy? + bne $1, $head_align # U : + +$both_0mod8: + cmple $18, 127, $1 # E : Can we unroll the loop? + bne $1, $no_unroll # U : + and $16, 63, $1 # E : get mod64 alignment + beq $1, $do_unroll # U : no single quads to fiddle + +$single_head_quad: + ldq $1, 0($17) # L : get 8 bytes + subq $18, 8, $18 # E : count -= 8 + addq $17, 8, $17 # E : src += 8 + nop # E : + + stq $1, 0($16) # L : store + addq $16, 8, $16 # E : dest += 8 + and $16, 63, $1 # E : get mod64 alignment + bne $1, $single_head_quad # U : still not fully aligned + +$do_unroll: + addq $16, 64, $7 # E : Initial (+1 trip) wh64 address + cmple $18, 63, $1 # E : Can we go through the unrolled loop? + bne $1, $tail_quads # U : Nope + nop # E : + +$unroll_body: + wh64 ($7) # L1 : memory subsystem hint: 64 bytes at + # ($7) are about to be over-written + ldq $6, 0($17) # L0 : bytes 0..7 + nop # E : + nop # E : + + ldq $4, 8($17) # L : bytes 8..15 + ldq $5, 16($17) # L : bytes 16..23 + addq $7, 64, $7 # E : Update next wh64 address + nop # E : + + ldq $3, 24($17) # L : bytes 24..31 + addq $16, 64, $1 # E : fallback value for wh64 + nop # E : + nop # E : + + addq $17, 32, $17 # E : src += 32 bytes + stq $6, 0($16) # L : bytes 0..7 + nop # E : + nop # E : + + stq $4, 8($16) # L : bytes 8..15 + stq $5, 16($16) # L : bytes 16..23 + subq $18, 192, $2 # E : At least two more trips to go? + nop # E : + + stq $3, 24($16) # L : bytes 24..31 + addq $16, 32, $16 # E : dest += 32 bytes + nop # E : + nop # E : + + ldq $6, 0($17) # L : bytes 0..7 + ldq $4, 8($17) # L : bytes 8..15 + cmovlt $2, $1, $7 # E : Latency 2, extra map slot - Use + # fallback wh64 address if < 2 more trips + nop # E : + + ldq $5, 16($17) # L : bytes 16..23 + ldq $3, 24($17) # L : bytes 24..31 + addq $16, 32, $16 # E : dest += 32 + subq $18, 64, $18 # E : count -= 64 + + addq $17, 32, $17 # E : src += 32 + stq $6, -32($16) # L : bytes 0..7 + stq $4, -24($16) # L : bytes 8..15 + cmple $18, 63, $1 # E : At least one more trip? + + stq $5, -16($16) # L : bytes 16..23 + stq $3, -8($16) # L : bytes 24..31 + nop # E : + beq $1, $unroll_body + +$tail_quads: +$no_unroll: + .align 4 + subq $18, 8, $18 # E : At least a quad left? + blt $18, $less_than_8 # U : Nope + nop # E : + nop # E : + +$move_a_quad: + ldq $1, 0($17) # L : fetch 8 + subq $18, 8, $18 # E : count -= 8 + addq $17, 8, $17 # E : src += 8 + nop # E : + + stq $1, 0($16) # L : store 8 + addq $16, 8, $16 # E : dest += 8 + bge $18, $move_a_quad # U : + nop # E : + +$less_than_8: + .align 4 + addq $18, 8, $18 # E : add back for trailing bytes + ble $18, $nomoredata # U : All-done + nop # E : + nop # E : + + /* Trailing bytes */ +$tail_bytes: + subq $18, 1, $18 # E : count-- + ldbu $1, 0($17) # L : fetch a byte + addq $17, 1, $17 # E : src++ + nop # E : + + stb $1, 0($16) # L : store a byte + addq $16, 1, $16 # E : dest++ + bgt $18, $tail_bytes # U : more to be done? + nop # E : + + /* branching to exit takes 3 extra cycles, so replicate exit here */ + ret $31, ($26), 1 # L0 : + nop # E : + nop # E : + nop # E : + +$misaligned: + mov $0, $4 # E : dest temp + and $0, 7, $1 # E : dest alignment mod8 + beq $1, $dest_0mod8 # U : life doesnt totally suck + nop + +$aligndest: + ble $18, $nomoredata # U : + ldbu $1, 0($17) # L : fetch a byte + subq $18, 1, $18 # E : count-- + addq $17, 1, $17 # E : src++ + + stb $1, 0($4) # L : store it + addq $4, 1, $4 # E : dest++ + and $4, 7, $1 # E : dest 0mod8 yet? + bne $1, $aligndest # U : go until we are aligned. + + /* Source has unknown alignment, but dest is known to be 0mod8 */ +$dest_0mod8: + subq $18, 8, $18 # E : At least a quad left? + blt $18, $misalign_tail # U : Nope + ldq_u $3, 0($17) # L : seed (rotating load) of 8 bytes + nop # E : + +$mis_quad: + ldq_u $16, 8($17) # L : Fetch next 8 + extql $3, $17, $3 # U : masking + extqh $16, $17, $1 # U : masking + bis $3, $1, $1 # E : merged bytes to store + + subq $18, 8, $18 # E : count -= 8 + addq $17, 8, $17 # E : src += 8 + stq $1, 0($4) # L : store 8 (aligned) + mov $16, $3 # E : "rotate" source data + + addq $4, 8, $4 # E : dest += 8 + bge $18, $mis_quad # U : More quads to move + nop + nop + +$misalign_tail: + addq $18, 8, $18 # E : account for tail stuff + ble $18, $nomoredata # U : + nop + nop + +$misalign_byte: + ldbu $1, 0($17) # L : fetch 1 + subq $18, 1, $18 # E : count-- + addq $17, 1, $17 # E : src++ + nop # E : + + stb $1, 0($4) # L : store + addq $4, 1, $4 # E : dest++ + bgt $18, $misalign_byte # U : more to go? + nop + + +$nomoredata: + ret $31, ($26), 1 # L0 : + nop # E : + nop # E : + nop # E : + + .end memcpy + +/* For backwards module compatability. */ +__memcpy = memcpy +.globl __memcpy diff --git a/arch/alpha/lib/ev6-memset.S b/arch/alpha/lib/ev6-memset.S new file mode 100644 index 000000000..626929fc5 --- /dev/null +++ b/arch/alpha/lib/ev6-memset.S @@ -0,0 +1,596 @@ +/* + * arch/alpha/lib/ev6-memset.S + * + * This is an efficient (and relatively small) implementation of the C library + * "memset()" function for the 21264 implementation of Alpha. + * + * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com> + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * The algorithm for the leading and trailing quadwords remains the same, + * however the loop has been unrolled to enable better memory throughput, + * and the code has been replicated for each of the entry points: __memset + * and __memsetw to permit better scheduling to eliminate the stalling + * encountered during the mask replication. + * A future enhancement might be to put in a byte store loop for really + * small (say < 32 bytes) memset()s. Whether or not that change would be + * a win in the kernel would depend upon the contextual usage. + * WARNING: Maintaining this is going to be more work than the above version, + * as fixes will need to be made in multiple places. The performance gain + * is worth it. + */ + + .set noat + .set noreorder +.text + .globl __memset + .globl __memsetw + .globl __constant_c_memset + .globl memset + + .ent __memset +.align 5 +__memset: +memset: + .frame $30,0,$26,0 + .prologue 0 + + /* + * Serious stalling happens. The only way to mitigate this is to + * undertake a major re-write to interleave the constant materialization + * with other parts of the fall-through code. This is important, even + * though it makes maintenance tougher. + * Do this later. + */ + and $17,255,$1 # E : 00000000000000ch + insbl $17,1,$2 # U : 000000000000ch00 + bis $16,$16,$0 # E : return value + ble $18,end_b # U : zero length requested? + + addq $18,$16,$6 # E : max address to write to + bis $1,$2,$17 # E : 000000000000chch + insbl $1,2,$3 # U : 0000000000ch0000 + insbl $1,3,$4 # U : 00000000ch000000 + + or $3,$4,$3 # E : 00000000chch0000 + inswl $17,4,$5 # U : 0000chch00000000 + xor $16,$6,$1 # E : will complete write be within one quadword? + inswl $17,6,$2 # U : chch000000000000 + + or $17,$3,$17 # E : 00000000chchchch + or $2,$5,$2 # E : chchchch00000000 + bic $1,7,$1 # E : fit within a single quadword? + and $16,7,$3 # E : Target addr misalignment + + or $17,$2,$17 # E : chchchchchchchch + beq $1,within_quad_b # U : + nop # E : + beq $3,aligned_b # U : target is 0mod8 + + /* + * Target address is misaligned, and won't fit within a quadword + */ + ldq_u $4,0($16) # L : Fetch first partial + bis $16,$16,$5 # E : Save the address + insql $17,$16,$2 # U : Insert new bytes + subq $3,8,$3 # E : Invert (for addressing uses) + + addq $18,$3,$18 # E : $18 is new count ($3 is negative) + mskql $4,$16,$4 # U : clear relevant parts of the quad + subq $16,$3,$16 # E : $16 is new aligned destination + bis $2,$4,$1 # E : Final bytes + + nop + stq_u $1,0($5) # L : Store result + nop + nop + +.align 4 +aligned_b: + /* + * We are now guaranteed to be quad aligned, with at least + * one partial quad to write. + */ + + sra $18,3,$3 # U : Number of remaining quads to write + and $18,7,$18 # E : Number of trailing bytes to write + bis $16,$16,$5 # E : Save dest address + beq $3,no_quad_b # U : tail stuff only + + /* + * it's worth the effort to unroll this and use wh64 if possible + * Lifted a bunch of code from clear_user.S + * At this point, entry values are: + * $16 Current destination address + * $5 A copy of $16 + * $6 The max quadword address to write to + * $18 Number trailer bytes + * $3 Number quads to write + */ + + and $16, 0x3f, $2 # E : Forward work (only useful for unrolled loop) + subq $3, 16, $4 # E : Only try to unroll if > 128 bytes + subq $2, 0x40, $1 # E : bias counter (aligning stuff 0mod64) + blt $4, loop_b # U : + + /* + * We know we've got at least 16 quads, minimum of one trip + * through unrolled loop. Do a quad at a time to get us 0mod64 + * aligned. + */ + + nop # E : + nop # E : + nop # E : + beq $1, $bigalign_b # U : + +$alignmod64_b: + stq $17, 0($5) # L : + subq $3, 1, $3 # E : For consistency later + addq $1, 8, $1 # E : Increment towards zero for alignment + addq $5, 8, $4 # E : Initial wh64 address (filler instruction) + + nop + nop + addq $5, 8, $5 # E : Inc address + blt $1, $alignmod64_b # U : + +$bigalign_b: + /* + * $3 - number quads left to go + * $5 - target address (aligned 0mod64) + * $17 - mask of stuff to store + * Scratch registers available: $7, $2, $4, $1 + * we know that we'll be taking a minimum of one trip through + * CWG Section 3.7.6: do not expect a sustained store rate of > 1/cycle + * Assumes the wh64 needs to be for 2 trips through the loop in the future + * The wh64 is issued on for the starting destination address for trip +2 + * through the loop, and if there are less than two trips left, the target + * address will be for the current trip. + */ + +$do_wh64_b: + wh64 ($4) # L1 : memory subsystem write hint + subq $3, 24, $2 # E : For determining future wh64 addresses + stq $17, 0($5) # L : + nop # E : + + addq $5, 128, $4 # E : speculative target of next wh64 + stq $17, 8($5) # L : + stq $17, 16($5) # L : + addq $5, 64, $7 # E : Fallback address for wh64 (== next trip addr) + + stq $17, 24($5) # L : + stq $17, 32($5) # L : + cmovlt $2, $7, $4 # E : Latency 2, extra mapping cycle + nop + + stq $17, 40($5) # L : + stq $17, 48($5) # L : + subq $3, 16, $2 # E : Repeat the loop at least once more? + nop + + stq $17, 56($5) # L : + addq $5, 64, $5 # E : + subq $3, 8, $3 # E : + bge $2, $do_wh64_b # U : + + nop + nop + nop + beq $3, no_quad_b # U : Might have finished already + +.align 4 + /* + * Simple loop for trailing quadwords, or for small amounts + * of data (where we can't use an unrolled loop and wh64) + */ +loop_b: + stq $17,0($5) # L : + subq $3,1,$3 # E : Decrement number quads left + addq $5,8,$5 # E : Inc address + bne $3,loop_b # U : more? + +no_quad_b: + /* + * Write 0..7 trailing bytes. + */ + nop # E : + beq $18,end_b # U : All done? + ldq $7,0($5) # L : + mskqh $7,$6,$2 # U : Mask final quad + + insqh $17,$6,$4 # U : New bits + bis $2,$4,$1 # E : Put it all together + stq $1,0($5) # L : And back to memory + ret $31,($26),1 # L0 : + +within_quad_b: + ldq_u $1,0($16) # L : + insql $17,$16,$2 # U : New bits + mskql $1,$16,$4 # U : Clear old + bis $2,$4,$2 # E : New result + + mskql $2,$6,$4 # U : + mskqh $1,$6,$2 # U : + bis $2,$4,$1 # E : + stq_u $1,0($16) # L : + +end_b: + nop + nop + nop + ret $31,($26),1 # L0 : + .end __memset + + /* + * This is the original body of code, prior to replication and + * rescheduling. Leave it here, as there may be calls to this + * entry point. + */ +.align 4 + .ent __memset +__constant_c_memset: + .frame $30,0,$26,0 + .prologue 0 + + addq $18,$16,$6 # E : max address to write to + bis $16,$16,$0 # E : return value + xor $16,$6,$1 # E : will complete write be within one quadword? + ble $18,end # U : zero length requested? + + bic $1,7,$1 # E : fit within a single quadword + beq $1,within_one_quad # U : + and $16,7,$3 # E : Target addr misalignment + beq $3,aligned # U : target is 0mod8 + + /* + * Target address is misaligned, and won't fit within a quadword + */ + ldq_u $4,0($16) # L : Fetch first partial + bis $16,$16,$5 # E : Save the address + insql $17,$16,$2 # U : Insert new bytes + subq $3,8,$3 # E : Invert (for addressing uses) + + addq $18,$3,$18 # E : $18 is new count ($3 is negative) + mskql $4,$16,$4 # U : clear relevant parts of the quad + subq $16,$3,$16 # E : $16 is new aligned destination + bis $2,$4,$1 # E : Final bytes + + nop + stq_u $1,0($5) # L : Store result + nop + nop + +.align 4 +aligned: + /* + * We are now guaranteed to be quad aligned, with at least + * one partial quad to write. + */ + + sra $18,3,$3 # U : Number of remaining quads to write + and $18,7,$18 # E : Number of trailing bytes to write + bis $16,$16,$5 # E : Save dest address + beq $3,no_quad # U : tail stuff only + + /* + * it's worth the effort to unroll this and use wh64 if possible + * Lifted a bunch of code from clear_user.S + * At this point, entry values are: + * $16 Current destination address + * $5 A copy of $16 + * $6 The max quadword address to write to + * $18 Number trailer bytes + * $3 Number quads to write + */ + + and $16, 0x3f, $2 # E : Forward work (only useful for unrolled loop) + subq $3, 16, $4 # E : Only try to unroll if > 128 bytes + subq $2, 0x40, $1 # E : bias counter (aligning stuff 0mod64) + blt $4, loop # U : + + /* + * We know we've got at least 16 quads, minimum of one trip + * through unrolled loop. Do a quad at a time to get us 0mod64 + * aligned. + */ + + nop # E : + nop # E : + nop # E : + beq $1, $bigalign # U : + +$alignmod64: + stq $17, 0($5) # L : + subq $3, 1, $3 # E : For consistency later + addq $1, 8, $1 # E : Increment towards zero for alignment + addq $5, 8, $4 # E : Initial wh64 address (filler instruction) + + nop + nop + addq $5, 8, $5 # E : Inc address + blt $1, $alignmod64 # U : + +$bigalign: + /* + * $3 - number quads left to go + * $5 - target address (aligned 0mod64) + * $17 - mask of stuff to store + * Scratch registers available: $7, $2, $4, $1 + * we know that we'll be taking a minimum of one trip through + * CWG Section 3.7.6: do not expect a sustained store rate of > 1/cycle + * Assumes the wh64 needs to be for 2 trips through the loop in the future + * The wh64 is issued on for the starting destination address for trip +2 + * through the loop, and if there are less than two trips left, the target + * address will be for the current trip. + */ + +$do_wh64: + wh64 ($4) # L1 : memory subsystem write hint + subq $3, 24, $2 # E : For determining future wh64 addresses + stq $17, 0($5) # L : + nop # E : + + addq $5, 128, $4 # E : speculative target of next wh64 + stq $17, 8($5) # L : + stq $17, 16($5) # L : + addq $5, 64, $7 # E : Fallback address for wh64 (== next trip addr) + + stq $17, 24($5) # L : + stq $17, 32($5) # L : + cmovlt $2, $7, $4 # E : Latency 2, extra mapping cycle + nop + + stq $17, 40($5) # L : + stq $17, 48($5) # L : + subq $3, 16, $2 # E : Repeat the loop at least once more? + nop + + stq $17, 56($5) # L : + addq $5, 64, $5 # E : + subq $3, 8, $3 # E : + bge $2, $do_wh64 # U : + + nop + nop + nop + beq $3, no_quad # U : Might have finished already + +.align 4 + /* + * Simple loop for trailing quadwords, or for small amounts + * of data (where we can't use an unrolled loop and wh64) + */ +loop: + stq $17,0($5) # L : + subq $3,1,$3 # E : Decrement number quads left + addq $5,8,$5 # E : Inc address + bne $3,loop # U : more? + +no_quad: + /* + * Write 0..7 trailing bytes. + */ + nop # E : + beq $18,end # U : All done? + ldq $7,0($5) # L : + mskqh $7,$6,$2 # U : Mask final quad + + insqh $17,$6,$4 # U : New bits + bis $2,$4,$1 # E : Put it all together + stq $1,0($5) # L : And back to memory + ret $31,($26),1 # L0 : + +within_one_quad: + ldq_u $1,0($16) # L : + insql $17,$16,$2 # U : New bits + mskql $1,$16,$4 # U : Clear old + bis $2,$4,$2 # E : New result + + mskql $2,$6,$4 # U : + mskqh $1,$6,$2 # U : + bis $2,$4,$1 # E : + stq_u $1,0($16) # L : + +end: + nop + nop + nop + ret $31,($26),1 # L0 : + .end __constant_c_memset + + /* + * This is a replicant of the __constant_c_memset code, rescheduled + * to mask stalls. Note that entry point names also had to change + */ + .align 5 + .ent __memsetw + +__memsetw: + .frame $30,0,$26,0 + .prologue 0 + + inswl $17,0,$5 # U : 000000000000c1c2 + inswl $17,2,$2 # U : 00000000c1c20000 + bis $16,$16,$0 # E : return value + addq $18,$16,$6 # E : max address to write to + + ble $18, end_w # U : zero length requested? + inswl $17,4,$3 # U : 0000c1c200000000 + inswl $17,6,$4 # U : c1c2000000000000 + xor $16,$6,$1 # E : will complete write be within one quadword? + + or $2,$5,$2 # E : 00000000c1c2c1c2 + or $3,$4,$17 # E : c1c2c1c200000000 + bic $1,7,$1 # E : fit within a single quadword + and $16,7,$3 # E : Target addr misalignment + + or $17,$2,$17 # E : c1c2c1c2c1c2c1c2 + beq $1,within_quad_w # U : + nop + beq $3,aligned_w # U : target is 0mod8 + + /* + * Target address is misaligned, and won't fit within a quadword + */ + ldq_u $4,0($16) # L : Fetch first partial + bis $16,$16,$5 # E : Save the address + insql $17,$16,$2 # U : Insert new bytes + subq $3,8,$3 # E : Invert (for addressing uses) + + addq $18,$3,$18 # E : $18 is new count ($3 is negative) + mskql $4,$16,$4 # U : clear relevant parts of the quad + subq $16,$3,$16 # E : $16 is new aligned destination + bis $2,$4,$1 # E : Final bytes + + nop + stq_u $1,0($5) # L : Store result + nop + nop + +.align 4 +aligned_w: + /* + * We are now guaranteed to be quad aligned, with at least + * one partial quad to write. + */ + + sra $18,3,$3 # U : Number of remaining quads to write + and $18,7,$18 # E : Number of trailing bytes to write + bis $16,$16,$5 # E : Save dest address + beq $3,no_quad_w # U : tail stuff only + + /* + * it's worth the effort to unroll this and use wh64 if possible + * Lifted a bunch of code from clear_user.S + * At this point, entry values are: + * $16 Current destination address + * $5 A copy of $16 + * $6 The max quadword address to write to + * $18 Number trailer bytes + * $3 Number quads to write + */ + + and $16, 0x3f, $2 # E : Forward work (only useful for unrolled loop) + subq $3, 16, $4 # E : Only try to unroll if > 128 bytes + subq $2, 0x40, $1 # E : bias counter (aligning stuff 0mod64) + blt $4, loop_w # U : + + /* + * We know we've got at least 16 quads, minimum of one trip + * through unrolled loop. Do a quad at a time to get us 0mod64 + * aligned. + */ + + nop # E : + nop # E : + nop # E : + beq $1, $bigalign_w # U : + +$alignmod64_w: + stq $17, 0($5) # L : + subq $3, 1, $3 # E : For consistency later + addq $1, 8, $1 # E : Increment towards zero for alignment + addq $5, 8, $4 # E : Initial wh64 address (filler instruction) + + nop + nop + addq $5, 8, $5 # E : Inc address + blt $1, $alignmod64_w # U : + +$bigalign_w: + /* + * $3 - number quads left to go + * $5 - target address (aligned 0mod64) + * $17 - mask of stuff to store + * Scratch registers available: $7, $2, $4, $1 + * we know that we'll be taking a minimum of one trip through + * CWG Section 3.7.6: do not expect a sustained store rate of > 1/cycle + * Assumes the wh64 needs to be for 2 trips through the loop in the future + * The wh64 is issued on for the starting destination address for trip +2 + * through the loop, and if there are less than two trips left, the target + * address will be for the current trip. + */ + +$do_wh64_w: + wh64 ($4) # L1 : memory subsystem write hint + subq $3, 24, $2 # E : For determining future wh64 addresses + stq $17, 0($5) # L : + nop # E : + + addq $5, 128, $4 # E : speculative target of next wh64 + stq $17, 8($5) # L : + stq $17, 16($5) # L : + addq $5, 64, $7 # E : Fallback address for wh64 (== next trip addr) + + stq $17, 24($5) # L : + stq $17, 32($5) # L : + cmovlt $2, $7, $4 # E : Latency 2, extra mapping cycle + nop + + stq $17, 40($5) # L : + stq $17, 48($5) # L : + subq $3, 16, $2 # E : Repeat the loop at least once more? + nop + + stq $17, 56($5) # L : + addq $5, 64, $5 # E : + subq $3, 8, $3 # E : + bge $2, $do_wh64_w # U : + + nop + nop + nop + beq $3, no_quad_w # U : Might have finished already + +.align 4 + /* + * Simple loop for trailing quadwords, or for small amounts + * of data (where we can't use an unrolled loop and wh64) + */ +loop_w: + stq $17,0($5) # L : + subq $3,1,$3 # E : Decrement number quads left + addq $5,8,$5 # E : Inc address + bne $3,loop_w # U : more? + +no_quad_w: + /* + * Write 0..7 trailing bytes. + */ + nop # E : + beq $18,end_w # U : All done? + ldq $7,0($5) # L : + mskqh $7,$6,$2 # U : Mask final quad + + insqh $17,$6,$4 # U : New bits + bis $2,$4,$1 # E : Put it all together + stq $1,0($5) # L : And back to memory + ret $31,($26),1 # L0 : + +within_quad_w: + ldq_u $1,0($16) # L : + insql $17,$16,$2 # U : New bits + mskql $1,$16,$4 # U : Clear old + bis $2,$4,$2 # E : New result + + mskql $2,$6,$4 # U : + mskqh $1,$6,$2 # U : + bis $2,$4,$1 # E : + stq_u $1,0($16) # L : + +end_w: + nop + nop + nop + ret $31,($26),1 # L0 : + + .end __memsetw diff --git a/arch/alpha/lib/ev6-strncpy_from_user.S b/arch/alpha/lib/ev6-strncpy_from_user.S new file mode 100644 index 000000000..8d446778b --- /dev/null +++ b/arch/alpha/lib/ev6-strncpy_from_user.S @@ -0,0 +1,425 @@ +/* + * arch/alpha/lib/ev6-strncpy_from_user.S + * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com> + * + * Just like strncpy except in the return value: + * + * -EFAULT if an exception occurs before the terminator is copied. + * N if the buffer filled. + * + * Otherwise the length of the string is returned. + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * A bunch of instructions got moved and temp registers were changed + * to aid in scheduling. Control flow was also re-arranged to eliminate + * branches, and to provide longer code sequences to enable better scheduling. + * A total rewrite (using byte load/stores for start & tail sequences) + * is desirable, but very difficult to do without a from-scratch rewrite. + * Save that for the future. + */ + + +#include <asm/errno.h> +#include <alpha/regdef.h> + + +/* Allow an exception for an insn; exit if we get one. */ +#define EX(x,y...) \ + 99: x,##y; \ + .section __ex_table,"a"; \ + .gprel32 99b; \ + lda $31, $exception-99b($0); \ + .previous + + + .set noat + .set noreorder + .text + + .globl __strncpy_from_user + .ent __strncpy_from_user + .frame $30, 0, $26 + .prologue 1 + + .align 4 +__strncpy_from_user: + ldgp $29, 0($27) # E E : becomes 2 instructions (for exceptions) + and a0, 7, t3 # E : find dest misalignment + beq a2, $zerolength # U : + + /* Are source and destination co-aligned? */ + mov a0, v0 # E : save the string start + xor a0, a1, t4 # E : + EX( ldq_u t1, 0(a1) ) # L : Latency=3 load first quadword + ldq_u t0, 0(a0) # L : load first (partial) aligned dest quadword + + addq a2, t3, a2 # E : bias count by dest misalignment + subq a2, 1, a3 # E : + addq zero, 1, t10 # E : + and t4, 7, t4 # E : misalignment between the two + + and a3, 7, t6 # E : number of tail bytes + sll t10, t6, t10 # E : t10 = bitmask of last count byte + bne t4, $unaligned # U : + lda t2, -1 # E : build a mask against false zero + + /* + * We are co-aligned; take care of a partial first word. + * On entry to this basic block: + * t0 == the first destination word for masking back in + * t1 == the first source word. + */ + + srl a3, 3, a2 # E : a2 = loop counter = (count - 1)/8 + addq a1, 8, a1 # E : + mskqh t2, a1, t2 # U : detection in the src word + nop + + /* Create the 1st output word and detect 0's in the 1st input word. */ + mskqh t1, a1, t3 # U : + mskql t0, a1, t0 # U : assemble the first output word + ornot t1, t2, t2 # E : + nop + + cmpbge zero, t2, t8 # E : bits set iff null found + or t0, t3, t0 # E : + beq a2, $a_eoc # U : + bne t8, $a_eos # U : 2nd branch in a quad. Bad. + + /* On entry to this basic block: + * t0 == a source quad not containing a null. + * a0 - current aligned destination address + * a1 - current aligned source address + * a2 - count of quadwords to move. + * NOTE: Loop improvement - unrolling this is going to be + * a huge win, since we're going to stall otherwise. + * Fix this later. For _really_ large copies, look + * at using wh64 on a look-ahead basis. See the code + * in clear_user.S and copy_user.S. + * Presumably, since (a0) and (a1) do not overlap (by C definition) + * Lots of nops here: + * - Separate loads from stores + * - Keep it to 1 branch/quadpack so the branch predictor + * can train. + */ +$a_loop: + stq_u t0, 0(a0) # L : + addq a0, 8, a0 # E : + nop + subq a2, 1, a2 # E : + + EX( ldq_u t0, 0(a1) ) # L : + addq a1, 8, a1 # E : + cmpbge zero, t0, t8 # E : Stall 2 cycles on t0 + beq a2, $a_eoc # U : + + beq t8, $a_loop # U : + nop + nop + nop + + /* Take care of the final (partial) word store. At this point + * the end-of-count bit is set in t8 iff it applies. + * + * On entry to this basic block we have: + * t0 == the source word containing the null + * t8 == the cmpbge mask that found it. + */ +$a_eos: + negq t8, t12 # E : find low bit set + and t8, t12, t12 # E : + + /* We're doing a partial word store and so need to combine + our source and original destination words. */ + ldq_u t1, 0(a0) # L : + subq t12, 1, t6 # E : + + or t12, t6, t8 # E : + zapnot t0, t8, t0 # U : clear src bytes > null + zap t1, t8, t1 # U : clear dst bytes <= null + or t0, t1, t0 # E : + + stq_u t0, 0(a0) # L : + br $finish_up # L0 : + nop + nop + + /* Add the end-of-count bit to the eos detection bitmask. */ + .align 4 +$a_eoc: + or t10, t8, t8 + br $a_eos + nop + nop + + +/* The source and destination are not co-aligned. Align the destination + and cope. We have to be very careful about not reading too much and + causing a SEGV. */ + + .align 4 +$u_head: + /* We know just enough now to be able to assemble the first + full source word. We can still find a zero at the end of it + that prevents us from outputting the whole thing. + + On entry to this basic block: + t0 == the first dest word, unmasked + t1 == the shifted low bits of the first source word + t6 == bytemask that is -1 in dest word bytes */ + + EX( ldq_u t2, 8(a1) ) # L : load second src word + addq a1, 8, a1 # E : + mskql t0, a0, t0 # U : mask trailing garbage in dst + extqh t2, a1, t4 # U : + + or t1, t4, t1 # E : first aligned src word complete + mskqh t1, a0, t1 # U : mask leading garbage in src + or t0, t1, t0 # E : first output word complete + or t0, t6, t6 # E : mask original data for zero test + + cmpbge zero, t6, t8 # E : + beq a2, $u_eocfin # U : + bne t8, $u_final # U : bad news - 2nd branch in a quad + lda t6, -1 # E : mask out the bits we have + + mskql t6, a1, t6 # U : already seen + stq_u t0, 0(a0) # L : store first output word + or t6, t2, t2 # E : + cmpbge zero, t2, t8 # E : find nulls in second partial + + addq a0, 8, a0 # E : + subq a2, 1, a2 # E : + bne t8, $u_late_head_exit # U : + nop + + /* Finally, we've got all the stupid leading edge cases taken care + of and we can set up to enter the main loop. */ + + extql t2, a1, t1 # U : position hi-bits of lo word + EX( ldq_u t2, 8(a1) ) # L : read next high-order source word + addq a1, 8, a1 # E : + cmpbge zero, t2, t8 # E : + + beq a2, $u_eoc # U : + bne t8, $u_eos # U : + nop + nop + + /* Unaligned copy main loop. In order to avoid reading too much, + the loop is structured to detect zeros in aligned source words. + This has, unfortunately, effectively pulled half of a loop + iteration out into the head and half into the tail, but it does + prevent nastiness from accumulating in the very thing we want + to run as fast as possible. + + On entry to this basic block: + t1 == the shifted high-order bits from the previous source word + t2 == the unshifted current source word + + We further know that t2 does not contain a null terminator. */ + + /* + * Extra nops here: + * separate load quads from store quads + * only one branch/quad to permit predictor training + */ + + .align 4 +$u_loop: + extqh t2, a1, t0 # U : extract high bits for current word + addq a1, 8, a1 # E : + extql t2, a1, t3 # U : extract low bits for next time + addq a0, 8, a0 # E : + + or t0, t1, t0 # E : current dst word now complete + EX( ldq_u t2, 0(a1) ) # L : load high word for next time + subq a2, 1, a2 # E : + nop + + stq_u t0, -8(a0) # L : save the current word + mov t3, t1 # E : + cmpbge zero, t2, t8 # E : test new word for eos + beq a2, $u_eoc # U : + + beq t8, $u_loop # U : + nop + nop + nop + + /* We've found a zero somewhere in the source word we just read. + If it resides in the lower half, we have one (probably partial) + word to write out, and if it resides in the upper half, we + have one full and one partial word left to write out. + + On entry to this basic block: + t1 == the shifted high-order bits from the previous source word + t2 == the unshifted current source word. */ + .align 4 +$u_eos: + extqh t2, a1, t0 # U : + or t0, t1, t0 # E : first (partial) source word complete + cmpbge zero, t0, t8 # E : is the null in this first bit? + nop + + bne t8, $u_final # U : + stq_u t0, 0(a0) # L : the null was in the high-order bits + addq a0, 8, a0 # E : + subq a2, 1, a2 # E : + + .align 4 +$u_late_head_exit: + extql t2, a1, t0 # U : + cmpbge zero, t0, t8 # E : + or t8, t10, t6 # E : + cmoveq a2, t6, t8 # E : + + /* Take care of a final (probably partial) result word. + On entry to this basic block: + t0 == assembled source word + t8 == cmpbge mask that found the null. */ + .align 4 +$u_final: + negq t8, t6 # E : isolate low bit set + and t6, t8, t12 # E : + ldq_u t1, 0(a0) # L : + subq t12, 1, t6 # E : + + or t6, t12, t8 # E : + zapnot t0, t8, t0 # U : kill source bytes > null + zap t1, t8, t1 # U : kill dest bytes <= null + or t0, t1, t0 # E : + + stq_u t0, 0(a0) # E : + br $finish_up # U : + nop + nop + + .align 4 +$u_eoc: # end-of-count + extqh t2, a1, t0 # U : + or t0, t1, t0 # E : + cmpbge zero, t0, t8 # E : + nop + + .align 4 +$u_eocfin: # end-of-count, final word + or t10, t8, t8 # E : + br $u_final # U : + nop + nop + + /* Unaligned copy entry point. */ + .align 4 +$unaligned: + + srl a3, 3, a2 # U : a2 = loop counter = (count - 1)/8 + and a0, 7, t4 # E : find dest misalignment + and a1, 7, t5 # E : find src misalignment + mov zero, t0 # E : + + /* Conditionally load the first destination word and a bytemask + with 0xff indicating that the destination byte is sacrosanct. */ + + mov zero, t6 # E : + beq t4, 1f # U : + ldq_u t0, 0(a0) # L : + lda t6, -1 # E : + + mskql t6, a0, t6 # E : + nop + nop + nop + + .align 4 +1: + subq a1, t4, a1 # E : sub dest misalignment from src addr + /* If source misalignment is larger than dest misalignment, we need + extra startup checks to avoid SEGV. */ + cmplt t4, t5, t12 # E : + extql t1, a1, t1 # U : shift src into place + lda t2, -1 # E : for creating masks later + + beq t12, $u_head # U : + mskqh t2, t5, t2 # U : begin src byte validity mask + cmpbge zero, t1, t8 # E : is there a zero? + nop + + extql t2, a1, t2 # U : + or t8, t10, t5 # E : test for end-of-count too + cmpbge zero, t2, t3 # E : + cmoveq a2, t5, t8 # E : Latency=2, extra map slot + + nop # E : goes with cmov + andnot t8, t3, t8 # E : + beq t8, $u_head # U : + nop + + /* At this point we've found a zero in the first partial word of + the source. We need to isolate the valid source data and mask + it into the original destination data. (Incidentally, we know + that we'll need at least one byte of that original dest word.) */ + + ldq_u t0, 0(a0) # L : + negq t8, t6 # E : build bitmask of bytes <= zero + mskqh t1, t4, t1 # U : + and t6, t8, t12 # E : + + subq t12, 1, t6 # E : + or t6, t12, t8 # E : + zapnot t2, t8, t2 # U : prepare source word; mirror changes + zapnot t1, t8, t1 # U : to source validity mask + + andnot t0, t2, t0 # E : zero place for source to reside + or t0, t1, t0 # E : and put it there + stq_u t0, 0(a0) # L : + nop + + .align 4 +$finish_up: + zapnot t0, t12, t4 # U : was last byte written null? + and t12, 0xf0, t3 # E : binary search for the address of the + cmovne t4, 1, t4 # E : Latency=2, extra map slot + nop # E : with cmovne + + and t12, 0xcc, t2 # E : last byte written + and t12, 0xaa, t1 # E : + cmovne t3, 4, t3 # E : Latency=2, extra map slot + nop # E : with cmovne + + bic a0, 7, t0 + cmovne t2, 2, t2 # E : Latency=2, extra map slot + nop # E : with cmovne + nop + + cmovne t1, 1, t1 # E : Latency=2, extra map slot + nop # E : with cmovne + addq t0, t3, t0 # E : + addq t1, t2, t1 # E : + + addq t0, t1, t0 # E : + addq t0, t4, t0 # add one if we filled the buffer + subq t0, v0, v0 # find string length + ret # L0 : + + .align 4 +$zerolength: + nop + nop + nop + clr v0 + +$exception: + nop + nop + nop + ret + + .end __strncpy_from_user diff --git a/arch/alpha/lib/ev6-stxcpy.S b/arch/alpha/lib/ev6-stxcpy.S new file mode 100644 index 000000000..f5b409e9a --- /dev/null +++ b/arch/alpha/lib/ev6-stxcpy.S @@ -0,0 +1,321 @@ +/* + * arch/alpha/lib/ev6-stxcpy.S + * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com> + * + * Copy a null-terminated string from SRC to DST. + * + * This is an internal routine used by strcpy, stpcpy, and strcat. + * As such, it uses special linkage conventions to make implementation + * of these public functions more efficient. + * + * On input: + * t9 = return address + * a0 = DST + * a1 = SRC + * + * On output: + * t12 = bitmask (with one bit set) indicating the last byte written + * a0 = unaligned address of the last *word* written + * + * Furthermore, v0, a3-a5, t11, and t12 are untouched. + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * Try not to change the actual algorithm if possible for consistency. + */ + +#include <alpha/regdef.h> + + .set noat + .set noreorder + + .text + +/* There is a problem with either gdb (as of 4.16) or gas (as of 2.7) that + doesn't like putting the entry point for a procedure somewhere in the + middle of the procedure descriptor. Work around this by putting the + aligned copy in its own procedure descriptor */ + + + .ent stxcpy_aligned + .align 4 +stxcpy_aligned: + .frame sp, 0, t9 + .prologue 0 + + /* On entry to this basic block: + t0 == the first destination word for masking back in + t1 == the first source word. */ + + /* Create the 1st output word and detect 0's in the 1st input word. */ + lda t2, -1 # E : build a mask against false zero + mskqh t2, a1, t2 # U : detection in the src word (stall) + mskqh t1, a1, t3 # U : + ornot t1, t2, t2 # E : (stall) + + mskql t0, a1, t0 # U : assemble the first output word + cmpbge zero, t2, t8 # E : bits set iff null found + or t0, t3, t1 # E : (stall) + bne t8, $a_eos # U : (stall) + + /* On entry to this basic block: + t0 == the first destination word for masking back in + t1 == a source word not containing a null. */ + /* Nops here to separate store quads from load quads */ + +$a_loop: + stq_u t1, 0(a0) # L : + addq a0, 8, a0 # E : + nop + nop + + ldq_u t1, 0(a1) # L : Latency=3 + addq a1, 8, a1 # E : + cmpbge zero, t1, t8 # E : (3 cycle stall) + beq t8, $a_loop # U : (stall for t8) + + /* Take care of the final (partial) word store. + On entry to this basic block we have: + t1 == the source word containing the null + t8 == the cmpbge mask that found it. */ +$a_eos: + negq t8, t6 # E : find low bit set + and t8, t6, t12 # E : (stall) + /* For the sake of the cache, don't read a destination word + if we're not going to need it. */ + and t12, 0x80, t6 # E : (stall) + bne t6, 1f # U : (stall) + + /* We're doing a partial word store and so need to combine + our source and original destination words. */ + ldq_u t0, 0(a0) # L : Latency=3 + subq t12, 1, t6 # E : + zapnot t1, t6, t1 # U : clear src bytes >= null (stall) + or t12, t6, t8 # E : (stall) + + zap t0, t8, t0 # E : clear dst bytes <= null + or t0, t1, t1 # E : (stall) + nop + nop + +1: stq_u t1, 0(a0) # L : + ret (t9) # L0 : Latency=3 + nop + nop + + .end stxcpy_aligned + + .align 4 + .ent __stxcpy + .globl __stxcpy +__stxcpy: + .frame sp, 0, t9 + .prologue 0 + + /* Are source and destination co-aligned? */ + xor a0, a1, t0 # E : + unop # E : + and t0, 7, t0 # E : (stall) + bne t0, $unaligned # U : (stall) + + /* We are co-aligned; take care of a partial first word. */ + ldq_u t1, 0(a1) # L : load first src word + and a0, 7, t0 # E : take care not to load a word ... + addq a1, 8, a1 # E : + beq t0, stxcpy_aligned # U : ... if we wont need it (stall) + + ldq_u t0, 0(a0) # L : + br stxcpy_aligned # L0 : Latency=3 + nop + nop + + +/* The source and destination are not co-aligned. Align the destination + and cope. We have to be very careful about not reading too much and + causing a SEGV. */ + + .align 4 +$u_head: + /* We know just enough now to be able to assemble the first + full source word. We can still find a zero at the end of it + that prevents us from outputting the whole thing. + + On entry to this basic block: + t0 == the first dest word, for masking back in, if needed else 0 + t1 == the low bits of the first source word + t6 == bytemask that is -1 in dest word bytes */ + + ldq_u t2, 8(a1) # L : + addq a1, 8, a1 # E : + extql t1, a1, t1 # U : (stall on a1) + extqh t2, a1, t4 # U : (stall on a1) + + mskql t0, a0, t0 # U : + or t1, t4, t1 # E : + mskqh t1, a0, t1 # U : (stall on t1) + or t0, t1, t1 # E : (stall on t1) + + or t1, t6, t6 # E : + cmpbge zero, t6, t8 # E : (stall) + lda t6, -1 # E : for masking just below + bne t8, $u_final # U : (stall) + + mskql t6, a1, t6 # U : mask out the bits we have + or t6, t2, t2 # E : already extracted before (stall) + cmpbge zero, t2, t8 # E : testing eos (stall) + bne t8, $u_late_head_exit # U : (stall) + + /* Finally, we've got all the stupid leading edge cases taken care + of and we can set up to enter the main loop. */ + + stq_u t1, 0(a0) # L : store first output word + addq a0, 8, a0 # E : + extql t2, a1, t0 # U : position ho-bits of lo word + ldq_u t2, 8(a1) # U : read next high-order source word + + addq a1, 8, a1 # E : + cmpbge zero, t2, t8 # E : (stall for t2) + nop # E : + bne t8, $u_eos # U : (stall) + + /* Unaligned copy main loop. In order to avoid reading too much, + the loop is structured to detect zeros in aligned source words. + This has, unfortunately, effectively pulled half of a loop + iteration out into the head and half into the tail, but it does + prevent nastiness from accumulating in the very thing we want + to run as fast as possible. + + On entry to this basic block: + t0 == the shifted high-order bits from the previous source word + t2 == the unshifted current source word + + We further know that t2 does not contain a null terminator. */ + + .align 3 +$u_loop: + extqh t2, a1, t1 # U : extract high bits for current word + addq a1, 8, a1 # E : (stall) + extql t2, a1, t3 # U : extract low bits for next time (stall) + addq a0, 8, a0 # E : + + or t0, t1, t1 # E : current dst word now complete + ldq_u t2, 0(a1) # L : Latency=3 load high word for next time + stq_u t1, -8(a0) # L : save the current word (stall) + mov t3, t0 # E : + + cmpbge zero, t2, t8 # E : test new word for eos + beq t8, $u_loop # U : (stall) + nop + nop + + /* We've found a zero somewhere in the source word we just read. + If it resides in the lower half, we have one (probably partial) + word to write out, and if it resides in the upper half, we + have one full and one partial word left to write out. + + On entry to this basic block: + t0 == the shifted high-order bits from the previous source word + t2 == the unshifted current source word. */ +$u_eos: + extqh t2, a1, t1 # U : + or t0, t1, t1 # E : first (partial) source word complete (stall) + cmpbge zero, t1, t8 # E : is the null in this first bit? (stall) + bne t8, $u_final # U : (stall) + +$u_late_head_exit: + stq_u t1, 0(a0) # L : the null was in the high-order bits + addq a0, 8, a0 # E : + extql t2, a1, t1 # U : + cmpbge zero, t1, t8 # E : (stall) + + /* Take care of a final (probably partial) result word. + On entry to this basic block: + t1 == assembled source word + t8 == cmpbge mask that found the null. */ +$u_final: + negq t8, t6 # E : isolate low bit set + and t6, t8, t12 # E : (stall) + and t12, 0x80, t6 # E : avoid dest word load if we can (stall) + bne t6, 1f # U : (stall) + + ldq_u t0, 0(a0) # E : + subq t12, 1, t6 # E : + or t6, t12, t8 # E : (stall) + zapnot t1, t6, t1 # U : kill source bytes >= null (stall) + + zap t0, t8, t0 # U : kill dest bytes <= null (2 cycle data stall) + or t0, t1, t1 # E : (stall) + nop + nop + +1: stq_u t1, 0(a0) # L : + ret (t9) # L0 : Latency=3 + nop + nop + + /* Unaligned copy entry point. */ + .align 4 +$unaligned: + + ldq_u t1, 0(a1) # L : load first source word + and a0, 7, t4 # E : find dest misalignment + and a1, 7, t5 # E : find src misalignment + /* Conditionally load the first destination word and a bytemask + with 0xff indicating that the destination byte is sacrosanct. */ + mov zero, t0 # E : + + mov zero, t6 # E : + beq t4, 1f # U : + ldq_u t0, 0(a0) # L : + lda t6, -1 # E : + + mskql t6, a0, t6 # U : + nop + nop + nop +1: + subq a1, t4, a1 # E : sub dest misalignment from src addr + /* If source misalignment is larger than dest misalignment, we need + extra startup checks to avoid SEGV. */ + cmplt t4, t5, t12 # E : + beq t12, $u_head # U : + lda t2, -1 # E : mask out leading garbage in source + + mskqh t2, t5, t2 # U : + ornot t1, t2, t3 # E : (stall) + cmpbge zero, t3, t8 # E : is there a zero? (stall) + beq t8, $u_head # U : (stall) + + /* At this point we've found a zero in the first partial word of + the source. We need to isolate the valid source data and mask + it into the original destination data. (Incidentally, we know + that we'll need at least one byte of that original dest word.) */ + + ldq_u t0, 0(a0) # L : + negq t8, t6 # E : build bitmask of bytes <= zero + and t6, t8, t12 # E : (stall) + and a1, 7, t5 # E : + + subq t12, 1, t6 # E : + or t6, t12, t8 # E : (stall) + srl t12, t5, t12 # U : adjust final null return value + zapnot t2, t8, t2 # U : prepare source word; mirror changes (stall) + + and t1, t2, t1 # E : to source validity mask + extql t2, a1, t2 # U : + extql t1, a1, t1 # U : (stall) + andnot t0, t2, t0 # .. e1 : zero place for source to reside (stall) + + or t0, t1, t1 # e1 : and put it there + stq_u t1, 0(a0) # .. e0 : (stall) + ret (t9) # e1 : + nop + + .end __stxcpy + diff --git a/arch/alpha/lib/ev6-stxncpy.S b/arch/alpha/lib/ev6-stxncpy.S new file mode 100644 index 000000000..7848b4c80 --- /dev/null +++ b/arch/alpha/lib/ev6-stxncpy.S @@ -0,0 +1,399 @@ +/* + * arch/alpha/lib/ev6-stxncpy.S + * 21264 version contributed by Rick Gorton <rick.gorton@api-networks.com> + * + * Copy no more than COUNT bytes of the null-terminated string from + * SRC to DST. + * + * This is an internal routine used by strncpy, stpncpy, and strncat. + * As such, it uses special linkage conventions to make implementation + * of these public functions more efficient. + * + * On input: + * t9 = return address + * a0 = DST + * a1 = SRC + * a2 = COUNT + * + * Furthermore, COUNT may not be zero. + * + * On output: + * t0 = last word written + * t10 = bitmask (with one bit set) indicating the byte position of + * the end of the range specified by COUNT + * t12 = bitmask (with one bit set) indicating the last byte written + * a0 = unaligned address of the last *word* written + * a2 = the number of full words left in COUNT + * + * Furthermore, v0, a3-a5, t11, t12, and $at are untouched. + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * Try not to change the actual algorithm if possible for consistency. + */ + +#include <alpha/regdef.h> + + .set noat + .set noreorder + + .text + +/* There is a problem with either gdb (as of 4.16) or gas (as of 2.7) that + doesn't like putting the entry point for a procedure somewhere in the + middle of the procedure descriptor. Work around this by putting the + aligned copy in its own procedure descriptor */ + + + .ent stxncpy_aligned + .align 4 +stxncpy_aligned: + .frame sp, 0, t9, 0 + .prologue 0 + + /* On entry to this basic block: + t0 == the first destination word for masking back in + t1 == the first source word. */ + + /* Create the 1st output word and detect 0's in the 1st input word. */ + lda t2, -1 # E : build a mask against false zero + mskqh t2, a1, t2 # U : detection in the src word (stall) + mskqh t1, a1, t3 # U : + ornot t1, t2, t2 # E : (stall) + + mskql t0, a1, t0 # U : assemble the first output word + cmpbge zero, t2, t8 # E : bits set iff null found + or t0, t3, t0 # E : (stall) + beq a2, $a_eoc # U : + + bne t8, $a_eos # U : + nop + nop + nop + + /* On entry to this basic block: + t0 == a source word not containing a null. */ + + /* + * nops here to: + * separate store quads from load quads + * limit of 1 bcond/quad to permit training + */ +$a_loop: + stq_u t0, 0(a0) # L : + addq a0, 8, a0 # E : + subq a2, 1, a2 # E : + nop + + ldq_u t0, 0(a1) # L : + addq a1, 8, a1 # E : + cmpbge zero, t0, t8 # E : + beq a2, $a_eoc # U : + + beq t8, $a_loop # U : + nop + nop + nop + + /* Take care of the final (partial) word store. At this point + the end-of-count bit is set in t8 iff it applies. + + On entry to this basic block we have: + t0 == the source word containing the null + t8 == the cmpbge mask that found it. */ + +$a_eos: + negq t8, t12 # E : find low bit set + and t8, t12, t12 # E : (stall) + /* For the sake of the cache, don't read a destination word + if we're not going to need it. */ + and t12, 0x80, t6 # E : (stall) + bne t6, 1f # U : (stall) + + /* We're doing a partial word store and so need to combine + our source and original destination words. */ + ldq_u t1, 0(a0) # L : + subq t12, 1, t6 # E : + or t12, t6, t8 # E : (stall) + zapnot t0, t8, t0 # U : clear src bytes > null (stall) + + zap t1, t8, t1 # .. e1 : clear dst bytes <= null + or t0, t1, t0 # e1 : (stall) + nop + nop + +1: stq_u t0, 0(a0) # L : + ret (t9) # L0 : Latency=3 + nop + nop + + /* Add the end-of-count bit to the eos detection bitmask. */ +$a_eoc: + or t10, t8, t8 # E : + br $a_eos # L0 : Latency=3 + nop + nop + + .end stxncpy_aligned + + .align 4 + .ent __stxncpy + .globl __stxncpy +__stxncpy: + .frame sp, 0, t9, 0 + .prologue 0 + + /* Are source and destination co-aligned? */ + xor a0, a1, t1 # E : + and a0, 7, t0 # E : find dest misalignment + and t1, 7, t1 # E : (stall) + addq a2, t0, a2 # E : bias count by dest misalignment (stall) + + subq a2, 1, a2 # E : + and a2, 7, t2 # E : (stall) + srl a2, 3, a2 # U : a2 = loop counter = (count - 1)/8 (stall) + addq zero, 1, t10 # E : + + sll t10, t2, t10 # U : t10 = bitmask of last count byte + bne t1, $unaligned # U : + /* We are co-aligned; take care of a partial first word. */ + ldq_u t1, 0(a1) # L : load first src word + addq a1, 8, a1 # E : + + beq t0, stxncpy_aligned # U : avoid loading dest word if not needed + ldq_u t0, 0(a0) # L : + nop + nop + + br stxncpy_aligned # .. e1 : + nop + nop + nop + + + +/* The source and destination are not co-aligned. Align the destination + and cope. We have to be very careful about not reading too much and + causing a SEGV. */ + + .align 4 +$u_head: + /* We know just enough now to be able to assemble the first + full source word. We can still find a zero at the end of it + that prevents us from outputting the whole thing. + + On entry to this basic block: + t0 == the first dest word, unmasked + t1 == the shifted low bits of the first source word + t6 == bytemask that is -1 in dest word bytes */ + + ldq_u t2, 8(a1) # L : Latency=3 load second src word + addq a1, 8, a1 # E : + mskql t0, a0, t0 # U : mask trailing garbage in dst + extqh t2, a1, t4 # U : (3 cycle stall on t2) + + or t1, t4, t1 # E : first aligned src word complete (stall) + mskqh t1, a0, t1 # U : mask leading garbage in src (stall) + or t0, t1, t0 # E : first output word complete (stall) + or t0, t6, t6 # E : mask original data for zero test (stall) + + cmpbge zero, t6, t8 # E : + beq a2, $u_eocfin # U : + nop + nop + + bne t8, $u_final # U : + lda t6, -1 # E : mask out the bits we have + mskql t6, a1, t6 # U : already seen (stall) + stq_u t0, 0(a0) # L : store first output word + + or t6, t2, t2 # E : + cmpbge zero, t2, t8 # E : find nulls in second partial (stall) + addq a0, 8, a0 # E : + subq a2, 1, a2 # E : + + bne t8, $u_late_head_exit # U : + /* Finally, we've got all the stupid leading edge cases taken care + of and we can set up to enter the main loop. */ + extql t2, a1, t1 # U : position hi-bits of lo word + ldq_u t2, 8(a1) # L : read next high-order source word + addq a1, 8, a1 # E : + + cmpbge zero, t2, t8 # E : (stall) + beq a2, $u_eoc # U : + nop + nop + + bne t8, $u_eos # e1 : + nop + nop + nop + + /* Unaligned copy main loop. In order to avoid reading too much, + the loop is structured to detect zeros in aligned source words. + This has, unfortunately, effectively pulled half of a loop + iteration out into the head and half into the tail, but it does + prevent nastiness from accumulating in the very thing we want + to run as fast as possible. + + On entry to this basic block: + t1 == the shifted high-order bits from the previous source word + t2 == the unshifted current source word + + We further know that t2 does not contain a null terminator. */ + + .align 4 +$u_loop: + extqh t2, a1, t0 # U : extract high bits for current word + addq a1, 8, a1 # E : + extql t2, a1, t3 # U : extract low bits for next time + addq a0, 8, a0 # E : + + or t0, t1, t0 # E : current dst word now complete + ldq_u t2, 0(a1) # U : Latency=3 load high word for next time + stq_u t0, -8(a0) # U : save the current word (stall) + mov t3, t1 # E : + + subq a2, 1, a2 # E : + cmpbge zero, t2, t8 # E : test new word for eos (2 cycle stall for data) + beq a2, $u_eoc # U : (stall) + nop + + beq t8, $u_loop # U : + nop + nop + nop + + /* We've found a zero somewhere in the source word we just read. + If it resides in the lower half, we have one (probably partial) + word to write out, and if it resides in the upper half, we + have one full and one partial word left to write out. + + On entry to this basic block: + t1 == the shifted high-order bits from the previous source word + t2 == the unshifted current source word. */ +$u_eos: + extqh t2, a1, t0 # U : + or t0, t1, t0 # E : first (partial) source word complete (stall) + cmpbge zero, t0, t8 # E : is the null in this first bit? (stall) + bne t8, $u_final # U : (stall) + + stq_u t0, 0(a0) # L : the null was in the high-order bits + addq a0, 8, a0 # E : + subq a2, 1, a2 # E : + nop + +$u_late_head_exit: + extql t2, a1, t0 # U : + cmpbge zero, t0, t8 # E : + or t8, t10, t6 # E : (stall) + cmoveq a2, t6, t8 # E : Latency=2, extra map slot (stall) + + /* Take care of a final (probably partial) result word. + On entry to this basic block: + t0 == assembled source word + t8 == cmpbge mask that found the null. */ +$u_final: + negq t8, t6 # E : isolate low bit set + and t6, t8, t12 # E : (stall) + and t12, 0x80, t6 # E : avoid dest word load if we can (stall) + bne t6, 1f # U : (stall) + + ldq_u t1, 0(a0) # L : + subq t12, 1, t6 # E : + or t6, t12, t8 # E : (stall) + zapnot t0, t8, t0 # U : kill source bytes > null + + zap t1, t8, t1 # U : kill dest bytes <= null + or t0, t1, t0 # E : (stall) + nop + nop + +1: stq_u t0, 0(a0) # L : + ret (t9) # L0 : Latency=3 + +$u_eoc: # end-of-count + extqh t2, a1, t0 # U : + or t0, t1, t0 # E : (stall) + cmpbge zero, t0, t8 # E : (stall) + nop + +$u_eocfin: # end-of-count, final word + or t10, t8, t8 # E : + br $u_final # L0 : Latency=3 + nop + nop + + /* Unaligned copy entry point. */ + .align 4 +$unaligned: + + ldq_u t1, 0(a1) # L : load first source word + and a0, 7, t4 # E : find dest misalignment + and a1, 7, t5 # E : find src misalignment + /* Conditionally load the first destination word and a bytemask + with 0xff indicating that the destination byte is sacrosanct. */ + mov zero, t0 # E : + + mov zero, t6 # E : + beq t4, 1f # U : + ldq_u t0, 0(a0) # L : + lda t6, -1 # E : + + mskql t6, a0, t6 # U : + nop + nop + nop +1: + subq a1, t4, a1 # E : sub dest misalignment from src addr + + /* If source misalignment is larger than dest misalignment, we need + extra startup checks to avoid SEGV. */ + + cmplt t4, t5, t12 # E : + extql t1, a1, t1 # U : shift src into place + lda t2, -1 # E : for creating masks later + beq t12, $u_head # U : (stall) + + mskqh t2, t5, t2 # U : begin src byte validity mask + cmpbge zero, t1, t8 # E : is there a zero? + extql t2, a1, t2 # U : + or t8, t10, t5 # E : test for end-of-count too + + cmpbge zero, t2, t3 # E : + cmoveq a2, t5, t8 # E : Latency=2, extra map slot + nop # E : keep with cmoveq + andnot t8, t3, t8 # E : (stall) + + beq t8, $u_head # U : + /* At this point we've found a zero in the first partial word of + the source. We need to isolate the valid source data and mask + it into the original destination data. (Incidentally, we know + that we'll need at least one byte of that original dest word.) */ + ldq_u t0, 0(a0) # L : + negq t8, t6 # E : build bitmask of bytes <= zero + mskqh t1, t4, t1 # U : + + and t6, t8, t12 # E : + subq t12, 1, t6 # E : (stall) + or t6, t12, t8 # E : (stall) + zapnot t2, t8, t2 # U : prepare source word; mirror changes (stall) + + zapnot t1, t8, t1 # U : to source validity mask + andnot t0, t2, t0 # E : zero place for source to reside + or t0, t1, t0 # E : and put it there (stall both t0, t1) + stq_u t0, 0(a0) # L : (stall) + + ret (t9) # L0 : Latency=3 + nop + nop + nop + + .end __stxncpy + diff --git a/arch/alpha/lib/ev67-strcat.S b/arch/alpha/lib/ev67-strcat.S new file mode 100644 index 000000000..c426fe3ed --- /dev/null +++ b/arch/alpha/lib/ev67-strcat.S @@ -0,0 +1,54 @@ +/* + * arch/alpha/lib/ev67-strcat.S + * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com> + * + * Append a null-terminated string from SRC to DST. + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * Try not to change the actual algorithm if possible for consistency. + * Commentary: It seems bogus to walk the input string twice - once + * to determine the length, and then again while doing the copy. + * A significant (future) enhancement would be to only read the input + * string once. + */ + + + .text + + .align 4 + .globl strcat + .ent strcat +strcat: + .frame $30, 0, $26 + .prologue 0 + + mov $16, $0 # E : set up return value + /* Find the end of the string. */ + ldq_u $1, 0($16) # L : load first quadword (a0 may be misaligned) + lda $2, -1 # E : + insqh $2, $16, $2 # U : + + andnot $16, 7, $16 # E : + or $2, $1, $1 # E : + cmpbge $31, $1, $2 # E : bits set iff byte == 0 + bne $2, $found # U : + +$loop: ldq $1, 8($16) # L : + addq $16, 8, $16 # E : + cmpbge $31, $1, $2 # E : + beq $2, $loop # U : + +$found: cttz $2, $3 # U0 : + addq $16, $3, $16 # E : + /* Now do the append. */ + mov $26, $23 # E : + br __stxcpy # L0 : + + .end strcat diff --git a/arch/alpha/lib/ev67-strchr.S b/arch/alpha/lib/ev67-strchr.S new file mode 100644 index 000000000..03c56d583 --- /dev/null +++ b/arch/alpha/lib/ev67-strchr.S @@ -0,0 +1,88 @@ +/* + * arch/alpha/lib/ev67-strchr.S + * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com> + * + * Return the address of a given character within a null-terminated + * string, or null if it is not found. + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * Try not to change the actual algorithm if possible for consistency. + */ + +#include <alpha/regdef.h> + + .set noreorder + .set noat + + .align 4 + .globl strchr + .ent strchr +strchr: + .frame sp, 0, ra + .prologue 0 + + ldq_u t0, 0(a0) # L : load first quadword Latency=3 + and a1, 0xff, t3 # E : 00000000000000ch + insbl a1, 1, t5 # U : 000000000000ch00 + insbl a1, 7, a2 # U : ch00000000000000 + + insbl t3, 6, a3 # U : 00ch000000000000 + or t5, t3, a1 # E : 000000000000chch + andnot a0, 7, v0 # E : align our loop pointer + lda t4, -1 # E : build garbage mask + + mskqh t4, a0, t4 # U : only want relevant part of first quad + or a2, a3, a2 # E : chch000000000000 + inswl a1, 2, t5 # E : 00000000chch0000 + inswl a1, 4, a3 # E : 0000chch00000000 + + or a1, a2, a1 # E : chch00000000chch + or a3, t5, t5 # E : 0000chchchch0000 + cmpbge zero, t0, t2 # E : bits set iff byte == zero + cmpbge zero, t4, t4 # E : bits set iff byte is garbage + + /* This quad is _very_ serialized. Lots of stalling happens */ + or t5, a1, a1 # E : chchchchchchchch + xor t0, a1, t1 # E : make bytes == c zero + cmpbge zero, t1, t3 # E : bits set iff byte == c + or t2, t3, t0 # E : bits set iff char match or zero match + + andnot t0, t4, t0 # E : clear garbage bits + cttz t0, a2 # U0 : speculative (in case we get a match) + nop # E : + bne t0, $found # U : + + /* + * Yuk. This loop is going to stall like crazy waiting for the + * data to be loaded. Not much can be done about it unless it's + * unrolled multiple times - is that safe to do in kernel space? + * Or would exception handling recovery code do the trick here? + */ +$loop: ldq t0, 8(v0) # L : Latency=3 + addq v0, 8, v0 # E : + xor t0, a1, t1 # E : + cmpbge zero, t0, t2 # E : bits set iff byte == 0 + + cmpbge zero, t1, t3 # E : bits set iff byte == c + or t2, t3, t0 # E : + cttz t3, a2 # U0 : speculative (in case we get a match) + beq t0, $loop # U : + +$found: negq t0, t1 # E : clear all but least set bit + and t0, t1, t0 # E : + and t0, t3, t1 # E : bit set iff byte was the char + addq v0, a2, v0 # E : Add in the bit number from above + + cmoveq t1, $31, v0 # E : Two mapping slots, latency = 2 + nop + nop + ret # L0 : + + .end strchr diff --git a/arch/alpha/lib/ev67-strlen.S b/arch/alpha/lib/ev67-strlen.S new file mode 100644 index 000000000..503928072 --- /dev/null +++ b/arch/alpha/lib/ev67-strlen.S @@ -0,0 +1,49 @@ +/* + * arch/alpha/lib/ev67-strlen.S + * 21264 version by Rick Gorton <rick.gorton@alpha-processor.com> + * + * Finds length of a 0-terminated string. Optimized for the + * Alpha architecture: + * + * - memory accessed as aligned quadwords only + * - uses bcmpge to compare 8 bytes in parallel + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + */ + + .set noreorder + .set noat + + .globl strlen + .ent strlen + .align 4 +strlen: + ldq_u $1, 0($16) # L : load first quadword ($16 may be misaligned) + lda $2, -1($31) # E : + insqh $2, $16, $2 # U : + andnot $16, 7, $0 # E : + + or $2, $1, $1 # E : + cmpbge $31, $1, $2 # E : $2 <- bitmask: bit i == 1 <==> i-th byte == 0 + nop # E : + bne $2, $found # U : + +$loop: ldq $1, 8($0) # L : + addq $0, 8, $0 # E : addr += 8 + cmpbge $31, $1, $2 # E : + beq $2, $loop # U : + +$found: + cttz $2, $3 # U0 : + addq $0, $3, $0 # E : + subq $0, $16, $0 # E : + ret $31, ($26) # L0 : + + .end strlen diff --git a/arch/alpha/lib/ev67-strlen_user.S b/arch/alpha/lib/ev67-strlen_user.S new file mode 100644 index 000000000..67f1e9426 --- /dev/null +++ b/arch/alpha/lib/ev67-strlen_user.S @@ -0,0 +1,109 @@ +/* + * arch/alpha/lib/ev67-strlen_user.S + * 21264 version contributed by Rick Gorton <rick.gorton@api-networks.com> + * + * Return the length of the string including the NULL terminator + * (strlen+1) or zero if an error occurred. + * + * In places where it is critical to limit the processing time, + * and the data is not trusted, strnlen_user() should be used. + * It will return a value greater than its second argument if + * that limit would be exceeded. This implementation is allowed + * to access memory beyond the limit, but will not cross a page + * boundary when doing so. + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * Try not to change the actual algorithm if possible for consistency. + */ + +#include <alpha/regdef.h> + + +/* Allow an exception for an insn; exit if we get one. */ +#define EX(x,y...) \ + 99: x,##y; \ + .section __ex_table,"a"; \ + .gprel32 99b; \ + lda v0, $exception-99b(zero); \ + .previous + + + .set noreorder + .set noat + .text + + .globl __strlen_user + .ent __strlen_user + .frame sp, 0, ra + + .align 4 +__strlen_user: + ldah a1, 32767(zero) # do not use plain strlen_user() for strings + # that might be almost 2 GB long; you should + # be using strnlen_user() instead + nop + nop + nop + + .globl __strnlen_user + + .align 4 +__strnlen_user: + ldgp $29,0($27) # E E : we do exceptions -- we need the gp. + /* Decomposes into lda/ldah */ + .prologue 1 + EX( ldq_u t0, 0(a0) ) # L : load first quadword (a0 may be misaligned) + lda t1, -1(zero) # E : + + insqh t1, a0, t1 # U : + andnot a0, 7, v0 # E : + or t1, t0, t0 # E : + subq a0, 1, a0 # E : get our +1 for the return + + cmpbge zero, t0, t1 # E : t1 <- bitmask: bit i == 1 <==> i-th byte == 0 + subq a1, 7, t2 # E : + subq a0, v0, t0 # E : + bne t1, $found # U : + + addq t2, t0, t2 # E : + addq a1, 1, a1 # E : + nop # E : + nop # E : + + .align 4 +$loop: ble t2, $limit # U : + EX( ldq t0, 8(v0) ) # L : + nop # E : + nop # E : + + cmpbge zero, t0, t1 # E : + subq t2, 8, t2 # E : + addq v0, 8, v0 # E : addr += 8 + beq t1, $loop # U : + +$found: cttz t1, t2 # U0 : + addq v0, t2, v0 # E : + subq v0, a0, v0 # E : + ret # L0 : + +$exception: + nop + nop + nop + ret + + .align 4 # currently redundant +$limit: + nop + nop + subq a1, t2, v0 + ret + + .end __strlen_user diff --git a/arch/alpha/lib/ev67-strncat.S b/arch/alpha/lib/ev67-strncat.S new file mode 100644 index 000000000..4ae716cd2 --- /dev/null +++ b/arch/alpha/lib/ev67-strncat.S @@ -0,0 +1,94 @@ +/* + * arch/alpha/lib/ev67-strncat.S + * 21264 version contributed by Rick Gorton <rick.gorton@api-networks.com> + * + * Append no more than COUNT characters from the null-terminated string SRC + * to the null-terminated string DST. Always null-terminate the new DST. + * + * This differs slightly from the semantics in libc in that we never write + * past count, whereas libc may write to count+1. This follows the generic + * implementation in lib/string.c and is, IMHO, more sensible. + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * Try not to change the actual algorithm if possible for consistency. + */ + + + .text + + .align 4 + .globl strncat + .ent strncat +strncat: + .frame $30, 0, $26 + .prologue 0 + + mov $16, $0 # set up return value + beq $18, $zerocount # U : + /* Find the end of the string. */ + ldq_u $1, 0($16) # L : load first quadword ($16 may be misaligned) + lda $2, -1($31) # E : + + insqh $2, $0, $2 # U : + andnot $16, 7, $16 # E : + nop # E : + or $2, $1, $1 # E : + + nop # E : + nop # E : + cmpbge $31, $1, $2 # E : bits set iff byte == 0 + bne $2, $found # U : + +$loop: ldq $1, 8($16) # L : + addq $16, 8, $16 # E : + cmpbge $31, $1, $2 # E : + beq $2, $loop # U : + +$found: cttz $2, $3 # U0 : + addq $16, $3, $16 # E : + nop # E : + bsr $23, __stxncpy # L0 :/* Now do the append. */ + + /* Worry about the null termination. */ + + zapnot $1, $27, $2 # U : was last byte a null? + cmplt $27, $24, $5 # E : did we fill the buffer completely? + bne $2, 0f # U : + ret # L0 : + +0: or $5, $18, $2 # E : + nop + bne $2, 2f # U : + and $24, 0x80, $3 # E : no zero next byte + + nop # E : + bne $3, 1f # U : + /* Here there are bytes left in the current word. Clear one. */ + addq $24, $24, $24 # E : end-of-count bit <<= 1 + nop # E : + +2: zap $1, $24, $1 # U : + nop # E : + stq_u $1, 0($16) # L : + ret # L0 : + +1: /* Here we must clear the first byte of the next DST word */ + stb $31, 8($16) # L : + nop # E : + nop # E : + ret # L0 : + +$zerocount: + nop # E : + nop # E : + nop # E : + ret # L0 : + + .end strncat diff --git a/arch/alpha/lib/memcpy.c b/arch/alpha/lib/memcpy.c index d715f0219..64083fc73 100644 --- a/arch/alpha/lib/memcpy.c +++ b/arch/alpha/lib/memcpy.c @@ -161,24 +161,3 @@ void * memcpy(void * dest, const void *src, size_t n) /* For backward modules compatibility, define __memcpy. */ asm("__memcpy = memcpy; .globl __memcpy"); - -void *memmove (void *dest, const void *src, size_t n) -{ - if (dest <= src) { - if (!(((unsigned long) dest ^ (unsigned long) src) & 7)) - __memcpy_aligned_up ((unsigned long) dest, - (unsigned long) src, n); - else - __memcpy_unaligned_up ((unsigned long) dest, - (unsigned long) src, n); - } - else { - if (!(((unsigned long) dest ^ (unsigned long) src) & 7)) - __memcpy_aligned_dn ((unsigned long) dest, - (unsigned long) src, n); - else - __memcpy_unaligned_dn ((unsigned long) dest, - (unsigned long) src, n); - } - return dest; -} diff --git a/arch/alpha/lib/memmove.S b/arch/alpha/lib/memmove.S new file mode 100644 index 000000000..3c8567e4e --- /dev/null +++ b/arch/alpha/lib/memmove.S @@ -0,0 +1,103 @@ +/* + * arch/alpha/lib/memmove.S + * + * Barely optimized memmove routine for Alpha EV5. + * + * This is hand-massaged output from the original memcpy.c. We defer to + * memcpy whenever possible; the backwards copy loops are not unrolled. + */ + + .set noat + .set noreorder + .text + + .align 4 + .globl memmove + .ent memmove +memmove: + addq $16,$18,$4 + addq $17,$18,$5 + cmpule $4,$17,$1 /* dest + n <= src */ + cmpule $5,$16,$2 /* dest >= src + n */ + + bis $1,$2,$1 + mov $16,$0 + xor $16,$17,$2 + bne $1,memcpy + + and $2,7,$2 /* Test for src/dest co-alignment. */ + bne $2,$misaligned + + and $4,7,$1 + beq $1,$skip_aligned_byte_loop_head + +$aligned_byte_loop_head: + lda $4,-1($4) + lda $5,-1($5) + unop + ble $18,$egress + + ldq_u $3,0($5) + ldq_u $2,0($4) + lda $18,-1($18) + extbl $3,$5,$1 + + insbl $1,$4,$1 + mskbl $2,$4,$2 + bis $1,$2,$1 + and $4,7,$6 + + stq_u $1,0($4) + bne $6,$aligned_byte_loop_head + +$skip_aligned_byte_loop_head: + lda $18,-8($18) + blt $18,$skip_aligned_word_loop + +$aligned_word_loop: + ldq $1,-8($5) + nop + lda $5,-8($5) + lda $18,-8($18) + + stq $1,-8($4) + nop + lda $4,-8($4) + bge $18,$aligned_word_loop + +$skip_aligned_word_loop: + lda $18,8($18) + bgt $18,$byte_loop_tail + unop + ret $31,($26),1 + + .align 4 +$misaligned: + nop + fnop + unop + beq $18,$egress + +$byte_loop_tail: + ldq_u $3,-1($5) + ldq_u $2,-1($4) + lda $5,-1($5) + lda $4,-1($4) + + lda $18,-1($18) + extbl $3,$5,$1 + insbl $1,$4,$1 + mskbl $2,$4,$2 + + bis $1,$2,$1 + stq_u $1,0($4) + nop + bgt $18,$byte_loop_tail + +$egress: + ret $31,($26),1 + nop + nop + nop + + .end memmove diff --git a/arch/alpha/lib/strcpy.S b/arch/alpha/lib/strcpy.S index dd21b5208..e0728e4ad 100644 --- a/arch/alpha/lib/strcpy.S +++ b/arch/alpha/lib/strcpy.S @@ -17,6 +17,7 @@ strcpy: mov $16, $0 # set up return value mov $26, $23 # set up return address + unop br __stxcpy # do the copy .end strcpy diff --git a/arch/alpha/lib/strncpy.S b/arch/alpha/lib/strncpy.S index dbc011c34..7d64d21d5 100644 --- a/arch/alpha/lib/strncpy.S +++ b/arch/alpha/lib/strncpy.S @@ -27,6 +27,10 @@ strncpy: beq $18, 0f mov $26, $23 # set return address br __stxncpy # do the work of the copy + 0: ret + nop + nop + nop .end strncpy diff --git a/arch/alpha/lib/stxcpy.S b/arch/alpha/lib/stxcpy.S index b7b9da482..5a427634d 100644 --- a/arch/alpha/lib/stxcpy.S +++ b/arch/alpha/lib/stxcpy.S @@ -1,4 +1,5 @@ -/* stxcpy.S +/* + * arch/alpha/lib/stxcpy.S * Contributed by Richard Henderson (rth@tamu.edu) * * Copy a null-terminated string from SRC to DST. diff --git a/arch/alpha/lib/stxncpy.S b/arch/alpha/lib/stxncpy.S index 5bab622e0..d7cddb074 100644 --- a/arch/alpha/lib/stxncpy.S +++ b/arch/alpha/lib/stxncpy.S @@ -1,4 +1,5 @@ -/* stxncpy.S +/* + * arch/alpha/lib/stxncpy.S * Contributed by Richard Henderson (rth@tamu.edu) * * Copy no more than COUNT bytes of the null-terminated string from diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c index 52e2b36f7..3b0ae7011 100644 --- a/arch/alpha/mm/init.c +++ b/arch/alpha/mm/init.c @@ -185,7 +185,7 @@ show_mem(void) reserved++; else if (PageSwapCache(mem_map+i)) cached++; - else if (!atomic_read(&mem_map[i].count)) + else if (!page_count(mem_map+i)) free++; else shared += atomic_read(&mem_map[i].count) - 1; diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile index 6fbdb5ea1..f74033b36 100644 --- a/arch/arm/boot/Makefile +++ b/arch/arm/boot/Makefile @@ -35,16 +35,21 @@ INITRD_PHYS = 0x00800000 INITRD_VIRT = 0xc0800000 endif +ifeq ($(CONFIG_ARCH_SHARK),y) +ZTEXTADDR = 0x08508000 +ZRELADDR = 0x08008000 +endif + ifeq ($(CONFIG_FOOTBRIDGE),y) ZTEXTADDR = 0x00008000 -PARAMS = 0x00000100 +PARAMS_PHYS = 0x00000100 INITRD_PHYS = 0x00800000 INITRD_VIRT = 0xc0800000 endif ifeq ($(CONFIG_ARCH_INTEGRATOR),y) ZTEXTADDR = 0x00008000 -PARAMS = 0x00000100 +PARAMS_PHYS = 0x00000100 INITRD_PHYS = 0x00800000 INITRD_VIRT = 0xc0800000 endif @@ -65,6 +70,14 @@ ZRELADDR = 0xf0008000 ZBSSADDR = 0xf03e0000 endif +ifeq ($(CONFIG_ARCH_P720T),y) +ZTEXTADDR = 0xc0018000 +ZRELADDR = 0xc0018000 +PARAMS_PHYS = 0xc0000100 +INITRD_PHYS = 0xc0400000 +INITRD_VIRT = 0xc0400000 +endif + ifeq ($(CONFIG_ARCH_SA1100),y) ZTEXTADDR = 0xc0008000 ZRELADDR = 0xc0008000 @@ -72,8 +85,9 @@ ifeq ($(CONFIG_SA1100_VICTOR),y) ZTEXTADDR = 0x00002000 ZBSSADDR = 0xc0100000 endif -ifeq ($(CONFIG_SA1100_THINCLIENT),y) - ZTEXTADDR = 0xC0200000 +ifeq ($(CONFIG_SA1100_SHERMAN),y) + ZTEXTADDR = 0x00050000 + ZBSSADDR = 0xc0100000 endif ifeq ($(CONFIG_SA1100_GRAPHICSCLIENT),y) ZTEXTADDR = 0xC0200000 diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 46b754ec5..bf8f1c947 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -18,6 +18,7 @@ ZLDFLAGS = -p -X -T vmlinux.lds # ifeq ($(CONFIG_ARCH_ACORN),y) OBJS += ll_char_wr.o font.o +ZLDFLAGS += -defsym params=$(PARAMS_PHYS) endif ifeq ($(CONFIG_ARCH_NETWINDER),y) @@ -36,6 +37,11 @@ ifeq ($(CONFIG_ARCH_L7200),y) OBJS += head-l7200.o endif +ifeq ($(CONFIG_ARCH_P720T),y) +# Borrow this code from SA1100 +OBJS += head-sa1100.o +endif + ifeq ($(CONFIG_ARCH_SA1100),y) OBJS += head-sa1100.o setup-sa1100.o ifeq ($(CONFIG_SA1100_NANOENGINE),y) diff --git a/arch/arm/def-configs/a5k b/arch/arm/def-configs/a5k index 11a1dfd67..c8ede2f80 100644 --- a/arch/arm/def-configs/a5k +++ b/arch/arm/def-configs/a5k @@ -2,36 +2,72 @@ # Automatically generated make config: don't edit # CONFIG_ARM=y +# CONFIG_SBUS is not set +CONFIG_UID16=y # # Code maturity level options # CONFIG_EXPERIMENTAL=y +CONFIG_OBSOLETE=y # -# System and processor type +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +CONFIG_ARCH_ARCA5K=y +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) # # CONFIG_ARCH_ARC is not set CONFIG_ARCH_A5K=y -# CONFIG_ARCH_RPC is not set -# CONFIG_ARCH_EBSA110 is not set -# CONFIG_FOOTBRIDGE is not set + +# +# Footbridge Implementations +# + +# +# SA11x0 Implementations +# CONFIG_ARCH_ACORN=y +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set # CONFIG_CPU_32 is not set CONFIG_CPU_26=y # CONFIG_PAGESIZE_16 is not set -# CONFIG_ISA_DMA is not set # -# Loadable module support +# Processor Type # -CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -CONFIG_KMOD=y +# CONFIG_DISCONTIGMEM is not set # # General setup # +# CONFIG_PCI is not set +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set @@ -42,9 +78,15 @@ CONFIG_KCORE_ELF=y CONFIG_BINFMT_AOUT=y # CONFIG_BINFMT_ELF is not set # CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set + +# +# Parallel port support +# CONFIG_PARPORT=m CONFIG_PARPORT_PC=m # CONFIG_PARPORT_PC_FIFO is not set +CONFIG_PARPORT_PC_SUPERIO=y # CONFIG_PARPORT_ARC is not set # CONFIG_PARPORT_AMIGA is not set # CONFIG_PARPORT_MFC3 is not set @@ -54,14 +96,9 @@ CONFIG_PARPORT_PC=m # CONFIG_PARPORT_1284 is not set # -# I2O device support +# Memory Technology Devices (MTD) # -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set +# CONFIG_MTD is not set # # Plug and Play configuration @@ -73,37 +110,16 @@ CONFIG_PARPORT_PC=m # Block devices # CONFIG_BLK_DEV_FD=y -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDECD is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -CONFIG_BLK_DEV_IDE_ICSIDE=y -# CONFIG_BLK_DEV_IDEDMA_ICS is not set -# CONFIG_BLK_DEV_IDE_RAPIDE is not set -# CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set CONFIG_BLK_DEV_LOOP=m # CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y -# CONFIG_BLK_DEV_XD is not set -CONFIG_PARIDE_PARPORT=m -# CONFIG_PARIDE is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_HD is not set # # Acorn-specific block devices @@ -113,100 +129,6 @@ CONFIG_BLK_DEV_MFM=m CONFIG_BLK_DEV_MFM_AUTODETECT=y # -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=y -CONFIG_SERIAL_CONSOLE=y -# CONFIG_ATOMWIDE_SERIAL is not set -# CONFIG_DUALSP_SERIAL is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_UNIX98_PTYS is not set -# CONFIG_PRINTER is not set -# CONFIG_PPDEV is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -CONFIG_MOUSE=y -# CONFIG_PSMOUSE is not set -# CONFIG_82C710_MOUSE is not set -# CONFIG_PC110_PAD is not set - -# -# Joysticks -# -# CONFIG_JOYSTICK is not set -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set - -# -# PCMCIA character device support -# -# CONFIG_PCMCIA_SERIAL_CS is not set -# CONFIG_AGP is not set - -# -# Support for USB -# -# CONFIG_USB is not set - -# -# Console drivers -# -CONFIG_FB=y - -# -# Frame-buffer support -# -CONFIG_FB=y -CONFIG_DUMMY_CONSOLE=y -CONFIG_FB_ACORN=y -# CONFIG_FB_MATROX is not set -# CONFIG_FB_ATY is not set -# CONFIG_FB_ATY128 is not set -# CONFIG_FB_3DFX is not set -# CONFIG_FB_VIRTUAL is not set -# CONFIG_FBCON_ADVANCED is not set -CONFIG_FBCON_MFB=y -CONFIG_FBCON_CFB2=y -CONFIG_FBCON_CFB4=y -CONFIG_FBCON_CFB8=y -# CONFIG_FBCON_FONTWIDTH8_ONLY is not set -CONFIG_FBCON_FONTS=y -# CONFIG_FONT_8x8 is not set -# CONFIG_FONT_8x16 is not set -# CONFIG_FONT_SUN8x16 is not set -# CONFIG_FONT_SUN12x22 is not set -# CONFIG_FONT_6x11 is not set -# CONFIG_FONT_PEARL_8x8 is not set -CONFIG_FONT_ACORN_8x8=y - -# # Networking options # # CONFIG_PACKET is not set @@ -218,16 +140,10 @@ CONFIG_INET=y # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set +# CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set - -# -# (it is safe to leave these untouched) -# -# CONFIG_SKB_LARGE is not set # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set @@ -238,9 +154,9 @@ CONFIG_INET=y # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set # CONFIG_LLC is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -253,16 +169,6 @@ CONFIG_INET=y # CONFIG_NET_SCHED is not set # -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# # Network device support # CONFIG_NETDEVICES=y @@ -272,7 +178,9 @@ CONFIG_NETDEVICES=y # # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set +# CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_NET_SB1000 is not set # @@ -286,19 +194,18 @@ CONFIG_ARM_ETHER3=y # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_RTL8139 is not set -# CONFIG_DM9102 is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set -# CONFIG_NET_EISA is not set +# CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set # # Ethernet (1000 Mbit) # -# CONFIG_YELLOWFIN is not set # CONFIG_ACENIC is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set @@ -312,7 +219,7 @@ CONFIG_ARM_ETHER3=y # CONFIG_NET_RADIO is not set # -# Token Ring driver support +# Token Ring devices # # CONFIG_TR is not set # CONFIG_NET_FC is not set @@ -325,9 +232,62 @@ CONFIG_ARM_ETHER3=y # CONFIG_WAN is not set # -# PCMCIA network device support +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes # -# CONFIG_NET_PCMCIA is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +CONFIG_BLK_DEV_IDE_ICSIDE=y +# CONFIG_BLK_DEV_IDEDMA_ICS is not set +# CONFIG_IDEDMA_ICS_AUTO is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_BLK_DEV_IDE_RAPIDE is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set # # SCSI support @@ -335,16 +295,90 @@ CONFIG_ARM_ETHER3=y # CONFIG_SCSI is not set # -# Sound +# I2O device support # -# CONFIG_SOUND is not set +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_ATOMWIDE_SERIAL is not set +# CONFIG_DUALSP_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set +# CONFIG_PRINTER is not set +# CONFIG_PPDEV is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_PHILIPSPAR is not set +# CONFIG_I2C_ELV is not set +# CONFIG_I2C_VELLEMAN is not set +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_CHARDEV=y + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +# CONFIG_PSMOUSE is not set +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set # -# Filesystems +# File systems # # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=y CONFIG_ADFS_FS=y +# CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set @@ -353,37 +387,60 @@ CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set # CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set # # Network File Systems # # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set # CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set # # Partition Types # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -# CONFIG_SGI_PARTITION is not set -# CONFIG_SUN_PARTITION is not set CONFIG_ACORN_PARTITION=y CONFIG_ACORN_PARTITION_ADFS=y CONFIG_ACORN_PARTITION_ICS=y @@ -394,6 +451,7 @@ CONFIG_NLS=y # # Native Language Support # +CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_CODEPAGE_437 is not set # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set @@ -410,6 +468,10 @@ CONFIG_NLS=y # CONFIG_NLS_CODEPAGE_866 is not set # CONFIG_NLS_CODEPAGE_869 is not set # CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set # CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set @@ -422,6 +484,45 @@ CONFIG_NLS=y # CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +CONFIG_FB=y + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_FB_ACORN=y +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_MFB=y +CONFIG_FBCON_CFB2=y +CONFIG_FBCON_CFB4=y +CONFIG_FBCON_CFB8=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +# CONFIG_FONT_8x8 is not set +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +CONFIG_FONT_ACORN_8x8=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set # # Kernel hacking diff --git a/arch/arm/def-configs/assabet b/arch/arm/def-configs/assabet index 7a4cd1778..8cf335a9f 100644 --- a/arch/arm/def-configs/assabet +++ b/arch/arm/def-configs/assabet @@ -12,57 +12,75 @@ CONFIG_EXPERIMENTAL=y # CONFIG_OBSOLETE is not set # +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# # System Type # -# CONFIG_ARCH_ARC is not set -# CONFIG_ARCH_A5K is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set # CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_RPC is not set CONFIG_ARCH_SA1100=y # +# Archimedes/A5000 Implementations +# + +# +# Footbridge Implementations +# + +# # SA11x0 Implementations # CONFIG_SA1100_ASSABET=y # CONFIG_ASSABET_NEPONSET is not set # CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set # CONFIG_SA1100_BITSY is not set # CONFIG_SA1100_LART is not set -# CONFIG_SA1100_THINCLIENT is not set # CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_NANOENGINE is not set # CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_PANGOLIN is not set CONFIG_ANGELBOOT=y -# CONFIG_SA1100_FREQUENCY_SCALE is not set +CONFIG_SA1100_FREQUENCY_SCALE=y # CONFIG_SA1100_VOLTAGE_SCALE is not set -CONFIG_CPU_32=y -# CONFIG_CPU_26 is not set -CONFIG_CPU_32v4=y -CONFIG_CPU_SA1100=y # CONFIG_ARCH_ACORN is not set # CONFIG_FOOTBRIDGE is not set # CONFIG_FOOTBRIDGE_HOST is not set # CONFIG_FOOTBRIDGE_ADDIN is not set -CONFIG_DISCONTIGMEM=y -# CONFIG_PCI is not set -# CONFIG_ISA is not set -# CONFIG_ISA_DMA is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set # -# Loadable module support +# Processor Type # -CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -# CONFIG_KMOD is not set +CONFIG_CPU_32v4=y +CONFIG_CPU_SA1100=y +CONFIG_DISCONTIGMEM=y # # General setup # +# CONFIG_PCI is not set +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +CONFIG_PC_KEYMAP=y CONFIG_HOTPLUG=y # -# PC Card support +# PCMCIA/CardBus support # CONFIG_PCMCIA=y # CONFIG_PCMCIA_DEBUG is not set @@ -135,16 +153,10 @@ CONFIG_INET=y # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set +# CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set - -# -# (it is safe to leave these untouched) -# -CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set @@ -181,13 +193,13 @@ CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y -# CONFIG_ARM_AM79C961A is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set @@ -320,13 +332,14 @@ CONFIG_BLK_DEV_IDECS=y # CONFIG_VT=y # CONFIG_VT_CONSOLE is not set -CONFIG_SERIAL_SA1100=y -CONFIG_SERIAL_SA1100_CONSOLE=y -# CONFIG_TOUCHSCREEN_SA1100 is not set -# CONFIG_TOUCHSCREEN_BITSY is not set # CONFIG_SERIAL is not set # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_SA1100_DEFAULT_BAUDRATE=9600 +CONFIG_TOUCHSCREEN_UCB1200=y +# CONFIG_TOUCHSCREEN_BITSY is not set CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=32 @@ -345,6 +358,10 @@ CONFIG_UNIX98_PTY_COUNT=32 # Joysticks # # CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # @@ -354,11 +371,6 @@ CONFIG_UNIX98_PTY_COUNT=32 # CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -367,10 +379,9 @@ CONFIG_UNIX98_PTY_COUNT=32 # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set +# CONFIG_AGP is not set # CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set # CONFIG_PCMCIA_SERIAL is not set -# CONFIG_AGP is not set # # File systems @@ -451,12 +462,14 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set CONFIG_NLS=y # # Native Language Support # +CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_NLS_CODEPAGE_437=y # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set @@ -473,6 +486,10 @@ CONFIG_NLS_CODEPAGE_437=y # CONFIG_NLS_CODEPAGE_866 is not set # CONFIG_NLS_CODEPAGE_869 is not set # CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set # CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set @@ -485,6 +502,7 @@ CONFIG_NLS_CODEPAGE_437=y # CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_UTF8 is not set # # Console drivers @@ -497,7 +515,9 @@ CONFIG_FB=y # CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_CYBER2000 is not set CONFIG_FB_SA1100=y +# CONFIG_FB_MQ200 is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB2=y @@ -517,8 +537,10 @@ CONFIG_FONT_8x8=y # CONFIG_SOUND=y CONFIG_SOUND_UDA1341=y +# CONFIG_SOUND_SA1100_SSP is not set # CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set # CONFIG_SOUND_ES1370 is not set # CONFIG_SOUND_ES1371 is not set # CONFIG_SOUND_ESSSOLO1 is not set diff --git a/arch/arm/def-configs/brutus b/arch/arm/def-configs/brutus index 34391812a..bdd14f552 100644 --- a/arch/arm/def-configs/brutus +++ b/arch/arm/def-configs/brutus @@ -12,10 +12,17 @@ CONFIG_EXPERIMENTAL=y # CONFIG_OBSOLETE is not set # +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# # System Type # -# CONFIG_ARCH_ARC is not set -# CONFIG_ARCH_A5K is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set # CONFIG_ARCH_FOOTBRIDGE is not set @@ -27,33 +34,30 @@ CONFIG_ARCH_SA1100=y # # CONFIG_SA1100_ASSABET is not set CONFIG_SA1100_BRUTUS=y +# CONFIG_SA1100_CERF is not set # CONFIG_SA1100_BITSY is not set # CONFIG_SA1100_LART is not set # CONFIG_SA1100_THINCLIENT is not set # CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_NANOENGINE is not set # CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set CONFIG_ANGELBOOT=y # CONFIG_SA1100_FREQUENCY_SCALE is not set # CONFIG_SA1100_VOLTAGE_SCALE is not set -CONFIG_CPU_32=y -# CONFIG_CPU_26 is not set -CONFIG_CPU_32v4=y -CONFIG_CPU_SA1100=y # CONFIG_ARCH_ACORN is not set # CONFIG_FOOTBRIDGE is not set # CONFIG_FOOTBRIDGE_HOST is not set # CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +CONFIG_CPU_32v4=y +CONFIG_CPU_SA1100=y CONFIG_DISCONTIGMEM=y # CONFIG_PCI is not set # CONFIG_ISA is not set # CONFIG_ISA_DMA is not set - -# -# Loadable module support -# -CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -# CONFIG_KMOD is not set +CONFIG_PC_KEYMAP=y # # General setup @@ -147,7 +151,7 @@ CONFIG_VT=y # CONFIG_VT_CONSOLE is not set CONFIG_SERIAL_SA1100=y CONFIG_SERIAL_SA1100_CONSOLE=y -# CONFIG_TOUCHSCREEN_SA1100 is not set +# CONFIG_TOUCHSCREEN_UCB1200 is not set # CONFIG_TOUCHSCREEN_BITSY is not set # CONFIG_SERIAL is not set # CONFIG_SERIAL_EXTENDED is not set @@ -192,9 +196,8 @@ CONFIG_UNIX98_PTY_COUNT=32 # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set # # File systems @@ -256,6 +259,7 @@ CONFIG_FB=y # CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_CYBER2000 is not set CONFIG_FB_SA1100=y # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set diff --git a/arch/arm/def-configs/cerf b/arch/arm/def-configs/cerf index accb50b3f..e2bf1e06a 100644 --- a/arch/arm/def-configs/cerf +++ b/arch/arm/def-configs/cerf @@ -21,8 +21,8 @@ CONFIG_MODULES=y # # System Type # -# CONFIG_ARCH_ARC is not set -# CONFIG_ARCH_A5K is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set # CONFIG_ARCH_FOOTBRIDGE is not set @@ -35,34 +35,39 @@ CONFIG_ARCH_SA1100=y # CONFIG_SA1100_ASSABET is not set # CONFIG_SA1100_BRUTUS is not set CONFIG_SA1100_CERF=y +CONFIG_SA1100_CERF_32MB=y # CONFIG_SA1100_BITSY is not set # CONFIG_SA1100_LART is not set # CONFIG_SA1100_THINCLIENT is not set # CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_NANOENGINE is not set # CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set # CONFIG_ANGELBOOT is not set # CONFIG_SA1100_FREQUENCY_SCALE is not set # CONFIG_SA1100_VOLTAGE_SCALE is not set -CONFIG_CPU_32=y -# CONFIG_CPU_26 is not set -CONFIG_CPU_32v4=y -CONFIG_CPU_SA1100=y # CONFIG_ARCH_ACORN is not set # CONFIG_FOOTBRIDGE is not set # CONFIG_FOOTBRIDGE_HOST is not set # CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +CONFIG_CPU_32v4=y +CONFIG_CPU_SA1100=y CONFIG_DISCONTIGMEM=y # CONFIG_PCI is not set # CONFIG_ISA is not set # CONFIG_ISA_DMA is not set +CONFIG_PC_KEYMAP=y # # General setup # +# CONFIG_SA1100_CERF_CMDLINE is not set CONFIG_HOTPLUG=y # -# PC Card support +# PCMCIA/CardBus support # CONFIG_PCMCIA=y # CONFIG_PCMCIA_DEBUG is not set @@ -70,7 +75,7 @@ CONFIG_SA1100_PCMCIA=y CONFIG_VIRTUAL_BUS=y CONFIG_NET=y CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_BSD_PROCESS_ACCT=y CONFIG_SYSCTL=y CONFIG_NWFPE=y CONFIG_KCORE_ELF=y @@ -80,7 +85,7 @@ CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # CONFIG_PM is not set # CONFIG_ARTHUR is not set -CONFIG_CMDLINE="keepinitrd" +CONFIG_CMDLINE="console=ttyS0,38400" CONFIG_LEDS=y CONFIG_LEDS_TIMER=y CONFIG_LEDS_CPU=y @@ -126,7 +131,9 @@ CONFIG_UNIX=y CONFIG_INET=y # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set @@ -282,10 +289,11 @@ CONFIG_BLK_DEV_IDECS=y # # Character devices # -# CONFIG_VT is not set +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set CONFIG_SERIAL_SA1100=y CONFIG_SERIAL_SA1100_CONSOLE=y -# CONFIG_TOUCHSCREEN_UCB1200 is not set +CONFIG_TOUCHSCREEN_UCB1200=y # CONFIG_TOUCHSCREEN_BITSY is not set # CONFIG_SERIAL is not set # CONFIG_SERIAL_EXTENDED is not set @@ -329,9 +337,9 @@ CONFIG_UNIX98_PTY_COUNT=32 # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set +# CONFIG_AGP is not set # CONFIG_DRM is not set # CONFIG_PCMCIA_SERIAL is not set -# CONFIG_AGP is not set # # File systems @@ -345,6 +353,7 @@ CONFIG_UNIX98_PTY_COUNT=32 # CONFIG_BFS_FS is not set # CONFIG_FAT_FS is not set # CONFIG_EFS_FS is not set +CONFIG_JFFS_FS_VERBOSE=0 # CONFIG_CRAMFS is not set # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set @@ -367,6 +376,7 @@ CONFIG_EXT2_FS=y # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set # CONFIG_NFSD is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y @@ -376,36 +386,37 @@ CONFIG_LOCKD=y # # Partition Types # -CONFIG_PARTITION_ADVANCED=y -# CONFIG_ACORN_PARTITION is not set -# CONFIG_OSF_PARTITION is not set -# CONFIG_AMIGA_PARTITION is not set -# CONFIG_ATARI_PARTITION is not set -# CONFIG_MAC_PARTITION is not set +# CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_UNIXWARE_DISKLABEL is not set -# CONFIG_SGI_PARTITION is not set -# CONFIG_ULTRIX_PARTITION is not set -# CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set # +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_FB=y + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_FB_SA1100=y +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB2=y +CONFIG_FBCON_CFB4=y +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# # Sound # -CONFIG_SOUND=y -# CONFIG_SOUND_CMPCI is not set -# CONFIG_SOUND_EMU10K1 is not set -# CONFIG_SOUND_ES1370 is not set -# CONFIG_SOUND_ES1371 is not set -# CONFIG_SOUND_ESSSOLO1 is not set -# CONFIG_SOUND_MAESTRO is not set -# CONFIG_SOUND_SONICVIBES is not set -# CONFIG_SOUND_TRIDENT is not set -# CONFIG_SOUND_MSNDCLAS is not set -# CONFIG_SOUND_MSNDPIN is not set -# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND is not set # # USB support diff --git a/arch/arm/def-configs/ebsa110 b/arch/arm/def-configs/ebsa110 index c2c7e0dcc..8f7981934 100644 --- a/arch/arm/def-configs/ebsa110 +++ b/arch/arm/def-configs/ebsa110 @@ -1,53 +1,79 @@ # -# Automatically generated by make menuconfig: don't edit +# Automatically generated make config: don't edit # CONFIG_ARM=y +# CONFIG_EISA is not set # CONFIG_SBUS is not set +# CONFIG_MCA is not set CONFIG_UID16=y # # Code maturity level options # CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y # # System Type # -# CONFIG_ARCH_ARC is not set -# CONFIG_ARCH_A5K is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set # CONFIG_ARCH_CO285 is not set CONFIG_ARCH_EBSA110=y # CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_RPC is not set # CONFIG_ARCH_SA1100 is not set -CONFIG_CPU_32=y -# CONFIG_CPU_26 is not set -CONFIG_CPU_32v4=y -CONFIG_CPU_SA110=y +# CONFIG_ARCH_CLPS711X is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Footbridge Implementations +# + +# +# SA11x0 Implementations +# + +# +# CLPS711X/EP721X Implementations +# # CONFIG_ARCH_ACORN is not set # CONFIG_FOOTBRIDGE is not set # CONFIG_FOOTBRIDGE_HOST is not set # CONFIG_FOOTBRIDGE_ADDIN is not set -# CONFIG_DISCONTIGMEM is not set -# CONFIG_PCI is not set -# CONFIG_ISA is not set -# CONFIG_ISA_DMA is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set # -# Loadable module support +# Processor Type # -CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -CONFIG_KMOD=y +CONFIG_CPU_32v4=y +CONFIG_CPU_SA110=y +# CONFIG_DISCONTIGMEM is not set # # General setup # +# CONFIG_ANGELBOOT is not set +# CONFIG_PCI is not set +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set CONFIG_NET=y CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_BSD_PROCESS_ACCT=y CONFIG_SYSCTL=y # CONFIG_NWFPE is not set CONFIG_KCORE_ELF=y @@ -55,6 +81,7 @@ CONFIG_KCORE_ELF=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set # CONFIG_ARTHUR is not set CONFIG_CMDLINE="root=/dev/nfs rw mem=16M console=ttyS1,38400n8" CONFIG_LEDS=y @@ -66,7 +93,7 @@ CONFIG_LEDS_TIMER=y CONFIG_PARPORT=y CONFIG_PARPORT_PC=y CONFIG_PARPORT_PC_FIFO=y -CONFIG_PARPORT_PC_SUPERIO=y +# CONFIG_PARPORT_PC_SUPERIO is not set # CONFIG_PARPORT_ARC is not set # CONFIG_PARPORT_AMIGA is not set # CONFIG_PARPORT_MFC3 is not set @@ -76,6 +103,11 @@ CONFIG_PARPORT_PC_SUPERIO=y CONFIG_PARPORT_1284=y # +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# # Plug and Play configuration # # CONFIG_PNP is not set @@ -88,15 +120,12 @@ CONFIG_PARPORT_1284=y # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_LVM is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_RAID15_DANGEROUS is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 # CONFIG_BLK_DEV_INITRD is not set # @@ -126,14 +155,12 @@ CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set -CONFIG_IP_ALIAS=y # CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y -# CONFIG_SKB_LARGE is not set # # IP: Netfilter Configuration @@ -164,9 +191,25 @@ CONFIG_IP_NF_TARGET_LOG=m CONFIG_IP_NF_COMPAT_IPCHAINS=m CONFIG_IP_NF_NAT_NEEDED=y # CONFIG_IP_NF_COMPAT_IPFWADM is not set -# CONFIG_IPV6 is not set +CONFIG_IPV6=m +CONFIG_IPV6_EUI64=y +# CONFIG_IPV6_NO_PB is not set + +# +# IPv6: Netfilter Configuration +# +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MARK=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m # CONFIG_KHTTPD is not set # CONFIG_ATM is not set + +# +# +# # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set @@ -174,6 +217,7 @@ CONFIG_IP_NF_NAT_NEEDED=y # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set @@ -196,6 +240,7 @@ CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -217,8 +262,9 @@ CONFIG_ARM_AM79C961A=y # # Ethernet (1000 Mbit) # -# CONFIG_YELLOWFIN is not set # CONFIG_ACENIC is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set @@ -287,6 +333,11 @@ CONFIG_PPP_BSDCOMP=m # CONFIG_ISDN is not set # +# Input core support +# +# CONFIG_INPUT is not set + +# # Character devices # # CONFIG_VT is not set @@ -299,7 +350,8 @@ CONFIG_SERIAL_EXTENDED=y # CONFIG_SERIAL_MULTIPORT is not set # CONFIG_HUB6 is not set # CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_UNIX98_PTYS is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 CONFIG_PRINTER=m # CONFIG_LP_CONSOLE is not set # CONFIG_PPDEV is not set @@ -319,6 +371,10 @@ CONFIG_PRINTER=m # Joysticks # # CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # @@ -326,19 +382,17 @@ CONFIG_PRINTER=m # CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set +CONFIG_SOFT_WATCHDOG=y # CONFIG_WDT is not set # CONFIG_WDTPCI is not set -CONFIG_SOFT_WATCHDOG=y # CONFIG_PCWATCHDOG is not set # CONFIG_ACQUIRE_WDT is not set +# CONFIG_60XX_WDT is not set # CONFIG_MIXCOMWD is not set +# CONFIG_I810_TCO is not set +# CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -347,9 +401,13 @@ CONFIG_SOFT_WATCHDOG=y # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems @@ -367,6 +425,7 @@ CONFIG_AUTOFS4_FS=y # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set @@ -400,7 +459,6 @@ CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y # CONFIG_NFSD is not set # CONFIG_NFSD_V3 is not set -# CONFIG_NFSD_TCP is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set @@ -427,6 +485,7 @@ CONFIG_PARTITION_ADVANCED=y # CONFIG_MAC_PARTITION is not set # CONFIG_MSDOS_PARTITION is not set # CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set @@ -438,7 +497,7 @@ CONFIG_PARTITION_ADVANCED=y # # Kernel hacking # -# CONFIG_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set diff --git a/arch/arm/def-configs/footbridge b/arch/arm/def-configs/footbridge index af2ccd01a..255c99945 100644 --- a/arch/arm/def-configs/footbridge +++ b/arch/arm/def-configs/footbridge @@ -2,54 +2,82 @@ # Automatically generated make config: don't edit # CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set CONFIG_UID16=y # # Code maturity level options # CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set # -# System and Processor Type +# Loadable module support # -# CONFIG_ARCH_ARC is not set -# CONFIG_ARCH_A5K is not set -# CONFIG_ARCH_RPC is not set +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -CONFIG_FOOTBRIDGE=y -CONFIG_HOST_FOOTBRIDGE=y -# CONFIG_ADDIN_FOOTBRIDGE is not set +CONFIG_ARCH_FOOTBRIDGE=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_CLPS711X is not set + +# +# Archimedes/A5000 Implementations +# # # Footbridge Implementations # -CONFIG_ARCH_EBSA285=y # CONFIG_ARCH_CATS is not set -CONFIG_ARCH_NETWINDER=y # CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +CONFIG_ARCH_EBSA285_HOST=y +CONFIG_ARCH_NETWINDER=y + +# +# SA11x0 Implementations +# + +# +# CLPS711X/EP721X Implementations +# # CONFIG_ARCH_ACORN is not set +CONFIG_FOOTBRIDGE=y +CONFIG_FOOTBRIDGE_HOST=y +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_ARCH_EBSA285=y CONFIG_CPU_32=y # CONFIG_CPU_26 is not set -CONFIG_CPU_32v4=y -CONFIG_CPU_SA110=y -CONFIG_PCI=y -CONFIG_PCI_NAMES=y -CONFIG_ISA=y -CONFIG_ISA_DMA=y -# CONFIG_SBUS is not set -# CONFIG_PCMCIA is not set -CONFIG_ALIGNMENT_TRAP=y # -# Loadable module support +# Processor Type # -CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -CONFIG_KMOD=y +CONFIG_CPU_32v4=y +CONFIG_CPU_SA110=y +# CONFIG_DISCONTIGMEM is not set # # General setup # +# CONFIG_ANGELBOOT is not set +CONFIG_PCI=y +CONFIG_ISA=y +CONFIG_ISA_DMA=y +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set CONFIG_NET=y CONFIG_SYSVIPC=y CONFIG_BSD_PROCESS_ACCT=y @@ -60,7 +88,12 @@ CONFIG_KCORE_ELF=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set # CONFIG_ARTHUR is not set +CONFIG_LEDS=y +CONFIG_LEDS_TIMER=y +# CONFIG_LEDS_CPU is not set +CONFIG_ALIGNMENT_TRAP=y # # Parallel port support @@ -76,25 +109,11 @@ CONFIG_PARPORT_PC_FIFO=y # CONFIG_PARPORT_SUNBPP is not set # CONFIG_PARPORT_OTHER is not set CONFIG_PARPORT_1284=y -CONFIG_CMDLINE="root=/dev/hda1 ro mem=32M parport=0x378,7 ide0=autotune" -CONFIG_LEDS=y -CONFIG_LEDS_TIMER=y -# CONFIG_LEDS_CPU is not set # -# IEEE 1394 (FireWire) support +# Memory Technology Devices (MTD) # -# CONFIG_IEEE1394 is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set +# CONFIG_MTD is not set # # Plug and Play configuration @@ -137,185 +156,13 @@ CONFIG_PARIDE_KTTI=m CONFIG_PARIDE_ON20=m CONFIG_PARIDE_ON26=m # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m -# CONFIG_BLK_DEV_LVM is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_RAID15_DANGEROUS is not set CONFIG_BLK_DEV_RAM=y -# CONFIG_BLK_DEV_INITRD is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=y -CONFIG_SERIAL_CONSOLE=y -# CONFIG_SERIAL_EXTENDED is not set -CONFIG_SERIAL_NONSTANDARD=y -# CONFIG_COMPUTONE is not set -# CONFIG_ROCKETPORT is not set -# CONFIG_CYCLADES is not set -CONFIG_SERIAL_21285=y -CONFIG_SERIAL_21285_CONSOLE=y -# CONFIG_DIGIEPCA is not set -# CONFIG_DIGI is not set -# CONFIG_ESPSERIAL is not set -# CONFIG_MOXA_INTELLIO is not set -# CONFIG_MOXA_SMARTIO is not set -# CONFIG_ISI is not set -# CONFIG_SYNCLINK is not set -# CONFIG_N_HDLC is not set -# CONFIG_RISCOM8 is not set -# CONFIG_SPECIALIX is not set -# CONFIG_SX is not set -# CONFIG_STALDRV is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 -CONFIG_PRINTER=m -# CONFIG_LP_CONSOLE is not set -# CONFIG_PPDEV is not set - -# -# I2C support -# -CONFIG_I2C=m -# CONFIG_I2C_ALGOBIT is not set -# CONFIG_I2C_ALGOPCF is not set -# CONFIG_I2C_CHARDEV is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -CONFIG_MOUSE=y -CONFIG_PSMOUSE=y -# CONFIG_82C710_MOUSE is not set -# CONFIG_PC110_PAD is not set - -# -# Joysticks -# -# CONFIG_JOYSTICK is not set -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -CONFIG_WATCHDOG=y -# CONFIG_WATCHDOG_NOWAYOUT is not set -# CONFIG_WDT is not set -# CONFIG_WDTPCI is not set -CONFIG_SOFT_WATCHDOG=y -# CONFIG_PCWATCHDOG is not set -# CONFIG_ACQUIRE_WDT is not set -# CONFIG_MIXCOMWD is not set -CONFIG_21285_WATCHDOG=m -CONFIG_977_WATCHDOG=m -CONFIG_DS1620=y -CONFIG_NWBUTTON=y -CONFIG_NWBUTTON_REBOOT=y -CONFIG_NWFLASH=m -CONFIG_NVRAM=m -CONFIG_RTC=y - -# -# Video For Linux -# -CONFIG_VIDEO_DEV=y -# CONFIG_I2C_PARPORT is not set - -# -# Radio Adapters -# -# CONFIG_RADIO_CADET is not set -# CONFIG_RADIO_RTRACK is not set -# CONFIG_RADIO_RTRACK2 is not set -# CONFIG_RADIO_AZTECH is not set -# CONFIG_RADIO_GEMTEK is not set -# CONFIG_RADIO_MIROPCM20 is not set -# CONFIG_RADIO_SF16FMI is not set -# CONFIG_RADIO_TERRATEC is not set -# CONFIG_RADIO_TRUST is not set -# CONFIG_RADIO_TYPHOON is not set -# CONFIG_RADIO_ZOLTRIX is not set - -# -# Video Adapters -# -# CONFIG_VIDEO_PMS is not set -# CONFIG_VIDEO_BWQCAM is not set -# CONFIG_VIDEO_CQCAM is not set -# CONFIG_VIDEO_CPIA is not set -# CONFIG_VIDEO_SAA5249 is not set -# CONFIG_TUNER_3036 is not set -# CONFIG_VIDEO_STRADIS is not set -# CONFIG_VIDEO_ZORAN is not set -# CONFIG_VIDEO_BUZ is not set -# CONFIG_VIDEO_ZR36120 is not set -CONFIG_VIDEO_CYBERPRO=m -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set -# CONFIG_AGP is not set - -# -# Console drivers -# -CONFIG_VGA_CONSOLE=y -CONFIG_FB=y - -# -# Frame-buffer support -# -CONFIG_FB=y -CONFIG_DUMMY_CONSOLE=y -# CONFIG_FB_RIVA is not set -# CONFIG_FB_CLGEN is not set -# CONFIG_FB_PM2 is not set -CONFIG_FB_CYBER2000=y -# CONFIG_FB_MATROX is not set -# CONFIG_FB_ATY is not set -# CONFIG_FB_ATY128 is not set -# CONFIG_FB_3DFX is not set -# CONFIG_FB_VIRTUAL is not set -CONFIG_FBCON_ADVANCED=y -# CONFIG_FBCON_MFB is not set -# CONFIG_FBCON_CFB2 is not set -# CONFIG_FBCON_CFB4 is not set -CONFIG_FBCON_CFB8=y -CONFIG_FBCON_CFB16=y -CONFIG_FBCON_CFB24=y -# CONFIG_FBCON_CFB32 is not set -# CONFIG_FBCON_AFB is not set -# CONFIG_FBCON_ILBM is not set -# CONFIG_FBCON_IPLAN2P2 is not set -# CONFIG_FBCON_IPLAN2P4 is not set -# CONFIG_FBCON_IPLAN2P8 is not set -# CONFIG_FBCON_MAC is not set -# CONFIG_FBCON_VGA_PLANES is not set -CONFIG_FBCON_VGA=y -# CONFIG_FBCON_HGA is not set -# CONFIG_FBCON_FONTWIDTH8_ONLY is not set -CONFIG_FBCON_FONTS=y -# CONFIG_FONT_8x8 is not set -# CONFIG_FONT_8x16 is not set -# CONFIG_FONT_SUN8x16 is not set -# CONFIG_FONT_SUN12x22 is not set -# CONFIG_FONT_6x11 is not set -# CONFIG_FONT_PEARL_8x8 is not set -CONFIG_FONT_ACORN_8x8=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y # # Networking options @@ -327,24 +174,21 @@ CONFIG_PACKET_MMAP=y # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set +CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -CONFIG_IP_ALIAS=y +# CONFIG_IP_MROUTE is not set +# CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y - -# -# (it is safe to leave these untouched) -# -# CONFIG_SKB_LARGE is not set # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set -# CONFIG_ATM is not set +CONFIG_ATM=y +# CONFIG_ATM_CLIP is not set +# CONFIG_ATM_LANE is not set # # @@ -352,10 +196,11 @@ CONFIG_SYN_COOKIES=y # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set @@ -367,55 +212,6 @@ CONFIG_SYN_COOKIES=y # CONFIG_NET_SCHED is not set # -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -CONFIG_IRDA=m - -# -# IrDA protocols -# -CONFIG_IRLAN=m -CONFIG_IRCOMM=m -CONFIG_IRDA_ULTRA=y -CONFIG_IRDA_OPTIONS=y - -# -# IrDA options -# -CONFIG_IRDA_CACHE_LAST_LSAP=y -CONFIG_IRDA_FAST_RR=y -# CONFIG_IRDA_DEBUG is not set -# CONFIG_IRDA_COMPRESSION is not set - -# -# Infrared-port device drivers -# - -# -# SIR device drivers -# -# CONFIG_IRTTY_SIR is not set -# CONFIG_IRPORT_SIR is not set - -# -# FIR device drivers -# -# CONFIG_NSC_FIR is not set -CONFIG_WINBOND_FIR=m -# CONFIG_TOSHIBA_FIR is not set -# CONFIG_SMC_IRCC_FIR is not set - -# -# Dongle support -# -# CONFIG_DONGLE is not set - -# # Network device support # CONFIG_NETDEVICES=y @@ -427,13 +223,13 @@ CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y -# CONFIG_ARM_AM79C961A is not set CONFIG_NET_VENDOR_3COM=y # CONFIG_EL1 is not set # CONFIG_EL2 is not set @@ -441,12 +237,15 @@ CONFIG_NET_VENDOR_3COM=y # CONFIG_EL16 is not set # CONFIG_EL3 is not set # CONFIG_3C515 is not set +# CONFIG_ELMC is not set +# CONFIG_ELMC_II is not set CONFIG_VORTEX=y # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set +# CONFIG_HP100 is not set # CONFIG_NET_ISA is not set CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set @@ -454,28 +253,34 @@ CONFIG_NET_PCI=y # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set -# CONFIG_DE4X5 is not set CONFIG_TULIP=m +# CONFIG_DE4X5 is not set # CONFIG_DGRS is not set # CONFIG_DM9102 is not set # CONFIG_EEPRO100 is not set +# CONFIG_EEPRO100_PM is not set # CONFIG_LNE390 is not set -# CONFIG_NE3210 is not set +# CONFIG_NATSEMI is not set CONFIG_NE2K_PCI=y -# CONFIG_RTL8129 is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set # CONFIG_8139TOO is not set +# CONFIG_RTL8129 is not set # CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set -# CONFIG_ES3210 is not set -# CONFIG_EPIC100 is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_HAPPYMEAL is not set # CONFIG_NET_POCKET is not set # # Ethernet (1000 Mbit) # -# CONFIG_YELLOWFIN is not set # CONFIG_ACENIC is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set @@ -511,6 +316,55 @@ CONFIG_SLIP_MODE_SLIP6=y # CONFIG_WAN is not set # +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +CONFIG_IRDA_ULTRA=y +CONFIG_IRDA_OPTIONS=y + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_DEBUG=y + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +# CONFIG_IRTTY_SIR is not set +# CONFIG_IRPORT_SIR is not set + +# +# FIR device drivers +# +# CONFIG_NSC_FIR is not set +CONFIG_WINBOND_FIR=m +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# # ATA/IDE/MFM/RLL support # CONFIG_IDE=y @@ -527,6 +381,15 @@ CONFIG_BLK_DEV_IDE=y # CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDEDISK=y CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set # CONFIG_BLK_DEV_IDECS is not set # CONFIG_BLK_DEV_IDECD is not set # CONFIG_BLK_DEV_IDETAPE is not set @@ -546,7 +409,6 @@ CONFIG_BLK_DEV_IDEDMA_PCI=y CONFIG_BLK_DEV_OFFBOARD=y CONFIG_IDEDMA_PCI_AUTO=y CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set # CONFIG_BLK_DEV_AEC62XX is not set @@ -556,26 +418,25 @@ CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_BLK_DEV_AMD7409 is not set # CONFIG_AMD7409_OVERRIDE is not set # CONFIG_BLK_DEV_CMD64X is not set -# CONFIG_CMD64X_RAID is not set CONFIG_BLK_DEV_CY82C693=y # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_HPT34X_AUTODMA is not set # CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_HPT366_FIP is not set -# CONFIG_HPT366_MODE3 is not set # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set CONFIG_BLK_DEV_PDC202XX=y # CONFIG_PDC202XX_BURST is not set -# CONFIG_PDC202XX_MASTER is not set +# CONFIG_BLK_DEV_OSB4 is not set # CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set -# CONFIG_VIA82CXXX_TUNING is not set CONFIG_BLK_DEV_SL82C105=y # CONFIG_IDE_CHIPSETS is not set CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set CONFIG_BLK_DEV_IDE_MODES=y # @@ -584,52 +445,164 @@ CONFIG_BLK_DEV_IDE_MODES=y # CONFIG_SCSI is not set # -# Sound +# IEEE 1394 (FireWire) support # -CONFIG_SOUND=m -# CONFIG_SOUND_CMPCI is not set -# CONFIG_SOUND_EMU10K1 is not set -# CONFIG_SOUND_ES1370 is not set -# CONFIG_SOUND_ES1371 is not set -# CONFIG_SOUND_ESSSOLO1 is not set -# CONFIG_SOUND_MAESTRO is not set -# CONFIG_SOUND_SONICVIBES is not set -# CONFIG_SOUND_TRIDENT is not set -# CONFIG_SOUND_MSNDCLAS is not set -# CONFIG_SOUND_MSNDPIN is not set -# CONFIG_SOUND_VIA82CXXX is not set -CONFIG_SOUND_OSS=m -# CONFIG_SOUND_TRACEINIT is not set -# CONFIG_SOUND_DMAP is not set -# CONFIG_SOUND_AD1816 is not set -# CONFIG_SOUND_SGALAXY is not set -CONFIG_SOUND_ADLIB=m -# CONFIG_SOUND_ACI_MIXER is not set -# CONFIG_SOUND_CS4232 is not set -# CONFIG_SOUND_SSCAPE is not set -# CONFIG_SOUND_GUS is not set -# CONFIG_SOUND_ICH is not set -# CONFIG_SOUND_VMIDI is not set -# CONFIG_SOUND_TRIX is not set -# CONFIG_SOUND_MSS is not set -# CONFIG_SOUND_MPU401 is not set -# CONFIG_SOUND_NM256 is not set -# CONFIG_SOUND_MAD16 is not set -# CONFIG_SOUND_PAS is not set -# CONFIG_PAS_JOYSTICK is not set -# CONFIG_SOUND_PSS is not set -# CONFIG_SOUND_SOFTOSS is not set -CONFIG_SOUND_SB=m -# CONFIG_SOUND_AWE32_SYNTH is not set -# CONFIG_SOUND_WAVEFRONT is not set -# CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_YM3812 is not set -# CONFIG_SOUND_OPL3SA1 is not set -# CONFIG_SOUND_OPL3SA2 is not set -# CONFIG_SOUND_UART6850 is not set -# CONFIG_SOUND_AEDSP16 is not set -# CONFIG_SOUND_VIDC is not set -CONFIG_SOUND_WAVEARTIST=m +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_DIGI is not set +# CONFIG_ESPSERIAL is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_ISI is not set +# CONFIG_SYNCLINK is not set +# CONFIG_N_HDLC is not set +# CONFIG_RISCOM8 is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +# CONFIG_STALDRV is not set +CONFIG_SERIAL_21285=y +CONFIG_SERIAL_21285_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_PRINTER=m +# CONFIG_LP_CONSOLE is not set +# CONFIG_PPDEV is not set + +# +# I2C support +# +CONFIG_I2C=m +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_CHARDEV is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +CONFIG_SOFT_WATCHDOG=y +# CONFIG_WDT is not set +# CONFIG_WDTPCI is not set +# CONFIG_PCWATCHDOG is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_60XX_WDT is not set +# CONFIG_MIXCOMWD is not set +# CONFIG_I810_TCO is not set +CONFIG_21285_WATCHDOG=m +CONFIG_977_WATCHDOG=m +CONFIG_DS1620=y +CONFIG_NWBUTTON=y +CONFIG_NWBUTTON_REBOOT=y +CONFIG_NWFLASH=m +# CONFIG_INTEL_RNG is not set +CONFIG_NVRAM=m +CONFIG_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# +CONFIG_VIDEO_PROC_FS=y +# CONFIG_I2C_PARPORT is not set + +# +# Video Adapters +# +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_BWQCAM is not set +# CONFIG_VIDEO_CQCAM is not set +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_STRADIS is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_BUZ is not set +# CONFIG_VIDEO_ZR36120 is not set +CONFIG_VIDEO_CYBERPRO=m + +# +# Radio Adapters +# +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_MAESTRO is not set +# CONFIG_RADIO_MIROPCM20 is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set # # File systems @@ -647,6 +620,7 @@ CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=m # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=m @@ -713,12 +687,14 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set CONFIG_NLS=y # # Native Language Support # +CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_NLS_CODEPAGE_437=m # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set @@ -735,6 +711,10 @@ CONFIG_NLS_CODEPAGE_852=m # CONFIG_NLS_CODEPAGE_866 is not set # CONFIG_NLS_CODEPAGE_869 is not set # CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set CONFIG_NLS_ISO8859_1=m CONFIG_NLS_ISO8859_2=m # CONFIG_NLS_ISO8859_3 is not set @@ -747,6 +727,110 @@ CONFIG_NLS_ISO8859_2=m # CONFIG_NLS_ISO8859_14 is not set CONFIG_NLS_ISO8859_15=m # CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +CONFIG_PC_KEYB=y +CONFIG_PC_KEYMAP=y +CONFIG_VGA_CONSOLE=y +CONFIG_FB=y + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_RIVA is not set +# CONFIG_FB_CLGEN is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_ACORN is not set +# CONFIG_FB_CLPS711X is not set +CONFIG_FB_CYBER2000=y +# CONFIG_FB_SA1100 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +CONFIG_FBCON_VGA=y +# CONFIG_FBCON_HGA is not set +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +# CONFIG_FONT_8x8 is not set +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +CONFIG_FONT_ACORN_8x8=y + +# +# Sound +# +CONFIG_SOUND=m +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +CONFIG_SOUND_OSS=m +# CONFIG_SOUND_TRACEINIT is not set +# CONFIG_SOUND_DMAP is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_SGALAXY is not set +CONFIG_SOUND_ADLIB=m +# CONFIG_SOUND_ACI_MIXER is not set +# CONFIG_SOUND_CS4232 is not set +# CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_NM256 is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_PAS is not set +# CONFIG_PAS_JOYSTICK is not set +# CONFIG_SOUND_PSS is not set +CONFIG_SOUND_SB=m +# CONFIG_SOUND_AWE32_SYNTH is not set +# CONFIG_SOUND_WAVEFRONT is not set +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_YM3812 is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_YMPCI is not set +# CONFIG_SOUND_UART6850 is not set +# CONFIG_SOUND_AEDSP16 is not set +CONFIG_SOUND_WAVEARTIST=m +# CONFIG_SOUND_TVMIXER is not set # # USB support @@ -757,7 +841,8 @@ CONFIG_USB_DEBUG=y # # Miscellaneous USB options # -# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set # # USB Controllers @@ -770,7 +855,8 @@ CONFIG_USB_OHCI=m # USB Devices # CONFIG_USB_PRINTER=m -CONFIG_USB_SCANNER=m +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set CONFIG_USB_AUDIO=m # CONFIG_USB_ACM is not set # CONFIG_USB_SERIAL is not set @@ -785,19 +871,16 @@ CONFIG_USB_AUDIO=m # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_DSBR is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_NET1080 is not set + +# +# USB Human Interface Devices (HID) +# # -# USB HID +# Input core support is needed for USB HID # -# CONFIG_USB_HID is not set -CONFIG_USB_KBD=m -CONFIG_USB_MOUSE=m -# CONFIG_USB_WACOM is not set -# CONFIG_USB_WMFORCE is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set # # Kernel hacking diff --git a/arch/arm/def-configs/graphicsclient b/arch/arm/def-configs/graphicsclient index 11415b363..92079d370 100644 --- a/arch/arm/def-configs/graphicsclient +++ b/arch/arm/def-configs/graphicsclient @@ -2,48 +2,88 @@ # Automatically generated make config: don't edit # CONFIG_ARM=y +# CONFIG_SBUS is not set +CONFIG_UID16=y # # Code maturity level options # CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set # -# System and processor type +# Loadable module support # -# CONFIG_ARCH_ARC is not set -# CONFIG_ARCH_A5K is not set -# CONFIG_ARCH_RPC is not set +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_FOOTBRIDGE is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_RPC is not set CONFIG_ARCH_SA1100=y + +# +# Archimedes/A5000 Implementations +# + +# +# Footbridge Implementations +# + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set # CONFIG_SA1100_BRUTUS is not set -# CONFIG_SA1100_EMPEG is not set -# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_BITSY is not set # CONFIG_SA1100_LART is not set -# CONFIG_SA1100_PLEB is not set CONFIG_SA1100_GRAPHICSCLIENT=y +# CONFIG_SA1100_NANOENGINE is not set # CONFIG_SA1100_VICTOR is not set -# CONFIG_SA1100_TIFON is not set -CONFIG_DISCONTIGMEM=y +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_ANGELBOOT is not set +# CONFIG_SA1100_FREQUENCY_SCALE is not set +# CONFIG_SA1100_VOLTAGE_SCALE is not set # CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set CONFIG_CPU_32=y # CONFIG_CPU_26 is not set + +# +# Processor Type +# CONFIG_CPU_32v4=y CONFIG_CPU_SA1100=y -# CONFIG_ISA_DMA is not set -CONFIG_ALIGNMENT_TRAP=y +CONFIG_DISCONTIGMEM=y # -# Loadable module support +# General setup # -CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -# CONFIG_KMOD is not set +# CONFIG_PCI is not set +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +CONFIG_PC_KEYMAP=y +CONFIG_HOTPLUG=y # -# General setup +# PCMCIA/CardBus support # +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_SA1100_PCMCIA=y +CONFIG_VIRTUAL_BUS=y CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set @@ -51,22 +91,24 @@ CONFIG_SYSCTL=y CONFIG_NWFPE=y CONFIG_KCORE_ELF=y # CONFIG_KCORE_AOUT is not set -CONFIG_BINFMT_AOUT=y +# CONFIG_BINFMT_AOUT is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set # CONFIG_ARTHUR is not set +CONFIG_CMDLINE="root=nfs" +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# # CONFIG_PARPORT is not set -CONFIG_CMDLINE="ip=off" # -# I2O device support +# Memory Technology Devices (MTD) # -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set +# CONFIG_MTD is not set # # Plug and Play configuration @@ -78,118 +120,28 @@ CONFIG_CMDLINE="ip=off" # Block devices # # CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_IDE is not set - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_ONLY is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set # CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_BLK_DEV_INITRD=y -# CONFIG_BLK_DEV_XD is not set -CONFIG_PARIDE_PARPORT=y -# CONFIG_PARIDE is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_HD is not set - -# -# Character devices -# -CONFIG_VT=y -# CONFIG_VT_CONSOLE is not set -CONFIG_SERIAL_SA1100=y -CONFIG_SERIAL_SA1100_CONSOLE=y -# CONFIG_SERIAL is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=32 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_JOYSTICK is not set -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set - -# -# PCMCIA character device support -# -# CONFIG_AGP is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# Console drivers -# -# CONFIG_VGA_CONSOLE is not set -CONFIG_FB=y - -# -# Frame-buffer support -# -CONFIG_FB=y -CONFIG_DUMMY_CONSOLE=y -CONFIG_FB_SA1100=y -# CONFIG_FB_MATROX is not set -# CONFIG_FB_ATY is not set -# CONFIG_FB_ATY128 is not set -# CONFIG_FB_3DFX is not set -# CONFIG_FB_VIRTUAL is not set -# CONFIG_FBCON_ADVANCED is not set -CONFIG_FBCON_CFB2=y -CONFIG_FBCON_CFB4=y -CONFIG_FBCON_CFB8=y -CONFIG_FBCON_FONTWIDTH8_ONLY=y -CONFIG_FBCON_FONTS=y -# CONFIG_FONT_8x8 is not set -CONFIG_FONT_8x16=y -# CONFIG_FONT_SUN8x16 is not set -# CONFIG_FONT_PEARL_8x8 is not set -# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_BLK_DEV_FLASH is not set # # Networking options # -# CONFIG_PACKET is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set # CONFIG_NETLINK is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -200,16 +152,10 @@ CONFIG_INET=y CONFIG_IP_PNP=y CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set +# CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set - -# -# (it is safe to leave these untouched) -# -CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set @@ -220,9 +166,9 @@ CONFIG_SKB_LARGE=y # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set # CONFIG_LLC is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -235,16 +181,6 @@ CONFIG_SKB_LARGE=y # CONFIG_NET_SCHED is not set # -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# # Network device support # CONFIG_NETDEVICES=y @@ -254,7 +190,9 @@ CONFIG_NETDEVICES=y # # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set +# CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_NET_SB1000 is not set # @@ -270,12 +208,10 @@ CONFIG_NET_VENDOR_SMC=y # CONFIG_ULTRA32 is not set CONFIG_SMC9194=y # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_RTL8139 is not set -# CONFIG_DM9102 is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set -# CONFIG_NET_EISA is not set +# CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set # @@ -295,7 +231,7 @@ CONFIG_SMC9194=y # CONFIG_NET_RADIO is not set # -# Token Ring driver support +# Token Ring devices # # CONFIG_TR is not set # CONFIG_NET_FC is not set @@ -310,7 +246,70 @@ CONFIG_SMC9194=y # # PCMCIA network device support # -# CONFIG_NET_PCMCIA is not set +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=m +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +# CONFIG_NET_PCMCIA_RADIO is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=m + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +CONFIG_BLK_DEV_IDECS=m +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set # # SCSI support @@ -318,54 +317,221 @@ CONFIG_SMC9194=y # CONFIG_SCSI is not set # -# Filesystems +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Character devices +# +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_SA1100_DEFAULT_BAUDRATE=38400 +# CONFIG_TOUCHSCREEN_UCB1200 is not set +# CONFIG_TOUCHSCREEN_BITSY is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=32 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_PCMCIA_SERIAL is not set + +# +# File systems # # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set # CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set +CONFIG_VFAT_FS=m # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set +CONFIG_RAMFS=y # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set # # Network File Systems # # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y # CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set # # Partition Types # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -# CONFIG_SGI_PARTITION is not set -# CONFIG_SUN_PARTITION is not set -# CONFIG_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_FB=y + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_CYBER2000 is not set +CONFIG_FB_SA1100=y +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB2=y +CONFIG_FBCON_CFB4=y +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_FONTWIDTH8_ONLY=y +CONFIG_FBCON_FONTS=y +# CONFIG_FONT_8x8 is not set +CONFIG_FONT_8x16=y +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set # # Kernel hacking @@ -373,6 +539,6 @@ CONFIG_MSDOS_PARTITION=y CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y -CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_DEBUG_LL is not set diff --git a/arch/arm/def-configs/integrator b/arch/arm/def-configs/integrator new file mode 100644 index 000000000..07133bff5 --- /dev/null +++ b/arch/arm/def-configs/integrator @@ -0,0 +1,511 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# System Type +# +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +CONFIG_ARCH_INTEGRATOR=y +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_CLPS711X is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Footbridge Implementations +# + +# +# SA11x0 Implementations +# + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set + +# +# Processor Type +# +CONFIG_CPU_32v4=y +CONFIG_CPU_ARM720=y +CONFIG_CPU_ARM920=y +CONFIG_CPU_ARM920_CPU_IDLE=y +CONFIG_CPU_ARM920_I_CACHE_ON=y +CONFIG_CPU_ARM920_D_CACHE_ON=y +# CONFIG_CPU_ARM920_WRITETHROUGH is not set +# CONFIG_DISCONTIGMEM is not set + +# +# General setup +# +# CONFIG_ANGELBOOT is not set +CONFIG_PCI_INTEGRATOR=y +CONFIG_PCI=y +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_NWFPE=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="root=1f04 mem=32M" +CONFIG_LEDS=y +CONFIG_LEDS_TIMER=y +CONFIG_LEDS_CPU=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_MTDRAM is not set + +# +# MTD drivers for mapped chips +# +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_JEDEC is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_PHYSMAP is not set + +# +# Drivers for chip mappings +# +# CONFIG_MTD_MIXMEM is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_OCTAGON is not set +# CONFIG_MTD_PNC2000 is not set +# CONFIG_MTD_RPXLITE is not set +# CONFIG_MTD_VMAX is not set + +# +# User modules and translation layers for MTD devices +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +CONFIG_MTD_ARM=y + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_TULIP=y +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +CONFIG_EEPRO100_PM=y +# CONFIG_LNE390 is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139TOO is not set +# CONFIG_RTL8129 is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_SERIAL_AMBA=y +CONFIG_SERIAL_INTEGRATOR=y +CONFIG_SERIAL_AMBA_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=y +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Console drivers +# +CONFIG_KMI_KEYB=y +CONFIG_PC_KEYMAP=y +CONFIG_VGA_CONSOLE=y +# CONFIG_FB is not set + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_LL=y diff --git a/arch/arm/def-configs/neponset b/arch/arm/def-configs/neponset new file mode 100644 index 000000000..b77cbd143 --- /dev/null +++ b/arch/arm/def-configs/neponset @@ -0,0 +1,576 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_SBUS is not set +CONFIG_UID16=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_RPC is not set +CONFIG_ARCH_SA1100=y + +# +# Archimedes/A5000 Implementations +# + +# +# Footbridge Implementations +# + +# +# SA11x0 Implementations +# +CONFIG_SA1100_ASSABET=y +CONFIG_ASSABET_NEPONSET=y +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_BITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_XP860 is not set +CONFIG_ANGELBOOT=y +CONFIG_SA1111=y +CONFIG_SA1100_FREQUENCY_SCALE=y +# CONFIG_SA1100_VOLTAGE_SCALE is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set + +# +# Processor Type +# +CONFIG_CPU_32v4=y +CONFIG_CPU_SA1100=y +CONFIG_DISCONTIGMEM=y + +# +# General setup +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +CONFIG_PC_KEYMAP=y +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_SA1100_PCMCIA=y +CONFIG_VIRTUAL_BUS=y +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_NWFPE=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="keepinitrd" +CONFIG_LEDS=y +CONFIG_LEDS_TIMER=y +CONFIG_LEDS_CPU=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_FLASH is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +CONFIG_NET_VENDOR_SMC=y +# CONFIG_WD80x3 is not set +# CONFIG_ULTRA is not set +# CONFIG_ULTRA32 is not set +CONFIG_SMC9194=y +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=y +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +# CONFIG_NET_PCMCIA_RADIO is not set +CONFIG_PCMCIA_NETCARD=y + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +CONFIG_BLK_DEV_IDECS=y +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Character devices +# +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_SA1100_DEFAULT_BAUDRATE=9600 +CONFIG_TOUCHSCREEN_UCB1200=y +# CONFIG_TOUCHSCREEN_BITSY is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=32 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_PCMCIA_SERIAL is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_FB=y + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_CYBER2000 is not set +CONFIG_FB_SA1100=y +# CONFIG_FB_MQ200 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB2=y +CONFIG_FBCON_CFB4=y +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_FONTWIDTH8_ONLY=y +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Sound +# +CONFIG_SOUND=y +CONFIG_SOUND_UDA1341=y +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_LL is not set diff --git a/arch/arm/def-configs/thinclient b/arch/arm/def-configs/pangolin index 5ad898616..6aebc40f8 100644 --- a/arch/arm/def-configs/thinclient +++ b/arch/arm/def-configs/pangolin @@ -1,57 +1,86 @@ # -# Automatically generated make config: don't edit +# Automatically generated by make menuconfig: don't edit # CONFIG_ARM=y +# CONFIG_SBUS is not set CONFIG_UID16=y # # Code maturity level options # CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set # -# System and processor type +# Loadable module support # -# CONFIG_ARCH_ARC is not set -# CONFIG_ARCH_A5K is not set -# CONFIG_ARCH_RPC is not set +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_FOOTBRIDGE is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_RPC is not set CONFIG_ARCH_SA1100=y + +# +# Archimedes/A5000 Implementations +# + +# +# Footbridge Implementations +# + +# +# SA11x0 Implementations +# # CONFIG_SA1100_ASSABET is not set # CONFIG_SA1100_BRUTUS is not set -# CONFIG_SA1100_EMPEG is not set -# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_CERF is not set # CONFIG_SA1100_BITSY is not set # CONFIG_SA1100_LART is not set -# CONFIG_SA1100_PLEB is not set -CONFIG_SA1100_THINCLIENT=y # CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_NANOENGINE is not set # CONFIG_SA1100_VICTOR is not set -# CONFIG_SA1100_TIFON is not set -CONFIG_DISCONTIGMEM=y +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_XP860 is not set +CONFIG_SA1100_PANGOLIN=y +# CONFIG_ANGELBOOT is not set +# CONFIG_SA1100_FREQUENCY_SCALE is not set +# CONFIG_SA1100_VOLTAGE_SCALE is not set # CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set CONFIG_CPU_32=y # CONFIG_CPU_26 is not set CONFIG_CPU_32v4=y CONFIG_CPU_SA1100=y -# CONFIG_PCI is not set -# CONFIG_ISA is not set -# CONFIG_ISA_DMA is not set -# CONFIG_SBUS is not set -# CONFIG_PCMCIA is not set -CONFIG_ALIGNMENT_TRAP=y +CONFIG_DISCONTIGMEM=y # -# Loadable module support +# General setup # -CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -# CONFIG_KMOD is not set +# CONFIG_PCI is not set +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +CONFIG_PC_KEYMAP=y +CONFIG_HOTPLUG=y # -# General setup +# PCMCIA/CardBus support # +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_SA1100_PCMCIA=y +CONFIG_VIRTUAL_BUS=y CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set @@ -59,26 +88,48 @@ CONFIG_SYSCTL=y CONFIG_NWFPE=y CONFIG_KCORE_ELF=y # CONFIG_KCORE_AOUT is not set -CONFIG_BINFMT_AOUT=y +# CONFIG_BINFMT_AOUT is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set # CONFIG_ARTHUR is not set +CONFIG_CMDLINE="keepinitrd" +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y # # Parallel port support # # CONFIG_PARPORT is not set -CONFIG_CMDLINE="root=nfs" -# CONFIG_LEDS is not set # -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_MTDRAM is not set +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_JEDEC is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_MIXMEM is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_OCTAGON is not set +# CONFIG_MTD_PNC2000 is not set +# CONFIG_MTD_RPXLITE is not set +# CONFIG_MTD_VMAX is not set +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set # # Plug and Play configuration @@ -94,95 +145,20 @@ CONFIG_CMDLINE="root=nfs" # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_LOOP is not set +CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_LVM is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set -# CONFIG_MD_STRIPED is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_FLASH=y # -# Character devices -# -CONFIG_VT=y -# CONFIG_VT_CONSOLE is not set -CONFIG_SERIAL_SA1100=y -CONFIG_SERIAL_SA1100_CONSOLE=y -# CONFIG_SERIAL is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=32 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_JOYSTICK is not set -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set -# CONFIG_AGP is not set - -# -# Console drivers -# -# CONFIG_VGA_CONSOLE is not set -CONFIG_FB=y - -# -# Frame-buffer support -# -CONFIG_FB=y -CONFIG_DUMMY_CONSOLE=y -CONFIG_FB_SA1100=y -# CONFIG_FB_VIRTUAL is not set -# CONFIG_FBCON_ADVANCED is not set -CONFIG_FBCON_CFB2=y -CONFIG_FBCON_CFB4=y -CONFIG_FBCON_CFB8=y -CONFIG_FBCON_FONTWIDTH8_ONLY=y -CONFIG_FBCON_FONTS=y -# CONFIG_FONT_8x8 is not set -CONFIG_FONT_8x16=y -# CONFIG_FONT_SUN8x16 is not set -# CONFIG_FONT_PEARL_8x8 is not set -# CONFIG_FONT_ACORN_8x8 is not set - -# # Networking options # CONFIG_PACKET=y @@ -194,32 +170,20 @@ CONFIG_UNIX=y CONFIG_INET=y # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IP_PNP_RARP is not set -# CONFIG_IP_ROUTER is not set +# CONFIG_IP_PNP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set +# CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set - -# -# (it is safe to leave these untouched) -# -CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set - -# -# -# # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set # CONFIG_LLC is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -232,16 +196,6 @@ CONFIG_SKB_LARGE=y # CONFIG_NET_SCHED is not set # -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# # Network device support # CONFIG_NETDEVICES=y @@ -250,9 +204,10 @@ CONFIG_NETDEVICES=y # ARCnet devices # # CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set +CONFIG_DUMMY=y # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_NET_SB1000 is not set # @@ -262,11 +217,7 @@ CONFIG_NET_ETHERNET=y # CONFIG_ARM_AM79C961A is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set -CONFIG_NET_VENDOR_SMC=y -# CONFIG_WD80x3 is not set -# CONFIG_ULTRA is not set -# CONFIG_ULTRA32 is not set -CONFIG_SMC9194=y +# CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set @@ -304,11 +255,65 @@ CONFIG_SMC9194=y # CONFIG_WAN is not set # +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=y +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +# CONFIG_NET_PCMCIA_RADIO is not set +CONFIG_PCMCIA_NETCARD=y + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# # ATA/IDE/MFM/RLL support # -# CONFIG_IDE is not set -# CONFIG_BLK_DEV_IDE_MODES is not set +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y +# CONFIG_BLK_DEV_HD_IDE is not set # CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +CONFIG_BLK_DEV_IDECS=y +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set # # SCSI support @@ -316,6 +321,72 @@ CONFIG_SMC9194=y # CONFIG_SCSI is not set # +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Character devices +# +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_SA1100_DEFAULT_BAUDRATE=115200 +# CONFIG_TOUCHSCREEN_UCB1200 is not set +# CONFIG_TOUCHSCREEN_BITSY is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=32 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_PCMCIA_SERIAL is not set + +# # File systems # # CONFIG_QUOTA is not set @@ -331,8 +402,10 @@ CONFIG_SMC9194=y # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set -# CONFIG_CRAMFS is not set -# CONFIG_RAMFS is not set +CONFIG_JFFS_FS=y +CONFIG_JFFS_FS_VERBOSE=1 +CONFIG_CRAMFS=y +CONFIG_RAMFS=y # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set @@ -361,7 +434,7 @@ CONFIG_EXT2_FS=y # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set -CONFIG_ROOT_NFS=y +# CONFIG_ROOT_NFS is not set # CONFIG_NFSD is not set # CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y @@ -387,6 +460,22 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_NLS is not set # +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_FB is not set + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# # USB support # # CONFIG_USB is not set @@ -397,6 +486,6 @@ CONFIG_MSDOS_PARTITION=y CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y -CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_DEBUG_LL is not set diff --git a/arch/arm/def-configs/rpc b/arch/arm/def-configs/rpc index afbfda2da..6d744d34d 100644 --- a/arch/arm/def-configs/rpc +++ b/arch/arm/def-configs/rpc @@ -2,45 +2,77 @@ # Automatically generated make config: don't edit # CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set CONFIG_UID16=y # # Code maturity level options # CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set # -# System and Processor Type +# Loadable module support # -# CONFIG_ARCH_ARC is not set -# CONFIG_ARCH_A5K is not set -CONFIG_ARCH_RPC=y +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_FOOTBRIDGE is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +CONFIG_ARCH_RPC=y +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_CLPS711X is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Footbridge Implementations +# + +# +# SA11x0 Implementations +# + +# +# CLPS711X/EP721X Implementations +# CONFIG_ARCH_ACORN=y +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set CONFIG_CPU_32=y # CONFIG_CPU_26 is not set + +# +# Processor Type +# CONFIG_CPU_32v3=y CONFIG_CPU_ARM6=y CONFIG_CPU_ARM7=y CONFIG_CPU_SA110=y -# CONFIG_PCI is not set -# CONFIG_ISA is not set -# CONFIG_ISA_DMA is not set -# CONFIG_SBUS is not set -# CONFIG_PCMCIA is not set -# CONFIG_ALIGNMENT_TRAP is not set - -# -# Loadable module support -# -CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -CONFIG_KMOD=y +# CONFIG_DISCONTIGMEM is not set # # General setup # +# CONFIG_ANGELBOOT is not set +# CONFIG_PCI is not set +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set @@ -51,7 +83,9 @@ CONFIG_KCORE_ELF=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set # CONFIG_ARTHUR is not set +# CONFIG_ALIGNMENT_TRAP is not set # # Parallel port support @@ -69,13 +103,9 @@ CONFIG_PARPORT_PC_SUPERIO=y # CONFIG_PARPORT_1284 is not set # -# I2O device support +# Memory Technology Devices (MTD) # -# CONFIG_I2O is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set +# CONFIG_MTD is not set # # Plug and Play configuration @@ -90,15 +120,12 @@ CONFIG_BLK_DEV_FD=y # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set CONFIG_BLK_DEV_LOOP=m # CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_LVM is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_RAID15_DANGEROUS is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y # @@ -106,114 +133,6 @@ CONFIG_BLK_DEV_INITRD=y # # -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -CONFIG_ATOMWIDE_SERIAL=y -CONFIG_DUALSP_SERIAL=y -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_UNIX98_PTYS is not set -CONFIG_PRINTER=m -# CONFIG_LP_CONSOLE is not set -# CONFIG_PPDEV is not set - -# -# I2C support -# -CONFIG_I2C=y -CONFIG_I2C_ALGOBIT=y -# CONFIG_I2C_PHILIPSPAR is not set -# CONFIG_I2C_ELV is not set -# CONFIG_I2C_VELLEMAN is not set -# CONFIG_I2C_ALGOPCF is not set -CONFIG_I2C_CHARDEV=y - -# -# Mice -# -CONFIG_BUSMOUSE=y -# CONFIG_ATIXL_BUSMOUSE is not set -# CONFIG_LOGIBUSMOUSE is not set -# CONFIG_MS_BUSMOUSE is not set -CONFIG_MOUSE=y -# CONFIG_PSMOUSE is not set -# CONFIG_82C710_MOUSE is not set -# CONFIG_PC110_PAD is not set - -# -# Joysticks -# -# CONFIG_JOYSTICK is not set -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set -# CONFIG_AGP is not set -CONFIG_RPCMOUSE=y - -# -# Console drivers -# -CONFIG_FB=y - -# -# Frame-buffer support -# -CONFIG_FB=y -CONFIG_DUMMY_CONSOLE=y -CONFIG_FB_ACORN=y -# CONFIG_FB_VIRTUAL is not set -CONFIG_FBCON_ADVANCED=y -CONFIG_FBCON_MFB=y -CONFIG_FBCON_CFB2=y -CONFIG_FBCON_CFB4=y -CONFIG_FBCON_CFB8=y -CONFIG_FBCON_CFB16=y -CONFIG_FBCON_CFB24=y -CONFIG_FBCON_CFB32=y -# CONFIG_FBCON_AFB is not set -# CONFIG_FBCON_ILBM is not set -# CONFIG_FBCON_IPLAN2P2 is not set -# CONFIG_FBCON_IPLAN2P4 is not set -# CONFIG_FBCON_IPLAN2P8 is not set -# CONFIG_FBCON_MAC is not set -# CONFIG_FBCON_VGA_PLANES is not set -# CONFIG_FBCON_VGA is not set -# CONFIG_FBCON_HGA is not set -# CONFIG_FBCON_FONTWIDTH8_ONLY is not set -CONFIG_FBCON_FONTS=y -# CONFIG_FONT_8x8 is not set -# CONFIG_FONT_8x16 is not set -# CONFIG_FONT_SUN8x16 is not set -# CONFIG_FONT_SUN12x22 is not set -# CONFIG_FONT_6x11 is not set -# CONFIG_FONT_PEARL_8x8 is not set -CONFIG_FONT_ACORN_8x8=y - -# # Networking options # # CONFIG_PACKET is not set @@ -222,19 +141,14 @@ CONFIG_FONT_ACORN_8x8=y # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set +CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set - -# -# (it is safe to leave these untouched) -# -CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set @@ -245,10 +159,11 @@ CONFIG_SKB_LARGE=y # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set @@ -260,16 +175,6 @@ CONFIG_SKB_LARGE=y # CONFIG_NET_SCHED is not set # -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# # Network device support # CONFIG_NETDEVICES=y @@ -281,14 +186,15 @@ CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y -CONFIG_ARM_ETHER1=m -CONFIG_ARM_ETHER3=m +CONFIG_ARM_ETHER1=y +CONFIG_ARM_ETHER3=y CONFIG_ARM_ETHERH=y # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set @@ -303,8 +209,9 @@ CONFIG_ARM_ETHERH=y # # Ethernet (1000 Mbit) # -# CONFIG_YELLOWFIN is not set # CONFIG_ACENIC is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set @@ -337,6 +244,16 @@ CONFIG_PPPOE=m # CONFIG_WAN is not set # +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# # ATA/IDE/MFM/RLL support # CONFIG_IDE=y @@ -353,6 +270,15 @@ CONFIG_BLK_DEV_IDE=y # CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDEDISK=y CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set # CONFIG_BLK_DEV_IDECS is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set @@ -372,6 +298,8 @@ CONFIG_BLK_DEV_IDEDMA=y CONFIG_BLK_DEV_IDE_RAPIDE=y # CONFIG_IDE_CHIPSETS is not set CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set # CONFIG_BLK_DEV_IDE_MODES is not set # @@ -427,14 +355,14 @@ CONFIG_SCSI_IMM=m # CONFIG_SCSI_IZIP_EPP16 is not set # CONFIG_SCSI_IZIP_SLOW_CTR is not set # CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_SIM710 is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set # CONFIG_SCSI_PSI240I is not set # CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_DEBUG is not set @@ -444,7 +372,7 @@ CONFIG_SCSI_ACORNSCSI_SYNC=y CONFIG_SCSI_ARXESCSI=m CONFIG_SCSI_CUMANA_2=m CONFIG_SCSI_EESOXSCSI=m -CONFIG_SCSI_POWERTECSCSI=m +CONFIG_SCSI_POWERTECSCSI=y # # The following drivers are not fully supported @@ -453,52 +381,101 @@ CONFIG_SCSI_CUMANA_1=m CONFIG_SCSI_OAK1=m # -# Sound +# I2O device support # -CONFIG_SOUND=m -# CONFIG_SOUND_CMPCI is not set -# CONFIG_SOUND_EMU10K1 is not set -# CONFIG_SOUND_ES1370 is not set -# CONFIG_SOUND_ES1371 is not set -# CONFIG_SOUND_ESSSOLO1 is not set -# CONFIG_SOUND_MAESTRO is not set -# CONFIG_SOUND_SONICVIBES is not set -# CONFIG_SOUND_TRIDENT is not set -# CONFIG_SOUND_MSNDCLAS is not set -# CONFIG_SOUND_MSNDPIN is not set -# CONFIG_SOUND_VIA82CXXX is not set -CONFIG_SOUND_OSS=m -# CONFIG_SOUND_TRACEINIT is not set -# CONFIG_SOUND_DMAP is not set -# CONFIG_SOUND_AD1816 is not set -# CONFIG_SOUND_SGALAXY is not set -# CONFIG_SOUND_ADLIB is not set -# CONFIG_SOUND_ACI_MIXER is not set -# CONFIG_SOUND_CS4232 is not set -# CONFIG_SOUND_SSCAPE is not set -# CONFIG_SOUND_GUS is not set -# CONFIG_SOUND_ICH is not set -# CONFIG_SOUND_VMIDI is not set -# CONFIG_SOUND_TRIX is not set -# CONFIG_SOUND_MSS is not set -# CONFIG_SOUND_MPU401 is not set -# CONFIG_SOUND_NM256 is not set -# CONFIG_SOUND_MAD16 is not set -# CONFIG_SOUND_PAS is not set -# CONFIG_PAS_JOYSTICK is not set -# CONFIG_SOUND_PSS is not set -CONFIG_SOUND_SOFTOSS=m -# CONFIG_SOUND_SB is not set -# CONFIG_SOUND_AWE32_SYNTH is not set -# CONFIG_SOUND_WAVEFRONT is not set -# CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_YM3812 is not set -# CONFIG_SOUND_OPL3SA1 is not set -# CONFIG_SOUND_OPL3SA2 is not set -# CONFIG_SOUND_UART6850 is not set -# CONFIG_SOUND_AEDSP16 is not set -CONFIG_SOUND_VIDC=m -# CONFIG_SOUND_WAVEARTIST is not set +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +CONFIG_ATOMWIDE_SERIAL=y +CONFIG_DUALSP_SERIAL=y +CONFIG_SERIAL_EXTENDED=y +# CONFIG_SERIAL_MANY_PORTS is not set +CONFIG_SERIAL_SHARE_IRQ=y +# CONFIG_SERIAL_DETECT_IRQ is not set +# CONFIG_SERIAL_MULTIPORT is not set +# CONFIG_HUB6 is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set +CONFIG_PRINTER=m +# CONFIG_LP_CONSOLE is not set +# CONFIG_PPDEV is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_PHILIPSPAR is not set +# CONFIG_I2C_ELV is not set +# CONFIG_I2C_VELLEMAN is not set +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_CHARDEV=y + +# +# Mice +# +CONFIG_BUSMOUSE=y +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_LOGIBUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set +CONFIG_MOUSE=y +# CONFIG_PSMOUSE is not set +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +CONFIG_RPCMOUSE=y + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems @@ -516,6 +493,7 @@ CONFIG_ADFS_FS=y # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y @@ -582,12 +560,14 @@ CONFIG_BSD_DISKLABEL=y CONFIG_SOLARIS_X86_PARTITION=y # CONFIG_UNIXWARE_DISKLABEL is not set CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set CONFIG_SUN_PARTITION=y CONFIG_NLS=y # # Native Language Support # +CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_CODEPAGE_737=m CONFIG_NLS_CODEPAGE_775=m @@ -604,6 +584,10 @@ CONFIG_NLS_CODEPAGE_865=m CONFIG_NLS_CODEPAGE_866=m CONFIG_NLS_CODEPAGE_869=m CONFIG_NLS_CODEPAGE_874=m +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set CONFIG_NLS_ISO8859_1=m CONFIG_NLS_ISO8859_2=m CONFIG_NLS_ISO8859_3=m @@ -616,6 +600,99 @@ CONFIG_NLS_ISO8859_9=m # CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set CONFIG_NLS_KOI8_R=m +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +CONFIG_FB=y + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_FB_ACORN=y +# CONFIG_FB_CLPS711X is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_SA1100 is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +CONFIG_FBCON_MFB=y +CONFIG_FBCON_CFB2=y +CONFIG_FBCON_CFB4=y +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y +CONFIG_FBCON_CFB32=y +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +# CONFIG_FONT_8x8 is not set +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +CONFIG_FONT_ACORN_8x8=y + +# +# Sound +# +CONFIG_SOUND=m +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +CONFIG_SOUND_OSS=m +# CONFIG_SOUND_TRACEINIT is not set +# CONFIG_SOUND_DMAP is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_ADLIB is not set +# CONFIG_SOUND_ACI_MIXER is not set +# CONFIG_SOUND_CS4232 is not set +# CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_NM256 is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_PAS is not set +# CONFIG_PAS_JOYSTICK is not set +# CONFIG_SOUND_PSS is not set +# CONFIG_SOUND_SB is not set +# CONFIG_SOUND_AWE32_SYNTH is not set +# CONFIG_SOUND_WAVEFRONT is not set +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_YM3812 is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_YMPCI is not set +# CONFIG_SOUND_UART6850 is not set +# CONFIG_SOUND_AEDSP16 is not set +CONFIG_SOUND_VIDC=m +# CONFIG_SOUND_TVMIXER is not set # # USB support @@ -627,7 +704,7 @@ CONFIG_NLS_KOI8_R=m # CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y -# CONFIG_DEBUG_USER is not set +CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_LL=y diff --git a/arch/arm/def-configs/sherman b/arch/arm/def-configs/sherman new file mode 100644 index 000000000..453fbf20f --- /dev/null +++ b/arch/arm/def-configs/sherman @@ -0,0 +1,210 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y + +# +# System and processor type +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_FOOTBRIDGE is not set +CONFIG_ARCH_SA1100=y +CONFIG_CPU_SA1100=y +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_EMPEG is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_VICTOR is not set +CONFIG_SA1100_SHERMAN=y +# CONFIG_VICTOR_BOARD1 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_ISA_DMA is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM2 is not set +# CONFIG_CPU_ARM3 is not set +# CONFIG_CPU_ARM6 is not set +# CONFIG_CPU_ARM7 is not set +CONFIG_CPU_SA110=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_ALIGNMENT_TRAP is not set +# CONFIG_TEXT_SECTIONS is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# General setup +# +# CONFIG_NET is not set +# CONFIG_SYSVIPC is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +CONFIG_NWFPE=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set +# CONFIG_PARPORT is not set +CONFIG_CMDLINE="" + +# +# Plug and Play support +# +# CONFIG_PNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_IDE is not set + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_IDEDISK is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_IDE_CHIPSETS is not set + +# +# Additional Block Devices +# +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_RAM=y +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE_PARPORT is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_FLASH=y + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set +# CONFIG_MOUSE is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set + +# +# Joystick support +# +# CONFIG_JOYSTICK is not set +# CONFIG_DTLK is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Partition Types +# +# CONFIG_OSF_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ACORN_PARTITION is not set +CONFIG_NLS=y + +# +# Native Language Support +# +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_INFO=y +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_DEBUG_LL=y diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index e79dd71e6..868fbd4a7 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -451,7 +451,6 @@ void __init pcibios_init(void) */ pci_assign_unassigned_resources(); pci_fixup_irqs(hw_pci->swizzle, hw_pci->map_irq); - pci_set_bus_ranges(); } char * __init pcibios_setup(char *str) @@ -463,8 +462,29 @@ char * __init pcibios_setup(char *str) return str; } +/* + * From arch/i386/kernel/pci-i386.c: + * + * We need to avoid collisions with `mirrored' VGA ports + * and other strange ISA hardware, so we always want the + * addresses to be allocated in the 0x000-0x0ff region + * modulo 0x400. + * + * Why? Because some silly external IO cards only decode + * the low 10 bits of the IO address. The 0x00-0xff region + * is reserved for motherboard devices that decode all 16 + * bits, so it's ok to allocate at, say, 0x2800-0x28ff, + * but we want to try to avoid allocating at 0x2900-0x2bff + * which might have be mirrored at 0x0100-0x03ff.. + */ void pcibios_align_resource(void *data, struct resource *res, unsigned long size) { + if (res->flags & IORESOURCE_IO) { + unsigned long start = res->start; + + if (start & 0x300) + res->start = (start + 0x3ff) & ~0x3ff; + } } /** diff --git a/arch/arm/kernel/dec21285.c b/arch/arm/kernel/dec21285.c index 8c427b379..bf265fab3 100644 --- a/arch/arm/kernel/dec21285.c +++ b/arch/arm/kernel/dec21285.c @@ -258,17 +258,21 @@ static void dc21285_parity_irq(int irq, void *dev_id, struct pt_regs *regs) void __init dc21285_init(struct arm_pci_sysdata *sysdata) { unsigned long cntl; - unsigned int mem_size; + unsigned int mem_size, mem_mask; unsigned int pci_cmd = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; int cfn_mode; + mem_size = (unsigned int)high_memory - PAGE_OFFSET; + for (mem_mask = 0x00100000; mem_mask < 0x10000000; mem_mask <<= 1) + if (mem_mask >= mem_size) + break; + /* * These registers need to be set up whether we're the * central function or not. */ - mem_size = (unsigned int)high_memory - PAGE_OFFSET; - *CSR_SDRAMBASEMASK = (mem_size - 1) & 0x0ffc0000; + *CSR_SDRAMBASEMASK = (mem_mask - 1) & 0x0ffc0000; *CSR_SDRAMBASEOFFSET = 0; *CSR_ROMBASEMASK = 0x80000000; *CSR_CSRBASEMASK = 0; diff --git a/arch/arm/kernel/dma-arc.c b/arch/arm/kernel/dma-arc.c index 2ad2edf3b..121a2792b 100644 --- a/arch/arm/kernel/dma-arc.c +++ b/arch/arm/kernel/dma-arc.c @@ -156,7 +156,7 @@ static void a5k_floppy_enable_dma(dmach_t channel, dma_t *dma) memcpy((void *)0x1c, fiqhandler_start, fiqhandler_length); regs.ARM_r9 = dma->buf.length; regs.ARM_r10 = dma->buf.address; - regs.ARM_fp = (int)PCIO_FLOPPYDMABASE; + regs.ARM_fp = FLOPPYDMA_BASE; set_fiq_regs(®s); enable_irq(dma->dma_irq); } @@ -191,7 +191,7 @@ static struct dma_ops sound_dma_ops = { void __init arch_dma_init(dma_t *dma) { #if defined(CONFIG_BLK_DEV_FD1772) || defined(CONFIG_BLK_DEV_FD1772_MODULE) - if (machine_is_arc()) { + if (machine_is_archimedes()) { dma[DMA_VIRTUAL_FLOPPY0].dma_irq = 64; dma[DMA_VIRTUAL_FLOPPY0].d_ops = &arc_floppy_data_dma_ops; dma[DMA_VIRTUAL_FLOPPY1].dma_irq = 65; diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index c8c737404..e659b966d 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -84,7 +84,7 @@ strb r12, [r12, #0x38] @ Disable FIQ register .endm - .macro get_irqnr_and_base, irqnr, irqstat, base + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp mov r4, #ioc_base_high @ point at IOC .if ioc_base_low orr r4, r4, #ioc_base_low @@ -165,36 +165,23 @@ irq_prio_h: .byte 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 .macro disable_fiq .endm - .macro get_irqnr_and_base, irqnr, irqstat, base - mov r4, #0xf3000000 - ldrb \irqstat, [r4] @ get interrupts - adr \base, irq_prio_ebsa110 - - teq \irqstat, #0 - ldrneb \irqnr, [\base, \irqstat] @ get IRQ number + .macro get_irqnr_and_base, irqnr, stat, base, tmp + mov \base, #IRQ_STAT + ldrb \stat, [\base] @ get interrupts + mov \irqnr, #0 + tst \stat, #15 + addeq \irqnr, \irqnr, #4 + moveq \stat, \stat, lsr #4 + tst \stat, #3 + addeq \irqnr, \irqnr, #2 + moveq \stat, \stat, lsr #2 + tst \stat, #1 + addeq \irqnr, \irqnr, #1 + moveq \stat, \stat, lsr #1 + tst \stat, #1 @ bit 0 should be set .endm .macro irq_prio_table -irq_prio_ebsa110: - .byte 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 1, 1, 2, 2, 2, 2 - .byte 4, 4, 1, 1, 2, 2, 2, 2, 3, 3, 1, 1, 2, 2, 2, 2 - .byte 5, 5, 1, 1, 2, 2, 2, 2, 3, 3, 1, 1, 2, 2, 2, 2 - .byte 5, 5, 1, 1, 2, 2, 2, 2, 3, 3, 1, 1, 2, 2, 2, 2 - - .byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2 - .byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2 - .byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2 - .byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2 - - .byte 7, 0, 1, 1, 2, 2, 2, 2, 3, 3, 1, 1, 2, 2, 2, 2 - .byte 4, 4, 1, 1, 2, 2, 2, 2, 3, 3, 1, 1, 2, 2, 2, 2 - .byte 5, 5, 1, 1, 2, 2, 2, 2, 3, 3, 1, 1, 2, 2, 2, 2 - .byte 5, 5, 1, 1, 2, 2, 2, 2, 3, 3, 1, 1, 2, 2, 2, 2 - - .byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2 - .byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2 - .byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2 - .byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2 .endm #elif defined(CONFIG_ARCH_SHARK) @@ -202,7 +189,7 @@ irq_prio_ebsa110: .macro disable_fiq .endm - .macro get_irqnr_and_base, irqnr, irqstat, base + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp mov r4, #0xe0000000 orr r4, r4, #0x20 @@ -238,7 +225,7 @@ irq_prio_ebsa110: .equ dc21285_high, ARMCSR_BASE & 0xff000000 .equ dc21285_low, ARMCSR_BASE & 0x00ffffff - .macro get_irqnr_and_base, irqnr, irqstat, base + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp mov r4, #dc21285_high .if dc21285_low orr r4, r4, #dc21285_low @@ -334,7 +321,7 @@ irq_prio_ebsa110: .macro disable_fiq .endm - .macro get_irqnr_and_base, irqnr, irqstat, base + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp ldr \irqstat, =INTCONT_BASE ldr \base, =soft_irq_mask ldr \irqstat, [\irqstat] @ get interrupts @@ -362,7 +349,7 @@ ENTRY(soft_irq_mask) .macro disable_fiq .endm - .macro get_irqnr_and_base, irqnr, irqstat, base + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp ldr \irqstat, =0xffff7000 ldr \irqstat, [\irqstat] @ get interrupts ldr \base, =soft_irq_mask @@ -390,7 +377,7 @@ ENTRY(soft_irq_mask) .macro disable_fiq .endm - .macro get_irqnr_and_base, irqnr, irqstat, base + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp mov r4, #0xfa000000 @ ICIP = 0xfa050000 add r4, r4, #0x00050000 ldr \irqstat, [r4] @ get irqs @@ -428,7 +415,7 @@ ENTRY(soft_irq_mask) .macro disable_fiq .endm - .macro get_irqnr_and_base, irqnr, irqstat, base + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp mov \irqstat, #irq_base_addr @ Virt addr IRQ regs add \irqstat, \irqstat, #0x00001000 @ Status reg ldr \irqstat, [\irqstat, #0] @ get interrupts @@ -449,7 +436,7 @@ ENTRY(soft_irq_mask) .macro disable_fiq .endm - .macro get_irqnr_and_base, irqnr, irqstat, base + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp /* FIXME: should not be using soo many LDRs here */ ldr \irqnr, =IO_ADDRESS(INTEGRATOR_IC_BASE) ldr \irqstat, [\irqnr, #IRQ_STATUS] @ get masked status @@ -470,6 +457,50 @@ ENTRY(soft_irq_mask) .macro irq_prio_table .endm +#elif defined(CONFIG_ARCH_P720T) + + .macro disable_fiq + .endm + +#if (INTSR2 - INTSR1) != (INTMR2 - INTMR1) +#error INTSR stride != INTMR stride +#endif + + .macro get_irqnr_and_base, irqnr, stat, base, mask + mov \base, #CLPS7111_BASE + ldr \stat, [\base, #INTSR1] + ldr \mask, [\base, #INTMR1] + mov \irqnr, #4 + mov \mask, \mask, lsl #16 + and \stat, \stat, \mask, lsr #16 + movs \stat, \stat, lsr #4 + bne 1001f + + add \base, \base, #INTSR2 - INTSR1 + ldr \stat, [\base, #INTSR1] + ldr \mask, [\base, #INTMR1] + mov \irqnr, #16 + mov \mask, \mask, lsl #16 + and \stat, \stat, \mask, lsr #16 + +1001: tst \stat, #255 + addeq \irqnr, \irqnr, #8 + moveq \stat, \stat, lsr #8 + tst \stat, #15 + addeq \irqnr, \irqnr, #4 + moveq \stat, \stat, lsr #4 + tst \stat, #3 + addeq \irqnr, \irqnr, #2 + moveq \stat, \stat, lsr #2 + tst \stat, #1 + addeq \irqnr, \irqnr, #1 + moveq \stat, \stat, lsr #1 + tst \stat, #1 @ bit 0 should be set + .endm + + .macro irq_prio_table + .endm + #else #error Unknown architecture #endif @@ -594,7 +625,7 @@ fpe_not_present: adr r10, wfs_mask_data ldmia r10, {r4, r5, r6, r7, r8} ldr r10, [sp, #S_PC] @ Load PC - sub r10, r10, #-4 + sub r10, r10, #4 mask_pc r10, r10 ldrt r10, [r10] @ get instruction and r5, r10, r5 @@ -660,7 +691,7 @@ __irq_svc: sub sp, sp, #S_FRAME_SIZE add r4, sp, #S_SP mov r6, lr stmia r4, {r5, r6, r7, r8, r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro -1: get_irqnr_and_base r0, r6, r5 +1: get_irqnr_and_base r0, r6, r5, lr movne r1, sp @ @ routine called with r0 = irq number, r1 = struct pt_regs * @@ -695,6 +726,28 @@ __und_svc: sub sp, sp, #S_FRAME_SIZE ldmia sp, {r0 - pc}^ @ Restore SVC registers .align 5 +__pabt_svc: sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ save r0 - r12 + ldr r2, .LCabt + add r0, sp, #S_FRAME_SIZE + ldmia r2, {r2 - r4} @ get pc, cpsr + add r5, sp, #S_SP + mov r1, lr + stmia r5, {r0 - r4} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro + mrs r9, cpsr @ Enable interrupts if they were + tst r3, #I_BIT + biceq r9, r9, #I_BIT @ previously + msr cpsr_c, r9 + mov r0, r2 @ address (pc) + mov r1, sp @ regs + bl SYMBOL_NAME(do_PrefetchAbort) @ call abort handler + mov r0, #I_BIT | MODE_SVC + msr cpsr_c, r0 + ldr r0, [sp, #S_PSR] + msr spsr, r0 + ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr + + .align 5 .LCirq: .word __temp_irq .LCund: .word __temp_und .LCabt: .word __temp_abt @@ -744,7 +797,7 @@ __irq_usr: sub sp, sp, #S_FRAME_SIZE stmdb r8, {sp, lr}^ alignment_trap r4, r7, __temp_irq zero_fp -1: get_irqnr_and_base r0, r6, r5 +1: get_irqnr_and_base r0, r6, r5, lr movne r1, sp adrsvc ne, lr, 1b @ @@ -762,7 +815,7 @@ __und_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go add r8, sp, #S_PC ldmia r4, {r5 - r7} stmia r8, {r5 - r7} @ Save USR pc, cpsr, old_r0 - stmdb r8, {sp, lr}^ @ Save user r0 - r12 + stmdb r8, {sp, lr}^ @ Save user sp, lr alignment_trap r4, r7, __temp_und zero_fp adrsvc al, r9, ret_from_sys_call @ r9 = normal FP return @@ -960,12 +1013,25 @@ vector_prefetch: msr spsr_c, r13 @ switch to SVC_32 mode ands lr, lr, #15 - ldreq lr, .LCtab_pabt - ldrne lr, .LCtab_pabt + 4 + ldr lr, [pc, lr, lsl #2] movs pc, lr -.LCtab_pabt: .word __pabt_usr - .word __pabt_invalid +.LCtab_pabt: .word __pabt_usr @ 0 (USR_26 / USR_32) + .word __pabt_invalid @ 1 (FIQ_26 / FIQ_32) + .word __pabt_invalid @ 2 (IRQ_26 / IRQ_32) + .word __pabt_svc @ 3 (SVC_26 / SVC_32) + .word __pabt_invalid @ 4 + .word __pabt_invalid @ 5 + .word __pabt_invalid @ 6 + .word __pabt_invalid @ 7 + .word __pabt_invalid @ 8 + .word __pabt_invalid @ 9 + .word __pabt_invalid @ a + .word __pabt_invalid @ b + .word __pabt_invalid @ c + .word __pabt_invalid @ d + .word __pabt_invalid @ e + .word __pabt_invalid @ f .align 5 diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c index b74d7550f..1be23e8fb 100644 --- a/arch/arm/kernel/fiq.c +++ b/arch/arm/kernel/fiq.c @@ -131,15 +131,14 @@ void set_fiq_regs(struct pt_regs *regs) #endif #ifdef CONFIG_CPU_32 "mrs %0, cpsr - bic %1, %0, #0xf - orr %1, %1, #0xc1 - msr cpsr, %1 @ select FIQ mode + mov %1, #0xc1 + msr cpsr_c, %1 @ select FIQ mode mov r0, r0 ldmia %2, {r8 - r14} - msr cpsr, %0 @ return to SVC mode + msr cpsr_c, %0 @ return to SVC mode mov r0, r0" #endif - : "=r" (tmp), "=r" (tmp2) + : "=&r" (tmp), "=&r" (tmp2) : "r" (®s->ARM_r8) /* These registers aren't modified by the above code in a way visible to the compiler, but we mark them as clobbers anyway @@ -164,15 +163,14 @@ void get_fiq_regs(struct pt_regs *regs) #endif #ifdef CONFIG_CPU_32 "mrs %0, cpsr - bic %1, %0, #0xf - orr %1, %1, #0xc1 - msr cpsr, %1 @ select FIQ mode + mov %1, #0xc1 + msr cpsr_c, %1 @ select FIQ mode mov r0, r0 stmia %2, {r8 - r14} - msr cpsr, %0 @ return to SVC mode + msr cpsr_c, %0 @ return to SVC mode mov r0, r0" #endif - : "=r" (tmp), "=r" (tmp2) + : "=&r" (tmp), "=&r" (tmp2) : "r" (®s->ARM_r8) /* These registers aren't modified by the above code in a way visible to the compiler, but we mark them as clobbers anyway diff --git a/arch/arm/kernel/head-armo.S b/arch/arm/kernel/head-armo.S index f42f3337d..13dd0d09e 100644 --- a/arch/arm/kernel/head-armo.S +++ b/arch/arm/kernel/head-armo.S @@ -21,7 +21,6 @@ */ .section ".text.init",#alloc,#execinstr ENTRY(stext) -ENTRY(_stext) __entry: cmp pc, #0x02000000 ldrlt pc, LC0 @ if 0x01800000, call at 0x02080000 teq r0, #0 @ Check for old calling method diff --git a/arch/arm/kernel/head-armv.S b/arch/arm/kernel/head-armv.S index 5e141bf51..5e529e702 100644 --- a/arch/arm/kernel/head-armv.S +++ b/arch/arm/kernel/head-armv.S @@ -16,28 +16,33 @@ #include <asm/mach-types.h> #include <asm/mach/arch.h> -#if (TEXTADDR & 0xffff) != 0x8000 -#error TEXTADDR must start at 0xXXXX8000 -#endif - #define K(a,b,c) ((a) << 24 | (b) << 12 | (c)) /* - * swapper_pg_dir is the virtual address of the "init_task" page tables. - * SWAPPER_PGDIR_OFFSET is the offset from the start of memory of the - * page tables. + * We place the page tables 16K below TEXTADDR. Therefore, we must make sure + * that TEXTADDR is correctly set. Currently, we expect the least significant + * "short" to be 0x8000, but we could probably relax this restriction to + * TEXTADDR > PAGE_OFFSET + 0x4000 * - * Note that at the moment, we assume TEXTADDR is the virtual equivalent - * of start of memory + 0x8000 + * Note that swapper_pg_dir is the virtual address of the page tables, and + * pgtbl gives us a position-independent reference to these tables. We can + * do this because stext == TEXT_ADDR */ -#define SWAPPER_PGDIR_OFFSET 0x4000 +#if (TEXTADDR & 0xffff) != 0x8000 +#error TEXTADDR must start at 0xXXXX8000 +#endif + .globl SYMBOL_NAME(swapper_pg_dir) - .equ SYMBOL_NAME(swapper_pg_dir), TEXTADDR - 0x8000 + SWAPPER_PGDIR_OFFSET + .equ SYMBOL_NAME(swapper_pg_dir), TEXTADDR - 0x4000 + + .macro pgtbl, reg + adr \reg, stext + sub \reg, \reg, #0x4000 + .endm .section ".text.init",#alloc,#execinstr .type stext, #function ENTRY(stext) -ENTRY(_stext) /* * Entry point. The general rules are: * should be called with r0 == 0 @@ -185,7 +190,7 @@ __mmap_switched: * r8 = page table flags */ __create_page_tables: - add r4, r5, #SWAPPER_PGDIR_OFFSET + pgtbl r4 mov r0, r4 mov r3, #0 add r2, r0, #0x4000 @ 16k of page table diff --git a/arch/arm/kernel/oldlatches.c b/arch/arm/kernel/oldlatches.c index fe40c58b5..7d8858b9e 100644 --- a/arch/arm/kernel/oldlatches.c +++ b/arch/arm/kernel/oldlatches.c @@ -26,12 +26,12 @@ static unsigned char latch_b_copy; /* newval=(oldval & ~mask)|newdata */ void oldlatch_aupdate(unsigned char mask,unsigned char newdata) { - if (machine_is_arc()) { + if (machine_is_archimedes()) { latch_a_copy = (latch_a_copy & ~mask) | newdata; printk("Latch: A = 0x%02x\n", latch_a_copy); - outb(latch_a_copy, LATCHAADDR); + __raw_writeb(latch_a_copy, LATCHA_BASE); } else BUG(); } @@ -40,19 +40,19 @@ void oldlatch_aupdate(unsigned char mask,unsigned char newdata) /* newval=(oldval & ~mask)|newdata */ void oldlatch_bupdate(unsigned char mask,unsigned char newdata) { - if (machine_is_arc()) { + if (machine_is_archimedes()) { latch_b_copy = (latch_b_copy & ~mask) | newdata; printk("Latch: B = 0x%02x\n", latch_b_copy); - outb(latch_b_copy, LATCHBADDR); + __raw_writeb(latch_b_copy, LATCHB_BASE); } else BUG(); } static void __init oldlatch_init(void) { - if (machine_is_arc()) { + if (machine_is_archimedes()) { oldlatch_aupdate(0xff, 0xff); /* Thats no FDC reset...*/ oldlatch_bupdate(0xff, LATCHB_FDCRESET); diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 8e8e3675f..9d0cc5c69 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -31,6 +31,7 @@ #include "ptrace.h" extern void c_backtrace (unsigned long fp, int pmode); +extern void show_pte(struct mm_struct *mm, unsigned long addr); const char *processor_modes[]= { "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , @@ -41,12 +42,6 @@ const char *processor_modes[]= static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; -static inline void console_verbose(void) -{ - extern int console_loglevel; - console_loglevel = 15; -} - /* * Stack pointers should always be within the kernels view of * physical memory. If it is not there, then we can't dump @@ -72,10 +67,14 @@ void dump_mem(unsigned long bottom, unsigned long top) printk("%08lx: ", p); for (i = 0; i < 8; i++, p += 4) { + unsigned int val; + if (p < bottom || p >= top) printk(" "); - else - printk("%08lx ", *(unsigned long *)p); + else { + __get_user(val, (unsigned long *)p); + printk("%08x ", val); + } if (i == 3) printk(" "); } @@ -91,45 +90,57 @@ void dump_mem(unsigned long bottom, unsigned long top) #define VMALLOC_OFFSET (8*1024*1024) #define MODULE_RANGE (8*1024*1024) -static void dump_instr(unsigned long pc, int user) +static void dump_instr(struct pt_regs *regs) { - int pmin = -2, pmax = 3, ok = 0; - extern char start_kernel, _etext; - - if (!user) { - unsigned long module_start, module_end; - unsigned long kernel_start, kernel_end; - - module_start = VMALLOC_START; - module_end = module_start + MODULE_RANGE; - - kernel_start = (unsigned long)&start_kernel; - kernel_end = (unsigned long)&_etext; - - if (pc >= kernel_start && pc < kernel_end) { - if (pc + pmin < kernel_start) - pmin = kernel_start - pc; - if (pc + pmax > kernel_end) - pmax = kernel_end - pc; - ok = 1; - } else if (pc >= module_start && pc < module_end) { - if (pc + pmin < module_start) - pmin = module_start - pc; - if (pc + pmax > module_end) - pmax = module_end - pc; - ok = 1; + unsigned long addr = instruction_pointer(regs); + const int thumb = thumb_mode(regs); + const int width = thumb ? 4 : 8; + int i; + + printk("Code: "); + for (i = -2; i < 3; i++) { + unsigned int val, bad; + + if (thumb) + bad = __get_user(val, &((u16 *)addr)[i]); + else + bad = __get_user(val, &((u32 *)addr)[i]); + + if (!bad) + printk(i == 0 ? "(%0*x) " : "%0*x", width, val); + else { + printk("bad PC value."); + break; } - } else - ok = verify_area(VERIFY_READ, (void *)(pc + pmin), pmax - pmin) == 0; - - printk ("Code: "); - if (ok) { - int i; - for (i = pmin; i < pmax; i++) - printk(i == 0 ? "(%08lx) " : "%08lx ", ((unsigned long *)pc)[i]); - printk ("\n"); - } else - printk ("pc not in code space\n"); + } + printk("\n"); +} + +static void dump_stack(struct task_struct *tsk, unsigned long sp) +{ + printk("Stack:\n"); + dump_mem(sp - 16, 8192+(unsigned long)tsk); +} + +static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) +{ + unsigned int fp; + int ok = 1; + + printk("Backtrace: "); + fp = regs->ARM_fp; + if (!fp) { + printk("no frame pointer"); + ok = 0; + } else if (verify_stack(fp)) { + printk("invalid frame pointer %08lx", fp); + ok = 0; + } else if (fp < 4096+(unsigned long)tsk) + printk("frame pointer underflow"); + printk("\n"); + + if (ok) + c_backtrace(fp, processor_mode(regs)); } spinlock_t die_lock = SPIN_LOCK_UNLOCKED; @@ -141,9 +152,9 @@ void die(const char *str, struct pt_regs *regs, int err) { struct task_struct *tsk = current; + console_verbose(); spin_lock_irq(&die_lock); - console_verbose(); printk("Internal error: %s: %x\n", str, err); printk("CPU: %d\n", smp_processor_id()); show_regs(regs); @@ -151,39 +162,22 @@ void die(const char *str, struct pt_regs *regs, int err) current->comm, current->pid, 4096+(unsigned long)tsk); if (!user_mode(regs)) { - unsigned long sp = (unsigned long)(regs + 1); - unsigned long fp; - int dump_info = 1; - - printk("Stack: "); - if (verify_stack(sp)) { - printk("invalid kernel stack pointer %08lx", sp); - dump_info = 0; - } else if (sp < 4096+(unsigned long)tsk) - printk("kernel stack pointer underflow"); - printk("\n"); - - if (dump_info) - dump_mem(sp - 16, 8192+(unsigned long)tsk); - - dump_info = 1; - - printk("Backtrace: "); - fp = regs->ARM_fp; - if (!fp) { - printk("no frame pointer"); - dump_info = 0; - } else if (verify_stack(fp)) { - printk("invalid frame pointer %08lx", fp); - dump_info = 0; - } else if (fp < 4096+(unsigned long)tsk) - printk("frame pointer underflow"); - printk("\n"); - - if (dump_info) - c_backtrace(fp, processor_mode(regs)); - - dump_instr(instruction_pointer(regs), 0); + mm_segment_t fs; + + /* + * We need to switch to kernel mode so that we can + * use __get_user to safely read from kernel space. + * Note that we now dump the code first, just in case + * the backtrace kills us. + */ + fs = get_fs(); + set_fs(KERNEL_DS); + + dump_instr(regs); + dump_stack(tsk, (unsigned long)(regs + 1)); + dump_backtrace(regs, tsk); + + set_fs(fs); } spin_unlock_irq(&die_lock); @@ -206,6 +200,7 @@ asmlinkage void do_undefinstr(int address, struct pt_regs *regs, int mode) #ifdef CONFIG_DEBUG_USER printk(KERN_INFO "%s (%d): undefined instruction: pc=%08lx\n", current->comm, current->pid, addr); + dump_instr(regs); #endif current->thread.error_code = 0; @@ -228,6 +223,7 @@ asmlinkage void do_excpt(int address, struct pt_regs *regs, int mode) #ifdef CONFIG_DEBUG_USER printk(KERN_INFO "%s (%d): address exception: pc=%08lx\n", current->comm, current->pid, instruction_pointer(regs)); + dump_instr(regs); #endif current->thread.error_code = 0; @@ -275,7 +271,7 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode) die("Oops", regs, 0); cli(); - while(1); + panic("bad mode"); } /* @@ -332,6 +328,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) * something catastrophic has happened */ printk("[%d] %s: arm syscall %d\n", current->pid, current->comm, no); + dump_instr(regs); if (user_mode(regs)) { show_regs(regs); c_backtrace(regs->ARM_fp, processor_mode(regs)); @@ -359,8 +356,9 @@ asmlinkage void deferred(int n, struct pt_regs *regs) } #ifdef CONFIG_DEBUG_USER - printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n", current->pid, - current->comm, n); + printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n", + current->pid, current->comm, n); + dump_instr(regs); #endif force_sig(SIGILL, current); die_if_kernel("Oops", regs, n); @@ -384,21 +382,10 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs) siginfo_t info; #ifdef CONFIG_DEBUG_USER - dump_instr(addr, 1); - { - pgd_t *pgd; - - pgd = pgd_offset(current->mm, addr); - printk ("*pgd = %08lx", pgd_val (*pgd)); - if (!pgd_none (*pgd)) { - pmd_t *pmd; - pmd = pmd_offset (pgd, addr); - printk (", *pmd = %08lx", pmd_val (*pmd)); - if (!pmd_none (*pmd)) - printk (", *pte = %08lx", pte_val(*pte_offset (pmd, addr))); - } - printk ("\n"); - } + printk(KERN_ERR "[%d] %s: bad data abort: code %d instr 0x%08lx\n", + current->pid, current->comm, code, instr); + dump_instr(regs); + show_pte(current->mm, addr); #endif info.si_signo = SIGILL; diff --git a/arch/arm/kernel/via82c505.c b/arch/arm/kernel/via82c505.c index 42a2bb448..ab97b6e80 100644 --- a/arch/arm/kernel/via82c505.c +++ b/arch/arm/kernel/via82c505.c @@ -76,7 +76,7 @@ static struct pci_ops via82c505_ops = { #ifdef CONFIG_ARCH_SHARK -static char size_wanted = 0; +static char size_wanted; static int dummy_read_config_byte(struct pci_dev *dev, int where, u8 *value) diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index b7e29ca55..fa7f10117 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -13,19 +13,35 @@ L_OBJS := changebit.o csumipv6.o csumpartial.o csumpartialcopy.o \ strncpy_from_user.o strnlen_user.o strchr.o strrchr.o \ testchangebit.o testclearbit.o testsetbit.o uaccess.o +l-obj-y := +l-obj-n := + O_TARGET := lib.o O_OBJS := backtrace.o delay.o -L_OBJS_arc := io-acorn.o floppydma.o -L_OBJS_rpc := io-acorn.o floppydma.o +ifeq ($(CONFIG_ARCH_ACORN),y) + half := n + full := y +else + half := y + full := n +endif + +L_OBJS_arc := ecard.o io-acorn.o floppydma.o +L_OBJS_rpc := ecard.o io-acorn.o floppydma.o L_OBJS_clps7500 := io-acorn.o -L_OBJS_ebsa110 := io-ebsa110.o -L_OBJS_footbridge := io-footbridge.o +L_OBJS_footbridge := io-pcio.o L_OBJS_l7200 := io-acorn.o -L_OBJS_nexuspci := io-footbridge.o -L_OBJS_sa1100 := io-footbridge.o +L_OBJS_nexuspci := io-pcio.o +L_OBJS_sa1100 := io-pcio.o L_OBJS_shark := io-shark.o -L_OBJS_integrator := io-shark.o +L_OBJS_integrator := io-pcio.o +L_OBJS_clps711x := io-shark.o + +l-obj-y += io-readsb.o io-writesb.o +l-obj-$(full) += io-readsw-armv3.o io-writesw-armv3.o +l-obj-$(half) += io-readsw-armv4.o io-writesw-armv4.o +l-obj-y += io-readsl.o io-writesl.o ifeq ($(PROCESSOR),armo) L_OBJS += uaccess-armo.o @@ -35,7 +51,7 @@ ifneq ($(MACHINE),ebsa110) OX_OBJS += io.o endif -L_OBJS += $(L_OBJS_$(MACHINE)) +L_OBJS += $(L_OBJS_$(MACHINE)) $(l-obj-y) include $(TOPDIR)/Rules.make diff --git a/arch/arm/lib/ecard.S b/arch/arm/lib/ecard.S new file mode 100644 index 000000000..9b0452d01 --- /dev/null +++ b/arch/arm/lib/ecard.S @@ -0,0 +1,47 @@ +/* + * linux/arch/arm/lib/ecard.S + * + * Copyright (C) 1995, 1996 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/config.h> /* for CONFIG_CPU_nn */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/hardware.h> + +#if defined(CONFIG_CPU_26) +#define CPSR2SPSR(rt) +#else +#define CPSR2SPSR(rt) \ + mrs rt, cpsr; \ + msr spsr, rt +#endif + +@ Purpose: call an expansion card loader to read bytes. +@ Proto : char read_loader(int offset, char *card_base, char *loader); +@ Returns: byte read + +ENTRY(ecard_loader_read) + stmfd sp!, {r4 - r12, lr} + mov r11, r1 + mov r1, r0 + CPSR2SPSR(r0) + mov lr, pc + mov pc, r2 + LOADREGS(fd, sp!, {r4 - r12, pc}) + +@ Purpose: call an expansion card loader to reset the card +@ Proto : void read_loader(int card_base, char *loader); +@ Returns: byte read + +ENTRY(ecard_loader_reset) + stmfd sp!, {r4 - r12, lr} + mov r11, r0 + CPSR2SPSR(r0) + mov lr, pc + add pc, r1, #8 + LOADREGS(fd, sp!, {r4 - r12, pc}) + diff --git a/arch/arm/lib/io-acorn.S b/arch/arm/lib/io-acorn.S index bc40496ac..a40272fdb 100644 --- a/arch/arm/lib/io-acorn.S +++ b/arch/arm/lib/io-acorn.S @@ -40,8 +40,6 @@ addeq \rd, \rd, #diff_pcio_base .endm -.iosw_bad_align_msg: - .ascii "insw: bad buffer alignment (%p), called from %08lX\n\0" .iosl_warning: .ascii "<4>insl/outsl not implemented, called from %08lX\0" .align @@ -56,422 +54,38 @@ ENTRY(outsl) mov r1, lr b SYMBOL_NAME(printk) -.iosw_bad_alignment: - adr r0, .iosw_bad_align_msg - mov r2, lr - b SYMBOL_NAME(panic) - - /* Purpose: read a block of data from a hardware register to memory. * Proto : void insw(int from_port, void *to, int len_in_words); * Notes : increment to, 'to' must be 16-bit aligned */ -.insw_align: tst r1, #1 - bne .iosw_bad_alignment - - ldr r3, [r0] - strb r3, [r1], #1 - mov r3, r3, lsr #8 - strb r3, [r1], #1 - - subs r2, r2, #1 - bne .insw_aligned - ENTRY(insw) teq r2, #0 - RETINSTR(moveq,pc,lr) + RETINSTR(moveq, pc, lr) addr r0 - tst r1, #3 - bne .insw_align - -.insw_aligned: mov ip, #0xff - orr ip, ip, ip, lsl #8 - stmfd sp!, {r4, r5, r6, lr} - - subs r2, r2, #8 - bmi .no_insw_8 - -.insw_8_lp: ldr r3, [r0] - and r3, r3, ip - ldr r4, [r0] - orr r3, r3, r4, lsl #16 - - ldr r4, [r0] - and r4, r4, ip - ldr r5, [r0] - orr r4, r4, r5, lsl #16 - - ldr r5, [r0] - and r5, r5, ip - ldr r6, [r0] - orr r5, r5, r6, lsl #16 - - ldr r6, [r0] - and r6, r6, ip - ldr lr, [r0] - orr r6, r6, lr, lsl #16 - - stmia r1!, {r3 - r6} - subs r2, r2, #8 - bpl .insw_8_lp - tst r2, #7 - LOADREGS(eqfd, sp!, {r4, r5, r6, pc}) + b __arch_readsw -.no_insw_8: tst r2, #4 - beq .no_insw_4 - - ldr r3, [r0] - and r3, r3, ip - ldr r4, [r0] - orr r3, r3, r4, lsl #16 - - ldr r4, [r0] - and r4, r4, ip - ldr r5, [r0] - orr r4, r4, r5, lsl #16 - - stmia r1!, {r3, r4} - -.no_insw_4: tst r2, #2 - beq .no_insw_2 - - ldr r3, [r0] - and r3, r3, ip - ldr r4, [r0] - orr r3, r3, r4, lsl #16 - - str r3, [r1], #4 - -.no_insw_2: tst r2, #1 - ldrne r3, [r0] - strneb r3, [r1], #1 - movne r3, r3, lsr #8 - strneb r3, [r1] - LOADREGS(fd, sp!, {r4, r5, r6, pc}) +ENTRY(insb) + teq r2, #0 + RETINSTR(moveq, pc, lr) + addr r0 + b __arch_readsb @ Purpose: write a block of data from memory to a hardware register. @ Proto : outsw(int to_reg, void *from, int len_in_words); @ Notes : increments from -.outsw_align: tst r1, #1 - bne .iosw_bad_alignment - - add r1, r1, #2 - - ldr r3, [r1, #-4] - mov r3, r3, lsr #16 - orr r3, r3, r3, lsl #16 - str r3, [r0] - subs r2, r2, #1 - bne .outsw_aligned - ENTRY(outsw) teq r2, #0 - RETINSTR(moveq,pc,lr) - addr r0 - tst r1, #3 - bne .outsw_align - -.outsw_aligned: stmfd sp!, {r4, r5, r6, lr} - - subs r2, r2, #8 - bmi .no_outsw_8 -.outsw_8_lp: ldmia r1!, {r3, r4, r5, r6} - - mov ip, r3, lsl #16 - orr ip, ip, ip, lsr #16 - str ip, [r0] - - mov ip, r3, lsr #16 - orr ip, ip, ip, lsl #16 - str ip, [r0] - - mov ip, r4, lsl #16 - orr ip, ip, ip, lsr #16 - str ip, [r0] - - mov ip, r4, lsr #16 - orr ip, ip, ip, lsl #16 - str ip, [r0] - - mov ip, r5, lsl #16 - orr ip, ip, ip, lsr #16 - str ip, [r0] - - mov ip, r5, lsr #16 - orr ip, ip, ip, lsl #16 - str ip, [r0] - - mov ip, r6, lsl #16 - orr ip, ip, ip, lsr #16 - str ip, [r0] - - mov ip, r6, lsr #16 - orr ip, ip, ip, lsl #16 - str ip, [r0] - - subs r2, r2, #8 - bpl .outsw_8_lp - tst r2, #7 - LOADREGS(eqfd, sp!, {r4, r5, r6, pc}) - -.no_outsw_8: tst r2, #4 - beq .no_outsw_4 - - ldmia r1!, {r3, r4} - - mov ip, r3, lsl #16 - orr ip, ip, ip, lsr #16 - str ip, [r0] - - mov ip, r3, lsr #16 - orr ip, ip, ip, lsl #16 - str ip, [r0] - - mov ip, r4, lsl #16 - orr ip, ip, ip, lsr #16 - str ip, [r0] - - mov ip, r4, lsr #16 - orr ip, ip, ip, lsl #16 - str ip, [r0] - -.no_outsw_4: tst r2, #2 - beq .no_outsw_2 - - ldr r3, [r1], #4 - - mov ip, r3, lsl #16 - orr ip, ip, ip, lsr #16 - str ip, [r0] - - mov ip, r3, lsr #16 - orr ip, ip, ip, lsl #16 - str ip, [r0] - -.no_outsw_2: tst r2, #1 - - ldrne r3, [r1] - - movne ip, r3, lsl #16 - orrne ip, ip, ip, lsr #16 - strne ip, [r0] - - LOADREGS(fd, sp!, {r4, r5, r6, pc}) - -.insb_align: rsb ip, ip, #4 - cmp ip, r2 - movgt ip, r2 - cmp ip, #2 - ldrb r3, [r0] - strb r3, [r1], #1 - ldrgeb r3, [r0] - strgeb r3, [r1], #1 - ldrgtb r3, [r0] - strgtb r3, [r1], #1 - subs r2, r2, ip - bne .insb_aligned - -ENTRY(insb) - teq r2, #0 - moveq pc, lr + RETINSTR(moveq, pc, lr) addr r0 - ands ip, r1, #3 - bne .insb_align - -.insb_aligned: stmfd sp!, {r4 - r6, lr} - - subs r2, r2, #16 - bmi .insb_no_16 - -.insb_16_lp: ldrb r3, [r0] - ldrb r4, [r0] - orr r3, r3, r4, lsl #8 - ldrb r4, [r0] - orr r3, r3, r4, lsl #16 - ldrb r4, [r0] - orr r3, r3, r4, lsl #24 - ldrb r4, [r0] - ldrb r5, [r0] - orr r4, r4, r5, lsl #8 - ldrb r5, [r0] - orr r4, r4, r5, lsl #16 - ldrb r5, [r0] - orr r4, r4, r5, lsl #24 - ldrb r5, [r0] - ldrb r6, [r0] - orr r5, r5, r6, lsl #8 - ldrb r6, [r0] - orr r5, r5, r6, lsl #16 - ldrb r6, [r0] - orr r5, r5, r6, lsl #24 - ldrb r6, [r0] - ldrb ip, [r0] - orr r6, r6, ip, lsl #8 - ldrb ip, [r0] - orr r6, r6, ip, lsl #16 - ldrb ip, [r0] - orr r6, r6, ip, lsl #24 - stmia r1!, {r3 - r6} - subs r2, r2, #16 - bpl .insb_16_lp - - tst r2, #15 - LOADREGS(eqfd, sp!, {r4 - r6, pc}) - -.insb_no_16: tst r2, #8 - beq .insb_no_8 - - ldrb r3, [r0] - ldrb r4, [r0] - orr r3, r3, r4, lsl #8 - ldrb r4, [r0] - orr r3, r3, r4, lsl #16 - ldrb r4, [r0] - orr r3, r3, r4, lsl #24 - ldrb r4, [r0] - ldrb r5, [r0] - orr r4, r4, r5, lsl #8 - ldrb r5, [r0] - orr r4, r4, r5, lsl #16 - ldrb r5, [r0] - orr r4, r4, r5, lsl #24 - stmia r1!, {r3, r4} - -.insb_no_8: tst r2, #4 - bne .insb_no_4 - - ldrb r3, [r0] - ldrb r4, [r0] - orr r3, r3, r4, lsl #8 - ldrb r4, [r0] - orr r3, r3, r4, lsl #16 - ldrb r4, [r0] - orr r3, r3, r4, lsl #24 - str r3, [r1], #4 - -.insb_no_4: ands r2, r2, #3 - LOADREGS(eqfd, sp!, {r4 - r6, pc}) - cmp r2, #2 - ldrb r3, [r0] - strb r3, [r1], #1 - ldrgeb r3, [r0] - strgeb r3, [r1], #1 - ldrgtb r3, [r0] - strgtb r3, [r1] - LOADREGS(fd, sp!, {r4 - r6, pc}) - - - -.outsb_align: rsb ip, ip, #4 - cmp ip, r2 - mov ip, r2 - cmp ip, #2 - ldrb r3, [r1], #1 - strb r3, [r0] - ldrgeb r3, [r1], #1 - strgeb r3, [r0] - ldrgtb r3, [r1], #1 - strgtb r3, [r0] - subs r2, r2, ip - bne .outsb_aligned + b __arch_writesw ENTRY(outsb) teq r2, #0 - moveq pc, lr + RETINSTR(moveq, pc, lr) addr r0 - ands ip, r1, #3 - bne .outsb_align - -.outsb_aligned: stmfd sp!, {r4 - r6, lr} - - subs r2, r2, #16 - bmi .outsb_no_16 - -.outsb_16_lp: ldmia r1!, {r3 - r6} - strb r3, [r0] - mov r3, r3, lsr #8 - strb r3, [r0] - mov r3, r3, lsr #8 - strb r3, [r0] - mov r3, r3, lsr #8 - strb r3, [r0] - - strb r4, [r0] - mov r4, r4, lsr #8 - strb r4, [r0] - mov r4, r4, lsr #8 - strb r4, [r0] - mov r4, r4, lsr #8 - strb r4, [r0] - - strb r5, [r0] - mov r5, r5, lsr #8 - strb r5, [r0] - mov r5, r5, lsr #8 - strb r5, [r0] - mov r5, r5, lsr #8 - strb r5, [r0] - - strb r6, [r0] - mov r6, r6, lsr #8 - strb r6, [r0] - mov r6, r6, lsr #8 - strb r6, [r0] - mov r6, r6, lsr #8 - strb r6, [r0] - subs r2, r2, #16 - bpl .outsb_16_lp - - tst r2, #15 - LOADREGS(eqfd, sp!, {r4 - r6, pc}) - -.outsb_no_16: tst r2, #8 - beq .outsb_no_8 - - ldmia r1, {r3, r4} - strb r3, [r0] - mov r3, r3, lsr #8 - strb r3, [r0] - mov r3, r3, lsr #8 - strb r3, [r0] - mov r3, r3, lsr #8 - strb r3, [r0] - - strb r4, [r0] - mov r4, r4, lsr #8 - strb r4, [r0] - mov r4, r4, lsr #8 - strb r4, [r0] - mov r4, r4, lsr #8 - strb r4, [r0] - -.outsb_no_8: tst r2, #4 - bne .outsb_no_4 - - ldr r3, [r1], #4 - strb r3, [r0] - mov r3, r3, lsr #8 - strb r3, [r0] - mov r3, r3, lsr #8 - strb r3, [r0] - mov r3, r3, lsr #8 - strb r3, [r0] - -.outsb_no_4: ands r2, r2, #3 - LOADREGS(eqfd, sp!, {r4 - r6, pc}) - cmp r2, #2 - ldrb r3, [r1], #1 - strb r3, [r0] - ldrgeb r3, [r1], #1 - strgeb r3, [r0] - ldrgtb r3, [r1] - strgtb r3, [r0] - LOADREGS(fd, sp!, {r4 - r6, pc}) - - - + b __arch_writesb @ Purpose: write a memc register @ Proto : void memc_write(int register, int value); @@ -488,146 +102,5 @@ ENTRY(memc_write) add r0, r0, #0x03600000 strb r0, [r0] RETINSTR(mov,pc,lr) -#define CPSR2SPSR(rt) -#else -#define CPSR2SPSR(rt) \ - mrs rt, cpsr; \ - msr spsr, rt -#endif - -@ Purpose: call an expansion card loader to read bytes. -@ Proto : char read_loader(int offset, char *card_base, char *loader); -@ Returns: byte read - -ENTRY(ecard_loader_read) - stmfd sp!, {r4 - r12, lr} - mov r11, r1 - mov r1, r0 - CPSR2SPSR(r0) - mov lr, pc - mov pc, r2 - LOADREGS(fd, sp!, {r4 - r12, pc}) - -@ Purpose: call an expansion card loader to reset the card -@ Proto : void read_loader(int card_base, char *loader); -@ Returns: byte read - -ENTRY(ecard_loader_reset) - stmfd sp!, {r4 - r12, lr} - mov r11, r0 - CPSR2SPSR(r0) - mov lr, pc - add pc, r1, #8 - LOADREGS(fd, sp!, {r4 - r12, pc}) - - -#if 0 - mov r2, r2, lsl#1 - mov ip, sp - stmfd sp!, {r4 - r10, fp, ip, lr, pc} - sub fp, ip, #4 - addr r3, r0 - add r0, r3, r0, lsl #2 - tst r1, #3 - beq Linswok - tst r1, #1 - bne Linsw_notaligned - cmp r2, #1 - ldrge r4, [r0] - strgeb r4, [r1], #1 - movgt r4, r4, LSR#8 - strgtb r4, [r1], #1 - LOADREGS(leea, fp, {r4 - r10, fp, sp, pc}) - sub r2, r2, #2 -Linswok: mov ip, #0xFF - orr ip, ip, ip, lsl #8 -Linswlp: subs r2, r2, #64 - bmi Linsw_toosmall - IN(r3) - IN(r4) - IN(r5) - IN(r6) - IN(r7) - IN(r8) - IN(r9) - IN(r10) - stmia r1!, {r3 - r10} - IN(r3) - IN(r4) - IN(r5) - IN(r6) - IN(r7) - IN(r8) - IN(r9) - IN(r10) - stmia r1!, {r3 - r10} - bne Linswlp - LOADREGS(ea, fp, {r4 - r10, fp, sp, pc}) -Linsw_toosmall: - adds r2, r2, #32 - bmi Linsw_toosmall2 -Linsw2lp: IN(r3) - IN(r4) - IN(r5) - IN(r6) - IN(r7) - IN(r8) - IN(r9) - IN(r10) - stmia r1!, {r3 - r10} - LOADREGS(eqea, fp, {r4 - r10, fp, sp, pc}) - b Linsw_notaligned -Linsw_toosmall2: - add r2, r2, #32 -Linsw_notaligned: - cmp r2, #1 - LOADREGS(ltea, fp, {r4 - r10, fp, sp, pc}) - ldr r4, [r0] - strb r4, [r1], #1 - movgt r4, r4, LSR#8 - strgtb r4, [r1], #1 - subs r2, r2, #2 - bgt Linsw_notaligned - LOADREGS(ea, fp, {r4 - r10, fp, sp, pc}) - - -ENTRY(outsw) - mov r2, r2, lsl#1 - mov ip, sp - stmfd sp!, {r4 - r8, fp, ip, lr, pc} - sub fp, ip, #4 - addr r3, r0 - tst r1, #2 - beq 1f - ldr r4, [r1], #2 - mov r4, r4, lsl #16 - orr r4, r4, r4, lsr #16 - str r4, [r3, r0, lsl #2] - subs r2, r2, #2 - LOADREGS(eqea, fp, {r4 - r8, fp, sp, pc}) -1: subs r2, r2, #32 - blt 2f - ldmia r1!, {r4, r5, r6, r7} - OUT(r4) - OUT(r5) - OUT(r6) - OUT(r7) - ldmia r1!, {r4, r5, r6, r7} - OUT(r4) - OUT(r5) - OUT(r6) - OUT(r7) - bne 1b - LOADREGS(ea, fp, {r4 - r8, fp, sp, pc}) -2: adds r2, r2, #32 - LOADREGS(eqea, fp, {r4 - r8, fp, sp, pc}) -3: ldr r4, [r1],#2 - mov r4, r4, lsl#16 - orr r4, r4, r4, lsr#16 - str r4, [r3, r0, lsl#2] - subs r2, r2, #2 - bgt 3b - LOADREGS(ea, fp, {r4 - r8, fp, sp, pc}) - #endif diff --git a/arch/arm/lib/io-ebsa110.S b/arch/arm/lib/io-ebsa110.S deleted file mode 100644 index b1c507886..000000000 --- a/arch/arm/lib/io-ebsa110.S +++ /dev/null @@ -1,169 +0,0 @@ -/* - * linux/arch/arm/lib/io-ebsa.S - * - * Copyright (C) 1995, 1996 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <linux/linkage.h> -#include <asm/assembler.h> - .text - .align - -#define OUT(reg) \ - mov r8, reg, lsl $16 ;\ - orr r8, r8, r8, lsr $16 ;\ - str r8, [r3, r0, lsl $2] ;\ - mov r8, reg, lsr $16 ;\ - orr r8, r8, r8, lsl $16 ;\ - str r8, [r3, r0, lsl $2] - -#define IN(reg) \ - ldr reg, [r0] ;\ - and reg, reg, ip ;\ - ldr lr, [r0] ;\ - orr reg, reg, lr, lsl $16 - -/* - * These make no sense on these machines. - * Print a warning message. - */ -ENTRY(insl) -ENTRY(outsl) -ENTRY(insb) -ENTRY(outsb) - adr r0, io_long_warning - mov r1, lr - b SYMBOL_NAME(printk) - -io_long_warning: - .ascii "<4>ins?/outs? not implemented on this architecture\0" - .align - -@ Purpose: read a block of data from a hardware register to memory. -@ Proto : insw(int from_port, void *to, int len_in_words); -@ Proto : inswb(int from_port, void *to, int len_in_bytes); -@ Notes : increment to - -ENTRY(insw) - mov r2, r2, lsl#1 -ENTRY(inswb) - mov ip, sp - stmfd sp!, {r4 - r10 ,fp ,ip ,lr ,pc} - sub fp, ip, #4 - cmp r0, #0x00c00000 - movge r3, #0 - movlt r3, #0xf0000000 - add r0, r3, r0, lsl #2 - tst r1, #3 - beq Linswok - tst r1, #1 - bne Linsw_notaligned - cmp r2, #1 - ldrge r4, [r0] - strgeb r4, [r1], #1 - movgt r4, r4, LSR#8 - strgtb r4, [r1], #1 - ldmleea fp, {r4 - r10, fp, sp, pc}^ - sub r2, r2, #2 -Linswok: mov ip, #0xFF - orr ip, ip, ip, lsl #8 -Linswlp: subs r2, r2, #64 - bmi Linsw_toosmall - IN(r3) - IN(r4) - IN(r5) - IN(r6) - IN(r7) - IN(r8) - IN(r9) - IN(r10) - stmia r1!, {r3 - r10} - IN(r3) - IN(r4) - IN(r5) - IN(r6) - IN(r7) - IN(r8) - IN(r9) - IN(r10) - stmia r1!, {r3 - r10} - bne Linswlp - LOADREGS(ea, fp, {r4 - r10, fp, sp, pc}) -Linsw_toosmall: - add r2, r2, #32 - bmi Linsw_toosmall2 -Linsw2lp: IN(r3) - IN(r4) - IN(r5) - IN(r6) - IN(r7) - IN(r8) - IN(r9) - IN(r10) - stmia r1!, {r3 - r10} - LOADREGS(eqea, fp, {r4 - r10, fp, sp, pc}) - b Linsw_notaligned -Linsw_toosmall2: - add r2, r2, #32 -Linsw_notaligned: - cmp r2, #1 - LOADREGS(ltea, fp, {r4 - r10, fp, sp, pc}) - ldr r4, [r0] - strb r4, [r1], #1 - movgt r4, r4, LSR#8 - strgtb r4, [r1], #1 - subs r2, r2, #2 - bgt Linsw_notaligned - LOADREGS(ea, fp, {r4 - r10, fp, sp, pc}) - -@ Purpose: write a block of data from memory to a hardware register. -@ Proto : outsw(int to_reg, void *from, int len_in_words); -@ Proto : outswb(int to_reg, void *from, int len_in_bytes); -@ Notes : increments from - -ENTRY(outsw) - mov r2, r2, LSL#1 -ENTRY(outswb) - mov ip, sp - stmfd sp!, {r4 - r8, fp, ip, lr, pc} - sub fp, ip, #4 - cmp r0, #0x00c00000 - movge r3, #0 - movlt r3, #0xf0000000 - tst r1, #2 - beq Loutsw32lp - ldr r4, [r1], #2 - mov r4, r4, lsl #16 - orr r4, r4, r4, lsr #16 - str r4, [r3, r0, lsl #2] - sub r2, r2, #2 - teq r2, #0 - LOADREGS(eqea, fp, {r4 - r8, fp, sp, pc}) -Loutsw32lp: subs r2,r2,#32 - blt Loutsw_toosmall - ldmia r1!,{r4,r5,r6,r7} - OUT(r4) - OUT(r5) - OUT(r6) - OUT(r7) - ldmia r1!,{r4,r5,r6,r7} - OUT(r4) - OUT(r5) - OUT(r6) - OUT(r7) - LOADREGS(eqea, fp, {r4 - r8, fp, sp, pc}) - b Loutsw32lp -Loutsw_toosmall: - adds r2,r2,#32 - LOADREGS(eqea, fp, {r4 - r8, fp, sp, pc}) -Llpx: ldr r4,[r1],#2 - mov r4,r4,LSL#16 - orr r4,r4,r4,LSR#16 - str r4,[r3,r0,LSL#2] - subs r2,r2,#2 - bgt Llpx - LOADREGS(ea, fp, {r4 - r8, fp, sp, pc}) - diff --git a/arch/arm/lib/io-footbridge.S b/arch/arm/lib/io-footbridge.S deleted file mode 100644 index 98f751258..000000000 --- a/arch/arm/lib/io-footbridge.S +++ /dev/null @@ -1,202 +0,0 @@ -#include <linux/linkage.h> -#include <asm/hardware.h> - - .equ pcio_high, PCIO_BASE & 0xff000000 - .equ pcio_low, PCIO_BASE & 0x00ffffff - - .macro ioaddr, rd,rn - add \rd, \rn, #pcio_high - .if pcio_low - add \rd, \rd, #pcio_low - .endif - .endm - -ENTRY(insl) - ioaddr r0, r0 - ands ip, r1, #3 - bne 2f - -1: ldr r3, [r0] - str r3, [r1], #4 - subs r2, r2, #1 - bne 1b - mov pc, lr - -2: cmp ip, #2 - ldr ip, [r0] - blt 4f - bgt 6f - - strh ip, [r1], #2 - mov ip, ip, lsr #16 -3: subs r2, r2, #1 - ldrne r3, [r0] - orrne ip, ip, r3, lsl #16 - strne ip, [r1], #4 - movne ip, r3, lsr #16 - bne 3b - strh ip, [r1], #2 - mov pc, lr - -4: strb ip, [r1], #1 - mov ip, ip, lsr #8 - strh ip, [r1], #2 - mov ip, ip, lsr #16 -5: subs r2, r2, #1 - ldrne r3, [r0] - orrne ip, ip, r3, lsl #8 - strne ip, [r1], #4 - movne ip, r3, lsr #24 - bne 5b - strb ip, [r1], #1 - mov pc, lr - -6: strb ip, [r1], #1 - mov ip, ip, lsr #8 -7: subs r2, r2, #1 - ldrne r3, [r0] - orrne ip, ip, r3, lsl #24 - strne ip, [r1], #4 - movne ip, r3, lsr #8 - bne 7b - strb ip, [r1], #1 - mov ip, ip, lsr #8 - strh ip, [r1], #2 - mov pc, lr - -ENTRY(outsl) - ioaddr r0, r0 - ands ip, r1, #3 - bne 2f - -1: ldr r3, [r1], #4 - str r3, [r0] - subs r2, r2, #1 - bne 1b - mov pc, lr - -2: bic r1, r1, #3 - cmp ip, #2 - ldr ip, [r1], #4 - mov ip, ip, lsr #16 - blt 4f - bgt 5f - -3: ldr r3, [r1], #4 - orr ip, ip, r3, lsl #16 - str ip, [r0] - mov ip, r3, lsr #16 - subs r2, r2, #1 - bne 3b - mov pc, lr - -4: ldr r3, [r1], #4 - orr ip, ip, r3, lsl #8 - str ip, [r0] - mov ip, r3, lsr #24 - subs r2, r2, #1 - bne 4b - mov pc, lr - -5: ldr r3, [r1], #4 - orr ip, ip, r3, lsl #24 - str ip, [r0] - mov ip, r3, lsr #8 - subs r2, r2, #1 - bne 5b - mov pc, lr - - /* Nobody could say these are optimal, but not to worry. */ - -ENTRY(outswb) - mov r2, r2, lsr #1 -ENTRY(outsw) - ioaddr r0, r0 -1: subs r2, r2, #1 - ldrgeh r3, [r1], #2 - strgeh r3, [r0] - bgt 1b - mov pc, lr - -ENTRY(inswb) - mov r2, r2, lsr #1 -ENTRY(insw) - stmfd sp!, {r4, r5, lr} - ioaddr r0, r0 - @ + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 - subs ip, r2, #8 - blo too_little - @ + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 - ands lr, r1, #3 @ check alignment - beq 1f - - ldrh r3, [r0] - strh r3, [r1], #2 - sub ip, ip, #1 - cmn ip, #8 - blo too_little - -1: ldrh r2, [r0] - ldrh r3, [r0] - orr r2, r2, r3, lsl #16 - ldrh r3, [r0] - ldrh r4, [r0] - orr r3, r3, r4, lsl #16 - ldrh r4, [r0] - ldrh r5, [r0] - orr r4, r4, r5, lsl #16 - ldrh r5, [r0] - ldrh lr, [r0] - orr r5, r5, lr, lsl #16 - stmia r1!, {r2, r3, r4, r5} - subs ip, ip, #8 - @ - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 + 0 + 1 - bhs 1b - @ - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 8 - 7 - cmn ip, #4 - ldrhsh r2, [r0] @ ... ... ... ... - 4 - 3 - 2 - 1 ... ... - ldrhsh r3, [r0] - orrhs r2, r2, r3, lsl #16 - ldrhsh r3, [r0] - ldrhsh r4, [r0] - orrhs r3, r3, r4, lsl #16 - stmhsia r1!, {r2, r3} - - tst ip, #2 - ldrneh r2, [r0] @ ... ... - 6 - 5 ... ... - 2 - 1 ... ... - ldrneh r3, [r0] - orrne r2, r2, r3, lsl #16 - strne r2, [r1], #4 - - tst ip, #1 - ldrneh r2, [r0] - strneh r2, [r1], #2 - - ldmfd sp!, {r4, r5, pc} - -too_little: subs r2, r2, #1 - ldrgeh r3, [r0] - strgeh r3, [r1], #2 - bgt too_little - - ldmfd sp!, {r4, r5, pc} - - -ENTRY(insb) - ioaddr r0, r0 -1: teq r2, #0 - ldrneb r3, [r0] - strneb r3, [r1], #1 - subne r2, r2, #1 - bne 1b - mov pc, lr - - -ENTRY(outsb) - ioaddr r0, r0 -1: teq r2, #0 - ldrneb r3, [r1], #1 - strneb r3, [r0] - subne r2, r2, #1 - bne 1b - mov pc, lr diff --git a/arch/arm/lib/io-pcio.S b/arch/arm/lib/io-pcio.S new file mode 100644 index 000000000..f57abfc10 --- /dev/null +++ b/arch/arm/lib/io-pcio.S @@ -0,0 +1,38 @@ +#include <linux/linkage.h> +#include <asm/hardware.h> + + .equ pcio_high, PCIO_BASE & 0xff000000 + .equ pcio_low, PCIO_BASE & 0x00ffffff + + .macro ioaddr, rd,rn + add \rd, \rn, #pcio_high + .if pcio_low + add \rd, \rd, #pcio_low + .endif + .endm + +ENTRY(insl) + ioaddr r0, r0 + b __arch_readsl + +ENTRY(outsl) + ioaddr r0, r0 + b __arch_writesl + + /* Nobody could say these are optimal, but not to worry. */ + +ENTRY(outsw) + ioaddr r0, r0 + b __arch_writesw + +ENTRY(insw) + ioaddr r0, r0 + b __arch_readsw + +ENTRY(insb) + ioaddr r0, r0 + b __arch_readsb + +ENTRY(outsb) + ioaddr r0, r0 + b __arch_writesb diff --git a/arch/arm/lib/io-readsb.S b/arch/arm/lib/io-readsb.S new file mode 100644 index 000000000..23cca8929 --- /dev/null +++ b/arch/arm/lib/io-readsb.S @@ -0,0 +1,111 @@ +/* + * linux/arch/arm/lib/io-readsb.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/hardware.h> + +.insb_align: rsb ip, ip, #4 + cmp ip, r2 + movgt ip, r2 + cmp ip, #2 + ldrb r3, [r0] + strb r3, [r1], #1 + ldrgeb r3, [r0] + strgeb r3, [r1], #1 + ldrgtb r3, [r0] + strgtb r3, [r1], #1 + subs r2, r2, ip + bne .insb_aligned + +ENTRY(__arch_readsb) + ands ip, r1, #3 + bne .insb_align + +.insb_aligned: stmfd sp!, {r4 - r6, lr} + + subs r2, r2, #16 + bmi .insb_no_16 + +.insb_16_lp: ldrb r3, [r0] + ldrb r4, [r0] + orr r3, r3, r4, lsl #8 + ldrb r4, [r0] + orr r3, r3, r4, lsl #16 + ldrb r4, [r0] + orr r3, r3, r4, lsl #24 + ldrb r4, [r0] + ldrb r5, [r0] + orr r4, r4, r5, lsl #8 + ldrb r5, [r0] + orr r4, r4, r5, lsl #16 + ldrb r5, [r0] + orr r4, r4, r5, lsl #24 + ldrb r5, [r0] + ldrb r6, [r0] + orr r5, r5, r6, lsl #8 + ldrb r6, [r0] + orr r5, r5, r6, lsl #16 + ldrb r6, [r0] + orr r5, r5, r6, lsl #24 + ldrb r6, [r0] + ldrb ip, [r0] + orr r6, r6, ip, lsl #8 + ldrb ip, [r0] + orr r6, r6, ip, lsl #16 + ldrb ip, [r0] + orr r6, r6, ip, lsl #24 + stmia r1!, {r3 - r6} + subs r2, r2, #16 + bpl .insb_16_lp + + tst r2, #15 + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + +.insb_no_16: tst r2, #8 + beq .insb_no_8 + + ldrb r3, [r0] + ldrb r4, [r0] + orr r3, r3, r4, lsl #8 + ldrb r4, [r0] + orr r3, r3, r4, lsl #16 + ldrb r4, [r0] + orr r3, r3, r4, lsl #24 + ldrb r4, [r0] + ldrb r5, [r0] + orr r4, r4, r5, lsl #8 + ldrb r5, [r0] + orr r4, r4, r5, lsl #16 + ldrb r5, [r0] + orr r4, r4, r5, lsl #24 + stmia r1!, {r3, r4} + +.insb_no_8: tst r2, #4 + bne .insb_no_4 + + ldrb r3, [r0] + ldrb r4, [r0] + orr r3, r3, r4, lsl #8 + ldrb r4, [r0] + orr r3, r3, r4, lsl #16 + ldrb r4, [r0] + orr r3, r3, r4, lsl #24 + str r3, [r1], #4 + +.insb_no_4: ands r2, r2, #3 + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + cmp r2, #2 + ldrb r3, [r0] + strb r3, [r1], #1 + ldrgeb r3, [r0] + strgeb r3, [r1], #1 + ldrgtb r3, [r0] + strgtb r3, [r1] + LOADREGS(fd, sp!, {r4 - r6, pc}) diff --git a/arch/arm/lib/io-readsl.S b/arch/arm/lib/io-readsl.S new file mode 100644 index 000000000..530175485 --- /dev/null +++ b/arch/arm/lib/io-readsl.S @@ -0,0 +1,65 @@ +/* + * linux/arch/arm/lib/io-readsb.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/hardware.h> + +ENTRY(__arch_readsl) + ands ip, r1, #3 + bne 2f + +1: ldr r3, [r0] + str r3, [r1], #4 + subs r2, r2, #1 + bne 1b + mov pc, lr + +2: cmp ip, #2 + ldr ip, [r0] + blt 4f + bgt 6f + + strh ip, [r1], #2 + mov ip, ip, lsr #16 +3: subs r2, r2, #1 + ldrne r3, [r0] + orrne ip, ip, r3, lsl #16 + strne ip, [r1], #4 + movne ip, r3, lsr #16 + bne 3b + strh ip, [r1], #2 + mov pc, lr + +4: strb ip, [r1], #1 + mov ip, ip, lsr #8 + strh ip, [r1], #2 + mov ip, ip, lsr #16 +5: subs r2, r2, #1 + ldrne r3, [r0] + orrne ip, ip, r3, lsl #8 + strne ip, [r1], #4 + movne ip, r3, lsr #24 + bne 5b + strb ip, [r1], #1 + mov pc, lr + +6: strb ip, [r1], #1 + mov ip, ip, lsr #8 +7: subs r2, r2, #1 + ldrne r3, [r0] + orrne ip, ip, r3, lsl #24 + strne ip, [r1], #4 + movne ip, r3, lsr #8 + bne 7b + strb ip, [r1], #1 + mov ip, ip, lsr #8 + strh ip, [r1], #2 + mov pc, lr + diff --git a/arch/arm/lib/io-readsw-armv3.S b/arch/arm/lib/io-readsw-armv3.S new file mode 100644 index 000000000..65fb94e2f --- /dev/null +++ b/arch/arm/lib/io-readsw-armv3.S @@ -0,0 +1,102 @@ +/* + * linux/arch/arm/lib/io-readsb.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/hardware.h> + +.insw_bad_alignment: + adr r0, .insw_bad_align_msg + mov r2, lr + b SYMBOL_NAME(panic) +.insw_bad_align_msg: + .asciz "insw: bad buffer alignment (0x%p, lr=0x%08lX)\n" + .align + +.insw_align: tst r1, #1 + bne .insw_bad_alignment + + ldr r3, [r0] + strb r3, [r1], #1 + mov r3, r3, lsr #8 + strb r3, [r1], #1 + + subs r2, r2, #1 + RETINSTR(moveq, pc, lr) + +ENTRY(__arch_readsw) + tst r1, #3 + bne .insw_align + +.insw_aligned: mov ip, #0xff + orr ip, ip, ip, lsl #8 + stmfd sp!, {r4, r5, r6, lr} + + subs r2, r2, #8 + bmi .no_insw_8 + +.insw_8_lp: ldr r3, [r0] + and r3, r3, ip + ldr r4, [r0] + orr r3, r3, r4, lsl #16 + + ldr r4, [r0] + and r4, r4, ip + ldr r5, [r0] + orr r4, r4, r5, lsl #16 + + ldr r5, [r0] + and r5, r5, ip + ldr r6, [r0] + orr r5, r5, r6, lsl #16 + + ldr r6, [r0] + and r6, r6, ip + ldr lr, [r0] + orr r6, r6, lr, lsl #16 + + stmia r1!, {r3 - r6} + subs r2, r2, #8 + bpl .insw_8_lp + tst r2, #7 + LOADREGS(eqfd, sp!, {r4, r5, r6, pc}) + +.no_insw_8: tst r2, #4 + beq .no_insw_4 + + ldr r3, [r0] + and r3, r3, ip + ldr r4, [r0] + orr r3, r3, r4, lsl #16 + + ldr r4, [r0] + and r4, r4, ip + ldr r5, [r0] + orr r4, r4, r5, lsl #16 + + stmia r1!, {r3, r4} + +.no_insw_4: tst r2, #2 + beq .no_insw_2 + + ldr r3, [r0] + and r3, r3, ip + ldr r4, [r0] + orr r3, r3, r4, lsl #16 + + str r3, [r1], #4 + +.no_insw_2: tst r2, #1 + ldrne r3, [r0] + strneb r3, [r1], #1 + movne r3, r3, lsr #8 + strneb r3, [r1] + LOADREGS(fd, sp!, {r4, r5, r6, pc}) + + diff --git a/arch/arm/lib/io-readsw-armv4.S b/arch/arm/lib/io-readsw-armv4.S new file mode 100644 index 000000000..6f1750a49 --- /dev/null +++ b/arch/arm/lib/io-readsw-armv4.S @@ -0,0 +1,87 @@ +/* + * linux/arch/arm/lib/io-readsb.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/hardware.h> + +.insw_bad_alignment: + adr r0, .insw_bad_align_msg + mov r2, lr + b SYMBOL_NAME(panic) +.insw_bad_align_msg: + .asciz "insw: bad buffer alignment (0x%p, lr=0x%08lX)\n" + .align + +.insw_align: tst r1, #1 + bne .insw_bad_alignment + + ldrh r3, [r0] + strh r3, [r1], #2 + + subs r2, r2, #1 + RETINSTR(moveq, pc, lr) + +ENTRY(__arch_readsw) + tst r1, #3 + bne .insw_align + + stmfd sp!, {r4, r5, lr} + + subs r2, r2, #8 + bmi .no_insw_8 + +.insw_8_lp: ldrh r3, [r0] + ldrh r4, [r0] + orr r3, r3, r4, lsl #16 + + ldrh r4, [r0] + ldrh r5, [r0] + orr r4, r4, r5, lsl #16 + + ldrh r5, [r0] + ldrh r6, [r0] + orr r5, r5, r6, lsl #16 + + ldrh ip, [r0] + ldrh lr, [r0] + orr ip, ip, lr, lsl #16 + + stmia r1!, {r3 - r5, ip} + subs r2, r2, #8 + bpl .insw_8_lp + tst r2, #7 + LOADREGS(eqfd, sp!, {r4, r5, pc}) + +.no_insw_8: tst r2, #4 + beq .no_insw_4 + + ldrh r3, [r0] + ldrh r4, [r0] + orr r3, r3, r4, lsl #16 + + ldrh r4, [r0] + ldrh ip, [r0] + orr r4, r4, ip, lsl #16 + + stmia r1!, {r3, r4} + +.no_insw_4: tst r2, #2 + beq .no_insw_2 + + ldrh r3, [r0] + ldrh ip, [r0] + orr r3, r3, ip, lsl #16 + + str r3, [r1], #4 + +.no_insw_2: tst r2, #1 + ldrneh r3, [r0] + strneh r3, [r1] + LOADREGS(fd, sp!, {r4, r5, pc}) diff --git a/arch/arm/lib/io-writesb.S b/arch/arm/lib/io-writesb.S new file mode 100644 index 000000000..b919fdaad --- /dev/null +++ b/arch/arm/lib/io-writesb.S @@ -0,0 +1,115 @@ +/* + * linux/arch/arm/lib/io-readsb.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/hardware.h> + +.outsb_align: rsb ip, ip, #4 + cmp ip, r2 + mov ip, r2 + cmp ip, #2 + ldrb r3, [r1], #1 + strb r3, [r0] + ldrgeb r3, [r1], #1 + strgeb r3, [r0] + ldrgtb r3, [r1], #1 + strgtb r3, [r0] + subs r2, r2, ip + bne .outsb_aligned + +ENTRY(__arch_writesb) + ands ip, r1, #3 + bne .outsb_align + +.outsb_aligned: stmfd sp!, {r4 - r6, lr} + + subs r2, r2, #16 + bmi .outsb_no_16 + +.outsb_16_lp: ldmia r1!, {r3 - r6} + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + + strb r5, [r0] + mov r5, r5, lsr #8 + strb r5, [r0] + mov r5, r5, lsr #8 + strb r5, [r0] + mov r5, r5, lsr #8 + strb r5, [r0] + + strb r6, [r0] + mov r6, r6, lsr #8 + strb r6, [r0] + mov r6, r6, lsr #8 + strb r6, [r0] + mov r6, r6, lsr #8 + strb r6, [r0] + subs r2, r2, #16 + bpl .outsb_16_lp + + tst r2, #15 + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + +.outsb_no_16: tst r2, #8 + beq .outsb_no_8 + + ldmia r1, {r3, r4} + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + +.outsb_no_8: tst r2, #4 + bne .outsb_no_4 + + ldr r3, [r1], #4 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + +.outsb_no_4: ands r2, r2, #3 + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + cmp r2, #2 + ldrb r3, [r1], #1 + strb r3, [r0] + ldrgeb r3, [r1], #1 + strgeb r3, [r0] + ldrgtb r3, [r1] + strgtb r3, [r0] + LOADREGS(fd, sp!, {r4 - r6, pc}) diff --git a/arch/arm/lib/io-writesl.S b/arch/arm/lib/io-writesl.S new file mode 100644 index 000000000..ccda08c39 --- /dev/null +++ b/arch/arm/lib/io-writesl.S @@ -0,0 +1,55 @@ +/* + * linux/arch/arm/lib/io-readsb.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/hardware.h> + +ENTRY(__arch_writesl) + ands ip, r1, #3 + bne 2f + +1: ldr r3, [r1], #4 + str r3, [r0] + subs r2, r2, #1 + bne 1b + mov pc, lr + +2: bic r1, r1, #3 + cmp ip, #2 + ldr ip, [r1], #4 + mov ip, ip, lsr #16 + blt 4f + bgt 5f + +3: ldr r3, [r1], #4 + orr ip, ip, r3, lsl #16 + str ip, [r0] + mov ip, r3, lsr #16 + subs r2, r2, #1 + bne 3b + mov pc, lr + +4: ldr r3, [r1], #4 + orr ip, ip, r3, lsl #8 + str ip, [r0] + mov ip, r3, lsr #24 + subs r2, r2, #1 + bne 4b + mov pc, lr + +5: ldr r3, [r1], #4 + orr ip, ip, r3, lsl #24 + str ip, [r0] + mov ip, r3, lsr #8 + subs r2, r2, #1 + bne 5b + mov pc, lr + + diff --git a/arch/arm/lib/io-writesw-armv3.S b/arch/arm/lib/io-writesw-armv3.S new file mode 100644 index 000000000..29c94cc3d --- /dev/null +++ b/arch/arm/lib/io-writesw-armv3.S @@ -0,0 +1,125 @@ +/* + * linux/arch/arm/lib/io-readsb.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/hardware.h> + +.outsw_bad_alignment: + adr r0, .outsw_bad_align_msg + mov r2, lr + b SYMBOL_NAME(panic) +.outsw_bad_align_msg: + .asciz "outsw: bad buffer alignment (0x%p, lr=0x%08lX)\n" + .align + +.outsw_align: tst r1, #1 + bne .outsw_bad_alignment + + add r1, r1, #2 + + ldr r3, [r1, #-4] + mov r3, r3, lsr #16 + orr r3, r3, r3, lsl #16 + str r3, [r0] + subs r2, r2, #1 + RETINSTR(moveq, pc, lr) + +ENTRY(__arch_writesw) + tst r1, #3 + bne .outsw_align + +.outsw_aligned: stmfd sp!, {r4, r5, r6, lr} + + subs r2, r2, #8 + bmi .no_outsw_8 +.outsw_8_lp: ldmia r1!, {r3, r4, r5, r6} + + mov ip, r3, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r3, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + mov ip, r4, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r4, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + mov ip, r5, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r5, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + mov ip, r6, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r6, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + subs r2, r2, #8 + bpl .outsw_8_lp + tst r2, #7 + LOADREGS(eqfd, sp!, {r4, r5, r6, pc}) + +.no_outsw_8: tst r2, #4 + beq .no_outsw_4 + + ldmia r1!, {r3, r4} + + mov ip, r3, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r3, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + mov ip, r4, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r4, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + +.no_outsw_4: tst r2, #2 + beq .no_outsw_2 + + ldr r3, [r1], #4 + + mov ip, r3, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r3, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + +.no_outsw_2: tst r2, #1 + + ldrne r3, [r1] + + movne ip, r3, lsl #16 + orrne ip, ip, ip, lsr #16 + strne ip, [r0] + + LOADREGS(fd, sp!, {r4, r5, r6, pc}) + + diff --git a/arch/arm/lib/io-writesw-armv4.S b/arch/arm/lib/io-writesw-armv4.S new file mode 100644 index 000000000..0f96d1325 --- /dev/null +++ b/arch/arm/lib/io-writesw-armv4.S @@ -0,0 +1,79 @@ +/* + * linux/arch/arm/lib/io-readsb.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/hardware.h> + +.outsw_bad_alignment: + adr r0, .outsw_bad_align_msg + mov r2, lr + b SYMBOL_NAME(panic) +.outsw_bad_align_msg: + .asciz "outsw: bad buffer alignment (0x%p, lr=0x%08lX)\n" + .align + +.outsw_align: tst r1, #1 + bne .outsw_bad_alignment + + ldrh r3, [r1], #2 + strh r3, [r0] + + subs r2, r2, #1 + RETINSTR(moveq, pc, lr) + +ENTRY(__arch_writesw) + tst r1, #3 + bne .outsw_align + + subs r2, r2, #8 + bmi .no_outsw_8 + + stmfd sp!, {r4, r5, lr} + +.outsw_8_lp: ldmia r1!, {r3, r4, r5, ip} + + strh r3, [r0] + mov r3, r3, lsr #16 + strh r3, [r0] + strh r4, [r0] + mov r4, r4, lsr #16 + strh r4, [r0] + strh r5, [r0] + mov r5, r5, lsr #16 + strh r5, [r0] + strh ip, [r0] + mov ip, ip, lsr #16 + strh ip, [r0] + + subs r2, r2, #8 + bpl .outsw_8_lp + ldmfd sp!, {r4, r5, lr} + tst r2, #7 + RETINSTR(moveq, pc, lr) + +.no_outsw_8: tst r2, #4 + ldmneia r1!, {r3, ip} + strneh r3, [r0] + movne r3, r3, lsr #16 + strneh r3, [r0] + strneh ip, [r0] + movne ip, ip, lsr #16 + strneh ip, [r0] + tst r2, #2 + ldrne r3, [r1], #4 + strneh r3, [r0] + movne r3, r3, lsr #16 + strneh r3, [r0] + tst r2, #1 + ldrneh r3, [r1] + strneh r3, [r0] + RETINSTR(mov, pc, lr) + + diff --git a/arch/arm/mach-footbridge/netwinder-hw.c b/arch/arm/mach-footbridge/netwinder-hw.c index 4b47b6e47..1a7a790cc 100644 --- a/arch/arm/mach-footbridge/netwinder-hw.c +++ b/arch/arm/mach-footbridge/netwinder-hw.c @@ -65,9 +65,9 @@ static inline void wb977_ww(int reg, int val) */ spinlock_t gpio_lock = SPIN_LOCK_UNLOCKED; -static unsigned int current_gpio_op = 0; -static unsigned int current_gpio_io = 0; -static unsigned int current_cpld = 0; +static unsigned int current_gpio_op; +static unsigned int current_gpio_io; +static unsigned int current_cpld; void gpio_modify_op(int mask, int set) { diff --git a/arch/arm/mm/fault-common.c b/arch/arm/mm/fault-common.c index 0e198ab8a..1cbdd7790 100644 --- a/arch/arm/mm/fault-common.c +++ b/arch/arm/mm/fault-common.c @@ -126,6 +126,39 @@ out: return fault; } +static int __do_vmalloc_fault(unsigned long addr, struct mm_struct *mm) +{ + /* Synchronise this task's top level page-table + * with the 'reference' page table. + */ + int offset = __pgd_offset(addr); + pgd_t *pgd, *pgd_k; + pmd_t *pmd, *pmd_k; + + pgd_k = init_mm.pgd + offset; + if (!pgd_present(*pgd_k)) + goto bad_area; + + pgd = mm->pgd + offset; +#if 0 /* note that we are two-level */ + if (!pgd_present(*pgd)) + set_pgd(pgd, *pgd_k); +#endif + + pmd_k = pmd_offset(pgd_k, addr); + if (pmd_none(*pmd_k)) + goto bad_area; + + pmd = pmd_offset(pgd, addr); + if (!pmd_none(*pmd)) + goto bad_area; + set_pmd(pmd, *pmd_k); + return 1; + +bad_area: + return -2; +} + static int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs) { struct task_struct *tsk; @@ -137,6 +170,18 @@ static int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs) mm = tsk->mm; /* + * We fault-in kernel-space virtual memory on-demand. The + * 'reference' page table is init_mm.pgd. + * + * NOTE! We MUST NOT take any locks for this case. We may + * be in an interrupt or a critical region, and should + * only copy the information from the master page table, + * nothing more. + */ + if (addr >= TASK_SIZE) + goto vmalloc_fault; + + /* * If we're in an interrupt or have no user * context, we must not take the fault.. */ @@ -147,6 +192,7 @@ static int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs) fault = __do_page_fault(mm, addr, mode, tsk); up(&mm->mmap_sem); +ret: /* * Handle the "normal" case first */ @@ -240,4 +286,8 @@ no_context: do_exit(SIGKILL); return 0; + +vmalloc_fault: + fault = __do_vmalloc_fault(addr, mm); + goto ret; } diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index ea833c58d..bfa085a52 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -377,34 +377,48 @@ static int __init check_initrd(struct meminfo *mi) /* * Reserve the various regions of node 0 */ -static inline void reserve_node_zero(unsigned int bootmap_pfn, unsigned int bootmap_pages) +static __init void reserve_node_zero(unsigned int bootmap_pfn, unsigned int bootmap_pages) { + pg_data_t *pgdat = NODE_DATA(0); + /* * Register the kernel text and data with bootmem. * Note that this can only be in node 0. */ - reserve_bootmem_node(NODE_DATA(0), __pa(&_stext), &_end - &_stext); + reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext); #ifdef CONFIG_CPU_32 /* * Reserve the page tables. These are already in use, * and can only be in node 0. */ - reserve_bootmem_node(NODE_DATA(0), __pa(swapper_pg_dir), + reserve_bootmem_node(pgdat, __pa(swapper_pg_dir), PTRS_PER_PGD * sizeof(void *)); -#else - /* - * Stop this memory from being grabbed - its special DMA - * memory that is required for the screen. - */ - reserve_bootmem_node(NODE_DATA(0), 0x02000000, 0x00080000); #endif /* * And don't forget to reserve the allocator bitmap, * which will be freed later. */ - reserve_bootmem_node(NODE_DATA(0), bootmap_pfn << PAGE_SHIFT, + reserve_bootmem_node(pgdat, bootmap_pfn << PAGE_SHIFT, bootmap_pages << PAGE_SHIFT); + + /* + * Hmm... This should go elsewhere, but we really really + * need to stop things allocating the low memory; we need + * a better implementation of GFP_DMA which does not assume + * that DMA-able memory starts at zero. + */ + if (machine_is_integrator()) + reserve_bootmem_node(pgdat, 0, __pa(swapper_pg_dir)); + /* + * These should likewise go elsewhere. They pre-reserve + * the screen memory region at the start of main system + * memory. + */ + if (machine_is_archimedes() || machine_is_a5k()) + reserve_bootmem_node(pgdat, 0x02000000, 0x00080000); + if (machine_is_p720t()) + reserve_bootmem_node(pgdat, 0xc0000000, 0x00014000); } /* @@ -412,11 +426,12 @@ static inline void reserve_node_zero(unsigned int bootmap_pfn, unsigned int boot */ static inline void free_bootmem_node_bank(int node, struct meminfo *mi) { + pg_data_t *pgdat = NODE_DATA(node); int bank; for (bank = 0; bank < mi->nr_banks; bank++) if (mi->bank[bank].node == node) - free_bootmem_node(NODE_DATA(node), mi->bank[bank].start, + free_bootmem_node(pgdat, mi->bank[bank].start, mi->bank[bank].size); } @@ -632,9 +647,11 @@ static inline void free_area(unsigned long addr, unsigned long end, char *s) void free_initmem(void) { - free_area((unsigned long)(&__init_begin), - (unsigned long)(&__init_end), - "init"); + if (!machine_is_integrator()) { + free_area((unsigned long)(&__init_begin), + (unsigned long)(&__init_end), + "init"); + } } #ifdef CONFIG_BLK_DEV_INITRD diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index 2ace55d47..d96fcbccb 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -361,6 +361,7 @@ void __init memtable_init(struct meminfo *mi) p ++; } +#ifdef FLUSH_BASE p->physical = FLUSH_BASE_PHYS; p->virtual = FLUSH_BASE; p->length = PGDIR_SIZE; @@ -371,6 +372,7 @@ void __init memtable_init(struct meminfo *mi) p->bufferable = 1; p ++; +#endif #ifdef FLUSH_BASE_MINICACHE p->physical = FLUSH_BASE_PHYS + PGDIR_SIZE; diff --git a/arch/arm/mm/proc-arm720.S b/arch/arm/mm/proc-arm720.S index 13620ad5f..e6fc86bd1 100644 --- a/arch/arm/mm/proc-arm720.S +++ b/arch/arm/mm/proc-arm720.S @@ -139,7 +139,7 @@ Ldata_ldmstm: tst r4, #1 << 21 @ check writeback bit Ldata_saver7: str r7, [sp, r5, lsr #14] @ Put register Ldata_simple: mrc p15, 0, r0, c6, c0, 0 @ get FAR mrc p15, 0, r3, c5, c0, 0 @ get FSR - and r3, r3, #15 + and r3, r3, #255 mov pc, lr ENTRY(cpu_arm720_data_abort) @@ -155,7 +155,7 @@ ENTRY(cpu_arm720_data_abort) b Ldata_unknown b Ldata_unknown b Ldata_lateldrpostconst @ ldr rd, [rn], #m - b Ldata_lateldrpreconst @ ldr rd, [rn, #m] @ RegVal + b Ldata_lateldrpreconst @ ldr rd, [rn, #m] b Ldata_lateldrpostreg @ ldr rd, [rn], rm b Ldata_lateldrprereg @ ldr rd, [rn, rm] b Ldata_ldmstm @ ldm*a rn, <rlist> @@ -177,25 +177,14 @@ Ldata_lateldrhpre: tst r4, #1 << 21 @ check writeback bit beq Ldata_simple Ldata_lateldrhpost: - tst r4, #1 << 22 @ check if register or immediate offset - beq Ldata_lateldrhpostreg -Ldata_lateldrhpostconst: - and r2, r4, #0xf @ load and clear low nibble of const offset - and r5, r4, #0xf00 @ load and clear high nibble of const offset - orrs r2, r2, r5, lsr #4 @ create offset - beq Ldata_simple @ don't have to do anything if zero - and r5, r4, #0xf << 16 @ get Rn - ldr r0, [sp, r5, lsr #14] + and r5, r4, #0x00f @ get Rm / low nibble of immediate value + tst r4, #1 << 22 @ if (immediate offset) + andne r2, r4, #0xf00 @ { immediate high nibble + orrne r2, r5, r2, lsr #4 @ combine nibbles } else + ldreq r2, [sp, r5, lsl #2] @ { load Rm value } + and r5, r4, #15 << 16 @ get Rn + ldr r0, [sp, r5, lsr #14] @ load Rn value tst r4, #1 << 23 @ U bit - subne r7, r0, r2, lsr #20 - addeq r7, r0, r2, lsr #20 - b Ldata_saver7 -Ldata_lateldrhpostreg: - and r5, r4, #0xf - ldr r2, [sp, r5, lsl #2] @ get Rm - and r5, r4, #0xf << 16 - ldr r0, [sp, r5, lsr #14] @ get Rn - tst r4, #1 << 23 subne r7, r0, r2 addeq r7, r0, r2 b Ldata_saver7 @@ -385,7 +374,7 @@ ENTRY(cpu_arm720_reset) cpu_armvlsi_name: - .asciz "ARM/VLSI" + .asciz "ARM" cpu_arm720_name: .asciz "ARM720T" .align @@ -471,8 +460,8 @@ cpu_elf_name: .asciz "v4" __arm720_proc_info: .long 0x41807200 @ cpu_val .long 0xffffff00 @ cpu_mask - .long 0x00000c0e @ __cpu_mmu_flags - b __arm720_setup @ --cpu_flush + .long 0x00000c1e @ section_mmu_flags + b __arm720_setup @ cpu_flush .long cpu_arch_name @ arch_name .long cpu_elf_name @ elf_name .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT @ elf_hwcap diff --git a/arch/arm/nwfpe/double_cpdo.c b/arch/arm/nwfpe/double_cpdo.c index 0415f31e0..5e5d4fdcf 100644 --- a/arch/arm/nwfpe/double_cpdo.c +++ b/arch/arm/nwfpe/double_cpdo.c @@ -44,7 +44,7 @@ unsigned int DoubleCPDO(const unsigned int opcode) float64 rFm, rFn; unsigned int Fd, Fm, Fn, nRc = 1; - //fp_printk("DoubleCPDO(0x%08x)\n",opcode); + //printk("DoubleCPDO(0x%08x)\n",opcode); Fm = getFm(opcode); if (CONSTANT_FM(opcode)) @@ -65,7 +65,7 @@ unsigned int DoubleCPDO(const unsigned int opcode) case typeExtended: // !! patb - //fp_printk("not implemented! why not?\n"); + //printk("not implemented! why not?\n"); //!! ScottB // should never get here, if extended involved // then other operand should be promoted then diff --git a/arch/arm/nwfpe/extended_cpdo.c b/arch/arm/nwfpe/extended_cpdo.c index 810f57102..762b1a0ef 100644 --- a/arch/arm/nwfpe/extended_cpdo.c +++ b/arch/arm/nwfpe/extended_cpdo.c @@ -42,7 +42,7 @@ unsigned int ExtendedCPDO(const unsigned int opcode) floatx80 rFm, rFn; unsigned int Fd, Fm, Fn, nRc = 1; - //fp_printk("ExtendedCPDO(0x%08x)\n",opcode); + //printk("ExtendedCPDO(0x%08x)\n",opcode); Fm = getFm(opcode); if (CONSTANT_FM(opcode)) diff --git a/arch/arm/nwfpe/fpa11_cpdo.c b/arch/arm/nwfpe/fpa11_cpdo.c index fd39a59f7..b2eaf1aad 100644 --- a/arch/arm/nwfpe/fpa11_cpdo.c +++ b/arch/arm/nwfpe/fpa11_cpdo.c @@ -30,7 +30,7 @@ unsigned int EmulateCPDO(const unsigned int opcode) { unsigned int Fd, nType, nDest, nRc = 1; - //fp_printk("EmulateCPDO(0x%08x)\n",opcode); + //printk("EmulateCPDO(0x%08x)\n",opcode); /* Get the destination size. If not valid let Linux perform an invalid instruction trap. */ diff --git a/arch/arm/nwfpe/fpa11_cpdt.c b/arch/arm/nwfpe/fpa11_cpdt.c index 0bad18769..d6a7bdc4a 100644 --- a/arch/arm/nwfpe/fpa11_cpdt.c +++ b/arch/arm/nwfpe/fpa11_cpdt.c @@ -189,7 +189,7 @@ unsigned int PerformLDF(const unsigned int opcode) unsigned int *pBase, *pAddress, *pFinal, nRc = 1, write_back = WRITE_BACK(opcode); - //fp_printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); + //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); pBase = (unsigned int*)readRegister(getRn(opcode)); if (REG_PC == getRn(opcode)) @@ -223,7 +223,7 @@ unsigned int PerformSTF(const unsigned int opcode) unsigned int *pBase, *pAddress, *pFinal, nRc = 1, write_back = WRITE_BACK(opcode); - //fp_printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); + //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); SetRoundingMode(ROUND_TO_NEAREST); pBase = (unsigned int*)readRegister(getRn(opcode)); @@ -322,7 +322,7 @@ unsigned int EmulateCPDT(const unsigned int opcode) { unsigned int nRc = 0; - //fp_printk("EmulateCPDT(0x%08x)\n",opcode); + //printk("EmulateCPDT(0x%08x)\n",opcode); if (LDF_OP(opcode)) { diff --git a/arch/arm/nwfpe/fpa11_cprt.c b/arch/arm/nwfpe/fpa11_cprt.c index d479ee932..c17c69465 100644 --- a/arch/arm/nwfpe/fpa11_cprt.c +++ b/arch/arm/nwfpe/fpa11_cprt.c @@ -44,7 +44,7 @@ unsigned int EmulateCPRT(const unsigned int opcode) { unsigned int nRc = 1; - //fp_printk("EmulateCPRT(0x%08x)\n",opcode); + //printk("EmulateCPRT(0x%08x)\n",opcode); if (opcode & 0x800000) { @@ -188,7 +188,7 @@ static unsigned int PerformComparison(const unsigned int opcode) int n_flag = opcode & 0x200000; /* 1 if CNxx */ unsigned int flags = 0; - //fp_printk("PerformComparison(0x%08x)\n",opcode); + //printk("PerformComparison(0x%08x)\n",opcode); Fn = getFn(opcode); Fm = getFm(opcode); @@ -201,21 +201,21 @@ static unsigned int PerformComparison(const unsigned int opcode) switch (fpa11->fType[Fn]) { case typeSingle: - //fp_printk("single.\n"); + //printk("single.\n"); if (float32_is_nan(fpa11->fpreg[Fn].fSingle)) goto unordered; rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); break; case typeDouble: - //fp_printk("double.\n"); + //printk("double.\n"); if (float64_is_nan(fpa11->fpreg[Fn].fDouble)) goto unordered; rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); break; case typeExtended: - //fp_printk("extended.\n"); + //printk("extended.\n"); if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended)) goto unordered; rFn = fpa11->fpreg[Fn].fExtended; @@ -226,32 +226,32 @@ static unsigned int PerformComparison(const unsigned int opcode) if (CONSTANT_FM(opcode)) { - //fp_printk("Fm is a constant: #%d.\n",Fm); + //printk("Fm is a constant: #%d.\n",Fm); rFm = getExtendedConstant(Fm); if (floatx80_is_nan(rFm)) goto unordered; } else { - //fp_printk("Fm = r%d which contains a ",Fm); + //printk("Fm = r%d which contains a ",Fm); switch (fpa11->fType[Fm]) { case typeSingle: - //fp_printk("single.\n"); + //printk("single.\n"); if (float32_is_nan(fpa11->fpreg[Fm].fSingle)) goto unordered; rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle); break; case typeDouble: - //fp_printk("double.\n"); + //printk("double.\n"); if (float64_is_nan(fpa11->fpreg[Fm].fDouble)) goto unordered; rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble); break; case typeExtended: - //fp_printk("extended.\n"); + //printk("extended.\n"); if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended)) goto unordered; rFm = fpa11->fpreg[Fm].fExtended; diff --git a/arch/arm/nwfpe/fpmodule.c b/arch/arm/nwfpe/fpmodule.c index 9d4f1570d..24fa2775f 100644 --- a/arch/arm/nwfpe/fpmodule.c +++ b/arch/arm/nwfpe/fpmodule.c @@ -46,7 +46,6 @@ extern FPA11 *fpa11; typedef struct task_struct* PTASK; #ifdef MODULE -int fp_printk(const char *,...); void fp_send_sig(unsigned long sig, PTASK p, int priv); #if LINUX_VERSION_CODE > 0x20115 MODULE_AUTHOR("Scott Bambrough <scottb@rebel.com>"); @@ -54,7 +53,6 @@ MODULE_DESCRIPTION("NWFPE floating point emulator"); #endif #else -#define fp_printk printk #define fp_send_sig send_sig #define kern_fp_enter fp_enter #endif @@ -74,23 +72,14 @@ extern void nwfpe_enter(void); /* Address of user registers on the kernel stack. */ unsigned int *userRegisters; -void __init fpe_version(void) -{ - static const char szTitle[] = "<4>NetWinder Floating Point Emulator "; - static const char szVersion[] = "V0.95 "; - static const char szCopyright[] = "(c) 1998-1999 Rebel.com\n"; - fp_printk(szTitle); - fp_printk(szVersion); - fp_printk(szCopyright); -} - int __init fpe_init(void) { if (sizeof(FPA11) > sizeof(union fp_state)) printk(KERN_ERR "nwfpe: bad structure size\n"); else { /* Display title, version and copyright information. */ - fpe_version(); + printk(KERN_WARNING "NetWinder Floating Point Emulator V0.95 " + "(c) 1998-1999 Rebel.com\n"); /* Save pointer to the old FP handler and then patch ourselves in */ orig_fp_enter = kern_fp_enter; diff --git a/arch/arm/nwfpe/softfloat.c b/arch/arm/nwfpe/softfloat.c index a7fc76cc8..a6e000011 100644 --- a/arch/arm/nwfpe/softfloat.c +++ b/arch/arm/nwfpe/softfloat.c @@ -39,7 +39,7 @@ and exception flags. */ int8 float_rounding_mode = float_round_nearest_even; int8 floatx80_rounding_precision = 80; -int8 float_exception_flags = 0; +int8 float_exception_flags; /* ------------------------------------------------------------------------------- @@ -418,9 +418,8 @@ static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig ) || ( ( zExp == 0x7FD ) && ( (sbits64) ( zSig + roundIncrement ) < 0 ) ) ) { - //register int lr; - //__asm__("mov %0, lr" :: "g" (lr)); - //fp_printk("roundAndPackFloat64 called from 0x%08x\n",lr); + //register int lr = __builtin_return_address(0); + //printk("roundAndPackFloat64 called from 0x%08x\n",lr); float_raise( float_flag_overflow | float_flag_inexact ); return packFloat64( zSign, 0x7FF, 0 ) - ( roundIncrement == 0 ); } diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index f3d1fb0b1..ff7ccec77 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -1,7 +1,10 @@ # Database of machine macros and numbers # -# To add an entry into this database, please see -# Documentation/arm/README +# Please do not send patches to this file; it is automatically generated! +# To add an entry into this database, please see Documentation/arm/README, +# or contact rmk@arm.linux.org.uk +# +# Last update: Mon Nov 20 22:59:11 2000 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -14,7 +17,7 @@ cats ARCH_CATS CATS 6 tbox ARCH_TBOX TBOX 7 co285 ARCH_CO285 CO285 8 clps7110 ARCH_CLPS7110 CLPS7110 9 -arc ARCH_ARC ARCHIMEDES 10 +archimedes ARCH_ARC ARCHIMEDES 10 a5k ARCH_A5K A5K 11 etoile ARCH_ETOILE ETOILE 12 lacie_nas ARCH_LACIE_NAS LACIE_NAS 13 @@ -28,7 +31,7 @@ pleb SA1100_PLEB PLEB 20 integrator ARCH_INTEGRATOR INTEGRATOR 21 bitsy SA1100_BITSY BITSY 22 ixp1200 ARCH_IXP1200 IXP1200 23 -thinclient SA1100_THINCLIENT THINCLIENT 24 +p720t ARCH_P720T P720T 24 assabet SA1100_ASSABET ASSABET 25 victor SA1100_VICTOR VICTOR 26 lart SA1100_LART LART 27 @@ -42,8 +45,16 @@ extenex1 SA1100_EXTENEX1 EXTENEX1 34 sherman SA1100_SHERMAN SHERMAN 35 accelent_sa SA1100_ACCELENT ACCELENT_SA 36 accelent_l7200 ARCH_L7200_ACCELENT ACCELENT_L7200 37 +netport SA1100_NETPORT NETPORT 38 +pangolin SA1100_PANGOLIN PANGOLIN 39 +yopy SA1100_YOPY YOPY 40 +sa1100 SA1100_SA1100 SA1100 41 +huw_webpanel ARCH_HUW_WEBPANEL HUW_WEBPANEL 42 +spotme ARCH_SPOTME SPOTME 43 +freebird ARCH_FREEBIRD FREEBIRD 44 +ti925 ARCH_TI925 TI925 45 +riscstation ARCH_RISCSTATION RISCSTATION 46 +cavy SA1100_CAVY CAVY 47 # The following are unallocated empeg SA1100_EMPEG EMPEG -tifon SA1100_TIFON TIFON -penny SA1100_PENNY PENNY diff --git a/arch/arm/vmlinux-armo.lds.in b/arch/arm/vmlinux-armo.lds.in index 5353e7f8f..0c0e720aa 100644 --- a/arch/arm/vmlinux-armo.lds.in +++ b/arch/arm/vmlinux-armo.lds.in @@ -9,6 +9,7 @@ SECTIONS . = TEXTADDR; .init : { + _stext = .; __init_begin = .; /* Init code and data */ *(.text.init) __proc_info_begin = .; diff --git a/arch/arm/vmlinux-armv.lds.in b/arch/arm/vmlinux-armv.lds.in index b54f2bd92..b0398852d 100644 --- a/arch/arm/vmlinux-armv.lds.in +++ b/arch/arm/vmlinux-armv.lds.in @@ -8,6 +8,7 @@ SECTIONS { . = TEXTADDR; .init : { /* Init code and data */ + _stext = .; __init_begin = .; *(.text.init) __proc_info_begin = .; diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S index 0da4e866e..c52b170ec 100644 --- a/arch/i386/boot/setup.S +++ b/arch/i386/boot/setup.S @@ -825,10 +825,18 @@ bootsect_panic_mess: # # Some machines have delusions that the keyboard buffer is always full # with no keyboard attached... +# +# If there is no keyboard controller, we will usually get 0xff +# to all the reads. With each IO taking a microsecond and +# a timeout of 100,000 iterations, this can take about half a +# second ("delay" == outb to port 0x80). That should be ok, +# and should also be plenty of time for a real keyboard controller +# to empty. +# empty_8042: pushl %ecx - movl $0x00FFFFFF, %ecx + movl $100000, %ecx empty_8042_loop: decl %ecx @@ -867,7 +875,7 @@ gettime: # Delay is needed after doing I/O delay: - jmp .+2 # jmp $+2 + outb %al,$0x80 ret # Descriptor tables diff --git a/arch/i386/config.in b/arch/i386/config.in index d6c63a8b8..87fc106f8 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -140,7 +140,7 @@ if [ "$CONFIG_MWINCHIP3D" = "y" ]; then fi tristate 'Toshiba Laptop support' CONFIG_TOSHIBA -tristate '/dev/cpu/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE +tristate '/dev/cpu/microcode - Intel IA32 CPU microcode support' CONFIG_MICROCODE tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR tristate '/dev/cpu/*/cpuid - CPU information support' CONFIG_X86_CPUID diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 9f8625c6e..bdcf8cf6b 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -649,20 +649,15 @@ CONFIG_USB_UHCI_ALT=y # CONFIG_USB_OHCI is not set # -# USB Devices +# USB Device Class drivers # -# CONFIG_USB_PRINTER is not set -# CONFIG_USB_SCANNER is not set # CONFIG_USB_AUDIO is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_IBMCAM is not set -# CONFIG_USB_OV511 is not set -# CONFIG_USB_DC2XX is not set +# CONFIG_USB_BLUETOOTH is not set CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_USS720 is not set -# CONFIG_USB_DABUSB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set # # USB Human Interface Devices (HID) @@ -673,6 +668,44 @@ CONFIG_USB_STORAGE=y # # +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_OV511 is not set +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DABUSB is not set + +# +# USB Network adaptors +# +# CONFIG_USB_PLUSB is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_NET1080 is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB misc drivers +# +# CONFIG_USB_RIO500 is not set + +# # Kernel hacking # # CONFIG_MAGIC_SYSRQ is not set diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index fc54896f8..4179c8f13 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -220,66 +220,19 @@ void __init setup_local_APIC (void) BUG(); /* - * Set up LVT0, LVT1: - * - * set up through-local-APIC on the BP's LINT0. This is not - * strictly necessery in pure symmetric-IO mode, but sometimes - * we delegate interrupts to the 8259A. - */ - /* - * TODO: set up through-local-APIC from through-I/O-APIC? --macro - */ - value = apic_read(APIC_LVT0) & APIC_LVT_MASKED; - if (!smp_processor_id() && (pic_mode || !value)) { - value = APIC_DM_EXTINT; - printk("enabled ExtINT on CPU#%d\n", smp_processor_id()); - } else { - value = APIC_DM_EXTINT | APIC_LVT_MASKED; - printk("masked ExtINT on CPU#%d\n", smp_processor_id()); - } - apic_write_around(APIC_LVT0, value); - - /* - * only the BP should see the LINT1 NMI signal, obviously. + * Intel recommends to set DFR, LDR and TPR before enabling + * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel + * document number 292116). So here it goes... */ - if (!smp_processor_id()) - value = APIC_DM_NMI; - else - value = APIC_DM_NMI | APIC_LVT_MASKED; - if (!APIC_INTEGRATED(ver)) /* 82489DX */ - value |= APIC_LVT_LEVEL_TRIGGER; - apic_write_around(APIC_LVT1, value); - - if (APIC_INTEGRATED(ver)) { /* !82489DX */ - maxlvt = get_maxlvt(); - if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ - apic_write(APIC_ESR, 0); - value = apic_read(APIC_ESR); - printk("ESR value before enabling vector: %08lx\n", value); - - value = ERROR_APIC_VECTOR; // enables sending errors - apic_write_around(APIC_LVTERR, value); - /* - * spec says clear errors after enabling vector. - */ - if (maxlvt > 3) - apic_write(APIC_ESR, 0); - value = apic_read(APIC_ESR); - printk("ESR value after enabling vector: %08lx\n", value); - } else - printk("No ESR for 82489DX.\n"); /* - * Set Task Priority to 'accept all'. We never change this - * later on. + * Put the APIC into flat delivery mode. + * Must be "all ones" explicitly for 82489DX. */ - value = apic_read(APIC_TASKPRI); - value &= ~APIC_TPRI_MASK; - apic_write_around(APIC_TASKPRI, value); + apic_write_around(APIC_DFR, 0xffffffff); /* - * Set up the logical destination ID and put the - * APIC into flat delivery mode. + * Set up the logical destination ID. */ value = apic_read(APIC_LDR); value &= ~APIC_LDR_MASK; @@ -287,9 +240,12 @@ void __init setup_local_APIC (void) apic_write_around(APIC_LDR, value); /* - * Must be "all ones" explicitly for 82489DX. + * Set Task Priority to 'accept all'. We never change this + * later on. */ - apic_write_around(APIC_DFR, 0xffffffff); + value = apic_read(APIC_TASKPRI); + value &= ~APIC_TPRI_MASK; + apic_write_around(APIC_TASKPRI, value); /* * Now that we are all set up, enable the APIC @@ -326,6 +282,56 @@ void __init setup_local_APIC (void) */ value |= SPURIOUS_APIC_VECTOR; apic_write_around(APIC_SPIV, value); + + /* + * Set up LVT0, LVT1: + * + * set up through-local-APIC on the BP's LINT0. This is not + * strictly necessery in pure symmetric-IO mode, but sometimes + * we delegate interrupts to the 8259A. + */ + /* + * TODO: set up through-local-APIC from through-I/O-APIC? --macro + */ + value = apic_read(APIC_LVT0) & APIC_LVT_MASKED; + if (!smp_processor_id() && (pic_mode || !value)) { + value = APIC_DM_EXTINT; + printk("enabled ExtINT on CPU#%d\n", smp_processor_id()); + } else { + value = APIC_DM_EXTINT | APIC_LVT_MASKED; + printk("masked ExtINT on CPU#%d\n", smp_processor_id()); + } + apic_write_around(APIC_LVT0, value); + + /* + * only the BP should see the LINT1 NMI signal, obviously. + */ + if (!smp_processor_id()) + value = APIC_DM_NMI; + else + value = APIC_DM_NMI | APIC_LVT_MASKED; + if (!APIC_INTEGRATED(ver)) /* 82489DX */ + value |= APIC_LVT_LEVEL_TRIGGER; + apic_write_around(APIC_LVT1, value); + + if (APIC_INTEGRATED(ver)) { /* !82489DX */ + maxlvt = get_maxlvt(); + if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ + apic_write(APIC_ESR, 0); + value = apic_read(APIC_ESR); + printk("ESR value before enabling vector: %08lx\n", value); + + value = ERROR_APIC_VECTOR; // enables sending errors + apic_write_around(APIC_LVTERR, value); + /* + * spec says clear errors after enabling vector. + */ + if (maxlvt > 3) + apic_write(APIC_ESR, 0); + value = apic_read(APIC_ESR); + printk("ESR value after enabling vector: %08lx\n", value); + } else + printk("No ESR for 82489DX.\n"); } void __init init_apic_mappings(void) diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index dc47528cd..9703e3304 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -37,6 +37,7 @@ * Nov 1999, Version 1.11 * Jan 2000, Version 1.12 * Feb 2000, Version 1.13 + * Nov 2000, Version 1.14 * * History: * 0.6b: first version in official kernel, Linux 1.3.46 @@ -144,6 +145,9 @@ * <tmh@magenta-logic.com> and <zlatko@iskon.hr>) modified by sfr. * Remove CONFIG_APM_SUSPEND_BOUNCE. The bounce ignore * interval is now configurable. + * 1.14: Make connection version persist across module unload/load. + * Enable and engage power management earlier. + * Disengage power management on module unload. * * APM 1.1 Reference: * @@ -344,9 +348,9 @@ static int kapmd_running; static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); -static struct apm_user * user_list = NULL; +static struct apm_user * user_list; -static char driver_version[] = "1.13"; /* no spaces */ +static char driver_version[] = "1.14"; /* no spaces */ static char * apm_event_name[] = { "system standby", @@ -527,7 +531,7 @@ static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info) &dummy, &dummy)) return (eax >> 8) & 0xff; *event = ebx; - if (apm_bios_info.version < 0x0102) + if (apm_info.connection_version < 0x0102) *info = ~0; /* indicate info not valid */ else *info = ecx; @@ -559,7 +563,7 @@ static int apm_do_idle(void) #ifdef ALWAYS_CALL_BUSY clock_slowed = 1; #else - clock_slowed = (apm_bios_info.flags & APM_IDLE_SLOWS_CLOCK) != 0; + clock_slowed = (apm_info.bios.flags & APM_IDLE_SLOWS_CLOCK) != 0; #endif return 1; } @@ -670,15 +674,15 @@ static int apm_enable_power_management(int enable) { u32 eax; - if ((enable == 0) && (apm_bios_info.flags & APM_BIOS_DISENGAGED)) + if ((enable == 0) && (apm_info.bios.flags & APM_BIOS_DISENGAGED)) return APM_NOT_ENGAGED; if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL, enable, &eax)) return (eax >> 8) & 0xff; if (enable) - apm_bios_info.flags &= ~APM_BIOS_DISABLED; + apm_info.bios.flags &= ~APM_BIOS_DISABLED; else - apm_bios_info.flags |= APM_BIOS_DISABLED; + apm_info.bios.flags |= APM_BIOS_DISABLED; return APM_SUCCESS; } #endif @@ -691,6 +695,8 @@ static int apm_get_power_status(u_short *status, u_short *bat, u_short *life) u32 edx; u32 dummy; + if (apm_info.get_power_status_broken) + return APM_32_UNSUPPORTED; if (apm_bios_call(APM_FUNC_GET_STATUS, APM_DEVICE_ALL, 0, &eax, &ebx, &ecx, &edx, &dummy)) return (eax >> 8) & 0xff; @@ -710,7 +716,7 @@ static int apm_get_battery_status(u_short which, u_short *status, u32 edx; u32 esi; - if (apm_bios_info.version < 0x0102) { + if (apm_info.connection_version < 0x0102) { /* pretend we only have one battery. */ if (which != 1) return APM_BAD_DEVICE; @@ -734,15 +740,15 @@ static int apm_engage_power_management(u_short device, int enable) u32 eax; if ((enable == 0) && (device == APM_DEVICE_ALL) - && (apm_bios_info.flags & APM_BIOS_DISABLED)) + && (apm_info.bios.flags & APM_BIOS_DISABLED)) return APM_DISABLED; if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable, &eax)) return (eax >> 8) & 0xff; if (device == APM_DEVICE_ALL) { if (enable) - apm_bios_info.flags &= ~APM_BIOS_DISENGAGED; + apm_info.bios.flags &= ~APM_BIOS_DISENGAGED; else - apm_bios_info.flags |= APM_BIOS_DISENGAGED; + apm_info.bios.flags |= APM_BIOS_DISENGAGED; } return APM_SUCCESS; } @@ -890,7 +896,7 @@ static int send_event(apm_event_t event) printk(KERN_CRIT "apm: Critical suspend was vetoed, expect armageddon\n" ); return 0; } - if (apm_bios_info.version > 0x100) + if (apm_info.connection_version > 0x100) apm_set_power_state(APM_STATE_REJECT); return 0; } @@ -993,13 +999,13 @@ static void check_events(void) case APM_USER_SUSPEND: #ifdef CONFIG_APM_IGNORE_USER_SUSPEND - if (apm_bios_info.version > 0x100) + if (apm_info.connection_version > 0x100) apm_set_power_state(APM_STATE_REJECT); break; #endif case APM_SYS_SUSPEND: if (ignore_bounce) { - if (apm_bios_info.version > 0x100) + if (apm_info.connection_version > 0x100) apm_set_power_state(APM_STATE_REJECT); break; } @@ -1064,7 +1070,7 @@ static void apm_event_handler(void) int err; if ((standbys_pending > 0) || (suspends_pending > 0)) { - if ((apm_bios_info.version > 0x100) && (pending_count-- <= 0)) { + if ((apm_info.connection_version > 0x100) && (pending_count-- <= 0)) { pending_count = 4; if (debug) printk(KERN_DEBUG "apm: setting state busy\n"); @@ -1334,7 +1340,7 @@ static int apm_get_info(char *buf, char **start, off_t fpos, int length) unsigned short bx; unsigned short cx; unsigned short dx; - unsigned short error; + int error; unsigned short ac_line_status = 0xff; unsigned short battery_status = 0xff; unsigned short battery_flag = 0xff; @@ -1351,7 +1357,7 @@ static int apm_get_info(char *buf, char **start, off_t fpos, int length) if ((cx & 0xff) != 0xff) percentage = cx & 0xff; - if (apm_bios_info.version > 0x100) { + if (apm_info.connection_version > 0x100) { battery_flag = (cx >> 8) & 0xff; if (dx != 0xffff) { units = (dx & 0x8000) ? "min" : "sec"; @@ -1399,9 +1405,9 @@ static int apm_get_info(char *buf, char **start, off_t fpos, int length) p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", driver_version, - (apm_bios_info.version >> 8) & 0xff, - apm_bios_info.version & 0xff, - apm_bios_info.flags, + (apm_info.bios.version >> 8) & 0xff, + apm_info.bios.version & 0xff, + apm_info.bios.flags, ac_line_status, battery_status, battery_flag, @@ -1417,7 +1423,7 @@ static int apm(void *unused) unsigned short bx; unsigned short cx; unsigned short dx; - unsigned short error; + int error; char * power_stat; char * bat_stat; @@ -1429,22 +1435,53 @@ static int apm(void *unused) sigfillset(¤t->blocked); current->tty = NULL; /* get rid of controlling tty */ - if (apm_bios_info.version > 0x100) { + if (apm_info.connection_version == 0) { + apm_info.connection_version = apm_info.bios.version; + if (apm_info.connection_version > 0x100) { + /* + * We only support BIOSs up to version 1.2 + */ + if (apm_info.connection_version > 0x0102) + apm_info.connection_version = 0x0102; + error = apm_driver_version(&apm_info.connection_version); + if (error != APM_SUCCESS) { + apm_error("driver version", error); + /* Fall back to an APM 1.0 connection. */ + apm_info.connection_version = 0x100; + } + } + } + + if (debug) + printk(KERN_INFO "apm: Connection version %d.%d\n", + (apm_info.connection_version >> 8) & 0xff, + apm_info.connection_version & 0xff); + +#ifdef CONFIG_APM_DO_ENABLE + if (apm_info.bios.flags & APM_BIOS_DISABLED) { /* - * We only support BIOSs up to version 1.2 + * This call causes my NEC UltraLite Versa 33/C to hang if it + * is booted with PM disabled but not in the docking station. + * Unfortunate ... */ - if (apm_bios_info.version > 0x0102) - apm_bios_info.version = 0x0102; - if (apm_driver_version(&apm_bios_info.version) != APM_SUCCESS) { - /* Fall back to an APM 1.0 connection. */ - apm_bios_info.version = 0x100; + error = apm_enable_power_management(1); + if (error) { + apm_error("enable power management", error); + return -1; + } + } +#endif + + if ((apm_info.bios.flags & APM_BIOS_DISENGAGED) + && (apm_info.connection_version > 0x0100)) { + error = apm_engage_power_management(APM_DEVICE_ALL, 1); + if (error) { + apm_error("engage power management", error); + return -1; } } - if (debug && (smp_num_cpus == 1)) { - printk(KERN_INFO "apm: Connection version %d.%d\n", - (apm_bios_info.version >> 8) & 0xff, - apm_bios_info.version & 0xff); + if (debug && (smp_num_cpus == 1)) { error = apm_get_power_status(&bx, &cx, &dx); if (error) printk(KERN_INFO "apm: power status not available\n"); @@ -1469,7 +1506,7 @@ static int apm(void *unused) printk("unknown\n"); else printk("%d%%\n", cx & 0xff); - if (apm_bios_info.version > 0x100) { + if (apm_info.connection_version > 0x100) { printk(KERN_INFO "apm: battery flag 0x%02x, battery life ", (cx >> 8) & 0xff); @@ -1483,29 +1520,6 @@ static int apm(void *unused) } } -#ifdef CONFIG_APM_DO_ENABLE - if (apm_bios_info.flags & APM_BIOS_DISABLED) { - /* - * This call causes my NEC UltraLite Versa 33/C to hang if it - * is booted with PM disabled but not in the docking station. - * Unfortunate ... - */ - error = apm_enable_power_management(1); - if (error) { - apm_error("enable power management", error); - return -1; - } - } -#endif - if ((apm_bios_info.flags & APM_BIOS_DISENGAGED) - && (apm_bios_info.version > 0x0100)) { - error = apm_engage_power_management(APM_DEVICE_ALL, 1); - if (error) { - apm_error("engage power management", error); - return -1; - } - } - /* Install our power off handler.. */ if (power_off) pm_power_off = apm_power_off; @@ -1584,17 +1598,19 @@ static struct miscdevice apm_device = { */ static int __init apm_init(void) { - if (apm_bios_info.version == 0) { + struct proc_dir_entry *apm_proc; + + if (apm_info.bios.version == 0) { printk(KERN_INFO "apm: BIOS not found.\n"); return -ENODEV; } printk(KERN_INFO "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n", - ((apm_bios_info.version >> 8) & 0xff), - (apm_bios_info.version & 0xff), - apm_bios_info.flags, + ((apm_info.bios.version >> 8) & 0xff), + (apm_info.bios.version & 0xff), + apm_info.bios.flags, driver_version); - if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) { + if ((apm_info.bios.flags & APM_32_BIT_SUPPORT) == 0) { printk(KERN_INFO "apm: no 32 bit BIOS support\n"); return -ENODEV; } @@ -1603,23 +1619,23 @@ static int __init apm_init(void) * Fix for the Compaq Contura 3/25c which reports BIOS version 0.1 * but is reportedly a 1.0 BIOS. */ - if (apm_bios_info.version == 0x001) - apm_bios_info.version = 0x100; + if (apm_info.bios.version == 0x001) + apm_info.bios.version = 0x100; /* BIOS < 1.2 doesn't set cseg_16_len */ - if (apm_bios_info.version < 0x102) - apm_bios_info.cseg_16_len = 0; /* 64k */ + if (apm_info.bios.version < 0x102) + apm_info.bios.cseg_16_len = 0; /* 64k */ if (debug) { printk(KERN_INFO "apm: entry %x:%lx cseg16 %x dseg %x", - apm_bios_info.cseg, apm_bios_info.offset, - apm_bios_info.cseg_16, apm_bios_info.dseg); - if (apm_bios_info.version > 0x100) + apm_info.bios.cseg, apm_info.bios.offset, + apm_info.bios.cseg_16, apm_info.bios.dseg); + if (apm_info.bios.version > 0x100) printk(" cseg len %x, dseg len %x", - apm_bios_info.cseg_len, - apm_bios_info.dseg_len); - if (apm_bios_info.version > 0x101) - printk(" cseg16 len %x", apm_bios_info.cseg_16_len); + apm_info.bios.cseg_len, + apm_info.bios.dseg_len); + if (apm_info.bios.version > 0x101) + printk(" cseg16 len %x", apm_info.bios.cseg_16_len); printk("\n"); } @@ -1647,16 +1663,16 @@ static int __init apm_init(void) __va((unsigned long)0x40 << 4)); _set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4)); - apm_bios_entry.offset = apm_bios_info.offset; + apm_bios_entry.offset = apm_info.bios.offset; apm_bios_entry.segment = APM_CS; set_base(gdt[APM_CS >> 3], - __va((unsigned long)apm_bios_info.cseg << 4)); + __va((unsigned long)apm_info.bios.cseg << 4)); set_base(gdt[APM_CS_16 >> 3], - __va((unsigned long)apm_bios_info.cseg_16 << 4)); + __va((unsigned long)apm_info.bios.cseg_16 << 4)); set_base(gdt[APM_DS >> 3], - __va((unsigned long)apm_bios_info.dseg << 4)); + __va((unsigned long)apm_info.bios.dseg << 4)); #ifndef APM_RELAX_SEGMENTS - if (apm_bios_info.version == 0x100) { + if (apm_info.bios.version == 0x100) { #endif /* For ASUS motherboard, Award BIOS rev 110 (and others?) */ _set_limit((char *)&gdt[APM_CS >> 3], 64 * 1024 - 1); @@ -1667,15 +1683,17 @@ static int __init apm_init(void) #ifndef APM_RELAX_SEGMENTS } else { _set_limit((char *)&gdt[APM_CS >> 3], - (apm_bios_info.cseg_len - 1) & 0xffff); + (apm_info.bios.cseg_len - 1) & 0xffff); _set_limit((char *)&gdt[APM_CS_16 >> 3], - (apm_bios_info.cseg_16_len - 1) & 0xffff); + (apm_info.bios.cseg_16_len - 1) & 0xffff); _set_limit((char *)&gdt[APM_DS >> 3], - (apm_bios_info.dseg_len - 1) & 0xffff); + (apm_info.bios.dseg_len - 1) & 0xffff); } #endif - create_proc_info_entry("apm", 0, NULL, apm_get_info); + apm_proc = create_proc_info_entry("apm", 0, NULL, apm_get_info); + if (apm_proc) + SET_MODULE_OWNER(apm_proc); kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); @@ -1692,6 +1710,14 @@ static int __init apm_init(void) static void __exit apm_exit(void) { + int error; + + if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0) + && (apm_info.connection_version > 0x0100)) { + error = apm_engage_power_management(APM_DEVICE_ALL, 0); + if (error) + apm_error("disengage power management", error); + } misc_deregister(&apm_device); remove_proc_entry("apm", NULL); #ifdef CONFIG_MAGIC_SYSRQ diff --git a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c new file mode 100644 index 000000000..b439568c1 --- /dev/null +++ b/arch/i386/kernel/dmi_scan.c @@ -0,0 +1,182 @@ +#include <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/apm_bios.h> +#include <asm/io.h> + +struct dmi_header +{ + u8 type; + u8 length; + u16 handle; +}; + +static char * __init dmi_string(struct dmi_header *dm, u8 s) +{ + u8 *bp=(u8 *)dm; + bp+=dm->length; + s--; + while(s>0) + { + bp+=strlen(bp); + bp++; + s--; + } + return bp; +} + +static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dmi_header *)) +{ + u8 *buf; + struct dmi_header *dm; + u8 *data; + int i=1; + int last = 0; + + buf = ioremap(base, len); + if(buf==NULL) + return -1; + + data = buf; + while(i<num && (data - buf) < len) + { + dm=(struct dmi_header *)data; + if(dm->type < last) + break; + last = dm->type; + decode(dm); + data+=dm->length; + while(*data || data[1]) + data++; + data+=2; + i++; + } + iounmap(buf); + return 0; +} + + +int __init dmi_iterate(void (*decode)(struct dmi_header *)) +{ + unsigned char buf[20]; + long fp=0xE0000L; + fp -= 16; + + while( fp < 0xFFFFF) + { + fp+=16; + isa_memcpy_fromio(buf, fp, 20); + if(memcmp(buf, "_DMI_", 5)==0) + { + u16 num=buf[13]<<8|buf[12]; + u16 len=buf[7]<<8|buf[6]; + u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]; + + printk(KERN_INFO "DMI %d.%d present.\n", + buf[14]>>4, buf[14]&0x0F); + printk(KERN_INFO "%d structures occupying %d bytes.\n", + buf[13]<<8|buf[12], + buf[7]<<8|buf[6]); + printk(KERN_INFO "DMI table at 0x%08X.\n", + buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]); + if(dmi_table(base,len, num, decode)==0) + return 0; + } + } + return -1; +} + + +/* + * Process a DMI table entry. Right now all we care about are the BIOS + * and machine entries. For 2.4 we should pull the smbus controller info + * out of here. + */ + +static void __init dmi_decode(struct dmi_header *dm) +{ + u8 *data = (u8 *)dm; + char *p; + + switch(dm->type) + { + case 0: + p=dmi_string(dm,data[4]); + + if(*p && *p!=' ') + { + printk("BIOS Vendor: %s\n", p); + printk("BIOS Version: %s\n", + dmi_string(dm, data[5])); + printk("BIOS Release: %s\n", + dmi_string(dm, data[8])); + } + + /* + * Check for clue free BIOS implementations who use + * the following QA technique + * + * [ Write BIOS Code ]<------ + * | ^ + * < Does it Compile >----N-- + * |Y ^ + * < Does it Boot Win98 >-N-- + * |Y + * [Ship It] + * + * Phoenix A04 08/24/2000 is known bad (Dell Inspiron 5000e) + * Phoenix A07 09/29/2000 is known good (Dell Inspiron 5000) + */ + + if(strcmp(dmi_string(dm, data[4]), "Phoenix Technologies LTD")==0) + { + if(strcmp(dmi_string(dm, data[5]), "A04")==0 + && strcmp(dmi_string(dm, data[8]), "08/24/2000")==0) + { + apm_info.get_power_status_broken = 1; + printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n"); + } + } + break; + case 1: + p=dmi_string(dm,data[4]); + + if(*p && *p!=' ') + { + printk("System Vendor: %s.\n",p); + printk("Product Name: %s.\n", + dmi_string(dm, data[5])); + printk("Version %s.\n", + dmi_string(dm, data[6])); + printk("Serial Number %s.\n", + dmi_string(dm, data[7])); + } + break; + case 2: + p=dmi_string(dm,data[4]); + + if(*p && *p!=' ') + { + printk("Board Vendor: %s.\n",p); + printk("Board Name: %s.\n", + dmi_string(dm, data[5])); + printk("Board Version: %s.\n", + dmi_string(dm, data[6])); + } + break; + case 3: + p=dmi_string(dm,data[8]); + if(*p && *p!=' ') + printk("Asset Tag: %s.\n", p); + break; + } +} + +static int __init dmi_scan_machine(void) +{ + return dmi_iterate(dmi_decode); +} + +module_init(dmi_scan_machine); diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S index fdb488a15..c74b80135 100644 --- a/arch/i386/kernel/head.S +++ b/arch/i386/kernel/head.S @@ -119,12 +119,12 @@ startup_32: /* * Clear BSS first so that there are no surprises... + * No need to cld as DF is already clear from cld above... */ xorl %eax,%eax movl $ SYMBOL_NAME(__bss_start),%edi movl $ SYMBOL_NAME(_end),%ecx subl %edi,%ecx - cld rep stosb diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c index 3de4a76d1..071b3991a 100644 --- a/arch/i386/kernel/i386_ksyms.c +++ b/arch/i386/kernel/i386_ksyms.c @@ -68,7 +68,7 @@ EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(pm_idle); EXPORT_SYMBOL(pm_power_off); EXPORT_SYMBOL(get_cmos_time); -EXPORT_SYMBOL(apm_bios_info); +EXPORT_SYMBOL(apm_info); EXPORT_SYMBOL(gdt); EXPORT_SYMBOL_NOVERS(__down_failed); diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 92ddd01f5..cf6878787 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -179,7 +179,7 @@ int get_irq_list(char *buf) #ifdef CONFIG_SMP unsigned char global_irq_holder = NO_PROC_ID; -unsigned volatile int global_irq_lock; +unsigned volatile long global_irq_lock; /* pendantic: long for set_bit --RR */ extern void show_stack(unsigned long* esp); diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c index 5f9925495..f0a88c20e 100644 --- a/arch/i386/kernel/microcode.c +++ b/arch/i386/kernel/microcode.c @@ -4,13 +4,13 @@ * Copyright (C) 2000 Tigran Aivazian * * This driver allows to upgrade microcode on Intel processors - * belonging to P6 family - PentiumPro, Pentium II, - * Pentium III, Xeon etc. + * belonging to IA-32 family - PentiumPro, Pentium II, + * Pentium III, Xeon, Pentium 4, etc. * - * Reference: Section 8.10 of Volume III, Intel Pentium III Manual, - * Order Number 243192 or free download from: + * Reference: Section 8.10 of Volume III, Intel Pentium 4 Manual, + * Order Number 245472 or free download from: * - * http://developer.intel.com/design/pentiumii/manuals/243192.htm + * http://developer.intel.com/design/pentium4/manuals/245472.htm * * For more information, go to http://www.urbanmyth.org/microcode * @@ -44,6 +44,9 @@ * to be 0 on my machine which is why it worked even when I * disabled update by the BIOS) * Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix. + * 1.08 11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and + * Tigran Aivazian <tigran@veritas.com> + * Intel Pentium 4 processor support and bugfixes. */ #include <linux/init.h> @@ -58,12 +61,20 @@ #include <asm/uaccess.h> #include <asm/processor.h> -#define MICROCODE_VERSION "1.07" +#define MICROCODE_VERSION "1.08" -MODULE_DESCRIPTION("Intel CPU (P6) microcode update driver"); +MODULE_DESCRIPTION("Intel CPU (IA-32) microcode update driver"); MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>"); EXPORT_NO_SYMBOLS; +#define MICRO_DEBUG 0 + +#if MICRO_DEBUG +#define printf(x...) printk(##x) +#else +#define printf(x...) +#endif + /* VFS interface */ static int microcode_open(struct inode *, struct file *); static ssize_t microcode_read(struct file *, char *, size_t, loff_t *); @@ -81,6 +92,7 @@ static unsigned int microcode_num; /* number of chunks in microcode */ static char *mc_applied; /* array of applied microcode blocks */ static unsigned int mc_fsize; /* file size of /dev/cpu/microcode */ +/* we share file_operations between misc and devfs mechanisms */ static struct file_operations microcode_fops = { owner: THIS_MODULE, read: microcode_read, @@ -99,23 +111,27 @@ static devfs_handle_t devfs_handle; static int __init microcode_init(void) { - int error = 0; + int error; - if (misc_register(µcode_dev) < 0) { + error = misc_register(µcode_dev); + if (error) printk(KERN_WARNING "microcode: can't misc_register on minor=%d\n", MICROCODE_MINOR); - error = 1; - } + devfs_handle = devfs_register(NULL, "cpu/microcode", DEVFS_FL_DEFAULT, 0, 0, S_IFREG | S_IRUSR | S_IWUSR, µcode_fops, NULL); if (devfs_handle == NULL && error) { printk(KERN_ERR "microcode: failed to devfs_register()\n"); - return -EINVAL; + goto out; } - printk(KERN_INFO "P6 Microcode Update Driver v%s\n", MICROCODE_VERSION); - return 0; + printk(KERN_INFO + "IA-32 Microcode Update Driver: v%s <tigran@veritas.com>\n", + MICROCODE_VERSION); + +out: + return error; } static void __exit microcode_exit(void) @@ -124,12 +140,12 @@ static void __exit microcode_exit(void) devfs_unregister(devfs_handle); if (mc_applied) kfree(mc_applied); - printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n", + printk(KERN_INFO "IA-32 Microcode Update Driver v%s unregistered\n", MICROCODE_VERSION); } -module_init(microcode_init); -module_exit(microcode_exit); +module_init(microcode_init) +module_exit(microcode_exit) static int microcode_open(struct inode *unused1, struct file *unused2) { @@ -175,18 +191,19 @@ static void do_update_one(void *unused) unsigned int pf = 0, val[2], rev, sig; int i,found=0; - req->err = 1; /* assume the worst */ + req->err = 1; /* assume update will fail on this cpu */ - if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 != 6){ - printk(KERN_ERR "microcode: CPU%d not an Intel P6\n", cpu_num); + if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 || + test_bit(X86_FEATURE_IA64, &c->x86_capability)){ + printk(KERN_ERR "microcode: CPU%d not a capable Intel processor\n", cpu_num); return; } sig = c->x86_mask + (c->x86_model<<4) + (c->x86<<8); - if (c->x86_model >= 5) { - /* get processor flags from BBL_CR_OVRD MSR (0x17) */ - rdmsr(0x17, val[0], val[1]); + if ((c->x86_model >= 5) || (c->x86 > 6)) { + /* get processor flags from MSR 0x17 */ + rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); pf = 1 << ((val[1] >> 18) & 7); } @@ -195,9 +212,28 @@ static void do_update_one(void *unused) microcode[i].ldrver == 1 && microcode[i].hdrver == 1) { found=1; - wrmsr(0x8B, 0, 0); + + printf("Microcode\n"); + printf(" Header Revision %d\n",microcode[i].hdrver); + printf(" Date %x/%x/%x\n", + ((microcode[i].date >> 24 ) & 0xff), + ((microcode[i].date >> 16 ) & 0xff), + (microcode[i].date & 0xFFFF)); + printf(" Type %x Family %x Model %x Stepping %x\n", + ((microcode[i].sig >> 12) & 0x3), + ((microcode[i].sig >> 8) & 0xf), + ((microcode[i].sig >> 4) & 0xf), + ((microcode[i].sig & 0xf))); + printf(" Checksum %x\n",microcode[i].cksum); + printf(" Loader Revision %x\n",microcode[i].ldrver); + printf(" Processor Flags %x\n\n",microcode[i].pf); + + /* trick, to work even if there was no prior update by the BIOS */ + wrmsr(MSR_IA32_UCODE_REV, 0, 0); __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx"); - rdmsr(0x8B, val[0], rev); + + /* get current (on-cpu) revision into rev (ignore val[0]) */ + rdmsr(MSR_IA32_UCODE_REV, val[0], rev); if (microcode[i].rev < rev) { printk(KERN_ERR "microcode: CPU%d not 'upgrading' to earlier revision" @@ -219,13 +255,20 @@ static void do_update_one(void *unused) break; } - wrmsr(0x79, (unsigned int)(m->bits), 0); + /* write microcode via MSR 0x79 */ + wrmsr(MSR_IA32_UCODE_WRITE, (unsigned int)(m->bits), 0); + + /* serialize */ __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx"); - rdmsr(0x8B, val[0], val[1]); + /* get the current revision from MSR 0x8B */ + rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); + + /* notify the caller of success on this cpu */ req->err = 0; req->slot = i; - printk(KERN_ERR "microcode: CPU%d updated from revision " + + printk(KERN_INFO "microcode: CPU%d updated from revision " "%d to %d, date=%08x\n", cpu_num, rev, val[1], m->date); } @@ -239,18 +282,21 @@ static void do_update_one(void *unused) static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos) { - if (*ppos >= mc_fsize) - return 0; + ssize_t ret = 0; + down_read(µcode_rwsem); + if (*ppos >= mc_fsize) + goto out; if (*ppos + len > mc_fsize) len = mc_fsize - *ppos; - if (copy_to_user(buf, mc_applied + *ppos, len)) { - up_read(µcode_rwsem); - return -EFAULT; - } + ret = -EFAULT; + if (copy_to_user(buf, mc_applied + *ppos, len)) + goto out; *ppos += len; + ret = len; +out: up_read(µcode_rwsem); - return len; + return ret; } static ssize_t microcode_write(struct file *file, const char *buf, size_t len, loff_t *ppos) @@ -267,8 +313,8 @@ static ssize_t microcode_write(struct file *file, const char *buf, size_t len, l mc_applied = kmalloc(smp_num_cpus*sizeof(struct microcode), GFP_KERNEL); if (!mc_applied) { - printk(KERN_ERR "microcode: out of memory for saved microcode\n"); up_write(µcode_rwsem); + printk(KERN_ERR "microcode: out of memory for saved microcode\n"); return -ENOMEM; } } @@ -307,10 +353,12 @@ static int microcode_ioctl(struct inode *inode, struct file *file, case MICROCODE_IOCFREE: down_write(µcode_rwsem); if (mc_applied) { + int bytes = smp_num_cpus * sizeof(struct microcode); + devfs_set_file_size(devfs_handle, 0); kfree(mc_applied); mc_applied = NULL; - printk(KERN_INFO "microcode: freed %d bytes\n", mc_fsize); + printk(KERN_INFO "microcode: freed %d bytes\n", bytes); mc_fsize = 0; up_write(µcode_rwsem); return 0; diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c index 47c83f58e..60764e3cd 100644 --- a/arch/i386/kernel/mtrr.c +++ b/arch/i386/kernel/mtrr.c @@ -480,12 +480,14 @@ static int have_wrcomb (void) } } /* End Function have_wrcomb */ +static u32 size_or_mask, size_and_mask; + static void intel_get_mtrr (unsigned int reg, unsigned long *base, unsigned long *size, mtrr_type *type) { - unsigned long dummy, mask_lo, base_lo; + unsigned long mask_lo, mask_hi, base_lo, base_hi; - rdmsr (MTRRphysMask_MSR(reg), mask_lo, dummy); + rdmsr (MTRRphysMask_MSR(reg), mask_lo, mask_hi); if ( (mask_lo & 0x800) == 0 ) { /* Invalid (i.e. free) range */ @@ -495,20 +497,17 @@ static void intel_get_mtrr (unsigned int reg, unsigned long *base, return; } - rdmsr(MTRRphysBase_MSR(reg), base_lo, dummy); + rdmsr(MTRRphysBase_MSR(reg), base_lo, base_hi); - /* We ignore the extra address bits (32-35). If someone wants to - run x86 Linux on a machine with >4GB memory, this will be the - least of their problems. */ + /* Work out the shifted address mask. */ + mask_lo = size_or_mask | mask_hi << (32 - PAGE_SHIFT) + | mask_lo >> PAGE_SHIFT; - /* Clean up mask_lo so it gives the real address mask. */ - mask_lo = (mask_lo & 0xfffff000UL); /* This works correctly if size is a power of two, i.e. a contiguous range. */ - *size = ~(mask_lo - 1); - - *base = (base_lo & 0xfffff000UL); - *type = (base_lo & 0xff); + *size = -mask_lo; + *base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT; + *type = base_lo & 0xff; } /* End Function intel_get_mtrr */ static void cyrix_get_arr (unsigned int reg, unsigned long *base, @@ -533,13 +532,13 @@ static void cyrix_get_arr (unsigned int reg, unsigned long *base, /* Enable interrupts if it was enabled previously */ __restore_flags (flags); shift = ((unsigned char *) base)[1] & 0x0f; - *base &= 0xfffff000UL; + *base >>= PAGE_SHIFT; /* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7 * Note: shift==0xf means 4G, this is unsupported. */ if (shift) - *size = (reg < 7 ? 0x800UL : 0x20000UL) << shift; + *size = (reg < 7 ? 0x1UL : 0x40UL) << shift; else *size = 0; @@ -576,7 +575,7 @@ static void amd_get_mtrr (unsigned int reg, unsigned long *base, /* Upper dword is region 1, lower is region 0 */ if (reg == 1) low = high; /* The base masks off on the right alignment */ - *base = low & 0xFFFE0000; + *base = (low & 0xFFFE0000) >> PAGE_SHIFT; *type = 0; if (low & 1) *type = MTRR_TYPE_UNCACHABLE; if (low & 2) *type = MTRR_TYPE_WRCOMB; @@ -601,7 +600,7 @@ static void amd_get_mtrr (unsigned int reg, unsigned long *base, * *128K ... */ low = (~low) & 0x1FFFC; - *size = (low + 4) << 15; + *size = (low + 4) << (15 - PAGE_SHIFT); return; } /* End Function amd_get_mtrr */ @@ -614,8 +613,8 @@ static struct static void centaur_get_mcr (unsigned int reg, unsigned long *base, unsigned long *size, mtrr_type *type) { - *base = centaur_mcr[reg].high & 0xfffff000; - *size = (~(centaur_mcr[reg].low & 0xfffff000))+1; + *base = centaur_mcr[reg].high >> PAGE_SHIFT; + *size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT; *type = MTRR_TYPE_WRCOMB; /* If it is there, it is write-combining */ } /* End Function centaur_get_mcr */ @@ -645,8 +644,10 @@ static void intel_set_mtrr_up (unsigned int reg, unsigned long base, } else { - wrmsr (MTRRphysBase_MSR (reg), base | type, 0); - wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0); + wrmsr (MTRRphysBase_MSR (reg), base << PAGE_SHIFT | type, + (base & size_and_mask) >> (32 - PAGE_SHIFT)); + wrmsr (MTRRphysMask_MSR (reg), -size << PAGE_SHIFT | 0x800, + (-size & size_and_mask) >> (32 - PAGE_SHIFT)); } if (do_safe) set_mtrr_done (&ctxt); } /* End Function intel_set_mtrr_up */ @@ -660,7 +661,9 @@ static void cyrix_set_arr_up (unsigned int reg, unsigned long base, arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */ /* count down from 32M (ARR0-ARR6) or from 2G (ARR7) */ - size >>= (reg < 7 ? 12 : 18); + if (reg >= 7) + size >>= 6; + size &= 0x7fff; /* make sure arr_size <= 14 */ for(arr_size = 0; size; arr_size++, size >>= 1); @@ -685,6 +688,7 @@ static void cyrix_set_arr_up (unsigned int reg, unsigned long base, } if (do_safe) set_mtrr_prepare (&ctxt); + base <<= PAGE_SHIFT; setCx86(arr, ((unsigned char *) &base)[3]); setCx86(arr+1, ((unsigned char *) &base)[2]); setCx86(arr+2, (((unsigned char *) &base)[1]) | arr_size); @@ -704,34 +708,36 @@ static void amd_set_mtrr_up (unsigned int reg, unsigned long base, [RETURNS] Nothing. */ { - u32 low, high; + u32 regs[2]; struct set_mtrr_context ctxt; if (do_safe) set_mtrr_prepare (&ctxt); /* * Low is MTRR0 , High MTRR 1 */ - rdmsr (0xC0000085, low, high); + rdmsr (0xC0000085, regs[0], regs[1]); /* * Blank to disable */ if (size == 0) - *(reg ? &high : &low) = 0; + regs[reg] = 0; else - /* Set the register to the base (already shifted for us), the - type (off by one) and an inverted bitmask of the size - The size is the only odd bit. We are fed say 512K - We invert this and we get 111 1111 1111 1011 but - if you subtract one and invert you get the desired - 111 1111 1111 1100 mask - */ - *(reg ? &high : &low)=(((~(size-1))>>15)&0x0001FFFC)|base|(type+1); + /* Set the register to the base, the type (off by one) and an + inverted bitmask of the size The size is the only odd + bit. We are fed say 512K We invert this and we get 111 1111 + 1111 1011 but if you subtract one and invert you get the + desired 111 1111 1111 1100 mask + + But ~(x - 1) == ~x + 1 == -x. Two's complement rocks! */ + regs[reg] = (-size>>(15-PAGE_SHIFT) & 0x0001FFFC) + | (base<<PAGE_SHIFT) | (type+1); + /* * The writeback rule is quite specific. See the manual. Its * disable local interrupts, write back the cache, set the mtrr */ __asm__ __volatile__ ("wbinvd" : : : "memory"); - wrmsr (0xC0000085, low, high); + wrmsr (0xC0000085, regs[0], regs[1]); if (do_safe) set_mtrr_done (&ctxt); } /* End Function amd_set_mtrr_up */ @@ -751,9 +757,8 @@ static void centaur_set_mcr_up (unsigned int reg, unsigned long base, } else { - high = base & 0xfffff000; /* base works on 4K pages... */ - low = ((~(size-1))&0xfffff000); - low |= 0x1f; /* only support write-combining... */ + high = base << PAGE_SHIFT; + low = -size << PAGE_SHIFT | 0x1f; /* only support write-combining... */ } centaur_mcr[reg].high = high; centaur_mcr[reg].low = low; @@ -1058,7 +1063,7 @@ static int generic_get_free_region (unsigned long base, unsigned long size) for (i = 0; i < max; ++i) { (*get_mtrr) (i, &lbase, &lsize, <ype); - if (lsize < 1) return i; + if (lsize == 0) return i; } return -ENOSPC; } /* End Function generic_get_free_region */ @@ -1075,10 +1080,10 @@ static int cyrix_get_free_region (unsigned long base, unsigned long size) unsigned long lbase, lsize; /* If we are to set up a region >32M then look at ARR7 immediately */ - if (size > 0x2000000UL) + if (size > 0x2000) { cyrix_get_arr (7, &lbase, &lsize, <ype); - if (lsize < 1) return 7; + if (lsize == 0) return 7; /* Else try ARR0-ARR6 first */ } else @@ -1087,11 +1092,11 @@ static int cyrix_get_free_region (unsigned long base, unsigned long size) { cyrix_get_arr (i, &lbase, &lsize, <ype); if ((i == 3) && arr3_protected) continue; - if (lsize < 1) return i; + if (lsize == 0) return i; } /* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */ cyrix_get_arr (i, &lbase, &lsize, <ype); - if ((lsize < 1) && (size >= 0x40000)) return i; + if ((lsize == 0) && (size >= 0x40)) return i; } return -ENOSPC; } /* End Function cyrix_get_free_region */ @@ -1100,9 +1105,9 @@ static int (*get_free_region) (unsigned long base, unsigned long size) = generic_get_free_region; /** - * mtrr_add - Add a memory type region - * @base: Physical base address of region - * @size: Physical size of region + * mtrr_add_page - Add a memory type region + * @base: Physical base address of region in pages (4 KB) + * @size: Physical size of region in pages (4 KB) * @type: Type of MTRR desired * @increment: If this is true do usage counting on the region * @@ -1135,11 +1140,11 @@ static int (*get_free_region) (unsigned long base, * failures and do not wish system log messages to be sent. */ -int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char increment) +int mtrr_add_page(unsigned long base, unsigned long size, unsigned int type, char increment) { /* [SUMMARY] Add an MTRR entry. - <base> The starting (base) address of the region. - <size> The size (in bytes) of the region. + <base> The starting (base, in pages) address of the region. + <size> The size of the region. (in pages) <type> The type of the new region. <increment> If true and the region already exists, the usage count will be incremented. @@ -1164,7 +1169,7 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc o Power of 2 block o base suitably aligned to the power */ - if ( type > MTRR_TYPE_WRCOMB || size < (1 << 17) || + if ( type > MTRR_TYPE_WRCOMB || size < (1 << (17-PAGE_SHIFT)) || (size & ~(size-1))-size || ( base & (size-1) ) ) return -EINVAL; break; @@ -1176,9 +1181,9 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc boot_cpu_data.x86_model == 1 && boot_cpu_data.x86_mask <= 7 ) { - if ( base & ((1 << 22)-1) ) + if ( base & ((1 << (22-PAGE_SHIFT))-1) ) { - printk (KERN_WARNING "mtrr: base(0x%lx) is not 4 MiB aligned\n", base); + printk (KERN_WARNING "mtrr: base(0x%lx000) is not 4 MiB aligned\n", base); return -EINVAL; } } @@ -1186,12 +1191,6 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc case MTRR_IF_CYRIX_ARR: case MTRR_IF_CENTAUR_MCR: - if ( (base & 0xfff) || (size & 0xfff) ) - { - printk ("mtrr: size and base must be multiples of 4 kiB\n"); - printk ("mtrr: size: %lx base: %lx\n", size, base); - return -EINVAL; - } if ( mtrr_if == MTRR_IF_CENTAUR_MCR ) { if (type != MTRR_TYPE_WRCOMB) @@ -1200,9 +1199,9 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc return -EINVAL; } } - else if (base + size < 0x100000) + else if (base + size < 0x100) { - printk (KERN_WARNING "mtrr: cannot set region below 1 MiB (0x%lx,0x%lx)\n", + printk (KERN_WARNING "mtrr: cannot set region below 1 MiB (0x%lx000,0x%lx000)\n", base, size); return -EINVAL; } @@ -1213,7 +1212,7 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc lbase = lbase >> 1, last = last >> 1); if (lbase != last) { - printk (KERN_WARNING "mtrr: base(0x%lx) is not aligned on a size(0x%lx) boundary\n", + printk (KERN_WARNING "mtrr: base(0x%lx000) is not aligned on a size(0x%lx000) boundary\n", base, size); return -EINVAL; } @@ -1228,12 +1227,20 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc printk ("mtrr: type: %u illegal\n", type); return -EINVAL; } + /* If the type is WC, check that this processor supports it */ if ( (type == MTRR_TYPE_WRCOMB) && !have_wrcomb () ) { printk (KERN_WARNING "mtrr: your processor doesn't support write-combining\n"); return -ENOSYS; } + + if ( base & size_or_mask || size & size_or_mask ) + { + printk ("mtrr: base or size exceeds the MTRR width\n"); + return -EINVAL; + } + increment = increment ? 1 : 0; max = get_num_var_ranges (); /* Search for existing MTRR */ @@ -1247,7 +1254,8 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc if ( (base < lbase) || (base + size > lbase + lsize) ) { up(&main_lock); - printk (KERN_WARNING "mtrr: 0x%lx,0x%lx overlaps existing 0x%lx,0x%lx\n", + printk (KERN_WARNING "mtrr: 0x%lx000,0x%lx000 overlaps existing" + " 0x%lx000,0x%lx000\n", base, size, lbase, lsize); return -EINVAL; } @@ -1256,7 +1264,7 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc { if (type == MTRR_TYPE_UNCACHABLE) continue; up(&main_lock); - printk ( "mtrr: type mismatch for %lx,%lx old: %s new: %s\n", + printk ( "mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n", base, size, attrib_to_str (ltype), attrib_to_str (type) ); return -EINVAL; } @@ -1278,10 +1286,67 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc compute_ascii (); up(&main_lock); return i; +} /* End Function mtrr_add_page */ + +/** + * mtrr_add - Add a memory type region + * @base: Physical base address of region + * @size: Physical size of region + * @type: Type of MTRR desired + * @increment: If this is true do usage counting on the region + * + * Memory type region registers control the caching on newer Intel and + * non Intel processors. This function allows drivers to request an + * MTRR is added. The details and hardware specifics of each processor's + * implementation are hidden from the caller, but nevertheless the + * caller should expect to need to provide a power of two size on an + * equivalent power of two boundary. + * + * If the region cannot be added either because all regions are in use + * or the CPU cannot support it a negative value is returned. On success + * the register number for this entry is returned, but should be treated + * as a cookie only. + * + * On a multiprocessor machine the changes are made to all processors. + * This is required on x86 by the Intel processors. + * + * The available types are + * + * %MTRR_TYPE_UNCACHEABLE - No caching + * + * %MTRR_TYPE_WRITEBACK - Write data back in bursts whenever + * + * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts + * + * %MTRR_TYPE_WRTHROUGH - Cache reads but not writes + * + * BUGS: Needs a quiet flag for the cases where drivers do not mind + * failures and do not wish system log messages to be sent. + */ + +int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char increment) +{ +/* [SUMMARY] Add an MTRR entry. + <base> The starting (base) address of the region. + <size> The size (in bytes) of the region. + <type> The type of the new region. + <increment> If true and the region already exists, the usage count will be + incremented. + [RETURNS] The MTRR register on success, else a negative number indicating + the error code. +*/ + + if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) ) + { + printk ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); + return -EINVAL; + } + return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, increment); } /* End Function mtrr_add */ /** - * mtrr_del - delete a memory type region + * mtrr_del_page - delete a memory type region * @reg: Register returned by mtrr_add * @base: Physical base address * @size: Size of region @@ -1295,7 +1360,7 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc * code. */ -int mtrr_del (int reg, unsigned long base, unsigned long size) +int mtrr_del_page (int reg, unsigned long base, unsigned long size) /* [SUMMARY] Delete MTRR/decrement usage count. <reg> The register. If this is less than 0 then <<base>> and <<size>> must be supplied. @@ -1320,7 +1385,7 @@ int mtrr_del (int reg, unsigned long base, unsigned long size) for (i = 0; i < max; ++i) { (*get_mtrr) (i, &lbase, &lsize, <ype); - if ( (lbase == base) && (lsize == size) ) + if (lbase == base && lsize == size) { reg = i; break; @@ -1329,7 +1394,7 @@ int mtrr_del (int reg, unsigned long base, unsigned long size) if (reg < 0) { up(&main_lock); - printk ("mtrr: no MTRR for %lx,%lx found\n", base, size); + printk ("mtrr: no MTRR for %lx000,%lx000 found\n", base, size); return -EINVAL; } } @@ -1365,12 +1430,46 @@ int mtrr_del (int reg, unsigned long base, unsigned long size) compute_ascii (); up (&main_lock); return reg; -} /* End Function mtrr_del */ +} /* End Function mtrr_del_page */ + +/** + * mtrr_del - delete a memory type region + * @reg: Register returned by mtrr_add + * @base: Physical base address + * @size: Size of region + * + * If register is supplied then base and size are ignored. This is + * how drivers should call it. + * + * Releases an MTRR region. If the usage count drops to zero the + * register is freed and the region returns to default state. + * On success the register is returned, on failure a negative error + * code. + */ + +int mtrr_del (int reg, unsigned long base, unsigned long size) +/* [SUMMARY] Delete MTRR/decrement usage count. + <reg> The register. If this is less than 0 then <<base>> and <<size>> must + be supplied. + <base> The base address of the region. This is ignored if <<reg>> is >= 0. + <size> The size of the region. This is ignored if <<reg>> is >= 0. + [RETURNS] The register on success, else a negative number indicating + the error code. +*/ +{ + if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) ) + { + printk ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); + return -EINVAL; + } + return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT); +} #ifdef USERSPACE_INTERFACE static int mtrr_file_add (unsigned long base, unsigned long size, - unsigned int type, char increment, struct file *file) + unsigned int type, char increment, struct file *file, int page) { int reg, max; unsigned int *fcount = file->private_data; @@ -1386,18 +1485,38 @@ static int mtrr_file_add (unsigned long base, unsigned long size, memset (fcount, 0, max * sizeof *fcount); file->private_data = fcount; } - reg = mtrr_add (base, size, type, 1); + if (!page) { + if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) ) + { + printk ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); + return -EINVAL; + } + base >>= PAGE_SHIFT; + size >>= PAGE_SHIFT; + } + reg = mtrr_add_page (base, size, type, 1); if (reg >= 0) ++fcount[reg]; return reg; } /* End Function mtrr_file_add */ static int mtrr_file_del (unsigned long base, unsigned long size, - struct file *file) + struct file *file, int page) { int reg; unsigned int *fcount = file->private_data; - reg = mtrr_del (-1, base, size); + if (!page) { + if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) ) + { + printk ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); + return -EINVAL; + } + base >>= PAGE_SHIFT; + size >>= PAGE_SHIFT; + } + reg = mtrr_del_page (-1, base, size); if (reg < 0) return reg; if (fcount == NULL) return reg; if (fcount[reg] < 1) return -EINVAL; @@ -1418,12 +1537,13 @@ static ssize_t mtrr_read (struct file *file, char *buf, size_t len, static ssize_t mtrr_write (struct file *file, const char *buf, size_t len, loff_t *ppos) /* Format of control line: - "base=%lx size=%lx type=%s" OR: + "base=%Lx size=%Lx type=%s" OR: "disable=%d" */ { int i, err; - unsigned long reg, base, size; + unsigned long reg; + unsigned long long base, size; char *ptr; char line[LINE_SIZE]; @@ -1438,7 +1558,7 @@ static ssize_t mtrr_write (struct file *file, const char *buf, size_t len, if ( !strncmp (line, "disable=", 8) ) { reg = simple_strtoul (line + 8, &ptr, 0); - err = mtrr_del (reg, 0, 0); + err = mtrr_del_page (reg, 0, 0); if (err < 0) return err; return len; } @@ -1447,14 +1567,20 @@ static ssize_t mtrr_write (struct file *file, const char *buf, size_t len, printk ("mtrr: no \"base=\" in line: \"%s\"\n", line); return -EINVAL; } - base = simple_strtoul (line + 5, &ptr, 0); + base = simple_strtoull (line + 5, &ptr, 0); for (; isspace (*ptr); ++ptr); if ( strncmp (ptr, "size=", 5) ) { printk ("mtrr: no \"size=\" in line: \"%s\"\n", line); return -EINVAL; } - size = simple_strtoul (ptr + 5, &ptr, 0); + size = simple_strtoull (ptr + 5, &ptr, 0); + if ( (base & 0xfff) || (size & 0xfff) ) + { + printk ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size: 0x%Lx base: 0x%Lx\n", size, base); + return -EINVAL; + } for (; isspace (*ptr); ++ptr); if ( strncmp (ptr, "type=", 5) ) { @@ -1466,7 +1592,9 @@ static ssize_t mtrr_write (struct file *file, const char *buf, size_t len, for (i = 0; i < MTRR_NUM_TYPES; ++i) { if ( strcmp (ptr, mtrr_strings[i]) ) continue; - err = mtrr_add (base, size, i, 1); + base >>= PAGE_SHIFT; + size >>= PAGE_SHIFT; + err = mtrr_add_page ((unsigned long)base, (unsigned long)size, i, 1); if (err < 0) return err; return len; } @@ -1490,7 +1618,7 @@ static int mtrr_ioctl (struct inode *inode, struct file *file, if ( !suser () ) return -EPERM; if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) return -EFAULT; - err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file); + err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file, 0); if (err < 0) return err; break; case MTRRIOC_SET_ENTRY: @@ -1504,7 +1632,7 @@ static int mtrr_ioctl (struct inode *inode, struct file *file, if ( !suser () ) return -EPERM; if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) return -EFAULT; - err = mtrr_file_del (sentry.base, sentry.size, file); + err = mtrr_file_del (sentry.base, sentry.size, file, 0); if (err < 0) return err; break; case MTRRIOC_KILL_ENTRY: @@ -1519,7 +1647,54 @@ static int mtrr_ioctl (struct inode *inode, struct file *file, return -EFAULT; if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL; (*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type); + + /* Hide entries that go above 4GB */ + if (gentry.base + gentry.size > 0x100000 || gentry.size == 0x100000) + gentry.base = gentry.size = gentry.type = 0; + else { + gentry.base <<= PAGE_SHIFT; + gentry.size <<= PAGE_SHIFT; + gentry.type = type; + } + + if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) ) + return -EFAULT; + break; + case MTRRIOC_ADD_PAGE_ENTRY: + if ( !suser () ) return -EPERM; + if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) + return -EFAULT; + err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file, 1); + if (err < 0) return err; + break; + case MTRRIOC_SET_PAGE_ENTRY: + if ( !suser () ) return -EPERM; + if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) + return -EFAULT; + err = mtrr_add_page (sentry.base, sentry.size, sentry.type, 0); + if (err < 0) return err; + break; + case MTRRIOC_DEL_PAGE_ENTRY: + if ( !suser () ) return -EPERM; + if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) + return -EFAULT; + err = mtrr_file_del (sentry.base, sentry.size, file, 1); + if (err < 0) return err; + break; + case MTRRIOC_KILL_PAGE_ENTRY: + if ( !suser () ) return -EPERM; + if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) + return -EFAULT; + err = mtrr_del_page (-1, sentry.base, sentry.size); + if (err < 0) return err; + break; + case MTRRIOC_GET_PAGE_ENTRY: + if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) ) + return -EFAULT; + if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL; + (*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type); gentry.type = type; + if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) ) return -EFAULT; break; @@ -1578,24 +1753,24 @@ static void compute_ascii (void) for (i = 0; i < max; i++) { (*get_mtrr) (i, &base, &size, &type); - if (size < 1) usage_table[i] = 0; + if (size == 0) usage_table[i] = 0; else { - if (size < 0x100000) + if (size < (0x100000 >> PAGE_SHIFT)) { - /* 1MB */ - factor = 'k'; - size >>= 10; + /* less than 1MB */ + factor = 'K'; + size <<= PAGE_SHIFT - 10; } else { factor = 'M'; - size >>= 20; + size >>= 20 - PAGE_SHIFT; } sprintf (ascii_buffer + ascii_buf_bytes, - "reg%02i: base=0x%08lx (%4liMB), size=%4li%cB: %s, count=%d\n", - i, base, base>>20, size, factor, + "reg%02i: base=0x%05lx000 (%4liMB), size=%4li%cB: %s, count=%d\n", + i, base, base >> (20 - PAGE_SHIFT), size, factor, attrib_to_str (type), usage_table[i]); ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes); } @@ -1762,11 +1937,38 @@ static int __init mtrr_setup(void) mtrr_if = MTRR_IF_INTEL; get_mtrr = intel_get_mtrr; set_mtrr_up = intel_set_mtrr_up; + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + /* The original Athlon docs said that + total addressable memory is 44 bits wide. + It was not really clear whether its MTRRs + follow this or not. (Read: 44 or 36 bits). + However, "x86-64_overview.pdf" explicitly + states that "previous implementations support + 36 bit MTRRs" and also provides a way to + query the width (in bits) of the physical + addressable memory on the Hammer family. + */ + if (boot_cpu_data.x86 == 7 && (cpuid_eax(0x80000000) >= 0x80000008)) { + u32 phys_addr; + phys_addr = cpuid_eax(0x80000008) & 0xff ; + size_or_mask = ~((1 << (phys_addr - PAGE_SHIFT)) - 1); + size_and_mask = ~size_or_mask & 0xfff00000; + break; + } + default: + /* Intel, etc. */ + size_or_mask = 0xff000000; /* 36 bits */ + size_and_mask = 0x00f00000; + break; + } } else if ( test_bit(X86_FEATURE_K6_MTRR, &boot_cpu_data.x86_capability) ) { /* Pre-Athlon (K6) AMD CPU MTRRs */ mtrr_if = MTRR_IF_AMD_K6; get_mtrr = amd_get_mtrr; set_mtrr_up = amd_set_mtrr_up; + size_or_mask = 0xfff00000; /* 32 bits */ + size_and_mask = 0; } else if ( test_bit(X86_FEATURE_CYRIX_ARR, &boot_cpu_data.x86_capability) ) { /* Cyrix ARRs */ mtrr_if = MTRR_IF_CYRIX_ARR; @@ -1774,12 +1976,16 @@ static int __init mtrr_setup(void) set_mtrr_up = cyrix_set_arr_up; get_free_region = cyrix_get_free_region; cyrix_arr_init(); + size_or_mask = 0xfff00000; /* 32 bits */ + size_and_mask = 0; } else if ( test_bit(X86_FEATURE_CENTAUR_MCR, &boot_cpu_data.x86_capability) ) { /* Centaur MCRs */ mtrr_if = MTRR_IF_CENTAUR_MCR; get_mtrr = centaur_get_mcr; set_mtrr_up = centaur_set_mcr_up; centaur_mcr_init(); + size_or_mask = 0xfff00000; /* 32 bits */ + size_and_mask = 0; } else { /* No supported MTRR interface */ mtrr_if = MTRR_IF_NONE; diff --git a/arch/i386/kernel/pci-irq.c b/arch/i386/kernel/pci-irq.c index 17a929bb2..cdf4fc827 100644 --- a/arch/i386/kernel/pci-irq.c +++ b/arch/i386/kernel/pci-irq.c @@ -176,7 +176,6 @@ static void pirq_ali_ide_interrupt(struct pci_dev *router, unsigned reg, unsigne pci_read_config_byte(router, reg, &x); x = (x & 0xe0) | val; /* clear the level->edge transform */ pci_write_config_byte(router, reg, x); - eisa_set_level_irq(irq); } static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) @@ -196,7 +195,6 @@ static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, i pirq_ali_ide_interrupt(router, 0x75, val, irq); break; } - eisa_set_level_irq(irq); return 1; } return 0; @@ -279,6 +277,54 @@ static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, return 1; } +static int pirq_sis_get(struct pci_dev *router, struct pci_dev *dev, int pirq) +{ + u8 x; + int reg = 0x41 + (pirq - 'A') ; + + pci_read_config_byte(router, reg, &x); + return (x & 0x80) ? 0 : (x & 0x0f); +} + +static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +{ + u8 x; + int reg = 0x41 + (pirq - 'A') ; + + pci_read_config_byte(router, reg, &x); + x = (pirq & 0x20) ? 0 : (irq & 0x0f); + pci_write_config_byte(router, reg, x); + + return 1; +} + +/* + * VLSI: nibble offset 0x74 - educated guess due to routing table and + * config space of VLSI 82C534 PCI-bridge/router (1004:0102) + * Tested on HP OmniBook 800 covering PIRQ 1, 2, 4, 8 for onboard + * devices, PIRQ 3 for non-pci(!) soundchip and (untested) PIRQ 6 + * for the busbridge to the docking station. + */ + +static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq) +{ + if (pirq > 8) { + printk("VLSI router pirq escape (%d)\n", pirq); + return 0; + } + return read_config_nybble(router, 0x74, pirq-1); +} + +static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +{ + if (pirq > 8) { + printk("VLSI router pirq escape (%d)\n", pirq); + return 0; + } + write_config_nybble(router, 0x74, pirq-1, irq); + return 1; +} + #ifdef CONFIG_PCI_BIOS static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) @@ -309,7 +355,8 @@ static struct irq_router pirq_routers[] = { { "OPTI", PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C700, pirq_opti_get, pirq_opti_set }, { "NatSemi", PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, pirq_cyrix_get, pirq_cyrix_set }, - + { "SIS", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, pirq_sis_get, pirq_sis_set }, + { "VLSI 82C534", PCI_VENDOR_ID_VLSI, PCI_DEVICE_ID_VLSI_82C534, pirq_vlsi_get, pirq_vlsi_set }, { "default", 0, 0, NULL, NULL } }; @@ -355,7 +402,7 @@ static void __init pirq_find_router(void) pirq_router_dev->slot_name); } -static struct irq_info *pirq_get_info(struct pci_dev *dev, int pin) +static struct irq_info *pirq_get_info(struct pci_dev *dev) { struct irq_routing_table *rt = pirq_table; int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); @@ -373,25 +420,28 @@ static void pcibios_test_irq_handler(int irq, void *dev_id, struct pt_regs *regs static int pcibios_lookup_irq(struct pci_dev *dev, int assign) { + u8 pin; struct irq_info *info; - int i, pirq, pin, newirq; + int i, pirq, newirq; int irq = 0; u32 mask; struct irq_router *r = pirq_router; - struct pci_dev *dev2, *d; + struct pci_dev *dev2; char *msg = NULL; if (!pirq_table) return 0; /* Find IRQ routing entry */ - pin = pci_get_interrupt_pin(dev, &d); - if (pin < 0) { + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + if (!pin) { DBG(" -> no interrupt pin\n"); return 0; } - DBG("IRQ for %s(%d) via %s", dev->slot_name, pin, d->slot_name); - info = pirq_get_info(d, pin); + pin = pin - 1; + + DBG("IRQ for %s:%d", dev->slot_name, pin); + info = pirq_get_info(dev); if (!info) { DBG(" -> not found in routing table\n"); return 0; @@ -405,9 +455,12 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs); mask &= pcibios_irq_mask; - /* Find the best IRQ to assign */ - newirq = 0; - if (assign) { + /* + * Find the best IRQ to assign: use the one + * reported by the device if possible. + */ + newirq = dev->irq; + if (!newirq && assign) { for (i = 0; i < 16; i++) { if (!(mask & (1 << i))) continue; @@ -417,16 +470,22 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) newirq = i; } } - DBG(" -> newirq=%d", newirq); } + DBG(" -> newirq=%d", newirq); /* Try to get current IRQ */ - if (r->get && (irq = r->get(pirq_router_dev, d, pirq))) { + if (r->get && (irq = r->get(pirq_router_dev, dev, pirq))) { DBG(" -> got IRQ %d\n", irq); msg = "Found"; + /* We refuse to override the dev->irq information. Give a warning! */ + if (dev->irq && dev->irq != irq) { + printk("IRQ routing conflict in pirq table! Try 'pci=autoirq'\n"); + return 0; + } } else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) { DBG(" -> assigning IRQ %d", newirq); - if (r->set(pirq_router_dev, d, pirq, newirq)) { + if (r->set(pirq_router_dev, dev, pirq, newirq)) { + eisa_set_level_irq(newirq); DBG(" ... OK\n"); msg = "Assigned"; irq = newirq; @@ -445,9 +504,14 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) /* Update IRQ for all devices with the same pirq value */ pci_for_each_dev(dev2) { - if ((pin = pci_get_interrupt_pin(dev2, &d)) >= 0 && - (info = pirq_get_info(d, pin)) && - info->irq[pin].link == pirq) { + pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin); + if (!pin) + continue; + pin--; + info = pirq_get_info(dev2); + if (!info) + continue; + if (info->irq[pin].link == pirq) { dev2->irq = irq; pirq_penalty[irq]++; if (dev != dev2) @@ -556,19 +620,17 @@ void pcibios_penalize_isa_irq(int irq) void pcibios_enable_irq(struct pci_dev *dev) { - if (!dev->irq) { - u8 pin; - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - if (pin && !pcibios_lookup_irq(dev, 1)) { - char *msg; - if (io_apic_assign_pci_irqs) - msg = " Probably buggy MP table."; - else if (pci_probe & PCI_BIOS_IRQ_SCAN) - msg = ""; - else - msg = " Please try using pci=biosirq."; - printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n", - 'A' + pin - 1, dev->slot_name, msg); - } + u8 pin; + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) { + char *msg; + if (io_apic_assign_pci_irqs) + msg = " Probably buggy MP table."; + else if (pci_probe & PCI_BIOS_IRQ_SCAN) + msg = ""; + else + msg = " Please try using pci=biosirq."; + printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n", + 'A' + pin - 1, dev->slot_name, msg); } } diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 6d3cf4d9a..8e7176c32 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -496,9 +496,9 @@ void release_thread(struct task_struct *dead_task) void copy_segments(struct task_struct *p, struct mm_struct *new_mm) { struct mm_struct * old_mm = current->mm; - void * old_ldt = old_mm->segments, * ldt = old_ldt; + void * old_ldt = old_mm->segments, * ldt; - if (!old_mm->segments) { + if (!old_ldt) { /* * default LDT - use the one from init_task */ diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 692965a06..fffe11398 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -126,7 +126,7 @@ unsigned int mca_pentium_flag; */ struct drive_info_struct { char dummy[32]; } drive_info; struct screen_info screen_info; -struct apm_bios_info apm_bios_info; +struct apm_info apm_info; struct sys_desc_table_struct { unsigned short length; unsigned char table[0]; @@ -608,7 +608,7 @@ void __init setup_arch(char **cmdline_p) ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV); drive_info = DRIVE_INFO; screen_info = SCREEN_INFO; - apm_bios_info = APM_BIOS_INFO; + apm_info.bios = APM_BIOS_INFO; if( SYS_DESC_TABLE.length != 0 ) { MCA_bus = SYS_DESC_TABLE.table[3] &0x2; machine_id = SYS_DESC_TABLE.table[0]; @@ -1531,8 +1531,32 @@ static void __init init_intel(struct cpuinfo_x86 *c) dh = des >> 4; dl = des & 0x0F; + /* Black magic... */ + switch ( dh ) { + case 0: + switch ( dl ) { + case 6: + /* L1 I cache */ + l1i += 8; + break; + case 8: + /* L1 I cache */ + l1i += 16; + break; + case 10: + /* L1 D cache */ + l1d += 8; + break; + case 12: + /* L1 D cache */ + l1d += 16; + break; + default: + /* TLB, or unknown */ + } + break; case 2: if ( dl ) { /* L3 cache */ @@ -1541,6 +1565,16 @@ static void __init init_intel(struct cpuinfo_x86 *c) } break; case 4: + if ( c->x86 > 6 && dl ) { + /* P4 family */ + if ( dl ) { + /* L3 cache */ + cs = 128 << (dl-1); + l3 += cs; + break; + } + } + /* else same as 8 - fall through */ case 8: if ( dl ) { /* L2 cache */ @@ -1556,9 +1590,16 @@ static void __init init_intel(struct cpuinfo_x86 *c) } break; case 7: - /* L1 I cache */ - cs = dl ? (16 << (dl-1)) : 12; - l1i += cs; + if ( dl >= 8 ) + { + /* L2 cache */ + cs = 64<<(dl-8); + l2 += cs; + } else { + /* L0 I cache, count as L1 */ + cs = dl ? (16 << (dl-1)) : 12; + l1i += cs; + } break; default: /* TLB, or something else we don't know about */ @@ -2066,8 +2107,8 @@ int get_cpuinfo(char * buffer) /* Intel-defined */ "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", - "pat", "pse36", "pn", "clflsh", NULL, "dtes", "acpi", "mmx", - "fxsr", "sse", "sse2", "selfsnoop", NULL, "acc", "ia64", NULL, + "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx", + "fxsr", "sse", "sse2", "ss", NULL, "tm", "ia64", NULL, /* AMD-defined */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -2113,7 +2154,7 @@ int get_cpuinfo(char * buffer) p += sprintf(p, "stepping\t: unknown\n"); if ( test_bit(X86_FEATURE_TSC, &c->x86_capability) ) { - p += sprintf(p, "cpu MHz\t\t: %lu.%06lu\n", + p += sprintf(p, "cpu MHz\t\t: %lu.%03lu\n", cpu_khz / 1000, (cpu_khz % 1000)); } @@ -2131,7 +2172,7 @@ int get_cpuinfo(char * buffer) "fpu_exception\t: %s\n" "cpuid level\t: %d\n" "wp\t\t: %s\n" - "features\t:", + "flags\t\t:", c->fdiv_bug ? "yes" : "no", c->hlt_works_ok ? "no" : "yes", c->f00f_bug ? "yes" : "no", diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 57a07765e..858e7dda0 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -886,8 +886,10 @@ void __init smp_boot_cpus(void) /* * If we couldn't find a local APIC, then get out of here now! */ - if (!verify_local_APIC()) { - printk(KERN_ERR "BIOS bug, local APIC at 0x%lX not detected!...\n", mp_lapic_addr); + if (APIC_INTEGRATED(apic_version[boot_cpu_id]) && + !test_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability)) { + printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", + boot_cpu_id); printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n"); #ifndef CONFIG_VISWS io_apic_irqs = 0; @@ -897,6 +899,8 @@ void __init smp_boot_cpus(void) goto smp_done; } + verify_local_APIC(); + /* * If SMP should be disabled, then really disable it! */ diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index b84421374..f2077f2f2 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -62,20 +62,8 @@ struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, */ struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, }; -extern int console_loglevel; extern void bust_spinlocks(void); -static inline void console_silent(void) -{ - console_loglevel = 0; -} - -static inline void console_verbose(void) -{ - if (console_loglevel) - console_loglevel = 15; -} - asmlinkage void divide_error(void); asmlinkage void debug(void); asmlinkage void nmi(void); diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 39a6ce0f8..b2e5a1bfc 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -198,7 +198,7 @@ void __init kmap_init(void) void show_mem(void) { - int i,free = 0, total = 0, reserved = 0; + int i, total = 0, reserved = 0; int shared = 0, cached = 0; int highmem = 0; @@ -214,9 +214,7 @@ void show_mem(void) reserved++; else if (PageSwapCache(mem_map+i)) cached++; - else if (!page_count(mem_map+i)) - free++; - else + else if (page_count(mem_map+i)) shared += page_count(mem_map+i) - 1; } printk("%d pages of RAM\n", total); @@ -437,7 +435,7 @@ void __init zap_low_mappings (void) } /* - * paging_init() sets up the page tables - note that the first 4MB are + * paging_init() sets up the page tables - note that the first 8MB are * already mapped by head.S. * * This routines also unmaps the page at virtual kernel address 0, so diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c index 30d4def40..b3646e275 100644 --- a/arch/ia64/kernel/irq.c +++ b/arch/ia64/kernel/irq.c @@ -181,7 +181,7 @@ int get_irq_list(char *buf) #ifdef CONFIG_SMP unsigned int global_irq_holder = NO_PROC_ID; -volatile unsigned int global_irq_lock; +volatile unsigned long global_irq_lock; /* long for set_bit --RR */ extern void show_stack(unsigned long* esp); diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index b2cd880ad..bfbb2050e 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -245,7 +245,7 @@ si_meminfo (struct sysinfo *val) void show_mem (void) { - int i,free = 0,total = 0,reserved = 0; + int i, total = 0, reserved = 0; int shared = 0, cached = 0; printk("Mem-info:\n"); @@ -258,9 +258,7 @@ show_mem (void) reserved++; else if (PageSwapCache(mem_map+i)) cached++; - else if (!page_count(mem_map + i)) - free++; - else + else if (page_count(mem_map + i)) shared += page_count(mem_map + i) - 1; } printk("%d pages of RAM\n", total); diff --git a/arch/m68k/amiga/amiga_ksyms.c b/arch/m68k/amiga/amiga_ksyms.c index e9fee546e..b7bd84c73 100644 --- a/arch/m68k/amiga/amiga_ksyms.c +++ b/arch/m68k/amiga/amiga_ksyms.c @@ -25,7 +25,6 @@ EXPORT_SYMBOL(amiga_audio_period); EXPORT_SYMBOL(amiga_audio_min_period); EXPORT_SYMBOL(amiga_do_irq); EXPORT_SYMBOL(amiga_do_irq_list); -EXPORT_SYMBOL(amiga_intena_vals); #ifdef CONFIG_AMIGA_PCMCIA EXPORT_SYMBOL(pcmcia_reset); diff --git a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c index 58759ba36..0902518f9 100644 --- a/arch/m68k/amiga/amiints.c +++ b/arch/m68k/amiga/amiints.c @@ -58,7 +58,7 @@ extern int cia_get_irq_list(struct ciabase *base, char *buf); /* irq node variables for amiga interrupt sources */ static irq_node_t *ami_irq_list[AMI_STD_IRQS]; -unsigned short amiga_intena_vals[AMI_STD_IRQS] = { +static unsigned short amiga_intena_vals[AMI_STD_IRQS] = { IF_VERTB, IF_COPER, IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_BLIT, IF_DSKSYN, IF_DSKBLK, IF_RBF, IF_TBE, IF_SOFT, IF_PORTS, IF_EXTER }; @@ -106,7 +106,7 @@ void __init amiga_init_IRQ(void) /* turn off PCMCIA interrupts */ if (AMIGAHW_PRESENT(PCMCIA)) - pcmcia_disable_irq(); + gayle.inten = GAYLE_IRQ_IDE; /* turn off all interrupts and enable the master interrupt bit */ custom.intena = 0x7fff; @@ -352,67 +352,16 @@ inline void amiga_do_irq(int irq, struct pt_regs *fp) ami_irq_list[irq]->handler(irq, ami_irq_list[irq]->dev_id, fp); } -void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server) +void amiga_do_irq_list(int irq, struct pt_regs *fp) { - irq_node_t *node, *slow_nodes; - unsigned short flags, intena; + irq_node_t *node; kstat.irqs[0][SYS_IRQS + irq]++; - if (server->count++) - server->reentrance = 1; - - intena = amiga_intena_vals[irq]; - custom.intreq = intena; - - /* serve fast handler if present - there can only be one of these */ - node = ami_irq_list[irq]; - /* - * Timer interrupts show up like this - */ - if (!node) { - server->count--; - return; - } + custom.intreq = amiga_intena_vals[irq]; - if (node && (node->flags & SA_INTERRUPT)) { - save_flags(flags); - cli(); + for (node = ami_irq_list[irq]; node; node = node->next) node->handler(irq, node->dev_id, fp); - restore_flags(flags); - - server->count--; - return; - } - - /* - * Disable the interrupt source in question and reenable all - * other interrupts. No interrupt handler should ever touch - * the intena flags directly! - */ - custom.intena = intena; - save_flags(flags); -#if 0 /* def CPU_M68060_ONLY */ - sti(); -#else - restore_flags((flags & ~0x0700) | (fp->sr & 0x0700)); -#endif - - slow_nodes = node; - for (;;) { - for (; node; node = node->next) - node->handler(irq, node->dev_id, fp); - - if (!server->reentrance) { - server->count--; - restore_flags(flags); - custom.intena = IF_SETCLR | intena; - return; - } - - server->reentrance = 0; - node = slow_nodes; - } } /* @@ -445,7 +394,6 @@ static void ami_int1(int irq, void *dev_id, struct pt_regs *fp) static void ami_int3(int irq, void *dev_id, struct pt_regs *fp) { unsigned short ints = custom.intreqr & custom.intenar; - static struct irq_server server = {0, 0}; /* if a blitter interrupt */ if (ints & IF_BLIT) { @@ -461,7 +409,7 @@ static void ami_int3(int irq, void *dev_id, struct pt_regs *fp) /* if a vertical blank interrupt */ if (ints & IF_VERTB) - amiga_do_irq_list(IRQ_AMIGA_VERTB, fp, &server); + amiga_do_irq_list(IRQ_AMIGA_VERTB, fp); } static void ami_int4(int irq, void *dev_id, struct pt_regs *fp) diff --git a/arch/m68k/amiga/amisound.c b/arch/m68k/amiga/amisound.c index 2210d05d6..4c94f7862 100644 --- a/arch/m68k/amiga/amisound.c +++ b/arch/m68k/amiga/amisound.c @@ -8,6 +8,7 @@ * for more details. */ +#include <linux/config.h> #include <linux/sched.h> #include <linux/timer.h> #include <linux/init.h> @@ -42,7 +43,9 @@ static u_long clock_constant; void __init amiga_init_sound(void) { - snd_data = amiga_chip_alloc(sizeof(sine_data), "Beep"); + static struct resource beep_res = { "Beep" }; + + snd_data = amiga_chip_alloc_res(sizeof(sine_data), &beep_res); if (!snd_data) { printk (KERN_CRIT "amiga init_sound: failed to allocate chipmem\n"); return; @@ -51,6 +54,11 @@ void __init amiga_init_sound(void) /* setup divisor */ clock_constant = (amiga_colorclock+DATA_SIZE/2)/DATA_SIZE; + + /* without amifb, turn video off and enable high quality sound */ +#ifndef CONFIG_FB_AMIGA + amifb_video_off(); +#endif } static void nosound( unsigned long ignored ); diff --git a/arch/m68k/amiga/chipram.c b/arch/m68k/amiga/chipram.c index b7f9f0508..dfae2b43f 100644 --- a/arch/m68k/amiga/chipram.c +++ b/arch/m68k/amiga/chipram.c @@ -3,173 +3,127 @@ ** ** Modified 03-May-94 by Geert Uytterhoeven <geert@linux-m68k.org> ** - 64-bit aligned allocations for full AGA compatibility +** +** Rewritten 15/9/2000 by Geert to use resource management */ +#include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/ioport.h> +#include <linux/slab.h> #include <asm/amigahw.h> -struct chip_desc { - unsigned first : 1; - unsigned last : 1; - unsigned alloced : 1; - unsigned length : 24; - long pad; /* We suppose this makes this struct 64 bits long!! */ -}; - -#define DP(ptr) ((struct chip_desc *)(ptr)) +unsigned long amiga_chip_size; -u_long amiga_chip_size; +static struct resource chipram_res = { "Chip RAM", CHIP_PHYSADDR }; static unsigned long chipavail; -static struct resource chipram = { "Chip RAM", 0 }; -unsigned long amiga_chip_avail( void ) +void __init amiga_chip_init(void) { -#ifdef DEBUG - printk("chip_avail : %ld bytes\n",chipavail); + if (!AMIGAHW_PRESENT(CHIP_RAM)) + return; + +#ifndef CONFIG_APUS_FAST_EXCEPT + /* + * Remove the first 4 pages where PPC exception handlers will be located + */ + amiga_chip_size -= 0x4000; #endif - return chipavail; -} + chipram_res.end = amiga_chip_size-1; + request_resource(&iomem_resource, &chipram_res); + chipavail = amiga_chip_size; +} -void __init amiga_chip_init (void) + +void *amiga_chip_alloc(unsigned long size, const char *name) { - struct chip_desc *dp; - - if (!AMIGAHW_PRESENT(CHIP_RAM)) - return; + struct resource *res; - chipram.end = amiga_chip_size-1; - request_resource(&iomem_resource, &chipram); - - /* initialize start boundary */ - - dp = DP(chipaddr); - dp->first = 1; - - dp->alloced = 0; - dp->length = amiga_chip_size - 2*sizeof(*dp); - - /* initialize end boundary */ - dp = DP(chipaddr + amiga_chip_size) - 1; - dp->last = 1; - - dp->alloced = 0; - dp->length = amiga_chip_size - 2*sizeof(*dp); - chipavail = dp->length; /*MILAN*/ + /* round up */ + size = PAGE_ALIGN(size); #ifdef DEBUG - printk ("chipram end boundary is %p, length is %d\n", dp, - dp->length); + printk("amiga_chip_alloc: allocate %ld bytes\n", size); #endif + res = kmalloc(sizeof(struct resource), GFP_KERNEL); + if (!res) + return NULL; + memset(res, 0, sizeof(struct resource)); + res->name = name; + + if (allocate_resource(&chipram_res, res, size, 0, UINT_MAX, PAGE_SIZE, NULL, NULL) < 0) { + kfree(res); + return NULL; + } + chipavail -= size; +#ifdef DEBUG + printk("amiga_chip_alloc: returning %lx\n", res->start); +#endif + return (void *)ZTWO_VADDR(res->start); } -void *amiga_chip_alloc(long size, const char *name) -{ - /* last chunk */ - struct chip_desc *dp; - void *ptr; - /* round off */ - size = (size + 7) & ~7; + /* + * Warning: + * amiga_chip_alloc_res is meant only for drivers that need to allocate + * Chip RAM before kmalloc() is functional. As a consequence, those + * drivers must not free that Chip RAM afterwards. + */ -#ifdef DEBUG - printk("amiga_chip_alloc: allocate %ld bytes\n", size); -#endif +void * __init amiga_chip_alloc_res(unsigned long size, struct resource *res) +{ + unsigned long start; + + /* round up */ + size = PAGE_ALIGN(size); + /* dmesg into chipmem prefers memory at the safe end */ + start = CHIP_PHYSADDR + chipavail - size; - /* - * get pointer to descriptor for last chunk by - * going backwards from end chunk - */ - dp = DP(chipaddr + amiga_chip_size) - 1; - dp = DP((unsigned long)dp - dp->length) - 1; - - while ((dp->alloced || dp->length < size) - && !dp->first) - dp = DP ((unsigned long)dp - dp[-1].length) - 2; - - if (dp->alloced || dp->length < size) { - printk ("no chipmem available for %ld allocation\n", size); - return NULL; - } - - if (dp->length < (size + 2*sizeof(*dp))) { - /* length too small to split; allocate the whole thing */ - dp->alloced = 1; - ptr = (void *)(dp+1); - dp = DP((unsigned long)ptr + dp->length); - dp->alloced = 1; #ifdef DEBUG - printk ("amiga_chip_alloc: no split\n"); + printk("amiga_chip_alloc_res: allocate %ld bytes\n", size); #endif - } else { - /* split the extent; use the end part */ - long newsize = dp->length - (2*sizeof(*dp) + size); - + if (allocate_resource(&chipram_res, res, size, start, UINT_MAX, PAGE_SIZE, NULL, NULL) < 0) { + printk("amiga_chip_alloc_res: first alloc failed!\n"); + if (allocate_resource(&chipram_res, res, size, 0, UINT_MAX, PAGE_SIZE, NULL, NULL) < 0) + return NULL; + } + chipavail -= size; #ifdef DEBUG - printk ("amiga_chip_alloc: splitting %d to %ld\n", dp->length, - newsize); + printk("amiga_chip_alloc_res: returning %lx\n", res->start); #endif - dp->length = newsize; - dp = DP((unsigned long)(dp+1) + newsize); - dp->first = dp->last = 0; - dp->alloced = 0; - dp->length = newsize; - dp++; - dp->first = dp->last = 0; - dp->alloced = 1; - dp->length = size; - ptr = (void *)(dp+1); - dp = DP((unsigned long)ptr + size); - dp->alloced = 1; - dp->length = size; - } + return (void *)ZTWO_VADDR(res->start); +} +void amiga_chip_free(void *ptr) +{ + unsigned long start = ZTWO_PADDR(ptr); + struct resource **p, *res; + unsigned long size; + + for (p = &chipram_res.child; (res = *p); p = &res->sibling) { + if (res->start != start) + continue; + *p = res->sibling; + size = res->end-start; #ifdef DEBUG - printk ("amiga_chip_alloc: returning %p\n", ptr); + printk("amiga_chip_free: free %ld bytes at %p\n", size, ptr); #endif - - if ((unsigned long)ptr & 7) - panic("amiga_chip_alloc: alignment violation\n"); - - chipavail -= size + (2*sizeof(*dp)); /*MILAN*/ - - if (!request_mem_region(ZTWO_PADDR(ptr), size, name)) - printk(KERN_WARNING "amiga_chip_alloc: region of size %ld at 0x%08lx " - "is busy\n", size, ZTWO_PADDR(ptr)); - - return ptr; + chipavail += size; + kfree(res); + return; + } + printk("amiga_chip_free: trying to free nonexistent region at %p\n", ptr); } -void amiga_chip_free (void *ptr) -{ - struct chip_desc *sdp = DP(ptr) - 1, *dp2; - struct chip_desc *edp = DP((unsigned long)ptr + sdp->length); - chipavail += sdp->length + (2* sizeof(sdp)); /*MILAN*/ +unsigned long amiga_chip_avail(void) +{ #ifdef DEBUG - printk("chip_free: free %ld bytes at %p\n",sdp->length,ptr); + printk("amiga_chip_avail : %ld bytes\n", chipavail); #endif - /* deallocate the chunk */ - sdp->alloced = edp->alloced = 0; - release_mem_region(ZTWO_PADDR(ptr), sdp->length); - - /* check if we should merge with the previous chunk */ - if (!sdp->first && !sdp[-1].alloced) { - dp2 = DP((unsigned long)sdp - sdp[-1].length) - 2; - dp2->length += sdp->length + 2*sizeof(*sdp); - edp->length = dp2->length; - sdp = dp2; - } - - /* check if we should merge with the following chunk */ - if (!edp->last && !edp[1].alloced) { - dp2 = DP((unsigned long)edp + edp[1].length) + 2; - dp2->length += edp->length + 2*sizeof(*sdp); - sdp->length = dp2->length; - edp = dp2; - } + return chipavail; } diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c index cda898699..d72d8af9f 100644 --- a/arch/m68k/amiga/cia.c +++ b/arch/m68k/amiga/cia.c @@ -27,18 +27,17 @@ struct ciabase { u_short int_mask; int handler_irq, cia_irq, server_irq; char *name; - struct irq_server server; irq_handler_t irq_list[CIA_IRQS]; } ciaa_base = { &ciaa, 0, 0, IF_PORTS, IRQ_AMIGA_AUTO_2, IRQ_AMIGA_CIAA, IRQ_AMIGA_PORTS, - "CIAA handler", {0, 0} + "CIAA handler" }, ciab_base = { &ciab, 0, 0, IF_EXTER, IRQ_AMIGA_AUTO_6, IRQ_AMIGA_CIAB, IRQ_AMIGA_EXTER, - "CIAB handler", {0, 0} + "CIAB handler" }; /* @@ -136,7 +135,7 @@ static void cia_handler(int irq, void *dev_id, struct pt_regs *fp) } ints >>= 1; } - amiga_do_irq_list(base->server_irq, fp, &base->server); + amiga_do_irq_list(base->server_irq, fp); } void __init cia_init_IRQ(struct ciabase *base) diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c index 528f206ff..618d9a618 100644 --- a/arch/m68k/amiga/config.c +++ b/arch/m68k/amiga/config.c @@ -31,6 +31,7 @@ #include <asm/amigahw.h> #include <asm/amigaints.h> #include <asm/irq.h> +#include <asm/keyboard.h> #include <asm/machdep.h> #include <asm/io.h> @@ -43,17 +44,36 @@ unsigned char amiga_vblank; unsigned char amiga_psfreq; struct amiga_hw_present amiga_hw_present; -static const char *amiga_models[] = { - "A500", "A500+", "A600", "A1000", "A1200", "A2000", "A2500", "A3000", - "A3000T", "A3000+", "A4000", "A4000T", "CDTV", "CD32", "Draco" +static const char s_a500[] __initdata = "A500"; +static const char s_a500p[] __initdata = "A500+"; +static const char s_a600[] __initdata = "A600"; +static const char s_a1000[] __initdata = "A1000"; +static const char s_a1200[] __initdata = "A1200"; +static const char s_a2000[] __initdata = "A2000"; +static const char s_a2500[] __initdata = "A2500"; +static const char s_a3000[] __initdata = "A3000"; +static const char s_a3000t[] __initdata = "A3000T"; +static const char s_a3000p[] __initdata = "A3000+"; +static const char s_a4000[] __initdata = "A4000"; +static const char s_a4000t[] __initdata = "A4000T"; +static const char s_cdtv[] __initdata = "CDTV"; +static const char s_cd32[] __initdata = "CD32"; +static const char s_draco[] __initdata = "Draco"; +static const char *amiga_models[] __initdata = { + s_a500, s_a500p, s_a600, s_a1000, s_a1200, s_a2000, s_a2500, s_a3000, + s_a3000t, s_a3000p, s_a4000, s_a4000t, s_cdtv, s_cd32, s_draco, }; +static char amiga_model_name[13] = "Amiga "; + extern char m68k_debug_device[]; static void amiga_sched_init(void (*handler)(int, void *, struct pt_regs *)); /* amiga specific keyboard functions */ extern int amiga_keyb_init(void); extern int amiga_kbdrate (struct kbd_repeat *); +extern int amiga_kbd_translate(unsigned char keycode, unsigned char *keycodep, + char raw_mode); /* amiga specific irq functions */ extern void amiga_init_IRQ (void); extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *); @@ -127,6 +147,8 @@ static struct resource rtc_resource = { NULL, 0x00dc0000, 0x00dcffff }; +static struct resource ram_resource[NUM_MEMINFO]; + /* * Parse an Amiga-specific record in the bootinfo @@ -200,8 +222,10 @@ static void __init amiga_identify(void) memset(&amiga_hw_present, 0, sizeof(amiga_hw_present)); printk("Amiga hardware found: "); - if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) + if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) { printk("[%s] ", amiga_models[amiga_model-AMI_500]); + strcat(amiga_model_name, amiga_models[amiga_model-AMI_500]); + } switch(amiga_model) { case AMI_UNKNOWN: @@ -367,6 +391,8 @@ void __init config_amiga(void) mach_sched_init = amiga_sched_init; mach_keyb_init = amiga_keyb_init; mach_kbdrate = amiga_kbdrate; + mach_kbd_translate = amiga_kbd_translate; + SYSRQ_KEY = 0xff; mach_init_IRQ = amiga_init_IRQ; mach_default_handler = &amiga_default_handler; mach_request_irq = amiga_request_irq; @@ -447,6 +473,17 @@ void __init config_amiga(void) disabled_z2mem>>10); } + /* request all RAM */ + for (i = 0; i < m68k_num_memory; i++) { + ram_resource[i].name = + (m68k_memory[i].addr >= 0x01000000) ? "32-bit Fast RAM" : + (m68k_memory[i].addr < 0x00c00000) ? "16-bit Fast RAM" : + "16-bit Slow RAM"; + ram_resource[i].start = m68k_memory[i].addr; + ram_resource[i].end = m68k_memory[i].addr+m68k_memory[i].size-1; + request_resource(&iomem_resource, &ram_resource[i]); + } + /* initialize chipram allocator */ amiga_chip_init (); @@ -478,8 +515,11 @@ static unsigned short jiffy_ticks; static void __init amiga_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)) { + static struct resource sched_res = { "timer" }; jiffy_ticks = (amiga_eclock+HZ/2)/HZ; + if (!request_mem_region(CIAB_PHYSADDR+0x400, 0x200, "timer")) + printk("Cannot allocate ciab.ta{lo,hi}\n"); ciab.cra &= 0xC0; /* turn off timer A, continuous mode, from Eclk */ ciab.talo = jiffy_ticks % 256; ciab.tahi = jiffy_ticks / 256; @@ -827,7 +867,9 @@ static void amiga_mem_console_write(struct console *co, const char *s, static void amiga_savekmsg_init(void) { - savekmsg = (struct savekmsg *)amiga_chip_alloc(SAVEKMSG_MAXMEM, "Debug"); + static struct resource debug_res = { "Debug" }; + + savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res); savekmsg->magic1 = SAVEKMSG_MAGIC1; savekmsg->magic2 = SAVEKMSG_MAGIC2; savekmsg->magicptr = virt_to_phys(savekmsg); @@ -933,9 +975,7 @@ static void amiga_heartbeat(int on) static void amiga_get_model(char *model) { - strcpy(model, "Amiga "); - if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) - strcat(model, amiga_models[amiga_model-AMI_500]); + strcpy(model, amiga_model_name); } diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c index d7a64faea..f4f284a9a 100644 --- a/arch/m68k/atari/atakeyb.c +++ b/arch/m68k/atari/atakeyb.c @@ -13,6 +13,7 @@ * enhanced by Bjoern Brauel and Roman Hodek */ +#include <linux/config.h> #include <linux/sched.h> #include <linux/kernel.h> #include <linux/interrupt.h> @@ -24,6 +25,7 @@ #include <linux/random.h> #include <linux/init.h> #include <linux/kbd_ll.h> +#include <linux/kbd_kern.h> #include <asm/atariints.h> #include <asm/atarihw.h> @@ -362,7 +364,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp) if (acia_stat & ACIA_RDRF) /* received a character */ { scancode = acia.key_data; /* get it or reset the ACIA, I'll get it! */ - mark_bh(KEYBOARD_BH); + tasklet_schedule(&keyboard_tasklet); interpret_scancode: switch (kb_state.state) { @@ -860,3 +862,16 @@ int atari_kbdrate( struct kbd_repeat *k ) return( 0 ); } + +int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode) +{ +#ifdef CONFIG_MAGIC_SYSRQ + /* ALT+HELP pressed? */ + if ((keycode == 98) && ((shift_state & 0xff) == 8)) + *keycodep = 0xff; + else +#endif + *keycodep = keycode; + return 1; +} + diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c index 3acfeff7a..70a32fb65 100644 --- a/arch/m68k/atari/config.c +++ b/arch/m68k/atari/config.c @@ -60,6 +60,8 @@ static int atari_get_hardware_list(char *buffer); /* atari specific keyboard functions */ extern int atari_keyb_init(void); extern int atari_kbdrate (struct kbd_repeat *); +extern int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep, + char raw_mode); extern void atari_kbd_leds (unsigned int); /* atari specific irq functions */ extern void atari_init_IRQ (void); @@ -253,6 +255,8 @@ void __init config_atari(void) mach_sched_init = atari_sched_init; mach_keyb_init = atari_keyb_init; mach_kbdrate = atari_kbdrate; + mach_kbd_translate = atari_kbd_translate; + SYSRQ_KEY = 0xff; mach_kbd_leds = atari_kbd_leds; mach_init_IRQ = atari_init_IRQ; mach_request_irq = atari_request_irq; diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c index d0acdaaae..b4a797f2e 100644 --- a/arch/m68k/atari/stram.c +++ b/arch/m68k/atari/stram.c @@ -20,6 +20,7 @@ #include <linux/vmalloc.h> #include <linux/pagemap.h> #include <linux/shm.h> +#include <linux/bootmem.h> #include <asm/setup.h> #include <asm/machdep.h> @@ -33,6 +34,7 @@ #ifdef CONFIG_STRAM_SWAP #define MAJOR_NR Z2RAM_MAJOR +#define do_z2_request do_stram_request #include <linux/blk.h> #undef DEVICE_NAME #define DEVICE_NAME "stram" @@ -123,6 +125,10 @@ unswap_by_move disabled because it does not handle swapped shm pages. */ +/* 2000-05-01: ++andreas + Integrated with bootmem. Remove all traces of unswap_by_move. +*/ + #ifdef CONFIG_STRAM_SWAP #define ALIGN_IF_SWAP(x) PAGE_ALIGN(x) #else @@ -130,10 +136,10 @@ #endif /* get index of swap page at address 'addr' */ -#define SWAP_NR(addr) (((unsigned long)(addr)-swap_start) >> PAGE_SHIFT) +#define SWAP_NR(addr) (((addr) - swap_start) >> PAGE_SHIFT) /* get address of swap page #'nr' */ -#define SWAP_ADDR(nr) ((void *)(swap_start + ((nr)<<PAGE_SHIFT))) +#define SWAP_ADDR(nr) (swap_start + ((nr) << PAGE_SHIFT)) /* get number of pages for 'n' bytes (already page-aligned) */ #define N_PAGES(n) ((n) >> PAGE_SHIFT) @@ -144,11 +150,8 @@ #define MAX_STRAM_FRACTION_NOM 1 #define MAX_STRAM_FRACTION_DENOM 3 -/* Start and end of the (pre-mem_init) reserved ST-RAM region */ -static unsigned long rsvd_stram_beg, rsvd_stram_end; - /* Start and end (virtual) of ST-RAM */ -static unsigned long stram_start, stram_end; +static void *stram_start, *stram_end; /* set after memory_init() executed and allocations via start_mem aren't * possible anymore */ @@ -159,7 +162,7 @@ static int kernel_in_stram; typedef struct stram_block { struct stram_block *next; - unsigned long start; + void *start; unsigned long size; unsigned flags; const char *owner; @@ -168,7 +171,6 @@ typedef struct stram_block { /* values for flags field */ #define BLOCK_FREE 0x01 /* free structure in the BLOCKs pool */ #define BLOCK_KMALLOCED 0x02 /* structure allocated by kmalloc() */ -#define BLOCK_STATIC 0x04 /* pre-mem_init() allocated block */ #define BLOCK_GFP 0x08 /* block allocated with __get_dma_pages() */ #define BLOCK_INSWAP 0x10 /* block allocated in swap space */ @@ -191,7 +193,7 @@ static BLOCK static_blocks[N_STATIC_BLOCKS]; static int max_swap_size = -1; /* start and end of swapping area */ -static unsigned long swap_start, swap_end; +static void *swap_start, *swap_end; /* The ST-RAM's swap info structure */ static struct swap_info_struct *stram_swap_info; @@ -215,7 +217,6 @@ static DECLARE_MUTEX(stram_swap_sem); #ifdef DO_PROC static unsigned stat_swap_read = 0; static unsigned stat_swap_write = 0; -static unsigned stat_swap_move = 0; static unsigned stat_swap_force = 0; #endif /* DO_PROC */ @@ -224,21 +225,19 @@ static unsigned stat_swap_force = 0; /***************************** Prototypes *****************************/ #ifdef CONFIG_STRAM_SWAP -static int swap_init( unsigned long start_mem, unsigned long swap_data ); +static int swap_init(void *start_mem, void *swap_data); static void *get_stram_region( unsigned long n_pages ); static void free_stram_region( unsigned long offset, unsigned long n_pages ); -static int in_some_region( unsigned long addr ); +static int in_some_region(void *addr); static unsigned long find_free_region( unsigned long n_pages, unsigned long *total_free, unsigned long *region_free ); -static void do_stram_request( void ); +static void do_stram_request(request_queue_t *); static int stram_open( struct inode *inode, struct file *filp ); static int stram_release( struct inode *inode, struct file *filp ); -static void do_z2_request( void ); #endif -static int get_gfp_order( unsigned long size ); -static void reserve_region( unsigned long addr, unsigned long end ); +static void reserve_region(void *start, void *end); static BLOCK *add_region( void *addr, unsigned long size ); static BLOCK *find_region( void *addr ); static int remove_region( BLOCK *block ); @@ -264,14 +263,12 @@ void __init atari_stram_init(void) /* determine whether kernel code resides in ST-RAM (then ST-RAM is the * first memory block at virtual 0x0) */ - stram_start = (unsigned long)phys_to_virt(0); + stram_start = phys_to_virt(0); kernel_in_stram = (stram_start == 0); for( i = 0; i < m68k_num_memory; ++i ) { if (m68k_memory[i].addr == 0) { /* skip first 2kB or page (supervisor-only!) */ - rsvd_stram_beg = stram_start + ALIGN_IF_SWAP(0x800); - rsvd_stram_end = rsvd_stram_beg; stram_end = stram_start + m68k_memory[i].size; return; } @@ -282,10 +279,10 @@ void __init atari_stram_init(void) /* - * This function is called from mem_init() to reserve the pages needed for + * This function is called from setup_arch() to reserve the pages needed for * ST-RAM management. */ -void __init atari_stram_reserve_pages(unsigned long start_mem) +void __init atari_stram_reserve_pages(void *start_mem) { #ifdef CONFIG_STRAM_SWAP /* if max_swap_size is negative (i.e. no stram_swap= option given), @@ -299,42 +296,24 @@ void __init atari_stram_reserve_pages(unsigned long start_mem) max_swap_size = (!MACH_IS_HADES && (N_PAGES(stram_end-stram_start)*MAX_STRAM_FRACTION_DENOM <= - max_mapnr*MAX_STRAM_FRACTION_NOM)) ? 16*1024*1024 : 0; + (high_memory>>PAGE_SHIFT)*MAX_STRAM_FRACTION_NOM)) ? 16*1024*1024 : 0; DPRINTK( "atari_stram_reserve_pages: max_swap_size = %d\n", max_swap_size ); #endif /* always reserve first page of ST-RAM, the first 2 kB are * supervisor-only! */ - set_bit( PG_reserved, &virt_to_page(stram_start)->flags ); + if (!kernel_in_stram) + reserve_bootmem (0, PAGE_SIZE); #ifdef CONFIG_STRAM_SWAP - if (!max_swap_size) { - fallback: -#endif - DPRINTK( "atari_stram_reserve_pages: swapping disabled\n" ); - if (!kernel_in_stram) { - /* Reserve all pages that have been marked by pre-mem_init - * stram_alloc() (e.g. for the screen memory). */ - reserve_region( rsvd_stram_beg, rsvd_stram_end ); - DPRINTK( "atari_stram_reserve_pages: reseverved %08lx-%08lx\n", - rsvd_stram_beg, rsvd_stram_end ); - } - /* else (kernel in ST-RAM): nothing to do, ST-RAM buffers are - * kernel data */ -#ifdef CONFIG_STRAM_SWAP - } - else { - unsigned long swap_data; - BLOCK *p; - - /* determine first page to use as swap: - * if the kernel is in TT-RAM, this is the first page of (usable) - * ST-RAM; else if there were already some allocations (probable...), - * use the lowest address of these (the list is sorted by address!); - * otherwise just use the end of kernel data (= start_mem) */ - swap_start = !kernel_in_stram ? stram_start + PAGE_SIZE : - alloc_list ? alloc_list->start : - start_mem; + { + void *swap_data; + + start_mem = (void *) PAGE_ALIGN ((unsigned long) start_mem); + /* determine first page to use as swap: if the kernel is + in TT-RAM, this is the first page of (usable) ST-RAM; + otherwise just use the end of kernel data (= start_mem) */ + swap_start = !kernel_in_stram ? stram_start + PAGE_SIZE : start_mem; /* decrement by one page, rest of kernel assumes that first swap page * is always reserved and maybe doesn't handle SWP_ENTRY == 0 * correctly */ @@ -343,7 +322,7 @@ void __init atari_stram_reserve_pages(unsigned long start_mem) if (swap_end-swap_start > max_swap_size) swap_end = swap_start + max_swap_size; DPRINTK( "atari_stram_reserve_pages: swapping enabled; " - "swap=%08lx-%08lx\n", swap_start, swap_end ); + "swap=%p-%p\n", swap_start, swap_end); /* reserve some amount of memory for maintainance of * swapping itself: one page for each 2048 (PAGE_SIZE/2) @@ -352,24 +331,18 @@ void __init atari_stram_reserve_pages(unsigned long start_mem) start_mem += ((SWAP_NR(swap_end) + PAGE_SIZE/2 - 1) >> (PAGE_SHIFT-1)) << PAGE_SHIFT; /* correct swap_start if necessary */ - if (swap_start == swap_data) - swap_start = start_mem; + if (swap_start + PAGE_SIZE == swap_data) + swap_start = start_mem - PAGE_SIZE; if (!swap_init( start_mem, swap_data )) { printk( KERN_ERR "ST-RAM swap space initialization failed\n" ); max_swap_size = 0; - goto fallback; + return; } /* reserve region for swapping meta-data */ - reserve_region( swap_data, start_mem ); + reserve_region(swap_data, start_mem); /* reserve swapping area itself */ - reserve_region( swap_start+PAGE_SIZE, swap_end ); - - /* Formerly static areas have been included in the swap area. */ - for( p = alloc_list; p; p = p->next ) { - if (p->flags & BLOCK_STATIC) - p->flags = (p->flags & ~BLOCK_STATIC) | BLOCK_INSWAP; - } + reserve_region(swap_start + PAGE_SIZE, swap_end); /* * If the whole ST-RAM is used for swapping, there are no allocatable @@ -387,15 +360,12 @@ void __init atari_stram_reserve_pages(unsigned long start_mem) * You just will get non-DMA-able memory... */ mach_max_dma_address = 0xffffffff; - - /* - * Ok, num_physpages needs not be really exact, but it's better to - * subtract the pages set aside for swapping. - */ - num_physpages -= SWAP_NR(swap_end)-1; } #endif - +} + +void atari_stram_mem_init_hook (void) +{ mem_init_done = 1; } @@ -420,68 +390,33 @@ void __init atari_stram_reserve_pages(unsigned long start_mem) * likely to fail :-( * */ -void *atari_stram_alloc( long size, unsigned long *start_mem, - const char *owner ) +void *atari_stram_alloc(long size, const char *owner) { void *addr = NULL; BLOCK *block; int flags; - DPRINTK( "atari_stram_alloc(size=%08lx,*start_mem=%08lx,owner=%s)\n", - size, start_mem ? *start_mem : 0xffffffff, owner ); - - if (start_mem && mem_init_done) { - printk( KERN_ERR "atari_stram_alloc called with start_mem!=NULL " - "after mem_init() from %p\n", __builtin_return_address(0) ); - return( NULL ); - } - if (!start_mem && !mem_init_done) { - printk( KERN_ERR "atari_stram_alloc called with start_mem==NULL " - "before mem_init() from %p\n", __builtin_return_address(0) ); - return( NULL ); - } + DPRINTK("atari_stram_alloc(size=%08lx,owner=%s)\n", size, owner); size = ALIGN_IF_SWAP(size); DPRINTK( "atari_stram_alloc: rounded size = %08lx\n", size ); - if (!mem_init_done) { - /* before mem_init(): allocate "statically", i.e. either in the kernel - * data space (current end in *start_mem), or at the end of currently - * reserved ST-RAM. */ - if (kernel_in_stram) { - /* Get memory from kernel data space */ - *start_mem = ALIGN_IF_SWAP(*start_mem); - addr = (void *)*start_mem; - *start_mem += size; - DPRINTK( "atari_stram_alloc: pre-mem_init and k/ST: " - "shifted start_mem to %08lx, addr=%p\n", - *start_mem, addr ); - } - else { - /* Get memory from rsvd_stram_beg */ - if (rsvd_stram_end + size < stram_end) { - addr = (void *) rsvd_stram_end; - rsvd_stram_end += size; - DPRINTK( "atari_stram_alloc: pre-mem_init and k/TT: " - "shifted rsvd_stram_end to %08lx, addr=%p\n", - rsvd_stram_end, addr ); - } - } - flags = BLOCK_STATIC; - } #ifdef CONFIG_STRAM_SWAP - else if (max_swap_size) { - /* If swapping is active (can only be the case after mem_init()!): - * make some free space in the swap "device". */ + if (max_swap_size) { + /* If swapping is active: make some free space in the swap + "device". */ DPRINTK( "atari_stram_alloc: after mem_init, swapping ok, " "calling get_region\n" ); addr = get_stram_region( N_PAGES(size) ); flags = BLOCK_INSWAP; } + else #endif + if (!mem_init_done) + return alloc_bootmem_low(size); else { /* After mem_init() and no swapping: can only resort to * __get_dma_pages() */ - addr = (void *)__get_dma_pages(GFP_KERNEL, get_gfp_order(size)); + addr = (void *)__get_dma_pages(GFP_KERNEL, get_order(size)); flags = BLOCK_GFP; DPRINTK( "atari_stram_alloc: after mem_init, swapping off, " "get_pages=%p\n", addr ); @@ -492,14 +427,12 @@ void *atari_stram_alloc( long size, unsigned long *start_mem, /* out of memory for BLOCK structure :-( */ DPRINTK( "atari_stram_alloc: out of mem for BLOCK -- " "freeing again\n" ); - if (flags == BLOCK_STATIC) - rsvd_stram_end -= size; #ifdef CONFIG_STRAM_SWAP - else if (flags == BLOCK_INSWAP) + if (flags == BLOCK_INSWAP) free_stram_region( SWAP_NR(addr), N_PAGES(size) ); -#endif else - free_pages( (unsigned long)addr, get_gfp_order(size)); +#endif + free_pages((unsigned long)addr, get_order(size)); return( NULL ); } block->owner = owner; @@ -527,15 +460,15 @@ void atari_stram_free( void *addr ) if (!max_swap_size) { #endif if (block->flags & BLOCK_GFP) { - DPRINTK( "atari_stram_free: is kmalloced, order_size=%d\n", - get_gfp_order(block->size) ); - free_pages( (unsigned long)addr, get_gfp_order(block->size) ); + DPRINTK("atari_stram_free: is kmalloced, order_size=%d\n", + get_order(block->size)); + free_pages((unsigned long)addr, get_order(block->size)); } else goto fail; #ifdef CONFIG_STRAM_SWAP } - else if (block->flags & (BLOCK_INSWAP|BLOCK_STATIC)) { + else if (block->flags & BLOCK_INSWAP) { DPRINTK( "atari_stram_free: is swap-alloced\n" ); free_stram_region( SWAP_NR(block->start), N_PAGES(block->size) ); } @@ -563,17 +496,18 @@ void atari_stram_free( void *addr ) * Initialize ST-RAM swap device * (lots copied and modified from sys_swapon() in mm/swapfile.c) */ -static int __init swap_init(unsigned long start_mem, unsigned long swap_data) +static int __init swap_init(void *start_mem, void *swap_data) { - static struct dentry fake_dentry[3]; + static struct dentry fake_dentry; + static struct vfsmount fake_vfsmnt; struct swap_info_struct *p; struct inode swap_inode; unsigned int type; - unsigned long addr; + void *addr; int i, j, k, prev; - DPRINTK( "swap_init(start_mem=%08lx, swap_data=%08lx)\n", - start_mem, swap_data ); + DPRINTK("swap_init(start_mem=%p, swap_data=%p)\n", + start_mem, swap_data); /* need at least one page for swapping to (and this also isn't very * much... :-) */ @@ -598,18 +532,16 @@ static int __init swap_init(unsigned long start_mem, unsigned long swap_data) stram_swap_type = type; /* fake some dir cache entries to give us some name in /dev/swaps */ - fake_dentry[0].d_covers = &fake_dentry[1]; - fake_dentry[0].d_parent = &fake_dentry[0]; - fake_dentry[1].d_parent = &fake_dentry[2]; - fake_dentry[1].d_name.name = "stram (internal)"; - fake_dentry[1].d_name.len = 16; - fake_dentry[2].d_covers = &fake_dentry[2]; - fake_dentry[2].d_parent = &fake_dentry[2]; + fake_dentry.d_parent = &fake_dentry; + fake_dentry.d_name.name = "stram (internal)"; + fake_dentry.d_name.len = 16; + fake_vfsmnt.mnt_parent = &fake_vfsmnt; p->flags = SWP_USED; - p->swap_file = &fake_dentry[0]; + p->swap_file = &fake_dentry; + p->swap_vfsmnt = &fake_vfsmnt; p->swap_device = 0; - p->swap_map = (unsigned short *)swap_data; + p->swap_map = swap_data; p->cluster_nr = 0; p->next = -1; p->prio = 0x7ff0; /* a rather high priority, but not the higest @@ -628,7 +560,7 @@ static int __init swap_init(unsigned long start_mem, unsigned long swap_data) k = 0; /* # of already allocated pages (from pre-mem_init stram_alloc()) */ p->lowest_bit = 0; p->highest_bit = 0; - for( i = 1, addr = (unsigned long)SWAP_ADDR(1); i < p->max; + for( i = 1, addr = SWAP_ADDR(1); i < p->max; i++, addr += PAGE_SIZE ) { if (in_some_region( addr )) { p->swap_map[i] = SWAP_MAP_BAD; @@ -685,8 +617,8 @@ static int __init swap_init(unsigned long start_mem, unsigned long swap_data) * what to do if a write is requested later. */ static inline void unswap_pte(struct vm_area_struct * vma, unsigned long - address, pte_t *dir, unsigned long entry, - unsigned long page /*, int isswap */) + address, pte_t *dir, swp_entry_t entry, + struct page *page) { pte_t pte = *dir; @@ -698,34 +630,25 @@ static inline void unswap_pte(struct vm_area_struct * vma, unsigned long memory */ if (pte_page(pte) != page) return; - if (0 /* isswap */) - virt_to_page(pte_page(pte))->offset = page; - else - /* We will be removing the swap cache in a moment, so... */ - set_pte(dir, pte_mkdirty(pte)); + /* We will be removing the swap cache in a moment, so... */ + set_pte(dir, pte_mkdirty(pte)); return; } - if (pte_val(pte) != entry) + if (pte_val(pte) != entry.val) return; - if (0 /* isswap */) { - DPRINTK( "unswap_pte: replacing entry %08lx by %08lx", entry, page ); - set_pte(dir, __pte(page)); - } - else { - DPRINTK( "unswap_pte: replacing entry %08lx by new page %08lx", - entry, page ); - set_pte(dir, pte_mkdirty(__mk_pte(page,vma->vm_page_prot))); - atomic_inc(&virt_to_page(page)->count); - ++vma->vm_mm->rss; - } + DPRINTK("unswap_pte: replacing entry %08lx by new page %p", + entry.val, page); + set_pte(dir, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); swap_free(entry); + get_page(page); + ++vma->vm_mm->rss; } static inline void unswap_pmd(struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long size, - unsigned long offset, unsigned long entry, - unsigned long page /* , int isswap */) + unsigned long offset, swp_entry_t entry, + struct page *page) { pte_t * pte; unsigned long end; @@ -733,7 +656,7 @@ static inline void unswap_pmd(struct vm_area_struct * vma, pmd_t *dir, if (pmd_none(*dir)) return; if (pmd_bad(*dir)) { - printk("unswap_pmd: bad pmd (%08lx)\n", pmd_val(*dir)); + pmd_ERROR(*dir); pmd_clear(dir); return; } @@ -744,8 +667,7 @@ static inline void unswap_pmd(struct vm_area_struct * vma, pmd_t *dir, if (end > PMD_SIZE) end = PMD_SIZE; do { - unswap_pte(vma, offset+address-vma->vm_start, pte, entry, - page /* , isswap */); + unswap_pte(vma, offset+address-vma->vm_start, pte, entry, page); address += PAGE_SIZE; pte++; } while (address < end); @@ -753,8 +675,7 @@ static inline void unswap_pmd(struct vm_area_struct * vma, pmd_t *dir, static inline void unswap_pgd(struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long size, - unsigned long entry, unsigned long page - /* , int isswap */) + swp_entry_t entry, struct page *page) { pmd_t * pmd; unsigned long offset, end; @@ -762,7 +683,7 @@ static inline void unswap_pgd(struct vm_area_struct * vma, pgd_t *dir, if (pgd_none(*dir)) return; if (pgd_bad(*dir)) { - printk("unswap_pgd: bad pgd (%08lx)\n", pgd_val(*dir)); + pgd_ERROR(*dir); pgd_clear(dir); return; } @@ -774,28 +695,26 @@ static inline void unswap_pgd(struct vm_area_struct * vma, pgd_t *dir, end = PGDIR_SIZE; do { unswap_pmd(vma, pmd, address, end - address, offset, entry, - page /* , isswap */); + page); address = (address + PMD_SIZE) & PMD_MASK; pmd++; } while (address < end); } static void unswap_vma(struct vm_area_struct * vma, pgd_t *pgdir, - unsigned long entry, unsigned long page - /* , int isswap */) + swp_entry_t entry, struct page *page) { unsigned long start = vma->vm_start, end = vma->vm_end; - while (start < end) { - unswap_pgd(vma, pgdir, start, end - start, entry, page - /* , isswap */); + do { + unswap_pgd(vma, pgdir, start, end - start, entry, page); start = (start + PGDIR_SIZE) & PGDIR_MASK; pgdir++; - } + } while (start < end); } -static void unswap_process(struct mm_struct * mm, unsigned long entry, - unsigned long page /* , int isswap */) +static void unswap_process(struct mm_struct * mm, swp_entry_t entry, + struct page *page) { struct vm_area_struct* vma; @@ -806,110 +725,18 @@ static void unswap_process(struct mm_struct * mm, unsigned long entry, return; for (vma = mm->mmap; vma; vma = vma->vm_next) { pgd_t * pgd = pgd_offset(mm, vma->vm_start); - unswap_vma(vma, pgd, entry, page /* , isswap */); + unswap_vma(vma, pgd, entry, page); } } -#if 0 -static int unswap_by_move(unsigned short *map, unsigned long max, - unsigned long start, unsigned long n_pages) -{ - struct task_struct *p; - unsigned long entry, rover = (start == 1) ? n_pages+1 : 1; - unsigned long i, j; - - DPRINTK( "unswapping %lu..%lu by moving in swap\n", - start, start+n_pages-1 ); - - /* can free the allocated pages by moving them to other swap pages */ - for( i = start; i < start+n_pages; ++i ) { - if (!map[i]) { - map[i] = SWAP_MAP_BAD; - DPRINTK( "unswap: page %lu was free\n", i ); - continue; - } - else if (map[i] == SWAP_MAP_BAD) { - printk( KERN_ERR "get_stram_region: page %lu already " - "reserved??\n", i ); - } - DPRINTK( "unswap: page %lu is alloced, count=%u\n", i, map[i] ); - - /* find a free page not in our region */ - for( j = rover; j != rover-1; j = (j == max-1) ? 1 : j+1 ) { - if (j >= start && j < start+n_pages) - continue; - if (!map[j]) { - rover = j+1; - break; - } - } - if (j == rover-1) { - printk( KERN_ERR "get_stram_region: not enough free swap " - "pages now??\n" ); - return( -ENOMEM ); - } - DPRINTK( "unswap: map[i=%lu]=%u map[j=%lu]=%u nr_swap=%u\n", - i, map[i], j, map[j], nr_swap_pages ); - - --nr_swap_pages; - entry = SWP_ENTRY( stram_swap_type, j ); - if (stram_swap_info->lowest_bit == j) - stram_swap_info->lowest_bit++; - if (stram_swap_info->highest_bit == j) - stram_swap_info->highest_bit--; - - memcpy( SWAP_ADDR(j), SWAP_ADDR(i), PAGE_SIZE ); -#ifdef DO_PROC - stat_swap_move++; -#endif - - while( map[i] ) { - read_lock(&tasklist_lock); - for_each_task(p) { - if (unswap_process( p->mm, SWP_ENTRY( stram_swap_type, i ), - entry, 1 )) { - read_unlock(&tasklist_lock); - map[j]++; - goto repeat; - } - } - read_unlock(&tasklist_lock); - if (map[i] && map[i] != SWAP_MAP_MAX) { - printk( KERN_ERR "get_stram_region: ST-RAM swap page %lu " - "not used by any process\n", i ); - /* quit while loop and overwrite bad map entry */ - break; - } - else if (!map[i]) { - /* somebody else must have swapped in that page, so free the - * new one (we're moving to) */ - DPRINTK( "unswap: map[i] became 0, also clearing map[j]\n" ); - map[j] = 0; - } - repeat: - } - - DPRINTK( "unswap: map[i=%lu]=%u map[j=%lu]=%u nr_swap=%u\n", - i, map[i], j, map[j], nr_swap_pages ); - map[i] = SWAP_MAP_BAD; - if (stram_swap_info->lowest_bit == i) - stram_swap_info->lowest_bit++; - if (stram_swap_info->highest_bit == i) - stram_swap_info->highest_bit--; - --nr_swap_pages; - } - return( 0 ); -} -#endif - static int unswap_by_read(unsigned short *map, unsigned long max, unsigned long start, unsigned long n_pages) { struct task_struct *p; - unsigned long entry, page; + struct page *page; + swp_entry_t entry; unsigned long i; - struct page *page_map; DPRINTK( "unswapping %lu..%lu by reading in\n", start, start+n_pages-1 ); @@ -932,28 +759,24 @@ static int unswap_by_read(unsigned short *map, unsigned long max, /* Get a page for the entry, using the existing swap cache page if there is one. Otherwise, get a clean page and read the swap into it. */ - page_map = read_swap_cache(entry); - if (page_map) { - page = (unsigned long) page_address(page_map); - read_lock(&tasklist_lock); - for_each_task(p) - unswap_process(p->mm, entry, page - /* , 0 */); - read_unlock(&tasklist_lock); - shm_unuse(entry, page); - /* Now get rid of the extra reference to - the temporary page we've been using. */ - if (PageSwapCache(page_map)) - delete_from_swap_cache(page_map); - __free_page(page_map); - #ifdef DO_PROC - stat_swap_force++; - #endif - } - else { + page = read_swap_cache(entry); + if (!page) { swap_free(entry); return -ENOMEM; } + read_lock(&tasklist_lock); + for_each_task(p) + unswap_process(p->mm, entry, page); + read_unlock(&tasklist_lock); + shm_unuse(entry, page); + /* Now get rid of the extra reference to the + temporary page we've been using. */ + if (PageSwapCache(page)) + delete_from_swap_cache(page); + __free_page(page); + #ifdef DO_PROC + stat_swap_force++; + #endif } DPRINTK( "unswap: map[i=%lu]=%u nr_swap=%u\n", @@ -998,14 +821,7 @@ static void *get_stram_region( unsigned long n_pages ) DPRINTK( "get_stram_region: region starts at %lu, has %lu free pages\n", start, region_free ); -#if 0 - err = ((total_free-region_free >= n_pages-region_free) ? - unswap_by_move( map, max, start, n_pages ) : - unswap_by_read( map, max, start, n_pages )); -#else err = unswap_by_read(map, max, start, n_pages); -#endif - if (err) goto end; @@ -1062,7 +878,7 @@ static void free_stram_region( unsigned long offset, unsigned long n_pages ) /* is addr in some of the allocated regions? */ -static int in_some_region( unsigned long addr ) +static int in_some_region(void *addr) { BLOCK *p; @@ -1164,17 +980,13 @@ static int stram_sizes[14] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static int refcnt = 0; -static void do_stram_request( void ) +static void do_stram_request(request_queue_t *q) { - unsigned long start, len; - - while( !QUEUE_EMPTY ) { - if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) - panic("stram: request list destroyed"); - if (CURRENT->bh) { - if (!buffer_locked(CURRENT->bh)) - panic("stram: block not locked"); - } + void *start; + unsigned long len; + + while (1) { + INIT_REQUEST; start = swap_start + (CURRENT->sector << 9); len = CURRENT->current_nr_sectors << 9; @@ -1188,13 +1000,13 @@ static void do_stram_request( void ) } if (CURRENT->cmd == READ) { - memcpy( CURRENT->buffer, (char *)start, len ); + memcpy(CURRENT->buffer, start, len); #ifdef DO_PROC stat_swap_read += N_PAGES(len); #endif } else { - memcpy( (char *)start, CURRENT->buffer, len ); + memcpy(start, CURRENT->buffer, len); #ifdef DO_PROC stat_swap_write += N_PAGES(len); #endif @@ -1251,19 +1063,15 @@ int __init stram_device_init(void) return( -ENXIO ); } - blk_dev[STRAM_MAJOR].request_fn = do_stram_request; + blk_init_queue(BLK_DEFAULT_QUEUE(STRAM_MAJOR), do_stram_request); blksize_size[STRAM_MAJOR] = stram_blocksizes; stram_sizes[STRAM_MINOR] = (swap_end - swap_start)/1024; blk_size[STRAM_MAJOR] = stram_sizes; register_disk(NULL, MKDEV(STRAM_MAJOR, STRAM_MINOR), 1, &stram_fops, (swap_end-swap_start)>>9); - do_z2_request(); /* to avoid warning */ return( 0 ); } -/* to avoid warning */ -static void do_z2_request( void ) { } - #endif /* CONFIG_STRAM_SWAP */ @@ -1271,30 +1079,10 @@ static void do_z2_request( void ) { } /* Misc Utility Functions */ /* ------------------------------------------------------------------------ */ - -/* return log2 of #pages for size */ -static int get_gfp_order( unsigned long size ) +/* reserve a range of pages */ +static void reserve_region(void *start, void *end) { - int order; - - size = N_PAGES( size + PAGE_SIZE -1 ); - order = -1; - do { - size >>= 1; - order++; - } while (size); - - return( order ); -} - - -/* reserve a range of pages in mem_map[] */ -static void reserve_region( unsigned long addr, unsigned long end ) -{ - mem_map_t *mapp = virt_to_page(addr); - - for( ; addr < end; addr += PAGE_SIZE, ++mapp ) - set_bit( PG_reserved, &mapp->flags ); + reserve_bootmem (virt_to_phys(start), end - start); } @@ -1328,11 +1116,11 @@ static BLOCK *add_region( void *addr, unsigned long size ) printk( KERN_ERR "Out of memory for ST-RAM descriptor blocks\n" ); return( NULL ); } - n->start = (unsigned long)addr; + n->start = addr; n->size = size; for( p = &alloc_list; *p; p = &((*p)->next) ) - if ((*p)->start > (unsigned long)addr) break; + if ((*p)->start > addr) break; n->next = *p; *p = n; @@ -1346,9 +1134,9 @@ static BLOCK *find_region( void *addr ) BLOCK *p; for( p = alloc_list; p; p = p->next ) { - if (p->start == (unsigned long)addr) + if (p->start == addr) return( p ); - if (p->start > (unsigned long)addr) + if (p->start > addr) break; } return( NULL ); @@ -1405,14 +1193,13 @@ int get_stram_list( char *buf ) ++used; } PRINT_PROC( - "Total ST-RAM: %8lu kB\n" + "Total ST-RAM: %8u kB\n" "Total ST-RAM swap: %8lu kB\n" "Free swap: %8u kB\n" "Used swap: %8u kB\n" "Allocated swap: %8u kB\n" "Swap Reads: %8u\n" "Swap Writes: %8u\n" - "Swap Moves: %8u\n" "Swap Forced Reads: %8u\n", (stram_end - stram_start) >> 10, (max-1) << (PAGE_SHIFT-10), @@ -1421,17 +1208,13 @@ int get_stram_list( char *buf ) rsvd << (PAGE_SHIFT-10), stat_swap_read, stat_swap_write, - stat_swap_move, stat_swap_force ); } else { #endif PRINT_PROC( "ST-RAM swapping disabled\n" ); - PRINT_PROC( - "Total ST-RAM: %8lu kB\n" - "Reserved ST-RAM: %8lu kB\n", - (stram_end - stram_start) >> 10, - (rsvd_stram_end - rsvd_stram_beg) >> 10 ); + PRINT_PROC("Total ST-RAM: %8u kB\n", + (stram_end - stram_start) >> 10); #ifdef CONFIG_STRAM_SWAP } #endif @@ -1441,12 +1224,10 @@ int get_stram_list( char *buf ) if (len + 50 >= PAGE_SIZE) break; PRINT_PROC("0x%08lx-0x%08lx: %s (", - virt_to_phys((void *)p->start), - virt_to_phys((void *)p->start+p->size-1), + virt_to_phys(p->start), + virt_to_phys(p->start+p->size-1), p->owner); - if (p->flags & BLOCK_STATIC) - PRINT_PROC( "static)\n" ); - else if (p->flags & BLOCK_GFP) + if (p->flags & BLOCK_GFP) PRINT_PROC( "page-alloced)\n" ); else if (p->flags & BLOCK_INSWAP) PRINT_PROC( "in swap)\n" ); diff --git a/arch/m68k/fpsp040/bindec.S b/arch/m68k/fpsp040/bindec.S index ef3a627bf..9fb65e320 100644 --- a/arch/m68k/fpsp040/bindec.S +++ b/arch/m68k/fpsp040/bindec.S @@ -484,7 +484,7 @@ A9_str: fmovex (%a0),%fp0 |load X from memory fabsx %fp0 |use abs(X) tstw %d5 |LAMBDA is in lower word of d5 - bnes sc_mul |if neg (LAMBDA = 1), scale by mul + bne sc_mul |if neg (LAMBDA = 1), scale by mul fdivx %fp1,%fp0 |calculate X / SCALE -> Y to fp0 bras A10_st |branch to A10 diff --git a/arch/m68k/fpsp040/decbin.S b/arch/m68k/fpsp040/decbin.S index af1279a4a..d2bf1b641 100644 --- a/arch/m68k/fpsp040/decbin.S +++ b/arch/m68k/fpsp040/decbin.S @@ -230,7 +230,7 @@ nextlw: | m_sign: btst #31,(%a0) |test sign of the mantissa - beqs ap_st_z |if clear, go to append/strip zeros + beq ap_st_z |if clear, go to append/strip zeros fnegx %fp0 |if set, negate fp0 | @@ -288,7 +288,7 @@ ap_st_z: cmpl #27,%d1 |test is with 27 ble pwrten |if abs(expA) <28, skip ap/st zeros btst #30,(%a0) |check sign of exp - bnes ap_st_n |if neg, go to neg side + bne ap_st_n |if neg, go to neg side clrl %d1 |zero count reg movel (%a0),%d4 |load lword 1 to d4 bfextu %d4{#28:#4},%d0 |get M16 in d0 @@ -336,7 +336,7 @@ ap_p_en: tstl %d0 |check if d0 is zero bnes ap_p_el |if not, get next bit fmulx %fp1,%fp0 |mul mantissa by 10**(no_bits_shifted) - bras pwrten |go calc pwrten + bra pwrten |go calc pwrten | | This section handles a negative adjusted exponent. | diff --git a/arch/m68k/fpsp040/do_func.S b/arch/m68k/fpsp040/do_func.S index 2df0c3700..0a9c776f0 100644 --- a/arch/m68k/fpsp040/do_func.S +++ b/arch/m68k/fpsp040/do_func.S @@ -77,7 +77,7 @@ not_fmovecr: movew CMDREG1B(%a6),%d0 andl #0x7F,%d0 cmpil #0x38,%d0 |if the extension is >= $38, - bges serror |it is illegal + bge serror |it is illegal bfextu STAG(%a6){#0:#3},%d1 lsll #3,%d0 |make room for STAG addl %d1,%d0 |combine for final index into table diff --git a/arch/m68k/fpsp040/get_op.S b/arch/m68k/fpsp040/get_op.S index 2bd236d45..480405d4f 100644 --- a/arch/m68k/fpsp040/get_op.S +++ b/arch/m68k/fpsp040/get_op.S @@ -171,7 +171,7 @@ PTENRP: get_op: clrb DY_MO_FLG(%a6) tstb UFLG_TMP(%a6) |test flag for unsupp/unimp state - beqs uni_getop + beq uni_getop uns_getop: btstb #direction_bit,CMDREG1B(%a6) diff --git a/arch/m68k/fpsp040/util.S b/arch/m68k/fpsp040/util.S index e59b352ab..cc9ae013b 100644 --- a/arch/m68k/fpsp040/util.S +++ b/arch/m68k/fpsp040/util.S @@ -138,20 +138,20 @@ ovf_e1_exc: | ovf_fsgl: clrl %d0 - bras ovf_res + bra ovf_res ovff_sgl: movel #0x00000001,%d0 |set single - bras ovf_res + bra ovf_res ovff_dbl: movel #0x00000002,%d0 |set double - bras ovf_res + bra ovf_res | | The precision is in the fpcr. | ovf_fpcr: bfextu FPCR_MODE(%a6){#0:#2},%d0 |set round precision - bras ovf_res + bra ovf_res | | diff --git a/arch/m68k/fpsp040/x_store.S b/arch/m68k/fpsp040/x_store.S index a3468f338..b3357fd65 100644 --- a/arch/m68k/fpsp040/x_store.S +++ b/arch/m68k/fpsp040/x_store.S @@ -92,7 +92,7 @@ opc011: cmpil #0,%d0 |if dest format is extended beq dest_ext |then branch cmpil #1,%d0 |if dest format is single - beqs dest_sgl |then branch + beq dest_sgl |then branch | | fall through to dest_dbl | diff --git a/arch/m68k/ifpsp060/os.S b/arch/m68k/ifpsp060/os.S index 4bbf86f96..037aa6c00 100644 --- a/arch/m68k/ifpsp060/os.S +++ b/arch/m68k/ifpsp060/os.S @@ -85,21 +85,20 @@ | .global _060_dmem_write _060_dmem_write: + subq.l #1,%d0 btst #0x5,0x4(%a6) | check for supervisor state beqs user_write super_write: move.b (%a0)+,(%a1)+ | copy 1 byte - subq.l #0x1,%d0 | decr byte counter - bnes super_write | quit if ctr = 0 + dbra %d0,super_write | quit if --ctr < 0 clr.l %d1 | return success rts user_write: - move.l %d0,-(%sp) | pass: counter - move.l %a1,-(%sp) | pass: user dst - move.l %a0,-(%sp) | pass: supervisor src - bsr.l _copyout | write byte to user mem - move.l %d0,%d1 | return success - add.l #0xc, %sp | clear 3 lw params + move.b (%a0)+,%d1 | copy 1 byte +copyoutae: + movs.b %d1,(%a1)+ + dbra %d0,user_write | quit if --ctr < 0 + clr.l %d1 | return success rts | @@ -119,21 +118,20 @@ user_write: .global _060_dmem_read _060_imem_read: _060_dmem_read: + subq.l #1,%d0 btst #0x5,0x4(%a6) | check for supervisor state beqs user_read super_read: move.b (%a0)+,(%a1)+ | copy 1 byte - subq.l #0x1,%d0 | decr byte counter - bnes super_read | quit if ctr = 0 + dbra %d0,super_read | quit if --ctr < 0 clr.l %d1 | return success rts user_read: - move.l %d0,-(%sp) | pass: counter - move.l %a1,-(%sp) | pass: super dst - move.l %a0,-(%sp) | pass: user src - bsr.l _copyin | read byte from user mem - move.l %d0,%d1 | return success - add.l #0xc,%sp | clear 3 lw params +copyinae: + movs.b (%a0)+,%d1 + move.b %d1,(%a1)+ | copy 1 byte + dbra %d0,user_read | quit if --ctr < 0 + clr.l %d1 | return success rts | @@ -150,14 +148,13 @@ user_read: | .global _060_dmem_read_byte _060_dmem_read_byte: + clr.l %d0 | clear whole longword + clr.l %d1 | assume success btst #0x5,0x4(%a6) | check for supervisor state bnes dmrbs | supervisor -dmrbu: clr.l %d0 | clear whole longword dmrbuae:movs.b (%a0),%d0 | fetch user byte - bras dmrbr -dmrbs: clr.l %d0 | clear whole longword - move.b (%a0),%d0 | fetch super byte -dmrbr: clr.l %d1 | return success + rts +dmrbs: move.b (%a0),%d0 | fetch super byte rts | @@ -187,14 +184,13 @@ dmrbr: clr.l %d1 | return success .global _060_imem_read_word _060_dmem_read_word: _060_imem_read_word: + clr.l %d1 | assume success + clr.l %d0 | clear whole longword btst #0x5,0x4(%a6) | check for supervisor state bnes dmrws | supervisor -dmrwu: clr.l %d0 | clear whole longword dmrwuae:movs.w (%a0), %d0 | fetch user word - bras dmrwr -dmrws: clr.l %d0 | clear whole longword - move.w (%a0), %d0 | fetch super word -dmrwr: clr.l %d1 | return success + rts +dmrws: move.w (%a0), %d0 | fetch super word rts | @@ -224,13 +220,12 @@ dmrwr: clr.l %d1 | return success .global _060_imem_read_long _060_dmem_read_long: _060_imem_read_long: + clr.l %d1 | assume success btst #0x5,0x4(%a6) | check for supervisor state bnes dmrls | supervisor -dmrlu: dmrluae:movs.l (%a0),%d0 | fetch user longword - bras dmrlr + rts dmrls: move.l (%a0),%d0 | fetch super longword -dmrlr: clr.l %d1 | return success rts | @@ -247,13 +242,12 @@ dmrlr: clr.l %d1 | return success | .global _060_dmem_write_byte _060_dmem_write_byte: + clr.l %d1 | assume success btst #0x5,0x4(%a6) | check for supervisor state bnes dmwbs | supervisor -dmwbu: dmwbuae:movs.b %d0,(%a0) | store user byte - bras dmwbr + rts dmwbs: move.b %d0,(%a0) | store super byte -dmwbr: clr.l %d1 | return success rts | @@ -270,6 +264,7 @@ dmwbr: clr.l %d1 | return success | .global _060_dmem_write_word _060_dmem_write_word: + clr.l %d1 | assume success btst #0x5,0x4(%a6) | check for supervisor state bnes dmwws | supervisor dmwwu: @@ -293,16 +288,16 @@ dmwwr: clr.l %d1 | return success | .global _060_dmem_write_long _060_dmem_write_long: + clr.l %d1 | assume success btst #0x5,0x4(%a6) | check for supervisor state bnes dmwls | supervisor -dmwlu: dmwluae:movs.l %d0,(%a0) | store user longword - bra dmwlr + rts dmwls: move.l %d0,(%a0) | store super longword -dmwlr: clr.l %d1 | return success rts +#if 0 |############################################### | @@ -323,7 +318,7 @@ _copyout: move.l 4(%sp),%a0 | source move.l 8(%sp),%a1 | destination move.l 12(%sp),%d0 | count - subq.l #1,%d0 + subq.l #1,%d0 moreout: move.b (%a0)+,%d1 | fetch supervisor byte copyoutae: @@ -348,6 +343,7 @@ copyinae: dbra %d0,morein | are we through yet? moveq #0,%d0 | return success rts +#endif |########################################################################### diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 165809c56..3e62e6fe1 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -28,6 +28,9 @@ * 12/03/96 Jes: Currently we only support m68k single-cpu systems, so * all pointers that used to be 'current' are now entry * number 0 in the 'current_set' list. + * + * 6/05/00 RZ: addedd writeback completion after return from sighandler + * for 68040 */ #include <linux/sys.h> @@ -104,8 +107,18 @@ do_trace: jbsr SYMBOL_NAME(syscall_trace) SYMBOL_NAME_LABEL(ret_from_signal) - RESTORE_SWITCH_STACK + RESTORE_SWITCH_STACK addql #4,%sp +/* on 68040 complete pending writebacks if any */ +#ifdef CONFIG_M68040 + bfextu %sp@(PT_VECTOR){#0,#4},%d0 + subql #7,%d0 | bus error frame ? + jbne 1f + movel %sp,%sp@- + jbsr SYMBOL_NAME(berr_040cleanup) + addql #4,%sp +1: +#endif jra SYMBOL_NAME(ret_from_exception) ENTRY(system_call) @@ -115,7 +128,7 @@ ENTRY(system_call) | save top of frame movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0) - btst #PF_TRACESYS_BIT,%curptr@(TASK_FLAGS+PF_TRACESYS_OFF) + btst #PT_TRACESYS_BIT,%curptr@(TASK_PTRACE+PT_TRACESYS_OFF) jne do_trace cmpl #NR_syscalls,%d0 jcc badsys @@ -136,7 +149,7 @@ SYMBOL_NAME_LABEL(ret_from_exception) jeq 2f #endif | check for delayed trace - bclr #PF_DTRACE_BIT,%curptr@(TASK_FLAGS+PF_DTRACE_OFF) + bclr #PT_DTRACE_BIT,%curptr@(TASK_PTRACE+PT_DTRACE_OFF) jne do_delayed_trace 5: tstl %curptr@(TASK_STATE) | state @@ -578,7 +591,7 @@ SYMBOL_NAME_LABEL(sys_call_table) .long SYMBOL_NAME(sys_mremap) .long SYMBOL_NAME(sys_setresuid16) .long SYMBOL_NAME(sys_getresuid16) /* 165 */ - .long SYMBOL_NAME(sys_ni_syscall) /* for vm86 */ + .long SYMBOL_NAME(sys_getpagesize) .long SYMBOL_NAME(sys_query_module) .long SYMBOL_NAME(sys_poll) .long SYMBOL_NAME(sys_nfsservctl) diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c index 74e1e4c1e..805ce9b83 100644 --- a/arch/m68k/kernel/ints.c +++ b/arch/m68k/kernel/ints.c @@ -71,6 +71,8 @@ int (*mach_request_irq) (unsigned int, void (*)(int, void *, struct pt_regs *), unsigned long, const char *, void *) = dummy_request_irq; void (*mach_free_irq) (unsigned int, void *) = dummy_free_irq; +void init_irq_proc(void); + /* * void init_IRQ(void) * @@ -257,3 +259,9 @@ int get_irq_list(char *buf) len += mach_get_irq_list(buf+len); return len; } + +void init_irq_proc(void) +{ + /* Insert /proc/irq driver here */ +} + diff --git a/arch/m68k/kernel/m68k_defs.c b/arch/m68k/kernel/m68k_defs.c index 47cffcfa9..817583a7d 100644 --- a/arch/m68k/kernel/m68k_defs.c +++ b/arch/m68k/kernel/m68k_defs.c @@ -24,6 +24,7 @@ int main(void) /* offsets into the task struct */ DEFINE(TASK_STATE, offsetof(struct task_struct, state)); DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); + DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace)); DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, sigpending)); DEFINE(TASK_NEEDRESCHED, offsetof(struct task_struct, need_resched)); DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c index 7bf46149f..35d194623 100644 --- a/arch/m68k/kernel/m68k_ksyms.c +++ b/arch/m68k/kernel/m68k_ksyms.c @@ -21,6 +21,7 @@ asmlinkage long long __ashrdi3 (long long, int); asmlinkage long long __lshrdi3 (long long, int); +asmlinkage long long __muldi3 (long long, long long); extern char m68k_debug_device[]; extern void dump_thread(struct pt_regs *, struct user *); @@ -72,6 +73,7 @@ EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memcmp); EXPORT_SYMBOL_NOVERS(memscan); +EXPORT_SYMBOL_NOVERS(__muldi3); EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c index 0dd5870f2..6b1f5f386 100644 --- a/arch/m68k/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace.c @@ -97,10 +97,10 @@ asmlinkage int 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) + if (current->ptrace & PT_PTRACED) goto out; /* set the ptrace bit in the process flags. */ - current->flags |= PF_PTRACED; + current->ptrace |= PT_PTRACED; ret = 0; goto out; } @@ -126,9 +126,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) (current->gid != child->gid)) && !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_irqsave(&tasklist_lock, flags); if (child->p_pptr != current) { @@ -143,7 +143,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) goto out; } ret = -ESRCH; - if (!(child->flags & PF_PTRACED)) + if (!(child->ptrace & PT_PTRACED)) goto out; if (child->state != TASK_STOPPED) { if (request != PTRACE_KILL) @@ -250,9 +250,9 @@ asmlinkage int 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; /* make sure the single step bit is not set. */ tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); @@ -287,7 +287,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ret = -EIO; if ((unsigned long) data > _NSIG) goto out; - child->flags &= ~PF_TRACESYS; + child->ptrace &= ~PT_TRACESYS; tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16); put_reg(child, PT_SR, tmp); @@ -304,7 +304,7 @@ asmlinkage int 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); child->exit_code = data; write_lock_irqsave(&tasklist_lock, flags); REMOVE_LINKS(child); @@ -384,8 +384,8 @@ out: asmlinkage void syscall_trace(void) { lock_kernel(); - if ((current->flags & (PF_PTRACED|PF_TRACESYS)) - != (PF_PTRACED|PF_TRACESYS)) + if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) + != (PT_PTRACED|PT_TRACESYS)) goto out; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c index a2e3f47f1..040f96d97 100644 --- a/arch/m68k/kernel/setup.c +++ b/arch/m68k/kernel/setup.c @@ -73,6 +73,8 @@ void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initd int (*mach_keyb_init) (void) __initdata = NULL; int (*mach_kbdrate) (struct kbd_repeat *) = NULL; void (*mach_kbd_leds) (unsigned int) = NULL; +int (*mach_kbd_translate)(unsigned char scancode, unsigned char *keycode, char raw_mode) = NULL; +unsigned int SYSRQ_KEY; /* machine dependent irq functions */ void (*mach_init_IRQ) (void) __initdata = NULL; void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL; diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c index fa13dc390..9d754f9b8 100644 --- a/arch/m68k/kernel/signal.c +++ b/arch/m68k/kernel/signal.c @@ -1043,7 +1043,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) if (!signr) break; - if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { current->exit_code = signr; current->state = TASK_STOPPED; regs->sr &= ~PS_T; diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index 86637d4d6..f7386cbc6 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -24,6 +24,7 @@ #include <asm/cachectl.h> #include <asm/traps.h> #include <asm/ipc.h> +#include <asm/page.h> /* * sys_pipe() is the normal C calling standard for creating @@ -661,6 +662,11 @@ out: return ret; } +asmlinkage int sys_getpagesize(void) +{ + return PAGE_SIZE; +} + /* * Old cruft */ diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c index 5fd9dc0a7..d5d6753cb 100644 --- a/arch/m68k/kernel/traps.c +++ b/arch/m68k/kernel/traps.c @@ -5,6 +5,7 @@ * * 68040 fixes by Michael Rausch * 68040 fixes by Martin Apel + * 68040 fixes and writeback by Richard Zidlicky * 68060 fixes by Roman Hodek * 68060 fixes by Jesper Skov * @@ -34,7 +35,7 @@ #include <asm/system.h> #include <asm/uaccess.h> #include <asm/traps.h> -#include <asm/pgtable.h> +#include <asm/pgalloc.h> #include <asm/machdep.h> #include <asm/siginfo.h> @@ -195,6 +196,7 @@ static char *space_names[] = { void die_if_kernel(char *,struct pt_regs *,int); asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code); +int send_fault_sig(struct pt_regs *regs); asmlinkage void trap_c(struct frame *fp); @@ -214,26 +216,33 @@ static inline void access_error060 (struct frame *fp) "movec %/d0,%/cacr" : : : "d0" ); /* return if there's no other error */ - if ((!(fslw & MMU060_ERR_BITS)) && !(fslw & MMU060_SEE)) + if (!(fslw & MMU060_ERR_BITS) && !(fslw & MMU060_SEE)) return; } if (fslw & (MMU060_DESC_ERR | MMU060_WP | MMU060_SP)) { unsigned long errorcode; unsigned long addr = fp->un.fmt4.effaddr; - errorcode = ((fslw & MMU060_WP) ? 1 : 0) | - ((fslw & MMU060_W) ? 2 : 0); + + if (fslw & MMU060_MA) + addr = (addr + 7) & -8; + + errorcode = 1; + if (fslw & MMU060_DESC_ERR) { + __flush_tlb040_one(addr); + errorcode = 0; + } + if (fslw & MMU060_W) + errorcode |= 2; #ifdef DEBUG printk("errorcode = %d\n", errorcode ); #endif - if (fslw & MMU060_MA) - addr = PAGE_ALIGN(addr); do_page_fault(&fp->ptregs, addr, errorcode); } else if (fslw & (MMU060_SEE)){ - /* Software Emulation Error. Probably an instruction - * using an unsupported addressing mode + /* Software Emulation Error. + * fault during mem_read/mem_write in ifpsp060/os.S */ - send_sig (SIGSEGV, current, 1); + send_fault_sig(&fp->ptregs); } else { printk("pc=%#lx, fa=%#lx\n", fp->ptregs.pc, fp->un.fmt4.effaddr); printk( "68060 access error, fslw=%lx\n", fslw ); @@ -243,74 +252,113 @@ static inline void access_error060 (struct frame *fp) #endif /* CONFIG_M68060 */ #if defined (CONFIG_M68040) -static inline unsigned long probe040 (int iswrite, int fc, unsigned long addr) +static inline unsigned long probe040(int iswrite, unsigned long addr) { unsigned long mmusr; - mm_segment_t fs = get_fs(); - set_fs (MAKE_MM_SEG(fc)); + asm volatile (".chip 68040"); if (iswrite) - /* write */ - asm volatile (".chip 68040\n\t" - "ptestw (%1)\n\t" - "movec %%mmusr,%0\n\t" - ".chip 68k" - : "=r" (mmusr) - : "a" (addr)); + asm volatile ("ptestw (%0)" : : "a" (addr)); else - asm volatile (".chip 68040\n\t" - "ptestr (%1)\n\t" - "movec %%mmusr,%0\n\t" - ".chip 68k" - : "=r" (mmusr) - : "a" (addr)); + asm volatile ("ptestr (%0)" : : "a" (addr)); + + asm volatile ("movec %%mmusr,%0" : "=r" (mmusr)); - set_fs (fs); + asm volatile (".chip 68k"); return mmusr; } -static inline void do_040writeback (unsigned short ssw, - unsigned short wbs, - unsigned long wba, - unsigned long wbd, - struct frame *fp) +static inline int do_040writeback1(unsigned short wbs, unsigned long wba, + unsigned long wbd) { - mm_segment_t fs = get_fs (); - unsigned long mmusr; - unsigned long errorcode; + int res = 0; - /* - * No special handling for the second writeback anymore. - * It misinterpreted the misaligned status sometimes. - * This way an extra page-fault may be caused (Martin Apel). - */ - - mmusr = probe040 (1, wbs & WBTM_040, wba); - errorcode = (mmusr & MMU_R_040) ? 3 : 2; - if (do_page_fault (&fp->ptregs, wba, errorcode)) - /* just return if we can't perform the writeback */ - return; + set_fs(MAKE_MM_SEG(wbs)); - set_fs (MAKE_MM_SEG(wbs & WBTM_040)); switch (wbs & WBSIZ_040) { - case BA_SIZE_BYTE: - put_user (wbd & 0xff, (char *)wba); + case BA_SIZE_BYTE: + res = put_user(wbd & 0xff, (char *)wba); break; - case BA_SIZE_WORD: - put_user (wbd & 0xffff, (short *)wba); + case BA_SIZE_WORD: + res = put_user(wbd & 0xffff, (short *)wba); break; - case BA_SIZE_LONG: - put_user (wbd, (int *)wba); + case BA_SIZE_LONG: + res = put_user(wbd, (int *)wba); break; } - set_fs (fs); + +#ifdef DEBUG + printk("do_040writeback1, res=%d\n",res); +#endif + + return res; +} + +/* after an exception in a writeback the stack frame coresponding + * to that exception is discarded, set a few bits in the old frame + * to simulate what it should look like + */ +static inline void fix_xframe040(struct frame *fp, unsigned short wbs) +{ + fp->un.fmt7.faddr = current->thread.faddr; + fp->un.fmt7.ssw = wbs & 0xff; +} + +static inline void do_040writebacks(struct frame *fp) +{ + int res = 0; +#if 0 + if (fp->un.fmt7.wb1s & WBV_040) + printk("access_error040: cannot handle 1st writeback. oops.\n"); +#endif + + if ((fp->un.fmt7.wb2s & WBV_040) && + !(fp->un.fmt7.wb2s & WBTT_040)) { + res = do_040writeback1(fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, + fp->un.fmt7.wb2d); + if (res) + fix_xframe040(fp, fp->un.fmt7.wb2s); + else + fp->un.fmt7.wb2s = 0; + } + + /* do the 2nd wb only if the first one was succesful (except for a kernel wb) */ + if (fp->un.fmt7.wb3s & WBV_040 && (!res || fp->un.fmt7.wb3s & 4)) { + res = do_040writeback1(fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, + fp->un.fmt7.wb3d); + if (res) + fix_xframe040(fp, fp->un.fmt7.wb3s); + else + fp->un.fmt7.wb3s = 0; + } + + if (res) + send_fault_sig(&fp->ptregs); +} + +/* + * called from sigreturn(), must ensure userspace code didn't + * manipulate exception frame to circumvent protection, then complete + * pending writebacks + * we just clear TM2 to turn it into an userspace access + */ +asmlinkage void berr_040cleanup(struct frame *fp) +{ + mm_segment_t old_fs = get_fs(); + + fp->un.fmt7.wb2s &= ~4; + fp->un.fmt7.wb3s &= ~4; + + do_040writebacks(fp); + set_fs(old_fs); } -static inline void access_error040 (struct frame *fp) +static inline void access_error040(struct frame *fp) { unsigned short ssw = fp->un.fmt7.ssw; + mm_segment_t old_fs = get_fs(); unsigned long mmusr; #ifdef DEBUG @@ -322,7 +370,6 @@ static inline void access_error040 (struct frame *fp) fp->un.fmt7.wb2d, fp->un.fmt7.wb3d); #endif - if (ssw & ATC_040) { unsigned long addr = fp->un.fmt7.faddr; unsigned long errorcode; @@ -332,56 +379,50 @@ static inline void access_error040 (struct frame *fp) * has been corrected if there was a misaligned access (MA). */ if (ssw & MA_040) - addr = PAGE_ALIGN (addr); + addr = (addr + 7) & -8; + set_fs(MAKE_MM_SEG(ssw)); /* MMU error, get the MMUSR info for this access */ - mmusr = probe040 (!(ssw & RW_040), ssw & TM_040, addr); + mmusr = probe040(!(ssw & RW_040), addr); #ifdef DEBUG printk("mmusr = %lx\n", mmusr); #endif - errorcode = ((mmusr & MMU_R_040) ? 1 : 0) | - ((ssw & RW_040) ? 0 : 2); -#ifdef CONFIG_FTRACE - { - unsigned long flags; - - save_flags(flags); - cli(); - do_ftrace(0xfa000000 | errorcode); - do_ftrace(mmusr); - restore_flags(flags); + errorcode = 1; + if (!(mmusr & MMU_R_040)) { + /* clear the invalid atc entry */ + __flush_tlb040_one(addr); + errorcode = 0; } + if (!(ssw & RW_040)) + errorcode |= 2; + if (do_page_fault(&fp->ptregs, addr, errorcode)) { +#ifdef DEBUG + printk("do_page_fault() !=0 \n"); #endif - do_page_fault (&fp->ptregs, addr, errorcode); + if (user_mode(&fp->ptregs)){ + /* delay writebacks after signal delivery */ +#ifdef DEBUG + printk(".. was usermode - return\n"); +#endif + return; + } + /* disable writeback into user space from kernel + * (if do_page_fault didn't fix the mapping, + * the writeback won't do good) + */ +#ifdef DEBUG + printk(".. disabling wb2\n"); +#endif + if (fp->un.fmt7.wb2a == fp->un.fmt7.faddr) + fp->un.fmt7.wb2s &= ~WBV_040; + } } else { - printk ("68040 access error, ssw=%x\n", ssw); - trap_c (fp); + printk("68040 access error, ssw=%x\n", ssw); + trap_c(fp); } -#if 0 - if (fp->un.fmt7.wb1s & WBV_040) - printk("access_error040: cannot handle 1st writeback. oops.\n"); -#endif - -/* - * We may have to do a couple of writebacks here. - * - * MR: we can speed up the thing a little bit and let do_040writeback() - * not produce another page fault as wb2 corresponds to the address that - * caused the fault. on write faults no second fault is generated, but - * on read faults for security reasons (although per definitionem impossible) - */ - - if (fp->un.fmt7.wb2s & WBV_040 && (fp->un.fmt7.wb2s & - WBTT_040) != BA_TT_MOVE16) - do_040writeback (ssw, - fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, - fp->un.fmt7.wb2d, fp); - - if (fp->un.fmt7.wb3s & WBV_040) - do_040writeback (ssw, fp->un.fmt7.wb3s, - fp->un.fmt7.wb3a, fp->un.fmt7.wb3d, - fp); + do_040writebacks(fp); + set_fs(old_fs); } #endif /* CONFIG_M68040 */ @@ -470,12 +511,14 @@ extern inline void bus_error030 (struct frame *fp) else if (buserr_type & SUN3_BUSERR_INVALID) errorcode = 0x00; else { +#ifdef DEBUG printk ("*** unexpected busfault type=%#04x\n", buserr_type); printk ("invalid %s access at %#lx from pc %#lx\n", !(ssw & RW) ? "write" : "read", addr, fp->ptregs.pc); +#endif die_if_kernel ("Oops", &fp->ptregs, buserr_type); - force_sig (SIGSEGV, current); + force_sig (SIGBUS, current); return; } @@ -596,7 +639,7 @@ static inline void bus_error030 (struct frame *fp) printk ("mmusr is %#x for addr %#lx in task %p\n", mmusr, addr, current); printk ("descriptor address is %#lx, contents %#lx\n", - mm_ptov(desc), *(unsigned long *)mm_ptov(desc)); + __va(desc), *(unsigned long *)__va(desc)); #endif errorcode = (mmusr & MMU_I) ? 0 : 1; @@ -694,7 +737,7 @@ static inline void bus_error030 (struct frame *fp) printk ("mmusr is %#x for addr %#lx in task %p\n", mmusr, addr, current); printk ("descriptor address is %#lx, contents %#lx\n", - mm_ptov(desc), *(unsigned long *)mm_ptov(desc)); + __va(desc), *(unsigned long *)__va(desc)); #endif if (mmusr & MMU_I) @@ -904,7 +947,7 @@ asmlinkage void trap_c(struct frame *fp) if (fp->ptregs.sr & PS_S) { if ((fp->ptregs.vector >> 2) == VEC_TRACE) { /* traced a trapping instruction */ - current->flags |= PF_DTRACE; + current->ptrace |= PT_DTRACE; } else bad_super_trap(fp); return; diff --git a/arch/m68k/lib/Makefile b/arch/m68k/lib/Makefile index b9480aeb6..a230bad9e 100644 --- a/arch/m68k/lib/Makefile +++ b/arch/m68k/lib/Makefile @@ -6,6 +6,6 @@ $(CC) $(AFLAGS) -traditional -c $< -o $@ L_TARGET = lib.a -L_OBJS = ashrdi3.o lshrdi3.o checksum.o memcpy.o memcmp.o memset.o semaphore.o +L_OBJS = ashrdi3.o lshrdi3.o checksum.o memcpy.o memcmp.o memset.o semaphore.o muldi3.o include $(TOPDIR)/Rules.make diff --git a/arch/m68k/lib/muldi3.c b/arch/m68k/lib/muldi3.c new file mode 100644 index 000000000..9ea8812fc --- /dev/null +++ b/arch/m68k/lib/muldi3.c @@ -0,0 +1,63 @@ +/* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and + gcc-2.7.2.3/longlong.h which is: */ +/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define BITS_PER_UNIT 8 + +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("mulu%.l %3,%1:%0" \ + : "=d" ((USItype)(w0)), \ + "=d" ((USItype)(w1)) \ + : "%0" ((USItype)(u)), \ + "dmi" ((USItype)(v))) + +#define __umulsidi3(u, v) \ + ({DIunion __w; \ + umul_ppmm (__w.s.high, __w.s.low, u, v); \ + __w.ll; }) + +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef int word_type __attribute__ ((mode (__word__))); + +struct DIstruct {SItype high, low;}; + +typedef union +{ + struct DIstruct s; + DItype ll; +} DIunion; + +DItype +__muldi3 (DItype u, DItype v) +{ + DIunion w; + DIunion uu, vv; + + uu.ll = u, + vv.ll = v; + + w.ll = __umulsidi3 (uu.s.low, vv.s.low); + w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high + + (USItype) uu.s.high * (USItype) vv.s.low); + + return w.ll; +} diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c index 445a99780..9b9bab2bd 100644 --- a/arch/m68k/mac/baboon.c +++ b/arch/m68k/mac/baboon.c @@ -27,8 +27,6 @@ volatile struct baboon *baboon; void baboon_irq(int, void *, struct pt_regs *); -extern int console_loglevel; - extern int macide_ack_intr(ide_hwif_t *); /* diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c index a0486cf95..1a1a38e60 100644 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@ -61,10 +61,6 @@ void *mac_env; /* Loaded by the boot asm */ /* The phys. video addr. - might be bogus on some machines */ unsigned long mac_orig_videoaddr; -/* Mac specific keyboard functions */ -extern int mackbd_init_hw(void); -extern void mackbd_leds(unsigned int leds); - /* Mac specific timer functions */ extern void mac_gettod (int *, int *, int *, int *, int *, int *); extern unsigned long mac_gettimeoffset (void); @@ -91,20 +87,21 @@ extern void nubus_sweep_video(void); extern void mac_debug_init(void); extern void mac_debugging_long(int, long); -#ifdef CONFIG_MAGIC_SYSRQ -static char mac_sysrq_xlate[128] = - "\000sdfghzxcv\000bqwer" /* 0x00 - 0x0f */ - "yt123465=97-80)o" /* 0x10 - 0x1f */ - "u(ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */ - "\t `\000\033\000\000\000\000\000\000\000\000\000\000\000" /* 0x30 - 0x3f */ - "\000.\000*\000+\000\000\000\000\000/\r\000-\000" /* 0x40 - 0x4f */ - "\000\00001234567a89\000\000\000" /* 0x50 - 0x5f */ - "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x60 - 0x6f */ - "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 0x70 - 0x7f */ -#endif - extern void (*kd_mksound)(unsigned int, unsigned int); +extern int mackbd_init_hw(void); +extern void mackbd_leds(unsigned int leds); +extern int mackbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode); + +extern void mac_hid_init_hw(void); +extern int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode); + +#ifdef CONFIG_MAGIC_SYSRQ +extern unsigned char mac_hid_kbd_sysrq_xlate[128]; +extern unsigned char pckbd_sysrq_xlate[128]; +extern unsigned char mackbd_sysrq_xlate[128]; +#endif /* CONFIG_MAGIC_SYSRQ */ + static void mac_get_model(char *str); void mac_bang(int irq, void *vector, struct pt_regs *p) @@ -118,8 +115,6 @@ static void mac_sched_init(void (*vector)(int, void *, struct pt_regs *)) via_init_clock(vector); } -extern int console_loglevel; - #if 0 void mac_waitbut (void) { @@ -213,76 +208,93 @@ static void mac_cache_card_flush(int writeback) void __init config_mac(void) { - - if (!MACH_IS_MAC) { - printk("ERROR: no Mac, but config_mac() called!! \n"); - } - - mach_sched_init = mac_sched_init; - mach_keyb_init = mackbd_init_hw; - mach_kbd_leds = mackbd_leds; - mach_init_IRQ = mac_init_IRQ; - mach_request_irq = mac_request_irq; - mach_free_irq = mac_free_irq; - enable_irq = mac_enable_irq; - disable_irq = mac_disable_irq; - mach_get_model = mac_get_model; - mach_default_handler = &mac_handlers; - mach_get_irq_list = mac_get_irq_list; - mach_gettimeoffset = mac_gettimeoffset; - mach_gettod = mac_gettod; - mach_hwclk = mac_hwclk; - mach_set_clock_mmss = mac_set_clock_mmss; + if (!MACH_IS_MAC) { + printk("ERROR: no Mac, but config_mac() called!! \n"); + } + +#ifdef CONFIG_VT +#ifdef CONFIG_INPUT_ADBHID + mach_keyb_init = mac_hid_init_hw; + mach_kbd_translate = mac_hid_kbd_translate; +#ifdef CONFIG_MAGIC_SYSRQ +#ifdef CONFIG_MAC_ADBKEYCODES + if (!keyboard_sends_linux_keycodes) { + mach_sysrq_xlate = mac_hid_kbd_sysrq_xlate; + SYSRQ_KEY = 0x69; + } else +#endif /* CONFIG_MAC_ADBKEYCODES */ + { + mach_sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; + } +#endif /* CONFIG_MAGIC_SYSRQ */ +#elif defined(CONFIG_ADB_KEYBOARD) + mach_keyb_init = mackbd_init_hw; + mach_kbd_leds = mackbd_leds; + mach_kbd_translate = mackbd_translate; + mach_sysrq_xlate = mackbd_sysrq_xlate; + SYSRQ_KEY = 0x69; +#endif /* CONFIG_INPUT_ADBHID */ +#endif /* CONFIG_VT */ + + mach_sched_init = mac_sched_init; + mach_init_IRQ = mac_init_IRQ; + mach_request_irq = mac_request_irq; + mach_free_irq = mac_free_irq; + enable_irq = mac_enable_irq; + disable_irq = mac_disable_irq; + mach_get_model = mac_get_model; + mach_default_handler = &mac_handlers; + mach_get_irq_list = mac_get_irq_list; + mach_gettimeoffset = mac_gettimeoffset; + mach_gettod = mac_gettod; + mach_hwclk = mac_hwclk; + mach_set_clock_mmss = mac_set_clock_mmss; #if 0 - mach_mksound = mac_mksound; + mach_mksound = mac_mksound; #endif - mach_reset = mac_reset; - mach_halt = mac_poweroff; - mach_power_off = mac_poweroff; - conswitchp = &dummy_con; - mach_max_dma_address = 0xffffffff; + mach_reset = mac_reset; + mach_halt = mac_poweroff; + mach_power_off = mac_poweroff; + conswitchp = &dummy_con; + mach_max_dma_address = 0xffffffff; #if 0 - mach_debug_init = mac_debug_init; -#endif - kd_mksound = mac_mksound; -#ifdef CONFIG_MAGIC_SYSRQ - mach_sysrq_key = 114; /* HELP */ - mach_sysrq_shift_state = 8; /* Alt */ - mach_sysrq_shift_mask = 0xff; /* all modifiers except CapsLock */ - mach_sysrq_xlate = mac_sysrq_xlate; + mach_debug_init = mac_debug_init; #endif + kd_mksound = mac_mksound; #ifdef CONFIG_HEARTBEAT #if 0 - mach_heartbeat = mac_heartbeat; - mach_heartbeat_irq = IRQ_MAC_TIMER; + mach_heartbeat = mac_heartbeat; + mach_heartbeat_irq = IRQ_MAC_TIMER; #endif #endif - /* - * Determine hardware present - */ + /* + * Determine hardware present + */ - mac_identify(); - mac_report_hardware(); + mac_identify(); + mac_report_hardware(); - /* AFAIK only the IIci takes a cache card. The IIfx has onboard - cache ... someone needs to figure out how to tell if it's on or - not. */ - if (macintosh_config->ident == MAC_MODEL_IICI - || macintosh_config->ident == MAC_MODEL_IIFX) { - mach_l2_flush = mac_cache_card_flush; - } + /* AFAIK only the IIci takes a cache card. The IIfx has onboard + cache ... someone needs to figure out how to tell if it's on or + not. */ + + if (macintosh_config->ident == MAC_MODEL_IICI + || macintosh_config->ident == MAC_MODEL_IIFX) { + mach_l2_flush = mac_cache_card_flush; + } #ifdef MAC_DEBUG_SOUND - /* goes on forever if timers broken */ - mac_mksound(1000,10); + /* goes on forever if timers broken */ + mac_mksound(1000,10); #endif - /* - * Check for machine specific fixups. - */ + /* + * Check for machine specific fixups. + */ #ifdef OLD_NUBUS_CODE - nubus_sweep_video(); + nubus_sweep_video(); #endif } diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c index febba1982..061b01bd8 100644 --- a/arch/m68k/mac/macints.c +++ b/arch/m68k/mac/macints.c @@ -211,8 +211,6 @@ static void scc_irq_disable(int); * console_loglevel determines NMI handler function */ -extern int console_loglevel; - extern void mac_bang(int, void *, struct pt_regs *); void mac_nmi_handler(int, void *, struct pt_regs *); diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c index c405fc0da..87d155ee0 100644 --- a/arch/m68k/mac/oss.c +++ b/arch/m68k/mac/oss.c @@ -35,7 +35,6 @@ void oss_nubus_irq(int, void *, struct pt_regs *); extern void via1_irq(int, void *, struct pt_regs *); extern void mac_scc_dispatch(int, void *, struct pt_regs *); -extern int console_loglevel; /* * Initialize the OSS diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c index 86bbf72cc..d792ef987 100644 --- a/arch/m68k/mac/psc.c +++ b/arch/m68k/mac/psc.c @@ -32,8 +32,6 @@ volatile __u8 *psc; void psc_irq(int, void *, struct pt_regs *); -extern int console_loglevel; - /* * Debugging dump, used in various places to see what's going on. */ diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c index af001907d..ec0b2ce19 100644 --- a/arch/m68k/mac/via.c +++ b/arch/m68k/mac/via.c @@ -74,7 +74,6 @@ void via_irq_clear(int irq); extern void mac_bang(int, void *, struct pt_regs *); extern void mac_scc_dispatch(int, void *, struct pt_regs *); -extern int console_loglevel; extern int oss_present; /* diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c index 3eba3d13b..8dc87ebc1 100644 --- a/arch/m68k/mm/fault.c +++ b/arch/m68k/mm/fault.c @@ -19,6 +19,55 @@ extern void die_if_kernel(char *, struct pt_regs *, long); extern const int frame_extra_sizes[]; /* in m68k/kernel/signal.c */ +int send_fault_sig(struct pt_regs *regs) +{ + siginfo_t siginfo = { 0, 0, 0, }; + + siginfo.si_signo = current->thread.signo; + siginfo.si_code = current->thread.code; + siginfo.si_addr = (void *)current->thread.faddr; + printk("send_fault_sig: %p,%d,%d\n", siginfo.si_addr, siginfo.si_signo, siginfo.si_code); + + if (user_mode(regs)) { + force_sig_info(siginfo.si_signo, + &siginfo, current); + } else { + unsigned long fixup; + + /* Are we prepared to handle this kernel fault? */ + if ((fixup = search_exception_table(regs->pc))) { + struct pt_regs *tregs; + /* Create a new four word stack frame, discarding the old + one. */ + regs->stkadj = frame_extra_sizes[regs->format]; + tregs = (struct pt_regs *)((ulong)regs + regs->stkadj); + tregs->vector = regs->vector; + tregs->format = 0; + tregs->pc = fixup; + tregs->sr = regs->sr; + return -1; + } + + //if (siginfo.si_signo == SIGBUS) + // force_sig_info(siginfo.si_signo, + // &siginfo, current); + + /* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + if ((unsigned long)siginfo.si_addr < PAGE_SIZE) + printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + else + printk(KERN_ALERT "Unable to handle kernel access"); + printk(" at virtual address %p\n", siginfo.si_addr); + die_if_kernel("Oops", regs, 0 /*error_code*/); + do_exit(SIGKILL); + } + + return 1; +} + /* * This routine handles page faults. It determines the problem, and * then passes it off to one of the appropriate routines. @@ -30,16 +79,15 @@ extern const int frame_extra_sizes[]; /* in m68k/kernel/signal.c */ * If this routine detects a bad access, it returns 1, otherwise it * returns 0. */ -asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, +int do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code) { struct mm_struct *mm = current->mm; struct vm_area_struct * vma; - unsigned long fixup; int write, fault; #ifdef DEBUG - printk ("regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n", + printk ("do page fault:\nregs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n", regs->sr, regs->pc, address, error_code, current->mm->pgd); #endif @@ -55,43 +103,46 @@ asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, vma = find_vma(mm, address); if (!vma) - goto bad_area; + goto map_err; if (vma->vm_flags & VM_IO) - goto bad_area; + goto acc_err; if (vma->vm_start <= address) goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; + goto map_err; if (user_mode(regs)) { /* Accessing the stack below usp is always a bug. The "+ 256" is there due to some instructions doing pre-decrement on the stack and that doesn't show up until later. */ if (address + 256 < rdusp()) - goto bad_area; + goto map_err; } if (expand_stack(vma, address)) - goto bad_area; + goto map_err; /* * Ok, we have a good vm_area for this memory access, so * we can handle it.. */ good_area: +#ifdef DEBUG + printk("do_page_fault: good_area\n"); +#endif write = 0; switch (error_code & 3) { default: /* 3: write, present */ /* fall through */ case 2: /* write, not present */ if (!(vma->vm_flags & VM_WRITE)) - goto bad_area; + goto acc_err; write++; break; case 1: /* read, present */ - goto bad_area; + goto acc_err; case 0: /* read, not present */ if (!(vma->vm_flags & (VM_READ | VM_EXEC))) - goto bad_area; + goto acc_err; } /* @@ -100,87 +151,56 @@ good_area: * the fault. */ fault = handle_mm_fault(mm, vma, address, write); +#ifdef DEBUG + printk("handle_mm_fault returns %d\n",fault); +#endif if (fault < 0) goto out_of_memory; if (!fault) - goto do_sigbus; + goto bus_err; /* There seems to be a missing invalidate somewhere in do_no_page. * Until I found it, this one cures the problem and makes * 1.2 run on the 68040 (Martin Apel). */ + #warning should be obsolete now... if (CPU_IS_040_OR_060) flush_tlb_page(vma, address); up(&mm->mmap_sem); return 0; /* - * Something tried to access memory that isn't in our memory map.. - * Fix it, but check if it's kernel or user first.. - */ -bad_area: - up(&mm->mmap_sem); - - /* User mode accesses just cause a SIGSEGV */ - if (user_mode(regs)) { - siginfo_t info; - info.si_signo = SIGSEGV; - info.si_code = SEGV_MAPERR; - info.si_addr = (void *)address; - force_sig_info(SIGSEGV, &info, current); - return 1; - } - -no_context: - /* Are we prepared to handle this kernel fault? */ - if ((fixup = search_exception_table(regs->pc)) != 0) { - struct pt_regs *tregs; - /* Create a new four word stack frame, discarding the old - one. */ - regs->stkadj = frame_extra_sizes[regs->format]; - tregs = (struct pt_regs *)((ulong)regs + regs->stkadj); - tregs->vector = regs->vector; - tregs->format = 0; - tregs->pc = fixup; - tregs->sr = regs->sr; - return -1; - } - -/* - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - */ - if ((unsigned long) address < PAGE_SIZE) { - printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); - } else - printk(KERN_ALERT "Unable to handle kernel access"); - printk(" at virtual address %08lx\n",address); - die_if_kernel("Oops", regs, error_code); - do_exit(SIGKILL); - -/* * We ran out of memory, or some other thing happened to us that made * us unable to handle the page fault gracefully. */ out_of_memory: - up(&mm->mmap_sem); printk("VM: killing process %s\n", current->comm); - if (error_code & 4) + if (user_mode(regs)) do_exit(SIGKILL); - goto no_context; -do_sigbus: +no_context: + current->thread.signo = SIGBUS; + current->thread.faddr = address; + return send_fault_sig(regs); + +bus_err: + current->thread.signo = SIGBUS; + current->thread.code = BUS_ADRERR; + current->thread.faddr = address; + goto send_sig; + +map_err: + current->thread.signo = SIGSEGV; + current->thread.code = SEGV_MAPERR; + current->thread.faddr = address; + goto send_sig; + +acc_err: + current->thread.signo = SIGSEGV; + current->thread.code = SEGV_ACCERR; + current->thread.faddr = address; + +send_sig: up(&mm->mmap_sem); - - /* - * Send a sigbus, regardless of whether we were in kernel - * or user mode. - */ - force_sig(SIGBUS, current); - - /* Kernel mode? Handle exceptions or die */ - if (!user_mode(regs)) - goto no_context; - - return 1; + return send_fault_sig(regs); } diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c index d48a0201b..06ffa5692 100644 --- a/arch/m68k/mvme147/config.c +++ b/arch/m68k/mvme147/config.c @@ -201,15 +201,6 @@ int mvme147_keyb_init (void) /*------------------- Serial console stuff ------------------------*/ -void m147_scc_write(struct console *co, const char *str, unsigned cnt); - - -void mvme147_init_console_port (struct console *co, int cflag) -{ - co->write = m147_scc_write; -} - - static void scc_delay (void) { int n; @@ -250,3 +241,31 @@ void m147_scc_write (struct console *co, const char *str, unsigned count) restore_flags(flags); } + +static int m147_scc_wait_key (struct console *co) +{ + volatile unsigned char *p = (volatile char *)M147_SCC_A_ADDR; + unsigned long flags; + int c; + + /* wait for rx buf filled */ + while ((*p & 0x01) == 0) + ; + + save_flags(flags); + cli(); + + *p = 8; + scc_delay(); + c = *p; + + restore_flags(flags); + return c; +} + + +void mvme147_init_console_port (struct console *co, int cflag) +{ + co->write = m147_scc_write; + co->wait_key = m147_scc_wait_key; +} diff --git a/arch/m68k/q40/README b/arch/m68k/q40/README index 60134d9de..b61ee9c6a 100644 --- a/arch/m68k/q40/README +++ b/arch/m68k/q40/README @@ -56,8 +56,7 @@ SRAM can also be used as additional console device, use debug=mem. This will save kernel startup msgs into SRAM, the screen will display only the penguin - and shell prompt if it gets that far.. -Serial console works and can also be used for debugging, provided serial -initialisation works. +Serial console works and can also be used for debugging, see loader_txt Most problems seem to be caused by fawlty or badly configured io-cards or harddrives anyway..there are so many things that can go wrong here. @@ -82,8 +81,9 @@ The main interrupt register IIRQ_REG will indicate whether an IRQ was internal or from some ISA devices, EIRQ_REG can distinguish up to 8 ISA IRQs. The Q40 custom chip is programmable to provide 2 periodic timers: - - 50 or 200 Hz - level 2, !!THIS CANT BE DISABLED!! - - 10 or 20 KHz - level 4 (and possibly 6 - hardware decoding..) + - 50 or 200 Hz - level 2, + - 10 or 20 KHz - level 4 + !!THIS CANT BE DISABLED!! Linux uses the 200 Hz interrupt for timer and beep by default. @@ -92,9 +92,6 @@ Interrupts ========== q40 master chip handles only level triggered interrupts :-(( -further limitation is no disabling etc. There is NO WAY to remove -an ISA irq request other than serve the HW specific control register, -the ISA irq lines are connected straight to the CPU ipl1 pin.. IRQ sharing is not yet implemented but this should be only a minor problem.. @@ -102,12 +99,17 @@ problem.. Linux has some requirements wrt interrupt architecture, these are to my knowledge: (a) interrupt handler must not be reentered even when sti() is called + from within handler (b) working enable/disable_irq Luckily these requirements are only important for drivers shared with other architectures - ide,serial,parallel, ethernet.. -q40ints.c now contains a trivial hack for (a), however (b) could -be only solved by driver-specific code +q40ints.c now contains a trivial hack for (a), (b) is more difficult +because only irq's 4-15 can be disabled - and only all o them at once. +Thus disable_irq() can effectively block the machine if the driver goes +asleep. +One thing to keep in minde when hacking around the interrupt code is +that there is no way to find out which IRQ caused a request. Keyboard ======== diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c index 2496aa9ba..294765dd2 100644 --- a/arch/m68k/q40/config.c +++ b/arch/m68k/q40/config.c @@ -13,6 +13,7 @@ */ #include <linux/config.h> +#include <stdarg.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/mm.h> @@ -22,6 +23,7 @@ #include <linux/linkage.h> #include <linux/init.h> #include <linux/major.h> +#include <linux/serial_reg.h> #include <asm/rtc.h> #include <asm/bootinfo.h> @@ -34,8 +36,8 @@ #include <asm/q40_master.h> #include <asm/keyboard.h> -extern void fd_floppy_eject(void); -extern void fd_floppy_setup(char *str, int *ints); +extern void floppy_eject(void); +extern void floppy_setup(char *str, int *ints); extern void q40_process_int (int level, struct pt_regs *regs); extern void (*q40_sys_default_handler[]) (int, void *, struct pt_regs *); /* added just for debugging */ @@ -65,9 +67,12 @@ extern char *saved_command_line; extern char m68k_debug_device[]; static void q40_mem_console_write(struct console *co, const char *b, unsigned int count); +#if 0 +extern int ql_ticks=0; +extern int sound_ticks=0; +#endif -static int ql_ticks=0; -static int sound_ticks=0; +extern int ql_ticks; static unsigned char bcd2bin (unsigned char b); static unsigned char bin2bcd (unsigned char b); @@ -81,16 +86,16 @@ static struct console q40_console_driver = { }; -/* Save tick handler routine pointer, will point to do_timer() in - * kernel/sched.c */ - -/* static void (*tick_handler)(int, void *, struct pt_regs *); */ - - /* early debugging function:*/ extern char *q40_mem_cptr; /*=(char *)0xff020000;*/ static int _cpleft; +int q40_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode) +{ + *keycodep = keycode; + return 1; +} + static void q40_mem_console_write(struct console *co, const char *s, unsigned int count) { @@ -140,6 +145,41 @@ static void q40_get_model(char *model) sprintf(model, "Q40"); } +/* pasted code to make parport_pc happy */ +extern __inline__ int __get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} +void *pci_alloc_consistent(void *hwdev, size_t size, + dma_addr_t *dma_handle) +{ + void *ret; + int gfp = GFP_ATOMIC; + + ret = (void *)__get_free_pages(gfp, __get_order(size)); + + if (ret != NULL) { + memset(ret, 0, size); + *dma_handle = virt_to_bus(ret); + } + return ret; +} + +void pci_free_consistent(void *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + free_pages((unsigned long)vaddr, __get_order(size)); +} +/* end pasted code */ + /* No hardware options on Q40? */ @@ -149,12 +189,23 @@ static int q40_get_hardware_list(char *buffer) return 0; } +static unsigned int serports[]={0x3f8,0x2f8,0x3e8,0x2e8,0}; +void q40_disable_irqs(void) +{ + unsigned i,j; + + j=0; + while((i=serports[j++])) outb(0,i+UART_IER); + master_outb(0,EXT_ENABLE_REG); + master_outb(0,KEY_IRQ_ENABLE_REG); +} void __init config_q40(void) { mach_sched_init = q40_sched_init; /* ok */ /*mach_kbdrate = q40_kbdrate;*/ /* unneeded ?*/ mach_keyb_init = q40_keyb_init; /* OK */ + mach_kbd_translate = q40_kbd_translate; mach_init_IRQ = q40_init_IRQ; mach_gettimeoffset = q40_gettimeoffset; mach_gettod = q40_gettod; @@ -177,13 +228,14 @@ void __init config_q40(void) mach_sysrq_key = 0x54; #endif conswitchp = &dummy_con; -#ifdef CONFIG_BLK_DEV_FD - mach_floppy_setup = fd_floppy_setup; - mach_floppy_eject = fd_floppy_eject; +#if 0 /*def CONFIG_BLK_DEV_FD*/ + mach_floppy_setup = floppy_setup; + mach_floppy_eject = floppy_eject; /**/ #endif - mach_max_dma_address = 0; /* no DMA at all */ + q40_disable_irqs(); + mach_max_dma_address = 32*1024*1024; /* no DMA at all, but ide-scsi requires it.. */ /* userfull for early debuging stages writes kernel messages into SRAM */ @@ -203,6 +255,7 @@ int q40_parse_bootinfo(const struct bi_record *rec) return 1; /* unknown */ } +#if 0 #define DAC_LEFT ((unsigned char *)0xff008000) #define DAC_RIGHT ((unsigned char *)0xff008004) void q40_mksound(unsigned int hz, unsigned int ticks) @@ -258,7 +311,11 @@ static void q40_timer_int (int irq, void *dev_id, struct pt_regs *fp) #endif q40_timer_routine(irq, dev_id, fp); } +#endif +#if 0 +extern void (*q40_timer_routine)(int, void *, struct pt_regs *); +extern void q40_timer_int(); void q40_sched_init (void (*timer_routine)(int, void *, struct pt_regs *)) { @@ -289,7 +346,7 @@ void q40_sched_init (void (*timer_routine)(int, void *, struct pt_regs *)) #endif #endif } - +#endif unsigned long q40_gettimeoffset (void) { diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c index c6625aad8..96d9414d3 100644 --- a/arch/m68k/q40/q40ints.c +++ b/arch/m68k/q40/q40ints.c @@ -7,18 +7,22 @@ * License. See the file COPYING in the main directory of this archive * for more details. * - * losely based on bvme6000ints.c + * .. used to be losely based on bvme6000ints.c * */ +#include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/string.h> +#include <linux/sched.h> +#include <asm/rtc.h> #include <asm/ptrace.h> #include <asm/system.h> #include <asm/irq.h> +#include <asm/hardirq.h> #include <asm/traps.h> #include <asm/q40_master.h> @@ -71,13 +75,16 @@ short unsigned q40_ablecount[Q40_IRQ_MAX+1]; * the q40 IRQ handling routines. */ +static int disabled=0; + void q40_init_IRQ (void) { int i; + disabled=0; for (i = 0; i <= Q40_IRQ_MAX; i++) { irq_tab[i].handler = q40_defhand; - irq_tab[i].flags = IRQ_FLG_STD; + irq_tab[i].flags = 0; irq_tab[i].dev_id = NULL; /* irq_tab[i].next = NULL;*/ irq_tab[i].devname[0] = 0; @@ -87,14 +94,10 @@ void q40_init_IRQ (void) } /* setup handler for ISA ints */ - sys_request_irq(IRQ2,q40_irq2_handler, IRQ_FLG_LOCK, "q40 ISA and master chip", NULL); + sys_request_irq(IRQ2,q40_irq2_handler, 0, "q40 ISA and master chip", NULL); /* now enable some ints.. */ - -#if 0 /* has been abandoned */ - master_outb(1,SER_ENABLE_REG); -#endif - master_outb(1,EXT_ENABLE_REG); + master_outb(1,EXT_ENABLE_REG); /* hm, aint that too early? */ /* would be spurious ints by now, q40kbd_init_hw() does that */ master_outb(0,KEY_IRQ_ENABLE_REG); @@ -124,24 +127,20 @@ int q40_request_irq(unsigned int irq, default: } - if (irq<Q40_IRQ_TIMER) + if (irq<Q40_IRQ_SAMPLE) { - if (!(irq_tab[irq].flags & IRQ_FLG_STD)) - { - if (irq_tab[irq].flags & IRQ_FLG_LOCK) + if (irq_tab[irq].dev_id != NULL) { printk("%s: IRQ %d from %s is not replaceable\n", __FUNCTION__, irq, irq_tab[irq].devname); return -EBUSY; } - if (flags & IRQ_FLG_REPLACE) + /*printk("IRQ %d set to handler %p\n",irq,handler);*/ + if (dev_id==NULL) { - printk("%s: %s can't replace IRQ %d from %s\n", - __FUNCTION__, devname, irq, irq_tab[irq].devname); - return -EBUSY; - } + printk("WARNING: dev_id == NULL in request_irq\n"); + dev_id=1; } - /*printk("IRQ %d set to handler %p\n",irq,handler);*/ irq_tab[irq].handler = handler; irq_tab[irq].flags = flags; irq_tab[irq].dev_id = dev_id; @@ -150,7 +149,7 @@ int q40_request_irq(unsigned int irq, return 0; } else { - /* Q40_IRQ_TIMER :somewhat special actions required here ..*/ + /* Q40_IRQ_SAMPLE :somewhat special actions required here ..*/ sys_request_irq(4,handler,flags,devname,dev_id); sys_request_irq(6,handler,flags,devname,dev_id); return 0; @@ -175,31 +174,120 @@ void q40_free_irq(unsigned int irq, void *dev_id) default: } - if (irq<Q40_IRQ_TIMER) + if (irq<Q40_IRQ_SAMPLE) { if (irq_tab[irq].dev_id != dev_id) printk("%s: Removing probably wrong IRQ %d from %s\n", __FUNCTION__, irq, irq_tab[irq].devname); irq_tab[irq].handler = q40_defhand; - irq_tab[irq].flags = IRQ_FLG_STD; + irq_tab[irq].flags = 0; irq_tab[irq].dev_id = NULL; /* irq_tab[irq].devname = NULL; */ /* do not reset state !! */ } else - { /* == Q40_IRQ_TIMER */ + { /* == Q40_IRQ_SAMPLE */ sys_free_irq(4,dev_id); sys_free_irq(6,dev_id); } } -#if 1 + void q40_process_int (int level, struct pt_regs *fp) { printk("unexpected interrupt %x\n",level); } + +/* + * this stuff doesn't really belong here.. +*/ +int ql_ticks=0; +static int sound_ticks=0; + +#define SVOL 45 + +void q40_mksound(unsigned int hz, unsigned int ticks) +{ + /* for now ignore hz, except that hz==0 switches off sound */ + /* simply alternate the ampl (128-SVOL)-(128+SVOL)-..-.. at 200Hz */ + if (hz==0) + { + if (sound_ticks) + sound_ticks=1; /* atomic - no irq spinlock used */ + + *DAC_LEFT=128; + *DAC_RIGHT=128; + + return; + } + /* sound itself is done in q40_timer_int */ + if (sound_ticks == 0) sound_ticks=1000; /* pretty long beep */ + sound_ticks=ticks<<1; +} + +static void (*q40_timer_routine)(int, void *, struct pt_regs *); +static short rtc_oldsecs=0; +unsigned rtc_irq_flags=0; +unsigned rtc_irq_ctrl=0; + +static void q40_timer_int (int irq, void * dev, struct pt_regs * regs) +{ + + +#if (HZ==100) + ql_ticks = ql_ticks ? 0 : 1; + if (sound_ticks) + { + unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL; + sound_ticks--; + *DAC_LEFT=sval; + *DAC_RIGHT=sval; + } +#ifdef CONFIG_Q40RTC + if (rtc_irq_ctrl && (rtc_oldsecs != RTC_SECS)) + { + rtc_oldsecs = RTC_SECS; + rtc_irq_flags = RTC_UIE; + rtc_interrupt(); + } #endif + if (ql_ticks) return; +#endif + q40_timer_routine(irq, dev, regs); +} + +void q40_sched_init (void (*timer_routine)(int, void *, struct pt_regs *)) +{ + int timer_irq; + + q40_timer_routine = timer_routine; + +#if (HZ==10000) + timer_irq=Q40_IRQ_SAMPLE; +#else + timer_irq=Q40_IRQ_FRAME; +#endif + + /*printk("registering sched/timer IRQ %d, handler %p\n", timer_irq,q40_timer_int);*/ + /*printk("timer routine %p\n",q40_timer_routine);*/ + + if (request_irq(timer_irq, q40_timer_int, 0, + "timer", q40_timer_int)) + panic ("Couldn't register timer int"); + +#if (HZ==10000) + master_outb(SAMPLE_LOW,SAMPLE_RATE_REG); + master_outb(-1,SAMPLE_CLEAR_REG); + master_outb(1,SAMPLE_ENABLE_REG); +#else + master_outb(-1,FRAME_CLEAR_REG); /* not necessary ? */ +#if (HZ==100) + master_outb( 1,FRAME_RATE_REG); +#endif +#endif +} + /* * tables to translate bits into IRQ numbers @@ -208,11 +296,12 @@ void q40_process_int (int level, struct pt_regs *fp) */ struct IRQ_TABLE{ unsigned mask; int irq ;}; - +#if 0 static struct IRQ_TABLE iirqs[]={ {IRQ_FRAME_MASK,Q40_IRQ_FRAME}, {IRQ_KEYB_MASK,Q40_IRQ_KEYBOARD}, {0,0}}; +#endif static struct IRQ_TABLE eirqs[]={ {IRQ3_MASK,3}, /* ser 1 */ {IRQ4_MASK,4}, /* ser 2 */ @@ -231,103 +320,124 @@ static struct IRQ_TABLE eirqs[]={ /* complain only this many times about spurious ints : */ static int ccleirq=60; /* ISA dev IRQ's*/ -static int cclirq=60; /* internal */ +/*static int cclirq=60;*/ /* internal */ /* FIX: add shared ints,mask,unmask,probing.... */ -/* this is an awfull hack.. */ + #define IRQ_INPROGRESS 1 -static int disabled=0; /*static unsigned short saved_mask;*/ +static int do_tint=0; + +#define DEBUG_Q40INT +#define IP_USE_DISABLE /* would be nice, but crashes ???? */ +/*static int dd_count=0;*/ +static int mext_disabled=0; /* ext irq disabled by master chip? */ +static int aliased_irq=0; /* how many times inside handler ?*/ + + +/* got level 2 interrupt, dispatch to ISA or keyboard/timer IRQs */ void q40_irq2_handler (int vec, void *devname, struct pt_regs *fp) { - /* got level 2 interrupt, dispatch to ISA or keyboard IRQs */ - - unsigned mir=master_inb(IIRQ_REG); + unsigned mir; unsigned mer; int irq,i; + repeat: + mir=master_inb(IIRQ_REG); + if (mir&IRQ_FRAME_MASK) + { /* dont loose ticks */ + do_tint++; + master_outb(-1,FRAME_CLEAR_REG); + } if ((mir&IRQ_SER_MASK) || (mir&IRQ_EXT_MASK)) { - /* some ISA dev caused the int */ - mer=master_inb(EIRQ_REG); - for (i=0; eirqs[i].mask; i++) { if (mer&(eirqs[i].mask)) { irq=eirqs[i].irq; - irq_tab[irq].count++; +/* + * There is a little mess wrt which IRQ really caused this irq request. The + * main problem is that IIRQ_REG and EIRQ_REG reflect the state when they + * are read - which is long after the request came in. In theory IRQs should + * not just go away but they occassionally do + */ + if (irq>4 && irq<=15 && mext_disabled) + { + /*aliased_irq++;*/ + goto iirq; + } if (irq_tab[irq].handler == q40_defhand ) { printk("handler for IRQ %d not defined\n",irq); continue; /* ignore uninited INTs :-( */ } - if ( irq_tab[irq].state & IRQ_INPROGRESS ) { + /* some handlers do sti() for irq latency reasons, */ + /* however reentering an active irq handler is not permitted */ +#ifdef IP_USE_DISABLE + /* in theory this is the better way to do it because it still */ + /* lets through eg the serial irqs, unfortunately it crashes */ + disable_irq(irq); + disabled=1; +#else /*printk("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n",irq,disabled ? "already" : "not yet"); */ - - /*saved_mask = fp->sr;*/ - fp->sr = (fp->sr & (~0x700))+0x200; + fp->sr = (((fp->sr) & (~0x700))+0x200); disabled=1; - return; +#endif + goto iirq; } + irq_tab[irq].count++; irq_tab[irq].state |= IRQ_INPROGRESS; irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp); + irq_tab[irq].state &= ~IRQ_INPROGRESS; /* naively enable everything, if that fails than */ /* this function will be reentered immediately thus */ /* getting another chance to disable the IRQ */ - irq_tab[irq].state &= ~IRQ_INPROGRESS; if ( disabled ) { +#ifdef IP_USE_DISABLE + if (irq>4){ + disabled=0; + /*dd_count--;*/ + enable_irq(irq);} +#else + disabled=0; /*printk("reenabling irq %d\n",irq); */ - fp->sr = (fp->sr & (~0x700)); /*saved_mask; */ - disabled=0; +#if 0 + fp->sr = ((fp->sr) & (~0x700)); /* unneeded ?! */ +#endif +#endif } - else if ( fp->sr &0x200 ) - printk("exiting irq handler: fp->sr &0x200 !!\n"); - - return; + goto repeat; /* return; */ } } - if (ccleirq>0) + if (mer && ccleirq>0 && !aliased_irq) printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer),ccleirq--; } - else + iirq: + mir=master_inb(IIRQ_REG); + if (mir&IRQ_FRAME_MASK) { - /* internal */ - - for (i=0; iirqs[i].mask; i++) + do_tint++; + master_outb(-1,FRAME_CLEAR_REG); + } + for(;do_tint>0;do_tint--) { - if (mir&(iirqs[i].mask)) - { - irq=iirqs[i].irq; - irq_tab[irq].count++; - if (irq_tab[irq].handler == q40_defhand ) - continue; /* ignore uninited INTs :-( */ - - /* the INPROGRESS stuff should be completely useless*/ - /* for internal ints, nevertheless test it..*/ - if ( irq_tab[irq].state & IRQ_INPROGRESS ) + irq_tab[Q40_IRQ_FRAME].count++; + irq_tab[Q40_IRQ_FRAME].handler(Q40_IRQ_FRAME,irq_tab[Q40_IRQ_FRAME].dev_id,fp); + } + if (mir&IRQ_KEYB_MASK) /* may handle it even if actually disabled*/ { - /*disable_irq(irq); - return;*/ - printk("rentering handler for IRQ %d !!\n",irq); - } - irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp); - irq_tab[irq].state &= ~IRQ_INPROGRESS; - /*enable_irq(irq);*/ /* better not try luck !*/ - return; - } - } - if (cclirq>0) - printk("internal level 2 interrupt from unknown source ? IIRQ_REG=%x\n",mir),cclirq--; + irq_tab[Q40_IRQ_KEYBOARD].count++; + irq_tab[Q40_IRQ_KEYBOARD].handler(Q40_IRQ_KEYBOARD,irq_tab[Q40_IRQ_KEYBOARD].dev_id,fp); } } @@ -335,9 +445,11 @@ int q40_get_irq_list (char *buf) { int i, len = 0; - for (i = 0; i <= Q40_IRQ_MAX; i++) { + for (i = 0; i <= Q40_IRQ_MAX; i++) + { if (irq_tab[i].count) - len += sprintf (buf+len, "Vec 0x%02x: %8d %s%s\n", + len += sprintf (buf+len, "%sIRQ %02d: %8d %s%s\n", + (i<=15) ? "ISA-" : " " , i, irq_tab[i].count, irq_tab[i].devname[0] ? irq_tab[i].devname : "?", irq_tab[i].handler == q40_defhand ? @@ -370,30 +482,17 @@ static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs) sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler }; -int irq_disabled=0; + void q40_enable_irq (unsigned int irq) { - /* enable ISA iqs */ - if ( irq>=0 && irq<=15 ) /* the moderately bad case */ + if ( irq>=5 && irq<=15 ) + { + mext_disabled--; + if (mext_disabled>0) + printk("q40_enable_irq : nested disable/enable\n"); + if (mext_disabled==0) master_outb(1,EXT_ENABLE_REG); -#if 0 - unsigned long flags; - int i; - - if (irq>=10 && irq <= 15) - { - if ( !(--q40_ablecount[irq])) - for (i=10,irq_disabled=0; i<=15; i++) - { - irq_disabled |= (q40_ablecount[irq] !=0); - } - if ( !irq_disabled ) - { - save_flags(flags); - restore_flags(flags & (~0x700)); - } } -#endif } @@ -404,19 +503,12 @@ void q40_disable_irq (unsigned int irq) * Any driver should not attempt to sleep accross disable_irq !! */ - if ( irq>=10 && irq<=15 ) /* the moderately bad case */ - master_outb(0,EXT_ENABLE_REG); -#if 0 - unsigned long flags; - - if (irq>=10 && irq <= 15) + if ( irq>=5 && irq<=15 ) { - save_flags(flags); - restore_flags(flags | 0x200 ); - irq_disabled=1; - q40_ablecount[irq]++; + master_outb(0,EXT_ENABLE_REG); + mext_disabled++; + if (mext_disabled>1) printk("disable_irq nesting count %d\n",mext_disabled); } -#endif } unsigned long q40_probe_irq_on (void) @@ -428,3 +520,7 @@ int q40_probe_irq_off (unsigned long irqs) { return -1; } +/* + * Local variables: + * compile-command: "m68k-linux-gcc -D__KERNEL__ -I/home/rz/lx/linux-2.2.6/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -m68040 -c -o q40ints.o q40ints.c" + */ diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 6a8cfe187..3ea928267 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -151,7 +151,8 @@ LOADADDR += 0x80080000 endif ifdef CONFIG_SGI_IP22 -LIBS += arch/mips/sgi/kernel/sgikern.a arch/mips/arc/arclib.a +CORE_FILES += arch/mips/sgi/kernel/ip22-kern.o +LIBS += arch/mips/arc/arclib.a SUBDIRS += arch/mips/sgi/kernel arch/mips/arc # # Set LOADADDR to >= 0x88069000 if you want to leave space for symmon, @@ -273,7 +274,6 @@ zdisk: vmlinux archclean: @$(MAKEBOOT) clean rm -f arch/$(ARCH)/ld.script - $(MAKE) -C arch/$(ARCH)/kernel clean $(MAKE) -C arch/$(ARCH)/tools clean $(MAKE) -C arch/mips/baget clean diff --git a/arch/mips/arc/Makefile b/arch/mips/arc/Makefile index e37207b33..8af31d353 100644 --- a/arch/mips/arc/Makefile +++ b/arch/mips/arc/Makefile @@ -1,4 +1,3 @@ -# $Id: Makefile,v 1.1 1998/10/18 13:32:08 tsbogend Exp $ # # Makefile for the SGI arcs prom monitor library routines # under Linux. @@ -10,11 +9,12 @@ # Note 2! The CFLAGS definitions are now in the main makefile... L_TARGET = arclib.a -L_OBJS = console.o init.o memory.o tree.o env.o cmdline.o misc.o time.o \ - file.o identify.o -ifdef CONFIG_ARC_CONSOLE -L_OBJS += arc_con.o -endif +obj-y += console.o init.o memory.o tree.o env.o cmdline.o misc.o \ + time.o file.o identify.o + +obj-$(CONFIG_ARC_CONSOLE) += arc_con.o + +L_OBJS := $(obj-y) include $(TOPDIR)/Rules.make diff --git a/arch/mips/defconfig b/arch/mips/defconfig index 6f64e8a9a..b75e37c6b 100644 --- a/arch/mips/defconfig +++ b/arch/mips/defconfig @@ -301,8 +301,6 @@ CONFIG_LOCKD=y # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set diff --git a/arch/mips/defconfig-atlas b/arch/mips/defconfig-atlas index 4b0740fe9..e622a3f9a 100644 --- a/arch/mips/defconfig-atlas +++ b/arch/mips/defconfig-atlas @@ -28,7 +28,7 @@ CONFIG_MIPS_ATLAS=y # CONFIG_MCA is not set # CONFIG_SBUS is not set CONFIG_PCI=y -# CONFIG_ISA is not set +CONFIG_SWAP_IO_SPACE=y # CONFIG_ISA is not set # CONFIG_EISA is not set # CONFIG_I8259 is not set @@ -429,8 +429,6 @@ CONFIG_LOCKD=y # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set diff --git a/arch/mips/defconfig-cp7000 b/arch/mips/defconfig-cp7000 index d67e287ba..1d98bca31 100644 --- a/arch/mips/defconfig-cp7000 +++ b/arch/mips/defconfig-cp7000 @@ -405,8 +405,6 @@ CONFIG_LOCKD=y # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set diff --git a/arch/mips/defconfig-ddb5476 b/arch/mips/defconfig-ddb5476 index 21f540a76..9c74cad89 100644 --- a/arch/mips/defconfig-ddb5476 +++ b/arch/mips/defconfig-ddb5476 @@ -468,8 +468,6 @@ CONFIG_LOCKD=y # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set diff --git a/arch/mips/defconfig-decstation b/arch/mips/defconfig-decstation index dece17abb..72ac15128 100644 --- a/arch/mips/defconfig-decstation +++ b/arch/mips/defconfig-decstation @@ -295,8 +295,6 @@ CONFIG_EXT2_FS=y # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set diff --git a/arch/mips/defconfig-ev64120 b/arch/mips/defconfig-ev64120 index 38dd7bbfb..004f6083f 100644 --- a/arch/mips/defconfig-ev64120 +++ b/arch/mips/defconfig-ev64120 @@ -404,8 +404,6 @@ CONFIG_LOCKD=y # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set diff --git a/arch/mips/defconfig-ev96100 b/arch/mips/defconfig-ev96100 index 262fd226a..eae29f655 100644 --- a/arch/mips/defconfig-ev96100 +++ b/arch/mips/defconfig-ev96100 @@ -395,8 +395,6 @@ CONFIG_LOCKD=y # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set diff --git a/arch/mips/defconfig-ip22 b/arch/mips/defconfig-ip22 index 6f64e8a9a..b75e37c6b 100644 --- a/arch/mips/defconfig-ip22 +++ b/arch/mips/defconfig-ip22 @@ -301,8 +301,6 @@ CONFIG_LOCKD=y # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set diff --git a/arch/mips/defconfig-malta b/arch/mips/defconfig-malta index 826c3f871..7f83eba55 100644 --- a/arch/mips/defconfig-malta +++ b/arch/mips/defconfig-malta @@ -29,7 +29,8 @@ CONFIG_MIPS_MALTA=y # CONFIG_SBUS is not set CONFIG_I8259=y CONFIG_PCI=y -# CONFIG_ISA is not set +CONFIG_HAVE_STD_PC_SERIAL_PORT=y +CONFIG_SWAP_IO_SPACE=y # CONFIG_ISA is not set # CONFIG_EISA is not set @@ -427,8 +428,6 @@ CONFIG_LOCKD=y # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set diff --git a/arch/mips/defconfig-rm200 b/arch/mips/defconfig-rm200 index 8fced9009..fefe5f65d 100644 --- a/arch/mips/defconfig-rm200 +++ b/arch/mips/defconfig-rm200 @@ -319,8 +319,6 @@ CONFIG_EXT2_FS=y # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 9be8406e4..6bec68661 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -11,97 +11,60 @@ .S.o: $(CC) $(AFLAGS) -c $< -o $@ -all: kernel.o head.o init_task.o EXTRA_ASFLAGS = -mips3 -mcpu=r4000 + +all: kernel.o head.o init_task.o + O_TARGET := kernel.o -O_OBJS := branch.o process.o signal.o entry.o traps.o ptrace.o vm86.o \ - ioport.o reset.o semaphore.o setup.o syscall.o sysmips.o ipc.o \ - scall_o32.o unaligned.o -OX_OBJS := mips_ksyms.o + +obj-y += branch.o process.o signal.o entry.o \ + traps.o ptrace.o vm86.o ioport.o reset.o \ + semaphore.o setup.o syscall.o sysmips.o \ + ipc.o scall_o32.o unaligned.o +obj-$(CONFIG_MODULES) += mips_ksyms.o ifdef CONFIG_CPU_R3000 -O_OBJS += r2300_misc.o r2300_fpu.o r2300_switch.o +obj-y += r2300_misc.o r2300_fpu.o r2300_switch.o else -O_OBJS += r4k_misc.o r4k_switch.o +obj-y += r4k_misc.o r4k_switch.o ifdef CONFIG_CPU_R6000 -O_OBJS += r6000_fpu.o +obj-y += r6000_fpu.o else -O_OBJS += r4k_fpu.o -endif +obj-y += r4k_fpu.o endif - -ifdef CONFIG_MIPS_FPE_MODULE -M_OBJS += fpe.o endif -ifndef CONFIG_MIPS_FPU_EMULATOR -O_OBJS += softfp.o -endif +obj-$(CONFIG_MIPS_FPE_MODULE) += fpe.o +obj-$(CONFIG_MIPS_FPU_EMULATOR) += softfp.o -ifdef CONFIG_ROTTEN_IRQ - OX_OBJS += old-irq.o -endif +# Old style irq support, going to die in 2.5. +export-objs += old-irq.o +obj-$(CONFIG_ROTTEN_IRQ) += old-irq.o ifndef CONFIG_DECSTATION ifndef CONFIG_BAGET_MIPS ifndef CONFIG_MIPS_ATLAS ifndef CONFIG_MIPS_MALTA ifndef CONFIG_MIPS_EV96100 - O_OBJS += time.o + obj-y += time.o endif endif endif endif endif -# -# Do we want to be able to execute IRIX elf binaries? -# -ifdef CONFIG_BINFMT_IRIX -O_OBJS += irixelf.o irixioctl.o irixsig.o sysirix.o irixinv.o -endif - -# -# Kernel debugging -# -ifdef CONFIG_REMOTE_DEBUG -O_OBJS += gdb-low.o gdb-stub.o -endif - -ifdef CONFIG_PCI -O_OBJS += pci-dma.o -endif - -ifdef CONFIG_PROC_FS -O_OBJS += proc.o -endif - -# -# Since we add the same object files to O_OBJS for different configurations. -# O_OBJS might contain duplicate files. We correct this by filtering out -# duplicate files. Just to avoid users having to know about all the -# compatibility stuff between various boards and boards. -# -O_OBJS := $(sort $(O_OBJS)) +obj-$(CONFIG_BINFMT_IRIX) += irixelf.o irixioctl.o irixsig.o sysirix.o \ + irixinv.o +obj-$(CONFIG_REMOTE_DEBUG) += gdb-low.o gdb-stub.o +obj-$(CONFIG_PCI) += pci-dma.o +obj-$(CONFIG_PROC_FS) += proc.o entry.o: entry.S - head.o: head.S -#r4k_switch.o: r4k_switch.S -# -#r4k_misc.o: r4k_misc.S -# -#r4k_fpu.o: r4k_fpu.S -# -#r2300_switch.o: r2300_switch.S -# -#r2300_misc.o: r2300_misc.S -# -#r2300_fpu.o: r2300_fpu.S -# -#r6000_fpu.o: r6000_fpu.S - -clean: +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) include $(TOPDIR)/Rules.make diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c index 6f6556da4..022bb1f77 100644 --- a/arch/mips/kernel/irixsig.c +++ b/arch/mips/kernel/irixsig.c @@ -716,7 +716,7 @@ repeat: SET_LINKS(p); notify_parent(p, SIGCHLD); } else - release(p); + release_task(p); goto end_waitsys; default: continue; diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index d3ea588f0..f2a1d7032 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -36,19 +36,6 @@ #include <asm/inst.h> #endif -extern int console_loglevel; - -static inline void console_silent(void) -{ - console_loglevel = 0; -} - -static inline void console_verbose(void) -{ - if (console_loglevel) - console_loglevel = 15; -} - /* * Machine specific interrupt handlers */ diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile index 52331d233..a5c870b73 100644 --- a/arch/mips/lib/Makefile +++ b/arch/mips/lib/Makefile @@ -9,26 +9,21 @@ L_TARGET = lib.a -L_OBJS = csum_partial.o csum_partial_copy.o \ - rtc-std.o rtc-no.o memcpy.o memset.o watch.o\ - strlen_user.o strncpy_user.o strnlen_user.o +obj-y += csum_partial.o csum_partial_copy.o \ + rtc-std.o rtc-no.o memcpy.o memset.o \ + watch.o strlen_user.o strncpy_user.o \ + strnlen_user.o ifdef CONFIG_CPU_R3000 - L_OBJS += r3k_dump_tlb.o + obj-y += r3k_dump_tlb.o else - L_OBJS += dump_tlb.o + obj-y += dump_tlb.o endif -ifdef CONFIG_BLK_DEV_FD - L_OBJS += floppy-no.o floppy-std.o -endif - -ifdef CONFIG_IDE - L_OBJS += ide-std.o ide-no.o -endif +obj-$(CONFIG_BLK_DEV_FD) += floppy-no.o floppy-std.o +obj-$(CONFIG_IDE) += ide-std.o ide-no.o +obj-$(CONFIG_PC_KEYB) += kbd-std.o kbd-no.o -ifdef CONFIG_PC_KEYB - L_OBJS += kbd-std.o kbd-no.o -endif +L_OBJS := $(filter-out $(export-objs), $(obj-y)) include $(TOPDIR)/Rules.make diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index 4febbefd2..67a987693 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile @@ -8,46 +8,20 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -O_OBJS := extable.o init.o fault.o loadmmu.o -ifdef CONFIG_CPU_R3000 -O_OBJS += r2300.o -endif +obj-y += extable.o init.o fault.o loadmmu.o -ifdef CONFIG_CPU_R4300 -O_OBJS += r4xx0.o -endif +obj-$(CONFIG_CPU_R3000) += r2300.o +obj-$(CONFIG_CPU_R4300) += r4xx0.o +obj-$(CONFIG_CPU_R4X00) += r4xx0.o +obj-$(CONFIG_CPU_R5000) += r4xx0.o +obj-$(CONFIG_CPU_NEVADA) += r4xx0.o +obj-$(CONFIG_CPU_R5432) += r5432.o +obj-$(CONFIG_CPU_RM7000) += rm7k.o +obj-$(CONFIG_CPU_MIPS32) += mips32.o +obj-$(CONFIG_SGI_IP22) += umap.o +obj-$(CONFIG_BAGET_MIPS) += umap.o -ifdef CONFIG_CPU_R4X00 -O_OBJS += r4xx0.o -endif - -ifdef CONFIG_CPU_R5000 -O_OBJS += r4xx0.o -endif - -ifdef CONFIG_CPU_R5432 -O_OBJS += r5432.o -endif - -ifdef CONFIG_CPU_RM7000 -O_OBJS += rm7k.o -endif - -ifdef CONFIG_CPU_NEVADA -O_OBJS += r4xx0.o -endif - -ifdef CONFIG_CPU_MIPS32 -O_OBJS += mips32.o -endif - -ifdef CONFIG_SGI_IP22 -O_OBJS += umap.o -endif - -ifdef CONFIG_BAGET_MIPS -O_OBJS += umap.o -endif +O_OBJS := $(filter-out $(export-objs), $(obj-y)) include $(TOPDIR)/Rules.make diff --git a/arch/mips/sgi/kernel/Makefile b/arch/mips/sgi/kernel/Makefile index f016cd12f..62fd01001 100644 --- a/arch/mips/sgi/kernel/Makefile +++ b/arch/mips/sgi/kernel/Makefile @@ -13,18 +13,15 @@ .S.o: $(CC) $(CFLAGS) -c $< -o $*.o -OBJS = indy_mc.o indy_sc.o indy_hpc.o indy_int.o indy_rtc.o \ - system.o indyIRQ.o reset.o setup.o time.o +O_TARGET := ip22-kern.o -all: sgikern.a +all: ip22-kern.o indyIRQ.o -sgikern.a: $(OBJS) - $(AR) rcs sgikern.a $(OBJS) - sync +obj-y += indy_mc.o indy_sc.o indy_hpc.o indy_int.o indy_rtc.o system.o \ + indyIRQ.o reset.o setup.o time.o indyIRQ.o: indyIRQ.S -dep: - $(CPP) $(CPPFLAGS) -M *.c > .depend +O_OBJS := $(obj-y) include $(TOPDIR)/Rules.make diff --git a/arch/mips64/arc/Makefile b/arch/mips64/arc/Makefile index 141093f78..eb805e260 100644 --- a/arch/mips64/arc/Makefile +++ b/arch/mips64/arc/Makefile @@ -3,15 +3,15 @@ # L_TARGET = arclib.a -L_OBJS = init.o printf.o tree.o env.o cmdline.o misc.o time.o \ - file.o identify.o +obj-y := init.o printf.o tree.o env.o cmdline.o misc.o time.o file.o \ + identify.o ifndef CONFIG_SGI_IP27 -L_OBJS += console.o + obj-y += console.o endif -ifdef CONFIG_ARC_MEMORY -L_OBJS += memory.o -endif +obj-$(CONFIG_ARC_MEMORY) += memory.o + +L_OBJS := $(obj-y) include $(TOPDIR)/Rules.make diff --git a/arch/mips64/defconfig b/arch/mips64/defconfig index 72f0b52bc..580ecb084 100644 --- a/arch/mips64/defconfig +++ b/arch/mips64/defconfig @@ -405,8 +405,6 @@ CONFIG_LOCKD_V4=y # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set diff --git a/arch/mips64/defconfig-ip22 b/arch/mips64/defconfig-ip22 index 3848c0c96..8a747d636 100644 --- a/arch/mips64/defconfig-ip22 +++ b/arch/mips64/defconfig-ip22 @@ -321,8 +321,6 @@ CONFIG_LOCKD=y # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set diff --git a/arch/mips64/defconfig-ip27 b/arch/mips64/defconfig-ip27 index 72f0b52bc..580ecb084 100644 --- a/arch/mips64/defconfig-ip27 +++ b/arch/mips64/defconfig-ip27 @@ -405,8 +405,6 @@ CONFIG_LOCKD_V4=y # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set diff --git a/arch/mips64/kernel/traps.c b/arch/mips64/kernel/traps.c index 997aee0c7..c6777f938 100644 --- a/arch/mips64/kernel/traps.c +++ b/arch/mips64/kernel/traps.c @@ -27,19 +27,6 @@ #include <asm/uaccess.h> #include <asm/mmu_context.h> -extern int console_loglevel; - -static inline void console_silent(void) -{ - console_loglevel = 0; -} - -static inline void console_verbose(void) -{ - if (console_loglevel) - console_loglevel = 15; -} - extern asmlinkage void __xtlb_mod(void); extern asmlinkage void __xtlb_tlbl(void); extern asmlinkage void __xtlb_tlbs(void); diff --git a/arch/mips64/lib/Makefile b/arch/mips64/lib/Makefile index b8392d527..9ce5f0bd7 100644 --- a/arch/mips64/lib/Makefile +++ b/arch/mips64/lib/Makefile @@ -8,9 +8,12 @@ $(CC) $(CFLAGS) -c $< -o $*.o L_TARGET = lib.a -L_OBJS = csum_partial.o csum_partial_copy.o dump_tlb.o floppy-std.o \ + +obj-y += csum_partial.o csum_partial_copy.o dump_tlb.o floppy-std.o \ floppy-no.o ide-std.o ide-no.o kbd-std.o kbd-no.o rtc-std.o \ rtc-no.o memset.o memcpy.o strlen_user.o strncpy_user.o \ strnlen_user.o watch.o +L_OBJS := $(obj-y) + include $(TOPDIR)/Rules.make diff --git a/arch/mips64/mm/Makefile b/arch/mips64/mm/Makefile index fe95aff18..2505f05bd 100644 --- a/arch/mips64/mm/Makefile +++ b/arch/mips64/mm/Makefile @@ -1,33 +1,18 @@ -# $Id: Makefile,v 1.4 2000/01/17 23:32:46 ralf Exp $ # # Makefile for the Linux/MIPS-specific parts of the memory manager. # O_TARGET := mm.o -O_OBJS := extable.o init.o fault.o loadmmu.o -ifdef CONFIG_CPU_R4300 -O_OBJS += r4xx0.o -endif -ifdef CONFIG_CPU_R4X00 -O_OBJS += r4xx0.o -endif -ifdef CONFIG_CPU_R5000 -O_OBJS += r4xx0.o -endif -ifdef CONFIG_CPU_NEVADA -O_OBJS += r4xx0.o -endif -ifdef CONFIG_CPU_R10000 -O_OBJS += andes.o -endif +obj-y := extable.o init.o fault.o loadmmu.o -ifdef CONFIG_SGI_IP22 -O_OBJS += umap.o -endif +obj-$(CONFIG_CPU_R4300) += r4xx0.o +obj-$(CONFIG_CPU_R4X00) += r4xx0.o +obj-$(CONFIG_CPU_R5000) += r4xx0.o +obj-$(CONFIG_CPU_NEVADA) += r4xx0.o +obj-$(CONFIG_CPU_R10000) += andes.o +obj-$(CONFIG_SGI_IP22) += umap.o -ifdef CONFIG_BAGET_MIPS -O_OBJS += umap.o -endif +O_OBJS := $(filter-out $(export-objs), $(obj-y)) include $(TOPDIR)/Rules.make diff --git a/arch/mips64/sgi-ip22/Makefile b/arch/mips64/sgi-ip22/Makefile index f303d90da..641fcbddf 100644 --- a/arch/mips64/sgi-ip22/Makefile +++ b/arch/mips64/sgi-ip22/Makefile @@ -1,4 +1,3 @@ -# $Id: Makefile,v 1.1 1999/08/20 21:13:33 ralf Exp $ # # Makefile for the SGI specific kernel interface routines # under Linux. @@ -10,7 +9,10 @@ $(CC) $(CFLAGS) -c $< -o $*.o L_TARGET = ip22.a -L_OBJS = ip22-berr.o ip22-mc.o ip22-sc.o ip22-hpc.o ip22-int.o ip22-rtc.o \ - ip22-setup.o system.o ip22-timer.o ip22-irq.o ip22-reset.o time.o + +obj-y += ip22-berr.o ip22-mc.o ip22-sc.o ip22-hpc.o ip22-int.o ip22-rtc.o \ + ip22-setup.o system.o ip22-timer.o ip22-irq.o ip22-reset.o time.o + +L_OBJS := $(obj-y) include $(TOPDIR)/Rules.make diff --git a/arch/mips64/sgi-ip27/Makefile b/arch/mips64/sgi-ip27/Makefile index cab7e6be5..49dd85cb4 100644 --- a/arch/mips64/sgi-ip27/Makefile +++ b/arch/mips64/sgi-ip27/Makefile @@ -8,8 +8,11 @@ $(CC) $(CFLAGS) -c $< -o $*.o O_TARGET = ip27.a -O_OBJS = ip27-berr.o ip27-console.o ip27-irq.o ip27-init.o ip27-irq-glue.o \ - ip27-klconfig.o ip27-klnuma.o ip27-memory.o ip27-nmi.o ip27-pci.o \ - ip27-pci-dma.o ip27-reset.o ip27-setup.o ip27-timer.o + +obj-y := ip27-berr.o ip27-console.o ip27-irq.o ip27-init.o ip27-irq-glue.o \ + ip27-klconfig.o ip27-klnuma.o ip27-memory.o ip27-nmi.o ip27-pci.o \ + ip27-pci-dma.o ip27-reset.o ip27-setup.o ip27-timer.o + +O_OBJS := $(obj-y) include $(TOPDIR)/Rules.make diff --git a/arch/mips64/tools/Makefile b/arch/mips64/tools/Makefile index 3218bfe5f..33d0c17b1 100644 --- a/arch/mips64/tools/Makefile +++ b/arch/mips64/tools/Makefile @@ -1,4 +1,3 @@ -# $Id: Makefile,v 1.1 1999/08/18 21:46:53 ralf Exp $ # # Makefile for MIPS kernel build tools. # diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile new file mode 100644 index 000000000..ec27df6b0 --- /dev/null +++ b/arch/parisc/Makefile @@ -0,0 +1,91 @@ +# +# parisc/Makefile +# +# This file is included by the global makefile so that you can add your own +# architecture-specific flags and dependencies. Remember to do have actions +# for "archclean" and "archdep" for cleaning up and making dependencies for +# this architecture +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1994 by Linus Torvalds +# Portions Copyright (C) 1999 The Puffin Group +# +# Modified for PA-RISC Linux by Paul Lahaie, Alex deVries, +# Mike Shaver, Helge Deller and Martin K. Petersen +# + +FINAL_LD=$(CROSS_COMPILE)ld --warn-common --warn-section-align + +CPP=$(CC) -E +OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S +LDFLAGS = +LINKFLAGS =-T $(TOPDIR)/arch/parisc/vmlinux.lds $(LDFLAGS) + +CFLAGS_PIPE := -pipe +CFLAGS_NSR := -fno-strength-reduce +CFLAGS := $(CFLAGS) -D__linux__ $(CFLAGS_PIPE) $(CFLAGS_NSR) + +# These should be on for older toolchains or SOM toolchains that don't +# enable them by default. +CFLAGS += -mno-space-regs -mfast-indirect-calls + +# If we become able to compile for specific platforms, this should be +# conditional on that. +CFLAGS += -mschedule=7200 + +# No fixed-point multiply +CFLAGS += -mdisable-fpregs + +HEAD = arch/parisc/kernel/head.o + +SUBDIRS := $(SUBDIRS) $(addprefix arch/parisc/, tools kernel mm lib hpux) +CORE_FILES := $(addprefix arch/parisc/, kernel/pdc_cons.o kernel/process.o \ + lib/lib.a mm/mm.o kernel/kernel.o hpux/hpux.o) \ + $(CORE_FILES) arch/parisc/kernel/init_task.o +LIBS := `$(CC) -print-libgcc-file-name` $(TOPDIR)/arch/parisc/lib/lib.a $(LIBS) + +ifdef CONFIG_MATH_EMULATION +SUBDIRS := $(SUBDIRS) arch/parisc/math-emu +DRIVERS := $(DRIVERS) arch/parisc/math-emu/math.a +endif + +ifdef CONFIG_KWDB +SUBDIRS := $(SUBDIRS) arch/parisc/kdb +DRIVERS := $(DRIVERS) arch/parisc/kdb/kdb.o + +arch/parisc/kdb: dummy + $(MAKE) linuxsubdirs SUBDIRS=arch/parisc/kdb +endif + +arch/parisc/kernel: dummy + $(MAKE) linuxsubdirs SUBDIRS=arch/parisc/kernel + +arch/parisc/mm: dummy + $(MAKE) linuxsubdirs SUBDIRS=arch/parisc/mm + +palo: vmlinux + export TOPDIR=`pwd`; export CONFIG_STI_CONSOLE=$(CONFIG_STI_CONSOLE); \ + unset STRIP LDFLAGS CPP CPPFLAGS AFLAGS CFLAGS CC LD; cd ../palo && make lifimage + +Image: palo + +Image-clean: + +ramdisk.o: + +zImage: palo + +bzImage: palo + +compressed: zImage + +install: + +archclean: + +archmrproper: + +archdep: diff --git a/arch/parisc/config.in b/arch/parisc/config.in new file mode 100644 index 000000000..eed80181e --- /dev/null +++ b/arch/parisc/config.in @@ -0,0 +1,208 @@ +# +# For a description of the syntax of this configuration file, +# see the Configure script. +# + +mainmenu_name "Linux Kernel Configuration" + +define_bool CONFIG_PARISC y +define_bool CONFIG_UID16 n + +mainmenu_option next_comment +comment 'Code maturity level options' +bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL +endmenu + +mainmenu_option next_comment +comment 'General options' + +# bool 'Symmetric multi-processing support' CONFIG_SMP +define_bool CONFIG_SMP n + +bool 'Kernel Debugger support' CONFIG_KWDB +# define_bool CONFIG_KWDB n + +# bool 'GSC/Gecko bus support' CONFIG_GSC y +define_bool CONFIG_GSC y + +bool 'U2/Uturn I/O MMU' CONFIG_IOMMU_CCIO y +bool 'LASI I/O support' CONFIG_GSC_LASI y + +bool 'PCI bus support' CONFIG_PCI y + +if [ "$CONFIG_PCI" = "y" ]; then + bool 'GSCtoPCI/DINO PCI support' CONFIG_GSC_DINO y + bool 'LBA/Elroy PCI support' CONFIG_PCI_LBA n +fi + +if [ "$CONFIG_PCI_LBA" = "y" ]; then + define_bool CONFIG_IOSAPIC y + define_bool CONFIG_IOMMU_SBA y +fi + +# +# if [ "$CONFIG_PCI_EPIC" = "y" ]; then... +# + +endmenu + +mainmenu_option next_comment +comment 'Loadable module support' +bool 'Enable loadable module support' CONFIG_MODULES +if [ "$CONFIG_MODULES" = "y" ]; then + bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS + bool 'Kernel module loader' CONFIG_KMOD +fi +endmenu + +mainmenu_option next_comment +comment 'General setup' + +bool 'Networking support' CONFIG_NET + +bool 'System V IPC' CONFIG_SYSVIPC +bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT +bool 'Sysctl support' CONFIG_SYSCTL +tristate 'Kernel support for SOM binaries' CONFIG_BINFMT_SOM +tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA +fi + +endmenu + +##source drivers/parport/Config.in +mainmenu_option next_comment +comment 'Parallel port support' + +tristate 'Parallel port support' CONFIG_PARPORT +if [ "$CONFIG_PARPORT" != "n" ]; then + if [ "$CONFIG_PCI" = "y" ]; then + dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT + if [ "$CONFIG_PARPORT_PC" != "n" ]; then + bool ' Use FIFO/DMA if available' CONFIG_PARPORT_PC_FIFO + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' SuperIO chipset support (EXPERIMENTAL)' CONFIG_PARPORT_PC_SUPERIO + fi + fi + fi + if [ "$CONFIG_GSC_LASI" = "y" ]; then + dep_tristate ' LASI/ASP builtin parallel-port' CONFIG_PARPORT_GSC $CONFIG_PARPORT + else + define_tristate CONFIG_PARPORT_GSC n + fi + + # If exactly one hardware type is selected then parport will optimise away + # support for loading any others. Defeat this if the user is keen. + bool ' Support foreign hardware' CONFIG_PARPORT_OTHER + + bool ' IEEE 1284 transfer modes' CONFIG_PARPORT_1284 +fi +endmenu + + +source drivers/block/Config.in + +if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in +fi + +mainmenu_option next_comment +comment 'SCSI support' + +tristate 'SCSI support' CONFIG_SCSI + +if [ "$CONFIG_SCSI" != "n" ]; then + comment 'SCSI support type (disk, tape, CDrom)' + + dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI + if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then + int 'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40 + fi + + dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI + dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI + if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then + bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR + int 'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2 + fi + dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI + + comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' + bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN + bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS + + mainmenu_option next_comment + comment 'SCSI low-level drivers' + if [ "$CONFIG_GSC_LASI" = "y" ]; then + dep_tristate 'Lasi SCSI support' CONFIG_SCSI_LASI $CONFIG_SCSI + dep_tristate 'Zalon SCSI support' CONFIG_SCSI_ZALON $CONFIG_SCSI + fi + if [ "$CONFIG_PCI" = "y" ]; then + dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI + fi + if [ "$CONFIG_SCSI_ZALON" != "n" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then + int ' default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8 + int ' maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32 + int ' synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 20 + bool ' enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE + bool ' use normal IO' CONFIG_SCSI_NCR53C8XX_IOMAPPED + fi + endmenu +fi +endmenu + +if [ "$CONFIG_NET" = "y" ]; then + mainmenu_option next_comment + comment 'Network device support' + + bool 'Network device support' CONFIG_NETDEVICES + + if [ "$CONFIG_NETDEVICES" = "y" ]; then + if [ "$CONFIG_GSC_LASI" = "y" ]; then + tristate 'Lasi ethernet' CONFIG_LASI_82596 + fi + source drivers/net/Config.in + fi + endmenu +fi + +source drivers/char/Config.in + +source fs/Config.in + +mainmenu_option next_comment +comment 'Sound Drivers' +tristate 'Sound card support' CONFIG_SOUND +if [ "$CONFIG_SOUND" != "n" ]; then + source drivers/sound/Config.in +fi +endmenu + +if [ "$CONFIG_VT" = "y" ]; then + mainmenu_option next_comment + comment 'Console drivers' + source drivers/video/Config.in + +# bool 'IODC console' CONFIG_IODC_CONSOLE + bool 'STI console' CONFIG_STI_CONSOLE + if [ "$CONFIG_IODC_CONSOLE" = "n" ]; then + if [ "$CONFIG_GSC_PS2" = "y" ]; then + define_bool CONFIG_DUMMY_CONSOLE y + fi + fi + if [ "$CONFIG_STI_CONSOLE" = "y" ]; then + define_bool CONFIG_DUMMY_CONSOLE y + fi + endmenu +fi +# endmenu + +mainmenu_option next_comment +comment 'Kernel hacking' + +#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +endmenu + diff --git a/arch/parisc/defconfig b/arch/parisc/defconfig new file mode 100644 index 000000000..352fa78c0 --- /dev/null +++ b/arch/parisc/defconfig @@ -0,0 +1,363 @@ +# +# Automatically generated by make menuconfig: don't edit +# +CONFIG_PARISC=y +# CONFIG_UID16 is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# General options +# +# CONFIG_SMP is not set +# CONFIG_KWDB is not set +CONFIG_GSC=y +CONFIG_IOMMU_CCIO=y +CONFIG_GSC_LASI=y +CONFIG_PCI=y +CONFIG_GSC_DINO=y +CONFIG_PCI_LBA=y +CONFIG_IOSAPIC=y +CONFIG_IOMMU_SBA=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_BINFMT_SOM=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_BINFMT_JAVA is not set + +# +# Parallel port support +# +CONFIG_PARPORT=y +# CONFIG_PARPORT_PC is not set +CONFIG_PARPORT_GSC=y +# CONFIG_PARPORT_OTHER is not set +# CONFIG_PARPORT_1284 is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# SCSI support +# +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 +CONFIG_CHR_DEV_ST=y +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 +CONFIG_CHR_DEV_SG=y +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set + +# +# SCSI low-level drivers +# +CONFIG_SCSI_LASI=y +CONFIG_SCSI_ZALON=y +CONFIG_SCSI_SYM53C8XX=y +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 +CONFIG_SCSI_NCR53C8XX_SYNC=20 +# CONFIG_SCSI_NCR53C8XX_PROFILE is not set +# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +CONFIG_LASI_82596=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_DE4X5 is not set +CONFIG_TULIP=y +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_LNE390 is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_RTL8129 is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_GSC_PS2=y +CONFIG_HIL=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +CONFIG_SERIAL_GSC=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_PRINTER=y +# CONFIG_LP_CONSOLE is not set +# CONFIG_PPDEV is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_GENRTC=y +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_NLS is not set + +# +# Sound Drivers +# +# CONFIG_SOUND is not set + +# +# Console drivers +# + +# +# Frame-buffer support +# +# CONFIG_FB is not set +# CONFIG_STI_CONSOLE is not set + +# +# Kernel hacking +# +CONFIG_MAGIC_SYSRQ=y diff --git a/arch/parisc/hpux/Makefile b/arch/parisc/hpux/Makefile new file mode 100644 index 000000000..d946959be --- /dev/null +++ b/arch/parisc/hpux/Makefile @@ -0,0 +1,16 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +all: hpux.o +O_TARGET = hpux.o +O_OBJS = entry_hpux.o gate.o wrappers.o fs.o ioctl.o sys_hpux.o + +.o.S: $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $*.S -o $*.o + +include $(TOPDIR)/Rules.make diff --git a/arch/parisc/hpux/entry_hpux.S b/arch/parisc/hpux/entry_hpux.S new file mode 100644 index 000000000..165aeb6af --- /dev/null +++ b/arch/parisc/hpux/entry_hpux.S @@ -0,0 +1,537 @@ +/* ----------------------------------------------------------------------------- + * + * Native PARISC/Linux Project (http://www.puffingroup.com/parisc) + * + * modified by Matthew Wilcox <willy@bofh.ai> 1999-07-26 + */ + + +#define ASSEMBLY + +#include <linux/sys.h> +#include <linux/linkage.h> +#include <asm/unistd.h> + + + .text + +#define ENTRY_NAME(_name_) .word _name_ + + .align 4 + .export hpux_call_table +hpux_call_table: + ENTRY_NAME(sys_ni_syscall) /* 0 */ + ENTRY_NAME(sys_exit) + ENTRY_NAME(hpux_fork_wrapper) + ENTRY_NAME(sys_read) + ENTRY_NAME(sys_write) + ENTRY_NAME(sys_open) /* 5 */ + ENTRY_NAME(sys_close) + ENTRY_NAME(hpux_wait) + ENTRY_NAME(sys_creat) + ENTRY_NAME(sys_link) + ENTRY_NAME(sys_unlink) /* 10 */ + ENTRY_NAME(hpux_execv_wrapper) + ENTRY_NAME(sys_chdir) + ENTRY_NAME(sys_time) + ENTRY_NAME(sys_mknod) + ENTRY_NAME(sys_chmod) /* 15 */ + ENTRY_NAME(sys_chown) + ENTRY_NAME(hpux_brk) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_lseek) + ENTRY_NAME(sys_getpid) /* 20 */ + ENTRY_NAME(hpux_mount) + ENTRY_NAME(sys_oldumount) + ENTRY_NAME(sys_setuid) + ENTRY_NAME(sys_getuid) + ENTRY_NAME(sys_stime) /* 25 */ + ENTRY_NAME(hpux_ptrace) + ENTRY_NAME(sys_alarm) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_pause) + ENTRY_NAME(sys_utime) /* 30 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_access) + ENTRY_NAME(hpux_nice) + ENTRY_NAME(sys_ni_syscall) /* 35 */ + ENTRY_NAME(sys_sync) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_newstat) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_newlstat) /* 40 */ + ENTRY_NAME(sys_dup) + ENTRY_NAME(hpux_pipe_wrapper) + ENTRY_NAME(sys_times) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 45 */ + ENTRY_NAME(sys_setgid) + ENTRY_NAME(sys_getgid) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 50 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_ioctl) + ENTRY_NAME(sys_ni_syscall) /* 55 */ + ENTRY_NAME(sys_symlink) + ENTRY_NAME(hpux_utssys) + ENTRY_NAME(sys_readlink) + ENTRY_NAME(hpux_execve_wrapper) + ENTRY_NAME(sys_umask) /* 60 */ + ENTRY_NAME(sys_chroot) + ENTRY_NAME(sys_fcntl) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 65 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_sbrk) + ENTRY_NAME(sys_ni_syscall) /* 70 */ + ENTRY_NAME(sys_mmap) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 75 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 80 */ + ENTRY_NAME(sys_getpgid) + ENTRY_NAME(sys_setpgid) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 85 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_dup2) /* 90 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_newfstat) + ENTRY_NAME(sys_select) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 95 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 100 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 105 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 110 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 115 */ + ENTRY_NAME(sys_gettimeofday) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 120 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_fchown) + ENTRY_NAME(sys_fchmod) + ENTRY_NAME(sys_ni_syscall) /* 125 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_rename) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 130 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_sysconf) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 135 */ + ENTRY_NAME(sys_mkdir) + ENTRY_NAME(sys_rmdir) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 140 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 145 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 150 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 155 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 160 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 165 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 170 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 175 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 180 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 185 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 190 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_getdomainname) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 195 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_waitpid) /* 200 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 205 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 210 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 215 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 220 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 225 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 230 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 235 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 240 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 245 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 250 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 255 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 260 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 265 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 270 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_fchdir) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_accept) /* 275 */ + ENTRY_NAME(sys_bind) + ENTRY_NAME(sys_connect) + ENTRY_NAME(sys_getpeername) + ENTRY_NAME(sys_getsockname) + ENTRY_NAME(sys_getsockopt) /* 280 */ + ENTRY_NAME(sys_listen) + ENTRY_NAME(sys_recv) + ENTRY_NAME(sys_recvfrom) + ENTRY_NAME(sys_recvmsg) + ENTRY_NAME(sys_send) /* 285 */ + ENTRY_NAME(sys_sendmsg) + ENTRY_NAME(sys_sendto) + ENTRY_NAME(sys_setsockopt) + ENTRY_NAME(sys_shutdown) + ENTRY_NAME(sys_socket) /* 290 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 295 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 300 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 305 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 310 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 315 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 320 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 325 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 330 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_lchown) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 335 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 340 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 345 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 350 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_nanosleep) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 355 */ + ENTRY_NAME(hpux_getdents) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 360 */ + ENTRY_NAME(hpux_fstat64) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 365 */ + ENTRY_NAME(hpux_lstat64) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_stat64) + ENTRY_NAME(sys_ni_syscall) /* 370 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 375 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 380 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 385 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 390 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 395 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 400 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 405 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 410 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 415 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 420 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 425 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 430 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 435 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 440 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 445 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 450 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 455 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 460 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 465 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 470 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 475 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 480 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 485 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 490 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 495 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 500 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 505 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) /* 510 */ + ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_ni_syscall) +.end + diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c new file mode 100644 index 000000000..4957a05f8 --- /dev/null +++ b/arch/parisc/hpux/fs.c @@ -0,0 +1,250 @@ +/* + * linux/arch/parisc/kernel/sys_hpux.c + * + * implements HPUX syscalls. + */ + +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/file.h> +#include <linux/smp_lock.h> +#include <linux/slab.h> +#include <asm/errno.h> +#include <asm/uaccess.h> + +int hpux_execve(struct pt_regs *regs) +{ + int error; + char *filename; + + filename = getname((char *) regs->gr[26]); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + + error = do_execve(filename, (char **) regs->gr[25], + (char **)regs->gr[24], regs); + + if (error == 0) + current->ptrace &= ~PT_DTRACE; + putname(filename); + +out: + return error; +} + +struct hpux_dirent { + long d_off_pad; /* we only have a 32-bit off_t */ + long d_off; + ino_t d_ino; + short d_reclen; + short d_namlen; + char d_name[1]; +}; + +struct getdents_callback { + struct hpux_dirent *current_dir; + struct hpux_dirent *previous; + int count; + int error; +}; + +#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) +#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1)) + +static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino) +{ + struct hpux_dirent * dirent; + struct getdents_callback * buf = (struct getdents_callback *) __buf; + int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); + + buf->error = -EINVAL; /* only used if we fail.. */ + if (reclen > buf->count) + return -EINVAL; + dirent = buf->previous; + if (dirent) + put_user(offset, &dirent->d_off); + dirent = buf->current_dir; + buf->previous = dirent; + put_user(ino, &dirent->d_ino); + put_user(reclen, &dirent->d_reclen); + put_user(namlen, &dirent->d_namlen); + copy_to_user(dirent->d_name, name, namlen); + put_user(0, dirent->d_name + namlen); + ((char *) dirent) += reclen; + buf->current_dir = dirent; + buf->count -= reclen; + return 0; +} + +#undef NAME_OFFSET +#undef ROUND_UP + +int hpux_getdents(unsigned int fd, struct hpux_dirent *dirent, unsigned int count) +{ + struct file * file; + struct dentry * dentry; + struct inode * inode; + struct hpux_dirent * lastdirent; + struct getdents_callback buf; + int error; + + lock_kernel(); + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + + dentry = file->f_dentry; + if (!dentry) + goto out_putf; + + inode = dentry->d_inode; + if (!inode) + goto out_putf; + + buf.current_dir = dirent; + buf.previous = NULL; + buf.count = count; + buf.error = 0; + + error = -ENOTDIR; + if (!file->f_op || !file->f_op->readdir) + goto out_putf; + + /* + * Get the inode's semaphore to prevent changes + * to the directory while we read it. + */ + down(&inode->i_sem); + error = file->f_op->readdir(file, &buf, filldir); + up(&inode->i_sem); + if (error < 0) + goto out_putf; + error = buf.error; + lastdirent = buf.previous; + if (lastdirent) { + put_user(file->f_pos, &lastdirent->d_off); + error = count - buf.count; + } + +out_putf: + fput(file); +out: + unlock_kernel(); + return error; +} + +int hpux_mount(const char *fs, const char *path, int mflag, + const char *fstype, const char *dataptr, int datalen) +{ + return -ENOSYS; +} + +static int cp_hpux_stat(struct inode * inode, struct hpux_stat64 * statbuf) +{ + struct hpux_stat64 tmp; + unsigned int blocks, indirect; + + memset(&tmp, 0, sizeof(tmp)); + tmp.st_dev = kdev_t_to_nr(inode->i_dev); + tmp.st_ino = inode->i_ino; + tmp.st_mode = inode->i_mode; + tmp.st_nlink = inode->i_nlink; + tmp.st_uid = inode->i_uid; + tmp.st_gid = inode->i_gid; + tmp.st_rdev = kdev_t_to_nr(inode->i_rdev); + tmp.st_size = inode->i_size; + tmp.st_atime = inode->i_atime; + tmp.st_mtime = inode->i_mtime; + tmp.st_ctime = inode->i_ctime; + +#define D_B 7 +#define I_B (BLOCK_SIZE / sizeof(unsigned short)) + + if (!inode->i_blksize) { + blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE; + if (blocks > D_B) { + indirect = (blocks - D_B + I_B - 1) / I_B; + blocks += indirect; + if (indirect > 1) { + indirect = (indirect - 1 + I_B - 1) / I_B; + blocks += indirect; + if (indirect > 1) + blocks++; + } + } + tmp.st_blocks = (BLOCK_SIZE / 512) * blocks; + tmp.st_blksize = BLOCK_SIZE; + } else { + tmp.st_blocks = inode->i_blocks; + tmp.st_blksize = inode->i_blksize; + } + return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; +} + +/* + * Revalidate the inode. This is required for proper NFS attribute caching. + * Blatently copied wholesale from fs/stat.c + */ +static __inline__ int +do_revalidate(struct dentry *dentry) +{ + struct inode * inode = dentry->d_inode; + if (inode->i_op && inode->i_op->revalidate) + return inode->i_op->revalidate(dentry); + return 0; +} + +long hpux_stat64(const char *path, struct hpux_stat64 *buf) +{ + struct nameidata nd; + int error; + + lock_kernel(); + error = user_path_walk(path, &nd); + if (!error) { + error = do_revalidate(nd.dentry); + if (!error) + error = cp_hpux_stat(nd.dentry->d_inode, buf); + path_release(&nd); + } + unlock_kernel(); + return error; +} + +long hpux_fstat64(unsigned int fd, struct hpux_stat64 *statbuf) +{ + struct file * f; + int err = -EBADF; + + lock_kernel(); + f = fget(fd); + if (f) { + struct dentry * dentry = f->f_dentry; + + err = do_revalidate(dentry); + if (!err) + err = cp_hpux_stat(dentry->d_inode, statbuf); + fput(f); + } + unlock_kernel(); + return err; +} + +long hpux_lstat64(char *filename, struct hpux_stat64 *statbuf) +{ + struct nameidata nd; + int error; + + lock_kernel(); + error = user_path_walk_link(filename, &nd); + if (!error) { + error = do_revalidate(nd.dentry); + if (!error) + error = cp_hpux_stat(nd.dentry->d_inode, statbuf); + path_release(&nd); + } + unlock_kernel(); + return error; +} diff --git a/arch/parisc/hpux/gate.S b/arch/parisc/hpux/gate.S new file mode 100644 index 000000000..0b8976386 --- /dev/null +++ b/arch/parisc/hpux/gate.S @@ -0,0 +1,72 @@ +/* ------------------------------------------------------------------------------ + * + * Linux/PARISC Project (http://www.thepuffingroup.com/parisc) + * + * System call entry code Copyright (c) Matthew Wilcox 1999 <willy@bofh.ai> + * Licensed under the GNU GPL. + * thanks to Philipp Rumpf, Mike Shaver and various others + * sorry about the wall, puffin.. + */ + +#define __ASSEMBLY__ +#include <asm/assembly.h> +#include <asm/offset.h> +#include <asm/unistd.h> +#include <asm/errno.h> + + .text + + .import hpux_call_table + .import hpux_syscall_exit,code + .export hpux_gateway_page + + .align 4096 +hpux_gateway_page: + nop + mfsp %sr7,%r1 ;! we must set sr3 to the space + mtsp %r1,%sr3 ;! of the user before the gate +#ifdef __LP64__ +#warning NEEDS WORK for 64-bit +#endif + ldw -64(%r30), %r28 ;! 8th argument + ldw -60(%r30), %r19 ;! 7th argument + ldw -56(%r30), %r20 ;! 6th argument + ldw -52(%r30), %r21 ;! 5th argument + gate .+8, %r0 ;! become privileged + mtsp %r0,%sr4 ;! get kernel space into sr4 + mtsp %r0,%sr5 ;! get kernel space into sr5 + mtsp %r0,%sr6 ;! get kernel space into sr6 + mtsp %r0,%sr7 ;! get kernel space into sr7 + mfctl %cr30,%r1 ;! get the kernel task ptr + mtctl %r0,%cr30 ;! zero it (flag) + STREG %r30,TASK_PT_GR30(%r1) ;! preserve userspace sp + STREG %r2,TASK_PT_GR2(%r1) ;! preserve rp + STREG %r27,TASK_PT_GR27(%r1) ;! user dp + STREG %r31,TASK_PT_GR31(%r1) ;! preserve syscall return ptr + + loadgp ;! setup kernel dp + + ldo TASK_SZ_ALGN+64(%r1),%r30 ;! set up kernel stack + + stw %r21, -52(%r30) ;! 5th argument + stw %r20, -56(%r30) ;! 6th argument + stw %r19, -60(%r30) ;! 7th argument + stw %r28, -64(%r30) ;! 8th argument + + ldil L%hpux_call_table, %r21 + ldo R%hpux_call_table(%r21), %r21 + comiclr,>>= __NR_HPUX_syscalls, %r22, %r0 + b,n syscall_nosys + ldwx,s %r22(%r21), %r21 + ldil L%hpux_syscall_exit,%r2 + be 0(%sr7,%r21) + ldo R%hpux_syscall_exit(%r2),%r2 + +syscall_nosys: + ldil L%hpux_syscall_exit,%r1 + be R%hpux_syscall_exit(%sr7,%r1) + ldo -ENOSYS(%r0),%r28 + + .align 4096 + .export end_hpux_gateway_page +end_hpux_gateway_page: diff --git a/arch/parisc/hpux/ioctl.c b/arch/parisc/hpux/ioctl.c new file mode 100644 index 000000000..9087123e1 --- /dev/null +++ b/arch/parisc/hpux/ioctl.c @@ -0,0 +1,63 @@ +/* + * linux/arch/parisc/hpux/ioctl.c + * + * implements some necessary HPUX ioctls. + */ + +/* + * Supported ioctls: + * TCGETA + * TCSETA + * TCSETAW + * TCSETAF + * TCSBRK + * TCXONC + * TCFLSH + * TIOCGWINSZ + * TIOCSWINSZ + * TIOCGPGRP + * TIOCSPGRP + */ + +#include <linux/smp_lock.h> +#include <asm/errno.h> +#include <asm/ioctl.h> +#include <asm/termios.h> +#include <asm/uaccess.h> + +int sys_ioctl(unsigned int, unsigned int, unsigned long); + +static int hpux_ioctl_t(int fd, unsigned long cmd, unsigned long arg) +{ + int result = -EOPNOTSUPP; + int nr = _IOC_NR(cmd); + switch (nr) { + case 106: + result = sys_ioctl(fd, TIOCSWINSZ, arg); + break; + case 107: + result = sys_ioctl(fd, TIOCGWINSZ, arg); + break; + } + return result; +} + +int hpux_ioctl(int fd, unsigned long cmd, unsigned long arg) +{ + int result = -EOPNOTSUPP; + int type = _IOC_TYPE(cmd); + switch (type) { + case 'T': + /* Our structures are now compatible with HPUX's */ + result = sys_ioctl(fd, cmd, arg); + break; + case 't': + result = hpux_ioctl_t(fd, cmd, arg); + break; + default: + /* If my mother ever sees this, I hope she disowns me. + * Take this out after NYLWE. */ + result = sys_ioctl(fd, cmd, arg); + } + return result; +} diff --git a/arch/parisc/hpux/sys_hpux.c b/arch/parisc/hpux/sys_hpux.c new file mode 100644 index 000000000..e0c832e76 --- /dev/null +++ b/arch/parisc/hpux/sys_hpux.c @@ -0,0 +1,334 @@ +/* + * linux/arch/parisc/kernel/sys_hpux.c + * + * implements HPUX syscalls. + */ + +#include <linux/sched.h> +#include <linux/smp_lock.h> +#include <linux/utsname.h> +#include <asm/errno.h> +#include <asm/uaccess.h> + +unsigned long sys_brk(unsigned long addr); + +unsigned long hpux_brk(unsigned long addr) +{ + /* Sigh. Looks like HP/UX libc relies on kernel bugs. */ + return sys_brk(addr + PAGE_SIZE); +} + +int hpux_sbrk(void) +{ + return -ENOSYS; +} + +/* Random other syscalls */ + +int hpux_nice(int priority_change) +{ + return -ENOSYS; +} + +int hpux_ptrace(void) +{ + return -ENOSYS; +} + +int hpux_wait(int *stat_loc) +{ + extern int sys_waitpid(int, int *, int); + return sys_waitpid(-1, stat_loc, 0); +} + +#define _SC_CPU_VERSION 10001 +#define _SC_OPEN_MAX 4 +#define CPU_PA_RISC1_1 0x210 + +int hpux_sysconf(int which) +{ + switch (which) { + case _SC_CPU_VERSION: + return CPU_PA_RISC1_1; + case _SC_OPEN_MAX: + return INT_MAX; + default: + return -EINVAL; + } +} + +/*****************************************************************************/ + +#define HPUX_UTSLEN 9 +#define HPUX_SNLEN 15 + +struct hpux_utsname { + char sysname[HPUX_UTSLEN]; + char nodename[HPUX_UTSLEN]; + char release[HPUX_UTSLEN]; + char version[HPUX_UTSLEN]; + char machine[HPUX_UTSLEN]; + char idnumber[HPUX_SNLEN]; +} ; + +struct hpux_ustat { + int32_t f_tfree; /* total free (daddr_t) */ + u_int32_t f_tinode; /* total inodes free (ino_t) */ + char f_fname[6]; /* filsys name */ + char f_fpack[6]; /* filsys pack name */ + u_int32_t f_blksize; /* filsys block size (int) */ +}; + +/* + * HPUX's utssys() call. It's a collection of miscellaneous functions, + * alas, so there's no nice way of splitting them up. + */ + +/* This function is called from hpux_utssys(); HP-UX implements + * ustat() as an option to utssys(). + * + * Now, struct ustat on HP-UX is exactly the same as on Linux, except + * that it contains one addition field on the end, int32_t f_blksize. + * So, we could have written this function to just call the Linux + * sys_ustat(), (defined in linux/fs/super.c), and then just + * added this additional field to the user's structure. But I figure + * if we're gonna be digging through filesystem structures to get + * this, we might as well just do the whole enchilada all in one go. + * + * So, most of this function is almost identical to sys_ustat(). + * I have placed comments at the few lines changed or added, to + * aid in porting forward if and when sys_ustat() is changed from + * its form in kernel 2.2.5. + */ +static int hpux_ustat(dev_t dev, struct hpux_ustat *ubuf) +{ + struct super_block *s; + struct hpux_ustat tmp; /* Changed to hpux_ustat */ + struct statfs sbuf; + int err = -EINVAL; + + lock_kernel(); + s = get_super(to_kdev_t(dev)); + if (s == NULL) + goto out; + err = vfs_statfs(s, &sbuf); + if (err) + goto out; + + memset(&tmp,0,sizeof(struct hpux_ustat)); /* Changed to hpux_ustat */ + + tmp.f_tfree = (int32_t)sbuf.f_bfree; + tmp.f_tinode = (u_int32_t)sbuf.f_ffree; + tmp.f_blksize = (u_int32_t)sbuf.f_bsize; /* Added this line */ + + /* Changed to hpux_ustat: */ + err = copy_to_user(ubuf,&tmp,sizeof(struct hpux_ustat)) ? -EFAULT : 0; +out: + unlock_kernel(); + return err; +} + + +/* This function is called from hpux_utssys(); HP-UX implements + * uname() as an option to utssys(). + * + * The form of this function is pretty much copied from sys_olduname(), + * defined in linux/arch/i386/kernel/sys_i386.c. + */ +/* TODO: Are these put_user calls OK? Should they pass an int? + * (I copied it from sys_i386.c like this.) + */ +static int hpux_uname(struct hpux_utsname *name) +{ + int error; + + if (!name) + return -EFAULT; + if (!access_ok(VERIFY_WRITE,name,sizeof(struct hpux_utsname))) + return -EFAULT; + + down_read(&uts_sem); + + error = __copy_to_user(&name->sysname,&system_utsname.sysname,HPUX_UTSLEN-1); + error |= __put_user(0,name->sysname+HPUX_UTSLEN-1); + error |= __copy_to_user(&name->nodename,&system_utsname.nodename,HPUX_UTSLEN-1); + error |= __put_user(0,name->nodename+HPUX_UTSLEN-1); + error |= __copy_to_user(&name->release,&system_utsname.release,HPUX_UTSLEN-1); + error |= __put_user(0,name->release+HPUX_UTSLEN-1); + error |= __copy_to_user(&name->version,&system_utsname.version,HPUX_UTSLEN-1); + error |= __put_user(0,name->version+HPUX_UTSLEN-1); + error |= __copy_to_user(&name->machine,&system_utsname.machine,HPUX_UTSLEN-1); + error |= __put_user(0,name->machine+HPUX_UTSLEN-1); + + up_read(&uts_sem); + + /* HP-UX utsname has no domainname field. */ + + /* TODO: Implement idnumber!!! */ +#if 0 + error |= __put_user(0,name->idnumber); + error |= __put_user(0,name->idnumber+HPUX_SNLEN-1); +#endif + + error = error ? -EFAULT : 0; + + return error; +} + +int sys_sethostname(char *, int); +int sys_gethostname(char *, int); + +/* Note: HP-UX just uses the old suser() function to check perms + * in this system call. We'll use capable(CAP_SYS_ADMIN). + */ +int hpux_utssys(char *ubuf, int n, int type) +{ + int len; + int error; + switch( type ) { + case 0: + /* uname(): */ + return( hpux_uname( (struct hpux_utsname *)ubuf ) ); + break ; + case 1: + /* Obsolete (used to be umask().) */ + return -EFAULT ; + break ; + case 2: + /* ustat(): */ + return( hpux_ustat((dev_t)n, (struct hpux_ustat *)ubuf) ); + break ; + case 3: + /* setuname(): + * + * On linux (unlike HP-UX), utsname.nodename + * is the same as the hostname. + * + * sys_sethostname() is defined in linux/kernel/sys.c. + */ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + /* Unlike Linux, HP-UX returns an error if n==0: */ + if ( n <= 0 ) + return -EINVAL ; + /* Unlike Linux, HP-UX truncates it if n is too big: */ + len = (n <= __NEW_UTS_LEN) ? n : __NEW_UTS_LEN ; + return( sys_sethostname(ubuf, len) ); + break ; + case 4: + /* sethostname(): + * + * sys_sethostname() is defined in linux/kernel/sys.c. + */ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + /* Unlike Linux, HP-UX returns an error if n==0: */ + if ( n <= 0 ) + return -EINVAL ; + /* Unlike Linux, HP-UX truncates it if n is too big: */ + len = (n <= __NEW_UTS_LEN) ? n : __NEW_UTS_LEN ; + return( sys_sethostname(ubuf, len) ); + break ; + case 5: + /* gethostname(): + * + * sys_gethostname() is defined in linux/kernel/sys.c. + */ + /* Unlike Linux, HP-UX returns an error if n==0: */ + if ( n <= 0 ) + return -EINVAL ; + return( sys_gethostname(ubuf, n) ); + break ; + case 6: + /* Supposedly called from setuname() in libc. + * TODO: When and why is this called? + * Is it ever even called? + * + * This code should look a lot like sys_sethostname(), + * defined in linux/kernel/sys.c. If that gets updated, + * update this code similarly. + */ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + /* Unlike Linux, HP-UX returns an error if n==0: */ + if ( n <= 0 ) + return -EINVAL ; + /* Unlike Linux, HP-UX truncates it if n is too big: */ + len = (n <= __NEW_UTS_LEN) ? n : __NEW_UTS_LEN ; + /**/ + /* TODO: print a warning about using this? */ + down_write(&uts_sem); + error = -EFAULT; + if (!copy_from_user(system_utsname.sysname, ubuf, len)) { + system_utsname.sysname[len] = 0; + error = 0; + } + up_write(&uts_sem); + return error; + break ; + case 7: + /* Sets utsname.release, if you're allowed. + * Undocumented. Used by swinstall to change the + * OS version, during OS updates. Yuck!!! + * + * This code should look a lot like sys_sethostname() + * in linux/kernel/sys.c. If that gets updated, update + * this code similarly. + */ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + /* Unlike Linux, HP-UX returns an error if n==0: */ + if ( n <= 0 ) + return -EINVAL ; + /* Unlike Linux, HP-UX truncates it if n is too big: */ + len = (n <= __NEW_UTS_LEN) ? n : __NEW_UTS_LEN ; + /**/ + /* TODO: print a warning about this? */ + down_write(&uts_sem); + error = -EFAULT; + if (!copy_from_user(system_utsname.release, ubuf, len)) { + system_utsname.release[len] = 0; + error = 0; + } + up_write(&uts_sem); + return error; + break ; + default: + /* This system call returns -EFAULT if given an unknown type. + * Why not -EINVAL? I don't know, it's just not what they did. + */ + return -EFAULT ; + } +} + +int hpux_getdomainname(char *name, int len) +{ + int nlen; + int err = -EFAULT; + + down_read(&uts_sem); + + nlen = strlen(system_utsname.domainname) + 1; + + if (nlen < len) + len = nlen; + if(len > __NEW_UTS_LEN) + goto done; + if(copy_to_user(name, system_utsname.domainname, len)) + goto done; + err = 0; +done: + up_read(&uts_sem); + return err; + +} + +int hpux_pipe(int *kstack_fildes) +{ + int error; + + lock_kernel(); + error = do_pipe(kstack_fildes); + unlock_kernel(); + return error; +} diff --git a/arch/parisc/hpux/wrappers.S b/arch/parisc/hpux/wrappers.S new file mode 100644 index 000000000..c150783d9 --- /dev/null +++ b/arch/parisc/hpux/wrappers.S @@ -0,0 +1,244 @@ +/*------------------------------------------------------------------------------ + * Native PARISC/Linux Project (http://www.puffingroup.com/parisc) + * + * HP-UX System Call Wrapper routines and System Call Return Path + * + * Copyright (C) 2000 Hewlett-Packard (John Marvin) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef __LP64__ +#warning Must be changed for PA64 +#endif + +#include <asm/offset.h> + + .level 1.1 + .text + +#define __ASSEMBLY__ +#include <asm/assembly.h> +#include <asm/signal.h> + + /* These should probably go in a header file somewhere. + * They are duplicated in kernel/wrappers.S + * Possibly we should consider consolidating these + * register save/restore macros. + */ + .macro reg_save regs +#ifdef __LP64__ +#warning NEEDS WORK for 64-bit +#endif + stw %r3, PT_GR3(\regs) + stw %r4, PT_GR4(\regs) + stw %r5, PT_GR5(\regs) + stw %r6, PT_GR6(\regs) + stw %r7, PT_GR7(\regs) + stw %r8, PT_GR8(\regs) + stw %r9, PT_GR9(\regs) + stw %r10,PT_GR10(\regs) + stw %r11,PT_GR11(\regs) + stw %r12,PT_GR12(\regs) + stw %r13,PT_GR13(\regs) + stw %r14,PT_GR14(\regs) + stw %r15,PT_GR15(\regs) + stw %r16,PT_GR16(\regs) + stw %r17,PT_GR17(\regs) + stw %r18,PT_GR18(\regs) + .endm + + .macro reg_restore regs + ldw PT_GR3(\regs), %r3 + ldw PT_GR4(\regs), %r4 + ldw PT_GR5(\regs), %r5 + ldw PT_GR6(\regs), %r6 + ldw PT_GR7(\regs), %r7 + ldw PT_GR8(\regs), %r8 + ldw PT_GR9(\regs), %r9 + ldw PT_GR10(\regs),%r10 + ldw PT_GR11(\regs),%r11 + ldw PT_GR12(\regs),%r12 + ldw PT_GR13(\regs),%r13 + ldw PT_GR14(\regs),%r14 + ldw PT_GR15(\regs),%r15 + ldw PT_GR16(\regs),%r16 + ldw PT_GR17(\regs),%r17 + ldw PT_GR18(\regs),%r18 + .endm + + + .export hpux_fork_wrapper + .import sys_fork + +hpux_fork_wrapper: + ldo TASK_REGS-TASK_SZ_ALGN-64(%r30),%r1 ;! get pt regs + ;! pointer in task + reg_save %r1 + + stw %r2,-20(%r30) + ldo 64(%r30),%r30 + stw %r2,PT_GR19(%r1) ;! save for child + stw %r30,PT_GR20(%r1) ;! save for child + ldil L%child_return,%r3 + ldo R%child_return(%r3),%r3 + stw %r3,PT_GR21(%r1) ;! save for child + + ldw TASK_PT_GR30(%r1),%r25 + copy %r1,%r24 + bl sys_clone,%r2 + ldi SIGCHLD,%r26 + + ldw -84(%r30),%r2 +fork_return: + ldo -64(%r30),%r30 + ldo TASK_REGS-TASK_SZ_ALGN-64(%r30),%r1 ;! get pt regs + + reg_restore %r1 + + /* + * HP-UX wants pid (child gets parent pid, parent gets child pid) + * in r28 and a flag in r29 (r29 == 1 for child, 0 for parent). + * Linux fork returns 0 for child, pid for parent. Since HP-UX + * libc stub throws away parent pid and returns 0 for child, + * we'll just return 0 for parent pid now. Only applications + * that jump directly to the gateway page (not supported) will + * know the difference. We can fix this later if necessary. + */ + + ldo -1024(%r0),%r1 + comb,>>=,n %r28,%r1,fork_exit /* just let the syscall exit handle it */ + or,= %r28,%r0,%r0 + or,tr %r0,%r0,%r29 /* r28 <> 0, we are parent, set r29 to 0 */ + ldo 1(%r0),%r29 /* r28 == 0, we are child, set r29 to 1 */ + +fork_exit: + bv %r0(%r2) + nop + + /* Set the return value for the child */ + +child_return: + ldw TASK_PT_GR19-TASK_SZ_ALGN-128(%r30),%r2 + b fork_return + copy %r0,%r28 + + .export hpux_execve_wrapper + .export hpux_execv_wrapper + .import hpux_execve + +hpux_execv_wrapper: + copy %r0,%r24 /* NULL environment */ + +hpux_execve_wrapper: + + ldo TASK_REGS-TASK_SZ_ALGN-64(%r30),%r1 ;! get pt regs + + /* + * Do we need to save/restore r3-r18 here? + * I don't think so. why would new thread need old + * threads registers? + */ + + /* Store arg0, arg1 and arg2 so that hpux_execve will find them */ + + stw %r26,PT_GR26(%r1) + stw %r25,PT_GR25(%r1) + stw %r24,PT_GR24(%r1) + + stw %r2,-20(%r30) + ldo 64(%r30),%r30 + bl hpux_execve,%r2 + copy %r1,%arg0 + + ldo -64(%r30),%r30 + ldw -20(%r30),%r2 + + /* If exec succeeded we need to load the args */ + + ldo -1024(%r0),%r1 + comb,>>= %r28,%r1,exec_error + copy %r2,%r19 + ldo -TASK_SZ_ALGN-64(%r30),%r1 ;! get task ptr + ldw TASK_PT_GR26(%r1),%r26 + ldw TASK_PT_GR25(%r1),%r25 + ldw TASK_PT_GR24(%r1),%r24 + ldw TASK_PT_GR23(%r1),%r23 + copy %r0,%r2 /* Flag to syscall_exit not to clear args */ + +exec_error: + bv %r0(%r19) + nop + + .export hpux_pipe_wrapper + .import hpux_pipe + + /* HP-UX expects pipefd's returned in r28 & r29 */ + +hpux_pipe_wrapper: + stw %r2,-20(%r30) + ldo 64(%r30),%r30 + bl hpux_pipe,%r2 + ldo -56(%r30),%r26 /* pass local array to hpux_pipe */ + + + ldo -1024(%r0),%r1 + comb,>>= %r28,%r1,pipe_exit /* let syscall exit handle it */ + ldw -84(%r30),%r2 + + /* if success, load fd's from stack array */ + + ldw -56(%r30),%r28 + ldw -52(%r30),%r29 + +pipe_exit: + bv %r0(%r2) + ldo -64(%r30),%r30 + + .export hpux_syscall_exit + .import syscall_exit + +hpux_syscall_exit: + + /* + * + * HP-UX call return conventions: + * + * if error: + * r22 = 1 + * r28 = errno value + * r29 = secondary return value + * else + * r22 = 0 + * r28 = return value + * r29 = secondary return value + * + * For now, we'll just check to see if r28 is < (unsigned long)-1024 + * (to handle addresses > 2 Gb) and if so set r22 to zero. If not, + * we'll complement r28 and set r22 to 1. Wrappers will be + * needed for syscalls that care about the secondary return value. + * The wrapper may also need a way of avoiding the following code, + * but we'll deal with that when it becomes necessary. + */ + + ldo -1024(%r0),%r1 + comb,<< %r28,%r1,no_error + copy %r0,%r22 + subi 0,%r28,%r28 + ldo 1(%r0),%r22 + +no_error: + b syscall_exit + nop diff --git a/arch/parisc/kernel/Makefile b/arch/parisc/kernel/Makefile new file mode 100644 index 000000000..03ce8e58b --- /dev/null +++ b/arch/parisc/kernel/Makefile @@ -0,0 +1,52 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +all: kernel.o init_task.o pdc_cons.o process.o head.o +O_TARGET = kernel.o +O_OBJS = + +# Object file lists. + +obj-y := +obj-m := +obj-n := +obj- := + +obj-y += cache.o setup.o traps.o time.o irq.o \ + syscall.o entry.o sys_parisc.o pdc.o ptrace.o hardware.o \ + inventory.o drivers.o semaphore.o pa7300lc.o pci-dma.o \ + signal.o hpmc.o \ + real1.o real2.o led.o parisc_ksyms.o + +export-objs := parisc_ksyms.o + + +obj-$(CONFIG_PCI) += pci.o +obj-$(CONFIG_VT) += keyboard.o +obj-$(CONFIG_PCI_LBA) += lba_pci.o +# I/O SAPIC is also on IA64 platforms. +# The two could be merged into a common source some day. +obj-$(CONFIG_IOSAPIC) += iosapic.o +obj-$(CONFIG_IOMMU_SBA) += sba_iommu.o +# Only use one of them: ccio-rm-dma is for PCX-W systems *only* +# obj-$(CONFIG_IOMMU_CCIO) += ccio-rm-dma.o +obj-$(CONFIG_IOMMU_CCIO) += ccio-dma.o + +.o.S: $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $*.S -o $*.o + +# Translate to Rules.make lists. + +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) +MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) +MIX_OBJS := $(sort $(filter $(export-objs), $(int-m))) + +include $(TOPDIR)/Rules.make diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c new file mode 100644 index 000000000..713a8b39a --- /dev/null +++ b/arch/parisc/kernel/cache.c @@ -0,0 +1,253 @@ +/* $Id: cache.c,v 1.4 2000/01/25 00:11:38 prumpf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1999 Helge Deller (07-13-1999) + * Copyright (C) 1999 SuSE GmbH Nuernberg + * Copyright (C) 2000 Philipp Rumpf (prumpf@tux.org) + * + * Cache and TLB management + * + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/mm.h> + +#include <asm/pdc.h> +#include <asm/cache.h> +#include <asm/system.h> +#include <asm/page.h> +#include <asm/pgalloc.h> + +struct pdc_cache_info cache_info; +#ifndef __LP64__ +static struct pdc_btlb_info btlb_info; +#endif + + +void __flush_page_to_ram(unsigned long address) +{ + __flush_dcache_range(address, PAGE_SIZE); + __flush_icache_range(address, PAGE_SIZE); +} + + + +void flush_data_cache(void) +{ + register unsigned long base = cache_info.dc_base; + register unsigned long count = cache_info.dc_count; + register unsigned long loop = cache_info.dc_loop; + register unsigned long stride = cache_info.dc_stride; + register unsigned long addr; + register long i, j; + + for(i=0,addr=base; i<count; i++,addr+=stride) + for(j=0; j<loop; j++) + fdce(addr); +} + +static inline void flush_data_tlb_space(void) +{ + unsigned long base = cache_info.dt_off_base; + unsigned long count = cache_info.dt_off_count; + unsigned long stride = cache_info.dt_off_stride; + unsigned long loop = cache_info.dt_loop; + + unsigned long addr; + long i,j; + + for(i=0,addr=base; i<count; i++,addr+=stride) + for(j=0; j<loop; j++) + pdtlbe(addr); +} + + + +void flush_data_tlb(void) +{ + unsigned long base = cache_info.dt_sp_base; + unsigned long count = cache_info.dt_sp_count; + unsigned long stride = cache_info.dt_sp_stride; + unsigned long space; + unsigned long old_sr1; + long i; + + old_sr1 = mfsp(1); + + for(i=0,space=base; i<count; i++, space+=stride) { + mtsp(space,1); + flush_data_tlb_space(); + } + + mtsp(old_sr1, 1); +} + +static inline void flush_instruction_tlb_space(void) +{ + unsigned long base = cache_info.it_off_base; + unsigned long count = cache_info.it_off_count; + unsigned long stride = cache_info.it_off_stride; + unsigned long loop = cache_info.it_loop; + + unsigned long addr; + long i,j; + + for(i=0,addr=base; i<count; i++,addr+=stride) + for(j=0; j<loop; j++) + pitlbe(addr); +} + +void flush_instruction_tlb(void) +{ + unsigned long base = cache_info.it_sp_base; + unsigned long count = cache_info.it_sp_count; + unsigned long stride = cache_info.it_sp_stride; + unsigned long space; + unsigned long old_sr1; + unsigned int i; + + old_sr1 = mfsp(1); + + for(i=0,space=base; i<count; i++, space+=stride) { + mtsp(space,1); + flush_instruction_tlb_space(); + } + + mtsp(old_sr1, 1); +} + + +void __flush_tlb_space(unsigned long space) +{ + unsigned long old_sr1; + + old_sr1 = mfsp(1); + mtsp(space, 1); + + flush_data_tlb_space(); + flush_instruction_tlb_space(); + + mtsp(old_sr1, 1); +} + + +void flush_instruction_cache(void) +{ + register unsigned long base = cache_info.ic_base; + register unsigned long count = cache_info.ic_count; + register unsigned long loop = cache_info.ic_loop; + register unsigned long stride = cache_info.ic_stride; + register unsigned long addr; + register long i, j; + unsigned long old_sr1; + + old_sr1 = mfsp(1); + mtsp(0,1); + + /* + * Note: fice instruction has 3 bit space field, so one must + * be specified (otherwise you are justing using whatever + * happens to be in sr0). + */ + + for(i=0,addr=base; i<count; i++,addr+=stride) + for(j=0; j<loop; j++) + fice(addr); + + mtsp(old_sr1, 1); +} + +/* not yet ... fdc() needs to be implemented in cache.h ! +void flush_datacache_range( unsigned int base, unsigned int end ) +{ + register long offset,offset_add; + offset_add = ( (1<<(cache_info.dc_conf.cc_block-1)) * + cache_info.dc_conf.cc_line ) << 4; + for (offset=base; offset<=end; offset+=offset_add) + fdc(space,offset); + fdc(space,end); +} +*/ + +/* flushes code and data-cache */ +void flush_all_caches(void) +{ + flush_instruction_cache(); + flush_data_cache(); + + flush_instruction_tlb(); + flush_data_tlb(); + + asm volatile("sync"); + asm volatile("syncdma"); + asm volatile("sync"); +} + +int get_cache_info(char *buffer) +{ + char *p = buffer; + + p += sprintf(p, "I-cache\t\t: %ld KB\n", + cache_info.ic_size/1024 ); + p += sprintf(p, "D-cache\t\t: %ld KB (%s)%s\n", + cache_info.dc_size/1024, + (cache_info.dc_conf.cc_wt ? "WT":"WB"), + (cache_info.dc_conf.cc_sh ? " - shared I/D":"") + ); + + p += sprintf(p, "ITLB entries\t: %ld\n" "DTLB entries\t: %ld%s\n", + cache_info.it_size, + cache_info.dt_size, + cache_info.dt_conf.tc_sh ? " - shared with ITLB":"" + ); + +#ifndef __LP64__ + /* BTLB - Block TLB */ + if (btlb_info.max_size==0) { + p += sprintf(p, "BTLB\t\t: not supported\n" ); + } else { + p += sprintf(p, + "BTLB fixed\t: max. %d pages, pagesize=%d (%dMB)\n" + "BTLB fix-entr.\t: %d instruction, %d data (%d combined)\n" + "BTLB var-entr.\t: %d instruction, %d data (%d combined)\n", + btlb_info.max_size, (int)4096, + btlb_info.max_size>>8, + btlb_info.fixed_range_info.num_i, + btlb_info.fixed_range_info.num_d, + btlb_info.fixed_range_info.num_comb, + btlb_info.variable_range_info.num_i, + btlb_info.variable_range_info.num_d, + btlb_info.variable_range_info.num_comb + ); + } +#endif + + return p - buffer; +} + + +void __init +cache_init(void) +{ + if(pdc_cache_info(&cache_info)<0) + panic("cache_init: pdc_cache_info failed"); + +#if 0 + printk("ic_size %lx dc_size %lx it_size %lx pdc_cache_info %d*long pdc_cache_cf %d\n", + cache_info.ic_size, + cache_info.dc_size, + cache_info.it_size, + sizeof (struct pdc_cache_info) / sizeof (long), + sizeof (struct pdc_cache_cf) + ); +#endif +#ifndef __LP64__ + if(pdc_btlb_info(&btlb_info)<0) { + memset(&btlb_info, 0, sizeof btlb_info); + } +#endif +} diff --git a/arch/parisc/kernel/ccio-dma.c b/arch/parisc/kernel/ccio-dma.c new file mode 100644 index 000000000..c8f72c813 --- /dev/null +++ b/arch/parisc/kernel/ccio-dma.c @@ -0,0 +1,1209 @@ +/* +** ccio-dma.c: +** DMA management routines for first generation cache-coherent machines. +** Program U2/Uturn in "Virtual Mode" and use the I/O MMU. +** +** (c) Copyright 2000 Grant Grundler +** (c) Copyright 2000 Ryan Bradetich +** (c) Copyright 2000 Hewlett-Packard Company +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** +** "Real Mode" operation refers to U2/Uturn chip operation. +** U2/Uturn were designed to perform coherency checks w/o using +** the I/O MMU - basically what x86 does. +** +** Philipp Rumpf has a "Real Mode" driver for PCX-W machines at: +** CVSROOT=:pserver:anonymous@198.186.203.37:/cvsroot/linux-parisc +** cvs -z3 co linux/arch/parisc/kernel/dma-rm.c +** +** I've rewritten his code to work under TPG's tree. See ccio-rm-dma.c. +** +** Drawbacks of using Real Mode are: +** o outbound DMA is slower - U2 won't prefetch data (GSC+ XQL signal). +** o Inbound DMA less efficient - U2 can't use DMA_FAST attribute. +** o Ability to do scatter/gather in HW is lost. +** o Doesn't work under PCX-U/U+ machines since they didn't follow +** the coherency design originally worked out. Only PCX-W does. +*/ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/spinlock.h> +#include <linux/malloc.h> +#include <linux/string.h> +#include <linux/pci.h> + +#include <asm/byteorder.h> +#include <asm/cache.h> /* for L1_CACHE_BYTES */ +#include <asm/uaccess.h> +#include <asm/pgalloc.h> +#include <asm/page.h> + +#include <asm/io.h> +#include <asm/gsc.h> /* for gsc_writeN()... */ + +/* +** Choose "ccio" since that's what HP-UX calls it. +** Make it easier for folks to migrate from one to the other :^) +*/ +#define MODULE_NAME "ccio" + +/* +#define DEBUG_CCIO_RES +#define DEBUG_CCIO_RUN +#define DEBUG_CCIO_INIT +#define DUMP_RESMAP +*/ + +#include <linux/proc_fs.h> +#include <asm/runway.h> /* for proc_runway_root */ + +#ifdef DEBUG_CCIO_INIT +#define DBG_INIT(x...) printk(x) +#else +#define DBG_INIT(x...) +#endif + +#ifdef DEBUG_CCIO_RUN +#define DBG_RUN(x...) printk(x) +#else +#define DBG_RUN(x...) +#endif + +#ifdef DEBUG_CCIO_RES +#define DBG_RES(x...) printk(x) +#else +#define DBG_RES(x...) +#endif + +#define CCIO_INLINE /* inline */ +#define WRITE_U32(value, addr) gsc_writel(value, (u32 *) (addr)) + +#define U2_IOA_RUNWAY 0x580 +#define U2_BC_GSC 0x501 +#define UTURN_IOA_RUNWAY 0x581 +#define UTURN_BC_GSC 0x502 +/* We *can't* support JAVA (T600). Venture there at your own risk. */ + +static void dump_resmap(void); + +static int ccio_driver_callback(struct hp_device *, struct pa_iodc_driver *); + +static struct pa_iodc_driver ccio_drivers_for[] = { + + {HPHW_IOA, U2_IOA_RUNWAY, 0x0, 0xb, 0, 0x10, + DRIVER_CHECK_HVERSION + + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + MODULE_NAME, "U2 I/O MMU", (void *) ccio_driver_callback}, + + {HPHW_IOA, UTURN_IOA_RUNWAY, 0x0, 0xb, 0, 0x10, + DRIVER_CHECK_HVERSION + + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + MODULE_NAME, "Uturn I/O MMU", (void *) ccio_driver_callback}, + +/* +** FIXME: The following claims the GSC bus port, not the IOA. +** And there are two busses below a single I/O TLB. +** +** These should go away once we have a real PA bus walk. +** Firmware wants to tell the PA bus walk code about the GSC ports +** since they are not "architected" PA I/O devices. Ie a PA bus walk +** wouldn't discover them. But the PA bus walk code could check +** the "fixed module table" to add such devices to an I/O Tree +** and proceed with the recursive, depth first bus walk. +*/ + {HPHW_BCPORT, U2_BC_GSC, 0x0, 0xc, 0, 0x10, + DRIVER_CHECK_HVERSION + + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + MODULE_NAME, "U2 GSC+ BC", (void *) ccio_driver_callback}, + + {HPHW_BCPORT, UTURN_BC_GSC, 0x0, 0xc, 0, 0x10, + DRIVER_CHECK_HVERSION + + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + MODULE_NAME, "Uturn GSC+ BC", (void *) ccio_driver_callback}, + + {0,0,0,0,0,0, + 0, + (char *) NULL, (char *) NULL, (void *) NULL } +}; + + +#define IS_U2(id) ( \ + (((id)->hw_type == HPHW_IOA) && ((id)->hversion == U2_IOA_RUNWAY)) || \ + (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == U2_BC_GSC)) \ +) + +#define IS_UTURN(id) ( \ + (((id)->hw_type == HPHW_IOA) && ((id)->hversion == UTURN_IOA_RUNWAY)) || \ + (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == UTURN_BC_GSC)) \ +) + + +#define IOA_NORMAL_MODE 0x00020080 /* IO_CONTROL to turn on CCIO */ +#define CMD_TLB_DIRECT_WRITE 35 /* IO_COMMAND for I/O TLB Writes */ +#define CMD_TLB_PURGE 33 /* IO_COMMAND to Purge I/O TLB entry */ + +struct ioa_registers { + /* Runway Supervisory Set */ + volatile int32_t unused1[12]; + volatile uint32_t io_command; /* Offset 12 */ + volatile uint32_t io_status; /* Offset 13 */ + volatile uint32_t io_control; /* Offset 14 */ + volatile int32_t unused2[1]; + + /* Runway Auxiliary Register Set */ + volatile uint32_t io_err_resp; /* Offset 0 */ + volatile uint32_t io_err_info; /* Offset 1 */ + volatile uint32_t io_err_req; /* Offset 2 */ + volatile uint32_t io_err_resp_hi; /* Offset 3 */ + volatile uint32_t io_tlb_entry_m; /* Offset 4 */ + volatile uint32_t io_tlb_entry_l; /* Offset 5 */ + volatile uint32_t unused3[1]; + volatile uint32_t io_pdir_base; /* Offset 7 */ + volatile uint32_t io_io_low_hv; /* Offset 8 */ + volatile uint32_t io_io_high_hv; /* Offset 9 */ + volatile uint32_t unused4[1]; + volatile uint32_t io_chain_id_mask; /* Offset 11 */ + volatile uint32_t unused5[2]; + volatile uint32_t io_io_low; /* Offset 14 */ + volatile uint32_t io_io_high; /* Offset 15 */ +}; + + +struct ccio_device { + struct ccio_device *next; /* list of LBA's in system */ + struct hp_device *iodc; /* data about dev from firmware */ + spinlock_t ccio_lock; + + struct ioa_registers *ccio_hpa; /* base address */ + u64 *pdir_base; /* physical base address */ + char *res_map; /* resource map, bit == pdir entry */ + + int res_hint; /* next available IOVP - circular search */ + int res_size; /* size of resource map in bytes */ + int chainid_shift; /* specify bit location of chain_id */ + int flags; /* state/functionality enabled */ +#ifdef DELAYED_RESOURCE_CNT + dma_addr_t res_delay[DELAYED_RESOURCE_CNT]; +#endif + + /* STUFF We don't need in performance path */ + int pdir_size; /* in bytes, determined by IOV Space size */ + int hw_rev; /* HW revision of chip */ +}; + + +/* Ratio of Host MEM to IOV Space size */ +static unsigned long ccio_mem_ratio = 4; +static struct ccio_device *ccio_list = NULL; + +static int ccio_proc_info(char *buffer, char **start, off_t offset, int length); +static unsigned long ccio_used_bytes = 0; +static unsigned long ccio_used_pages = 0; +static int ccio_cujo_bug = 0; + +static unsigned long ccio_alloc_size = 0; +static unsigned long ccio_free_size = 0; + +/************************************************************** +* +* I/O Pdir Resource Management +* +* Bits set in the resource map are in use. +* Each bit can represent a number of pages. +* LSbs represent lower addresses (IOVA's). +* +* This was was copied from sba_iommu.c. Don't try to unify +* the two resource managers unless a way to have different +* allocation policies is also adjusted. We'd like to avoid +* I/O TLB thrashing by having resource allocation policy +* match the I/O TLB replacement policy. +* +***************************************************************/ +#define PAGES_PER_RANGE 1 /* could increase this to 4 or 8 if needed */ +#define IOVP_SIZE PAGE_SIZE +#define IOVP_SHIFT PAGE_SHIFT +#define IOVP_MASK PAGE_MASK + +/* Convert from IOVP to IOVA and vice versa. */ +#define CCIO_IOVA(iovp,offset) ((iovp) | (offset)) +#define CCIO_IOVP(iova) ((iova) & ~(IOVP_SIZE-1) ) + +#define PDIR_INDEX(iovp) ((iovp)>>IOVP_SHIFT) +#define MKIOVP(pdir_idx) ((long)(pdir_idx) << IOVP_SHIFT) +#define MKIOVA(iovp,offset) (dma_addr_t)((long)iovp | (long)offset) + +/* CUJO20 KLUDGE start */ +#define CUJO_20_BITMASK 0x0ffff000 /* upper nibble is a don't care */ +#define CUJO_20_STEP 0x10000000 /* inc upper nibble */ +#define CUJO_20_BADPAGE1 0x01003000 /* pages that hpmc on raven U+ */ +#define CUJO_20_BADPAGE2 0x01607000 /* pages that hpmc on firehawk U+ */ +#define CUJO_20_BADHVERS 0x6821 /* low nibble 1 is cujo rev 2.0 */ +#define CUJO_RAVEN_LOC 0xf1000000UL /* cujo location on raven U+ */ +#define CUJO_FIREHAWK_LOC 0xf1604000UL /* cujo location on firehawk U+ */ +/* CUJO20 KLUDGE end */ + +/* +** Don't worry about the 150% average search length on a miss. +** If the search wraps around, and passes the res_hint, it will +** cause the kernel to panic anyhow. +*/ + +/* ioa->res_hint = idx + (size >> 3); \ */ + +#define CCIO_SEARCH_LOOP(ioa, idx, mask, size) \ + for(; res_ptr < res_end; ++res_ptr) \ + { \ + if(0 == ((*res_ptr) & mask)) { \ + *res_ptr |= mask; \ + idx = (int)((unsigned long)res_ptr - (unsigned long)ioa->res_map); \ + ioa->res_hint = 0;\ + goto resource_found; \ + } \ + } + +#define CCIO_FIND_FREE_MAPPING(ioa, idx, mask, size) { \ + u##size *res_ptr = (u##size *)&((ioa)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \ + u##size *res_end = (u##size *)&(ioa)->res_map[ioa->res_size]; \ + CCIO_SEARCH_LOOP(ioa, idx, mask, size); \ + res_ptr = (u##size *)&(ioa)->res_map[0]; \ + CCIO_SEARCH_LOOP(ioa, idx, mask, size); \ +} + +/* +** Find available bit in this ioa's resource map. +** Use a "circular" search: +** o Most IOVA's are "temporary" - avg search time should be small. +** o keep a history of what happened for debugging +** o KISS. +** +** Perf optimizations: +** o search for log2(size) bits at a time. +** o search for available resource bits using byte/word/whatever. +** o use different search for "large" (eg > 4 pages) or "very large" +** (eg > 16 pages) mappings. +*/ +static int +ccio_alloc_range(struct ccio_device *ioa, size_t size) +{ + int res_idx; + unsigned long mask, flags; + unsigned int pages_needed = size >> PAGE_SHIFT; + + ASSERT(pages_needed); + ASSERT((pages_needed * IOVP_SIZE) < DMA_CHUNK_SIZE); + ASSERT(pages_needed < (BITS_PER_LONG - IOVP_SHIFT)); + + mask = (unsigned long) -1L; + mask >>= BITS_PER_LONG - pages_needed; + + DBG_RES(__FUNCTION__ " size: %d pages_needed %d pages_mask 0x%08lx\n", + size, pages_needed, mask); + + spin_lock_irqsave(&ioa->ccio_lock, flags); + + /* + ** "seek and ye shall find"...praying never hurts either... + ** ggg sacrafices another 710 to the computer gods. + */ + + if(pages_needed <= 8) { + CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 8); + } else if(pages_needed <= 16) { + CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 16); + } else if(pages_needed <= 32) { + CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 32); +#ifdef __LP64__ + } else if(pages_needed <= 64) { + CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 64) +#endif + } else { + panic(__FILE__ ":" __FUNCTION__ "() Too many pages to map.\n"); + } + +#ifdef DUMP_RESMAP + dump_resmap(); +#endif + panic(__FILE__ ":" __FUNCTION__ "() I/O MMU is out of mapping resources\n"); + +resource_found: + + DBG_RES(__FUNCTION__ " res_idx %d mask 0x%08lx res_hint: %d\n", + res_idx, mask, ioa->res_hint); + + ccio_used_pages += pages_needed; + ccio_used_bytes += ((pages_needed >> 3) ? (pages_needed >> 3) : 1); + + spin_unlock_irqrestore(&ioa->ccio_lock, flags); + +#ifdef DUMP_RESMAP + dump_resmap(); +#endif + + /* + ** return the bit address (convert from byte to bit). + */ + return (res_idx << 3); +} + + +#define CCIO_FREE_MAPPINGS(ioa, idx, mask, size) \ + u##size *res_ptr = (u##size *)&((ioa)->res_map[idx + (((size >> 3) - 1) & ~((size >> 3) - 1))]); \ + ASSERT((*res_ptr & mask) == mask); \ + *res_ptr &= ~mask; + +/* +** clear bits in the ioa's resource map +*/ +static void +ccio_free_range(struct ccio_device *ioa, dma_addr_t iova, size_t size) +{ + unsigned long mask, flags; + unsigned long iovp = CCIO_IOVP(iova); + unsigned int res_idx = PDIR_INDEX(iovp)>>3; + unsigned int pages_mapped = (size >> IOVP_SHIFT) + !!(size & ~IOVP_MASK); + + ASSERT(pages_needed); + ASSERT((pages_needed * IOVP_SIZE) < DMA_CHUNK_SIZE); + ASSERT(pages_needed < (BITS_PER_LONG - IOVP_SHIFT)); + + mask = (unsigned long) -1L; + mask >>= BITS_PER_LONG - pages_mapped; + + DBG_RES(__FUNCTION__ " res_idx: %d size: %d pages_mapped %d mask 0x%08lx\n", + res_idx, size, pages_mapped, mask); + + spin_lock_irqsave(&ioa->ccio_lock, flags); + + if(pages_mapped <= 8) { + CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 8); + } else if(pages_mapped <= 16) { + CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 16); + } else if(pages_mapped <= 32) { + CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 32); +#ifdef __LP64__ + } else if(pages_mapped <= 64) { + CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 64); +#endif + } else { + panic(__FILE__ ":" __FUNCTION__ "() Too many pages to unmap.\n"); + } + + ccio_used_pages -= (pages_mapped ? pages_mapped : 1); + ccio_used_bytes -= ((pages_mapped >> 3) ? (pages_mapped >> 3) : 1); + + spin_unlock_irqrestore(&ioa->ccio_lock, flags); + +#ifdef DUMP_RESMAP + dump_resmap(); +#endif +} + + +/**************************************************************** +** +** CCIO dma_ops support routines +** +*****************************************************************/ + +typedef unsigned long space_t; +#define KERNEL_SPACE 0 + + +/* +** DMA "Page Type" and Hints +** o if SAFE_DMA isn't set, mapping is for FAST_DMA. SAFE_DMA should be +** set for subcacheline DMA transfers since we don't want to damage the +** other part of a cacheline. +** o SAFE_DMA must be set for "memory" allocated via pci_alloc_consistent(). +** This bit tells U2 to do R/M/W for partial cachelines. "Streaming" +** data can avoid this if the mapping covers full cache lines. +** o STOP_MOST is needed for atomicity across cachelines. +** Apperently only "some EISA devices" need this. +** Using CONFIG_ISA is hack. Only the IOA with EISA under it needs +** to use this hint iff the EISA devices needs this feature. +** According to the U2 ERS, STOP_MOST enabled pages hurt performance. +** o PREFETCH should *not* be set for cases like Multiple PCI devices +** behind GSCtoPCI (dino) bus converter. Only one cacheline per GSC +** device can be fetched and multiply DMA streams will thrash the +** prefetch buffer and burn memory bandwidth. See 6.7.3 "Prefetch Rules +** and Invalidation of Prefetch Entries". +** +** FIXME: the default hints need to be per GSC device - not global. +** +** HP-UX dorks: linux device driver programming model is totally different +** than HP-UX's. HP-UX always sets HINT_PREFETCH since it's drivers +** do special things to work on non-coherent platforms...linux has to +** be much more careful with this. +*/ +#define IOPDIR_VALID 0x01UL +#define HINT_SAFE_DMA 0x02UL /* used for pci_alloc_consistent() pages */ +#ifdef CONFIG_ISA /* EISA support really */ +#define HINT_STOP_MOST 0x04UL /* LSL support */ +#else +#define HINT_STOP_MOST 0x00UL /* only needed for "some EISA devices" */ +#endif +#define HINT_UDPATE_ENB 0x08UL /* not used/supported by U2 */ +#define HINT_PREFETCH 0x10UL /* for outbound pages which are not SAFE */ + + +/* +** Use direction (ie PCI_DMA_TODEVICE) to pick hint. +** ccio_alloc_consistent() depends on this to get SAFE_DMA +** when it passes in BIDIRECTIONAL flag. +*/ +static u32 hint_lookup[] = { + [PCI_DMA_BIDIRECTIONAL] HINT_STOP_MOST | HINT_SAFE_DMA | IOPDIR_VALID, + [PCI_DMA_TODEVICE] HINT_STOP_MOST | HINT_PREFETCH | IOPDIR_VALID, + [PCI_DMA_FROMDEVICE] HINT_STOP_MOST | IOPDIR_VALID, + [PCI_DMA_NONE] 0, /* not valid */ +}; + +/* +** Initialize an I/O Pdir entry +** +** Given a virtual address (vba, arg2) and space id, (sid, arg1), +** load the I/O PDIR entry pointed to by pdir_ptr (arg0). Each IO Pdir +** entry consists of 8 bytes as shown below (MSB == bit 0): +** +** +** WORD 0: +** +------+----------------+-----------------------------------------------+ +** | Phys | Virtual Index | Phys | +** | 0:3 | 0:11 | 4:19 | +** |4 bits| 12 bits | 16 bits | +** +------+----------------+-----------------------------------------------+ +** WORD 1: +** +-----------------------+-----------------------------------------------+ +** | Phys | Rsvd | Prefetch |Update |Rsvd |Lock |Safe |Valid | +** | 20:39 | | Enable |Enable | |Enable|DMA | | +** | 20 bits | 5 bits | 1 bit |1 bit |2 bits|1 bit |1 bit |1 bit | +** +-----------------------+-----------------------------------------------+ +** +** The virtual index field is filled with the results of the LCI +** (Load Coherence Index) instruction. The 8 bits used for the virtual +** index are bits 12:19 of the value returned by LCI. +*/ + +void CCIO_INLINE +ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, void * vba, unsigned long hints) +{ + register unsigned long pa = (volatile unsigned long) vba; + register unsigned long ci; /* coherent index */ + + /* We currently only support kernel addresses */ + ASSERT(sid == 0); + ASSERT(((unsigned long) vba & 0xf0000000UL) == 0xc0000000UL); + + mtsp(sid,1); + + /* + ** WORD 1 - low order word + ** "hints" parm includes the VALID bit! + ** "dep" clobbers the physical address offset bits as well. + */ + pa = virt_to_phys(vba); + asm volatile("depw %1,31,12,%0" : "+r" (pa) : "r" (hints)); + ((u32 *)pdir_ptr)[1] = (u32) pa; + + /* + ** WORD 0 - high order word + */ + +#ifdef __LP64__ + /* + ** get bits 12:15 of physical address + ** shift bits 16:31 of physical address + ** and deposit them + */ + asm volatile ("extrd,u %1,15,4,%0" : "=r" (ci) : "r" (pa)); + asm volatile ("extrd,u %1,31,16,%0" : "+r" (ci) : "r" (ci)); + asm volatile ("depd %1,35,4,%0" : "+r" (pa) : "r" (ci)); +#else + pa = 0; +#endif + /* + ** get CPU coherency index bits + ** Grab virtual index [0:11] + ** Deposit virt_idx bits into I/O PDIR word + */ + asm volatile ("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba)); + asm volatile ("extru %1,19,12,%0" : "+r" (ci) : "r" (ci)); + asm volatile ("depw %1,15,12,%0" : "+r" (pa) : "r" (ci)); + + ((u32 *)pdir_ptr)[0] = (u32) pa; + + + /* FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360) + ** PCX-U/U+ do. (eg C200/C240) + ** PCX-T'? Don't know. (eg C110 or similar K-class) + ** + ** See PDC_MODEL/option 0/SW_CAP word for "Non-coherent IO-PDIR bit". + ** Hopefully we can patch (NOP) these out at boot time somehow. + ** + ** "Since PCX-U employs an offset hash that is incompatible with + ** the real mode coherence index generation of U2, the PDIR entry + ** must be flushed to memory to retain coherence." + */ + asm volatile("fdc 0(%0)" : : "r" (pdir_ptr)); + asm volatile("sync"); +} + + +/* +** Remove stale entries from the I/O TLB. +** Need to do this whenever an entry in the PDIR is marked invalid. +*/ +static CCIO_INLINE void +ccio_clear_io_tlb( struct ccio_device *d, dma_addr_t iovp, size_t byte_cnt) +{ + u32 chain_size = 1 << d->chainid_shift; + + iovp &= ~(IOVP_SIZE-1); /* clear offset bits, just want pagenum */ + byte_cnt += chain_size; + + while (byte_cnt > chain_size) { + WRITE_U32(CMD_TLB_PURGE | iovp, &d->ccio_hpa->io_command); + iovp += chain_size; + byte_cnt -= chain_size; + } +} + + +/*********************************************************** + * + * Mark the I/O Pdir entries invalid and blow away the + * corresponding I/O TLB entries. + * + * FIXME: at some threshhold it might be "cheaper" to just blow + * away the entire I/O TLB instead of individual entries. + * + * FIXME: Uturn has 256 TLB entries. We don't need to purge every + * PDIR entry - just once for each possible TLB entry. + * (We do need to maker I/O PDIR entries invalid regardless). + ***********************************************************/ +static CCIO_INLINE void +ccio_mark_invalid(struct ccio_device *d, dma_addr_t iova, size_t byte_cnt) +{ + u32 iovp = (u32) CCIO_IOVP(iova); + size_t saved_byte_cnt; + + /* round up to nearest page size */ + saved_byte_cnt = byte_cnt = (byte_cnt + IOVP_SIZE - 1) & IOVP_MASK; + + while (byte_cnt > 0) { + /* invalidate one page at a time */ + unsigned int idx = PDIR_INDEX(iovp); + char *pdir_ptr = (char *) &(d->pdir_base[idx]); + + ASSERT( idx < (d->pdir_size/sizeof(u64))); + + pdir_ptr[7] = 0; /* clear only VALID bit */ + + /* + ** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360) + ** PCX-U/U+ do. (eg C200/C240) + ** See PDC_MODEL/option 0/SW_CAP for "Non-coherent IO-PDIR bit". + ** + ** Hopefully someone figures out how to patch (NOP) the + ** FDC/SYNC out at boot time. + */ + asm volatile("fdc 0(%0)" : : "r" (pdir_ptr[7])); + + iovp += IOVP_SIZE; + byte_cnt -= IOVP_SIZE; + } + + asm volatile("sync"); + ccio_clear_io_tlb(d, CCIO_IOVP(iova), saved_byte_cnt); +} + + +/**************************************************************** +** +** CCIO dma_ops +** +*****************************************************************/ + +void __init ccio_init(void) +{ + register_driver(ccio_drivers_for); +} + + +static int ccio_dma_supported( struct pci_dev *dev, dma_addr_t mask) +{ + if (dev == NULL) { + printk(MODULE_NAME ": EISA/ISA/et al not supported\n"); + BUG(); + return(0); + } + + dev->dma_mask = mask; /* save it */ + + /* only support 32-bit devices (ie PCI/GSC) */ + return((int) (mask >= 0xffffffffUL)); +} + +/* +** Dump a hex representation of the resource map. +*/ + +#ifdef DUMP_RESMAP +static +void dump_resmap() +{ + struct ccio_device *ioa = ccio_list; + unsigned long *res_ptr = (unsigned long *)ioa->res_map; + unsigned long i = 0; + + printk("res_map: "); + for(; i < (ioa->res_size / sizeof(unsigned long)); ++i, ++res_ptr) + printk("%08lx ", *res_ptr); + + printk("\n"); +} +#endif + +/* +** map_single returns a fully formed IOVA +*/ +static dma_addr_t ccio_map_single(struct pci_dev *dev, void *addr, size_t size, int direction) +{ + struct ccio_device *ioa = ccio_list; /* FIXME : see Multi-IOC below */ + dma_addr_t iovp; + dma_addr_t offset; + u64 *pdir_start; + unsigned long hint = hint_lookup[direction]; + int idx; + + ASSERT(size > 0); + + /* save offset bits */ + offset = ((dma_addr_t) addr) & ~IOVP_MASK; + + /* round up to nearest IOVP_SIZE */ + size = (size + offset + IOVP_SIZE - 1) & IOVP_MASK; + + idx = ccio_alloc_range(ioa, size); + iovp = (dma_addr_t) MKIOVP(idx); + + DBG_RUN(__FUNCTION__ " 0x%p -> 0x%lx", addr, (long) iovp | offset); + + pdir_start = &(ioa->pdir_base[idx]); + + /* If not cacheline aligned, force SAFE_DMA on the whole mess */ + if ((size % L1_CACHE_BYTES) || ((unsigned long) addr % L1_CACHE_BYTES)) + hint |= HINT_SAFE_DMA; + + /* round up to nearest IOVP_SIZE */ + size = (size + IOVP_SIZE - 1) & IOVP_MASK; + + while (size > 0) { + + ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, addr, hint); + + DBG_RUN(" pdir %p %08x%08x\n", + pdir_start, + (u32) (((u32 *) pdir_start)[0]), + (u32) (((u32 *) pdir_start)[1]) + ); + addr += IOVP_SIZE; + size -= IOVP_SIZE; + pdir_start++; + } + /* form complete address */ + return CCIO_IOVA(iovp, offset); +} + + +static void ccio_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, int direction) +{ +#ifdef FIXME +/* Multi-IOC (ie N-class) : need to lookup IOC from dev +** o If we can't know about lba PCI data structs, that eliminates ->sysdata. +** o walking up pcidev->parent dead ends at elroy too +** o leaves hashing dev->bus->number into some lookup. +** (may only work for N-class) +*/ + struct ccio_device *ioa = dev->sysdata +#else + struct ccio_device *ioa = ccio_list; +#endif + dma_addr_t offset; + + offset = iova & ~IOVP_MASK; + + /* round up to nearest IOVP_SIZE */ + size = (size + offset + IOVP_SIZE - 1) & IOVP_MASK; + + /* Mask off offset */ + iova &= IOVP_MASK; + + DBG_RUN(__FUNCTION__ " iovp 0x%lx\n", (long) iova); + +#ifdef DELAYED_RESOURCE_CNT + if (ioa->saved_cnt < DELAYED_RESOURCE_CNT) { + ioa->saved_iova[ioa->saved_cnt] = iova; + ioa->saved_size[ioa->saved_cnt] = size; + ccio_saved_cnt++; + } else { + do { +#endif + ccio_mark_invalid(ioa, iova, size); + ccio_free_range(ioa, iova, size); + +#ifdef DELAYED_RESOURCE_CNT + d->saved_cnt--; + iova = ioa->saved_iova[ioa->saved_cnt]; + size = ioa->saved_size[ioa->saved_cnt]; + } while (ioa->saved_cnt) + } +#endif +} + + +static void * ccio_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) +{ + void *ret; + unsigned long flags; + struct ccio_device *ioa = ccio_list; + + DBG_RUN(__FUNCTION__ " size 0x%x\n", size); + +#if 0 +/* GRANT Need to establish hierarchy for non-PCI devs as well +** and then provide matching gsc_map_xxx() functions for them as well. +*/ + if (!hwdev) { + /* only support PCI */ + *dma_handle = 0; + return 0; + } +#endif + spin_lock_irqsave(&ioa->ccio_lock, flags); + ccio_alloc_size += get_order(size); + spin_unlock_irqrestore(&ioa->ccio_lock, flags); + + ret = (void *) __get_free_pages(GFP_ATOMIC, get_order(size)); + + if (ret) { + memset(ret, 0, size); + *dma_handle = ccio_map_single(hwdev, ret, size, PCI_DMA_BIDIRECTIONAL); + } + DBG_RUN(__FUNCTION__ " ret %p\n", ret); + + return ret; +} + + +static void ccio_free_consistent (struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) +{ + unsigned long flags; + struct ccio_device *ioa = ccio_list; + + spin_lock_irqsave(&ioa->ccio_lock, flags); + ccio_free_size += get_order(size); + spin_unlock_irqrestore(&ioa->ccio_lock, flags); + + ccio_unmap_single(hwdev, dma_handle, size, 0); + free_pages((unsigned long) vaddr, get_order(size)); +} + + +static int ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +{ + int tmp = nents; + + DBG_RUN(KERN_WARNING __FUNCTION__ " START\n"); + + /* KISS: map each buffer seperately. */ + while (nents) { + sg_dma_address(sglist) = ccio_map_single(dev, sglist->address, sglist->length, direction); + sg_dma_len(sglist) = sglist->length; + nents--; + sglist++; + } + + DBG_RUN(KERN_WARNING __FUNCTION__ " DONE\n"); + return tmp; +} + + +static void ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +{ + DBG_RUN(KERN_WARNING __FUNCTION__ " : unmapping %d entries\n", nents); + while (nents) { + ccio_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction); + nents--; + sglist++; + } + return; +} + + +static struct pci_dma_ops ccio_ops = { + ccio_dma_supported, + ccio_alloc_consistent, + ccio_free_consistent, + ccio_map_single, + ccio_unmap_single, + ccio_map_sg, + ccio_unmap_sg, + NULL, /* dma_sync_single : NOP for U2/Uturn */ + NULL, /* dma_sync_sg : ditto */ +}; + +#if 0 +/* GRANT - is this needed for U2 or not? */ + +/* +** Get the size of the I/O TLB for this I/O MMU. +** +** If spa_shift is non-zero (ie probably U2), +** then calculate the I/O TLB size using spa_shift. +** +** Otherwise we are supposed to get the IODC entry point ENTRY TLB +** and execute it. However, both U2 and Uturn firmware supplies spa_shift. +** I think only Java (K/D/R-class too?) systems don't do this. +*/ +static int +ccio_get_iotlb_size(struct hp_device *d) +{ + if(d->spa_shift == 0) { + panic(__FUNCTION__ ": Can't determine I/O TLB size.\n"); + } + return(1 << d->spa_shift); +} +#else + +/* Uturn supports 256 TLB entries */ +#define CCIO_CHAINID_SHIFT 8 +#define CCIO_CHAINID_MASK 0xff + +#endif /* 0 */ + + +/* +** Figure out how big the I/O PDIR should be and alloc it. +** Also sets variables which depend on pdir size. +*/ +static void +ccio_alloc_pdir(struct ccio_device *ioa) +{ + extern unsigned long mem_max; /* arch.../setup.c */ + + u32 iova_space_size = 0; + void * pdir_base; + int pdir_size, iov_order; + + /* + ** Determine IOVA Space size from memory size. + ** Using "mem_max" is a kluge. + ** + ** Ideally, PCI drivers would register the maximum number + ** of DMA they can have outstanding for each device they + ** own. Next best thing would be to guess how much DMA + ** can be outstanding based on PCI Class/sub-class. Both + ** methods still require some "extra" to support PCI + ** Hot-Plug/Removal of PCI cards. (aka PCI OLARD). + */ + /* limit IOVA space size to 1MB-1GB */ + if (mem_max < (ccio_mem_ratio*1024*1024)) { + iova_space_size = 1024*1024; +#ifdef __LP64__ + } else if (mem_max > (ccio_mem_ratio*512*1024*1024)) { + iova_space_size = 512*1024*1024; +#endif + } else { + iova_space_size = (u32) (mem_max/ccio_mem_ratio); + } + + /* + ** iova space must be log2() in size. + ** thus, pdir/res_map will also be log2(). + */ + + /* We could use larger page sizes in order to *decrease* the number + ** of mappings needed. (ie 8k pages means 1/2 the mappings). + ** + ** Note: Grant Grunder says "Using 8k I/O pages isn't trivial either + ** since the pages must also be physically contiguous - typically + ** this is the case under linux." + */ + + iov_order = get_order(iova_space_size); + ASSERT(iov_order <= (30 - IOVP_SHIFT)); /* iova_space_size <= 1GB */ + ASSERT(iov_order >= (20 - IOVP_SHIFT)); /* iova_space_size >= 1MB */ + iova_space_size = 1 << (iov_order + IOVP_SHIFT); + + ioa->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64); + + ASSERT(pdir_size < 4*1024*1024); /* max pdir size < 4MB */ + + /* Verify it's a power of two */ + ASSERT((1 << get_order(pdir_size)) == (pdir_size >> PAGE_SHIFT)); + + DBG_INIT(__FUNCTION__ " hpa 0x%p mem %dMB IOV %dMB (%d bits)\n PDIR size 0x%0x", + ioa->ccio_hpa, (int) (mem_max>>20), iova_space_size>>20, + iov_order + PAGE_SHIFT, pdir_size); + + ioa->pdir_base = + pdir_base = (void *) __get_free_pages(GFP_KERNEL, get_order(pdir_size)); + if (NULL == pdir_base) + { + panic(__FILE__ ":" __FUNCTION__ "() could not allocate I/O Page Table\n"); + } + memset(pdir_base, 0, pdir_size); + + ASSERT((((unsigned long) pdir_base) & PAGE_MASK) == (unsigned long) pdir_base); + + DBG_INIT(" base %p", pdir_base); + + /* + ** Chainid is the upper most bits of an IOVP used to determine + ** which TLB entry an IOVP will use. + */ + ioa->chainid_shift = get_order(iova_space_size)+PAGE_SHIFT-CCIO_CHAINID_SHIFT; + + DBG_INIT(" chainid_shift 0x%x\n", ioa->chainid_shift); +} + + +static void +ccio_hw_init(struct ccio_device *ioa) +{ + int i; + + /* + ** Initialize IOA hardware + */ + WRITE_U32(CCIO_CHAINID_MASK << ioa->chainid_shift, &ioa->ccio_hpa->io_chain_id_mask); + WRITE_U32(virt_to_phys(ioa->pdir_base), &ioa->ccio_hpa->io_pdir_base); + + + /* + ** Go to "Virtual Mode" + */ + WRITE_U32(IOA_NORMAL_MODE, &ioa->ccio_hpa->io_control); + + /* + ** Initialize all I/O TLB entries to 0 (Valid bit off). + */ + WRITE_U32(0, &ioa->ccio_hpa->io_tlb_entry_m); + WRITE_U32(0, &ioa->ccio_hpa->io_tlb_entry_l); + + for (i = 1 << CCIO_CHAINID_SHIFT; i ; i--) { + WRITE_U32((CMD_TLB_DIRECT_WRITE | (i << ioa->chainid_shift)), + &ioa->ccio_hpa->io_command); + } + +} + + +static void +ccio_resmap_init(struct ccio_device *ioa) +{ + u32 res_size; + + /* + ** Ok...we do more than just init resource map + */ + ioa->ccio_lock = SPIN_LOCK_UNLOCKED; + + ioa->res_hint = 16; /* next available IOVP - circular search */ + + /* resource map size dictated by pdir_size */ + res_size = ioa->pdir_size/sizeof(u64); /* entries */ + res_size >>= 3; /* convert bit count to byte count */ + DBG_INIT(__FUNCTION__ "() res_size 0x%x\n", res_size); + + ioa->res_size = res_size; + ioa->res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size)); + if (NULL == ioa->res_map) + { + panic(__FILE__ ":" __FUNCTION__ "() could not allocate resource map\n"); + } + memset(ioa->res_map, 0, res_size); +} + +/* CUJO20 KLUDGE start */ +static struct { + u16 hversion; + u8 spa; + u8 type; + u32 foo[3]; /* 16 bytes total */ +} cujo_iodc __attribute__ ((aligned (64))); +static unsigned long cujo_result[32] __attribute__ ((aligned (16))) = {0,0,0,0}; + +/* +** CUJO 2.0 incorrectly decodes a memory access for specific +** pages (every page at specific iotlb locations dependent +** upon where the cujo is flexed - diff on raven/firehawk. +** resulting in an hpmc and/or silent data corruption. +** Workaround is to prevent use of those I/O TLB entries +** by marking the suspect bitmap range entries as busy. +*/ +static void +ccio_cujo20_hack(struct ccio_device *ioa) +{ + unsigned long status; + unsigned int idx; + u8 *res_ptr = ioa->res_map; + u32 iovp=0x0; + unsigned long mask; + + status = pdc_iodc_read( &cujo_result, (void *) CUJO_RAVEN_LOC, 0, &cujo_iodc, 16); + if (status == 0) { + if (cujo_iodc.hversion==CUJO_20_BADHVERS) + iovp = CUJO_20_BADPAGE1; + } else { + status = pdc_iodc_read( &cujo_result, (void *) CUJO_FIREHAWK_LOC, 0, &cujo_iodc, 16); + if (status == 0) { + if (cujo_iodc.hversion==CUJO_20_BADHVERS) + iovp = CUJO_20_BADPAGE2; + } else { + /* not a defective system */ + return; + } + } + + printk(MODULE_NAME ": Cujo 2.0 bug needs a work around\n"); + ccio_cujo_bug = 1; + + /* + ** mark bit entries that match "bad page" + */ + idx = PDIR_INDEX(iovp)>>3; + mask = 0xff; + + while(idx * sizeof(u8) < ioa->res_size) { + res_ptr[idx] |= mask; + idx += (PDIR_INDEX(CUJO_20_STEP)>>3); + ccio_used_pages += 8; + ccio_used_bytes += 1; + } +} +/* CUJO20 KLUDGE end */ + +#ifdef CONFIG_PROC_FS +static int ccio_proc_info(char *buf, char **start, off_t offset, int len) +{ + unsigned long i = 0; + struct ccio_device *ioa = ccio_list; + unsigned long *res_ptr = (unsigned long *)ioa->res_map; + unsigned long total_pages = ioa->res_size << 3; /* 8 bits per byte */ + + sprintf(buf, "%s\nCujo 2.0 bug : %s\n", + parisc_getHWdescription(ioa->iodc->hw_type, ioa->iodc->hversion, + ioa->iodc->sversion), + (ccio_cujo_bug ? "yes" : "no")); + + sprintf(buf, "%sIO pdir size : %d bytes (%d entries)\n", + buf, ((ioa->res_size << 3) * sizeof(u64)), /* 8 bits per byte */ + ioa->res_size << 3); /* 8 bits per byte */ + + sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", + buf, ioa->res_size, ioa->res_size << 3); /* 8 bits per byte */ + + strcat(buf, " total: free: used: % used:\n"); + sprintf(buf, "%sblocks %8d %8ld %8ld %8ld%%\n", buf, ioa->res_size, + ioa->res_size - ccio_used_bytes, ccio_used_bytes, + (ccio_used_bytes * 100) / ioa->res_size); + + sprintf(buf, "%spages %8ld %8ld %8ld %8ld%%\n", buf, total_pages, + total_pages - ccio_used_pages, ccio_used_pages, + (ccio_used_pages * 100 / total_pages)); + + sprintf(buf, "%sconsistent %8ld %8ld\n", buf, + ccio_alloc_size, ccio_free_size); + + strcat(buf, "\nResource bitmap:\n"); + + for(; i < (ioa->res_size / sizeof(unsigned long)); ++i, ++res_ptr) + len += sprintf(buf, "%s%08lx ", buf, *res_ptr); + + strcat(buf, "\n"); + return strlen(buf); +} +#endif + +/* +** Determine if ccio should claim this chip (return 0) or not (return 1). +** If so, initialize the chip and tell other partners in crime they +** have work to do. +*/ +static int +ccio_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri) +{ + struct ccio_device *ioa; + + printk("%s found %s at 0x%p\n", dri->name, dri->version, d->hpa); + + if (ccio_list) { + printk(MODULE_NAME ": already initialized one device\n"); + return(0); + } + + ioa = kmalloc(sizeof(struct ccio_device), GFP_KERNEL); + if (NULL == ioa) + { + printk(MODULE_NAME " - couldn't alloc ccio_device\n"); + return(1); + } + memset(ioa, 0, sizeof(struct ccio_device)); + + /* + ** ccio list is used mainly as a kluge to support a single instance. + ** Eventually, with core dumps, it'll be useful for debugging. + */ + ccio_list = ioa; + ioa->iodc = d; + +#if 1 +/* KLUGE: determine IOA hpa based on GSC port value. +** Needed until we have a PA bus walk. Can only discover IOA via +** walking the architected PA MMIO space as described by the I/O ACD. +** "Legacy" PA Firmware only tells us about unarchitected devices +** that can't be detected by PA/EISA/PCI bus walks. +*/ + switch((long) d->hpa) { + case 0xf3fbf000L: /* C110 IOA0 LBC (aka GSC port) */ + /* ccio_hpa same as C200 IOA0 */ + case 0xf203f000L: /* C180/C200/240/C360 IOA0 LBC (aka GSC port) */ + ioa->ccio_hpa = (struct ioa_registers *) 0xfff88000L; + break; + case 0xf103f000L: /* C180/C200/240/C360 IOA1 LBC (aka GSC port) */ + ioa->ccio_hpa = (struct ioa_registers *) 0xfff8A000L; + break; + default: + panic("ccio-dma.c doesn't know this GSC port Address!\n"); + break; + }; +#else + ioa->ccio_hpa = d->hpa; +#endif + + ccio_alloc_pdir(ioa); + ccio_hw_init(ioa); + ccio_resmap_init(ioa); + + /* CUJO20 KLUDGE start */ + ccio_cujo20_hack(ioa); + /* CUJO20 KLUDGE end */ + + hppa_dma_ops = &ccio_ops; + + create_proc_info_entry(MODULE_NAME, 0, proc_runway_root, ccio_proc_info); + return(0); +} + + + diff --git a/arch/parisc/kernel/ccio-rm-dma.c b/arch/parisc/kernel/ccio-rm-dma.c new file mode 100644 index 000000000..25ec90c1b --- /dev/null +++ b/arch/parisc/kernel/ccio-rm-dma.c @@ -0,0 +1,212 @@ +/* + * ccio-rm-dma.c: + * DMA management routines for first generation cache-coherent machines. + * "Real Mode" operation refers to U2/Uturn chip operation. The chip + * can perform coherency checks w/o using the I/O MMU. That's all we + * need until support for more than 4GB phys mem is needed. + * + * This is the trivial case - basically what x86 does. + * + * Drawbacks of using Real Mode are: + * o outbound DMA is slower since one isn't using the prefetching + * U2 can do for outbound DMA. + * o Ability to do scatter/gather in HW is also lost. + * o only known to work with PCX-W processor. (eg C360) + * (PCX-U/U+ are not coherent with U2 in real mode.) + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * + * Original version/author: + * CVSROOT=:pserver:anonymous@198.186.203.37:/cvsroot/linux-parisc + * cvs -z3 co linux/arch/parisc/kernel/dma-rm.c + * + * (C) Copyright 2000 Philipp Rumpf <prumpf@tux.org> + * + * + * Adopted for The Puffin Group's parisc-linux port by Grant Grundler. + * (C) Copyright 2000 Grant Grundler <grundler@puffin.external.hp.com> + * + */ + +#include <linux/types.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/pci.h> + +#include <asm/uaccess.h> +#include <asm/pgalloc.h> + +#include <asm/io.h> +#include <asm/hardware.h> +#include <asm/page.h> + +/* Only chose "ccio" since that's what HP-UX calls it.... +** Make it easier for folks to migrate from one to the other :^) +*/ +#define MODULE_NAME "ccio" + +#define U2_IOA_RUNWAY 0x580 +#define U2_BC_GSC 0x501 +#define UTURN_IOA_RUNWAY 0x581 +#define UTURN_BC_GSC 0x502 + +static int ccio_driver_callback(struct hp_device *, struct pa_iodc_driver *); + +static struct pa_iodc_driver ccio_drivers_for[] = { + + {HPHW_BCPORT, U2_BC_GSC, 0x0, 0xb, 0, 0x10, + DRIVER_CHECK_HVERSION + + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + MODULE_NAME, "U2 I/O MMU", (void *) ccio_driver_callback}, + + {HPHW_BCPORT, UTURN_BC_GSC, 0x0, 0xb, 0, 0x10, + DRIVER_CHECK_HVERSION + + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + MODULE_NAME, "Uturn I/O MMU", (void *) ccio_driver_callback}, + + {0,0,0,0,0,0, + 0, + (char *) NULL, (char *) NULL, (void *) NULL } +}; + + +#define IS_U2(id) ( \ + (((id)->hw_type == HPHW_IOA) && ((id)->hversion == U2_IOA_RUNWAY)) || \ + (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == U2_BC_GSC)) \ +) + +#define IS_UTURN(id) ( \ + (((id)->hw_type == HPHW_IOA) && ((id)->hversion == UTURN_IOA_RUNWAY)) || \ + (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == UTURN_BC_GSC)) \ +) + + +void __init ccio_init(void) +{ + register_driver(ccio_drivers_for); +} + + +static int ccio_dma_supported( struct pci_dev *dev, dma_addr_t mask) +{ + if (dev == NULL) { + printk(MODULE_NAME ": EISA/ISA/et al not supported\n"); + BUG(); + return(0); + } + + dev->dma_mask = mask; /* save it */ + + /* only support 32-bit devices (ie PCI/GSC) */ + return((int) (mask >= 0xffffffffUL)); +} + + +static void *ccio_alloc_consistent(struct pci_dev *dev, size_t size, + dma_addr_t *handle) +{ + void *ret; + + ret = (void *)__get_free_pages(GFP_ATOMIC, get_order(size)); + + if (ret != NULL) { + memset(ret, 0, size); + *handle = virt_to_phys(ret); + } + return ret; +} + +static void ccio_free_consistent(struct pci_dev *dev, size_t size, + void *vaddr, dma_addr_t handle) +{ + free_pages((unsigned long)vaddr, get_order(size)); +} + +static dma_addr_t ccio_map_single(struct pci_dev *dev, void *ptr, size_t size, + int direction) +{ + return virt_to_phys(ptr); +} + +static void ccio_unmap_single(struct pci_dev *dev, dma_addr_t dma_addr, + size_t size, int direction) +{ + /* Nothing to do */ +} + + +static int ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +{ + int tmp = nents; + + /* KISS: map each buffer seperately. */ + while (nents) { + sg_dma_address(sglist) = ccio_map_single(dev, sglist->address, sglist->length, direction); + sg_dma_len(sglist) = sglist->length; + nents--; + sglist++; + } + + return tmp; +} + + +static void ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +{ +#if 0 + while (nents) { + ccio_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction); + nents--; + sglist++; + } + return; +#else + /* Do nothing (copied from current ccio_unmap_single() :^) */ +#endif +} + + +static struct pci_dma_ops ccio_ops = { + ccio_dma_supported, + ccio_alloc_consistent, + ccio_free_consistent, + ccio_map_single, + ccio_unmap_single, + ccio_map_sg, + ccio_unmap_sg, + NULL, /* dma_sync_single : NOP for U2 */ + NULL, /* dma_sync_sg : ditto */ + + +}; + + +/* +** Determine if u2 should claim this chip (return 0) or not (return 1). +** If so, initialize the chip and tell other partners in crime they +** have work to do. +*/ +static int +ccio_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri) +{ + printk("%s found %s at 0x%p\n", dri->name, dri->version, d->hpa); + +/* +** FIXME - should check U2 registers to verify it's really running +** in "Real Mode". +*/ + +#if 0 +/* will need this for "Virtual Mode" operation */ + ccio_hw_init(ccio_dev); + ccio_common_init(ccio_dev); +#endif + hppa_dma_ops = &ccio_ops; + return 0; +} diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c new file mode 100644 index 000000000..ba93bbda0 --- /dev/null +++ b/arch/parisc/kernel/drivers.c @@ -0,0 +1,134 @@ +/* + +drivers.c + +Copyright (c) 1999 The Puffin Group + +This is a collection of routines intended to register all the devices +in a system, and register device drivers. + +*/ + +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/pdc.h> + + +extern struct hp_hardware *parisc_get_reference( + unsigned short hw_type, unsigned long hversion, + unsigned long sversion ); + + +/* I'm assuming there'll never be 64 devices. We should probably make + this more flexible. */ + +#define MAX_DEVICES 64 + +unsigned int num_devices = 0; + +struct hp_device devices[MAX_DEVICES]; + +static unsigned long pdc_result[32] __attribute__ ((aligned (16))) = {0,0,0,0}; +static u8 iodc_data[32] __attribute__ ((aligned (64))); + +/* + * XXX should we be using a locked array ? + */ + +int register_driver(struct pa_iodc_driver *driver) +{ + unsigned int i; + struct hp_device * device; + + for (;driver->check;driver++) { + + for (i=0;i<num_devices;i++) { + device = &devices[i]; + + if (device->managed) continue; + + if ((driver->check & DRIVER_CHECK_HWTYPE) && + (driver->hw_type != device->hw_type)) + continue; + if ((driver->check & DRIVER_CHECK_HVERSION) && + (driver->hversion != device->hversion)) + continue; + if ((driver->check & DRIVER_CHECK_HVERSION_REV) && + (driver->hversion_rev != device->hversion_rev)) + continue; + if ((driver->check & DRIVER_CHECK_SVERSION) && + (driver->sversion != device->sversion)) + continue; + if ((driver->check & DRIVER_CHECK_SVERSION_REV) && + (driver->sversion_rev != device->sversion_rev)) + continue; + if ((driver->check & DRIVER_CHECK_OPT) && + (driver->opt != device->opt)) + continue; + if ( (*driver->callback)(device,driver) ==0) { + device->managed=1; + } else { + printk("Warning : device (%d, 0x%x, 0x%x, 0x%x, 0x%x) NOT claimed by %s %s\n", + device->hw_type, + device->hversion, device->hversion_rev, + device->sversion, device->sversion_rev, + driver->name, driver->version); + } + } + } + return 0; +} + + +struct hp_device * register_module(void *hpa) +{ + + struct hp_device * d; + int status; + + d = &devices[num_devices]; + status = pdc_iodc_read(&pdc_result,hpa,0,&iodc_data,32 ); + if (status !=PDC_RET_OK) { + /* There is no device here, so we'll skip it */ + return 0; + } + + d->hw_type = iodc_data[3]&0x1f; + d->hversion = (iodc_data[0]<<4)|((iodc_data[1]&0xf0)>>4); + d->sversion = + ((iodc_data[4]&0x0f)<<16)|(iodc_data[5]<<8)|(iodc_data[6]); + d->hversion_rev = iodc_data[1]&0x0f; + d->sversion_rev = iodc_data[4]>>4; + d->opt = iodc_data[7]; + d->hpa = hpa; + d->managed=0; + d->reference = parisc_get_reference(d->hw_type, d->hversion, + d->sversion); + + num_devices++; + + return d; +} + +void print_devices(char * buf) { + + int i; + struct hp_device *d; + printk("Found devices:\n"); + for (i=0;i<num_devices;i++) { + d = &devices[i]; + printk(KERN_INFO + "%d. %s (%d) at 0x%p, versions 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", + i+1, + (d->reference) ? d->reference->name : "Unknown device", + d->hw_type,d->hpa, d->hversion, d->hversion_rev, + d->sversion, d->sversion_rev, d->opt); + + } + printk("That's a total of %d devices.\n",num_devices); +} + + diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S new file mode 100644 index 000000000..0839e0bbb --- /dev/null +++ b/arch/parisc/kernel/entry.S @@ -0,0 +1,1867 @@ +/*------------------------------------------------------------------------------ + * Native PARISC/Linux Project (http://www.puffingroup.com/parisc) + * + * kernel entry points (interruptions, system call wrappers) + * Copyright (C) 1999,2000 Philipp Rumpf + * Copyright (C) 1999 SuSE GmbH Nuernberg + * Copyright (C) 2000 Hewlett-Packard (John Marvin) + * Copyright (C) 1999 Hewlett-Packard (Frank Rowand) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/config.h> +#include <asm/offset.h> + +/* the following is the setup i think we should follow: + * whenever the CPU is interruptible, the following has to be true: + * CR30 is the kernel sp or 0 if we currently use the kernel stack + * CR31 is the kernel gp */ + +/* we have the following possibilities to act on an interruption: + * - handle in assembly and use shadowed registers only + * - save registers to kernel stack and handle in assembly or C */ + + .text + +#ifdef __LP64__ + .level 2.0w +#endif + +#define __ASSEMBLY__ +#include <asm/assembly.h> /* for LDREG/STREG defines */ +#include <asm/pgtable.h> +#include <asm/psw.h> +#include <asm/signal.h> + +#ifdef __LP64__ +#define FRAME_SIZE 64 +#else +#define FRAME_SIZE 64 +#endif + + /* Switch to virtual mapping, trashing only %r1 */ + .macro virt_map rfi_type + mtsm %r0 + tovirt %r29 + tovirt %r30 + mfsp %sr7, %r1 + mtsp %r1, %sr3 + mtsp %r0, %sr4 + mtsp %r0, %sr5 + mtsp %r0, %sr6 + mtsp %r0, %sr7 + ldil L%KERNEL_PSW, %r1 + ldo R%KERNEL_PSW(%r1), %r1 + LDIL_FIXUP(%r1) + mtctl %r1, %cr22 + mtctl %r0, %cr17 + mtctl %r0, %cr17 + ldil L%.+28, %r1 + ldo R%.+24(%r1), %r1 + LDIL_FIXUP(%r1) + mtctl %r1, %cr18 + ldo 4(%r1), %r1 + mtctl %r1, %cr18 + \rfi_type + nop + .endm + + .macro get_stack + mfctl %cr30, %r1 + comib,=,n 0, %r1, 0f /* forward so predicted not taken */ + + /* we save the registers in the task struct */ + ldo TASK_REGS(%r1), %r29 + tophys %r29 + STREG %r30, PT_GR30(%r29) + STREG %r1, PT_CR30(%r29) + ldo TASK_SZ_ALGN(%r1), %r30 + b 1f /* unconditional so predicted taken */ + mtctl %r0,%cr30 +0: + /* we put a struct pt_regs on the stack and save the registers there */ + copy %r30,%r29 + ldo PT_SZ_ALGN(%r30),%r30 + tophys %r29 + STREG %r30,PT_GR30(%r29) + STREG %r0,PT_CR30(%r29) +1: + .endm + + .macro rest_stack regs + LDREG PT_CR30(\regs), %r1 + comib,=,n 0, %r1, 2f/* forward so predicted not taken */ + + /* we restore the registers out of the task struct */ + mtctl %r1, %cr30 + LDREG PT_GR1(\regs), %r1 + LDREG PT_GR30(\regs),%r30 + b 3f + LDREG PT_GR29(\regs),%r29 +2: + /* we take a struct pt_regs off the stack */ + LDREG PT_GR1(\regs), %r1 + LDREG PT_GR29(\regs), %r29 + ldo -PT_SZ_ALGN(%r30), %r30 +3: + .endm + +#ifdef OLD + /* fixme interruption handler */ + .macro def code + /* WARNING!!! THIS IS DEBUG CODE ONLY!!! */ + b unimplemented_64bitirq + ldi \code, %r1 + .align 32 + .endm + + /* Use def to enable break - KWDB wants em + * (calls traps.c:handle_interruption) */ + .macro pass_break code + +#else + /* default interruption handler + * (calls traps.c:handle_interruption) */ + .macro def code +#endif + mtctl %r29, %cr31 + mtctl %r1, %cr28 + ldi \code, %r1 + b intr_save + mtctl %r1, %cr29 + .align 32 + .endm + + /* Interrupt interruption handler + * (calls irq.c:do_irq_mask) */ + .macro extint code + mtctl %r29, %cr31 + mtctl %r1, %cr28 + mfctl %cr23, %r1 + mtctl %r1, %cr23 + b intr_extint + mtctl %r1, %cr29 + .align 32 + .endm + + .import os_hpmc, code + + /* HPMC handler */ + .macro hpmc code + nop /* must be a NOP, will be patched later */ + ldil L%PA(os_hpmc), %r3 + ldo R%PA(os_hpmc)(%r3), %r3 + bv,n 0(%r3) + nop + .word 0 /* checksum (will be patched) */ + .word PA(os_hpmc) /* address of handler */ + .word 0 /* length of handler */ + .endm + + /* + * Performance Note: Instructions will be moved up into + * this part of the code later on, once we are sure + * that the tlb miss handlers are close to final form. + */ + + /* Register definitions for tlb miss handler macros */ + + va = r8 /* virtual address for which the trap occured */ + spc = r24 /* space for which the trap occured */ + +#ifndef __LP64__ + + /* + * itlb miss interruption handler (parisc 1.1 - 32 bit) + */ + + .macro itlb_11 code + + mfctl %pcsq, spc + b itlb_miss_11 + mfctl %pcoq, va + + .align 32 + .endm +#endif + + /* + * itlb miss interruption handler (parisc 2.0) + */ + + .macro itlb_20 code + + mfctl %pcsq, spc +#ifdef __LP64__ + b itlb_miss_20w +#else + b itlb_miss_20 +#endif + mfctl %pcoq, va + + .align 32 + .endm + +#ifndef __LP64__ + /* + * naitlb miss interruption handler (parisc 1.1 - 32 bit) + * + * Note: naitlb misses will be treated + * as an ordinary itlb miss for now. + * However, note that naitlb misses + * have the faulting address in the + * IOR/ISR. + */ + + .macro naitlb_11 code + + mfctl %isr,spc + b itlb_miss_11 + mfctl %ior,va + /* FIXME: If user causes a naitlb miss, the priv level may not be in + * lower bits of va, where the itlb miss handler is expecting them + */ + + .align 32 + .endm +#endif + + /* + * naitlb miss interruption handler (parisc 2.0) + * + * Note: naitlb misses will be treated + * as an ordinary itlb miss for now. + * However, note that naitlb misses + * have the faulting address in the + * IOR/ISR. + */ + + .macro naitlb_20 code + + mfctl %isr,spc +#ifdef __LP64__ + b itlb_miss_20w +#else + b itlb_miss_20 +#endif + mfctl %ior,va + /* FIXME: If user causes a naitlb miss, the priv level may not be in + * lower bits of va, where the itlb miss handler is expecting them + */ + + .align 32 + .endm + +#ifndef __LP64__ + /* + * dtlb miss interruption handler (parisc 1.1 - 32 bit) + */ + + .macro dtlb_11 code + + mfctl %isr, spc + b dtlb_miss_11 + mfctl %ior, va + + .align 32 + .endm +#endif + + /* + * dtlb miss interruption handler (parisc 2.0) + */ + + .macro dtlb_20 code + + mfctl %isr, spc +#ifdef __LP64__ + b dtlb_miss_20w +#else + b dtlb_miss_20 +#endif + mfctl %ior, va + + .align 32 + .endm + +#ifndef __LP64__ + /* nadtlb miss interruption handler (parisc 1.1 - 32 bit) + * + * Note: nadtlb misses will be treated + * as an ordinary dtlb miss for now. + * + */ + + .macro nadtlb_11 code + + mfctl %isr,spc + b dtlb_miss_11 + mfctl %ior,va + + .align 32 + .endm +#endif + + /* nadtlb miss interruption handler (parisc 2.0) + * + * Note: nadtlb misses will be treated + * as an ordinary dtlb miss for now. + * + */ + + .macro nadtlb_20 code + + mfctl %isr,spc +#ifdef __LP64__ + b dtlb_miss_20w +#else + b dtlb_miss_20 +#endif + mfctl %ior,va + + .align 32 + .endm + +#ifndef __LP64__ + /* + * dirty bit trap interruption handler (parisc 1.1 - 32 bit) + */ + + .macro dbit_11 code + + mfctl %isr,spc + b dbit_trap_11 + mfctl %ior,va + + .align 32 + .endm +#endif + + /* + * dirty bit trap interruption handler (parisc 2.0) + */ + + .macro dbit_20 code + + mfctl %isr,spc +#ifdef __LP64__ + b dbit_trap_20w +#else + b dbit_trap_20 +#endif + mfctl %ior,va + + .align 32 + .endm + + /* + * Align fault_vector_20 on 4K boundary so that both + * fault_vector_11 and fault_vector_20 are on the + * same page. This is only necessary as long as we + * write protect the kernel text, which we may stop + * doing once we use large parge translations to cover + * the static part of the kernel address space. + */ + + + .export fault_vector_20 + + .align 4096 + +fault_vector_20: + /* First vector is invalid (0) */ + .ascii "cows can fly" + .byte 0 + .align 32 + + hpmc 1 + def 2 + def 3 + extint 4 + def 5 + itlb_20 6 + def 7 + def 8 + def 9 + def 10 + def 11 + def 12 + def 13 + def 14 + dtlb_20 15 + naitlb_20 16 + nadtlb_20 17 + def 18 + def 19 + dbit_20 20 + def 21 + def 22 + def 23 + def 24 + def 25 + def 26 + def 27 + def 28 + def 29 + def 30 + def 31 + +#ifndef __LP64__ + + .export fault_vector_11 + + .align 2048 + +fault_vector_11: + /* First vector is invalid (0) */ + .ascii "cows can fly" + .byte 0 + .align 32 + + hpmc 1 + def 2 + def 3 + extint 4 + def 5 + itlb_11 6 + def 7 + def 8 + def 9 + def 10 + def 11 + def 12 + def 13 + def 14 + dtlb_11 15 + naitlb_11 16 + nadtlb_11 17 + def 18 + def 19 + dbit_11 20 + def 21 + def 22 + def 23 + def 24 + def 25 + def 26 + def 27 + def 28 + def 29 + def 30 + def 31 + +#endif + + .import handle_interruption,code + .import handle_real_interruption,code + .import do_irq_mask,code + .import parisc_stopkernel,code + .import cpu_irq_region,data + + /* + * r26 = function to be called + * r25 = argument to pass in + * r24 = flags for do_fork() + * + * Kernel threads don't ever return, so they don't need + * a true register context. We just save away the arguments + * for copy_thread/ret_ to properly set up the child. + */ + +#define CLONE_VM 0x100 /* Must agree with <linux/sched.h> */ + + .export __kernel_thread, code + .import do_fork +__kernel_thread: + STREG %r2, -RP_OFFSET(%r30) + + copy %r30, %r1 + ldo PT_SZ_ALGN(%r30),%r30 +#ifdef __LP64__ + /* Yo, function pointers in wide mode are little structs... -PB */ + /* XXX FIXME do we need to honor the fptr's %dp value too? */ + ldd 16(%r26), %r26 +#endif + STREG %r26, PT_GR26(%r1) /* Store function & argument for child */ + STREG %r25, PT_GR25(%r1) + ldo CLONE_VM(%r0), %r26 /* Force CLONE_VM since only init_mm */ + or %r26, %r24, %r26 /* will have kernel mappings. */ + copy %r0, %r25 + bl do_fork, %r2 + copy %r1, %r24 + + /* Parent Returns here */ + + ldo -PT_SZ_ALGN(%r30), %r30 + LDREG -RP_OFFSET(%r30), %r2 + bv %r0(%r2) + nop + + /* + * Child Returns here + * + * copy_thread moved args from temp save area set up above + * into task save area. + */ + + .export ret_from_kernel_thread +ret_from_kernel_thread: + + LDREG TASK_PT_GR26-TASK_SZ_ALGN(%r30), %r1 + LDREG TASK_PT_GR25-TASK_SZ_ALGN(%r30), %r26 + ble 0(%sr7, %r1) + copy %r31, %r2 + + b sys_exit + ldi 0, %r26 + + .import sys_execve, code + .export __execve, code +__execve: + copy %r2, %r15 + copy %r23, %r17 + copy %r30, %r16 + ldo PT_SZ_ALGN(%r30), %r30 + STREG %r26, PT_GR26(%r16) + STREG %r25, PT_GR25(%r16) + STREG %r24, PT_GR24(%r16) + bl sys_execve, %r2 + copy %r16, %r26 + + comib,<>,n 0,%r28,__execve_failed + + b intr_return + STREG %r17, PT_CR30(%r16) + +__execve_failed: + /* yes, this will trap and die. */ + copy %r15, %r2 + bv %r0(%r2) + nop + + .align 4 + + /* + * struct task_struct *_switch_to(struct task_struct *prev, + * struct task_struct *next) + * + * switch kernel stacks and return prev */ + .export _switch_to, code +_switch_to: + STREG %r2, -RP_OFFSET(%r30) + + callee_save + + ldil L%_switch_to_ret, %r2 + ldo R%_switch_to_ret(%r2), %r2 + LDIL_FIXUP(%r2) + + STREG %r2, TASK_PT_KPC(%r26) + LDREG TASK_PT_KPC(%r25), %r2 + + STREG %r30, TASK_PT_KSP(%r26) + LDREG TASK_PT_KSP(%r25), %r30 + + bv %r0(%r2) + nop + +_switch_to_ret: + mtctl %r0, %cr0 /* Needed for single stepping */ + callee_rest + + LDREG -RP_OFFSET(%r30), %r2 + bv %r0(%r2) + copy %r26, %r28 + + /* + * Common rfi return path for interruptions, kernel execve, and some + * syscalls. The sys_rt_sigreturn syscall will return via this path + * if the signal was received when the process was running; if the + * process was blocked on a syscall then the normal syscall_exit + * path is used. All syscalls for traced proceses exit via + * intr_restore. + * Note that the following code uses a "relied upon translation". See + * the parisc ACD for details. The ssm is necessary due to a PCXT bug. + */ + + .align 4096 + + .export syscall_exit_rfi +syscall_exit_rfi: + copy %r30,%r16 + /* FIXME! depi below has hardcoded dependency on kernel stack size */ + depi 0,31,14,%r16 /* get task pointer */ + ldo TASK_REGS(%r16),%r16 + /* Force iaoq to userspace, as the user has had access to our current + * context via sigcontext. + * XXX do we need any other protection here? + */ + LDREG PT_IAOQ0(%r16),%r19 + depi 3,31,2,%r19 + STREG %r19,PT_IAOQ0(%r16) + LDREG PT_IAOQ1(%r16),%r19 + depi 3,31,2,%r19 + STREG %r19,PT_IAOQ1(%r16) + +intr_return: + + /* Check for software interrupts */ + + .import irq_stat,data + + ldil L%irq_stat,%r19 + ldo R%irq_stat(%r19),%r19 + LDIL_FIXUP(%r19) + +#ifdef CONFIG_SMP + copy %r30,%r1 + /* FIXME! depi below has hardcoded dependency on kernel stack size */ + depi 0,31,14,%r1 /* get task pointer */ + ldw TASK_PROCESSOR(%r1),%r20 /* get cpu # - int */ +#if (IRQSTAT_SZ == 32) + dep %r20,26,27,%r20 /* shift left 5 bits */ +#else +#error IRQSTAT_SZ changed, fix dep +#endif /* IRQSTAT_SZ */ + add %r19,%r20,%r19 +#endif /* CONFIG_SMP */ + + ldw IRQSTAT_SI_ACTIVE(%r19),%r20 /* hardirq.h: unsigned int */ + ldw IRQSTAT_SI_MASK(%r19),%r19 /* hardirq.h: unsigned int */ + and %r19,%r20,%r20 + comib,<>,n 0,%r20,intr_do_softirq /* forward */ + +intr_check_resched: + + /* check for reschedule */ + copy %r30,%r1 + /* FIXME! depi below has hardcoded dependency on kernel stack size */ + depi 0,31,14,%r1 /* get task pointer */ + LDREG TASK_NEED_RESCHED(%r1),%r19 /* sched.h: long need_resched */ + comib,<>,n 0,%r19,intr_do_resched /* forward */ + +intr_check_sig: + /* As above */ + copy %r30,%r1 + depi 0,31,14,%r1 /* get task pointer */ + ldw TASK_SIGPENDING(%r1),%r19 /* sched.h: int sigpending */ + comib,<>,n 0,%r19,intr_do_signal /* forward */ + +intr_restore: + copy %r16, %r29 + ldo PT_FR31(%r29), %r29 + rest_fp %r29 + copy %r16, %r29 + rest_general %r29 + ssm 0,%r0 + nop + nop + nop + nop + nop + nop + nop + tophys %r29 + mtsm %r0 + rest_specials %r29 + rest_stack %r29 + rfi + nop + nop + nop + nop + nop + nop + nop + nop + + .import do_softirq,code +intr_do_softirq: + bl do_softirq,%r2 + nop + b intr_check_resched + nop + + .import schedule,code +intr_do_resched: + /* Only do reschedule if we are returning to user space */ + LDREG PT_SR7(%r16), %r20 + comib,= 0,%r20,intr_restore /* backward */ + nop + + bl schedule,%r2 + ssm PSW_SM_I, %r0 + + /* It's OK to leave I bit on */ + b intr_return /* start over if we got a resched */ + nop + + .import do_signal,code +intr_do_signal: + /* Only do signals if we are returning to user space */ + LDREG PT_SR7(%r16), %r20 + comib,= 0,%r20,intr_restore /* backward */ + nop + + copy %r0, %r24 /* unsigned long in_syscall */ + copy %r16, %r25 /* struct pt_regs *regs */ + ssm PSW_SM_I, %r0 + bl do_signal,%r2 + copy %r0, %r26 /* sigset_t *oldset = NULL */ + + b intr_restore + nop + + /* CR28 - saved GR1 + * CR29 - argument for do_irq_mask */ + + /* External interrupts */ +intr_extint: + get_stack + save_specials %r29 + virt_map rfi + save_general %r29 + + ldo PT_FR0(%r29), %r24 + save_fp %r24 + + loadgp + + copy %r29, %r24 /* arg2 is pt_regs */ + copy %r29, %r16 /* save pt_regs */ +#ifdef CONFIG_KWDB + copy %r29, %r3 /* KWDB - update frame pointer (gr3) */ +#endif + + /* sorry to put this cruft in the interrupt path */ + ldil L%cpu_irq_region, %r25 + ldo R%cpu_irq_region(%r25), %r25 + bl do_irq_mask,%r2 +#ifdef __LP64__ + LDIL_FIXUP(%r25) +#else + nop +#endif + + b intr_return + nop + + /* Generic interruptions (illegal insn, unaligned, page fault, etc) */ + + .export intr_save, code /* for os_hpmc */ + +intr_save: + get_stack + save_specials %r29 + + mfctl %cr20, %r1 + STREG %r1, PT_ISR(%r29) + mfctl %cr21, %r1 + STREG %r1, PT_IOR(%r29) + + virt_map rfi + save_general %r29 + + ldo PT_FR0(%r29), %r25 + save_fp %r25 + + loadgp + + copy %r29, %r25 /* arg1 is pt_regs */ +#ifdef CONFIG_KWDB + copy %r29, %r3 /* KWDB - update frame pointer (gr3) */ +#endif + + bl handle_interruption,%r2 + copy %r29, %r16 /* save pt_regs */ + + b intr_return + nop + + /* + * Note for all tlb miss handlers: + * + * cr24 contains a pointer to the kernel address space + * page directory. + * + * cr25 contains a pointer to the current user address + * space page directory. + * + * sr3 will contain the space id of the user address space + * of the current running thread while that thread is + * running in the kernel. + */ + + /* + * register number allocations. Note that these are all + * in the shadowed registers + */ + + t0 = r1 /* temporary register 0 */ + va = r8 /* virtual address for which the trap occured */ + t1 = r9 /* temporary register 1 */ + pte = r16 /* pte/phys page # */ + prot = r17 /* prot bits */ + spc = r24 /* space for which the trap occured */ + ptp = r25 /* page directory/page table pointer */ + +#ifdef __LP64__ + +dtlb_miss_20w: + + extrd,u spc,31,7,t1 /* adjust va */ + depd t1,31,7,va /* adjust va */ + depdi 0,31,7,spc /* adjust space */ + mfctl %cr25,ptp /* Assume user space miss */ + or,*<> %r0,spc,%r0 /* If it is user space, nullify */ + mfctl %cr24,ptp /* Load kernel pgd instead */ + extrd,u va,33,9,t1 /* Get pgd index */ + + mfsp %sr7,t0 /* Get current space */ + or,*= %r0,t0,%r0 /* If kernel, nullify following test */ + comb,<>,n t0,spc,dtlb_fault /* forward */ + + /* First level page table lookup */ + + ldd,s t1(ptp),ptp + extrd,u va,42,9,t0 /* get second-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_fault + depdi 0,63,12,ptp /* clear prot bits */ + + /* Second level page table lookup */ + + ldd,s t0(ptp),ptp + extrd,u va,51,9,t0 /* get third-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_fault + depdi 0,63,12,ptp /* clear prot bits */ + + /* Third level page table lookup */ + + shladd t0,3,ptp,ptp + ldi _PAGE_ACCESSED,t1 + ldd 0(ptp),pte + bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_fault + + /* Check whether the "accessed" bit was set, otherwise do so */ + + or t1,pte,t0 /* t0 has R bit set */ + and,*<> t1,pte,%r0 /* test and nullify if already set */ + std t0,0(ptp) /* write back pte */ + + copy spc,prot /* init prot with faulting space */ + + depd pte,8,7,prot + extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0 + depdi 1,12,1,prot + extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0 + depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */ + extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0 + depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */ + + /* Get rid of prot bits and convert to page addr for idtlbt */ + + depdi 0,63,12,pte + extrd,u pte,56,32,pte + idtlbt %r16,%r17 + + rfir + nop +#else + +dtlb_miss_11: + mfctl %cr25,ptp /* Assume user space miss */ + or,<> %r0,spc,%r0 /* If it is user space, nullify */ + mfctl %cr24,ptp /* Load kernel pgd instead */ + extru va,9,10,t1 /* Get pgd index */ + + mfsp %sr7,t0 /* Get current space */ + or,= %r0,t0,%r0 /* If kernel, nullify following test */ + comb,<>,n t0,spc,dtlb_fault /* forward */ + + /* First level page table lookup */ + + ldwx,s t1(ptp),ptp + extru va,19,10,t0 /* get second-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_fault + depi 0,31,12,ptp /* clear prot bits */ + + /* Second level page table lookup */ + + sh2addl t0,ptp,ptp + ldi _PAGE_ACCESSED,t1 + ldw 0(ptp),pte + bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_fault + + /* Check whether the "accessed" bit was set, otherwise do so */ + + or t1,pte,t0 /* t0 has R bit set */ + and,<> t1,pte,%r0 /* test and nullify if already set */ + stw t0,0(ptp) /* write back pte */ + + copy spc,prot /* init prot with faulting space */ + dep pte,8,7,prot + + extru,= pte,_PAGE_NO_CACHE_BIT,1,r0 + depi 1,12,1,prot + extru,= pte,_PAGE_USER_BIT,1,r0 + depi 7,11,3,prot /* Set for user space (1 rsvd for read) */ + extru,= pte,_PAGE_GATEWAY_BIT,1,r0 + depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */ + + /* Get rid of prot bits and convert to page addr for idtlba */ + + depi 0,31,12,pte + extru pte,24,25,pte + + mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */ + mtsp spc,%sr1 + + idtlba pte,(%sr1,va) + idtlbp prot,(%sr1,va) + + mtsp t0, %sr1 /* Restore sr1 */ + + rfir + nop + +dtlb_miss_20: + .level 2.0 + + mfctl %cr25,ptp /* Assume user space miss */ + or,<> %r0,spc,%r0 /* If it is user space, nullify */ + mfctl %cr24,ptp /* Load kernel pgd instead */ + extru va,9,10,t1 /* Get pgd index */ + + mfsp %sr7,t0 /* Get current space */ + or,= %r0,t0,%r0 /* If kernel, nullify following test */ + comb,<>,n t0,spc,dtlb_fault /* forward */ + + /* First level page table lookup */ + + ldwx,s t1(ptp),ptp + extru va,19,10,t0 /* get second-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_fault + depi 0,31,12,ptp /* clear prot bits */ + + /* Second level page table lookup */ + + sh2addl t0,ptp,ptp + ldi _PAGE_ACCESSED,t1 + ldw 0(ptp),pte + bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_fault + + /* Check whether the "accessed" bit was set, otherwise do so */ + + or t1,pte,t0 /* t0 has R bit set */ + and,<> t1,pte,%r0 /* test and nullify if already set */ + stw t0,0(ptp) /* write back pte */ + + copy spc,prot /* init prot with faulting space */ + + depd pte,8,7,prot + extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0 + depdi 1,12,1,prot + extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0 + depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */ + extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0 + depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */ + + /* Get rid of prot bits and convert to page addr for idtlbt */ + + depdi 0,63,12,pte + extrd,u pte,56,25,pte + idtlbt %r16,%r17 + + .level 1.1 + + rfir + nop +#endif + +#ifdef __LP64__ +itlb_miss_20w: + + /* + * I miss is a little different, since we allow users to fault + * on the gateway page which is in the kernel address space. + */ + + extrd,u spc,31,7,t1 /* adjust va */ + depd t1,31,7,va /* adjust va */ + depdi 0,31,7,spc /* adjust space */ + cmpib,*= 0,spc,itlb_miss_kernel_20w + extrd,u va,33,9,t1 /* Get pgd index */ + + mfctl %cr25,ptp /* load user pgd */ + + mfsp %sr7,t0 /* Get current space */ + or,*= %r0,t0,%r0 /* If kernel, nullify following test */ + cmpb,*<>,n t0,spc,itlb_fault /* forward */ + + /* First level page table lookup */ + +itlb_miss_common_20w: + ldd,s t1(ptp),ptp + extrd,u va,42,9,t0 /* get second-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault + depdi 0,63,12,ptp /* clear prot bits */ + + /* Second level page table lookup */ + + ldd,s t0(ptp),ptp + extrd,u va,51,9,t0 /* get third-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault + depdi 0,63,12,ptp /* clear prot bits */ + + /* Third level page table lookup */ + + shladd t0,3,ptp,ptp + ldi _PAGE_ACCESSED,t1 + ldd 0(ptp),pte + bb,>=,n pte,_PAGE_PRESENT_BIT,itlb_fault + + /* Check whether the "accessed" bit was set, otherwise do so */ + + or t1,pte,t0 /* t0 has R bit set */ + and,*<> t1,pte,%r0 /* test and nullify if already set */ + std t0,0(ptp) /* write back pte */ + + copy spc,prot /* init prot with faulting space */ + + depd pte,8,7,prot + extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0 + depdi 1,12,1,prot + extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0 + depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */ + extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0 + depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */ + + /* Get rid of prot bits and convert to page addr for iitlbt */ + + depdi 0,63,12,pte + extrd,u pte,56,32,pte + iitlbt %r16,%r17 + + rfir + nop + +itlb_miss_kernel_20w: + b itlb_miss_common_20w + mfctl %cr24,ptp /* Load kernel pgd */ +#else + +itlb_miss_11: + + /* + * I miss is a little different, since we allow users to fault + * on the gateway page which is in the kernel address space. + */ + + comib,= 0,spc,itlb_miss_kernel_11 + extru va,9,10,t1 /* Get pgd index */ + + mfctl %cr25,ptp /* load user pgd */ + + mfsp %sr7,t0 /* Get current space */ + or,= %r0,t0,%r0 /* If kernel, nullify following test */ + comb,<>,n t0,spc,itlb_fault /* forward */ + + /* First level page table lookup */ + +itlb_miss_common_11: + ldwx,s t1(ptp),ptp + extru va,19,10,t0 /* get second-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault + depi 0,31,12,ptp /* clear prot bits */ + + /* Second level page table lookup */ + + sh2addl t0,ptp,ptp + ldi _PAGE_ACCESSED,t1 + ldw 0(ptp),pte + bb,>=,n pte,_PAGE_PRESENT_BIT,itlb_fault + + /* Check whether the "accessed" bit was set, otherwise do so */ + + or t1,pte,t0 /* t0 has R bit set */ + and,<> t1,pte,%r0 /* test and nullify if already set */ + stw t0,0(ptp) /* write back pte */ + + copy spc,prot /* init prot with faulting space */ + dep pte,8,7,prot + + extru,= pte,_PAGE_NO_CACHE_BIT,1,r0 + depi 1,12,1,prot + extru,= pte,_PAGE_USER_BIT,1,r0 + depi 7,11,3,prot /* Set for user space (1 rsvd for read) */ + extru,= pte,_PAGE_GATEWAY_BIT,1,r0 + depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */ + + /* Get rid of prot bits and convert to page addr for iitlba */ + + depi 0,31,12,pte + extru pte,24,25,pte + + mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */ + mtsp spc,%sr1 + + iitlba pte,(%sr1,va) + iitlbp prot,(%sr1,va) + + mtsp t0, %sr1 /* Restore sr1 */ + + rfir + nop + +itlb_miss_kernel_11: + b itlb_miss_common_11 + mfctl %cr24,ptp /* Load kernel pgd */ + +itlb_miss_20: + + /* + * I miss is a little different, since we allow users to fault + * on the gateway page which is in the kernel address space. + */ + + comib,= 0,spc,itlb_miss_kernel_20 + extru va,9,10,t1 /* Get pgd index */ + + mfctl %cr25,ptp /* load user pgd */ + + mfsp %sr7,t0 /* Get current space */ + or,= %r0,t0,%r0 /* If kernel, nullify following test */ + comb,<>,n t0,spc,itlb_fault /* forward */ + + /* First level page table lookup */ + +itlb_miss_common_20: + ldwx,s t1(ptp),ptp + extru va,19,10,t0 /* get second-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault + depi 0,31,12,ptp /* clear prot bits */ + + /* Second level page table lookup */ + + sh2addl t0,ptp,ptp + ldi _PAGE_ACCESSED,t1 + ldw 0(ptp),pte + bb,>=,n pte,_PAGE_PRESENT_BIT,itlb_fault + + /* Check whether the "accessed" bit was set, otherwise do so */ + + or t1,pte,t0 /* t0 has R bit set */ + and,<> t1,pte,%r0 /* test and nullify if already set */ + stw t0,0(ptp) /* write back pte */ + + copy spc,prot /* init prot with faulting space */ + + .level 2.0 + + depd pte,8,7,prot + extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0 + depdi 1,12,1,prot + extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0 + depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */ + extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0 + depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */ + + /* Get rid of prot bits and convert to page addr for iitlbt */ + + depdi 0,63,12,pte + extrd,u pte,56,25,pte + iitlbt %r16,%r17 + .level 1.1 + + rfir + nop + + +itlb_miss_kernel_20: + b itlb_miss_common_20 + mfctl %cr24,ptp /* Load kernel pgd */ +#endif + +#ifdef __LP64__ + +dbit_trap_20w: + + extrd,u spc,31,7,t1 /* adjust va */ + depd t1,31,7,va /* adjust va */ + depdi 0,1,2,va /* adjust va */ + depdi 0,31,7,spc /* adjust space */ + mfctl %cr25,ptp /* Assume user space miss */ + or,*<> %r0,spc,%r0 /* If it is user space, nullify */ + mfctl %cr24,ptp /* Load kernel pgd instead */ + extrd,u va,33,9,t1 /* Get pgd index */ + + mfsp %sr7,t0 /* Get current space */ + or,*= %r0,t0,%r0 /* If kernel, nullify following test */ + comb,<>,n t0,spc,dbit_fault /* forward */ + + /* First level page table lookup */ + + ldd,s t1(ptp),ptp + extrd,u va,42,9,t0 /* get second-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault + depdi 0,63,12,ptp /* clear prot bits */ + + /* Second level page table lookup */ + + ldd,s t0(ptp),ptp + extrd,u va,51,9,t0 /* get third-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault + depdi 0,63,12,ptp /* clear prot bits */ + + /* Third level page table lookup */ + + shladd t0,3,ptp,ptp + ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1 + ldd 0(ptp),pte + bb,>=,n pte,_PAGE_PRESENT_BIT,dbit_fault + + /* Set Accessed and Dirty bits in the pte */ + + or t1,pte,pte + std pte,0(ptp) /* write back pte */ + + copy spc,prot /* init prot with faulting space */ + + depd pte,8,7,prot + extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0 + depdi 1,12,1,prot + extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0 + depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */ + extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0 + depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */ + + /* Get rid of prot bits and convert to page addr for idtlbt */ + + depdi 0,63,12,pte + extrd,u pte,56,32,pte + idtlbt %r16,%r17 + + rfir + nop +#else + +dbit_trap_11: + mfctl %cr25,ptp /* Assume user space trap */ + or,<> %r0,spc,%r0 /* If it is user space, nullify */ + mfctl %cr24,ptp /* Load kernel pgd instead */ + extru va,9,10,t1 /* Get pgd index */ + + mfsp %sr7,t0 /* Get current space */ + or,= %r0,t0,%r0 /* If kernel, nullify following test */ + comb,<>,n t0,spc,dbit_fault /* forward */ + + /* First level page table lookup */ + + ldwx,s t1(ptp),ptp + extru va,19,10,t0 /* get second-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault + depi 0,31,12,ptp /* clear prot bits */ + + /* Second level page table lookup */ + + sh2addl t0,ptp,ptp + ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1 + ldw 0(ptp),pte + bb,>=,n pte,_PAGE_PRESENT_BIT,dbit_fault + + /* Set Accessed and Dirty bits in the pte */ + + or t1,pte,pte + stw pte,0(ptp) /* write back pte */ + + copy spc,prot /* init prot with faulting space */ + dep pte,8,7,prot + + extru,= pte,_PAGE_NO_CACHE_BIT,1,r0 + depi 1,12,1,prot + extru,= pte,_PAGE_USER_BIT,1,r0 + depi 7,11,3,prot /* Set for user space (1 rsvd for read) */ + extru,= pte,_PAGE_GATEWAY_BIT,1,r0 + depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */ + + /* Get rid of prot bits and convert to page addr for idtlba */ + + depi 0,31,12,pte + extru pte,24,25,pte + + mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */ + mtsp spc,%sr1 + + idtlba pte,(%sr1,va) + idtlbp prot,(%sr1,va) + + mtsp t0, %sr1 /* Restore sr1 */ + + rfir + nop + +dbit_trap_20: + mfctl %cr25,ptp /* Assume user space trap */ + or,<> %r0,spc,%r0 /* If it is user space, nullify */ + mfctl %cr24,ptp /* Load kernel pgd instead */ + extru va,9,10,t1 /* Get pgd index */ + + mfsp %sr7,t0 /* Get current space */ + or,= %r0,t0,%r0 /* If kernel, nullify following test */ + comb,<>,n t0,spc,dbit_fault /* forward */ + + /* First level page table lookup */ + + ldwx,s t1(ptp),ptp + extru va,19,10,t0 /* get second-level index */ + bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault + depi 0,31,12,ptp /* clear prot bits */ + + /* Second level page table lookup */ + + sh2addl t0,ptp,ptp + ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1 + ldw 0(ptp),pte + bb,>=,n pte,_PAGE_PRESENT_BIT,dbit_fault + + /* Set Accessed and Dirty bits in the pte */ + + or t1,pte,pte + stw pte,0(ptp) /* write back pte */ + + copy spc,prot /* init prot with faulting space */ + + .level 2.0 + + depd pte,8,7,prot + extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0 + depdi 1,12,1,prot + extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0 + depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */ + extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0 + depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */ + + /* Get rid of prot bits and convert to page addr for idtlbt */ + + depdi 0,63,12,pte + extrd,u pte,56,25,pte + idtlbt %r16,%r17 + + .level 1.1 + + rfir + nop +#endif + + .import handle_interruption,code + +kernel_bad_space: + b tlb_fault + ldi 31,%r1 /* Use an unused code */ + +dbit_fault: + b tlb_fault + ldi 20,%r1 + +itlb_fault: + b tlb_fault + ldi 6,%r1 + +dtlb_fault: + ldi 15,%r1 + + /* Fall Through */ + +tlb_fault: + mtctl %r1,%cr29 + mtctl %r29,%cr31 + + get_stack + save_specials %r29 /* Note this saves a trashed r1 */ + + SAVE_CR (%cr20, PT_ISR(%r29)) + SAVE_CR (%cr21, PT_IOR(%r29)) + + virt_map rfir + + STREG %r1,PT_GR1(%r29) /* save good value after rfir */ + + save_general %r29 + + ldo PT_FR0(%r29), %r25 + save_fp %r25 + + loadgp + + copy %r29, %r25 + + bl handle_interruption, %r2 + copy %r29, %r16 + + b intr_return + nop + + /* Register saving semantics for system calls: + + %r1 clobbered by system call macro in userspace + %r2 saved in PT_REGS by gateway page + %r3 - %r18 preserved by C code (saved by signal code) + %r19 - %r20 saved in PT_REGS by gateway page + %r21 - %r22 non-standard syscall args + stored in kernel stack by gateway page + %r23 - %r26 arg3-arg0, saved in PT_REGS by gateway page + %r27 - %r30 saved in PT_REGS by gateway page + %r31 syscall return pointer + */ + + /* Floating point registers (FIXME: what do we do with these?) + + %fr0 - %fr3 status/exception, not preserved + %fr4 - %fr7 arguments + %fr8 - %fr11 not preserved by C code + %fr12 - %fr21 preserved by C code + %fr22 - %fr31 not preserved by C code + */ + + .macro reg_save regs + STREG %r3, PT_GR3(\regs) + STREG %r4, PT_GR4(\regs) + STREG %r5, PT_GR5(\regs) + STREG %r6, PT_GR6(\regs) + STREG %r7, PT_GR7(\regs) + STREG %r8, PT_GR8(\regs) + STREG %r9, PT_GR9(\regs) + STREG %r10,PT_GR10(\regs) + STREG %r11,PT_GR11(\regs) + STREG %r12,PT_GR12(\regs) + STREG %r13,PT_GR13(\regs) + STREG %r14,PT_GR14(\regs) + STREG %r15,PT_GR15(\regs) + STREG %r16,PT_GR16(\regs) + STREG %r17,PT_GR17(\regs) + STREG %r18,PT_GR18(\regs) + .endm + + .macro reg_restore regs + LDREG PT_GR3(\regs), %r3 + LDREG PT_GR4(\regs), %r4 + LDREG PT_GR5(\regs), %r5 + LDREG PT_GR6(\regs), %r6 + LDREG PT_GR7(\regs), %r7 + LDREG PT_GR8(\regs), %r8 + LDREG PT_GR9(\regs), %r9 + LDREG PT_GR10(\regs),%r10 + LDREG PT_GR11(\regs),%r11 + LDREG PT_GR12(\regs),%r12 + LDREG PT_GR13(\regs),%r13 + LDREG PT_GR14(\regs),%r14 + LDREG PT_GR15(\regs),%r15 + LDREG PT_GR16(\regs),%r16 + LDREG PT_GR17(\regs),%r17 + LDREG PT_GR18(\regs),%r18 + .endm + + .export sys_fork_wrapper +sys_fork_wrapper: + ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get pt regs */ + reg_save %r1 + + STREG %r2,-RP_OFFSET(%r30) + ldo FRAME_SIZE(%r30),%r30 + + /* These are call-clobbered registers and therefore + also syscall-clobbered (we hope). */ + STREG %r2,PT_GR19(%r1) /* save for child */ + STREG %r30,PT_GR20(%r1) + ldil L%child_return, %r3 + ldo R%child_return(%r3), %r3 + LDIL_FIXUP(%r3) + STREG %r3,PT_GR21(%r1) /* save for child */ + + LDREG PT_GR30(%r1),%r25 + copy %r1,%r24 + bl sys_clone,%r2 + ldi SIGCHLD,%r26 + + LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2 +wrapper_exit: + ldo -FRAME_SIZE(%r30),%r30 /* get the stackframe */ + ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get pt regs */ + + reg_restore %r1 + + bv %r0(%r2) + nop + + /* Set the return value for the child */ +child_return: + LDREG TASK_PT_GR19-TASK_SZ_ALGN-128(%r30),%r2 + b wrapper_exit + copy %r0,%r28 + + + .export sys_clone_wrapper +sys_clone_wrapper: + ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get pt regs */ + reg_save %r1 + + STREG %r2,-RP_OFFSET(%r30) + ldo FRAME_SIZE(%r30),%r30 + + STREG %r30,PT_GR20(%r1) + ldil L%child_return,%r3 + ldo R%child_return(%r3),%r3 + LDIL_FIXUP(%r3) + + bl sys_clone,%r2 + STREG %r3,PT_GR21(%r1) /* save for child */ + + b wrapper_exit + LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2 + + + .export sys_vfork_wrapper +sys_vfork_wrapper: + ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get pt regs */ + reg_save %r1 + + STREG %r2,-RP_OFFSET(%r30) + ldo FRAME_SIZE(%r30),%r30 + + STREG %r30,PT_GR20(%r1) + ldil L%child_return,%r3 + ldo R%child_return(%r3),%r3 + LDIL_FIXUP(%r3) + STREG %r3,PT_GR21(%r1) /* save for child */ + + bl sys_vfork,%r2 + copy %r1,%r26 + + b wrapper_exit + LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2 + + + .macro execve_wrapper execve + ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get pt regs */ + + /* + * Do we need to save/restore r3-r18 here? + * I don't think so. why would new thread need old + * threads registers? + */ + + /* %arg0 - %arg3 are already saved for us. */ + + STREG %r2,-RP_OFFSET(%r30) + ldo FRAME_SIZE(%r30),%r30 + bl \execve,%r2 + copy %r1,%arg0 + + ldo -FRAME_SIZE(%r30),%r30 + LDREG -RP_OFFSET(%r30),%r2 + + /* If exec succeeded we need to load the args */ + + ldo -1024(%r0),%r1 + comb,>>= %r28,%r1,error_\execve + copy %r2,%r19 + +error_\execve: + bv %r0(%r19) + nop + .endm + + .export sys_execve_wrapper + .import sys_execve + +sys_execve_wrapper: + execve_wrapper sys_execve + +#ifdef __LP64__ + .export sys32_execve_wrapper + .import sys32_execve + +sys32_execve_wrapper: + execve_wrapper sys32_execve +#endif + + .export sys_rt_sigreturn_wrapper +sys_rt_sigreturn_wrapper: + ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30), %r26 + /* Don't save regs, we are going to restore them from sigcontext. */ + STREG %r2, -RP_OFFSET(%r30) + bl sys_rt_sigreturn,%r2 + ldo FRAME_SIZE(%r30), %r30 + + ldo -FRAME_SIZE(%r30), %r30 + LDREG -RP_OFFSET(%r30), %r2 + + /* FIXME: I think we need to restore a few more things here. */ + ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get pt regs */ + reg_restore %r1 + + /* If the signal was received while the process was blocked on a + * syscall, then r2 will take us to syscall_exit; otherwise r2 will + * take us to syscall_exit_rfi and on to intr_return. + */ + bv %r0(%r2) + LDREG PT_GR28(%r1),%r28 /* reload original r28 for syscall_exit */ + + .export sys_sigaltstack_wrapper +sys_sigaltstack_wrapper: + /* Get the user stack pointer */ + LDREG -TASK_SZ_ALGN-FRAME_SIZE+TASK_PT_GR30(%r30), %r24 + STREG %r2, -RP_OFFSET(%r30) + bl do_sigaltstack,%r2 + ldo FRAME_SIZE(%r30), %r30 + + ldo -FRAME_SIZE(%r30), %r30 + LDREG -RP_OFFSET(%r30), %r2 + bv %r0(%r2) + nop + + .export sys_rt_sigsuspend_wrapper +sys_rt_sigsuspend_wrapper: + ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30), %r24 + reg_save %r24 + + STREG %r2, -RP_OFFSET(%r30) + bl sys_rt_sigsuspend,%r2 + ldo FRAME_SIZE(%r30), %r30 + + ldo -FRAME_SIZE(%r30), %r30 + LDREG -RP_OFFSET(%r30), %r2 + + ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 + reg_restore %r1 + + bv %r0(%r2) + nop + + .export syscall_exit +syscall_exit: + /* NOTE: HP-UX syscalls also come through here + after hpux_syscall_exit fixes up return + values. */ + /* NOTE: Not all syscalls exit this way. rt_sigreturn will exit + * via syscall_exit_rfi if the signal was received while the process + * was running. All traced processes will probably exit via + * syscall_exit_rfi in the future. + */ + + /* save return value now */ + + STREG %r28,TASK_PT_GR28-TASK_SZ_ALGN-FRAME_SIZE(%r30) + +syscall_check_bh: + +/* #ifdef NOTNOW */ + /* Check for software interrupts */ + + .import irq_stat,data + + ldil L%irq_stat,%r19 + ldo R%irq_stat(%r19),%r19 + LDIL_FIXUP(%r19) + +#ifdef CONFIG_SMP + /* sched.h: int processor */ + ldw TASK_PROCESSOR-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r20 /* get cpu # */ +#if (IRQSTAT_SZ == 32) + dep %r20,26,27,%r20 /* shift left 5 bits */ +#else +#error IRQSTAT_SZ changed, fix dep +#endif /* IRQSTAT_SZ */ + add %r19,%r20,%r19 +#endif /* CONFIG_SMP */ + + ldw IRQSTAT_SI_ACTIVE(%r19),%r20 /* hardirq.h: unsigned int */ + ldw IRQSTAT_SI_MASK(%r19),%r19 /* hardirq.h: unsigned int */ + and %r19,%r20,%r20 + comib,<>,n 0,%r20,syscall_do_softirq /* forward */ +/* #endif */ + + +syscall_check_resched: + + /* check for reschedule */ + + LDREG TASK_NEED_RESCHED-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r19 /* long */ + comib,<>,n 0,%r19,syscall_do_resched /* forward */ + +syscall_check_sig: + ldo -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */ + /* check for pending signals */ + ldw TASK_SIGPENDING(%r1),%r19 + comib,<>,n 0,%r19,syscall_do_signal /* forward */ + +syscall_restore: + /* disable interrupts while dicking with the kernel stack, */ + /* or life can become unpleasant */ + rsm PSW_SM_I, %r20 + LDREG TASK_PTRACE(%r1), %r19 /* Are we being ptraced? */ + bb,<,n %r19,31,syscall_restore_rfi + LDREG TASK_PT_GR20(%r1),%r19 + mtctl %r19, %cr27 + + LDREG TASK_PT_GR2(%r1),%r2 /* restore user rp */ + LDREG TASK_PT_GR21(%r1),%r21 + LDREG TASK_PT_GR22(%r1),%r22 + LDREG TASK_PT_GR23(%r1),%r23 + LDREG TASK_PT_GR24(%r1),%r24 + LDREG TASK_PT_GR25(%r1),%r25 + LDREG TASK_PT_GR26(%r1),%r26 + LDREG TASK_PT_GR27(%r1),%r27 /* restore user dp */ + LDREG TASK_PT_GR28(%r1),%r28 /* syscall return value */ + LDREG TASK_PT_GR29(%r1),%r29 + LDREG TASK_PT_GR30(%r1),%r30 /* restore user sp */ + LDREG TASK_PT_GR31(%r1),%r31 /* restore syscall rp */ + ldo TASK_PT_FR31(%r1),%r19 /* reload fpregs */ + rest_fp %r19 + LDREG TASK_PT_SAR(%r1),%r19 /* restore SAR */ + mtsar %r19 + LDREG TASK_PT_GR19(%r1),%r19 + + mtctl %r1,%cr30 /* intrhandler okay. */ + mfsp %sr3,%r1 /* Get users space id */ + mtsp %r1,%sr4 /* Restore sr4 */ + mtsp %r1,%sr5 /* Restore sr5 */ + mtsp %r1,%sr6 /* Restore sr6 */ + + depi 3,31,2,%r31 /* ensure return to user mode. */ + + mtsm %r20 /* restore irq state */ + mfctl %cr27,%r20 + + /* + * Due to a dependency in the tlb miss handlers on sr7, it + * is essential that sr7 get set in the delay slot. + */ + +#ifdef __LP64__ + + /* Note the be (and mtsp) is executed in narrow mode. This is OK + * for 32 bit processes, but won't work once we support 64 bit + * processes. + */ + + rsm PSW_SM_W, %r0 + be 0(%sr3,%r31) /* return to user space */ + mtsp %r1,%sr7 /* Restore sr7 */ +#else + be 0(%sr3,%r31) /* return to user space */ + mtsp %r1,%sr7 /* Restore sr7 */ +#endif + + /* We have to return via an RFI, so that PSW T and R bits can be set + * appropriately. + * This sets up pt_regs so we can return via intr_restore, which is not + * the most efficient way of doing things, but it works. + */ +syscall_restore_rfi: + ldo -1(%r0),%r2 /* Set recovery cntr to -1 */ + mtctl %r2,%cr0 /* for immediate trap */ + copy %r0,%r2 /* Create a reasonable PSW */ + /* XXX W bit??? */ + depi -1,13,1,%r2 + depi -1,28,1,%r2 + depi -1,30,1,%r2 + depi -1,31,1,%r2 + bb,<,n %r19,15,set_rbit /* PT_SINGLESTEP */ + bb,>=,n %r19,14,set_nobit /* PT_BLOCKSTEP, see ptrace.c */ +set_tbit: + depi -1,7,1,%r2 + b,n set_nobit +set_rbit: + depi -1,27,1,%r2 +set_nobit: + STREG %r2,TASK_PT_PSW(%r1) + STREG %r1,TASK_PT_CR30(%r1) + mfsp %sr0,%r2 + STREG %r2,TASK_PT_SR0(%r1) + mfsp %sr1,%r2 + STREG %r2,TASK_PT_SR1(%r1) + mfsp %sr2,%r2 + STREG %r2,TASK_PT_SR2(%r1) + mfsp %sr3,%r2 + STREG %r2,TASK_PT_SR3(%r1) + STREG %r2,TASK_PT_SR4(%r1) + STREG %r2,TASK_PT_SR5(%r1) + STREG %r2,TASK_PT_SR6(%r1) + STREG %r2,TASK_PT_SR7(%r1) + STREG %r2,TASK_PT_IASQ0(%r1) + STREG %r2,TASK_PT_IASQ1(%r1) + LDREG TASK_PT_GR31(%r1),%r2 + depi 3,31,2,%r2 /* ensure return to user mode. */ + STREG %r2,TASK_PT_IAOQ0(%r1) + ldo 4(%r2),%r2 + STREG %r2,TASK_PT_IAOQ1(%r1) + ldo TASK_REGS(%r1),%r25 + reg_save %r25 /* Save r3 to r18 */ + copy %r25,%r16 + b intr_restore + nop + + .import do_softirq,code +syscall_do_softirq: + bl do_softirq,%r2 + nop + b syscall_check_resched + ssm PSW_SM_I, %r0 /* do_softirq returns with I bit off */ + + .import schedule,code +syscall_do_resched: + bl schedule,%r2 + nop + b syscall_check_bh /* if resched, we start over again */ + nop + + .import do_signal,code +syscall_do_signal: + /* Save callee-save registers (for sigcontext). + FIXME: After this point the process structure should be + consistent with all the relevant state of the process + before the syscall. We need to verify this. */ + ldo TASK_REGS(%r1), %r25 /* struct pt_regs *regs */ + reg_save %r25 + + ldi 1, %r24 /* unsigned long in_syscall */ + + bl do_signal,%r2 + copy %r0, %r26 /* sigset_t *oldset = NULL */ + + ldo -TASK_SZ_ALGN-FRAME_SIZE(%r30), %r1 /* reload task ptr */ + ldo TASK_REGS(%r1), %r20 /* reload pt_regs */ + reg_restore %r20 + + b,n syscall_restore + +#ifdef __LP64__ +unimplemented_64bitirq: + ssm PSW_SM_Q+PSW_SM_I, %r0 + /* indicate that we had an interrupt */ + ldi 0x77, %r28 + ldi 0x77, %r29 + /* save interrupt registers in GRs for diagnosis */ + mfctl %cr17, %r17 + mfctl %cr18, %r18 + mfctl %cr19, %r19 + mfctl %cr20, %r20 + mfctl %cr21, %r21 + mfctl %cr22, %r22 + b,n . + nop +#endif diff --git a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c new file mode 100644 index 000000000..75d5c6695 --- /dev/null +++ b/arch/parisc/kernel/hardware.c @@ -0,0 +1,1446 @@ +/* + * Hardware descriptions for HP 9000 based hardware, including + * system types, SCSI controllers, DMA controllers, HPPB controllers + * and lots more. + * + * Based on the document "PA-RISC 1.1 I/O Firmware Architecture + * Reference Specification", March 7, 1999, version 0.96. This + * is available at ?. + * + * Copyright 1999 by Alex deVries <adevries@thepuffingroup.com> + * and copyright 1999 The Puffin Group Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include <asm/hardware.h> +#include <linux/stddef.h> +#include <linux/kernel.h> + +#define HPHW_NUM_TYPES 3431 + +static char * hw_type_name[16] = { + "Processor", + "Memory", + "B DMA", + "Obsolete", + "A DMA", + "A Direct", + "Obsolete", + "Bus Converter Port", + "HP CIO Adapter", + "Console", + "Foreign I/O Module", + "Bus Adapter", + "IOA (?)", + "Bus Bridge to Foreign Bus", + "HP Clothing: Fabric Component" +}; + +/* + * XXX Could this be __init ?? + */ + +static struct hp_hardware hp_hardware_list[] = { + {HPHW_NPROC,0x01,0x4,0x0,"Indigo (840, 930)"}, + {HPHW_NPROC,0x8,0x4,0x01,"Firefox(825,925)"}, + {HPHW_NPROC,0xA,0x4,0x01,"Top Gun (835,834,935,635)"}, + {HPHW_NPROC,0xB,0x4,0x01,"Technical Shogun (845, 645)"}, + {HPHW_NPROC,0xF,0x4,0x01,"Commercial Shogun (949)"}, + {HPHW_NPROC,0xC,0x4,0x01,"Cheetah (850, 950)"}, + {HPHW_NPROC,0x80,0x4,0x01,"Cheetah (950S)"}, + {HPHW_NPROC,0x81,0x4,0x01,"Jaguar (855, 955)"}, + {HPHW_NPROC,0x82,0x4,0x01,"Cougar (860, 960)"}, + {HPHW_NPROC,0x83,0x4,0x13,"Panther (865, 870, 980)"}, + {HPHW_NPROC,0x100,0x4,0x01,"Burgundy (810)"}, + {HPHW_NPROC,0x101,0x4,0x01,"SilverFox Low (822, 922)"}, + {HPHW_NPROC,0x102,0x4,0x01,"SilverFox High (832, 932)"}, + {HPHW_NPROC,0x103,0x4,0x01,"Lego, SilverLite (815, 808, 920)"}, + {HPHW_NPROC,0x104,0x4,0x03,"SilverBullet Low (842, 948)"}, + {HPHW_NPROC,0x105,0x4,0x03,"SilverBullet High (852, 958)"}, + {HPHW_NPROC,0x106,0x4,0x81,"Oboe"}, + {HPHW_NPROC,0x180,0x4,0x12,"Dragon"}, + {HPHW_NPROC,0x181,0x4,0x13,"Chimera (890, 990, 992)"}, + {HPHW_NPROC,0x182,0x4,0x91,"TNT 100 (891,T500)"}, + {HPHW_NPROC,0x183,0x4,0x91,"TNT 120 (892,T520)"}, + {HPHW_NPROC,0x184,0x4,0x91,"Jade 180 U (893,T540)"}, + {HPHW_NPROC,0x1FF,0x4,0x91,"Hitachi X Processor"}, + {HPHW_NPROC,0x200,0x4,0x81,"Cobra (720)"}, + {HPHW_NPROC,0x201,0x4,0x81,"Coral (750)"}, + {HPHW_NPROC,0x202,0x4,0x81,"King Cobra (730)"}, + {HPHW_NPROC,0x203,0x4,0x81,"Hardball (735/99)"}, + {HPHW_NPROC,0x204,0x4,0x81,"Coral II (755/99)"}, + {HPHW_NPROC,0x205,0x4,0x81,"Coral II (755/125)"}, + {HPHW_NPROC,0x205,0x4,0x91,"Snake Eagle "}, + {HPHW_NPROC,0x206,0x4,0x81,"Snake Cheetah (735/130)"}, + {HPHW_NPROC,0x280,0x4,0x81,"Nova Low (817, 827, 957, 957LX)"}, + {HPHW_NPROC,0x281,0x4,0x81,"Nova High (837, 847, 857, 967, 967LX)"}, + {HPHW_NPROC,0x282,0x4,0x81,"Nova8 (807, 917, 917LX, 927,927LX, 937, 937LX, 947,947LX)"}, + {HPHW_NPROC,0x283,0x4,0x81,"Nova64 (867, 877, 977)"}, + {HPHW_NPROC,0x284,0x4,0x81,"TNova (887, 897, 987)"}, + {HPHW_NPROC,0x285,0x4,0x81,"TNova64"}, + {HPHW_NPROC,0x286,0x4,0x91,"Hydra64 (Nova)"}, + {HPHW_NPROC,0x287,0x4,0x91,"Hydra96 (Nova)"}, + {HPHW_NPROC,0x288,0x4,0x81,"TNova96"}, + {HPHW_NPROC,0x300,0x4,0x81,"Bushmaster (710)"}, + {HPHW_NPROC,0x302,0x4,0x81,"Flounder (705)"}, + {HPHW_NPROC,0x310,0x4,0x81,"Scorpio (715/50)"}, + {HPHW_NPROC,0x311,0x4,0x81,"Scorpio Jr.(715/33)"}, + {HPHW_NPROC,0x312,0x4,0x81,"Strider-50 (715S/50)"}, + {HPHW_NPROC,0x313,0x4,0x81,"Strider-33 (715S/33)"}, + {HPHW_NPROC,0x314,0x4,0x81,"Trailways-50 (715T/50)"}, + {HPHW_NPROC,0x315,0x4,0x81,"Trailways-33 (715T/33)"}, + {HPHW_NPROC,0x316,0x4,0x81,"Scorpio Sr.(715/75)"}, + {HPHW_NPROC,0x317,0x4,0x81,"Scorpio 100 (715/100)"}, + {HPHW_NPROC,0x318,0x4,0x81,"Spectra (725/50)"}, + {HPHW_NPROC,0x319,0x4,0x81,"Spectra (725/75)"}, + {HPHW_NPROC,0x320,0x4,0x81,"Spectra (725/100)"}, + {HPHW_NPROC,0x401,0x4,0x81,"Pace (745i, 747i)"}, + {HPHW_NPROC,0x402,0x4,0x81,"Sidewinder (742i)"}, + {HPHW_NPROC,0x403,0x4,0x81,"Fast Pace"}, + {HPHW_NPROC,0x480,0x4,0x81,"Orville (E23)"}, + {HPHW_NPROC,0x481,0x4,0x81,"Wilbur (E25)"}, + {HPHW_NPROC,0x482,0x4,0x81,"WB-80 (E35)"}, + {HPHW_NPROC,0x483,0x4,0x81,"WB-96 (E45)"}, + {HPHW_NPROC,0x48,0x4,0x81,"UL Proc L-100 (811/D210,D310)"}, + {HPHW_NPROC,0x48,0x4,0x81,"UL Proc L-75 (801/D200)"}, + {HPHW_NPROC,0x501,0x4,0x81,"Merlin L2 132 (9000/778/B132L)"}, + {HPHW_NPROC,0x502,0x4,0x81,"Merlin L2 160 (9000/778/B160L)"}, + {HPHW_NPROC,0x503,0x4,0x81,"Merlin L2+ 132 (9000/778/B132L)"}, + {HPHW_NPROC,0x504,0x4,0x81,"Merlin L2+ 180 (9000/778/B180L)"}, + {HPHW_NPROC,0x505,0x4,0x81,"Raven L2 132 (9000/778/C132L)"}, + {HPHW_NPROC,0x506,0x4,0x81,"Raven L2 160 (9000/779/C160L)"}, + {HPHW_NPROC,0x507,0x4,0x81,"Raven L2 180 (9000/779/C180L)"}, + {HPHW_NPROC,0x508,0x4,0x81,"Raven L2 160 (9000/779/C160L)"}, + {HPHW_NPROC,0x509,0x4,0x81,"712/132 L2 Upgrade"}, + {HPHW_NPROC,0x50A,0x4,0x81,"712/160 L2 Upgrade"}, + {HPHW_NPROC,0x50B,0x4,0x81,"715/132 L2 Upgrade"}, + {HPHW_NPROC,0x50C,0x4,0x81,"715/160 L2 Upgrade"}, + {HPHW_NPROC,0x50D,0x4,0x81,"Rocky2 L2 120"}, + {HPHW_NPROC,0x50E,0x4,0x81,"Rocky2 L2 150"}, + {HPHW_NPROC,0x50F,0x4,0x81,"Anole L2 132 (744)"}, + {HPHW_NPROC,0x510,0x4,0x81,"Anole L2 165 (744)"}, + {HPHW_NPROC,0x511,0x4,0x81,"Kiji L2 132"}, + {HPHW_NPROC,0x512,0x4,0x81,"UL L2 132 (803/D220,D320)"}, + {HPHW_NPROC,0x513,0x4,0x81,"UL L2 160 (813/D220,D320)"}, + {HPHW_NPROC,0x514,0x4,0x81,"Merlin Jr L2 132"}, + {HPHW_NPROC,0x515,0x4,0x81,"Staccato L2 132"}, + {HPHW_NPROC,0x516,0x4,0x81,"Staccato L2 180 (A Class 180)"}, + {HPHW_NPROC,0x580,0x4,0x81,"KittyHawk DC2-100 (K100)"}, + {HPHW_NPROC,0x581,0x4,0x91,"KittyHawk DC3-120 (K210)"}, + {HPHW_NPROC,0x582,0x4,0x91,"KittyHawk DC3 100 (K400)"}, + {HPHW_NPROC,0x583,0x4,0x91,"KittyHawk DC3 120 (K410)"}, + {HPHW_NPROC,0x584,0x4,0x91,"LighteningHawk T120"}, + {HPHW_NPROC,0x585,0x4,0x91,"SkyHawk 100"}, + {HPHW_NPROC,0x586,0x4,0x91,"SkyHawk 120"}, + {HPHW_NPROC,0x587,0x4,0x81,"UL Proc 1-way T'120"}, + {HPHW_NPROC,0x588,0x4,0x91,"UL Proc 2-way T'120"}, + {HPHW_NPROC,0x589,0x4,0x81,"UL Proc 1-way T'100 (821/D250,D350)"}, + {HPHW_NPROC,0x58A,0x4,0x91,"UL Proc 2-way T'100 (831/D250,D350)"}, + {HPHW_NPROC,0x58B,0x4,0x91,"KittyHawk DC2 100 (K200)"}, + {HPHW_NPROC,0x58C,0x4,0x91,"ThunderHawk DC3- 120 1M (K220)"}, + {HPHW_NPROC,0x58D,0x4,0x91,"ThunderHawk DC3 120 1M (K420)"}, + {HPHW_NPROC,0x58E,0x4,0x81,"Raven 120 T'"}, + {HPHW_NPROC,0x58F,0x4,0x91,"Mohawk 160 U 1M DC3 (K450)"}, + {HPHW_NPROC,0x590,0x4,0x91,"Mohawk 180 U 1M DC3 (K460)"}, + {HPHW_NPROC,0x591,0x4,0x91,"Mohawk 200 U 1M DC3"}, + {HPHW_NPROC,0x592,0x4,0x81,"Raven 100 T'"}, + {HPHW_NPROC,0x593,0x4,0x91,"FireHawk 160 U"}, + {HPHW_NPROC,0x594,0x4,0x91,"FireHawk 180 U"}, + {HPHW_NPROC,0x595,0x4,0x91,"FireHawk 220 U"}, + {HPHW_NPROC,0x596,0x4,0x91,"FireHawk 240 U"}, + {HPHW_NPROC,0x597,0x4,0x91,"SPP2000 processor"}, + {HPHW_NPROC,0x598,0x4,0x81,"Raven U 230 (9000/780/C230)"}, + {HPHW_NPROC,0x599,0x4,0x81,"Raven U 240 (9000/780/C240)"}, + {HPHW_NPROC,0x59A,0x4,0x91,"Unlisted but reserved"}, + {HPHW_NPROC,0x59A,0x4,0x81,"Unlisted but reserved"}, + {HPHW_NPROC,0x59B,0x4,0x81,"Raven U 160 (9000/780/C160)"}, + {HPHW_NPROC,0x59D,0x4,0x81,"Raven U 200 (9000/780/C200)"}, + {HPHW_NPROC,0x59E,0x4,0x91,"ThunderHawk T' 120"}, + {HPHW_NPROC,0x59F,0x4,0x91,"Raven U 180+ (9000/780/\?\?\?\?)"}, + {HPHW_NPROC,0x5A0,0x4,0x81,"UL 1w T120 1MB/1MB (841/D260,D360)"}, + {HPHW_NPROC,0x5A1,0x4,0x91,"UL 2w T120 1MB/1MB (851/D260,D360)"}, + {HPHW_NPROC,0x5A2,0x4,0x81,"UL 1w U160 512K/512K (861/D270,D370)"}, + {HPHW_NPROC,0x5A3,0x4,0x91,"UL 2w U160 512K/512K (871/D270,D370)"}, + {HPHW_NPROC,0x5A4,0x4,0x91,"Mohawk 160 U 1M DC3- (K250)"}, + {HPHW_NPROC,0x5A5,0x4,0x91,"Mohawk 180 U 1M DC3- (K260)"}, + {HPHW_NPROC,0x5A6,0x4,0x91,"Mohawk 200 U 1M DC3-"}, + {HPHW_NPROC,0x5A7,0x4,0x81,"UL proc 1-way U160 1M/1M"}, + {HPHW_NPROC,0x5A8,0x4,0x91,"UL proc 2-way U160 1M/1M"}, + {HPHW_NPROC,0x5A9,0x4,0x81,"UL proc 1-way U180 1M/1M"}, + {HPHW_NPROC,0x5AA,0x4,0x91,"UL proc 2-way U180 1M/1M"}, + {HPHW_NPROC,0x5AB,0x4,0x91,"Obsolete"}, + {HPHW_NPROC,0x5AB,0x4,0x81,"Obsolete"}, + {HPHW_NPROC,0x5AC,0x4,0x91,"Obsolete"}, + {HPHW_NPROC,0x5AC,0x4,0x81,"Obsolete"}, + {HPHW_NPROC,0x5AD,0x4,0x91,"BraveHawk 180MHz DC3-"}, + {HPHW_NPROC,0x5AE,0x4,0x91,"BraveHawk 200MHz DC3- (898/K370)"}, + {HPHW_NPROC,0x5AF,0x4,0x91,"BraveHawk 220MHz DC3-"}, + {HPHW_NPROC,0x5B0,0x4,0x91,"BraveHawk 180MHz DC3"}, + {HPHW_NPROC,0x5B1,0x4,0x91,"BraveHawk 200MHz DC3 (899/K570)"}, + {HPHW_NPROC,0x5B2,0x4,0x91,"BraveHawk 220MHz DC3"}, + {HPHW_NPROC,0x5B3,0x4,0x91,"FireHawk 200"}, + {HPHW_NPROC,0x5B4,0x4,0x91,"SPP2500"}, + {HPHW_NPROC,0x5B5,0x4,0x91,"SummitHawk U+"}, + {HPHW_NPROC,0x5B6,0x4,0x91,"DragonHawk U+ 240 DC3"}, + {HPHW_NPROC,0x5B7,0x4,0x91,"DragonHawk U+ 240 DC3-"}, + {HPHW_NPROC,0x5B8,0x4,0x91,"SPP2250 240 MHz"}, + {HPHW_NPROC,0x5B9,0x4,0x81,"UL 1w U+/240 (350/550)"}, + {HPHW_NPROC,0x5BA,0x4,0x91,"UL 2w U+/240 (350/550)"}, + {HPHW_NPROC,0x5BB,0x4,0x81,"AllegroHigh W "}, + {HPHW_NPROC,0x5BC,0x4,0x91,"AllegroLow W"}, + {HPHW_NPROC,0x5BD,0x4,0x91,"Forte W 2-way"}, + {HPHW_NPROC,0x5BE,0x4,0x91,"Prelude W"}, + {HPHW_NPROC,0x5BF,0x4,0x91,"Forte W 4-way"}, + {HPHW_NPROC,0x5C0,0x4,0x91,"M2250"}, + {HPHW_NPROC,0x5C1,0x4,0x91,"M2500"}, + {HPHW_NPROC,0x5C2,0x4,0x91,"Sonata 440"}, + {HPHW_NPROC,0x5C3,0x4,0x91,"Sonata 360"}, + {HPHW_NPROC,0x5C4,0x4,0x91,"Rhapsody 440"}, + {HPHW_NPROC,0x5C5,0x4,0x91,"Rhapsody 360"}, + {HPHW_NPROC,0x5C6,0x4,0x91,"Raven W 360 (9000/780/\?\?\?\?)"}, + {HPHW_NPROC,0x5C7,0x4,0x91,"Halfdome W 440"}, + {HPHW_NPROC,0x5C8,0x4,0x81,"Lego 360 processor"}, + {HPHW_NPROC,0x5C9,0x4,0x91,"Rhapsody DC- 440"}, + {HPHW_NPROC,0x5CA,0x4,0x91,"Rhapsody DC- 360"}, + {HPHW_NPROC,0x5CB,0x4,0x91,"Crescendo 440"}, + {HPHW_NPROC,0x5FF,0x4,0x91,"Hitachi W"}, + {HPHW_NPROC,0x600,0x4,0x81,"Gecko (712/60)"}, + {HPHW_NPROC,0x601,0x4,0x81,"Gecko 80 (712/80)"}, + {HPHW_NPROC,0x602,0x4,0x81,"Gecko 100 (712/100)"}, + {HPHW_NPROC,0x603,0x4,0x81,"Anole 64 (743/64)"}, + {HPHW_NPROC,0x604,0x4,0x81,"Anole 100 (743/100)"}, + {HPHW_NPROC,0x605,0x4,0x81,"Gecko 120 (712/120)"}, + {HPHW_NPROC,0x606,0x4,0x81,"Gila 80"}, + {HPHW_NPROC,0x607,0x4,0x81,"Gila 100"}, + {HPHW_NPROC,0x608,0x4,0x81,"Gila 120"}, + {HPHW_NPROC,0x609,0x4,0x81,"Scorpio-L 80"}, + {HPHW_NPROC,0x60A,0x4,0x81,"Mirage Jr (715/64)"}, + {HPHW_NPROC,0x60B,0x4,0x81,"Mirage 100"}, + {HPHW_NPROC,0x60C,0x4,0x81,"Mirage 100+"}, + {HPHW_NPROC,0x60D,0x4,0x81,"Electra 100"}, + {HPHW_NPROC,0x60E,0x4,0x81,"Electra 120"}, + {HPHW_NPROC,0x610,0x4,0x81,"Scorpio-L 100"}, + {HPHW_NPROC,0x611,0x4,0x81,"Scorpio-L 120"}, + {HPHW_NPROC,0x612,0x4,0x81,"Spectra-L 80"}, + {HPHW_NPROC,0x613,0x4,0x81,"Spectra-L 100"}, + {HPHW_NPROC,0x614,0x4,0x81,"Spectra-L 120"}, + {HPHW_NPROC,0x615,0x4,0x81,"Piranha 100"}, + {HPHW_NPROC,0x616,0x4,0x81,"Piranha 120"}, + {HPHW_NPROC,0x617,0x4,0x81,"Jason 50"}, + {HPHW_NPROC,0x618,0x4,0x81,"Jason 100"}, + {HPHW_NPROC,0x619,0x4,0x81,"Mirage 80 "}, + {HPHW_NPROC,0x61A,0x4,0x81,"SAIC L-80"}, + {HPHW_NPROC,0x61B,0x4,0x81,"Rocky1 L-60"}, + {HPHW_NPROC,0x61C,0x4,0x81,"Anole T (743/T)"}, + {HPHW_NPROC,0x67E,0x4,0x81,"Hitachi Tiny 80"}, + {HPHW_NPROC,0x67F,0x4,0x81,"Hitachi Tiny 64"}, + {HPHW_NPROC,0x700,0x4,0x91,"NEC Aska Processor"}, + {HPHW_A_DIRECT, 0x004, 0x0000D, 0x00, "Arrakis MUX"}, + {HPHW_A_DIRECT, 0x005, 0x0000D, 0x00, "Dyun Kiuh MUX"}, + {HPHW_A_DIRECT, 0x006, 0x0000D, 0x00, "Baat Kiuh AP/MUX (40299B)"}, + {HPHW_A_DIRECT, 0x007, 0x0000D, 0x00, "Dino AP"}, + {HPHW_A_DIRECT, 0x009, 0x0000D, 0x00, "Solaris Direct Connect MUX (J2092A)"}, + {HPHW_A_DIRECT, 0x00A, 0x0000D, 0x00, "Solaris RS-422/423 MUX (J2093A)"}, + {HPHW_A_DIRECT, 0x00B, 0x0000D, 0x00, "Solaris RS-422/423 Quadriloops MUX"}, + {HPHW_A_DIRECT, 0x00C, 0x0000D, 0x00, "Solaris Modem MUX (J2094A)"}, + {HPHW_A_DIRECT, 0x00D, 0x0000D, 0x00, "Twins Direct Connect MUX"}, + {HPHW_A_DIRECT, 0x00E, 0x0000D, 0x00, "Twins Modem MUX"}, + {HPHW_A_DIRECT, 0x00F, 0x0000D, 0x00, "Nautilus RS-485"}, + {HPHW_A_DIRECT, 0x010, 0x0000D, 0x00, "UltraLight CAP/MUX"}, + {HPHW_A_DIRECT, 0x015, 0x0000D, 0x00, "Eole CAP/MUX"}, + {HPHW_A_DIRECT, 0x024, 0x0000D, 0x00, "Sahp Kiuh AP/MUX"}, + {HPHW_A_DIRECT, 0x034, 0x0000D, 0x00, "Sahp Kiuh Low AP/MUX"}, + {HPHW_A_DIRECT, 0x044, 0x0000D, 0x00, "Sahp Baat Kiuh AP/MUX"}, + {HPHW_A_DIRECT, 0x004, 0x0000E, 0x80, "Burgundy RS-232"}, + {HPHW_A_DIRECT, 0x005, 0x0000E, 0x80, "Silverfox RS-232"}, + {HPHW_A_DIRECT, 0x006, 0x0000E, 0x80, "Lego RS-232"}, + {HPHW_A_DIRECT, 0x004, 0x0000F, 0x00, "Peacock Graphics"}, + {HPHW_A_DIRECT, 0x004, 0x00014, 0x80, "Burgundy HIL"}, + {HPHW_A_DIRECT, 0x005, 0x00014, 0x80, "Peacock HIL"}, + {HPHW_A_DIRECT, 0x004, 0x00015, 0x80, "Leonardo"}, + {HPHW_A_DIRECT, 0x004, 0x00016, 0x80, "HP-PB HRM"}, + {HPHW_A_DIRECT, 0x004, 0x00017, 0x80, "HP-PB HRC"}, + {HPHW_A_DIRECT, 0x004, 0x0003A, 0x80, "Skunk Centronics (28655A)"}, + {HPHW_A_DIRECT, 0x024, 0x0003A, 0x80, "Sahp Kiuh Centronics"}, + {HPHW_A_DIRECT, 0x044, 0x0003A, 0x80, "Sahp Baat Kiuh Centronics"}, + {HPHW_A_DIRECT, 0x004, 0x0004E, 0x80, "AT&T DataKit (AMSO)"}, + {HPHW_A_DIRECT, 0x004, 0x0009B, 0x80, "Test&Meas GSC HPIB"}, + {HPHW_A_DIRECT, 0x004, 0x000A8, 0x00, "Rocky2-120 Front Keyboard"}, + {HPHW_A_DIRECT, 0x005, 0x000A8, 0x00, "Rocky2-150 Front Keyboard"}, + {HPHW_A_DIRECT, 0x004, 0x00101, 0x80, "Hitachi Console Module"}, + {HPHW_A_DIRECT, 0x004, 0x00102, 0x80, "Hitachi Boot Module"}, + {HPHW_A_DIRECT, 0x004, 0x00203, 0x80, "MELCO HBMLA MLAIT"}, + {HPHW_A_DIRECT, 0x004, 0x00208, 0x80, "MELCO HBDPC"}, + {HPHW_A_DIRECT, 0x004, 0x00300, 0x00, "DCI TWINAX TERM IO MUX"}, + {HPHW_A_DMA, 0x004, 0x00039, 0x80, "Skunk SCSI (28655A)"}, + {HPHW_A_DMA, 0x005, 0x00039, 0x80, "KittyHawk CSY Core SCSI"}, + {HPHW_A_DMA, 0x014, 0x00039, 0x80, "Diablo SCSI"}, + {HPHW_A_DMA, 0x024, 0x00039, 0x80, "Sahp Kiuh SCSI"}, + {HPHW_A_DMA, 0x034, 0x00039, 0x80, "Sahp Kiuh Low SCSI"}, + {HPHW_A_DMA, 0x044, 0x00039, 0x80, "Sahp Baat Kiuh SCSI"}, + {HPHW_A_DMA, 0x004, 0x0003B, 0x80, "Wizard SCSI"}, + {HPHW_A_DMA, 0x005, 0x0003B, 0x80, "KittyHawk CSY Core FW-SCSI"}, + {HPHW_A_DMA, 0x006, 0x0003B, 0x80, "Symbios EPIC FW-SCSI"}, + {HPHW_A_DMA, 0x004, 0x00040, 0x80, "HP-PB Shazam HPIB (28650A)"}, + {HPHW_A_DMA, 0x005, 0x00040, 0x80, "Burgundy HPIB"}, + {HPHW_A_DMA, 0x004, 0x00041, 0x80, "HP-PB HP-FL"}, + {HPHW_A_DMA, 0x004, 0x00042, 0x80, "HP-PB LoQuix HPIB (28650B)"}, + {HPHW_A_DMA, 0x004, 0x00043, 0x80, "HP-PB Crypt LoQuix"}, + {HPHW_A_DMA, 0x004, 0x00044, 0x80, "HP-PB Shazam GPIO (28651A)"}, + {HPHW_A_DMA, 0x004, 0x00045, 0x80, "HP-PB LoQuix GPIO"}, + {HPHW_A_DMA, 0x004, 0x00046, 0x80, "2-Port X.25 NIO_ACC (AMSO)"}, + {HPHW_A_DMA, 0x004, 0x00047, 0x80, "4-Port X.25 NIO_ACC (AMSO)"}, + {HPHW_A_DMA, 0x004, 0x0004B, 0x80, "LGB Control"}, + {HPHW_A_DMA, 0x004, 0x0004C, 0x80, "Martian RTI (AMSO)"}, + {HPHW_A_DMA, 0x004, 0x0004D, 0x80, "ACC Mux (AMSO)"}, + {HPHW_A_DMA, 0x004, 0x00050, 0x80, "Lanbrusca 802.3 (36967A)"}, + {HPHW_A_DMA, 0x004, 0x00056, 0x80, "HP-PB LoQuix FDDI"}, + {HPHW_A_DMA, 0x004, 0x00057, 0x80, "HP-PB LoQuix FDDI (28670A)"}, + {HPHW_A_DMA, 0x012, 0x00089, 0x80, "Barracuda Add-on FW-SCSI"}, + {HPHW_A_DMA, 0x013, 0x00089, 0x80, "Bluefish Add-on FW-SCSI"}, + {HPHW_A_DMA, 0x014, 0x00089, 0x80, "Shrike Add-on FW-SCSI"}, + {HPHW_A_DMA, 0x015, 0x00089, 0x80, "KittyHawk GSY Core FW-SCSI"}, + {HPHW_A_DMA, 0x017, 0x00089, 0x80, "Shrike Jade Add-on FW-SCSI (A3644A)"}, + {HPHW_A_DMA, 0x01F, 0x00089, 0x80, "SkyHawk 100/120 FW-SCSI"}, + {HPHW_A_DMA, 0x027, 0x00089, 0x80, "Piranha 100 FW-SCSI"}, + {HPHW_A_DMA, 0x032, 0x00089, 0x80, "Raven T' Core FW-SCSI"}, + {HPHW_A_DMA, 0x03d, 0x00089, 0x80, "Merlin 160 Core FW-SCSI"}, + {HPHW_A_DMA, 0x044, 0x00089, 0x80, "Mohawk Core FW-SCSI"}, + {HPHW_A_DMA, 0x051, 0x00089, 0x80, "Firehawk FW-SCSI"}, + {HPHW_A_DMA, 0x058, 0x00089, 0x80, "FireHawk 200 FW-SCSI"}, + {HPHW_A_DMA, 0x05C, 0x00089, 0x80, "SummitHawk 230 Ultra-SCSI"}, + {HPHW_A_DMA, 0x014, 0x00091, 0x80, "Baby Hugo Add-on Net FC (A3406A)"}, + {HPHW_A_DMA, 0x020, 0x00091, 0x80, "Baby Jade Add-on Net FC (A3638A)"}, + {HPHW_A_DMA, 0x004, 0x00092, 0x80, "GSC+ YLIASTER ATM"}, + {HPHW_A_DMA, 0x004, 0x00095, 0x80, "Hamlyn GSC+ Network Card"}, + {HPHW_A_DMA, 0x004, 0x00098, 0x80, "Lo-fat Emulator"}, + {HPHW_A_DMA, 0x004, 0x0009A, 0x80, "GSC+ Venus ATM"}, + {HPHW_A_DMA, 0x005, 0x0009A, 0x80, "GSC+ Samorobrive ATM"}, + {HPHW_A_DMA, 0x004, 0x0009D, 0x80, "HP HSC-PCI Cards"}, + {HPHW_A_DMA, 0x004, 0x0009E, 0x80, "Alaxis GSC+ 155Mb ATM"}, + {HPHW_A_DMA, 0x005, 0x0009E, 0x80, "Alaxis GSC+ 622Mb ATM"}, + {HPHW_A_DMA, 0x05C, 0x0009F, 0x80, "SummitHawk 230 USB"}, + {HPHW_A_DMA, 0x05C, 0x000A0, 0x80, "SummitHawk 230 100BaseT"}, + {HPHW_A_DMA, 0x015, 0x000A7, 0x80, "Baby Hugo Add-on mass FC (A3404A)"}, + {HPHW_A_DMA, 0x018, 0x000A7, 0x80, "Mombasa GS Add-on mass FC (A3591)"}, + {HPHW_A_DMA, 0x021, 0x000A7, 0x80, "Baby Jade Add-on mass FC (A3636A)"}, + {HPHW_A_DMA, 0x004, 0x00201, 0x80, "MELCO HCMAP"}, + {HPHW_A_DMA, 0x004, 0x00202, 0x80, "MELCO HBMLA MLAMA"}, + {HPHW_A_DMA, 0x004, 0x00205, 0x80, "MELCO HBRFU"}, + {HPHW_A_DMA, 0x004, 0x00380, 0x80, "Interphase NIO-FC"}, + {HPHW_A_DMA, 0x004, 0x00381, 0x80, "Interphase NIO-ATM"}, + {HPHW_A_DMA, 0x004, 0x00382, 0x80, "Interphase NIO-100BaseTX"}, + {HPHW_BA, 0x004, 0x00070, 0x0, "Cobra Core BA"}, + {HPHW_BA, 0x005, 0x00070, 0x0, "Coral Core BA"}, + {HPHW_BA, 0x006, 0x00070, 0x0, "Bushmaster Core BA"}, + {HPHW_BA, 0x007, 0x00070, 0x0, "Scorpio Core BA"}, + {HPHW_BA, 0x008, 0x00070, 0x0, "Flounder Core BA"}, + {HPHW_BA, 0x009, 0x00070, 0x0, "Outfield Core BA"}, + {HPHW_BA, 0x00A, 0x00070, 0x0, "CoralII Core BA"}, + {HPHW_BA, 0x00B, 0x00070, 0x0, "Scorpio Jr. Core BA"}, + {HPHW_BA, 0x00C, 0x00070, 0x0, "Strider-50 Core BA"}, + {HPHW_BA, 0x00D, 0x00070, 0x0, "Strider-33 Core BA"}, + {HPHW_BA, 0x00E, 0x00070, 0x0, "Trailways-50 Core BA"}, + {HPHW_BA, 0x00F, 0x00070, 0x0, "Trailways-33 Core BA"}, + {HPHW_BA, 0x010, 0x00070, 0x0, "Pace Core BA"}, + {HPHW_BA, 0x011, 0x00070, 0x0, "Sidewinder Core BA"}, + {HPHW_BA, 0x019, 0x00070, 0x0, "Scorpio Sr. Core BA"}, + {HPHW_BA, 0x020, 0x00070, 0x0, "Scorpio 100 Core BA"}, + {HPHW_BA, 0x021, 0x00070, 0x0, "Spectra 50 Core BA"}, + {HPHW_BA, 0x022, 0x00070, 0x0, "Spectra 75 Core BA"}, + {HPHW_BA, 0x023, 0x00070, 0x0, "Spectra 100 Core BA"}, + {HPHW_BA, 0x024, 0x00070, 0x0, "Fast Pace Core BA"}, + {HPHW_BA, 0x026, 0x00070, 0x0, "CoralII Jaguar Core BA"}, + {HPHW_BA, 0x004, 0x00076, 0x0, "Cobra EISA BA"}, + {HPHW_BA, 0x005, 0x00076, 0x0, "Coral EISA BA"}, + {HPHW_BA, 0x007, 0x00076, 0x0, "Scorpio EISA BA"}, + {HPHW_BA, 0x00A, 0x00076, 0x0, "CoralII EISA BA"}, + {HPHW_BA, 0x00B, 0x00076, 0x0, "Scorpio Jr. EISA BA"}, + {HPHW_BA, 0x00C, 0x00076, 0x0, "Strider-50 Core EISA"}, + {HPHW_BA, 0x00D, 0x00076, 0x0, "Strider-33 Core EISA"}, + {HPHW_BA, 0x00E, 0x00076, 0x0, "Trailways-50 Core EISA"}, + {HPHW_BA, 0x00F, 0x00076, 0x0, "Trailways-33 Core EISA"}, + {HPHW_BA, 0x010, 0x00076, 0x0, "Pace Core EISA"}, + {HPHW_BA, 0x019, 0x00076, 0x0, "Scorpio Sr. EISA BA"}, + {HPHW_BA, 0x020, 0x00076, 0x0, "Scorpio 100 EISA BA"}, + {HPHW_BA, 0x021, 0x00076, 0x0, "Spectra 50 EISA BA"}, + {HPHW_BA, 0x022, 0x00076, 0x0, "Spectra 75 EISA BA"}, + {HPHW_BA, 0x023, 0x00076, 0x0, "Spectra 100 EISA BA"}, + {HPHW_BA, 0x026, 0x00076, 0x0, "CoralII Jaguar EISA BA"}, + {HPHW_BA, 0x010, 0x00078, 0x0, "Pace VME BA"}, + {HPHW_BA, 0x011, 0x00078, 0x0, "Sidewinder VME BA"}, + {HPHW_BA, 0x01A, 0x00078, 0x0, "Anole 64 VME BA"}, + {HPHW_BA, 0x01B, 0x00078, 0x0, "Anole 100 VME BA"}, + {HPHW_BA, 0x024, 0x00078, 0x0, "Fast Pace VME BA"}, + {HPHW_BA, 0x034, 0x00078, 0x0, "Anole T VME BA"}, + {HPHW_BA, 0x04A, 0x00078, 0x0, "Anole L2 132 BME BA"}, + {HPHW_BA, 0x04C, 0x00078, 0x0, "Anole L2 165 VME BA"}, + {HPHW_BA, 0x011, 0x00081, 0x0, "WB-96 Core BA"}, + {HPHW_BA, 0x012, 0x00081, 0x0, "Orville UX Core BA"}, + {HPHW_BA, 0x013, 0x00081, 0x0, "Wilbur UX Core BA"}, + {HPHW_BA, 0x014, 0x00081, 0x0, "WB-80 Core BA"}, + {HPHW_BA, 0x015, 0x00081, 0x0, "KittyHawk GSY Core BA"}, + {HPHW_BA, 0x016, 0x00081, 0x0, "Gecko Core BA"}, + {HPHW_BA, 0x018, 0x00081, 0x0, "Gecko Optional BA"}, + {HPHW_BA, 0x01A, 0x00081, 0x0, "Anole 64 Core BA"}, + {HPHW_BA, 0x01B, 0x00081, 0x0, "Anole 100 Core BA"}, + {HPHW_BA, 0x01C, 0x00081, 0x0, "Gecko 80 Core BA"}, + {HPHW_BA, 0x01D, 0x00081, 0x0, "Gecko 100 Core BA"}, + {HPHW_BA, 0x01F, 0x00081, 0x0, "SkyHawk 100/120 Core BA"}, + {HPHW_BA, 0x027, 0x00081, 0x0, "Piranha 100 Core BA"}, + {HPHW_BA, 0x028, 0x00081, 0x0, "Mirage Jr Core BA"}, + {HPHW_BA, 0x029, 0x00081, 0x0, "Mirage Core BA"}, + {HPHW_BA, 0x02A, 0x00081, 0x0, "Electra Core BA"}, + {HPHW_BA, 0x02B, 0x00081, 0x0, "Mirage 80 Core BA"}, + {HPHW_BA, 0x02C, 0x00081, 0x0, "Mirage 100+ Core BA"}, + {HPHW_BA, 0x02E, 0x00081, 0x0, "UL 350 Lasi Core BA"}, + {HPHW_BA, 0x02F, 0x00081, 0x0, "UL 550 Lasi Core BA"}, + {HPHW_BA, 0x032, 0x00081, 0x0, "Raven T' Core BA"}, + {HPHW_BA, 0x033, 0x00081, 0x0, "Anole T Core BA"}, + {HPHW_BA, 0x034, 0x00081, 0x0, "SAIC L-80 Core BA"}, + {HPHW_BA, 0x035, 0x00081, 0x0, "PCX-L2 712/132 Core BA"}, + {HPHW_BA, 0x036, 0x00081, 0x0, "PCX-L2 712/160 Core BA"}, + {HPHW_BA, 0x03B, 0x00081, 0x0, "Raven U/L2 Core BA"}, + {HPHW_BA, 0x03C, 0x00081, 0x0, "Merlin 132 Core BA"}, + {HPHW_BA, 0x03D, 0x00081, 0x0, "Merlin 160 Core BA"}, + {HPHW_BA, 0x03E, 0x00081, 0x0, "Merlin+ 132 Core BA"}, + {HPHW_BA, 0x03F, 0x00081, 0x0, "Merlin+ 180 Core BA"}, + {HPHW_BA, 0x044, 0x00081, 0x0, "Mohawk Core BA"}, + {HPHW_BA, 0x045, 0x00081, 0x0, "Rocky1 Core BA"}, + {HPHW_BA, 0x046, 0x00081, 0x0, "Rocky2 120 Core BA"}, + {HPHW_BA, 0x047, 0x00081, 0x0, "Rocky2 150 Core BA"}, + {HPHW_BA, 0x04B, 0x00081, 0x0, "Anole L2 132 Core BA"}, + {HPHW_BA, 0x04D, 0x00081, 0x0, "Anole L2 165 Core BA"}, + {HPHW_BA, 0x04E, 0x00081, 0x0, "Kiji L2 132 Core BA"}, + {HPHW_BA, 0x050, 0x00081, 0x0, "Merlin Jr 132 Core BA"}, + {HPHW_BA, 0x051, 0x00081, 0x0, "Firehawk Core BA"}, + {HPHW_BA, 0x056, 0x00081, 0x0, "Raven+ w SE FWSCSI Core BA"}, + {HPHW_BA, 0x057, 0x00081, 0x0, "Raven+ w Diff FWSCSI Core BA"}, + {HPHW_BA, 0x058, 0x00081, 0x0, "FireHawk 200 Core BA"}, + {HPHW_BA, 0x05C, 0x00081, 0x0, "SummitHawk 230 Core BA"}, + {HPHW_BA, 0x05E, 0x00081, 0x0, "Staccato 132 Core BA"}, + {HPHW_BA, 0x05E, 0x00081, 0x0, "Staccato 180 Core BA"}, + {HPHW_BA, 0x05F, 0x00081, 0x0, "Staccato 180 Lasi"}, + {HPHW_BA, 0x800, 0x00081, 0x0, "Hitachi Tiny 64 Core BA"}, + {HPHW_BA, 0x801, 0x00081, 0x0, "Hitachi Tiny 80 Core BA"}, + {HPHW_BA, 0x004, 0x0008B, 0x0, "Anole Optional PCMCIA BA"}, + {HPHW_BA, 0x004, 0x0008E, 0x0, "GSC ITR Wax BA"}, + {HPHW_BA, 0x011, 0x0008E, 0x0, "SuperPace Wax BA"}, + {HPHW_BA, 0x012, 0x0008E, 0x0, "Mirage Jr Wax BA"}, + {HPHW_BA, 0x013, 0x0008E, 0x0, "Mirage Wax BA"}, + {HPHW_BA, 0x014, 0x0008E, 0x0, "Electra Wax BA"}, + {HPHW_BA, 0x017, 0x0008E, 0x0, "Raven Backplane Wax BA"}, + {HPHW_BA, 0x01E, 0x0008E, 0x0, "Raven T' Wax BA"}, + {HPHW_BA, 0x01F, 0x0008E, 0x0, "SkyHawk Wax BA"}, + {HPHW_BA, 0x023, 0x0008E, 0x0, "Rocky1 Wax BA"}, + {HPHW_BA, 0x02B, 0x0008E, 0x0, "Mirage 80 Wax BA"}, + {HPHW_BA, 0x02C, 0x0008E, 0x0, "Mirage 100+ Wax BA"}, + {HPHW_BA, 0x030, 0x0008E, 0x0, "UL 350 Core Wax BA"}, + {HPHW_BA, 0x031, 0x0008E, 0x0, "UL 550 Core Wax BA"}, + {HPHW_BA, 0x034, 0x0008E, 0x0, "SAIC L-80 Wax BA"}, + {HPHW_BA, 0x03A, 0x0008E, 0x0, "Merlin+ Wax BA"}, + {HPHW_BA, 0x040, 0x0008E, 0x0, "Merlin 132 Wax BA"}, + {HPHW_BA, 0x041, 0x0008E, 0x0, "Merlin 160 Wax BA"}, + {HPHW_BA, 0x043, 0x0008E, 0x0, "Merlin 132/160 Wax BA"}, + {HPHW_BA, 0x052, 0x0008E, 0x0, "Raven+ Hi Power Backplane w/EISA Wax BA"}, + {HPHW_BA, 0x054, 0x0008E, 0x0, "Raven+ Lo Power Backplane w/EISA Wax BA"}, + {HPHW_BA, 0x059, 0x0008E, 0x0, "FireHawk 200 Wax BA"}, + {HPHW_BA, 0x05A, 0x0008E, 0x0, "Raven+ L2 Backplane w/EISA Wax BA"}, + {HPHW_BA, 0x05D, 0x0008E, 0x0, "SummitHawk Wax BA"}, + {HPHW_BA, 0x800, 0x0008E, 0x0, "Hitachi Tiny 64 Wax BA"}, + {HPHW_BA, 0x801, 0x0008E, 0x0, "Hitachi Tiny 80 Wax BA"}, + {HPHW_BA, 0x011, 0x00090, 0x0, "SuperPace Wax EISA BA"}, + {HPHW_BA, 0x017, 0x00090, 0x0, "Raven Backplane Wax EISA BA"}, + {HPHW_BA, 0x01E, 0x00090, 0x0, "Raven T' Wax EISA BA"}, + {HPHW_BA, 0x01F, 0x00090, 0x0, "SkyHawk 100/120 Wax EISA BA"}, + {HPHW_BA, 0x027, 0x00090, 0x0, "Piranha 100 Wax EISA BA"}, + {HPHW_BA, 0x028, 0x00090, 0x0, "Mirage Jr Wax EISA BA"}, + {HPHW_BA, 0x029, 0x00090, 0x0, "Mirage Wax EISA BA"}, + {HPHW_BA, 0x02A, 0x00090, 0x0, "Electra Wax EISA BA"}, + {HPHW_BA, 0x02B, 0x00090, 0x0, "Mirage 80 Wax EISA BA"}, + {HPHW_BA, 0x02C, 0x00090, 0x0, "Mirage 100+ Wax EISA BA"}, + {HPHW_BA, 0x030, 0x00090, 0x0, "UL 350 Wax EISA BA"}, + {HPHW_BA, 0x031, 0x00090, 0x0, "UL 550 Wax EISA BA"}, + {HPHW_BA, 0x034, 0x00090, 0x0, "SAIC L-80 Wax EISA BA"}, + {HPHW_BA, 0x03A, 0x00090, 0x0, "Merlin+ Wax EISA BA"}, + {HPHW_BA, 0x040, 0x00090, 0x0, "Merlin 132 Wax EISA BA"}, + {HPHW_BA, 0x041, 0x00090, 0x0, "Merlin 160 Wax EISA BA"}, + {HPHW_BA, 0x043, 0x00090, 0x0, "Merlin 132/160 Wax EISA BA"}, + {HPHW_BA, 0x052, 0x00090, 0x0, "Raven Hi Power Backplane Wax EISA BA"}, + {HPHW_BA, 0x054, 0x00090, 0x0, "Raven Lo Power Backplane Wax EISA BA"}, + {HPHW_BA, 0x059, 0x00090, 0x0, "FireHawk 200 Wax EISA BA"}, + {HPHW_BA, 0x05A, 0x00090, 0x0, "Raven L2 Backplane Wax EISA BA"}, + {HPHW_BA, 0x05D, 0x00090, 0x0, "SummitHawk Wax EISA BA"}, + {HPHW_BA, 0x800, 0x00090, 0x0, "Hitachi Tiny 64 Wax EISA BA"}, + {HPHW_BA, 0x801, 0x00090, 0x0, "Hitachi Tiny 80 Wax EISA BA"}, + {HPHW_BA, 0x01A, 0x00093, 0x0, "Anole 64 TIMI BA"}, + {HPHW_BA, 0x01B, 0x00093, 0x0, "Anole 64 TIMI BA"}, + {HPHW_BA, 0x034, 0x00093, 0x0, "Anole T TIMI BA"}, + {HPHW_BA, 0x04A, 0x00093, 0x0, "Anole L2 132 TIMI BA"}, + {HPHW_BA, 0x04C, 0x00093, 0x0, "Anole L2 165 TIMI BA"}, + {HPHW_BA, 0x582, 0x000A5, 0x00, "Epic PCI Bridge"}, + {HPHW_BCPORT, 0x504, 0x00000, 0x00, "Phantom PseudoBC GSC+ Port"}, + {HPHW_BCPORT, 0x505, 0x00000, 0x00, "Phantom PseudoBC GSC+ Port"}, + {HPHW_BCPORT, 0x503, 0x0000C, 0x00, "Java BC GSC+ Port"}, + {HPHW_BCPORT, 0x57F, 0x0000C, 0x00, "Hitachi Ghostview GSC+ Port"}, + {HPHW_BCPORT, 0x501, 0x0000C, 0x00, "U2-IOA BC GSC+ Port"}, + {HPHW_BCPORT, 0x502, 0x0000C, 0x00, "Uturn-IOA BC GSC+ Port"}, + {HPHW_BCPORT, 0x780, 0x0000C, 0x00, "Astro BC Ropes Port"}, + {HPHW_BCPORT, 0x506, 0x0000C, 0x00, "NEC-IOS BC HSC Port"}, + {HPHW_BCPORT, 0x004, 0x0000C, 0x00, "Cheetah BC SMB Port"}, + {HPHW_BCPORT, 0x006, 0x0000C, 0x00, "Cheetah BC MID_BUS Port"}, + {HPHW_BCPORT, 0x005, 0x0000C, 0x00, "Condor BC MID_BUS Port"}, + {HPHW_BCPORT, 0x100, 0x0000C, 0x00, "Condor BC HP-PB Port"}, + {HPHW_BCPORT, 0x184, 0x0000C, 0x00, "Summit BC Port"}, + {HPHW_BCPORT, 0x101, 0x0000C, 0x00, "Summit BC HP-PB Port"}, + {HPHW_BCPORT, 0x102, 0x0000C, 0x00, "HP-PB Port (prefetch)"}, + {HPHW_BCPORT, 0x500, 0x0000C, 0x00, "Gecko BOA BC GSC+ Port"}, + {HPHW_BCPORT, 0x103, 0x0000C, 0x00, "Gecko BOA BC HP-PB Port"}, + {HPHW_BCPORT, 0x507, 0x0000C, 0x00, "Keyaki BC GSC+ Port"}, + {HPHW_BCPORT, 0x508, 0x0000C, 0x00, "Keyaki-DX BC GSC+ Port"}, + {HPHW_BCPORT, 0x584, 0x0000C, 0x10, "DEW BC Runway Port"}, + {HPHW_BCPORT, 0x800, 0x0000C, 0x10, "DEW BC Merced Port"}, + {HPHW_BCPORT, 0x801, 0x0000C, 0x10, "SMC Bus Interface Merced Bus0"}, + {HPHW_BCPORT, 0x802, 0x0000C, 0x10, "SMC Bus INterface Merced Bus1"}, + {HPHW_BCPORT, 0x803, 0x0000C, 0x10, "IKE I/O Bus Converter Merced Port"}, + {HPHW_BCPORT, 0x781, 0x0000C, 0x00, "IKE I/O Bus Converter Ropes Port"}, + {HPHW_BCPORT, 0x804, 0x0000C, 0x10, "REO I/O Bus Converter Merced Port"}, + {HPHW_BCPORT, 0x782, 0x0000C, 0x00, "REO I/O Bus Converter Ropes Port"}, + {HPHW_BRIDGE, 0x680, 0x0000A, 0x00, "Dino PCI Bridge"}, + {HPHW_BRIDGE, 0x682, 0x0000A, 0x00, "Cujo PCI Bridge"}, + {HPHW_BRIDGE, 0x782, 0x0000A, 0x00, "Elroy PCI Bridge"}, + {HPHW_BRIDGE, 0x583, 0x000A5, 0x00, "Saga PCI Bridge"}, + {HPHW_B_DMA, 0x004, 0x00018, 0x00, "Parallel I/O"}, + {HPHW_B_DMA, 0x004, 0x00019, 0x00, "Parallel RDB"}, + {HPHW_B_DMA, 0x004, 0x00020, 0x80, "MID_BUS PSI"}, + {HPHW_B_DMA, 0x004, 0x0002F, 0x80, "HP-PB Transit PSI (36960A)"}, + {HPHW_B_DMA, 0x008, 0x00051, 0x80, "HP-PB Transit 802.3"}, + {HPHW_B_DMA, 0x004, 0x00052, 0x80, "Miura LAN/Console (J2146A)"}, + {HPHW_B_DMA, 0x008, 0x00058, 0x80, "HP-PB Transit 802.4"}, + {HPHW_B_DMA, 0x005, 0x00060, 0x80, "KittyHawk CSY Core LAN/Console"}, + {HPHW_B_DMA, 0x014, 0x00060, 0x80, "Diablo LAN/Console"}, + {HPHW_B_DMA, 0x054, 0x00060, 0x80, "Countach LAN/Console"}, + {HPHW_B_DMA, 0x004, 0x00094, 0x80, "KittyHawk GSC+ Exerciser"}, + {HPHW_B_DMA, 0x004, 0x00100, 0x80, "HP-PB HF Interface"}, + {HPHW_B_DMA, 0x000, 0x00206, 0x80, "MELCO HMPHA"}, + {HPHW_B_DMA, 0x005, 0x00206, 0x80, "MELCO HMPHA_10"}, + {HPHW_B_DMA, 0x006, 0x00206, 0x80, "MELCO HMQHA"}, + {HPHW_B_DMA, 0x007, 0x00206, 0x80, "MELCO HMQHA_10"}, + {HPHW_B_DMA, 0x004, 0x207, 0x80, "MELCO HNDWA MDWS-70"}, + {HPHW_CIO, 0x004, 0x00010, 0x00, "VLSI CIO"}, + {HPHW_CIO, 0x005, 0x00010, 0x00, "Silverfox CIO"}, + {HPHW_CIO, 0x006, 0x00010, 0x00, "Emerald CIO"}, + {HPHW_CIO, 0x008, 0x00010, 0x00, "Discrete CIO"}, + {HPHW_CONSOLE, 0x004, 0x0001C, 0x00, "Cheetah console"}, + {HPHW_CONSOLE, 0x005, 0x0001C, 0x00, "Emerald console"}, + {HPHW_CONSOLE, 0x01A, 0x0001F, 0x00, "Jason/Anole 64 Null Console"}, + {HPHW_CONSOLE, 0x01B, 0x0001F, 0x00, "Jason/Anole 100 Null Console"}, + {HPHW_FABRIC, 0x004, 0x000AA, 0x80, "Halfdome DNA Central Agent"}, + {HPHW_FABRIC, 0x004, 0x000AB, 0x00, "Halfdome TOGO Fabric Crossbar"}, + {HPHW_FABRIC, 0x004, 0x000AC, 0x00, "Halfdome Sakura Fabric Router"}, + {HPHW_FIO, 0x025, 0x0002E, 0x80, "Armyknife Optional X.25"}, + {HPHW_FIO, 0x004, 0x0004F, 0x0, "8-Port X.25 EISA-ACC (AMSO)"}, + {HPHW_FIO, 0x004, 0x00071, 0x0, "Cobra Core SCSI"}, + {HPHW_FIO, 0x005, 0x00071, 0x0, "Coral Core SCSI"}, + {HPHW_FIO, 0x006, 0x00071, 0x0, "Bushmaster Core SCSI"}, + {HPHW_FIO, 0x007, 0x00071, 0x0, "Scorpio Core SCSI"}, + {HPHW_FIO, 0x008, 0x00071, 0x0, "Flounder Core SCSI"}, + {HPHW_FIO, 0x009, 0x00071, 0x0, "Outfield Core SCSI"}, + {HPHW_FIO, 0x00A, 0x00071, 0x0, "CoralII Core SCSI"}, + {HPHW_FIO, 0x00B, 0x00071, 0x0, "Scorpio Jr. Core SCSI"}, + {HPHW_FIO, 0x00C, 0x00071, 0x0, "Strider-50 Core SCSI"}, + {HPHW_FIO, 0x00D, 0x00071, 0x0, "Strider-33 Core SCSI"}, + {HPHW_FIO, 0x00E, 0x00071, 0x0, "Trailways-50 Core SCSI"}, + {HPHW_FIO, 0x00F, 0x00071, 0x0, "Trailways-33 Core SCSI"}, + {HPHW_FIO, 0x010, 0x00071, 0x0, "Pace Core SCSI"}, + {HPHW_FIO, 0x011, 0x00071, 0x0, "Sidewinder Core SCSI"}, + {HPHW_FIO, 0x019, 0x00071, 0x0, "Scorpio Sr. Core SCSI"}, + {HPHW_FIO, 0x020, 0x00071, 0x0, "Scorpio 100 Core SCSI"}, + {HPHW_FIO, 0x021, 0x00071, 0x0, "Spectra 50 Core SCSI"}, + {HPHW_FIO, 0x022, 0x00071, 0x0, "Spectra 75 Core SCSI"}, + {HPHW_FIO, 0x023, 0x00071, 0x0, "Spectra 100 Core SCSI"}, + {HPHW_FIO, 0x024, 0x00071, 0x0, "Fast Pace Core SCSI"}, + {HPHW_FIO, 0x026, 0x00071, 0x0, "CoralII Jaguar Core SCSI"}, + {HPHW_FIO, 0x004, 0x00072, 0x0, "Cobra Core LAN (802.3)"}, + {HPHW_FIO, 0x005, 0x00072, 0x0, "Coral Core LAN (802.3)"}, + {HPHW_FIO, 0x006, 0x00072, 0x0, "Bushmaster Core LAN (802.3)"}, + {HPHW_FIO, 0x007, 0x00072, 0x0, "Scorpio Core LAN (802.3)"}, + {HPHW_FIO, 0x008, 0x00072, 0x0, "Flounder Core LAN (802.3)"}, + {HPHW_FIO, 0x009, 0x00072, 0x0, "Outfield Core LAN (802.3)"}, + {HPHW_FIO, 0x00A, 0x00072, 0x0, "CoralII Core LAN (802.3)"}, + {HPHW_FIO, 0x00B, 0x00072, 0x0, "Scorpio Jr. Core LAN (802.3)"}, + {HPHW_FIO, 0x00C, 0x00072, 0x0, "Strider-50 Core LAN (802.3)"}, + {HPHW_FIO, 0x00D, 0x00072, 0x0, "Strider-33 Core LAN (802.3)"}, + {HPHW_FIO, 0x00E, 0x00072, 0x0, "Trailways-50 Core LAN (802.3)"}, + {HPHW_FIO, 0x00F, 0x00072, 0x0, "Trailways-33 Core LAN (802.3)"}, + {HPHW_FIO, 0x010, 0x00072, 0x0, "Pace Core Lan (802.3)"}, + {HPHW_FIO, 0x011, 0x00072, 0x0, "Sidewinder Core Lan (802.3)"}, + {HPHW_FIO, 0x019, 0x00072, 0x0, "Scorpio Sr. Core LAN (802.3)"}, + {HPHW_FIO, 0x020, 0x00072, 0x0, "Scorpio 100 Core LAN (802.3)"}, + {HPHW_FIO, 0x021, 0x00072, 0x0, "Spectra 50 Core LAN (802.3)"}, + {HPHW_FIO, 0x022, 0x00072, 0x0, "Spectra 75 Core LAN (802.3)"}, + {HPHW_FIO, 0x023, 0x00072, 0x0, "Spectra 100 Core LAN (802.3)"}, + {HPHW_FIO, 0x024, 0x00072, 0x0, "Fast Pace Core Lan (802.3)"}, + {HPHW_FIO, 0x026, 0x00072, 0x0, "CoralII Jaguar Core LAN (802.3)"}, + {HPHW_FIO, 0x004, 0x00073, 0x0, "Cobra Core HIL"}, + {HPHW_FIO, 0x005, 0x00073, 0x0, "Coral Core HIL"}, + {HPHW_FIO, 0x006, 0x00073, 0x0, "Bushmaster Core HIL"}, + {HPHW_FIO, 0x007, 0x00073, 0x0, "Scorpio Core HIL"}, + {HPHW_FIO, 0x008, 0x00073, 0x0, "Flounder Core HIL"}, + {HPHW_FIO, 0x009, 0x00073, 0x0, "Outfield Core HIL"}, + {HPHW_FIO, 0x00A, 0x00073, 0x0, "CoralII Core HIL"}, + {HPHW_FIO, 0x00B, 0x00073, 0x0, "Scorpio Jr. Core HIL"}, + {HPHW_FIO, 0x00C, 0x00073, 0x0, "Strider-50 Core HIL"}, + {HPHW_FIO, 0x00D, 0x00073, 0x0, "Strider-33 Core HIL"}, + {HPHW_FIO, 0x00E, 0x00073, 0x0, "Trailways-50 Core HIL"}, + {HPHW_FIO, 0x00F, 0x00073, 0x0, "Trailways-33 Core HIL"}, + {HPHW_FIO, 0x010, 0x00073, 0x0, "Pace Core HIL"}, + {HPHW_FIO, 0x011, 0x00073, 0xcc, "SuperPace Wax HIL"}, + {HPHW_FIO, 0x012, 0x00073, 0x0, "Mirage Jr Wax HIL"}, + {HPHW_FIO, 0x013, 0x00073, 0x0, "Mirage 100 Wax HIL"}, + {HPHW_FIO, 0x014, 0x00073, 0x0, "Electra Wax HIL"}, + {HPHW_FIO, 0x017, 0x00073, 0x0, "Raven Backplane Wax HIL"}, + {HPHW_FIO, 0x019, 0x00073, 0x0, "Scorpio Sr. Core HIL"}, + {HPHW_FIO, 0x01E, 0x00073, 0x0, "Raven T' Wax HIL"}, + {HPHW_FIO, 0x01F, 0x00073, 0x0, "SkyHawk 100/120 Wax HIL"}, + {HPHW_FIO, 0x020, 0x00073, 0x0, "Scorpio 100 Core HIL"}, + {HPHW_FIO, 0x021, 0x00073, 0x0, "Spectra 50 Core HIL"}, + {HPHW_FIO, 0x022, 0x00073, 0x0, "Spectra 75 Core HIL"}, + {HPHW_FIO, 0x023, 0x00073, 0x0, "Spectra 100 Core HIL"}, + {HPHW_FIO, 0x024, 0x00073, 0x0, "Fast Pace Core HIL"}, + {HPHW_FIO, 0x026, 0x00073, 0x0, "CoralII Jaguar Core HIL"}, + {HPHW_FIO, 0x02B, 0x00073, 0x0, "Mirage 80 Wax HIL"}, + {HPHW_FIO, 0x02C, 0x00073, 0x0, "Mirage 100+ Wax HIL"}, + {HPHW_FIO, 0x03A, 0x00073, 0x0, "Merlin+ Wax HIL"}, + {HPHW_FIO, 0x040, 0x00073, 0x0, "Merlin 132 Wax HIL"}, + {HPHW_FIO, 0x041, 0x00073, 0x0, "Merlin 160 Wax HIL"}, + {HPHW_FIO, 0x043, 0x00073, 0x0, "Merlin 132/160 Wax HIL"}, + {HPHW_FIO, 0x052, 0x00073, 0x0, "Raven+ Hi Power Backplane w/EISA Wax HIL"}, + {HPHW_FIO, 0x053, 0x00073, 0x0, "Raven+ Hi Power Backplane wo/EISA Wax HIL"}, + {HPHW_FIO, 0x054, 0x00073, 0x0, "Raven+ Lo Power Backplane w/EISA Wax HIL"}, + {HPHW_FIO, 0x055, 0x00073, 0x0, "Raven+ Lo Power Backplane wo/EISA Wax HIL"}, + {HPHW_FIO, 0x059, 0x00073, 0x0, "FireHawk 200 Wax HIL"}, + {HPHW_FIO, 0x05A, 0x00073, 0x0, "Raven+ L2 Backplane w/EISA Wax HIL"}, + {HPHW_FIO, 0x05B, 0x00073, 0x0, "Raven+ L2 Backplane wo/EISA Wax HIL"}, + {HPHW_FIO, 0x05D, 0x00073, 0x0, "SummitHawk Wax HIL"}, + {HPHW_FIO, 0x800, 0x00073, 0x0, "Hitachi Tiny 64 Wax HIL"}, + {HPHW_FIO, 0x801, 0x00073, 0x0, "Hitachi Tiny 80 Wax HIL"}, + {HPHW_FIO, 0x004, 0x00074, 0x0, "Cobra Core Centronics"}, + {HPHW_FIO, 0x005, 0x00074, 0x0, "Coral Core Centronics"}, + {HPHW_FIO, 0x006, 0x00074, 0x0, "Bushmaster Core Centronics"}, + {HPHW_FIO, 0x007, 0x00074, 0x0, "Scorpio Core Centronics"}, + {HPHW_FIO, 0x008, 0x00074, 0x0, "Flounder Core Centronics"}, + {HPHW_FIO, 0x009, 0x00074, 0x0, "Outfield Core Centronics"}, + {HPHW_FIO, 0x00A, 0x00074, 0x0, "CoralII Core Centronics"}, + {HPHW_FIO, 0x00B, 0x00074, 0x0, "Scorpio Jr. Core Centronics"}, + {HPHW_FIO, 0x00C, 0x00074, 0x0, "Strider-50 Core Centronics"}, + {HPHW_FIO, 0x00D, 0x00074, 0x0, "Strider-33 Core Centronics"}, + {HPHW_FIO, 0x00E, 0x00074, 0x0, "Trailways-50 Core Centronics"}, + {HPHW_FIO, 0x00F, 0x00074, 0x0, "Trailways-33 Core Centronics"}, + {HPHW_FIO, 0x010, 0x00074, 0x0, "Pace Core Centronics"}, + {HPHW_FIO, 0x011, 0x00074, 0x0, "Sidewinder Core Centronics"}, + {HPHW_FIO, 0x015, 0x00074, 0x0, "KittyHawk GSY Core Centronics"}, + {HPHW_FIO, 0x016, 0x00074, 0x0, "Gecko Core Centronics"}, + {HPHW_FIO, 0x019, 0x00074, 0x0, "Scorpio Sr. Core Centronics"}, + {HPHW_FIO, 0x01A, 0x00074, 0x0, "Anole 64 Core Centronics"}, + {HPHW_FIO, 0x01B, 0x00074, 0x0, "Anole 100 Core Centronics"}, + {HPHW_FIO, 0x01C, 0x00074, 0x0, "Gecko 80 Core Centronics"}, + {HPHW_FIO, 0x01D, 0x00074, 0x0, "Gecko 100 Core Centronics"}, + {HPHW_FIO, 0x01F, 0x00074, 0x0, "SkyHawk 100/120 Core Centronics"}, + {HPHW_FIO, 0x020, 0x00074, 0x0, "Scorpio 100 Core Centronics"}, + {HPHW_FIO, 0x021, 0x00074, 0x0, "Spectra 50 Core Centronics"}, + {HPHW_FIO, 0x022, 0x00074, 0x0, "Spectra 75 Core Centronics"}, + {HPHW_FIO, 0x023, 0x00074, 0x0, "Spectra 100 Core Centronics"}, + {HPHW_FIO, 0x024, 0x00074, 0x0, "Fast Pace Core Centronics"}, + {HPHW_FIO, 0x026, 0x00074, 0x0, "CoralII Jaguar Core Centronics"}, + {HPHW_FIO, 0x027, 0x00074, 0x0, "Piranha 100 Core Centronics"}, + {HPHW_FIO, 0x028, 0x00074, 0x0, "Mirage Jr Core Centronics"}, + {HPHW_FIO, 0x029, 0x00074, 0x0, "Mirage Core Centronics"}, + {HPHW_FIO, 0x02A, 0x00074, 0x0, "Electra Core Centronics"}, + {HPHW_FIO, 0x02B, 0x00074, 0x0, "Mirage 80 Core Centronics"}, + {HPHW_FIO, 0x02C, 0x00074, 0x0, "Mirage 100+ Core Centronics"}, + {HPHW_FIO, 0x02E, 0x00074, 0x0, "UL 350 Core Centronics"}, + {HPHW_FIO, 0x02F, 0x00074, 0x0, "UL 550 Core Centronics"}, + {HPHW_FIO, 0x032, 0x00074, 0x0, "Raven T' Core Centronics"}, + {HPHW_FIO, 0x033, 0x00074, 0x0, "Anole T Core Centronics"}, + {HPHW_FIO, 0x034, 0x00074, 0x0, "SAIC L-80 Core Centronics"}, + {HPHW_FIO, 0x035, 0x00074, 0x0, "PCX-L2 712/132 Core Centronics"}, + {HPHW_FIO, 0x036, 0x00074, 0x0, "PCX-L2 712/160 Core Centronics"}, + {HPHW_FIO, 0x03B, 0x00074, 0x0, "Raven U/L2 Core Centronics"}, + {HPHW_FIO, 0x03C, 0x00074, 0x0, "Merlin 132 Core Centronics"}, + {HPHW_FIO, 0x03D, 0x00074, 0x0, "Merlin 160 Core Centronics"}, + {HPHW_FIO, 0x03E, 0x00074, 0x0, "Merlin+ 132 Core Centronics"}, + {HPHW_FIO, 0x03F, 0x00074, 0x0, "Merlin+ 180 Core Centronics"}, + {HPHW_FIO, 0x044, 0x00074, 0x0, "Mohawk Core Centronics"}, + {HPHW_FIO, 0x045, 0x00074, 0x0, "Rocky1 Core Centronics"}, + {HPHW_FIO, 0x046, 0x00074, 0x0, "Rocky2 120 Core Centronics"}, + {HPHW_FIO, 0x047, 0x00074, 0x0, "Rocky2 150 Core Centronics"}, + {HPHW_FIO, 0x04B, 0x00074, 0x0, "Anole L2 132 Core Centronics"}, + {HPHW_FIO, 0x04D, 0x00074, 0x0, "Anole L2 165 Core Centronics"}, + {HPHW_FIO, 0x050, 0x00074, 0x0, "Merlin Jr 132 Core Centronics"}, + {HPHW_FIO, 0x051, 0x00074, 0x0, "Firehawk Core Centronics"}, + {HPHW_FIO, 0x056, 0x00074, 0x0, "Raven+ wSE FWSCSI Core Centronics"}, + {HPHW_FIO, 0x057, 0x00074, 0x0, "Raven+ wDiff FWSCSI Core Centronics"}, + {HPHW_FIO, 0x058, 0x00074, 0x0, "FireHawk 200 Core Centronics"}, + {HPHW_FIO, 0x05C, 0x00074, 0x0, "SummitHawk 230 Core Centronics"}, + {HPHW_FIO, 0x800, 0x00074, 0x0, "Hitachi Tiny 64 Core Centronics"}, + {HPHW_FIO, 0x801, 0x00074, 0x0, "Hitachi Tiny 80 Core Centronics"}, + {HPHW_FIO, 0x004, 0x00075, 0x0, "Cobra Core RS-232"}, + {HPHW_FIO, 0x005, 0x00075, 0x0, "Coral Core RS-232"}, + {HPHW_FIO, 0x006, 0x00075, 0x0, "Bushmaster Core RS-232"}, + {HPHW_FIO, 0x007, 0x00075, 0x0, "Scorpio Core RS-232"}, + {HPHW_FIO, 0x008, 0x00075, 0x0, "Flounder Core RS-232"}, + {HPHW_FIO, 0x009, 0x00075, 0x0, "Outfield Core RS-232"}, + {HPHW_FIO, 0x00A, 0x00075, 0x0, "CoralII Core RS-232"}, + {HPHW_FIO, 0x00B, 0x00075, 0x0, "Scorpio Jr. Core RS-232"}, + {HPHW_FIO, 0x00C, 0x00075, 0x0, "Strider-50 Core RS-232"}, + {HPHW_FIO, 0x00D, 0x00075, 0x0, "Strider-33 Core RS-232"}, + {HPHW_FIO, 0x00E, 0x00075, 0x0, "Trailways-50 Core RS-232"}, + {HPHW_FIO, 0x00F, 0x00075, 0x0, "Trailways-33 Core RS-232"}, + {HPHW_FIO, 0x010, 0x00075, 0x0, "Pace Core RS-232"}, + {HPHW_FIO, 0x011, 0x00075, 0x0, "Sidewinder Core RS-232"}, + {HPHW_FIO, 0x019, 0x00075, 0x0, "Scorpio Sr. Core RS-232"}, + {HPHW_FIO, 0x020, 0x00075, 0x0, "Scorpio 100 Core RS-232"}, + {HPHW_FIO, 0x021, 0x00075, 0x0, "Spectra 50 Core RS-232"}, + {HPHW_FIO, 0x022, 0x00075, 0x0, "Spectra 75 Core RS-232"}, + {HPHW_FIO, 0x023, 0x00075, 0x0, "Spectra 100 Core RS-232"}, + {HPHW_FIO, 0x024, 0x00075, 0x0, "Fast Pace Core RS-232"}, + {HPHW_FIO, 0x026, 0x00075, 0x0, "CoralII Jaguar Core RS-232"}, + {HPHW_FIO, 0x004, 0x00077, 0x0, "Coral SGC Graphics"}, + {HPHW_FIO, 0x005, 0x00077, 0x0, "Hyperdrive Optional Graphics"}, + {HPHW_FIO, 0x006, 0x00077, 0x0, "Stinger Optional Graphics"}, + {HPHW_FIO, 0x007, 0x00077, 0x0, "Scorpio Builtin Graphics"}, + {HPHW_FIO, 0x008, 0x00077, 0x0, "Anole Hyperdrive Optional Graphics"}, + {HPHW_FIO, 0x009, 0x00077, 0x0, "Thunder II graphics EISA form"}, + {HPHW_FIO, 0x00A, 0x00077, 0x0, "Thunder II graphics GSA form"}, + {HPHW_FIO, 0x00B, 0x00077, 0x0, "Scorpio Jr Builtin Graphics"}, + {HPHW_FIO, 0x00C, 0x00077, 0x0, "Strider-50 SSC Graphics"}, + {HPHW_FIO, 0x00D, 0x00077, 0x0, "Strider-33 SSC Graphics"}, + {HPHW_FIO, 0x00E, 0x00077, 0x0, "Trailways-50 SSC Graphics"}, + {HPHW_FIO, 0x00F, 0x00077, 0x0, "Trailways-33 SSC Graphics"}, + {HPHW_FIO, 0x010, 0x00077, 0x0, "Pace SGC Graphics"}, + {HPHW_FIO, 0x011, 0x00077, 0x0, "Mohawk Opt. 2D Graphics (Kid)"}, + {HPHW_FIO, 0x012, 0x00077, 0x0, "Raven Opt. 2D Graphics (Goat)"}, + {HPHW_FIO, 0x016, 0x00077, 0x0, "Lego 24 SCG Graphics"}, + {HPHW_FIO, 0x017, 0x00077, 0x0, "Lego 24Z SCG Graphics"}, + {HPHW_FIO, 0x018, 0x00077, 0x0, "Lego 48Z SCG Graphics"}, + {HPHW_FIO, 0x019, 0x00077, 0x0, "Scorpio Sr Builtin Graphics"}, + {HPHW_FIO, 0x020, 0x00077, 0x0, "Scorpio 100 Builtin Graphics"}, + {HPHW_FIO, 0x021, 0x00077, 0x0, "Spectra 50 Builtin Graphics"}, + {HPHW_FIO, 0x022, 0x00077, 0x0, "Spectra 75 Builtin Graphics"}, + {HPHW_FIO, 0x023, 0x00077, 0x0, "Spectra 100 Builtin Graphics"}, + {HPHW_FIO, 0x024, 0x00077, 0x0, "Fast Pace SGC Graphics"}, + {HPHW_FIO, 0x006, 0x0007A, 0x0, "Bushmaster Audio"}, + {HPHW_FIO, 0x008, 0x0007A, 0x0, "Flounder Audio"}, + {HPHW_FIO, 0x004, 0x0007B, 0x0, "UL Optional Audio"}, + {HPHW_FIO, 0x007, 0x0007B, 0x0, "Scorpio Audio"}, + {HPHW_FIO, 0x00B, 0x0007B, 0x0, "Scorpio Jr. Audio"}, + {HPHW_FIO, 0x00C, 0x0007B, 0x0, "Strider-50 Audio"}, + {HPHW_FIO, 0x00D, 0x0007B, 0x0, "Strider-33 Audio"}, + {HPHW_FIO, 0x00E, 0x0007B, 0x0, "Trailways-50 Audio"}, + {HPHW_FIO, 0x00F, 0x0007B, 0x0, "Trailways-33 Audio"}, + {HPHW_FIO, 0x016, 0x0007B, 0x0, "Gecko Audio"}, + {HPHW_FIO, 0x019, 0x0007B, 0x0, "Scorpio Sr. Audio"}, + {HPHW_FIO, 0x01A, 0x0007B, 0x0, "Anole 64 Audio"}, + {HPHW_FIO, 0x01B, 0x0007B, 0x0, "Anole 100 Audio"}, + {HPHW_FIO, 0x01C, 0x0007B, 0x0, "Gecko 80 Audio"}, + {HPHW_FIO, 0x01D, 0x0007B, 0x0, "Gecko 100 Audio"}, + {HPHW_FIO, 0x01F, 0x0007B, 0x0, "SkyHawk 100/120 Audio"}, + {HPHW_FIO, 0x020, 0x0007B, 0x0, "Scorpio 100 Audio"}, + {HPHW_FIO, 0x021, 0x0007B, 0x0, "Spectra 50 Audio"}, + {HPHW_FIO, 0x022, 0x0007B, 0x0, "Spectra 75 Audio"}, + {HPHW_FIO, 0x023, 0x0007B, 0x0, "Spectra 100 Audio"}, + {HPHW_FIO, 0x028, 0x0007B, 0x0, "Mirage Jr Audio"}, + {HPHW_FIO, 0x029, 0x0007B, 0x0, "Mirage Audio"}, + {HPHW_FIO, 0x02A, 0x0007B, 0x0, "Electra Audio"}, + {HPHW_FIO, 0x02B, 0x0007B, 0x0, "Mirage 80 Audio"}, + {HPHW_FIO, 0x02C, 0x0007B, 0x0, "Mirage 100+ Audio"}, + {HPHW_FIO, 0x032, 0x0007B, 0x0, "Raven T' Audio"}, + {HPHW_FIO, 0x034, 0x0007B, 0x0, "SAIC L-80 Audio"}, + {HPHW_FIO, 0x035, 0x0007B, 0x0, "PCX-L2 712/132 Core Audio"}, + {HPHW_FIO, 0x036, 0x0007B, 0x0, "PCX-L2 712/160 Core Audio"}, + {HPHW_FIO, 0x03B, 0x0007B, 0x0, "Raven U/L2 Core Audio"}, + {HPHW_FIO, 0x03C, 0x0007B, 0x0, "Merlin 132 Core Audio"}, + {HPHW_FIO, 0x03D, 0x0007B, 0x0, "Merlin 160 Core Audio"}, + {HPHW_FIO, 0x03E, 0x0007B, 0x0, "Merlin+ 132 Core Audio"}, + {HPHW_FIO, 0x03F, 0x0007B, 0x0, "Merlin+ 180 Core Audio"}, + {HPHW_FIO, 0x044, 0x0007B, 0x0, "Mohawk Core Audio"}, + {HPHW_FIO, 0x046, 0x0007B, 0x0, "Rocky2 120 Core Audio"}, + {HPHW_FIO, 0x047, 0x0007B, 0x0, "Rocky2 150 Core Audio"}, + {HPHW_FIO, 0x04B, 0x0007B, 0x0, "Anole L2 132 Core Audio"}, + {HPHW_FIO, 0x04D, 0x0007B, 0x0, "Anole L2 165 Core Audio"}, + {HPHW_FIO, 0x04E, 0x0007B, 0x0, "Kiji L2 132 Core Audio"}, + {HPHW_FIO, 0x050, 0x0007B, 0x0, "Merlin Jr 132 Core Audio"}, + {HPHW_FIO, 0x051, 0x0007B, 0x0, "Firehawk Audio"}, + {HPHW_FIO, 0x056, 0x0007B, 0x0, "Raven+ w SE FWSCSU Core Audio"}, + {HPHW_FIO, 0x057, 0x0007B, 0x0, "Raven+ w Diff FWSCSU Core Audio"}, + {HPHW_FIO, 0x058, 0x0007B, 0x0, "FireHawk 200 Audio"}, + {HPHW_FIO, 0x05C, 0x0007B, 0x0, "SummitHawk 230 Core Audio"}, + {HPHW_FIO, 0x800, 0x0007B, 0x0, "Hitachi Tiny 64 Audio"}, + {HPHW_FIO, 0x801, 0x0007B, 0x0, "Hitachi Tiny 80 Audio"}, + {HPHW_FIO, 0x009, 0x0007C, 0x0, "Outfield FW SCSI"}, + {HPHW_FIO, 0x00A, 0x0007C, 0x0, "CoralII FW SCSI"}, + {HPHW_FIO, 0x026, 0x0007C, 0x0, "CoralII Jaguar FW SCSI"}, + {HPHW_FIO, 0x009, 0x0007D, 0x0, "Outfield FDDI"}, + {HPHW_FIO, 0x00A, 0x0007D, 0x0, "CoralII FDDI"}, + {HPHW_FIO, 0x026, 0x0007D, 0x0, "CoralII Jaguar FDDI"}, + {HPHW_FIO, 0x010, 0x0007E, 0x0, "Pace Audio"}, + {HPHW_FIO, 0x024, 0x0007E, 0x0, "Fast Pace Audio"}, + {HPHW_FIO, 0x009, 0x0007F, 0x0, "Outfield Audio"}, + {HPHW_FIO, 0x00A, 0x0007F, 0x0, "CoralII Audio"}, + {HPHW_FIO, 0x026, 0x0007F, 0x0, "CoralII Jaguar Audio"}, + {HPHW_FIO, 0x010, 0x00080, 0x0, "Pace Core HPIB"}, + {HPHW_FIO, 0x024, 0x00080, 0x0, "Fast Pace Core HPIB"}, + {HPHW_FIO, 0x016, 0x00082, 0x0, "Gecko Core SCSI"}, + {HPHW_FIO, 0x01A, 0x00082, 0x0, "Anole 64 Core SCSI"}, + {HPHW_FIO, 0x01B, 0x00082, 0x0, "Anole 100 Core SCSI"}, + {HPHW_FIO, 0x01C, 0x00082, 0x0, "Gecko 80 Core SCSI"}, + {HPHW_FIO, 0x01D, 0x00082, 0x0, "Gecko 100 Core SCSI"}, + {HPHW_FIO, 0x01F, 0x00082, 0x0, "SkyHawk 100/120 Core SCSI"}, + {HPHW_FIO, 0x027, 0x00082, 0x0, "Piranha 100 Core SCSI"}, + {HPHW_FIO, 0x028, 0x00082, 0x0, "Mirage Jr Core SCSI"}, + {HPHW_FIO, 0x029, 0x00082, 0x0, "Mirage Core SCSI"}, + {HPHW_FIO, 0x02A, 0x00082, 0x0, "Electra Core SCSI"}, + {HPHW_FIO, 0x02B, 0x00082, 0x0, "Mirage 80 Core SCSI"}, + {HPHW_FIO, 0x02C, 0x00082, 0x0, "Mirage 100+ Core SCSI"}, + {HPHW_FIO, 0x02E, 0x00082, 0x0, "UL 350 Core SCSI"}, + {HPHW_FIO, 0x02F, 0x00082, 0x0, "UL 550 Core SCSI"}, + {HPHW_FIO, 0x032, 0x00082, 0x0, "Raven T' Core SCSI"}, + {HPHW_FIO, 0x033, 0x00082, 0x0, "Anole T Core SCSI"}, + {HPHW_FIO, 0x034, 0x00082, 0x0, "SAIC L-80 Core SCSI"}, + {HPHW_FIO, 0x035, 0x00082, 0x0, "PCX-L2 712/132 Core SCSI"}, + {HPHW_FIO, 0x036, 0x00082, 0x0, "PCX-L2 712/160 Core SCSI"}, + {HPHW_FIO, 0x03B, 0x00082, 0x0, "Raven U/L2 Core SCSI"}, + {HPHW_FIO, 0x03C, 0x00082, 0x0, "Merlin 132 Core SCSI"}, + {HPHW_FIO, 0x03D, 0x00082, 0x0, "Merlin 160 Core SCSI"}, + {HPHW_FIO, 0x03E, 0x00082, 0x0, "Merlin+ 132 Core SCSI"}, + {HPHW_FIO, 0x03F, 0x00082, 0x0, "Merlin+ 180 Core SCSI"}, + {HPHW_FIO, 0x044, 0x00082, 0x0, "Mohawk Core SCSI"}, + {HPHW_FIO, 0x045, 0x00082, 0x0, "Rocky1 Core SCSI"}, + {HPHW_FIO, 0x046, 0x00082, 0x0, "Rocky2 120 Core SCSI"}, + {HPHW_FIO, 0x047, 0x00082, 0x0, "Rocky2 150 Core SCSI"}, + {HPHW_FIO, 0x04B, 0x00082, 0x0, "Anole L2 132 Core SCSI"}, + {HPHW_FIO, 0x04D, 0x00082, 0x0, "Anole L2 165 Core SCSI"}, + {HPHW_FIO, 0x04E, 0x00082, 0x0, "Kiji L2 132 Core SCSI"}, + {HPHW_FIO, 0x050, 0x00082, 0x0, "Merlin Jr 132 Core SCSI"}, + {HPHW_FIO, 0x051, 0x00082, 0x0, "Firehawk Core SCSI"}, + {HPHW_FIO, 0x056, 0x00082, 0x0, "Raven+ w SE FWSCSI Core SCSI"}, + {HPHW_FIO, 0x057, 0x00082, 0x0, "Raven+ w Diff FWSCSI Core SCSI"}, + {HPHW_FIO, 0x058, 0x00082, 0x0, "FireHawk 200 Core SCSI"}, + {HPHW_FIO, 0x05C, 0x00082, 0x0, "SummitHawk 230 Core SCSI"}, + {HPHW_FIO, 0x05E, 0x00082, 0x0, "Staccato 132 Core SCSI"}, + {HPHW_FIO, 0x05F, 0x00082, 0x0, "Staccato 180 Core SCSI"}, + {HPHW_FIO, 0x800, 0x00082, 0x0, "Hitachi Tiny 64 Core SCSI"}, + {HPHW_FIO, 0x801, 0x00082, 0x0, "Hitachi Tiny 80 Core SCSI"}, + {HPHW_FIO, 0x016, 0x00083, 0x0, "Gecko Core PC Floppy"}, + {HPHW_FIO, 0x01C, 0x00083, 0x0, "Gecko 80 Core PC Floppy"}, + {HPHW_FIO, 0x01D, 0x00083, 0x0, "Gecko 100 Core PC Floppy"}, + {HPHW_FIO, 0x051, 0x00083, 0x0, "Firehawk Core PC Floppy"}, + {HPHW_FIO, 0x058, 0x00083, 0x0, "FireHawk 200 Core PC Floppy"}, + {HPHW_FIO, 0x027, 0x00083, 0x0, "Piranha 100 Core PC Floppy"}, + {HPHW_FIO, 0x028, 0x00083, 0x0, "Mirage Jr Core PC Floppy"}, + {HPHW_FIO, 0x029, 0x00083, 0x0, "Mirage Core PC Floppy"}, + {HPHW_FIO, 0x02A, 0x00083, 0x0, "Electra Core PC Floppy"}, + {HPHW_FIO, 0x02B, 0x00083, 0x0, "Mirage 80 Core PC Floppy"}, + {HPHW_FIO, 0x02C, 0x00083, 0x0, "Mirage 100+ Core PC Floppy"}, + {HPHW_FIO, 0x02E, 0x00083, 0x0, "UL 350 Core PC Floppy"}, + {HPHW_FIO, 0x02F, 0x00083, 0x0, "UL 550 Core PC Floppy"}, + {HPHW_FIO, 0x032, 0x00083, 0x0, "Raven T' Core PC Floppy"}, + {HPHW_FIO, 0x034, 0x00083, 0x0, "SAIC L-80 Core PC Floopy"}, + {HPHW_FIO, 0x035, 0x00083, 0x0, "PCX-L2 712/132 Core Floopy"}, + {HPHW_FIO, 0x036, 0x00083, 0x0, "PCX-L2 712/160 Core Floopy"}, + {HPHW_FIO, 0x03B, 0x00083, 0x0, "Raven U/L2 Core PC Floopy"}, + {HPHW_FIO, 0x03C, 0x00083, 0x0, "Merlin 132 Core PC Floopy"}, + {HPHW_FIO, 0x03D, 0x00083, 0x0, "Merlin 160 Core PC Floopy"}, + {HPHW_FIO, 0x03E, 0x00083, 0x0, "Merlin+ 132 Core PC Floopy"}, + {HPHW_FIO, 0x03F, 0x00083, 0x0, "Merlin+ 180 Core PC Floopy"}, + {HPHW_FIO, 0x045, 0x00083, 0x0, "Rocky1 Core PC Floopy"}, + {HPHW_FIO, 0x046, 0x00083, 0x0, "Rocky2 120 Core PC Floopy"}, + {HPHW_FIO, 0x047, 0x00083, 0x0, "Rocky2 150 Core PC Floopy"}, + {HPHW_FIO, 0x04E, 0x00083, 0x0, "Kiji L2 132 Core PC Floopy"}, + {HPHW_FIO, 0x050, 0x00083, 0x0, "Merlin Jr 132 Core PC Floopy"}, + {HPHW_FIO, 0x056, 0x00083, 0x0, "Raven+ w SE FWSCSI Core PC Floopy"}, + {HPHW_FIO, 0x057, 0x00083, 0x0, "Raven+ w Diff FWSCSI Core PC Floopy"}, + {HPHW_FIO, 0x800, 0x00083, 0x0, "Hitachi Tiny 64 Core PC Floopy"}, + {HPHW_FIO, 0x801, 0x00083, 0x0, "Hitachi Tiny 80 Core PC Floopy"}, + {HPHW_FIO, 0x015, 0x00084, 0x0, "KittyHawk GSY Core PC Keyboard"}, + {HPHW_FIO, 0x016, 0x00084, 0x0, "Gecko Core PC Keyboard"}, + {HPHW_FIO, 0x018, 0x00084, 0x0, "Gecko Optional PC Keyboard"}, + {HPHW_FIO, 0x01A, 0x00084, 0x0, "Anole 64 Core PC Keyboard"}, + {HPHW_FIO, 0x01B, 0x00084, 0x0, "Anole 100 Core PC Keyboard"}, + {HPHW_FIO, 0x01C, 0x00084, 0x0, "Gecko 80 Core PC Keyboard"}, + {HPHW_FIO, 0x01D, 0x00084, 0x0, "Gecko 100 Core PC Keyboard"}, + {HPHW_FIO, 0x01F, 0x00084, 0x0, "SkyHawk 100/120 Core PC Keyboard"}, + {HPHW_FIO, 0x027, 0x00084, 0x0, "Piranha 100 Core PC Keyboard"}, + {HPHW_FIO, 0x028, 0x00084, 0x0, "Mirage Jr Core PC Keyboard"}, + {HPHW_FIO, 0x029, 0x00084, 0x0, "Mirage Core PC Keyboard"}, + {HPHW_FIO, 0x02A, 0x00084, 0x0, "Electra Core PC Keyboard"}, + {HPHW_FIO, 0x02B, 0x00084, 0x0, "Mirage 80 Core PC Keyboard"}, + {HPHW_FIO, 0x02C, 0x00084, 0x0, "Mirage 100+ Core PC Keyboard"}, + {HPHW_FIO, 0x02E, 0x00084, 0x0, "UL 350 Core PC Keyboard"}, + {HPHW_FIO, 0x02F, 0x00084, 0x0, "UL 550 Core PC Keyboard"}, + {HPHW_FIO, 0x032, 0x00084, 0x0, "Raven T' Core PC Keyboard"}, + {HPHW_FIO, 0x033, 0x00084, 0x0, "Anole T Core PC Keyboard"}, + {HPHW_FIO, 0x034, 0x00084, 0x0, "SAIC L-80 Core PC Keyboard"}, + {HPHW_FIO, 0x035, 0x00084, 0x0, "PCX-L2 712/132 Core Keyboard"}, + {HPHW_FIO, 0x036, 0x00084, 0x0, "PCX-L2 712/160 Core Keyboard"}, + {HPHW_FIO, 0x03B, 0x00084, 0x0, "Raven U/L2 Core PC Keyboard"}, + {HPHW_FIO, 0x03C, 0x00084, 0x0, "Merlin 132 Core PC Keyboard"}, + {HPHW_FIO, 0x03D, 0x00084, 0x0, "Merlin 160 Core PC Keyboard"}, + {HPHW_FIO, 0x03E, 0x00084, 0x0, "Merlin+ 132 Core PC Keyboard"}, + {HPHW_FIO, 0x03F, 0x00084, 0x0, "Merlin+ 180 Core PC Keyboard"}, + {HPHW_FIO, 0x044, 0x00084, 0x0, "Mohawk Core PC Keyboard"}, + {HPHW_FIO, 0x045, 0x00084, 0x0, "Rocky1 Core PC Keyboard"}, + {HPHW_FIO, 0x046, 0x00084, 0x0, "Rocky2 120 Core PC Keyboard"}, + {HPHW_FIO, 0x047, 0x00084, 0x0, "Rocky2 150 Core PC Keyboard"}, + {HPHW_FIO, 0x048, 0x00084, 0x0, "Rocky2 120 Dino PC Keyboard"}, + {HPHW_FIO, 0x049, 0x00084, 0x0, "Rocky2 150 Dino PC Keyboard"}, + {HPHW_FIO, 0x04B, 0x00084, 0x0, "Anole L2 132 Core PC Keyboard"}, + {HPHW_FIO, 0x04D, 0x00084, 0x0, "Anole L2 165 Core PC Keyboard"}, + {HPHW_FIO, 0x04E, 0x00084, 0x0, "Kiji L2 132 Core PC Keyboard"}, + {HPHW_FIO, 0x050, 0x00084, 0x0, "Merlin Jr 132 Core PC Keyboard"}, + {HPHW_FIO, 0x051, 0x00084, 0x0, "Firehawk Core PC Keyboard"}, + {HPHW_FIO, 0x056, 0x00084, 0x0, "Raven+ w SE FWSCSI Core PC Keyboard"}, + {HPHW_FIO, 0x057, 0x00084, 0x0, "Raven+ w Diff FWSCSI Core PC Keyboard"}, + {HPHW_FIO, 0x058, 0x00084, 0x0, "FireHawk 200 Core PC Keyboard"}, + {HPHW_FIO, 0x05C, 0x00084, 0x0, "SummitHawk 230 Core PC Keyboard"}, + {HPHW_FIO, 0x800, 0x00084, 0x0, "Hitachi Tiny 64 Core PC Keyboard"}, + {HPHW_FIO, 0x801, 0x00084, 0x0, "Hitachi Tiny 80 Core PC Keyboard"}, + {HPHW_FIO, 0x004, 0x00085, 0x0, "Solo GSC Optional Graphics"}, + {HPHW_FIO, 0x005, 0x00085, 0x0, "Duet GSC Optional Graphics"}, + {HPHW_FIO, 0x008, 0x00085, 0x0, "Anole Artist Optional Graphics"}, + {HPHW_FIO, 0x010, 0x00085, 0x0, "Mirage 80 GSC Builtin Graphics"}, + {HPHW_FIO, 0x011, 0x00085, 0x0, "Mirage 100+ GSC Builtin Graphics"}, + {HPHW_FIO, 0x012, 0x00085, 0x0, "Mirage Jr GSC Builtin Graphics"}, + {HPHW_FIO, 0x013, 0x00085, 0x0, "Mirage GSC Builtin Graphics"}, + {HPHW_FIO, 0x014, 0x00085, 0x0, "Electra GSC Builtin Graphics"}, + {HPHW_FIO, 0x016, 0x00085, 0x0, "Gecko GSC Core Graphics"}, + {HPHW_FIO, 0x017, 0x00085, 0x0, "Gecko GSC Optional Graphics"}, + {HPHW_FIO, 0x01A, 0x00085, 0x0, "Anole 64 Artist Builtin Graphics"}, + {HPHW_FIO, 0x01B, 0x00085, 0x0, "Anole 100 Artist Builtin Graphics"}, + {HPHW_FIO, 0x01C, 0x00085, 0x0, "Gecko 80 GSC Core Graphics"}, + {HPHW_FIO, 0x01D, 0x00085, 0x0, "Gecko 100 GSC Core Graphics"}, + {HPHW_FIO, 0x032, 0x00085, 0x0, "Raven T' GSC Core Graphics"}, + {HPHW_FIO, 0x033, 0x00085, 0x0, "Anole T Artist Builtin Graphics"}, + {HPHW_FIO, 0x034, 0x00085, 0x0, "SAIC L-80 GSC Core Graphics"}, + {HPHW_FIO, 0x035, 0x00085, 0x0, "PCX-L2 712/132 Core Graphics"}, + {HPHW_FIO, 0x036, 0x00085, 0x0, "PCX-L2 712/160 Core Graphics"}, + {HPHW_FIO, 0x03B, 0x00085, 0x0, "Raven U/L2 Core Graphics"}, + {HPHW_FIO, 0x03C, 0x00085, 0x0, "Merlin 132 Core Graphics"}, + {HPHW_FIO, 0x03D, 0x00085, 0x0, "Merlin 160 Core Graphics"}, + {HPHW_FIO, 0x03E, 0x00085, 0x0, "Merlin+ 132 Core Graphics"}, + {HPHW_FIO, 0x03F, 0x00085, 0x0, "Merlin+ 180 Core Graphics"}, + {HPHW_FIO, 0x045, 0x00085, 0x0, "Rocky1 Core Graphics"}, + {HPHW_FIO, 0x046, 0x00085, 0x0, "Rocky2 120 Core Graphics"}, + {HPHW_FIO, 0x047, 0x00085, 0x0, "Rocky2 150 Core Graphics"}, + {HPHW_FIO, 0x04B, 0x00085, 0x0, "Anole L2 132 Core Graphics"}, + {HPHW_FIO, 0x04D, 0x00085, 0x0, "Anole L2 165 Core Graphics"}, + {HPHW_FIO, 0x04E, 0x00085, 0x0, "Kiji L2 132 Core Graphics"}, + {HPHW_FIO, 0x050, 0x00085, 0x0, "Merlin Jr 132 Core Graphics"}, + {HPHW_FIO, 0x056, 0x00085, 0x0, "Raven+ w SE FWSCSI Core Graphics"}, + {HPHW_FIO, 0x057, 0x00085, 0x0, "Raven+ w Diff FWSCSI Core Graphics"}, + {HPHW_FIO, 0x800, 0x00085, 0x0, "Hitachi Tiny 64 Core Graphics"}, + {HPHW_FIO, 0x801, 0x00085, 0x0, "Hitachi Tiny 80 Core Graphics"}, + {HPHW_FIO, 0x004, 0x00086, 0x0, "GSC IBM Token Ring"}, + {HPHW_FIO, 0x015, 0x00087, 0x0, "Gecko Optional ISDN"}, + {HPHW_FIO, 0x016, 0x00087, 0x0, "Gecko Core ISDN"}, + {HPHW_FIO, 0x01C, 0x00087, 0x0, "Gecko 80 Core ISDN"}, + {HPHW_FIO, 0x01D, 0x00087, 0x0, "Gecko 100 Core ISDN"}, + {HPHW_FIO, 0x010, 0x00088, 0x0, "Pace VME Networking"}, + {HPHW_FIO, 0x011, 0x00088, 0x0, "Sidewinder VME Networking"}, + {HPHW_FIO, 0x01A, 0x00088, 0x0, "Anole 64 VME Networking"}, + {HPHW_FIO, 0x01B, 0x00088, 0x0, "Anole 100 VME Networking"}, + {HPHW_FIO, 0x024, 0x00088, 0x0, "Fast Pace VME Networking"}, + {HPHW_FIO, 0x034, 0x00088, 0x0, "Anole T VME Networking"}, + {HPHW_FIO, 0x04A, 0x00088, 0x0, "Anole L2 132 VME Networking"}, + {HPHW_FIO, 0x04C, 0x00088, 0x0, "Anole L2 165 VME Networking"}, + {HPHW_FIO, 0x03B, 0x00089, 0x0, "Raven U/L2 Core FW-SCSI"}, + {HPHW_FIO, 0x011, 0x0008A, 0x0, "WB-96 Core Lan (802.3)"}, + {HPHW_FIO, 0x012, 0x0008A, 0x0, "Orville Core Lan (802.3)"}, + {HPHW_FIO, 0x013, 0x0008A, 0x0, "Wilbur Core Lan (802.3)"}, + {HPHW_FIO, 0x014, 0x0008A, 0x0, "WB-80 Core Lan (802.3)"}, + {HPHW_FIO, 0x015, 0x0008A, 0x0, "KittyHawk GSY Core Lan (802.3)"}, + {HPHW_FIO, 0x016, 0x0008A, 0x0, "Gecko Core Lan (802.3)"}, + {HPHW_FIO, 0x018, 0x0008A, 0x0, "Gecko Optional Lan (802.3)"}, + {HPHW_FIO, 0x01A, 0x0008A, 0x0, "Anole 64 Core Lan (802.3)"}, + {HPHW_FIO, 0x01B, 0x0008A, 0x0, "Anole 100 Core Lan (802.3)"}, + {HPHW_FIO, 0x01C, 0x0008A, 0x0, "Gecko 80 Core Lan (802.3)"}, + {HPHW_FIO, 0x01D, 0x0008A, 0x0, "Gecko 100 Core Lan (802.3)"}, + {HPHW_FIO, 0x01F, 0x0008A, 0x0, "SkyHawk 100/120 Core LAN (802.3)"}, + {HPHW_FIO, 0x027, 0x0008A, 0x0, "Piranha 100 Core LAN (802.3)"}, + {HPHW_FIO, 0x028, 0x0008A, 0x0, "Mirage Jr Core LAN (802.3)"}, + {HPHW_FIO, 0x029, 0x0008A, 0x0, "Mirage Core LAN (802.3)"}, + {HPHW_FIO, 0x02A, 0x0008A, 0x0, "Electra Core LAN (802.3)"}, + {HPHW_FIO, 0x02B, 0x0008A, 0x0, "Mirage 80 Core LAN (802.3)"}, + {HPHW_FIO, 0x02C, 0x0008A, 0x0, "Mirage 100+ Core LAN (802.3)"}, + {HPHW_FIO, 0x02E, 0x0008A, 0x0, "UL 350 Core LAN (802.3)"}, + {HPHW_FIO, 0x02F, 0x0008A, 0x0, "UL 350 Core LAN (802.3)"}, + {HPHW_FIO, 0x032, 0x0008A, 0x0, "Raven T' Core LAN (802.3)"}, + {HPHW_FIO, 0x033, 0x0008A, 0x0, "Anole T Core Lan (802.3)"}, + {HPHW_FIO, 0x034, 0x0008A, 0x0, "SAIC L-80 Core Lan (802.3)"}, + {HPHW_FIO, 0x035, 0x0008A, 0x0, "PCX-L2 712/132 Core Lan (802.3)"}, + {HPHW_FIO, 0x036, 0x0008A, 0x0, "PCX-L2 712/160 Core Lan (802.3)"}, + {HPHW_FIO, 0x03B, 0x0008A, 0x0, "Raven U/L2 Core Lan (802.3)"}, + {HPHW_FIO, 0x03C, 0x0008A, 0x0, "Merlin 132 Core Lan (802.3)"}, + {HPHW_FIO, 0x03D, 0x0008A, 0x0, "Merlin 160 Core Lan (802.3)"}, + {HPHW_FIO, 0x044, 0x0008A, 0x0, "Mohawk Core Lan (802.3)"}, + {HPHW_FIO, 0x045, 0x0008A, 0x0, "Rocky1 Core LAN (802.3)"}, + {HPHW_FIO, 0x046, 0x0008A, 0x0, "Rocky2 120 Core LAN (802.3)"}, + {HPHW_FIO, 0x047, 0x0008A, 0x0, "Rocky2 150 Core LAN (802.3)"}, + {HPHW_FIO, 0x04B, 0x0008A, 0x0, "Anole L2 132 Core LAN (802.3)"}, + {HPHW_FIO, 0x04D, 0x0008A, 0x0, "Anole L2 165 Core LAN (802.3)"}, + {HPHW_FIO, 0x04E, 0x0008A, 0x0, "Kiji L2 132 Core LAN (802.3)"}, + {HPHW_FIO, 0x050, 0x0008A, 0x0, "Merlin Jr 132 Core Lan (802.3)"}, + {HPHW_FIO, 0x058, 0x0008A, 0x0, "FireHawk 200 Core LAN (802.3)"}, + {HPHW_FIO, 0x800, 0x0008A, 0x0, "Hitachi Tiny 64 Core Lan (802.3)"}, + {HPHW_FIO, 0x801, 0x0008A, 0x0, "Hitachi Tiny 80 Core Lan (802.3)"}, + {HPHW_FIO, 0x004, 0x0008C, 0x0, "SkyHawk 100/120 Wax RS-232"}, + {HPHW_FIO, 0x005, 0x0008C, 0x0, "SAIC L-80 Wax RS-232"}, + {HPHW_FIO, 0x006, 0x0008C, 0x0, "Raven U/L2 Dino RS-232"}, + {HPHW_FIO, 0x007, 0x0008C, 0x0, "Dino RS-232"}, + {HPHW_FIO, 0x008, 0x0008C, 0x0, "Merlin 132 Dino RS-232"}, + {HPHW_FIO, 0x009, 0x0008C, 0x0, "Merlin 160 Dino RS-232"}, + {HPHW_FIO, 0x00A, 0x0008C, 0x0, "Merlin Jr 132 Dino RS-232"}, + {HPHW_FIO, 0x010, 0x0008C, 0x0, "Mirage 80 Wax RS-232"}, + {HPHW_FIO, 0x011, 0x0008C, 0x0, "Mirage 100+ Wax RS-232"}, + {HPHW_FIO, 0x012, 0x0008C, 0x0, "Mirage Jr Wax RS-232"}, + {HPHW_FIO, 0x013, 0x0008C, 0x0, "Mirage Wax RS-232"}, + {HPHW_FIO, 0x014, 0x0008C, 0x0, "Electra Wax RS-232"}, + {HPHW_FIO, 0x015, 0x0008C, 0x0, "KittyHawk GSY Core RS-232"}, + {HPHW_FIO, 0x016, 0x0008C, 0x0, "Gecko Core RS-232"}, + {HPHW_FIO, 0x017, 0x0008C, 0x0, "Raven Backplane RS-232"}, + {HPHW_FIO, 0x018, 0x0008C, 0x0, "Gecko Optional RS-232"}, + {HPHW_FIO, 0x019, 0x0008C, 0x0, "Merlin+ 180 Dino RS-232"}, + {HPHW_FIO, 0x01A, 0x0008C, 0x0, "Anole 64 Core RS-232"}, + {HPHW_FIO, 0x01B, 0x0008C, 0x0, "Anole 100 Core RS-232"}, + {HPHW_FIO, 0x01C, 0x0008C, 0x0, "Gecko 80 Core RS-232"}, + {HPHW_FIO, 0x01D, 0x0008C, 0x0, "Gecko 100 Core RS-232"}, + {HPHW_FIO, 0x01E, 0x0008C, 0x0, "Raven T' Wax RS-232"}, + {HPHW_FIO, 0x01F, 0x0008C, 0x0, "SkyHawk 100/120 Core RS-232"}, + {HPHW_FIO, 0x020, 0x0008C, 0x0, "Anole 64 Timi RS-232"}, + {HPHW_FIO, 0x021, 0x0008C, 0x0, "Anole 100 Timi RS-232"}, + {HPHW_FIO, 0x022, 0x0008C, 0x0, "Merlin+ 132 Dino RS-232"}, + {HPHW_FIO, 0x023, 0x0008C, 0x0, "Rocky1 Wax RS-232"}, + {HPHW_FIO, 0x025, 0x0008C, 0x0, "Armyknife Optional RS-232"}, + {HPHW_FIO, 0x026, 0x0008C, 0x0, "Piranha 100 Wax RS-232"}, + {HPHW_FIO, 0x027, 0x0008C, 0x0, "Piranha 100 Core RS-232"}, + {HPHW_FIO, 0x028, 0x0008C, 0x0, "Mirage Jr Core RS-232"}, + {HPHW_FIO, 0x029, 0x0008C, 0x0, "Mirage Core RS-232"}, + {HPHW_FIO, 0x02A, 0x0008C, 0x0, "Electra Core RS-232"}, + {HPHW_FIO, 0x02B, 0x0008C, 0x0, "Mirage 80 Core RS-232"}, + {HPHW_FIO, 0x02C, 0x0008C, 0x0, "Mirage 100+ Core RS-232"}, + {HPHW_FIO, 0x02E, 0x0008C, 0x0, "UL 350 Lasi Core RS-232"}, + {HPHW_FIO, 0x02F, 0x0008C, 0x0, "UL 550 Lasi Core RS-232"}, + {HPHW_FIO, 0x030, 0x0008C, 0x0, "UL 350 Wax Core RS-232"}, + {HPHW_FIO, 0x031, 0x0008C, 0x0, "UL 550 Wax Core RS-232"}, + {HPHW_FIO, 0x032, 0x0008C, 0x0, "Raven T' Lasi Core RS-232"}, + {HPHW_FIO, 0x033, 0x0008C, 0x0, "Anole T Core RS-232"}, + {HPHW_FIO, 0x034, 0x0008C, 0x0, "SAIC L-80 Core RS-232"}, + {HPHW_FIO, 0x035, 0x0008C, 0x0, "PCX-L2 712/132 Core RS-232"}, + {HPHW_FIO, 0x036, 0x0008C, 0x0, "PCX-L2 712/160 Core RS-232"}, + {HPHW_FIO, 0x03A, 0x0008C, 0x0, "Merlin+ Wax RS-232"}, + {HPHW_FIO, 0x03B, 0x0008C, 0x0, "Raven U/L2 Core RS-232"}, + {HPHW_FIO, 0x03C, 0x0008C, 0x0, "Merlin 132 Core RS-232"}, + {HPHW_FIO, 0x03D, 0x0008C, 0x0, "Merlin 160 Core RS-232"}, + {HPHW_FIO, 0x03E, 0x0008C, 0x0, "Merlin+ 132 Core RS-232"}, + {HPHW_FIO, 0x03F, 0x0008C, 0x0, "Merlin+ 180 Core RS-232"}, + {HPHW_FIO, 0x040, 0x0008C, 0x0, "Merlin 132 Wax RS-232"}, + {HPHW_FIO, 0x041, 0x0008C, 0x0, "Merlin 160 Wax RS-232"}, + {HPHW_FIO, 0x043, 0x0008C, 0x0, "Merlin 132/160 Wax RS-232"}, + {HPHW_FIO, 0x044, 0x0008C, 0x0, "Mohawk Core RS-232"}, + {HPHW_FIO, 0x045, 0x0008C, 0x0, "Rocky1 Core RS-232"}, + {HPHW_FIO, 0x046, 0x0008C, 0x0, "Rocky2 120 Core RS-232"}, + {HPHW_FIO, 0x047, 0x0008C, 0x0, "Rocky2 150 Core RS-232"}, + {HPHW_FIO, 0x048, 0x0008C, 0x0, "Rocky2 120 Dino RS-232"}, + {HPHW_FIO, 0x049, 0x0008C, 0x0, "Rocky2 150 Dino RS-232"}, + {HPHW_FIO, 0x04A, 0x0008C, 0x0, "Anole L2 132 TIMI RS-232"}, + {HPHW_FIO, 0x04B, 0x0008C, 0x0, "Anole L2 l32 Core RS-232"}, + {HPHW_FIO, 0x04C, 0x0008D, 0x0, "Anole L2 165 TIMI RS-232"}, + {HPHW_FIO, 0x04D, 0x0008C, 0x0, "Anole L2 165 Core RS-232"}, + {HPHW_FIO, 0x04E, 0x0008C, 0x0, "Kiji L2 132 Core RS-232"}, + {HPHW_FIO, 0x04F, 0x0008C, 0x0, "Kiji L2 132 Dino RS-232"}, + {HPHW_FIO, 0x050, 0x0008C, 0x0, "Merlin Jr 132 Core RS-232"}, + {HPHW_FIO, 0x051, 0x0008C, 0x0, "Firehawk Core RS-232"}, + {HPHW_FIO, 0x052, 0x0008C, 0x0, "Raven+ Hi Power Backplane w EISA RS-232"}, + {HPHW_FIO, 0x053, 0x0008C, 0x0, "Raven+ Hi Power Backplane w/o EISA RS-232"}, + {HPHW_FIO, 0x054, 0x0008C, 0x0, "Raven+ Lo Power Backplane w EISA RS-232"}, + {HPHW_FIO, 0x055, 0x0008C, 0x0, "Raven+ Lo Power Backplane w/o EISA RS-232"}, + {HPHW_FIO, 0x056, 0x0008C, 0x0, "Raven+ w SE FWSCSI Core RS-232"}, + {HPHW_FIO, 0x057, 0x0008C, 0x0, "Raven+ w Diff FWSCSI Core RS-232"}, + {HPHW_FIO, 0x058, 0x0008C, 0x0, "FireHawk 200 Core RS-232"}, + {HPHW_FIO, 0x059, 0x0008C, 0x0, "FireHawk 200 Wax RS-232"}, + {HPHW_FIO, 0x05A, 0x0008C, 0x0, "Raven+ L2 Backplane w EISA RS-232"}, + {HPHW_FIO, 0x05B, 0x0008C, 0x0, "Raven+ L2 Backplane w/o EISA RS-232"}, + {HPHW_FIO, 0x05D, 0x0008C, 0x0, "SummitHawk Dino RS-232"}, + {HPHW_FIO, 0x05E, 0x0008C, 0x0, "Staccato 132 Core LAN RS-232"}, + {HPHW_FIO, 0x05F, 0x0008C, 0x0, "Staccato 180 Core LAN RS-232"}, + {HPHW_FIO, 0x800, 0x0008C, 0x0, "Hitachi Tiny 64 Core RS-232"}, + {HPHW_FIO, 0x801, 0x0008C, 0x0, "Hitachi Tiny 80 Core RS-232"}, + {HPHW_FIO, 0x015, 0x0008D, 0x0, "Gecko Optional RJ-16"}, + {HPHW_FIO, 0x016, 0x0008D, 0x0, "Gecko Core RJ-16"}, + {HPHW_FIO, 0x01C, 0x0008D, 0x0, "Gecko 80 Core RJ-16"}, + {HPHW_FIO, 0x01D, 0x0008D, 0x0, "Gecko 100 Core RJ-16"}, + {HPHW_FIO, 0x004, 0x0008F, 0x0, "Anole Boot Rom"}, + {HPHW_FIO, 0x005, 0x0008F, 0x0, "Rocky1 Boot Rom"}, + {HPHW_FIO, 0x006, 0x0008F, 0x0, "Rocky2 120 Boot Rom"}, + {HPHW_FIO, 0x007, 0x0008F, 0x0, "Rocky2 150 Boot Rom"}, + {HPHW_FIO, 0x006, 0x00096, 0x0, "Raven U/L2 Dino PS2 Keyboard"}, + {HPHW_FIO, 0x007, 0x00096, 0x0, "Dino PS2 Keyboard"}, + {HPHW_FIO, 0x008, 0x00096, 0x0, "Merlin 132 Dino PS2 Keyboard"}, + {HPHW_FIO, 0x009, 0x00096, 0x0, "Merlin 160 Dino PS2 Keyboard"}, + {HPHW_FIO, 0x00A, 0x00096, 0x0, "Merlin Jr 132 Dino PS2 Keyboard"}, + {HPHW_FIO, 0x019, 0x00096, 0x0, "Merlin+ 180 Dino PS2 Keyboard"}, + {HPHW_FIO, 0x022, 0x00096, 0x0, "Merlin+ 132 Dino PS2 Keyboard"}, + {HPHW_FIO, 0x004, 0x00097, 0x0, "Cascade EISA 100VG lan"}, + {HPHW_FIO, 0x023, 0x00099, 0x0, "Rocky1 Wax HPIB"}, + {HPHW_FIO, 0x048, 0x00099, 0x0, "Rocky2 120 Clark/Dino HPIB"}, + {HPHW_FIO, 0x049, 0x00099, 0x0, "Rocky2 150 Clark/Dino HPIB"}, + {HPHW_FIO, 0x004, 0x000A1, 0x0, "SPP2000 Console TTY"}, + {HPHW_FIO, 0x004, 0x000A2, 0x0, "Forte Core PCI 10/100BT LAN"}, + {HPHW_FIO, 0x005, 0x000A2, 0x0, "AllegroLow PCI 10/100BT LAN"}, + {HPHW_FIO, 0x006, 0x000A2, 0x0, "AllegroHIgh Core PCI 10/100BT LAN"}, + {HPHW_FIO, 0x007, 0x000A2, 0x0, "PCI Plug-in Lan"}, + {HPHW_FIO, 0x00A, 0x000A2, 0x0, "Lego 360 Core PCI 10/100BT Lan"}, + {HPHW_FIO, 0x03E, 0x000A2, 0x0, "Merlin+ 132 Core PCI Lan"}, + {HPHW_FIO, 0x03F, 0x000A2, 0x0, "Merlin+ 180 Core PCI Lan"}, + {HPHW_FIO, 0x056, 0x000A2, 0x0, "Raven+ w SE FWSCSI Core PCI Lan"}, + {HPHW_FIO, 0x057, 0x000A2, 0x0, "Raven+ w Diff FWSCSI Core PCI Lan"}, + {HPHW_FIO, 0x05E, 0x000A2, 0x0, "Staccato 132 PCI Lan"}, + {HPHW_FIO, 0x05F, 0x000A2, 0x0, "Staccato 180 PCI Lan"}, + {HPHW_FIO, 0x004, 0x000A3, 0x0, "Forte Core PCI LVD Ultra2 SCSI"}, + {HPHW_FIO, 0x004, 0x000A3, 0x0, "Forte Core PCI SE UltraSCSI"}, + {HPHW_FIO, 0x004, 0x000A3, 0x0, "Forte Core PCI IDE/ATAPI CD-ROM"}, + {HPHW_FIO, 0x005, 0x000A3, 0x0, "AllegroLow Core PCI LVD Ultra2 SCSI"}, + {HPHW_FIO, 0x005, 0x000A3, 0x0, "AllegroLow Core PCI IDE/ATAPI CD-ROM"}, + {HPHW_FIO, 0x006, 0x000A3, 0x0, "AllegroHigh Core PCI LVD Ultra2 SCSI"}, + {HPHW_FIO, 0x006, 0x000A3, 0x0, "AllegroHigh Core PCI IDE/ATAPI CD-ROM"}, + {HPHW_FIO, 0x007, 0x000A3, 0x0, "PCI Plug-in Disk"}, + {HPHW_FIO, 0x008, 0x000A3, 0x0, "A5158A S FC Tachlite HBA"}, + {HPHW_FIO, 0x009, 0x000A3, 0x0, "A5157A D FC HBA"}, + {HPHW_FIO, 0x00A, 0x000A3, 0x0, "Lego 360 Core PCI LVD Ultra2 SCSI"}, + {HPHW_FIO, 0x00A, 0x000A3, 0x0, "Lego 360 Core PCI NSE UltraSCSI"}, + {HPHW_FIO, 0x00A, 0x000A3, 0x0, "Lego 360 Core PCI WSE UltraSCSI"}, + {HPHW_FIO, 0x00A, 0x000A3, 0x0, "Lego 360 Core PCI IDE/ATAPI CD-ROM"}, + {HPHW_FIO, 0x03E, 0x000A3, 0x0, "Merlin+ 132 Core SE FWSCSI PCI Disk"}, + {HPHW_FIO, 0x03F, 0x000A3, 0x0, "Merlin+ 180 Core SE FWSCSI PCI Disk"}, + {HPHW_FIO, 0x056, 0x000A3, 0x0, "Raven+ w SE FWSCSI Core PCI Disk"}, + {HPHW_FIO, 0x057, 0x000A3, 0x0, "Raven+ w Diff FWSCSI Core PCI Disk"}, + {HPHW_FIO, 0x004, 0x000A4, 0x0, "SPP2000 Core BA"}, + {HPHW_FIO, 0x004, 0x000A6, 0x0, "Sonic Ethernet 802.3 Card"}, + {HPHW_FIO, 0x004, 0x000A9, 0x00, "Forte Core PCI SuperIO RS-232"}, + {HPHW_FIO, 0x004, 0x000A9, 0x00, "Forte Core PCI USB KB"}, + {HPHW_FIO, 0x005, 0x000A9, 0x00, "AllegroLow Core PCI SuperIO RS-232"}, + {HPHW_FIO, 0x005, 0x000A9, 0x00, "AllegroLow Core PCI USB KB"}, + {HPHW_FIO, 0x006, 0x000A9, 0x00, "AllegroHigh Core PCI SuperIO RS-232"}, + {HPHW_FIO, 0x006, 0x000A9, 0x00, "AllegroHigh Core PCI USB KB"}, + {HPHW_FIO, 0x007, 0x000A9, 0x0, "Miscelaneous PCI Plug-in"}, + {HPHW_FIO, 0x00A, 0x000A9, 0x0, "Lego 360 Core PCI SuperIO RS-232"}, + {HPHW_FIO, 0x00A, 0x000A9, 0x0, "Lego 360 Core PCI USB KB"}, + {HPHW_FIO, 0x004, 0x00320, 0x0, "Metheus Frame Buffer"}, + {HPHW_FIO, 0x004, 0x00340, 0x0, "BARCO CX4500 VME Grphx Cnsl"}, + {HPHW_FIO, 0x004, 0x00360, 0x0, "Hughes TOG VME FDDI"}, + {HPHW_IOA, 0x185, 0x0000B, 0x00, "Java BC Summit Port"}, + {HPHW_IOA, 0x1FF, 0x0000B, 0x00, "Hitachi Ghostview Summit Port"}, + {HPHW_IOA, 0x580, 0x0000B, 0x10, "U2-IOA BC Runway Port"}, + {HPHW_IOA, 0x581, 0x0000B, 0x10, "Uturn-IOA BC Runway Port"}, + {HPHW_IOA, 0x582, 0x0000B, 0x10, "Astro BC Runway Port"}, + {HPHW_IOA, 0x700, 0x0000B, 0x00, "NEC-IOS BC System Bus Port"}, + {HPHW_MEMORY, 0x002, 0x00008, 0x00, "MID_BUS"}, + {HPHW_MEMORY, 0x00C, 0x00008, 0x08, "Kahlua 8MB"}, + {HPHW_MEMORY, 0x00D, 0x00008, 0x08, "Kahlua 4MB"}, + {HPHW_MEMORY, 0x00E, 0x00008, 0x08, "Tequila 16MB"}, + {HPHW_MEMORY, 0x00F, 0x00008, 0x08, "Tequila 32MB"}, + {HPHW_MEMORY, 0x040, 0x00008, 0x00, "Hitachi"}, + {HPHW_MEMORY, 0x004, 0x00009, 0x00, "Cheetah"}, + {HPHW_MEMORY, 0x005, 0x00009, 0x00, "Emerald"}, + {HPHW_MEMORY, 0x008, 0x00009, 0x00, "Indigo 3MB/5MB"}, + {HPHW_MEMORY, 0x00C, 0x00009, 0x00, "Indigo 8MB"}, + {HPHW_MEMORY, 0x00D, 0x00009, 0x00, "Paradise 4MB"}, + {HPHW_MEMORY, 0x00E, 0x00009, 0x00, "Burgundy Onboard"}, + {HPHW_MEMORY, 0x012, 0x00009, 0x00, "Indigo 12MB/20MB"}, + {HPHW_MEMORY, 0x013, 0x00009, 0x00, "Cobra"}, + {HPHW_MEMORY, 0x014, 0x00009, 0x00, "Nova"}, + {HPHW_MEMORY, 0x015, 0x00009, 0x00, "Coral"}, + {HPHW_MEMORY, 0x016, 0x00009, 0x00, "Bushmaster"}, + {HPHW_MEMORY, 0x017, 0x00009, 0x00, "Scorpio"}, + {HPHW_MEMORY, 0x018, 0x00009, 0x00, "Flounder"}, + {HPHW_MEMORY, 0x019, 0x00009, 0x00, "Hardball"}, + {HPHW_MEMORY, 0x01A, 0x00009, 0x00, "CoralII 99"}, + {HPHW_MEMORY, 0x01B, 0x00009, 0x00, "Scorpio Jr."}, + {HPHW_MEMORY, 0x01C, 0x00009, 0x00, "Strider-50 (715T)"}, + {HPHW_MEMORY, 0x01D, 0x00009, 0x00, "Strider-33 (707T)"}, + {HPHW_MEMORY, 0x01E, 0x00009, 0x00, "Trailways-50 (715S)"}, + {HPHW_MEMORY, 0x01F, 0x00009, 0x00, "Trailways-33 (707S)"}, + {HPHW_MEMORY, 0x020, 0x00009, 0x00, "Pace"}, + {HPHW_MEMORY, 0x021, 0x00009, 0x00, "Sidewinder"}, + {HPHW_MEMORY, 0x022, 0x00009, 0x00, "Orville"}, + {HPHW_MEMORY, 0x023, 0x00009, 0x00, "Wilbur"}, + {HPHW_MEMORY, 0x026, 0x00009, 0x00, "Gecko"}, + {HPHW_MEMORY, 0x027, 0x00009, 0x00, "Scorpio Sr."}, + {HPHW_MEMORY, 0x028, 0x00009, 0x00, "Scorpio 100"}, + {HPHW_MEMORY, 0x029, 0x00009, 0x00, "Spectra 50"}, + {HPHW_MEMORY, 0x02A, 0x00009, 0x00, "CoralII 132"}, + {HPHW_MEMORY, 0x02F, 0x00009, 0x00, "KittyHawk DC2-"}, + {HPHW_MEMORY, 0x030, 0x00009, 0x00, "Spectra 75"}, + {HPHW_MEMORY, 0x031, 0x00009, 0x00, "Spectra 100"}, + {HPHW_MEMORY, 0x032, 0x00009, 0x00, "KittyHawk DC3"}, + {HPHW_MEMORY, 0x033, 0x00009, 0x00, "Fast Pace"}, + {HPHW_MEMORY, 0x034, 0x00009, 0x00, "Snake Eagle"}, + {HPHW_MEMORY, 0x035, 0x00009, 0x00, "Anole 64"}, + {HPHW_MEMORY, 0x036, 0x00009, 0x00, "Anole 100"}, + {HPHW_MEMORY, 0x037, 0x00009, 0x00, "Snake Cheetah"}, + {HPHW_MEMORY, 0x038, 0x00009, 0x00, "Gecko 80"}, + {HPHW_MEMORY, 0x039, 0x00009, 0x00, "Gecko 100"}, + {HPHW_MEMORY, 0x03A, 0x00009, 0x00, "Gecko 120"}, + {HPHW_MEMORY, 0x03B, 0x00009, 0x00, "Gila 80"}, + {HPHW_MEMORY, 0x03C, 0x00009, 0x00, "Gila 100"}, + {HPHW_MEMORY, 0x03D, 0x00009, 0x00, "Gila 120"}, + {HPHW_MEMORY, 0x03E, 0x00009, 0x00, "Scorpio-L 80"}, + {HPHW_MEMORY, 0x03F, 0x00009, 0x00, "Scorpio-L 100"}, + {HPHW_MEMORY, 0x040, 0x00009, 0x00, "Scorpio-L 120"}, + {HPHW_MEMORY, 0x041, 0x00009, 0x00, "Spectra-L 80"}, + {HPHW_MEMORY, 0x042, 0x00009, 0x00, "Spectra-L 100"}, + {HPHW_MEMORY, 0x043, 0x00009, 0x00, "Spectra-L 120"}, + {HPHW_MEMORY, 0x044, 0x00009, 0x00, "Piranha 100"}, + {HPHW_MEMORY, 0x045, 0x00009, 0x00, "Piranha 120"}, + {HPHW_MEMORY, 0x046, 0x00009, 0x00, "Jason 50"}, + {HPHW_MEMORY, 0x047, 0x00009, 0x00, "Jason 100"}, + {HPHW_MEMORY, 0x049, 0x00009, 0x00, "SkyHawk 100/120"}, + {HPHW_MEMORY, 0x04A, 0x00009, 0x00, "Mirage Jr"}, + {HPHW_MEMORY, 0x04B, 0x00009, 0x00, "Mirage 100"}, + {HPHW_MEMORY, 0x04C, 0x00009, 0x00, "Mirage 100+"}, + {HPHW_MEMORY, 0x04D, 0x00009, 0x00, "Electra 100"}, + {HPHW_MEMORY, 0x04E, 0x00009, 0x00, "Electra 120"}, + {HPHW_MEMORY, 0x04F, 0x00009, 0x00, "Mirage 80"}, + {HPHW_MEMORY, 0x050, 0x00009, 0x00, "UL Proc 1 way T'100"}, + {HPHW_MEMORY, 0x051, 0x00009, 0x00, "UL Proc 1 way T'120"}, + {HPHW_MEMORY, 0x052, 0x00009, 0x00, "UL Proc 2 way T'100"}, + {HPHW_MEMORY, 0x053, 0x00009, 0x00, "KittyHawk DC3-"}, + {HPHW_MEMORY, 0x054, 0x00009, 0x00, "UL Proc 2 way T'120"}, + {HPHW_MEMORY, 0x055, 0x00009, 0x00, "Raven 120 mem"}, + {HPHW_MEMORY, 0x056, 0x00009, 0x00, "UL Proc L 75"}, + {HPHW_MEMORY, 0x057, 0x00009, 0x00, "UL Proc L 100"}, + {HPHW_MEMORY, 0x058, 0x00009, 0x00, "Anole T"}, + {HPHW_MEMORY, 0x059, 0x00009, 0x00, "SAIC L-80"}, + {HPHW_MEMORY, 0x05A, 0x00009, 0x00, "Merlin+ L2 180"}, + {HPHW_MEMORY, 0x05B, 0x00009, 0x00, "Raven U 200 2-way"}, + {HPHW_MEMORY, 0x05C, 0x00009, 0x00, "Raven U 180+"}, + {HPHW_MEMORY, 0x05D, 0x00009, 0x00, "Raven U 200"}, + {HPHW_MEMORY, 0x05E, 0x00009, 0x00, "Rocky2 150 Memory"}, + {HPHW_MEMORY, 0x08A, 0x00009, 0x00, "Staccato L2 132 Memory"}, + {HPHW_MEMORY, 0x08B, 0x00009, 0x00, "Staccato L2 180 Memory"}, + {HPHW_MEMORY, 0x05F, 0x00009, 0x00, "SPP2000 Memory"}, + {HPHW_MEMORY, 0x060, 0x00009, 0x00, "Merlin L2 132"}, + {HPHW_MEMORY, 0x061, 0x00009, 0x00, "Merlin+ L2 132"}, + {HPHW_MEMORY, 0x063, 0x00009, 0x00, "712/132 L2 Upgrade"}, + {HPHW_MEMORY, 0x064, 0x00009, 0x00, "712/160 L2 Upgrade"}, + {HPHW_MEMORY, 0x065, 0x00009, 0x00, "715/132 L2 Upgrade"}, + {HPHW_MEMORY, 0x066, 0x00009, 0x00, "715/160 L2 Upgrade"}, + {HPHW_MEMORY, 0x067, 0x00009, 0x00, "Merlin 160/ThunderHawk Memory"}, + {HPHW_MEMORY, 0x068, 0x00009, 0x00, "LightningHawk Memory"}, + {HPHW_MEMORY, 0x069, 0x00009, 0x00, "Rocky1 Memory"}, + {HPHW_MEMORY, 0x06A, 0x00009, 0x00, "Raven L2 132"}, + {HPHW_MEMORY, 0x06B, 0x00009, 0x00, "Raven L2 160"}, + {HPHW_MEMORY, 0x06C, 0x00009, 0x00, "Raven L2 187"}, + {HPHW_MEMORY, 0x06D, 0x00009, 0x00, "Raven L2 200"}, + {HPHW_MEMORY, 0x06E, 0x00009, 0x00, "Raven U 230"}, + {HPHW_MEMORY, 0x06F, 0x00009, 0x00, "Raven U 240"}, + {HPHW_MEMORY, 0x070, 0x00009, 0x00, "Rocky2 120 Memory"}, + {HPHW_MEMORY, 0x071, 0x00009, 0x00, "Raven U 160"}, + {HPHW_MEMORY, 0x072, 0x00009, 0x00, "Raven U 180"}, + {HPHW_MEMORY, 0x072, 0x00009, 0x00, "UL Proc 1 way T'120 1MB/1MB"}, + {HPHW_MEMORY, 0x073, 0x00009, 0x00, "UL Proc 2 way T'120 1MB/1MB"}, + {HPHW_MEMORY, 0x074, 0x00009, 0x00, "Anole L2 132 memory"}, + {HPHW_MEMORY, 0x075, 0x00009, 0x00, "Anole L2 165 memory"}, + {HPHW_MEMORY, 0x076, 0x00009, 0x00, "UL 1 way U160 512K/512K memory"}, + {HPHW_MEMORY, 0x077, 0x00009, 0x00, "UL 2 way U160 512K/512K memory"}, + {HPHW_MEMORY, 0x078, 0x00009, 0x00, "Kiji L2 132 memory"}, + {HPHW_MEMORY, 0x079, 0x00009, 0x00, "UL 1 way U160 1M/1M memory"}, + {HPHW_MEMORY, 0x07A, 0x00009, 0x00, "UL 2 way U160 1M/1M memory"}, + {HPHW_MEMORY, 0x07B, 0x00009, 0x00, "UL 1 way U180 1M/1M memory"}, + {HPHW_MEMORY, 0x07C, 0x00009, 0x00, "UL 2 way U180 1M/1M memory"}, + {HPHW_MEMORY, 0x07D, 0x00009, 0x00, "UL 1 way U240 U+ 2M/2M memory"}, + {HPHW_MEMORY, 0x07E, 0x00009, 0x00, "UL 2 way U240 U+ 2M/2M memory"}, + {HPHW_MEMORY, 0x07F, 0x00009, 0x00, "UL L2 132 memory"}, + {HPHW_MEMORY, 0x080, 0x00009, 0x00, "UL L2 160 memory"}, + {HPHW_MEMORY, 0x081, 0x00009, 0x00, "Merlin Jr 132 memory"}, + {HPHW_MEMORY, 0x082, 0x00009, 0x00, "FireHawk 200 Memory"}, + {HPHW_MEMORY, 0x083, 0x00009, 0x00, "SummitHawk Memory"}, + {HPHW_MEMORY, 0x084, 0x00009, 0x00, "Jade Upgrade Memory"}, + {HPHW_MEMORY, 0x085, 0x00009, 0x00, "SPP2500 Memory"}, + {HPHW_MEMORY, 0x086, 0x00009, 0x00, "AllegroHigh Memory"}, + {HPHW_MEMORY, 0x087, 0x00009, 0x00, "AllegroLow Memory"}, + {HPHW_MEMORY, 0x088, 0x00009, 0x00, "Forte 2w Memory"}, + {HPHW_MEMORY, 0x089, 0x00009, 0x00, "Forte 4w Memory"}, + {HPHW_MEMORY, 0x08A, 0x00009, 0x00, "Staccato L2 132 Memory"}, + {HPHW_MEMORY, 0x08B, 0x00009, 0x00, "Staccato L2 180 Memory"}, + {HPHW_MEMORY, 0x090, 0x00009, 0x00, "Prelude SMC Memory"}, + {HPHW_MEMORY, 0x091, 0x00009, 0x00, "Lego 360 Memory"}, + {HPHW_MEMORY, 0x7FF, 0x00009, 0x00, "NEC Aska memory"}, + {HPHW_MEMORY, 0x800, 0x00009, 0x00, "Hitachi Tiny 64"}, + {HPHW_MEMORY, 0x801, 0x00009, 0x00, "Hitachi Tiny 80"}, + {HPHW_MEMORY, 0x8FF, 0x00009, 0x00, "Hitachi X memory"}, + {HPHW_MEMORY, 0x091, 0x00009, 0x00, "M2250 Memory"}, + {HPHW_MEMORY, 0x092, 0x00009, 0x00, "M2500 Memory"}, + {HPHW_MEMORY, 0x093, 0x00009, 0x00, "Sonata 440 Memory"}, + {HPHW_MEMORY, 0x094, 0x00009, 0x00, "Sonata 360 Memory"}, + {HPHW_MEMORY, 0x095, 0x00009, 0x00, "Rhapsody 440 Memory"}, + {HPHW_MEMORY, 0x096, 0x00009, 0x00, "Rhapsody 360 Memory"}, + {HPHW_MEMORY, 0x097, 0x00009, 0x00, "Raven W 360 Memory"}, + {HPHW_MEMORY, 0x098, 0x00009, 0x00, "Halfdome W 440 Memory"}, + {HPHW_MEMORY, 0x099, 0x00009, 0x00, "Rhapsody DC- 440 Memory"}, + {HPHW_MEMORY, 0x09A, 0x00009, 0x00, "Rhapsody DC- 360 Memory"}, + {HPHW_MEMORY, 0x09B, 0x00009, 0x00, "Crescendo Memory"}, + {HPHW_OTHER, 0x004, 0x00030, 0x00, "Master"}, + {HPHW_OTHER, 0x004, 0x00034, 0x00, "Slave"}, + {HPHW_OTHER, 0x004, 0x00038, 0x00, "EDU"}, + {HPHW_OTHER, 0x004, 0x00049, 0x00, "LGB Control"}, + {0, } /* leave the last entry empty ! */ +}; + + +static struct hp_cpu_type_mask { + unsigned short model; + unsigned short mask; + enum cpu_type cpu; +} hp_cpu_type_mask_list[] = { + + { 0x0000, 0x0ff0, pcx }, /* 0x0000 - 0x000f */ + { 0x0048, 0x0ff0, pcxl }, /* 0x0040 - 0x004f */ + { 0x0080, 0x0ff0, pcx }, /* 0x0080 - 0x008f */ + { 0x0100, 0x0ff0, pcx }, /* 0x0100 - 0x010f */ + { 0x0182, 0x0ffe, pcx }, /* 0x0182 - 0x0183 */ + { 0x0182, 0x0ffe, pcxt }, /* 0x0182 - 0x0183 */ + { 0x0184, 0x0fff, pcxu }, /* 0x0184 - 0x0184 */ + { 0x0200, 0x0ffe, pcxs }, /* 0x0200 - 0x0201 */ + { 0x0202, 0x0fff, pcxs }, /* 0x0202 - 0x0202 */ + { 0x0203, 0x0fff, pcxt }, /* 0x0203 - 0x0203 */ + { 0x0204, 0x0ffc, pcxt }, /* 0x0204 - 0x0207 */ + { 0x0280, 0x0ffc, pcxs }, /* 0x0280 - 0x0283 */ + { 0x0284, 0x0ffc, pcxt }, /* 0x0284 - 0x0287 */ + { 0x0288, 0x0fff, pcxt }, /* 0x0288 - 0x0288 */ + { 0x0300, 0x0ffc, pcxs }, /* 0x0300 - 0x0303 */ + { 0x0310, 0x0ff0, pcxt }, /* 0x0310 - 0x031f */ + { 0x0320, 0x0ff0, pcxt }, /* 0x0320 - 0x032f */ + { 0x0400, 0x0ff0, pcxt }, /* 0x0400 - 0x040f */ + { 0x0480, 0x0ff0, pcxl }, /* 0x0480 - 0x048f */ + { 0x0500, 0x0ff0, pcxl2 }, /* 0x0500 - 0x050f */ + { 0x0510, 0x0ff0, pcxl2 }, /* 0x0510 - 0x051f */ + { 0x0580, 0x0ff8, pcxt_ }, /* 0x0580 - 0x0587 */ + { 0x0588, 0x0ffc, pcxt_ }, /* 0x0588 - 0x058b */ + { 0x058c, 0x0ffe, pcxt_ }, /* 0x058c - 0x058d */ + { 0x058e, 0x0fff, pcxt_ }, /* 0x058e - 0x058e */ + { 0x058f, 0x0fff, pcxu }, /* 0x058f - 0x058f */ + { 0x0590, 0x0ffe, pcxu }, /* 0x0590 - 0x0591 */ + { 0x0592, 0x0fff, pcxt_ }, /* 0x0592 - 0x0592 */ + { 0x0593, 0x0fff, pcxu }, /* 0x0593 - 0x0593 */ + { 0x0594, 0x0ffc, pcxu }, /* 0x0594 - 0x0597 */ + { 0x0598, 0x0ffc, pcxu }, /* 0x0598 - 0x059b */ + { 0x059c, 0x0ffe, pcxu_ }, /* 0x059c - 0x059d */ + { 0x059e, 0x0fff, pcxt_ }, /* 0x059e - 0x059e */ + { 0x059f, 0x0fff, pcxu }, /* 0x059f - 0x059f */ + { 0x05a0, 0x0ffe, pcxt_ }, /* 0x05a0 - 0x05a1 */ + { 0x05a2, 0x0ffe, pcxu }, /* 0x05a2 - 0x05a3 */ + { 0x05a4, 0x0ffc, pcxu }, /* 0x05a4 - 0x05a7 */ + { 0x05a8, 0x0ffc, pcxu }, /* 0x05a8 - 0x05ab */ + { 0x05ad, 0x0fff, pcxu_ }, /* 0x05ad - 0x05ad */ + { 0x05ae, 0x0ffe, pcxu_ }, /* 0x05ae - 0x05af */ + { 0x05b0, 0x0ffe, pcxu_ }, /* 0x05b0 - 0x05b1 */ + { 0x05b2, 0x0fff, pcxu_ }, /* 0x05b2 - 0x05b2 */ + { 0x05b3, 0x0fff, pcxu }, /* 0x05b3 - 0x05b3 */ + { 0x05b4, 0x0fff, pcxw }, /* 0x05b4 - 0x05b4 */ + { 0x05b5, 0x0fff, pcxu_ }, /* 0x05b5 - 0x05b5 */ + { 0x05b6, 0x0ffe, pcxu_ }, /* 0x05b6 - 0x05b7 */ + { 0x05b8, 0x0ffe, pcxu_ }, /* 0x05b8 - 0x05b9 */ + { 0x05ba, 0x0fff, pcxu_ }, /* 0x05ba - 0x05ba */ + { 0x05bb, 0x0fff, pcxw }, /* 0x05bb - 0x05bb */ + { 0x05bc, 0x0ffc, pcxw }, /* 0x05bc - 0x05bf */ + { 0x05c0, 0x0fc0, pcxw }, /* 0x05c0 - 0x05ff */ + { 0x0600, 0x0ff0, pcxl }, /* 0x0600 - 0x060f */ + { 0x0610, 0x0ff0, pcxl }, /* 0x0610 - 0x061f */ + { 0x0000, 0x0000, pcx } /* terminate table */ +}; + +char *cpu_name_version[][2] = { + [pcx] { "PA7000 (PCX)", "1.0" }, + [pcxs] { "PA7000 (PCX-S)", "1.1a" }, + [pcxt] { "PA7100 (PCX-T)", "1.1b" }, + [pcxt_] { "PA7200 (PCX-T')", "1.1c" }, + [pcxl] { "PA7100LC (PCX-L)", "1.1d" }, + [pcxl2] { "PA7300LC (PCX-L2)", "1.1e" }, + [pcxu] { "PA8000 (PCX-U)", "2.0" }, + [pcxu_] { "PA8200 (PCX-U+)", "2.0" }, + [pcxw] { "PA8500 (PCX-W)", "2.0" }, + [pcxw_] { "PA8600 (PCX-W+)", "2.0" } +}; + +char *parisc_getHWtype(unsigned short hw_type) +{ + if (hw_type <= HPHW_CIO) { + return hw_type_name[hw_type]; + } else { + return "Unknown Type"; + } +} + +char *parisc_getHWdescription(unsigned short hw_type, unsigned long hversion, + unsigned long sversion) +{ + struct hp_hardware *listptr; + + for (listptr = hp_hardware_list; listptr->name; listptr++) { + if ((listptr->hw_type==hw_type) && + (listptr->hversion==hversion) && + (listptr->sversion==sversion)){ + return listptr->name; + } + } + return "unknown device"; +} + + +/* Interpret hversion (ret[0]) from PDC_MODEL(4)/PDC_MODEL_INFO(0) */ +enum cpu_type parisc_get_cpu_type(unsigned long hversion) +{ + struct hp_cpu_type_mask *ptr; + unsigned short model = ((unsigned short) (hversion)) >> 4; + + for (ptr = hp_cpu_type_mask_list; 0 != ptr->mask; ptr++) { + if (ptr->model == (model & ptr->mask)) + return ptr->cpu; + } + panic("parisc_get_cpu_type() could not identify CPU type\n"); + + return pcx; /* not reached: */ +} + + +struct hp_hardware *parisc_get_reference(unsigned short hw_type, + unsigned long hversion, unsigned long sversion) +{ + struct hp_hardware *listptr = hp_hardware_list; + + for (listptr = hp_hardware_list; listptr->name; listptr++) { + if ((listptr->hw_type == hw_type) && + (listptr->hversion == hversion) && + (listptr->sversion == sversion)) { + return listptr; + } + } + return NULL; +} diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S new file mode 100644 index 000000000..ce45dd608 --- /dev/null +++ b/arch/parisc/kernel/head.S @@ -0,0 +1,156 @@ +/* + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1999 by Helge Deller + * Copyright 1999 SuSE GmbH (Philipp Rumpf) + * Copyright 1999 Philipp Rumpf (prumpf@tux.org) + * + * Initial Version 04-23-1999 by Helge Deller (helge.deller@ruhr-uni-bochum.de) + */ + + +#include <asm/offset.h> +#include <asm/psw.h> + +#define __ASSEMBLY__ +/********* +#include <asm/pdc.h> +*********/ +#include <asm/assembly.h> +#include <asm/pgtable.h> + + + .level 1.1 + + .section .initcall.init + .align 4 + .export __initcall_start +__initcall_start: + .export __initcall_end +__initcall_end: + .export __setup_start +__setup_start: + .export __setup_end +__setup_end: + + .text + .align 4 + .import init_task_union,data + .import $global$ /* forward declaration */ + .import fault_vector_11,code /* IVA parisc 1.1 32 bit */ + .import fault_vector_20,code /* IVA parisc 2.0 32 bit */ + .import start_parisc,code /* then enable VM and go here */ + + .export stext + .export _stext,data /* Kernel want it this way! */ +_stext: +stext: + .proc + .callinfo + + /* Make sure sr4-sr7 are set to zero for the kernel address space */ + + mtsp %r0,%sr4 + mtsp %r0,%sr5 + mtsp %r0,%sr6 + mtsp %r0,%sr7 + + /* Initialize startup VM. Just map first 8 MB of memory */ + + ldil L%PA(pg0),%r1 + ldo R%PA(pg0)(%r1),%r1 + ldo _PAGE_TABLE(%r1),%r3 + ldil L%PA(swapper_pg_dir),%r4 + ldo R%PA(swapper_pg_dir)(%r4),%r4 + mtctl %r4,%cr24 /* Initialize kernel root pointer */ + mtctl %r4,%cr25 /* Initialize user root pointer */ + stw %r3,0xc00(%r4) /* Hardwired 0xc0000000 kernel vaddr start */ + ldo 0x1000(%r3),%r3 + stw %r3,0xc04(%r4) + ldo _PAGE_KERNEL(%r0),%r3 /* Hardwired 0x0 phys addr start */ +$pgt_fill_loop: + stwm %r3,4(%r1) + ldo 0x1000(%r3),%r3 + bb,>= %r3,8,$pgt_fill_loop + nop + + /* Initialize the global data pointer */ + ldil L%$global$,%dp + ldo R%$global$(%dp),%dp + + /* And the stack pointer, physical too */ + ldil L%init_task_union+TASK_SZ_ALGN,%sp + ldo R%init_task_union+TASK_SZ_ALGN(%sp),%sp + + /* we need this to take interruptions directly after the rfi below */ + /* (which we need for PA2.0 boxes) */ + mtctl %r0, %cr30 + + /* + * Set up our interrupt table. HPMCs might not work after this! + * + * We need to install the correct iva for PA1.1 or PA2.0. The + * following short sequence of instructions can determine this + * (without being illegal on a PA1.1 machine). + */ + + ldi 32,%r10 + mtctl %r10,%cr11 + .level 2.0 + mfctl,w %cr11,%r10 + .level 1.1 + comib,<>,n 0,%r10,$is_pa20 + ldil L%PA(fault_vector_11),%r10 + b $install_iva + ldo R%PA(fault_vector_11)(%r10),%r10 + +$is_pa20: + ldil L%PA(fault_vector_20),%r10 + ldo R%PA(fault_vector_20)(%r10),%r10 + +$install_iva: + mtctl %r10,%cr14 + + /* Disable (most) interruptions */ + mtsm %r0 + + /* kernel PSW: + * - no interruptions except for HPMC and TOC (which are handled by PDC) + * - Q bit set (IODC / PDC interruptions) + * - big-endian + * - virtually mapped + */ + + ldil L%KERNEL_PSW,%r10 + ldo R%KERNEL_PSW(%r10),%r10 + mtctl %r10,%ipsw + + /* Set the space pointers for the post-RFI world */ + mtctl %r0,%cr17 /* Clear two-level IIA Space Queue */ + mtctl %r0,%cr17 /* effectively setting kernel space. */ + + /* And the return address(es) too */ + ldil L%start_parisc,%r10 + ldo R%start_parisc(%r10),%r10 + mtctl %r10,%cr18 + ldo 4(%r10),%r10 + mtctl %r10,%cr18 + + /* Jump to hyperspace */ + rfi + nop + + .procend + + .data + + .align 4 + .export $global$,data + + .type $global$,@object + .size $global$,4 +$global$: + .word 0 diff --git a/arch/parisc/kernel/hpmc.S b/arch/parisc/kernel/hpmc.S new file mode 100644 index 000000000..c77aee04e --- /dev/null +++ b/arch/parisc/kernel/hpmc.S @@ -0,0 +1,319 @@ +/* + * HPMC (High Priority Machine Check) handler. + * + * Copyright (C) 1999 Philipp Rumpf <prumpf@tux.org> + * Copyright (C) 1999 Hewlett-Packard (Frank Rowand) + * Copyright (C) 2000 Hewlett-Packard (John Marvin) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +/* + * This HPMC handler retrieves the HPMC pim data, resets IO and + * returns to the default trap handler with code set to 1 (HPMC). + * The default trap handler calls handle interruption, which + * does a stack and register dump. This at least allows kernel + * developers to get back to C code in virtual mode, where they + * have the option to examine and print values from memory that + * would help in debugging an HPMC caused by a software bug. + * + * There is more to do here: + * + * 1) On MP systems we need to synchronize processors + * before calling pdc/iodc. + * 2) We should be checking the system state and not + * returning to the fault handler if things are really + * bad. + * + */ + + .level 1.1 + .data + +#define __ASSEMBLY__ +#include <asm/assembly.h> +#include <asm/pdc.h> + + /* + * stack for os_hpmc, the HPMC handler. + * buffer for IODC procedures (for the HPMC handler). + * + * IODC requires 7K byte stack. That leaves 1K byte for os_hpmc. + */ + + .align 4096 +hpmc_stack: + .block 16384 + +#define HPMC_IODC_BUF_SIZE 0x8000 + + .align 4096 +hpmc_iodc_buf: + .block HPMC_IODC_BUF_SIZE + + .align 8 +hpmc_raddr: + .block 128 + +#define HPMC_PIM_DATA_SIZE 896 /* Enough to hold all architected 2.0 state */ + + .export hpmc_pim_data, data + .align 8 +hpmc_pim_data: + .block HPMC_PIM_DATA_SIZE + + .text + + .export os_hpmc, code + .import intr_save, code + +os_hpmc: + + /* + * registers modified: + * + * Using callee saves registers without saving them. The + * original values are in the pim dump if we need them. + * + * r2 (rp) return pointer + * r3 address of PDCE_PROC + * r4 scratch + * r5 scratch + * r23 (arg3) procedure arg + * r24 (arg2) procedure arg + * r25 (arg1) procedure arg + * r26 (arg0) procedure arg + * r30 (sp) stack pointer + * + * registers read: + * + * r26 contains address of PDCE_PROC on entry + * r28 (ret0) return value from procedure + */ + + copy arg0, %r3 /* save address of PDCE_PROC */ + + /* + * disable nested HPMCs + * + * Increment os_hpmc checksum to invalidate it. + * Do this before turning the PSW M bit off. + */ + + mfctl %cr14, %r4 + ldw 52(%r4),%r5 + addi 1,%r5,%r5 + stw %r5,52(%r4) + + /* MP_FIXME: synchronize all processors. */ + + /* Setup stack pointer. */ + + ldil L%PA(hpmc_stack),sp + ldo R%PA(hpmc_stack)(sp),sp + + ldo 128(sp),sp /* leave room for arguments */ + + /* + * Most PDC routines require that the M bit be off. + * So turn on the Q bit and turn off the M bit. + */ + + ldo 8(%r0),%r4 /* PSW Q on, PSW M off */ + mtctl %r4,ipsw + mtctl %r0,pcsq + mtctl %r0,pcsq + ldil L%PA(os_hpmc_1),%r4 + ldo R%PA(os_hpmc_1)(%r4),%r4 + mtctl %r4,pcoq + ldo 4(%r4),%r4 + mtctl %r4,pcoq + rfi + nop + +os_hpmc_1: + + /* Call PDC_PIM to get HPMC pim info */ + + /* + * Note that on some newer boxes, PDC_PIM must be called + * before PDC_IO if you want IO to be reset. PDC_PIM sets + * a flag that PDC_IO examines. + */ + + ldo PDC_PIM(%r0), arg0 + ldo PDC_PIM_HPMC(%r0),arg1 /* Transfer HPMC data */ + ldil L%PA(hpmc_raddr),arg2 + ldo R%PA(hpmc_raddr)(arg2),arg2 + ldil L%PA(hpmc_pim_data),arg3 + ldo R%PA(hpmc_pim_data)(arg3),arg3 + ldil L%HPMC_PIM_DATA_SIZE,%r4 + ldo R%HPMC_PIM_DATA_SIZE(%r4),%r4 + stw %r4,-52(sp) + + ldil L%PA(os_hpmc_2), rp + bv (r3) /* call pdce_proc */ + ldo R%PA(os_hpmc_2)(rp), rp + +os_hpmc_2: + comib,<> 0,ret0, os_hpmc_fail + + /* Reset IO by calling the hversion dependent PDC_IO routine */ + + ldo PDC_IO(%r0),arg0 + ldo 0(%r0),arg1 /* log IO errors */ + ldo 0(%r0),arg2 /* reserved */ + ldo 0(%r0),arg3 /* reserved */ + stw %r0,-52(sp) /* reserved */ + + ldil L%PA(os_hpmc_3),rp + bv (%r3) /* call pdce_proc */ + ldo R%PA(os_hpmc_3)(rp),rp + +os_hpmc_3: + + /* FIXME? Check for errors from PDC_IO (-1 might be OK) */ + + /* + * Initialize the IODC console device (HPA,SPA, path etc. + * are stored on page 0. + */ + + /* + * Load IODC into hpmc_iodc_buf by calling PDC_IODC. + * Note that PDC_IODC handles flushing the appropriate + * data and instruction cache lines. + */ + + ldo PDC_IODC(%r0),arg0 + ldo PDC_IODC_READ(%r0),arg1 + ldil L%PA(hpmc_raddr),arg2 + ldo R%PA(hpmc_raddr)(arg2),arg2 + ldw BOOT_CONSOLE_HPA_OFFSET(%r0),arg3 /* console hpa */ + ldo PDC_IODC_RI_INIT(%r0),%r4 + stw %r4,-52(sp) + ldil L%PA(hpmc_iodc_buf),%r4 + ldo R%PA(hpmc_iodc_buf)(%r4),%r4 + stw %r4,-56(sp) + ldil L%HPMC_IODC_BUF_SIZE,%r4 + ldo R%HPMC_IODC_BUF_SIZE(%r4),%r4 + stw %r4,-60(sp) + + ldil L%PA(os_hpmc_4),rp + bv (%r3) /* call pdce_proc */ + ldo R%PA(os_hpmc_4)(rp),rp + +os_hpmc_4: + comib,<> 0,ret0,os_hpmc_fail + + /* Call the entry init (just loaded by PDC_IODC) */ + + ldw BOOT_CONSOLE_HPA_OFFSET(%r0),arg0 /* console hpa */ + ldo ENTRY_INIT_MOD_DEV(%r0), arg1 + ldw BOOT_CONSOLE_SPA_OFFSET(%r0),arg2 /* console spa */ + depi 0,31,11,arg2 /* clear bits 21-31 */ + ldo BOOT_CONSOLE_PATH_OFFSET(%r0),arg3 /* console path */ + ldil L%PA(hpmc_raddr),%r4 + ldo R%PA(hpmc_raddr)(%r4),%r4 + stw %r4, -52(sp) + stw %r0, -56(sp) /* HV */ + stw %r0, -60(sp) /* HV */ + stw %r0, -64(sp) /* HV */ + stw %r0, -68(sp) /* lang, must be zero */ + + ldil L%PA(hpmc_iodc_buf),%r5 + ldo R%PA(hpmc_iodc_buf)(%r5),%r5 + ldil L%PA(os_hpmc_5),rp + bv (%r5) + ldo R%PA(os_hpmc_5)(rp),rp + +os_hpmc_5: + comib,<> 0,ret0,os_hpmc_fail + + /* Prepare to call intr_save */ + + /* + * Load kernel page directory (load into user also, since + * we don't intend to ever return to user land anyway) + */ + + ldil L%PA(swapper_pg_dir),%r4 + ldo R%PA(swapper_pg_dir)(%r4),%r4 + mtctl %r4,%cr24 /* Initialize kernel root pointer */ + mtctl %r4,%cr25 /* Initialize user root pointer */ + + /* Clear sr4-sr7 */ + + mtsp %r0, %sr4 + mtsp %r0, %sr5 + mtsp %r0, %sr6 + mtsp %r0, %sr7 + + tovirt %r30 /* make sp virtual */ + + rsm 8,%r0 /* Clear Q bit */ + ldi 1,%r1 + mtctl %r1,%cr29 /* Set trap code to "1" for HPMC */ + mtctl %r0,%cr30 /* Force interruptions to use hpmc stack */ + ldil L%PA(intr_save), %r1 + ldo R%PA(intr_save)(%r1), %r1 + be 0(%sr7,%r1) + nop + +os_hpmc_fail: + + /* + * Reset the system + * + * Some systems may lockup from a broadcast reset, so try the + * hversion PDC_BROADCAST_RESET() first. + * MP_FIXME: reset all processors if more than one central bus. + */ + + /* PDC_BROADCAST_RESET() */ + + ldo PDC_BROADCAST_RESET(%r0),arg0 + ldo 0(%r0),arg1 /* do reset */ + + ldil L%PA(os_hpmc_6),rp + bv (%r3) /* call pdce_proc */ + ldo R%PA(os_hpmc_6)(rp),rp + +os_hpmc_6: + + /* + * possible return values: + * -1 non-existent procedure + * -2 non-existent option + * -16 unaligned stack + * + * If call returned, do a broadcast reset. + */ + + ldil L%0xfffc0000,%r4 /* IO_BROADCAST */ + ldo 5(%r0),%r5 + stw %r5,48(%r4) /* CMD_RESET to IO_COMMAND offset */ + + b . + nop + + /* this label used to compute os_hpmc checksum */ + + .export os_hpmc_end, code + +os_hpmc_end: + + nop diff --git a/arch/parisc/kernel/init_task.c b/arch/parisc/kernel/init_task.c new file mode 100644 index 000000000..a838548de --- /dev/null +++ b/arch/parisc/kernel/init_task.c @@ -0,0 +1,29 @@ +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/init.h> + +#include <asm/uaccess.h> +#include <asm/pgtable.h> +#include <asm/pgalloc.h> + +static struct vm_area_struct init_mmap = INIT_MMAP; +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; +struct mm_struct init_mm = INIT_MM(init_mm); + +/* + * Initial task structure. + * + * We need to make sure that this is 16384-byte aligned due to the + * way process stacks are handled. This is done by having a special + * "init_task" linker map entry.. + */ +union task_union init_task_union + __attribute__((section("init_task"), aligned(4096))) = { INIT_TASK(init_task_union.task) }; + +unsigned long swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((aligned(4096))) = { 0, }; +#ifdef __LP64__ +unsigned long pmd0[PTRS_PER_PMD] __attribute__ ((aligned(4096))) = { 0, }; +#endif +unsigned long pg0[PT_INITIAL * PTRS_PER_PTE] __attribute__ ((aligned(4096))) = { 0, }; diff --git a/arch/parisc/kernel/inventory.c b/arch/parisc/kernel/inventory.c new file mode 100644 index 000000000..ab97cff1e --- /dev/null +++ b/arch/parisc/kernel/inventory.c @@ -0,0 +1,397 @@ + +/* Copyright (c) 1999 The Puffin Group */ +/* Written by David Kennedy and Alex deVries */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/pdc.h> + +/* +** Debug options +** DEBUG_PAT Dump details which PDC PAT provides about ranges/devices. +*/ +#undef DEBUG_PAT + +extern char *parisc_getHWtype(unsigned short hw_type); + +extern struct hp_device * register_module(void *hpa); +extern void print_devices(char * buf); + + +int pdc_hpa_processor(void *address); + +#ifndef __LP64__ +static u8 iodc_data[32] __attribute__ ((aligned (64))); +static struct pdc_model model __attribute__ ((aligned (8))); +#endif +static unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0}; +static struct pdc_hpa processor_hpa __attribute__ ((aligned (8))); +static struct pdc_system_map module_result __attribute__ ((aligned (8))); +static struct pdc_module_path module_path __attribute__ ((aligned (8))); + +#ifdef __LP64__ +#include <asm/pdcpat.h> + +int pdc_pat = 0; + +/* +** The module object is filled via PDC_PAT_CELL[Return Cell Module]. +** If a module is found, register module will get the IODC bytes via +** pdc_iodc_read() using the PA view of conf_base_addr for the hpa parameter. +** +** The IO view can be used by PDC_PAT_CELL[Return Cell Module] +** only for SBAs and LBAs. This view will cause an invalid +** argument error for all other cell module types. +** +*/ + +static int +pat_query_module( ulong pcell_loc, ulong mod_index) +{ + extern int num_devices; + extern struct hp_device devices[]; + + pdc_pat_cell_mod_maddr_block_t pa_pdc_cell; + struct hp_device * dev = &devices[num_devices]; + uint64_t temp; /* 64-bit scratch value */ + long status; /* PDC return value status */ + + /* return cell module (PA or Processor view) */ + status = pdc_pat_cell_module(& pdc_result, pcell_loc, mod_index, + PA_VIEW, & pa_pdc_cell); + + if (status != PDC_RET_OK) { + /* no more cell modules or error */ + return status; + } + + /* + ** save parameters in the hp_device + ** (The idea being the device driver will call pdc_pat_cell_module() + ** and store the results in it's own data structure.) + */ + dev->pcell_loc = pcell_loc; + dev->mod_index = mod_index; + + /* save generic info returned from the call */ + /* REVISIT: who is the consumer of this? not sure yet... */ + dev->mod_info = pa_pdc_cell.mod_info; /* pass to PAT_GET_ENTITY() */ + dev->pmod_loc = pa_pdc_cell.mod_location; + dev->mod_path = pa_pdc_cell.mod_path; + + temp = pa_pdc_cell.cba; + register_module((void *) PAT_GET_CBA(temp)); /* fills in dev->hpa */ + +#ifdef DEBUG_PAT + /* dump what we see so far... */ + switch (PAT_GET_ENTITY(dev->mod_info)) { + ulong i; + + case PAT_ENTITY_PROC: + printk ("PAT_ENTITY_PROC: id_eid 0x%lx\n", pa_pdc_cell.mod[0]); + break; + + case PAT_ENTITY_MEM: + printk ("PAT_ENTITY_MEM: amount 0x%lx min_gni_base 0x%lx min_gni_len 0x%lx\n", + pa_pdc_cell.mod[0], + pa_pdc_cell.mod[1], + pa_pdc_cell.mod[2]); + break; + case PAT_ENTITY_CA: + printk ("PAT_ENTITY_CA: %ld\n",pcell_loc); + break; + + case PAT_ENTITY_PBC: + printk ("PAT_ENTITY_PBC: "); + goto print_ranges; + + case PAT_ENTITY_SBA: + printk ("PAT_ENTITY_SBA: "); + goto print_ranges; + + case PAT_ENTITY_LBA: + printk ("PAT_ENTITY_LBA: "); + +print_ranges: + printk ("ranges %ld\n", pa_pdc_cell.mod[1]); + for (i = 0; i < pa_pdc_cell.mod[1]; i++) { + printk (" %ld: 0x%016lx 0x%016lx 0x%016lx\n", i, + pa_pdc_cell.mod[2+i*3], /* type */ + pa_pdc_cell.mod[3+i*3], /* start */ + pa_pdc_cell.mod[4+i*3]); /* finish (ie end) */ + } + printk("\n"); + break; + } +#endif /* DEBUG_PAT */ + return PDC_RET_OK; +} + + +static int do_pat_inventory(void) +{ + ulong mod_index=0; + int status; + ulong cell_num; + ulong pcell_loc; + + pdc_pat = (pdc_pat_cell_get_number(&pdc_result) == PDC_OK); + if (!pdc_pat) + { + return 0; + } + + cell_num = pdc_result[0]; /* Cell number call was made */ + + /* As of PDC PAT ARS 2.5, ret[1] is NOT architected! */ + pcell_loc = pdc_result[1]; /* Physical location of the cell */ + +#ifdef DEBUG_PAT + printk("CELL_GET_NUMBER: 0x%lx 0x%lx\n", cell_num, pcell_loc); +#endif + + status = pdc_pat_cell_num_to_loc(&pdc_result, cell_num); + if (status == PDC_BAD_OPTION) + { + /* Prelude (and it's successors: Lclass, A400/500) only + ** implement PDC_PAT_CELL sub-options 0 and 2. + ** "Home cook'n is best anyhow!" + */ + } else if (PDC_OK == status) { + /* so far only Halfdome supports this */ + pcell_loc = pdc_result[0]; + } else { + panic("WTF? CELL_GET_NUMBER give me invalid cell number?"); + } + + while (PDC_RET_OK == pat_query_module(pcell_loc, mod_index)) + { + mod_index++; + } + + return mod_index; +} +#endif /* __LP64__ */ + +static int do_newer_workstation_inventory(void) +{ + long status; + int i, num = 0; + + /* So the idea here is to simply try one SYSTEM_MAP call. If + that one works, great, otherwise do it another way */ + + status = pdc_system_map_find_mods(&module_result,&module_path,0); + + if (status == PDC_RET_OK) { + /* This is for newer non-PDC-PAT boxes */ + + printk("a newer box...\n"); + for(i=0, status=PDC_RET_OK; status != PDC_RET_NE_PROC && + status != PDC_RET_NE_MOD ;i++) { + + status = pdc_system_map_find_mods(&module_result,&module_path,i); + if (status == PDC_RET_OK) { + num++; + register_module(module_result.mod_addr); + } + } + } + + return (num > 0); +} + +#ifndef __LP64__ +static struct pdc_memory_map r_addr __attribute__ ((aligned (8))); + +static int really_do_oldhw_inventory(void) +{ + int i, mod, num = 0; + int status; + unsigned int hw_type; + unsigned int func; + + /* This is undocumented at the time of writing, but basically + we're setting up mod_path so that bc[0..4]=0xff, and step + through mod to get the "Path Structure for GSC Modules". If + it works, use the returned HPA and determine the hardware type. */ + + for (i=0;i<6;i++) module_path.bc[i]=0xff; + + for (mod=0;mod<16;mod++) { + char *stype = NULL; + + module_path.mod=mod; + status = pdc_mem_map_hpa(&r_addr, &module_path); + if (status!=PDC_RET_OK) continue; + + status = pdc_iodc_read(&pdc_result,(void *) r_addr.hpa, + 0, &iodc_data,32 ); + if (status!=PDC_RET_OK) continue; + hw_type = iodc_data[3]&0x1f; + + switch (hw_type) + { + case HPHW_NPROC: /* 0 */ + stype="Processor"; break; + + case HPHW_MEMORY: /* 1 */ + stype="Memory"; break; + + case HPHW_B_DMA: /* 2 */ + stype="Type B DMA"; break; + + case HPHW_A_DMA: /* 4 */ + stype="Type A DMA"; break; + + case HPHW_A_DIRECT: /* 5 */ + stype="Type A Direct"; break; + + case HPHW_BCPORT: /* 7 */ + stype="Bus Converter Port"; break; + + case HPHW_CONSOLE: /* 9 */ + stype="Console"; break; + + case HPHW_FIO: /* 10 - Graphics */ + stype="Foreign I/O (Graphics)"; break; + + case HPHW_BA: /* 11 - Bus Adapter */ + stype="Bus Adapter"; break; + + case HPHW_IOA: /* 12 */ + stype="I/O Adapter"; break; + + case HPHW_BRIDGE: /* 13 */ + stype="Bridge"; break; + + case HPHW_FABRIC: /* 14 */ + stype="Fabric"; break; + + case HPHW_FAULTY: /* 31 */ + stype="Faulty HW"; break; + + case HPHW_OTHER: /* 42 */ + default: + printk("Don't know this hw_type: %d\n", hw_type); + break; + } + + // This is kluged. But don't want to replicate code for + // most of the above cases. + if (stype) { +#ifdef DBG_PDC_QUERY + // parisc/kernel/drivers.c + extern int num_devices; + extern struct hp_device devices[]; + struct hp_hardware *h; +#endif + + status = pdc_mem_map_hpa(&r_addr, &module_path); + if (status==PDC_RET_OK && register_module((void *) r_addr.hpa) != NULL) + num++; + + + if (hw_type == HPHW_BA) { + /* Now, we're checking for devices for each + module. I seem to think that the + modules in question are Lasi (2), 2nd Lasi (6) + Wax (5). To do this, set bc[5]=0, and set + bc[4] to the module, and step through the + functions. */ + + for (i=0;i<4;i++) module_path.bc[i]=0xff; + module_path.bc[4]=mod; + for (func=0;func<16;func++) { + module_path.mod = func; + module_path.bc[5]=0; + status = pdc_mem_map_hpa(&r_addr, &module_path); + if (status!=PDC_RET_OK) continue; + if (register_module((void *) r_addr.hpa) != NULL) + num++; + } + } + // reset module_path.bc[] + for (i=0;i<6;i++) module_path.bc[i]=0xff; + + +#ifdef DBG_PDC_QUERY +// +// Let print_devices() dump everything which is registered. +// + h = devices[num_devices-1].reference; + + if (h) stype = h->name; + printk("Found %s at %d\n", stype, module_path.mod); +#endif + } + } + return num; +} + +static int +do_old_inventory(void) +{ + unsigned int bus_id; + long status; + int ok = 0; + + printk(" an older box...\n"); + + /* Here, we're going to check the model, and decide + if we should even bother trying. */ + + status = pdc_model_info(&model); + + bus_id = (model.hversion >> (4+7) ) &0x1f; + + /* Here, we're checking the HVERSION of the CPU. + We're only checking the 0th CPU, since it'll + be the same on an SMP box. */ + + switch (bus_id) { + case 0x4: /* 720, 730, 750, 735, 755 */ + case 0x6: /* 705, 710 */ + case 0x7: /* 715, 725 */ + case 0x8: /* 745, 747, 742 */ + case 0xA: /* 712 and similiar */ + case 0xC: /* 715/64, at least */ + + /* Do inventory using MEM_MAP */ + really_do_oldhw_inventory(); + ok = 1; + break; + default: /* Everything else */ + printk("This is a very very old machine, with a bus_id of 0x%x.\n",bus_id); + panic("This will probably never run Linux.\n"); + } + + return ok; +} + +#endif /* !__LP64__ */ + +void do_inventory(void){ + if((pdc_hpa_processor(&processor_hpa))<0){ + printk(KERN_INFO "Couldn't get the HPA of the processor.\n" ); + } + + printk("Searching for devices in PDC firmware... "); + printk("processor hpa 0x%lx\n", processor_hpa.hpa); + + if (!( + do_newer_workstation_inventory() +#ifdef __LP64__ + || do_pat_inventory() +#else /* __LP64__ */ + || do_old_inventory() +#endif /* __LP64__ */ + )) + { + panic("I can't get the hardware inventory on this machine"); + } + print_devices(NULL); +} + diff --git a/arch/parisc/kernel/iosapic.c b/arch/parisc/kernel/iosapic.c new file mode 100644 index 000000000..688cbf9bb --- /dev/null +++ b/arch/parisc/kernel/iosapic.c @@ -0,0 +1,1100 @@ +/* +** I/O Sapic Driver - PCI interrupt line support +** +** (c) Copyright 1999 Grant Grundler +** (c) Copyright 1999 Hewlett-Packard Company +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** The I/O sapic driver manages the Interrupt Redirection Table which is +** the control logic to convert PCI line based interrupts into a Message +** Signaled Interrupt (aka Transaction Based Interrupt, TBI). +** +** Acronyms +** -------- +** HPA Hard Physical Address (aka MMIO address) +** IRQ Interrupt ReQuest. Implies Line based interrupt. +** IRT Interrupt Routing Table (provided by PAT firmware) +** IRdT Interrupt Redirection Table. IRQ line to TXN ADDR/DATA +** table which is implemented in I/O SAPIC. +** ISR Interrupt Service Routine. aka Interrupt handler. +** MSI Message Signaled Interrupt. PCI 2.2 functionality. +** aka Transaction Based Interrupt (or TBI). +** PA Precision Architecture. HP's RISC architecture. +** RISC Reduced Instruction Set Computer. +** +** +** What's a Message Signalled Interrupt? +** ------------------------------------- +** MSI is a write transaction which targets a processor and is similar +** to a processor write to memory or MMIO. MSIs can be generated by I/O +** devices as well as processors and require *architecture* to work. +** +** PA only supports MSI. So I/O subsystems must either natively generate +** MSIs (e.g. GSC or HP-PB) or convert line based interrupts into MSIs +** (e.g. PCI and EISA). IA64 supports MSIs via a "local SAPIC" which +** acts on behalf of a processor. +** +** MSI allows any I/O device to interrupt any processor. This makes +** load balancing of the interrupt processing possible on an SMP platform. +** Interrupts are also ordered WRT to DMA data. It's possible on I/O +** coherent systems to completely eliminate PIO reads from the interrupt +** path. The device and driver must be designed and implemented to +** guarantee all DMA has been issued (issues about atomicity here) +** before the MSI is issued. I/O status can then safely be read from +** DMA'd data by the ISR. +** +** +** PA Firmware +** ----------- +** PA-RISC platforms have two fundementally different types of firmware. +** For PCI devices, "Legacy" PDC initializes the "INTERRUPT_LINE" register +** and BARs similar to a traditional PC BIOS. +** The newer "PAT" firmware supports PDC calls which return tables. +** PAT firmware only initializes PCI Console and Boot interface. +** With these tables, the OS can progam all other PCI devices. +** +** One such PAT PDC call returns the "Interrupt Routing Table" (IRT). +** The IRT maps each PCI slot's INTA-D "output" line to an I/O SAPIC +** input line. If the IRT is not available, this driver assumes +** INTERRUPT_LINE register has been programmed by firmware. The latter +** case also means online addition of PCI cards can NOT be supported +** even if HW support is present. +** +** All platforms with PAT firmware to date (Oct 1999) use one Interrupt +** Routing Table for the entire platform. +** +** Where's the iosapic? +** -------------------- +** I/O sapic is part of the "Core Electronics Complex". And on HP platforms +** it's integrated as part of the PCI bus adapter, "lba". So no bus walk +** will discover I/O Sapic. I/O Sapic driver learns about each device +** when lba driver advertises the presence of the I/O sapic by calling +** iosapic_register(). +** +** +** IRQ region notes +** ---------------- +** The data passed to iosapic_interrupt() is per IRQ line. +** Each IRQ line will get one txn_addr/data pair. Thus each IRQ region, +** will have several txn_addr/data pairs (up to 7 for current I/O SAPIC +** implementations). The IRQ region "sysdata" will NOT be directly passed +** to the interrupt handler like GSCtoPCI (dino.c). +** +** iosapic interrupt handler will NOT call do_irq_mask(). +** It doesn't need to read a bit mask to determine which IRQ line was pulled +** since it already knows based on vector_info passed to iosapic_interrupt(). +** +** One IRQ number represents both an IRQ line and a driver ISR. +** The I/O sapic driver can't manage shared IRQ lines because +** additional data besides the IRQ number must be passed via +** irq_region_ops. do_irq() and request_irq() must manage +** a sharing a bit in the mask. +** +** iosapic_interrupt() replaces do_irq_mask() and calls do_irq(). +** Which IRQ line was asserted is already known since each +** line has unique data associated with it. We could omit +** iosapic_interrupt() from the calling path if it did NOT need +** to write EOI. For unshared lines, it really doesn't. +** +** Unfortunately, can't optimize out EOI if IRQ line isn't "shared". +** N-class console "device" and some sort of heartbeat actually share +** one line though only one driver is registered...<sigh>...this was +** true for HP-UX at least. May not be true for parisc-linux. +** +** +** Overview of exported iosapic functions +** -------------------------------------- +** (caveat: code isn't finished yet - this is just the plan) +** +** iosapic_init: +** o initialize globals (lock, etc) +** o try to read IRT. Presence of IRT determines if this is +** a PAT platform or not. +** +** iosapic_register(): +** o create iosapic_info instance data structure +** o allocate vector_info array for this iosapic +** o initialize vector_info - read corresponding IRdT? +** +** iosapic_xlate_pin: (only called by fixup_irq for PAT platform) +** o intr_pin = read cfg (INTERRUPT_PIN); +** o if (device under PCI-PCI bridge) +** translate slot/pin +** +** iosapic_fixup_irq: +** o if PAT platform (IRT present) +** intr_pin = iosapic_xlate_pin(isi,pcidev): +** intr_line = find IRT entry(isi, PCI_SLOT(pcidev), intr_pin) +** save IRT entry into vector_info later +** write cfg INTERRUPT_LINE (with intr_line)? +** else +** intr_line = pcidev->irq +** IRT pointer = NULL +** endif +** o locate vector_info (needs: isi, intr_line) +** o allocate processor "irq" and get txn_addr/data +** o request_irq(processor_irq, iosapic_interrupt, vector_info,...) +** o pcidev->irq = isi->isi_region...base + intr_line; +** +** iosapic_interrupt: +** o call do_irq(vector->isi->irq_region, vector->irq_line, regs) +** o assume level triggered and write EOI +** +** iosapic_enable_irq: +** o clear any pending IRQ on that line +** o enable IRdT - call enable_irq(vector[line]->processor_irq) +** o write EOI in case line is already asserted. +** +** iosapic_disable_irq: +** o disable IRdT - call disable_irq(vector[line]->processor_irq) +** +** FIXME: mask/unmask +*/ + + +/* FIXME: determine which include files are really needed */ +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/pci.h> /* pci cfg accessor functions */ +#include <linux/init.h> +#include <linux/malloc.h> +#include <linux/smp_lock.h> +#include <linux/interrupt.h> /* irqaction */ +#include <linux/irq.h> /* irq_region support */ + +#include <asm/byteorder.h> /* get in-line asm for swab */ +#include <asm/pdc.h> +#include <asm/pdcpat.h> +#include <asm/page.h> +#include <asm/segment.h> +#include <asm/system.h> +#include <asm/gsc.h> /* gsc_read/write functions */ + +#include <asm/iosapic.h> +#include "./iosapic_private.h" + +#define MODULE_NAME "iosapic" + +/* "local" compile flags */ +#undef IOSAPIC_CALLBACK +#undef PCI_BRIDGE_FUNCS +#undef DEBUG_IOSAPIC +#undef DEBUG_IOSAPIC_IRT + + +#ifdef DEBUG_IOSAPIC +static char assert_buf[128]; + +static int +assert_failed (char *a, char *f, int l) +{ + sprintf(assert_buf, + "ASSERT(%s) failed!\nline %d in %s\n", + a, /* assertion text */ + l, /* line number */ + f); /* file name */ + panic(assert_buf); + return 0; +} + +#undef ASSERT +#define ASSERT(EX) { if (!(EX)) assert_failed(# EX, __FILE__, __LINE__); } + +#define DBG(x...) printk(x) + +#else /* DEBUG_IOSAPIC */ + +#define DBG(x...) +#define ASSERT(EX) + +#endif /* DEBUG_IOSAPIC */ + +#ifdef DEBUG_IOSAPIC_IRT +#define DBG_IRT(x...) printk(x) +#else +#define DBG_IRT(x...) +#endif + + +#define READ_U8(addr) gsc_readb(addr) +#define READ_U16(addr) le16_to_cpu(gsc_readw((u16 *) (addr))) +#define READ_U32(addr) le32_to_cpu(gsc_readl((u32 *) (addr))) +#define READ_REG16(addr) gsc_readw((u16 *) (addr)) +#define READ_REG32(addr) gsc_readl((u32 *) (addr)) +#define WRITE_U8(value, addr) gsc_writeb(value, addr) +#define WRITE_U16(value, addr) gsc_writew(cpu_to_le16(value), (u16 *) (addr)) +#define WRITE_U32(value, addr) gsc_writel(cpu_to_le32(value), (u32 *) (addr)) +#define WRITE_REG16(value, addr) gsc_writew(value, (u16 *) (addr)) +#define WRITE_REG32(value, addr) gsc_writel(value, (u32 *) (addr)) + + +#define IOSAPIC_REG_SELECT 0 +#define IOSAPIC_REG_WINDOW 0x10 +#define IOSAPIC_REG_EOI 0x40 + +#define IOSAPIC_REG_VERSION 0x1 + +#define IOSAPIC_IRDT_ENTRY(idx) (0x10+(idx)*2) +#define IOSAPIC_IRDT_ENTRY_HI(idx) (0x11+(idx)*2) + +/* +** FIXME: revisit which GFP flags we should really be using. +** GFP_KERNEL includes __GFP_WAIT flag and that may not +** be acceptable. Since this is boot time, we shouldn't have +** to wait ever and this code should (will?) never get called +** from the interrrupt context. +*/ +#define IOSAPIC_KALLOC(a_type, cnt) \ + (a_type *) kmalloc(sizeof(a_type)*(cnt), GFP_KERNEL) +#define IOSAPIC_FREE(addr, f_type, cnt) kfree((void *)addr) + + +#define IOSAPIC_LOCK(lck) spin_lock_irqsave(lck, irqflags) +#define IOSAPIC_UNLOCK(lck) spin_unlock_irqrestore(lck, irqflags) + + +#define IOSAPIC_VERSION_MASK 0x000000ff +#define IOSAPIC_VERSION_SHIFT 0x0 +#define IOSAPIC_VERSION(ver) \ + (int) ((ver & IOSAPIC_VERSION_MASK) >> IOSAPIC_VERSION_SHIFT) + +#define IOSAPIC_MAX_ENTRY_MASK 0x00ff0000 + +#define IOSAPIC_MAX_ENTRY_SHIFT 0x10 +#define IOSAPIC_IRDT_MAX_ENTRY(ver) \ + (int) ((ver&IOSAPIC_MAX_ENTRY_MASK) >> IOSAPIC_MAX_ENTRY_SHIFT) + +/* bits in the "low" I/O Sapic IRdT entry */ +#define IOSAPIC_IRDT_ENABLE 0x10000 +#define IOSAPIC_IRDT_PO_LOW 0x02000 +#define IOSAPIC_IRDT_LEVEL_TRIG 0x08000 +#define IOSAPIC_IRDT_MODE_LPRI 0x00100 + +/* bits in the "high" I/O Sapic IRdT entry */ +#define IOSAPIC_IRDT_ID_EID_SHIFT 0x10 + + + +#define IOSAPIC_EOI(eoi_addr, eoi_data) gsc_writel(eoi_data, eoi_addr) + +#if IOSAPIC_CALLBACK +/* +** Shouldn't use callback since SAPIC doesn't have an officially assigned +** H or S version numbers. Slight long term risk the number chosen would +** collide with something else. +** But benefit is cleaner lba/sapic interface. +** Might be worth it but for just use direct calls for now. +** +** Entry below is copied from lba driver. +** Only thing different is hw_type. +*/ +static struct pa_iodc_driver iosapic_driver_for[] = { + {HPHW_OTHER, 0x782, 0, 0x0000A, 0, 0x00, + DRIVER_CHECK_HWTYPE + DRIVER_CHECK_HVERSION + DRIVER_CHECK_SVERSION, + "I/O Sapic", "",(void *) iosapic_callback}, + {0,0,0,0,0,0, + 0, + (char *) NULL,(char *) NULL,(void *) NULL} +}; +#endif /* IOSAPIO_CALLBACK */ + + +static struct iosapic_info *iosapic_list; +static spinlock_t iosapic_lock; +static int iosapic_count; + + +/* +** REVISIT: future platforms may have more than one IRT. +** If so, the following three fields form a structure which +** then be linked into a list. Names are chosen to make searching +** for them easy - not necessarily accurate (eg "cell"). +** +** Alternative: iosapic_info could point to the IRT it's in. +** iosapic_register() could search a list of IRT's. +*/ +static struct irt_entry *irt_cell; +static size_t irt_num_entry; + + + +/* +** iosapic_load_irt +** +** The "Get PCI INT Routing Table Size" option returns the number of +** entries in the PCI interrupt routing table for the cell specified +** in the cell_number argument. The cell number must be for a cell +** within the caller's protection domain. +** +** The "Get PCI INT Routing Table" option returns, for the cell +** specified in the cell_number argument, the PCI interrupt routing +** table in the caller allocated memory pointed to by mem_addr. +** We assume the IRT only contains entries for I/O SAPIC and +** calculate the size based on the size of I/O sapic entries. +** +** The PCI interrupt routing table entry format is derived from the +** IA64 SAL Specification 2.4. The PCI interrupt routing table defines +** the routing of PCI interrupt signals between the PCI device output +** "pins" and the IO SAPICs' input "lines" (including core I/O PCI +** devices). This table does NOT include information for devices/slots +** behind PCI to PCI bridges. See PCI to PCI Bridge Architecture Spec. +** for the architected method of routing of IRQ's behind PPB's. +*/ + + +static int __init /* return number of entries as success/fail flag */ +iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt) +{ + struct pdc_pat_io_num pdc_io_num; /* PAT PDC return block */ + long status; /* PDC return value status */ + struct irt_entry *table = NULL; /* start of interrupt routing tbl */ + unsigned long num_entries = 0UL; + + ASSERT(NULL != irt); + /* FIXME ASSERT(((&pdc_io_num) & (0x3f)) == 0); enforce 32-byte alignment */ + + /* Try PAT_PDC to get interrupt routing table size */ + DBG(KERN_DEBUG "calling get_irt_size\n"); + status = pdc_pat_get_irt_size( &pdc_io_num, cell_num); + DBG(KERN_DEBUG "get_irt_size: %ld\n", status); + + switch(status) { + + case PDC_RET_OK: /* PAT box. Proceed to get the IRT */ + + /* save the number of entries in the table */ + num_entries = pdc_io_num.num; + ASSERT(0UL != num_entries); + + /* + ** allocate memory for interrupt routing table + ** This interface isn't really right. We are assuming + ** the contents of the table are exclusively + ** for I/O sapic devices. + */ + table = IOSAPIC_KALLOC(struct irt_entry, num_entries); + if (table == NULL) { + printk(KERN_WARNING MODULE_NAME ": read_irt : can not alloc mem for IRT\n"); + return 0; + } + + /* get PCI INT routing table */ + status = pdc_pat_get_irt( (void *) table, cell_num); + DBG(KERN_DEBUG "pdc_pat_get_irt: %ld\n", status); + ASSERT(status == PDC_RET_OK); + break; + + case PDC_RET_NE_PROC: /* Not a PAT platform. Try PDC_PCI extensions */ + /* + ** C3000/J5000 (and similar) platforms with "legacy" PDC + ** will return exactly one IRT. + ** So if we have one, don't need to get it again. + */ + if (NULL != irt_cell) + break; + + status = pdc_pci_irt_size( (void *)&pdc_io_num, + /* elroy HPA (really a NOP) */ 0); + DBG(KERN_WARNING "pdc_pci_irt_size: %ld\n", status); + + if (PDC_RET_OK != status) { + /* Not a "legacy" system with I/O SAPIC either */ + return 0; + } + + num_entries = pdc_io_num.num; + ASSERT(0UL != num_entries); + + table = IOSAPIC_KALLOC(struct irt_entry, num_entries); + if (table == NULL) { + printk(KERN_WARNING MODULE_NAME ": read_irt : can not alloc mem for IRT\n"); + return 0; + } + + status = pdc_pci_irt( (void *) &pdc_io_num, + (void *) NULL, /* Elroy HPA - not used */ + (void *) table); + + ASSERT(PDC_RET_OK == status); + break; + + default: + printk(KERN_WARNING MODULE_NAME ": PDC_PAT_IO call failed with %ld\n", status); + break; + } + + /* return interrupt table address */ + *irt = table; + + +#ifdef DEBUG_IOSAPIC_IRT + { + struct irt_entry *p = table; + int i; + + printk(MODULE_NAME " Interrupt Routing Table (cell %ld)\n", cell_num); + printk(MODULE_NAME " start = 0x%p num_entries %ld entry_size %d\n", + table, + num_entries, + (int) sizeof(struct irt_entry)); + + for (i = 0 ; i < num_entries ; i++, p++) + { + printk(MODULE_NAME " %02x %02x %02x %02x %02x %02x %02x %02x %08x%08x\n", + p->entry_type, p->entry_length, p->interrupt_type, + p->polarity_trigger, p->src_bus_irq_devno, p->src_bus_id, + p->src_seg_id, p->dest_iosapic_intin, + ((u32 *) p)[2], + ((u32 *) p)[3] + ); + } + } +#endif /* DEBUG_IOSAPIC_IRT */ + + return num_entries; +} + + + +void __init +iosapic_init(void) +{ + /* init global data */ + iosapic_lock = SPIN_LOCK_UNLOCKED; + iosapic_list = (struct iosapic_info *) NULL; + iosapic_count = 0; + + DBG("iosapic_init()\n"); + + /* + ** get IRT for this cell. + */ + irt_num_entry = iosapic_load_irt(0L, &irt_cell); + if (0 == irt_num_entry) + irt_cell = NULL; /* old PDC w/o iosapic */ + +#ifdef IOSAPIC_CALLBACK + /* + ** When new I/O SAPICs are discovered, this callback + ** will get invoked. Implies lba driver will register + ** I/O Sapic as a device it "discovered" with faked + ** IODC data. + */ + register_driver(iosapic_driver_for); +#endif /* IOSAPIC_CALLBACK */ +} + + +/* +** Return the IRT entry in case we need to look something else up. +*/ +static struct irt_entry * +irt_find_irqline(struct iosapic_info *isi, u8 slot, u8 intr_pin) +{ + struct irt_entry *i = irt_cell; + int cnt; /* track how many entries we've looked at */ + u8 irq_devno = (slot << IRT_DEV_SHIFT) | (intr_pin-1); + + DBG_IRT("irt_find_irqline() SLOT %d pin %d\n", slot, intr_pin); + + for (cnt=0; cnt < irt_num_entry; cnt++, i++) { + + /* + ** Validate: entry_type, entry_length, interrupt_type + ** + ** Difference between validate vs compare is the former + ** should print debug info and is not expected to "fail" + ** on current platforms. + */ + if (i->entry_type != IRT_IOSAPIC_TYPE) { + DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry %d type %d\n", i, cnt, i->entry_type); + continue; + } + + if (i->entry_length != IRT_IOSAPIC_LENGTH) { + DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry %d length %d\n", i, cnt, i->entry_length); + continue; + } + + if (i->interrupt_type != IRT_VECTORED_INTR) { + DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry %d interrupt_type %d\n", i, cnt, i->interrupt_type); + continue; + } + + /* + ** Compare: dest_iosapic_addr, src_bus_irq_devno + */ + if (i->dest_iosapic_addr != (u64) ((long) isi->isi_hpa)) + continue; + + if ((i->src_bus_irq_devno & IRT_IRQ_DEVNO_MASK) != irq_devno) + continue; + + /* + ** Ignore: src_bus_id and rc_seg_id correlate with + ** iosapic_info->isi_hpa on HP platforms. + ** If needed, pass in "PFA" (aka config space addr) + ** instead of slot. + */ + + /* Found it! */ + return i; + } + + printk(KERN_WARNING MODULE_NAME ": 0x%p : no IRT entry for slot %d, pin %d\n", + isi->isi_hpa, slot, intr_pin); + return NULL; +} + + +/* +** xlate_pin() supports the skewing of IRQ lines done by subsidiary bridges. +** Legacy PDC already does this translation for us and stores it in INTR_LINE. +** +** PAT PDC needs to basically do what legacy PDC does: +** o read PIN +** o adjust PIN in case device is "behind" a PPB +** (eg 4-port 100BT and SCSI/LAN "Combo Card") +** o convert slot/pin to I/O SAPIC input line. +** +** HP platforms only support: +** o one level of skewing for any number of PPBs +** o only support PCI-PCI Bridges. +*/ +static struct irt_entry * +iosapic_xlate_pin(struct iosapic_info *isi, struct pci_dev *pcidev) +{ + u8 intr_pin, intr_slot; + + (void) pci_read_config_byte(pcidev, PCI_INTERRUPT_PIN, &intr_pin); + + DBG_IRT("iosapic_xlate_pin() SLOT %d pin %d\n", PCI_SLOT(pcidev->devfn), intr_pin); + + if (0 == intr_pin) + { + /* + ** The device does NOT support/use IRQ lines. + */ + return NULL; + } + + /* Check if pcidev behind a PPB */ + if (NULL != pcidev->bus->self) + { + /* Convert pcidev INTR_PIN into something we + ** can lookup in the IRT. + */ +#ifdef PCI_BRIDGE_FUNCS + /* + ** Proposal #1: + ** + ** call implementation specific translation function + ** This is architecturally "cleaner". HP-UX doesn't + ** support other secondary bus types (eg. E/ISA) directly. + ** May be needed for other processor (eg IA64) architectures + ** or by some ambitous soul who wants to watch TV. + */ + if (pci_bridge_funcs->xlate_intr_line) { + intr_pin = (*pci_bridge_funcs->xlate_intr_line)(pcidev); + } +#else /* PCI_BRIDGE_FUNCS */ + struct pci_bus *p = pcidev->bus; + /* + ** Proposal #2: + ** The "pin" is skewed ((pin + dev - 1) % 4). + ** + ** This isn't very clean since I/O SAPIC must assume: + ** - all platforms only have PCI busses. + ** - only PCI-PCI bridge (eg not PCI-EISA, PCI-PCMCIA) + ** - IRQ routing is only skewed once regardless of + ** the number of PPB's between iosapic and device. + ** (Bit3 expansion chassis follows this rule) + ** + ** Advantage is it's really easy to implement. + */ + intr_pin = ((intr_pin-1)+PCI_SLOT(pcidev->devfn)) % 4; + intr_pin++; /* convert back to INTA-D (1-4) */ +#endif /* PCI_BRIDGE_FUNCS */ + + /* + ** Locate the host slot the PPB nearest the Host bus + ** adapter. + */ + while (NULL != p->parent->self) + p = p->parent; + + intr_slot = PCI_SLOT(p->self->devfn); + } else { + intr_slot = PCI_SLOT(pcidev->devfn); + } + DBG_IRT("iosapic_xlate_pin: bus %d slot %d pin %d\n", + pcidev->bus->secondary, intr_slot, intr_pin); + + return irt_find_irqline(isi, intr_slot, intr_pin); +} + + +static void +iosapic_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct vector_info *vi = (struct vector_info *)dev_id; + extern void do_irq(struct irqaction *a, int i, struct pt_regs *p); + int irq_num = vi->vi_ios->isi_region->data.irqbase + vi->vi_irqline; + + DBG("iosapic_interrupt(): irq %d line %d eoi %p\n", irq, vi->vi_irqline, + vi->vi_eoi_addr); + +/* FIXME: Need to mask/unmask? processor IRQ is already masked... */ + do_irq(&vi->vi_ios->isi_region->action[vi->vi_irqline], irq_num, regs); + + /* + ** PCI only supports level triggered in order to share IRQ lines. + ** I/O SAPIC must always issue EOI. + */ + IOSAPIC_EOI(vi->vi_eoi_addr, vi->vi_eoi_data); +} + + +int +iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev) +{ + struct iosapic_info *isi = (struct iosapic_info *)isi_obj; + struct irt_entry *irte = NULL; /* only used if PAT PDC */ + struct vector_info *vi; + int isi_line; /* line used by device */ + int tmp; + + if (NULL == isi) { + printk(KERN_WARNING MODULE_NAME ": 0x%p hpa not registered\n", isi->isi_hpa); + return(-1); + } + + /* lookup IRT entry for isi/slot/pin set */ + irte = iosapic_xlate_pin(isi, pcidev); + if (NULL == irte) { + return(-1); + } + DBG_IRT("iosapic_fixup_irq(): irte %p %x %x %x %x %x %x %x %x\n", + irte, + irte->entry_type, + irte->entry_length, + irte->polarity_trigger, + irte->src_bus_irq_devno, + irte->src_bus_id, + irte->src_seg_id, + irte->dest_iosapic_intin, + (u32) irte->dest_iosapic_addr); + isi_line = irte->dest_iosapic_intin; + + /* get vector info for this input line */ + ASSERT(NULL != isi->isi_vector); + vi = &(isi->isi_vector[isi_line]); + DBG_IRT("iosapic_fixup_irq: line %d vi 0x%p\n", isi_line, vi); + vi->vi_irte = irte; + + /* Allocate processor IRQ */ + vi->vi_txn_irq = txn_alloc_irq(); + +/* XXX/FIXME The txn_alloc_irq() code and related code should be moved +** to enable_irq(). That way we only allocate processor IRQ bits +** for devices that actually have drivers claiming them. +** Right now we assign an IRQ to every PCI device present regardless +** of whether it's used or not. +*/ + if (vi->vi_txn_irq < 0) + panic("I/O sapic: couldn't get TXN IRQ\n"); + + /* enable_irq() will use txn_* to program IRdT */ + vi->vi_txn_addr = txn_alloc_addr(vi->vi_txn_irq); + vi->vi_txn_data = txn_alloc_data(vi->vi_txn_irq, 8); + ASSERT(vi->vi_txn_data < 256); /* matches 8 above */ + + tmp = request_irq(vi->vi_txn_irq, iosapic_interrupt, 0, "iosapic", vi); + ASSERT(tmp == 0); + + vi->vi_eoi_addr = ((void *) isi->isi_hpa) + IOSAPIC_REG_EOI; + vi->vi_eoi_data = cpu_to_le32(vi->vi_irqline); + + ASSERT(NULL != isi->isi_region); + /* + ** pcidev->irq still needs to be virtualized. + */ + pcidev->irq = isi->isi_region->data.irqbase + isi_line; + + DBG_IRT("iosapic_fixup_irq() %d:%d %x %x line %d irq %d\n", PCI_SLOT(pcidev->devfn), + PCI_FUNC(pcidev->devfn), pcidev->vendor, pcidev->device, isi_line, pcidev->irq); + + return(pcidev->irq); +} + + +static void +iosapic_rd_irt_entry(struct vector_info *vi , u32 *dp0, u32 *dp1) +{ + struct iosapic_info *isp = vi->vi_ios; + u8 idx = vi->vi_irqline; + + /* point the window register to the lower word */ + WRITE_U32(IOSAPIC_IRDT_ENTRY(idx), isp->isi_hpa+IOSAPIC_REG_SELECT); + *dp0 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW); + + /* point the window register to the higher word */ + WRITE_U32(IOSAPIC_IRDT_ENTRY_HI(idx), isp->isi_hpa+IOSAPIC_REG_SELECT); + *dp1 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW); +} + + +static void +iosapic_wr_irt_entry(struct vector_info *vi, u32 dp0, u32 dp1) +{ + struct iosapic_info *isp = vi->vi_ios; + + ASSERT(NULL != isp); + ASSERT(NULL != isp->isi_hpa); + DBG_IRT("iosapic_wr_irt_entry(): irq %d hpa %p WINDOW %p 0x%x 0x%x\n", + vi->vi_irqline, + isp->isi_hpa, isp->isi_hpa+IOSAPIC_REG_WINDOW, + dp0, dp1); + + /* point the window register to the lower word */ + WRITE_U32(IOSAPIC_IRDT_ENTRY(vi->vi_irqline), isp->isi_hpa+IOSAPIC_REG_SELECT); + WRITE_U32( dp0, isp->isi_hpa+IOSAPIC_REG_WINDOW); + + /* Read the window register to flush the writes down to HW */ + dp0 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW); + + /* point the window register to the higher word */ + WRITE_U32(IOSAPIC_IRDT_ENTRY_HI(vi->vi_irqline), isp->isi_hpa+IOSAPIC_REG_SELECT); + WRITE_U32( dp1, isp->isi_hpa+IOSAPIC_REG_WINDOW); + + /* Read the window register to flush the writes down to HW */ + dp1 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW); +} + + +/* +** set_irt prepares the data (dp0, dp1) according to the vector_info +** and target cpu (id_eid). dp0/dp1 are then used to program I/O SAPIC +** IRdT for the given "vector" (aka IRQ line). +*/ +static void +iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1) +{ + u32 mode = 0; + struct irt_entry *p = vi->vi_irte; + ASSERT(NULL != vi->vi_irte); + + if ((p->polarity_trigger & IRT_PO_MASK) == IRT_ACTIVE_LO) + mode |= IOSAPIC_IRDT_PO_LOW; + + if (((p->polarity_trigger >> IRT_EL_SHIFT) & IRT_EL_MASK) == IRT_LEVEL_TRIG) + mode |= IOSAPIC_IRDT_LEVEL_TRIG; + + /* + ** IA64 REVISIT + ** PA doesn't support EXTINT or LPRIO bits. + */ + + ASSERT(vi->vi_txn_data); + *dp0 = mode | (u32) vi->vi_txn_data; + + /* + ** Extracting id_eid isn't a real clean way of getting it. + ** But the encoding is the same for both PA and IA64 platforms. + */ +#ifdef __LP64__ + if (pdc_pat) { + /* + ** PAT PDC just hands it to us "right". + ** vi_txn_addr comes from cpu_data[x].txn_addr. + */ + *dp1 = (u32) (vi->vi_txn_addr); + } else +#endif + { + /* + ** eg if base_addr == 0xfffa0000), + ** we want to get 0xa0ff0000. + ** + ** eid 0x0ff00000 -> 0x00ff0000 + ** id 0x000ff000 -> 0xff000000 + */ + *dp1 = (((u32)vi->vi_txn_addr & 0x0ff00000) >> 4) | + (((u32)vi->vi_txn_addr & 0x000ff000) << 12); + } + DBG_IRT("iosapic_set_irt_data(): 0x%x 0x%x\n", *dp0, *dp1); +} + + +static void +iosapic_disable_irq(void *irq_dev, int irq) +{ + ulong irqflags; + struct vector_info *vi = &(((struct vector_info *) irq_dev)[irq]); + u32 d0, d1; + + ASSERT(NULL != vi); + + IOSAPIC_LOCK(&iosapic_lock); + +#ifdef REVISIT_DESIGN_ISSUE +/* +** XXX/FIXME + +disable_irq()/enable_irq(): drawback of using IRQ as a "handle" + +Current disable_irq interface only allows the irq_region support routines +to manage sharing of "irq" objects. The problem is the disable_irq() +interface specifies which IRQ line needs to be disabled but does not +identify the particular ISR which needs to be disabled. IO sapic +(and similar code in Dino) can only support one handler per IRQ +since they don't further encode the meaning of the IRQ number. +irq_region support has to hide it's implementation of "shared IRQ" +behind a function call. + +Encoding the IRQ would be possible by I/O SAPIC but makes life really +complicated for the IRQ handler and not help performance. + +Need more info on how Linux supports shared IRQ lines on a PC. +*/ +#endif /* REVISIT_DESIGN_ISSUE */ + + iosapic_rd_irt_entry(vi, &d0, &d1); + d0 |= IOSAPIC_IRDT_ENABLE; + iosapic_wr_irt_entry(vi, d0, d1); + + IOSAPIC_UNLOCK(&iosapic_lock); + + /* disable ISR for parent */ + disable_irq(vi->vi_txn_irq); +} + + +static void +iosapic_enable_irq(void *dev, int irq) +{ + struct vector_info *vi = &(((struct vector_info *) dev)[irq]); + u32 d0, d1; + + ASSERT(NULL != vi); + ASSERT(NULL != vi->vi_irte); + + /* data is initialized by fixup_irq */ + ASSERT(0 < vi->vi_txn_irq); + ASSERT(0UL != vi->vi_txn_addr); + ASSERT(0UL != vi->vi_txn_data); + + iosapic_set_irt_data(vi, &d0, &d1); + iosapic_wr_irt_entry(vi, d0, d1); + + +#ifdef DEBUG_IOSAPIC_IRT +{ +u32 *t = (u32 *) ((ulong) vi->vi_eoi_addr & ~0xffUL); +printk("iosapic_enable_irq(): regs %p", vi->vi_eoi_addr); +while (t < vi->vi_eoi_addr) printk(" %x", READ_U32(t++)); +printk("\n"); +} + +printk("iosapic_enable_irq(): sel "); +{ + struct iosapic_info *isp = vi->vi_ios; + + for (d0=0x10; d0<0x1e; d0++) { + /* point the window register to the lower word */ + WRITE_U32(d0, isp->isi_hpa+IOSAPIC_REG_SELECT); + + /* read the word */ + d1 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW); + printk(" %x", d1); + } +} +printk("\n"); +#endif + + /* + ** KLUGE: IRQ should not be asserted when Drivers enabling their IRQ. + ** PCI supports level triggered in order to share IRQ lines. + ** + ** Issueing I/O SAPIC an EOI causes an interrupt iff IRQ line is + ** asserted. + */ + IOSAPIC_EOI(vi->vi_eoi_addr, vi->vi_eoi_data); +} + + +static void +iosapic_mask_irq(void *dev, int irq) +{ + BUG(); +} + + +static void +iosapic_unmask_irq(void *dev, int irq) +{ + BUG(); +} + + +static struct irq_region_ops iosapic_irq_ops = { + iosapic_disable_irq, + iosapic_enable_irq, + iosapic_mask_irq, + iosapic_unmask_irq +}; + + +/* +** squirrel away the I/O Sapic Version +*/ +static unsigned int +iosapic_rd_version(struct iosapic_info *isi) +{ + ASSERT(isi); + ASSERT(isi->isi_hpa); + + /* point window to the version register */ + WRITE_U32(IOSAPIC_REG_VERSION, isi->isi_hpa+IOSAPIC_REG_SELECT); + + /* now read the version register */ + return (READ_U32(isi->isi_hpa+IOSAPIC_REG_WINDOW)); +} + + +#ifndef IOSAPIC_CALLBACK +/* +** iosapic_register() is the alternative to iosapic_driver_for(). +** (Only one or the other should be implemented.) +*/ + +/* +** iosapic_register() is called by "drivers" with an integrated I/O SAPIC. +** Caller must be certain they have an I/O SAPIC and know it's MMIO address. +** +** o allocate iosapic_info and add it to the list +** o read iosapic version and squirrel that away +** o read size of IRdT. +** o allocate and initialize isi_vector[] +** o allocate isi_region (registers region handlers) +*/ +void * +iosapic_register(void *hpa) +{ + struct iosapic_info *isi = NULL; + struct irt_entry *irte = irt_cell; + struct vector_info *vip; + int cnt; /* track how many entries we've looked at */ + + /* + ** Astro based platforms can't support PCI OLARD if they + ** implement the legacy PDC (not PAT). Though Legacy PDC + ** supports an IRT, LBA's with no device under them + ** are *not* listed in the IRT. + ** Search the IRT and ignore iosapic's which aren't + ** in the IRT. + */ + ASSERT(NULL != irte); /* always have built-in devices */ + for (cnt=0; cnt < irt_num_entry; cnt++, irte++) { + ASSERT(IRT_IOSAPIC_TYPE == irte->entry_type); + /* + ** We need sign extension of the hpa on 32-bit kernels. + ** The address in the IRT is *always* 64 bit and really + ** is an unsigned quantity (like all physical addresses). + */ + if (irte->dest_iosapic_addr == (s64) ((long) hpa)) + break; + } + + if (cnt >= irt_num_entry) + return (NULL); + + if ((isi = IOSAPIC_KALLOC(struct iosapic_info, 1)) == NULL) { + BUG(); + return (NULL); + } + + memset(isi, 0, sizeof(struct iosapic_info)); + + isi->isi_hpa = (unsigned char *) hpa; + isi->isi_version = iosapic_rd_version(isi); + isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1; + + vip = isi->isi_vector = + IOSAPIC_KALLOC(struct vector_info, isi->isi_num_vectors); + + if (vip == NULL) { + IOSAPIC_FREE(isi, struct iosapic_info, 1); + return (NULL); + } + + memset(vip, 0, sizeof(struct vector_info) * isi->isi_num_vectors); + + /* + ** Initialize vector array + */ + for (cnt=0; cnt < isi->isi_num_vectors; cnt++, vip++) { + vip->vi_irqline = (unsigned char) cnt; + vip->vi_ios = isi; + } + + isi->isi_region = alloc_irq_region(isi->isi_num_vectors, + &iosapic_irq_ops, IRQ_REG_DIS|IRQ_REG_MASK, + "I/O Sapic", (void *) isi->isi_vector); + + ASSERT(NULL != isi->isi_region); + return ((void *) isi); +} +#endif /* !IOSAPIC_CALLBACK */ + + + +#ifdef DEBUG_IOSAPIC + +static void +iosapic_prt_irt(void *irt, long num_entry) +{ + unsigned int i, *irp = (unsigned int *) irt; + + ASSERT(NULL != irt); + + printk(KERN_DEBUG MODULE_NAME ": Interrupt Routing Table (%lx entries)\n", num_entry); + + for (i=0; i<num_entry; i++, irp += 4) { + printk(KERN_DEBUG "%p : %2d %.8x %.8x %.8x %.8x\n", + irp, i, irp[0], irp[1], irp[2], irp[3]); + } +} + + +static void +iosapic_prt_vi(struct vector_info *vi) +{ + ASSERT(NULL != vi); + + printk(KERN_DEBUG MODULE_NAME ": vector_info[%d] is at %p\n", vi->vi_irqline, vi); + printk(KERN_DEBUG "\t\tvi_status: %.4x\n", vi->vi_status); + printk(KERN_DEBUG "\t\tvi_txn_irq: %d\n", vi->vi_txn_irq); + printk(KERN_DEBUG "\t\tvi_txn_addr: %lx\n", vi->vi_txn_addr); + printk(KERN_DEBUG "\t\tvi_txn_data: %lx\n", vi->vi_txn_data); + printk(KERN_DEBUG "\t\tvi_eoi_addr: %p\n", vi->vi_eoi_addr); + printk(KERN_DEBUG "\t\tvi_eoi_data: %x\n", vi->vi_eoi_data); +} + + +static void +iosapic_prt_isi(struct iosapic_info *isi) +{ + ASSERT(NULL != isi); + printk(KERN_DEBUG MODULE_NAME ": io_sapic_info at %p\n", isi); + printk(KERN_DEBUG "\t\tisi_hpa: %p\n", isi->isi_hpa); + printk(KERN_DEBUG "\t\tisi_satus: %x\n", isi->isi_status); + printk(KERN_DEBUG "\t\tisi_version: %x\n", isi->isi_version); + printk(KERN_DEBUG "\t\tisi_vector: %p\n", isi->isi_vector); +} +#endif /* DEBUG_IOSAPIC */ diff --git a/arch/parisc/kernel/iosapic_private.h b/arch/parisc/kernel/iosapic_private.h new file mode 100644 index 000000000..f310501c4 --- /dev/null +++ b/arch/parisc/kernel/iosapic_private.h @@ -0,0 +1,165 @@ +/* +** This file is private to iosapic driver. +** If stuff needs to be used by another driver, move it to a common file. +** +** WARNING: fields most data structures here are ordered to make sure +** they pack nicely for 64-bit compilation. (ie sizeof(long) == 8) +*/ + + +/* +** Interrupt Routing Stuff +** ----------------------- +** The interrupt routing table consists of entries derived from +** MP Specification Draft 1.5. There is one interrupt routing +** table per cell. N- and L-class consist of a single cell. +*/ +struct irt_entry { + + /* Entry Type 139 identifies an I/O SAPIC interrupt entry */ + u8 entry_type; + + /* Entry Length 16 indicates entry is 16 bytes long */ + u8 entry_length; + + /* + ** Interrupt Type of 0 indicates a vectored interrupt, + ** all other values are reserved + */ + u8 interrupt_type; + + /* + ** PO and EL + ** Polarity of SAPIC I/O input signals: + ** 00 = Reserved + ** 01 = Active high + ** 10 = Reserved + ** 11 = Active low + ** Trigger mode of SAPIC I/O input signals: + ** 00 = Reserved + ** 01 = Edge-triggered + ** 10 = Reserved + ** 11 = Level-triggered + */ + u8 polarity_trigger; + + /* + ** IRQ and DEVNO + ** irq identifies PCI interrupt signal where + ** 0x0 corresponds to INT_A#, + ** 0x1 corresponds to INT_B#, + ** 0x2 corresponds to INT_C# + ** 0x3 corresponds to INT_D# + ** PCI device number where interrupt originates + */ + u8 src_bus_irq_devno; + + /* Source Bus ID identifies the bus where interrupt signal comes from */ + u8 src_bus_id; + + /* + ** Segment ID is unique across a protection domain and + ** identifies a segment of PCI buses (reserved in + ** MP Specification Draft 1.5) + */ + u8 src_seg_id; + + /* + ** Destination I/O SAPIC INTIN# identifies the INTIN n pin + ** to which the signal is connected + */ + u8 dest_iosapic_intin; + + /* + ** Destination I/O SAPIC Address identifies the I/O SAPIC + ** to which the signal is connected + */ + u64 dest_iosapic_addr; +}; + +#define IRT_IOSAPIC_TYPE 139 +#define IRT_IOSAPIC_LENGTH 16 + +#define IRT_VECTORED_INTR 0 + +#define IRT_PO_MASK 0x3 +#define IRT_ACTIVE_HI 1 +#define IRT_ACTIVE_LO 3 + +#define IRT_EL_MASK 0x3 +#define IRT_EL_SHIFT 2 +#define IRT_EDGE_TRIG 1 +#define IRT_LEVEL_TRIG 3 + +#define IRT_IRQ_MASK 0x3 +#define IRT_DEV_MASK 0x1f +#define IRT_DEV_SHIFT 2 + +#define IRT_IRQ_DEVNO_MASK ((IRT_DEV_MASK << IRT_DEV_SHIFT) | IRT_IRQ_MASK) + +#ifdef SUPPORT_MULTI_CELL +struct iosapic_irt { + struct iosapic_irt *irt_next; /* next routing table */ + struct irt_entry *irt_base; /* intr routing table address */ + size_t irte_count; /* number of entries in the table */ + size_t irte_size; /* size (bytes) of each entry */ +}; +#endif + +struct vector_info { + struct iosapic_info *vi_ios; /* I/O SAPIC this vector is on */ + struct irt_entry *vi_irte; /* IRT entry */ + u32 *vi_eoi_addr; /* precalculate EOI reg address */ + u32 vi_eoi_data; /* IA64: ? PA: swapped txn_data */ + u8 vi_status; /* status/flags */ + u8 vi_irqline; /* INTINn(IRQ) */ + int vi_txn_irq; /* virtual IRQ number for processor */ + ulong vi_txn_addr; /* IA64: id_eid PA: partial HPA */ + ulong vi_txn_data; /* IA64: vector PA: EIR bit */ +}; + + +struct iosapic_info { + struct iosapic_info *isi_next; /* list of I/O SAPIC */ + volatile void *isi_hpa; /* physical base address */ + struct irq_region *isi_region; /* each I/O SAPIC is one region */ + struct vector_info *isi_vector; /* IRdT (IRQ line) array */ + int isi_num_vectors; /* size of IRdT array */ + int isi_status; /* status/flags */ + unsigned int isi_version; /* DEBUG: data fr version reg */ +}; + + + +#ifdef __IA64__ +/* +** PA risc does NOT have any local sapics. IA64 does. +** PIB (Processor Interrupt Block) is handled by Astro or Dew (Stretch CEC). +** +** PA: Get id_eid from IRT and hardcode PIB to 0xfeeNNNN0 +** Emulate the data on PAT platforms. +*/ +struct local_sapic_info { + struct local_sapic_info *lsi_next; /* point to next CPU info */ + int *lsi_cpu_id; /* point to logical CPU id */ + unsigned long *lsi_id_eid; /* point to IA-64 CPU id */ + int *lsi_status; /* point to CPU status */ + void *lsi_private; /* point to special info */ +}; + +/* +** "root" data structure which ties everything together. +** Should always be able to start with sapic_root and locate +** the desired information. +*/ +struct sapic_info { + struct sapic_info *si_next; /* info is per cell */ + int si_cellid; /* cell id */ + unsigned int si_status; /* status */ + char *si_pib_base; /* intr blk base address */ + local_sapic_info_t *si_local_info; + io_sapic_info_t *si_io_info; + extint_info_t *si_extint_info;/* External Intr info */ +}; +#endif + diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c new file mode 100644 index 000000000..aec36f7cc --- /dev/null +++ b/arch/parisc/kernel/irq.c @@ -0,0 +1,538 @@ +/* $Id: irq.c,v 1.8 2000/02/08 02:01:17 grundler Exp $ + * + * Code to handle x86 style IRQs plus some generic interrupt stuff. + * + * This is not in any way SMP-clean. + * + * Copyright (C) 1992 Linus Torvalds + * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle + * Copyright (C) 1999 SuSE GmbH (Author: Philipp Rumpf, prumpf@tux.org) + * Copyright (C) 2000 Hewlett Packard Corp (Co-Author: Grant Grundler, grundler@cup.hp.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <linux/config.h> +#include <linux/bitops.h> +#include <asm/bitops.h> +#include <asm/pdc.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/ioport.h> +#include <linux/timex.h> +#include <linux/malloc.h> +#include <linux/random.h> +#include <linux/interrupt.h> +#include <linux/irq.h> + +#include <asm/cache.h> + +#undef DEBUG_IRQ + +extern void timer_interrupt(int, void *, struct pt_regs *); +extern void ipi_interrupt(int, void *, struct pt_regs *); + +#ifdef DEBUG_IRQ +#define DBG_IRQ(x...) printk(x) +#else /* DEBUG_IRQ */ +#define DBG_IRQ(x...) +#endif /* DEBUG_IRQ */ + +#define EIEM_MASK(irq) (1L<<(MAX_CPU_IRQ-IRQ_OFFSET(irq))) +#define CLEAR_EIEM_BIT(irq) set_eiem(get_eiem() & ~EIEM_MASK(irq)) +#define SET_EIEM_BIT(irq) set_eiem(get_eiem() | EIEM_MASK(irq)) + +static void disable_cpu_irq(void *unused, int irq) +{ + CLEAR_EIEM_BIT(irq); +} + +static void enable_cpu_irq(void *unused, int irq) +{ + unsigned long mask = EIEM_MASK(irq); + + mtctl(mask, 23); + SET_EIEM_BIT(irq); +} + +static struct irqaction cpu_irq_actions[IRQ_PER_REGION] = { + [IRQ_OFFSET(TIMER_IRQ)] { timer_interrupt, 0, 0, "timer", NULL, NULL }, + [IRQ_OFFSET(IPI_IRQ)] { ipi_interrupt, 0, 0, "IPI", NULL, NULL }, +}; + +struct irq_region cpu_irq_region = { + { disable_cpu_irq, enable_cpu_irq, NULL, NULL }, + { &cpu_data[0], "PA-PIC", IRQ_REG_MASK|IRQ_REG_DIS, IRQ_FROM_REGION(CPU_IRQ_REGION)}, + cpu_irq_actions +}; + +struct irq_region *irq_region[NR_IRQ_REGS] = { + [ 0 ] NULL, /* abuse will data page fault (aka code 15) */ + [ CPU_IRQ_REGION ] &cpu_irq_region, +}; + + + +/* we special-case the real IRQs here, which feels right given the relatively + * high cost of indirect calls. If anyone is bored enough to benchmark this + * and find out whether I am right, feel free to. prumpf */ + +static inline void mask_irq(int irq) +{ + struct irq_region *region; + +#ifdef DEBUG_IRQ + if (irq != TIMER_IRQ) +#endif + DBG_IRQ("mask_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq)); + + if(IRQ_REGION(irq) != CPU_IRQ_REGION) { + region = irq_region[IRQ_REGION(irq)]; + if(region->data.flags & IRQ_REG_MASK) + region->ops.mask_irq(region->data.dev, IRQ_OFFSET(irq)); + } else { + CLEAR_EIEM_BIT(irq); + } +} + +static inline void unmask_irq(int irq) +{ + struct irq_region *region; + +#ifdef DEBUG_IRQ + if (irq != TIMER_IRQ) +#endif + DBG_IRQ("unmask_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq)); + + if(IRQ_REGION(irq) != CPU_IRQ_REGION) { + region = irq_region[IRQ_REGION(irq)]; + if(region->data.flags & IRQ_REG_MASK) + region->ops.unmask_irq(region->data.dev, IRQ_OFFSET(irq)); + } else { + SET_EIEM_BIT(irq); + } +} + +void disable_irq(int irq) +{ + struct irq_region *region; + +#ifdef DEBUG_IRQ + if (irq != TIMER_IRQ) +#endif + DBG_IRQ("disable_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq)); + region = irq_region[IRQ_REGION(irq)]; + + if(region->data.flags & IRQ_REG_DIS) + region->ops.disable_irq(region->data.dev, IRQ_OFFSET(irq)); + else + BUG(); +} + +void enable_irq(int irq) +{ + struct irq_region *region; + +#ifdef DEBUG_IRQ + if (irq != TIMER_IRQ) +#endif + DBG_IRQ("enable_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq)); + region = irq_region[IRQ_REGION(irq)]; + + if(region->data.flags & IRQ_REG_DIS) + region->ops.enable_irq(region->data.dev, IRQ_OFFSET(irq)); + else + BUG(); +} + +int get_irq_list(char *buf) +{ +#ifdef CONFIG_PROC_FS + char *p = buf; + int i, j; + int regnr, irq_no; + struct irq_region *region; + struct irqaction *action, *mainaction; + + p += sprintf(p, " "); + for (j=0; j<smp_num_cpus; j++) + p += sprintf(p, "CPU%d ",j); + *p++ = '\n'; + + for (regnr = 0; regnr < NR_IRQ_REGS; regnr++) { + region = irq_region[regnr]; + if (!region || !region->action) + continue; + + mainaction = region->action; + + for (i = 0; i <= MAX_CPU_IRQ; i++) { + action = mainaction++; + if (!action || !action->name) + continue; + + irq_no = IRQ_FROM_REGION(regnr) + i; + + p += sprintf(p, "%3d: ", irq_no); +#ifndef CONFIG_SMP + p += sprintf(p, "%10u ", kstat_irqs(irq_no)); +#else + for (j = 0; j < smp_num_cpus; j++) + p += sprintf(p, "%10u ", + kstat.irqs[cpu_logical_map(j)][irq_no]); +#endif + p += sprintf(p, " %14s", + region->data.name ? region->data.name : "N/A"); + p += sprintf(p, " %s", action->name); + + for (action=action->next; action; action = action->next) + p += sprintf(p, ", %s", action->name); + *p++ = '\n'; + } + } + + p += sprintf(p, "\n"); +#if CONFIG_SMP + p += sprintf(p, "LOC: "); + for (j = 0; j < smp_num_cpus; j++) + p += sprintf(p, "%10u ", + apic_timer_irqs[cpu_logical_map(j)]); + p += sprintf(p, "\n"); +#endif + + return p - buf; + +#else /* CONFIG_PROC_FS */ + + return 0; + +#endif /* CONFIG_PROC_FS */ +} + + + +/* +** The following form a "set": Virtual IRQ, Transaction Address, Trans Data. +** Respectively, these map to IRQ region+EIRR, Processor HPA, EIRR bit. +** +** To use txn_XXX() interfaces, get a Virtual IRQ first. +** Then use that to get the Transaction address and data. +*/ + +int +txn_alloc_irq(void) +{ + int irq; + + /* never return irq 0 cause that's the interval timer */ + for(irq=1; irq<=MAX_CPU_IRQ; irq++) { + if(cpu_irq_region.action[irq].handler == NULL) { + return (IRQ_FROM_REGION(CPU_IRQ_REGION) + irq); + } + } + + /* unlikely, but be prepared */ + return -1; +} + +int +txn_claim_irq(int irq) +{ + if (irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)].handler ==NULL) + { + return irq; + } + + /* unlikely, but be prepared */ + return -1; +} + +unsigned long +txn_alloc_addr(int virt_irq) +{ + struct cpuinfo_parisc *dev = (struct cpuinfo_parisc *) (irq_region[IRQ_REGION(virt_irq)]->data.dev); + + if (0==dev) { + printk(KERN_ERR "txn_alloc_addr(0x%x): CPU IRQ region? dev %p\n", + virt_irq,dev); + return(0UL); + } + return (dev->txn_addr); +} + + +/* +** The alloc process needs to accept a parameter to accomodate limitations +** of the HW/SW which use these bits: +** Legacy PA I/O (GSC/NIO): 5 bits (architected EIM register) +** V-class (EPIC): 6 bits +** N/L-class/A500: 8 bits (iosapic) +** PCI 2.2 MSI: 16 bits (I think) +** Existing PCI devices: 32-bits (NCR c720/ATM/GigE/HyperFabric) +** +** On the service provider side: +** o PA 1.1 (and PA2.0 narrow mode) 5-bits (width of EIR register) +** o PA 2.0 wide mode 6-bits (per processor) +** o IA64 8-bits (0-256 total) +** +** So a Legacy PA I/O device on a PA 2.0 box can't use all +** the bits supported by the processor...and the N/L-class +** I/O subsystem supports more bits than PA2.0 has. The first +** case is the problem. +*/ +unsigned int +txn_alloc_data(int virt_irq, unsigned int bits_wide) +{ + /* XXX FIXME : bits_wide indicates how wide the transaction + ** data is allowed to be...we may need a different virt_irq + ** if this one won't work. Another reason to index virtual + ** irq's into a table which can manage CPU/IRQ bit seperately. + */ + if (IRQ_OFFSET(virt_irq) > (1 << (bits_wide -1))) + { + panic("Sorry -- didn't allocate valid IRQ for this device\n"); + } + + return(IRQ_OFFSET(virt_irq)); +} + + +/* FIXME: SMP, flags, bottom halves, rest */ +void do_irq(struct irqaction *action, int irq, struct pt_regs * regs) +{ + int cpu = smp_processor_id(); + + irq_enter(cpu, irq); + +#ifdef DEBUG_IRQ + if (irq != TIMER_IRQ) +#endif + DBG_IRQ("do_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq)); + if (action->handler == NULL) + printk(KERN_ERR "No handler for interrupt %d !\n", irq); + + for(; action && action->handler; action = action->next) { + action->handler(irq, action->dev_id, regs); + } + + irq_exit(cpu, irq); + + /* don't need to care about unmasking and stuff */ + do_softirq(); +} + +void do_irq_mask(unsigned long mask, struct irq_region *region, struct pt_regs *regs) +{ + unsigned long bit; + int irq; + int cpu = smp_processor_id(); + +#ifdef DEBUG_IRQ + if (mask != (1L << MAX_CPU_IRQ)) + printk("do_irq_mask %08lx %p %p\n", mask, region, regs); +#endif + + for(bit=(1L<<MAX_CPU_IRQ), irq = 0; mask && bit; bit>>=1, irq++) { + int irq_num; + if(!(bit&mask)) + continue; + + irq_num = region->data.irqbase + irq; + + ++kstat.irqs[cpu][IRQ_FROM_REGION(CPU_IRQ_REGION) | irq]; + if (IRQ_REGION(irq_num) != CPU_IRQ_REGION) + ++kstat.irqs[cpu][irq_num]; + + mask_irq(irq_num); + do_irq(®ion->action[irq], irq_num, regs); + unmask_irq(irq_num); + } +} + +static inline int alloc_irqregion(void) +{ + int irqreg; + + for(irqreg=1; irqreg<=(NR_IRQ_REGS); irqreg++) { + if(irq_region[irqreg] == NULL) + return irqreg; + } + + return 0; +} + +struct irq_region *alloc_irq_region( + int count, struct irq_region_ops *ops, unsigned long flags, + const char *name, void *dev) +{ + struct irq_region *region; + int index; + + index = alloc_irqregion(); + + if((IRQ_REGION(count-1))) + return NULL; + + if (count < IRQ_PER_REGION) { + DBG_IRQ("alloc_irq_region() using minimum of %d irq lines for %s (%d)\n", + IRQ_PER_REGION, name, count); + count = IRQ_PER_REGION; + } + + if(flags & IRQ_REG_MASK) + if(!(ops->mask_irq && ops->unmask_irq)) + return NULL; + + if(flags & IRQ_REG_DIS) + if(!(ops->disable_irq && ops->enable_irq)) + return NULL; + + if((irq_region[index])) + return NULL; + + region = kmalloc(sizeof *region, GFP_ATOMIC); + if(!region) + return NULL; + + region->action = kmalloc(sizeof *region->action * count, GFP_ATOMIC); + if(!region->action) { + kfree(region); + return NULL; + } + memset(region->action, 0, sizeof *region->action * count); + + region->ops = *ops; + region->data.irqbase = IRQ_FROM_REGION(index); + region->data.flags = flags; + region->data.name = name; + region->data.dev = dev; + + irq_region[index] = region; + + return irq_region[index]; +} + + + +/* FIXME: SMP, flags, bottom halves, rest */ + +int request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char * devname, + void *dev_id) +{ + struct irqaction * action; + +#if 0 + printk(KERN_INFO "request_irq(%d, %p, 0x%lx, %s, %p)\n",irq, handler, irqflags, devname, dev_id); +#endif + if(!handler) { + printk(KERN_ERR "request_irq(%d,...): Augh! No handler for irq!\n", + irq); + return -EINVAL; + } + + if ((IRQ_REGION(irq) == 0) || irq_region[IRQ_REGION(irq)] == NULL) { + /* + ** Bug catcher for drivers which use "char" or u8 for + ** the IRQ number. They lose the region number which + ** is in pcidev->irq (an int). + */ + printk(KERN_ERR "%p (%s?) called request_irq with an invalid irq %d\n", + __builtin_return_address(0), devname, irq); + return -EINVAL; + } + + action = &irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)]; + + if(action->handler) { + while(action->next) + action = action->next; + + action->next = kmalloc(sizeof *action, GFP_ATOMIC); + + action = action->next; + } + + if(!action) { + printk(KERN_ERR "request_irq():Augh! No action!\n") ; + return -ENOMEM; + } + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + enable_irq(irq); + return 0; +} + +void free_irq(unsigned int irq, void *dev_id) +{ + struct irqaction *action, **p; + + action = &irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)]; + + if(action->dev_id == dev_id) { + if(action->next == NULL) + action->handler = NULL; + else + memcpy(action, action->next, sizeof *action); + + return; + } + + p = &action->next; + action = action->next; + + for (; (action = *p) != NULL; p = &action->next) { + if (action->dev_id != dev_id) + continue; + + /* Found it - now free it */ + *p = action->next; + kfree(action); + + return; + } + + printk(KERN_ERR "Trying to free free IRQ%d\n",irq); +} + +unsigned long probe_irq_on (void) +{ + return 0; +} + +int probe_irq_off (unsigned long irqs) +{ + return 0; +} + + +void __init init_IRQ(void) +{ +} + +void init_irq_proc(void) +{ +} diff --git a/arch/parisc/kernel/keyboard.c b/arch/parisc/kernel/keyboard.c new file mode 100644 index 000000000..05044db49 --- /dev/null +++ b/arch/parisc/kernel/keyboard.c @@ -0,0 +1,82 @@ +/* + * linux/arch/parisc/kernel/keyboard.c + * + * Alex deVries <adevries@thepuffingroup.com> + * Copyright (1999) The Puffin Group + * Mostly rewritten by Philipp Rumpf <prumpf@tux.org> + * Copyright 2000 Philipp Rumpf + */ + +#include <linux/keyboard.h> +#include <asm/keyboard.h> + +static int def_setkeycode(unsigned int x, unsigned int y) +{ + return 0; +} + +static int def_getkeycode(unsigned int x) +{ + return 0; +} + +static int def_translate(unsigned char scancode, unsigned char *keycode, + char raw) +{ + *keycode = scancode; + + return 1; +} + +static char def_unexpected_up(unsigned char c) +{ + return 128; +} + +static void def_leds(unsigned char leds) +{ +} + +static void def_init_hw(void) +{ +} + +static char def_sysrq_xlate[NR_KEYS]; + +static struct kbd_ops def_kbd_ops = { + setkeycode: def_setkeycode, + getkeycode: def_getkeycode, + translate: def_translate, + unexpected_up: def_unexpected_up, + leds: def_leds, + init_hw: def_init_hw, + + sysrq_key: 0xff, + sysrq_xlate: def_sysrq_xlate, +}; + +struct kbd_ops *kbd_ops = &def_kbd_ops; + +void register_kbd_ops(struct kbd_ops *ops) +{ + if(ops->setkeycode) + kbd_ops->setkeycode = ops->setkeycode; + + if(ops->getkeycode) + kbd_ops->getkeycode = ops->getkeycode; + + if(ops->translate) + kbd_ops->translate = ops->translate; + + if(ops->unexpected_up) + kbd_ops->unexpected_up = ops->unexpected_up; + + if(ops->leds) + kbd_ops->leds = ops->leds; + + if(ops->init_hw) + kbd_ops->init_hw = ops->init_hw; + + kbd_ops->sysrq_key = ops->sysrq_key; + kbd_ops->sysrq_xlate = ops->sysrq_xlate; +} diff --git a/arch/parisc/kernel/lasimap.map b/arch/parisc/kernel/lasimap.map new file mode 100644 index 000000000..2a9ee223c --- /dev/null +++ b/arch/parisc/kernel/lasimap.map @@ -0,0 +1,322 @@ +# HP 712 kernel keymap. This uses 7 modifier combinations. + +keymaps 0-2,4-5,8,12 +# ie, plain, Shift, AltGr, Control, Control+Shift, Alt and Control+Alt + + +# Change the above line into +# keymaps 0-2,4-6,8,12 +# in case you want the entries +# altgr control keycode 83 = Boot +# altgr control keycode 111 = Boot +# below. +# +# In fact AltGr is used very little, and one more keymap can +# be saved by mapping AltGr to Alt (and adapting a few entries): +# keycode 100 = Alt +# +keycode 1 = F9 F19 Console_21 + control keycode 1 = F9 + alt keycode 1 = Console_9 + control alt keycode 1 = Console_9 +keycode 2 = +keycode 3 = F5 F15 Console_17 + control keycode 3 = F5 + alt keycode 3 = Console_5 + control alt keycode 3 = Console_5 +keycode 4 = F3 F13 Console_15 + control keycode 4 = F3 + alt keycode 4 = Console_3 + control alt keycode 4 = Console_3 +keycode 5 = F1 F11 Console_13 + control keycode 5 = F1 + alt keycode 5 = Console_1 + control alt keycode 5 = Console_1 +keycode 6 = F2 F12 Console_14 + control keycode 6 = F2 + alt keycode 6 = Console_2 + control alt keycode 6 = Console_2 +keycode 7 = F12 F12 Console_24 + control keycode 7 = F12 + alt keycode 7 = Console_12 + control alt keycode 7 = Console_12 +keycode 8 = +keycode 9 = F10 F20 Console_22 + control keycode 9 = F10 + alt keycode 9 = Console_10 + control alt keycode 9 = Console_10 +keycode 10 = F8 F18 Console_20 + control keycode 10 = F8 + alt keycode 10 = Console_8 + control alt keycode 10 = Console_8 +keycode 11 = F6 F16 Console_18 + control keycode 11 = F6 + alt keycode 11 = Console_6 + control alt keycode 11 = Console_6 +keycode 12 = F4 F14 Console_16 + control keycode 12 = F4 + alt keycode 12 = Console_4 + control alt keycode 12 = Console_4 +keycode 13 = Tab Tab + alt keycode 13 = Meta_Tab +keycode 14 = grave asciitilde + control keycode 14 = nul + alt keycode 14 = Meta_grave +keycode 15 = +keycode 16 = +keycode 17 = Alt +keycode 18 = Shift +keycode 19 = +keycode 20 = Control +keycode 21 = q +keycode 22 = one exclam exclam +keycode 23 = +keycode 24 = +keycode 25 = +keycode 26 = z +keycode 27 = s +keycode 28 = a + altgr keycode 28 = Hex_A +keycode 29 = w +keycode 30 = two at at +keycode 31 = +keycode 32 = +keycode 33 = c + altgr keycode 46 = Hex_C +keycode 34 = x +keycode 35 = d + altgr keycode 35 = Hex_D +keycode 36 = e + altgr keycode 36 = Hex_E +keycode 37 = four dollar +keycode 38 = three numbersign +keycode 39 = +keycode 40 = +keycode 41 = +keycode 42 = v +keycode 43 = f + altgr keycode 43 = Hex_F +keycode 44 = t +keycode 45 = r +keycode 46 = five percent +keycode 47 = +keycode 48 = +keycode 49 = n +keycode 50 = b + altgr keycode 50 = Hex_B +keycode 51 = h +keycode 52 = g +keycode 53 = y +keycode 54 = six asciicircum +keycode 55 = +keycode 56 = +keycode 57 = +keycode 58 = m +keycode 59 = j +keycode 60 = u +keycode 61 = seven ampersand +keycode 62 = eight asterisk asterisk +keycode 63 = +keycode 64 = +keycode 65 = comma less + alt keycode 65 = Meta_comma +keycode 66 = k +keycode 67 = i +keycode 68 = o +keycode 69 = zero parenright bracketright +keycode 70 = nine parenleft bracketleft +keycode 71 = +keycode 72 = +keycode 73 = period greater + control keycode 73 = Compose + alt keycode 73 = Meta_period +keycode 74 = slash question + control keycode 74 = Delete + alt keycode 53 = Meta_slash +keycode 75 = l +keycode 76 = semicolon colon + alt keycode 39 = Meta_semicolon +keycode 77 = p +keycode 78 = minus underscore +keycode 79 = +keycode 80 = +keycode 81 = +keycode 82 = apostrophe quotedbl + control keycode 82 = Control_g + alt keycode 40 = Meta_apostrophe +keycode 83 = +keycode 84 = bracketleft braceleft + control keycode 84 = Escape + alt keycode 26 = Meta_bracketleft +keycode 85 = equal plus +keycode 86 = +keycode 87 = +keycode 88 = Caps_Lock +keycode 88 = +keycode 89 = +keycode 89 = +keycode 89 = +keycode 90 = Return + alt keycode 90 = Meta_Control_m +keycode 91 = bracketright braceright asciitilde + control keycode 91 = Control_bracketright + alt keycode 91 = Meta_bracketright +keycode 92 = +keycode 93 = backslash bar + control keycode 43 = Control_backslash + alt keycode 43 = Meta_backslash +keycode 94 = +keycode 95 = +keycode 96 = +keycode 97 = +keycode 98 = +keycode 99 = +keycode 100 = +keycode 101 = +keycode 102 = BackSpace +keycode 103 = +keycode 104 = +keycode 105 = KP_1 + alt keycode 105 = Ascii_1 + altgr keycode 105 = Hex_1 +keycode 106 = +keycode 107 = KP_4 + alt keycode 107 = Ascii_4 + altgr keycode 107 = Hex_4 +keycode 108 = KP_7 + alt keycode 108 = Ascii_7 + altgr keycode 108 = Hex_7 +keycode 109 = +keycode 110 = +keycode 111 = +keycode 112 = KP_0 + alt keycode 82 = Ascii_0 + altgr keycode 82 = Hex_0 +keycode 113 = KP_Period +keycode 114 = KP_2 + alt keycode 114 = Ascii_2 + altgr keycode 114 = Hex_2 +keycode 115 = KP_5 + alt keycode 115 = Ascii_5 + altgr keycode 115 = Hex_5 +keycode 116 = KP_6 + alt keycode 116 = Ascii_6 + altgr keycode 116 = Hex_6 +keycode 117 = KP_8 + alt keycode 117 = Ascii_8 + altgr keycode 117 = Hex_8 +keycode 118 = Escape +keycode 119 = +keycode 120 = F11 +keycode 121 = KP_Add +keycode 122 = KP_3 + alt keycode 122 = Ascii_3 + altgr keycode 122 = Hex_3 +keycode 123 = KP_Subtract +keycode 124 = KP_Multiply +keycode 125 = KP_9 + alt keycode 125 = Ascii_9 + altgr keycode 125 = Hex_9 +keycode 126 = +# 131!! +keycode 127 = F7 F17 Console_19 + control keycode 127 = F7 + alt keycode 127 = Console_7 + control alt keycode 127 = Console_7 + +string F1 = "\033[[A" +string F2 = "\033[[B" +string F3 = "\033[[C" +string F4 = "\033[[D" +string F5 = "\033[[E" +string F6 = "\033[17~" +string F7 = "\033[18~" +string F8 = "\033[19~" +string F9 = "\033[20~" +string F10 = "\033[21~" +string F11 = "\033[23~" +string F12 = "\033[24~" +string F13 = "\033[25~" +string F14 = "\033[26~" +string F15 = "\033[28~" +string F16 = "\033[29~" +string F17 = "\033[31~" +string F18 = "\033[32~" +string F19 = "\033[33~" +string F20 = "\033[34~" +string Find = "\033[1~" +string Insert = "\033[2~" +string Remove = "\033[3~" +string Select = "\033[4~" +string Prior = "\033[5~" +string Next = "\033[6~" +string Macro = "\033[M" +string Pause = "\033[P" +compose '`' 'A' to 'À' +compose '`' 'a' to 'à' +compose '\'' 'A' to 'Á' +compose '\'' 'a' to 'á' +compose '^' 'A' to 'Â' +compose '^' 'a' to 'â' +compose '~' 'A' to 'Ã' +compose '~' 'a' to 'ã' +compose '"' 'A' to 'Ä' +compose '"' 'a' to 'ä' +compose 'O' 'A' to 'Å' +compose 'o' 'a' to 'å' +compose '0' 'A' to 'Å' +compose '0' 'a' to 'å' +compose 'A' 'A' to 'Å' +compose 'a' 'a' to 'å' +compose 'A' 'E' to 'Æ' +compose 'a' 'e' to 'æ' +compose ',' 'C' to 'Ç' +compose ',' 'c' to 'ç' +compose '`' 'E' to 'È' +compose '`' 'e' to 'è' +compose '\'' 'E' to 'É' +compose '\'' 'e' to 'é' +compose '^' 'E' to 'Ê' +compose '^' 'e' to 'ê' +compose '"' 'E' to 'Ë' +compose '"' 'e' to 'ë' +compose '`' 'I' to 'Ì' +compose '`' 'i' to 'ì' +compose '\'' 'I' to 'Í' +compose '\'' 'i' to 'í' +compose '^' 'I' to 'Î' +compose '^' 'i' to 'î' +compose '"' 'I' to 'Ï' +compose '"' 'i' to 'ï' +compose '-' 'D' to 'Ð' +compose '-' 'd' to 'ð' +compose '~' 'N' to 'Ñ' +compose '~' 'n' to 'ñ' +compose '`' 'O' to 'Ò' +compose '`' 'o' to 'ò' +compose '\'' 'O' to 'Ó' +compose '\'' 'o' to 'ó' +compose '^' 'O' to 'Ô' +compose '^' 'o' to 'ô' +compose '~' 'O' to 'Õ' +compose '~' 'o' to 'õ' +compose '"' 'O' to 'Ö' +compose '"' 'o' to 'ö' +compose '/' 'O' to 'Ø' +compose '/' 'o' to 'ø' +compose '`' 'U' to 'Ù' +compose '`' 'u' to 'ù' +compose '\'' 'U' to 'Ú' +compose '\'' 'u' to 'ú' +compose '^' 'U' to 'Û' +compose '^' 'u' to 'û' +compose '"' 'U' to 'Ü' +compose '"' 'u' to 'ü' +compose '\'' 'Y' to 'Ý' +compose '\'' 'y' to 'ý' +compose 'T' 'H' to 'Þ' +compose 't' 'h' to 'þ' +compose 's' 's' to 'ß' +compose '"' 'y' to 'ÿ' +compose 's' 'z' to 'ß' +compose 'i' 'j' to 'ÿ' diff --git a/arch/parisc/kernel/lba_pci.c b/arch/parisc/kernel/lba_pci.c new file mode 100644 index 000000000..6096d0153 --- /dev/null +++ b/arch/parisc/kernel/lba_pci.c @@ -0,0 +1,1346 @@ +/* +** PCI Lower Bus Adapter (LBA) manager +** +** (c) Copyright 1999,2000 Grant Grundler +** (c) Copyright 1999,2000 Hewlett-Packard Company +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** +** This module primarily provides access to PCI bus (config/IOport +** spaces) on platforms with an SBA/LBA chipset. A/B/C/J/L/N-class +** with 4 digit model numbers - eg C3000 (and A400...sigh). +** +** LBA driver isn't as simple as the Dino driver because: +** (a) this chip has substantial bug fixes between revisions +** (Only one Dino bug has a software workaround :^( ) +** (b) has more options which we don't (yet) support (DMA hints, OLARD) +** (c) IRQ support lives in the I/O SAPIC driver (not with PCI driver) +** (d) play nicely with both PAT and "Legacy" PA-RISC firmware (PDC). +** (dino only deals with "Legacy" PDC) +** +** LBA driver passes the I/O SAPIC HPA to the I/O SAPIC driver. +** (I/O SAPIC is integratd in the LBA chip). +** +** FIXME: Add support to SBA and LBA drivers for DMA hint sets +** FIXME: Add support for PCI card hot-plug (OLARD). +*/ + +#include <linux/delay.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/init.h> /* for __init and __devinit */ +#include <linux/pci.h> +#include <linux/ioport.h> +#include <linux/malloc.h> +#include <linux/smp_lock.h> + +#include <asm/byteorder.h> +#include <asm/irq.h> /* for struct irq_region support */ +#include <asm/pdc.h> +#include <asm/pdcpat.h> +#include <asm/page.h> +#include <asm/segment.h> +#include <asm/system.h> + +#include <asm/hardware.h> /* for register_driver() stuff */ +#include <asm/iosapic.h> /* for iosapic_register() */ +#include <asm/gsc.h> /* gsc_read/write stuff */ + + +#ifndef TRUE +#define TRUE (1 == 1) +#define FALSE (1 == 0) +#endif + +#undef DEBUG_LBA /* general stuff */ +#undef DEBUG_LBA_PORT /* debug I/O Port access */ +#undef DEBUG_LBA_CFG /* debug Config Space Access (ie PCI Bus walk) */ +#undef DEBUG_LBA_PAT /* debug PCI Resource Mgt code - PDC PAT only */ + +#ifdef DEBUG_LBA +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +#ifdef DEBUG_LBA_PORT +#define DBG_PORT(x...) printk(x) +#else +#define DBG_PORT(x...) +#endif + +#ifdef DEBUG_LBA_CFG +#define DBG_CFG(x...) printk(x) +#else +#define DBG_CFG(x...) +#endif + +#ifdef DEBUG_LBA_PAT +#define DBG_PAT(x...) printk(x) +#else +#define DBG_PAT(x...) +#endif + +/* +** Config accessor functions only pass in the 8-bit bus number and not +** the 8-bit "PCI Segment" number. Each LBA will be assigned a PCI bus +** number based on what firmware wrote into the scratch register. +** +** The "secondary" bus number is set to this before calling +** pci_register_ops(). If any PPB's are present, the scan will +** discover them and update the "secondary" and "subordinate" +** fields in the pci_bus structure. +** +** Changes in the configuration *may* result in a different +** bus number for each LBA depending on what firmware does. +*/ + +#define MODULE_NAME "lba" + +static int lba_driver_callback(struct hp_device *, struct pa_iodc_driver *); + + +static struct pa_iodc_driver lba_drivers_for[]= { + + {HPHW_BRIDGE, 0x782, 0x0, 0xa, 0,0, + DRIVER_CHECK_HVERSION + + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + MODULE_NAME, "tbd", (void *) lba_driver_callback}, + + {0,0,0,0,0,0, + 0, + (char *) NULL, (char *) NULL, (void *) NULL} +}; + + +#define LBA_FUNC_ID 0x0000 /* function id */ +#define LBA_FCLASS 0x0008 /* function class, bist, header, rev... */ +#define LBA_CAPABLE 0x0030 /* capabilities register */ + +#define LBA_PCI_CFG_ADDR 0x0040 /* poke CFG address here */ +#define LBA_PCI_CFG_DATA 0x0048 /* read or write data here */ + +#define LBA_PMC_MTLT 0x0050 /* Firmware sets this - read only. */ +#define LBA_FW_SCRATCH 0x0058 /* Firmware writes the PCI bus number here. */ +#define LBA_ERROR_ADDR 0x0070 /* On error, address gets logged here */ + +#define LBA_ARB_MASK 0x0080 /* bit 0 enable arbitration. PAT/PDC enables */ +#define LBA_ARB_PRI 0x0088 /* firmware sets this. */ +#define LBA_ARB_MODE 0x0090 /* firmware sets this. */ +#define LBA_ARB_MTLT 0x0098 /* firmware sets this. */ + +#define LBA_MOD_ID 0x0100 /* Module ID. PDC_PAT_CELL reports 4 */ + +#define LBA_STAT_CTL 0x0108 /* Status & Control */ +#define HF_ENABLE 0x40 /* enable HF mode (default is -1 mode) */ + +#define LBA_LMMIO_BASE 0x0200 /* < 4GB I/O address range */ +#define LBA_LMMIO_MASK 0x0208 + +#define LBA_GMMIO_BASE 0x0210 /* > 4GB I/O address range */ +#define LBA_GMMIO_MASK 0x0218 + +#define LBA_WLMMIO_BASE 0x0220 /* All < 4GB ranges under the same *SBA* */ +#define LBA_WLMMIO_MASK 0x0228 + +#define LBA_WGMMIO_BASE 0x0230 /* All > 4GB ranges under the same *SBA* */ +#define LBA_WGMMIO_MASK 0x0238 + +#define LBA_IOS_BASE 0x0240 /* I/O port space for this LBA */ +#define LBA_IOS_MASK 0x0248 + +#define LBA_ELMMIO_BASE 0x0250 /* Extra LMMIO range */ +#define LBA_ELMMIO_MASK 0x0258 + +#define LBA_EIOS_BASE 0x0260 /* Extra I/O port space */ +#define LBA_EIOS_MASK 0x0268 + +#define LBA_DMA_CTL 0x0278 /* firmware sets this */ + +/* RESET: ignore DMA stuff until we can measure performance */ +#define LBA_IBASE 0x0300 /* DMA support */ +#define LBA_IMASK 0x0308 +#define LBA_HINT_CFG 0x0310 +#define LBA_HINT_BASE 0x0380 /* 14 registers at every 8 bytes. */ + +/* ERROR regs are needed for config cycle kluges */ +#define LBA_ERROR_CONFIG 0x0680 +#define LBA_ERROR_STATUS 0x0688 + +#define LBA_IOSAPIC_BASE 0x800 /* Offset of IRQ logic */ + +/* non-postable I/O port space, densely packed */ +#ifdef __LP64__ +#define LBA_ASTRO_PORT_BASE (0xfffffffffee00000UL) +#else +#define LBA_ASTRO_PORT_BASE (0xfee00000UL) +#endif + + +/* +** lba_device: Per instance Elroy data structure +*/ +struct lba_device { + struct pci_hba_data hba; + + spinlock_t lba_lock; + void *iosapic_obj; + +#ifdef __LP64__ + unsigned long lmmio_base; /* PA_VIEW - fixup MEM addresses */ + unsigned long gmmio_base; /* PA_VIEW - Not used (yet) */ + unsigned long iop_base; /* PA_VIEW - for IO port accessor funcs */ +#endif + + int flags; /* state/functionality enabled */ + int hw_rev; /* HW revision of chip */ +}; + + +static u32 lba_t32; + +/* +** lba "flags" +*/ +#define LBA_FLAG_NO_DMA_DURING_CFG 0x01 +#define LBA_FLAG_SKIP_PROBE 0x10 + +/* Tape Release 4 == hw_rev 5 */ +#define LBA_TR4PLUS(d) ((d)->hw_rev > 0x4) +#define LBA_DMA_DURING_CFG_DISABLED(d) ((d)->flags & LBA_FLAG_NO_DMA_DURING_CFG) +#define LBA_SKIP_PROBE(d) ((d)->flags & LBA_FLAG_SKIP_PROBE) + + +/* Looks nice and keeps the compiler happy */ +#define LBA_DEV(d) ((struct lba_device *) (d)) + + +/* +** Only allow 8 subsidiary busses per LBA +** Problem is the PCI bus numbering is globally shared. +*/ +#define LBA_MAX_NUM_BUSES 8 + +/************************************ + * LBA register read and write support + * + * BE WARNED: register writes are posted. + * (ie follow writes which must reach HW with a read) + */ +#define READ_U8(addr) gsc_readb(addr) +#define READ_U16(addr) gsc_readw((u16 *) (addr)) +#define READ_U32(addr) gsc_readl((u32 *) (addr)) +#define WRITE_U8(value, addr) gsc_writeb(value, addr) +#define WRITE_U16(value, addr) gsc_writew(value, (u16 *) (addr)) +#define WRITE_U32(value, addr) gsc_writel(value, (u32 *) (addr)) + +#define READ_REG8(addr) gsc_readb(addr) +#define READ_REG16(addr) le16_to_cpu(gsc_readw((u16 *) (addr))) +#define READ_REG32(addr) le32_to_cpu(gsc_readl((u32 *) (addr))) +#define WRITE_REG8(value, addr) gsc_writeb(value, addr) +#define WRITE_REG16(value, addr) gsc_writew(cpu_to_le16(value), (u16 *) (addr)) +#define WRITE_REG32(value, addr) gsc_writel(cpu_to_le32(value), (u32 *) (addr)) + + +#define LBA_CFG_TOK(bus,dfn) ((u32) ((bus)<<16 | (dfn)<<8)) +#define LBA_CFG_BUS(tok) ((u8) ((tok)>>16)) +#define LBA_CFG_DEV(tok) ((u8) ((tok)>>11) & 0x1f) +#define LBA_CFG_FUNC(tok) ((u8) ((tok)>>8 ) & 0x7) + + +#ifdef DEBUG_LBA +/* Extract LBA (Rope) number from HPA */ +#define LBA_NUM(x) ((((uintptr_t) x) >> 13) & 0xf) +#endif /* DEBUG_LBA */ + +#ifdef __LP64__ +/* PDC_PAT */ +static unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0}; +#endif + +/* +** One time initialization to let the world know the LBA was found. +** This is the only routine which is NOT static. +** Must be called exactly once before pci_init(). +*/ +void __init lba_init(void) +{ + register_driver(lba_drivers_for); +} + + +static void +lba_dump_res(struct resource *r, int d) +{ + int i; + + if (NULL == r) + return; + + printk("(%p)", r->parent); + for (i = d; i ; --i) printk(" "); + printk("%p [%lx,%lx]/%x\n", r, r->start, r->end, (int) r->flags); + lba_dump_res(r->child, d+2); + lba_dump_res(r->sibling, d); +} + + +/* +** LBA rev 2.0, 2.1, 2.2, and 3.0 bus walks require a complex +** workaround for cfg cycles: +** -- preserve LBA state +** -- LBA_FLAG_NO_DMA_DURING_CFG workaround +** -- turn on smart mode +** -- probe with config writes before doing config reads +** -- check ERROR_STATUS +** -- clear ERROR_STATUS +** -- restore LBA state +** +** The workaround is only used for device discovery. +*/ + +static int +lba_device_present( u8 bus, u8 dfn, struct lba_device *d) +{ + u8 first_bus = d->hba.hba_bus->secondary; + u8 last_sub_bus = d->hba.hba_bus->subordinate; +#if 0 +/* FIXME - see below in this function */ + u8 dev = PCI_SLOT(dfn); + u8 func = PCI_FUNC(dfn); +#endif + + ASSERT(bus >= first_bus); + ASSERT(bus <= last_sub_bus); + ASSERT((bus - first_bus) < LBA_MAX_NUM_BUSES); + + if ((bus < first_bus) || + (bus > last_sub_bus) || + ((bus - first_bus) >= LBA_MAX_NUM_BUSES)) + { + /* devices that fall into any of these cases won't get claimed */ + return(FALSE); + } + +#if 0 +/* +** FIXME: Need to implement code to fill the devices bitmap based +** on contents of the local pci_bus tree "data base". +** pci_register_ops() walks the bus for us and builds the tree. +** For now, always do the config cycle. +*/ + bus -= first_bus; + + return (((d->devices[bus][dev]) >> func) & 0x1); +#else + return TRUE; +#endif +} + + + +#define LBA_CFG_SETUP(d, tok) { \ + /* Save contents of error config register. */ \ + error_config = READ_REG32(d->hba.base_addr + LBA_ERROR_CONFIG); \ +\ + /* Save contents of status control register. */ \ + status_control = READ_REG32(d->hba.base_addr + LBA_STAT_CTL); \ +\ + /* For LBA rev 2.0, 2.1, 2.2, and 3.0, we must disable DMA \ + ** arbitration for full bus walks. \ + */ \ + if (LBA_DMA_DURING_CFG_DISABLED(d)) { \ + /* Save contents of arb mask register. */ \ + arb_mask = READ_REG32(d->hba.base_addr + LBA_ARB_MASK); \ +\ + /* \ + * Turn off all device arbitration bits (i.e. everything \ + * except arbitration enable bit). \ + */ \ + WRITE_REG32(0x1, d->hba.base_addr + LBA_ARB_MASK); \ + } \ +\ + /* \ + * Set the smart mode bit so that master aborts don't cause \ + * LBA to go into PCI fatal mode (required). \ + */ \ + WRITE_REG32(error_config | 0x20, d->hba.base_addr + LBA_ERROR_CONFIG); \ +} + + +#define LBA_CFG_PROBE(d, tok) { \ + /* \ + * Setup Vendor ID write and read back the address register \ + * to make sure that LBA is the bus master. \ + */ \ + WRITE_REG32(tok | PCI_VENDOR_ID, (d)->hba.base_addr + LBA_PCI_CFG_ADDR);\ + /* \ + * Read address register to ensure that LBA is the bus master, \ + * which implies that DMA traffic has stopped when DMA arb is off. \ + */ \ + lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR); \ + /* \ + * Generate a cfg write cycle (will have no affect on \ + * Vendor ID register since read-only). \ + */ \ + WRITE_REG32(~0, (d)->hba.base_addr + LBA_PCI_CFG_DATA); \ + /* \ + * Make sure write has completed before proceeding further, \ + * i.e. before setting clear enable. \ + */ \ + lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR); \ +} + + +/* + * HPREVISIT: + * -- Can't tell if config cycle got the error. + * + * OV bit is broken until rev 4.0, so can't use OV bit and + * LBA_ERROR_LOG_ADDR to tell if error belongs to config cycle. + * + * As of rev 4.0, no longer need the error check. + * + * -- Even if we could tell, we still want to return -1 + * for **ANY** error (not just master abort). + * + * -- Only clear non-fatal errors (we don't want to bring + * LBA out of pci-fatal mode). + * + * Actually, there is still a race in which + * we could be clearing a fatal error. We will + * live with this during our real mode bus walk + * until rev 4.0 (no driver activity during + * real mode bus walk). The real mode bus walk + * has race conditions concerning the use of + * smart mode as well. + */ + +#define LBA_MASTER_ABORT_ERROR 0xc +#define LBA_FATAL_ERROR 0x10 + +#define LBA_CFG_MASTER_ABORT_CHECK(d, base, tok, error) { \ + u32 error_status = 0; \ + /* \ + * Set clear enable (CE) bit. Unset by HW when new \ + * errors are logged -- LBA HW ERS section 14.3.3). \ + */ \ + WRITE_REG32(status_control | 0x20, base + LBA_STAT_CTL); \ + error_status = READ_REG32(base + LBA_ERROR_STATUS); \ + if ((error_status & 0x1f) != 0) { \ + /* \ + * Fail the config read request. \ + */ \ + error = 1; \ + if ((error_status & LBA_FATAL_ERROR) == 0) { \ + /* \ + * Clear error status (if fatal bit not set) by setting \ + * clear error log bit (CL). \ + */ \ + WRITE_REG32(status_control | 0x10, base + LBA_STAT_CTL); \ + } \ + } \ +} + +#define LBA_CFG_TR4_ADDR_SETUP(d, addr) \ + WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR) + +#define LBA_CFG_ADDR_SETUP(d, addr) { \ + WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR); \ + /* \ + * HPREVISIT: \ + * -- Potentially could skip this once DMA bug fixed. \ + * \ + * Read address register to ensure that LBA is the bus master, \ + * which implies that DMA traffic has stopped when DMA arb is off. \ + */ \ + lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR); \ +} + + +#define LBA_CFG_RESTORE(d, base) { \ + /* \ + * Restore status control register (turn off clear enable). \ + */ \ + WRITE_REG32(status_control, base + LBA_STAT_CTL); \ + /* \ + * Restore error config register (turn off smart mode). \ + */ \ + WRITE_REG32(error_config, base + LBA_ERROR_CONFIG); \ + if (LBA_DMA_DURING_CFG_DISABLED(d)) { \ + /* \ + * Restore arb mask register (reenables DMA arbitration). \ + */ \ + WRITE_REG32(arb_mask, base + LBA_ARB_MASK); \ + } \ +} + + + +static unsigned int +lba_rd_cfg( struct lba_device *d, u32 tok, u8 reg, u32 size) +{ + u32 data = ~0; + int error = 0; + u32 arb_mask = 0; /* used by LBA_CFG_SETUP/RESTORE */ + u32 error_config = 0; /* used by LBA_CFG_SETUP/RESTORE */ + u32 status_control = 0; /* used by LBA_CFG_SETUP/RESTORE */ + + ASSERT((size == sizeof(u8)) || + (size == sizeof(u16)) || + (size == sizeof(u32))); + + if ((size != sizeof(u8)) && + (size != sizeof(u16)) && + (size != sizeof(u32))) { + return(data); + } + + LBA_CFG_SETUP(d, tok); + LBA_CFG_PROBE(d, tok); + LBA_CFG_MASTER_ABORT_CHECK(d, d->hba.base_addr, tok, error); + if (!error) { + LBA_CFG_ADDR_SETUP(d, tok | reg); + switch (size) { + case sizeof(u8): + data = (u32) READ_REG8(d->hba.base_addr + LBA_PCI_CFG_DATA + (reg & 3)); + break; + case sizeof(u16): + data = (u32) READ_REG16(d->hba.base_addr + LBA_PCI_CFG_DATA + (reg & 2)); + break; + case sizeof(u32): + data = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_DATA); + break; + default: + break; /* leave data as -1 */ + } + } + LBA_CFG_RESTORE(d, d->hba.base_addr); + return(data); +} + + + +#define LBA_CFG_RD(size, mask) \ +static int lba_cfg_read##size (struct pci_dev *dev, int pos, u##size *data) \ +{ \ + struct lba_device *d = LBA_DEV(dev->bus->sysdata); \ + u32 local_bus = (dev->bus->parent == NULL) ? 0 : dev->bus->secondary; \ + u32 tok = LBA_CFG_TOK(local_bus,dev->devfn); \ + \ + if ((!LBA_TR4PLUS(d)) && (!LBA_SKIP_PROBE(d))) { \ + /* original - Generate config cycle on broken elroy \ + with risk we will miss PCI bus errors. */ \ + *data = (u##size) lba_rd_cfg(d, tok, pos, sizeof(u##size)); \ + DBG_CFG(KERN_DEBUG "%s(%s+%2x) -> 0x%x (a)\n", __FUNCTION__, dev->slot_name, pos, *data); \ + return(*data == (u##size) -1); \ + } \ + \ + if (LBA_SKIP_PROBE(d) && (!lba_device_present(dev->bus->secondary, dev->devfn, d))) \ + { \ + DBG_CFG(KERN_DEBUG "%s(%s+%2x) -> -1 (b)\n", __FUNCTION__, dev->slot_name, pos, *data); \ + /* either don't want to look or know device isn't present. */ \ + *data = (u##size) -1; \ + return(0); \ + } \ + \ + /* Basic Algorithm \ + ** Should only get here on fully working LBA rev. \ + ** This is how simple the code should have been. \ + */ \ + LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); \ + *data = READ_REG##size(d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & mask));\ + DBG_CFG(KERN_DEBUG "%s(%s+%2x) -> 0x%x (c)\n", __FUNCTION__, dev->slot_name, pos, *data);\ + return(*data == (u##size) -1); \ +} + +LBA_CFG_RD( 8, 3) +LBA_CFG_RD(16, 2) +LBA_CFG_RD(32, 0) + + + +static void +lba_wr_cfg( struct lba_device *d, u32 tok, u8 reg, u32 data, u32 size) +{ + int error = 0; + u32 arb_mask = 0; + u32 error_config = 0; + u32 status_control = 0; + + ASSERT((size == sizeof(u8)) || + (size == sizeof(u16)) || + (size == sizeof(u32))); + + if ((size != sizeof(u8)) && + (size != sizeof(u16)) && + (size != sizeof(u32))) { + return; + } + + LBA_CFG_SETUP(d, tok); + LBA_CFG_ADDR_SETUP(d, tok | reg); + switch (size) { + case sizeof(u8): + WRITE_REG8((u8) data, d->hba.base_addr + LBA_PCI_CFG_DATA + (reg&3)); + break; + case sizeof(u16): + WRITE_REG16((u8) data, d->hba.base_addr + LBA_PCI_CFG_DATA +(reg&2)); + break; + case sizeof(u32): + WRITE_REG32(data, d->hba.base_addr + LBA_PCI_CFG_DATA); + break; + default: + break; + } + LBA_CFG_MASTER_ABORT_CHECK(d, d->hba.base_addr, tok, error); + LBA_CFG_RESTORE(d, d->hba.base_addr); +} + + +/* + * LBA 4.0 config write code implements non-postable semantics + * by doing a read of CONFIG ADDR after the write. + */ + +#define LBA_CFG_WR(size, mask) \ +static int lba_cfg_write##size (struct pci_dev *dev, int pos, u##size data) \ +{ \ + struct lba_device *d = LBA_DEV(dev->bus->sysdata); \ + u32 local_bus = (dev->bus->parent == NULL) ? 0 : dev->bus->secondary; \ + u32 tok = LBA_CFG_TOK(local_bus,dev->devfn); \ + \ + ASSERT((tok & 0xff) == 0); \ + ASSERT(pos < 0x100); \ + \ + if ((!LBA_TR4PLUS(d)) && (!LBA_SKIP_PROBE(d))) { \ + /* Original Workaround */ \ + lba_wr_cfg(d, tok, pos, (u32) data, sizeof(u##size)); \ + DBG_CFG(KERN_DEBUG "%s(%s+%2x) = 0x%x (a)\n", __FUNCTION__, dev->slot_name, pos, data); \ + return 0; \ + } \ + \ + if (LBA_SKIP_PROBE(d) && (!lba_device_present(dev->bus->secondary, dev->devfn, d))) { \ + DBG_CFG(KERN_DEBUG "%s(%s+%2x) = 0x%x (b)\n", __FUNCTION__, dev->slot_name, pos, data); \ + return 1; /* New Workaround */ \ + } \ + \ + DBG_CFG(KERN_DEBUG "%s(%s+%2x) = 0x%x (c)\n", __FUNCTION__, dev->slot_name, pos, data); \ + /* Basic Algorithm */ \ + LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); \ + WRITE_REG##size(data, d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & mask)); \ + lba_t32 = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_ADDR); \ + return 0; \ +} + + +LBA_CFG_WR( 8, 3) +LBA_CFG_WR(16, 2) +LBA_CFG_WR(32, 0) + +static struct pci_ops lba_cfg_ops = { + lba_cfg_read8, lba_cfg_read16, lba_cfg_read32, + lba_cfg_write8, lba_cfg_write16, lba_cfg_write32 + +}; + + + +static void +lba_bios_init(void) +{ + DBG(KERN_DEBUG MODULE_NAME ": lba_bios_init\n"); +} + + +#ifdef __LP64__ + +/* +** Determine if a device is already configured. +** If so, reserve it resources. +** +** Read PCI cfg command register and see if I/O or MMIO is enabled. +** PAT has to enable the devices it's using. +** +** Note: resources are fixed up before we try to claim them. +*/ +static void +lba_claim_dev_resources(struct pci_dev *dev) +{ + u16 cmd; + int i, srch_flags; + + (void) lba_cfg_read16(dev, PCI_COMMAND, &cmd); + + srch_flags = (cmd & PCI_COMMAND_IO) ? IORESOURCE_IO : 0; + if (cmd & PCI_COMMAND_MEMORY) + srch_flags |= IORESOURCE_MEM; + + if (!srch_flags) + return; + + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { + if (dev->resource[i].flags & srch_flags) { + pci_claim_resource(dev, i); + DBG(" claimed %s %d [%lx,%lx]/%x\n", + dev->slot_name, i, + dev->resource[i].start, + dev->resource[i].end, + (int) dev->resource[i].flags + ); + } + } +} +#endif + + +/* +** The algorithm is generic code. +** But it needs to access local data structures to get the IRQ base. +** Could make this a "pci_fixup_irq(bus, region)" but not sure +** it's worth it. +** +** Called by do_pci_scan_bus() immediately after each PCI bus is walked. +** Resources aren't allocated until recursive buswalk below HBA is completed. +*/ +static void +lba_fixup_bus(struct pci_bus *bus) +{ + struct list_head *ln; + struct pci_dev *dev; + u16 fbb_enable = PCI_STATUS_FAST_BACK; + u16 status; + struct lba_device *ldev = LBA_DEV(bus->sysdata); +#ifdef __LP64__ + int i; +#endif + DBG("lba_fixup_bus(0x%p) bus %d sysdata 0x%p\n", + bus, bus->secondary, bus->sysdata); + + /* + ** Properly Setup MMIO resources for this bus. + ** pci_alloc_primary_bus() mangles this. + */ + if (NULL == bus->self) { + int err; + + DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n", + ldev->hba.io_space.name, + ldev->hba.io_space.start, + ldev->hba.io_space.end, + (int) ldev->hba.io_space.flags); + DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n", + ldev->hba.mem_space.name, + ldev->hba.mem_space.start, + ldev->hba.mem_space.end, + (int) ldev->hba.mem_space.flags); + + err = request_resource(&ioport_resource, &(ldev->hba.io_space)); + if (err < 0) { + BUG(); + lba_dump_res(&ioport_resource, 2); + } + err = request_resource(&iomem_resource, &(ldev->hba.mem_space)); + if (err < 0) { + BUG(); + lba_dump_res(&iomem_resource, 2); + } + + bus->resource[0] = &(ldev->hba.io_space); + bus->resource[1] = &(ldev->hba.mem_space); + } + + list_for_each(ln, &bus->devices) { + + dev = pci_dev_b(ln); + +#ifdef __LP64__ + /* + ** 0-5 are the "standard PCI regions" + ** (see comments near PCI_NUM_RESOURCES in include/linux/pci.h) + */ + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { + struct resource *res = &(dev->resource[i]); + + if (res->flags & IORESOURCE_MEM) { + /* "Globalize" PCI address */ + res->start |= ldev->lmmio_base; + res->end |= ldev->lmmio_base; + } + } +#endif + + /* + ** If one device does not support FBB transfers, + ** No one on the bus can be allowed to use them. + */ + (void) lba_cfg_read16(dev, PCI_STATUS, &status); + fbb_enable &= status; + +#ifdef __LP64__ + if (pdc_pat) { + /* Claim resources for PDC's devices */ + lba_claim_dev_resources(dev); + } +#endif /* __LP64__ */ + + /* + ** P2PB's have no IRQs. ignore them. + */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) + continue; + + /* Adjust INTERRUPT_LINE for this dev */ + iosapic_fixup_irq(LBA_DEV(bus->sysdata)->iosapic_obj, dev); + } + +#if 0 +/* FIXME/REVISIT - finish figuring out to set FBB on both +** pbus_set_ranges() clobbers PCI_BRIDGE_CONTROL. +** Can't fixup here anyway....garr... +*/ + if (fbb_enable) { + if (bus->self) { + u8 control; + /* enable on PPB */ + (void) lba_cfg_read8(bus->self, PCI_BRIDGE_CONTROL, &control); + (void) lba_cfg_write8(bus->self, PCI_BRIDGE_CONTROL, control | PCI_STATUS_FAST_BACK); + + } else { + /* enable on LBA */ + } + fbb_enable = PCI_COMMAND_FAST_BACK; + } + + /* Lastly enable FBB/PERR/SERR on all devices too */ + list_for_each(ln, &bus->devices) { + (void) lba_cfg_read16(dev, PCI_COMMAND, &status); + status |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR | fbb_enable; + (void) lba_cfg_write16(dev, PCI_COMMAND, status); + } +#endif +} + + +struct pci_bios_ops lba_bios_ops = { + lba_bios_init, + lba_fixup_bus /* void lba_fixup_bus(struct pci_bus *bus) */ +}; + + + + +/******************************************************* +** +** LBA Sprockets "I/O Port" Space Accessor Functions +** +** This set of accessor functions is intended for use with +** "legacy firmware" (ie Sprockets on Allegro/Forte boxes). +** +** Many PCI devices don't require use of I/O port space (eg Tulip, +** NCR720) since they export the same registers to both MMIO and +** I/O port space. In general I/O port space is slower than +** MMIO since drivers are designed so PIO writes can be posted. +** +********************************************************/ + +#define LBA_PORT_IN(size, mask) \ +static u##size lba_astro_in##size (struct pci_hba_data *d, u16 addr) \ +{ \ + u##size t; \ + ASSERT(bus != NULL); \ + DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x) ->", __FUNCTION__, bus, addr); \ + t = READ_REG##size(LBA_ASTRO_PORT_BASE + addr); \ + DBG_PORT(" 0x%x\n", t); \ + return (t); \ +} + +LBA_PORT_IN( 8, 3) +LBA_PORT_IN(16, 2) +LBA_PORT_IN(32, 0) + + + +/* +** BUG X4107: Ordering broken - DMA RD return can bypass PIO WR +** +** Fixed in Elroy 2.2. The READ_U32(..., LBA_FUNC_ID) below is +** guarantee non-postable completion semantics - not avoid X4107. +** The READ_U32 only guarantees the write data gets to elroy but +** out to the PCI bus. We can't read stuff from I/O port space +** since we don't know what has side-effects. Attempting to read +** from configuration space would be suicidal given the number of +** bugs in that elroy functionality. +** +** Description: +** DMA read results can improperly pass PIO writes (X4107). The +** result of this bug is that if a processor modifies a location in +** memory after having issued PIO writes, the PIO writes are not +** guaranteed to be completed before a PCI device is allowed to see +** the modified data in a DMA read. +** +** Note that IKE bug X3719 in TR1 IKEs will result in the same +** symptom. +** +** Workaround: +** The workaround for this bug is to always follow a PIO write with +** a PIO read to the same bus before starting DMA on that PCI bus. +** +*/ +#define LBA_PORT_OUT(size, mask) \ +static void lba_astro_out##size (struct pci_hba_data *d, u16 addr, u##size val) \ +{ \ + ASSERT(bus != NULL); \ + DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, d, addr, val); \ + WRITE_REG##size(val, LBA_ASTRO_PORT_BASE + addr); \ + if (LBA_DEV(d)->hw_rev < 3) \ + lba_t32 = READ_U32(d->base_addr + LBA_FUNC_ID); \ +} + +LBA_PORT_OUT( 8, 3) +LBA_PORT_OUT(16, 2) +LBA_PORT_OUT(32, 0) + + +static struct pci_port_ops lba_astro_port_ops = { + lba_astro_in8, lba_astro_in16, lba_astro_in32, + lba_astro_out8, lba_astro_out16, lba_astro_out32 +}; + + +#ifdef __LP64__ + +#define PIOP_TO_GMMIO(lba, addr) \ + ((lba)->iop_base + (((addr)&0xFFFC)<<10) + ((addr)&3)) + +/******************************************************* +** +** LBA PAT "I/O Port" Space Accessor Functions +** +** This set of accessor functions is intended for use with +** "PAT PDC" firmware (ie Prelude/Rhapsody/Piranha boxes). +** +** This uses the PIOP space located in the first 64MB of GMMIO. +** Each rope gets a full 64*KB* (ie 4 bytes per page) this way. +** bits 1:0 stay the same. bits 15:2 become 25:12. +** Then add the base and we can generate an I/O Port cycle. +********************************************************/ +#undef LBA_PORT_IN +#define LBA_PORT_IN(size, mask) \ +static u##size lba_pat_in##size (struct pci_hba_data *l, u16 addr) \ +{ \ + u##size t; \ + ASSERT(bus != NULL); \ + DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x) ->", __FUNCTION__, l, addr); \ + t = READ_REG##size(PIOP_TO_GMMIO(LBA_DEV(l), addr)); \ + DBG_PORT(" 0x%x\n", t); \ + return (t); \ +} + +LBA_PORT_IN( 8, 3) +LBA_PORT_IN(16, 2) +LBA_PORT_IN(32, 0) + + +#undef LBA_PORT_OUT +#define LBA_PORT_OUT(size, mask) \ +static void lba_pat_out##size (struct pci_hba_data *l, u16 addr, u##size val) \ +{ \ + void *where = (void *) PIOP_TO_GMMIO(LBA_DEV(l), addr); \ + ASSERT(bus != NULL); \ + DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, l, addr, val); \ + WRITE_REG##size(val, where); \ + /* flush the I/O down to the elroy at least */ \ + lba_t32 = READ_U32(l->base_addr + LBA_FUNC_ID); \ +} + +LBA_PORT_OUT( 8, 3) +LBA_PORT_OUT(16, 2) +LBA_PORT_OUT(32, 0) + + +static struct pci_port_ops lba_pat_port_ops = { + lba_pat_in8, lba_pat_in16, lba_pat_in32, + lba_pat_out8, lba_pat_out16, lba_pat_out32 +}; + + + +/* +** make range information from PDC available to PCI subsystem. +** We make the PDC call here in order to get the PCI bus range +** numbers. The rest will get forwarded in pcibios_fixup_bus(). +** We don't have a struct pci_bus assigned to us yet. +*/ +static void +lba_pat_resources( struct hp_device *d, struct lba_device *lba_dev) +{ + pdc_pat_cell_mod_maddr_block_t pa_pdc_cell; /* PA_VIEW */ +#ifdef DONT_NEED_THIS_FOR_ASTRO + pdc_pat_cell_mod_maddr_block_t io_pdc_cell; /* IO_VIEW */ + long io_count; +#endif + long status; /* PDC return status */ + long pa_count; + int i; + + /* return cell module (IO view) */ + status = pdc_pat_cell_module(& pdc_result, d->pcell_loc, d->mod_index, + PA_VIEW, & pa_pdc_cell); + pa_count = pa_pdc_cell.mod[1]; + +#ifdef DONT_NEED_THIS_FOR_ASTRO + status |= pdc_pat_cell_module(& pdc_result, d->pcell_loc, d->mod_index, + IO_VIEW, & io_pdc_cell); + io_count = io_pdc_cell.mod[1]; +#endif + + /* We've already done this once for device discovery...*/ + if (status != PDC_RET_OK) { + panic("pdc_pat_cell_module() call failed for LBA!\n"); + } + + if (PAT_GET_ENTITY(pa_pdc_cell.mod_info) != PAT_ENTITY_LBA) { + panic("pdc_pat_cell_module() entity returned != PAT_ENTITY_LBA!\n"); + } + + /* + ** Inspect the resources PAT tells us about + */ + for (i = 0; i < pa_count; i++) { + struct { + unsigned long type; + unsigned long start; + unsigned long end; /* aka finish */ + } *p; + struct resource *r; + + p = (void *) &(pa_pdc_cell.mod[2+i*3]); + + /* Convert the PAT range data to PCI "struct resource" */ + switch(p->type & 0xff) { + case PAT_PBNUM: + lba_dev->hba.bus_num.start = p->start; + lba_dev->hba.bus_num.end = p->end; + break; + case PAT_LMMIO: + /* used to fix up pre-initialized MEM BARs */ + lba_dev->lmmio_base = p->start; + + r = &(lba_dev->hba.mem_space); + r->name = "LBA LMMIO"; + r->start = p->start; + r->end = p->end; + r->flags = IORESOURCE_MEM; + r->parent = r->sibling = r->child = NULL; + break; + case PAT_GMMIO: + printk(KERN_WARNING MODULE_NAME + " range[%d] : ignoring GMMIO (0x%lx)\n", + i, p->start); + lba_dev->gmmio_base = p->start; + break; + case PAT_NPIOP: + printk(KERN_WARNING MODULE_NAME + " range[%d] : ignoring NPIOP (0x%lx)\n", + i, p->start); + break; + case PAT_PIOP: + /* + ** Postable I/O port space is per PCI host adapter. + */ + + /* save base of 64MB PIOP region */ + lba_dev->iop_base = p->start; + + r = &(lba_dev->hba.io_space); + r->name = "LBA I/O Port"; + r->start = lba_dev->hba.hba_num << 16; + r->end = r->start + 0xffffUL; + r->flags = IORESOURCE_IO; + r->parent = r->sibling = r->child = NULL; + break; + default: + printk(KERN_WARNING MODULE_NAME + " range[%d] : unknown pat range type (0x%lx)\n", + i, p->type & 0xff); + break; + } + } +} +#endif /* __LP64__ */ + + +static void +lba_legacy_resources( struct hp_device *d, struct lba_device *lba_dev) +{ + int lba_num; + struct resource *r; +#ifdef __LP64__ + /* + ** Used to sign extend instead BAR values are only 32-bit. + ** 64-bit BARs have the upper 32-bit's zero'd by firmware. + ** "Sprockets" PDC initializes for 32-bit OS. + */ + lba_dev->lmmio_base = 0xffffffff00000000UL; +#endif + + /* + ** With "legacy" firmware, the lowest byte of FW_SCRATCH + ** represents bus->secondary and the second byte represents + ** bus->subsidiary (i.e. highest PPB programmed by firmware). + ** PCI bus walk *should* end up with the same result. + ** FIXME: But we don't have sanity checks in PCI or LBA. + */ + lba_num = READ_REG32(d->hpa + LBA_FW_SCRATCH); + r = &(lba_dev->hba.bus_num); + r->name = "LBA PCI Busses"; + r->start = lba_num & 0xff; + r->end = (lba_num>>8) & 0xff; + + /* Set up local PCI Bus resources - we don't really need + ** them for Legacy boxes but it's nice to see in /proc. + */ + r = &(lba_dev->hba.mem_space); + r->name = "LBA PCI LMMIO"; + r->flags = IORESOURCE_MEM; + r->start = READ_REG32(d->hpa + LBA_LMMIO_BASE); + r->end = r->start + ~ (READ_REG32(d->hpa + LBA_LMMIO_MASK)); + + r = &(lba_dev->hba.io_space); + r->name = "LBA PCI I/O Ports"; + r->flags = IORESOURCE_IO; + r->start = READ_REG32(d->hpa + LBA_IOS_BASE); + r->end = r->start + (READ_REG32(d->hpa + LBA_IOS_MASK) ^ 0xffff); + + lba_num = lba_dev->hba.hba_num << 16; + r->start |= lba_num; + r->end |= lba_num; +} + + +/************************************************************************** +** +** LBA initialization code (HW and SW) +** +** o identify LBA chip itself +** o initialize LBA chip modes (HardFail) +** o FIXME: initialize DMA hints for reasonable defaults +** o enable configuration functions +** o call pci_register_ops() to discover devs (fixup/fixup_bus get invoked) +** +**************************************************************************/ + +static void +lba_hw_init(struct lba_device *d) +{ + u32 stat; + + /* Set HF mode as the default (vs. -1 mode). */ + stat = READ_REG32(d->hba.base_addr + LBA_STAT_CTL); + WRITE_REG32(stat | HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL); + + /* + ** FIXME: Hint registers are programmed with default hint + ** values by firmware. Hints should be sane even if we + ** can't reprogram them the way drivers want. + */ +} + + + +static void +lba_common_init(struct lba_device *lba_dev) +{ + pci_bios = &lba_bios_ops; + pcibios_register_hba((struct pci_hba_data *)lba_dev); + lba_dev->lba_lock = SPIN_LOCK_UNLOCKED; + + /* + ** Set flags which depend on hw_rev + */ + if (!LBA_TR4PLUS(lba_dev)) { + lba_dev->flags |= LBA_FLAG_NO_DMA_DURING_CFG; + } +} + + + +/* +** Determine if lba should claim this chip (return 0) or not (return 1). +** If so, initialize the chip and tell other partners in crime they +** have work to do. +*/ +static __init int +lba_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri) +{ + struct lba_device *lba_dev; + struct pci_bus *lba_bus; + u32 func_class; + void *tmp_obj; + + /* from drivers/pci/setup-bus.c */ + extern void __init pbus_set_ranges(struct pci_bus *, struct pbus_set_ranges_data *); + + /* Read HW Rev First */ + func_class = READ_REG32(d->hpa + LBA_FCLASS); + func_class &= 0xf; + + switch (func_class) { + case 0: dri->version = "TR1.0"; break; + case 1: dri->version = "TR2.0"; break; + case 2: dri->version = "TR2.1"; break; + case 3: dri->version = "TR2.2"; break; + case 4: dri->version = "TR3.0"; break; + case 5: dri->version = "TR4.0"; break; + default: dri->version = "TR4+"; + } + + printk("%s version %s (0x%x) found at 0x%p\n", dri->name, dri->version, func_class & 0xf, d->hpa); + + /* Just in case we find some prototypes... */ + if (func_class < 2) { + printk(KERN_WARNING "Can't support LBA older than TR2.1 " + "- continuing under adversity.\n"); + } + + /* + ** Tell I/O SAPIC driver we have a IRQ handler/region. + */ + tmp_obj = iosapic_register(d->hpa+LBA_IOSAPIC_BASE); + if (NULL == tmp_obj) { + /* iosapic may have failed. But more likely the + ** slot isn't occupied and thus has no IRT entries. + ** iosapic_register looks for this iosapic in the IRT + ** before bothering to allocating data structures + ** we don't need. + */ + DBG(KERN_WARNING MODULE_NAME ": iosapic_register says not used\n"); + return (1); + } + + lba_dev = kmalloc(sizeof(struct lba_device), GFP_KERNEL); + if (NULL == lba_dev) + { + printk("lba_init_chip - couldn't alloc lba_device\n"); + return(1); + } + + memset(lba_dev, 0, sizeof(struct lba_device)); + + + /* ---------- First : initialize data we already have --------- */ + + /* + ** Need hw_rev to adjust configuration space behavior. + ** LBA_TR4PLUS macro uses hw_rev field. + */ + lba_dev->hw_rev = func_class; + + lba_dev->hba.base_addr = d->hpa; /* faster access */ + lba_dev->iosapic_obj = tmp_obj; /* save interrupt handle */ + + /* ------------ Second : initialize common stuff ---------- */ + lba_common_init(lba_dev); + lba_hw_init(lba_dev); + + /* ---------- Third : setup I/O Port and MMIO resources --------- */ +#ifdef __LP64__ + + if (pdc_pat) { + /* PDC PAT firmware uses PIOP region of GMMIO space. */ + pci_port = &lba_pat_port_ops; + + /* Go ask PDC PAT what resources this LBA has */ + lba_pat_resources(d, lba_dev); + + } else { +#endif + /* Sprockets PDC uses NPIOP region */ + pci_port = &lba_astro_port_ops; + + /* Poke the chip a bit for /proc output */ + lba_legacy_resources(d, lba_dev); +#ifdef __LP64__ + } +#endif + + /* + ** Tell PCI support another PCI bus was found. + ** Walks PCI bus for us too. + */ + lba_bus = lba_dev->hba.hba_bus = + pci_scan_bus( lba_dev->hba.bus_num.start, &lba_cfg_ops, (void *) lba_dev); + +#ifdef __LP64__ + if (pdc_pat) { + + /* determine window sizes needed by PCI-PCI bridges */ + DBG_PAT("LBA pcibios_size_bridge()\n"); + pcibios_size_bridge(lba_bus, NULL); + + /* assign resources to un-initialized devices */ + DBG_PAT("LBA pcibios_assign_unassigned_resources()\n"); + pcibios_assign_unassigned_resources(lba_bus); + +#ifdef DEBUG_LBA_PAT + DBG_PAT("\nLBA PIOP resource tree\n"); + lba_dump_res(&lba_dev->hba.io_space, 2); + DBG_PAT("\nLBA LMMIO resource tree\n"); + lba_dump_res(&lba_dev->hba.mem_space, 2); +#endif + + /* program *all* PCI-PCI bridge range registers */ + DBG_PAT("LBA pbus_set_ranges()\n"); + pbus_set_ranges(lba_bus, NULL); + } +#endif /* __LP64__ */ + + /* + ** Once PCI register ops has walked the bus, access to config + ** space is restricted. Avoids master aborts on config cycles. + ** Early LBA revs go fatal on *any* master abort. + */ + if (!LBA_TR4PLUS(lba_dev)) { + lba_dev->flags |= LBA_FLAG_SKIP_PROBE; + } + + /* Whew! Finally done! Tell services we got this one covered. */ + return 0; +} + + +/* +** Initialize the IBASE/IMASK registers for LBA (Elroy). +** Only called from sba_iommu.c initialization sequence. +*/ +void lba_init_iregs(void *sba_hpa, u32 ibase, u32 imask) +{ + extern struct pci_hba_data *hba_list; /* arch/parisc/kernel/pci.c */ + struct pci_hba_data *lba; + + imask <<= 2; /* adjust for hints - 2 more bits */ + + ASSERT((ibase & 0x003fffff) == 0); + ASSERT((imask & 0x003fffff) == 0); + + /* FIXME: sba_hpa is intended to search some table to + ** determine which LBA's belong to the caller's SBA. + ** IS_ASTRO: just assume only one SBA for now. + */ + ASSERT(NULL != hba_list); + DBG(KERN_DEBUG "%s() ibase 0x%x imask 0x%x\n", __FUNCTION__, ibase, imask); + + for (lba = hba_list; NULL != lba; lba = lba->next) { + DBG(KERN_DEBUG "%s() base_addr %p\n", __FUNCTION__, lba->base_addr); + WRITE_REG32( imask, lba->base_addr + LBA_IMASK); + WRITE_REG32( ibase, lba->base_addr + LBA_IBASE); + } + DBG(KERN_DEBUG "%s() done\n", __FUNCTION__); +} + diff --git a/arch/parisc/kernel/led.c b/arch/parisc/kernel/led.c new file mode 100644 index 000000000..a375423f3 --- /dev/null +++ b/arch/parisc/kernel/led.c @@ -0,0 +1,451 @@ +/* + * Chassis LCD/LED driver for HP-PARISC workstations + * + * (c) Copyright 2000 Red Hat Software + * (c) Copyright 2000 Helge Deller <hdeller@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/bitops.h> +#include <asm/io.h> +#include <asm/gsc.h> +#include <asm/processor.h> +#include <asm/hardware.h> +#include <asm/param.h> /* HZ */ +#include <asm/led.h> + + +/* define to disable all LED functions */ +#undef DISABLE_LEDS + + +#define CPU_HVERSION ((boot_cpu_data.hversion >> 4) & 0x0FFF) + + +struct lcd_block { + unsigned char command; /* stores the command byte */ + unsigned char on; /* value for turning LED on */ + unsigned char off; /* value for turning LED off */ +}; + +/* Structure returned by PDC_RETURN_CHASSIS_INFO */ +struct pdc_chassis_lcd_info_ret_block { + unsigned long model:16; /* DISPLAY_MODEL_XXXX (see below) */ + unsigned long lcd_width:16; /* width of the LCD in chars (DISPLAY_MODEL_LCD only) */ + char *lcd_cmd_reg_addr; /* ptr to LCD cmd-register & data ptr for LED */ + char *lcd_data_reg_addr; /* ptr to LCD data-register (LCD only) */ + unsigned int min_cmd_delay; /* delay in uS after cmd-write (LCD only) */ + unsigned char reset_cmd1; /* command #1 for writing LCD string (LCD only) */ + unsigned char reset_cmd2; /* command #2 for writing LCD string (LCD only) */ + unsigned char act_enable; /* 0 = no activity (LCD only) */ + struct lcd_block heartbeat; + struct lcd_block disk_io; + struct lcd_block lan_rcv; + struct lcd_block lan_tx; + char _pad; +}; + +/* values for pdc_chassis_lcd_info_ret_block.model: */ +#define DISPLAY_MODEL_LCD 0 /* KittyHawk LED or LCD */ +#define DISPLAY_MODEL_NONE 1 /* no LED or LCD */ +#define DISPLAY_MODEL_LASI 2 /* LASI style 8 bit LED */ +#define DISPLAY_MODEL_OLD_ASP 0x7F /* faked: ASP style 8 x 1 bit LED (only very old ASP versions) */ + + +/* LCD_CMD and LCD_DATA for KittyHawk machines */ +#ifdef __LP64__ +#define KITTYHAWK_LCD_CMD 0xfffffffff0190000L +#else +#define KITTYHAWK_LCD_CMD 0xf0190000 +#endif +#define KITTYHAWK_LCD_DATA (KITTYHAWK_LCD_CMD + 1) + + +/* lcd_info is pre-initialized to the values needed to program KittyHawk LCD's */ +static struct pdc_chassis_lcd_info_ret_block +lcd_info __attribute__((aligned(8))) = +{ + model:DISPLAY_MODEL_LCD, + lcd_width:16, + lcd_cmd_reg_addr:(char *) KITTYHAWK_LCD_CMD, + lcd_data_reg_addr:(char *) KITTYHAWK_LCD_DATA, + min_cmd_delay:40, + reset_cmd1:0x80, + reset_cmd2:0xc0, +}; + + +/* direct access to some of the lcd_info variables */ +#define LCD_CMD_REG lcd_info.lcd_cmd_reg_addr +#define LCD_DATA_REG lcd_info.lcd_data_reg_addr +#define LED_DATA_REG lcd_info.lcd_cmd_reg_addr /* LASI & ASP only */ + + + + +/* + ** + ** led_ASP_driver() + ** + */ +#define LED_DATA 0x01 /* data to shift (0:on 1:off) */ +#define LED_STROBE 0x02 /* strobe to clock data */ +static void led_ASP_driver(unsigned char leds) +{ + int i; + + leds = ~leds; + for (i = 0; i < 8; i++) { + unsigned char value; + value = (leds & 0x80) >> 7; + gsc_writeb( value, LED_DATA_REG ); + gsc_writeb( value | LED_STROBE, LED_DATA_REG ); + leds <<= 1; + } +} + + +/* + ** + ** led_LASI_driver() + ** + */ +static void led_LASI_driver(unsigned char leds) +{ + leds = ~leds; + gsc_writeb( leds, LED_DATA_REG ); +} + + +/* + ** + ** led_LCD_driver() + ** + ** The logic of the LCD driver is, that we write at every interrupt + ** only to one of LCD_CMD_REG _or_ LCD_DATA_REG - registers. + ** That way we don't need to let this interrupt routine busywait + ** the "min_cmd_delay", since idlewaiting in an interrupt-routine is + ** allways a BAD IDEA ! + ** + ** TODO: check the value of "min_cmd_delay" against the value of HZ. + ** + */ + +static void led_LCD_driver(unsigned char leds) +{ + static int last_index; /* 0:heartbeat, 1:disk, 2:lan_in, 3:lan_out */ + static int last_was_cmd;/* 0: CMD was written last, 1: DATA was last */ + struct lcd_block *block_ptr; + int value; + + // leds = ~leds; /* needed ? */ + + switch (last_index) { + case 0: block_ptr = &lcd_info.heartbeat; + value = leds & LED_HEARTBEAT; + break; + case 1: block_ptr = &lcd_info.disk_io; + value = leds & LED_DISK_IO; + break; + case 2: block_ptr = &lcd_info.lan_rcv; + value = leds & LED_LAN_RCV; + break; + case 3: block_ptr = &lcd_info.lan_tx; + value = leds & LED_LAN_TX; + break; + default: /* should never happen: */ + BUG(); + return; + } + + if (last_was_cmd) { + /* write the value to the LCD data port */ + gsc_writeb( value ? block_ptr->on : block_ptr->off, LCD_DATA_REG ); + } else { + /* write the command-byte to the LCD command register */ + gsc_writeb( block_ptr->command, LCD_CMD_REG ); + } + + /* now update the vars for the next interrupt iteration */ + if (++last_was_cmd == 2) { + last_was_cmd = 0; + if (++last_index == 4) + last_index = 0; + } +} + + + +static char currentleds; /* stores current value of the LEDs */ + +static void (*led_func_ptr) (unsigned char); /* ptr to LCD/LED-specific function */ + +/* + ** led_interrupt_func() + ** + ** is called at every timer interrupt from time.c, + ** updates the chassis LCD/LED + */ + +#define HEARTBEAT_LEN (HZ/16) + +void led_interrupt_func(void) +{ +#ifndef DISABLE_LEDS + static int count; + static int lastleds = -1; + static int nr; + + /* exit, if not initialized */ + if (!led_func_ptr) + return; + + /* increment the local counter */ + if (count == (HZ-1)) + count = 0; + else + count++; + + /* calculate the Heartbeat */ + if ((count % (HZ/2)) < HEARTBEAT_LEN) + currentleds |= LED_HEARTBEAT; + else + currentleds &= ~LED_HEARTBEAT; + + /* roll LEDs 0..2 */ + if (count == 0) { + if (nr++ >= 2) + nr = 0; + currentleds &= ~7; + currentleds |= (1 << nr); + } + + /* now update the LEDs */ + if (currentleds != lastleds) { + led_func_ptr(currentleds); + lastleds = currentleds; + } +#endif +} + + +/* + ** register_led_driver() + ** + ** All information in lcd_info needs to be set up prior + ** calling this function. + */ + +static void __init register_led_driver(void) +{ +#ifndef DISABLE_LEDS + switch (lcd_info.model) { + case DISPLAY_MODEL_LCD: + printk(KERN_INFO "LCD display at (%p,%p)\n", + LCD_CMD_REG , LCD_DATA_REG); + led_func_ptr = led_LCD_driver; + break; + + case DISPLAY_MODEL_LASI: + printk(KERN_INFO "LED display at %p\n", + LED_DATA_REG); + led_func_ptr = led_LASI_driver; + break; + + case DISPLAY_MODEL_OLD_ASP: + printk(KERN_INFO "LED (ASP-style) display at %p\n", + LED_DATA_REG); + led_func_ptr = led_ASP_driver; + break; + + default: + printk(KERN_ERR "%s: Wrong LCD/LED model %d !\n", + __FUNCTION__, lcd_info.model); + return; + } +#endif +} + +/* + * XXX - could this move to lasi.c ?? + */ + +/* + ** lasi_led_init() + ** + ** lasi_led_init() is called from lasi.c with the base hpa + ** of the lasi controller chip. + ** Since Mirage and Electra machines use a different LED + ** address register, we need to check for these machines + ** explicitly. + */ + +#ifdef CONFIG_GSC_LASI +void __init lasi_led_init(unsigned long lasi_hpa) +{ + if (lcd_info.model != DISPLAY_MODEL_NONE || + lasi_hpa == 0) + return; + + printk("%s: CPU_HVERSION %x\n", __FUNCTION__, CPU_HVERSION); + + /* Mirage and Electra machines need special offsets */ + switch (CPU_HVERSION) { + case 0x60A: /* Mirage Jr (715/64) */ + case 0x60B: /* Mirage 100 */ + case 0x60C: /* Mirage 100+ */ + case 0x60D: /* Electra 100 */ + case 0x60E: /* Electra 120 */ + LED_DATA_REG = (char *) (lasi_hpa - 0x00020000); + break; + default: + LED_DATA_REG = (char *) (lasi_hpa + 0x0000C000); + break; + } /* switch() */ + + lcd_info.model = DISPLAY_MODEL_LASI; + register_led_driver(); +} +#endif + + +/* + ** asp_led_init() + ** + ** asp_led_init() is called from asp.c with the ptr + ** to the LED display. + */ + +#ifdef CONFIG_GSC_LASI +void __init asp_led_init(unsigned long led_ptr) +{ + if (lcd_info.model != DISPLAY_MODEL_NONE || + led_ptr == 0) + return; + + lcd_info.model = DISPLAY_MODEL_OLD_ASP; + LED_DATA_REG = (char *) led_ptr; + + register_led_driver(); +} + +#endif + + + +/* + ** register_led_regions() + ** + ** Simple function, which registers the LCD/LED regions for /procfs. + ** At bootup - where the initialisation of the LCD/LED normally happens - + ** not all internal structures of request_region() are properly set up, + ** so that we delay the registration until busdevice.c is executed. + ** + */ + +void __init register_led_regions(void) +{ + switch (lcd_info.model) { + case DISPLAY_MODEL_LCD: + request_region((unsigned long)LCD_CMD_REG, 1, "lcd_cmd"); + request_region((unsigned long)LCD_DATA_REG, 1, "lcd_data"); + break; + case DISPLAY_MODEL_LASI: + case DISPLAY_MODEL_OLD_ASP: + request_region((unsigned long)LED_DATA_REG, 1, "led_data"); + break; + } +} + + + +/* + ** led_init() + ** + ** led_init() is called very early in the bootup-process from setup.c + ** and asks the PDC for an usable chassis LCD or LED. + ** If the PDC doesn't return any info, then the LED + ** is detected by lasi.c or asp.c and registered with the + ** above functions lasi_led_init() or asp_led_init(). + ** KittyHawk machines have often a buggy PDC, so that + ** we explicitly check for those machines here. + */ + +int __init led_init(void) +{ +#ifndef DISABLE_LEDS + long pdc_result[32]; + + printk("%s: CPU_HVERSION %x\n", __FUNCTION__, CPU_HVERSION); + + /* Work around the buggy PDC of KittyHawk-machines */ + switch (CPU_HVERSION) { + case 0x580: /* KittyHawk DC2-100 (K100) */ + case 0x581: /* KittyHawk DC3-120 (K210) */ + case 0x582: /* KittyHawk DC3 100 (K400) */ + case 0x583: /* KittyHawk DC3 120 (K410) */ + case 0x58B: /* KittyHawk DC2 100 (K200) */ + printk("%s: KittyHawk-Machine found !!\n", __FUNCTION__); + goto found; /* use the preinitialized values of lcd_info */ + + default: + break; + } + + /* initialize pdc_result, so we can check the return values of pdc_chassis_info() */ + pdc_result[0] = pdc_result[1] = 0; + + if (pdc_chassis_info(&pdc_result, &lcd_info, sizeof(lcd_info)) == PDC_OK) { + printk("%s: chassis info: model %d, ret0=%d, ret1=%d\n", + __FUNCTION__, lcd_info.model, pdc_result[0], pdc_result[1]); + + /* check the results. Some machines have a buggy PDC */ + if (pdc_result[0] <= 0 || pdc_result[0] != pdc_result[1]) + goto not_found; + + switch (lcd_info.model) { + case DISPLAY_MODEL_LCD: /* LCD display */ + if (pdc_result[0] != sizeof(struct pdc_chassis_lcd_info_ret_block) + && pdc_result[0] != sizeof(struct pdc_chassis_lcd_info_ret_block) - 1) + goto not_found; + printk("%s: min_cmd_delay = %d uS\n", + __FUNCTION__, lcd_info.min_cmd_delay); + break; + + case DISPLAY_MODEL_NONE: /* no LED or LCD available */ + goto not_found; + + case DISPLAY_MODEL_LASI: /* Lasi style 8 bit LED display */ + if (pdc_result[0] != 8 && pdc_result[0] != 32) + goto not_found; + break; + + default: + printk(KERN_WARNING "Unknown LCD/LED model %d\n", + lcd_info.model); + goto not_found; + } /* switch() */ + +found: + /* register the LCD/LED driver */ + register_led_driver(); + return 0; + + } /* if() */ + +not_found: + lcd_info.model = DISPLAY_MODEL_NONE; + return 1; +#endif +} diff --git a/arch/parisc/kernel/pa7300lc.c b/arch/parisc/kernel/pa7300lc.c new file mode 100644 index 000000000..307e4b2fd --- /dev/null +++ b/arch/parisc/kernel/pa7300lc.c @@ -0,0 +1,54 @@ +/* + * linux/arch/parisc/kernel/pa7300lc.c + * - PA7300LC-specific functions + * + * Copyright (C) 2000 Philipp Rumpf */ + +#include <asm/gsc.h> +#include <asm/ptrace.h> +#include <asm/machdep.h> +#include <linux/smp.h> +#include <linux/kernel.h> + +/* CPU register indices */ + +#define MIOC_STATUS 0xf040 +#define MIOC_CONTROL 0xf080 +#define MDERRADD 0xf0e0 +#define DMAERR 0xf0e8 +#define DIOERR 0xf0ec +#define HIDMAMEM 0xf0f4 + +/* read CPU Diagnose register index */ +static u32 diag_read(int index) +{ + return 0; +} + +/* this returns the HPA of the CPU it was called on */ +static u32 cpu_hpa(void) +{ + return 0xfffb0000; +} + +static void pa7300lc_lpmc(int code, struct pt_regs *regs) +{ + u32 hpa; + printk(KERN_WARNING "LPMC on CPU %d\n", smp_processor_id()); + + show_regs(regs); + + hpa = cpu_hpa(); + printk(KERN_WARNING + "MIOC_CONTROL %08x\n" "MIOC_STATUS %08x\n" + "MDERRADD %08x\n" "DMAERR %08x\n" + "DIOERR %08x\n" "HIDMAMEM %08x\n", + gsc_readl(hpa+MIOC_CONTROL), gsc_readl(hpa+MIOC_STATUS), + gsc_readl(hpa+MDERRADD), gsc_readl(hpa+DMAERR), + gsc_readl(hpa+DIOERR), gsc_readl(hpa+HIDMAMEM)); +} + +void pa7300lc_init(void) +{ + cpu_lpmc = pa7300lc_lpmc; +} diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c new file mode 100644 index 000000000..2b4dbd74c --- /dev/null +++ b/arch/parisc/kernel/parisc_ksyms.c @@ -0,0 +1,138 @@ +/* + * Architecture-specific kernel symbols + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> + +#include <linux/string.h> +EXPORT_SYMBOL_NOVERS(memscan); +EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL_NOVERS(memcpy); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strchr); +EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strcpy); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strncat); +EXPORT_SYMBOL(strncmp); +EXPORT_SYMBOL(strncpy); +EXPORT_SYMBOL(strtok); + +#include <linux/pci.h> +EXPORT_SYMBOL(hppa_dma_ops); + +#include <asm/irq.h> +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); + +#include <asm/processor.h> +EXPORT_SYMBOL(kernel_thread); +EXPORT_SYMBOL(boot_cpu_data); + +#ifdef CONFIG_SMP +EXPORT_SYMBOL(synchronize_irq); + +#include <asm/smplock.h> +EXPORT_SYMBOL(kernel_flag); + +#include <asm/system.h> +EXPORT_SYMBOL(__global_sti); +EXPORT_SYMBOL(__global_cli); +EXPORT_SYMBOL(__global_save_flags); +EXPORT_SYMBOL(__global_restore_flags); + +#endif + +#include <asm/uaccess.h> +EXPORT_SYMBOL(lcopy_to_user); +EXPORT_SYMBOL(lcopy_from_user); + +/* Needed so insmod can set dp value */ + +extern int data_start; + +EXPORT_SYMBOL_NOVERS(data_start); + +#include <asm/gsc.h> +EXPORT_SYMBOL(_gsc_writeb); +EXPORT_SYMBOL(_gsc_writew); +EXPORT_SYMBOL(_gsc_writel); +EXPORT_SYMBOL(_gsc_readb); +EXPORT_SYMBOL(_gsc_readw); +EXPORT_SYMBOL(_gsc_readl); +EXPORT_SYMBOL(busdevice_alloc_irq); +EXPORT_SYMBOL(register_driver); +EXPORT_SYMBOL(gsc_alloc_irq); +EXPORT_SYMBOL(pdc_iodc_read); + +extern void $$divI(void); +extern void $$divU(void); +extern void $$remI(void); +extern void $$remU(void); +extern void $$mulI(void); +extern void $$mulU(void); +extern void $$divU_3(void); +extern void $$divU_5(void); +extern void $$divU_6(void); +extern void $$divU_9(void); +extern void $$divU_10(void); +extern void $$divU_12(void); +extern void $$divU_7(void); +extern void $$divU_14(void); +extern void $$divU_15(void); +extern void $$divI_3(void); +extern void $$divI_5(void); +extern void $$divI_6(void); +extern void $$divI_7(void); +extern void $$divI_9(void); +extern void $$divI_10(void); +extern void $$divI_12(void); +extern void $$divI_14(void); +extern void $$divI_15(void); + +EXPORT_SYMBOL_NOVERS($$divI); +EXPORT_SYMBOL_NOVERS($$divU); +EXPORT_SYMBOL_NOVERS($$remI); +EXPORT_SYMBOL_NOVERS($$remU); +EXPORT_SYMBOL_NOVERS($$mulI); +EXPORT_SYMBOL_NOVERS($$mulU); +EXPORT_SYMBOL_NOVERS($$divU_3); +EXPORT_SYMBOL_NOVERS($$divU_5); +EXPORT_SYMBOL_NOVERS($$divU_6); +EXPORT_SYMBOL_NOVERS($$divU_9); +EXPORT_SYMBOL_NOVERS($$divU_10); +EXPORT_SYMBOL_NOVERS($$divU_12); +EXPORT_SYMBOL_NOVERS($$divU_7); +EXPORT_SYMBOL_NOVERS($$divU_14); +EXPORT_SYMBOL_NOVERS($$divU_15); +EXPORT_SYMBOL_NOVERS($$divI_3); +EXPORT_SYMBOL_NOVERS($$divI_5); +EXPORT_SYMBOL_NOVERS($$divI_6); +EXPORT_SYMBOL_NOVERS($$divI_7); +EXPORT_SYMBOL_NOVERS($$divI_9); +EXPORT_SYMBOL_NOVERS($$divI_10); +EXPORT_SYMBOL_NOVERS($$divI_12); +EXPORT_SYMBOL_NOVERS($$divI_14); +EXPORT_SYMBOL_NOVERS($$divI_15); + +extern void __ashrdi3(void); + +EXPORT_SYMBOL_NOVERS(__ashrdi3); + +#ifdef __LP64__ +extern void __divdi3(void); +extern void __udivdi3(void); + +EXPORT_SYMBOL_NOVERS(__divdi3); +EXPORT_SYMBOL_NOVERS(__udivdi3); +#endif + +#ifndef __LP64__ +extern void $$dyncall(void); +EXPORT_SYMBOL_NOVERS($$dyncall); +#endif + diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c new file mode 100644 index 000000000..88a9ddc77 --- /dev/null +++ b/arch/parisc/kernel/pci-dma.c @@ -0,0 +1,547 @@ +/* +** Dynamic DMA mapping support. +** See Documentation/DMA-mapping.txt for interface definitions. +** +** (c) Copyright 1999,2000 Hewlett-Packard Company +** (c) Copyright 2000 Grant Grundler +** (c) Copyright 2000 Philipp Rumpf <prumpf@tux.org> +** (c) Copyright 2000 John Marvin +** +** This implementation is for PA-RISC platforms that do not support +** I/O TLBs (aka DMA address translation hardware). +** +** "leveraged" from 2.3.47: arch/ia64/kernel/pci-dma.c. +** (I assume it's from David Mosberger-Tang but there was no Copyright) +** +** AFAIK, all PA7100LC and PA7300LC platforms can use this code. +** All PA2.0 machines but V-class can alias xxx_alloc_consistent() +** to use regular cacheable memory. +** +** - ggg +*/ + +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <linux/malloc.h> +#include <linux/vmalloc.h> + +#include <asm/uaccess.h> +#include <asm/pgalloc.h> + +#include <asm/io.h> +#include <asm/page.h> /* get_order */ +#include <asm/dma.h> /* for DMA_CHUNK_SIZE */ + +#include <linux/proc_fs.h> + +static struct proc_dir_entry * proc_gsc_root = NULL; +static int pcxl_proc_info(char *buffer, char **start, off_t offset, int length); +static unsigned long pcxl_used_bytes = 0; +static unsigned long pcxl_used_pages = 0; + +extern unsigned long pcxl_dma_start; /* Start of pcxl dma mapping area */ +static spinlock_t pcxl_res_lock; +static char *pcxl_res_map; +static int pcxl_res_hint; +static int pcxl_res_size; + +#ifdef DEBUG_PCXL_RESOURCE +#define DBG_RES(x...) printk(x) +#else +#define DBG_RES(x...) +#endif + + +/* +** Dump a hex representation of the resource map. +*/ + +#ifdef DUMP_RESMAP +static +void dump_resmap(void) +{ + u_long *res_ptr = (unsigned long *)pcxl_res_map; + u_long i = 0; + + printk("res_map: "); + for(; i < (pcxl_res_size / sizeof(unsigned long)); ++i, ++res_ptr) + printk("%08lx ", *res_ptr); + + printk("\n"); +} +#else +static inline void dump_resmap(void) {;} +#endif + +static int pa11_dma_supported( struct pci_dev *dev, dma_addr_t mask) +{ + return 1; +} + +static inline int map_pte_uncached(pte_t * pte, + unsigned long vaddr, + unsigned long size, unsigned long *paddr_ptr) +{ + unsigned long end; + unsigned long orig_vaddr = vaddr; + + vaddr &= ~PMD_MASK; + end = vaddr + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + if (!pte_none(*pte)) + printk(KERN_ERR "map_pte_uncached: page already exists\n"); + set_pte(pte, __mk_pte(*paddr_ptr, PAGE_KERNEL_UNC)); + pdtlb_kernel(orig_vaddr); + vaddr += PAGE_SIZE; + orig_vaddr += PAGE_SIZE; + (*paddr_ptr) += PAGE_SIZE; + pte++; + } while (vaddr < end); + return 0; +} + +static inline int map_pmd_uncached(pmd_t * pmd, unsigned long vaddr, + unsigned long size, unsigned long *paddr_ptr) +{ + unsigned long end; + unsigned long orig_vaddr = vaddr; + + vaddr &= ~PGDIR_MASK; + end = vaddr + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + do { + pte_t * pte = pte_alloc_kernel(pmd, vaddr); + if (!pte) + return -ENOMEM; + if (map_pte_uncached(pte, orig_vaddr, end - vaddr, paddr_ptr)) + return -ENOMEM; + vaddr = (vaddr + PMD_SIZE) & PMD_MASK; + orig_vaddr += PMD_SIZE; + pmd++; + } while (vaddr < end); + return 0; +} + +static inline int map_uncached_pages(unsigned long vaddr, unsigned long size, + unsigned long paddr) +{ + pgd_t * dir; + unsigned long end = vaddr + size; + + dir = pgd_offset_k(vaddr); + do { + pmd_t *pmd; + + pmd = pmd_alloc_kernel(dir, vaddr); + if (!pmd) + return -ENOMEM; + if (map_pmd_uncached(pmd, vaddr, end - vaddr, &paddr)) + return -ENOMEM; + vaddr = vaddr + PGDIR_SIZE; + dir++; + } while (vaddr && (vaddr < end)); + return 0; +} + +static inline void unmap_uncached_pte(pmd_t * pmd, unsigned long vaddr, + unsigned long size) +{ + pte_t * pte; + unsigned long end; + unsigned long orig_vaddr = vaddr; + + if (pmd_none(*pmd)) + return; + if (pmd_bad(*pmd)) { + pmd_ERROR(*pmd); + pmd_clear(pmd); + return; + } + pte = pte_offset(pmd, vaddr); + vaddr &= ~PMD_MASK; + end = vaddr + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + pte_t page = *pte; + pte_clear(pte); + pdtlb_kernel(orig_vaddr); + vaddr += PAGE_SIZE; + orig_vaddr += PAGE_SIZE; + pte++; + if (pte_none(page) || pte_present(page)) + continue; + printk(KERN_CRIT "Whee.. Swapped out page in kernel page table\n"); + } while (vaddr < end); +} + +static inline void unmap_uncached_pmd(pgd_t * dir, unsigned long vaddr, + unsigned long size) +{ + pmd_t * pmd; + unsigned long end; + unsigned long orig_vaddr = vaddr; + + if (pgd_none(*dir)) + return; + if (pgd_bad(*dir)) { + pgd_ERROR(*dir); + pgd_clear(dir); + return; + } + pmd = pmd_offset(dir, vaddr); + vaddr &= ~PGDIR_MASK; + end = vaddr + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + do { + unmap_uncached_pte(pmd, orig_vaddr, end - vaddr); + vaddr = (vaddr + PMD_SIZE) & PMD_MASK; + orig_vaddr += PMD_SIZE; + pmd++; + } while (vaddr < end); +} + +static void unmap_uncached_pages(unsigned long vaddr, unsigned long size) +{ + pgd_t * dir; + unsigned long end = vaddr + size; + + dir = pgd_offset_k(vaddr); + do { + unmap_uncached_pmd(dir, vaddr, end - vaddr); + vaddr = vaddr + PGDIR_SIZE; + dir++; + } while (vaddr && (vaddr < end)); +} + +#define PCXL_SEARCH_LOOP(idx, mask, size) \ + for(; res_ptr < res_end; ++res_ptr) \ + { \ + if(0 == ((*res_ptr) & mask)) { \ + *res_ptr |= mask; \ + idx = (int)((u_long)res_ptr - (u_long)pcxl_res_map); \ + pcxl_res_hint = idx + (size >> 3); \ + goto resource_found; \ + } \ + } + +#define PCXL_FIND_FREE_MAPPING(idx, mask, size) { \ + u##size *res_ptr = (u##size *)&(pcxl_res_map[pcxl_res_hint & ~((size >> 3) - 1)]); \ + u##size *res_end = (u##size *)&pcxl_res_map[pcxl_res_size]; \ + PCXL_SEARCH_LOOP(idx, mask, size); \ + res_ptr = (u##size *)&pcxl_res_map[0]; \ + PCXL_SEARCH_LOOP(idx, mask, size); \ +} + +unsigned long +pcxl_alloc_range(size_t size) +{ + int res_idx; + u_long mask, flags; + unsigned int pages_needed = size >> PAGE_SHIFT; + + ASSERT(pages_needed); + ASSERT((pages_needed * PAGE_SIZE) < DMA_CHUNK_SIZE); + ASSERT(pages_needed < (BITS_PER_LONG - PAGE_SHIFT)); + + mask = (u_long) -1L; + mask >>= BITS_PER_LONG - pages_needed; + + DBG_RES("pcxl_alloc_range() size: %d pages_needed %d pages_mask 0x%08lx\n", + size, pages_needed, mask); + + spin_lock_irqsave(&pcxl_res_lock, flags); + + if(pages_needed <= 8) { + PCXL_FIND_FREE_MAPPING(res_idx, mask, 8); + } else if(pages_needed <= 16) { + PCXL_FIND_FREE_MAPPING(res_idx, mask, 16); + } else if(pages_needed <= 32) { + PCXL_FIND_FREE_MAPPING(res_idx, mask, 32); + } else { + panic(__FILE__ ": pcxl_alloc_range() Too many pages to map.\n"); + } + + dump_resmap(); + panic(__FILE__ ": pcxl_alloc_range() out of dma mapping resources\n"); + +resource_found: + + DBG_RES("pcxl_alloc_range() res_idx %d mask 0x%08lx res_hint: %d\n", + res_idx, mask, pcxl_res_hint); + + pcxl_used_pages += pages_needed; + pcxl_used_bytes += ((pages_needed >> 3) ? (pages_needed >> 3) : 1); + + spin_unlock_irqrestore(&pcxl_res_lock, flags); + + dump_resmap(); + + /* + ** return the corresponding vaddr in the pcxl dma map + */ + return (pcxl_dma_start + (res_idx << (PAGE_SHIFT + 3))); +} + +#define PCXL_FREE_MAPPINGS(idx, m, size) \ + u##size *res_ptr = (u##size *)&(pcxl_res_map[(idx) + (((size >> 3) - 1) & (~((size >> 3) - 1)))]); \ + ASSERT((*res_ptr & m) == m); \ + *res_ptr &= ~m; + +/* +** clear bits in the pcxl resource map +*/ +static void +pcxl_free_range(unsigned long vaddr, size_t size) +{ + u_long mask, flags; + unsigned int res_idx = (vaddr - pcxl_dma_start) >> (PAGE_SHIFT + 3); + unsigned int pages_mapped = size >> PAGE_SHIFT; + + ASSERT(pages_mapped); + ASSERT((pages_mapped * PAGE_SIZE) < DMA_CHUNK_SIZE); + ASSERT(pages_mapped < (BITS_PER_LONG - PAGE_SHIFT)); + + mask = (u_long) -1L; + mask >>= BITS_PER_LONG - pages_mapped; + + DBG_RES("pcxl_free_range() res_idx: %d size: %d pages_mapped %d mask 0x%08lx\n", + res_idx, size, pages_mapped, mask); + + spin_lock_irqsave(&pcxl_res_lock, flags); + + if(pages_mapped <= 8) { + PCXL_FREE_MAPPINGS(res_idx, mask, 8); + } else if(pages_mapped <= 16) { + PCXL_FREE_MAPPINGS(res_idx, mask, 16); + } else if(pages_mapped <= 32) { + PCXL_FREE_MAPPINGS(res_idx, mask, 32); + } else { + panic(__FILE__ ": pcxl_free_range() Too many pages to unmap.\n"); + } + + pcxl_used_pages -= (pages_mapped ? pages_mapped : 1); + pcxl_used_bytes -= ((pages_mapped >> 3) ? (pages_mapped >> 3) : 1); + + spin_unlock_irqrestore(&pcxl_res_lock, flags); + + dump_resmap(); +} + +static int __init +pcxl_dma_init(void) +{ + if (pcxl_dma_start == 0) + return 0; + + spin_lock_init(&pcxl_res_lock); + pcxl_res_size = PCXL_DMA_MAP_SIZE >> (PAGE_SHIFT + 3); + pcxl_res_hint = 0; + pcxl_res_map = (char *)__get_free_pages(GFP_KERNEL, + get_order(pcxl_res_size)); + + proc_gsc_root = proc_mkdir("gsc", 0); + create_proc_info_entry("dino", 0, proc_gsc_root, pcxl_proc_info); + return 0; +} + +__initcall(pcxl_dma_init); + +static void * pa11_dma_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) +{ + unsigned long vaddr; + unsigned long paddr; + int order; + + order = get_order(size); + size = 1 << (order + PAGE_SHIFT); + vaddr = pcxl_alloc_range(size); + paddr = __get_free_pages(GFP_ATOMIC, order); + flush_kernel_dcache_range(paddr, size); + paddr = __pa(paddr); + map_uncached_pages(vaddr, size, paddr); + *dma_handle = (dma_addr_t) paddr; + +#if 0 +/* This probably isn't needed to support EISA cards. +** ISA cards will certainly only support 24-bit DMA addressing. +** Not clear if we can, want, or need to support ISA. +*/ + if (!hwdev || hwdev->dma_mask != 0xffffffff) + gfp |= GFP_DMA; +#endif + return (void *)vaddr; +} + +static void pa11_dma_free_consistent (struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) +{ + int order; + + order = get_order(size); + size = 1 << (order + PAGE_SHIFT); + unmap_uncached_pages((unsigned long)vaddr, size); + pcxl_free_range((unsigned long)vaddr, size); + free_pages((unsigned long)__va(dma_handle), order); +} + +static dma_addr_t pa11_dma_map_single(struct pci_dev *dev, void *addr, size_t size, int direction) +{ + if (direction == PCI_DMA_NONE) { + printk(KERN_ERR "pa11_dma_map_single(PCI_DMA_NONE) called by %p\n", __builtin_return_address(0)); + BUG(); + } + + flush_kernel_dcache_range((unsigned long) addr, size); + return virt_to_phys(addr); +} + +static void pa11_dma_unmap_single(struct pci_dev *dev, dma_addr_t dma_handle, size_t size, int direction) +{ + if (direction == PCI_DMA_NONE) { + printk(KERN_ERR "pa11_dma_unmap_single(PCI_DMA_NONE) called by %p\n", __builtin_return_address(0)); + BUG(); + } + + if (direction == PCI_DMA_TODEVICE) + return; + + /* + * For PCI_DMA_FROMDEVICE this flush is not necessary for the + * simple map/unmap case. However, it IS necessary if if + * pci_dma_sync_single has been called and the buffer reused. + */ + + flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), size); + return; +} + +static int pa11_dma_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +{ + int i; + + if (direction == PCI_DMA_NONE) + BUG(); + + for (i = 0; i < nents; i++, sglist++ ) { + sg_dma_address(sglist) = (dma_addr_t) virt_to_phys(sglist->address); + sg_dma_len(sglist) = sglist->length; + flush_kernel_dcache_range((unsigned long)sglist->address, + sglist->length); + } + return nents; +} + +static void pa11_dma_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +{ + int i; + + if (direction == PCI_DMA_NONE) + BUG(); + + if (direction == PCI_DMA_TODEVICE) + return; + + /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ + + for (i = 0; i < nents; i++, sglist++ ) + flush_kernel_dcache_range((unsigned long) sglist->address, sglist->length); + return; +} + +static void pa11_dma_sync_single(struct pci_dev *dev, dma_addr_t dma_handle, size_t size, int direction) +{ + if (direction == PCI_DMA_NONE) + BUG(); + + flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), size); +} + +static void pa11_dma_sync_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +{ + int i; + + /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ + + for (i = 0; i < nents; i++, sglist++ ) + flush_kernel_dcache_range((unsigned long) sglist->address, sglist->length); +} + +struct pci_dma_ops pcxl_dma_ops = { + pa11_dma_supported, /* dma_support */ + pa11_dma_alloc_consistent, + pa11_dma_free_consistent, + pa11_dma_map_single, /* map_single */ + pa11_dma_unmap_single, /* unmap_single */ + pa11_dma_map_sg, /* map_sg */ + pa11_dma_unmap_sg, /* unmap_sg */ + pa11_dma_sync_single, /* dma_sync_single */ + pa11_dma_sync_sg /* dma_sync_sg */ +}; + +static void *fail_alloc_consistent(struct pci_dev *hwdev, size_t size, + dma_addr_t *dma_handle) +{ + return NULL; +} + +static void fail_free_consistent(struct pci_dev *dev, size_t size, + void *vaddr, dma_addr_t iova) +{ + return; +} + +struct pci_dma_ops pcx_dma_ops = { + pa11_dma_supported, /* dma_support */ + fail_alloc_consistent, + fail_free_consistent, + pa11_dma_map_single, /* map_single */ + pa11_dma_unmap_single, /* unmap_single */ + pa11_dma_map_sg, /* map_sg */ + pa11_dma_unmap_sg, /* unmap_sg */ + pa11_dma_sync_single, /* dma_sync_single */ + pa11_dma_sync_sg /* dma_sync_sg */ +}; + +struct pci_dma_ops *hppa_dma_ops; + +static int pcxl_proc_info(char *buf, char **start, off_t offset, int len) +{ + u_long i = 0; + unsigned long *res_ptr = (u_long *)pcxl_res_map; + unsigned long total_pages = pcxl_res_size << 3; /* 8 bits per byte */ + + sprintf(buf, "\nDMA Mapping Area size : %d bytes (%d pages)\n", + PCXL_DMA_MAP_SIZE, + (pcxl_res_size << 3) ); /* 1 bit per page */ + + sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", + buf, pcxl_res_size, pcxl_res_size << 3); /* 8 bits per byte */ + + strcat(buf, " total: free: used: % used:\n"); + sprintf(buf, "%sblocks %8d %8ld %8ld %8ld%%\n", buf, pcxl_res_size, + pcxl_res_size - pcxl_used_bytes, pcxl_used_bytes, + (pcxl_used_bytes * 100) / pcxl_res_size); + + sprintf(buf, "%spages %8ld %8ld %8ld %8ld%%\n", buf, total_pages, + total_pages - pcxl_used_pages, pcxl_used_pages, + (pcxl_used_pages * 100 / total_pages)); + + strcat(buf, "\nResource bitmap:"); + + for(; i < (pcxl_res_size / sizeof(u_long)); ++i, ++res_ptr) { + if ((i & 7) == 0) + strcat(buf,"\n "); + sprintf(buf, "%s %08lx", buf, *res_ptr); + } + strcat(buf, "\n"); + return strlen(buf); +} + diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c new file mode 100644 index 000000000..a46f69832 --- /dev/null +++ b/arch/parisc/kernel/pci.c @@ -0,0 +1,535 @@ +/* $Id: pci.c,v 1.6 2000/01/29 00:12:05 grundler Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1997, 1998 Ralf Baechle + * Copyright (C) 1999 SuSE GmbH + * Copyright (C) 1999 Hewlett-Packard Company + * Copyright (C) 1999, 2000 Grant Grundler + */ +#include <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> /* for __init and __devinit */ +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/string.h> /* for memcpy() */ + +#include <asm/system.h> + +#ifdef CONFIG_PCI + +#undef DEBUG_RESOURCES + +#ifdef DEBUG_RESOURCES +#define DBG_RES(x...) printk(x) +#else +#define DBG_RES(x...) +#endif + +/* To be used as: mdelay(pci_post_reset_delay); +** +** post_reset is the time the kernel should stall to prevent anyone from +** accessing the PCI bus once #RESET is de-asserted. +** PCI spec somewhere says 1 second but with multi-PCI bus systems, +** this makes the boot time much longer than necessary. +** 20ms seems to work for all the HP PCI implementations to date. +*/ +int pci_post_reset_delay = 50; + +struct pci_port_ops *pci_port; +struct pci_bios_ops *pci_bios; + +struct pci_hba_data *hba_list = NULL; +int hba_count = 0; + +/* +** parisc_pci_hba used by pci_port->in/out() ops to lookup bus data. +*/ +#define PCI_HBA_MAX 32 +static struct pci_hba_data *parisc_pci_hba[PCI_HBA_MAX]; + + +/******************************************************************** +** +** I/O port space support +** +*********************************************************************/ + +#define PCI_PORT_HBA(a) ((a)>>16) +#define PCI_PORT_ADDR(a) ((a) & 0xffffUL) + +/* KLUGE : inb needs to be defined differently for PCI devices than +** for other bus interfaces. Doing this at runtime sucks but is the +** only way one driver binary can support devices on different bus types. +** +*/ + +#define PCI_PORT_IN(type, size) \ +u##size in##type (int addr) \ +{ \ + int b = PCI_PORT_HBA(addr); \ + u##size d = (u##size) -1; \ + ASSERT(pci_port); /* make sure services are defined */ \ + ASSERT(parisc_pci_hba[b]); /* make sure ioaddr are "fixed up" */ \ + if (parisc_pci_hba[b] == NULL) { \ + printk(KERN_WARNING "\nPCI Host Bus Adapter %d not registered. in" #size "(0x%x) returning -1\n", b, addr); \ + } else { \ + d = pci_port->in##type(parisc_pci_hba[b], PCI_PORT_ADDR(addr)); \ + } \ + return d; \ +} + +PCI_PORT_IN(b, 8) +PCI_PORT_IN(w, 16) +PCI_PORT_IN(l, 32) + + +#define PCI_PORT_OUT(type, size) \ +void out##type (u##size d, int addr) \ +{ \ + int b = PCI_PORT_HBA(addr); \ + ASSERT(pci_port); \ + pci_port->out##type(parisc_pci_hba[b], PCI_PORT_ADDR(addr), d); \ +} + +PCI_PORT_OUT(b, 8) +PCI_PORT_OUT(w, 16) +PCI_PORT_OUT(l, 32) + + + +/* + * BIOS32 replacement. + */ +void pcibios_init(void) +{ + ASSERT(pci_bios != NULL); + + if (pci_bios) + { + if (pci_bios->init) { + (*pci_bios->init)(); + } else { + printk(KERN_WARNING "pci_bios != NULL but init() is!\n"); + } + } +} + + +/* Called from pci_do_scan_bus() *after* walking a bus but before walking PPBs. */ +void pcibios_fixup_bus(struct pci_bus *bus) +{ + ASSERT(pci_bios != NULL); + + /* If this is a bridge, get the current bases */ + if (bus->self) { + pci_read_bridge_bases(bus); + } + + if (pci_bios) { + if (pci_bios->fixup_bus) { + (*pci_bios->fixup_bus)(bus); + } else { + printk(KERN_WARNING "pci_bios != NULL but fixup_bus() is!\n"); + } + } +} + + +char *pcibios_setup(char *str) +{ + return str; +} + +#endif /* defined(CONFIG_PCI) */ + + + +/* ------------------------------------------------------------------- +** linux-2.4: NEW STUFF +** -------------------- +*/ + +/* +** Used in drivers/pci/quirks.c +*/ +struct pci_fixup pcibios_fixups[] = { {0} }; + + +/* +** called by drivers/pci/setup.c:pdev_fixup_irq() +*/ +void __devinit pcibios_update_irq(struct pci_dev *dev, int irq) +{ +/* +** updates IRQ_LINE cfg register to reflect PCI-PCI bridge skewing. +** +** Calling path for Alpha is: +** alpha/kernel/pci.c:common_init_pci(swizzle_func, pci_map_irq_func ) +** drivers/pci/setup.c:pci_fixup_irqs() +** drivers/pci/setup.c:pci_fixup_irq() (for each PCI device) +** invoke swizzle and map functions +** alpha/kernel/pci.c:pcibios_update_irq() +** +** Don't need this for PA legacy PDC systems. +** +** On PAT PDC systems, We only support one "swizzle" for any number +** of PCI-PCI bridges deep. That's how bit3 PCI expansion chassis +** are implemented. The IRQ lines are "skewed" for all devices but +** *NOT* routed through the PCI-PCI bridge. Ie any device "0" will +** share an IRQ line. Legacy PDC is expecting this IRQ line routing +** as well. +** +** Unfortunately, PCI spec allows the IRQ lines to be routed +** around the PCI bridge as long as the IRQ lines are skewed +** based on the device number...<sigh>... +** +** Lastly, dino.c might be able to use pci_fixup_irq() to +** support RS-232 and PS/2 children. Not sure how but it's +** something to think about. +*/ +} + + +/* ------------------------------------ +** +** Program one BAR in PCI config space. +** +** ------------------------------------ +** PAT PDC systems need this routine. PA legacy PDC does not. +** +** Used by alpha/arm: +** alpha/kernel/pci.c:common_init_pci() +** (or arm/kernel/pci.c:pcibios_init()) +** drivers/pci/setup.c:pci_assign_unassigned_resources() +** drivers/pci/setup.c:pdev_assign_unassigned_resources() +** arch/<foo>/kernel/pci.c:pcibios_update_resource() +** +** When BAR's are configured by linux, this routine +** will update configuration space with the "normalized" +** address. "root" indicates where the range starts and res +** is some portion of that range. +** +** For all PA-RISC systems except V-class, root->start would be zero. +** +** PAT PDC can tell us which MMIO ranges are available or already in use. +** I/O port space and such are not memory mapped anyway for PA-Risc. +*/ +void __devinit +pcibios_update_resource( + struct pci_dev *dev, + struct resource *root, + struct resource *res, + int barnum + ) +{ + int where; + u32 barval = 0; + + DBG_RES("pcibios_update_resource(%s, ..., %d) [%lx,%lx]/%x\n", + dev->slot_name, + barnum, res->start, res->end, (int) res->flags); + + if (barnum >= PCI_BRIDGE_RESOURCES) { + /* handled in pbus_set_ranges_data() */ + return; + } + + if (barnum == PCI_ROM_RESOURCE) { + where = PCI_ROM_ADDRESS; + } else { + /* 0-5 standard PCI "regions" */ + where = PCI_BASE_ADDRESS_0 + (barnum * 4); + } + + if (res->flags & IORESOURCE_IO) { + barval = PCI_PORT_ADDR(res->start); + } else if (res->flags & IORESOURCE_MEM) { + /* This should work for VCLASS too */ + barval = res->start & 0xffffffffUL; + } else { + panic("pcibios_update_resource() WTF? flags not IO or MEM"); + } + + pci_write_config_dword(dev, where, barval); + +/* XXX FIXME - Elroy does support 64-bit (dual cycle) addressing. +** But at least one device (Symbios 53c896) which has 64-bit BAR +** doesn't actually work right with dual cycle addresses. +** So ignore the whole mess for now. +*/ + + if ((res->flags & (PCI_BASE_ADDRESS_SPACE + | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) + == (PCI_BASE_ADDRESS_SPACE_MEMORY + | PCI_BASE_ADDRESS_MEM_TYPE_64)) { + pci_write_config_dword(dev, where+4, 0); + printk(KERN_WARNING "PCI: dev %s type 64-bit\n", dev->name); + } +} + +/* +** Called by pci_set_master() - a driver interface. +** +** Legacy PDC guarantees to set: +** Map Memory BAR's into PA IO space. +** Map Expansion ROM BAR into one common PA IO space per bus. +** Map IO BAR's into PCI IO space. +** Command (see below) +** Cache Line Size +** Latency Timer +** Interrupt Line +** PPB: secondary latency timer, io/mmio base/limit, +** bus numbers, bridge control +** +*/ +void +pcibios_set_master(struct pci_dev *dev) +{ + u8 lat; + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); + if (lat >= 16) return; + + /* + ** HP generally has fewer devices on the bus than other architectures. + */ + printk("PCIBIOS: Setting latency timer of %s to 128\n", dev->slot_name); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80); +} + + +/* +** called by drivers/pci/setup-res.c:pbus_set_ranges(). +*/ +void pcibios_fixup_pbus_ranges( + struct pci_bus *bus, + struct pbus_set_ranges_data *ranges + ) +{ + /* + ** I/O space may see busnumbers here. Something + ** in the form of 0xbbxxxx where bb is the bus num + ** and xxxx is the I/O port space address. + ** Remaining address translation are done in the + ** PCI Host adapter specific code - ie dino_out8. + */ + ranges->io_start = PCI_PORT_ADDR(ranges->io_start); + ranges->io_end = PCI_PORT_ADDR(ranges->io_end); + + DBG_RES("pcibios_fixup_pbus_ranges(%02x, [%lx,%lx %lx,%lx])\n", bus->number, + ranges->io_start, ranges->io_end, + ranges->mem_start, ranges->mem_end); +} + +#define MAX(val1, val2) ((val1) > (val2) ? (val1) : (val2)) + + +/* +** pcibios align resources() is called everytime generic PCI code +** wants to generate a new address. The process of looking for +** an available address, each candidate is first "aligned" and +** then checked if the resource is available until a match is found. +** +** Since we are just checking candidates, don't use any fields other +** than res->start. +*/ +void __devinit +pcibios_align_resource(void *data, struct resource *res, unsigned long size) +{ + unsigned long mask, align; + + DBG_RES("pcibios_align_resource(%s, (%p) [%lx,%lx]/%x, 0x%lx)\n", + ((struct pci_dev *) data)->slot_name, + res->parent, res->start, res->end, (int) res->flags, size); + + /* has resource already been aligned/assigned? */ + if (res->parent) + return; + + /* If it's not IO, then it's gotta be MEM */ + align = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; + + /* Align to largest of MIN or input size */ + mask = MAX(size, align) - 1; + res->start += mask; + res->start &= ~mask; + + /* + ** WARNING : caller is expected to update "end" field. + ** We can't since it might really represent the *size*. + ** The difference is "end = start + size" vs "end += size". + */ +} + + +#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) + +void __devinit +pcibios_size_bridge(struct pci_bus *bus, struct pbus_set_ranges_data *outer) +{ + struct pbus_set_ranges_data inner; + struct pci_dev *dev; + struct pci_dev *bridge = bus->self; + struct list_head *ln; + + /* set reasonable default "window" for pcibios_align_resource */ + inner.io_start = inner.io_end = 0; + inner.mem_start = inner.mem_end = 0; + + /* Collect information about how our direct children are layed out. */ + for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) { + int i; + dev = pci_dev_b(ln); + + /* Skip bridges here - we'll catch them below */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) + continue; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource res; + unsigned long size; + + if (dev->resource[i].flags == 0) + continue; + + memcpy(&res, &dev->resource[i], sizeof(res)); + size = res.end - res.start + 1; + + if (res.flags & IORESOURCE_IO) { + res.start = inner.io_end; + pcibios_align_resource(dev, &res, size); + inner.io_end += res.start + size; + } else if (res.flags & IORESOURCE_MEM) { + res.start = inner.mem_end; + pcibios_align_resource(dev, &res, size); + inner.mem_end = res.start + size; + } + + DBG_RES(" %s inner size %lx/%x IO %lx MEM %lx\n", + dev->slot_name, + size, res.flags, inner.io_end, inner.mem_end); + } + } + + /* And for all of the subordinate busses. */ + for (ln=bus->children.next; ln != &bus->children; ln=ln->next) + pcibios_size_bridge(pci_bus_b(ln), &inner); + + /* turn the ending locations into sizes (subtract start) */ + inner.io_end -= inner.io_start - 1; + inner.mem_end -= inner.mem_start - 1; + + /* Align the sizes up by bridge rules */ + inner.io_end = ROUND_UP(inner.io_end, 4*1024) - 1; + inner.mem_end = ROUND_UP(inner.mem_end, 1*1024*1024) - 1; + + /* PPB - PCI bridge Device will normaller also have "outer" != NULL. */ + if (bridge) { + /* Adjust the bus' allocation requirements */ + /* PPB's pci device Bridge resources */ + + bus->resource[0] = &bridge->resource[PCI_BRIDGE_RESOURCES]; + bus->resource[1] = &bridge->resource[PCI_BRIDGE_RESOURCES + 1]; + + bus->resource[0]->start = bus->resource[1]->start = 0; + bus->resource[0]->parent= bus->resource[1]->parent = NULL; + + bus->resource[0]->end = inner.io_end; + bus->resource[0]->flags = IORESOURCE_IO; + + bus->resource[1]->end = inner.mem_end; + bus->resource[1]->flags = IORESOURCE_MEM; + } + + /* adjust parent's resource requirements */ + if (outer) { + outer->io_end = ROUND_UP(outer->io_end, 4*1024); + outer->io_end += inner.io_end; + + outer->mem_end = ROUND_UP(outer->mem_end, 1*1024*1024); + outer->mem_end += inner.mem_end; + } +} + +#undef ROUND_UP + + +int __devinit +pcibios_enable_device(struct pci_dev *dev) +{ + u16 cmd, old_cmd; + int idx; + + /* + ** The various platform PDC's (aka "BIOS" for PCs) don't + ** enable all the same bits. We just make sure they are here. + */ + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + + /* + ** See if any resources have been allocated + */ + for (idx=0; idx<6; idx++) { + struct resource *r = &dev->resource[idx]; + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + + /* + ** System error and Parity Error reporting are enabled by default. + ** Devices that do NOT want those behaviors should clear them + ** (eg PCI graphics, possibly networking). + ** Interfaces like SCSI certainly should not. We want the + ** system to crash if a system or parity error is detected. + ** At least until the device driver can recover from such an error. + */ + cmd |= (PCI_COMMAND_SERR | PCI_COMMAND_PARITY); + + if (cmd != old_cmd) { + printk("PCIBIOS: Enabling device %s (%04x -> %04x)\n", + dev->slot_name, old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + + return 0; +} + + +void __devinit +pcibios_assign_unassigned_resources(struct pci_bus *bus) +{ + struct list_head *ln; + + for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) + { + pdev_assign_unassigned_resources(pci_dev_b(ln)); + } + + /* And for all of the sub-busses. */ + for (ln=bus->children.next; ln != &bus->children; ln=ln->next) + pcibios_assign_unassigned_resources(pci_bus_b(ln)); + +} + +/* +** PARISC specific (unfortunately) +*/ +void pcibios_register_hba(struct pci_hba_data *hba) +{ + hba->next = hba_list; + hba_list = hba; + + ASSERT(hba_count < PCI_HBA_MAX); + + /* + ** pci_port->in/out() uses parisc_pci_hba to lookup parameter. + */ + parisc_pci_hba[hba_count] = hba; + hba->hba_num = hba_count++; +} diff --git a/arch/parisc/kernel/pdc.c b/arch/parisc/kernel/pdc.c new file mode 100644 index 000000000..4fa4327c0 --- /dev/null +++ b/arch/parisc/kernel/pdc.c @@ -0,0 +1,217 @@ +/* arch/parisc/kernel/pdc.c - safe pdc access routines + * + * Copyright 1999 SuSE GmbH Nuernberg (Philipp Rumpf, prumpf@tux.org) + * portions Copyright 1999 The Puffin Group, (Alex deVries, David Kennedy) + * + * only these routines should be used out of the real kernel (i.e. everything + * using virtual addresses) for obvious reasons */ + +/* I think it would be in everyone's best interest to follow this + * guidelines when writing PDC wrappers: + * + * - the name of the pdc wrapper should match one of the macros + * used for the first two arguments + * - don't use caps for random parts of the name + * - use ASSERT_ALIGN to ensure the aligment of the arguments is + * correct + * - use __pa() to convert virtual (kernel) pointers to physical + * ones. + * - the name of the struct used for pdc return values should equal + * one of the macros used for the first two arguments to the + * corresponding PDC call + * - keep the order of arguments + * - don't be smart (setting trailing NUL bytes for strings, return + * something useful even if the call failed) unless you are sure + * it's not going to affect functionality or performance + * + * Example: + * int pdc_cache_info(struct pdc_cache_info *cache_info ) + * { + * ASSERT_ALIGN(cache_info, 8); + * + * return mem_pdc_call(PDC_CACHE,PDC_CACHE_INFO,__pa(cache_info),0); + * } + * prumpf 991016 + */ + +#include <linux/kernel.h> +#include <linux/string.h> + +#include <asm/page.h> +#include <asm/pdc.h> +#include <asm/real.h> +#include <asm/system.h> + + +#define ASSERT_ALIGN(ptr, align) \ + do { if(((unsigned long)(ptr)) & (align-1)) { \ + printk("PDC: %s:%d %s() called with " \ + "unaligned argument from %p", __FILE__, __LINE__, \ + __FUNCTION__, __builtin_return_address(0)); \ + \ + return -1; \ + } } while(0) + +/* verify address can be accessed without an HPMC */ +int pdc_add_valid(void *address) +{ + ASSERT_ALIGN(address, 4); + + return mem_pdc_call(PDC_ADD_VALID, PDC_ADD_VALID_VERIFY, (unsigned long)address); +} + +#if 0 +int pdc_chassis_warn(struct pdc_chassis_warn *address) +{ + ASSERT_ALIGN(address, 4); + + return mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_WARN, __pa(address), 0); +} +#endif + +int pdc_chassis_disp(unsigned long disp) +{ + return mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_DISP, disp); +} + +int pdc_chassis_info(void *pdc_result, void *chassis_info, unsigned long len) +{ + ASSERT_ALIGN(pdc_result, 4); + ASSERT_ALIGN(chassis_info, 4); + return mem_pdc_call(PDC_CHASSIS,PDC_RETURN_CHASSIS_INFO, + __pa(pdc_result), __pa(chassis_info), len); +} + +int pdc_hpa_processor(void *address) +{ + /* We're using 0 for the last parameter just to make sure. + It's actually HVERSION dependant. And remember, life is + hard without a backspace. */ + ASSERT_ALIGN(address, 4); + + return mem_pdc_call(PDC_HPA, PDC_HPA_PROCESSOR, __pa(address),0); +} + +#if 0 +int pdc_hpa_modules(void *address) +{ + return mem_pdc_call(PDC_HPA, PDC_HPA_MODULES, address); +} +#endif + +int pdc_iodc_read(void *address, void * hpa, unsigned int index, + void * iodc_data, unsigned int iodc_data_size) +{ + ASSERT_ALIGN(address, 4); + ASSERT_ALIGN(iodc_data, 8); + return mem_pdc_call(PDC_IODC, PDC_IODC_READ, + __pa(address), hpa, index, __pa(iodc_data), iodc_data_size); +} + + +int pdc_system_map_find_mods(void *pdc_mod_info, + void *mod_path, int index) +{ + return mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_MODULE, + __pa(pdc_mod_info), __pa(mod_path), (long)index); +} + + +int pdc_model_info(struct pdc_model *model) { + ASSERT_ALIGN(model, 8); + return mem_pdc_call(PDC_MODEL,PDC_MODEL_INFO,__pa(model),0); +} + +/* get system model name from PDC ROM (e.g. 9000/715 or 9000/778/B160L) */ +int pdc_model_sysmodel(char * name) +{ + struct pdc_model_sysmodel sys_model; + int retval; + + ASSERT_ALIGN(&sys_model, 8); + ASSERT_ALIGN(name, 4); + + sys_model.mod_len = 0; + retval = mem_pdc_call(PDC_MODEL,PDC_MODEL_SYSMODEL,__pa(&sys_model), + OS_ID_HPUX,__pa(name)); + + if (retval == PDC_RET_OK) + name[sys_model.mod_len] = '\0'; /* add trailing '\0' */ + else + name[0] = 0; + + return retval; +} + +/* id: 0 = cpu revision, 1 = boot-rom-version */ +int pdc_model_versions(struct pdc_model_cpuid *cpu_id, int id) { + return mem_pdc_call(PDC_MODEL,PDC_MODEL_VERSIONS,__pa(cpu_id),id); +} + +int pdc_model_cpuid(struct pdc_model_cpuid *cpu_id) { + cpu_id->cpuid = 0; /* preset zero (call maybe not implemented!) */ + return mem_pdc_call(PDC_MODEL,6,__pa(cpu_id),0); /* 6="return CPU ID" */ +} + +int pdc_cache_info(struct pdc_cache_info *cache_info) { + ASSERT_ALIGN(cache_info, 8); + + return mem_pdc_call(PDC_CACHE,PDC_CACHE_INFO,__pa(cache_info),0); +} + +#ifndef __LP64__ +int pdc_btlb_info( struct pdc_btlb_info *btlb ) { + int status; + status = mem_pdc_call(PDC_BLOCK_TLB,PDC_BTLB_INFO,__pa(btlb),0); + if (status<0) btlb->max_size = 0; + return status; +} + +int pdc_mem_map_hpa(void *r_addr, void *mod_path) { + return mem_pdc_call(PDC_MEM_MAP,PDC_MEM_MAP_HPA, + __pa(r_addr),__pa(mod_path)); +} + +int pdc_lan_station_id(char *lan_addr, void *net_hpa) { + struct pdc_lan_station_id id; + unsigned char *addr; + + if (mem_pdc_call(PDC_LAN_STATION_ID, PDC_LAN_STATION_ID_READ, + __pa(&id), net_hpa) < 0) + addr = 0; /* FIXME: else read MAC from NVRAM */ + else + addr = id.addr; + if (addr) + memmove( lan_addr, addr, PDC_LAN_STATION_ID_SIZE); + else + memset( lan_addr, 0, PDC_LAN_STATION_ID_SIZE); + return (addr != 0); +} +#endif + + +/* Similar to PDC_PAT stuff in pdcpat.c - but added for Forte/Allegro boxes */ +int pdc_pci_irt_size(void *r_addr, void *hpa) +{ + return mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL_SIZE, + __pa(r_addr), hpa); + +} + +int pdc_pci_irt(void *r_addr, void *hpa, void *tbl) +{ + return mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL, + __pa(r_addr), hpa, __pa(tbl)); +} + +/* access the TOD clock */ +int pdc_tod_read(struct pdc_tod *tod) +{ + ASSERT_ALIGN(tod, 8); + return mem_pdc_call(PDC_TOD, PDC_TOD_READ, __pa(tod), 0); +} + +int pdc_tod_set(unsigned long sec, unsigned long usec) +{ + return mem_pdc_call(PDC_TOD, PDC_TOD_WRITE, sec, usec); +} diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c new file mode 100644 index 000000000..f2d45862b --- /dev/null +++ b/arch/parisc/kernel/pdc_cons.c @@ -0,0 +1,179 @@ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/console.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <asm/page.h> +#include <asm/types.h> +#include <asm/system.h> +#include <asm/pdc.h> /* for iodc_call() proto and friends */ +#include <asm/real.h> + +static int __attribute__((aligned(8))) iodc_retbuf[32]; +static char __attribute__((aligned(64))) iodc_dbuf[4096]; + +/* + * pdc_putc: + * Console character print using IODC. + * + * Note that only these special chars are architected for console IODC io: + * BEL, BS, CR, and LF. Others are passed through. + * Since the HP console requires CR+LF to perform a 'newline', we translate + * "\n" to "\r\n". + */ + +static int posx; /* for simple TAB-Simulation... */ + +/* XXX Should we spinlock posx usage */ + +void pdc_putc(unsigned char c) +{ + unsigned int n; + unsigned long flags; + + switch (c) { + case '\n': + iodc_dbuf[0] = '\r'; + iodc_dbuf[1] = '\n'; + n = 2; + posx = 0; + break; + case '\t': + pdc_putc(' '); + while (posx & 7) /* expand TAB */ + pdc_putc(' '); + return; /* return since IODC can't handle this */ + case '\b': + posx-=2; /* BS */ + default: + iodc_dbuf[0] = c; + n = 1; + posx++; + break; + } + { + real32_call(PAGE0->mem_cons.iodc_io, + (unsigned long)PAGE0->mem_cons.hpa, ENTRY_IO_COUT, + PAGE0->mem_cons.spa, __pa(PAGE0->mem_cons.dp.layers), + __pa(iodc_retbuf), 0, __pa(iodc_dbuf), n, 0); + } +} + +static void pdc_console_write(struct console *co, const char *s, unsigned count) +{ + while(count--) + pdc_putc(*s++); +} + +int pdc_console_wait_key(struct console *co) +{ + int ch = 'X'; + int status; + + /* Bail if no console input device. */ + if (!PAGE0->mem_kbd.iodc_io) + return 0; + + /* wait for a keyboard (rs232)-input */ + do { + unsigned long flags; + + save_flags(flags); + cli(); + status = real32_call(PAGE0->mem_kbd.iodc_io, + (unsigned long)PAGE0->mem_kbd.hpa, ENTRY_IO_CIN, + PAGE0->mem_kbd.spa, __pa(PAGE0->mem_kbd.dp.layers), + __pa(iodc_retbuf), 0, __pa(iodc_dbuf), 1, 0); + restore_flags(flags); + ch = *iodc_dbuf; /* save the character directly to ch */ + } while (*iodc_retbuf == 0); /* wait for a key */ + return ch; +} + +int pdc_getc(void) +{ + return pdc_console_wait_key(NULL); +} + +static int pdc_console_setup(struct console *co, char *options) +{ + return 0; +} + +static struct console pdc_cons = { + name: "ttyB", + write: pdc_console_write, + read: NULL, + device: NULL, + wait_key: pdc_console_wait_key, + unblank: NULL, + setup: pdc_console_setup, + flags: CON_PRINTBUFFER|CON_ENABLED, // |CON_CONSDEV, + index: -1, +}; + +static int pdc_console_initialized; + +void pdc_console_init(void) +{ + if (pdc_console_initialized) + return; + ++pdc_console_initialized; + + /* If the console is duplex then copy the COUT parameters to CIN. */ + if (PAGE0->mem_cons.cl_class == CL_DUPLEX) + memcpy(&PAGE0->mem_kbd, &PAGE0->mem_cons, sizeof(PAGE0->mem_cons)); + + pdc_console_write(0, "PDC Console Initialized\n", 24); + /* register the pdc console */ + register_console(&pdc_cons); +} + + +/* Unregister the pdc console with the printk console layer */ +void pdc_console_die(void) +{ + printk("Switching from PDC console\n"); + if (!pdc_console_initialized) + return; + --pdc_console_initialized; + +#ifdef CONFIG_VT_CONSOLE + { + /* fixme (needed?): Wait for console-tasklet to finish !*/ + extern struct tasklet_struct console_tasklet; + tasklet_schedule(&console_tasklet); + } +#endif + + unregister_console(&pdc_cons); +} + + +/* + * Used for emergencies. Currently only used if an HPMC occurs. If an + * HPMC occurs, it is possible that the current console may not be + * properly initialed after the PDC IO reset. This routine unregisters all + * of the current consoles, reinitializes the pdc console and + * registers it. + */ + +void pdc_console_restart(void) +{ + struct console *console; + extern int log_size; + + if (pdc_console_initialized) + return; + + while ((console = console_drivers) != (struct console *)0) + unregister_console(console_drivers); + + log_size = 0; + pdc_console_init(); + printk("Switched to PDC console\n"); + return; +} + diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c new file mode 100644 index 000000000..a8d7a707e --- /dev/null +++ b/arch/parisc/kernel/process.c @@ -0,0 +1,250 @@ +/* + * linux/arch/parisc/kernel/process.c + * based on the work for i386 + */ + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +#define __KERNEL_SYSCALLS__ +#include <stdarg.h> + +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/stddef.h> +#include <linux/unistd.h> +#include <linux/ptrace.h> +#include <linux/malloc.h> +#include <linux/vmalloc.h> +#include <linux/interrupt.h> +#include <linux/reboot.h> +#include <linux/init.h> +#include <linux/version.h> +#include <linux/elf.h> + +#include <asm/machdep.h> +#include <asm/offset.h> +#include <asm/uaccess.h> +#include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/io.h> +#include <asm/gsc.h> +#include <asm/processor.h> + +spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED; + +#ifdef __LP64__ +/* The 64-bit code should work equally well in 32-bit land but I didn't + * want to take the time to confirm that. -PB + */ +extern unsigned int ret_from_kernel_thread; +#else +asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread"); +#endif + + +int hlt_counter=0; + +void disable_hlt(void) +{ + hlt_counter++; +} + +void enable_hlt(void) +{ + hlt_counter--; +} + +/* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +void cpu_idle(void) +{ + /* endless idle loop with no priority at all */ + init_idle(); + current->nice = 20; + current->counter = -100; + + while (1) { + while (!current->need_resched) { + } + schedule(); + check_pgt_cache(); + } +} + +void __init reboot_setup(char *str, int *ints) +{ +} + +struct notifier_block *mach_notifier; + +void machine_restart(char *ptr) +{ + notifier_call_chain(&mach_notifier, MACH_RESTART, ptr); +} + +void machine_halt(void) +{ + notifier_call_chain(&mach_notifier, MACH_HALT, NULL); +} + +void machine_power_on(void) +{ + notifier_call_chain(&mach_notifier, MACH_POWER_ON, NULL); +} + +void machine_power_off(void) +{ + notifier_call_chain(&mach_notifier, MACH_POWER_OFF, NULL); +} + + +void machine_heartbeat(void) +{ +} + + +/* + * Create a kernel thread + */ + +extern pid_t __kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); +pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) +{ + + /* + * FIXME: Once we are sure we don't need any debug here, + * kernel_thread can become a #define. + */ + + return __kernel_thread(fn, arg, flags); +} + +/* + * Free current thread data structures etc.. + */ +void exit_thread(void) +{ +} + +void flush_thread(void) +{ + set_fs(USER_DS); +} + +void release_thread(struct task_struct *dead_task) +{ +} + +/* + * Fill in the FPU structure for a core dump. + */ +int dump_fpu (struct pt_regs * regs, elf_fpregset_t *r) +{ + memcpy(r, regs->fr, sizeof *r); + return 1; +} + +/* Note that "fork()" is implemented in terms of clone, with + parameters (SIGCHLD, regs->gr[30], regs). */ +int +sys_clone(unsigned long clone_flags, unsigned long usp, + struct pt_regs *regs) +{ + return do_fork(clone_flags, usp, regs, 0); +} + +int +sys_vfork(struct pt_regs *regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, + regs->gr[30], regs, 0); +} + +int +copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + unsigned long unused, /* in ia64 this is "user_stack_size" */ + struct task_struct * p, struct pt_regs * pregs) +{ + struct pt_regs * cregs = &(p->thread.regs); + long ksp; + + *cregs = *pregs; + + /* Set the return value for the child. Note that this is not + actually restored by the syscall exit path, but we put it + here for consistency in case of signals. */ + cregs->gr[28] = 0; /* child */ + + /* + * We need to differentiate between a user fork and a + * kernel fork. We can't use user_mode, because the + * the syscall path doesn't save iaoq. Right now + * We rely on the fact that kernel_thread passes + * in zero for usp. + */ + if (usp == 0) { + /* Kernel Thread */ + ksp = (((unsigned long)(p)) + TASK_SZ_ALGN); + cregs->ksp = ksp; /* always return to kernel */ +#ifdef __LP64__ + cregs->kpc = (unsigned long) &ret_from_kernel_thread; +#else + cregs->kpc = (unsigned long) ret_from_kernel_thread; +#endif + + /* + * Copy function and argument to be called from + * ret_from_kernel_thread. + */ + cregs->gr[26] = pregs->gr[26]; + cregs->gr[25] = pregs->gr[25]; + + } else { + /* User Thread: + * + * Use same stack depth as parent when in wrapper + * + * Note that the fork wrappers are responsible + * for setting gr[20] and gr[21]. + */ + + cregs->ksp = ((unsigned long)(p)) + + (pregs->gr[20] & (INIT_TASK_SIZE - 1)); + cregs->kpc = pregs->gr[21]; + } + + return 0; +} + +/* + * sys_execve() executes a new program. + */ + +asmlinkage int sys_execve(struct pt_regs *regs) +{ + int error; + char *filename; + + filename = getname((char *) regs->gr[26]); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, (char **) regs->gr[25], + (char **) regs->gr[24], regs); + if (error == 0) + current->ptrace &= ~PT_DTRACE; + putname(filename); +out: + + return error; +} diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c new file mode 100644 index 000000000..176b4386a --- /dev/null +++ b/arch/parisc/kernel/ptrace.c @@ -0,0 +1,305 @@ +/* + * Kernel support for the ptrace() and syscall tracing interfaces. + * + * Copyright (C) 2000 Hewlett-Packard Co, Linuxcare Inc. + * Copyright (C) 2000 Matthew Wilcox <matthew@wil.cx> + * Copyright (C) 2000 David Huggins-Daines <dhd@debian.org> + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/errno.h> +#include <linux/ptrace.h> +#include <linux/user.h> + +#include <asm/uaccess.h> +#include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/processor.h> +#include <asm/offset.h> + +/* These are used in entry.S, syscall_restore_rfi. We need to record the + * current stepping mode somewhere other than in PSW, because there is no + * concept of saving and restoring the users PSW over a syscall. We choose + * to use these two bits in task->ptrace. These bits must not clash with + * any PT_* defined in include/linux/sched.h, and must match with the bit + * tests in entry.S + */ +#define PT_SINGLESTEP 0x10000 +#define PT_BLOCKSTEP 0x20000 + +long sys_ptrace(long request, pid_t pid, long addr, long data) +{ + struct task_struct *child; + long ret; + + lock_kernel(); + ret = -EPERM; + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->ptrace & PT_PTRACED) + goto out; + /* set the ptrace bit in the process flags. */ + current->ptrace |= PT_PTRACED; + ret = 0; + goto out; + } + + ret = -ESRCH; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) + goto out; + ret = -EPERM; + if (pid == 1) /* no messing around with init! */ + goto out_tsk; + + if (request == PTRACE_ATTACH) { + if (child == current) + goto out_tsk; + if ((!child->dumpable || + (current->uid != child->euid) || + (current->uid != child->suid) || + (current->uid != child->uid) || + (current->gid != child->egid) || + (current->gid != child->sgid) || + (!cap_issubset(child->cap_permitted, current->cap_permitted)) || + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) + goto out_tsk; + /* the same process cannot be attached many times */ + if (child->ptrace & PT_PTRACED) + goto out_tsk; + child->ptrace |= PT_PTRACED; + if (child->p_pptr != current) { + unsigned long flags; + + write_lock_irqsave(&tasklist_lock, flags); + REMOVE_LINKS(child); + child->p_pptr = current; + SET_LINKS(child); + write_unlock_irqrestore(&tasklist_lock, flags); + } + send_sig(SIGSTOP, child, 1); + ret = 0; + goto out_tsk; + } + ret = -ESRCH; + if (!(child->ptrace & PT_PTRACED)) + goto out_tsk; + if (child->state != TASK_STOPPED) { + if (request != PTRACE_KILL) + goto out_tsk; + } + if (child->p_pptr != current) + goto out_tsk; + + switch (request) { + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + int copied; + + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + ret = -EIO; + if (copied != sizeof(tmp)) + goto out_tsk; + ret = put_user(tmp,(unsigned long *) data); + goto out_tsk; + } + + /* when I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + ret = 0; + if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) + goto out_tsk; + ret = -EIO; + goto out_tsk; + + /* Read the word at location addr in the USER area. This will need + to change when the kernel no longer saves all regs on a syscall. */ + case PTRACE_PEEKUSR: { + unsigned long tmp; + + ret = -EIO; + if ((addr & 3) || (unsigned long) addr >= sizeof(struct pt_regs)) + goto out_tsk; + + tmp = *(unsigned long *) ((char *) task_regs(child) + addr); + ret = put_user(tmp, (unsigned long *) data); + goto out_tsk; + } + + /* Write the word at location addr in the USER area. This will need + to change when the kernel no longer saves all regs on a syscall. + FIXME. There is a problem at the moment in that r3-r18 are only + saved if the process is ptraced on syscall entry, and even then + those values are overwritten by actual register values on syscall + exit. */ + case PTRACE_POKEUSR: + ret = -EIO; + if ((addr & 3) || (unsigned long) addr >= sizeof(struct pt_regs)) + goto out_tsk; + /* XXX This test probably needs adjusting. We probably want to + * allow writes to some bits of PSW, and may want to block writes + * to (some) space registers. Some register values written here + * may be ignored in entry.S:syscall_restore_rfi; e.g. iaoq is + * written with r31/r31+4, and not with the values in pt_regs. + */ + /* Allow writing of gr1-gr31, fr*, sr*, iasq*, iaoq*, sar */ + if (addr == PT_PSW || (addr > PT_IAOQ1 && addr != PT_SAR)) + goto out_tsk; + + *(unsigned long *) ((char *) task_regs(child) + addr) = data; + ret = 0; + goto out_tsk; + + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: + ret = -EIO; + if ((unsigned long) data > _NSIG) + goto out_tsk; + child->ptrace &= ~(PT_SINGLESTEP|PT_BLOCKSTEP); + if (request == PTRACE_SYSCALL) + child->ptrace |= PT_TRACESYS; + else + child->ptrace &= ~PT_TRACESYS; + child->exit_code = data; + goto out_wake_notrap; + + case PTRACE_KILL: + /* + * make the child exit. Best I can do is send it a + * sigkill. perhaps it should be put in the status + * that it wants to exit. + */ + if (child->state == TASK_ZOMBIE) /* already dead */ + goto out_tsk; + child->exit_code = SIGKILL; + goto out_wake_notrap; + + case PTRACE_SINGLEBLOCK: + ret = -EIO; + if ((unsigned long) data > _NSIG) + goto out_tsk; + child->ptrace &= ~(PT_TRACESYS|PT_SINGLESTEP); + child->ptrace |= PT_BLOCKSTEP; + child->exit_code = data; + + /* Enable taken branch trap. */ + pa_psw(child)->r = 0; + pa_psw(child)->t = 1; + pa_psw(child)->h = 0; + pa_psw(child)->l = 0; + goto out_wake; + + case PTRACE_SINGLESTEP: + ret = -EIO; + if ((unsigned long) data > _NSIG) + goto out_tsk; + child->ptrace &= ~(PT_TRACESYS|PT_BLOCKSTEP); + child->ptrace |= PT_SINGLESTEP; + child->exit_code = data; + + if (pa_psw(child)->n) { + struct siginfo si; + + /* Nullified, just crank over the queue. */ + task_regs(child)->iaoq[0] = task_regs(child)->iaoq[1]; + task_regs(child)->iasq[0] = task_regs(child)->iasq[1]; + task_regs(child)->iaoq[1] = task_regs(child)->iaoq[0] + 4; + pa_psw(child)->n = 0; + pa_psw(child)->x = 0; + pa_psw(child)->y = 0; + pa_psw(child)->z = 0; + pa_psw(child)->b = 0; + pa_psw(child)->r = 0; + pa_psw(child)->t = 0; + pa_psw(child)->h = 0; + pa_psw(child)->l = 0; + /* Don't wake up the child, but let the + parent know something happened. */ + si.si_code = TRAP_TRACE; + si.si_addr = (void *) (task_regs(child)->iaoq[0] & ~3); + si.si_signo = SIGTRAP; + si.si_errno = 0; + force_sig_info(SIGTRAP, &si, child); + //notify_parent(child, SIGCHLD); + //ret = 0; + goto out_wake; + } + + /* Enable recovery counter traps. The recovery counter + * itself will be set to zero on a task switch. If the + * task is suspended on a syscall then the syscall return + * path will overwrite the recovery counter with a suitable + * value such that it traps once back in user space. We + * disable interrupts in the childs PSW here also, to avoid + * interrupts while the recovery counter is decrementing. + */ + pa_psw(child)->r = 1; + pa_psw(child)->t = 0; + pa_psw(child)->h = 0; + pa_psw(child)->l = 0; + /* give it a chance to run. */ + goto out_wake; + + case PTRACE_DETACH: + ret = -EIO; + if ((unsigned long) data > _NSIG) + goto out_tsk; + child->ptrace &= ~(PT_PTRACED|PT_TRACESYS|PT_SINGLESTEP|PT_BLOCKSTEP); + 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); + goto out_wake_notrap; + + default: + ret = -EIO; + goto out_tsk; + } + +out_wake_notrap: + /* make sure the trap bits are not set */ + pa_psw(child)->r = 0; + pa_psw(child)->t = 0; + pa_psw(child)->h = 0; + pa_psw(child)->l = 0; +out_wake: + wake_up_process(child); + ret = 0; +out_tsk: + free_task_struct(child); +out: + unlock_kernel(); + return ret; +} + +void syscall_trace(void) +{ + if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) != + (PT_PTRACED|PT_TRACESYS)) + return; + current->exit_code = SIGTRAP; + current->state = TASK_STOPPED; + notify_parent(current, SIGCHLD); + schedule(); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +} diff --git a/arch/parisc/kernel/real1.c b/arch/parisc/kernel/real1.c new file mode 100644 index 000000000..2bb26bc88 --- /dev/null +++ b/arch/parisc/kernel/real1.c @@ -0,0 +1,154 @@ +/* + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000 Hewlett Packard (Paul Bame bame@puffin.external.hp.com) + * + * most of these calls might reasonably be moved to ../kernel -PB + * + * The basic principle is to construct a stack frame in C then call + * some assembly which adopts that stack, does some rfi magic, may + * switch wide/narrow mode, and calls the routine described by the + * 'fn' parameter WHICH IS NOT A FUNCTION POINTER!!!!!!!!!!!!!!!! + */ +#include <linux/spinlock.h> +#include <asm/system.h> +#include <stdarg.h> +#include <asm/pgtable.h> /* for __pa() */ +#include <asm/pdc.h> + +static spinlock_t pdc_lock = SPIN_LOCK_UNLOCKED; + +/***************** 32-bit real-mode calls ***********/ +/* The struct below is used + * to overlay real_stack (real2.S), preparing a 32-bit call frame. + * real32_call_asm() then uses this stack in narrow real mode + */ + +struct narrow_stack { + /* use int, not long which is 64 bits */ + unsigned int arg13; + unsigned int arg12; + unsigned int arg11; + unsigned int arg10; + unsigned int arg9; + unsigned int arg8; + unsigned int arg7; + unsigned int arg6; + unsigned int arg5; + unsigned int arg4; + unsigned int arg3; + unsigned int arg2; + unsigned int arg1; + unsigned int arg0; + unsigned int frame_marker[8]; + unsigned int sp; + /* in reality, there's nearly 8k of stack after this */ +}; + +long +real32_call(unsigned long fn, ...) +{ + unsigned long r; + va_list args; + unsigned long flags; + extern struct narrow_stack real_stack; + extern unsigned long real32_call_asm(unsigned int *, + unsigned int *, unsigned int); + + va_start(args, fn); + real_stack.arg0 = va_arg(args, unsigned int); + real_stack.arg1 = va_arg(args, unsigned int); + real_stack.arg2 = va_arg(args, unsigned int); + real_stack.arg3 = va_arg(args, unsigned int); + real_stack.arg4 = va_arg(args, unsigned int); + real_stack.arg5 = va_arg(args, unsigned int); + real_stack.arg6 = va_arg(args, unsigned int); + real_stack.arg7 = va_arg(args, unsigned int); + real_stack.arg8 = va_arg(args, unsigned int); + real_stack.arg9 = va_arg(args, unsigned int); + real_stack.arg10 = va_arg(args, unsigned int); + real_stack.arg11 = va_arg(args, unsigned int); + real_stack.arg12 = va_arg(args, unsigned int); + real_stack.arg13 = va_arg(args, unsigned int); + va_end(args); + + if (fn == 0) { + /* mem_pdc call */ + fn = PAGE0->mem_pdc; + } + + spin_lock_irqsave(&pdc_lock, flags); + r = real32_call_asm(&real_stack.sp, &real_stack.arg0, fn); + spin_unlock_irqrestore(&pdc_lock, flags); + + return r; +} + +#ifdef __LP64__ +/***************** 64-bit real-mode calls ***********/ + +struct wide_stack { + unsigned long arg0; + unsigned long arg1; + unsigned long arg2; + unsigned long arg3; + unsigned long arg4; + unsigned long arg5; + unsigned long arg6; + unsigned long arg7; + unsigned long arg8; + unsigned long arg9; + unsigned long arg10; + unsigned long arg11; + unsigned long arg12; + unsigned long arg13; + unsigned long frame_marker[2]; /* rp, previous sp */ + unsigned long sp; + /* in reality, there's nearly 8k of stack after this */ +}; + +long +real64_call(unsigned long fn, ...) +{ + unsigned long r; + va_list args; + unsigned long flags; + extern struct wide_stack real_stack; + extern unsigned long real64_call_asm(unsigned long *, + unsigned long *, unsigned long); + + va_start(args, fn); + real_stack.arg0 = va_arg(args, unsigned long); + real_stack.arg1 = va_arg(args, unsigned long); + real_stack.arg2 = va_arg(args, unsigned long); + real_stack.arg3 = va_arg(args, unsigned long); + real_stack.arg4 = va_arg(args, unsigned long); + real_stack.arg5 = va_arg(args, unsigned long); + real_stack.arg6 = va_arg(args, unsigned long); + real_stack.arg7 = va_arg(args, unsigned long); + real_stack.arg8 = va_arg(args, unsigned long); + real_stack.arg9 = va_arg(args, unsigned long); + real_stack.arg10 = va_arg(args, unsigned long); + real_stack.arg11 = va_arg(args, unsigned long); + real_stack.arg12 = va_arg(args, unsigned long); + real_stack.arg13 = va_arg(args, unsigned long); + va_end(args); + + if (fn == 0) { + /* mem_pdc call */ + fn = PAGE0->mem_pdc_hi; + fn <<= 32; + fn |= PAGE0->mem_pdc; + } + + spin_lock_irqsave(&pdc_lock, flags); + r = real64_call_asm(&real_stack.sp, &real_stack.arg0, fn); + spin_unlock_irqrestore(&pdc_lock, flags); + + return r; +} + +#endif diff --git a/arch/parisc/kernel/real2.S b/arch/parisc/kernel/real2.S new file mode 100644 index 000000000..eb1425ec4 --- /dev/null +++ b/arch/parisc/kernel/real2.S @@ -0,0 +1,274 @@ +/* + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000 Hewlett Packard (Paul Bame bame@puffin.external.hp.com) + * + */ +#define __ASSEMBLY__ +#include <asm/assembly.h> +#include <asm/psw.h> + + .section .bss + .export real_stack + .align 64 +real_stack: + .block 8192 + +#ifdef __LP64__ +# define REG_SZ 8 +#else +# define REG_SZ 4 +#endif + +#define N_SAVED_REGS 9 + +save_cr_space: + .block REG_SZ * N_SAVED_REGS + + +/************************ 32-bit real-mode calls ***********************/ +/* This can be called in both narrow and wide kernels */ + .text + .export real32_call_asm + /* unsigned long real32_call_asm(unsigned int *sp, + * unsigned int *arg0p, + * unsigned int iodc_fn) + * sp is value of stack pointer to adopt before calling PDC (virt) + * arg0p points to where saved arg values may be found + * iodc_fn is the IODC function to call + */ +real32_call_asm: + STREG %rp, -RP_OFFSET(%sp) /* save RP */ +#ifdef __LP64__ + callee_save + ldo 2*REG_SZ(%sp), %sp /* room for a couple more saves */ + STREG %r27, -1*REG_SZ(%sp) + STREG %r29, -2*REG_SZ(%sp) +#endif + STREG %sp, -REG_SZ(%arg0) /* save SP on real-mode stack */ + copy %arg0, %sp /* adopt the real-mode SP */ + + /* save iodc_fn */ + copy %arg2, %r31 + + /* load up the arg registers from the saved arg area */ + /* 32-bit calling convention passes first 4 args in registers */ + ldw 0(%arg1), %arg0 /* note overwriting arg0 */ + ldw -8(%arg1), %arg2 + ldw -12(%arg1), %arg3 + ldw -4(%arg1), %arg1 /* obviously must do this one last! */ + + tophys %sp + + b,l rfi_virt2real,%r2 + nop + + b,l save_control_regs,%r2 /* modifies r1, r2, r28 */ + nop + +#ifdef __LP64__ + rsm PSW_SM_W, %r0 /* go narrow */ +#endif + + ldil L%PA(ric_ret), %r2 + ldo R%PA(ric_ret)(%r2), %r2 + bv 0(%r31) + nop +ric_ret: +#ifdef __LP64__ + ssm PSW_SM_W, %r0 /* go wide */ +#endif + /* restore CRs before going virtual in case we page fault */ + b,l restore_control_regs, %r2 /* modifies r1, r2, r26 */ + nop + + b,l rfi_real2virt,%r2 + nop + + tovirt %sp + LDREG -REG_SZ(%sp), %sp /* restore SP */ +#ifdef __LP64__ + LDREG -1*REG_SZ(%sp), %r27 + LDREG -2*REG_SZ(%sp), %r29 + ldo -2*REG_SZ(%sp), %sp + callee_rest +#endif + LDREG -RP_OFFSET(%sp), %rp /* restore RP */ + bv 0(%rp) + nop + + +# define PUSH_CR(r, where) mfctl r, %r1 ! STREG,ma %r1, REG_SZ(where) +# define POP_CR(r, where) LDREG,mb -REG_SZ(where), %r1 ! mtctl %r1, r + + .text +save_control_regs: + load32 PA(save_cr_space), %r28 + PUSH_CR(%cr24, %r28) + PUSH_CR(%cr25, %r28) + PUSH_CR(%cr26, %r28) + PUSH_CR(%cr27, %r28) + PUSH_CR(%cr28, %r28) + PUSH_CR(%cr29, %r28) + PUSH_CR(%cr30, %r28) + PUSH_CR(%cr31, %r28) + PUSH_CR(%cr15, %r28) + bv 0(%r2) + nop + +restore_control_regs: + load32 PA(save_cr_space + (N_SAVED_REGS * REG_SZ)), %r26 + POP_CR(%cr15, %r26) + POP_CR(%cr31, %r26) + POP_CR(%cr30, %r26) + POP_CR(%cr29, %r26) + POP_CR(%cr28, %r26) + POP_CR(%cr27, %r26) + POP_CR(%cr26, %r26) + POP_CR(%cr25, %r26) + POP_CR(%cr24, %r26) + bv 0(%r2) + nop + +/* rfi_virt2real() and rfi_real2virt() could perhaps be adapted for + * more general-purpose use by the several places which need RFIs + */ + .align 128 + .text +rfi_virt2real: + /* switch to real mode... */ + ssm 0,0 /* See "relied upon translation" */ + nop /* comment in interruption.S */ + nop + nop + nop + nop + nop + nop + nop + + mtsm 0 /* disable interruptions */ + mtctl 0, %cr17 /* space 0 */ + mtctl 0, %cr17 + load32 PA(rfi_v2r_1), %r1 + mtctl %r1, %cr18 + ldo 4(%r1), %r1 + mtctl %r1, %cr18 + load32 PDC_PSW, %r1 + mtctl %r1, %cr22 + rfi + + nop + nop + nop + nop + nop + nop + nop + nop +rfi_v2r_1: + tophys %r2 + bv 0(%r2) + nop + + .text + .align 128 +rfi_real2virt: + ssm 0,0 /* See "relied upon translation" */ + nop /* comment in interruption.S */ + nop + nop + nop + nop + nop + nop + nop + + mtsm 0 /* disable interruptions */ + mtctl 0, %cr17 /* space 0 */ + mtctl 0, %cr17 + load32 (rfi_r2v_1), %r1 + mtctl %r1, %cr18 + ldo 4(%r1), %r1 + mtctl %r1, %cr18 + load32 KERNEL_PSW, %r1 + mtctl %r1, %cr22 + rfi + + nop + nop + nop + nop + nop + nop + nop + nop +rfi_r2v_1: + tovirt %r2 + bv 0(%r2) + nop + +#ifdef __LP64__ + +/************************ 64-bit real-mode calls ***********************/ +/* This is only usable in wide kernels right now and will probably stay so */ + .text + .export real64_call_asm + /* unsigned long real64_call_asm(unsigned long *sp, + * unsigned long *arg0p, + * unsigned long fn) + * sp is value of stack pointer to adopt before calling PDC (virt) + * arg0p points to where saved arg values may be found + * iodc_fn is the IODC function to call + */ +real64_call_asm: + std %rp, -0x10(%sp) /* save RP */ + std %sp, -8(%arg0) /* save SP on real-mode stack */ + copy %arg0, %sp /* adopt the real-mode SP */ + + /* save fn */ + copy %arg2, %r31 + + /* set up the new ap */ + ldo 64(%arg1), %r29 + + /* load up the arg registers from the saved arg area */ + /* 32-bit calling convention passes first 4 args in registers */ + ldd 0*REG_SZ(%arg1), %arg0 /* note overwriting arg0 */ + ldd 2*REG_SZ(%arg1), %arg2 + ldd 3*REG_SZ(%arg1), %arg3 + ldd 4*REG_SZ(%arg1), %r22 + ldd 5*REG_SZ(%arg1), %r21 + ldd 6*REG_SZ(%arg1), %r20 + ldd 7*REG_SZ(%arg1), %r19 + ldd 1*REG_SZ(%arg1), %arg1 /* do this one last! */ + + tophys %sp + + b,l rfi_virt2real,%r2 + nop + + b,l save_control_regs,%r2 /* modifies r1, r2, r28 */ + nop + + load32 PA(r64_ret), %r2 + bv 0(%r31) + nop +r64_ret: + /* restore CRs before going virtual in case we page fault */ + b,l restore_control_regs, %r2 /* modifies r1, r2, r26 */ + nop + + b,l rfi_real2virt,%r2 + nop + + tovirt %sp + ldd -8(%sp), %sp /* restore SP */ + ldd -0x10(%sp), %rp /* restore RP */ + bv 0(%rp) + nop + +#endif diff --git a/arch/parisc/kernel/sba_iommu.c b/arch/parisc/kernel/sba_iommu.c new file mode 100644 index 000000000..b7b541478 --- /dev/null +++ b/arch/parisc/kernel/sba_iommu.c @@ -0,0 +1,1752 @@ +/* +** System Bus Adapter (SBA) I/O MMU manager +** +** (c) Copyright 2000 Grant Grundler +** (c) Copyright 2000 Hewlett-Packard Company +** +** Portions (c) 1999 Dave S. Miller (from sparc64 I/O MMU code) +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** +** This module initializes the IOC (I/O Controller) found on B1000/C3000/ +** J5000/J7000/N-class/L-class machines and their successors. +** +** FIXME: Multi-IOC support missing - depends on hp_device data +** FIXME: add DMA hint support programming in both sba and lba modules. +*/ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/malloc.h> +#include <linux/init.h> + +#include <linux/mm.h> +#include <linux/string.h> +#define PCI_DEBUG /* for ASSERT */ +#include <linux/pci.h> +#undef PCI_DEBUG + +#include <asm/byteorder.h> +#include <asm/io.h> +#include <asm/dma.h> /* for DMA_CHUNK_SIZE */ + +#include <asm/hardware.h> /* for register_driver() stuff */ +#include <asm/gsc.h> /* FIXME: for gsc_read/gsc_write */ + +#include <linux/proc_fs.h> +#include <asm/runway.h> /* for proc_runway_root */ + + +#define MODULE_NAME "SBA" + +/* +** The number of debug flags is a clue - this code is fragile. +** Don't even think about messing with it unless you have +** plenty of 710's to sacrafice to the computer gods. :^) +*/ +#undef DEBUG_SBA_INIT +#undef DEBUG_SBA_RUN +#undef DEBUG_SBA_RUN_SG +#undef DEBUG_SBA_RESOURCE +#undef ASSERT_PDIR_SANITY +#undef DEBUG_LARGE_SG_ENTRIES + +#if 1 +#define SBA_INLINE +#else +#define SBA_INLINE __inline__ +#endif + +#ifdef DEBUG_SBA_INIT +#define DBG_INIT(x...) printk(x) +#else +#define DBG_INIT(x...) +#endif + +#ifdef DEBUG_SBA_RUN +#define DBG_RUN(x...) printk(x) +#else +#define DBG_RUN(x...) +#endif + +#ifdef DEBUG_SBA_RUN_SG +#define DBG_RUN_SG(x...) printk(x) +#else +#define DBG_RUN_SG(x...) +#endif + + +#ifdef DEBUG_SBA_RESOURCE +#define DBG_RES(x...) printk(x) +#else +#define DBG_RES(x...) +#endif + +/* +** The number of pdir entries to "free" before issueing +** a read to PCOM register to flush out PCOM writes. +** Interacts with allocation granularity (ie 4 or 8 entries +** allocated and free'd/purged at a time might make this +** less interesting). +*/ +#if 0 +#define DELAYED_RESOURCE_CNT 16 +#else +#undef DELAYED_RESOURCE_CNT +#endif + +#define DEFAULT_DMA_HINT_REG 0 + +#define ASTRO_RUNWAY_PORT 0x582 +#define ASTRO_ROPES_PORT 0x780 + +#define IKE_MERCED_PORT 0x803 +#define IKE_ROPES_PORT 0x781 + +int sba_driver_callback(struct hp_device *, struct pa_iodc_driver *); + +static struct pa_iodc_driver sba_drivers_for[] = { + +/* FIXME: why is SVERSION checked? */ + + {HPHW_IOA, ASTRO_RUNWAY_PORT, 0x0, 0xb, 0, 0x10, + DRIVER_CHECK_HVERSION + + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + MODULE_NAME, "I/O MMU", (void *) sba_driver_callback}, + + {HPHW_BCPORT, ASTRO_ROPES_PORT, 0x0, 0xb, 0, 0x10, + DRIVER_CHECK_HVERSION + + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + MODULE_NAME, "I/O MMU", (void *) sba_driver_callback}, + +#if 0 +/* FIXME : N-class! Use a different "callback"? */ + {HPHW_BCPORT, IKE_MERCED_PORT, 0x0, 0xb, 0, 0x10, + DRIVER_CHECK_HVERSION + + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + MODULE_NAME, "I/O MMU", (void *) sba_driver_callback}, + + {HPHW_BCPORT, IKE_ROPES_PORT, 0x0, 0xb, 0, 0x10, + DRIVER_CHECK_HVERSION + + DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, + MODULE_NAME, "I/O MMU", (void *) sba_driver_callback}, +#endif + + {0,0,0,0,0,0, + 0, + (char *) NULL, (char *) NULL, (void *) NULL } +}; + + +#define SBA_FUNC_ID 0x0000 /* function id */ +#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */ + +#define IS_ASTRO(id) ( \ + (((id)->hw_type == HPHW_IOA) && ((id)->hversion == ASTRO_RUNWAY_PORT)) || \ + (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == ASTRO_ROPES_PORT)) \ +) + +#define CONFIG_FUNC_SIZE 4096 /* SBA configuration function reg set */ + +#define ASTRO_IOC_OFFSET 0x20000 +/* Ike's IOC's occupy functions 2 and 3 (not 0 and 1) */ +#define IKE_IOC_OFFSET(p) ((p+2)*CONFIG_FUNC_SIZE) + +#define IOC_CTRL 0x8 /* IOC_CTRL offset */ +#define IOC_CTRL_TE (0x1 << 0) /* TOC Enable */ +#define IOC_CTRL_RM (0x1 << 8) /* Real Mode */ +#define IOC_CTRL_NC (0x1 << 9) /* Non Coherent Mode */ + +#define MAX_IOC 2 /* per Ike. Astro only has 1 */ + + +/* +** Offsets into MBIB (Function 0 on Ike and hopefully Astro) +** Firmware programs this stuff. Don't touch it. +*/ +#define IOS_DIST_BASE 0x390 +#define IOS_DIST_MASK 0x398 +#define IOS_DIST_ROUTE 0x3A0 + +#define IOS_DIRECT_BASE 0x3C0 +#define IOS_DIRECT_MASK 0x3C8 +#define IOS_DIRECT_ROUTE 0x3D0 + +/* +** Offsets into I/O TLB (Function 2 and 3 on Ike) +*/ +#define ROPE0_CTL 0x200 /* "regbus pci0" */ +#define ROPE1_CTL 0x208 +#define ROPE2_CTL 0x210 +#define ROPE3_CTL 0x218 +#define ROPE4_CTL 0x220 +#define ROPE5_CTL 0x228 +#define ROPE6_CTL 0x230 +#define ROPE7_CTL 0x238 + +#define HF_ENABLE 0x40 + + +#define IOC_IBASE 0x300 /* IO TLB */ +#define IOC_IMASK 0x308 +#define IOC_PCOM 0x310 +#define IOC_TCNFG 0x318 +#define IOC_PDIR_BASE 0x320 + +#define IOC_IOVA_SPACE_BASE 0 /* IOVA ranges start at 0 */ + +/* +** IOC supports 4/8/16/64KB page sizes (see TCNFG register) +** It's safer (avoid memory corruption) to keep DMA page mappings +** equivalently sized to VM PAGE_SIZE. +** +** We really can't avoid generating a new mapping for each +** page since the Virtual Coherence Index has to be generated +** and updated for each page. +** +** IOVP_SIZE could only be greater than PAGE_SIZE if we are +** confident the drivers really only touch the next physical +** page iff that driver instance owns it. +*/ +#define IOVP_SIZE PAGE_SIZE +#define IOVP_SHIFT PAGE_SHIFT +#define IOVP_MASK PAGE_MASK + +#define SBA_PERF_CFG 0x708 /* Performance Counter stuff */ +#define SBA_PERF_MASK1 0x718 +#define SBA_PERF_MASK2 0x730 + + +/* +** Offsets into PCI Performance Counters (functions 12 and 13) +** Controlled by PERF registers in function 2 & 3 respectively. +*/ +#define SBA_PERF_CNT1 0x200 +#define SBA_PERF_CNT2 0x208 +#define SBA_PERF_CNT3 0x210 + + +struct ioc { + char *ioc_hpa; /* I/O MMU base address */ + char *res_map; /* resource map, bit == pdir entry */ + u64 *pdir_base; /* physical base address */ + + unsigned long *res_hint; /* next available IOVP - circular search */ + unsigned int res_bitshift; /* from the LEFT! */ + unsigned int res_size; /* size of resource map in bytes */ + unsigned int hint_shift_pdir; + spinlock_t res_lock; + unsigned long hint_mask_pdir; /* bits used for DMA hints */ +#ifdef DELAYED_RESOURCE_CNT + dma_addr_t res_delay[DELAYED_RESOURCE_CNT]; +#endif + +#ifdef CONFIG_PROC_FS +#define SBA_SEARCH_SAMPLE 0x100 + unsigned long avg_search[SBA_SEARCH_SAMPLE]; + unsigned long avg_idx; /* current index into avg_search */ + unsigned long used_pages; + unsigned long msingle_calls; + unsigned long msingle_pages; + unsigned long msg_calls; + unsigned long msg_pages; + unsigned long usingle_calls; + unsigned long usingle_pages; + unsigned long usg_calls; + unsigned long usg_pages; +#endif + + /* STUFF We don't need in performance path */ + unsigned int pdir_size; /* in bytes, determined by IOV Space size */ + unsigned long ibase; /* pdir IOV Space base - shared w/lba_pci */ + unsigned long imask; /* pdir IOV Space mask - shared w/lba_pci */ +}; + +struct sba_device { + struct sba_device *next; /* list of LBA's in system */ + struct hp_device *iodc; /* data about dev from firmware */ + char *sba_hpa; /* base address */ + spinlock_t sba_lock; + unsigned int flags; /* state/functionality enabled */ + unsigned int hw_rev; /* HW revision of chip */ + + unsigned int num_ioc; /* number of on-board IOC's */ + struct ioc ioc[MAX_IOC]; +}; + + +static struct sba_device *sba_list; +static int sba_count; + +/* Ratio of Host MEM to IOV Space size */ +static unsigned long sba_mem_ratio = 4; + +/* Looks nice and keeps the compiler happy */ +#define SBA_DEV(d) ((struct sba_device *) (d)) + + +#define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1)) + + +/************************************ +** SBA register read and write support +** +** BE WARNED: register writes are posted. +** (ie follow writes which must reach HW with a read) +*/ +#define READ_U8(addr) gsc_readb(addr) +#define READ_U16(addr) gsc_readw((u16 *) (addr)) +#define READ_U32(addr) gsc_readl((u32 *) (addr)) +#define WRITE_U8(value, addr) gsc_writeb(value, addr) +#define WRITE_U16(value, addr) gsc_writew(value, (u16 *) (addr)) +#define WRITE_U32(value, addr) gsc_writel(value, (u32 *) (addr)) + +#define READ_REG8(addr) gsc_readb(addr) +#define READ_REG16(addr) le16_to_cpu(gsc_readw((u16 *) (addr))) +#define READ_REG32(addr) le32_to_cpu(gsc_readl((u32 *) (addr))) +#define READ_REG64(addr) le64_to_cpu(gsc_readq((u64 *) (addr))) +#define WRITE_REG8(value, addr) gsc_writeb(value, addr) +#define WRITE_REG16(value, addr) gsc_writew(cpu_to_le16(value), (u16 *) (addr)) +#define WRITE_REG32(value, addr) gsc_writel(cpu_to_le32(value), (u32 *) (addr)) +#define WRITE_REG64(value, addr) gsc_writeq(cpu_to_le64(value), (u64 *) (addr)) + +#ifdef DEBUG_SBA_INIT + +static void +sba_dump_ranges(char *hpa) +{ + printk("SBA at 0x%p\n", hpa); + printk("IOS_DIST_BASE : %08x %08x\n", + READ_REG32(hpa+IOS_DIST_BASE+4), + READ_REG32(hpa+IOS_DIST_BASE)); + printk("IOS_DIST_MASK : %08x %08x\n", + READ_REG32(hpa+IOS_DIST_MASK+4), + READ_REG32(hpa+IOS_DIST_MASK)); + printk("IOS_DIST_ROUTE : %08x %08x\n", + READ_REG32(hpa+IOS_DIST_ROUTE+4), + READ_REG32(hpa+IOS_DIST_ROUTE)); + printk("\n"); + printk("IOS_DIRECT_BASE : %08x %08x\n", + READ_REG32(hpa+IOS_DIRECT_BASE+4), + READ_REG32(hpa+IOS_DIRECT_BASE)); + printk("IOS_DIRECT_MASK : %08x %08x\n", + READ_REG32(hpa+IOS_DIRECT_MASK+4), + READ_REG32(hpa+IOS_DIRECT_MASK)); + printk("IOS_DIRECT_ROUTE: %08x %08x\n", + READ_REG32(hpa+IOS_DIRECT_ROUTE+4), + READ_REG32(hpa+IOS_DIRECT_ROUTE)); +} + +static void +sba_dump_tlb(char *hpa) +{ + printk("IO TLB at 0x%p\n", hpa); + printk("IOC_IBASE : %08x %08x\n", + READ_REG32(hpa+IOC_IBASE+4), + READ_REG32(hpa+IOC_IBASE)); + printk("IOC_IMASK : %08x %08x\n", + READ_REG32(hpa+IOC_IMASK+4), + READ_REG32(hpa+IOC_IMASK)); + printk("IOC_TCNFG : %08x %08x\n", + READ_REG32(hpa+IOC_TCNFG+4), + READ_REG32(hpa+IOC_TCNFG)); + printk("IOC_PDIR_BASE: %08x %08x\n", + READ_REG32(hpa+IOC_PDIR_BASE+4), + READ_REG32(hpa+IOC_PDIR_BASE)); + printk("\n"); +} +#endif + + +#ifdef ASSERT_PDIR_SANITY + +static void +sba_dump_pdir_entry(struct ioc *ioc, char *msg, uint pide) +{ + /* start printing from lowest pde in rval */ + u64 *ptr = &(ioc->pdir_base[pide & (~0U * BITS_PER_LONG)]); + unsigned long *rptr = (unsigned long *) &(ioc->res_map[(pide >>3) & ~(sizeof(unsigned long) - 1)]); + uint rcnt; + + printk("SBA: %s rp %p bit %d rval 0x%lx\n", + msg, + rptr, pide & (BITS_PER_LONG - 1), *rptr); + + rcnt = 0; + while (rcnt < BITS_PER_LONG) { + printk("%s %2d %p %016Lx\n", + (rcnt == (pide & (BITS_PER_LONG - 1))) + ? " -->" : " ", + rcnt, ptr, *ptr ); + rcnt++; + ptr++; + } + printk(msg); +} + + +/* Verify the resource map and pdir state is consistent */ +static int +sba_check_pdir(struct ioc *ioc, char *msg) +{ + u32 *rptr_end = (u32 *) &(ioc->res_map[ioc->res_size]); + u32 *rptr = (u32 *) ioc->res_map; /* resource map ptr */ + u64 *pptr = ioc->pdir_base; /* pdir ptr */ + uint pide = 0; + + while (rptr < rptr_end) { + u32 rval = *rptr; + int rcnt = 32; /* number of bits we might check */ + + while (rcnt) { + /* Get last byte and highest bit from that */ + u32 pde = ((u32) (((char *)pptr)[7])) << 24; + if ((rval ^ pde) & 0x80000000) + { + /* + ** BUMMER! -- res_map != pdir -- + ** Dump rval and matching pdir entries + */ + sba_dump_pdir_entry(ioc, msg, pide); + return(1); + } + rcnt--; + rval <<= 1; /* try the next bit */ + pptr++; + pide++; + } + rptr++; /* look at next word of res_map */ + } + /* It'd be nice if we always got here :^) */ + return 0; +} + + +static void +sba_dump_sg( struct ioc *ioc, struct scatterlist *startsg, int nents) +{ + while (nents-- > 0) { + printk(" %d : %08lx/%05x %p/%05x\n", + nents, + (unsigned long) sg_dma_address(startsg), + sg_dma_len(startsg), + startsg->address, startsg->length); + startsg++; + } +} + +#endif /* ASSERT_PDIR_SANITY */ + + + +/* +** One time initialization to let the world know the LBA was found. +** This is the only routine which is NOT static. +** Must be called exactly once before pci_init(). +*/ +void __init +sba_init(void) +{ + sba_list = (struct sba_device *) NULL; + sba_count = 0; + +#ifdef DEBUG_SBA_INIT + sba_dump_ranges((char *) 0xFED00000L); +#endif + + register_driver(sba_drivers_for); +} + + + +/************************************************************** +* +* I/O Pdir Resource Management +* +* Bits set in the resource map are in use. +* Each bit can represent a number of pages. +* LSbs represent lower addresses (IOVA's). +* +***************************************************************/ +#define PAGES_PER_RANGE 1 /* could increase this to 4 or 8 if needed */ + +/* Convert from IOVP to IOVA and vice versa. */ +#define SBA_IOVA(ioc,iovp,offset,hint_reg) ((iovp) | (offset) | ((hint_reg)<<(ioc->hint_shift_pdir))) +#define SBA_IOVP(ioc,iova) ((iova) & ioc->hint_mask_pdir) + +/* FIXME : review these macros to verify correctness and usage */ +#define PDIR_INDEX(iovp) ((iovp)>>IOVP_SHIFT) +#define MKIOVP(dma_hint,pide) (dma_addr_t)((long)(dma_hint) | ((long)(pide) << IOVP_SHIFT)) +#define MKIOVA(iovp,offset) (dma_addr_t)((long)iovp | (long)offset) + +#define RESMAP_MASK(n) (~0UL << (BITS_PER_LONG - (n))) +#define RESMAP_IDX_MASK (sizeof(unsigned long) - 1) + + +/* +** Perf optimizations: +** o search for log2(size) bits at a time. +** +** Search should use register width as "stride" to search the res_map. +*/ + +static SBA_INLINE unsigned long +sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted) +{ + unsigned long *res_ptr = ioc->res_hint; + unsigned long *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]); + unsigned long pide = ~0UL; + + ASSERT(((unsigned long) ioc->res_hint & (sizeof(unsigned long) - 1UL)) == 0); + ASSERT(res_ptr < res_end); + if (bits_wanted > (BITS_PER_LONG/2)) { + /* Search word at a time - no mask needed */ + for(; res_ptr < res_end; ++res_ptr) { + if (*res_ptr == 0) { + *res_ptr = RESMAP_MASK(bits_wanted); + pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map); + pide <<= 3; /* convert to bit address */ + ASSERT(0 != pide); + break; + } + } + /* point to the next word on next pass */ + res_ptr++; + ioc->res_bitshift = 0; + } else { + /* + ** Search the resource bit map on well-aligned values. + ** "o" is the alignment. + ** We need the alignment to invalidate I/O TLB using + ** SBA HW features in the unmap path. + */ + unsigned long o = 1 << get_order(bits_wanted << PAGE_SHIFT); + uint bitshiftcnt = ROUNDUP(ioc->res_bitshift, o); + unsigned long mask; + + if (bitshiftcnt >= BITS_PER_LONG) { + bitshiftcnt = 0; + res_ptr++; + } + mask = RESMAP_MASK(bits_wanted) >> bitshiftcnt; + + DBG_RES("sba_search_bitmap() o %ld %p", o, res_ptr); + while(res_ptr < res_end) + { + DBG_RES(" %p %lx %lx\n", res_ptr, mask, *res_ptr); + ASSERT(0 != mask); + if(0 == ((*res_ptr) & mask)) { + *res_ptr |= mask; /* mark resources busy! */ + pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map); + pide <<= 3; /* convert to bit address */ + pide += bitshiftcnt; + ASSERT(0 != pide); + break; + } + mask >>= o; + bitshiftcnt += o; + if (0 == mask) { + mask = RESMAP_MASK(bits_wanted); + bitshiftcnt=0; + res_ptr++; + } + } + /* look in the same word on the next pass */ + ioc->res_bitshift = bitshiftcnt + bits_wanted; + } + + /* wrapped ? */ + ioc->res_hint = (res_end == res_ptr) ? (unsigned long *) ioc->res_map : res_ptr; + return (pide); +} + + +static int +sba_alloc_range(struct ioc *ioc, size_t size) +{ + unsigned int pages_needed = size >> IOVP_SHIFT; +#ifdef CONFIG_PROC_FS + unsigned long cr_start = mfctl(16); +#endif + unsigned long pide; + + ASSERT(pages_needed); + ASSERT((pages_needed * IOVP_SIZE) < DMA_CHUNK_SIZE); + ASSERT(pages_needed < BITS_PER_LONG); + ASSERT(0 == (size & ~IOVP_MASK)); + + /* + ** "seek and ye shall find"...praying never hurts either... + ** ggg sacrifices another 710 to the computer gods. + */ + + pide = sba_search_bitmap(ioc, pages_needed); + if (pide >= (ioc->res_size << 3)) { + pide = sba_search_bitmap(ioc, pages_needed); + if (pide >= (ioc->res_size << 3)) + panic(__FILE__ ": I/O MMU @ %p is out of mapping resources\n", ioc->ioc_hpa); + } + +#ifdef ASSERT_PDIR_SANITY + /* verify the first enable bit is clear */ + if(0x00 != ((u8 *) ioc->pdir_base)[pide*sizeof(u64) + 7]) { + sba_dump_pdir_entry(ioc, "sba_search_bitmap() botched it?", pide); + } +#endif + + DBG_RES("sba_alloc_range(%x) %d -> %lx hint %x/%x\n", + size, pages_needed, pide, + (uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map), + ioc->res_bitshift ); + +#ifdef CONFIG_PROC_FS + { + unsigned long cr_end = mfctl(16); + unsigned long tmp = cr_end - cr_start; + /* check for roll over */ + cr_start = (cr_end < cr_start) ? -(tmp) : (tmp); + } + ioc->avg_search[ioc->avg_idx++] = cr_start; + ioc->avg_idx &= SBA_SEARCH_SAMPLE - 1; + + ioc->used_pages += pages_needed; +#endif + + return (pide); +} + + +/* +** clear bits in the ioc's resource map +*/ +static SBA_INLINE void +sba_free_range(struct ioc *ioc, dma_addr_t iova, size_t size) +{ + unsigned long iovp = SBA_IOVP(ioc, iova); + unsigned int pide = PDIR_INDEX(iovp); + unsigned int ridx = pide >> 3; /* convert bit to byte address */ + unsigned long *res_ptr = (unsigned long *) &((ioc)->res_map[ridx & ~RESMAP_IDX_MASK]); + + int bits_not_wanted = size >> IOVP_SHIFT; + + /* 3-bits "bit" address plus 2 (or 3) bits for "byte" == bit in word */ + unsigned long m = RESMAP_MASK(bits_not_wanted) >> (pide & (BITS_PER_LONG - 1)); + + DBG_RES("sba_free_range( ,%x,%x) %x/%lx %x %p %lx\n", + (uint) iova, size, + bits_not_wanted, m, pide, res_ptr, *res_ptr); + +#ifdef CONFIG_PROC_FS + ioc->used_pages -= bits_not_wanted; +#endif + + ASSERT(m != 0); + ASSERT(bits_not_wanted); + ASSERT((bits_not_wanted * IOVP_SIZE) < DMA_CHUNK_SIZE); + ASSERT(bits_not_wanted < BITS_PER_LONG); + ASSERT((*res_ptr & m) == m); /* verify same bits are set */ + *res_ptr &= ~m; +} + + +/************************************************************** +* +* "Dynamic DMA Mapping" support (aka "Coherent I/O") +* +***************************************************************/ + +#define SBA_DMA_HINT(ioc, val) ((val) << (ioc)->hint_shift_pdir) + + +typedef unsigned long space_t; +#define KERNEL_SPACE 0 + +/* +* SBA Mapping Routine +* +* Given a virtual address (vba, arg2) and space id, (sid, arg1) +* sba_io_pdir_entry() loads the I/O PDIR entry pointed to by +* pdir_ptr (arg0). Each IO Pdir entry consists of 8 bytes as +* shown below (MSB == bit 0): +* +* 0 19 51 55 63 +* +-+---------------------+----------------------------------+----+--------+ +* |V| U | PPN[43:12] | U | VI | +* +-+---------------------+----------------------------------+----+--------+ +* +* V == Valid Bit +* U == Unused +* PPN == Physical Page Number +* VI == Virtual Index (aka Coherent Index) +* +* The physical address fields are filled with the results of the LPA +* instruction. The virtual index field is filled with the results of +* of the LCI (Load Coherence Index) instruction. The 8 bits used for +* the virtual index are bits 12:19 of the value returned by LCI. +* +* We need to pre-swap the bytes since PCX-W is Big Endian. +*/ + +void SBA_INLINE +sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba) +{ + u64 pa; /* physical address */ + register unsigned ci; /* coherent index */ + + /* We currently only support kernel addresses */ + ASSERT(sid == 0); + ASSERT(((unsigned long) vba & 0xc0000000UL) == 0xc0000000UL); + + pa = virt_to_phys(vba); + pa &= ~4095ULL; /* clear out offset bits */ + + mtsp(sid,1); + asm("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba)); + pa |= (ci >> 12) & 0xff; /* move CI (8 bits) into lowest byte */ + + pa |= 0x8000000000000000ULL; /* set "valid" bit */ + *pdir_ptr = cpu_to_le64(pa); /* swap and store into I/O Pdir */ +} + + +/*********************************************************** + * The Ike PCOM (Purge Command Register) is to purge + * stale entries in the IO TLB when unmapping entries. + * + * The PCOM register supports purging of multiple pages, with a minium + * of 1 page and a maximum of 2GB. Hardware requires the address be + * aligned to the size of the range being purged. The size of the range + * must be a power of 2. + ***********************************************************/ +static SBA_INLINE void +sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) +{ + u32 iovp = (u32) SBA_IOVP(ioc,iova); + + /* Even though this is a big-endian machine, the entries + ** in the iopdir are swapped. That's why we clear the byte + ** at +7 instead of at +0. + */ + int off = PDIR_INDEX(iovp)*sizeof(u64)+7; + + /* Must be non-zero and rounded up */ + ASSERT(byte_cnt > 0); + ASSERT(0 == (byte_cnt & ~IOVP_MASK)); + +#ifdef ASSERT_PDIR_SANITY + /* Assert first pdir entry is set */ + if (0x80 != (((u8 *) ioc->pdir_base)[off])) { + sba_dump_pdir_entry(ioc,"sba_mark_invalid()", PDIR_INDEX(iovp)); + } +#endif + + if (byte_cnt <= IOVP_SIZE) + { + ASSERT( off < ioc->pdir_size); + + iovp |= IOVP_SHIFT; /* set "size" field for PCOM */ + + /* + ** clear I/O PDIR entry "valid" bit + ** Do NOT clear the rest - save it for debugging. + ** We should only clear bits that have previously + ** been enabled. + */ + ((u8 *)(ioc->pdir_base))[off] = 0; + } else { + u32 t = get_order(byte_cnt) + PAGE_SHIFT; + + iovp |= t; + ASSERT(t <= 31); /* 2GB! Max value of "size" field */ + + do { + /* verify this pdir entry is enabled */ + ASSERT(0x80 == (((u8 *) ioc->pdir_base)[off] & 0x80)); + /* clear I/O Pdir entry "valid" bit first */ + ((u8 *)(ioc->pdir_base))[off] = 0; + off += sizeof(u64); + byte_cnt -= IOVP_SIZE; + } while (byte_cnt > 0); + } + + WRITE_REG32(iovp, ioc->ioc_hpa+IOC_PCOM); +} + +static int +sba_dma_supported( struct pci_dev *dev, dma_addr_t mask) +{ + if (dev == NULL) { + printk(MODULE_NAME ": EISA/ISA/et al not supported\n"); + BUG(); + return(0); + } + + dev->dma_mask = mask; /* save it */ + + /* only support PCI devices */ + return((int) (mask >= 0xffffffff)); +} + + +/* +** map_single returns a fully formed IOVA +*/ +static dma_addr_t +sba_map_single(struct pci_dev *dev, void *addr, size_t size, int direction) +{ + struct ioc *ioc = &sba_list->ioc[0]; /* FIXME : see Multi-IOC below */ + unsigned long flags; + dma_addr_t iovp; + dma_addr_t offset; + u64 *pdir_start; + int pide; + + ASSERT(size > 0); + + /* save offset bits */ + offset = ((dma_addr_t) addr) & ~IOVP_MASK; + + /* round up to nearest IOVP_SIZE */ + size = (size + offset + ~IOVP_MASK) & IOVP_MASK; + + spin_lock_irqsave(&ioc->res_lock, flags); +#ifdef ASSERT_PDIR_SANITY + sba_check_pdir(ioc,"Check before sba_map_single()"); +#endif + +#ifdef CONFIG_PROC_FS + ioc->msingle_calls++; + ioc->msingle_pages += size >> IOVP_SHIFT; +#endif + pide = sba_alloc_range(ioc, size); + iovp = (dma_addr_t) pide << IOVP_SHIFT; + + DBG_RUN("sba_map_single() 0x%p -> 0x%lx", addr, (long) iovp | offset); + + pdir_start = &(ioc->pdir_base[pide]); + + while (size > 0) { + ASSERT(((u8 *)pdir_start)[7] == 0); /* verify availability */ + sba_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long) addr); + + DBG_RUN(" pdir 0x%p %02x%02x%02x%02x%02x%02x%02x%02x\n", + pdir_start, + (u8) (((u8 *) pdir_start)[7]), + (u8) (((u8 *) pdir_start)[6]), + (u8) (((u8 *) pdir_start)[5]), + (u8) (((u8 *) pdir_start)[4]), + (u8) (((u8 *) pdir_start)[3]), + (u8) (((u8 *) pdir_start)[2]), + (u8) (((u8 *) pdir_start)[1]), + (u8) (((u8 *) pdir_start)[0]) + ); + + addr += IOVP_SIZE; + size -= IOVP_SIZE; + pdir_start++; + } + /* form complete address */ +#ifdef ASSERT_PDIR_SANITY + sba_check_pdir(ioc,"Check after sba_map_single()"); +#endif + spin_unlock_irqrestore(&ioc->res_lock, flags); + return SBA_IOVA(ioc, iovp, offset, DEFAULT_DMA_HINT_REG); +} + + +static void +sba_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, int direction) +{ +#ifdef FIXME +/* Multi-IOC (ie N-class) : need to lookup IOC from dev +** o If we can't know about lba PCI data structs, that eliminates ->sysdata. +** o walking up pcidev->parent dead ends at elroy too +** o leaves hashing dev->bus->number into some lookup. +** (may only work for N-class) +** o use (struct pci_hba) and put fields in there for DMA. +** (ioc and per device dma_hint.) +** +** Last one seems the clearest and most promising. +** sba_dma_supported() fill in those fields when the driver queries +** the system for support. +*/ + struct ioc *ioc = (struct ioc *) ((struct pci_hba *) (dev->sysdata))->dma_data; +#else + struct ioc *ioc = &sba_list->ioc[0]; +#endif + + unsigned long flags; + dma_addr_t offset; + offset = iova & ~IOVP_MASK; + + DBG_RUN("%s() iovp 0x%lx/%x\n", __FUNCTION__, (long) iova, size); + + iova ^= offset; /* clear offset bits */ + size += offset; + size = ROUNDUP(size, IOVP_SIZE); + + ASSERT(0 != iova); + + spin_lock_irqsave(&ioc->res_lock, flags); +#ifdef CONFIG_PROC_FS + ioc->usingle_calls++; + ioc->usingle_pages += size >> IOVP_SHIFT; +#endif +#ifdef DELAYED_RESOURCE_CNT + if (ioc->saved_cnt < DELAYED_RESOURCE_CNT) { + ioc->saved_iova[ioc->saved_cnt] = iova; + ioc->saved_size[ioc->saved_cnt] = size; + ioc_saved_cnt++; + } else { + do { +#endif + sba_mark_invalid(ioc, iova, size); + sba_free_range(ioc, iova, size); + +#ifdef DELAYED_RESOURCE_CNT + ioc->saved_cnt--; + iova = ioc->saved_iova[ioc->saved_cnt]; + size = ioc->saved_size[ioc->saved_cnt]; + } while (ioc->saved_cnt) + + /* flush purges */ + (void) (volatile) READ_REG32(ioc->ioc_hpa+IOC_PCOM); + } +#else + /* flush purges */ + READ_REG32(ioc->ioc_hpa+IOC_PCOM); +#endif + spin_unlock_irqrestore(&ioc->res_lock, flags); +} + + +static void * +sba_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) +{ + void *ret; + + if (!hwdev) { + /* only support PCI */ + *dma_handle = 0; + return 0; + } + + ret = (void *) __get_free_pages(GFP_ATOMIC, get_order(size)); + + if (ret) { + memset(ret, 0, size); + *dma_handle = sba_map_single(hwdev, ret, size, 0); + } + + return ret; +} + + +static void +sba_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) +{ + sba_unmap_single(hwdev, dma_handle, size, 0); + free_pages((unsigned long) vaddr, get_order(size)); +} + +/* +** Two address ranges are "virtually contiguous" iff: +** 1) end of prev == start of next, or... append case +** 3) end of next == start of prev prepend case +** +** and they are DMA contiguous *iff*: +** 2) end of prev and start of next are both on a page boundry +** +** (shift left is a quick trick to mask off upper bits) +*/ +#define DMA_CONTIG(__X, __Y) \ + (((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL) + +/* +** Assumption is two transactions are mutually exclusive. +** ie both go to different parts of memory. +** If both are true, then both transaction are on the same page. +*/ +#define DMA_SAME_PAGE(s1,e1,s2,e2) \ + ( ((((s1) ^ (s2)) >> PAGE_SHIFT) == 0) \ + && ((((e1) ^ (e2)) >> PAGE_SHIFT) == 0) ) + +/* +** Since 0 is a valid pdir_base index value, can't use that +** to determine if a value is valid or not. Use a flag to indicate +** the SG list entry contains a valid pdir index. +*/ +#define PIDE_FLAG 0x80000000UL + +#ifdef DEBUG_LARGE_SG_ENTRIES +int dump_run_sg = 0; +#endif + +static SBA_INLINE int +sba_fill_pdir( + struct ioc *ioc, + struct scatterlist *startsg, + int nents) +{ + struct scatterlist *dma_sg = startsg; /* pointer to current DMA */ + int n_mappings = 0; + u64 *pdirp = 0; + unsigned long dma_offset = 0; + + dma_sg--; + while (nents-- > 0) { + int cnt = sg_dma_len(startsg); + sg_dma_len(startsg) = 0; + +#ifdef DEBUG_LARGE_SG_ENTRIES + if (dump_run_sg) + printk(" %d : %08lx/%05x %p/%05x\n", + nents, + (unsigned long) sg_dma_address(startsg), cnt, + startsg->address, startsg->length + ); +#else + DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n", + nents, + (unsigned long) sg_dma_address(startsg), cnt, + startsg->address, startsg->length + ); +#endif + /* + ** Look for the start of a new DMA stream + */ + if (sg_dma_address(startsg) & PIDE_FLAG) { + u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG; + dma_offset = (unsigned long) pide & ~IOVP_MASK; + pide >>= IOVP_SHIFT; + pdirp = &(ioc->pdir_base[pide]); + sg_dma_address(startsg) = 0; + ++dma_sg; + sg_dma_address(dma_sg) = (pide << IOVP_SHIFT) + dma_offset; + n_mappings++; + } + + /* + ** Look for a VCONTIG chunk + */ + if (cnt) { + unsigned long vaddr = (unsigned long) startsg->address; + ASSERT(pdirp); + + sg_dma_len(dma_sg) += cnt; + cnt += dma_offset; + dma_offset=0; /* only want offset on first chunk */ + cnt = ROUNDUP(cnt, IOVP_SIZE); +#ifdef CONFIG_PROC_FS + ioc->msg_pages += cnt >> IOVP_SHIFT; +#endif + do { + sba_io_pdir_entry(pdirp, KERNEL_SPACE, vaddr); + vaddr += IOVP_SIZE; + cnt -= IOVP_SIZE; + pdirp++; + } while (cnt > 0); + } + startsg++; + } +#ifdef DEBUG_LARGE_SG_ENTRIES + dump_run_sg = 0; +#endif + return(n_mappings); +} + + + +/* +** First pass is to walk the SG list and determine where the breaks are +** in the DMA stream. Allocates PDIR entries but does not fill them. +** Returns the number of DMA chunks. +** +** Doing the fill seperate from the coalescing/allocation keeps the +** code simpler. Future enhancement could make one pass through +** the sglist do both. +*/ +static SBA_INLINE int +sba_coalesce_chunks( struct ioc *ioc, + struct scatterlist *startsg, + int nents) +{ + int n_mappings = 0; + + while (nents > 0) { + struct scatterlist *dma_sg; /* next DMA stream head */ + unsigned long dma_offset, dma_len; /* start/len of DMA stream */ + struct scatterlist *chunksg; /* virtually contig chunk head */ + unsigned long chunk_addr, chunk_len; /* start/len of VCONTIG chunk */ + + /* + ** Prepare for first/next DMA stream + */ + dma_sg = chunksg = startsg; + dma_len = chunk_len = startsg->length; + chunk_addr = (unsigned long) startsg->address; + dma_offset = 0UL; + + /* + ** This loop terminates one iteration "early" since + ** it's always looking one "ahead". + */ + while (--nents > 0) { + /* ptr to coalesce prev and next */ + struct scatterlist *prev_sg = startsg; + unsigned long prev_end = (unsigned long) prev_sg->address + prev_sg->length; + unsigned long current_end; + + /* PARANOID: clear entries */ + sg_dma_address(startsg) = 0; + sg_dma_len(startsg) = 0; + + /* Now start looking ahead */ + startsg++; + current_end = (unsigned long) startsg->address + startsg->length; + + /* + ** First look for virtually contiguous blocks. + ** PARISC needs this since it's cache is virtually + ** indexed and we need the associated virtual + ** address for each I/O address we map. + ** + ** 1) can we *prepend* the next transaction? + */ + if (current_end == (unsigned long) prev_sg->address) + { + /* prepend : get new offset */ + chunksg = startsg; + chunk_addr = (unsigned long) prev_sg->address; + chunk_len += startsg->length; + dma_len += startsg->length; + continue; + } + + /* + ** 2) or append the next transaction? + */ + if (prev_end == (unsigned long) startsg->address) + { + chunk_len += startsg->length; + dma_len += startsg->length; + continue; + } + +#ifdef DEBUG_LARGE_SG_ENTRIES + dump_run_sg = (chunk_len > IOVP_SIZE); +#endif + /* + ** Not virtually contigous. + ** Terminate prev chunk. + ** Start a new chunk. + ** + ** Once we start a new VCONTIG chunk, the offset + ** can't change. And we need the offset from the first + ** chunk - not the last one. Ergo Successive chunks + ** must start on page boundaries and dove tail + ** with it's predecessor. + */ + sg_dma_len(prev_sg) = chunk_len; + + chunk_len = startsg->length; + dma_offset |= (chunk_addr & ~IOVP_MASK); + ASSERT((0 == (chunk_addr & ~IOVP_MASK)) || + (dma_offset == (chunk_addr & ~IOVP_MASK))); + +#if 0 + /* + ** 4) do the chunks end/start on page boundaries? + ** Easier than 3 since no offsets are involved. + */ + if (DMA_CONTIG(prev_end, startsg->address)) + { + /* + ** Yes. + ** Reset chunk ptr. + */ + chunksg = startsg; + chunk_addr = (unsigned long) startsg->address; + + continue; + } else +#endif + { + break; + } + } + + /* + ** End of DMA Stream + ** Terminate chunk. + ** Allocate space for DMA stream. + */ + sg_dma_len(startsg) = chunk_len; + dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK; + sg_dma_address(dma_sg) = + PIDE_FLAG + | (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT) + | dma_offset; + n_mappings++; + } + + return n_mappings; +} + + +/* +** And this algorithm still generally only ends up coalescing entries +** that happens to be on the same page due to how sglists are assembled. +*/ +static int +sba_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +{ + struct ioc *ioc = &sba_list->ioc[0]; /* FIXME : see Multi-IOC below */ + int coalesced, filled = 0; + unsigned long flags; + + DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents); + + /* Fast path single entry scatterlists. */ + if (nents == 1) { + sg_dma_address(sglist)= sba_map_single(dev, sglist->address, + sglist->length, direction); + sg_dma_len(sglist)= sglist->length; + return 1; + } + + spin_lock_irqsave(&ioc->res_lock, flags); + +#ifdef ASSERT_PDIR_SANITY + if (sba_check_pdir(ioc,"Check before sba_map_sg()")) + { + sba_dump_sg(ioc, sglist, nents); + panic("Check before sba_map_sg()"); + } +#endif + +#ifdef CONFIG_PROC_FS + ioc->msg_calls++; +#endif + + /* + ** First coalesce the chunks and allocate I/O pdir space + ** + ** If this is one DMA stream, we can properly map using the + ** correct virtual address associated with each DMA page. + ** w/o this association, we wouldn't have coherent DMA! + ** Access to the virtual address is what forces a two pass algorithm. + */ + coalesced = sba_coalesce_chunks(ioc, sglist, nents); + + /* + ** Program the I/O Pdir + ** + ** map the virtual addresses to the I/O Pdir + ** o dma_address will contain the pdir index + ** o dma_len will contain the number of bytes to map + ** o address contains the virtual address. + */ + filled = sba_fill_pdir(ioc, sglist, nents); + +#ifdef ASSERT_PDIR_SANITY + if (sba_check_pdir(ioc,"Check after sba_map_sg()")) + { + sba_dump_sg(ioc, sglist, nents); + panic("Check after sba_map_sg()\n"); + } +#endif + + spin_unlock_irqrestore(&ioc->res_lock, flags); + + ASSERT(coalesced == filled); + DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled); + + return filled; +} + + +static void +sba_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +{ + struct ioc *ioc = &sba_list->ioc[0]; /* FIXME : see Multi-IOC below */ +#ifdef ASSERT_PDIR_SANITY + unsigned long flags; +#endif + + DBG_RUN_SG("%s() START %d entries, %p,%x\n", + __FUNCTION__, nents, sglist->address, sglist->length); + +#ifdef CONFIG_PROC_FS + ioc->usg_calls++; +#endif + +#ifdef ASSERT_PDIR_SANITY + spin_lock_irqsave(&ioc->res_lock, flags); + sba_check_pdir(ioc,"Check before sba_unmap_sg()"); + spin_unlock_irqrestore(&ioc->res_lock, flags); +#endif + + while (sg_dma_len(sglist) && nents--) { + +#ifdef CONFIG_PROC_FS + ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT; +#endif + sba_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction); + ++sglist; + } + + DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__, nents); + +#ifdef ASSERT_PDIR_SANITY + spin_lock_irqsave(&ioc->res_lock, flags); + sba_check_pdir(ioc,"Check after sba_unmap_sg()"); + spin_unlock_irqrestore(&ioc->res_lock, flags); +#endif + +} + +static struct pci_dma_ops sba_ops = { + sba_dma_supported, + sba_alloc_consistent, /* allocate cacheable host mem */ + sba_free_consistent, /* release cacheable host mem */ + sba_map_single, + sba_unmap_single, + sba_map_sg, + sba_unmap_sg, + NULL, /* dma_sync_single */ + NULL /* dma_sync_sg */ +}; + + +/************************************************************************** +** +** SBA PAT PDC support +** +** o call pdc_pat_cell_module() +** o store ranges in PCI "resource" structures +** +**************************************************************************/ + +static void +sba_get_pat_resources(struct sba_device *sba_dev) +{ +#if 0 +/* +** TODO/REVISIT/FIXME: support for directed ranges requires calls to +** PAT PDC to program the SBA/LBA directed range registers...this +** burden may fall on the LBA code since it directly supports the +** PCI subsystem. It's not clear yet. - ggg +*/ +PAT_MOD(mod)->mod_info.mod_pages = PAT_GET_MOD_PAGES(temp); + FIXME : ??? +PAT_MOD(mod)->mod_info.dvi = PAT_GET_DVI(temp); + Tells where the dvi bits are located in the address. +PAT_MOD(mod)->mod_info.ioc = PAT_GET_IOC(temp); + FIXME : ??? +#endif +} + + +/************************************************************** +* +* Initialization and claim +* +***************************************************************/ + + +static void +sba_ioc_init(struct ioc *ioc) +{ + extern unsigned long mem_max; /* arch.../setup.c */ + extern void lba_init_iregs(void *, u32, u32); /* arch.../lba_pci.c */ + + u32 iova_space_size, iova_space_mask; + void * pdir_base; + int pdir_size, iov_order; + + /* + ** Determine IOVA Space size from memory size. + ** Using "mem_max" is a kluge. + ** + ** Ideally, PCI drivers would register the maximum number + ** of DMA they can have outstanding for each device they + ** own. Next best thing would be to guess how much DMA + ** can be outstanding based on PCI Class/sub-class. Both + ** methods still require some "extra" to support PCI + ** Hot-Plug/Removal of PCI cards. (aka PCI OLARD). + ** + ** While we have 32-bits "IOVA" space, top two 2 bits are used + ** for DMA hints - ergo only 30 bits max. + */ + /* limit IOVA space size to 1MB-1GB */ + if (mem_max < (sba_mem_ratio*1024*1024)) { + iova_space_size = 1024*1024; +#ifdef __LP64__ + } else if (mem_max > (sba_mem_ratio*512*1024*1024)) { + iova_space_size = 512*1024*1024; +#endif + } else { + iova_space_size = (u32) (mem_max/sba_mem_ratio); + } + + /* + ** iova space must be log2() in size. + ** thus, pdir/res_map will also be log2(). + */ + iov_order = get_order(iova_space_size >> (IOVP_SHIFT-PAGE_SHIFT)); + ASSERT(iov_order <= (30 - IOVP_SHIFT)); /* iova_space_size <= 1GB */ + ASSERT(iov_order >= (20 - IOVP_SHIFT)); /* iova_space_size >= 1MB */ + iova_space_size = 1 << (iov_order + IOVP_SHIFT); + + ioc->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64); + + ASSERT(pdir_size < 4*1024*1024); /* max pdir size < 4MB */ + + /* Verify it's a power of two */ + ASSERT((1 << get_order(pdir_size)) == (pdir_size >> PAGE_SHIFT)); + + DBG_INIT("%s() hpa 0x%p mem %dMBIOV %dMB (%d bits) PDIR size 0x%0x", + __FUNCTION__, ioc->ioc_hpa, (int) (mem_max>>20), + iova_space_size>>20, iov_order + PAGE_SHIFT, pdir_size); + + /* FIXME : DMA HINTs not used */ + ioc->hint_shift_pdir = iov_order + PAGE_SHIFT; + ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT)); + + ioc->pdir_base = + pdir_base = (void *) __get_free_pages(GFP_KERNEL, get_order(pdir_size)); + if (NULL == pdir_base) + { + panic(__FILE__ ":%s() could not allocate I/O Page Table\n", __FUNCTION__); + } + memset(pdir_base, 0, pdir_size); + + DBG_INIT("sba_ioc_init() pdir %p size %x hint_shift_pdir %x hint_mask_pdir %lx\n", + pdir_base, pdir_size, + ioc->hint_shift_pdir, ioc->hint_mask_pdir); + + ASSERT((((unsigned long) pdir_base) & PAGE_MASK) == (unsigned long) pdir_base); + WRITE_REG64(virt_to_phys(pdir_base), (u64 *)(ioc->ioc_hpa+IOC_PDIR_BASE)); + + DBG_INIT(" base %p\n", pdir_base); + + /* build IMASK for IOC and Elroy */ + iova_space_mask = 0xffffffff; + iova_space_mask <<= (iov_order + PAGE_SHIFT); + + /* + ** On C3000 w/512MB mem, HP-UX 10.20 reports: + ** ibase=0, imask=0xFE000000, size=0x2000000. + */ + ioc->ibase = IOC_IOVA_SPACE_BASE | 1; /* bit 0 == enable bit */ + ioc->imask = iova_space_mask; /* save it */ + + DBG_INIT("%s() IOV base 0x%lx mask 0x%0lx\n", __FUNCTION__, + ioc->ibase, ioc->imask); + + /* + ** FIXME: Hint registers are programmed with default hint + ** values during boot, so hints should be sane even if we + ** can't reprogram them the way drivers want. + */ + + /* + ** setup Elroy IBASE/IMASK registers as well. + */ + lba_init_iregs(ioc->ioc_hpa, ioc->ibase, ioc->imask); + + /* + ** Program the IOC's ibase and enable IOVA translation + */ + WRITE_REG32(ioc->ibase, ioc->ioc_hpa+IOC_IBASE); + WRITE_REG32(ioc->imask, ioc->ioc_hpa+IOC_IMASK); + + /* Set I/O PDIR Page size to 4K */ + WRITE_REG32(0, ioc->ioc_hpa+IOC_TCNFG); + + /* + ** Clear I/O TLB of any possible entries. + ** (Yes. This is a it paranoid...but so what) + */ + WRITE_REG32(0 | 31, ioc->ioc_hpa+IOC_PCOM); + + DBG_INIT("%s() DONE\n", __FUNCTION__); +} + + + +/************************************************************************** +** +** SBA initialization code (HW and SW) +** +** o identify SBA chip itself +** o initialize SBA chip modes (HardFail) +** o initialize SBA chip modes (HardFail) +** o FIXME: initialize DMA hints for reasonable defaults +** +**************************************************************************/ + +static void +sba_hw_init(struct sba_device *sba_dev) +{ + int i; + int num_ioc; + u32 ioc_ctl; + + ioc_ctl = READ_REG32(sba_dev->sba_hpa+IOC_CTRL); + DBG_INIT("%s() hpa 0x%p ioc_ctl 0x%x ->", __FUNCTION__, sba_dev->sba_hpa, ioc_ctl ); + ioc_ctl &= ~(IOC_CTRL_RM | IOC_CTRL_NC); + ASSERT(ioc_ctl & IOC_CTRL_TE); /* astro: firmware enables this */ + + WRITE_REG32(ioc_ctl, sba_dev->sba_hpa+IOC_CTRL); + +#ifdef SBA_DEBUG_INIT + ioc_ctl = READ_REG32(sba_dev->sba_hpa+IOC_CTRL); + DBG_INIT(" 0x%x\n", ioc_ctl ); +#endif + + if (IS_ASTRO(sba_dev->iodc)) { + /* PAT_PDC (L-class) also reports the same goofy base */ + sba_dev->ioc[0].ioc_hpa = (char *) ASTRO_IOC_OFFSET; + num_ioc = 1; + } else { + sba_dev->ioc[0].ioc_hpa = sba_dev->ioc[1].ioc_hpa = 0; + num_ioc = 2; + } + + sba_dev->num_ioc = num_ioc; + for( i = 0; i < num_ioc; i++) + { + (unsigned long) sba_dev->ioc[i].ioc_hpa += (unsigned long) sba_dev->sba_hpa + IKE_IOC_OFFSET(i); + + /* + ** Make sure the box crashes if we get any errors on a rope. + */ + WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE0_CTL); + WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE1_CTL); + WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE2_CTL); + WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE3_CTL); + WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE4_CTL); + WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE5_CTL); + WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE6_CTL); + WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE7_CTL); + + /* flush out the writes */ + READ_REG32(sba_dev->ioc[i].ioc_hpa + ROPE7_CTL); + + sba_ioc_init(&(sba_dev->ioc[i])); + } +} + +static void +sba_common_init(struct sba_device *sba_dev) +{ + int i; + + /* add this one to the head of the list (order doesn't matter) + ** This will be useful for debugging - especially if we get coredumps + */ + sba_dev->next = sba_list; + sba_list = sba_dev; + sba_count++; + + for(i=0; i< sba_dev->num_ioc; i++) { + int res_size; +#ifdef CONFIG_DMB_TRAP + extern void iterate_pages(unsigned long , unsigned long , + void (*)(pte_t * , unsigned long), + unsigned long ); + void set_data_memory_break(pte_t * , unsigned long); +#endif + /* resource map size dictated by pdir_size */ + res_size = sba_dev->ioc[i].pdir_size/sizeof(u64); /* entries */ + res_size >>= 3; /* convert bit count to byte count */ + DBG_INIT("%s() res_size 0x%x\n", __FUNCTION__, res_size); + + sba_dev->ioc[i].res_size = res_size; + sba_dev->ioc[i].res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size)); + +#ifdef CONFIG_DMB_TRAP + iterate_pages( sba_dev->ioc[i].res_map, res_size, + set_data_memory_break, 0); +#endif + + if (NULL == sba_dev->ioc[i].res_map) + { + panic(__FILE__ ":%s() could not allocate resource map\n", __FUNCTION__ ); + } + + memset(sba_dev->ioc[i].res_map, 0, res_size); + /* next available IOVP - circular search */ + sba_dev->ioc[i].res_hint = (unsigned long *) + &(sba_dev->ioc[i].res_map[L1_CACHE_BYTES]); + +#ifdef ASSERT_PDIR_SANITY + /* Mark first bit busy - ie no IOVA 0 */ + sba_dev->ioc[i].res_map[0] = 0x80; + sba_dev->ioc[i].pdir_base[0] = 0xeeffc0addbba0080ULL; +#endif + +#ifdef CONFIG_DMB_TRAP + iterate_pages( sba_dev->ioc[i].res_map, res_size, + set_data_memory_break, 0); + iterate_pages( sba_dev->ioc[i].pdir_base, sba_dev->ioc[i].pdir_size, + set_data_memory_break, 0); +#endif + + DBG_INIT("sba_common_init() %d res_map %x %p\n", + i, res_size, sba_dev->ioc[i].res_map); + } + + sba_dev->sba_lock = SPIN_LOCK_UNLOCKED; +} + +#ifdef CONFIG_PROC_FS +static int sba_proc_info(char *buf, char **start, off_t offset, int len) +{ + struct sba_device *sba_dev = sba_list; +/* FIXME: Multi-IOC support broken! */ + struct ioc *ioc = &sba_dev->ioc[0]; + int total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */ + unsigned long i = 0, avg = 0, min, max; + + sprintf(buf, "%s rev %d.%d\n", + parisc_getHWdescription(sba_dev->iodc->hw_type, + sba_dev->iodc->hversion, sba_dev->iodc->sversion), + (sba_dev->hw_rev & 0x7) + 1, + (sba_dev->hw_rev & 0x18) >> 3 + ); + sprintf(buf, "%sIO PDIR size : %d bytes (%d entries)\n", + buf, + ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits per byte */ + total_pages); /* 8 bits per byte */ + + sprintf(buf, "%sIO PDIR entries : %ld free %ld used (%d%%)\n", buf, + total_pages - ioc->used_pages, ioc->used_pages, + (int) (ioc->used_pages * 100 / total_pages)); + + sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", + buf, ioc->res_size, ioc->res_size << 3); /* 8 bits per byte */ + + min = max = ioc->avg_search[0]; + for (i = 0; i < SBA_SEARCH_SAMPLE; i++) { + avg += ioc->avg_search[i]; + if (ioc->avg_search[i] > max) max = ioc->avg_search[i]; + if (ioc->avg_search[i] < min) min = ioc->avg_search[i]; + } + avg /= SBA_SEARCH_SAMPLE; + sprintf(buf, "%s Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n", + buf, min, avg, max); + + sprintf(buf, "%spci_map_single(): %8ld calls %8ld pages (avg %d/1000)\n", + buf, ioc->msingle_calls, ioc->msingle_pages, + (int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls)); + + /* KLUGE - unmap_sg calls unmap_single for each mapped page */ + min = ioc->usingle_calls - ioc->usg_calls; + max = ioc->usingle_pages - ioc->usg_pages; + sprintf(buf, "%spci_unmap_single: %8ld calls %8ld pages (avg %d/1000)\n", + buf, min, max, + (int) ((max * 1000)/min)); + + sprintf(buf, "%spci_map_sg() : %8ld calls %8ld pages (avg %d/1000)\n", + buf, ioc->msg_calls, ioc->msg_pages, + (int) ((ioc->msg_pages * 1000)/ioc->msg_calls)); + + sprintf(buf, "%spci_unmap_sg() : %8ld calls %8ld pages (avg %d/1000)\n", + buf, ioc->usg_calls, ioc->usg_pages, + (int) ((ioc->usg_pages * 1000)/ioc->usg_calls)); + + return strlen(buf); +} + +static int +sba_resource_map(char *buf, char **start, off_t offset, int len) +{ + struct sba_device *sba_dev = sba_list; + struct ioc *ioc = &sba_dev->ioc[0]; + unsigned long *res_ptr = (unsigned long *)ioc->res_map; + int i; + + for(i = 0; i < (ioc->res_size / sizeof(unsigned long)); ++i, ++res_ptr) { + if ((i & 7) == 0) + strcat(buf,"\n "); + sprintf(buf, "%s %08lx", buf, *res_ptr); + } + strcat(buf, "\n"); + + return strlen(buf); +} +#endif + +/* +** Determine if lba should claim this chip (return 0) or not (return 1). +** If so, initialize the chip and tell other partners in crime they +** have work to do. +*/ +int +sba_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri) +{ + struct sba_device *sba_dev; + u32 func_class; + int i; + + if (IS_ASTRO(d)) { + static char astro_rev[]="Astro ?.?"; + + /* Read HW Rev First */ + func_class = READ_REG32(d->hpa); + + astro_rev[6] = '1' + (char) (func_class & 0x7); + astro_rev[8] = '0' + (char) ((func_class & 0x18) >> 3); + dri->version = astro_rev; + } else { + static char ike_rev[]="Ike rev ?"; + + /* Read HW Rev First */ + func_class = READ_REG32(d->hpa + SBA_FCLASS); + + ike_rev[8] = '0' + (char) (func_class & 0xff); + dri->version = ike_rev; + } + + printk("%s found %s at 0x%p\n", dri->name, dri->version, d->hpa); + + sba_dev = kmalloc(sizeof(struct sba_device), GFP_KERNEL); + if (NULL == sba_dev) + { + printk(MODULE_NAME " - couldn't alloc sba_device\n"); + return(1); + } + memset(sba_dev, 0, sizeof(struct sba_device)); + for(i=0; i<MAX_IOC; i++) + spin_lock_init(&(sba_dev->ioc[i].res_lock)); + + + sba_dev->hw_rev = func_class; + sba_dev->iodc = d; + sba_dev->sba_hpa = d->hpa; /* faster access */ + + sba_get_pat_resources(sba_dev); + sba_hw_init(sba_dev); + sba_common_init(sba_dev); + + hppa_dma_ops = &sba_ops; + +#ifdef CONFIG_PROC_FS + if (IS_ASTRO(d)) { + create_proc_info_entry("Astro", 0, proc_runway_root, sba_proc_info); + } else { + create_proc_info_entry("Ike", 0, proc_runway_root, sba_proc_info); + } + create_proc_info_entry("bitmap", 0, proc_runway_root, sba_resource_map); +#endif + return 0; +} diff --git a/arch/parisc/kernel/semaphore.c b/arch/parisc/kernel/semaphore.c new file mode 100644 index 000000000..81156de7d --- /dev/null +++ b/arch/parisc/kernel/semaphore.c @@ -0,0 +1,239 @@ +/* + * Just taken from alpha implementation. + * This can't work well, perhaps. + */ +/* + * Generic semaphore code. Buyer beware. Do your own + * specific changes in <asm/semaphore-helper.h> + */ + +#include <linux/sched.h> +#include <asm/semaphore-helper.h> + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to sleep, while the "waking" variable is + * incremented when the "up()" code goes to wake up waiting + * processes. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * waking_non_zero() (from asm/semaphore.h) must execute + * atomically. + * + * When __up() is called, the count was negative before + * incrementing it, and we need to wake up somebody. + * + * This routine adds one to the count of processes that need to + * wake up and exit. ALL waiting processes actually wake up but + * only the one that gets to the "waking" field first will gate + * through and acquire the semaphore. The others will go back + * to sleep. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in <asm/semaphore.h> + * where we want to avoid any extra jumps and calls. + */ +void __up(struct semaphore *sem) +{ + wake_one_more(sem); + wake_up(&sem->wait); +} + +/* + * Perform the "down" function. Return zero for semaphore acquired, + * return negative for signalled out of the function. + * + * If called from __down, the return is ignored and the wait loop is + * not interruptible. This means that a task waiting on a semaphore + * using "down()" cannot be killed until someone does an "up()" on + * the semaphore. + * + * If called from __down_interruptible, the return value gets checked + * upon return. If the return value is negative then the task continues + * with the negative value in the return register (it can be tested by + * the caller). + * + * Either form may be used in conjunction with "up()". + * + */ + + +#define DOWN_HEAD(task_state) \ + \ + \ + current->state = (task_state); \ + add_wait_queue(&sem->wait, &wait); \ + \ + /* \ + * Ok, we're set up. sem->count is known to be less than zero \ + * so we must wait. \ + * \ + * We can let go the lock for purposes of waiting. \ + * We re-acquire it after awaking so as to protect \ + * all semaphore operations. \ + * \ + * If "up()" is called before we call waking_non_zero() then \ + * we will catch it right away. If it is called later then \ + * we will have to go through a wakeup cycle to catch it. \ + * \ + * Multiple waiters contend for the semaphore lock to see \ + * who gets to gate through and who has to wait some more. \ + */ \ + for (;;) { + +#define DOWN_TAIL(task_state) \ + current->state = (task_state); \ + } \ + current->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +void __down(struct semaphore * sem) +{ + DECLARE_WAITQUEUE(wait, current); + + DOWN_HEAD(TASK_UNINTERRUPTIBLE) + if (waking_non_zero(sem)) + break; + schedule(); + DOWN_TAIL(TASK_UNINTERRUPTIBLE) +} + +int __down_interruptible(struct semaphore * sem) +{ + DECLARE_WAITQUEUE(wait, current); + int ret = 0; + + DOWN_HEAD(TASK_INTERRUPTIBLE) + + ret = waking_non_zero_interruptible(sem, current); + if (ret) + { + if (ret == 1) + /* ret != 0 only if we get interrupted -arca */ + ret = 0; + break; + } + schedule(); + DOWN_TAIL(TASK_INTERRUPTIBLE) + return ret; +} + +int __down_trylock(struct semaphore * sem) +{ + return waking_non_zero_trylock(sem); +} + + +/* Wait for the lock to become unbiased. Readers + * are non-exclusive. =) + */ +void down_read_failed(struct rw_semaphore *sem) +{ + DECLARE_WAITQUEUE(wait, current); + + __up_read(sem); /* this takes care of granting the lock */ + + add_wait_queue(&sem->wait, &wait); + + while (atomic_read(&sem->count) < 0) { + set_task_state(current, TASK_UNINTERRUPTIBLE); + if (atomic_read(&sem->count) >= 0) + break; + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + current->state = TASK_RUNNING; +} + +void down_read_failed_biased(struct rw_semaphore *sem) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ + + for (;;) { + if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0)) + break; + set_task_state(current, TASK_UNINTERRUPTIBLE); + if (!sem->read_bias_granted) + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + current->state = TASK_RUNNING; +} + + +/* Wait for the lock to become unbiased. Since we're + * a writer, we'll make ourselves exclusive. + */ +void down_write_failed(struct rw_semaphore *sem) +{ + DECLARE_WAITQUEUE(wait, current); + + __up_write(sem); /* this takes care of granting the lock */ + + add_wait_queue_exclusive(&sem->wait, &wait); + + while (atomic_read(&sem->count) < 0) { + set_task_state(current, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (atomic_read(&sem->count) >= 0) + break; /* we must attempt to aquire or bias the lock */ + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + current->state = TASK_RUNNING; +} + +void down_write_failed_biased(struct rw_semaphore *sem) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */ + + for (;;) { + if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0)) + break; + set_task_state(current, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (!sem->write_bias_granted) + schedule(); + } + + remove_wait_queue(&sem->write_bias_wait, &wait); + current->state = TASK_RUNNING; + + /* if the lock is currently unbiased, awaken the sleepers + * FIXME: this wakes up the readers early in a bit of a + * stampede -> bad! + */ + if (atomic_read(&sem->count) >= 0) + wake_up(&sem->wait); +} + + +/* Called when someone has done an up that transitioned from + * negative to non-negative, meaning that the lock has been + * granted to whomever owned the bias. + */ +void rwsem_wake_readers(struct rw_semaphore *sem) +{ + if (xchg(&sem->read_bias_granted, 1)) + BUG(); + wake_up(&sem->wait); +} + +void rwsem_wake_writer(struct rw_semaphore *sem) +{ + if (xchg(&sem->write_bias_granted, 1)) + BUG(); + wake_up(&sem->write_bias_wait); +} diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c new file mode 100644 index 000000000..16a35df30 --- /dev/null +++ b/arch/parisc/kernel/setup.c @@ -0,0 +1,614 @@ +/* $Id: setup.c,v 1.8 2000/02/02 04:42:38 prumpf Exp $ + * + * Initial setup-routines for HP 9000 based hardware. + * + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * Modifications for PA-RISC (C) 1999 Helge Deller <helge.deller@ruhr-uni-bochum.de> + * Modifications copyright 1999 SuSE GmbH (Philipp Rumpf) + * Modifications copyright 2000 Martin K. Petersen <mkp@mkp.net> + * Modifications copyright 2000 Philipp Rumpf <prumpf@tux.org> + * + * Initial PA-RISC Version: 04-23-1999 by Helge Deller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/malloc.h> +#include <linux/mm.h> +#include <linux/ptrace.h> +#include <linux/sched.h> +#include <linux/stddef.h> +#include <linux/unistd.h> +#include <linux/user.h> +#include <linux/tty.h> +#include <linux/config.h> +#include <linux/fs.h> +#include <linux/kdev_t.h> +#include <linux/major.h> +#include <linux/string.h> +#include <linux/blk.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/console.h> +#include <linux/bootmem.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/threads.h> + +#include <asm/cache.h> +#include <asm/hardware.h> /* for register_driver() stuff */ +#include <asm/processor.h> +#include <asm/page.h> +#include <asm/pdc.h> +#include <asm/led.h> +#include <asm/real.h> +#include <asm/system.h> +#include <asm/machdep.h> /* for pa7300lc_init() proto */ + +#include <asm/irq.h> /* for struct irq_region */ +#include <asm/pdcpat.h> /* for PA_VIEW PDC_PAT_CPU_GET_NUMBER etc */ + +#include <linux/proc_fs.h> + +#define COMMAND_LINE_SIZE 1024 +char saved_command_line[COMMAND_LINE_SIZE]; + +/* +** KLUGE ALERT! +** +** We *really* should be using a combination of request_resource() +** and request_region()! But request_region() requires kmalloc since +** returns a new struct resource. And kmalloc just isn't available +** until after mem_init() is called from start_kernel(). +** +** FIXME: assume contiguous memory initially. +** Additional chunks of memory might be added to sysram_resource.sibling. +*/ +static struct resource sysrom_resource = { + name: "System ROM", start: 0x0f0000000UL, end: 0x0f00fffffUL, + flags: IORESOURCE_BUSY | IORESOURCE_MEM, + parent: &iomem_resource, sibling: NULL, child: NULL }; + +static struct resource pdcdata_resource; + +static struct resource sysram_resource = { + name: "System RAM", start: 0UL, end: ~0UL /* bogus */, + flags: IORESOURCE_MEM, + parent: &iomem_resource, sibling: &sysrom_resource, child: &pdcdata_resource}; + +extern char _text; /* start of kernel code, defined by linker */ +extern int data_start; +extern char _edata; /* end of data, begin BSS, defined by linker */ +extern char _end; /* end of BSS, defined by linker */ + +static struct resource data_resource = { + name: "kernel Data", start: virt_to_phys(&data_start), end: virt_to_phys(&_end)-1, + flags: IORESOURCE_BUSY | IORESOURCE_MEM, + parent: &sysram_resource, sibling: NULL, child: NULL}; + +static struct resource code_resource = { + name: "Kernel Code", start: virt_to_phys(&_text), end: virt_to_phys(&data_start)-1, + flags: IORESOURCE_BUSY | IORESOURCE_MEM, + parent: &sysram_resource, sibling: &data_resource, child: NULL}; + +static struct resource pdcdata_resource = { + name: "PDC data (Page Zero)", start: 0, end: 0x9ff, + flags: IORESOURCE_BUSY | IORESOURCE_MEM, + parent: &sysram_resource, sibling: &code_resource, child: NULL}; + + + + +struct system_cpuinfo_parisc boot_cpu_data; +struct cpuinfo_parisc cpu_data[NR_CPUS]; + +extern void do_inventory(void); +extern void cache_init(void); +extern struct hp_device * register_module(void *hpa); + +static int cpu_driver_callback(struct hp_device *, struct pa_iodc_driver *); + +static struct pa_iodc_driver cpu_drivers_for[] = { + {HPHW_NPROC, 0x0, 0x0, 0x0, 0, 0, + DRIVER_CHECK_HWTYPE, + "CPU", "PARISC", (void *) cpu_driver_callback}, + {0,0,0,0,0,0, + 0, + (char *) NULL, (char *) NULL, (void *) NULL } +}; + +static long fallback_cpu_hpa[] = { 0xfffa0000L, 0xfffbe000L, 0x0 }; + + +/* +** PARISC CPU driver - claim "device" and initialize CPU data structures. +** +** Consolidate per CPU initialization into (mostly) one module. +** Monarch CPU will initialize boot_cpu_data which shouldn't +** change once the system has booted. +** +** The callback *should* do per-instance initialization of +** everything including the monarch. Some of the code that's +** in setup.c:start_parisc() should migrate here and start_parisc() +** should "register_driver(cpu_driver_for)" before calling +** do_inventory(). +** +** The goal of consolidating CPU initialization into one place is +** to make sure all CPU's get initialized the same way. +** It would be nice if the even the manarch through the exact same code path. +** (up to rendevous at least). +*/ +#undef ASSERT +#define ASSERT(expr) \ + if(!(expr)) { \ + printk( "\n" __FILE__ ":%d: Assertion " #expr " failed!\n",__LINE__); \ + panic(#expr); \ + } + +static int +cpu_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri) +{ +#ifdef __LP64__ + extern int pdc_pat; /* arch/parisc/kernel/inventory.c */ + static unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0}; +#endif + struct cpuinfo_parisc *p; + +#ifndef CONFIG_SMP + if (boot_cpu_data.cpu_count > 0) { + printk(KERN_INFO "CONFIG_SMP disabled - not claiming addional CPUs\n"); + return(1); + } +#endif + + p = &cpu_data[boot_cpu_data.cpu_count]; + boot_cpu_data.cpu_count++; + +/* TODO: Enable FP regs - done early in start_parisc() now */ + + /* initialize counters */ + memset(p, 0, sizeof(struct cpuinfo_parisc)); + + p->hpa = (unsigned long) d->hpa; /* save CPU hpa */ + +#ifdef __LP64__ + if (pdc_pat) { + ulong status; + pdc_pat_cell_mod_maddr_block_t pa_pdc_cell; + + status = pdc_pat_cell_module(& pdc_result, d->pcell_loc, + d->mod_index, PA_VIEW, & pa_pdc_cell); + + ASSERT(PDC_RET_OK == status); + + /* verify it's the same as what do_pat_inventory() found */ + ASSERT(d->mod_info == pa_pdc_cell.mod_info); + ASSERT(d->pmod_loc == pa_pdc_cell.mod_location); + ASSERT(d->mod_path == pa_pdc_cell.mod_path); + + p->txn_addr = pa_pdc_cell.mod[0]; /* id_eid for IO sapic */ + + /* get the cpu number */ + status = mem_pdc_call( PDC_PAT_CPU, PDC_PAT_CPU_GET_NUMBER, + __pa(& pdc_result), d->hpa); + + ASSERT(PDC_RET_OK == status); + + p->cpuid = pdc_result[0]; + + } else +#endif + { + p->txn_addr = (unsigned long) d->hpa; /* for normal parisc */ + + /* logical CPU ID and update global counter */ + p->cpuid = boot_cpu_data.cpu_count - 1; + } + + /* + ** itimer and ipi IRQ handlers are statically initialized in + ** arch/parisc/kernel/irq.c + */ + p->region = irq_region[IRQ_FROM_REGION(CPU_IRQ_REGION)]; + + return(0); +} + + +void __xchg_called_with_bad_pointer(void) +{ + printk(KERN_EMERG "xchg() called with bad pointer !\n"); +} + + +/* Some versions of IODC don't list the CPU, and since we don't walk + * the bus yet, we have to probe for processors at well known hpa + * addresses. + */ + +void __init register_fallback_cpu (void) +{ + struct hp_device *d = NULL; + int i = 0; + +#ifdef CONFIG_SMP +#error "Revisit CPU fallback addresses for SMP (Assuming bus walk hasn't been implemented)" +#endif + printk ("No CPUs reported by firmware - probing...\n"); + + while (fallback_cpu_hpa[i]) { + + d = register_module ((void *) fallback_cpu_hpa[i]); + + if (d > 0) { + printk ("Found CPU at %lx\n", fallback_cpu_hpa[i]); + cpu_driver_callback (d, 0); + return; + } + + i++; + } + + panic ("No CPUs found. System halted.\n"); + return; +} + + +/* + * Get CPU information and store it in the boot_cpu_data structure. */ +void __init collect_boot_cpu_data(void) +{ + memset(&boot_cpu_data,0,sizeof(boot_cpu_data)); + + boot_cpu_data.cpu_hz = 100 * PAGE0->mem_10msec; /* Hz of this PARISC */ + + /* get CPU-Model Information... */ +#define p ((unsigned long *)&boot_cpu_data.pdc.model) + if(pdc_model_info(&boot_cpu_data.pdc.model)==0) + printk("model %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8]); +#undef p + + if(pdc_model_versions(&boot_cpu_data.pdc.versions, 0)==0) + printk("vers %08lx\n", boot_cpu_data.pdc.versions.cpuid); + + if(pdc_model_cpuid(&boot_cpu_data.pdc.cpuid)==0) + printk("cpuid %08lx\n", boot_cpu_data.pdc.cpuid.cpuid); + + printk("CPUID vers %ld rev %ld\n", + (boot_cpu_data.pdc.cpuid.cpuid >> 5) & 127, + boot_cpu_data.pdc.cpuid.cpuid & 31); + + if (pdc_model_sysmodel(boot_cpu_data.pdc.sys_model_name)==0) + printk("model %s\n",boot_cpu_data.pdc.sys_model_name); + + boot_cpu_data.model_name = parisc_getHWdescription(HPHW_NPROC, + boot_cpu_data.pdc.model.hversion>>4, + boot_cpu_data.pdc.model.sversion>>8); + + boot_cpu_data.hversion = boot_cpu_data.pdc.model.hversion; + boot_cpu_data.sversion = boot_cpu_data.pdc.model.sversion; + + boot_cpu_data.cpu_type = + parisc_get_cpu_type(boot_cpu_data.pdc.model.hversion); + + boot_cpu_data.cpu_name = cpu_name_version[boot_cpu_data.cpu_type][0]; + boot_cpu_data.family_name = cpu_name_version[boot_cpu_data.cpu_type][1]; +} + + +#ifdef __LP64__ +#define COMMAND_GLOBAL 0xfffffffffffe0030UL +#else +#define COMMAND_GLOBAL 0xfffe0030 +#endif + +#define CMD_RESET 5 /* reset any module */ + +/* +** The Wright Brothers and Gecko systems have a H/W problem +** (Lasi...'nuf said) may cause a broadcast reset to lockup +** the system. An HVERSION dependent PDC call was developed +** to perform a "safe", platform specific broadcast reset instead +** of kludging up all the code. +** +** Older machines which do not implement PDC_BROADCAST_RESET will +** return (with an error) and the regular broadcast reset can be +** issued. Obviously, if the PDC does implement PDC_BROADCAST_RESET +** the PDC call will not return (the system will be reset). +*/ +static int +reset_parisc(struct notifier_block *self, unsigned long command, void *ptr) +{ + printk("%s: %s(cmd=%lu)\n", __FILE__, __FUNCTION__, command); + + switch(command) { + case MACH_RESTART: +#ifdef FASTBOOT_SELFTEST_SUPPORT + /* + ** If user has modified the Firmware Selftest Bitmap, + ** run the tests specified in the bitmap after the + ** system is rebooted w/PDC_DO_RESET. + ** + ** ftc_bitmap = 0x1AUL "Skip destructive memory tests" + ** + ** Using "directed resets" at each processor with the MEM_TOC + ** vector cleared will also avoid running destructive + ** memory self tests. (Not implemented yet) + */ + if (ftc_bitmap) { + mem_pdc_call( PDC_BROADCAST_RESET, + PDC_DO_FIRM_TEST_RESET, PDC_FIRM_TEST_MAGIC, + ftc_bitmap); + } +#endif + + /* "Normal" system reset */ + (void) mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_RESET, + 0L, 0L, 0L); + + /* Nope...box should reset with just CMD_RESET now */ + gsc_writel(CMD_RESET, COMMAND_GLOBAL); + + /* Wait for RESET to lay us to rest. */ + while (1) ; + + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block parisc_block = { reset_parisc, NULL, 0 }; + + +/* start_parisc() will be called from head.S to setup our new memory_start + and actually start our kernel ! + Memory-Layout is: + - Kernel-Image (code+data+BSS) + - Stack (stack-size see below!, stack-setup-code is in head.S) + - memory_start at end of stack.. +*/ + +unsigned long mem_start, mem_max; +unsigned long start_pfn, max_pfn; +extern asmlinkage void __init start_kernel(void); + +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define PFN_PHYS(x) ((x) << PAGE_SHIFT) + +void __init start_parisc(unsigned arg0, unsigned arg1, + unsigned arg2, unsigned arg3) +{ + register unsigned long ccr; + unsigned long memory_start; + + /* Clear BSS */ + + { + char *p = &_edata, *q = &_end; + + while (p < q) { + *p++ = 0; + } + } + + + pdc_console_init(); + +#ifdef __LP64__ + printk("The 64-bit Kernel has started...\n"); +#else + printk("The 32-bit Kernel has started...\n"); +#endif + + /* + ** Enable FP coprocessor + ** + ** REVISIT: ccr should be set by PDC_COPROC results to support PA1.0. + ** Hardcoding works for PA1.1 processors. + ** + ** REVISIT: this could be done in the "code 22" trap handler. + ** (frowands idea - that way we know which processes need FP + ** registers saved on the interrupt stack.) + ** + ** NEWS FLASH: wide kernels need FP coprocessor enabled to handle + ** formatted printing of %lx for example (double divides I think) + */ + ccr = 0xc0; + mtctl(ccr, 10); + printk("Enabled FP coprocessor\n"); + +#ifdef __LP64__ + printk( "If this is the LAST MESSAGE YOU SEE, you're probably using\n" + "32-bit millicode by mistake.\n"); +#endif + + memory_start = (unsigned long) &_end; + memory_start = (memory_start + PAGE_SIZE) & PAGE_MASK; + printk("Free memory starts at: 0x%lx\n", memory_start); + + /* Collect stuff passed in from the boot loader */ + printk(KERN_WARNING "%s(0x%x,0x%x,0x%x,0x%x)\n", + __FUNCTION__, arg0, arg1, arg2, arg3); + + /* arg0 is free-mem start, arg1 is ptr to command line */ + if (arg0 < 64) { + /* called from hpux boot loader */ + saved_command_line[0] = '\0'; + } else { + strcpy(saved_command_line, (char *)__va(arg1)); + printk("PALO command line: '%s'\nPALO initrd %x-%x\n", + saved_command_line, arg2, arg3); + +#ifdef CONFIG_BLK_DEV_INITRD + if (arg2 != 0) /* did palo pass us a ramdisk? */ + { + initrd_start = (unsigned long)__va(arg2); + initrd_end = (unsigned long)__va(arg3); + } +#endif + } + + mem_start = __pa(memory_start); +#define MAX_MEM (512*1024*1024) + mem_max = (PAGE0->imm_max_mem > MAX_MEM ? MAX_MEM : PAGE0->imm_max_mem); + + collect_boot_cpu_data(); + + /* initialize the LCD/LED after boot_cpu_data is available ! */ + led_init(); /* LCD/LED initialization */ + + do_inventory(); /* probe for hardware */ + register_driver(cpu_drivers_for); /* claim all the CPUs */ + + if (boot_cpu_data.cpu_count == 0) + register_fallback_cpu(); + + printk("CPU(s): %d x %s at %d.%06d MHz\n", + boot_cpu_data.cpu_count, + boot_cpu_data.cpu_name, + boot_cpu_data.cpu_hz / 1000000, + boot_cpu_data.cpu_hz % 1000000 ); + + switch (boot_cpu_data.cpu_type) { + case pcx: + case pcxs: + case pcxt: + hppa_dma_ops = &pcx_dma_ops; + break; + case pcxl2: + pa7300lc_init(); + case pcxl: /* falls through */ + hppa_dma_ops = &pcxl_dma_ops; + break; + default: + break; + } + +#if 1 + /* KLUGE! this really belongs in kernel/resource.c! */ + iomem_resource.end = ~0UL; +#endif + sysram_resource.end = mem_max - 1; + notifier_chain_register(&mach_notifier, &parisc_block); + start_kernel(); /* now back to arch-generic code... */ +} + +void __init setup_arch(char **cmdline_p) +{ + unsigned long bootmap_size; + unsigned long start_pfn; + unsigned long mem_free; + + *cmdline_p = saved_command_line; + + /* initialize bootmem */ + + start_pfn = PFN_UP(mem_start); + max_pfn = PFN_DOWN(mem_max); + + bootmap_size = init_bootmem(start_pfn, max_pfn); + + mem_start += bootmap_size; + mem_free = mem_max - mem_start; + + /* free_bootmem handles rounding nicely */ + printk("free_bootmem(0x%lx, 0x%lx)\n", (unsigned long)mem_start, + (unsigned long)mem_free); + free_bootmem(mem_start, mem_free); + +#ifdef CONFIG_BLK_DEV_INITRD + printk("initrd: %08x-%08x\n", (int) initrd_start, (int) initrd_end); + + if (initrd_end != 0) { + initrd_below_start_ok = 1; + reserve_bootmem(__pa(initrd_start), initrd_end - initrd_start); + } +#endif + + cache_init(); + + paging_init(); + + if((unsigned long)&init_task_union&(INIT_TASK_SIZE - 1)) { + printk("init_task_union not aligned. Please recompile the kernel after changing the first line in arch/parisc/kernel/init_task.c from \n\"#define PAD 0\" to\n\"#define PAD 1\" or vice versa\n"); + for(;;); + } + + +#ifdef CONFIG_SERIAL_CONSOLE + /* nothing */ +#elif CONFIG_VT +#if defined(CONFIG_STI_CONSOLE) + conswitchp = &dummy_con; /* we use take_over_console() later ! */ +#elif defined(CONFIG_IODC_CONSOLE) + conswitchp = &prom_con; /* it's currently really "prom_con" */ +#elif defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif +#endif + +} + +#ifdef CONFIG_PROC_FS +/* + * Get CPU information for use by procfs. + */ + +int get_cpuinfo(char *buffer) +{ + char *p = buffer; + int n; + + for(n=0; n<boot_cpu_data.cpu_count; n++) { +#ifdef CONFIG_SMP + if (!(cpu_online_map & (1<<n))) + continue; +#endif + p += sprintf(p, "processor\t: %d\n" + "cpu family\t: PA-RISC %s\n", + n, boot_cpu_data.family_name); + + p += sprintf(p, "cpu\t\t: %s\n", boot_cpu_data.cpu_name ); + + /* cpu MHz */ + p += sprintf(p, "cpu MHz\t\t: %d.%06d\n", + boot_cpu_data.cpu_hz / 1000000, + boot_cpu_data.cpu_hz % 1000000 ); + + p += sprintf(p, "model\t\t: %s\n" + "model name\t: %s\n", + boot_cpu_data.pdc.sys_model_name, + boot_cpu_data.model_name); + + p += sprintf(p, "hversion\t: 0x%08x\n" + "sversion\t: 0x%08x\n", + boot_cpu_data.hversion, + boot_cpu_data.sversion ); + + p += get_cache_info(p); + /* print cachesize info ? */ + p += sprintf(p, "bogomips\t: %lu.%02lu\n", + (loops_per_sec+2500)/500000, + ((loops_per_sec+2500)/5000) % 100); + } + return p - buffer; +} +#endif + diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c new file mode 100644 index 000000000..fec670ab8 --- /dev/null +++ b/arch/parisc/kernel/signal.c @@ -0,0 +1,653 @@ +/* + * linux/arch/parisc/kernel/signal.c: Architecture-specific signal + * handling support. + * + * Copyright (C) 2000 David Huggins-Daines <dhd@debian.org> + * Copyright (C) 2000 Linuxcare, Inc. + * + * Based on the ia64, i386, and alpha versions. + * + * Like the IA-64, we are a recent enough port (we are *starting* + * with glibc2.2) that we do not need to support the old non-realtime + * Linux signals. Therefore we don't. HP/UX signals will go in + * arch/parisc/hpux/signal.c when we figure out how to do them. + */ + +#include <linux/version.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/kernel.h> +#include <linux/signal.h> +#include <linux/errno.h> +#include <linux/wait.h> +#include <linux/ptrace.h> +#include <linux/unistd.h> +#include <linux/stddef.h> +#include <asm/ucontext.h> +#include <asm/uaccess.h> +#include <asm/pgalloc.h> + +#define DEBUG_SIG 0 + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +extern long sys_wait4 (int, int *, int, struct rusage *); +int do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall); + +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* + * If you change siginfo_t structure, please be sure + * this code is fixed accordingly. It should never + * copy any pad contained in the structure to avoid + * security leaks, but must copy the generic 3 ints + * plus the relevant union member. + */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + /* FIXME: should we put the interruption code here? */ + case __SI_POLL >> 16: + err |= __put_user(from->si_addr, &to->si_addr); + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + err |= __put_user(from->si_pid, &to->si_pid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ +#ifdef __LP64__ +#include "sys32.h" +#endif + +asmlinkage int +sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs *regs) +{ + sigset_t saveset, newset; +#ifdef __LP64__ + /* XXX FIXME -- assumes 32-bit user app! */ + sigset_t32 newset32; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t32)) + return -EINVAL; + + if (copy_from_user(&newset32, (sigset_t32 *)unewset, sizeof(newset32))) + return -EFAULT; + + newset.sig[0] = newset32.sig[0] | ((unsigned long)newset32.sig[1] << 32); +#else + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; +#endif + sigdelsetmask(&newset, ~_BLOCKABLE); + + spin_lock_irq(¤t->sigmask_lock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + regs->gr[28] = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs, 1)) + return -EINTR; + } +} + +/* + * Do a signal return - restore sigcontext. + */ + +struct rt_sigframe { + unsigned int tramp[4]; + struct siginfo info; + struct ucontext uc; +}; + +/* Trampoline for calling rt_sigreturn() */ +#define INSN_LDI_R25_0 0x34190000 /* ldi 0,%r25 (in_syscall=0) */ +#define INSN_LDI_R25_1 0x34190002 /* ldi 1,%r25 (in_syscall=1) */ +#define INSN_LDI_R20 0x3414015a /* ldi __NR_rt_sigreturn,%r20 */ +#define INSN_BLE_SR2_R0 0xe4008200 /* be,l 0x100(%sr2,%r0),%sr0,%r31 */ +#define INSN_NOP 0x80000240 /* nop */ +/* For debugging */ +#define INSN_DIE_HORRIBLY 0x68000ccc /* stw %r0,0x666(%sr0,%r0) */ + +/* + * The 32-bit ABI wants at least 48 bytes for a function call frame: + * 16 bytes for arg0-arg3, and 32 bytes for magic (the only part of + * which Linux/parisc uses is sp-20 for the saved return pointer...) + * Then, the stack pointer must be rounded to a cache line (64 bytes). + */ +#define PARISC_RT_SIGFRAME_SIZE \ + (((sizeof(struct rt_sigframe) + 48) + 63) & -64) + +static long +restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs) +{ + long err = 0; + + err |= __copy_from_user(regs->gr, sc->sc_gr, sizeof(regs->gr)); + err |= __copy_from_user(regs->fr, sc->sc_fr, sizeof(regs->fr)); + err |= __copy_from_user(regs->iaoq, sc->sc_iaoq, sizeof(regs->iaoq)); + err |= __copy_from_user(regs->iasq, sc->sc_iasq, sizeof(regs->iasq)); + err |= __get_user(regs->sar, &sc->sc_sar); + +#if DEBUG_SIG + printk("restore_sigcontext: r28 is %ld\n", regs->gr[28]); +#endif + return err; +} + +void +sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) +{ + struct rt_sigframe *frame; + struct siginfo si; + sigset_t set; + unsigned long usp = regs->gr[30]; + + /* Unwind the user stack to get the rt_sigframe structure. */ + frame = (struct rt_sigframe *) + (usp - PARISC_RT_SIGFRAME_SIZE); +#if DEBUG_SIG + printk("in sys_rt_sigreturn, frame is %p\n", frame); +#endif + + /* Verify that it's a good sigcontext before using it */ + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + goto give_sigsegv; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto give_sigsegv; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + /* Good thing we saved the old gr[30], eh? */ + if (restore_sigcontext(&frame->uc.uc_mcontext, regs)) + goto give_sigsegv; + +#if DEBUG_SIG + printk("usp: %#08lx stack %p", + usp, &frame->uc.uc_stack); +#endif + + /* I don't know why everyone else assumes they can call this + with a pointer to a stack_t on the kernel stack. That + makes no sense. Anyway we'll do it like m68k, since we + also are using segmentation in the same way as them. */ + if (do_sigaltstack(&frame->uc.uc_stack, NULL, usp) == -EFAULT) + goto give_sigsegv; + + /* If we are on the syscall path IAOQ will not be restored, and + * if we are on the interrupt path we must not corrupt gr31. + */ + if (in_syscall) + regs->gr[31] = regs->iaoq[0]; +#if DEBUG_SIG + printk("returning to %#lx\n", regs->iaoq[0]); + printk("in sys_rt_sigreturn:\n"); + show_regs(regs); +#endif + return; + +give_sigsegv: +#if DEBUG_SIG + printk("fuckup in sys_rt_sigreturn, sending SIGSEGV\n"); +#endif + si.si_signo = SIGSEGV; + si.si_errno = 0; + si.si_code = SI_KERNEL; + si.si_pid = current->pid; + si.si_uid = current->uid; + si.si_addr = &frame->uc; + force_sig_info(SIGSEGV, &si, current); + return; +} + +/* + * Set up a signal frame. + */ + +static inline void * +get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) +{ + if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp)) + sp = current->sas_ss_sp + current->sas_ss_size; + + return (void *) sp; /* Stacks grow up. Fun. */ +} + +static long +setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, int in_syscall) + +{ + unsigned long flags = 0; + long err = 0; + + if (on_sig_stack((unsigned long) sc)) + flags |= PARISC_SC_FLAG_ONSTACK; + if (in_syscall) { + flags |= PARISC_SC_FLAG_IN_SYSCALL; + /* regs->iaoq is undefined in the syscall return path */ + err |= __put_user(regs->gr[31], &sc->sc_iaoq[0]); + err |= __put_user(regs->gr[31]+4, &sc->sc_iaoq[1]); +#if DEBUG_SIG + printk("setup_sigcontext: iaoq %#lx/%#lx\n", regs->gr[31], regs->gr[31]); +#endif + } else { + err |= __copy_to_user(sc->sc_iaoq, regs->iaoq, sizeof(regs->iaoq)); + err |= __copy_to_user(sc->sc_iasq, regs->iasq, sizeof(regs->iasq)); +#if DEBUG_SIG + printk("setup_sigcontext: iaoq %#lx/%#lx\n", regs->iaoq[0], regs->iaoq[1]); +#endif + } + + err |= __put_user(flags, &sc->sc_flags); + err |= __copy_to_user(sc->sc_gr, regs->gr, sizeof(regs->gr)); + err |= __copy_to_user(sc->sc_fr, regs->fr, sizeof(regs->fr)); + err |= __put_user(regs->sar, &sc->sc_sar); +#if DEBUG_SIG + printk("setup_sigcontext: r28 is %ld\n", regs->gr[28]); +#endif + + return err; +} + +static long +setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs, int in_syscall) +{ + struct rt_sigframe *frame; + unsigned long rp, usp, haddr; + struct siginfo si; + int err = 0; + + usp = regs->gr[30]; + /* access_ok is broken, so do a simplistic "are we stomping on + kernel space" assertion. */ + if (usp > PAGE_OFFSET) { + printk("setup_rt_frame: called on kernel space (usp=%#lx), NOW YOU MUST DIE!!!\n", + usp); + show_regs(regs); + while(1); + } + + frame = get_sigframe(ka, usp, sizeof(*frame)); + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + +#if DEBUG_SIG + printk("setup_rt_frame 1: frame %p info %p\n", frame, info); +#endif + + err |= __copy_to_user(&frame->info, info, sizeof(siginfo_t)); + err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= __put_user(sas_ss_flags(regs->gr[30]), + &frame->uc.uc_stack.ss_flags); + err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, in_syscall); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + if (err) + goto give_sigsegv; + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + err |= __put_user(in_syscall ? INSN_LDI_R25_1 : INSN_LDI_R25_0, + &frame->tramp[0]); + err |= __put_user(INSN_LDI_R20, &frame->tramp[1]); + err |= __put_user(INSN_BLE_SR2_R0, &frame->tramp[2]); + err |= __put_user(INSN_NOP, &frame->tramp[3]); + +#if DEBUG_SIG + /* Assert that we're flushing in the correct space... */ + { + int sid; + asm ("mfsp %%sr3,%0" : "=r" (sid)); + printk("flushing 64 bytes at space %#x offset %p\n", + sid, frame->tramp); + } +#endif + +#if CACHE_FLUSHING_IS_NOT_BROKEN + flush_icache_range((unsigned long) &frame->tramp[0], + (unsigned long) &frame->tramp[4]); +#else + /* It should *always* be cache line-aligned, but the compiler + sometimes screws up. */ + asm volatile("fdc 0(%%sr3,%0)\n\t" + "fdc %1(%%sr3,%0)\n\t" + "sync\n\t" + "fic 0(%%sr3,%0)\n\t" + "fic %1(%%sr3,%0)\n\t" + "sync\n\t" + : : "r" (frame->tramp), "r" (L1_CACHE_BYTES)); +#endif + rp = (unsigned long) frame->tramp; + + if (err) + goto give_sigsegv; + +#ifdef __LP64__ +/* Much more has to happen with signals than this -- but it'll at least */ +/* provide a pointer to some places which definitely need a look. */ +#define HACK unsigned int +#else +#define HACK unsigned long +#endif + haddr = (HACK) ka->sa.sa_handler; + /* ARGH! Fucking brain damage. You don't want to know. */ + if (haddr & 2) { + HACK *plabel; + HACK ltp; + + plabel = (HACK *) (haddr & ~3); + err |= __get_user(haddr, plabel); + err |= __get_user(ltp, plabel + 1); + if (err) + goto give_sigsegv; + regs->gr[19] = ltp; + } + + /* The syscall return path will create IAOQ values from r31. + */ + if (in_syscall) + regs->gr[31] = (HACK) haddr; + else { + regs->iaoq[0] = (HACK) haddr | 3; + regs->iaoq[1] = regs->iaoq[0] + 4; + } + + regs->gr[2] = rp; /* userland return pointer */ + regs->gr[26] = sig; /* signal number */ + regs->gr[25] = (HACK) &frame->info; /* siginfo pointer */ + regs->gr[24] = (HACK) &frame->uc; /* ucontext pointer */ +#if DEBUG_SIG + printk("making sigreturn frame: %#lx + %#lx = %#lx\n", + regs->gr[30], PARISC_RT_SIGFRAME_SIZE, + regs->gr[30] + PARISC_RT_SIGFRAME_SIZE); +#endif + /* Raise the user stack pointer to make a proper call frame. */ + regs->gr[30] = ((HACK) frame + PARISC_RT_SIGFRAME_SIZE); + +#if DEBUG_SIG + printk("SIG deliver (%s:%d): frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n", + current->comm, current->pid, frame, regs->gr[30], + regs->iaoq[0], regs->iaoq[1], rp); +#endif + + return 1; + +give_sigsegv: +#if DEBUG_SIG + printk("fuckup in setup_rt_frame, sending SIGSEGV\n"); +#endif + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + si.si_signo = SIGSEGV; + si.si_errno = 0; + si.si_code = SI_KERNEL; + si.si_pid = current->pid; + si.si_uid = current->uid; + si.si_addr = frame; + force_sig_info(SIGSEGV, &si, current); + return 0; +} + +/* + * OK, we're invoking a handler. + */ + +static long +handle_signal(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, + struct pt_regs *regs, int in_syscall) +{ +#if DEBUG_SIG + printk("handle_signal(sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p)\n", + sig, ka, info, oldset, regs); +#endif + /* Set up the stack frame */ + if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall)) + return 0; + + if (ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + + if (!(ka->sa.sa_flags & SA_NODEFER)) { + spin_lock_irq(¤t->sigmask_lock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked,sig); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + } + return 1; +} + +/* + * Note that 'init' is a special process: it doesn't get signals it doesn't + * want to handle. Thus you cannot kill init even with a SIGKILL even by + * mistake. + * + * We need to be able to restore the syscall arguments (r21-r26) to + * restart syscalls. Thus, the syscall path should save them in the + * pt_regs structure (it's okay to do so since they are caller-save + * registers). As noted below, the syscall number gets restored for + * us due to the magic of delayed branching. + */ +asmlinkage int +do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall) +{ + siginfo_t info; + struct k_sigaction *ka; + +#if DEBUG_SIG + printk("do_signal(oldset=0x%p, regs=0x%p, sr7 %#lx, pending %d, in_syscall=%d\n", + oldset, regs, regs->sr[7], current->sigpending, in_syscall); +#endif + /* Everyone else checks to see if they are in kernel mode at + this point and exits if that's the case. I'm not sure why + we would be called in that case, but for some reason we + are. */ + + if (!oldset) + oldset = ¤t->blocked; + +#if DEBUG_SIG + printk("do_signal: oldset %08lx:%08lx\n", oldset->sig[0], oldset->sig[1]); +#endif + + for (;;) { + unsigned long signr; + + spin_lock_irq(¤t->sigmask_lock); + signr = dequeue_signal(¤t->blocked, &info); + spin_unlock_irq(¤t->sigmask_lock); +#if DEBUG_SIG + printk("do_signal: signr=%ld, pid=%d\n", signr, current->pid); +#endif + + if (!signr) + break; + + if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { + /* Let the debugger run. */ + current->exit_code = signr; + set_current_state(TASK_STOPPED); + notify_parent(current, SIGCHLD); + schedule(); + + /* We're back. Did the debugger cancel the sig? */ + if (!(signr = current->exit_code)) + continue; + current->exit_code = 0; + + /* The debugger continued. Ignore SIGSTOP. */ + if (signr == SIGSTOP) + continue; + + /* Update the siginfo structure. Is this good? */ + if (signr != info.si_signo) { + info.si_signo = signr; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = current->p_pptr->pid; + info.si_uid = current->p_pptr->uid; + } + + /* If the (new) signal is now blocked, requeue it. */ + if (sigismember(¤t->blocked, signr)) { + send_sig_info(signr, &info, current); + continue; + } + } + + ka = ¤t->sig->action[signr-1]; +#if DEBUG_SIG + printk("sa_handler is %lx\n", ka->sa.sa_handler); +#endif + if ((unsigned long) ka->sa.sa_handler == (unsigned long) SIG_IGN) { + if (signr != SIGCHLD) + continue; + while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) + /* nothing */; + continue; + } + + if ((unsigned long) ka->sa.sa_handler == (unsigned long) SIG_DFL) { + int exit_code = signr; + + /* Init gets no signals it doesn't want. */ + if (current->pid == 1) + continue; + + switch (signr) { + case SIGCONT: case SIGCHLD: case SIGWINCH: + continue; + + case SIGTSTP: case SIGTTIN: case SIGTTOU: + if (is_orphaned_pgrp(current->pgrp)) + continue; + /* FALLTHRU */ + + case SIGSTOP: + set_current_state(TASK_STOPPED); + current->exit_code = signr; + if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) + notify_parent(current, SIGCHLD); + schedule(); + continue; + + case SIGQUIT: case SIGILL: case SIGTRAP: + case SIGABRT: case SIGFPE: case SIGSEGV: + case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: + if (signr == SIGQUIT) /* Userspace debugging */ + show_regs(regs); + if (do_coredump(signr, regs)) + exit_code |= 0x80; + /* FALLTHRU */ + + default: + lock_kernel(); + sigaddset(¤t->pending.signal, signr); + recalc_sigpending(current); + current->flags |= PF_SIGNALED; + do_exit(exit_code); + /* NOTREACHED */ + } + } + + /* Restart a system call if necessary. */ + if (in_syscall) { + /* Check the return code */ + switch (regs->gr[28]) { + case -ERESTARTNOHAND: +#if DEBUG_SIG + printk("ERESTARTNOHAND: returning -EINTR\n"); +#endif + regs->gr[28] = -EINTR; + break; + + case -ERESTARTSYS: + if (!(ka->sa.sa_flags & SA_RESTART)) { +#if DEBUG_SIG + printk("ERESTARTSYS: putting -EINTR\n"); +#endif + regs->gr[28] = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + /* A syscall is just a branch, so all + we have to do is fiddle the return + pointer. */ + regs->gr[31] -= 8; /* delayed branching */ + /* Preserve original r28. */ + regs->gr[28] = regs->orig_r28; + break; + } + } + /* Whee! Actually deliver the signal. If the + delivery failed, we need to continue to iterate in + this loop so we can deliver the SIGSEGV... */ + if (handle_signal(signr, ka, &info, oldset, regs, in_syscall)) { +#if DEBUG_SIG + printk("Exiting do_signal (success), regs->gr[28] = %ld\n", regs->gr[28]); +#endif + return 1; + } + } + + /* Did we come from a system call? */ + if (in_syscall) { + /* Restart the system call - no handlers present */ + if (regs->gr[28] == -ERESTARTNOHAND || + regs->gr[28] == -ERESTARTSYS || + regs->gr[28] == -ERESTARTNOINTR) { + /* Hooray for delayed branching. We don't + have to restore %r20 (the system call + number) because it gets loaded in the delay + slot of the branch external instruction. */ + regs->gr[31] -= 8; + /* Preserve original r28. */ + regs->gr[28] = regs->orig_r28; + } + } +#if DEBUG_SIG + printk("Exiting do_signal (not delivered), regs->gr[28] = %ld\n", regs->gr[28]); +#endif + return 0; +} diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c new file mode 100644 index 000000000..85aca70af --- /dev/null +++ b/arch/parisc/kernel/sys_parisc.c @@ -0,0 +1,88 @@ +/* + * linux/arch/parisc/kernel/sys_parisc.c + * + * this implements the missing syscalls. + */ + +#include <asm/uaccess.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/linkage.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/smp_lock.h> + +/* for some reason, "old_readdir" is the only syscall which does not begin + * with "sys_", which breaks the ENTRY_* macros in syscall.S so I "fixed" + * it here. + */ + +int sys_old_readdir(unsigned int fd, void *dirent, unsigned int count) +{ + return old_readdir(fd, dirent, count); +} + +int sys_pipe(int *fildes) +{ + int fd[2]; + int error; + + lock_kernel(); + error = do_pipe(fd); + unlock_kernel(); + if (!error) { + if (copy_to_user(fildes, fd, 2*sizeof(int))) + error = -EFAULT; + } + return error; +} + +int sys_pause(void) +{ + current->state = TASK_INTERRUPTIBLE; + schedule(); + return -ERESTARTNOHAND; +} + +int sys_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, unsigned long fd, + unsigned long offset) +{ + struct file * file = NULL; + int error; + + down(¤t->mm->mmap_sem); + lock_kernel(); + if (!(flags & MAP_ANONYMOUS)) { + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + } + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + error = do_mmap(file, addr, len, prot, flags, offset); + if (file != NULL) + fput(file); +out: + unlock_kernel(); + up(¤t->mm->mmap_sem); + return error; +} + +int sys_ioperm(unsigned long from, unsigned long num, int on) +{ + return -ENOSYS; +} + +long sys_shmat_wrapper(int shmid, void *shmaddr, int shmflag) +{ + extern int sys_shmat(int shmid, char *shmaddr, int shmflg, + unsigned long * raddr); + unsigned long raddr; + int r; + + r = sys_shmat(shmid, shmaddr, shmflag, &raddr); + if (r < 0) + return r; + return raddr; +} diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S new file mode 100644 index 000000000..bfa757471 --- /dev/null +++ b/arch/parisc/kernel/syscall.S @@ -0,0 +1,563 @@ +/* + * Linux/PARISC Project (http://www.thepuffingroup.com/parisc) + * + * System call entry code Copyright (c) Matthew Wilcox 1999 <willy@bofh.ai> + * Licensed under the GNU GPL. + * thanks to Philipp Rumpf, Mike Shaver and various others + * sorry about the wall, puffin.. + */ + +#include <asm/offset.h> +#include <asm/unistd.h> +#include <asm/errno.h> +#include <asm/psw.h> + +#define __ASSEMBLY__ +#include <asm/assembly.h> +#include <asm/processor.h> +#include <linux/version.h> + +#ifdef __LP64__ + .level 2.0w +#else + .level 1.1 +#endif + .text + + .import syscall_exit,code + .import syscall_exit_rfi,code + .export linux_gateway_page + + /* Linux gateway page is aliased to virtual page 0 in the kernel + * address space. Since it is a gateway page it cannot be + * dereferenced, so null pointers will still fault. We start + * the actual entry point at 0x100. We put break instructions + * at the beginning of the page to trap null indirect function + * pointers. + */ + + .align 4096 +linux_gateway_page: + + break 0,0 + + .align 256 +linux_gateway_entry: + mfsp %sr7,%r1 /* we must set sr3 to the space */ + mtsp %r1,%sr3 /* of the user before the gate */ + gate .+8, %r0 /* become privileged */ + mtsp %r0,%sr4 /* get kernel space into sr4 */ + mtsp %r0,%sr5 /* get kernel space into sr5 */ + mtsp %r0,%sr6 /* get kernel space into sr6 */ + mtsp %r0,%sr7 /* get kernel space into sr7 */ +#ifdef __LP64__ + /* for now we can *always* set the W bit on entry to the syscall + * since we don't support wide userland processes. We could + * also save the current SM other than in r0 and restore it on + * exit from the syscall, and also use that value to know + * whether to do narrow or wide syscalls. -PB + */ + ssm PSW_SM_W, %r0 +#endif + mtctl %r28,%cr27 + rsm PSW_I, %r28 /* no ints for a bit */ + mfctl %cr30,%r1 /* get the kernel task ptr */ + mtctl %r0,%cr30 /* zero it (flag) */ + + /* Save some registers for sigcontext and potential task + switch (see entry.S for the details of which ones are + saved/restored) */ + STREG %r2, TASK_PT_GR2(%r1) /* preserve rp */ + STREG %r19, TASK_PT_GR19(%r1) + STREG %r20, TASK_PT_GR20(%r1) + STREG %r21, TASK_PT_GR21(%r1) + STREG %r22, TASK_PT_GR22(%r1) + STREG %r23, TASK_PT_GR23(%r1) /* 4th argument */ + STREG %r24, TASK_PT_GR24(%r1) /* 3rd argument */ + STREG %r25, TASK_PT_GR25(%r1) /* 2nd argument */ + STREG %r26, TASK_PT_GR26(%r1) /* 1st argument */ + STREG %r27, TASK_PT_GR27(%r1) /* user dp */ + mfctl %cr27,%r19 + STREG %r19, TASK_PT_GR28(%r1) /* return value 0 */ + STREG %r19, TASK_PT_ORIG_R28(%r1) /* return value 0 (saved for signals) */ + STREG %r29, TASK_PT_GR29(%r1) /* return value 1 */ + STREG %r30, TASK_PT_GR30(%r1) /* preserve userspace sp */ + STREG %r31, TASK_PT_GR31(%r1) /* preserve syscall return ptr */ + + ldo TASK_PT_FR0(%r1), %r27 /* save fpregs from the kernel */ + save_fp %r27 /* or potential task switch */ + + mfctl %cr11, %r27 /* i.e. SAR */ + STREG %r27, TASK_PT_SAR(%r1) + + loadgp + + ldo TASK_SZ_ALGN+64(%r1),%r30 /* set up kernel stack */ + +#ifndef __LP64__ + /* no need to save these on stack because in wide mode the first 8 + * args are passed in registers */ + stw %r22, -52(%r30) /* 5th argument */ + stw %r21, -56(%r30) /* 6th argument */ +#endif + + /* for some unknown reason, task_struct.ptrace is an unsigned long so use LDREG */ + LDREG TASK_PTRACE(%r1), %r19 /* Are we being ptraced? */ + mtsm %r28 /* irqs back */ + + bb,<,n %r19, 31, .Ltracesys /* must match PT_PTRACE bit */ + + /* Note! We cannot use the syscall table that is mapped + nearby since the gateway page is mapped execute-only. */ + + ldil L%sys_call_table, %r1 + ldo R%sys_call_table(%r1), %r19 + LDIL_FIXUP(%r19) + + comiclr,>>= __NR_Linux_syscalls, %r20, %r0 + b,n .Lsyscall_nosys + +#ifdef __LP64__ + ldd,s %r20(%r19), %r19 +#else + ldwx,s %r20(%r19), %r19 +#endif + /* If this is a sys_rt_sigreturn call, and the signal was received + * when not in_syscall, then we want to return via syscall_exit_rfi, + * not syscall_exit. Signal no. in r20, in_syscall in r25 (see + * trampoline code in signal.c). + */ + ldi __NR_rt_sigreturn,%r2 + comb,= %r2,%r20,.Lrt_sigreturn +.Lin_syscall: + ldil L%syscall_exit,%r2 + LDIL_FIXUP(%r2) + be 0(%sr7,%r19) + ldo R%syscall_exit(%r2),%r2 +.Lrt_sigreturn: + comib,<> 0,%r25,.Lin_syscall + ldil L%syscall_exit_rfi,%r2 + LDIL_FIXUP(%r2) + be 0(%sr7,%r19) + ldo R%syscall_exit_rfi(%r2),%r2 + + /* Note! Because we are not running where we were linked, any + calls to functions external to this file must be indirect. To + be safe, we apply the opposite rule to functions within this + file, with local labels given to them to ensure correctness. */ + +.Lsyscall_nosys: +syscall_nosys: + ldil L%syscall_exit,%r1 + LDIL_FIXUP(%r1) + be R%syscall_exit(%sr7,%r1) + ldo -ENOSYS(%r0),%r28 /* set errno */ + + +/* Warning! This trace code is a virtual duplicate of the code above so be + * sure to maintain both! */ +.Ltracesys: +tracesys: + /* Need to save more registers so the debugger can see where we + * are. + */ + ldo -TASK_SZ_ALGN-64(%r30),%r1 /* get task ptr */ + ssm 0,%r2 /* Lower 8 bits only!! */ + STREG %r2,TASK_PT_PSW(%r1) + STREG %r1,TASK_PT_CR30(%r1) + mfsp %sr0,%r2 + STREG %r2,TASK_PT_SR0(%r1) + mfsp %sr1,%r2 + STREG %r2,TASK_PT_SR1(%r1) + mfsp %sr2,%r2 + STREG %r2,TASK_PT_SR2(%r1) + mfsp %sr3,%r2 + STREG %r2,TASK_PT_SR3(%r1) + STREG %r2,TASK_PT_SR4(%r1) + STREG %r2,TASK_PT_SR5(%r1) + STREG %r2,TASK_PT_SR6(%r1) + STREG %r2,TASK_PT_SR7(%r1) + STREG %r2,TASK_PT_IASQ0(%r1) + STREG %r2,TASK_PT_IASQ1(%r1) + LDREG TASK_PT_GR31(%r1),%r2 + STREG %r2,TASK_PT_IAOQ0(%r1) + ldo 4(%r2),%r2 + STREG %r2,TASK_PT_IAOQ1(%r1) + ldo TASK_REGS(%r1),%r2 + /* reg_save %r2 */ + STREG %r3,PT_GR3(%r2) + STREG %r4,PT_GR4(%r2) + STREG %r5,PT_GR5(%r2) + STREG %r6,PT_GR6(%r2) + STREG %r7,PT_GR7(%r2) + STREG %r8,PT_GR8(%r2) + STREG %r9,PT_GR9(%r2) + STREG %r10,PT_GR10(%r2) + STREG %r11,PT_GR11(%r2) + STREG %r12,PT_GR12(%r2) + STREG %r13,PT_GR13(%r2) + STREG %r14,PT_GR14(%r2) + STREG %r15,PT_GR15(%r2) + STREG %r16,PT_GR16(%r2) + STREG %r17,PT_GR17(%r2) + STREG %r18,PT_GR18(%r2) + /* Finished saving things for the debugger */ + + ldil L%syscall_trace,%r1 + LDIL_FIXUP(%r1) + ldil L%tracesys_next,%r2 + LDIL_FIXUP(%r2) + be R%syscall_trace(%sr7,%r1) + ldo R%tracesys_next(%r2),%r2 + +tracesys_next: + ldil L%sys_call_table,%r1 + LDIL_FIXUP(%r1) + ldo R%sys_call_table(%r1), %r19 + + ldo -TASK_SZ_ALGN-64(%r30),%r1 /* get task ptr */ + LDREG TASK_PT_GR20(%r1), %r20 + LDREG TASK_PT_GR26(%r1), %r26 /* Restore the users args */ + LDREG TASK_PT_GR25(%r1), %r25 + LDREG TASK_PT_GR24(%r1), %r24 + LDREG TASK_PT_GR23(%r1), %r23 +#ifdef __LP64__ + LDREG TASK_PT_GR22(%r1), %r22 + LDREG TASK_PT_GR21(%r1), %r21 +#endif + + comiclr,>>= __NR_Linux_syscalls, %r20, %r0 + b,n .Lsyscall_nosys + +#ifdef __LP64__ + ldd,s %r20(%r19), %r19 +#else + ldwx,s %r20(%r19), %r19 +#endif + /* If this is a sys_rt_sigreturn call, and the signal was received + * when not in_syscall, then we want to return via syscall_exit_rfi, + * not syscall_exit. Signal no. in r20, in_syscall in r25 (see + * trampoline code in signal.c). + */ + ldi __NR_rt_sigreturn,%r2 + comb,= %r2,%r20,.Ltrace_rt_sigreturn +.Ltrace_in_syscall: + ldil L%tracesys_exit,%r2 + LDIL_FIXUP(%r2) + be 0(%sr7,%r19) + ldo R%tracesys_exit(%r2),%r2 + + /* Do *not* call this function on the gateway page, because it + makes a direct call to syscall_trace. */ + +tracesys_exit: + ldo -TASK_SZ_ALGN-64(%r30),%r1 /* get task ptr */ + bl syscall_trace, %r2 + STREG %r28,TASK_PT_GR28(%r1) /* save return value now */ + ldo -TASK_SZ_ALGN-64(%r30),%r1 /* get task ptr */ + LDREG TASK_PT_GR28(%r1), %r28 /* Restore return val. */ + + ldil L%syscall_exit,%r1 + LDIL_FIXUP(%r1) + be,n R%syscall_exit(%sr7,%r1) + +.Ltrace_rt_sigreturn: + comib,<> 0,%r25,.Ltrace_in_syscall + ldil L%tracesys_sigexit,%r2 + LDIL_FIXUP(%r2) + be 0(%sr7,%r19) + ldo R%tracesys_sigexit(%r2),%r2 + +tracesys_sigexit: + ldo -TASK_SZ_ALGN-64(%r30),%r1 /* get task ptr */ + bl syscall_trace, %r2 + nop + + ldil L%syscall_exit_rfi,%r1 + LDIL_FIXUP(%r1) + be,n R%syscall_exit_rfi(%sr7,%r1) + +#ifdef __LP64__ +/* Use ENTRY_SAME for 32-bit syscalls which are the same on wide and + * narrow palinux. Use ENTRY_DIFF for those where a 32-bit specific + * implementation is required on wide palinux. + */ +#define ENTRY_SAME(_name_) .dword sys_##_name_ +#define ENTRY_DIFF(_name_) .dword sys32_##_name_ +#define ENTRY_UHOH(_name_) .dword sys32_unimplemented +#else +#define ENTRY_SAME(_name_) .word sys_##_name_ +#define ENTRY_DIFF(_name_) .word sys_##_name_ +#define ENTRY_UHOH(_name_) .word sys_##_name_ +#endif + + .align 8 + .export sys_call_table +.Lsys_call_table: +sys_call_table: + ENTRY_SAME(ni_syscall) /* 0 - old "setup()" system call*/ + ENTRY_SAME(exit) + ENTRY_SAME(fork_wrapper) + ENTRY_SAME(read) + ENTRY_SAME(write) + ENTRY_SAME(open) /* 5 */ + ENTRY_SAME(close) + ENTRY_SAME(waitpid) + ENTRY_SAME(creat) + ENTRY_SAME(link) + ENTRY_SAME(unlink) /* 10 */ + ENTRY_DIFF(execve_wrapper) + ENTRY_SAME(chdir) + /* See comments in kernel/time.c!!! Maybe we don't need this? */ + ENTRY_DIFF(time) + ENTRY_SAME(mknod) + ENTRY_SAME(chmod) /* 15 */ + ENTRY_SAME(lchown) + ENTRY_SAME(socket) + /* struct stat is MAYBE identical wide and narrow ?? */ + ENTRY_DIFF(newstat) + ENTRY_SAME(lseek) + ENTRY_SAME(getpid) /* 20 */ + /* the 'void * data' parameter may need re-packing in wide */ + ENTRY_DIFF(mount) + /* concerned about struct sockaddr in wide/narrow */ + /* ---> I think sockaddr is OK unless the compiler packs the struct */ + /* differently to align the char array */ + ENTRY_SAME(bind) + ENTRY_SAME(setuid) + ENTRY_SAME(getuid) + ENTRY_SAME(stime) /* 25 */ + ENTRY_SAME(ptrace) + ENTRY_SAME(alarm) + /* see stat comment */ + ENTRY_DIFF(newfstat) + ENTRY_SAME(pause) + /* struct utimbuf uses time_t which might vary */ + ENTRY_DIFF(utime) /* 30 */ + /* struct sockaddr... */ + ENTRY_SAME(connect) + ENTRY_SAME(listen) + ENTRY_SAME(access) + ENTRY_SAME(nice) + /* struct sockaddr... */ + ENTRY_SAME(accept) /* 35 */ + ENTRY_SAME(sync) + ENTRY_SAME(kill) + ENTRY_SAME(rename) + ENTRY_SAME(mkdir) + ENTRY_SAME(rmdir) /* 40 */ + ENTRY_SAME(dup) + ENTRY_SAME(pipe) + ENTRY_DIFF(times) + /* struct sockaddr... */ + ENTRY_SAME(getsockname) + /* it seems possible brk() could return a >4G pointer... */ + ENTRY_SAME(brk) /* 45 */ + ENTRY_SAME(setgid) + ENTRY_SAME(getgid) + ENTRY_SAME(signal) + ENTRY_SAME(geteuid) + ENTRY_SAME(getegid) /* 50 */ + ENTRY_SAME(acct) + ENTRY_SAME(umount) + /* struct sockaddr... */ + ENTRY_SAME(getpeername) + /* This one's a huge ugly mess */ + ENTRY_DIFF(ioctl) + /* struct flock? */ + ENTRY_DIFF(fcntl) /* 55 */ + ENTRY_SAME(socketpair) + ENTRY_SAME(setpgid) + ENTRY_SAME(send) + ENTRY_SAME(newuname) + ENTRY_SAME(umask) /* 60 */ + ENTRY_SAME(chroot) + ENTRY_SAME(ustat) + ENTRY_SAME(dup2) + ENTRY_SAME(getppid) + ENTRY_SAME(getpgrp) /* 65 */ + ENTRY_SAME(setsid) + ENTRY_SAME(pivot_root) + /* I don't like this */ + ENTRY_UHOH(sgetmask) + ENTRY_UHOH(ssetmask) + ENTRY_SAME(setreuid) /* 70 */ + ENTRY_SAME(setregid) + ENTRY_SAME(mincore) + ENTRY_DIFF(sigpending) + ENTRY_SAME(sethostname) + /* Following 3 have linux-common-code structs containing longs -( */ + ENTRY_DIFF(setrlimit) /* 75 */ + ENTRY_DIFF(getrlimit) + ENTRY_DIFF(getrusage) + /* struct timeval and timezone are maybe?? consistent wide and narrow */ + ENTRY_SAME(gettimeofday) + ENTRY_SAME(settimeofday) + ENTRY_SAME(getgroups) /* 80 */ + ENTRY_SAME(setgroups) + /* struct socketaddr... */ + ENTRY_SAME(sendto) + ENTRY_SAME(symlink) + /* see stat comment */ + ENTRY_DIFF(newlstat) + ENTRY_SAME(readlink) /* 85 */ + /* suspect we'll need some work for narrow shlibs on wide kernel */ + ENTRY_UHOH(uselib) + ENTRY_SAME(swapon) + ENTRY_SAME(reboot) + /* argh! struct dirent contains a long */ + ENTRY_UHOH(old_readdir) + /* I'm not certain about off_t... */ + ENTRY_SAME(mmap) /* 90 */ + ENTRY_SAME(munmap) + ENTRY_SAME(truncate) + ENTRY_SAME(ftruncate) + ENTRY_SAME(fchmod) + ENTRY_SAME(fchown) /* 95 */ + ENTRY_SAME(getpriority) + ENTRY_SAME(setpriority) + ENTRY_SAME(recv) + ENTRY_DIFF(statfs) + ENTRY_DIFF(fstatfs) /* 100 */ + ENTRY_SAME(ni_syscall) + /* don't think hppa glibc even provides an entry pt for this + * so disable for now */ + ENTRY_UHOH(socketcall) + ENTRY_SAME(syslog) + /* even though manpage says struct timeval contains longs, ours has + * time_t and suseconds_t -- both of which are safe wide/narrow */ + ENTRY_SAME(setitimer) + ENTRY_SAME(getitimer) /* 105 */ + ENTRY_SAME(capget) + ENTRY_SAME(capset) + ENTRY_SAME(pread) + ENTRY_SAME(pwrite) + ENTRY_SAME(getcwd) /* 110 */ + ENTRY_SAME(vhangup) + ENTRY_SAME(ni_syscall) + ENTRY_SAME(vfork_wrapper) + /* struct rusage contains longs... */ + ENTRY_DIFF(wait4) + ENTRY_SAME(swapoff) /* 115 */ + /* struct sysinfo contains longs */ + ENTRY_SAME(sysinfo) + ENTRY_SAME(shutdown) + ENTRY_SAME(fsync) + ENTRY_SAME(madvise) + ENTRY_SAME(clone_wrapper) /* 120 */ + ENTRY_SAME(setdomainname) + ENTRY_SAME(sendfile) + /* struct sockaddr... */ + ENTRY_SAME(recvfrom) + /* struct timex contains longs */ + ENTRY_UHOH(adjtimex) + ENTRY_SAME(mprotect) /* 125 */ + /* old_sigset_t forced to 32 bits. Beware glibc sigset_t */ + ENTRY_DIFF(sigprocmask) + ENTRY_SAME(create_module) + /* struct module contains longs, but insmod builds a 64 bit struct + * if running under a 64 bit kernel */ + ENTRY_SAME(init_module) + ENTRY_SAME(delete_module) + /* struct kernel_sym contains a long. Linus never heard of size_t? */ + ENTRY_DIFF(get_kernel_syms) /* 130 */ + ENTRY_SAME(quotactl) + ENTRY_SAME(getpgid) + ENTRY_SAME(fchdir) + /* bdflush(func, addr) where func has least-significant-bit set means + * addr is a pointer to long :-( */ + ENTRY_UHOH(bdflush) + ENTRY_SAME(sysfs) /* 135 */ + ENTRY_SAME(personality) + ENTRY_SAME(ni_syscall) /* for afs_syscall */ + ENTRY_SAME(setfsuid) + ENTRY_SAME(setfsgid) + /* I think this might work */ + ENTRY_SAME(llseek) /* 140 */ + /* struct linux_dirent has longs, like 'unsigned long d_ino' which + * almost definitely should be 'ino_t d_ino' but it's too late now */ + ENTRY_DIFF(getdents) + /* it is POSSIBLE that select will be OK because even though fd_set + * contains longs, the macros and sizes are clever. */ + ENTRY_SAME(select) + ENTRY_SAME(flock) + ENTRY_SAME(msync) + /* struct iovec contains pointers */ + ENTRY_UHOH(readv) /* 145 */ + ENTRY_UHOH(writev) + ENTRY_SAME(getsid) + ENTRY_SAME(fdatasync) + /* struct __sysctl_args is a mess */ + ENTRY_DIFF(sysctl) + ENTRY_SAME(mlock) /* 150 */ + ENTRY_SAME(munlock) + ENTRY_SAME(mlockall) + ENTRY_SAME(munlockall) + /* struct sched_param is ok for now */ + ENTRY_SAME(sched_setparam) + ENTRY_SAME(sched_getparam) /* 155 */ + ENTRY_SAME(sched_setscheduler) + ENTRY_SAME(sched_getscheduler) + ENTRY_SAME(sched_yield) + ENTRY_SAME(sched_get_priority_max) + ENTRY_SAME(sched_get_priority_min) /* 160 */ + /* These 2 would've worked if someone had defined struct timespec + * carefully, like timeval for example (which is about the same). + * Unfortunately it contains a long :-( */ + ENTRY_DIFF(sched_rr_get_interval) + ENTRY_DIFF(nanosleep) + ENTRY_SAME(mremap) + ENTRY_SAME(setresuid) + ENTRY_SAME(getresuid) /* 165 */ + /* might work, but in general signals need a thorough review */ + ENTRY_UHOH(sigaltstack_wrapper) + /* struct passed back to user can contain long symbol values */ + ENTRY_DIFF(query_module) + ENTRY_SAME(poll) + /* structs contain pointers and an in_addr... */ + ENTRY_UHOH(nfsservctl) + ENTRY_SAME(setresgid) /* 170 */ + ENTRY_SAME(getresgid) + ENTRY_SAME(prctl) + /* signals need a careful review */ + ENTRY_SAME(rt_sigreturn_wrapper) + ENTRY_DIFF(rt_sigaction) + ENTRY_DIFF(rt_sigprocmask) /* 175 */ + ENTRY_DIFF(rt_sigpending) + ENTRY_UHOH(rt_sigtimedwait) + ENTRY_UHOH(rt_sigqueueinfo) + ENTRY_SAME(rt_sigsuspend_wrapper) /* not really SAME -- see the code */ + ENTRY_SAME(chown) /* 180 */ + /* *sockopt() might work... */ + ENTRY_SAME(setsockopt) + ENTRY_SAME(getsockopt) + /* struct msghdr contains pointers... */ + ENTRY_UHOH(sendmsg) + ENTRY_UHOH(recvmsg) + ENTRY_SAME(semop) /* 185 */ + ENTRY_SAME(semget) + /* needs a more careful review */ + ENTRY_UHOH(semctl) + /* struct msgbuf contains a long */ + ENTRY_UHOH(msgsnd) + ENTRY_UHOH(msgrcv) + ENTRY_SAME(msgget) /* 190 */ + /* struct msqid_ds contains pointers */ + ENTRY_UHOH(msgctl) + ENTRY_SAME(shmat_wrapper) + ENTRY_SAME(shmdt) + ENTRY_SAME(shmget) + /***************/ + /* struct shmid_ds contains pointers */ + ENTRY_UHOH(shmctl) /* 195 */ + ENTRY_SAME(ni_syscall) /* streams1 */ + ENTRY_SAME(ni_syscall) /* streams2 */ + +.end + + /* Make sure nothing else is placed on this page */ + + .align 4096 + .export end_linux_gateway_page +end_linux_gateway_page: + diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c new file mode 100644 index 000000000..7b3de0e0a --- /dev/null +++ b/arch/parisc/kernel/time.c @@ -0,0 +1,98 @@ +/* + * linux/arch/arm/kernel/time.c + * + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * Modifications for ARM (C) 1994, 1995, 1996,1997 Russell King + * Copyright (C) 1999 SuSE GmbH, (Philipp Rumpf, prumpf@tux.org) + * + * 1994-07-02 Alan Modra + * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime + * 1998-12-20 Updated NTP code according to technical memorandum Jan '96 + * "A Kernel Model for Precision Timekeeping" by Dave Mills + */ +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/smp.h> + +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/param.h> +#include <asm/pdc.h> +#include <asm/led.h> + +#include <linux/timex.h> + +extern rwlock_t xtime_lock; + +static int timer_value; +static int timer_delta; +static struct pdc_tod tod_data __attribute__((aligned(8))); + +void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int old; + int lost = 0; + int cr16; + + old = timer_value; + + cr16 = mfctl(16); + while((timer_value - cr16) < (timer_delta / 2)) { + timer_value += timer_delta; + lost++; + } + + mtctl(timer_value ,16); + + do_timer(regs); + + led_interrupt_func(); +} + +void do_gettimeofday(struct timeval *tv) +{ + unsigned long flags; + + read_lock_irqsave(&xtime_lock, flags); + tv->tv_sec = xtime.tv_sec; + tv->tv_usec = xtime.tv_usec; + read_unlock_irqrestore(&xtime_lock, flags); + +} + +void do_settimeofday(struct timeval *tv) +{ + write_lock_irq(&xtime_lock); + xtime.tv_sec = tv->tv_sec; + xtime.tv_usec = tv->tv_usec; + write_unlock_irq(&xtime_lock); +} + +void __init time_init(void) +{ + timer_delta = (100 * PAGE0->mem_10msec) / HZ; + + /* make the first timer interrupt go off in one second */ + timer_value = mfctl(16) + (HZ * timer_delta); + mtctl(timer_value, 16); + + + if(pdc_tod_read(&tod_data) == 0) { + xtime.tv_sec = tod_data.tod_sec; + xtime.tv_usec = tod_data.tod_usec; + } else { + printk(KERN_ERR "Error reading tod clock\n"); + xtime.tv_sec = 0; + xtime.tv_usec = 0; + } + +} + diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c new file mode 100644 index 000000000..d85553702 --- /dev/null +++ b/arch/parisc/kernel/traps.c @@ -0,0 +1,895 @@ +/* + * linux/arch/parisc/traps.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1999, 2000 Philipp Rumpf <prumpf@tux.org> + */ + +/* + * 'Traps.c' handles hardware traps and faults after we have saved some + * state in 'asm.s'. + */ + +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/ptrace.h> +#include <linux/timer.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/spinlock.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <asm/system.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/atomic.h> + +#include <asm/smp.h> +#include <asm/pdc.h> + +#ifdef CONFIG_KWDB +#include <kdb/break.h> /* for BI2_KGDB_GDB */ +#include <kdb/kgdb_types.h> /* for __() */ +#include <kdb/save_state.h> /* for struct save_state */ +#include <kdb/kgdb_machine.h> /* for pt_regs_to_ssp and ssp_to_pt_regs */ +#include <kdb/trap.h> /* for I_BRK_INST */ +#endif /* CONFIG_KWDB */ + + +static inline void console_verbose(void) +{ + extern int console_loglevel; + console_loglevel = 15; +} + + +void page_exception(void); + +/* + * These constants are for searching for possible module text + * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is + * a guess of how much space is likely to be vmalloced. + */ +#define VMALLOC_OFFSET (8*1024*1024) +#define MODULE_RANGE (8*1024*1024) + +int kstack_depth_to_print = 24; + +static void printbinary(unsigned long x, int nbits) +{ + unsigned long mask = 1UL << (nbits - 1); + while (mask != 0) { + printk(mask & x ? "1" : "0"); + mask >>= 1; + } +} + +void show_regs(struct pt_regs *regs) +{ + int i; +#ifdef __LP64__ +#define RFMT " %016lx" +#else +#define RFMT " %08lx" +#endif + + printk("\n"); /* don't want to have that pretty register dump messed up */ + + printk(" YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\nPSW: "); + printbinary(regs->gr[0], 32); + printk("\n"); + + for (i = 0; i < 32; i += 4) { + int j; + printk("r%d-%d\t", i, i + 3); + for (j = 0; j < 4; j++) { + printk(RFMT, i + j == 0 ? 0 : regs->gr[i + j]); + } + printk("\n"); + } + + for (i = 0; i < 8; i += 4) { + int j; + printk("sr%d-%d\t", i, i + 4); + for (j = 0; j < 4; j++) { + printk(RFMT, regs->sr[i + j]); + } + printk("\n"); + } + +#if REDICULOUSLY_VERBOSE + for (i = 0; i < 32; i++) { + printk("FR%2d : %016lx ", i, regs->fr[i]); + if ((i & 1) == 1) + printk("\n"); + } +#endif + + printk("\nIASQ:" RFMT RFMT " IAOQ:" RFMT RFMT "\n", + regs->iasq[0], regs->iasq[1], regs->iaoq[0], regs->iaoq[1]); + printk(" IIR: %08lx ISR:" RFMT " IOR:" RFMT "\nORIG_R28:" RFMT + "\n", regs->iir, regs->isr, regs->ior, regs->orig_r28); +} + +void +die_if_kernel (char *str, struct pt_regs *regs, long err) +{ + if (user_mode(regs)) { +#if 1 + if (err == 0) + return; /* STFU */ + + /* XXX for debugging only */ + printk ("!!die_if_kernel: %s(%d): %s %ld\n", + current->comm, current->pid, str, err); + show_regs(regs); +#endif + return; + } + + printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err); + + show_regs(regs); + + /* Wot's wrong wif bein' racy? */ + if (current->thread.flags & PARISC_KERNEL_DEATH) { + printk("die_if_kernel recursion detected.\n"); + sti(); + while (1); + } + current->thread.flags |= PARISC_KERNEL_DEATH; + do_exit(SIGSEGV); +} + +asmlinkage void cache_flush_denied(struct pt_regs * regs, long error_code) +{ +} + +asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) +{ +} + +#ifndef CONFIG_MATH_EMULATION + +asmlinkage void math_emulate(long arg) +{ +} + +#endif /* CONFIG_MATH_EMULATION */ + +int syscall_ipi(int (*syscall) (struct pt_regs *), struct pt_regs *regs) +{ + return syscall(regs); +} + +struct { + int retval; + + int (*func) (void *, struct pt_regs *); + void * data; +} ipi_action[NR_CPUS]; + +void ipi_interrupt(int irq, void *unused, struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + + if(!ipi_action[cpu].func) + BUG(); + + ipi_action[cpu].retval = + ipi_action[cpu].func(ipi_action[cpu].data, regs); +} + +/* gdb uses break 4,8 */ +#define GDB_BREAK_INSN 0x10004 +void handle_gdb_break(struct pt_regs *regs, int wot) +{ + struct siginfo si; + + si.si_code = wot; + si.si_addr = (void *) (regs->iaoq[0] & ~3); + si.si_signo = SIGTRAP; + si.si_errno = 0; + force_sig_info(SIGTRAP, &si, current); +} + +void handle_break(unsigned iir, struct pt_regs *regs) +{ + struct siginfo si; +#ifdef CONFIG_KWDB + struct save_state ssp; +#endif /* CONFIG_KWDB */ + + flush_all_caches(); + switch(iir) { + case 0x00: + /* show registers, halt */ + cli(); + printk("break 0,0: pid=%d command='%s'\n", + current->pid, current->comm); + die_if_kernel("Breakpoint", regs, 0); + show_regs(regs); + si.si_code = TRAP_BRKPT; + si.si_addr = (void *) (regs->iaoq[0] & ~3); + si.si_signo = SIGTRAP; + force_sig_info(SIGTRAP, &si, current); + break; + + case GDB_BREAK_INSN: + die_if_kernel("Breakpoint", regs, 0); + handle_gdb_break(regs, TRAP_BRKPT); + break; + +#ifdef CONFIG_KWDB + + case KGDB_BREAK_INSN: + mtctl(0, 15); + pt_regs_to_ssp(regs, &ssp); + kgdb_trap(I_BRK_INST, &ssp, 1); + ssp_to_pt_regs(&ssp, regs); + break; + + case KGDB_INIT_BREAK_INSN: + mtctl(0, 15); + pt_regs_to_ssp(regs, &ssp); + kgdb_trap(I_BRK_INST, &ssp, 1); + ssp_to_pt_regs(&ssp, regs); + + /* Advance pcoq to skip break */ + regs->iaoq[0] = regs->iaoq[1]; + regs->iaoq[1] += 4; + break; + +#endif /* CONFIG_KWDB */ + + default: + set_eiem(0); + printk("break %#08x: pid=%d command='%s'\n", + iir, current->pid, current->comm); + show_regs(regs); + si.si_signo = SIGTRAP; + si.si_code = TRAP_BRKPT; + si.si_addr = (void *) (regs->iaoq[0] & ~3); + force_sig_info(SIGTRAP, &si, current); + return; + } +} + +/* Format of the floating-point exception registers. */ +struct exc_reg { + unsigned int exception : 6; + unsigned int ei : 26; +}; + +/* Macros for grabbing bits of the instruction format from the 'ei' + field above. */ +/* Major opcode 0c and 0e */ +#define FP0CE_UID(i) (((i) >> 6) & 3) +#define FP0CE_CLASS(i) (((i) >> 9) & 3) +#define FP0CE_SUBOP(i) (((i) >> 13) & 7) +#define FP0CE_SUBOP1(i) (((i) >> 15) & 7) /* Class 1 subopcode */ +#define FP0C_FORMAT(i) (((i) >> 11) & 3) +#define FP0E_FORMAT(i) (((i) >> 11) & 1) + +/* Major opcode 0c, uid 2 (performance monitoring) */ +#define FPPM_SUBOP(i) (((i) >> 9) & 0x1f) + +/* Major opcode 2e (fused operations). */ +#define FP2E_SUBOP(i) (((i) >> 5) & 1) +#define FP2E_FORMAT(i) (((i) >> 11) & 1) + +/* Major opcode 26 (FMPYSUB) */ +/* Major opcode 06 (FMPYADD) */ +#define FPx6_FORMAT(i) ((i) & 0x1f) + +/* Flags and enable bits of the status word. */ +#define FPSW_FLAGS(w) ((w) >> 27) +#define FPSW_ENABLE(w) ((w) & 0x1f) +#define FPSW_V (1<<4) +#define FPSW_Z (1<<3) +#define FPSW_O (1<<2) +#define FPSW_U (1<<1) +#define FPSW_I (1<<0) + +/* Emulate a floating point instruction if necessary and possible + (this will be moved elsewhere eventually). Return zero if + successful or if emulation was not required, -1 if the instruction + is actually illegal or unimplemented. The status word passed as + the first parameter will be modified to signal exceptions, if + any. */ + +/* FIXME!!! This is really incomplete and, at the moment, most + illegal FP instructions will simply act as no-ops. Obviously that + is *not* what we want. Also we don't even try to handle exception + types other than the 'unimplemented' ones. */ +int +fp_emul_insn(u32 *sw, struct exc_reg exc, struct pt_regs *regs) +{ + switch (exc.exception) { + case 0x3: /* Unimplemented, opcode 06 */ + break; + case 0x9: /* Unimplemented, opcode 0c */ + /* We do not support quadword operations, end of + story. There's no support for them in GCC. */ + if (FP0C_FORMAT(exc.ei) == 3) + return -1; /* SIGILL */ + /* Fall through. */ + case 0xa: /* Unimplemented, opcode 0e */ + if (FP0CE_CLASS(exc.ei) == 1) { + /* FCNV instructions of various sorts. */ + } else { + if (FP0CE_CLASS(exc.ei == 0) + && FP0CE_SUBOP(exc.ei == 5)) { + /* FRND instructions should be + emulated, at some point, I + guess. */ + return -1; /* SIGILL */ + } + } + break; + case 0x23: /* Unimplemented, opcode 26 */ + break; + case 0x2b: /* Unimplemented, opcode 2e */ + break; + case 0x1: /* Unimplemented, opcode 0e/0c */ + /* FIXME: How the hell are we supposed to tell which + opcode it is? */ + break; + default: + return -1; /* Punt */ + } + + return 0; +} + +/* Handle a floating point exception. Return zero if the faulting + instruction can be completed successfully. */ +int +handle_fpe(struct pt_regs *regs) +{ + struct siginfo si; + union { + struct fpsw { + /* flag bits */ + unsigned int fv : 1; + unsigned int fz : 1; + unsigned int fo : 1; + unsigned int fu : 1; + unsigned int fi : 1; + + unsigned int c : 1; + unsigned int pad1 : 4; + unsigned int cq : 11; + unsigned int rm : 2; + unsigned int pad2 : 2; + unsigned int t : 1; + unsigned int d : 1; + + /* enable bits */ + unsigned int ev : 1; + unsigned int ez : 1; + unsigned int eo : 1; + unsigned int eu : 1; + unsigned int ei : 1; + } status; + u32 word; + } sw; + struct exc_reg excepts[7]; + unsigned int code = 0; + unsigned int throw; + + /* Status word = FR0L. */ + memcpy(&sw, regs->fr, sizeof(sw)); + /* Exception words = FR0R-FR3R. */ + memcpy(excepts, ((char *) regs->fr) + 4, sizeof(excepts)); + + /* This is all CPU dependent. Since there is no public + documentation on the PA2.0 processors we will just assume + everything is like the 7100/7100LC/7300LC for now. + + Specifically: All exceptions are marked as "unimplemented" + in the exception word, and the only exception word used is + excepts[1]. */ + + /* Try to emulate the instruction. Also determine if it is + really an illegal instruction in the process. + + FIXME: fp_emul_insn() only checks for the "unimplemented" + exceptions at the moment. So this may break horribly on + PA2.0, where we may want to also check to see if we should + just send SIGFPE (or maybe not, let's see the documentation + first...) */ + if (fp_emul_insn(&sw.word, excepts[1], regs) == -1) + goto send_sigill; + + /* Take the intersection of the flag bits in the FPSW and the + enable bits in the FPSW. */ + throw = FPSW_FLAGS(sw.word) & FPSW_ENABLE(sw.word); + + /* Concoct an appropriate si_code. Of course we don't know + what to do if multiple exceptions were enabled and multiple + flags were set. Maybe that's why HP/UX doesn't implement + feenableexcept(). */ + + if (throw == 0) + goto success; /* Duh. */ + else if (throw & FPSW_V) + code = FPE_FLTINV; + else if (throw & FPSW_Z) + code = FPE_FLTDIV; + else if (throw & FPSW_O) + code = FPE_FLTOVF; + else if (throw & FPSW_U) + code = FPE_FLTUND; + else if (throw & FPSW_I) + code = FPE_FLTRES; + +#if 1 /* Debugging... */ + printk("Unemulated floating point exception, pid=%d (%s)\n", + current->pid, current->comm); + show_regs(regs); + { + int i; + printk("FP Status: %08x\n", sw.word); + printk("FP Exceptions:\n"); + for (i = 0; i < 7; i++) { + printk("\tExcept%d: exception %03x insn %06x\n", + i, excepts[i].exception, excepts[i].ei); + } + } +#endif + + /* FIXME: Should we clear the flag bits, T bit, and exception + registers here? */ + + si.si_signo = SIGFPE; + si.si_errno = 0; + si.si_code = code; + si.si_addr = (void *) regs->iaoq[0]; + force_sig_info(SIGFPE, &si, current); + return -1; + + send_sigill: + si.si_signo = SIGILL; + si.si_errno = 0; + si.si_code = ILL_COPROC; + si.si_addr = (void *) regs->iaoq[0]; + force_sig_info(SIGILL, &si, current); + return -1; + + success: + /* We absolutely have to clear the T bit and exception + registers to allow the process to recover. Otherwise every + subsequent floating point instruction will trap. */ + sw.status.t = 0; + memset(excepts, 0, sizeof(excepts)); + + memcpy(regs->fr, &sw, sizeof(sw)); + memcpy(((char *) regs->fr) + 4,excepts , sizeof(excepts)); + return 0; +} + +int handle_toc(void) +{ + return 0; +} + +void default_trap(int code, struct pt_regs *regs) +{ + printk("Trap %d on CPU %d\n", code, smp_processor_id()); + + show_regs(regs); +} + +void (*cpu_lpmc) (int code, struct pt_regs *regs) = default_trap; + + +#ifdef CONFIG_KWDB +int +debug_call (void) { + printk ("Debug call.\n"); + return 0; +} + +int +debug_call_leaf (void) { + return 0; +} +#endif /* CONFIG_KWDB */ + +extern void do_page_fault(struct pt_regs *, int, unsigned long); +extern void parisc_terminate(char *, struct pt_regs *, int, unsigned long); +extern void transfer_pim_to_trap_frame(struct pt_regs *); +extern void pdc_console_restart(void); + +void handle_interruption(int code, struct pt_regs *regs) +{ + unsigned long fault_address = 0; + unsigned long fault_space = 0; + struct siginfo si; +#ifdef CONFIG_KWDB + struct save_state ssp; +#endif /* CONFIG_KWDB */ + + if (code == 1) + pdc_console_restart(); /* switch back to pdc if HPMC */ + else + sti(); + +#ifdef __LP64__ + + /* + * FIXME: + * For 32 bit processes we don't want the b bits (bits 0 & 1) + * in the ior. This is more appropriately handled in the tlb + * miss handlers. Changes need to be made to support addresses + * >32 bits for 64 bit processes. + */ + + regs->ior &= 0x3FFFFFFFFFFFFFFFUL; +#endif + +#if 0 + printk("interrupted with code %d, regs %p\n", code, regs); + show_regs(regs); +#endif + + switch(code) { + case 1: + parisc_terminate("High Priority Machine Check (HPMC)",regs,code,0); + /* NOT REACHED */ + case 3: /* Recovery counter trap */ + regs->gr[0] &= ~PSW_R; + if (regs->iasq[0]) + handle_gdb_break(regs, TRAP_TRACE); + /* else this must be the start of a syscall - just let it + * run. + */ + return; + + case 5: + flush_all_caches(); + cpu_lpmc(5, regs); + return; + + case 6: + fault_address = regs->iaoq[0]; + fault_space = regs->iasq[0]; + break; + + case 9: /* Break Instruction */ + handle_break(regs->iir,regs); + return; + + case 14: + /* Assist Exception Trap, i.e. floating point exception. */ + die_if_kernel("Floating point exception", regs, 0); /* quiet */ + handle_fpe(regs); + return; + case 15: + case 16: /* Non-Access TLB miss faulting address is in IOR */ + case 17: + case 26: + fault_address = regs->ior; + fault_space = regs->isr; + + if (code == 26 && fault_space == 0) + parisc_terminate("Data access rights fault in kernel",regs,code,fault_address); + break; + + case 19: + regs->gr[0] |= PSW_X; /* So we can single-step over the trap */ + /* fall thru */ + case 21: + handle_gdb_break(regs, TRAP_HWBKPT); + return; + + case 25: /* Taken branch trap */ + regs->gr[0] &= ~PSW_T; + if (regs->iasq[0]) + handle_gdb_break(regs, TRAP_BRANCH); + /* else this must be the start of a syscall - just let it + * run. + */ + return; + +#if 0 /* def CONFIG_KWDB */ + case I_TAKEN_BR: /* 25 */ + mtctl(0, 15); + pt_regs_to_ssp(regs, &ssp); + kgdb_trap(I_TAKEN_BR, &ssp, 1); + ssp_to_pt_regs(&ssp, regs); + break; +#endif /* CONFIG_KWDB */ + + case 8: + die_if_kernel("Illegal instruction", regs, code); + si.si_code = ILL_ILLOPC; + goto give_sigill; + + case 10: + die_if_kernel("Priviledged operation - shouldn't happen!", regs, code); + si.si_code = ILL_PRVOPC; + goto give_sigill; + case 11: + die_if_kernel("Priviledged register - shouldn't happen!", regs, code); + si.si_code = ILL_PRVREG; + give_sigill: + si.si_signo = SIGILL; + si.si_errno = 0; + si.si_addr = (void *) regs->iaoq[0]; + force_sig_info(SIGILL, &si, current); + return; + + case 28: /* Unaligned just causes SIGBUS for now */ + die_if_kernel("Unaligned data reference", regs, code); + si.si_code = BUS_ADRALN; + si.si_signo = SIGBUS; + si.si_errno = 0; + si.si_addr = (void *) regs->ior; + force_sig_info(SIGBUS, &si, current); + return; + + default: + if (user_mode(regs)) { + printk("\nhandle_interruption() pid=%d command='%s'\n", + current->pid, current->comm); + show_regs(regs); + /* SIGBUS, for lack of a better one. */ + si.si_signo = SIGBUS; + si.si_code = BUS_OBJERR; + si.si_errno = 0; + si.si_addr = (void *) regs->ior; + force_sig_info(SIGBUS, &si, current); + return; + } + parisc_terminate("Unexpected Interruption!",regs,code,0); + /* NOT REACHED */ + } + + if (user_mode(regs)) { + if (fault_space != regs->sr[7]) { + if (fault_space == 0) + printk("User Fault on Kernel Space "); + else /* this case should never happen, but whatever... */ + printk("User Fault (long pointer) "); + printk("pid=%d command='%s'\n", current->pid, current->comm); + show_regs(regs); + si.si_signo = SIGSEGV; + si.si_errno = 0; + si.si_code = SEGV_MAPERR; + si.si_addr = (void *) regs->ior; + force_sig_info(SIGSEGV, &si, current); + return; + } + } + else { + + /* + * The kernel should never fault on its own address space. + */ + + if (fault_space == 0) + parisc_terminate("Kernel Fault",regs,code,fault_address); + } + +#ifdef CONFIG_KWDB + debug_call_leaf (); +#endif /* CONFIG_KWDB */ + + do_page_fault(regs, code, fault_address); + + /* + * This should not be necessary. + * However, we do not currently + * implement flush_page_to_ram. + * + * The problem is that if we just + * brought in some code through the + * D-cache, the I-cache may not see + * it since it hasn't been flushed + * to ram. + */ + +/* flush_all_caches(); */ + +#if 0 + printk("returning %p\n", regs); +/* show_regs(regs); */ +#endif + + return; + +} + +void show_stack(unsigned long sp) +{ +#if 1 + if ((sp & 0xc0000000UL) == 0xc0000000UL) { + + __u32 *stackptr; + __u32 *dumpptr; + + /* Stack Dump! */ + + stackptr = (__u32 *)sp; + dumpptr = (__u32 *)(sp & ~(INIT_TASK_SIZE - 1)); + printk("\nDumping Stack from %p to %p:\n",dumpptr,stackptr); + while (dumpptr < stackptr) { + printk("%04x %08x %08x %08x %08x %08x %08x %08x %08x\n", + ((__u32)dumpptr) & 0xffff, + dumpptr[0], dumpptr[1], dumpptr[2], dumpptr[3], + dumpptr[4], dumpptr[5], dumpptr[6], dumpptr[7]); + dumpptr += 8; + } + } +#endif +} + + +void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long offset) +{ + set_eiem(0); + cli(); + + if (code == 1) + transfer_pim_to_trap_frame(regs); + +#if 1 + show_stack(regs->gr[30]); +#endif + + printk("\n%s: Code=%d regs=%p (Addr=%08lx)\n",msg,code,regs,offset); + show_regs(regs); + + for(;;) + ; +} + +void transfer_pim_to_trap_frame(struct pt_regs *regs) +{ + register int i; + extern unsigned int hpmc_pim_data[]; + struct pdc_hpmc_pim_11 *pim_narrow; + struct pdc_hpmc_pim_20 *pim_wide; + + if (boot_cpu_data.cpu_type >= pcxu) { + + pim_wide = (struct pdc_hpmc_pim_20 *)hpmc_pim_data; + + /* + * Note: The following code will probably generate a + * bunch of truncation error warnings from the compiler. + * Could be handled with an ifdef, but perhaps there + * is a better way. + */ + + regs->gr[0] = pim_wide->cr[22]; + + for (i = 1; i < 32; i++) + regs->gr[i] = pim_wide->gr[i]; + + for (i = 0; i < 32; i++) + regs->fr[i] = pim_wide->fr[i]; + + for (i = 0; i < 8; i++) + regs->sr[i] = pim_wide->sr[i]; + + regs->iasq[0] = pim_wide->cr[17]; + regs->iasq[1] = pim_wide->iasq_back; + regs->iaoq[0] = pim_wide->cr[18]; + regs->iaoq[1] = pim_wide->iaoq_back; + + regs->cr30 = pim_wide->cr[30]; + regs->sar = pim_wide->cr[11]; + regs->iir = pim_wide->cr[19]; + regs->isr = pim_wide->cr[20]; + regs->ior = pim_wide->cr[21]; + } + else { + pim_narrow = (struct pdc_hpmc_pim_11 *)hpmc_pim_data; + + regs->gr[0] = pim_narrow->cr[22]; + + for (i = 1; i < 32; i++) + regs->gr[i] = pim_narrow->gr[i]; + + for (i = 0; i < 32; i++) + regs->fr[i] = pim_narrow->fr[i]; + + for (i = 0; i < 8; i++) + regs->sr[i] = pim_narrow->sr[i]; + + regs->iasq[0] = pim_narrow->cr[17]; + regs->iasq[1] = pim_narrow->iasq_back; + regs->iaoq[0] = pim_narrow->cr[18]; + regs->iaoq[1] = pim_narrow->iaoq_back; + + regs->cr30 = pim_narrow->cr[30]; + regs->sar = pim_narrow->cr[11]; + regs->iir = pim_narrow->cr[19]; + regs->isr = pim_narrow->cr[20]; + regs->ior = pim_narrow->cr[21]; + } + + /* + * The following fields only have meaning if we came through + * another path. So just zero them here. + */ + + regs->ksp = 0; + regs->kpc = 0; + regs->orig_r28 = 0; +} + +int __init check_ivt(void *iva) +{ + int i; + u32 check = 0; + u32 *ivap; + u32 *hpmcp; + u32 length; + extern void os_hpmc(void); + extern void os_hpmc_end(void); + + if(strcmp((char *)iva, "cows can fly")) + return -1; + + ivap = (u32 *)iva; + + for (i = 0; i < 8; i++) + *ivap++ = 0; + + /* Compute Checksum for HPMC handler */ + + length = (u32)((unsigned long)os_hpmc_end - (unsigned long)os_hpmc); + ivap[7] = length; + + hpmcp = (u32 *)os_hpmc; + + for(i=0; i<length/4; i++) + check += *hpmcp++; + + for(i=0; i<8; i++) + check += ivap[i]; + + ivap[5] = -check; + + return 0; +} + +#ifndef __LP64__ +extern const void fault_vector_11; +#endif +extern const void fault_vector_20; + +void __init trap_init(void) +{ + volatile long eiem; + void *iva; + + printk("trap_init\n"); + + if (boot_cpu_data.cpu_type >= pcxu) + iva = (void *) &fault_vector_20; + else +#ifdef __LP64__ + panic("Can't boot 64-bit OS on PA1.1 processor!"); +#else + iva = (void *) &fault_vector_11; +#endif + + if(check_ivt(iva)) + panic("IVT invalid"); + + mtctl(0, 30); + mtctl(90000000, 16); + set_eiem(-1L); + mtctl(-1L, 23); + asm volatile ("rsm 0,%0" : "=r" (eiem)); +} diff --git a/arch/parisc/lib/Makefile b/arch/parisc/lib/Makefile new file mode 100644 index 000000000..9f0670667 --- /dev/null +++ b/arch/parisc/lib/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for parisc-specific library files.. +# + + +L_TARGET = lib.a +L_OBJS = lusercopy.o bitops.o checksum.o + + +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o + +include $(TOPDIR)/Rules.make diff --git a/arch/parisc/lib/bitops.c b/arch/parisc/lib/bitops.c new file mode 100644 index 000000000..c275c4246 --- /dev/null +++ b/arch/parisc/lib/bitops.c @@ -0,0 +1,60 @@ +/* atomic.c: atomic operations which got too long to be inlined all over + * the place. + * + * Copyright 1999 Philipp Rumpf (prumpf@tux.org */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <asm/system.h> +#include <asm/atomic.h> + +#ifdef CONFIG_SMP +spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] = { + [0 ... (ATOMIC_HASH_SIZE-1)] = SPIN_LOCK_UNLOCKED +}; +#endif + +spinlock_t __atomic_lock = SPIN_LOCK_UNLOCKED; + +#ifndef __LP64__ +unsigned long __xchg(unsigned long x, unsigned long *ptr, int size) +{ + unsigned long temp, flags; + + if (size != sizeof x) { + printk("__xchg called with bad pointer\n"); + } + spin_lock_irqsave(&__atomic_lock, flags); + temp = *ptr; + *ptr = x; + spin_unlock_irqrestore(&__atomic_lock, flags); + return temp; +} +#else +unsigned long __xchg(unsigned long x, unsigned long *ptr, int size) +{ + unsigned long temp, flags; + unsigned int *ptr32; + + if (size == 8) { +try_long: + spin_lock_irqsave(&__atomic_lock, flags); + temp = *ptr; + *ptr = x; + spin_unlock_irqrestore(&__atomic_lock, flags); + return temp; + } + if (size == 4) { + ptr32 = (unsigned int *)ptr; + spin_lock_irqsave(&__atomic_lock, flags); + temp = (unsigned long)*ptr32; + *ptr32 = (unsigned int)x; + spin_unlock_irqrestore(&__atomic_lock, flags); + return temp; + } + + printk("__xchg called with bad pointer\n"); + goto try_long; +} +#endif diff --git a/arch/parisc/lib/checksum.c b/arch/parisc/lib/checksum.c new file mode 100644 index 000000000..fa02027dd --- /dev/null +++ b/arch/parisc/lib/checksum.c @@ -0,0 +1,130 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * MIPS specific IP/TCP/UDP checksumming routines + * + * Authors: Ralf Baechle, <ralf@waldorf-gmbh.de> + * Lots of code moved from tcp.c and ip.c; see those files + * for more names. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * $Id: checksum.c,v 1.3 1997/12/01 17:57:34 ralf Exp $ + */ +#include <net/checksum.h> +#include <linux/types.h> +#include <asm/byteorder.h> +#include <asm/string.h> +#include <asm/uaccess.h> + +static inline unsigned short from32to16(unsigned int x) +{ + /* 32 bits --> 16 bits + carry */ + x = (x & 0xffff) + (x >> 16); + /* 16 bits + carry --> 16 bits including carry */ + x = (x & 0xffff) + (x >> 16); + return (unsigned short)x; +} + +static inline unsigned int do_csum(const unsigned char * buff, int len) +{ + int odd, count; + unsigned int result = 0; + + if (len <= 0) + goto out; + odd = 1 & (unsigned long) buff; + if (odd) { + result = be16_to_cpu(*buff); + len--; + buff++; + } + count = len >> 1; /* nr of 16-bit words.. */ + if (count) { + if (2 & (unsigned long) buff) { + result += *(unsigned short *) buff; + count--; + len -= 2; + buff += 2; + } + count >>= 1; /* nr of 32-bit words.. */ + if (count) { + unsigned int carry = 0; + do { + unsigned int w = *(unsigned int *) buff; + count--; + buff += 4; + result += carry; + result += w; + carry = (w > result); + } while (count); + result += carry; + result = (result & 0xffff) + (result >> 16); + } + if (len & 2) { + result += *(unsigned short *) buff; + buff += 2; + } + } + if (len & 1) + result += le16_to_cpu(*buff); + result = from32to16(result); + if (odd) + result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); +out: + return result; +} + +/* + * computes a partial checksum, e.g. for TCP/UDP fragments + */ +unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum) +{ + unsigned int result = do_csum(buff, len); + + /* add in old sum, and carry.. */ + result += sum; + if(sum > result) + result += 1; + return result; +} + +/* + * copy while checksumming, otherwise like csum_partial + */ +unsigned int csum_partial_copy(const char *src, char *dst, + int len, unsigned int sum) +{ + /* + * It's 2:30 am and I don't feel like doing it real ... + * This is lots slower than the real thing (tm) + */ + sum = csum_partial(src, len, sum); + memcpy(dst, src, len); + + return sum; +} + +/* + * Copy from userspace and compute checksum. If we catch an exception + * then zero the rest of the buffer. + */ +unsigned int csum_partial_copy_from_user (const char *src, char *dst, + int len, unsigned int sum, + int *err_ptr) +{ + int missing; + + missing = copy_from_user(dst, src, len); + if (missing) { + memset(dst + len - missing, 0, missing); + *err_ptr = -EFAULT; + } + + return csum_partial(dst, len, sum); +} diff --git a/arch/parisc/lib/lusercopy.S b/arch/parisc/lib/lusercopy.S new file mode 100644 index 000000000..b4b88b53c --- /dev/null +++ b/arch/parisc/lib/lusercopy.S @@ -0,0 +1,242 @@ +/*------------------------------------------------------------------------------ + * Native PARISC/Linux Project (http://www.puffingroup.com/parisc) + * + * Assembly Language User Access Routines + * Copyright (C) 2000 Hewlett-Packard (John Marvin) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * These routines still have plenty of room for optimization + * (word & doubleword load/store, dual issue, store hints, etc.). + */ + +/* + * The following routines assume that space register 3 (sr3) contains + * the space id associated with the current users address space. + */ + + + .level 1.1 + .text + +#include <asm/assembly.h> +#include <asm/errno.h> + + /* + * get_sr gets the appropriate space value into + * sr1 for kernel/user space access, depending + * on the flag stored in the task structure. + */ + + /* FIXME! depi below has hardcoded idea of kernel stack size */ + + .macro get_sr + copy %r30,%r1 ;! Get task structure + depi 0,31,14,%r1 ;! into r1 + ldw TASK_SEGMENT(%r1),%r22 + mfsp %sr3,%r1 + or,<> %r22,%r0,%r0 + copy %r0,%r1 + mtsp %r1,%sr1 + .endm + + /* + * unsigned long + * lcopy_to_user(void *to, const void *from, unsigned long n) + * + * Returns 0 for success. + * otherwise, returns number of bytes not transferred. + */ + + .export lcopy_to_user,code +lcopy_to_user: + .proc + .callinfo NO_CALLS + .entry + comib,=,n 0,%r24,$lctu_done + get_sr +$lctu_loop: + ldbs,ma 1(%r25),%r1 + addib,<> -1,%r24,$lctu_loop +1: stbs,ma %r1,1(%sr1,%r26) +$lctu_done: + bv %r0(%r2) + copy %r24,%r28 + .exit + +2: b $lctu_done + ldo 1(%r24),%r24 + + .section __ex_table,"a" + .word 1b,(2b-1b) + .previous + + .procend + + /* + * unsigned long + * lcopy_from_user(void *to, const void *from, unsigned long n) + * + * Returns 0 for success. + * otherwise, returns number of bytes not transferred. + * + * NOTE: This routine will also zero any bytes in the + * destination that were not copied due to a fault. + * + */ + + .export lcopy_from_user,code +lcopy_from_user: + .proc + .callinfo NO_CALLS + .entry + comib,=,n 0,%r24,$lcfu_done + get_sr +$lcfu_loop: +1: ldbs,ma 1(%sr1,%r25),%r1 + addib,<> -1,%r24,$lcfu_loop + stbs,ma %r1,1(%r26) +$lcfu_done: + bv %r0(%r2) + copy %r24,%r28 + .exit + +2: copy %r24,%r23 +$lcfu_zero_loop: + addib,<> -1,%r23,$lcfu_zero_loop + stbs,ma %r0,1(%r26) + b $lcfu_done + nop + + .section __ex_table,"a" + .word 1b,(2b-1b) + .previous + + .procend + + /* + * long lstrncpy_from_user(char *dst, const char *src, long n) + * + * Returns -EFAULT if exception before terminator, + * N if the entire buffer filled, + * otherwise strlen + 1 (i.e. includes zero byte) + */ + + .export lstrncpy_from_user,code +lstrncpy_from_user: + .proc + .callinfo NO_CALLS + .entry + comib,= 0,%r24,$lsfu_done + copy %r26,%r23 + get_sr +1: ldbs,ma 1(%sr1,%r25),%r1 +$lsfu_loop: + stbs,ma %r1,1(%r26) + comib,=,n 0,%r1,$lsfu_done + addib,<>,n -1,%r24,$lsfu_loop +2: ldbs,ma 1(%sr1,%r25),%r1 +$lsfu_done: + sub %r26,%r23,%r28 +$lsfu_exit: + bv %r0(%r2) + nop + .exit + +3: b $lsfu_exit + ldi -EFAULT,%r28 + + .section __ex_table,"a" + .word 1b,(3b-1b) + .word 2b,(2b-1b) + .previous + + .procend + + /* + * unsigned long lclear_user(void *to, unsigned long n) + * + * Returns 0 for success. + * otherwise, returns number of bytes not transferred. + */ + + .export lclear_user,code +lclear_user: + .proc + .callinfo NO_CALLS + .entry + comib,=,n 0,%r25,$lclu_done + get_sr +$lclu_loop: + addib,<> -1,%r25,$lclu_loop +1: stbs,ma %r0,1(%sr1,%r26) + +$lclu_done: + bv %r0(%r2) + copy %r25,%r28 + .exit + +2: b $lclu_done + ldo 1(%r25),%r25 + + .section __ex_table,"a" + .word 1b,(2b-1b) + .previous + + .procend + + /* + * long lstrnlen_user(char *s, long n) + * + * Returns 0 if exception before zero byte or reaching N, + * N+1 if N would be exceeded, + * else strlen + 1 (i.e. includes zero byte). + */ + + .export lstrnlen_user,code +lstrnlen_user: + .proc + .callinfo NO_CALLS + .entry + comib,= 0,%r25,$lslen_nzero + copy %r26,%r24 + get_sr +1: ldbs,ma 1(%sr1,%r26),%r1 +$lslen_loop: + comib,=,n 0,%r1,$lslen_done + addib,<> -1,%r25,$lslen_loop +2: ldbs,ma 1(%sr1,%r26),%r1 +$lslen_done: + bv %r0(%r2) + sub %r26,%r24,%r28 + .exit + +$lslen_nzero: + b $lslen_done + ldo 1(%r26),%r26 /* special case for N == 0 */ + +3: b $lslen_done + copy %r24,%r26 /* reset r26 so 0 is returned on fault */ + + .section __ex_table,"a" + .word 1b,(3b-1b) + .word 2b,(2b-1b) + .previous + + .procend + + .end diff --git a/arch/parisc/mm/Makefile b/arch/parisc/mm/Makefile new file mode 100644 index 000000000..819872a7f --- /dev/null +++ b/arch/parisc/mm/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for the linux parisc-specific parts of the memory manager. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +O_TARGET := mm.o +O_OBJS := init.o fault.o kmap.o extable.o + +include $(TOPDIR)/Rules.make diff --git a/arch/parisc/mm/extable.c b/arch/parisc/mm/extable.c new file mode 100644 index 000000000..705688934 --- /dev/null +++ b/arch/parisc/mm/extable.c @@ -0,0 +1,69 @@ +/* + * Kernel exception handling table support. Derived from arch/i386/mm/extable.c. + * + * Copyright (C) 2000 Hewlett-Packard Co + * Copyright (C) 2000 John Marvin (jsm@fc.hp.com) + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/mm.h> +#include <linux/ptrace.h> +#include <asm/uaccess.h> + + +extern const struct exception_table_entry __start___ex_table[]; +extern const struct exception_table_entry __stop___ex_table[]; + +static inline const struct exception_table_entry * +search_one_table (const struct exception_table_entry *first, + const struct exception_table_entry *last, + unsigned long addr) +{ + /* Abort early if the search value is out of range. */ + + if ((addr < first->addr) || (addr > last->addr)) + return 0; + + while (first <= last) { + const struct exception_table_entry *mid; + long diff; + + mid = first + ((last - first)/2); + diff = mid->addr - addr; + + if (diff == 0) + return mid; + else if (diff < 0) + first = mid+1; + else + last = mid-1; + } + + return 0; +} + +const struct exception_table_entry * +search_exception_table (unsigned long addr) +{ +#ifndef CONFIG_MODULE + /* There is only the kernel to search. */ + return search_one_table(__start___ex_table, + __stop___ex_table - 1, + addr); +#else + struct exception_table_entry *ret; + /* 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); + if (ret) + return ret; + } + return 0; +#endif +} diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c new file mode 100644 index 000000000..68d4614ec --- /dev/null +++ b/arch/parisc/mm/fault.c @@ -0,0 +1,283 @@ +/* $Id: fault.c,v 1.5 2000/01/26 16:20:29 jsm Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * + * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle + * Copyright 1999 SuSE GmbH (Philipp Rumpf, prumpf@tux.org) + * Copyright 1999 Hewlett Packard Co. + * + */ + +#include <linux/mm.h> +#include <linux/ptrace.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include <asm/uaccess.h> + + +/* Defines for parisc_acctyp() */ +#define READ 0 +#define WRITE 1 + +/* Various important other fields */ +#define bit22set(x) (x & 0x00000200) +#define bits23_25set(x) (x & 0x000001c0) +#define isGraphicsFlushRead(x) ((x & 0xfc003fdf) == 0x04001a80) + /* extended opcode is 0x6a */ + +#define BITSSET 0x1c0 /* for identifying LDCW */ + +/* + * parisc_acctyp(unsigned int inst) -- + * Given a PA-RISC memory access instruction, determine if the + * the instruction would perform a memory read or memory write + * operation. + * + * This function assumes that the given instruction is a memory access + * instruction (i.e. you should really only call it if you know that + * the instruction has generated some sort of a memory access fault). + * + * Returns: + * VM_READ if read operation + * VM_WRITE if write operation + * VM_EXEC if execute operation + */ +static unsigned long +parisc_acctyp(unsigned long code, unsigned int inst) +{ + if (code == 6 || code == 16) + return VM_EXEC; + + switch (inst & 0xf0000000) { + case 0x40000000: /* load */ + case 0x50000000: /* new load */ + return VM_READ; + + case 0x60000000: /* store */ + case 0x70000000: /* new store */ + return VM_WRITE; + + case 0x20000000: /* coproc */ + case 0x30000000: /* coproc2 */ + if (bit22set(inst)) + return VM_WRITE; + + case 0x0: /* indexed/memory management */ + if (bit22set(inst)) { + /* + * Check for the 'Graphics Flush Read' instruction. + * It resembles an FDC instruction, except for bits + * 20 and 21. Any combination other than zero will + * utilize the block mover functionality on some + * older PA-RISC platforms. The case where a block + * move is performed from VM to graphics IO space + * should be treated as a READ. + * + * The significance of bits 20,21 in the FDC + * instruction is: + * + * 00 Flush data cache (normal instruction behavior) + * 01 Graphics flush write (IO space -> VM) + * 10 Graphics flush read (VM -> IO space) + * 11 Graphics flush read/write (VM <-> IO space) + */ + if (isGraphicsFlushRead(inst)) + return VM_READ; + return VM_WRITE; + } else { + /* + * Check for LDCWX and LDCWS (semaphore instructions). + * If bits 23 through 25 are all 1's it is one of + * the above two instructions and is a write. + * + * Note: With the limited bits we are looking at, + * this will also catch PROBEW and PROBEWI. However, + * these should never get in here because they don't + * generate exceptions of the type: + * Data TLB miss fault/data page fault + * Data memory protection trap + */ + if (bits23_25set(inst) == BITSSET) + return VM_WRITE; + } + return VM_READ; /* Default */ + } + return VM_READ; /* Default */ +} + +#undef bit22set +#undef bits23_25set +#undef isGraphicsFlushRead +#undef BITSSET + +/* This is similar to expand_stack(), except that it is for stacks + * that grow upwards. + */ + +static inline int expand_stackup(struct vm_area_struct * vma, unsigned long address) +{ + unsigned long grow; + + address += 4 + PAGE_SIZE - 1; + address &= PAGE_MASK; + grow = (address - vma->vm_end) >> PAGE_SHIFT; + if (address - vma->vm_start > current->rlim[RLIMIT_STACK].rlim_cur || + ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) + return -ENOMEM; + vma->vm_end = address; + vma->vm_mm->total_vm += grow; + if (vma->vm_flags & VM_LOCKED) + vma->vm_mm->locked_vm += grow; + return 0; +} + + +/* This is similar to find_vma(), except that it understands that stacks + * grow up rather than down. + * XXX Optimise by making use of cache and avl tree as per find_vma(). + */ + +struct vm_area_struct * pa_find_vma(struct mm_struct * mm, unsigned long addr) +{ + struct vm_area_struct *vma = NULL; + + if (mm) { + vma = mm->mmap; + if (!vma || addr < vma->vm_start) + return NULL; + while (vma->vm_next && addr >= vma->vm_next->vm_start) + vma = vma->vm_next; + } + return vma; +} + + +/* + * This routine handles page faults. It determines the address, + * and the problem, and then passes it off to one of the appropriate + * routines. + */ +extern void parisc_terminate(char *, struct pt_regs *, int, unsigned long); + +void do_page_fault(struct pt_regs *regs, unsigned long code, + unsigned long address) +{ + struct vm_area_struct * vma; + struct task_struct *tsk = current; + struct mm_struct *mm = tsk->mm; + const struct exception_table_entry *fix; + unsigned long acc_type; + + if (in_interrupt() || !mm) + goto no_context; + + down(&mm->mmap_sem); + vma = pa_find_vma(mm, address); + if (!vma) + goto bad_area; + if (address < vma->vm_end) + goto good_area; + if (!(vma->vm_flags & VM_GROWSUP) || expand_stackup(vma, address)) + goto bad_area; +/* + * Ok, we have a good vm_area for this memory access. We still need to + * check the access permissions. + */ + +good_area: + + acc_type = parisc_acctyp(code,regs->iir); + + if ((vma->vm_flags & acc_type) != acc_type) + goto bad_area; + + /* + * If for any reason at all we couldn't handle the fault, make + * sure we exit gracefully rather than endlessly redo the + * fault. + */ + + switch (handle_mm_fault(mm, vma, address, (acc_type & VM_WRITE) != 0)) { + case 1: + ++current->min_flt; + break; + case 2: + ++current->maj_flt; + break; + case 0: + /* + * We ran out of memory, or some other thing happened + * to us that made us unable to handle the page fault + * gracefully. + */ + goto bad_area; + default: + goto out_of_memory; + } + up(&mm->mmap_sem); + return; + +/* + * Something tried to access memory that isn't in our memory map.. + */ +bad_area: + up(&mm->mmap_sem); + + if (user_mode(regs)) { + struct siginfo si; + + printk("\ndo_page_fault() pid=%d command='%s'\n", + tsk->pid, tsk->comm); + show_regs(regs); + /* FIXME: actually we need to get the signo and code correct */ + si.si_signo = SIGSEGV; + si.si_errno = 0; + si.si_code = SEGV_MAPERR; + si.si_addr = (void *) address; + force_sig_info(SIGSEGV, &si, current); + return; + } + +no_context: + + if (!user_mode(regs)) { + + fix = search_exception_table(regs->iaoq[0]); + + if (fix) { + + if (fix->skip & 1) + regs->gr[8] = -EFAULT; + if (fix->skip & 2) + regs->gr[9] = 0; + + regs->iaoq[0] += ((fix->skip) & ~3); + + /* + * NOTE: In some cases the faulting instruction + * may be in the delay slot of a branch. We + * don't want to take the branch, so we don't + * increment iaoq[1], instead we set it to be + * iaoq[0]+4, and clear the B bit in the PSW + */ + + regs->iaoq[1] = regs->iaoq[0] + 4; + regs->gr[0] &= ~PSW_B; /* IPSW in gr[0] */ + + return; + } + } + + parisc_terminate("Bad Address (null pointer deref?)",regs,code,address); + + out_of_memory: + up(&mm->mmap_sem); + printk("VM: killing process %s\n", current->comm); + if (user_mode(regs)) + do_exit(SIGKILL); + goto no_context; +} diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c new file mode 100644 index 000000000..c3e16c463 --- /dev/null +++ b/arch/parisc/mm/init.c @@ -0,0 +1,479 @@ +/* + * linux/arch/parisc/mm/init.c + * + * Copyright (C) 1995 Linus Torvalds + * Copyright 1999 SuSE GmbH + * changed by Philipp Rumpf + * Copyright 1999 Philipp Rumpf (prumpf@tux.org) + * + */ + +#include <linux/config.h> + +#include <linux/mm.h> +#include <linux/bootmem.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/pci.h> /* for hppa_dma_ops and pcxl_dma_ops */ +#include <linux/swap.h> +#include <linux/unistd.h> + +#include <asm/pgalloc.h> + +static unsigned long totalram_pages; +extern unsigned long max_pfn, mem_max; + +void free_initmem(void) { +} + +/* + * Just an arbitrary offset to serve as a "hole" between mapping areas + * (between top of physical memory and a potential pcxl dma mapping + * area, and below the vmalloc mapping area). + * + * The current 32K value just means that there will be a 32K "hole" + * between mapping areas. That means that any out-of-bounds memory + * accesses will hopefully be caught. The vmalloc() routines leaves + * a hole of 4kB between each vmalloced area for the same reason. + */ + +#define VM_MAP_OFFSET (32*1024) +#define SET_MAP_OFFSET(x) ((void *)(((unsigned long)(x) + VM_MAP_OFFSET) \ + & ~(VM_MAP_OFFSET-1))) + +void *vmalloc_start; +unsigned long pcxl_dma_start; + +void __init mem_init(void) +{ + max_mapnr = num_physpages = max_low_pfn; + high_memory = __va(max_low_pfn * PAGE_SIZE); + + totalram_pages += free_all_bootmem(); + printk("Memory: %luk available\n", totalram_pages << (PAGE_SHIFT-10)); + + if (hppa_dma_ops == &pcxl_dma_ops) { + pcxl_dma_start = (unsigned long)SET_MAP_OFFSET(high_memory); + vmalloc_start = SET_MAP_OFFSET(pcxl_dma_start + PCXL_DMA_MAP_SIZE); + } + else { + pcxl_dma_start = 0; + vmalloc_start = SET_MAP_OFFSET(high_memory); + } +} + +void __bad_pgd(pgd_t *pgd) +{ + printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd)); + pgd_val(*pgd) = _PAGE_TABLE + __pa(BAD_PAGETABLE); +} + +void __bad_pmd(pmd_t *pmd) +{ + printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); + pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE); +} + +pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) +{ + pte_t *pte; + + pte = (pte_t *) __get_free_page(GFP_KERNEL); + + if (pmd_none(*pmd)) { + if (pte) { + clear_page(pte); + pmd_val(*pmd) = _PAGE_TABLE + __pa((unsigned long)pte); + return pte + offset; + } + pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE); + return NULL; + } + + free_page((unsigned long)pte); + + if (pmd_bad(*pmd)) { + __bad_pmd(pmd); + return NULL; + } + + return (pte_t *) pmd_page(*pmd) + offset; +} + +int do_check_pgt_cache(int low, int high) +{ + return 0; +} + +/* + * BAD_PAGE is the page that is used for page faults when linux + * is out-of-memory. Older versions of linux just did a + * do_exit(), but using this instead means there is less risk + * for a process dying in kernel mode, possibly leaving an inode + * unused etc.. + * + * BAD_PAGETABLE is the accompanying page-table: it is initialized + * to point to BAD_PAGE entries. + * + * ZERO_PAGE is a special page that is used for zero-initialized + * data and COW. + */ +pte_t * __bad_pagetable(void) +{ + return (pte_t *) NULL; +} + +unsigned long *empty_zero_page; +unsigned long *empty_bad_page; + +pte_t __bad_page(void) +{ + return *(pte_t *)NULL; +} + +void show_mem(void) +{ + int i,free = 0,total = 0,reserved = 0; + int shared = 0, cached = 0; + + printk("Mem-info:\n"); + show_free_areas(); + printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); + i = max_mapnr; + while (i-- > 0) { + total++; + if (PageReserved(mem_map+i)) + reserved++; + else if (PageSwapCache(mem_map+i)) + cached++; + else if (!atomic_read(&mem_map[i].count)) + free++; + else + shared += atomic_read(&mem_map[i].count) - 1; + } + printk("%d pages of RAM\n",total); + printk("%d reserved pages\n",reserved); + printk("%d pages shared\n",shared); + printk("%d pages swap cached\n",cached); + show_buffers(); +} + +void set_pte_phys (unsigned long vaddr, unsigned long phys) +{ +} + + +/* + * pagetable_init() sets up the page tables + * + * Note that gateway_init() places the Linux gateway page at page 0. + * Since gateway pages cannot be dereferenced this has the desirable + * side effect of trapping those pesky NULL-reference errors in the + * kernel. + */ +static void __init pagetable_init(void) +{ + pgd_t *pg_dir; + pmd_t *pmd; + pte_t *pg_table; + unsigned long tmp1; + unsigned long tmp2; + unsigned long address; + unsigned long ro_start; + unsigned long ro_end; + unsigned long fv_addr; + extern const int stext; + extern int data_start; + extern const unsigned long fault_vector_20; + + ro_start = __pa((unsigned long)&stext); + ro_end = __pa((unsigned long)&data_start); + fv_addr = __pa((unsigned long)&fault_vector_20) & PAGE_MASK; + + printk("pagetable_init\n"); + + /* Map whole memory from PAGE_OFFSET */ + pg_dir = (pgd_t *)swapper_pg_dir + USER_PGD_PTRS; + + address = 0; + while (address < mem_max) { + /* XXX: BTLB should be done here */ + +#if PTRS_PER_PMD == 1 + pmd = (pmd_t *)__pa(pg_dir); +#else + pmd = (pmd_t *) (PAGE_MASK & pgd_val(*pg_dir)); + + /* + * pmd is physical at this point + */ + + if (!pmd) { + pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); + pmd = (pmd_t *) __pa(pmd); + } + + pgd_val(*pg_dir) = _PAGE_TABLE | (unsigned long) pmd; +#endif + pg_dir++; + + /* now change pmd to kernel virtual addresses */ + + pmd = (pmd_t *) __va(pmd); + for (tmp1 = 0 ; tmp1 < PTRS_PER_PMD ; tmp1++,pmd++) { + + /* + * pg_table is physical at this point + */ + + pg_table = (pte_t *) (PAGE_MASK & pmd_val(*pmd)); + if (!pg_table) { + pg_table = (pte_t *) + alloc_bootmem_low_pages(PAGE_SIZE); + pg_table = (pte_t *) __pa(pg_table); + } + + pmd_val(*pmd) = _PAGE_TABLE | + (unsigned long) pg_table; + + /* now change pg_table to kernel virtual addresses */ + + pg_table = (pte_t *) __va(pg_table); + for (tmp2=0; tmp2 < PTRS_PER_PTE; tmp2++,pg_table++) { + pte_t pte; + +#if !defined(CONFIG_KWDB) && !defined(CONFIG_STI_CONSOLE) +#warning STI console should explicitly allocate executable pages but does not +/* KWDB needs to write kernel text when setting break points. +** +** The right thing to do seems like KWDB modify only the pte which +** has a break point on it...otherwise we might mask worse bugs. +*/ + if (address >= ro_start && address < ro_end + && address != fv_addr) + pte = __mk_pte(address, PAGE_KERNEL_RO); + else +#endif + pte = __mk_pte(address, PAGE_KERNEL); + + if (address >= mem_max) + pte_val(pte) = 0; + + set_pte(pg_table, pte); + + address += PAGE_SIZE; + } + + if (address >= mem_max) + break; + } + } + + empty_zero_page = alloc_bootmem_pages(PAGE_SIZE); + memset(empty_zero_page, 0, PAGE_SIZE); +} + +unsigned long gateway_pgd_offset; +unsigned long gateway_pgd_entry; + +static void __init gateway_init(void) +{ + unsigned long hpux_gateway_page_addr; + unsigned long linux_gateway_page_addr; + pgd_t *pg_dir; + pmd_t *pmd_base; + pmd_t *pmd; + pte_t *pg_table_base; + pte_t *pg_table; + /* FIXME: These are 'const' in order to trick the compiler + into not treating them as DP-relative data. */ + extern void * const hpux_gateway_page; + extern void * const linux_gateway_page; + pte_t pte; + + hpux_gateway_page_addr = HPUX_GATEWAY_ADDR & PAGE_MASK; + linux_gateway_page_addr = LINUX_GATEWAY_ADDR & PAGE_MASK; + + gateway_pgd_offset = hpux_gateway_page_addr >> PGDIR_SHIFT; + + /* + * Setup Linux Gateway page. + * + * The Linux gateway page will reside in kernel space (on virtual + * page 0), so it doesn't need to be aliased into user space. + */ + + pg_dir = (pgd_t *)swapper_pg_dir; + +#if PTRS_PER_PMD == 1 + pmd_base = (pmd_t *)pg_dir; + pmd = pmd_base + + ((linux_gateway_page_addr) >> PGDIR_SHIFT); + +#else + pmd_base = (pmd_t *) alloc_bootmem_pages(PAGE_SIZE); + pgd_val(*(pg_dir + (linux_gateway_page_addr >> PGDIR_SHIFT))) = + _PAGE_TABLE | __pa(pmd_base); + + pmd = pmd_base + + ((linux_gateway_page_addr & (PMD_MASK) & (PGDIR_SIZE - 1)) >> + PMD_SHIFT); +#endif + + pg_table_base = (pte_t *) alloc_bootmem_pages(PAGE_SIZE); + + pmd_val(*pmd) = _PAGE_TABLE | __pa(pg_table_base); + + pte = __mk_pte(__pa(&linux_gateway_page), PAGE_GATEWAY); + + pg_table = pg_table_base + + ((linux_gateway_page_addr & (PAGE_MASK) & (PMD_SIZE - 1)) >> + PAGE_SHIFT); + + set_pte(pg_table,pte); + + /* + * Setup HP-UX gateway page. + * This page will be aliased into each user address space. + */ + + pg_table_base = (pte_t *) alloc_bootmem_pages(PAGE_SIZE); + + pte = __mk_pte(__pa(&hpux_gateway_page), PAGE_GATEWAY); + pg_table = pg_table_base + + ((hpux_gateway_page_addr & (PAGE_MASK) & (PMD_SIZE - 1)) >> + PAGE_SHIFT); + + set_pte(pg_table,pte); + + +#if PTRS_PER_PMD == 1 + pmd_base = (pmd_t *)pg_table_base; +#else + pmd_base = (pmd_t *) alloc_bootmem_pages(PAGE_SIZE); + pmd = pmd_base + + ((hpux_gateway_page_addr & (PMD_MASK) & (PGDIR_SIZE - 1)) >> + PMD_SHIFT); + pmd_val(*pmd) = _PAGE_TABLE | __pa(pg_table_base); +#endif + + gateway_pgd_entry = _PAGE_TABLE | __pa(pmd_base); + + /* + * We will be aliasing the HP-UX gateway page into all HP-UX + * user spaces at the same address (not counting the space register + * value) that will be equivalently mapped as long as space register + * hashing is disabled. It will be a problem if anyone touches + * the gateway pages at its "kernel" address, since that is + * NOT equivalently mapped. We'll flush the caches at this + * point, just in case some code has touched those addresses + * previous to this, but all bets are off if they get touched + * after this point. + */ + + flush_all_caches(); + + return; +} + +void __init paging_init(void) +{ + pagetable_init(); + gateway_init(); + + { + unsigned long zones_size[MAX_NR_ZONES] = { max_pfn/2, max_pfn/2, }; + + free_area_init(zones_size); + } +} + +#define NR_SPACE_IDS 8192 + +static unsigned long space_id[NR_SPACE_IDS / (8 * sizeof(long))]; +static unsigned long space_id_index; +static unsigned long free_space_ids = NR_SPACE_IDS; + +/* + * XXX: We should probably unfold the set_bit / test_bit / clear_bit + * locking out of these two functions and have a single spinlock on the + * space_id data structures. + * + * Don't bother. This is all going to be significantly changed in the + * very near future. + */ + +#define SPACEID_SHIFT (PAGE_SHIFT + (PT_NLEVELS)*(PAGE_SHIFT - PT_NLEVELS) - 32) + +unsigned long alloc_sid(void) +{ + unsigned long index; + + if (free_space_ids == 0) + BUG(); + + free_space_ids--; + + do { + index = find_next_zero_bit(space_id, NR_SPACE_IDS, space_id_index); + } while(test_and_set_bit(index, space_id)); + + space_id_index = index; + + return index << SPACEID_SHIFT; +} + +void free_sid(unsigned long spaceid) +{ + unsigned long index = spaceid >> SPACEID_SHIFT; + if (index < 0) + BUG(); + + clear_bit(index, space_id); + + if (space_id_index > index) { + space_id_index = index; + } + free_space_ids++; +} + +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long start, unsigned long end) +{ +#if 0 + for (; start < end; start += PAGE_SIZE) { + ClearPageReserved(mem_map + MAP_NR(start)); + set_page_count(mem_map+MAP_NR(start), 1); + free_page(start); + totalram_pages++; + } + printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); +#endif +} +#endif + +void si_meminfo(struct sysinfo *val) +{ + int i; + + i = max_mapnr; + val->totalram = totalram_pages; + val->sharedram = 0; + val->freeram = nr_free_pages(); + val->bufferram = atomic_read(&buffermem_pages); +#if 0 + while (i-- > 0) { + if (PageReserved(mem_map+i)) + continue; + val->totalram++; + if (!atomic_read(&mem_map[i].count)) + continue; + val->sharedram += atomic_read(&mem_map[i].count) - 1; + } + val->totalram <<= PAGE_SHIFT; + val->sharedram <<= PAGE_SHIFT; +#endif + val->totalhigh = 0; + val->freehigh = 0; + return; +} diff --git a/arch/parisc/mm/kmap.c b/arch/parisc/mm/kmap.c new file mode 100644 index 000000000..686d540d9 --- /dev/null +++ b/arch/parisc/mm/kmap.c @@ -0,0 +1,143 @@ +/* +** Stolen mostly from arch/parisc/kernel/pci-dma.c +*/ + +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/pci.h> + +#include <linux/malloc.h> +#include <linux/vmalloc.h> + +#include <asm/uaccess.h> +#include <asm/pgalloc.h> + +#include <asm/io.h> +#include <asm/page.h> /* get_order */ + +#undef flush_cache_all +#define flush_cache_all flush_all_caches + +typedef void (*pte_iterator_t) (pte_t * pte, unsigned long arg); + +#if 0 +/* XXX This routine could be used with iterate_page() to replace + * unmap_uncached_page() and save a little code space but I didn't + * do that since I'm not certain whether this is the right path. -PB + */ +static void unmap_cached_pte(pte_t * pte, unsigned long arg) +{ + pte_t page = *pte; + pte_clear(pte); + if (!pte_none(page)) { + if (pte_present(page)) { + unsigned long map_nr = pte_pagenr(page); + if (map_nr < max_mapnr) + __free_page(mem_map + map_nr); + } else { + printk(KERN_CRIT + "Whee.. Swapped out page in kernel page table\n"); + } + } +} +#endif + +/* These two routines should probably check a few things... */ +static void set_uncached(pte_t * pte, unsigned long arg) +{ + pte_val(*pte) |= _PAGE_NO_CACHE; +} + +static void set_cached(pte_t * pte, unsigned long arg) +{ + pte_val(*pte) &= ~_PAGE_NO_CACHE; +} + +static inline void iterate_pte(pmd_t * pmd, unsigned long address, + unsigned long size, pte_iterator_t op, + unsigned long arg) +{ + pte_t *pte; + unsigned long end; + + if (pmd_none(*pmd)) + return; + if (pmd_bad(*pmd)) { + pmd_ERROR(*pmd); + pmd_clear(pmd); + return; + } + pte = pte_offset(pmd, address); + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + op(pte, arg); + address += PAGE_SIZE; + pte++; + } while (address < end); +} + +static inline void iterate_pmd(pgd_t * dir, unsigned long address, + unsigned long size, pte_iterator_t op, + unsigned long arg) +{ + pmd_t *pmd; + unsigned long end; + + if (pgd_none(*dir)) + return; + if (pgd_bad(*dir)) { + pgd_ERROR(*dir); + pgd_clear(dir); + return; + } + pmd = pmd_offset(dir, address); + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + do { + iterate_pte(pmd, address, end - address, op, arg); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); +} + +static void iterate_pages(unsigned long address, unsigned long size, + pte_iterator_t op, unsigned long arg) +{ + pgd_t *dir; + unsigned long end = address + size; + + dir = pgd_offset_k(address); + flush_cache_all(); + do { + iterate_pmd(dir, address, end - address, op, arg); + address = (address + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } while (address && (address < end)); + flush_tlb_all(); +} + +void +kernel_set_cachemode(unsigned long vaddr, unsigned long size, int what) +{ + switch (what) { + case IOMAP_FULL_CACHING: + iterate_pages(vaddr, size, set_cached, 0); + flush_tlb_range(&init_mm, vaddr, size); + break; + case IOMAP_NOCACHE_SER: + iterate_pages(vaddr, size, set_uncached, 0); + flush_tlb_range(&init_mm, vaddr, size); + break; + default: + printk(KERN_CRIT + "kernel_set_cachemode mode %d not understood\n", + what); + break; + } +} diff --git a/arch/parisc/mm/pa11.c b/arch/parisc/mm/pa11.c new file mode 100644 index 000000000..42f0d57f6 --- /dev/null +++ b/arch/parisc/mm/pa11.c @@ -0,0 +1,170 @@ +/* $Id: pa11.c,v 1.1 1999/03/17 01:05:41 pjlahaie Exp $ + * + * pa11.c: PA 1.1 specific mmu/cache code. + * + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> + +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/sgialib.h> +#include <asm/mmu_context.h> + +extern unsigned long mips_tlb_entries; + +/* page functions */ +void pa11_clear_page(unsigned long page) +{ +} + +static void pa11_copy_page(unsigned long to, unsigned long from) +{ +} + +/* Cache operations. */ +static inline void pa11_flush_cache_all(void) { } +static void pa11_flush_cache_mm(struct mm_struct *mm) { } +static void pa11_flush_cache_range(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ +} + +static void pa11_flush_cache_page(struct vm_area_struct *vma, + unsigned long page) +{ +} + +static void pa11_flush_page_to_ram(unsigned long page) +{ +} + +static void pa11_flush_cache_sigtramp(unsigned long page) +{ +} + +/* TLB operations. */ +static inline void pa11_flush_tlb_all(void) +{ + unsigned long flags; + int entry; + + save_and_cli(flags); +/* Here we will need to flush all the TLBs */ + restore_flags(flags); +} + +static void pa11_flush_tlb_mm(struct mm_struct *mm) +{ +/* This is what the MIPS does.. Is it the right thing for PA-RISC? */ + if(mm == current->mm) + pa11_flush_tlb_all(); +} + +static void pa11_flush_tlb_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + if(mm == current->mm) + pa11_flush_tlb_all(); +} + +static void pa11_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + if(vma->vm_mm == current->mm) + pa11_flush_tlb_all(); +} + +static void pa11_load_pgd(unsigned long pg_dir) +{ + unsigned long flags; + /* We need to do the right thing here */ +} + +/* + * Initialize new page directory with pointers to invalid ptes + */ +static void pa11_pgd_init(unsigned long page) +{ + unsigned long dummy1, dummy2; + +} + +static void pa11_update_mmu_cache(struct vm_area_struct * vma, + unsigned long address, pte_t pte) +{ + pa11_flush_tlb_page(vma, address); +} + +static void pa11_show_regs(struct pt_regs * regs) +{ + /* + * Saved main processor registers + */ + printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + 0, (unsigned long) regs->regs[1], (unsigned long) regs->regs[2], + (unsigned long) regs->regs[3], (unsigned long) regs->regs[4], + (unsigned long) regs->regs[5], (unsigned long) regs->regs[6], + (unsigned long) regs->regs[7]); + printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + (unsigned long) regs->regs[8], (unsigned long) regs->regs[9], + (unsigned long) regs->regs[10], (unsigned long) regs->regs[11], + (unsigned long) regs->regs[12], (unsigned long) regs->regs[13], + (unsigned long) regs->regs[14], (unsigned long) regs->regs[15]); + printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + (unsigned long) regs->regs[16], (unsigned long) regs->regs[17], + (unsigned long) regs->regs[18], (unsigned long) regs->regs[19], + (unsigned long) regs->regs[20], (unsigned long) regs->regs[21], + (unsigned long) regs->regs[22], (unsigned long) regs->regs[23]); + printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx\n", + (unsigned long) regs->regs[24], (unsigned long) regs->regs[25], + (unsigned long) regs->regs[28], (unsigned long) regs->regs[29], + (unsigned long) regs->regs[30], (unsigned long) regs->regs[31]); + + /* + * Saved cp0 registers + */ + printk("epc : %08lx\nStatus: %08x\nCause : %08x\n", + (unsigned long) regs->cp0_epc, (unsigned int) regs->cp0_status, + (unsigned int) regs->cp0_cause); +} + +static int pa11_user_mode(struct pt_regs *regs) +{ + /* Return user mode stuff?? */ +} + +__initfunc(void ld_mmu_pa11(void)) +{ + + /* Taken directly from the MIPS arch.. Lots of bad things here */ + clear_page = pa11_clear_page; + copy_page = pa11_copy_page; + + flush_cache_all = pa11_flush_cache_all; + flush_cache_mm = pa11_flush_cache_mm; + flush_cache_range = pa11_flush_cache_range; + flush_cache_page = pa11_flush_cache_page; + flush_cache_sigtramp = pa11_flush_cache_sigtramp; + flush_page_to_ram = pa11_flush_page_to_ram; + + flush_tlb_all = pa11_flush_tlb_all; + flush_tlb_mm = pa11_flush_tlb_mm; + flush_tlb_range = pa11_flush_tlb_range; + flush_tlb_page = pa11_flush_tlb_page; + pa11_asid_setup(); + + load_pgd = pa11_load_pgd; + pgd_init = pa11_pgd_init; + update_mmu_cache = pa11_update_mmu_cache; + + show_regs = pa11_show_regs; + + add_wired_entry = pa11_add_wired_entry; + + user_mode = pa11_user_mode; + flush_tlb_all(); +} diff --git a/arch/parisc/mm/pa20.c b/arch/parisc/mm/pa20.c new file mode 100644 index 000000000..cbc0343a0 --- /dev/null +++ b/arch/parisc/mm/pa20.c @@ -0,0 +1,170 @@ +/* $Id: pa20.c,v 1.1 1999/03/17 01:05:41 pjlahaie Exp $ + * + * pa20.c: PA 2.0 specific mmu/cache code. + * + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> + +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/sgialib.h> +#include <asm/mmu_context.h> + +extern unsigned long mips_tlb_entries; + +/* page functions */ +void pa20_clear_page(unsigned long page) +{ +} + +static void pa20_copy_page(unsigned long to, unsigned long from) +{ +} + +/* Cache operations. */ +static inline void pa20_flush_cache_all(void) { } +static void pa20_flush_cache_mm(struct mm_struct *mm) { } +static void pa20_flush_cache_range(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ +} + +static void pa20_flush_cache_page(struct vm_area_struct *vma, + unsigned long page) +{ +} + +static void pa20_flush_page_to_ram(unsigned long page) +{ +} + +static void pa20_flush_cache_sigtramp(unsigned long page) +{ +} + +/* TLB operations. */ +static inline void pa20_flush_tlb_all(void) +{ + unsigned long flags; + int entry; + + save_and_cli(flags); +/* Here we will need to flush all the TLBs */ + restore_flags(flags); +} + +static void pa20_flush_tlb_mm(struct mm_struct *mm) +{ +/* This is what the MIPS does.. Is it the right thing for PA-RISC? */ + if(mm == current->mm) + pa20_flush_tlb_all(); +} + +static void pa20_flush_tlb_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + if(mm == current->mm) + pa20_flush_tlb_all(); +} + +static void pa20_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + if(vma->vm_mm == current->mm) + pa20_flush_tlb_all(); +} + +static void pa20_load_pgd(unsigned long pg_dir) +{ + unsigned long flags; + /* We need to do the right thing here */ +} + +/* + * Initialize new page directory with pointers to invalid ptes + */ +static void pa20_pgd_init(unsigned long page) +{ + unsigned long dummy1, dummy2; + +} + +static void pa20_update_mmu_cache(struct vm_area_struct * vma, + unsigned long address, pte_t pte) +{ + pa20_flush_tlb_page(vma, address); +} + +static void pa20_show_regs(struct pt_regs * regs) +{ + /* + * Saved main processor registers + */ + printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + 0, (unsigned long) regs->regs[1], (unsigned long) regs->regs[2], + (unsigned long) regs->regs[3], (unsigned long) regs->regs[4], + (unsigned long) regs->regs[5], (unsigned long) regs->regs[6], + (unsigned long) regs->regs[7]); + printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + (unsigned long) regs->regs[8], (unsigned long) regs->regs[9], + (unsigned long) regs->regs[10], (unsigned long) regs->regs[11], + (unsigned long) regs->regs[12], (unsigned long) regs->regs[13], + (unsigned long) regs->regs[14], (unsigned long) regs->regs[15]); + printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + (unsigned long) regs->regs[16], (unsigned long) regs->regs[17], + (unsigned long) regs->regs[18], (unsigned long) regs->regs[19], + (unsigned long) regs->regs[20], (unsigned long) regs->regs[21], + (unsigned long) regs->regs[22], (unsigned long) regs->regs[23]); + printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx\n", + (unsigned long) regs->regs[24], (unsigned long) regs->regs[25], + (unsigned long) regs->regs[28], (unsigned long) regs->regs[29], + (unsigned long) regs->regs[30], (unsigned long) regs->regs[31]); + + /* + * Saved cp0 registers + */ + printk("epc : %08lx\nStatus: %08x\nCause : %08x\n", + (unsigned long) regs->cp0_epc, (unsigned int) regs->cp0_status, + (unsigned int) regs->cp0_cause); +} + +static int pa20_user_mode(struct pt_regs *regs) +{ + /* Return user mode stuff?? */ +} + +__initfunc(void ld_mmu_pa20(void)) +{ + + /* Taken directly from the MIPS arch.. Lots of bad things here */ + clear_page = pa20_clear_page; + copy_page = pa20_copy_page; + + flush_cache_all = pa20_flush_cache_all; + flush_cache_mm = pa20_flush_cache_mm; + flush_cache_range = pa20_flush_cache_range; + flush_cache_page = pa20_flush_cache_page; + flush_cache_sigtramp = pa20_flush_cache_sigtramp; + flush_page_to_ram = pa20_flush_page_to_ram; + + flush_tlb_all = pa20_flush_tlb_all; + flush_tlb_mm = pa20_flush_tlb_mm; + flush_tlb_range = pa20_flush_tlb_range; + flush_tlb_page = pa20_flush_tlb_page; + pa20_asid_setup(); + + load_pgd = pa20_load_pgd; + pgd_init = pa20_pgd_init; + update_mmu_cache = pa20_update_mmu_cache; + + show_regs = pa20_show_regs; + + add_wired_entry = pa20_add_wired_entry; + + user_mode = pa20_user_mode; + flush_tlb_all(); +} diff --git a/arch/parisc/tools/Makefile b/arch/parisc/tools/Makefile new file mode 100644 index 000000000..54fad5647 --- /dev/null +++ b/arch/parisc/tools/Makefile @@ -0,0 +1,28 @@ +# Makefile for MIPS kernel build tools. +# +# Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) +# Copyright (C) 1997 Ralf Baechle (ralf@gnu.ai.mit.edu) +# +# $Id: Makefile,v 1.3 1999/09/29 05:19:56 grundler Exp $ +# +TARGET := $(TOPDIR)/include/asm-$(ARCH)/offset.h + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: $(TARGET) + +$(TARGET): offset.h + cmp -s $^ $@ || (cp $^ $(TARGET).new && mv $(TARGET).new $(TARGET)) + +offset.h: offset.s + sed -n '/^@@@/s///p' $^ >$@ + +offset.s: offset.c + +clean: + rm -f offset.[hs] $(TARGET).new + +include $(TOPDIR)/Rules.make diff --git a/arch/parisc/tools/offset.c b/arch/parisc/tools/offset.c new file mode 100644 index 000000000..167087f7e --- /dev/null +++ b/arch/parisc/tools/offset.c @@ -0,0 +1,326 @@ +/* $Id: offset.c,v 1.2 2000/01/31 13:42:59 jsm Exp $ + * + * offset.c: Calculate pt_regs and task_struct offsets. + * + * Copyright (C) 1996 David S. Miller + * Made portable by Ralf Baechle + * Adapted to parisc by Philipp Rumpf, (C) 1999 SuSE GmbH Nuernberg */ + +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/version.h> + +#include <asm/ptrace.h> +#include <asm/processor.h> +#include <asm/hardirq.h> + +#define text(t) __asm__("\n@@@" t) +#define _offset(type, member) (&(((type *)NULL)->member)) + +#define offset(string, ptr, member) \ + __asm__("\n@@@" string "%0" : : "i" (_offset(ptr, member))) +#define size(string, size) \ + __asm__("\n@@@" string "%0" : : "i" (sizeof(size))) +#define align(x,y) (((x)+(2*(y))-1)-(((x)+(y)-1)%(y))) +#define size_align(string, size, algn) \ + __asm__("\n@@@" string "%0" : : "i" \ + align(sizeof(size),algn)) +#define linefeed text("") + +text("/* DO NOT TOUCH, AUTOGENERATED BY OFFSET.C */"); +linefeed; +text("#ifndef _PARISC_OFFSET_H"); +text("#define _PARISC_OFFSET_H"); +linefeed; + +void output_task_ptreg_defines(void) +{ + text("/* PA-RISC task pt_regs offsets. */"); + offset("#define TASK_REGS ", struct task_struct, thread.regs); + offset("#define TASK_PT_PSW ", struct task_struct, thread.regs.gr[ 0]); + offset("#define TASK_PT_GR1 ", struct task_struct, thread.regs.gr[ 1]); + offset("#define TASK_PT_GR2 ", struct task_struct, thread.regs.gr[ 2]); + offset("#define TASK_PT_GR3 ", struct task_struct, thread.regs.gr[ 3]); + offset("#define TASK_PT_GR4 ", struct task_struct, thread.regs.gr[ 4]); + offset("#define TASK_PT_GR5 ", struct task_struct, thread.regs.gr[ 5]); + offset("#define TASK_PT_GR6 ", struct task_struct, thread.regs.gr[ 6]); + offset("#define TASK_PT_GR7 ", struct task_struct, thread.regs.gr[ 7]); + offset("#define TASK_PT_GR8 ", struct task_struct, thread.regs.gr[ 8]); + offset("#define TASK_PT_GR9 ", struct task_struct, thread.regs.gr[ 9]); + offset("#define TASK_PT_GR10 ", struct task_struct, thread.regs.gr[10]); + offset("#define TASK_PT_GR11 ", struct task_struct, thread.regs.gr[11]); + offset("#define TASK_PT_GR12 ", struct task_struct, thread.regs.gr[12]); + offset("#define TASK_PT_GR13 ", struct task_struct, thread.regs.gr[13]); + offset("#define TASK_PT_GR14 ", struct task_struct, thread.regs.gr[14]); + offset("#define TASK_PT_GR15 ", struct task_struct, thread.regs.gr[15]); + offset("#define TASK_PT_GR16 ", struct task_struct, thread.regs.gr[16]); + offset("#define TASK_PT_GR17 ", struct task_struct, thread.regs.gr[17]); + offset("#define TASK_PT_GR18 ", struct task_struct, thread.regs.gr[18]); + offset("#define TASK_PT_GR19 ", struct task_struct, thread.regs.gr[19]); + offset("#define TASK_PT_GR20 ", struct task_struct, thread.regs.gr[20]); + offset("#define TASK_PT_GR21 ", struct task_struct, thread.regs.gr[21]); + offset("#define TASK_PT_GR22 ", struct task_struct, thread.regs.gr[22]); + offset("#define TASK_PT_GR23 ", struct task_struct, thread.regs.gr[23]); + offset("#define TASK_PT_GR24 ", struct task_struct, thread.regs.gr[24]); + offset("#define TASK_PT_GR25 ", struct task_struct, thread.regs.gr[25]); + offset("#define TASK_PT_GR26 ", struct task_struct, thread.regs.gr[26]); + offset("#define TASK_PT_GR27 ", struct task_struct, thread.regs.gr[27]); + offset("#define TASK_PT_GR28 ", struct task_struct, thread.regs.gr[28]); + offset("#define TASK_PT_GR29 ", struct task_struct, thread.regs.gr[29]); + offset("#define TASK_PT_GR30 ", struct task_struct, thread.regs.gr[30]); + offset("#define TASK_PT_GR31 ", struct task_struct, thread.regs.gr[31]); + offset("#define TASK_PT_FR0 ", struct task_struct, thread.regs.fr[ 0]); + offset("#define TASK_PT_FR1 ", struct task_struct, thread.regs.fr[ 1]); + offset("#define TASK_PT_FR2 ", struct task_struct, thread.regs.fr[ 2]); + offset("#define TASK_PT_FR3 ", struct task_struct, thread.regs.fr[ 3]); + offset("#define TASK_PT_FR4 ", struct task_struct, thread.regs.fr[ 4]); + offset("#define TASK_PT_FR5 ", struct task_struct, thread.regs.fr[ 5]); + offset("#define TASK_PT_FR6 ", struct task_struct, thread.regs.fr[ 6]); + offset("#define TASK_PT_FR7 ", struct task_struct, thread.regs.fr[ 7]); + offset("#define TASK_PT_FR8 ", struct task_struct, thread.regs.fr[ 8]); + offset("#define TASK_PT_FR9 ", struct task_struct, thread.regs.fr[ 9]); + offset("#define TASK_PT_FR10 ", struct task_struct, thread.regs.fr[10]); + offset("#define TASK_PT_FR11 ", struct task_struct, thread.regs.fr[11]); + offset("#define TASK_PT_FR12 ", struct task_struct, thread.regs.fr[12]); + offset("#define TASK_PT_FR13 ", struct task_struct, thread.regs.fr[13]); + offset("#define TASK_PT_FR14 ", struct task_struct, thread.regs.fr[14]); + offset("#define TASK_PT_FR15 ", struct task_struct, thread.regs.fr[15]); + offset("#define TASK_PT_FR16 ", struct task_struct, thread.regs.fr[16]); + offset("#define TASK_PT_FR17 ", struct task_struct, thread.regs.fr[17]); + offset("#define TASK_PT_FR18 ", struct task_struct, thread.regs.fr[18]); + offset("#define TASK_PT_FR19 ", struct task_struct, thread.regs.fr[19]); + offset("#define TASK_PT_FR20 ", struct task_struct, thread.regs.fr[20]); + offset("#define TASK_PT_FR21 ", struct task_struct, thread.regs.fr[21]); + offset("#define TASK_PT_FR22 ", struct task_struct, thread.regs.fr[22]); + offset("#define TASK_PT_FR23 ", struct task_struct, thread.regs.fr[23]); + offset("#define TASK_PT_FR24 ", struct task_struct, thread.regs.fr[24]); + offset("#define TASK_PT_FR25 ", struct task_struct, thread.regs.fr[25]); + offset("#define TASK_PT_FR26 ", struct task_struct, thread.regs.fr[26]); + offset("#define TASK_PT_FR27 ", struct task_struct, thread.regs.fr[27]); + offset("#define TASK_PT_FR28 ", struct task_struct, thread.regs.fr[28]); + offset("#define TASK_PT_FR29 ", struct task_struct, thread.regs.fr[29]); + offset("#define TASK_PT_FR30 ", struct task_struct, thread.regs.fr[30]); + offset("#define TASK_PT_FR31 ", struct task_struct, thread.regs.fr[31]); + offset("#define TASK_PT_SR0 ", struct task_struct, thread.regs.sr[ 0]); + offset("#define TASK_PT_SR1 ", struct task_struct, thread.regs.sr[ 1]); + offset("#define TASK_PT_SR2 ", struct task_struct, thread.regs.sr[ 2]); + offset("#define TASK_PT_SR3 ", struct task_struct, thread.regs.sr[ 3]); + offset("#define TASK_PT_SR4 ", struct task_struct, thread.regs.sr[ 4]); + offset("#define TASK_PT_SR5 ", struct task_struct, thread.regs.sr[ 5]); + offset("#define TASK_PT_SR6 ", struct task_struct, thread.regs.sr[ 6]); + offset("#define TASK_PT_SR7 ", struct task_struct, thread.regs.sr[ 7]); + offset("#define TASK_PT_IASQ0 ", struct task_struct, thread.regs.iasq[0]); + offset("#define TASK_PT_IASQ1 ", struct task_struct, thread.regs.iasq[1]); + offset("#define TASK_PT_IAOQ0 ", struct task_struct, thread.regs.iaoq[0]); + offset("#define TASK_PT_IAOQ1 ", struct task_struct, thread.regs.iaoq[1]); + offset("#define TASK_PT_CR24 ", struct task_struct, thread.regs.cr24); + offset("#define TASK_PT_CR25 ", struct task_struct, thread.regs.cr25); + offset("#define TASK_PT_CR26 ", struct task_struct, thread.regs.cr26); + offset("#define TASK_PT_CR27 ", struct task_struct, thread.regs.cr27); + offset("#define TASK_PT_CR30 ", struct task_struct, thread.regs.cr30); + offset("#define TASK_PT_ORIG_R28 ", struct task_struct, thread.regs.orig_r28); + offset("#define TASK_PT_KSP ", struct task_struct, thread.regs.ksp); + offset("#define TASK_PT_KPC ", struct task_struct, thread.regs.kpc); + offset("#define TASK_PT_SAR ", struct task_struct, thread.regs.sar); + offset("#define TASK_PT_CR11 ", struct task_struct, thread.regs.sar); + offset("#define TASK_PT_IIR ", struct task_struct, thread.regs.iir); + offset("#define TASK_PT_ISR ", struct task_struct, thread.regs.isr); + offset("#define TASK_PT_IOR ", struct task_struct, thread.regs.ior); + offset("#define TASK_PT_CR_PID0 ", struct task_struct, thread.regs.cr_pid[0]); + offset("#define TASK_PT_CR_PID1 ", struct task_struct, thread.regs.cr_pid[1]); + offset("#define TASK_PT_CR_PID2 ", struct task_struct, thread.regs.cr_pid[2]); + offset("#define TASK_PT_CR_PID3 ", struct task_struct, thread.regs.cr_pid[3]); + size("#define TASK_SZ ", struct task_struct); + size_align("#define TASK_SZ_ALGN ", struct task_struct, 64); + linefeed; +} + +void output_ptreg_defines(void) +{ + text("/* PA-RISC pt_regs offsets. */"); + offset("#define PT_PSW ", struct pt_regs, gr[ 0]); + offset("#define PT_GR1 ", struct pt_regs, gr[ 1]); + offset("#define PT_GR2 ", struct pt_regs, gr[ 2]); + offset("#define PT_GR3 ", struct pt_regs, gr[ 3]); + offset("#define PT_GR4 ", struct pt_regs, gr[ 4]); + offset("#define PT_GR5 ", struct pt_regs, gr[ 5]); + offset("#define PT_GR6 ", struct pt_regs, gr[ 6]); + offset("#define PT_GR7 ", struct pt_regs, gr[ 7]); + offset("#define PT_GR8 ", struct pt_regs, gr[ 8]); + offset("#define PT_GR9 ", struct pt_regs, gr[ 9]); + offset("#define PT_GR10 ", struct pt_regs, gr[10]); + offset("#define PT_GR11 ", struct pt_regs, gr[11]); + offset("#define PT_GR12 ", struct pt_regs, gr[12]); + offset("#define PT_GR13 ", struct pt_regs, gr[13]); + offset("#define PT_GR14 ", struct pt_regs, gr[14]); + offset("#define PT_GR15 ", struct pt_regs, gr[15]); + offset("#define PT_GR16 ", struct pt_regs, gr[16]); + offset("#define PT_GR17 ", struct pt_regs, gr[17]); + offset("#define PT_GR18 ", struct pt_regs, gr[18]); + offset("#define PT_GR19 ", struct pt_regs, gr[19]); + offset("#define PT_GR20 ", struct pt_regs, gr[20]); + offset("#define PT_GR21 ", struct pt_regs, gr[21]); + offset("#define PT_GR22 ", struct pt_regs, gr[22]); + offset("#define PT_GR23 ", struct pt_regs, gr[23]); + offset("#define PT_GR24 ", struct pt_regs, gr[24]); + offset("#define PT_GR25 ", struct pt_regs, gr[25]); + offset("#define PT_GR26 ", struct pt_regs, gr[26]); + offset("#define PT_GR27 ", struct pt_regs, gr[27]); + offset("#define PT_GR28 ", struct pt_regs, gr[28]); + offset("#define PT_GR29 ", struct pt_regs, gr[29]); + offset("#define PT_GR30 ", struct pt_regs, gr[30]); + offset("#define PT_GR31 ", struct pt_regs, gr[31]); + offset("#define PT_FR0 ", struct pt_regs, fr[ 0]); + offset("#define PT_FR1 ", struct pt_regs, fr[ 1]); + offset("#define PT_FR2 ", struct pt_regs, fr[ 2]); + offset("#define PT_FR3 ", struct pt_regs, fr[ 3]); + offset("#define PT_FR4 ", struct pt_regs, fr[ 4]); + offset("#define PT_FR5 ", struct pt_regs, fr[ 5]); + offset("#define PT_FR6 ", struct pt_regs, fr[ 6]); + offset("#define PT_FR7 ", struct pt_regs, fr[ 7]); + offset("#define PT_FR8 ", struct pt_regs, fr[ 8]); + offset("#define PT_FR9 ", struct pt_regs, fr[ 9]); + offset("#define PT_FR10 ", struct pt_regs, fr[10]); + offset("#define PT_FR11 ", struct pt_regs, fr[11]); + offset("#define PT_FR12 ", struct pt_regs, fr[12]); + offset("#define PT_FR13 ", struct pt_regs, fr[13]); + offset("#define PT_FR14 ", struct pt_regs, fr[14]); + offset("#define PT_FR15 ", struct pt_regs, fr[15]); + offset("#define PT_FR16 ", struct pt_regs, fr[16]); + offset("#define PT_FR17 ", struct pt_regs, fr[17]); + offset("#define PT_FR18 ", struct pt_regs, fr[18]); + offset("#define PT_FR19 ", struct pt_regs, fr[19]); + offset("#define PT_FR20 ", struct pt_regs, fr[20]); + offset("#define PT_FR21 ", struct pt_regs, fr[21]); + offset("#define PT_FR22 ", struct pt_regs, fr[22]); + offset("#define PT_FR23 ", struct pt_regs, fr[23]); + offset("#define PT_FR24 ", struct pt_regs, fr[24]); + offset("#define PT_FR25 ", struct pt_regs, fr[25]); + offset("#define PT_FR26 ", struct pt_regs, fr[26]); + offset("#define PT_FR27 ", struct pt_regs, fr[27]); + offset("#define PT_FR28 ", struct pt_regs, fr[28]); + offset("#define PT_FR29 ", struct pt_regs, fr[29]); + offset("#define PT_FR30 ", struct pt_regs, fr[30]); + offset("#define PT_FR31 ", struct pt_regs, fr[31]); + offset("#define PT_SR0 ", struct pt_regs, sr[ 0]); + offset("#define PT_SR1 ", struct pt_regs, sr[ 1]); + offset("#define PT_SR2 ", struct pt_regs, sr[ 2]); + offset("#define PT_SR3 ", struct pt_regs, sr[ 3]); + offset("#define PT_SR4 ", struct pt_regs, sr[ 4]); + offset("#define PT_SR5 ", struct pt_regs, sr[ 5]); + offset("#define PT_SR6 ", struct pt_regs, sr[ 6]); + offset("#define PT_SR7 ", struct pt_regs, sr[ 7]); + offset("#define PT_IASQ0 ", struct pt_regs, iasq[0]); + offset("#define PT_IASQ1 ", struct pt_regs, iasq[1]); + offset("#define PT_IAOQ0 ", struct pt_regs, iaoq[0]); + offset("#define PT_IAOQ1 ", struct pt_regs, iaoq[1]); + offset("#define PT_CR24 ", struct pt_regs, cr24); + offset("#define PT_CR25 ", struct pt_regs, cr25); + offset("#define PT_CR26 ", struct pt_regs, cr26); + offset("#define PT_CR27 ", struct pt_regs, cr27); + offset("#define PT_CR30 ", struct pt_regs, cr30); + offset("#define PT_ORIG_R28 ", struct pt_regs, orig_r28); + offset("#define PT_KSP ", struct pt_regs, ksp); + offset("#define PT_KPC ", struct pt_regs, kpc); + offset("#define PT_SAR ", struct pt_regs, sar); + offset("#define PT_CR11 ", struct pt_regs, sar); + offset("#define PT_IIR ", struct pt_regs, iir); + offset("#define PT_ISR ", struct pt_regs, isr); + offset("#define PT_IOR ", struct pt_regs, ior); + offset("#define PT_CR_PID0 ", struct pt_regs, cr_pid[0]); + offset("#define PT_CR_PID1 ", struct pt_regs, cr_pid[1]); + offset("#define PT_CR_PID2 ", struct pt_regs, cr_pid[2]); + offset("#define PT_CR_PID3 ", struct pt_regs, cr_pid[3]); + size("#define PT_SIZE ", struct pt_regs); + size_align("#define PT_SZ_ALGN ", struct pt_regs, 64); + linefeed; +} + +void output_task_defines(void) +{ + text("/* PARISC task_struct offsets. */"); + offset("#define TASK_STATE ", struct task_struct, state); + offset("#define TASK_FLAGS ", struct task_struct, flags); + offset("#define TASK_SIGPENDING ", struct task_struct, sigpending); + offset("#define TASK_SEGMENT ", struct task_struct, addr_limit); + offset("#define TASK_NEED_RESCHED ", struct task_struct, need_resched); + offset("#define TASK_COUNTER ", struct task_struct, counter); + offset("#define TASK_PTRACE ", struct task_struct, ptrace); + offset("#define TASK_NICE ", struct task_struct, nice); + offset("#define TASK_MM ", struct task_struct, mm); + offset("#define TASK_PROCESSOR ", struct task_struct, processor); + size ("#define TASK_SZ ", struct task_struct); + size_align("#define TASK_SZ_ALGN ", struct task_struct, 64); + linefeed; +} + +void output_irq_stat_defines(void) +{ + text("/* PARISC irq_cpustat_t offsets. */"); + offset("#define IRQSTAT_SI_ACTIVE ", irq_cpustat_t, __softirq_active); + offset("#define IRQSTAT_SI_MASK ", irq_cpustat_t, __softirq_mask); + size ("#define IRQSTAT_SZ ", irq_cpustat_t); + linefeed; +} + +#ifdef PRUMPF_HAD_MORE_TIME +void output_thread_defines(void) +{ + text("/* PARISC specific thread_struct offsets. */"); + offset("#define THREAD_REG16 ", struct task_struct, thread.reg16); + offset("#define THREAD_REG17 ", struct task_struct, thread.reg17); + offset("#define THREAD_REG18 ", struct task_struct, thread.reg18); + offset("#define THREAD_REG19 ", struct task_struct, thread.reg19); + offset("#define THREAD_REG20 ", struct task_struct, thread.reg20); + offset("#define THREAD_REG21 ", struct task_struct, thread.reg21); + offset("#define THREAD_REG22 ", struct task_struct, thread.reg22); + offset("#define THREAD_REG23 ", struct task_struct, thread.reg23); + offset("#define THREAD_REG29 ", struct task_struct, thread.reg29); + offset("#define THREAD_REG30 ", struct task_struct, thread.reg30); + offset("#define THREAD_REG31 ", struct task_struct, thread.reg31); + offset("#define THREAD_STATUS ", struct task_struct, thread.cp0_status); + offset("#define THREAD_FPU ", struct task_struct, thread.fpu); + offset("#define THREAD_BVADDR ", struct task_struct, thread.cp0_badvaddr); + offset("#define THREAD_BUADDR ", struct task_struct, thread.cp0_baduaddr); + offset("#define THREAD_ECODE ", struct task_struct, thread.error_code); + offset("#define THREAD_TRAPNO ", struct task_struct, thread.trap_no); + offset("#define THREAD_PGDIR ", struct task_struct, thread.pg_dir); + offset("#define THREAD_MFLAGS ", struct task_struct, thread.mflags); + offset("#define THREAD_CURDS ", struct task_struct, thread.current_ds); + offset("#define THREAD_TRAMP ", struct task_struct, thread.irix_trampoline); + offset("#define THREAD_OLDCTX ", struct task_struct, thread.irix_oldctx); + linefeed; +} + +void output_mm_defines(void) +{ + text("/* Linux mm_struct offsets. */"); + offset("#define MM_COUNT ", struct mm_struct, count); + offset("#define MM_PGD ", struct mm_struct, pgd); + offset("#define MM_CONTEXT ", struct mm_struct, context); + linefeed; +} + +void output_sc_defines(void) +{ + text("/* Linux sigcontext offsets. */"); + offset("#define SC_REGMASK ", struct sigcontext, sc_regmask); + offset("#define SC_STATUS ", struct sigcontext, sc_status); + offset("#define SC_PC ", struct sigcontext, sc_pc); + offset("#define SC_REGS ", struct sigcontext, sc_regs); + offset("#define SC_FPREGS ", struct sigcontext, sc_fpregs); + offset("#define SC_OWNEDFP ", struct sigcontext, sc_ownedfp); + offset("#define SC_FPC_CSR ", struct sigcontext, sc_fpc_csr); + offset("#define SC_FPC_EIR ", struct sigcontext, sc_fpc_eir); + offset("#define SC_SSFLAGS ", struct sigcontext, sc_ssflags); + offset("#define SC_MDHI ", struct sigcontext, sc_mdhi); + offset("#define SC_MDLO ", struct sigcontext, sc_mdlo); + offset("#define SC_CAUSE ", struct sigcontext, sc_cause); + offset("#define SC_BADVADDR ", struct sigcontext, sc_badvaddr); + offset("#define SC_SIGSET ", struct sigcontext, sc_sigset); + linefeed; +} + +#endif + +text("#endif /* !(_PARISC_OFFSET_H) */"); diff --git a/arch/parisc/vmlinux.lds b/arch/parisc/vmlinux.lds new file mode 100644 index 000000000..268fc59ce --- /dev/null +++ b/arch/parisc/vmlinux.lds @@ -0,0 +1,79 @@ +/* ld script to make hppa Linux kernel */ +OUTPUT_FORMAT("elf32-hppa") +OUTPUT_ARCH(hppa) +ENTRY(_stext) +SECTIONS +{ + +/* right now use 0x10000/0x11000, later when we don't use Console and + * Boot-Device IODC, we will change this to 0x8000 !!! + */ + + . = 0xc0100000; +/* . = 0x10000; */ + + _text = .; /* Text and read-only data */ + .text BLOCK(16) : { + *(.text*) + *(.PARISC.unwind) + *(.fixup) + *(.lock.text) /* out-of-line lock text */ + *(.gnu.warning) + } = 0 + + . = ALIGN(16); + .rodata : { *(.rodata) } + .kstrtab : { *(.kstrtab) } + + _etext = .; /* End of text section */ + + .data BLOCK(8192) : { /* Data without special */ + data_start = .; + *(.data) + } + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; + + + . = ALIGN(16384); + __init_begin = .; + .init.text : { *(.init.text) } + .init.data : { *(.init.data) } + . = ALIGN(16); + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; + __init_end = .; + + + init_task BLOCK(16384) : { *(init_task) } /* The initial task and kernel stack */ + + _edata = .; /* End of data section */ + + + .bss : { *(.bss) *(COMMON) } /* BSS */ + + + _end = . ; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .note 0 : { *(.note) } + +} diff --git a/arch/ppc/8260_io/uart.c b/arch/ppc/8260_io/uart.c index f7ce9da03..e6e223b61 100644 --- a/arch/ppc/8260_io/uart.c +++ b/arch/ppc/8260_io/uart.c @@ -496,8 +496,9 @@ static _INLINE_ void check_modem_status(struct async_struct *info) #ifdef SERIAL_DEBUG_OPEN printk("scheduling hangup..."); #endif - queue_task(&info->tqueue_hangup, - &tq_scheduler); + MOD_INC_USE_COUNT; + if (schedule_task(&info->tqueue_hangup) == 0) + MOD_DEC_USE_COUNT; } } if (info->flags & ASYNC_CTS_FLOW) { @@ -624,10 +625,9 @@ static void do_serial_hangup(void *private_) struct tty_struct *tty; tty = info->tty; - if (!tty) - return; - - tty_hangup(tty); + if (tty) + tty_hangup(tty); + MOD_DEC_USE_COUNT; } /*static void rs_8xx_timer(void) diff --git a/arch/ppc/8xx_io/fec.c b/arch/ppc/8xx_io/fec.c index 45f10b635..659576e8c 100644 --- a/arch/ppc/8xx_io/fec.c +++ b/arch/ppc/8xx_io/fec.c @@ -1214,7 +1214,7 @@ static void mii_queue_relink(uint mii_reg, struct net_device *dev) fep->phy_task.routine = (void *)mii_relink; fep->phy_task.data = dev; - queue_task(&fep->phy_task, &tq_scheduler); + schedule_task(&fep->phy_task); } static void mii_queue_config(uint mii_reg, struct net_device *dev) @@ -1223,7 +1223,7 @@ static void mii_queue_config(uint mii_reg, struct net_device *dev) fep->phy_task.routine = (void *)mii_display_config; fep->phy_task.data = dev; - queue_task(&fep->phy_task, &tq_scheduler); + schedule_task(&fep->phy_task); } diff --git a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c index 7c05954c2..598e13ac0 100644 --- a/arch/ppc/8xx_io/uart.c +++ b/arch/ppc/8xx_io/uart.c @@ -514,8 +514,9 @@ static _INLINE_ void check_modem_status(struct async_struct *info) #ifdef SERIAL_DEBUG_OPEN printk("scheduling hangup..."); #endif - queue_task(&info->tqueue_hangup, - &tq_scheduler); + MOD_INC_USE_COUNT; + if (schedule_task(&info->tqueue_hangup) == 0) + MOD_DEC_USE_COUNT; } } if (info->flags & ASYNC_CTS_FLOW) { @@ -645,10 +646,9 @@ static void do_serial_hangup(void *private_) struct tty_struct *tty; tty = info->tty; - if (!tty) - return; - - tty_hangup(tty); + if (tty) + tty_hangup(tty); + MOD_DEC_USE_COUNT; } /*static void rs_8xx_timer(void) diff --git a/arch/ppc/amiga/config.c b/arch/ppc/amiga/config.c index 83e33e17b..4586d8abe 100644 --- a/arch/ppc/amiga/config.c +++ b/arch/ppc/amiga/config.c @@ -49,11 +49,28 @@ unsigned char amiga_vblank; unsigned char amiga_psfreq; struct amiga_hw_present amiga_hw_present; -static const char *amiga_models[] = { - "A500", "A500+", "A600", "A1000", "A1200", "A2000", "A2500", "A3000", - "A3000T", "A3000+", "A4000", "A4000T", "CDTV", "CD32", "Draco" +static const char s_a500[] __initdata = "A500"; +static const char s_a500p[] __initdata = "A500+"; +static const char s_a600[] __initdata = "A600"; +static const char s_a1000[] __initdata = "A1000"; +static const char s_a1200[] __initdata = "A1200"; +static const char s_a2000[] __initdata = "A2000"; +static const char s_a2500[] __initdata = "A2500"; +static const char s_a3000[] __initdata = "A3000"; +static const char s_a3000t[] __initdata = "A3000T"; +static const char s_a3000p[] __initdata = "A3000+"; +static const char s_a4000[] __initdata = "A4000"; +static const char s_a4000t[] __initdata = "A4000T"; +static const char s_cdtv[] __initdata = "CDTV"; +static const char s_cd32[] __initdata = "CD32"; +static const char s_draco[] __initdata = "Draco"; +static const char *amiga_models[] __initdata = { + s_a500, s_a500p, s_a600, s_a1000, s_a1200, s_a2000, s_a2500, s_a3000, + s_a3000t, s_a3000p, s_a4000, s_a4000t, s_cdtv, s_cd32, s_draco, }; +static char amiga_model_name[13] = "Amiga "; + extern char m68k_debug_device[]; static void amiga_sched_init(void (*handler)(int, void *, struct pt_regs *)); @@ -117,6 +134,26 @@ static char amiga_sysrq_xlate[128] = extern void (*kd_mksound)(unsigned int, unsigned int); + + /* + * Motherboard Resources present in all Amiga models + */ + +static struct resource mb_res[] = { + { "Ranger Memory", 0x00c00000, 0x00c7ffff }, + { "CIA B", 0x00bfd000, 0x00bfdfff }, + { "CIA A", 0x00bfe000, 0x00bfefff }, + { "Custom I/O", 0x00dff000, 0x00dfffff }, + { "Kickstart ROM", 0x00f80000, 0x00ffffff } +}; + +static struct resource rtc_resource = { + "A2000 RTC", 0x00dc0000, 0x00dcffff +}; + +static struct resource ram_resource[NUM_MEMINFO]; + + /* * Parse an Amiga-specific record in the bootinfo */ @@ -157,11 +194,15 @@ int amiga_parse_bootinfo(const struct bi_record *record) break; case BI_AMIGA_AUTOCON: - if (zorro_num_autocon < ZORRO_NUM_AUTO) - memcpy(&zorro_autocon[zorro_num_autocon++], - (const struct ConfigDev *)data, - sizeof(struct ConfigDev)); - else + if (zorro_num_autocon < ZORRO_NUM_AUTO) { + const struct ConfigDev *cd = (struct ConfigDev *)data; + struct zorro_dev *dev = &zorro_autocon[zorro_num_autocon++]; + dev->rom = cd->cd_Rom; + dev->slotaddr = cd->cd_SlotAddr; + dev->slotsize = cd->cd_SlotSize; + dev->resource.start = (unsigned long)cd->cd_BoardAddr; + dev->resource.end = dev->resource.start+cd->cd_BoardSize-1; + } else printk("amiga_parse_bootinfo: too many AutoConfig devices\n"); break; @@ -188,8 +229,10 @@ static void __init amiga_identify(void) memset(&amiga_hw_present, 0, sizeof(amiga_hw_present)); printk("Amiga hardware found: "); - if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) + if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) { printk("[%s] ", amiga_models[amiga_model-AMI_500]); + strcat(amiga_model_name, amiga_models[amiga_model-AMI_500]); + } switch(amiga_model) { case AMI_UNKNOWN: @@ -342,9 +385,19 @@ static void __init amiga_identify(void) void __init config_amiga(void) { + int i; + amiga_debug_init(); amiga_identify(); + /* Some APUS boxes may have PCI memory, but ... */ + iomem_resource.name = "Memory"; + request_resource(&iomem_resource, &ranger_resource); + request_resource(&iomem_resource, &ciab_resource); + request_resource(&iomem_resource, &ciaa_resource); + request_resource(&iomem_resource, &custom_chips_resource); + request_resource(&iomem_resource, &kickstart_resource); + mach_sched_init = amiga_sched_init; mach_keyb_init = amiga_keyb_init; mach_kbdrate = amiga_kbdrate; @@ -362,9 +415,12 @@ void __init config_amiga(void) mach_gettimeoffset = amiga_gettimeoffset; if (AMIGAHW_PRESENT(A3000_CLK)){ mach_gettod = a3000_gettod; + rtc_resource.name[1] = '3'; + request_resource(&iomem_resource, &rtc_resource); } else{ /* if (AMIGAHW_PRESENT(A2000_CLK)) */ mach_gettod = a2000_gettod; + request_resource(&iomem_resource, &rtc_resource); } mach_max_dma_address = 0xffffffff; /* @@ -404,6 +460,17 @@ void __init config_amiga(void) /* ensure that the DMA master bit is set */ custom.dmacon = DMAF_SETCLR | DMAF_MASTER; + /* request all RAM */ + for (i = 0; i < m68k_num_memory; i++) { + ram_resource[i].name = + (m68k_memory[i].addr >= 0x01000000) ? "32-bit Fast RAM" : + (m68k_memory[i].addr < 0x00c00000) ? "16-bit Fast RAM" : + "16-bit Slow RAM"; + ram_resource[i].start = m68k_memory[i].addr; + ram_resource[i].end = m68k_memory[i].addr+m68k_memory[i].size-1; + request_resource(&iomem_resource, &ram_resource[i]); + } + /* initialize chipram allocator */ amiga_chip_init (); @@ -437,6 +504,8 @@ static void __init amiga_sched_init(void (*timer_routine)(int, void *, { jiffy_ticks = (amiga_eclock+HZ/2)/HZ; + if (!request_mem_region(CIAB_PHYSADDR+0x400, 0x200, "timer")) + printk("Cannot allocate ciab.ta{lo,hi}\n"); ciab.cra &= 0xC0; /* turn off timer A, continuous mode, from Eclk */ ciab.talo = jiffy_ticks % 256; ciab.tahi = jiffy_ticks / 256; @@ -727,7 +796,7 @@ static void amiga_mem_console_write(struct console *co, const char *s, static void amiga_savekmsg_init(void) { - savekmsg = (struct savekmsg *)amiga_chip_alloc(SAVEKMSG_MAXMEM); + savekmsg = (struct savekmsg *)amiga_chip_alloc(SAVEKMSG_MAXMEM, "Debug"); savekmsg->magic1 = SAVEKMSG_MAGIC1; savekmsg->magic2 = SAVEKMSG_MAGIC2; savekmsg->magicptr = virt_to_phys(savekmsg); @@ -840,9 +909,7 @@ static void amiga_heartbeat(int on) static void amiga_get_model(char *model) { - strcpy(model, "Amiga "); - if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) - strcat(model, amiga_models[amiga_model-AMI_500]); + strcpy(model, amiga_model_name); } diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 2c17e7bcb..c3d77a67e 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -293,7 +293,7 @@ void show_mem(void) reserved++; else if (PageSwapCache(mem_map+i)) cached++; - else if (!atomic_read(&mem_map[i].count)) + else if (!page_count(mem_map+i)) free++; else shared += atomic_read(&mem_map[i].count) - 1; diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 71fbe4665..4af4f6565 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -47,12 +47,6 @@ extern pgm_check_handler_t do_page_fault; asmlinkage int system_call(void); -static inline void console_verbose(void) -{ - extern int console_loglevel; - console_loglevel = 15; -} - #define DO_ERROR(trapnr, signr, str, name, tsk) \ asmlinkage void name(struct pt_regs * regs, long error_code) \ { \ diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 1a22e429b..177e5e8f2 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -192,7 +192,7 @@ int do_check_pgt_cache(int low, int high) void show_mem(void) { - int i,free = 0,total = 0,reserved = 0; + int i, total = 0, reserved = 0; int shared = 0, cached = 0; printk("Mem-info:\n"); @@ -205,9 +205,7 @@ void show_mem(void) reserved++; else if (PageSwapCache(mem_map+i)) cached++; - else if (!atomic_read(&mem_map[i].count)) - free++; - else + else if (page_count(mem_map+i)) shared += atomic_read(&mem_map[i].count) - 1; } printk("%d pages of RAM\n",total); diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index db11c1247..4aeaf8efa 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c @@ -28,12 +28,6 @@ #include <asm/atomic.h> #include <asm/processor.h> -static inline void console_verbose(void) -{ - extern int console_loglevel; - console_loglevel = 15; -} - #define DO_ERROR(trapnr, signr, str, name, tsk) \ asmlinkage void do_##name(unsigned long r4, unsigned long r5, \ unsigned long r6, unsigned long r7, \ diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 5a0ac1f10..e03dba90a 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -150,7 +150,7 @@ int do_check_pgt_cache(int low, int high) void show_mem(void) { - int i,free = 0,total = 0,reserved = 0; + int i, total = 0, reserved = 0; int shared = 0, cached = 0; printk("Mem-info:\n"); @@ -163,9 +163,7 @@ void show_mem(void) reserved++; else if (PageSwapCache(mem_map+i)) cached++; - else if (!page_count(mem_map+i)) - free++; - else + else if (page_count(mem_map+i)) shared += page_count(mem_map+i) - 1; } printk("%d pages of RAM\n",total); diff --git a/arch/sparc/boot/piggyback.c b/arch/sparc/boot/piggyback.c index 04049be7a..6962cc68e 100644 --- a/arch/sparc/boot/piggyback.c +++ b/arch/sparc/boot/piggyback.c @@ -1,9 +1,10 @@ -/* $Id: piggyback.c,v 1.3 2000/03/11 00:22:26 zaitcev Exp $ +/* $Id: piggyback.c,v 1.4 2000/12/05 00:48:57 anton Exp $ Simple utility to make a single-image install kernel with initial ramdisk for Sparc tftpbooting without need to set up nfs. - + Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - + Pete Zaitcev <zaitcev@yahoo.com> endian fixes for cross-compiles, 2000. + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -34,6 +35,24 @@ * as PROM looks for a.out image only. */ +unsigned short ld2(char *p) +{ + return (p[0] << 8) | p[1]; +} + +unsigned int ld4(char *p) +{ + return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; +} + +void st4(char *p, unsigned int x) +{ + p[0] = x >> 24; + p[1] = x >> 16; + p[2] = x >> 8; + p[3] = x; +} + void usage(void) { /* fs_img.gz is an image of initial ramdisk. */ @@ -50,7 +69,8 @@ void die(char *str) int main(int argc,char **argv) { - char buffer [1024], *q, *r; + static char aout_magic[] = { 0x01, 0x03, 0x01, 0x07 }; + unsigned char buffer[1024], *q, *r; unsigned int i, j, k, start, end, offset; FILE *map; struct stat s; @@ -74,21 +94,20 @@ int main(int argc,char **argv) } if ((image = open(argv[1],O_RDWR)) < 0) die(argv[1]); if (read(image,buffer,512) != 512) die(argv[1]); - if (!memcmp (buffer, "\177ELF", 4)) { - unsigned int *p = (unsigned int *)(buffer + *(unsigned int *)(buffer + 28)); - - i = p[1] + *(unsigned int *)(buffer + 24) - p[2]; + if (memcmp (buffer, "\177ELF", 4) == 0) { + q = buffer + ld4(buffer + 28); + i = ld4(q + 4) + ld4(buffer + 24) - ld4(q + 8); if (lseek(image,i,0) < 0) die("lseek"); if (read(image,buffer,512) != 512) die(argv[1]); j = 0; - } else if (*(unsigned int *)buffer == 0x01030107) { + } else if (memcmp(buffer, aout_magic, 4) == 0) { i = j = 32; } else { fprintf (stderr, "Not ELF nor a.out. Don't blame me.\n"); exit(1); } k = i; - i += ((*(unsigned short *)(buffer + j + 2))<<2) - 512; + i += (ld2(buffer + j + 2)<<2) - 512; if (lseek(image,i,0) < 0) die("lseek"); if (read(image,buffer,1024) != 1024) die(argv[1]); for (q = buffer, r = q + 512; q < r; q += 4) { @@ -101,10 +120,12 @@ int main(int argc,char **argv) } offset = i + (q - buffer) + 10; if (lseek(image, offset, 0) < 0) die ("lseek"); - *(unsigned *)buffer = 0; - *(unsigned *)(buffer + 4) = 0x01000000; - *(unsigned *)(buffer + 8) = ((end + 32 + 4095) & ~4095); - *(unsigned *)(buffer + 12) = s.st_size; + + st4(buffer, 0); + st4(buffer + 4, 0x01000000); + st4(buffer + 8, (end + 32 + 4095) & ~4095); + st4(buffer + 12, s.st_size); + if (write(image,buffer+2,14) != 14) die (argv[1]); if (lseek(image, k - start + ((end + 32 + 4095) & ~4095), 0) < 0) die ("lseek"); if ((tail = open(argv[3],O_RDONLY)) < 0) die(argv[3]); diff --git a/arch/sparc/config.in b/arch/sparc/config.in index 1a75cdf17..dbe1d1fb2 100644 --- a/arch/sparc/config.in +++ b/arch/sparc/config.in @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.105 2000/11/12 10:01:41 davem Exp $ +# $Id: config.in,v 1.106 2000/11/17 04:27:52 davem Exp $ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index e0be43e08..41ef9737e 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -1,4 +1,4 @@ -/* $Id: ioport.c,v 1.40 2000/10/10 09:44:46 anton Exp $ +/* $Id: ioport.c,v 1.42 2000/12/05 00:56:36 anton Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -447,6 +447,7 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int dir */ void sbus_dma_sync_single(struct sbus_dev *sdev, u32 ba, long size, int direction) { +#if 0 unsigned long va; struct resource *res; @@ -461,6 +462,7 @@ void sbus_dma_sync_single(struct sbus_dev *sdev, u32 ba, long size, int directio * to a kernel near you. - Anton */ /* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */ +#endif } void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) @@ -584,7 +586,8 @@ void pci_free_consistent(struct pci_dev *pdev, size_t n, void *p, dma_addr_t ba) * 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. */ -dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) +dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, + int direction) { if (direction == PCI_DMA_NONE) BUG(); diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index e7b4e96de..c9ba85b27 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -1,4 +1,4 @@ -/* $Id: pcic.c,v 1.19 2000/11/08 04:49:17 davem Exp $ +/* $Id: pcic.c,v 1.20 2000/12/05 00:56:36 anton Exp $ * pcic.c: Sparc/PCI controller support * * Copyright (C) 1998 V. Roganov and G. Raiko @@ -556,8 +556,8 @@ static void pcic_map_pci_device(struct linux_pcic *pcic, */ printk("PCIC: Skipping I/O space at 0x%lx," "this will Oops if a driver attaches;" - "device '%s' (%x,%x)\n", address, namebuf, - dev->device, dev->vendor); + "device '%s' at %02x:%02x)\n", address, + namebuf, dev->bus->number, dev->devfn); } } } @@ -568,12 +568,12 @@ pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node) { struct pcic_ca2irq *p; int i, ivec; - char namebuf[64]; /* P3 remove */ + char namebuf[64]; if (node == 0 || node == -1) { strcpy(namebuf, "???"); } else { - prom_getstring(node, "name", namebuf, sizeof(namebuf)); /* P3 remove */ + prom_getstring(node, "name", namebuf, sizeof(namebuf)); } if ((p = pcic->pcic_imap) == 0) { @@ -612,8 +612,8 @@ pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node) if (p->irq == 0 || p->irq >= 15) { /* Corrupted map */ printk("PCIC: BAD IRQ %d\n", p->irq); for (;;) {} } - printk("PCIC: setting irq %x for device (%x,%x)\n", - p->irq, dev->device, dev->vendor); + printk("PCIC: setting irq %d at pin %d for device %02x:%02x\n", + p->irq, p->pin, dev->bus->number, dev->devfn); dev->irq = p->irq; i = p->pin; diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c index 414dfd076..90b305a8c 100644 --- a/arch/sparc/kernel/smp.c +++ b/arch/sparc/kernel/smp.c @@ -26,7 +26,6 @@ #include <asm/pgalloc.h> #include <asm/pgtable.h> #include <asm/oplib.h> -#include <asm/atops.h> #include <asm/hardirq.h> #include <asm/softirq.h> diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index 997e4d0ce..d9883654e 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.104 2000/09/06 05:43:00 anton Exp $ +/* $Id: sparc_ksyms.c,v 1.105 2000/12/11 05:24:25 anton Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -111,6 +111,11 @@ EXPORT_SYMBOL_PRIVATE(_rw_read_enter); EXPORT_SYMBOL_PRIVATE(_rw_read_exit); EXPORT_SYMBOL_PRIVATE(_rw_write_enter); #endif +/* semaphores */ +EXPORT_SYMBOL(__up); +EXPORT_SYMBOL(__down); +EXPORT_SYMBOL(__down_trylock); +EXPORT_SYMBOL(__down_interruptible); /* rw semaphores */ EXPORT_SYMBOL_NOVERS(___down_read); EXPORT_SYMBOL_NOVERS(___down_write); diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index 280392629..d14dbc2ac 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c @@ -28,7 +28,6 @@ #include <asm/pgalloc.h> #include <asm/pgtable.h> #include <asm/oplib.h> -#include <asm/atops.h> #include <asm/hardirq.h> #include <asm/softirq.h> #include <asm/sbus.h> diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c index d6c126d00..230a95e6b 100644 --- a/arch/sparc/kernel/sun4m_smp.c +++ b/arch/sparc/kernel/sun4m_smp.c @@ -25,7 +25,6 @@ #include <asm/pgalloc.h> #include <asm/pgtable.h> #include <asm/oplib.h> -#include <asm/atops.h> #include <asm/hardirq.h> #include <asm/softirq.h> diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c index dd011c143..498fdb26f 100644 --- a/arch/sparc/kernel/sys_sparc.c +++ b/arch/sparc/kernel/sys_sparc.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.66 2000/07/10 20:57:35 davem Exp $ +/* $Id: sys_sparc.c,v 1.67 2000/11/30 08:37:31 anton Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that @@ -34,6 +34,8 @@ asmlinkage unsigned long sys_getpagesize(void) return PAGE_SIZE; /* Possibly older binaries want 8192 on sun4's? */ } +#define COLOUR_ALIGN(addr) (((addr)+SHMLBA-1)&~(SHMLBA-1)) + unsigned long get_unmapped_area(unsigned long addr, unsigned long len) { struct vm_area_struct * vmm; @@ -45,7 +47,11 @@ unsigned long get_unmapped_area(unsigned long addr, unsigned long len) return 0; if (!addr) addr = TASK_UNMAPPED_BASE; - addr = PAGE_ALIGN(addr); + + if (current->thread.flags & SPARC_FLAG_MMAPSHARED) + addr = COLOUR_ALIGN(addr); + else + addr = PAGE_ALIGN(addr); for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { /* At this point: (!vmm || addr < vmm->vm_end). */ @@ -58,6 +64,8 @@ unsigned long get_unmapped_area(unsigned long addr, unsigned long len) if (!vmm || addr + len <= vmm->vm_start) return addr; addr = vmm->vm_end; + if (current->thread.flags & SPARC_FLAG_MMAPSHARED) + addr = COLOUR_ALIGN(addr); } } @@ -224,10 +232,16 @@ static unsigned long do_mmap2(unsigned long addr, unsigned long len, goto out_putf; flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + + if (flags & MAP_SHARED) + current->thread.flags |= SPARC_FLAG_MMAPSHARED; + down(¤t->mm->mmap_sem); retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); up(¤t->mm->mmap_sem); + current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); + out_putf: if (file) fput(file); @@ -259,6 +273,7 @@ asmlinkage unsigned long sparc_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr) { + struct vm_area_struct *vma; unsigned long ret = -EINVAL; if (ARCH_SUN4C_SUN4) { if (old_len > 0x20000000 || new_len > 0x20000000) @@ -270,6 +285,9 @@ asmlinkage unsigned long sparc_mremap(unsigned long addr, new_len > TASK_SIZE - PAGE_SIZE) goto out; down(¤t->mm->mmap_sem); + vma = find_vma(current->mm, addr); + if (vma && (vma->vm_flags & VM_SHARED)) + current->thread.flags |= SPARC_FLAG_MMAPSHARED; if (flags & MREMAP_FIXED) { if (ARCH_SUN4C_SUN4 && new_addr < 0xe0000000 && @@ -290,6 +308,7 @@ asmlinkage unsigned long sparc_mremap(unsigned long addr, } ret = do_mremap(addr, old_len, new_len, flags, new_addr); out_sem: + current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); up(¤t->mm->mmap_sem); out: return ret; @@ -302,12 +321,10 @@ c_sys_nis_syscall (struct pt_regs *regs) static int count = 0; if (count++ > 5) return -ENOSYS; - lock_kernel(); printk ("%s[%d]: Unimplemented SPARC system call %d\n", current->comm, current->pid, (int)regs->u_regs[1]); #ifdef DEBUG_UNIMP_SYSCALL show_regs (regs); #endif - unlock_kernel(); return -ENOSYS; } diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c index 85161a3a6..d27495bd6 100644 --- a/arch/sparc/mm/init.c +++ b/arch/sparc/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.95 2000/11/10 04:49:56 davem Exp $ +/* $Id: init.c,v 1.96 2000/11/30 08:51:50 anton Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -579,7 +579,8 @@ void si_meminfo(struct sysinfo *val) void flush_page_to_ram(struct page *page) { - unsigned long vaddr = (unsigned long) kmap(page); - __flush_page_to_ram(vaddr); - kunmap(page); + unsigned long vaddr = (unsigned long)page_address(page); + + if (vaddr) + __flush_page_to_ram(vaddr); } diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index b32199c13..0dba7d0a3 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.224 2000/11/09 22:40:05 davem Exp $ +/* $Id: srmmu.c,v 1.225 2000/11/30 08:37:31 anton Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -51,7 +51,6 @@ enum mbus_module srmmu_modtype; unsigned int hwbug_bitmask; int vac_cache_size; int vac_line_size; -int vac_badbits; extern struct resource sparc_iomap; @@ -1286,75 +1285,6 @@ static void srmmu_destroy_context(struct mm_struct *mm) } } -static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) -{ - if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) { - struct vm_area_struct *vmaring; - struct file *file; - struct address_space *mapping; - unsigned long flags, offset, vaddr, start; - int alias_found = 0; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - - __save_and_cli(flags); - - file = vma->vm_file; - if (!file) - goto done; - mapping = file->f_dentry->d_inode->i_mapping; - offset = (address & PAGE_MASK) - vma->vm_start; - spin_lock(&mapping->i_shared_lock); - vmaring = mapping->i_mmap_shared; - if (vmaring != NULL) do { - /* Do not mistake ourselves as another mapping. */ - if(vmaring == vma) - continue; - - vaddr = vmaring->vm_start + offset; - if ((vaddr ^ address) & vac_badbits) { - alias_found++; - start = vmaring->vm_start; - while (start < vmaring->vm_end) { - pgdp = srmmu_pgd_offset(vmaring->vm_mm, start); - if(!pgdp) goto next; - pmdp = srmmu_pmd_offset(pgdp, start); - if(!pmdp) goto next; - ptep = srmmu_pte_offset(pmdp, start); - if(!ptep) goto next; - - if((pte_val(*ptep) & SRMMU_ET_MASK) == SRMMU_VALID) { -#if 0 - printk("Fixing USER/USER alias [%ld:%08lx]\n", - vmaring->vm_mm->context, start); -#endif - flush_cache_page(vmaring, start); - srmmu_set_pte(ptep, __pte((pte_val(*ptep) & - ~SRMMU_CACHE))); - flush_tlb_page(vmaring, start); - } - next: - start += PAGE_SIZE; - } - } - } while ((vmaring = vmaring->vm_next_share) != NULL); - spin_unlock(&mapping->i_shared_lock); - - if(alias_found && ((pte_val(pte) & SRMMU_CACHE) != 0)) { - pgdp = srmmu_pgd_offset(vma->vm_mm, address); - pmdp = srmmu_pmd_offset(pgdp, address); - ptep = srmmu_pte_offset(pmdp, address); - flush_cache_page(vma, address); - srmmu_set_pte(ptep, __pte((pte_val(*ptep) & ~SRMMU_CACHE))); - flush_tlb_page(vma, address); - } - done: - __restore_flags(flags); - } -} - /* Init various srmmu chip types. */ static void __init srmmu_is_bad(void) { @@ -1389,7 +1319,6 @@ static void __init init_vac_layout(void) } vac_cache_size = cache_lines * vac_line_size; - vac_badbits = (vac_cache_size - 1) & PAGE_MASK; #ifdef CONFIG_SMP if(vac_cache_size > max_size) max_size = vac_cache_size; @@ -1410,7 +1339,6 @@ static void __init init_vac_layout(void) #ifdef CONFIG_SMP vac_cache_size = max_size; vac_line_size = min_line_size; - vac_badbits = (vac_cache_size - 1) & PAGE_MASK; #endif printk("SRMMU: Using VAC size of %d bytes, line size %d bytes.\n", (int)vac_cache_size, (int)vac_line_size); @@ -1465,7 +1393,6 @@ static void __init init_hypersparc(void) BTFIXUPSET_CALL(flush_page_for_dma, hypersparc_flush_page_for_dma, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(update_mmu_cache, srmmu_vac_update_mmu_cache, BTFIXUPCALL_NORM); poke_srmmu = poke_hypersparc; hypersparc_setup_blockops(); @@ -1532,7 +1459,6 @@ static void __init init_cypress_common(void) BTFIXUPSET_CALL(flush_sig_insns, cypress_flush_sig_insns, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(flush_page_for_dma, cypress_flush_page_for_dma, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(update_mmu_cache, srmmu_vac_update_mmu_cache, BTFIXUPCALL_NORM); poke_srmmu = poke_cypress; } diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c index edba89672..1b32dd8ef 100644 --- a/arch/sparc/mm/sun4c.c +++ b/arch/sparc/mm/sun4c.c @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.201 2000/11/09 22:39:36 davem Exp $ +/* $Id: sun4c.c,v 1.202 2000/12/01 03:17:31 anton Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -2373,78 +2373,6 @@ static int sun4c_check_pgt_cache(int low, int high) return freed; } -/* There are really two cases of aliases to watch out for, and these - * are: - * - * 1) A user's page which can be aliased with the kernels virtual - * mapping of the physical page. - * - * 2) Multiple user mappings of the same inode/anonymous object - * such that two copies of the same data for the same phys page - * can live (writable) in the cache at the same time. - * - * We handle number 1 by flushing the kernel copy of the page always - * after COW page operations. - * - * NOTE: We are a bit slowed down now because the VMA arg is indeed used - * now, so our ref/mod bit tracking quick userfaults eat a few more - * cycles than they used to. - */ -static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long address, pte_t pte) -{ - pgd_t *pgdp; - pte_t *ptep; - - if (vma->vm_file) { - struct address_space *mapping; - unsigned long offset = (address & PAGE_MASK) - vma->vm_start; - struct vm_area_struct *vmaring; - int alias_found = 0; - - mapping = vma->vm_file->f_dentry->d_inode->i_mapping; - spin_lock(&mapping->i_shared_lock); - vmaring = mapping->i_mmap_shared; - if (vmaring != NULL) do { - unsigned long vaddr = vmaring->vm_start + offset; - unsigned long start; - - /* Do not mistake ourselves as another mapping. */ - if (vmaring == vma) - continue; - - if (S4CVAC_BADALIAS(vaddr, address)) { - alias_found++; - start = vmaring->vm_start; - while (start < vmaring->vm_end) { - pgdp = sun4c_pgd_offset(vmaring->vm_mm, start); - if (!pgdp) - goto next; - ptep = sun4c_pte_offset((pmd_t *) pgdp, start); - if (!ptep) - goto next; - - if (pte_val(*ptep) & _SUN4C_PAGE_PRESENT) { - flush_cache_page(vmaring, start); - *ptep = __pte(pte_val(*ptep) | - _SUN4C_PAGE_NOCACHE); - flush_tlb_page(vmaring, start); - } - next: - start += PAGE_SIZE; - } - } - } while ((vmaring = vmaring->vm_next_share) != NULL); - spin_unlock(&mapping->i_shared_lock); - - if (alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) { - pgdp = sun4c_pgd_offset(vma->vm_mm, address); - ptep = sun4c_pte_offset((pmd_t *) pgdp, address); - *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_NOCACHE); - pte = *ptep; - } - } -} - /* An experiment, turn off by default for now... -DaveM */ #define SUN4C_PRELOAD_PSEG @@ -2486,8 +2414,6 @@ void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, p #endif start += PAGE_SIZE; } - if ((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) - sun4c_vac_alias_fixup(vma, address, pte); #ifndef SUN4C_PRELOAD_PSEG sun4c_put_pte(address, pte_val(pte)); #endif @@ -2500,9 +2426,6 @@ void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, p add_lru(entry); } - if ((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) - sun4c_vac_alias_fixup(vma, address, pte); - sun4c_put_pte(address, pte_val(pte)); restore_flags(flags); } diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index e1ae982bf..a0311626e 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.98 2000/11/13 10:03:32 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.99 2000/12/09 04:15:24 anton Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -179,6 +179,7 @@ EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(__flushw_user); +EXPORT_SYMBOL(flush_icache_range); EXPORT_SYMBOL(__flush_dcache_page); EXPORT_SYMBOL(mstk48t02_regs); diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index 235d34889..391979c87 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.46 2000/08/29 07:01:54 davem Exp $ +/* $Id: sys_sparc.c,v 1.47 2000/11/29 05:56:12 anton Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -40,6 +40,8 @@ asmlinkage unsigned long sys_getpagesize(void) return PAGE_SIZE; } +#define COLOUR_ALIGN(addr) (((addr)+SHMLBA-1)&~(SHMLBA-1)) + unsigned long get_unmapped_area(unsigned long addr, unsigned long len) { struct vm_area_struct * vmm; @@ -51,7 +53,11 @@ unsigned long get_unmapped_area(unsigned long addr, unsigned long len) return 0; if (!addr) addr = TASK_UNMAPPED_BASE; - addr = PAGE_ALIGN(addr); + + if (current->thread.flags & SPARC_FLAG_MMAPSHARED) + addr = COLOUR_ALIGN(addr); + else + addr = PAGE_ALIGN(addr); task_size -= len; @@ -66,6 +72,8 @@ unsigned long get_unmapped_area(unsigned long addr, unsigned long len) if (!vmm || addr + len <= vmm->vm_start) return addr; addr = vmm->vm_end; + if (current->thread.flags & SPARC_FLAG_MMAPSHARED) + addr = COLOUR_ALIGN(addr); } } @@ -232,10 +240,15 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, goto out_putf; } + if (flags & MAP_SHARED) + current->thread.flags |= SPARC_FLAG_MMAPSHARED; + down(¤t->mm->mmap_sem); retval = do_mmap(file, addr, len, prot, flags, off); up(¤t->mm->mmap_sem); + current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); + out_putf: if (file) fput(file); @@ -264,6 +277,7 @@ asmlinkage unsigned long sys64_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr) { + struct vm_area_struct *vma; unsigned long ret = -EINVAL; if (current->thread.flags & SPARC_FLAG_32BIT) goto out; @@ -272,6 +286,9 @@ asmlinkage unsigned long sys64_mremap(unsigned long addr, if (addr < PAGE_OFFSET && addr + old_len > -PAGE_OFFSET) goto out; down(¤t->mm->mmap_sem); + vma = find_vma(current->mm, addr); + if (vma && (vma->vm_flags & VM_SHARED)) + current->thread.flags |= SPARC_FLAG_MMAPSHARED; if (flags & MREMAP_FIXED) { if (new_addr < PAGE_OFFSET && new_addr + new_len > -PAGE_OFFSET) @@ -280,13 +297,14 @@ asmlinkage unsigned long sys64_mremap(unsigned long addr, ret = -ENOMEM; if (!(flags & MREMAP_MAYMOVE)) goto out_sem; - new_addr = get_unmapped_area (addr, new_len); + new_addr = get_unmapped_area(addr, new_len); if (!new_addr) goto out_sem; flags |= MREMAP_FIXED; } ret = do_mremap(addr, old_len, new_len, flags, new_addr); out_sem: + current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); up(¤t->mm->mmap_sem); out: return ret; diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 9b211d86d..0964409c9 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.166 2000/11/10 04:49:56 davem Exp $ +/* $Id: sys_sparc32.c,v 1.168 2000/12/11 18:59:35 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -2966,6 +2966,7 @@ static int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm) err = copy_from_user(kaddr + offset, (char *)A(str), bytes_to_copy); + flush_dcache_page(page); flush_page_to_ram(page); kunmap(page); @@ -4133,6 +4134,7 @@ asmlinkage unsigned long sys32_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, u32 __new_addr) { + struct vm_area_struct *vma; unsigned long ret = -EINVAL; unsigned long new_addr = AA(__new_addr); @@ -4141,6 +4143,9 @@ asmlinkage unsigned long sys32_mremap(unsigned long addr, if (addr > 0xf0000000UL - old_len) goto out; down(¤t->mm->mmap_sem); + vma = find_vma(current->mm, addr); + if (vma && (vma->vm_flags & VM_SHARED)) + current->thread.flags |= SPARC_FLAG_MMAPSHARED; if (flags & MREMAP_FIXED) { if (new_addr > 0xf0000000UL - new_len) goto out_sem; @@ -4148,13 +4153,14 @@ asmlinkage unsigned long sys32_mremap(unsigned long addr, ret = -ENOMEM; if (!(flags & MREMAP_MAYMOVE)) goto out_sem; - new_addr = get_unmapped_area (addr, new_len); + new_addr = get_unmapped_area(addr, new_len); if (!new_addr) goto out_sem; flags |= MREMAP_FIXED; } ret = do_mremap(addr, old_len, new_len, flags, new_addr); out_sem: + current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); up(¤t->mm->mmap_sem); out: return ret; diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c index a5f5411f5..a9d143759 100644 --- a/arch/sparc64/kernel/sys_sunos32.c +++ b/arch/sparc64/kernel/sys_sunos32.c @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.54 2000/08/12 13:25:41 davem Exp $ +/* $Id: sys_sunos32.c,v 1.55 2000/11/18 02:10:59 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index de4968ac4..2562df1f3 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.67 2000/07/30 23:12:24 davem Exp $ +/* $Id: traps.c,v 1.68 2000/11/22 06:50:37 davem Exp $ * arch/sparc64/kernel/traps.c * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -551,7 +551,7 @@ void do_fpe_common(struct pt_regs *regs) else if (fsr & 0x01) info.si_code = FPE_FLTRES; } - send_sig_info(SIGFPE, &info, current); + force_sig_info(SIGFPE, &info, current); } } @@ -594,7 +594,7 @@ void do_tof(struct pt_regs *regs) info.si_code = EMT_TAGOVF; info.si_addr = (void *)regs->tpc; info.si_trapno = 0; - send_sig_info(SIGEMT, &info, current); + force_sig_info(SIGEMT, &info, current); } void do_div0(struct pt_regs *regs) @@ -606,7 +606,7 @@ void do_div0(struct pt_regs *regs) info.si_code = FPE_INTDIV; info.si_addr = (void *)regs->tpc; info.si_trapno = 0; - send_sig_info(SIGFPE, &info, current); + force_sig_info(SIGFPE, &info, current); } void instruction_dump (unsigned int *pc) @@ -715,7 +715,7 @@ void do_illegal_instruction(struct pt_regs *regs) info.si_code = ILL_ILLOPC; info.si_addr = (void *)pc; info.si_trapno = 0; - send_sig_info(SIGILL, &info, current); + force_sig_info(SIGILL, &info, current); } void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr) @@ -734,7 +734,7 @@ void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned lo info.si_code = BUS_ADRALN; info.si_addr = (void *)sfar; info.si_trapno = 0; - send_sig_info(SIGBUS, &info, current); + force_sig_info(SIGBUS, &info, current); } void do_privop(struct pt_regs *regs) @@ -746,7 +746,7 @@ void do_privop(struct pt_regs *regs) info.si_code = ILL_PRVOPC; info.si_addr = (void *)regs->tpc; info.si_trapno = 0; - send_sig_info(SIGILL, &info, current); + force_sig_info(SIGILL, &info, current); } void do_privact(struct pt_regs *regs) diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 6da2d0b85..289092756 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.159 2000/11/06 06:59:04 davem Exp $ +/* $Id: init.c,v 1.161 2000/12/09 20:16:58 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -113,6 +113,17 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t p __update_mmu_cache(vma, address, pte); } +/* In arch/sparc64/mm/ultra.S */ +extern void __flush_icache_page(unsigned long); + +void flush_icache_range(unsigned long start, unsigned long end) +{ + unsigned long kaddr; + + for (kaddr = start; kaddr < end; kaddr += PAGE_SIZE) + __flush_icache_page(__get_phys(kaddr)); +} + /* * BAD_PAGE is the page that is used for page faults when linux * is out-of-memory. Older versions of linux just did a diff --git a/arch/sparc64/solaris/ioctl.c b/arch/sparc64/solaris/ioctl.c index 4a10c1b4c..72c8f3405 100644 --- a/arch/sparc64/solaris/ioctl.c +++ b/arch/sparc64/solaris/ioctl.c @@ -1,4 +1,4 @@ -/* $Id: ioctl.c,v 1.15 2000/07/28 12:15:02 davem Exp $ +/* $Id: ioctl.c,v 1.16 2000/11/18 02:10:59 davem Exp $ * ioctl.c: Solaris ioctl emulation. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) diff --git a/arch/sparc64/solaris/socket.c b/arch/sparc64/solaris/socket.c index 9b910a633..e016e4b1a 100644 --- a/arch/sparc64/solaris/socket.c +++ b/arch/sparc64/solaris/socket.c @@ -1,4 +1,4 @@ -/* $Id: socket.c,v 1.3 2000/08/14 23:50:31 anton Exp $ +/* $Id: socket.c,v 1.4 2000/11/18 02:11:00 davem Exp $ * socket.c: Socket syscall emulation for Solaris 2.6+ * * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) |