diff -u --recursive --new-file v2.1.88/linux/CREDITS linux/CREDITS --- v2.1.88/linux/CREDITS Mon Feb 23 18:12:01 1998 +++ linux/CREDITS Mon Feb 23 10:25:10 1998 @@ -1841,10 +1841,12 @@ S: The Netherlands N: David Woodhouse -E: dwmw2@cam.ac.uk +E: Dave@imladris.demon.co.uk D: Extensive ARCnet rewrite D: ARCnet COM20020, COM90xx IO-MAP drivers D: SO_BINDTODEVICE in 2.1.x (from Elliot Poger's code in 2.0.31) +D: Contributed to NCPFS rewrite for 2.1.x dcache +D: Alpha platforms: SX164, LX164 and Ruffian ported to 2.1.x S: Robinson College, Grange Road S: Cambridge. CB3 9AN S: England diff -u --recursive --new-file v2.1.88/linux/Makefile linux/Makefile --- v2.1.88/linux/Makefile Mon Feb 23 18:12:01 1998 +++ linux/Makefile Mon Feb 23 18:10:59 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 88 +SUBLEVEL = 89 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) diff -u --recursive --new-file v2.1.88/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.1.88/linux/arch/alpha/config.in Tue Feb 17 13:12:44 1998 +++ linux/arch/alpha/config.in Mon Feb 23 10:25:10 1998 @@ -46,6 +46,8 @@ EB64+ CONFIG_ALPHA_EB64P \ EB164 CONFIG_ALPHA_EB164 \ PC164 CONFIG_ALPHA_PC164 \ + LX164 CONFIG_ALPHA_LX164 \ + SX164 CONFIG_ALPHA_SX164 \ Jensen CONFIG_ALPHA_JENSEN \ Noname CONFIG_ALPHA_NONAME \ Mikasa CONFIG_ALPHA_MIKASA \ @@ -54,6 +56,7 @@ Miata CONFIG_ALPHA_MIATA \ Sable CONFIG_ALPHA_SABLE \ AlphaBook1 CONFIG_ALPHA_BOOK1 \ + Ruffian CONFIG_ALPHA_RUFFIAN \ Platform2000 CONFIG_ALPHA_P2K" Cabriolet if [ "$CONFIG_ALPHA_BOOK1" = "y" ] @@ -102,7 +105,8 @@ define_bool CONFIG_ALPHA_EV4 y define_bool CONFIG_ALPHA_T2 y fi -if [ "$CONFIG_ALPHA_MIATA" = "y" ] +if [ "$CONFIG_ALPHA_MIATA" = "y" -o "$CONFIG_ALPHA_LX164" = "y" \ + -o "$CONFIG_ALPHA_SX164" = "y" -o "$CONFIG_ALPHA_RUFFIAN" = "y" ] then define_bool CONFIG_PCI y define_bool CONFIG_ALPHA_EV5 y @@ -122,7 +126,8 @@ -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \ -o "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_ALCOR" = "y" \ -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_MIATA" = "y" \ - -o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" ] + -o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \ + -o "$CONFIG_ALPHA_LX164" = "y" -o "$CONFIG_ALPHA_SX164" = "y" ] then bool 'Using SRM as bootloader' CONFIG_ALPHA_SRM fi diff -u --recursive --new-file v2.1.88/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile --- v2.1.88/linux/arch/alpha/kernel/Makefile Tue Feb 17 13:12:44 1998 +++ linux/arch/alpha/kernel/Makefile Mon Feb 23 10:25:10 1998 @@ -35,6 +35,13 @@ ifdef CONFIG_ALPHA_T2 O_OBJS += t2.o endif +ifneq ($(CONFIG_ALPHA_PC164)$(CONFIG_ALPHA_LX164),nn) +O_OBJS += smc37c93x.o +endif +ifdef CONFIG_ALPHA_SX164 +O_OBJS += smc37c669.o +endif + all: kernel.o head.o diff -u --recursive --new-file v2.1.88/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c --- v2.1.88/linux/arch/alpha/kernel/bios32.c Mon Jan 12 14:51:14 1998 +++ linux/arch/alpha/kernel/bios32.c Mon Feb 23 10:25:10 1998 @@ -27,6 +27,8 @@ #include #include #include +#include +#include #if 0 # define DBG_DEVS(args) printk args @@ -98,8 +100,11 @@ extern struct hwrpb_struct *hwrpb; /* Forward declarations for some extra fixup routines for specific hardware. */ -#ifdef CONFIG_ALPHA_PC164 -static int SMCInit(void); +#if defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164) +extern int SMC93x_Init(void); +#endif +#ifdef CONFIG_ALPHA_SX164 +extern int SMC669_Init(void); #endif #ifdef CONFIG_ALPHA_MIATA static int es1888_init(void); @@ -174,16 +179,25 @@ struct pci_bus *bus; unsigned short cmd; -#if defined(CONFIG_ALPHA_EISA) +#ifdef CONFIG_ALPHA_EISA /* * HACK: the PCI-to-EISA bridge does not seem to identify * itself as a bridge... :-( */ - if (dev->vendor == 0x8086 && dev->device == 0x0482) { + if (dev->vendor == PCI_VENDOR_ID_INTEL && + dev->device == PCI_DEVICE_ID_INTEL_82375) { DBG_DEVS(("disable_dev: ignoring PCEB...\n")); return; } #endif +#ifdef CONFIG_ALPHA_SX164 + if (dev->vendor == PCI_VENDOR_ID_CONTAQ && + /* FIXME: We want a symbolic device name here. */ + dev->device == 0xc693) { + DBG_DEVS(("disable_dev: ignoring CYPRESS bridge...\n")); + return; + } +#endif bus = dev->bus; pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); @@ -206,6 +220,7 @@ unsigned int base, mask, size, reg; unsigned int alignto; +#ifdef CONFIG_ALPHA_EISA /* * HACK: the PCI-to-EISA bridge does not seem to identify * itself as a bridge... :-( @@ -215,6 +230,14 @@ DBG_DEVS(("layout_dev: ignoring PCEB...\n")); return; } +#endif +#ifdef CONFIG_ALPHA_SX164 + if (dev->vendor == PCI_VENDOR_ID_CONTAQ && + dev->device == 0xc693) { + DBG_DEVS(("layout_dev: ignoring CYPRESS bridge...\n")); + return; + } +#endif bus = dev->bus; pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); @@ -729,6 +752,46 @@ 0x0000000); } } +#ifdef CONFIG_ALPHA_SX164 + /* If it the CYPRESS PCI-ISA bridge, disable IDE + interrupt routing through PCI (ie do through PIC). */ + else if (dev->vendor == PCI_VENDOR_ID_CONTAQ && + dev->device == 0xc693 && + PCI_FUNC(dev->devfn) == 0) { + pcibios_write_config_word(dev->bus->number, + dev->devfn, 0x04, 0x0007); + + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x40, 0x80); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x41, 0x80); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x42, 0x80); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x43, 0x80); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x44, 0x27); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x45, 0xe0); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x48, 0xf0); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x49, 0x40); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x4a, 0x00); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x4b, 0x80); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x4c, 0x80); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x4d, 0x70); + + outb(0, DMA1_RESET_REG); + outb(0, DMA2_RESET_REG); + outb(DMA_MODE_CASCADE, DMA2_MODE_REG); + outb(0, DMA2_MASK_REG); + } +#endif /* SX164 */ } if (ide_base) { enable_ide(ide_base); @@ -750,7 +813,7 @@ */ static inline void eb66p_fixup(void) { - static char irq_tab[5][5] = { + static char irq_tab[5][5] __initdata = { {16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J25 */ {16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J26 */ { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ @@ -762,7 +825,7 @@ /* - * The PC164 has 19 PCI interrupts, four from each of the four PCI + * The PC164/LX164 has 19 PCI interrupts, four from each of the four PCI * slots, the SIO, PCI/IDE, and USB. * * Each of the interrupts can be individually masked. This is @@ -803,10 +866,10 @@ * */ -#ifdef CONFIG_ALPHA_PC164 +#if defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164) static inline void alphapc164_fixup(void) { - static char irq_tab[7][5] = { + static char irq_tab[7][5] __initdata = { /*INT INTA INTB INTC INTD */ { 16+2, 16+2, 16+9, 16+13, 16+17}, /* IdSel 5, slot 2, J20 */ { 16+0, 16+0, 16+7, 16+11, 16+15}, /* IdSel 6, slot 0, J29 */ @@ -818,7 +881,7 @@ }; common_fixup(5, 11, 5, irq_tab, 0); - SMCInit(); + SMC93x_Init(); } #endif @@ -837,7 +900,7 @@ */ static inline void cabriolet_fixup(void) { - static char irq_tab[5][5] = { + static char irq_tab[5][5] __initdata = { { 16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 5, slot 2, J21 */ { 16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J19 */ { 16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J20 */ @@ -893,7 +956,7 @@ */ static inline void eb66_and_eb64p_fixup(void) { - static char irq_tab[5][5] = { + static char irq_tab[5][5] __initdata = { {16+7, 16+7, 16+7, 16+7, 16+7}, /* IdSel 5, slot ?, ?? */ {16+0, 16+0, 16+2, 16+4, 16+9}, /* IdSel 6, slot ?, ?? */ {16+1, 16+1, 16+3, 16+8, 16+10}, /* IdSel 7, slot ?, ?? */ @@ -942,7 +1005,7 @@ */ static inline void mikasa_fixup(void) { - static char irq_tab[8][5] = { + static char irq_tab[8][5] __initdata = { /*INT INTA INTB INTC INTD */ {16+12, 16+12, 16+12, 16+12, 16+12}, /* IdSel 17, SCSI */ { -1, -1, -1, -1, -1}, /* IdSel 18, PCEB */ @@ -1013,7 +1076,7 @@ */ static inline void noritake_fixup(void) { - static char irq_tab[13][5] = { + static char irq_tab[13][5] __initdata = { /*INT INTA INTB INTC INTD */ { -1, -1, -1, -1, -1}, /* IdSel 18, PCEB */ { -1, -1, -1, -1, -1}, /* IdSel 19, PPB */ @@ -1077,7 +1140,7 @@ */ static inline void alcor_fixup(void) { - static char irq_tab[6][5] = { + static char irq_tab[6][5] __initdata = { /*INT INTA INTB INTC INTD */ { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 18, slot 0 */ {16+16, 16+16, 16+17, 16+18, 16+19}, /* IdSel 19, slot 3 */ @@ -1132,7 +1195,7 @@ */ static inline void xlt_fixup(void) { - static char irq_tab[7][5] = { + static char irq_tab[7][5] __initdata = { /*INT INTA INTB INTC INTD */ {16+13, 16+13, 16+13, 16+13, 16+13}, /* IdSel 17, TULIP */ { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 18, slot 0 */ @@ -1194,13 +1257,16 @@ * above for PCI interrupts. The IRQ relates to which bit the interrupt * comes in on. This makes interrupt processing much easier. */ -/* NOTE: the IRQ assignments below are arbitrary, but need to be consistent - with the values in the sable_irq_to_mask[] and sable_mask_to_irq[] tables - in irq.c +/* + * NOTE: the IRQ assignments below are arbitrary, but need to be consistent + * with the values in the sable_irq_to_mask[] and sable_mask_to_irq[] tables + * in irq.c */ + +#ifdef CONFIG_ALPHA_SABLE static inline void sable_fixup(void) { - static char irq_tab[9][5] = { + static char irq_tab[9][5] __initdata = { /*INT INTA INTB INTC INTD */ { 32+0, 32+0, 32+0, 32+0, 32+0}, /* IdSel 0, TULIP */ { 32+1, 32+1, 32+1, 32+1, 32+1}, /* IdSel 1, SCSI */ @@ -1214,6 +1280,7 @@ }; common_fixup(0, 8, 5, irq_tab, 0); } +#endif /* * Fixup configuration for MIATA (EV56+PYXIS) @@ -1282,7 +1349,7 @@ #ifdef CONFIG_ALPHA_MIATA static inline void miata_fixup(void) { - static char irq_tab[18][5] = { + static char irq_tab[18][5] __initdata = { /*INT INTA INTB INTC INTD */ {16+ 8, 16+ 8, 16+ 8, 16+ 8, 16+ 8}, /* IdSel 14, DC21142 */ { -1, -1, -1, -1, -1}, /* IdSel 15, EIDE */ @@ -1311,6 +1378,64 @@ #endif /* + * Fixup configuration for SX164 (PCA56+PYXIS) + * + * Summary @ PYXIS_INT_REQ: + * Bit Meaning + * 0 RSVD + * 1 NMI + * 2 Halt/Reset switch + * 3 MBZ + * 4 RAZ + * 5 RAZ + * 6 Interval timer (RTC) + * 7 PCI-ISA Bridge + * 8 Interrupt Line A from slot 3 + * 9 Interrupt Line A from slot 2 + *10 Interrupt Line A from slot 1 + *11 Interrupt Line A from slot 0 + *12 Interrupt Line B from slot 3 + *13 Interrupt Line B from slot 2 + *14 Interrupt Line B from slot 1 + *15 Interrupt line B from slot 0 + *16 Interrupt Line C from slot 3 + + *17 Interrupt Line C from slot 2 + *18 Interrupt Line C from slot 1 + *19 Interrupt Line C from slot 0 + *20 Interrupt Line D from slot 3 + *21 Interrupt Line D from slot 2 + *22 Interrupt Line D from slot 1 + *23 Interrupt Line D from slot 0 + * + * IdSel + * 5 32 bit PCI option slot 2 + * 6 64 bit PCI option slot 0 + * 7 64 bit PCI option slot 1 + * 8 Cypress I/O + * 9 32 bit PCI option slot 3 + * + */ + +#ifdef CONFIG_ALPHA_SX164 +static inline void sx164_fixup(void) +{ + static char irq_tab[5][5] __initdata = { + /*INT INTA INTB INTC INTD */ + { 16+ 9, 16+ 9, 16+13, 16+17, 16+21}, /* IdSel 5 slot 2 J17 */ + { 16+11, 16+11, 16+15, 16+19, 16+23}, /* IdSel 6 slot 0 J19 */ + { 16+10, 16+10, 16+14, 16+18, 16+22}, /* IdSel 7 slot 1 J18 */ + { -1, -1, -1, -1, -1}, /* IdSel 8 SIO */ + { 16+ 8, 16+ 8, 16+12, 16+16, 16+20} /* IdSel 9 slot 3 J15 */ + }; + + common_fixup(5, 9, 5, irq_tab, 0); + + SMC669_Init(); +} +#endif + +/* * Fixup configuration for all boards that route the PCI interrupts * through the SIO PCI/ISA bridge. This includes Noname (AXPpci33), * Avanti (AlphaStation) and Kenetics's Platform 2000. @@ -1336,7 +1461,7 @@ * that they use the default INTA line, if they are interrupt * driven at all). */ - static const char pirq_tab[][5] = { + static const char pirq_tab[][5] __initdata = { #ifdef CONFIG_ALPHA_P2K { 0, 0, -1, -1, -1}, /* idsel 6 (53c810) */ {-1, -1, -1, -1, -1}, /* idsel 7 (SIO: PCI/ISA bridge) */ @@ -1560,9 +1685,10 @@ extern void tga_console_init(void); #endif /* CONFIG_TGA_CONSOLE */ -unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end) +unsigned long __init +pcibios_fixup(unsigned long mem_start, unsigned long mem_end) { -#if PCI_MODIFY +#if PCI_MODIFY && !defined(CONFIG_ALPHA_RUFFIAN) /* * Scan the tree, allocating PCI memory and I/O space. */ @@ -1577,7 +1703,7 @@ sio_fixup(); #elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB164) cabriolet_fixup(); -#elif defined(CONFIG_ALPHA_PC164) +#elif defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164) alphapc164_fixup(); #elif defined(CONFIG_ALPHA_EB66P) eb66p_fixup(); @@ -1597,6 +1723,10 @@ miata_fixup(); #elif defined(CONFIG_ALPHA_NORITAKE) noritake_fixup(); +#elif defined(CONFIG_ALPHA_SX164) + sx164_fixup(); +#elif defined(CONFIG_ALPHA_RUFFIAN) + /* no fixup needed */ #else # error "You must tell me what kind of platform you want." #endif @@ -1702,251 +1832,12 @@ } -#ifdef CONFIG_ALPHA_PC164 -/* device "activate" register contents */ -#define DEVICE_ON 1 -#define DEVICE_OFF 0 - -/* configuration on/off keys */ -#define CONFIG_ON_KEY 0x55 -#define CONFIG_OFF_KEY 0xaa - -/* configuration space device definitions */ -#define FDC 0 -#define IDE1 1 -#define IDE2 2 -#define PARP 3 -#define SER1 4 -#define SER2 5 -#define RTCL 6 -#define KYBD 7 -#define AUXIO 8 - -/* Chip register offsets from base */ -#define CONFIG_CONTROL 0x02 -#define INDEX_ADDRESS 0x03 -#define LOGICAL_DEVICE_NUMBER 0x07 -#define DEVICE_ID 0x20 -#define DEVICE_REV 0x21 -#define POWER_CONTROL 0x22 -#define POWER_MGMT 0x23 -#define OSC 0x24 - -#define ACTIVATE 0x30 -#define ADDR_HI 0x60 -#define ADDR_LO 0x61 -#define INTERRUPT_SEL 0x70 -#define INTERRUPT_SEL_2 0x72 /* KYBD/MOUS only */ -#define DMA_CHANNEL_SEL 0x74 /* FDC/PARP only */ - -#define FDD_MODE_REGISTER 0x90 -#define FDD_OPTION_REGISTER 0x91 - -/* values that we read back that are expected ... */ -#define VALID_DEVICE_ID 2 - -/* default device addresses */ -#define KYBD_INTERRUPT 1 -#define MOUS_INTERRUPT 12 -#define COM2_BASE 0x2f8 -#define COM2_INTERRUPT 3 -#define COM1_BASE 0x3f8 -#define COM1_INTERRUPT 4 -#define PARP_BASE 0x3bc -#define PARP_INTERRUPT 7 - -#define SMC_DEBUG 0 - -static unsigned long SMCConfigState(unsigned long baseAddr) -{ - unsigned char devId; - unsigned char devRev; - - unsigned long configPort; - unsigned long indexPort; - unsigned long dataPort; - - configPort = indexPort = baseAddr; - dataPort = configPort + 1; - - outb(CONFIG_ON_KEY, configPort); - outb(CONFIG_ON_KEY, configPort); - outb(DEVICE_ID, indexPort); - devId = inb(dataPort); - if ( devId == VALID_DEVICE_ID ) { - outb(DEVICE_REV, indexPort); - devRev = inb(dataPort); - } - else { - baseAddr = 0; - } - return baseAddr; -} - -static void SMCRunState(unsigned long baseAddr) -{ - outb(CONFIG_OFF_KEY, baseAddr); -} - -static unsigned long SMCDetectUltraIO(void) -{ - unsigned long baseAddr; - - baseAddr = 0x3F0; - if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x3F0 ) { - return( baseAddr ); - } - baseAddr = 0x370; - if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x370 ) { - return( baseAddr ); - } - return( ( unsigned long )0 ); -} - -static void SMCEnableDevice(unsigned long baseAddr, - unsigned long device, - unsigned long portaddr, - unsigned long interrupt) -{ - unsigned long indexPort; - unsigned long dataPort; - - indexPort = baseAddr; - dataPort = baseAddr + 1; - - outb(LOGICAL_DEVICE_NUMBER, indexPort); - outb(device, dataPort); - - outb(ADDR_LO, indexPort); - outb(( portaddr & 0xFF ), dataPort); - - outb(ADDR_HI, indexPort); - outb((portaddr >> 8) & 0xFF, dataPort); - - outb(INTERRUPT_SEL, indexPort); - outb(interrupt, dataPort); - - outb(ACTIVATE, indexPort); - outb(DEVICE_ON, dataPort); -} - -static void SMCEnableKYBD(unsigned long baseAddr) -{ - unsigned long indexPort; - unsigned long dataPort; - - indexPort = baseAddr; - dataPort = baseAddr + 1; - - outb(LOGICAL_DEVICE_NUMBER, indexPort); - outb(KYBD, dataPort); - - outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */ - outb(KYBD_INTERRUPT, dataPort); - - outb(INTERRUPT_SEL_2, indexPort); /* Secondary interrupt select */ - outb(MOUS_INTERRUPT, dataPort); - - outb(ACTIVATE, indexPort); - outb(DEVICE_ON, dataPort); -} - -static void SMCEnableFDC(unsigned long baseAddr) -{ - unsigned long indexPort; - unsigned long dataPort; - - unsigned char oldValue; - - indexPort = baseAddr; - dataPort = baseAddr + 1; - - outb(LOGICAL_DEVICE_NUMBER, indexPort); - outb(FDC, dataPort); - - outb(FDD_MODE_REGISTER, indexPort); - oldValue = inb(dataPort); - - oldValue |= 0x0E; /* Enable burst mode */ - outb(oldValue, dataPort); - - outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */ - outb(0x06, dataPort ); - - outb(DMA_CHANNEL_SEL, indexPort); /* DMA channel select */ - outb(0x02, dataPort); - - outb(ACTIVATE, indexPort); - outb(DEVICE_ON, dataPort); -} - -#if SMC_DEBUG -static void SMCReportDeviceStatus(unsigned long baseAddr) -{ - unsigned long indexPort; - unsigned long dataPort; - unsigned char currentControl; - - indexPort = baseAddr; - dataPort = baseAddr + 1; - - outb(POWER_CONTROL, indexPort); - currentControl = inb(dataPort); - - printk(currentControl & (1 << FDC) - ? "\t+FDC Enabled\n" : "\t-FDC Disabled\n"); - printk(currentControl & (1 << IDE1) - ? "\t+IDE1 Enabled\n" : "\t-IDE1 Disabled\n"); - printk(currentControl & (1 << IDE2) - ? "\t+IDE2 Enabled\n" : "\t-IDE2 Disabled\n"); - printk(currentControl & (1 << PARP) - ? "\t+PARP Enabled\n" : "\t-PARP Disabled\n"); - printk(currentControl & (1 << SER1) - ? "\t+SER1 Enabled\n" : "\t-SER1 Disabled\n"); - printk(currentControl & (1 << SER2) - ? "\t+SER2 Enabled\n" : "\t-SER2 Disabled\n"); - - printk( "\n" ); -} -#endif - -static int SMCInit(void) -{ - unsigned long SMCUltraBase; - - if ((SMCUltraBase = SMCDetectUltraIO()) != 0UL) { - printk("SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n", - SMCUltraBase); -#if SMC_DEBUG - SMCReportDeviceStatus(SMCUltraBase); -#endif - SMCEnableDevice(SMCUltraBase, SER1, COM1_BASE, COM1_INTERRUPT); - SMCEnableDevice(SMCUltraBase, SER2, COM2_BASE, COM2_INTERRUPT); - SMCEnableDevice(SMCUltraBase, PARP, PARP_BASE, PARP_INTERRUPT); - /* On PC164, IDE on the SMC is not enabled; - CMD646 (PCI) on MB */ - SMCEnableKYBD(SMCUltraBase); - SMCEnableFDC(SMCUltraBase); -#if SMC_DEBUG - SMCReportDeviceStatus(SMCUltraBase); -#endif - SMCRunState(SMCUltraBase); - return 1; - } - else { -#if SMC_DEBUG - printk("No SMC FDC37C93X Ultra I/O Controller found\n"); -#endif - return 0; - } -} -#endif /* CONFIG_ALPHA_PC164 */ - #ifdef CONFIG_ALPHA_MIATA /* * Init the built-in ES1888 sound chip (SB16 compatible) */ -static int es1888_init(void) +static int __init +es1888_init(void) { /* Sequence of IO reads to init the audio controller */ inb(0x0229); diff -u --recursive --new-file v2.1.88/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v2.1.88/linux/arch/alpha/kernel/irq.c Mon Feb 23 18:12:01 1998 +++ linux/arch/alpha/kernel/irq.c Mon Feb 23 10:25:10 1998 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,9 @@ #elif defined(CONFIG_ALPHA_ALCOR) /* always mask out unused timer irq 0, "irqs" 20-30, and the EISA cascade: */ # define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~0xfff000000001UL) +#elif defined(CONFIG_ALPHA_RUFFIAN) + /* must leave timer irq 0 in the mask */ +# define PROBE_MASK ((1UL << NR_IRQS) - 1) #else /* always mask out unused timer irq 0: */ # define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~1UL) @@ -210,6 +214,53 @@ } } +#ifdef CONFIG_ALPHA_RUFFIAN +static inline void +ruffian_update_hw(unsigned long irq, unsigned long mask) +{ + switch (irq) { + case 16 ... 47: + /* Note inverted sense of mask bits: */ + /* Make CERTAIN none of the bogus ints get enabled... */ + *(vulp)PYXIS_INT_MASK = + ~((long)mask >> 16) & 0x00000000ffffffbfUL; + mb(); + /* ... and read it back to make sure it got written. */ + *(vulp)PYXIS_INT_MASK; + break; + case 8 ... 15: /* ISA PIC2 */ + outb(mask >> 8, 0xA1); + break; + case 0 ... 7: /* ISA PIC1 */ + outb(mask, 0x21); + break; + } +} +#endif + +#ifdef CONFIG_ALPHA_SX164 +static inline void +sx164_update_hw(unsigned long irq, unsigned long mask) +{ + switch (irq) { + case 16 ... 39: + /* Make CERTAIN none of the bogus ints get enabled */ + *(vulp)PYXIS_INT_MASK = + ~((long)mask >> 16) & ~0x000000000000003bUL; + mb(); + /* ... and read it back to make sure it got written. */ + *(vulp)PYXIS_INT_MASK; + break; + case 8 ... 15: /* ISA PIC2 */ + outb(mask >> 8, 0xA1); + break; + case 0 ... 7: /* ISA PIC1 */ + outb(mask, 0x21); + break; + } +} +#endif + /* Unlabeled mechanisms based on the number of irqs. Someone should probably document and name these. */ @@ -262,7 +313,8 @@ } } -#if defined(CONFIG_ALPHA_PC164) && defined(CONFIG_ALPHA_SRM) +#if (defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)) \ + && defined(CONFIG_ALPHA_SRM) /* * On the pc164, we cannot take over the IRQs from the SRM, * so we call down to do our dirty work. Too bad the SRM @@ -313,6 +365,10 @@ alcor_and_xlt_update_hw(irq, mask); #elif defined(CONFIG_ALPHA_MIKASA) mikasa_update_hw(irq, mask); +#elif defined(CONFIG_ALPHA_SX164) + sx164_update_hw(irq, mask); +#elif defined(CONFIG_ALPHA_RUFFIAN) + ruffian_update_hw(irq, mask); #elif NR_IRQS == 33 update_hw_33(irq, mask); #elif NR_IRQS == 32 @@ -355,7 +411,7 @@ unmask_irq(IRQ_TO_MASK(irq_nr)); restore_flags(flags); } -#endif /* PC164 && SRM */ +#endif /* (PC164 || LX164) && SRM */ /* * Initial irq handlers. @@ -404,9 +460,23 @@ outb(0xE0 | 4, 0x534); /* slave 2 */ break; } -#else /* CONFIG_ALPHA_SABLE */ +#elif defined(CONFIG_ALPHA_RUFFIAN) if (irq < 16) { - /* ACK the interrupt making it the lowest priority */ + /* Ack PYXIS ISA interrupt. */ + *(vulp)PYXIS_INT_REQ = 1 << 7; + mb(); + if (irq > 7) { + outb(0x20, 0xa0); + } + outb(0x20, 0x20); + } else { + /* Ack PYXIS interrupt. */ + *(vulp)PYXIS_INT_REQ = (1UL << (irq - 16)); + mb(); + } +#else + if (irq < 16) { + /* Ack the interrupt making it the lowest priority */ /* First the slave .. */ if (irq > 7) { outb(0xE0 | (irq - 8), 0xa0); @@ -418,9 +488,9 @@ /* on ALCOR/XLT, need to dismiss interrupt via GRU */ *(vuip)GRU_INT_CLEAR = 0x80000000; mb(); *(vuip)GRU_INT_CLEAR = 0x00000000; mb(); -#endif /* ALCOR || XLT */ +#endif } -#endif /* CONFIG_ALPHA_SABLE */ +#endif } int check_irq(unsigned int irq) @@ -830,7 +900,7 @@ restore_flags(flags); } -#if defined(CONFIG_ALPHA_MIATA) +#if defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_SX164) /* We have to conditionally compile this because of PYXIS_xxx symbols */ static inline void miata_device_interrupt(unsigned long vector, struct pt_regs *regs) @@ -850,15 +920,19 @@ *(vulp)PYXIS_INT_MASK, inb(0x20) | (inb(0xA0) << 8)); #endif -#if 1 - /* - * For now, AND off any bits we are not interested in: - * HALT (2), timer (6), ISA Bridge (7), 21142/3 (8) - * then all the PCI slots/INTXs (12-31). - */ + /* For now, AND off and bits we are not interested in. */ +#if defined(CONFIG_ALPHA_MIATA) + /* HALT (2), timer (6), ISA Bridge (7), 21142/3 (8), + then all the PCI slots/INTXs (12-31). */ /* Maybe HALT should only be used for SRM console boots? */ pld &= 0x00000000fffff1c4UL; #endif +#if defined(CONFIG_ALPHA_SX164) + /* HALT (2), timer (6), ISA Bridge (7), + then all the PCI slots/INTXs (8-23). */ + /* HALT should only be used for SRM console boots. */ + pld &= 0x0000000000ffffc0UL; +#endif /* * Now for every possible bit set, work through them and call @@ -879,7 +953,7 @@ } restore_flags(flags); } -#endif /* MIATA */ +#endif /* MIATA || SX164 */ static inline void noritake_device_interrupt(unsigned long vector, struct pt_regs *regs) @@ -917,6 +991,69 @@ restore_flags(flags); } +#if defined(CONFIG_ALPHA_RUFFIAN) +static inline void +ruffian_device_interrupt(unsigned long vector, struct pt_regs *regs) +{ + unsigned long pld; + unsigned int i; + unsigned long flags; + + save_flags(flags); + cli(); + + /* Read the interrupt summary register of PYXIS */ + pld = *(vulp)PYXIS_INT_REQ; + + /* For now, AND off any bits we are not interested in: + * HALT (2), timer (6), ISA Bridge (7), 21142 (8) + * then all the PCI slots/INTXs (12-31) + * flash(5) :DWH: + */ + pld &= 0x00000000ffffff9fUL; + + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + + if (i == 7) { + /* Copy this bit from isa_device_interrupt cause + we need to hook into int 0 for the timer. I + refuse to soil device_interrupt with ifdefs. */ + + /* Generate a PCI interrupt acknowledge cycle. + The PIC will respond with the interrupt + vector of the highest priority interrupt + that is pending. The PALcode sets up the + interrupts vectors such that irq level L + generates vector L. */ + + unsigned int j = *(vuip)PYXIS_IACK_SC & 0xff; + if (j == 7 && !(inb(0x20) & 0x80)) { + /* It's only a passive release... */ + } else if (j == 0) { + timer_interrupt(regs); + ack_irq(0); + } else { + device_interrupt(j, j, regs); + } + } else { + device_interrupt(16 + i, 16 + i, regs); + } + + *(vulp)PYXIS_INT_REQ = 1UL << i; + mb(); + *(vulp)PYXIS_INT_REQ; + } + + restore_flags(flags); +} +#endif /* RUFFIAN */ + #endif /* CONFIG_PCI */ /* @@ -1119,16 +1256,18 @@ #if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_ALPHA_NONAME) || \ defined(CONFIG_ALPHA_P2K) || defined(CONFIG_ALPHA_SRM) srm_device_interrupt(vector, ®s); -#elif defined(CONFIG_ALPHA_MIATA) +#elif defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_SX164) miata_device_interrupt(vector, ®s); #elif defined(CONFIG_ALPHA_NORITAKE) noritake_device_interrupt(vector, ®s); #elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) alcor_and_xlt_device_interrupt(vector, ®s); -#elif NR_IRQS == 33 - cabriolet_and_eb66p_device_interrupt(vector, ®s); +#elif defined(CONFIG_ALPHA_RUFFIAN) + ruffian_device_interrupt(vector, ®s); #elif defined(CONFIG_ALPHA_MIKASA) mikasa_device_interrupt(vector, ®s); +#elif NR_IRQS == 33 + cabriolet_and_eb66p_device_interrupt(vector, ®s); #elif NR_IRQS == 32 eb66_and_eb64p_device_interrupt(vector, ®s); #elif NR_IRQS == 16 @@ -1154,6 +1293,57 @@ outb(0x44, 0x535); /* enable cascades in master */ } +#ifdef CONFIG_ALPHA_SX164 +static inline void sx164_init_IRQ(void) +{ + /* note invert on MASK bits */ + *(vulp)PYXIS_INT_MASK = ~((long)irq_mask >> 16); mb(); +#if 0 + *(vulp)PYXIS_INT_HILO = 0x000000B2UL; mb(); /* ISA/NMI HI */ + *(vulp)PYXIS_RT_COUNT = 0UL; mb(); /* clear count */ +#endif + enable_irq(16 + 6); /* enable timer */ + enable_irq(16 + 7); /* enable ISA PIC cascade */ + enable_irq(2); /* enable cascade */ +} +#endif /* SX164 */ + +#ifdef CONFIG_ALPHA_RUFFIAN +static inline void ruffian_init_IRQ(void) +{ + /* invert 6&7 for i82371 */ + *(vulp)PYXIS_INT_HILO = 0x000000c0UL; mb(); + *(vulp)PYXIS_INT_CNFG = 0x00002064UL; mb(); /* all clear */ + *(vulp)PYXIS_INT_MASK = 0x00000000UL; mb(); + *(vulp)PYXIS_INT_REQ = 0xffffffffUL; mb(); + + outb(0x11,0xA0); + outb(0x08,0xA1); + outb(0x02,0xA1); + outb(0x01,0xA1); + outb(0xFF,0xA1); + + outb(0x11,0x20); + outb(0x00,0x21); + outb(0x04,0x21); + outb(0x01,0x21); + outb(0xFF,0x21); + + /* Send -INTA pulses to clear any pending interrupts ...*/ + *(vuip) IACK_SC; + + /* Finish writing the 82C59A PIC Operation Control Words */ + outb(0x20,0xA0); + outb(0x20,0x20); + + /* Turn on the interrupt controller, the timer interrupt */ + enable_irq(16 + 7); /* enable ISA PIC cascade */ + enable_irq(0); /* enable timer */ + enable_irq(2); /* enable 2nd PIC cascade */ +} +#endif /* RUFFIAN */ + + #ifdef CONFIG_ALPHA_MIATA static inline void miata_init_IRQ(void) { @@ -1219,27 +1409,36 @@ enable_irq(2); /* enable cascade */ } -void init_IRQ(void) +void __init +init_IRQ(void) { wrent(entInt, 0); dma_outb(0, DMA1_RESET_REG); dma_outb(0, DMA2_RESET_REG); +#ifndef CONFIG_ALPHA_SX164 dma_outb(0, DMA1_CLR_MASK_REG); + /* We need to figure out why this fails on the SX164. */ dma_outb(0, DMA2_CLR_MASK_REG); +#endif #if defined(CONFIG_ALPHA_SABLE) sable_init_IRQ(); #elif defined(CONFIG_ALPHA_MIATA) miata_init_IRQ(); +#elif defined(CONFIG_ALPHA_SX164) + sx164_init_IRQ(); #elif defined(CONFIG_ALPHA_NORITAKE) noritake_init_IRQ(); #elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) alcor_and_xlt_init_IRQ(); -#elif defined(CONFIG_ALPHA_PC164) && defined(CONFIG_ALPHA_SRM) +#elif (defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)) \ + && defined(CONFIG_ALPHA_SRM) /* Disable all the PCI interrupts? Otherwise, everthing was done by SRM already. */ #elif defined(CONFIG_ALPHA_MIKASA) mikasa_init_IRQ(); +#elif defined(CONFIG_ALPHA_RUFFIAN) + ruffian_init_IRQ(); #elif NR_IRQS == 33 init_IRQ_33(); #elif NR_IRQS == 32 diff -u --recursive --new-file v2.1.88/linux/arch/alpha/kernel/pyxis.c linux/arch/alpha/kernel/pyxis.c --- v2.1.88/linux/arch/alpha/kernel/pyxis.c Fri Jan 30 11:28:05 1998 +++ linux/arch/alpha/kernel/pyxis.c Mon Feb 23 10:25:10 1998 @@ -375,6 +375,10 @@ mb() ; pyxis_err = *(vuip)PYXIS_ERR ; +#ifdef CONFIG_ALPHA_RUFFIAN + printk("pyxis_init: Skipping window register rewrites --" + " trust DeskStation firmware!\n"); +#else /* * Set up the PCI->physical memory translation windows. * For now, windows 1,2 and 3 are disabled. In the future, we may @@ -390,6 +394,7 @@ *(vuip)PYXIS_W2_BASE = 0x0 ; *(vuip)PYXIS_W3_BASE = 0x0 ; mb(); +#endif /* * check ASN in HWRPB for validity, report if bad @@ -510,3 +515,42 @@ } #endif } + +#if defined(CONFIG_ALPHA_RUFFIAN) +/* Note: This is only used by MILO, AFAIK... */ +/* + * The DeskStation Ruffian motherboard firmware does not place + * the memory size in the PALimpure area. Therefore, we use + * the Bank Configuration Registers in PYXIS to obtain the size. + */ +unsigned long pyxis_get_bank_size(unsigned long offset) +{ + unsigned long bank_addr, bank, ret = 0; + + /* Valid offsets are: 0x800, 0x840 and 0x880 + since Ruffian only uses three banks. */ + bank_addr = (unsigned long)PYXIS_MCR + offset; + bank = *(vulp)bank_addr; + + /* Check BANK_ENABLE */ + if (bank & 0x01) { + static unsigned long size[] = { + 0x40000000UL, /* 0x00, 1G */ + 0x20000000UL, /* 0x02, 512M */ + 0x10000000UL, /* 0x04, 256M */ + 0x08000000UL, /* 0x06, 128M */ + 0x04000000UL, /* 0x08, 64M */ + 0x02000000UL, /* 0x0a, 32M */ + 0x01000000UL, /* 0x0c, 16M */ + 0x00800000UL, /* 0x0e, 8M */ + 0x80000000UL, /* 0x10, 2G */ + }; + + bank = (bank & 0x1e) >> 1; + if (bank < sizeof(size)/sizeof(*size)) + ret = size[bank]; + } + + return ret; +} +#endif /* CONFIG_ALPHA_RUFFIAN */ diff -u --recursive --new-file v2.1.88/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v2.1.88/linux/arch/alpha/kernel/setup.c Mon Jan 12 14:51:14 1998 +++ linux/arch/alpha/kernel/setup.c Mon Feb 23 10:25:10 1998 @@ -107,11 +107,13 @@ outb(LATCH >> 8, 0x40); /* MSB */ request_region(0x40, 0x20, "timer"); /* reserve pit */ #else +#ifndef CONFIG_ALPHA_RUFFIAN outb(0x36, 0x43); /* counter 0: system timer */ outb(0x00, 0x40); outb(0x00, 0x40); - request_region(0x70, 0x10, "timer"); /* reserve rtc */ #endif + request_region(0x70, 0x10, "timer"); /* reserve rtc */ +#endif /* RTC */ outb(0xb6, 0x43); /* counter 2: speaker */ outb(0x31, 0x42); @@ -186,38 +188,115 @@ #endif } + +#define N(a) (sizeof(a)/sizeof(a[0])) + + +static void +get_sysnames(long type, long variation, + char **type_name, char **variation_name) +{ + static char *sys_unknown = "Unknown"; + static char *systype_names[] = { + "0", + "ADU", "Cobra", "Ruby", "Flamingo", "Mannequin", "Jensen", + "Pelican", "Morgan", "Sable", "Medulla", "Noname", + "Turbolaser", "Avanti", "Mustang", "Alcor", "Tradewind", + "Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1", + "Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake", + "Cortex", "29", "Miata", "XXM", "Takara", "Yukon", + "Tsunami", "Wildfire", "CUSCO" + }; + + static char *unofficial_names[] = {"100", "Ruffian"}; + + static char * eb164_names[] = {"EB164", "PC164", "LX164", "SX164"}; + static int eb164_indices[] = {0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3}; + + static char * alcor_names[] = {"Alcor", "Maverick", "Bret"}; + static int alcor_indices[] = {0,0,0,1,1,1,0,0,0,0,0,0,2,2,2,2,2,2}; + + static char * eb64p_names[] = {"EB64+", "Cabriolet", "AlphaPCI64"}; + static int eb64p_indices[] = {0,0,1.2}; + + static char * eb66_names[] = {"EB66", "EB66+"}; + static int eb66_indices[] = {0,0,1}; + + long member; + + /* Restore real CABRIO and EB66+ family names, ie EB64+ and EB66 */ + if (type < 0) + type = -type; + + /* If not in the tables, make it UNKNOWN, + else set type name to family */ + if (type < N(systype_names)) { + *type_name = systype_names[type]; + } else if ((type > ST_UNOFFICIAL_BIAS) && + (type - ST_UNOFFICIAL_BIAS) < N(unofficial_names)) { + *type_name = unofficial_names[type - ST_UNOFFICIAL_BIAS]; + } else { + *type_name = sys_unknown; + *variation_name = sys_unknown; + return; + } + + /* Set variation to "0"; if variation is zero, done */ + *variation_name = systype_names[0]; + if (variation == 0) { + return; + } + + member = (variation >> 10) & 0x3f; /* member ID is a bit-field */ + + switch (type) { + case ST_DEC_EB164: + if (member < N(eb164_indices)) + *variation_name = eb164_names[eb164_indices[member]]; + break; + case ST_DEC_ALCOR: + if (member < N(alcor_indices)) + *variation_name = alcor_names[alcor_indices[member]]; + break; + case ST_DEC_EB64P: + if (member < N(eb64p_indices)) + *variation_name = eb64p_names[eb64p_indices[member]]; + break; + case ST_DEC_EB66: + if (member < N(eb66_indices)) + *variation_name = eb66_names[eb66_indices[member]]; + break; + } +} + /* * BUFFER is PAGE_SIZE bytes long. */ int get_cpuinfo(char *buffer) { - const char *cpu_name[] = { - "EV3", "EV4", "Unknown 1", "LCA4", "EV5", "EV45", "EV56", - "EV6", "PCA56" + static char *cpu_names[] = { + "EV3", "EV4", "Unknown", "LCA4", "EV5", "EV45", "EV56", + "EV6", "PCA56", "PCA57" }; -# define SYSTYPE_NAME_BIAS 20 - const char *systype_name[] = { - "Cabriolet", "EB66P", "-18", "-17", "-16", "-15", - "-14", "-13", "-12", "-11", "-10", "-9", "-8", - "-7", "-6", "-5", "-4", "-3", "-2", "-1", "0", - "ADU", "Cobra", "Ruby", "Flamingo", "5", "Jensen", - "Pelican", "8", "Sable", "AXPvme", "Noname", - "Turbolaser", "Avanti", "Mustang", "Alcor", "16", - "Mikasa", "18", "EB66", "EB64+", "AlphaBook1", - "Rawhide", "Lego", "Lynx", "25", "EB164", "Noritake", - "Cortex", "29", "Miata", "31", "Takara", "Yukon" - }; - struct percpu_struct *cpu; - unsigned int cpu_index; - long sysname_index; + extern struct unaligned_stat { unsigned long count, va, pc; } unaligned[2]; -# define N(a) (sizeof(a)/sizeof(a[0])) + + struct percpu_struct *cpu; + unsigned int cpu_index; + char *cpu_name; + char *systype_name; + char *sysvariation_name; cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset); cpu_index = (unsigned) (cpu->type - 1); - sysname_index = hwrpb->sys_type + SYSTYPE_NAME_BIAS; + cpu_name = "Unknown"; + if (cpu_index < N(cpu_names)) + cpu_name = cpu_names[cpu_index]; + + get_sysnames(hwrpb->sys_type, hwrpb->sys_variation, + &systype_name, &sysvariation_name); return sprintf(buffer, "cpu\t\t\t: Alpha\n" @@ -226,7 +305,7 @@ "cpu revision\t\t: %ld\n" "cpu serial number\t: %s\n" "system type\t\t: %s\n" - "system variation\t: %ld\n" + "system variation\t: %s\n" "system revision\t\t: %ld\n" "system serial number\t: %s\n" "cycle frequency [Hz]\t: %lu\n" @@ -238,12 +317,9 @@ "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n" "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n", - (cpu_index < N(cpu_name) - ? cpu_name[cpu_index] : "Unknown"), - cpu->variation, cpu->revision, (char*)cpu->serial_no, - (sysname_index < N(systype_name) - ? systype_name[sysname_index] : "Unknown"), - hwrpb->sys_variation, hwrpb->sys_revision, + cpu_name, cpu->variation, cpu->revision, + (char*)cpu->serial_no, + systype_name, sysvariation_name, hwrpb->sys_revision, (char*)hwrpb->ssn, hwrpb->cycle_freq, hwrpb->intr_freq / 4096, @@ -254,5 +330,4 @@ loops_per_sec / 500000, (loops_per_sec / 5000) % 100, unaligned[0].count, unaligned[0].pc, unaligned[0].va, unaligned[1].count, unaligned[1].pc, unaligned[1].va); -# undef N } diff -u --recursive --new-file v2.1.88/linux/arch/alpha/kernel/smc37c669.c linux/arch/alpha/kernel/smc37c669.c --- v2.1.88/linux/arch/alpha/kernel/smc37c669.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/smc37c669.c Mon Feb 23 10:25:10 1998 @@ -0,0 +1,2584 @@ +/* + * SMC 37C669 initialization code + */ +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#if 0 +# define DBG_DEVS(args) printk args +#else +# define DBG_DEVS(args) +#endif + +#define KB 1024 +#define MB (1024*KB) +#define GB (1024*MB) + +#define SMC_DEBUG 0 + +/* File: smcc669_def.h + * + * Copyright (C) 1997 by + * Digital Equipment Corporation, Maynard, Massachusetts. + * All rights reserved. + * + * This software is furnished under a license and may be used and copied + * only in accordance of the terms of such license and with the + * inclusion of the above copyright notice. This software or any other + * copies thereof may not be provided or otherwise made available to any + * other person. No title to and ownership of the software is hereby + * transferred. + * + * The information in this software is subject to change without notice + * and should not be construed as a commitment by Digital Equipment + * Corporation. + * + * Digital assumes no responsibility for the use or reliability of its + * software on equipment which is not supplied by Digital. + * + * + * Abstract: + * + * This file contains header definitions for the SMC37c669 + * Super I/O controller. + * + * Author: + * + * Eric Rasmussen + * + * Modification History: + * + * er 28-Jan-1997 Initial Entry + */ + +#ifndef __SMC37c669_H +#define __SMC37c669_H + +/* +** Macros for handling device IRQs +** +** The mask acts as a flag used in mapping actual ISA IRQs (0 - 15) +** to device IRQs (A - H). +*/ +#define SMC37c669_DEVICE_IRQ_MASK 0x80000000 +#define SMC37c669_DEVICE_IRQ( __i ) \ + ((SMC37c669_DEVICE_IRQ_MASK) | (__i)) +#define SMC37c669_IS_DEVICE_IRQ(__i) \ + (((__i) & (SMC37c669_DEVICE_IRQ_MASK)) == (SMC37c669_DEVICE_IRQ_MASK)) +#define SMC37c669_RAW_DEVICE_IRQ(__i) \ + ((__i) & ~(SMC37c669_DEVICE_IRQ_MASK)) + +/* +** Macros for handling device DRQs +** +** The mask acts as a flag used in mapping actual ISA DMA +** channels to device DMA channels (A - C). +*/ +#define SMC37c669_DEVICE_DRQ_MASK 0x80000000 +#define SMC37c669_DEVICE_DRQ(__d) \ + ((SMC37c669_DEVICE_DRQ_MASK) | (__d)) +#define SMC37c669_IS_DEVICE_DRQ(__d) \ + (((__d) & (SMC37c669_DEVICE_DRQ_MASK)) == (SMC37c669_DEVICE_DRQ_MASK)) +#define SMC37c669_RAW_DEVICE_DRQ(__d) \ + ((__d) & ~(SMC37c669_DEVICE_DRQ_MASK)) + +#define SMC37c669_DEVICE_ID 0x3 + +/* +** SMC37c669 Device Function Definitions +*/ +#define SERIAL_0 0 +#define SERIAL_1 1 +#define PARALLEL_0 2 +#define FLOPPY_0 3 +#define IDE_0 4 +#define NUM_FUNCS 5 + +/* +** Default Device Function Mappings +*/ +#define COM1_BASE 0x3F8 +#define COM1_IRQ 4 +#define COM2_BASE 0x2F8 +#define COM2_IRQ 3 +#define PARP_BASE 0x3BC +#define PARP_IRQ 7 +#define PARP_DRQ 3 +#define FDC_BASE 0x3F0 +#define FDC_IRQ 6 +#define FDC_DRQ 2 + +/* +** Configuration On/Off Key Definitions +*/ +#define SMC37c669_CONFIG_ON_KEY 0x55 +#define SMC37c669_CONFIG_OFF_KEY 0xAA + +/* +** SMC 37c669 Device IRQs +*/ +#define SMC37c669_DEVICE_IRQ_A ( SMC37c669_DEVICE_IRQ( 0x01 ) ) +#define SMC37c669_DEVICE_IRQ_B ( SMC37c669_DEVICE_IRQ( 0x02 ) ) +#define SMC37c669_DEVICE_IRQ_C ( SMC37c669_DEVICE_IRQ( 0x03 ) ) +#define SMC37c669_DEVICE_IRQ_D ( SMC37c669_DEVICE_IRQ( 0x04 ) ) +#define SMC37c669_DEVICE_IRQ_E ( SMC37c669_DEVICE_IRQ( 0x05 ) ) +#define SMC37c669_DEVICE_IRQ_F ( SMC37c669_DEVICE_IRQ( 0x06 ) ) +/* SMC37c669_DEVICE_IRQ_G *** RESERVED ***/ +#define SMC37c669_DEVICE_IRQ_H ( SMC37c669_DEVICE_IRQ( 0x08 ) ) + +/* +** SMC 37c669 Device DMA Channel Definitions +*/ +#define SMC37c669_DEVICE_DRQ_A ( SMC37c669_DEVICE_DRQ( 0x01 ) ) +#define SMC37c669_DEVICE_DRQ_B ( SMC37c669_DEVICE_DRQ( 0x02 ) ) +#define SMC37c669_DEVICE_DRQ_C ( SMC37c669_DEVICE_DRQ( 0x03 ) ) + +/* +** Configuration Register Index Definitions +*/ +#define SMC37c669_CR00_INDEX 0x00 +#define SMC37c669_CR01_INDEX 0x01 +#define SMC37c669_CR02_INDEX 0x02 +#define SMC37c669_CR03_INDEX 0x03 +#define SMC37c669_CR04_INDEX 0x04 +#define SMC37c669_CR05_INDEX 0x05 +#define SMC37c669_CR06_INDEX 0x06 +#define SMC37c669_CR07_INDEX 0x07 +#define SMC37c669_CR08_INDEX 0x08 +#define SMC37c669_CR09_INDEX 0x09 +#define SMC37c669_CR0A_INDEX 0x0A +#define SMC37c669_CR0B_INDEX 0x0B +#define SMC37c669_CR0C_INDEX 0x0C +#define SMC37c669_CR0D_INDEX 0x0D +#define SMC37c669_CR0E_INDEX 0x0E +#define SMC37c669_CR0F_INDEX 0x0F +#define SMC37c669_CR10_INDEX 0x10 +#define SMC37c669_CR11_INDEX 0x11 +#define SMC37c669_CR12_INDEX 0x12 +#define SMC37c669_CR13_INDEX 0x13 +#define SMC37c669_CR14_INDEX 0x14 +#define SMC37c669_CR15_INDEX 0x15 +#define SMC37c669_CR16_INDEX 0x16 +#define SMC37c669_CR17_INDEX 0x17 +#define SMC37c669_CR18_INDEX 0x18 +#define SMC37c669_CR19_INDEX 0x19 +#define SMC37c669_CR1A_INDEX 0x1A +#define SMC37c669_CR1B_INDEX 0x1B +#define SMC37c669_CR1C_INDEX 0x1C +#define SMC37c669_CR1D_INDEX 0x1D +#define SMC37c669_CR1E_INDEX 0x1E +#define SMC37c669_CR1F_INDEX 0x1F +#define SMC37c669_CR20_INDEX 0x20 +#define SMC37c669_CR21_INDEX 0x21 +#define SMC37c669_CR22_INDEX 0x22 +#define SMC37c669_CR23_INDEX 0x23 +#define SMC37c669_CR24_INDEX 0x24 +#define SMC37c669_CR25_INDEX 0x25 +#define SMC37c669_CR26_INDEX 0x26 +#define SMC37c669_CR27_INDEX 0x27 +#define SMC37c669_CR28_INDEX 0x28 +#define SMC37c669_CR29_INDEX 0x29 + +/* +** Configuration Register Alias Definitions +*/ +#define SMC37c669_DEVICE_ID_INDEX SMC37c669_CR0D_INDEX +#define SMC37c669_DEVICE_REVISION_INDEX SMC37c669_CR0E_INDEX +#define SMC37c669_FDC_BASE_ADDRESS_INDEX SMC37c669_CR20_INDEX +#define SMC37c669_IDE_BASE_ADDRESS_INDEX SMC37c669_CR21_INDEX +#define SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX SMC37c669_CR22_INDEX +#define SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX SMC37c669_CR23_INDEX +#define SMC37c669_SERIAL0_BASE_ADDRESS_INDEX SMC37c669_CR24_INDEX +#define SMC37c669_SERIAL1_BASE_ADDRESS_INDEX SMC37c669_CR25_INDEX +#define SMC37c669_PARALLEL_FDC_DRQ_INDEX SMC37c669_CR26_INDEX +#define SMC37c669_PARALLEL_FDC_IRQ_INDEX SMC37c669_CR27_INDEX +#define SMC37c669_SERIAL_IRQ_INDEX SMC37c669_CR28_INDEX + +/* +** Configuration Register Definitions +** +** The INDEX (write only) and DATA (read/write) ports are effective +** only when the chip is in the Configuration State. +*/ +typedef struct _SMC37c669_CONFIG_REGS { + unsigned char index_port; + unsigned char data_port; +} SMC37c669_CONFIG_REGS; + +/* +** CR00 - default value 0x28 +** +** IDE_EN (CR00<1:0>): +** 0x - 30ua pull-ups on nIDEEN, nHDCS0, NHDCS1 +** 11 - IRQ_H available as IRQ output, +** IRRX2, IRTX2 available as alternate IR pins +** 10 - nIDEEN, nHDCS0, nHDCS1 used to control IDE +** +** VALID (CR00<7>): +** A high level on this software controlled bit can +** be used to indicate that a valid configuration +** cycle has occurred. The control software must +** take care to set this bit at the appropriate times. +** Set to zero after power up. This bit has no +** effect on any other hardware in the chip. +** +*/ +typedef union _SMC37c669_CR00 { + unsigned char as_uchar; + struct { + unsigned ide_en : 2; /* See note above */ + unsigned reserved1 : 1; /* RAZ */ + unsigned fdc_pwr : 1; /* 1 = supply power to FDC */ + unsigned reserved2 : 3; /* Read as 010b */ + unsigned valid : 1; /* See note above */ + } by_field; +} SMC37c669_CR00; + +/* +** CR01 - default value 0x9C +*/ +typedef union _SMC37c669_CR01 { + unsigned char as_uchar; + struct { + unsigned reserved1 : 2; /* RAZ */ + unsigned ppt_pwr : 1; /* 1 = supply power to PPT */ + unsigned ppt_mode : 1; /* 1 = Printer mode, 0 = EPP */ + unsigned reserved2 : 1; /* Read as 1 */ + unsigned reserved3 : 2; /* RAZ */ + unsigned lock_crx: 1; /* Lock CR00 - CR18 */ + } by_field; +} SMC37c669_CR01; + +/* +** CR02 - default value 0x88 +*/ +typedef union _SMC37c669_CR02 { + unsigned char as_uchar; + struct { + unsigned reserved1 : 3; /* RAZ */ + unsigned uart1_pwr : 1; /* 1 = supply power to UART1 */ + unsigned reserved2 : 3; /* RAZ */ + unsigned uart2_pwr : 1; /* 1 = supply power to UART2 */ + } by_field; +} SMC37c669_CR02; + +/* +** CR03 - default value 0x78 +** +** CR03<7> CR03<2> Pin 94 +** ------- ------- ------ +** 0 X DRV2 (input) +** 1 0 ADRX +** 1 1 IRQ_B +** +** CR03<6> CR03<5> Op Mode +** ------- ------- ------- +** 0 0 Model 30 +** 0 1 PS/2 +** 1 0 Reserved +** 1 1 AT Mode +*/ +typedef union _SMC37c669_CR03 { + unsigned char as_uchar; + struct { + unsigned pwrgd_gamecs : 1; /* 1 = PWRGD, 0 = GAMECS */ + unsigned fdc_mode2 : 1; /* 1 = Enhanced Mode 2 */ + unsigned pin94_0 : 1; /* See note above */ + unsigned reserved1 : 1; /* RAZ */ + unsigned drvden : 1; /* 1 = high, 0 - output */ + unsigned op_mode : 2; /* See note above */ + unsigned pin94_1 : 1; /* See note above */ + } by_field; +} SMC37c669_CR03; + +/* +** CR04 - default value 0x00 +** +** PP_EXT_MODE: +** If CR01 = 0 and PP_EXT_MODE = +** 00 - Standard and Bidirectional +** 01 - EPP mode and SPP +** 10 - ECP mode +** In this mode, 2 drives can be supported +** directly, 3 or 4 drives must use external +** 4 drive support. SPP can be selected +** through the ECR register of ECP as mode 000. +** 11 - ECP mode and EPP mode +** In this mode, 2 drives can be supported +** directly, 3 or 4 drives must use external +** 4 drive support. SPP can be selected +** through the ECR register of ECP as mode 000. +** In this mode, EPP can be selected through +** the ECR register of ECP as mode 100. +** +** PP_FDC: +** 00 - Normal +** 01 - PPFD1 +** 10 - PPFD2 +** 11 - Reserved +** +** MIDI1: +** Serial Clock Select: +** A low level on this bit disables MIDI support, +** clock = divide by 13. A high level on this +** bit enables MIDI support, clock = divide by 12. +** +** MIDI operates at 31.25 Kbps which can be derived +** from 125 KHz (24 MHz / 12 = 2 MHz, 2 MHz / 16 = 125 KHz) +** +** ALT_IO: +** 0 - Use pins IRRX, IRTX +** 1 - Use pins IRRX2, IRTX2 +** +** If this bit is set, the IR receive and transmit +** functions will not be available on pins 25 and 26 +** unless CR00 = 11. +*/ +typedef union _SMC37c669_CR04 { + unsigned char as_uchar; + struct { + unsigned ppt_ext_mode : 2; /* See note above */ + unsigned ppt_fdc : 2; /* See note above */ + unsigned midi1 : 1; /* See note above */ + unsigned midi2 : 1; /* See note above */ + unsigned epp_type : 1; /* 0 = EPP 1.9, 1 = EPP 1.7 */ + unsigned alt_io : 1; /* See note above */ + } by_field; +} SMC37c669_CR04; + +/* +** CR05 - default value 0x00 +** +** DEN_SEL: +** 00 - Densel output normal +** 01 - Reserved +** 10 - Densel output 1 +** 11 - Densel output 0 +** +*/ +typedef union _SMC37c669_CR05 { + unsigned char as_uchar; + struct { + unsigned reserved1 : 2; /* RAZ */ + unsigned fdc_dma_mode : 1; /* 0 = burst, 1 = non-burst */ + unsigned den_sel : 2; /* See note above */ + unsigned swap_drv : 1; /* Swap the FDC motor selects */ + unsigned extx4 : 1; /* 0 = 2 drive, 1 = external 4 drive decode */ + unsigned reserved2 : 1; /* RAZ */ + } by_field; +} SMC37c669_CR05; + +/* +** CR06 - default value 0xFF +*/ +typedef union _SMC37c669_CR06 { + unsigned char as_uchar; + struct { + unsigned floppy_a : 2; /* Type of floppy drive A */ + unsigned floppy_b : 2; /* Type of floppy drive B */ + unsigned floppy_c : 2; /* Type of floppy drive C */ + unsigned floppy_d : 2; /* Type of floppy drive D */ + } by_field; +} SMC37c669_CR06; + +/* +** CR07 - default value 0x00 +** +** Auto Power Management CR07<7:4>: +** 0 - Auto Powerdown disabled (default) +** 1 - Auto Powerdown enabled +** +** This bit is reset to the default state by POR or +** a hardware reset. +** +*/ +typedef union _SMC37c669_CR07 { + unsigned char as_uchar; + struct { + unsigned floppy_boot : 2; /* 0 = A:, 1 = B: */ + unsigned reserved1 : 2; /* RAZ */ + unsigned ppt_en : 1; /* See note above */ + unsigned uart1_en : 1; /* See note above */ + unsigned uart2_en : 1; /* See note above */ + unsigned fdc_en : 1; /* See note above */ + } by_field; +} SMC37c669_CR07; + +/* +** CR08 - default value 0x00 +*/ +typedef union _SMC37c669_CR08 { + unsigned char as_uchar; + struct { + unsigned zero : 4; /* 0 */ + unsigned addrx7_4 : 4; /* ADR<7:3> for ADRx decode */ + } by_field; +} SMC37c669_CR08; + +/* +** CR09 - default value 0x00 +** +** ADRx_CONFIG: +** 00 - ADRx disabled +** 01 - 1 byte decode A<3:0> = 0000b +** 10 - 8 byte block decode A<3:0> = 0XXXb +** 11 - 16 byte block decode A<3:0> = XXXXb +** +*/ +typedef union _SMC37c669_CR09 { + unsigned char as_uchar; + struct { + unsigned adra8 : 3; /* ADR<10:8> for ADRx decode */ + unsigned reserved1 : 3; + unsigned adrx_config : 2; /* See note above */ + } by_field; +} SMC37c669_CR09; + +/* +** CR0A - default value 0x00 +*/ +typedef union _SMC37c669_CR0A { + unsigned char as_uchar; + struct { + unsigned ecp_fifo_threshold : 4; + unsigned reserved1 : 4; + } by_field; +} SMC37c669_CR0A; + +/* +** CR0B - default value 0x00 +*/ +typedef union _SMC37c669_CR0B { + unsigned char as_uchar; + struct { + unsigned fdd0_drtx : 2; /* FDD0 Data Rate Table */ + unsigned fdd1_drtx : 2; /* FDD1 Data Rate Table */ + unsigned fdd2_drtx : 2; /* FDD2 Data Rate Table */ + unsigned fdd3_drtx : 2; /* FDD3 Data Rate Table */ + } by_field; +} SMC37c669_CR0B; + +/* +** CR0C - default value 0x00 +** +** UART2_MODE: +** 000 - Standard (default) +** 001 - IrDA (HPSIR) +** 010 - Amplitude Shift Keyed IR @500 KHz +** 011 - Reserved +** 1xx - Reserved +** +*/ +typedef union _SMC37c669_CR0C { + unsigned char as_uchar; + struct { + unsigned uart2_rcv_polarity : 1; /* 1 = invert RX */ + unsigned uart2_xmit_polarity : 1; /* 1 = invert TX */ + unsigned uart2_duplex : 1; /* 1 = full, 0 = half */ + unsigned uart2_mode : 3; /* See note above */ + unsigned uart1_speed : 1; /* 1 = high speed enabled */ + unsigned uart2_speed : 1; /* 1 = high speed enabled */ + } by_field; +} SMC37c669_CR0C; + +/* +** CR0D - default value 0x03 +** +** Device ID Register - read only +*/ +typedef union _SMC37c669_CR0D { + unsigned char as_uchar; + struct { + unsigned device_id : 8; /* Returns 0x3 in this field */ + } by_field; +} SMC37c669_CR0D; + +/* +** CR0E - default value 0x02 +** +** Device Revision Register - read only +*/ +typedef union _SMC37c669_CR0E { + unsigned char as_uchar; + struct { + unsigned device_rev : 8; /* Returns 0x2 in this field */ + } by_field; +} SMC37c669_CR0E; + +/* +** CR0F - default value 0x00 +*/ +typedef union _SMC37c669_CR0F { + unsigned char as_uchar; + struct { + unsigned test0 : 1; /* Reserved - set to 0 */ + unsigned test1 : 1; /* Reserved - set to 0 */ + unsigned test2 : 1; /* Reserved - set to 0 */ + unsigned test3 : 1; /* Reserved - set t0 0 */ + unsigned test4 : 1; /* Reserved - set to 0 */ + unsigned test5 : 1; /* Reserved - set t0 0 */ + unsigned test6 : 1; /* Reserved - set t0 0 */ + unsigned test7 : 1; /* Reserved - set to 0 */ + } by_field; +} SMC37c669_CR0F; + +/* +** CR10 - default value 0x00 +*/ +typedef union _SMC37c669_CR10 { + unsigned char as_uchar; + struct { + unsigned reserved1 : 3; /* RAZ */ + unsigned pll_gain : 1; /* 1 = 3V, 2 = 5V operation */ + unsigned pll_stop : 1; /* 1 = stop PLLs */ + unsigned ace_stop : 1; /* 1 = stop UART clocks */ + unsigned pll_clock_ctrl : 1; /* 0 = 14.318 MHz, 1 = 24 MHz */ + unsigned ir_test : 1; /* Enable IR test mode */ + } by_field; +} SMC37c669_CR10; + +/* +** CR11 - default value 0x00 +*/ +typedef union _SMC37c669_CR11 { + unsigned char as_uchar; + struct { + unsigned ir_loopback : 1; /* Internal IR loop back */ + unsigned test_10ms : 1; /* Test 10ms autopowerdown FDC timeout */ + unsigned reserved1 : 6; /* RAZ */ + } by_field; +} SMC37c669_CR11; + +/* +** CR12 - CR1D are reserved registers +*/ + +/* +** CR1E - default value 0x80 +** +** GAMECS: +** 00 - GAMECS disabled +** 01 - 1 byte decode ADR<3:0> = 0001b +** 10 - 8 byte block decode ADR<3:0> = 0XXXb +** 11 - 16 byte block decode ADR<3:0> = XXXXb +** +*/ +typedef union _SMC37c66_CR1E { + unsigned char as_uchar; + struct { + unsigned gamecs_config: 2; /* See note above */ + unsigned gamecs_addr9_4 : 6; /* GAMECS Addr<9:4> */ + } by_field; +} SMC37c669_CR1E; + +/* +** CR1F - default value 0x00 +** +** DT0 DT1 DRVDEN0 DRVDEN1 Drive Type +** --- --- ------- ------- ---------- +** 0 0 DENSEL DRATE0 4/2/1 MB 3.5" +** 2/1 MB 5.25" +** 2/1.6/1 MB 3.5" (3-mode) +** 0 1 DRATE1 DRATE0 +** 1 0 nDENSEL DRATE0 PS/2 +** 1 1 DRATE0 DRATE1 +** +** Note: DENSEL, DRATE1, and DRATE0 map onto two output +** pins - DRVDEN0 and DRVDEN1. +** +*/ +typedef union _SMC37c669_CR1F { + unsigned char as_uchar; + struct { + unsigned fdd0_drive_type : 2; /* FDD0 drive type */ + unsigned fdd1_drive_type : 2; /* FDD1 drive type */ + unsigned fdd2_drive_type : 2; /* FDD2 drive type */ + unsigned fdd3_drive_type : 2; /* FDD3 drive type */ + } by_field; +} SMC37c669_CR1F; + +/* +** CR20 - default value 0x3C +** +** FDC Base Address Register +** - To disable this decode set Addr<9:8> = 0 +** - A<10> = 0, A<3:0> = 0XXXb to access. +** +*/ +typedef union _SMC37c669_CR20 { + unsigned char as_uchar; + struct { + unsigned zero : 2; /* 0 */ + unsigned addr9_4 : 6; /* FDC Addr<9:4> */ + } by_field; +} SMC37c669_CR20; + +/* +** CR21 - default value 0x3C +** +** IDE Base Address Register +** - To disable this decode set Addr<9:8> = 0 +** - A<10> = 0, A<3:0> = 0XXXb to access. +** +*/ +typedef union _SMC37c669_CR21 { + unsigned char as_uchar; + struct { + unsigned zero : 2; /* 0 */ + unsigned addr9_4 : 6; /* IDE Addr<9:4> */ + } by_field; +} SMC37c669_CR21; + +/* +** CR22 - default value 0x3D +** +** IDE Alternate Status Base Address Register +** - To disable this decode set Addr<9:8> = 0 +** - A<10> = 0, A<3:0> = 0110b to access. +** +*/ +typedef union _SMC37c669_CR22 { + unsigned char as_uchar; + struct { + unsigned zero : 2; /* 0 */ + unsigned addr9_4 : 6; /* IDE Alt Status Addr<9:4> */ + } by_field; +} SMC37c669_CR22; + +/* +** CR23 - default value 0x00 +** +** Parallel Port Base Address Register +** - To disable this decode set Addr<9:8> = 0 +** - A<10> = 0 to access. +** - If EPP is enabled, A<2:0> = XXXb to access. +** If EPP is NOT enabled, A<1:0> = XXb to access +** +*/ +typedef union _SMC37c669_CR23 { + unsigned char as_uchar; + struct { + unsigned addr9_2 : 8; /* Parallel Port Addr<9:2> */ + } by_field; +} SMC37c669_CR23; + +/* +** CR24 - default value 0x00 +** +** UART1 Base Address Register +** - To disable this decode set Addr<9:8> = 0 +** - A<10> = 0, A<2:0> = XXXb to access. +** +*/ +typedef union _SMC37c669_CR24 { + unsigned char as_uchar; + struct { + unsigned zero : 1; /* 0 */ + unsigned addr9_3 : 7; /* UART1 Addr<9:3> */ + } by_field; +} SMC37c669_CR24; + +/* +** CR25 - default value 0x00 +** +** UART2 Base Address Register +** - To disable this decode set Addr<9:8> = 0 +** - A<10> = 0, A<2:0> = XXXb to access. +** +*/ +typedef union _SMC37c669_CR25 { + unsigned char as_uchar; + struct { + unsigned zero : 1; /* 0 */ + unsigned addr9_3 : 7; /* UART2 Addr<9:3> */ + } by_field; +} SMC37c669_CR25; + +/* +** CR26 - default value 0x00 +** +** Parallel Port / FDC DMA Select Register +** +** D3 - D0 DMA +** D7 - D4 Selected +** ------- -------- +** 0000 None +** 0001 DMA_A +** 0010 DMA_B +** 0011 DMA_C +** +*/ +typedef union _SMC37c669_CR26 { + unsigned char as_uchar; + struct { + unsigned ppt_drq : 4; /* See note above */ + unsigned fdc_drq : 4; /* See note above */ + } by_field; +} SMC37c669_CR26; + +/* +** CR27 - default value 0x00 +** +** Parallel Port / FDC IRQ Select Register +** +** D3 - D0 IRQ +** D7 - D4 Selected +** ------- -------- +** 0000 None +** 0001 IRQ_A +** 0010 IRQ_B +** 0011 IRQ_C +** 0100 IRQ_D +** 0101 IRQ_E +** 0110 IRQ_F +** 0111 Reserved +** 1000 IRQ_H +** +** Any unselected IRQ REQ is in tristate +** +*/ +typedef union _SMC37c669_CR27 { + unsigned char as_uchar; + struct { + unsigned ppt_irq : 4; /* See note above */ + unsigned fdc_irq : 4; /* See note above */ + } by_field; +} SMC37c669_CR27; + +/* +** CR28 - default value 0x00 +** +** UART IRQ Select Register +** +** D3 - D0 IRQ +** D7 - D4 Selected +** ------- -------- +** 0000 None +** 0001 IRQ_A +** 0010 IRQ_B +** 0011 IRQ_C +** 0100 IRQ_D +** 0101 IRQ_E +** 0110 IRQ_F +** 0111 Reserved +** 1000 IRQ_H +** 1111 share with UART1 (only for UART2) +** +** Any unselected IRQ REQ is in tristate +** +** To share an IRQ between UART1 and UART2, set +** UART1 to use the desired IRQ and set UART2 to +** 0xF to enable sharing mechanism. +** +*/ +typedef union _SMC37c669_CR28 { + unsigned char as_uchar; + struct { + unsigned uart2_irq : 4; /* See note above */ + unsigned uart1_irq : 4; /* See note above */ + } by_field; +} SMC37c669_CR28; + +/* +** CR29 - default value 0x00 +** +** IRQIN IRQ Select Register +** +** D3 - D0 IRQ +** D7 - D4 Selected +** ------- -------- +** 0000 None +** 0001 IRQ_A +** 0010 IRQ_B +** 0011 IRQ_C +** 0100 IRQ_D +** 0101 IRQ_E +** 0110 IRQ_F +** 0111 Reserved +** 1000 IRQ_H +** +** Any unselected IRQ REQ is in tristate +** +*/ +typedef union _SMC37c669_CR29 { + unsigned char as_uchar; + struct { + unsigned irqin_irq : 4; /* See note above */ + unsigned reserved1 : 4; /* RAZ */ + } by_field; +} SMC37c669_CR29; + +/* +** Aliases of Configuration Register formats (should match +** the set of index aliases). +** +** Note that CR24 and CR25 have the same format and are the +** base address registers for UART1 and UART2. Because of +** this we only define 1 alias here - for CR24 - as the serial +** base address register. +** +** Note that CR21 and CR22 have the same format and are the +** base address and alternate status address registers for +** the IDE controller. Because of this we only define 1 alias +** here - for CR21 - as the IDE address register. +** +*/ +typedef SMC37c669_CR0D SMC37c669_DEVICE_ID_REGISTER; +typedef SMC37c669_CR0E SMC37c669_DEVICE_REVISION_REGISTER; +typedef SMC37c669_CR20 SMC37c669_FDC_BASE_ADDRESS_REGISTER; +typedef SMC37c669_CR21 SMC37c669_IDE_ADDRESS_REGISTER; +typedef SMC37c669_CR23 SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER; +typedef SMC37c669_CR24 SMC37c669_SERIAL_BASE_ADDRESS_REGISTER; +typedef SMC37c669_CR26 SMC37c669_PARALLEL_FDC_DRQ_REGISTER; +typedef SMC37c669_CR27 SMC37c669_PARALLEL_FDC_IRQ_REGISTER; +typedef SMC37c669_CR28 SMC37c669_SERIAL_IRQ_REGISTER; + +/* +** ISA/Device IRQ Translation Table Entry Definition +*/ +typedef struct _SMC37c669_IRQ_TRANSLATION_ENTRY { + int device_irq; + int isa_irq; +} SMC37c669_IRQ_TRANSLATION_ENTRY; + +/* +** ISA/Device DMA Translation Table Entry Definition +*/ +typedef struct _SMC37c669_DRQ_TRANSLATION_ENTRY { + int device_drq; + int isa_drq; +} SMC37c669_DRQ_TRANSLATION_ENTRY; + +/* +** External Interface Function Prototype Declarations +*/ + +SMC37c669_CONFIG_REGS *SMC37c669_detect( + void +); + +unsigned int SMC37c669_enable_device( + unsigned int func +); + +unsigned int SMC37c669_disable_device( + unsigned int func +); + +unsigned int SMC37c669_configure_device( + unsigned int func, + int port, + int irq, + int drq +); + +void SMC37c669_display_device_info( + void +); + +#endif /* __SMC37c669_H */ + +/* file: smcc669.c + * + * Copyright (C) 1997 by + * Digital Equipment Corporation, Maynard, Massachusetts. + * All rights reserved. + * + * This software is furnished under a license and may be used and copied + * only in accordance of the terms of such license and with the + * inclusion of the above copyright notice. This software or any other + * copies thereof may not be provided or otherwise made available to any + * other person. No title to and ownership of the software is hereby + * transferred. + * + * The information in this software is subject to change without notice + * and should not be construed as a commitment by digital equipment + * corporation. + * + * Digital assumes no responsibility for the use or reliability of its + * software on equipment which is not supplied by digital. + */ + +/* + *++ + * FACILITY: + * + * Alpha SRM Console Firmware + * + * MODULE DESCRIPTION: + * + * SMC37c669 Super I/O controller configuration routines. + * + * AUTHORS: + * + * Eric Rasmussen + * + * CREATION DATE: + * + * 28-Jan-1997 + * + * MODIFICATION HISTORY: + * + * er 01-May-1997 Fixed pointer conversion errors in + * SMC37c669_get_device_config(). + * er 28-Jan-1997 Initial version. + * + *-- + */ +#if 0 +/* $INCLUDE_OPTIONS$ */ +#include "cp$inc:platform_io.h" +/* $INCLUDE_OPTIONS_END$ */ +#include "cp$src:common.h" +#include "cp$inc:prototypes.h" +#include "cp$src:kernel_def.h" +#include "cp$src:msg_def.h" +#include "cp$src:smcc669_def.h" +/* Platform-specific includes */ +#include "cp$src:platform.h" +#endif + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define wb( _x_, _y_ ) outb( _y_, (unsigned int)((unsigned long)_x_) ) +#define rb( _x_ ) inb( (unsigned int)((unsigned long)_x_) ) + +/* +** Local storage for device configuration information. +** +** Since the SMC37c669 does not provide an explicit +** mechanism for enabling/disabling individual device +** functions, other than unmapping the device, local +** storage for device configuration information is +** allocated here for use in implementing our own +** function enable/disable scheme. +*/ +static struct DEVICE_CONFIG { + unsigned int port1; + unsigned int port2; + unsigned int irq; + unsigned int drq; +} local_config [NUM_FUNCS]; + +/* +** List of all possible addresses for the Super I/O chip +*/ +static unsigned long SMC37c669_Addresses[] __initdata = + { + 0x3F0UL, /* Primary address */ + 0x370UL, /* Secondary address */ + 0UL /* End of list */ + }; + +/* +** Global Pointer to the Super I/O device +*/ +static SMC37c669_CONFIG_REGS *SMC37c669 __initdata = NULL; + +/* +** IRQ Translation Table +** +** The IRQ translation table is a list of SMC37c669 device +** and standard ISA IRQs. +** +*/ +static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_table __initdata; + +/* +** The following definition is for the default IRQ +** translation table. +*/ +static SMC37c669_IRQ_TRANSLATION_ENTRY SMC37c669_default_irq_table[] +__initdata = + { + { SMC37c669_DEVICE_IRQ_A, -1 }, + { SMC37c669_DEVICE_IRQ_B, -1 }, + { SMC37c669_DEVICE_IRQ_C, 7 }, + { SMC37c669_DEVICE_IRQ_D, 6 }, + { SMC37c669_DEVICE_IRQ_E, 4 }, + { SMC37c669_DEVICE_IRQ_F, 3 }, + { SMC37c669_DEVICE_IRQ_H, -1 }, + { -1, -1 } /* End of table */ + }; + +/* +** DRQ Translation Table +** +** The DRQ translation table is a list of SMC37c669 device and +** ISA DMA channels. +** +*/ +static SMC37c669_DRQ_TRANSLATION_ENTRY *SMC37c669_drq_table __initdata; + +/* +** The following definition is the default DRQ +** translation table. +*/ +static SMC37c669_DRQ_TRANSLATION_ENTRY SMC37c669_default_drq_table[] +__initdata = + { + { SMC37c669_DEVICE_DRQ_A, 2 }, + { SMC37c669_DEVICE_DRQ_B, 3 }, + { SMC37c669_DEVICE_DRQ_C, -1 }, + { -1, -1 } /* End of table */ + }; + +/* +** Local Function Prototype Declarations +*/ + +static unsigned int SMC37c669_is_device_enabled( + unsigned int func +); + +#if 0 +static unsigned int SMC37c669_get_device_config( + unsigned int func, + int *port, + int *irq, + int *drq +); +#endif + +static void SMC37c669_config_mode( + unsigned int enable +); + +static unsigned char SMC37c669_read_config( + unsigned char index +); + +static void SMC37c669_write_config( + unsigned char index, + unsigned char data +); + +static void SMC37c669_init_local_config( void ); + +static struct DEVICE_CONFIG *SMC37c669_get_config( + unsigned int func +); + +static int SMC37c669_xlate_irq( + unsigned int irq +); + +static int SMC37c669_xlate_drq( + unsigned int drq +); + +#if 0 +/* +** External Data Declarations +*/ + +extern struct LOCK spl_atomic; + +/* +** External Function Prototype Declarations +*/ + +/* From kernel_alpha.mar */ +extern spinlock( + struct LOCK *spl +); + +extern spinunlock( + struct LOCK *spl +); + +/* From filesys.c */ +int allocinode( + char *name, + int can_create, + struct INODE **ipp +); + +extern int null_procedure( void ); + +int smcc669_init( void ); +int smcc669_open( struct FILE *fp, char *info, char *next, char *mode ); +int smcc669_read( struct FILE *fp, int size, int number, unsigned char *buf ); +int smcc669_write( struct FILE *fp, int size, int number, unsigned char *buf ); +int smcc669_close( struct FILE *fp ); + +struct DDB smc_ddb = { + "smc", /* how this routine wants to be called */ + smcc669_read, /* read routine */ + smcc669_write, /* write routine */ + smcc669_open, /* open routine */ + smcc669_close, /* close routine */ + null_procedure, /* name expansion routine */ + null_procedure, /* delete routine */ + null_procedure, /* create routine */ + null_procedure, /* setmode */ + null_procedure, /* validation routine */ + 0, /* class specific use */ + 1, /* allows information */ + 0, /* must be stacked */ + 0, /* is a flash update driver */ + 0, /* is a block device */ + 0, /* not seekable */ + 0, /* is an ethernet device */ + 0, /* is a filesystem driver */ +}; +#endif + +#define spinlock(x) +#define spinunlock(x) + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function detects the presence of an SMC37c669 Super I/O +** controller. +** +** FORMAL PARAMETERS: +** +** None +** +** RETURN VALUE: +** +** Returns a pointer to the device if found, otherwise, +** the NULL pointer is returned. +** +** SIDE EFFECTS: +** +** None +** +**-- +*/ +SMC37c669_CONFIG_REGS * __init SMC37c669_detect( void ) +{ + int i; + SMC37c669_DEVICE_ID_REGISTER id; + + for ( i = 0; SMC37c669_Addresses[i] != 0; i++ ) { +/* +** Initialize the device pointer even though we don't yet know if +** the controller is at this address. The support functions access +** the controller through this device pointer so we need to set it +** even when we are looking ... +*/ + SMC37c669 = ( SMC37c669_CONFIG_REGS * )SMC37c669_Addresses[i]; +/* +** Enter configuration mode +*/ + SMC37c669_config_mode( TRUE ); +/* +** Read the device id +*/ + id.as_uchar = SMC37c669_read_config( SMC37c669_DEVICE_ID_INDEX ); +/* +** Exit configuration mode +*/ + SMC37c669_config_mode( FALSE ); +/* +** Does the device id match? If so, assume we have found an +** SMC37c669 controller at this address. +*/ + if ( id.by_field.device_id == SMC37c669_DEVICE_ID ) { +/* +** Initialize the IRQ and DRQ translation tables. +*/ + SMC37c669_irq_table = SMC37c669_default_irq_table; + SMC37c669_drq_table = SMC37c669_default_drq_table; +/* +** erfix +** +** If the platform can't use the IRQ and DRQ defaults set up in this +** file, it should call a platform-specific external routine at this +** point to reset the IRQ and DRQ translation table pointers to point +** at the appropriate tables for the platform. If the defaults are +** acceptable, then the external routine should do nothing. +*/ + +/* +** Put the chip back into configuration mode +*/ + SMC37c669_config_mode( TRUE ); +/* +** Initialize local storage for configuration information +*/ + SMC37c669_init_local_config( ); +/* +** Exit configuration mode +*/ + SMC37c669_config_mode( FALSE ); +/* +** SMC37c669 controller found, break out of search loop +*/ + break; + } + else { +/* +** Otherwise, we did not find an SMC37c669 controller at this +** address so set the device pointer to NULL. +*/ + SMC37c669 = NULL; + } + } + return SMC37c669; +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function enables an SMC37c669 device function. +** +** FORMAL PARAMETERS: +** +** func: +** Which device function to enable +** +** RETURN VALUE: +** +** Returns TRUE is the device function was enabled, otherwise, FALSE +** +** SIDE EFFECTS: +** +** {@description or none@} +** +** DESIGN: +** +** Enabling a device function in the SMC37c669 controller involves +** setting all of its mappings (port, irq, drq ...). A local +** "shadow" copy of the device configuration is kept so we can +** just set each mapping to what the local copy says. +** +** This function ALWAYS updates the local shadow configuration of +** the device function being enabled, even if the device is always +** enabled. To avoid replication of code, functions such as +** configure_device set up the local copy and then call this +** function to the update the real device. +** +**-- +*/ +unsigned int __init SMC37c669_enable_device ( unsigned int func ) +{ + unsigned int ret_val = FALSE; +/* +** Put the device into configuration mode +*/ + SMC37c669_config_mode( TRUE ); + switch ( func ) { + case SERIAL_0: + { + SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_SERIAL_IRQ_REGISTER irq; +/* +** Enable the serial 1 IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX ); + + irq.by_field.uart1_irq = + SMC37c669_RAW_DEVICE_IRQ( + SMC37c669_xlate_irq( local_config[ func ].irq ) + ); + + SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar ); +/* +** Enable the serial 1 port base address mapping +*/ + base_addr.as_uchar = 0; + base_addr.by_field.addr9_3 = local_config[ func ].port1 >> 3; + + SMC37c669_write_config( + SMC37c669_SERIAL0_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case SERIAL_1: + { + SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_SERIAL_IRQ_REGISTER irq; +/* +** Enable the serial 2 IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX ); + + irq.by_field.uart2_irq = + SMC37c669_RAW_DEVICE_IRQ( + SMC37c669_xlate_irq( local_config[ func ].irq ) + ); + + SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar ); +/* +** Enable the serial 2 port base address mapping +*/ + base_addr.as_uchar = 0; + base_addr.by_field.addr9_3 = local_config[ func ].port1 >> 3; + + SMC37c669_write_config( + SMC37c669_SERIAL1_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case PARALLEL_0: + { + SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq; + SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq; +/* +** Enable the parallel port DMA channel mapping +*/ + drq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX ); + + drq.by_field.ppt_drq = + SMC37c669_RAW_DEVICE_DRQ( + SMC37c669_xlate_drq( local_config[ func ].drq ) + ); + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_DRQ_INDEX, + drq.as_uchar + ); +/* +** Enable the parallel port IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX ); + + irq.by_field.ppt_irq = + SMC37c669_RAW_DEVICE_IRQ( + SMC37c669_xlate_irq( local_config[ func ].irq ) + ); + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_IRQ_INDEX, + irq.as_uchar + ); +/* +** Enable the parallel port base address mapping +*/ + base_addr.as_uchar = 0; + base_addr.by_field.addr9_2 = local_config[ func ].port1 >> 2; + + SMC37c669_write_config( + SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case FLOPPY_0: + { + SMC37c669_FDC_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq; + SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq; +/* +** Enable the floppy controller DMA channel mapping +*/ + drq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX ); + + drq.by_field.fdc_drq = + SMC37c669_RAW_DEVICE_DRQ( + SMC37c669_xlate_drq( local_config[ func ].drq ) + ); + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_DRQ_INDEX, + drq.as_uchar + ); +/* +** Enable the floppy controller IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX ); + + irq.by_field.fdc_irq = + SMC37c669_RAW_DEVICE_IRQ( + SMC37c669_xlate_irq( local_config[ func ].irq ) + ); + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_IRQ_INDEX, + irq.as_uchar + ); +/* +** Enable the floppy controller base address mapping +*/ + base_addr.as_uchar = 0; + base_addr.by_field.addr9_4 = local_config[ func ].port1 >> 4; + + SMC37c669_write_config( + SMC37c669_FDC_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case IDE_0: + { + SMC37c669_IDE_ADDRESS_REGISTER ide_addr; +/* +** Enable the IDE alternate status base address mapping +*/ + ide_addr.as_uchar = 0; + ide_addr.by_field.addr9_4 = local_config[ func ].port2 >> 4; + + SMC37c669_write_config( + SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX, + ide_addr.as_uchar + ); +/* +** Enable the IDE controller base address mapping +*/ + ide_addr.as_uchar = 0; + ide_addr.by_field.addr9_4 = local_config[ func ].port1 >> 4; + + SMC37c669_write_config( + SMC37c669_IDE_BASE_ADDRESS_INDEX, + ide_addr.as_uchar + ); + ret_val = TRUE; + break; + } + } +/* +** Exit configuration mode and return +*/ + SMC37c669_config_mode( FALSE ); + + return ret_val; +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function disables a device function within the +** SMC37c669 Super I/O controller. +** +** FORMAL PARAMETERS: +** +** func: +** Which function to disable +** +** RETURN VALUE: +** +** Return TRUE if the device function was disabled, otherwise, FALSE +** +** SIDE EFFECTS: +** +** {@description or none@} +** +** DESIGN: +** +** Disabling a function in the SMC37c669 device involves +** disabling all the function's mappings (port, irq, drq ...). +** A shadow copy of the device configuration is maintained +** in local storage so we won't worry aboving saving the +** current configuration information. +** +**-- +*/ +unsigned int __init SMC37c669_disable_device ( unsigned int func ) +{ + unsigned int ret_val = FALSE; + +/* +** Put the device into configuration mode +*/ + SMC37c669_config_mode( TRUE ); + switch ( func ) { + case SERIAL_0: + { + SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_SERIAL_IRQ_REGISTER irq; +/* +** Disable the serial 1 IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX ); + + irq.by_field.uart1_irq = 0; + + SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar ); +/* +** Disable the serial 1 port base address mapping +*/ + base_addr.as_uchar = 0; + SMC37c669_write_config( + SMC37c669_SERIAL0_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case SERIAL_1: + { + SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_SERIAL_IRQ_REGISTER irq; +/* +** Disable the serial 2 IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX ); + + irq.by_field.uart2_irq = 0; + + SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar ); +/* +** Disable the serial 2 port base address mapping +*/ + base_addr.as_uchar = 0; + + SMC37c669_write_config( + SMC37c669_SERIAL1_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case PARALLEL_0: + { + SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq; + SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq; +/* +** Disable the parallel port DMA channel mapping +*/ + drq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX ); + + drq.by_field.ppt_drq = 0; + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_DRQ_INDEX, + drq.as_uchar + ); +/* +** Disable the parallel port IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX ); + + irq.by_field.ppt_irq = 0; + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_IRQ_INDEX, + irq.as_uchar + ); +/* +** Disable the parallel port base address mapping +*/ + base_addr.as_uchar = 0; + + SMC37c669_write_config( + SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case FLOPPY_0: + { + SMC37c669_FDC_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq; + SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq; +/* +** Disable the floppy controller DMA channel mapping +*/ + drq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX ); + + drq.by_field.fdc_drq = 0; + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_DRQ_INDEX, + drq.as_uchar + ); +/* +** Disable the floppy controller IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX ); + + irq.by_field.fdc_irq = 0; + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_IRQ_INDEX, + irq.as_uchar + ); +/* +** Disable the floppy controller base address mapping +*/ + base_addr.as_uchar = 0; + + SMC37c669_write_config( + SMC37c669_FDC_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case IDE_0: + { + SMC37c669_IDE_ADDRESS_REGISTER ide_addr; +/* +** Disable the IDE alternate status base address mapping +*/ + ide_addr.as_uchar = 0; + + SMC37c669_write_config( + SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX, + ide_addr.as_uchar + ); +/* +** Disable the IDE controller base address mapping +*/ + ide_addr.as_uchar = 0; + + SMC37c669_write_config( + SMC37c669_IDE_BASE_ADDRESS_INDEX, + ide_addr.as_uchar + ); + ret_val = TRUE; + break; + } + } +/* +** Exit configuration mode and return +*/ + SMC37c669_config_mode( FALSE ); + + return ret_val; +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function configures a device function within the +** SMC37c669 Super I/O controller. +** +** FORMAL PARAMETERS: +** +** func: +** Which device function +** +** port: +** I/O port for the function to use +** +** irq: +** IRQ for the device function to use +** +** drq: +** DMA channel for the device function to use +** +** RETURN VALUE: +** +** Returns TRUE if the device function was configured, +** otherwise, FALSE. +** +** SIDE EFFECTS: +** +** {@description or none@} +** +** DESIGN: +** +** If this function returns TRUE, the local shadow copy of +** the configuration is also updated. If the device function +** is currently disabled, only the local shadow copy is +** updated and the actual device function will be updated +** if/when is is enabled. +** +**-- +*/ +unsigned int __init SMC37c669_configure_device ( + unsigned int func, + int port, + int irq, + int drq ) +{ + struct DEVICE_CONFIG *cp; + +/* +** Check for a valid configuration +*/ + if ( ( cp = SMC37c669_get_config ( func ) ) != NULL ) { +/* +** Configuration is valid, update the local shadow copy +*/ + if ( ( drq & ~0xFF ) == 0 ) { + cp->drq = drq; + } + if ( ( irq & ~0xFF ) == 0 ) { + cp->irq = irq; + } + if ( ( port & ~0xFFFF ) == 0 ) { + cp->port1 = port; + } +/* +** If the device function is enabled, update the actual +** device configuration. +*/ + if ( SMC37c669_is_device_enabled( func ) ) { + SMC37c669_enable_device( func ); + } + return TRUE; + } + return FALSE; +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function determines whether a device function +** within the SMC37c669 controller is enabled. +** +** FORMAL PARAMETERS: +** +** func: +** Which device function +** +** RETURN VALUE: +** +** Returns TRUE if the device function is enabled, otherwise, FALSE +** +** SIDE EFFECTS: +** +** {@description or none@} +** +** DESIGN: +** +** To check whether a device is enabled we will only look at +** the port base address mapping. According to the SMC37c669 +** specification, all of the port base address mappings are +** disabled if the addr<9:8> (bits <7:6> of the register) are +** zero. +** +**-- +*/ +static unsigned int __init SMC37c669_is_device_enabled ( unsigned int func ) +{ + unsigned char base_addr = 0; + unsigned int dev_ok = FALSE; + unsigned int ret_val = FALSE; +/* +** Enter configuration mode +*/ + SMC37c669_config_mode( TRUE ); + + switch ( func ) { + case SERIAL_0: + base_addr = + SMC37c669_read_config( SMC37c669_SERIAL0_BASE_ADDRESS_INDEX ); + dev_ok = TRUE; + break; + case SERIAL_1: + base_addr = + SMC37c669_read_config( SMC37c669_SERIAL1_BASE_ADDRESS_INDEX ); + dev_ok = TRUE; + break; + case PARALLEL_0: + base_addr = + SMC37c669_read_config( SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX ); + dev_ok = TRUE; + break; + case FLOPPY_0: + base_addr = + SMC37c669_read_config( SMC37c669_FDC_BASE_ADDRESS_INDEX ); + dev_ok = TRUE; + break; + case IDE_0: + base_addr = + SMC37c669_read_config( SMC37c669_IDE_BASE_ADDRESS_INDEX ); + dev_ok = TRUE; + break; + } +/* +** If we have a valid device, check base_addr<7:6> to see if the +** device is enabled (mapped). +*/ + if ( ( dev_ok ) && ( ( base_addr & 0xC0 ) != 0 ) ) { +/* +** The mapping is not disabled, so assume that the function is +** enabled. +*/ + ret_val = TRUE; + } +/* +** Exit configuration mode +*/ + SMC37c669_config_mode( FALSE ); + + return ret_val; +} + + +#if 0 +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function retrieves the configuration information of a +** device function within the SMC37c699 Super I/O controller. +** +** FORMAL PARAMETERS: +** +** func: +** Which device function +** +** port: +** I/O port returned +** +** irq: +** IRQ returned +** +** drq: +** DMA channel returned +** +** RETURN VALUE: +** +** Returns TRUE if the device configuration was successfully +** retrieved, otherwise, FALSE. +** +** SIDE EFFECTS: +** +** The data pointed to by the port, irq, and drq parameters +** my be modified even if the configuration is not successfully +** retrieved. +** +** DESIGN: +** +** The device configuration is fetched from the local shadow +** copy. Any unused parameters will be set to -1. Any +** parameter which is not desired can specify the NULL +** pointer. +** +**-- +*/ +static unsigned int __init SMC37c669_get_device_config ( + unsigned int func, + int *port, + int *irq, + int *drq ) +{ + struct DEVICE_CONFIG *cp; + unsigned int ret_val = FALSE; +/* +** Check for a valid device configuration +*/ + if ( ( cp = SMC37c669_get_config( func ) ) != NULL ) { + if ( drq != NULL ) { + *drq = cp->drq; + ret_val = TRUE; + } + if ( irq != NULL ) { + *irq = cp->irq; + ret_val = TRUE; + } + if ( port != NULL ) { + *port = cp->port1; + ret_val = TRUE; + } + } + return ret_val; +} +#endif + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function displays the current state of the SMC37c699 +** Super I/O controller's device functions. +** +** FORMAL PARAMETERS: +** +** None +** +** RETURN VALUE: +** +** None +** +** SIDE EFFECTS: +** +** None +** +**-- +*/ +void __init SMC37c669_display_device_info ( void ) +{ + if ( SMC37c669_is_device_enabled( SERIAL_0 ) ) { + printk( " Serial 0: Enabled [ Port 0x%x, IRQ %d ]\n", + local_config[ SERIAL_0 ].port1, + local_config[ SERIAL_0 ].irq + ); + } + else { + printk( " Serial 0: Disabled\n" ); + } + + if ( SMC37c669_is_device_enabled( SERIAL_1 ) ) { + printk( " Serial 1: Enabled [ Port 0x%x, IRQ %d ]\n", + local_config[ SERIAL_1 ].port1, + local_config[ SERIAL_1 ].irq + ); + } + else { + printk( " Serial 1: Disabled\n" ); + } + + if ( SMC37c669_is_device_enabled( PARALLEL_0 ) ) { + printk( " Parallel: Enabled [ Port 0x%x, IRQ %d/%d ]\n", + local_config[ PARALLEL_0 ].port1, + local_config[ PARALLEL_0 ].irq, + local_config[ PARALLEL_0 ].drq + ); + } + else { + printk( " Parallel: Disabled\n" ); + } + + if ( SMC37c669_is_device_enabled( FLOPPY_0 ) ) { + printk( " Floppy Ctrl: Enabled [ Port 0x%x, IRQ %d/%d ]\n", + local_config[ FLOPPY_0 ].port1, + local_config[ FLOPPY_0 ].irq, + local_config[ FLOPPY_0 ].drq + ); + } + else { + printk( " Floppy Ctrl: Disabled\n" ); + } + + if ( SMC37c669_is_device_enabled( IDE_0 ) ) { + printk( " IDE 0: Enabled [ Port 0x%x, IRQ %d ]\n", + local_config[ IDE_0 ].port1, + local_config[ IDE_0 ].irq + ); + } + else { + printk( " IDE 0: Disabled\n" ); + } +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function puts the SMC37c669 Super I/O controller into, +** and takes it out of, configuration mode. +** +** FORMAL PARAMETERS: +** +** enable: +** TRUE to enter configuration mode, FALSE to exit. +** +** RETURN VALUE: +** +** None +** +** SIDE EFFECTS: +** +** The SMC37c669 controller may be left in configuration mode. +** +**-- +*/ +static void __init SMC37c669_config_mode( + unsigned int enable ) +{ + if ( enable ) { +/* +** To enter configuration mode, two writes in succession to the index +** port are required. If a write to another address or port occurs +** between these two writes, the chip does not enter configuration +** mode. Therefore, a spinlock is placed around the two writes to +** guarantee that they complete uninterrupted. +*/ + spinlock( &spl_atomic ); + wb( &SMC37c669->index_port, SMC37c669_CONFIG_ON_KEY ); + wb( &SMC37c669->index_port, SMC37c669_CONFIG_ON_KEY ); + spinunlock( &spl_atomic ); + } + else { + wb( &SMC37c669->index_port, SMC37c669_CONFIG_OFF_KEY ); + } +} + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function reads an SMC37c669 Super I/O controller +** configuration register. This function assumes that the +** device is already in configuration mode. +** +** FORMAL PARAMETERS: +** +** index: +** Index value of configuration register to read +** +** RETURN VALUE: +** +** Data read from configuration register +** +** SIDE EFFECTS: +** +** None +** +**-- +*/ +static unsigned char __init SMC37c669_read_config( + unsigned char index ) +{ + unsigned char data; + + wb( &SMC37c669->index_port, index ); + data = rb( &SMC37c669->data_port ); + return data; +} + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function writes an SMC37c669 Super I/O controller +** configuration register. This function assumes that the +** device is already in configuration mode. +** +** FORMAL PARAMETERS: +** +** index: +** Index of configuration register to write +** +** data: +** Data to be written +** +** RETURN VALUE: +** +** None +** +** SIDE EFFECTS: +** +** None +** +**-- +*/ +static void __init SMC37c669_write_config( + unsigned char index, + unsigned char data ) +{ + wb( &SMC37c669->index_port, index ); + wb( &SMC37c669->data_port, data ); +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function initializes the local device +** configuration storage. This function assumes +** that the device is already in configuration +** mode. +** +** FORMAL PARAMETERS: +** +** None +** +** RETURN VALUE: +** +** None +** +** SIDE EFFECTS: +** +** Local storage for device configuration information +** is initialized. +** +**-- +*/ +static void __init SMC37c669_init_local_config ( void ) +{ + SMC37c669_SERIAL_BASE_ADDRESS_REGISTER uart_base; + SMC37c669_SERIAL_IRQ_REGISTER uart_irqs; + SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER ppt_base; + SMC37c669_PARALLEL_FDC_IRQ_REGISTER ppt_fdc_irqs; + SMC37c669_PARALLEL_FDC_DRQ_REGISTER ppt_fdc_drqs; + SMC37c669_FDC_BASE_ADDRESS_REGISTER fdc_base; + SMC37c669_IDE_ADDRESS_REGISTER ide_base; + SMC37c669_IDE_ADDRESS_REGISTER ide_alt; + +/* +** Get serial port 1 base address +*/ + uart_base.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL0_BASE_ADDRESS_INDEX ); +/* +** Get IRQs for serial ports 1 & 2 +*/ + uart_irqs.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX ); +/* +** Store local configuration information for serial port 1 +*/ + local_config[SERIAL_0].port1 = uart_base.by_field.addr9_3 << 3; + local_config[SERIAL_0].irq = + SMC37c669_xlate_irq( + SMC37c669_DEVICE_IRQ( uart_irqs.by_field.uart1_irq ) + ); +/* +** Get serial port 2 base address +*/ + uart_base.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL1_BASE_ADDRESS_INDEX ); +/* +** Store local configuration information for serial port 2 +*/ + local_config[SERIAL_1].port1 = uart_base.by_field.addr9_3 << 3; + local_config[SERIAL_1].irq = + SMC37c669_xlate_irq( + SMC37c669_DEVICE_IRQ( uart_irqs.by_field.uart2_irq ) + ); +/* +** Get parallel port base address +*/ + ppt_base.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX ); +/* +** Get IRQs for parallel port and floppy controller +*/ + ppt_fdc_irqs.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX ); +/* +** Get DRQs for parallel port and floppy controller +*/ + ppt_fdc_drqs.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX ); +/* +** Store local configuration information for parallel port +*/ + local_config[PARALLEL_0].port1 = ppt_base.by_field.addr9_2 << 2; + local_config[PARALLEL_0].irq = + SMC37c669_xlate_irq( + SMC37c669_DEVICE_IRQ( ppt_fdc_irqs.by_field.ppt_irq ) + ); + local_config[PARALLEL_0].drq = + SMC37c669_xlate_drq( + SMC37c669_DEVICE_DRQ( ppt_fdc_drqs.by_field.ppt_drq ) + ); +/* +** Get floppy controller base address +*/ + fdc_base.as_uchar = + SMC37c669_read_config( SMC37c669_FDC_BASE_ADDRESS_INDEX ); +/* +** Store local configuration information for floppy controller +*/ + local_config[FLOPPY_0].port1 = fdc_base.by_field.addr9_4 << 4; + local_config[FLOPPY_0].irq = + SMC37c669_xlate_irq( + SMC37c669_DEVICE_IRQ( ppt_fdc_irqs.by_field.fdc_irq ) + ); + local_config[FLOPPY_0].drq = + SMC37c669_xlate_drq( + SMC37c669_DEVICE_DRQ( ppt_fdc_drqs.by_field.fdc_drq ) + ); +/* +** Get IDE controller base address +*/ + ide_base.as_uchar = + SMC37c669_read_config( SMC37c669_IDE_BASE_ADDRESS_INDEX ); +/* +** Get IDE alternate status base address +*/ + ide_alt.as_uchar = + SMC37c669_read_config( SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX ); +/* +** Store local configuration information for IDE controller +*/ + local_config[IDE_0].port1 = ide_base.by_field.addr9_4 << 4; + local_config[IDE_0].port2 = ide_alt.by_field.addr9_4 << 4; + local_config[IDE_0].irq = 14; +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function returns a pointer to the local shadow +** configuration of the requested device function. +** +** FORMAL PARAMETERS: +** +** func: +** Which device function +** +** RETURN VALUE: +** +** Returns a pointer to the DEVICE_CONFIG structure for the +** requested function, otherwise, NULL. +** +** SIDE EFFECTS: +** +** {@description or none@} +** +**-- +*/ +static struct DEVICE_CONFIG * __init SMC37c669_get_config( unsigned int func ) +{ + struct DEVICE_CONFIG *cp = NULL; + + switch ( func ) { + case SERIAL_0: + cp = &local_config[ SERIAL_0 ]; + break; + case SERIAL_1: + cp = &local_config[ SERIAL_1 ]; + break; + case PARALLEL_0: + cp = &local_config[ PARALLEL_0 ]; + break; + case FLOPPY_0: + cp = &local_config[ FLOPPY_0 ]; + break; + case IDE_0: + cp = &local_config[ IDE_0 ]; + break; + } + return cp; +} + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function translates IRQs back and forth between ISA +** IRQs and SMC37c669 device IRQs. +** +** FORMAL PARAMETERS: +** +** irq: +** The IRQ to translate +** +** RETURN VALUE: +** +** Returns the translated IRQ, otherwise, returns -1. +** +** SIDE EFFECTS: +** +** {@description or none@} +** +**-- +*/ +static int __init SMC37c669_xlate_irq ( unsigned int irq ) +{ + int i, translated_irq = -1; + + if ( SMC37c669_IS_DEVICE_IRQ( irq ) ) { +/* +** We are translating a device IRQ to an ISA IRQ +*/ + for ( i = 0; ( SMC37c669_irq_table[i].device_irq != -1 ) || ( SMC37c669_irq_table[i].isa_irq != -1 ); i++ ) { + if ( irq == SMC37c669_irq_table[i].device_irq ) { + translated_irq = SMC37c669_irq_table[i].isa_irq; + break; + } + } + } + else { +/* +** We are translating an ISA IRQ to a device IRQ +*/ + for ( i = 0; ( SMC37c669_irq_table[i].isa_irq != -1 ) || ( SMC37c669_irq_table[i].device_irq != -1 ); i++ ) { + if ( irq == SMC37c669_irq_table[i].isa_irq ) { + translated_irq = SMC37c669_irq_table[i].device_irq; + break; + } + } + } + return translated_irq; +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function translates DMA channels back and forth between +** ISA DMA channels and SMC37c669 device DMA channels. +** +** FORMAL PARAMETERS: +** +** drq: +** The DMA channel to translate +** +** RETURN VALUE: +** +** Returns the translated DMA channel, otherwise, returns -1 +** +** SIDE EFFECTS: +** +** {@description or none@} +** +**-- +*/ +static int __init SMC37c669_xlate_drq ( unsigned int drq ) +{ + int i, translated_drq = -1; + + if ( SMC37c669_IS_DEVICE_DRQ( drq ) ) { +/* +** We are translating a device DMA channel to an ISA DMA channel +*/ + for ( i = 0; ( SMC37c669_drq_table[i].device_drq != -1 ) || ( SMC37c669_drq_table[i].isa_drq != -1 ); i++ ) { + if ( drq == SMC37c669_drq_table[i].device_drq ) { + translated_drq = SMC37c669_drq_table[i].isa_drq; + break; + } + } + } + else { +/* +** We are translating an ISA DMA channel to a device DMA channel +*/ + for ( i = 0; ( SMC37c669_drq_table[i].isa_drq != -1 ) || ( SMC37c669_drq_table[i].device_drq != -1 ); i++ ) { + if ( drq == SMC37c669_drq_table[i].isa_drq ) { + translated_drq = SMC37c669_drq_table[i].device_drq; + break; + } + } + } + return translated_drq; +} + +#if 0 +int __init smcc669_init ( void ) +{ + struct INODE *ip; + + allocinode( smc_ddb.name, 1, &ip ); + ip->dva = &smc_ddb; + ip->attr = ATTR$M_WRITE | ATTR$M_READ; + ip->len[0] = 0x30; + ip->misc = 0; + INODE_UNLOCK( ip ); + + return msg_success; +} + +int __init smcc669_open( struct FILE *fp, char *info, char *next, char *mode ) +{ + struct INODE *ip; +/* +** Allow multiple readers but only one writer. ip->misc keeps track +** of the number of writers +*/ + ip = fp->ip; + INODE_LOCK( ip ); + if ( fp->mode & ATTR$M_WRITE ) { + if ( ip->misc ) { + INODE_UNLOCK( ip ); + return msg_failure; /* too many writers */ + } + ip->misc++; + } +/* +** Treat the information field as a byte offset +*/ + *fp->offset = xtoi( info ); + INODE_UNLOCK( ip ); + + return msg_success; +} + +int __init smcc669_close( struct FILE *fp ) +{ + struct INODE *ip; + + ip = fp->ip; + if ( fp->mode & ATTR$M_WRITE ) { + INODE_LOCK( ip ); + ip->misc--; + INODE_UNLOCK( ip ); + } + return msg_success; +} + +int __init smcc669_read( struct FILE *fp, int size, int number, unsigned char *buf ) +{ + int i; + int length; + int nbytes; + struct INODE *ip; + +/* +** Always access a byte at a time +*/ + ip = fp->ip; + length = size * number; + nbytes = 0; + + SMC37c669_config_mode( TRUE ); + for ( i = 0; i < length; i++ ) { + if ( !inrange( *fp->offset, 0, ip->len[0] ) ) + break; + *buf++ = SMC37c669_read_config( *fp->offset ); + *fp->offset += 1; + nbytes++; + } + SMC37c669_config_mode( FALSE ); + return nbytes; +} + +int __init smcc669_write( struct FILE *fp, int size, int number, unsigned char *buf ) +{ + int i; + int length; + int nbytes; + struct INODE *ip; +/* +** Always access a byte at a time +*/ + ip = fp->ip; + length = size * number; + nbytes = 0; + + SMC37c669_config_mode( TRUE ); + for ( i = 0; i < length; i++ ) { + if ( !inrange( *fp->offset, 0, ip->len[0] ) ) + break; + SMC37c669_write_config( *fp->offset, *buf ); + *fp->offset += 1; + buf++; + nbytes++; + } + SMC37c669_config_mode( FALSE ); + return nbytes; +} +#endif + +void __init +SMC37c669_dump_registers(void) +{ + int i; + for (i = 0; i <= 0x29; i++) + printk("-- CR%02x : %02x\n", i, SMC37c669_read_config(i)); +} +/*+ + * ============================================================================ + * = SMC_init - SMC37c669 Super I/O controller initialization = + * ============================================================================ + * + * OVERVIEW: + * + * This routine configures and enables device functions on the + * SMC37c669 Super I/O controller. + * + * FORM OF CALL: + * + * SMC_init( ); + * + * RETURNS: + * + * Nothing + * + * ARGUMENTS: + * + * None + * + * SIDE EFFECTS: + * + * None + * + */ +void __init SMC669_Init ( void ) +{ + SMC37c669_CONFIG_REGS *SMC_base; + + if ( ( SMC_base = SMC37c669_detect( ) ) != NULL ) { + printk( "SMC37c669 Super I/O Controller found @ 0x%lx\n", + (unsigned long) SMC_base ); +#if SMC_DEBUG + SMC37c669_config_mode( TRUE ); + SMC37c669_dump_registers( ); + SMC37c669_config_mode( FALSE ); + SMC37c669_display_device_info( ); +#endif + SMC37c669_disable_device( SERIAL_0 ); + SMC37c669_configure_device( + SERIAL_0, + COM1_BASE, + COM1_IRQ, + -1 + ); + SMC37c669_enable_device( SERIAL_0 ); + + SMC37c669_disable_device( SERIAL_1 ); + SMC37c669_configure_device( + SERIAL_1, + COM2_BASE, + COM2_IRQ, + -1 + ); + SMC37c669_enable_device( SERIAL_1 ); + + SMC37c669_disable_device( PARALLEL_0 ); + SMC37c669_configure_device( + PARALLEL_0, + PARP_BASE, + PARP_IRQ, + PARP_DRQ + ); + SMC37c669_enable_device( PARALLEL_0 ); + + SMC37c669_disable_device( FLOPPY_0 ); + SMC37c669_configure_device( + FLOPPY_0, + FDC_BASE, + FDC_IRQ, + FDC_DRQ + ); + SMC37c669_enable_device( FLOPPY_0 ); + + SMC37c669_disable_device( IDE_0 ); + +#if SMC_DEBUG + SMC37c669_config_mode( TRUE ); + SMC37c669_dump_registers( ); + SMC37c669_config_mode( FALSE ); + SMC37c669_display_device_info( ); +#endif + } + else { +#if SMC_DEBUG + printk( "No SMC37c669 Super I/O Controller found\n" ); +#endif + } +} diff -u --recursive --new-file v2.1.88/linux/arch/alpha/kernel/smc37c93x.c linux/arch/alpha/kernel/smc37c93x.c --- v2.1.88/linux/arch/alpha/kernel/smc37c93x.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/smc37c93x.c Mon Feb 23 10:25:10 1998 @@ -0,0 +1,264 @@ +/* + * SMC 37C93X initialization code + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#if 0 +# define DBG_DEVS(args) printk args +#else +# define DBG_DEVS(args) +#endif + +#define KB 1024 +#define MB (1024*KB) +#define GB (1024*MB) + +/* device "activate" register contents */ +#define DEVICE_ON 1 +#define DEVICE_OFF 0 + +/* configuration on/off keys */ +#define CONFIG_ON_KEY 0x55 +#define CONFIG_OFF_KEY 0xaa + +/* configuration space device definitions */ +#define FDC 0 +#define IDE1 1 +#define IDE2 2 +#define PARP 3 +#define SER1 4 +#define SER2 5 +#define RTCL 6 +#define KYBD 7 +#define AUXIO 8 + +/* Chip register offsets from base */ +#define CONFIG_CONTROL 0x02 +#define INDEX_ADDRESS 0x03 +#define LOGICAL_DEVICE_NUMBER 0x07 +#define DEVICE_ID 0x20 +#define DEVICE_REV 0x21 +#define POWER_CONTROL 0x22 +#define POWER_MGMT 0x23 +#define OSC 0x24 + +#define ACTIVATE 0x30 +#define ADDR_HI 0x60 +#define ADDR_LO 0x61 +#define INTERRUPT_SEL 0x70 +#define INTERRUPT_SEL_2 0x72 /* KYBD/MOUS only */ +#define DMA_CHANNEL_SEL 0x74 /* FDC/PARP only */ + +#define FDD_MODE_REGISTER 0x90 +#define FDD_OPTION_REGISTER 0x91 + +/* values that we read back that are expected ... */ +#define VALID_DEVICE_ID 2 + +/* default device addresses */ +#define KYBD_INTERRUPT 1 +#define MOUS_INTERRUPT 12 +#define COM2_BASE 0x2f8 +#define COM2_INTERRUPT 3 +#define COM1_BASE 0x3f8 +#define COM1_INTERRUPT 4 +#define PARP_BASE 0x3bc +#define PARP_INTERRUPT 7 + +#define SMC_DEBUG 0 + +static unsigned long __init SMCConfigState(unsigned long baseAddr) +{ + unsigned char devId; + unsigned char devRev; + + unsigned long configPort; + unsigned long indexPort; + unsigned long dataPort; + + configPort = indexPort = baseAddr; + dataPort = configPort + 1; + + outb(CONFIG_ON_KEY, configPort); + outb(CONFIG_ON_KEY, configPort); + outb(DEVICE_ID, indexPort); + devId = inb(dataPort); + if ( devId == VALID_DEVICE_ID ) { + outb(DEVICE_REV, indexPort); + devRev = inb(dataPort); + } + else { + baseAddr = 0; + } + return baseAddr; +} + +static void __init SMCRunState(unsigned long baseAddr) +{ + outb(CONFIG_OFF_KEY, baseAddr); +} + +static unsigned long __init SMCDetectUltraIO(void) +{ + unsigned long baseAddr; + + baseAddr = 0x3F0; + if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x3F0 ) { + return( baseAddr ); + } + baseAddr = 0x370; + if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x370 ) { + return( baseAddr ); + } + return( ( unsigned long )0 ); +} + +static void __init SMCEnableDevice(unsigned long baseAddr, + unsigned long device, + unsigned long portaddr, + unsigned long interrupt) +{ + unsigned long indexPort; + unsigned long dataPort; + + indexPort = baseAddr; + dataPort = baseAddr + 1; + + outb(LOGICAL_DEVICE_NUMBER, indexPort); + outb(device, dataPort); + + outb(ADDR_LO, indexPort); + outb(( portaddr & 0xFF ), dataPort); + + outb(ADDR_HI, indexPort); + outb((portaddr >> 8) & 0xFF, dataPort); + + outb(INTERRUPT_SEL, indexPort); + outb(interrupt, dataPort); + + outb(ACTIVATE, indexPort); + outb(DEVICE_ON, dataPort); +} + +static void __init SMCEnableKYBD(unsigned long baseAddr) +{ + unsigned long indexPort; + unsigned long dataPort; + + indexPort = baseAddr; + dataPort = baseAddr + 1; + + outb(LOGICAL_DEVICE_NUMBER, indexPort); + outb(KYBD, dataPort); + + outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */ + outb(KYBD_INTERRUPT, dataPort); + + outb(INTERRUPT_SEL_2, indexPort); /* Secondary interrupt select */ + outb(MOUS_INTERRUPT, dataPort); + + outb(ACTIVATE, indexPort); + outb(DEVICE_ON, dataPort); +} + +static void __init SMCEnableFDC(unsigned long baseAddr) +{ + unsigned long indexPort; + unsigned long dataPort; + + unsigned char oldValue; + + indexPort = baseAddr; + dataPort = baseAddr + 1; + + outb(LOGICAL_DEVICE_NUMBER, indexPort); + outb(FDC, dataPort); + + outb(FDD_MODE_REGISTER, indexPort); + oldValue = inb(dataPort); + + oldValue |= 0x0E; /* Enable burst mode */ + outb(oldValue, dataPort); + + outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */ + outb(0x06, dataPort ); + + outb(DMA_CHANNEL_SEL, indexPort); /* DMA channel select */ + outb(0x02, dataPort); + + outb(ACTIVATE, indexPort); + outb(DEVICE_ON, dataPort); +} + +#if SMC_DEBUG +static void __init SMCReportDeviceStatus(unsigned long baseAddr) +{ + unsigned long indexPort; + unsigned long dataPort; + unsigned char currentControl; + + indexPort = baseAddr; + dataPort = baseAddr + 1; + + outb(POWER_CONTROL, indexPort); + currentControl = inb(dataPort); + + printk(currentControl & (1 << FDC) + ? "\t+FDC Enabled\n" : "\t-FDC Disabled\n"); + printk(currentControl & (1 << IDE1) + ? "\t+IDE1 Enabled\n" : "\t-IDE1 Disabled\n"); + printk(currentControl & (1 << IDE2) + ? "\t+IDE2 Enabled\n" : "\t-IDE2 Disabled\n"); + printk(currentControl & (1 << PARP) + ? "\t+PARP Enabled\n" : "\t-PARP Disabled\n"); + printk(currentControl & (1 << SER1) + ? "\t+SER1 Enabled\n" : "\t-SER1 Disabled\n"); + printk(currentControl & (1 << SER2) + ? "\t+SER2 Enabled\n" : "\t-SER2 Disabled\n"); + + printk( "\n" ); +} +#endif + +int __init SMC93x_Init(void) +{ + unsigned long SMCUltraBase; + + if ((SMCUltraBase = SMCDetectUltraIO()) != 0UL) { + printk("SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n", + SMCUltraBase); +#if SMC_DEBUG + SMCReportDeviceStatus(SMCUltraBase); +#endif + SMCEnableDevice(SMCUltraBase, SER1, COM1_BASE, COM1_INTERRUPT); + SMCEnableDevice(SMCUltraBase, SER2, COM2_BASE, COM2_INTERRUPT); + SMCEnableDevice(SMCUltraBase, PARP, PARP_BASE, PARP_INTERRUPT); + /* On PC164, IDE on the SMC is not enabled; + CMD646 (PCI) on MB */ + SMCEnableKYBD(SMCUltraBase); + SMCEnableFDC(SMCUltraBase); +#if SMC_DEBUG + SMCReportDeviceStatus(SMCUltraBase); +#endif + SMCRunState(SMCUltraBase); + return 1; + } + else { +#if SMC_DEBUG + printk("No SMC FDC37C93X Ultra I/O Controller found\n"); +#endif + return 0; + } +} diff -u --recursive --new-file v2.1.88/linux/arch/i386/kernel/ldt.c linux/arch/i386/kernel/ldt.c --- v2.1.88/linux/arch/i386/kernel/ldt.c Fri Nov 14 18:28:48 1997 +++ linux/arch/i386/kernel/ldt.c Sat Feb 21 12:42:28 1998 @@ -33,31 +33,6 @@ return copy_to_user(ptr, address, size) ? -EFAULT : size; } -static inline int limits_ok(struct modify_ldt_ldt_s *ldt_info) -{ - unsigned long base, limit; - /* linear address of first and last accessible byte */ - unsigned long first, last; - - base = ldt_info->base_addr; - limit = ldt_info->limit; - if (ldt_info->limit_in_pages) - limit = limit * PAGE_SIZE + PAGE_SIZE - 1; - - first = base; - last = limit + base; - - /* segment grows down? */ - if (ldt_info->contents == 1) { - /* data segment grows down */ - first = base+limit+1; - last = base+65535; - if (ldt_info->seg_32bit) - last = base-1; - } - return (last >= first && last < TASK_SIZE); -} - static int write_ldt(void * ptr, unsigned long bytecount, int oldmode) { struct modify_ldt_ldt_s ldt_info; @@ -71,9 +46,6 @@ return -EFAULT; if ((ldt_info.contents == 3 && (oldmode || ldt_info.seg_not_present == 0)) || ldt_info.entry_number >= LDT_ENTRIES) - return -EINVAL; - - if (!limits_ok(&ldt_info) && (oldmode || ldt_info.seg_not_present == 0)) return -EINVAL; if (!current->ldt) { diff -u --recursive --new-file v2.1.88/linux/drivers/acorn/block/fd1772.c linux/drivers/acorn/block/fd1772.c --- v2.1.88/linux/drivers/acorn/block/fd1772.c Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/block/fd1772.c Sat Feb 21 13:25:15 1998 @@ -116,7 +116,6 @@ * 16/11/96 - Fiddled and frigged for 2.0.18 */ -#include #include #include #include diff -u --recursive --new-file v2.1.88/linux/drivers/acorn/scsi/cumana_1.c linux/drivers/acorn/scsi/cumana_1.c --- v2.1.88/linux/drivers/acorn/scsi/cumana_1.c Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/scsi/cumana_1.c Sat Feb 21 13:25:15 1998 @@ -36,7 +36,6 @@ * $Log: cumana_NCR5380.c,v $ */ -#include #include #include #include diff -u --recursive --new-file v2.1.88/linux/drivers/acorn/scsi/ecoscsi.c linux/drivers/acorn/scsi/ecoscsi.c --- v2.1.88/linux/drivers/acorn/scsi/ecoscsi.c Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/scsi/ecoscsi.c Sat Feb 21 13:25:15 1998 @@ -35,7 +35,6 @@ * $Log: ecoscsi_NCR5380.c,v $ */ -#include #include #include #include diff -u --recursive --new-file v2.1.88/linux/drivers/acorn/scsi/oak.c linux/drivers/acorn/scsi/oak.c --- v2.1.88/linux/drivers/acorn/scsi/oak.c Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/scsi/oak.c Sat Feb 21 13:25:15 1998 @@ -35,7 +35,6 @@ * $Log: oak.c,v $ */ -#include #include #include #include diff -u --recursive --new-file v2.1.88/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.1.88/linux/drivers/block/floppy.c Tue Feb 17 13:12:46 1998 +++ linux/drivers/block/floppy.c Sun Feb 22 10:48:45 1998 @@ -148,7 +148,7 @@ #include #include -static int can_use_virtual_dma=0; +static int can_use_virtual_dma=2; /* ======= * can use virtual DMA: * 0 = use of virtual DMA disallowed by config @@ -2083,7 +2083,7 @@ #define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2) #define FM_MODE(x,y) ((y) & ~(((x)->rate & 0x80) >>1)) -#define CT(x) ((x) | 0x40) +#define CT(x) ((x) | 0xc0) static void setup_format_params(int track) { struct fparm { @@ -2465,6 +2465,32 @@ } #endif +/* work around a bug in pseudo DMA + * (on some FDCs) pseudo DMA does not stop when the CPU stops + * sending data. Hence we need a different way to signal the + * transfer length: We use SECT_PER_TRACK. Unfortunately, this + * does not work with MT, hence we can only transfer one head at + * a time + */ +static int virtualdmabug_workaround() { + int hard_sectors, end_sector; + if(CT(COMMAND) == FD_WRITE) { + COMMAND &= ~0x80; /* switch off multiple track mode */ + + hard_sectors = raw_cmd->length >> (7 + SIZECODE); + end_sector = SECTOR + hard_sectors - 1; +#ifdef FLOPPY_SANITY_CHECK + if(end_sector > SECT_PER_TRACK) { + printk("too many sectors %d > %d\n", + end_sector, SECT_PER_TRACK); + return 0; + } +#endif + SECT_PER_TRACK = end_sector; /* make sure SECT_PER_TRACK points + * to end of transfer */ + } +} + /* * Formulate a read/write request. * this routine decides where to load the data (directly to buffer, or to @@ -2541,11 +2567,17 @@ CODE2SIZE; SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE; SECTOR = ((sector_t % _floppy->sect) << 2 >> SIZECODE) + 1; + + /* tracksize describes the size which can be filled up with sectors + * of size ssize. + */ tracksize = _floppy->sect - _floppy->sect % ssize; if (tracksize < _floppy->sect){ SECT_PER_TRACK ++; if (tracksize <= sector_t % _floppy->sect) SECTOR--; + + /* if we are beyond tracksize, fill up using smaller sectors */ while (tracksize <= sector_t % _floppy->sect){ while(tracksize + ssize > _floppy->sect){ SIZECODE--; @@ -2555,8 +2587,12 @@ tracksize += ssize; } max_sector = HEAD * _floppy->sect + tracksize; - } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) + } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) { + max_sector = _floppy->sect; + } else if (!HEAD && CT(COMMAND) == FD_WRITE) { + /* for virtual DMA bug workaround */ max_sector = _floppy->sect; + } aligned_sector_t = sector_t - (sector_t % _floppy->sect) % ssize; max_size = CURRENT->nr_sectors; @@ -2625,6 +2661,8 @@ /* check_dma_crossing(raw_cmd->kernel_data, raw_cmd->length, "end of make_raw_request [1]");*/ + + virtualdmabug_workaround(); return 2; } } @@ -2730,6 +2768,8 @@ return 0; } #endif + + virtualdmabug_workaround(); return 2; } diff -u --recursive --new-file v2.1.88/linux/drivers/char/rtc.c linux/drivers/char/rtc.c --- v2.1.88/linux/drivers/char/rtc.c Mon Dec 8 23:58:04 1997 +++ linux/drivers/char/rtc.c Mon Feb 23 10:25:10 1998 @@ -28,9 +28,14 @@ * Based on other minimal char device drivers, like Alan's * watchdog, Ted's random, etc. etc. * + * 1.07 Paul Gortmaker. + * 1.08 Miquel van Smoorenburg: disallow certain things on the + * DEC Alpha as the CMOS clock is also used for other things. + * 1.09 Nikita Schmidt: epoch support and some Alpha cleanup. + * */ -#define RTC_VERSION "1.07" +#define RTC_VERSION "1.09" #define RTC_IRQ 8 /* Can't see this changing soon. */ #define RTC_IO_EXTENT 0x10 /* Only really two ports, but... */ @@ -82,7 +87,7 @@ size_t count, loff_t *ppos); static int rtc_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); + unsigned int cmd, unsigned long arg); static unsigned int rtc_poll(struct file *file, poll_table *wait); @@ -106,16 +111,27 @@ unsigned long rtc_freq = 0; /* Current periodic IRQ rate */ unsigned long rtc_irq_data = 0; /* our output to the world */ +/* + * If this driver ever becomes modularised, it will be really nice + * to make the epoch retain its value across module reload... + */ + +static unsigned long epoch = 1900; /* year corresponding to 0x00 */ + unsigned char days_in_mo[] = - {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; /* * A very tiny interrupt handler. It runs with SA_INTERRUPT set, * so that there is no possibility of conflicting with the * set_rtc_mmss() call that happens during some timer interrupts. * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) + * + * On Alpha we won't get any interrupts anyway, as they all end up + * in the system timer code. */ +#ifndef __alpha__ static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { /* @@ -136,9 +152,11 @@ add_timer(&rtc_irq_timer); } } +#endif /* * Now all the various file operations that we export. + * They are all useless on Alpha... *sigh*. */ static long long rtc_llseek(struct file *file, loff_t offset, int origin) @@ -149,6 +167,9 @@ static ssize_t rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos) { +#ifdef __alpha__ + return -EIO; +#else struct wait_queue wait = { current, NULL }; unsigned long data; ssize_t retval; @@ -175,239 +196,269 @@ retval = put_user(data, (unsigned long *)buf); if (!retval) retval = sizeof(unsigned long); -out: + out: current->state = TASK_RUNNING; remove_wait_queue(&rtc_wait, &wait); return retval; +#endif } static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) + unsigned long arg) { unsigned long flags; struct rtc_time wtime; switch (cmd) { - case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ - { - mask_rtc_irq_bit(RTC_AIE); - return 0; - } - case RTC_AIE_ON: /* Allow alarm interrupts. */ - { - set_rtc_irq_bit(RTC_AIE); - return 0; - } - case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ - { - mask_rtc_irq_bit(RTC_PIE); - if (rtc_status & RTC_TIMER_ON) { - del_timer(&rtc_irq_timer); - rtc_status &= ~RTC_TIMER_ON; - } - return 0; +#ifndef __alpha__ + case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ + { + mask_rtc_irq_bit(RTC_AIE); + return 0; + } + case RTC_AIE_ON: /* Allow alarm interrupts. */ + { + set_rtc_irq_bit(RTC_AIE); + return 0; + } + case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ + { + mask_rtc_irq_bit(RTC_PIE); + if (rtc_status & RTC_TIMER_ON) { + del_timer(&rtc_irq_timer); + rtc_status &= ~RTC_TIMER_ON; } - case RTC_PIE_ON: /* Allow periodic ints */ - { + return 0; + } + case RTC_PIE_ON: /* Allow periodic ints */ + { - /* - * We don't really want Joe User enabling more - * than 64Hz of interrupts on a multi-user machine. - */ - if ((rtc_freq > 64) && (!suser())) - return -EACCES; - - if (!(rtc_status & RTC_TIMER_ON)) { - rtc_status |= RTC_TIMER_ON; - rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100; - add_timer(&rtc_irq_timer); - } - set_rtc_irq_bit(RTC_PIE); - return 0; - } - case RTC_UIE_OFF: /* Mask ints from RTC updates. */ - { - mask_rtc_irq_bit(RTC_UIE); - return 0; + /* + * We don't really want Joe User enabling more + * than 64Hz of interrupts on a multi-user machine. + */ + if ((rtc_freq > 64) && (!suser())) + return -EACCES; + + if (!(rtc_status & RTC_TIMER_ON)) { + rtc_status |= RTC_TIMER_ON; + rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100; + add_timer(&rtc_irq_timer); } - case RTC_UIE_ON: /* Allow ints for RTC updates. */ - { - set_rtc_irq_bit(RTC_UIE); - return 0; - } - case RTC_ALM_READ: /* Read the present alarm time */ - { - /* - * This returns a struct rtc_time. Reading >= 0xc0 - * means "don't care" or "match all". Only the tm_hour, - * tm_min, and tm_sec values are filled in. - */ + set_rtc_irq_bit(RTC_PIE); + return 0; + } + case RTC_UIE_OFF: /* Mask ints from RTC updates. */ + { + mask_rtc_irq_bit(RTC_UIE); + return 0; + } + case RTC_UIE_ON: /* Allow ints for RTC updates. */ + { + set_rtc_irq_bit(RTC_UIE); + return 0; + } +#endif + case RTC_ALM_READ: /* Read the present alarm time */ + { + /* + * This returns a struct rtc_time. Reading >= 0xc0 + * means "don't care" or "match all". Only the tm_hour, + * tm_min, and tm_sec values are filled in. + */ - get_rtc_alm_time(&wtime); - break; - } - case RTC_ALM_SET: /* Store a time into the alarm */ - { - /* - * This expects a struct rtc_time. Writing 0xff means - * "don't care" or "match all". Only the tm_hour, - * tm_min and tm_sec are used. - */ - unsigned char hrs, min, sec; - struct rtc_time alm_tm; - - if (copy_from_user(&alm_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) - return -EFAULT; - - hrs = alm_tm.tm_hour; - min = alm_tm.tm_min; - sec = alm_tm.tm_sec; - - if (hrs >= 24) - hrs = 0xff; - - if (min >= 60) - min = 0xff; - - if (sec >= 60) - sec = 0xff; - - save_flags(flags); - cli(); - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || - RTC_ALWAYS_BCD) - { - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hrs); - } - CMOS_WRITE(hrs, RTC_HOURS_ALARM); - CMOS_WRITE(min, RTC_MINUTES_ALARM); - CMOS_WRITE(sec, RTC_SECONDS_ALARM); - restore_flags(flags); + get_rtc_alm_time(&wtime); + break; + } + case RTC_ALM_SET: /* Store a time into the alarm */ + { + /* + * This expects a struct rtc_time. Writing 0xff means + * "don't care" or "match all". Only the tm_hour, + * tm_min and tm_sec are used. + */ + unsigned char hrs, min, sec; + struct rtc_time alm_tm; + + if (copy_from_user(&alm_tm, (struct rtc_time*)arg, + sizeof(struct rtc_time))) + return -EFAULT; + + hrs = alm_tm.tm_hour; + min = alm_tm.tm_min; + sec = alm_tm.tm_sec; + + if (hrs >= 24) + hrs = 0xff; + + if (min >= 60) + min = 0xff; + + if (sec >= 60) + sec = 0xff; + + save_flags(flags); + cli(); + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || + RTC_ALWAYS_BCD) + { + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + } + CMOS_WRITE(hrs, RTC_HOURS_ALARM); + CMOS_WRITE(min, RTC_MINUTES_ALARM); + CMOS_WRITE(sec, RTC_SECONDS_ALARM); + restore_flags(flags); - return 0; - } - case RTC_RD_TIME: /* Read the time/date from RTC */ - { - get_rtc_time(&wtime); - break; - } - case RTC_SET_TIME: /* Set the RTC */ - { - struct rtc_time rtc_tm; - unsigned char mon, day, hrs, min, sec, leap_yr; - unsigned char save_control, save_freq_select; - unsigned int yrs; - unsigned long flags; + return 0; + } + case RTC_RD_TIME: /* Read the time/date from RTC */ + { + get_rtc_time(&wtime); + break; + } + case RTC_SET_TIME: /* Set the RTC */ + { + struct rtc_time rtc_tm; + unsigned char mon, day, hrs, min, sec, leap_yr; + unsigned char save_control, save_freq_select; + unsigned int yrs; + unsigned long flags; - if (!suser()) - return -EACCES; - - if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) - return -EFAULT; + if (!suser()) + return -EACCES; - yrs = rtc_tm.tm_year + 1900 + ARCFUDGE; - mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ - day = rtc_tm.tm_mday; - hrs = rtc_tm.tm_hour; - min = rtc_tm.tm_min; - sec = rtc_tm.tm_sec; + if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, + sizeof(struct rtc_time))) + return -EFAULT; + + yrs = rtc_tm.tm_year + 1900 + ARCFUDGE; + mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ + day = rtc_tm.tm_mday; + hrs = rtc_tm.tm_hour; + min = rtc_tm.tm_min; + sec = rtc_tm.tm_sec; - if ((yrs < 1970) || (yrs > 2069)) - return -EINVAL; + if (yrs < 1970) + return -EINVAL; - leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); - if ((mon > 12) || (day == 0)) - return -EINVAL; + if ((mon > 12) || (day == 0)) + return -EINVAL; - if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) - return -EINVAL; + if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; - if ((hrs >= 24) || (min >= 60) || (sec >= 60)) - return -EINVAL; + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; - if (yrs >= 2000) - yrs -= 2000; /* RTC (0, 1, ... 69) */ - else - yrs -= 1900; /* RTC (70, 71, ... 99) */ - - save_flags(flags); - cli(); - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || - RTC_ALWAYS_BCD) - { - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hrs); - BIN_TO_BCD(day); - BIN_TO_BCD(mon); - BIN_TO_BCD(yrs); + if ((yrs -= epoch) > 255) /* They are unsigned */ + return -EINVAL; + + save_flags(flags); + cli(); + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) + || RTC_ALWAYS_BCD) { + if (yrs > 169) { + restore_flags(flags); + return -EINVAL; } + if (yrs >= 100) + yrs -= 100; - save_control = CMOS_READ(RTC_CONTROL); - CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); - save_freq_select = CMOS_READ(RTC_FREQ_SELECT); - CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - - CMOS_WRITE(yrs, RTC_YEAR); - CMOS_WRITE(mon, RTC_MONTH); - CMOS_WRITE(day, RTC_DAY_OF_MONTH); - CMOS_WRITE(hrs, RTC_HOURS); - CMOS_WRITE(min, RTC_MINUTES); - CMOS_WRITE(sec, RTC_SECONDS); + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(yrs); + } + + save_control = CMOS_READ(RTC_CONTROL); + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + CMOS_WRITE(yrs, RTC_YEAR); + CMOS_WRITE(mon, RTC_MONTH); + CMOS_WRITE(day, RTC_DAY_OF_MONTH); + CMOS_WRITE(hrs, RTC_HOURS); + CMOS_WRITE(min, RTC_MINUTES); + CMOS_WRITE(sec, RTC_SECONDS); - CMOS_WRITE(save_control, RTC_CONTROL); - CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - restore_flags(flags); - return 0; - } - case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ - { - return put_user(rtc_freq, (unsigned long *)arg); - } - case RTC_IRQP_SET: /* Set periodic IRQ rate. */ - { - int tmp = 0; - unsigned char val; + restore_flags(flags); + return 0; + } + case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ + { + return put_user(rtc_freq, (unsigned long *)arg); + } +#ifndef __alpha__ + case RTC_IRQP_SET: /* Set periodic IRQ rate. */ + { + int tmp = 0; + unsigned char val; - /* - * The max we can do is 8192Hz. - */ - if ((arg < 2) || (arg > 8192)) - return -EINVAL; - /* - * We don't really want Joe User generating more - * than 64Hz of interrupts on a multi-user machine. - */ - if ((arg > 64) && (!suser())) - return -EACCES; - - while (arg > (1< 8192)) + return -EINVAL; + /* + * We don't really want Joe User generating more + * than 64Hz of interrupts on a multi-user machine. + */ + if ((arg > 64) && (!suser())) + return -EACCES; + + while (arg > (1< 10 && year < 44) { + epoch = 1980; + guess = "ARC console"; + } else if (year < 96) { + epoch = 1952; + guess = "Digital UNIX"; + } + if (guess) + printk("rtc: %s epoch (%ld) detected\n", guess, epoch); +#else init_timer(&rtc_irq_timer); rtc_irq_timer.function = rtc_dropped_irq; rtc_wait = NULL; @@ -514,6 +610,7 @@ CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT); restore_flags(flags); rtc_freq = 1024; +#endif return 0; } @@ -529,6 +626,7 @@ * for something that requires a steady > 1KHz signal anyways.) */ +#ifndef __alpha__ void rtc_dropped_irq(unsigned long data) { unsigned long flags; @@ -545,6 +643,7 @@ rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */ restore_flags(flags); } +#endif /* * Info exported via "/proc/rtc". @@ -572,10 +671,10 @@ * time or for Universal Standard Time (GMT). Probably local though. */ p += sprintf(p, - "rtc_time\t: %02d:%02d:%02d\n" - "rtc_date\t: %04d-%02d-%02d\n", - tm.tm_hour, tm.tm_min, tm.tm_sec, - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); get_rtc_alm_time(&tm); @@ -601,24 +700,24 @@ p += sprintf(p, "**\n"); p += sprintf(p, - "DST_enable\t: %s\n" - "BCD\t\t: %s\n" - "24hr\t\t: %s\n" - "square_wave\t: %s\n" - "alarm_IRQ\t: %s\n" - "update_IRQ\t: %s\n" - "periodic_IRQ\t: %s\n" - "periodic_freq\t: %ld\n" - "batt_status\t: %s\n", - (ctrl & RTC_DST_EN) ? "yes" : "no", - (ctrl & RTC_DM_BINARY) ? "no" : "yes", - (ctrl & RTC_24H) ? "yes" : "no", - (ctrl & RTC_SQWE) ? "yes" : "no", - (ctrl & RTC_AIE) ? "yes" : "no", - (ctrl & RTC_UIE) ? "yes" : "no", - (ctrl & RTC_PIE) ? "yes" : "no", - rtc_freq, - batt ? "okay" : "dead"); + "DST_enable\t: %s\n" + "BCD\t\t: %s\n" + "24hr\t\t: %s\n" + "square_wave\t: %s\n" + "alarm_IRQ\t: %s\n" + "update_IRQ\t: %s\n" + "periodic_IRQ\t: %s\n" + "periodic_freq\t: %ld\n" + "batt_status\t: %s\n", + (ctrl & RTC_DST_EN) ? "yes" : "no", + (ctrl & RTC_DM_BINARY) ? "no" : "yes", + (ctrl & RTC_24H) ? "yes" : "no", + (ctrl & RTC_SQWE) ? "yes" : "no", + (ctrl & RTC_AIE) ? "yes" : "no", + (ctrl & RTC_UIE) ? "yes" : "no", + (ctrl & RTC_PIE) ? "yes" : "no", + rtc_freq, + batt ? "okay" : "dead"); return p - buf; } @@ -689,7 +788,7 @@ * Account for differences between how the RTC uses the values * and how they are defined in a struct rtc_time; */ - if (rtc_tm->tm_year <= 69) + if ((rtc_tm->tm_year += epoch - 1900) <= 69) rtc_tm->tm_year += 100; /* if ARCFUDGE == 0, the optimizer should do away with this */ @@ -732,6 +831,8 @@ * We also clear out any old irq data after an ioctl() that * meddles with the interrupt enable/disable bits. */ + +#ifndef __alpha__ void mask_rtc_irq_bit(unsigned char bit) { unsigned char val; @@ -761,4 +862,4 @@ rtc_irq_data = 0; restore_flags(flags); } - +#endif diff -u --recursive --new-file v2.1.88/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.1.88/linux/drivers/scsi/Config.in Thu Feb 12 20:56:09 1998 +++ linux/drivers/scsi/Config.in Mon Feb 23 13:01:55 1998 @@ -123,7 +123,7 @@ # The actual configuration in any kernel release could change at any time as I hack it to # simulate various conditions that I am testing. # -if [ "`whoami`" = "eric" ]; then +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI fi if [ "$CONFIG_PPC" = "y" ]; then diff -u --recursive --new-file v2.1.88/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v2.1.88/linux/drivers/scsi/sr.c Mon Feb 23 18:12:08 1998 +++ linux/drivers/scsi/sr.c Sat Feb 21 12:34:38 1998 @@ -471,7 +471,7 @@ { spin_unlock_irqrestore(&io_request_lock, flags); scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0); - /* scsi_ioctl may allow CURRENT to change, so start over. * + /* scsi_ioctl may allow CURRENT to change, so start over. */ SDev->was_reset = 0; continue; } diff -u --recursive --new-file v2.1.88/linux/drivers/sound/sound_firmware.c linux/drivers/sound/sound_firmware.c --- v2.1.88/linux/drivers/sound/sound_firmware.c Mon Dec 1 10:34:11 1997 +++ linux/drivers/sound/sound_firmware.c Mon Feb 23 10:25:15 1998 @@ -5,8 +5,6 @@ #include #include -static int errno; - static int do_mod_firmware_load(const char *fn, char **fp) { int fd; diff -u --recursive --new-file v2.1.88/linux/fs/buffer.c linux/fs/buffer.c --- v2.1.88/linux/fs/buffer.c Mon Feb 23 18:12:10 1998 +++ linux/fs/buffer.c Mon Feb 23 15:24:32 1998 @@ -1321,14 +1321,13 @@ /* Run the hooks that have to be done when a page I/O has completed. */ static inline void after_unlock_page (struct page * page) { - if (test_and_clear_bit(PG_decr_after, &page->flags)) + if (test_and_clear_bit(PG_decr_after, &page->flags)) { atomic_dec(&nr_async_pages); - if (test_and_clear_bit(PG_swap_unlock_after, &page->flags)) { - /* - * We're doing a swap, so check that this page is - * swap-cached and do the necessary cleanup. - */ - swap_after_unlock_page(page->offset); +#ifdef DEBUG_SWAP + printk ("DebugVM: Finished IO on page %p, nr_async_pages %d\n", + (char *) page_address(page), + atomic_read(&nr_async_pages)); +#endif } if (test_and_clear_bit(PG_free_after, &page->flags)) __free_page(page); diff -u --recursive --new-file v2.1.88/linux/fs/fat/file.c linux/fs/fat/file.c --- v2.1.88/linux/fs/fat/file.c Fri Jan 23 18:10:32 1998 +++ linux/fs/fat/file.c Sun Feb 22 10:48:11 1998 @@ -105,7 +105,7 @@ NULL, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ - NULL, /* readpage */ + generic_readpage, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ fat_truncate, /* truncate */ diff -u --recursive --new-file v2.1.88/linux/fs/inode.c linux/fs/inode.c --- v2.1.88/linux/fs/inode.c Thu Feb 12 20:56:12 1998 +++ linux/fs/inode.c Mon Feb 23 12:56:37 1998 @@ -701,19 +701,22 @@ list_add(&inode->i_list, inode_in_use.prev); } #ifdef INODE_PARANOIA +if (inode->i_flock) +printk(KERN_ERR "iput: inode %s/%ld still has locks!\n", +kdevname(inode->i_dev), inode->i_ino); if (!list_empty(&inode->i_dentry)) -printk("iput: device %s inode %ld still has aliases!\n", +printk(KERN_ERR "iput: device %s inode %ld still has aliases!\n", kdevname(inode->i_dev), inode->i_ino); if (inode->i_count) -printk("iput: device %s inode %ld count changed, count=%d\n", +printk(KERN_ERR "iput: device %s inode %ld count changed, count=%d\n", kdevname(inode->i_dev), inode->i_ino, inode->i_count); if (atomic_read(&inode->i_sem.count) != 1) -printk("iput: Aieee, semaphore in use device %s, count=%d\n", +printk(KERN_ERR "iput: Aieee, semaphore in use device %s, count=%d\n", kdevname(inode->i_dev), atomic_read(&inode->i_sem.count)); #endif } - if (inode->i_count > (1<<15)) { - printk("iput: device %s inode %ld count wrapped\n", + if (inode->i_count > (1<<31)) { + printk(KERN_ERR "iput: inode %s/%ld count wrapped\n", kdevname(inode->i_dev), inode->i_ino); } spin_unlock(&inode_lock); diff -u --recursive --new-file v2.1.88/linux/fs/ioctl.c linux/fs/ioctl.c --- v2.1.88/linux/fs/ioctl.c Sun Jul 13 21:20:10 1997 +++ linux/fs/ioctl.c Mon Feb 23 12:55:58 1998 @@ -13,6 +13,7 @@ #include #include #include /* for f_flags values */ +#include #include @@ -52,7 +53,8 @@ int on, error = -EBADF; lock_kernel(); - if (fd >= NR_OPEN || !(filp = current->files->fd[fd])) + filp = fget(fd); + if (!filp) goto out; error = 0; switch (cmd) { @@ -90,13 +92,16 @@ break; default: - if (filp->f_dentry && filp->f_dentry->d_inode && S_ISREG(filp->f_dentry->d_inode->i_mode)) + error = -ENOTTY; + if (!filp->f_dentry || !filp->f_dentry->d_inode) + error = -ENOENT; + else if (S_ISREG(filp->f_dentry->d_inode->i_mode)) error = file_ioctl(filp, cmd, arg); else if (filp->f_op && filp->f_op->ioctl) error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg); - else - error = -ENOTTY; } + fput(filp); + out: unlock_kernel(); return error; diff -u --recursive --new-file v2.1.88/linux/fs/isofs/dir.c linux/fs/isofs/dir.c --- v2.1.88/linux/fs/isofs/dir.c Thu Dec 18 16:37:02 1997 +++ linux/fs/isofs/dir.c Sat Feb 21 13:19:29 1998 @@ -101,11 +101,12 @@ unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); unsigned char bufbits = ISOFS_BUFFER_BITS(inode); unsigned int block, offset; - int inode_number; + int inode_number = 0; /* Quiet GCC */ struct buffer_head *bh; int len; int map; - int high_sierra = 0; + int high_sierra; + int first_de = 1; char *p = NULL; /* Quiet GCC */ struct iso_directory_record *de; @@ -114,6 +115,7 @@ offset = filp->f_pos & (bufsize - 1); block = isofs_bmap(inode, filp->f_pos >> bufbits); + high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra; if (!block) return 0; @@ -129,7 +131,7 @@ printk("inode->i_size = %x\n",inode->i_size); #endif de = (struct iso_directory_record *) (bh->b_data + offset); - inode_number = (block << bufbits) + (offset & (bufsize - 1)); + if(first_de) inode_number = (block << bufbits) + (offset & (bufsize - 1)); de_len = *(unsigned char *) de; #ifdef DEBUG @@ -177,6 +179,13 @@ break; } + if(de->flags[-high_sierra] & 0x80) { + first_de = 0; + filp->f_pos += de_len; + continue; + } + first_de = 1; + /* Handle the case of the '.' directory */ if (de->name_len[0] == 1 && de->name[0] == 0) { if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0) @@ -200,7 +209,6 @@ is no Rock Ridge NM field. */ if (inode->i_sb->u.isofs_sb.s_unhide == 'n') { /* Do not report hidden or associated files */ - high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra; if (de->flags[-high_sierra] & 5) { filp->f_pos += de_len; continue; diff -u --recursive --new-file v2.1.88/linux/fs/isofs/inode.c linux/fs/isofs/inode.c --- v2.1.88/linux/fs/isofs/inode.c Thu Feb 12 20:56:12 1998 +++ linux/fs/isofs/inode.c Sat Feb 21 13:19:29 1998 @@ -5,7 +5,8 @@ * 1992, 1993, 1994 Eric Youngdale Modified for ISO9660 filesystem. * 1994 Eberhard Moenkeberg - multi session handling. * 1995 Mark Dobie - allow mounting of some weird VideoCDs and PhotoCDs. - * + * 1997 Gordon Chaffee - Joliet CDs + * 1998 Eric Lammerts - ISO9660 Level 3 */ #include @@ -655,17 +656,24 @@ int isofs_bmap(struct inode * inode,int block) { + off_t b_off, offset, size; + struct inode *ino; + unsigned int firstext; + unsigned long nextino; + int i; if (block<0) { printk("_isofs_bmap: block<0"); return 0; } + b_off = block << ISOFS_BUFFER_BITS(inode); + /* * If we are beyond the end of this file, don't give out any * blocks. */ - if( (block << ISOFS_BUFFER_BITS(inode)) >= inode->i_size ) + if( b_off > inode->i_size ) { off_t max_legal_read_offset; @@ -679,7 +687,7 @@ */ max_legal_read_offset = (inode->i_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); - if( (block << ISOFS_BUFFER_BITS(inode)) >= max_legal_read_offset ) + if( b_off >= max_legal_read_offset ) { printk("_isofs_bmap: block>= EOF(%d, %ld)\n", block, @@ -688,7 +696,42 @@ return 0; } - return (inode->u.isofs_i.i_first_extent >> ISOFS_BUFFER_BITS(inode)) + block; + offset = 0; + firstext = inode->u.isofs_i.i_first_extent; + size = inode->u.isofs_i.i_section_size; + nextino = inode->u.isofs_i.i_next_section_ino; +#ifdef DEBUG + printk("first inode: inode=%lu nextino=%lu firstext=%u size=%lu\n", + inode->i_ino, nextino, firstext, size); +#endif + i = 0; + while(b_off >= offset + size) { + offset += size; + + if(nextino == 0) return 0; + ino = iget(inode->i_sb, nextino); + if(!ino) return 0; + firstext = ino->u.isofs_i.i_first_extent; + size = ino->u.isofs_i.i_section_size; +#ifdef DEBUG + printk("read inode: inode=%lu ino=%lu nextino=%lu firstext=%u size=%lu\n", + inode->i_ino, nextino, ino->u.isofs_i.i_next_section_ino, firstext, size); +#endif + nextino = ino->u.isofs_i.i_next_section_ino; + iput(ino); + + if(++i > 100) { + printk("isofs_bmap: More than 100 file sections ?!?, aborting...\n"); + printk("isofs_bmap: ino=%lu block=%d firstext=%u size=%u nextino=%lu\n", + inode->i_ino, block, firstext, (unsigned)size, nextino); + return 0; + } + } +#ifdef DEBUG + printk("isofs_bmap: mapped inode:block %lu:%d to block %lu\n", + inode->i_ino, block, (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode)); +#endif + return (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode); } @@ -702,6 +745,82 @@ } } +static int isofs_read_level3_size(struct inode * inode) +{ + unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); + struct buffer_head * bh = NULL; + struct iso_directory_record * raw_inode = NULL; /* quiet gcc */ + unsigned char *pnt = NULL; + void *cpnt = NULL; + int block = 0; /* Quiet GCC */ + unsigned long ino; + int i; + + inode->i_size = 0; + inode->u.isofs_i.i_next_section_ino = 0; + ino = inode->i_ino; + i = 0; + do { + if(i > 100) { + printk("isofs_read_level3_size: More than 100 file sections ?!?, aborting...\n" + "isofs_read_level3_size: inode=%lu ino=%lu\n", inode->i_ino, ino); + return 0; + } + + if(bh == NULL || block != ino >> ISOFS_BUFFER_BITS(inode)) { + if(bh) brelse(bh); + block = ino >> ISOFS_BUFFER_BITS(inode); + if (!(bh=bread(inode->i_dev,block, bufsize))) { + printk("unable to read i-node block"); + return 1; + } + } + pnt = ((unsigned char *) bh->b_data + + (ino & (bufsize - 1))); + + if ((ino & (bufsize - 1)) + *pnt > bufsize){ + int frag1, offset; + + offset = (ino & (bufsize - 1)); + frag1 = bufsize - offset; + cpnt = kmalloc(*pnt,GFP_KERNEL); + if (cpnt == NULL) { + printk(KERN_INFO "NoMem ISO inode %lu\n",inode->i_ino); + brelse(bh); + return 1; + } + memcpy(cpnt, bh->b_data + offset, frag1); + brelse(bh); + if (!(bh = bread(inode->i_dev,++block, bufsize))) { + kfree(cpnt); + printk("unable to read i-node block"); + return 1; + } + offset += *pnt - bufsize; + memcpy((char *)cpnt+frag1, bh->b_data, offset); + pnt = ((unsigned char *) cpnt); + } + + if(*pnt == 0) { + ino = (ino & ~(ISOFS_BLOCK_SIZE - 1)) + ISOFS_BLOCK_SIZE; + continue; + } + raw_inode = ((struct iso_directory_record *) pnt); + + inode->i_size += isonum_733 (raw_inode->size); + if(i == 1) inode->u.isofs_i.i_next_section_ino = ino; + + ino += *pnt; + if (cpnt) { + kfree (cpnt); + cpnt = NULL; + } + i++; + } while(raw_inode->flags[-inode->i_sb->u.isofs_sb.s_high_sierra] & 0x80); + brelse(bh); + return 0; +} + void isofs_read_inode(struct inode * inode) { unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); @@ -744,8 +863,15 @@ } inode->i_uid = inode->i_sb->u.isofs_sb.s_uid; inode->i_gid = inode->i_sb->u.isofs_sb.s_gid; - inode->i_size = isonum_733 (raw_inode->size); inode->i_blocks = inode->i_blksize = 0; + + + inode->u.isofs_i.i_section_size = isonum_733 (raw_inode->size); + if(raw_inode->flags[-high_sierra] & 0x80) { + if(isofs_read_level3_size(inode)) goto fail; + } else { + inode->i_size = isonum_733 (raw_inode->size); + } /* There are defective discs out there - we do this to protect ourselves. A cdrom will never contain more than 800Mb */ diff -u --recursive --new-file v2.1.88/linux/fs/locks.c linux/fs/locks.c --- v2.1.88/linux/fs/locks.c Mon Feb 23 18:12:10 1998 +++ linux/fs/locks.c Mon Feb 23 12:55:58 1998 @@ -111,6 +111,7 @@ #include #include #include +#include #include #include @@ -289,15 +290,21 @@ int error; lock_kernel(); - if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd])) - error = -EBADF; - else if (!flock_make_lock(filp, &file_lock, cmd)) - error = -EINVAL; - else if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3)) - error = -EBADF; - else - error = flock_lock_file(filp, &file_lock, - (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1); + error = -EBADF; + filp = fget(fd); + if (!filp) + goto out; + error = -EINVAL; + if (!flock_make_lock(filp, &file_lock, cmd)) + goto out_putf; + error = -EBADF; + if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3)) + goto out_putf; + error = flock_lock_file(filp, &file_lock, + (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1); +out_putf: + fput(filp); +out: unlock_kernel(); return (error); } @@ -307,36 +314,34 @@ */ int fcntl_getlk(unsigned int fd, struct flock *l) { - struct flock flock; struct file *filp; - struct dentry *dentry; - struct inode *inode; struct file_lock *fl,file_lock; + struct flock flock; int error; - if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd])) - return -EBADF; + error = -EFAULT; if (copy_from_user(&flock, l, sizeof(flock))) - return -EFAULT; - + goto out; + error = -EINVAL; if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK)) - return -EINVAL; + goto out; - dentry = filp->f_dentry; - if (!dentry) - return -EINVAL; - - inode = dentry->d_inode; - if (!inode) - return -EINVAL; + error = -EBADF; + filp = fget(fd); + if (!filp) + goto out; + + error = -EINVAL; + if (!filp->f_dentry || !filp->f_dentry->d_inode) + goto out_putf; if (!posix_make_lock(filp, &file_lock, &flock)) - return -EINVAL; + goto out_putf; if (filp->f_op->lock) { error = filp->f_op->lock(filp, F_GETLK, &file_lock); if (error < 0) - return error; + goto out_putf; fl = &file_lock; } else { fl = posix_test_lock(filp, &file_lock); @@ -351,8 +356,14 @@ flock.l_whence = 0; flock.l_type = fl->fl_type; } + error = -EFAULT; + if (!copy_to_user(l, &flock, sizeof(flock))) + error = 0; - return (copy_to_user(l, &flock, sizeof(flock)) ? -EFAULT : 0); +out_putf: + fput(filp); +out: + return error; } /* Apply the lock described by l to an open file descriptor. @@ -367,22 +378,26 @@ struct inode *inode; int error; + /* + * This might block, so we do it before checking the inode. + */ + error = -EFAULT; + if (copy_from_user(&flock, l, sizeof(flock))) + goto out; + /* Get arguments and validate them ... */ - if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd])) - return -EBADF; + error = -EBADF; + filp = fget(fd); + if (!filp) + goto out; + error = -EINVAL; if (!(dentry = filp->f_dentry)) - return -EINVAL; - + goto out_putf; if (!(inode = dentry->d_inode)) - return -EINVAL; - /* - * This might block, so we do it before checking the inode. - */ - if (copy_from_user(&flock, l, sizeof(flock))) - return (-EFAULT); + goto out_putf; /* Don't allow mandatory locks on files that may be memory mapped * and shared. @@ -391,23 +406,26 @@ (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && inode->i_mmap) { struct vm_area_struct *vma = inode->i_mmap; + error = -EAGAIN; do { if (vma->vm_flags & VM_MAYSHARE) - return (-EAGAIN); + goto out_putf; } while ((vma = vma->vm_next_share) != NULL); } + error = -EINVAL; if (!posix_make_lock(filp, &file_lock, &flock)) - return (-EINVAL); + goto out_putf; + error = -EBADF; switch (flock.l_type) { case F_RDLCK: if (!(filp->f_mode & FMODE_READ)) - return (-EBADF); + goto out_putf; break; case F_WRLCK: if (!(filp->f_mode & FMODE_WRITE)) - return (-EBADF); + goto out_putf; break; case F_UNLCK: break; @@ -425,20 +443,25 @@ } } if (!(filp->f_mode & 3)) - return (-EBADF); + goto out_putf; break; #endif default: - return (-EINVAL); + error = -EINVAL; + goto out_putf; } if (filp->f_op->lock != NULL) { error = filp->f_op->lock(filp, cmd, &file_lock); if (error < 0) - return (error); + goto out_putf; } + error = posix_lock_file(filp, &file_lock, cmd == F_SETLKW); - return (posix_lock_file(filp, &file_lock, cmd == F_SETLKW)); +out_putf: + fput(filp); +out: + return error; } /* diff -u --recursive --new-file v2.1.88/linux/fs/open.c linux/fs/open.c --- v2.1.88/linux/fs/open.c Mon Feb 23 18:12:10 1998 +++ linux/fs/open.c Mon Feb 23 12:55:58 1998 @@ -47,24 +47,31 @@ asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf) { + struct file * file; struct inode * inode; struct dentry * dentry; - struct file * file; + struct super_block * sb; int error; lock_kernel(); - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - error = -EBADF; - else if (!(dentry = file->f_dentry)) - error = -ENOENT; - else if (!(inode = dentry->d_inode)) - error = -ENOENT; - else if (!inode->i_sb) - error = -ENODEV; - else if (!inode->i_sb->s_op->statfs) - error = -ENOSYS; - else - error = inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs)); + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + error = -ENOENT; + if (!(dentry = file->f_dentry)) + goto out_putf; + if (!(inode = dentry->d_inode)) + goto out_putf; + error = -ENODEV; + if (!(sb = inode->i_sb)) + goto out_putf; + error = -ENOSYS; + if (sb->s_op->statfs) + error = sb->s_op->statfs(sb, buf, sizeof(struct statfs)); +out_putf: + fput(file); +out: unlock_kernel(); return error; } @@ -147,23 +154,29 @@ int error; lock_kernel(); - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - error = -EBADF; - else if (!(dentry = file->f_dentry)) - error = -ENOENT; - else if (!(inode = dentry->d_inode)) - error = -ENOENT; - else if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) - error = -EACCES; - else if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - error = -EPERM; - else { - error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, - lengthi_size ? length : inode->i_size, - abs(inode->i_size - length)); - if (!error) - error = do_truncate(dentry, length); - } + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + error = -ENOENT; + if (!(dentry = file->f_dentry)) + goto out_putf; + if (!(inode = dentry->d_inode)) + goto out_putf; + error = -EACCES; + if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) + goto out_putf; + error = -EPERM; + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + goto out_putf; + error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, + lengthi_size ? length : inode->i_size, + abs(inode->i_size - length)); + if (!error) + error = do_truncate(dentry, length); +out_putf: + fput(file); +out: unlock_kernel(); return error; } @@ -347,30 +360,28 @@ lock_kernel(); error = -EBADF; - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + file = fget(fd); + if (!file) goto out; error = -ENOENT; if (!(dentry = file->f_dentry)) - goto out; + goto out_putf; if (!(inode = dentry->d_inode)) - goto out; + goto out_putf; error = -ENOTDIR; if (!S_ISDIR(inode->i_mode)) - goto out; - - error = permission(inode,MAY_EXEC); - if (error) - goto out; + goto out_putf; - { - struct dentry *tmp; - - tmp = current->fs->pwd; + error = permission(inode, MAY_EXEC); + if (!error) { + struct dentry *tmp = current->fs->pwd; current->fs->pwd = dget(dentry); dput(tmp); } +out_putf: + fput(file); out: unlock_kernel(); return error; @@ -421,28 +432,34 @@ struct inode * inode; struct dentry * dentry; struct file * file; - struct iattr newattrs; int err = -EBADF; + struct iattr newattrs; lock_kernel(); - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + file = fget(fd); + if (!file) goto out; + err = -ENOENT; if (!(dentry = file->f_dentry)) - goto out; + goto out_putf; if (!(inode = dentry->d_inode)) - goto out; + goto out_putf; + err = -EROFS; if (IS_RDONLY(inode)) - goto out; + goto out_putf; err = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - goto out; + goto out_putf; if (mode == (mode_t) -1) mode = inode->i_mode; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; err = notify_change(dentry, &newattrs); + +out_putf: + fput(file); out: unlock_kernel(); return err; @@ -487,8 +504,8 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group) { struct inode * inode; - struct iattr newattrs; int error; + struct iattr newattrs; error = -ENOENT; if (!(inode = dentry->d_inode)) { @@ -581,13 +598,13 @@ int error = -EBADF; lock_kernel(); - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + file = fget(fd); + if (!file) goto out; error = -ENOENT; - if (!(dentry = file->f_dentry)) - goto out; - - error = chown_common(dentry, user, group); + if ((dentry = file->f_dentry) != NULL) + error = chown_common(dentry, user, group); + fput(file); out: unlock_kernel(); @@ -608,16 +625,17 @@ * for the internal routines (ie open_namei()/follow_link() etc). 00 is * used by symlinks. */ -static int do_open(const char * filename,int flags,int mode, int fd) +static int do_open(const char * filename, int flags, int mode, int fd) { struct inode * inode; struct dentry * dentry; struct file * f; int flag,error; + error = -ENFILE; f = get_empty_filp(); if (!f) - return -ENFILE; + goto out; f->f_flags = flag = flags; f->f_mode = (flag+1) & O_ACCMODE; if (f->f_mode) @@ -648,7 +666,7 @@ } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); - current->files->fd[fd] = f; + fd_install(fd, f); return 0; cleanup_all: @@ -658,6 +676,7 @@ dput(dentry); cleanup_file: put_filp(f); +out: return error; } @@ -670,6 +689,10 @@ struct files_struct * files = current->files; fd = find_first_zero_bit(&files->open_fds, NR_OPEN); + /* + * N.B. For clone tasks sharing a files structure, this test + * will limit the total number of files that can be opened. + */ if (fd < current->rlim[RLIMIT_NOFILE].rlim_cur) { FD_SET(fd, &files->open_fds); FD_CLR(fd, &files->close_on_exec); @@ -678,36 +701,37 @@ return -EMFILE; } -inline void put_unused_fd(int fd) +inline void put_unused_fd(unsigned int fd) { FD_CLR(fd, ¤t->files->open_fds); } -asmlinkage int sys_open(const char * filename,int flags,int mode) +asmlinkage int sys_open(const char * filename, int flags, int mode) { char * tmp; int fd, error; lock_kernel(); - error = get_unused_fd(); - if (error < 0) + fd = get_unused_fd(); + if (fd < 0) goto out; - fd = error; tmp = getname(filename); error = PTR_ERR(tmp); - if (!IS_ERR(tmp)) { - error = do_open(tmp,flags,mode,fd); - putname(tmp); - if (!error) { - error = fd; - goto out; - } - } - put_unused_fd(fd); + if (IS_ERR(tmp)) + goto out_fail; + error = do_open(tmp, flags, mode, fd); + putname(tmp); + if (error) + goto out_fail; out: unlock_kernel(); - return error; + return fd; + +out_fail: + put_unused_fd(fd); + fd = error; + goto out; } #ifndef __alpha__ @@ -728,11 +752,14 @@ #endif +/* + * Called when retiring the last use of a file pointer. + */ int __fput(struct file *filp) { - int error = 0; struct dentry * dentry = filp->f_dentry; struct inode * inode = dentry->d_inode; + int error = 0; if (filp->f_op && filp->f_op->release) error = filp->f_op->release(inode, filp); @@ -756,6 +783,11 @@ return fput(filp); } +/* + * Careful here! We test whether the file pointer is NULL before + * releasing the fd. This ensures that one clone task can't release + * an fd while another clone is opening it. + */ asmlinkage int sys_close(unsigned int fd) { int error; diff -u --recursive --new-file v2.1.88/linux/fs/read_write.c linux/fs/read_write.c --- v2.1.88/linux/fs/read_write.c Tue Oct 21 08:57:29 1997 +++ linux/fs/read_write.c Mon Feb 23 12:55:58 1998 @@ -62,14 +62,18 @@ lock_kernel(); retval = -EBADF; - if (fd >= NR_OPEN || - !(file = current->files->fd[fd]) || - !(dentry = file->f_dentry) || - !(inode = dentry->d_inode)) + file = fget(fd); + if (!file) goto bad; + /* N.B. Shouldn't this be ENOENT?? */ + if (!(dentry = file->f_dentry) || + !(inode = dentry->d_inode)) + goto out_putf; retval = -EINVAL; if (origin <= 2) retval = llseek(file, offset, origin); +out_putf: + fput(file); bad: unlock_kernel(); return retval; @@ -88,24 +92,28 @@ lock_kernel(); retval = -EBADF; - if (fd >= NR_OPEN || - !(file = current->files->fd[fd]) || - !(dentry = file->f_dentry) || - !(inode = dentry->d_inode)) + file = fget(fd); + if (!file) goto bad; + /* N.B. Shouldn't this be ENOENT?? */ + if (!(dentry = file->f_dentry) || + !(inode = dentry->d_inode)) + goto out_putf; retval = -EINVAL; if (origin > 2) - goto bad; + goto out_putf; offset = llseek(file, ((loff_t) offset_high << 32) | offset_low, origin); retval = (int)offset & INT_MAX; if (offset >= 0) { - retval = copy_to_user(result, &offset, sizeof(offset)); - if (retval) - retval = -EFAULT; + retval = -EFAULT; + if (!copy_to_user(result, &offset, sizeof(offset))) + retval = 0; } +out_putf: + fput(file); bad: unlock_kernel(); return retval; @@ -201,9 +209,10 @@ if (count > UIO_MAXIOV) goto out_nofree; if (count > UIO_FASTIOV) { - iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL); ret = -ENOMEM; - if (!iov) goto out_nofree; + iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL); + if (!iov) + goto out_nofree; } ret = -EFAULT; if (copy_from_user(iov, vector, count*sizeof(*vector))) @@ -280,11 +289,10 @@ file = fget(fd); if (!file) goto bad_file; - if (!(file->f_mode & FMODE_READ)) - goto out; - ret = do_readv_writev(VERIFY_WRITE, file, vector, count); -out: + if (file->f_mode & FMODE_READ) + ret = do_readv_writev(VERIFY_WRITE, file, vector, count); fput(file); + bad_file: unlock_kernel(); return ret; @@ -302,15 +310,13 @@ file = fget(fd); if (!file) goto bad_file; - if (!(file->f_mode & FMODE_WRITE)) - goto out; - - down(&file->f_dentry->d_inode->i_sem); - ret = do_readv_writev(VERIFY_READ, file, vector, count); - up(&file->f_dentry->d_inode->i_sem); - -out: + if (file->f_mode & FMODE_WRITE) { + down(&file->f_dentry->d_inode->i_sem); + ret = do_readv_writev(VERIFY_READ, file, vector, count); + up(&file->f_dentry->d_inode->i_sem); + } fput(file); + bad_file: unlock_kernel(); return ret; diff -u --recursive --new-file v2.1.88/linux/fs/readdir.c linux/fs/readdir.c --- v2.1.88/linux/fs/readdir.c Sat Sep 20 12:21:34 1997 +++ linux/fs/readdir.c Mon Feb 23 12:55:58 1998 @@ -4,12 +4,13 @@ * Copyright (C) 1995 Linus Torvalds */ +#include +#include #include #include #include +#include #include -#include -#include #include #include @@ -65,27 +66,24 @@ lock_kernel(); error = -EBADF; - if (fd >= NR_OPEN) - goto out; - - file = current->files->fd[fd]; + file = fget(fd); if (!file) goto out; dentry = file->f_dentry; if (!dentry) - goto out; + goto out_putf; inode = dentry->d_inode; if (!inode) - goto out; + goto out_putf; buf.count = 0; buf.dirent = dirent; error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) - goto out; + goto out_putf; /* * Get the inode's semaphore to prevent changes @@ -95,8 +93,11 @@ error = file->f_op->readdir(file, &buf, fillonedir); up(&inode->i_sem); if (error < 0) - goto out; + goto out_putf; error = buf.count; + +out_putf: + fput(file); out: unlock_kernel(); return error; @@ -155,20 +156,17 @@ lock_kernel(); error = -EBADF; - if (fd >= NR_OPEN) - goto out; - - file = current->files->fd[fd]; + file = fget(fd); if (!file) goto out; dentry = file->f_dentry; if (!dentry) - goto out; + goto out_putf; inode = dentry->d_inode; if (!inode) - goto out; + goto out_putf; buf.current_dir = (struct linux_dirent *) dirent; buf.previous = NULL; @@ -177,7 +175,7 @@ error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) - goto out; + goto out_putf; /* * Get the inode's semaphore to prevent changes @@ -187,13 +185,16 @@ error = file->f_op->readdir(file, &buf, filldir); up(&inode->i_sem); if (error < 0) - goto out; - lastdirent = buf.previous; + 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; diff -u --recursive --new-file v2.1.88/linux/fs/stat.c linux/fs/stat.c --- v2.1.88/linux/fs/stat.c Sun Jan 4 00:53:41 1998 +++ linux/fs/stat.c Mon Feb 23 12:55:58 1998 @@ -4,13 +4,14 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +#include +#include #include #include #include #include -#include +#include #include -#include #include #include @@ -220,12 +221,14 @@ int err = -EBADF; lock_kernel(); - if (fd < NR_OPEN && (f = current->files->fd[fd]) != NULL) { + f = fget(fd); + if (f) { struct dentry * dentry = f->f_dentry; err = do_revalidate(dentry); if (!err) err = cp_old_stat(dentry->d_inode, statbuf); + fput(f); } unlock_kernel(); return err; @@ -239,12 +242,14 @@ int err = -EBADF; lock_kernel(); - if (fd < NR_OPEN && (f = current->files->fd[fd]) != NULL) { + f = fget(fd); + if (f) { struct dentry * dentry = f->f_dentry; err = do_revalidate(dentry); if (!err) err = cp_new_stat(dentry->d_inode, statbuf); + fput(f); } unlock_kernel(); return err; diff -u --recursive --new-file v2.1.88/linux/include/asm-alpha/hwrpb.h linux/include/asm-alpha/hwrpb.h --- v2.1.88/linux/include/asm-alpha/hwrpb.h Mon Jan 12 14:51:14 1998 +++ linux/include/asm-alpha/hwrpb.h Mon Feb 23 10:25:10 1998 @@ -15,6 +15,8 @@ #define EV45_CPU 6 /* EV4.5 (21064/xxx) */ #define EV56_CPU 7 /* EV5.6 (21164) */ #define EV6_CPU 8 /* EV6 (21164) */ +#define PCA56_CPU 9 /* PCA56 (21164PC) */ +#define PCA57_CPU 10 /* PCA57 (??) */ /* * DEC system types for Alpha systems. Found in HWRPB. @@ -39,8 +41,26 @@ #define ST_DEC_EB64P 20 /* EB64+ systype */ #define ST_DEC_EB66P -19 /* EB66 systype */ #define ST_DEC_EBPC64 -20 /* Cabriolet (AlphaPC64) systype */ +#define ST_DEC_BURNS 21 /* Laptop systype */ +#define ST_DEC_RAWHIDE 22 /* Rawhide systype */ +#define ST_DEC_K2 23 /* K2 systype */ +#define ST_DEC_LYNX 24 /* Lynx systype */ +#define ST_DEC_XL 25 /* Alpha XL systype */ #define ST_DEC_EB164 26 /* EB164 systype */ +#define ST_DEC_NORITAKE 27 /* Noritake systype */ +#define ST_DEC_CORTEX 28 /* Cortex systype */ #define ST_DEC_MIATA 30 /* MIATA systype */ +#define ST_DEC_XXM 31 /* XXM systype */ +#define ST_DEC_TAKARA 32 /* Takara systype */ +#define ST_DEC_YUKON 33 /* Yukon systype */ +#define ST_DEC_TSUNAMI 34 /* Tsunami systype */ +#define ST_DEC_WILDFIRE 35 /* Wildfire systype */ +#define ST_DEC_CUSCO 36 /* CUSCO systype */ + +/* UNOFFICIAL!!! */ +#define ST_UNOFFICIAL_BIAS 100 +#define ST_DTI_RUFFIAN 101 /* RUFFIAN systype */ + struct pcb_struct { unsigned long ksp; diff -u --recursive --new-file v2.1.88/linux/include/asm-alpha/irq.h linux/include/asm-alpha/irq.h --- v2.1.88/linux/include/asm-alpha/irq.h Mon Jan 12 14:51:14 1998 +++ linux/include/asm-alpha/irq.h Mon Feb 23 10:25:10 1998 @@ -10,13 +10,18 @@ #include #include -#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P) || defined(CONFIG_ALPHA_EB164) || defined(CONFIG_ALPHA_PC164) +#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P) || \ + defined(CONFIG_ALPHA_EB164) || defined(CONFIG_ALPHA_PC164) || \ + defined(CONFIG_ALPHA_LX164) # define NR_IRQS 33 -#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P) || defined(CONFIG_ALPHA_MIKASA) +#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P) || \ + defined(CONFIG_ALPHA_MIKASA) # define NR_IRQS 32 -#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) || defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_NORITAKE) +#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) || \ + defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_NORITAKE) || \ + defined(CONFIG_ALPHA_RUFFIAN) # define NR_IRQS 48 -#elif defined(CONFIG_ALPHA_SABLE) +#elif defined(CONFIG_ALPHA_SABLE) || defined(CONFIG_ALPHA_SX164) # define NR_IRQS 40 #else # define NR_IRQS 16 diff -u --recursive --new-file v2.1.88/linux/include/asm-alpha/pyxis.h linux/include/asm-alpha/pyxis.h --- v2.1.88/linux/include/asm-alpha/pyxis.h Mon Jan 12 14:51:14 1998 +++ linux/include/asm-alpha/pyxis.h Mon Feb 23 10:25:10 1998 @@ -178,6 +178,20 @@ * Translate physical memory address as seen on (PCI) bus into * a kernel virtual address and vv. */ + +#if defined(CONFIG_ALPHA_RUFFIAN) +/* Ruffian doesn't do 1G PCI window. */ + +extern inline unsigned long virt_to_bus(void * address) +{ + return virt_to_phys(address); +} + +extern inline void * bus_to_virt(unsigned long address) +{ + return phys_to_virt(address); +} +#else extern inline unsigned long virt_to_bus(void * address) { return virt_to_phys(address) + PYXIS_DMA_WIN_BASE; @@ -187,6 +201,7 @@ { return phys_to_virt(address - PYXIS_DMA_WIN_BASE); } +#endif /* RUFFIAN */ /* * I/O functions: diff -u --recursive --new-file v2.1.88/linux/include/asm-i386/floppy.h linux/include/asm-i386/floppy.h --- v2.1.88/linux/include/asm-i386/floppy.h Mon Feb 23 18:12:11 1998 +++ linux/include/asm-i386/floppy.h Mon Feb 23 16:17:31 1998 @@ -29,7 +29,6 @@ #define SW fd_routine[use_virtual_dma&1] #define CSW fd_routine[can_use_virtual_dma & 1] -#define NCSW fd_routine[(can_use_virtual_dma >> 1)& 1] #define fd_inb(port) inb_p(port) @@ -39,9 +38,6 @@ #define fd_free_dma() CSW._free_dma(FLOPPY_DMA) #define fd_enable_irq() enable_irq(FLOPPY_IRQ) #define fd_disable_irq() disable_irq(FLOPPY_IRQ) -#define fd_request_irq() NCSW._request_irq(FLOPPY_IRQ, floppy_interrupt,\ - SA_INTERRUPT|SA_SAMPLE_RANDOM,\ - "floppy", NULL) #define fd_free_irq() free_irq(FLOPPY_IRQ, NULL) #define fd_get_dma_residue() SW._get_dma_residue(FLOPPY_DMA) #define fd_dma_mem_alloc(size) SW._dma_mem_alloc(size) @@ -180,14 +176,15 @@ } -static int vdma_request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, - const char *device, - void *dev_id) +static int fd_request_irq(void) { - return request_irq(irq, floppy_hardint,SA_INTERRUPT,device, - dev_id); + if(can_use_virtual_dma) + return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT, + "floppy", NULL); + else + return request_irq(FLOPPY_IRQ, floppy_interrupt, + SA_INTERRUPT|SA_SAMPLE_RANDOM, + "floppy", NULL); } @@ -265,11 +262,6 @@ int (*_request_dma)(unsigned int dmanr, const char * device_id); void (*_free_dma)(unsigned int dmanr); int (*_get_dma_residue)(unsigned int dummy); - int (*_request_irq)(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, - const char *device, - void *dev_id); unsigned long (*_dma_mem_alloc) (unsigned long size); int (*_dma_setup)(char *addr, unsigned long size, int mode, int io); } fd_routine[] = { @@ -277,7 +269,6 @@ request_dma, free_dma, get_dma_residue, - request_irq, dma_mem_alloc, hard_dma_setup }, @@ -285,7 +276,6 @@ vdma_request_dma, vdma_nop, vdma_get_dma_residue, - vdma_request_irq, vdma_mem_alloc, vdma_dma_setup } diff -u --recursive --new-file v2.1.88/linux/include/linux/file.h linux/include/linux/file.h --- v2.1.88/linux/include/linux/file.h Mon Feb 23 18:12:11 1998 +++ linux/include/linux/file.h Mon Feb 23 12:55:58 1998 @@ -47,4 +47,12 @@ } } +/* + * Install a file pointer in the files structure. + */ +extern inline void fd_install(unsigned long fd, struct file *file) +{ + current->files->fd[fd] = file; +} + #endif diff -u --recursive --new-file v2.1.88/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.1.88/linux/include/linux/fs.h Mon Feb 23 18:12:12 1998 +++ linux/include/linux/fs.h Mon Feb 23 16:17:03 1998 @@ -638,14 +638,20 @@ extern int register_filesystem(struct file_system_type *); extern int unregister_filesystem(struct file_system_type *); +/* fs/open.c */ + asmlinkage int sys_open(const char *, int, int); asmlinkage int sys_close(unsigned int); /* yes, it's really unsigned */ - -extern void kill_fasync(struct fasync_struct *fa, int sig); +extern int do_truncate(struct dentry *, unsigned long); +extern int get_unused_fd(void); +extern void put_unused_fd(unsigned int); +extern int __fput(struct file *); +extern int close_fp(struct file *); extern char * getname(const char * filename); extern void putname(char * name); -extern int do_truncate(struct dentry *, unsigned long); + +extern void kill_fasync(struct fasync_struct *fa, int sig); extern int register_blkdev(unsigned int, const char *, struct file_operations *); extern int unregister_blkdev(unsigned int major, const char * name); extern int blkdev_open(struct inode * inode, struct file * filp); @@ -755,32 +761,6 @@ #define namei(pathname) __namei(pathname, 1) #define lnamei(pathname) __namei(pathname, 0) -#include - -/* Intended for short locks of the global data structures in inode.c. - * Could be replaced with spinlocks completely, since there is - * no blocking during manipulation of the static data; however the - * lock in invalidate_inodes() may last relatively long. - */ -extern struct semaphore vfs_sem; -extern inline void vfs_lock(void) -{ -#if 0 -#ifdef __SMP__ - down(&vfs_sem); -#endif -#endif -} - -extern inline void vfs_unlock(void) -{ -#if 0 -#ifdef __SMP__ - up(&vfs_sem); -#endif -#endif -} - extern void iput(struct inode *); extern struct inode * iget(struct super_block *, unsigned long); extern void clear_inode(struct inode *); @@ -788,10 +768,7 @@ extern void insert_inode_hash(struct inode *); extern void remove_inode_hash(struct inode *); -extern int get_unused_fd(void); -extern void put_unused_fd(int); extern struct file * get_empty_filp(void); -extern int close_fp(struct file *); extern struct buffer_head * get_hash_table(kdev_t, int, int); extern struct buffer_head * getblk(kdev_t, int, int); extern struct buffer_head * find_buffer(kdev_t dev, int block, int size); diff -u --recursive --new-file v2.1.88/linux/include/linux/iso_fs_i.h linux/include/linux/iso_fs_i.h --- v2.1.88/linux/include/linux/iso_fs_i.h Thu Feb 12 20:56:13 1998 +++ linux/include/linux/iso_fs_i.h Sat Feb 21 13:19:29 1998 @@ -6,6 +6,9 @@ */ struct iso_inode_info { unsigned int i_first_extent; + unsigned char i_file_format; + unsigned long i_next_section_ino; + off_t i_section_size; }; #endif diff -u --recursive --new-file v2.1.88/linux/include/linux/kerneld.h linux/include/linux/kerneld.h --- v2.1.88/linux/include/linux/kerneld.h Sat Nov 29 10:33:21 1997 +++ linux/include/linux/kerneld.h Mon Feb 23 10:25:15 1998 @@ -48,8 +48,10 @@ }; #ifdef __KERNEL__ +#include + extern int kerneld_send(int msgtype, int ret_size, int msgsz, - const char *text, const char *ret_val); + const char *text, const char *ret_val); /* * Request that a module should be loaded. @@ -59,8 +61,8 @@ static inline int request_module(const char *name) { return kerneld_send(KERNELD_REQUEST_MODULE, - 0 | KERNELD_WAIT, - strlen(name), name, NULL); + 0 | KERNELD_WAIT, + strlen(name), name, NULL); } /* @@ -70,8 +72,8 @@ static inline int release_module(const char *name, int waitflag) { return kerneld_send(KERNELD_RELEASE_MODULE, - 0 | (waitflag?KERNELD_WAIT:KERNELD_NOWAIT), - strlen(name), name, NULL); + 0 | (waitflag?KERNELD_WAIT:KERNELD_NOWAIT), + strlen(name), name, NULL); } /* @@ -81,8 +83,8 @@ static inline int delayed_release_module(const char *name) { return kerneld_send(KERNELD_DELAYED_RELEASE_MODULE, - 0 | KERNELD_NOWAIT, - strlen(name), name, NULL); + 0 | KERNELD_NOWAIT, + strlen(name), name, NULL); } /* @@ -94,8 +96,8 @@ static inline int cancel_release_module(const char *name) { return kerneld_send(KERNELD_CANCEL_RELEASE_MODULE, - 0 | KERNELD_NOWAIT, - strlen(name), name, NULL); + 0 | KERNELD_NOWAIT, + strlen(name), name, NULL); } /* @@ -104,8 +106,8 @@ static inline int ksystem(const char *cmd, int waitflag) { return kerneld_send(KERNELD_SYSTEM, - 0 | (waitflag?KERNELD_WAIT:KERNELD_NOWAIT), - strlen(cmd), cmd, NULL); + 0 | (waitflag?KERNELD_WAIT:KERNELD_NOWAIT), + strlen(cmd), cmd, NULL); } /* @@ -114,18 +116,19 @@ static inline int kerneld_route(const char *ip_route) { return kerneld_send(KERNELD_REQUEST_ROUTE, - 0 | KERNELD_WAIT, - strlen(ip_route), ip_route, NULL); + 0 | KERNELD_WAIT, + strlen(ip_route), ip_route, NULL); } /* * Handle an external screen blanker */ -static inline int kerneld_blanker(int on_off) /* 0 => "off", else "on" */ +static inline int kerneld_blanker(int on_off) { + char *s = on_off ? "on" : "off"; return kerneld_send(KERNELD_BLANKER, - 0 | (on_off?KERNELD_NOWAIT:KERNELD_WAIT), - strlen(on_off?"on":"off"), on_off?"on":"off", NULL); + 0 | (on_off ? KERNELD_NOWAIT : KERNELD_WAIT), + strlen(s), s, NULL); } #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.1.88/linux/include/linux/mc146818rtc.h linux/include/linux/mc146818rtc.h --- v2.1.88/linux/include/linux/mc146818rtc.h Fri Feb 6 15:33:06 1998 +++ linux/include/linux/mc146818rtc.h Mon Feb 23 16:17:31 1998 @@ -142,6 +142,8 @@ #define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time) /* Set RTC time */ #define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */ #define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */ +#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */ +#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */ #endif /* _MC146818RTC_H */ diff -u --recursive --new-file v2.1.88/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.1.88/linux/include/linux/mm.h Fri Feb 6 15:32:54 1998 +++ linux/include/linux/mm.h Mon Feb 23 16:17:03 1998 @@ -133,7 +133,7 @@ #define PG_uptodate 3 #define PG_free_after 4 #define PG_decr_after 5 -#define PG_swap_unlock_after 6 +/* Unused 6 */ #define PG_DMA 7 #define PG_Slab 8 #define PG_swap_cache 9 @@ -146,7 +146,6 @@ #define PageUptodate(page) (test_bit(PG_uptodate, &(page)->flags)) #define PageFreeAfter(page) (test_bit(PG_free_after, &(page)->flags)) #define PageDecrAfter(page) (test_bit(PG_decr_after, &(page)->flags)) -#define PageSwapUnlockAfter(page) (test_bit(PG_swap_unlock_after, &(page)->flags)) #define PageDMA(page) (test_bit(PG_DMA, &(page)->flags)) #define PageSlab(page) (test_bit(PG_Slab, &(page)->flags)) #define PageSwapCache(page) (test_bit(PG_swap_cache, &(page)->flags)) @@ -252,6 +251,7 @@ } /* memory.c & swap.c*/ +extern int free_memory_available(void); #define free_page(addr) free_pages((addr),0) extern void FASTCALL(free_pages(unsigned long addr, unsigned long order)); diff -u --recursive --new-file v2.1.88/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.1.88/linux/include/linux/pci.h Tue Feb 17 13:12:49 1998 +++ linux/include/linux/pci.h Mon Feb 23 10:25:10 1998 @@ -503,6 +503,7 @@ #define PCI_VENDOR_ID_CONTAQ 0x1080 #define PCI_DEVICE_ID_CONTAQ_82C599 0x0600 +/* ??? Alpha SX164 has reference to device nr 0xc693 as a CYPRESS bridge. */ #define PCI_VENDOR_ID_FOREX 0x1083 diff -u --recursive --new-file v2.1.88/linux/include/linux/swap.h linux/include/linux/swap.h --- v2.1.88/linux/include/linux/swap.h Mon Feb 23 18:12:12 1998 +++ linux/include/linux/swap.h Mon Feb 23 15:24:32 1998 @@ -9,6 +9,8 @@ #ifdef __KERNEL__ +#undef DEBUG_SWAP + #include #define SWP_USED 1 @@ -21,7 +23,6 @@ kdev_t swap_device; struct dentry * swap_file; unsigned char * swap_map; - unsigned char * swap_lockmap; unsigned int lowest_bit; unsigned int highest_bit; unsigned int cluster_next; @@ -53,11 +54,7 @@ /* linux/mm/page_io.c */ extern void rw_swap_page(int, unsigned long, char *, int); -#define read_swap_page(nr,buf) \ - rw_swap_page(READ,(nr),(buf),1) -#define write_swap_page(nr,buf) \ - rw_swap_page(WRITE,(nr),(buf),1) -extern void swap_after_unlock_page (unsigned long entry); +extern void rw_swap_page_nocache(int, unsigned long, char *); /* linux/mm/page_alloc.c */ extern void swap_in(struct task_struct *, struct vm_area_struct *, @@ -68,6 +65,8 @@ extern void show_swap_cache_info(void); extern int add_to_swap_cache(struct page *, unsigned long); extern void swap_duplicate(unsigned long); +extern struct page * read_swap_cache_async(unsigned long, int); +#define read_swap_cache(entry) read_swap_cache_async(entry, 1); /* linux/mm/swapfile.c */ extern unsigned int nr_swapfiles; @@ -107,12 +106,18 @@ /* * Work out if there are any other processes sharing this page, ignoring - * any page reference coming from the page or swap cache. + * any page reference coming from the swap cache, or from outstanding + * swap IO on this page. (The page cache _does_ count as another valid + * reference to the page, however.) */ static inline int is_page_shared(struct page *page) { int count = atomic_read(&page->count); - if (page->inode) + if (PageReserved(page)) + return 1; + if (page->inode == &swapper_inode) + count--; + if (PageFreeAfter(page)) count--; return (count > 1); } diff -u --recursive --new-file v2.1.88/linux/include/net/neighbour.h linux/include/net/neighbour.h --- v2.1.88/linux/include/net/neighbour.h Fri Feb 6 15:34:56 1998 +++ linux/include/net/neighbour.h Mon Feb 23 16:19:55 1998 @@ -249,12 +249,12 @@ return 0; } -extern __inline__ int neigh_table_lock(struct neigh_table *tbl) +extern __inline__ void neigh_table_lock(struct neigh_table *tbl) { atomic_inc(&tbl->lock); } -extern __inline__ int neigh_table_unlock(struct neigh_table *tbl) +extern __inline__ void neigh_table_unlock(struct neigh_table *tbl) { atomic_dec(&tbl->lock); } diff -u --recursive --new-file v2.1.88/linux/ipc/shm.c linux/ipc/shm.c --- v2.1.88/linux/ipc/shm.c Tue Dec 9 09:49:59 1997 +++ linux/ipc/shm.c Mon Feb 23 16:13:51 1998 @@ -689,7 +689,7 @@ goto done; } if (!pte_none(pte)) { - read_swap_page(pte_val(pte), (char *) page); + rw_swap_page(READ, pte_val(pte), (char *) page, 1); /* FIXME */ pte = __pte(shp->shm_pages[idx]); if (pte_present(pte)) { free_page (page); /* doesn't sleep */ @@ -820,7 +820,7 @@ if (atomic_read(&mem_map[MAP_NR(pte_page(page))].count) != 1) goto check_table; shp->shm_pages[idx] = swap_nr; - write_swap_page (swap_nr, (char *) pte_page(page)); + rw_swap_page(WRITE, swap_nr, (char *) pte_page(page), 1); /* FIXME */ free_page(pte_page(page)); swap_successes++; shm_swp++; diff -u --recursive --new-file v2.1.88/linux/kernel/sysctl.c linux/kernel/sysctl.c --- v2.1.88/linux/kernel/sysctl.c Sat Jan 10 15:15:21 1998 +++ linux/kernel/sysctl.c Sat Feb 21 13:27:56 1998 @@ -523,9 +523,7 @@ proc_unregister(root, de->low_ino); table->de = NULL; kfree(de); - } else - printk("unregister_proc_table: %s not empty!\n", - table->procname); + } } } diff -u --recursive --new-file v2.1.88/linux/mm/filemap.c linux/mm/filemap.c --- v2.1.88/linux/mm/filemap.c Tue Feb 3 18:26:30 1998 +++ linux/mm/filemap.c Mon Feb 23 15:24:32 1998 @@ -162,10 +162,12 @@ if (test_and_clear_bit(PG_referenced, &page->flags)) break; - /* is it a page cache page? */ + /* is it a swap-cache or page-cache page? */ if (page->inode) { - if (page->inode == &swapper_inode) - panic ("Shrinking a swap cache page"); + if (PageSwapCache(page)) { + delete_from_swap_cache(page); + return 1; + } remove_page_from_hash_queue(page); remove_page_from_inode_queue(page); __free_page(page); diff -u --recursive --new-file v2.1.88/linux/mm/memory.c linux/mm/memory.c --- v2.1.88/linux/mm/memory.c Tue Feb 17 13:12:49 1998 +++ linux/mm/memory.c Mon Feb 23 15:24:32 1998 @@ -267,8 +267,10 @@ } if (cow) pte = pte_wrprotect(pte); +#if 0 /* No longer needed with the new swap cache code */ if (delete_from_swap_cache(&mem_map[page_nr])) pte = pte_mkdirty(pte); +#endif set_pte(dst_pte, pte_mkold(pte)); set_pte(src_pte, pte); atomic_inc(&mem_map[page_nr].count); @@ -616,8 +618,11 @@ unsigned long old_page, new_page; struct page * page_map; - new_page = __get_free_page(GFP_KERNEL); pte = *page_table; + new_page = __get_free_page(GFP_KERNEL); + /* Did someone else copy this page for us while we slept? */ + if (pte_val(*page_table) != pte_val(pte)) + goto end_wp_page; if (!pte_present(pte)) goto end_wp_page; if (pte_write(pte)) @@ -626,15 +631,12 @@ if (MAP_NR(old_page) >= max_mapnr) goto bad_wp_page; tsk->min_flt++; - page_map = mem_map + MAP_NR(old_page); - if (PageSwapCache(page_map)) - delete_from_swap_cache(page_map); /* * Do we need to copy? */ - if (atomic_read(&mem_map[MAP_NR(old_page)].count) != 1) { + if (is_page_shared(page_map)) { if (new_page) { if (PageReserved(mem_map + MAP_NR(old_page))) ++vma->vm_mm->rss; @@ -654,6 +656,8 @@ oom(tsk); return; } + if (PageSwapCache(page_map)) + delete_from_swap_cache(page_map); flush_cache_page(vma, address); set_pte(page_table, pte_mkdirty(pte_mkwrite(pte))); flush_tlb_page(vma, address); diff -u --recursive --new-file v2.1.88/linux/mm/page_alloc.c linux/mm/page_alloc.c --- v2.1.88/linux/mm/page_alloc.c Thu Jan 15 21:35:49 1998 +++ linux/mm/page_alloc.c Mon Feb 23 15:24:32 1998 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include /* for cli()/sti() */ @@ -101,6 +102,30 @@ static spinlock_t page_alloc_lock; #endif +/* + * This routine is used by the kernel swap deamon to determine + * whether we have "enough" free pages. It is fairly arbitrary, + * but this had better return false if any reasonable "get_free_page()" + * allocation could currently fail.. + * + * Right now we just require that the highest memory order should + * have at least two entries. Whether this makes sense or not + * under real load is to be tested, but it also gives us some + * guarantee about memory fragmentation (essentially, it means + * that there should be at least two large areas available). + */ +int free_memory_available(void) +{ + int retval; + unsigned long flags; + struct free_area_struct * last = free_area + NR_MEM_LISTS - 1; + + spin_lock_irqsave(&page_alloc_lock, flags); + retval = (last->next != memory_head(last)) && (last->next->next != memory_head(last)); + spin_unlock_irqrestore(&page_alloc_lock, flags); + return retval; +} + static inline void free_pages_ok(unsigned long map_nr, unsigned long order) { struct free_area_struct *area = free_area + order; @@ -328,31 +353,38 @@ void swap_in(struct task_struct * tsk, struct vm_area_struct * vma, pte_t * page_table, unsigned long entry, int write_access) { - unsigned long page = __get_free_page(GFP_KERNEL); + unsigned long page; + struct page *page_map; + + page_map = read_swap_cache(entry); if (pte_val(*page_table) != entry) { - free_page(page); + if (page_map) + free_page_and_swap_cache(page_address(page_map)); return; } - if (!page) { + if (!page_map) { set_pte(page_table, BAD_PAGE); swap_free(entry); oom(tsk); return; } - read_swap_page(entry, (char *) page); - if (pte_val(*page_table) != entry) { - free_page(page); - return; - } + + page = page_address(page_map); vma->vm_mm->rss++; - tsk->maj_flt++; - if (!write_access && add_to_swap_cache(&mem_map[MAP_NR(page)], entry)) { - /* keep swap page allocated for the moment (swap cache) */ + tsk->min_flt++; + swap_free(entry); + + if (!write_access || is_page_shared(page_map)) { set_pte(page_table, mk_pte(page, vma->vm_page_prot)); return; } + + /* The page is unshared, and we want write access. In this + case, it is safe to tear down the swap cache and give the + page over entirely to this process. */ + + delete_from_swap_cache(page_map); set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)))); - swap_free(entry); return; } diff -u --recursive --new-file v2.1.88/linux/mm/page_io.c linux/mm/page_io.c --- v2.1.88/linux/mm/page_io.c Mon Jan 12 14:33:20 1998 +++ linux/mm/page_io.c Mon Feb 23 15:24:32 1998 @@ -6,6 +6,7 @@ * Swap reorganised 29.12.95, * Asynchronous swapping added 30.12.95. Stephen Tweedie * Removed race in async swapping. 14.4.1996. Bruno Haible + * Add swap of shared pages through the page cache. 20.2.1998. Stephen Tweedie */ #include @@ -27,26 +28,36 @@ #include #include -static struct wait_queue * lock_queue = NULL; - /* * Reads or writes a swap page. * wait=1: start I/O and wait for completion. wait=0: start asynchronous I/O. + * All IO to swap files (as opposed to swap partitions) is done + * synchronously. * - * Important prevention of race condition: The first thing we do is set a lock - * on this swap page, which lasts until I/O completes. This way a - * write_swap_page(entry) immediately followed by a read_swap_page(entry) - * on the same entry will first complete the write_swap_page(). Fortunately, - * not more than one write_swap_page() request can be pending per entry. So - * all races the caller must catch are: multiple read_swap_page() requests - * on the same entry. + * Important prevention of race condition: the caller *must* atomically + * create a unique swap cache entry for this swap page before calling + * rw_swap_page, and must lock that page. By ensuring that there is a + * single page of memory reserved for the swap entry, the normal VM page + * lock on that page also doubles as a lock on swap entries. Having only + * one lock to deal with per swap entry (rather than locking swap and memory + * independently) also makes it easier to make certain swapping operations + * atomic, which is particularly important when we are trying to ensure + * that shared pages stay shared while being swapped. */ + void rw_swap_page(int rw, unsigned long entry, char * buf, int wait) { unsigned long type, offset; struct swap_info_struct * p; struct page *page = mem_map + MAP_NR(buf); +#ifdef DEBUG_SWAP + printk ("DebugVM: %s_swap_page entry %08lx, page %p (count %d), %s\n", + (rw == READ) ? "read" : "write", + entry, buf, atomic_read(&page->count), + wait ? "wait" : "nowait"); +#endif + if (page->inode && page->inode != &swapper_inode) panic ("Tried to swap a non-swapper page"); type = SWP_TYPE(entry); @@ -61,31 +72,28 @@ return; } if (p->swap_map && !p->swap_map[offset]) { - printk("Hmm.. Trying to use unallocated swap (%08lx)\n", entry); + printk("Hmm.. Trying to %s unallocated swap (%08lx)\n", + (rw == READ) ? "read" : "write", + entry); return; } if (!(p->flags & SWP_USED)) { printk("Trying to swap to unused swap-device\n"); return; } - /* - * For now, this is not legal! - */ - if (PageSwapCache(page)) - panic ("Trying to swap a swap-cache page!"); - /* Make sure we are the only process doing I/O with this swap page. */ - while (test_and_set_bit(offset,p->swap_lockmap)) { - run_task_queue(&tq_disk); - sleep_on(&lock_queue); + if (!PageLocked(page)) { + printk("VM: swap page is unlocked\n"); + return; } - - if (rw == READ) + + if (rw == READ) { + clear_bit(PG_uptodate, &page->flags); kstat.pswpin++; - else + } else kstat.pswpout++; + atomic_inc(&page->count); - wait_on_page(page); /* * Make sure that we have a swap cache association for this * page. We need this to find which swap page to unlock once @@ -94,17 +102,19 @@ * as if it were: we are not allowed to manipulate the inode * hashing for locked pages. */ - if (PageSwapCache(page)) { - if (page->offset != entry) - panic ("swap entry mismatch"); - } else - page->offset = entry; + if (!PageSwapCache(page)) { + printk("VM: swap page is not in swap cache\n"); + return; + } + if (page->offset != entry) { + printk ("swap entry mismatch"); + return; + } if (p->swap_device) { if (!wait) { set_bit(PG_free_after, &page->flags); set_bit(PG_decr_after, &page->flags); - set_bit(PG_swap_unlock_after, &page->flags); atomic_inc(&nr_async_pages); } ll_rw_page(rw,p->swap_device,offset,buf); @@ -155,38 +165,49 @@ } } ll_rw_swap_file(rw,swapf->i_dev, zones, i,buf); + /* Unlike ll_rw_page, ll_rw_swap_file won't unlock the + page for us. */ + clear_bit(PG_locked, &page->flags); + wake_up(&page->wait); } else printk("rw_swap_page: no swap file or device\n"); atomic_dec(&page->count); - if (offset && !test_and_clear_bit(offset,p->swap_lockmap)) - printk("rw_swap_page: lock already cleared\n"); - wake_up(&lock_queue); +#ifdef DEBUG_SWAP + printk ("DebugVM: %s_swap_page finished on page %p (count %d)\n", + (rw == READ) ? "read" : "write", + buf, atomic_read(&page->count)); +#endif } - -/* This is run when asynchronous page I/O has completed. */ -void swap_after_unlock_page (unsigned long entry) +/* + * Setting up a new swap file needs a simple wrapper just to read the + * swap signature. SysV shared memory also needs a simple wrapper. + */ +void rw_swap_page_nocache(int rw, unsigned long entry, char *buffer) { - unsigned long type, offset; - struct swap_info_struct * p; - - type = SWP_TYPE(entry); - if (type >= nr_swapfiles) { - printk("swap_after_unlock_page: bad swap-device\n"); + struct page *page; + + page = mem_map + MAP_NR((unsigned long) buffer); + wait_on_page(page); + set_bit(PG_locked, &page->flags); + if (test_and_set_bit(PG_swap_cache, &page->flags)) { + printk ("VM: read_swap_page: page already in swap cache!\n"); return; } - p = &swap_info[type]; - offset = SWP_OFFSET(entry); - if (offset >= p->max) { - printk("swap_after_unlock_page: weirdness\n"); + if (page->inode) { + printk ("VM: read_swap_page: page already in page cache!\n"); return; } - if (!test_and_clear_bit(offset,p->swap_lockmap)) - printk("swap_after_unlock_page: lock already cleared\n"); - wake_up(&lock_queue); + page->inode = &swapper_inode; + page->offset = entry; + rw_swap_page(rw, entry, buffer, 1); + page->inode = 0; + clear_bit(PG_swap_cache, &page->flags); } + + /* * Swap partitions are now read via brw_page. ll_rw_page is an * asynchronous function now --- we must call wait_on_page afterwards @@ -211,7 +232,7 @@ panic("ll_rw_page: bad block dev cmd, must be R/W"); } page = mem_map + MAP_NR(buffer); - if (test_and_set_bit(PG_locked, &page->flags)) - panic ("ll_rw_page: page already locked"); + if (!PageLocked(page)) + panic ("ll_rw_page: page not already locked"); brw_page(rw, page, dev, &block, PAGE_SIZE, 0); } diff -u --recursive --new-file v2.1.88/linux/mm/swap_state.c linux/mm/swap_state.c --- v2.1.88/linux/mm/swap_state.c Mon Jan 12 14:33:20 1998 +++ linux/mm/swap_state.c Mon Feb 23 15:24:32 1998 @@ -55,29 +55,33 @@ int add_to_swap_cache(struct page *page, unsigned long entry) { - struct swap_info_struct * p = &swap_info[SWP_TYPE(entry)]; - #ifdef SWAP_CACHE_INFO swap_cache_add_total++; #endif - if (PageLocked(page)) - panic("Adding page cache to locked page"); - if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) { - if (PageTestandSetSwapCache(page)) - panic("swap_cache: replacing non-empty entry"); - if (page->inode) - panic("swap_cache: replacing page-cached entry"); - atomic_inc(&page->count); - page->inode = &swapper_inode; - page->offset = entry; - add_page_to_hash_queue(page, &swapper_inode, entry); - add_page_to_inode_queue(&swapper_inode, page); -#ifdef SWAP_CACHE_INFO - swap_cache_add_success++; +#ifdef DEBUG_SWAP + printk("DebugVM: add_to_swap_cache(%08lx count %d, entry %08lx)\n", + page_address(page), atomic_read(&page->count), entry); #endif - return 1; + if (PageTestandSetSwapCache(page)) { + printk("swap_cache: replacing non-empty entry %08lx " + "on page %08lx", + page->offset, page_address(page)); + return 0; } - return 0; + if (page->inode) { + printk("swap_cache: replacing page-cached entry " + "on page %08lx", page_address(page)); + return 0; + } + atomic_inc(&page->count); + page->inode = &swapper_inode; + page->offset = entry; + add_page_to_hash_queue(page, &swapper_inode, entry); + add_page_to_inode_queue(&swapper_inode, page); +#ifdef SWAP_CACHE_INFO + swap_cache_add_success++; +#endif + return 1; } /* @@ -110,6 +114,10 @@ entry, p->swap_map[offset]); p->swap_map[offset] = 127; } +#ifdef DEBUG_SWAP + printk("DebugVM: swap_duplicate(entry %08lx, count now %d)\n", + entry, p->swap_map[offset]); +#endif out: return; @@ -120,25 +128,37 @@ printk("swap_duplicate: offset exceeds max\n"); goto out; bad_unused: - printk("swap_duplicate: unused page\n"); + printk("swap_duplicate at %8p: unused page\n", + __builtin_return_address(0)); goto out; } void remove_from_swap_cache(struct page *page) { - if (!page->inode) - panic ("Removing swap cache page with zero inode hash"); - if (page->inode != &swapper_inode) - panic ("Removing swap cache page with wrong inode hash"); - if (PageLocked(page)) - panic ("Removing swap cache from locked page"); + if (!page->inode) { + printk ("VM: Removing swap cache page with zero inode hash " + "on page %08lx", page_address(page)); + return; + } + if (page->inode != &swapper_inode) { + printk ("VM: Removing swap cache page with wrong inode hash " + "on page %08lx", page_address(page)); + } /* * This will be a legal case once we have a more mature swap cache. */ - if (atomic_read(&page->count) == 1) - panic ("Removing page cache on unshared page"); + if (atomic_read(&page->count) == 1) { + printk ("VM: Removing page cache on unshared page %08lx", + page_address(page)); + return; + } + +#ifdef DEBUG_SWAP + printk("DebugVM: remove_from_swap_cache(%08lx count %d)\n", + page_address(page), atomic_read(&page->count)); +#endif remove_page_from_hash_queue (page); remove_page_from_inode_queue (page); PageClearSwapCache (page); @@ -172,6 +192,11 @@ #ifdef SWAP_CACHE_INFO swap_cache_del_success++; #endif +#ifdef DEBUG_SWAP + printk("DebugVM: delete_from_swap_cache(%08lx count %d, " + "entry %08lx)\n", + page_address(page), atomic_read(&page->count), entry); +#endif remove_from_swap_cache (page); swap_free (entry); return 1; @@ -190,8 +215,86 @@ /* * If we are the only user, then free up the swap cache. */ - if (PageSwapCache(page) && !is_page_shared(page)) + if (PageSwapCache(page) && !is_page_shared(page)) { delete_from_swap_cache(page); + } free_page(addr); } + + +/* + * Lookup a swap entry in the swap cache. We need to be careful about + * locked pages. A found page will be returned with its refcount + * incremented. + */ + +static struct page * lookup_swap_cache(unsigned long entry) +{ + struct page *found; + + while (1) { + found = find_page(&swapper_inode, entry); + if (!found) + return 0; + if (found->inode != &swapper_inode + || !PageSwapCache(found)) { + __free_page(found); + printk ("VM: Found a non-swapper swap page!\n"); + return 0; + } + if (!PageLocked(found)) + return found; + __free_page(found); + __wait_on_page(found); + } +} + +/* + * Locate a page of swap in physical memory, reserving swap cache space + * and reading the disk if it is not already cached. If wait==0, we are + * only doing readahead, so don't worry if the page is already locked. + */ + +struct page * read_swap_cache_async(unsigned long entry, int wait) +{ + struct page *found_page, *new_page = 0; + unsigned long new_page_addr = 0; + +#ifdef DEBUG_SWAP + printk("DebugVM: read_swap_cache_async entry %08lx%s\n", + entry, wait ? ", wait" : ""); +#endif +repeat: + found_page = lookup_swap_cache(entry); + if (found_page) { + if (new_page) + __free_page(new_page); + return found_page; + } + + /* The entry is not present. Lock down a new page, add it to + * the swap cache and read its contents. */ + if (!new_page) { + new_page_addr = __get_free_page(GFP_KERNEL); + if (!new_page_addr) + return 0; /* Out of memory */ + new_page = mem_map + MAP_NR(new_page_addr); + goto repeat; /* We might have stalled */ + } + + if (!add_to_swap_cache(new_page, entry)) { + free_page(new_page_addr); + return 0; + } + swap_duplicate(entry); /* Account for the swap cache */ + set_bit(PG_locked, &new_page->flags); + rw_swap_page(READ, entry, (char *) new_page_addr, wait); +#ifdef DEBUG_SWAP + printk("DebugVM: read_swap_cache_async created " + "entry %08lx at %p\n", + entry, (char *) page_address(new_page)); +#endif + return new_page; +} + diff -u --recursive --new-file v2.1.88/linux/mm/swapfile.c linux/mm/swapfile.c --- v2.1.88/linux/mm/swapfile.c Mon Jan 12 14:33:20 1998 +++ linux/mm/swapfile.c Mon Feb 23 15:24:32 1998 @@ -21,6 +21,7 @@ #include #include /* for blk_size */ #include +#include #include #include @@ -51,8 +52,6 @@ offset = si->cluster_next++; if (si->swap_map[offset]) continue; - if (test_bit(offset, si->swap_lockmap)) - continue; si->cluster_nr--; goto got_page; } @@ -61,8 +60,6 @@ for (offset = si->lowest_bit; offset <= si->highest_bit ; offset++) { if (si->swap_map[offset]) continue; - if (test_bit(offset, si->swap_lockmap)) - continue; si->lowest_bit = offset; got_page: si->swap_map[offset] = 1; @@ -153,6 +150,10 @@ if (!--p->swap_map[offset]) nr_swap_pages++; } +#ifdef DEBUG_SWAP + printk("DebugVM: swap_free(entry %08lx, count now %d)\n", + entry, p->swap_map[offset]); +#endif out: return; @@ -173,42 +174,38 @@ /* * The swap entry has been read in advance, and we return 1 to indicate * that the page has been used or is no longer needed. + * + * Always set the resulting pte to be nowrite (the same as COW pages + * after one process has exited). We don't know just how many ptes will + * share this swap entry, so be cautious and let do_wp_page work out + * what to do if a write is requested later. */ -static inline int unuse_pte(struct vm_area_struct * vma, unsigned long address, +static inline void unuse_pte(struct vm_area_struct * vma, unsigned long address, pte_t *dir, unsigned long entry, unsigned long page) { pte_t pte = *dir; if (pte_none(pte)) - return 0; + return; if (pte_present(pte)) { - struct page *pg; - unsigned long page_nr = MAP_NR(pte_page(pte)); - unsigned long pg_swap_entry; - - if (page_nr >= max_mapnr) - return 0; - pg = mem_map + page_nr; - if (!(pg_swap_entry = in_swap_cache(pg))) - return 0; - if (SWP_TYPE(pg_swap_entry) != SWP_TYPE(entry)) - return 0; - delete_from_swap_cache(pg); + /* If this entry is swap-cached, then page must already + hold the right address for any copies in physical + memory */ + if (pte_page(pte) != page) + return; + /* We will be removing the swap cache in a moment, so... */ set_pte(dir, pte_mkdirty(pte)); - if (pg_swap_entry != entry) - return 0; - free_page(page); - return 1; + return; } if (pte_val(pte) != entry) - return 0; - set_pte(dir, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)))); - ++vma->vm_mm->rss; + return; + set_pte(dir, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); swap_free(entry); - return 1; + atomic_inc(&mem_map[MAP_NR(page)].count); + ++vma->vm_mm->rss; } -static inline int unuse_pmd(struct vm_area_struct * vma, pmd_t *dir, +static inline void unuse_pmd(struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long size, unsigned long offset, unsigned long entry, unsigned long page) { @@ -216,11 +213,11 @@ unsigned long end; if (pmd_none(*dir)) - return 0; + return; if (pmd_bad(*dir)) { printk("unuse_pmd: bad pmd (%08lx)\n", pmd_val(*dir)); pmd_clear(dir); - return 0; + return; } pte = pte_offset(dir, address); offset += address & PMD_MASK; @@ -229,16 +226,13 @@ if (end > PMD_SIZE) end = PMD_SIZE; do { - if (unuse_pte(vma, offset+address-vma->vm_start, pte, entry, - page)) - return 1; + unuse_pte(vma, offset+address-vma->vm_start, pte, entry, page); address += PAGE_SIZE; pte++; } while (address < end); - return 0; } -static inline int unuse_pgd(struct vm_area_struct * vma, pgd_t *dir, +static inline void unuse_pgd(struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long size, unsigned long entry, unsigned long page) { @@ -246,11 +240,11 @@ unsigned long offset, end; if (pgd_none(*dir)) - return 0; + return; if (pgd_bad(*dir)) { printk("unuse_pgd: bad pgd (%08lx)\n", pgd_val(*dir)); pgd_clear(dir); - return 0; + return; } pmd = pmd_offset(dir, address); offset = address & PGDIR_MASK; @@ -259,30 +253,26 @@ if (end > PGDIR_SIZE) end = PGDIR_SIZE; do { - if (unuse_pmd(vma, pmd, address, end - address, offset, entry, - page)) - return 1; + unuse_pmd(vma, pmd, address, end - address, offset, entry, + page); address = (address + PMD_SIZE) & PMD_MASK; pmd++; } while (address < end); - return 0; } -static int unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir, +static void unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir, unsigned long entry, unsigned long page) { unsigned long start = vma->vm_start, end = vma->vm_end; while (start < end) { - if (unuse_pgd(vma, pgdir, start, end - start, entry, page)) - return 1; + unuse_pgd(vma, pgdir, start, end - start, entry, page); start = (start + PGDIR_SIZE) & PGDIR_MASK; pgdir++; } - return 0; } -static int unuse_process(struct mm_struct * mm, unsigned long entry, +static void unuse_process(struct mm_struct * mm, unsigned long entry, unsigned long page) { struct vm_area_struct* vma; @@ -291,13 +281,12 @@ * Go through process' page directory. */ if (!mm || mm == &init_mm) - return 0; + return; for (vma = mm->mmap; vma; vma = vma->vm_next) { pgd_t * pgd = pgd_offset(mm, vma->vm_start); - if (unuse_vma(vma, pgd, entry, page)) - return 1; + unuse_vma(vma, pgd, entry, page); } - return 0; + return; } /* @@ -310,19 +299,14 @@ struct swap_info_struct * si = &swap_info[type]; struct task_struct *p; unsigned long page = 0; + struct page *page_map; unsigned long entry; int i; while (1) { - if (!page) { - page = __get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - } - /* - * Find a swap page in use and read it in. - */ + * Find a swap page in use and read it in. + */ for (i = 1 , entry = 0; i < si->max ; i++) { if (si->swap_map[i] > 0 && si->swap_map[i] != 0x80) { entry = SWP_ENTRY(type, i); @@ -331,36 +315,31 @@ } if (!entry) break; - read_swap_page(entry, (char *) page); + /* 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) + return -ENOMEM; + page = page_address(page_map); read_lock(&tasklist_lock); - for_each_task(p) { - if (unuse_process(p->mm, entry, page)) { - page = 0; - goto unlock; - } - } - unlock: + for_each_task(p) + unuse_process(p->mm, entry, page); read_unlock(&tasklist_lock); - if (page) { - /* - * If we couldn't find an entry, there are several - * possible reasons: someone else freed it first, - * we freed the last reference to an overflowed entry, - * or the system has lost track of the use counts. - */ - if (si->swap_map[i] != 0) { - if (si->swap_map[i] != 127) - printk("try_to_unuse: entry %08lx " - "not in use\n", entry); - si->swap_map[i] = 0; - nr_swap_pages++; - } + /* 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); + if (si->swap_map[i] != 0) { + if (si->swap_map[i] != 127) + printk("try_to_unuse: entry %08lx " + "not in use\n", entry); + si->swap_map[i] = 0; + nr_swap_pages++; } } - - if (page) - free_page(page); return 0; } @@ -371,7 +350,7 @@ struct file filp; int i, type, prev; int err = -EPERM; - + lock_kernel(); if (!suser()) goto out; @@ -445,8 +424,6 @@ p->swap_device = 0; vfree(p->swap_map); p->swap_map = NULL; - free_page((long) p->swap_lockmap); - p->swap_lockmap = NULL; p->flags = 0; err = 0; out: @@ -506,6 +483,7 @@ int error = -EPERM; struct file filp; static int least_priority = 0; + unsigned char *avail_map = 0; lock_kernel(); if (!suser()) @@ -523,7 +501,6 @@ p->swap_file = NULL; p->swap_device = 0; p->swap_map = NULL; - p->swap_lockmap = NULL; p->lowest_bit = 0; p->highest_bit = 0; p->cluster_nr = 0; @@ -566,24 +543,24 @@ } } else if (!S_ISREG(swap_dentry->d_inode->i_mode)) goto bad_swap; - p->swap_lockmap = (unsigned char *) get_free_page(GFP_USER); - if (!p->swap_lockmap) { + avail_map = (unsigned char *) get_free_page(GFP_USER); + if (!avail_map) { printk("Unable to start swapping: out of memory :-)\n"); error = -ENOMEM; goto bad_swap; } - read_swap_page(SWP_ENTRY(type,0), (char *) p->swap_lockmap); - if (memcmp("SWAP-SPACE",p->swap_lockmap+PAGE_SIZE-10,10)) { + rw_swap_page_nocache(READ, SWP_ENTRY(type,0), (char *) avail_map); + if (memcmp("SWAP-SPACE",avail_map+PAGE_SIZE-10,10)) { printk("Unable to find swap-space signature\n"); error = -EINVAL; goto bad_swap; } - memset(p->swap_lockmap+PAGE_SIZE-10,0,10); + memset(avail_map+PAGE_SIZE-10,0,10); j = 0; p->lowest_bit = 0; p->highest_bit = 0; for (i = 1 ; i < 8*PAGE_SIZE ; i++) { - if (test_bit(i,p->swap_lockmap)) { + if (test_bit(i,avail_map)) { if (!p->lowest_bit) p->lowest_bit = i; p->highest_bit = i; @@ -602,13 +579,12 @@ goto bad_swap; } for (i = 1 ; i < p->max ; i++) { - if (test_bit(i,p->swap_lockmap)) + if (test_bit(i,avail_map)) p->swap_map[i] = 0; else p->swap_map[i] = 0x80; } p->swap_map[0] = 0x80; - memset(p->swap_lockmap,0,PAGE_SIZE); p->flags = SWP_WRITEOK; p->pages = j; nr_swap_pages += j; @@ -635,15 +611,15 @@ if(filp.f_op && filp.f_op->release) filp.f_op->release(filp.f_dentry->d_inode,&filp); bad_swap_2: - free_page((long) p->swap_lockmap); vfree(p->swap_map); dput(p->swap_file); p->swap_device = 0; p->swap_file = NULL; p->swap_map = NULL; - p->swap_lockmap = NULL; p->flags = 0; out: + if (avail_map) + free_page((long) avail_map); unlock_kernel(); return error; } diff -u --recursive --new-file v2.1.88/linux/mm/vmscan.c linux/mm/vmscan.c --- v2.1.88/linux/mm/vmscan.c Thu Jan 15 21:07:58 1998 +++ linux/mm/vmscan.c Mon Feb 23 15:24:32 1998 @@ -7,7 +7,7 @@ * kswapd added: 7.1.96 sct * Removed kswapd_ctl limits, and swap out as many pages as needed * to bring the system back to free_pages_high: 2.4.97, Rik van Riel. - * Version: $Id: vmscan.c,v 1.23 1997/04/12 04:31:05 davem Exp $ + * Version: $Id: vmscan.c,v 1.5 1998/02/23 22:14:28 sct Exp $ */ #include @@ -80,73 +80,158 @@ || PageLocked(page_map) || ((gfp_mask & __GFP_DMA) && !PageDMA(page_map))) return 0; - /* Deal with page aging. Pages age from being unused; they - * rejuvenate on being accessed. Only swap old pages (age==0 - * is oldest). + + /* + * Deal with page aging. There are several special cases to + * consider: + * + * Page has been accessed, but is swap cached. If the page is + * getting sufficiently "interesting" --- its age is getting + * high --- then if we are sufficiently short of free swap + * pages, then delete the swap cache. We can only do this if + * the swap page's reference count is one: ie. there are no + * other references to it beyond the swap cache (as there must + * still be pte's pointing to it if count > 1). + * + * If the page has NOT been touched, and its age reaches zero, + * then we are swapping it out: * - * This test will no longer work once swap cached pages can be - * shared! - */ - if ((pte_dirty(pte) && delete_from_swap_cache(page_map)) - || pte_young(pte)) { + * If there is already a swap cache page for this page, then + * another process has already allocated swap space, so just + * dereference the physical page and copy in the swap entry + * from the swap cache. + * + * Note, we rely on all pages read in from swap either having + * the swap cache flag set, OR being marked writable in the pte, + * but NEVER BOTH. (It IS legal to be neither cached nor dirty, + * however.) + * + * -- Stephen Tweedie 1998 */ + + if (pte_write(pte)) { + /* + * We _will_ allow dirty cached mappings later on, once + * MAP_SHARED|MAP_ANONYMOUS is working, but for now + * catch this as a bug. + */ + if (is_page_shared(page_map)) { + printk ("VM: Found a shared writable dirty page!\n"); + return 0; + } + if (PageSwapCache(page_map)) { + printk ("VM: Found a writable swap-cached page!\n"); + return 0; + } + } + + if (pte_young(pte)) { set_pte(page_table, pte_mkold(pte)); touch_page(page_map); + /* + * We should test here to see if we want to recover any + * swap cache page here. We do this if the page seeing + * enough activity, AND we are sufficiently low on swap + * + * We need to track both the number of available swap + * pages and the total number present before we can do + * this... + */ return 0; } + age_page(page_map); if (page_map->age) return 0; + if (pte_dirty(pte)) { - if (PageSwapCache(page_map)) - panic ("Can't still be swap cached!!!"); if (vma->vm_ops && vma->vm_ops->swapout) { pid_t pid = tsk->pid; vma->vm_mm->rss--; if (vma->vm_ops->swapout(vma, address - vma->vm_start + vma->vm_offset, page_table)) kill_proc(pid, SIGBUS, 1); } else { - if (!(entry = get_swap_page())) - return 0; + /* + * This is a dirty, swappable page. First of all, + * get a suitable swap entry for it, and make sure + * we have the swap cache set up to associate the + * page with that swap entry. + */ + if (PageSwapCache(page_map)) { + entry = page_map->offset; + } else { + entry = get_swap_page(); + if (!entry) + return 0; /* No swap space left */ + } + vma->vm_mm->rss--; + tsk->nswap++; flush_cache_page(vma, address); set_pte(page_table, __pte(entry)); flush_tlb_page(vma, address); - tsk->nswap++; + swap_duplicate(entry); + + /* Now to write back the page. We have two + * cases: if the page is already part of the + * swap cache, then it is already on disk. Just + * free the page and return (we release the swap + * cache on the last accessor too). + * + * If we have made a new swap entry, then we + * start the write out to disk. If the page is + * shared, however, we still need to keep the + * copy in memory, so we add it to the swap + * cache. */ + if (PageSwapCache(page_map)) { + free_page_and_swap_cache(page); + return (atomic_read(&page_map->count) == 0); + } + add_to_swap_cache(page_map, entry); + /* We checked we were unlocked way up above, and we + have been careful not to stall until here */ + set_bit(PG_locked, &page_map->flags); + /* OK, do a physical write to swap. */ rw_swap_page(WRITE, entry, (char *) page, (gfp_mask & __GFP_WAIT)); } - /* - * For now, this is safe, because the test above makes - * sure that this page is currently not swap-cached. - */ - if (PageSwapCache(page_map)) - panic ("Page became cached after IO"); - free_page(page); + /* Now we can free the current physical page. We also + * free up the swap cache if this is the last use of the + * page. Note that there is a race here: the page may + * still be shared COW by another process, but that + * process may exit while we are writing out the page + * asynchronously. That's no problem, shrink_mmap() can + * correctly clean up the occassional unshared page + * which gets left behind in the swap cache. */ + free_page_and_swap_cache(page); return 1; /* we slept: the process may not exist any more */ } - /* - * Eventually, find_in_swap_cache will be able to return true - * even for pages shared with other processes. - */ - if ((entry = find_in_swap_cache(page_map))) { - if (atomic_read(&page_map->count) != 1) { - set_pte(page_table, pte_mkdirty(pte)); - printk("Aiee.. duplicated cached swap-cache entry\n"); - return 0; - } + + /* The page was _not_ dirty, but still has a zero age. It must + * already be uptodate on disk. If it is in the swap cache, + * then we can just unlink the page now. Remove the swap cache + * too if this is the last user. */ + if ((entry = in_swap_cache(page_map))) { vma->vm_mm->rss--; flush_cache_page(vma, address); set_pte(page_table, __pte(entry)); flush_tlb_page(vma, address); - free_page(page); - return 1; + swap_duplicate(entry); + free_page_and_swap_cache(page); + return (atomic_read(&page_map->count) == 0); } + /* + * A clean page to be discarded? Must be mmap()ed from + * somewhere. Unlink the pte, and tell the filemap code to + * discard any cached backing page if this is the last user. + */ + if (PageSwapCache(page_map)) { + printk ("VM: How can this page _still_ be cached?"); + return 0; + } vma->vm_mm->rss--; flush_cache_page(vma, address); pte_clear(page_table); flush_tlb_page(vma, address); entry = page_unuse(page); - if (PageSwapCache(page_map)) - panic ("How can this page _still_ be cached?"); free_page(page); return entry; } @@ -424,7 +509,7 @@ void kswapd_setup(void) { int i; - char *revision="$Revision: 1.23 $", *s, *e; + char *revision="$Revision: 1.5 $", *s, *e; if ((s = strchr(revision, ':')) && (e = strchr(s, '$'))) @@ -441,6 +526,7 @@ */ int kswapd(void *unused) { + struct wait_queue wait = { current, NULL }; current->session = 1; current->pgrp = 1; sprintf(current->comm, "kswapd"); @@ -460,14 +546,15 @@ priorities. */ init_swap_timer(); - + add_wait_queue(&kswapd_wait, &wait); while (1) { - int fail; + int async; kswapd_awake = 0; flush_signals(current); run_task_queue(&tq_disk); - interruptible_sleep_on(&kswapd_wait); + schedule(); + current->state = TASK_INTERRUPTIBLE; kswapd_awake = 1; swapstats.wakeups++; /* Do the background pageout: @@ -477,27 +564,30 @@ * If we've had too many consecutive failures, * go back to sleep to let other tasks run. */ - for (fail = 0; fail++ < MAX_SWAP_FAIL;) { - int pages, gfp_mask; + async = 1; + for (;;) { + int gfp_mask; - pages = nr_free_pages; - if (nr_free_pages >= min_free_pages) - pages += atomic_read(&nr_async_pages); - if (pages >= free_pages_high) + if (free_memory_available()) break; gfp_mask = __GFP_IO; - if (pages < free_pages_low) + if (!async) gfp_mask |= __GFP_WAIT; - if (try_to_free_page(gfp_mask)) - fail = 0; + async = try_to_free_page(gfp_mask); + if (!(gfp_mask & __GFP_WAIT) || async) + continue; + + /* + * Not good. We failed to free a page even though + * we were synchronous. Complain and give up.. + */ + printk("kswapd: failed to free page\n"); + break; } - /* - * Report failure if we couldn't reach the minimum goal. - */ - if (nr_free_pages < min_free_pages) - printk("kswapd: failed, got %d of %d\n", - nr_free_pages, min_free_pages); } + /* As if we could ever get here - maybe we want to make this killable */ + remove_wait_queue(&kswapd_wait, &wait); + return 0; } /* diff -u --recursive --new-file v2.1.88/linux/scripts/lxdialog/checklist.c linux/scripts/lxdialog/checklist.c --- v2.1.88/linux/scripts/lxdialog/checklist.c Sat Mar 2 23:22:25 1996 +++ linux/scripts/lxdialog/checklist.c Mon Feb 23 12:31:02 1998 @@ -188,9 +188,16 @@ check_x = (list_width - check_x) / 2; item_x = check_x + 4; + if (choice >= list_height) { + scroll = choice - list_height + 1; + choice -= scroll; + } + /* Print the list */ - for (i = 0; i < max_choice; i++) - print_item (list, items[i * 3 + 1], status[i], i, i == choice); + for (i = 0; i < max_choice; i++) { + print_item (list, items[(scroll+i) * 3 + 1], + status[i+scroll], i, i == choice); + } wnoutrefresh (list);