diff -urP old/arch/alpha/kernel/bios32.c new/arch/alpha/kernel/bios32.c --- old/arch/alpha/kernel/bios32.c Fri May 5 12:00:46 2000 +++ new/arch/alpha/kernel/bios32.c Thu May 11 12:13:29 2000 @@ -327,6 +327,28 @@ */ #define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1)) +static short __inline__ +__disable_dev(struct pci_dev *dev) +{ + unsigned short cmd, orig_cmd; + + pcibios_read_config_word(dev->bus->number, dev->devfn, + PCI_COMMAND, &cmd); + + orig_cmd = cmd; + cmd &= (~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY & ~PCI_COMMAND_MASTER); + + pcibios_write_config_word(dev->bus->number, dev->devfn, + PCI_COMMAND, cmd); + return orig_cmd; +} + +static void __inline__ +__enable_dev(struct pci_dev *dev, short orig_cmd) +{ + pcibios_write_config_word(dev->bus->number, dev->devfn, + PCI_COMMAND, orig_cmd); +} /* * The following structure records initial configuration of devices @@ -344,6 +366,7 @@ struct srm_io_reset *next; struct pci_dev *dev; u32 io; + short cmd; u8 reg; } *srm_io_resets; @@ -354,6 +377,7 @@ { struct srm_irq_reset *qreset; struct srm_io_reset *ireset; + struct pci_dev *last_dev; /* Reset any IRQs that we changed. */ for (qreset = srm_irq_resets; qreset ; qreset = qreset->next) { @@ -370,6 +394,15 @@ #endif } + /* Disable any devices which had IO addresses that we changed. */ + last_dev = NULL; + for (ireset = srm_io_resets; ireset ; ireset = ireset->next) { + if (ireset->dev != last_dev) { + ireset->cmd = __disable_dev(ireset->dev); + last_dev = ireset->dev; + } + } + /* Reset any IO addresses that we changed. */ for (ireset = srm_io_resets; ireset ; ireset = ireset->next) { pcibios_write_config_dword(ireset->dev->bus->number, @@ -383,31 +416,40 @@ ireset->io); #endif } + + /* Re-enable any devices which had IO addresses that we changed. */ + last_dev = NULL; + for (ireset = srm_io_resets; ireset ; ireset = ireset->next) { + if (ireset->dev != last_dev) { + __enable_dev(ireset->dev, ireset->cmd); + last_dev = ireset->dev; + } + } } static void new_irq_reset(struct pci_dev *dev, u8 irq) { - struct srm_irq_reset *n; - n = kmalloc(sizeof(*n), GFP_KERNEL); + struct srm_irq_reset *new; + new = kmalloc(sizeof(*new), GFP_KERNEL); - n->next = srm_irq_resets; - n->dev = dev; - n->irq = irq; - srm_irq_resets = n; + new->next = srm_irq_resets; + new->dev = dev; + new->irq = irq; + srm_irq_resets = new; } static void new_io_reset(struct pci_dev *dev, u8 reg, u32 io) { - struct srm_io_reset *n; - n = kmalloc(sizeof(*n), GFP_KERNEL); + struct srm_io_reset *new; + new = kmalloc(sizeof(*new), GFP_KERNEL); - n->next = srm_io_resets; - n->dev = dev; - n->reg = reg; - n->io = io; - srm_io_resets = n; + new->next = srm_io_resets; + new->dev = dev; + new->reg = reg; + new->io = io; + srm_io_resets = new; } @@ -418,9 +460,6 @@ static void __init disable_dev(struct pci_dev *dev) { - struct pci_bus *bus; - unsigned short cmd; - /* * HACK: the PCI-to-EISA bridge does not seem to identify * itself as a bridge... :-( @@ -442,10 +481,11 @@ /* * We don't have code that will init the CYPRESS bridge correctly * so we do the next best thing, and depend on the previous - * console code to do the right thing, and ignore it here... :-\ + * console code to do the right thing, and ignore it mostly... :-\ */ if (dev->vendor == PCI_VENDOR_ID_CONTAQ && - dev->device == PCI_DEVICE_ID_CONTAQ_82C693) { + dev->device == PCI_DEVICE_ID_CONTAQ_82C693 && + PCI_FUNC(dev->devfn) == 0) { DBG_DEVS(("disable_dev: ignoring CYPRESS bridge...\n")); return; } @@ -463,12 +503,7 @@ DBG_DEVS(("disable_dev: disabling %04x:%04x\n", dev->vendor, dev->device)); - bus = dev->bus; - pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); - - /* hack, turn it off first... */ - cmd &= (~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY & ~PCI_COMMAND_MASTER); - pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND, cmd); + (void)__disable_dev(dev); } @@ -489,6 +524,7 @@ unsigned int orig_base; unsigned int alignto; unsigned long handle; + int start_idx = 0; /* * HACK: the PCI-to-EISA bridge does not seem to identify @@ -511,18 +547,24 @@ /* * We don't have code that will init the CYPRESS bridge correctly * so we do the next best thing, and depend on the previous - * console code to do the right thing, and ignore it here... :-\ + * console code to do the right thing, and ignore it mostly... :-\ */ if (dev->vendor == PCI_VENDOR_ID_CONTAQ && dev->device == PCI_DEVICE_ID_CONTAQ_82C693) { + int func = PCI_FUNC(dev->devfn); + if (func == 0) { DBG_DEVS(("layout_dev: ignoring CYPRESS bridge...\n")); return; + } + if (func == 1 || func == 2) { + start_idx = 4; /* bypass BAR 0 - 3 for the IDE devs */ + } } bus = dev->bus; pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); - for (idx = 0; idx <= 5; idx++) { + for (idx = start_idx; idx <= 5; idx++) { off = PCI_BASE_ADDRESS_0 + 4*idx; /* * Figure out how much space and of what type this @@ -713,6 +755,46 @@ dev->device, dev->class, cmd|PCI_COMMAND_MASTER)); } +/* We must save away the current bridge settings for restore during exit. */ +static void __init +save_bridge_setup(struct pci_dev *bridge) +{ + unsigned int dword; + + pcibios_read_config_dword(bridge->bus->number, bridge->devfn, + PCI_IO_BASE, &dword); + new_io_reset(bridge, PCI_IO_BASE, dword); + + pcibios_read_config_dword(bridge->bus->number, bridge->devfn, + PCI_IO_BASE_UPPER16, &dword); + new_io_reset(bridge, PCI_IO_BASE_UPPER16, dword); + + pcibios_read_config_dword(bridge->bus->number, bridge->devfn, + PCI_PREF_BASE_UPPER32, &dword); + new_io_reset(bridge, PCI_PREF_BASE_UPPER32, dword); + + pcibios_read_config_dword(bridge->bus->number, bridge->devfn, + PCI_PREF_LIMIT_UPPER32, &dword); + new_io_reset(bridge, PCI_PREF_LIMIT_UPPER32, dword); + + pcibios_read_config_dword(bridge->bus->number, bridge->devfn, + PCI_MEMORY_BASE, &dword); + new_io_reset(bridge, PCI_MEMORY_BASE, dword); + + pcibios_read_config_dword(bridge->bus->number, bridge->devfn, + PCI_PREF_MEMORY_BASE, &dword); + new_io_reset(bridge, PCI_PREF_MEMORY_BASE, dword); + + /* Must use dword that contains PCI_BRIDGE_CONTROL. */ + pcibios_read_config_dword(bridge->bus->number, bridge->devfn, + PCI_INTERRUPT_LINE, &dword); + new_io_reset(bridge, PCI_INTERRUPT_LINE, dword); + + pcibios_read_config_dword(bridge->bus->number, bridge->devfn, + PCI_COMMAND, &dword); + new_io_reset(bridge, PCI_COMMAND, dword); +} + static int __init layout_bus(struct pci_bus *bus) { @@ -764,6 +846,7 @@ if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) found_vga = 1; } + /* * Recursively allocate space for all of the sub-buses: */ @@ -772,6 +855,7 @@ for (child = bus->children; child; child = child->next) { found_vga += layout_bus(child); } + /* * Align the current bases on 4K and 1MB boundaries: */ @@ -783,6 +867,8 @@ DBG_DEVS(("layout_bus: config bus %d bridge\n", bus->number)); + save_bridge_setup(bridge); + /* * Set up the top and bottom of the PCI I/O segment * for this bus. @@ -1364,7 +1450,6 @@ layout_hoses(void) { struct linux_hose_info * hose; - int i; /* On multiple bus machines, we play games with pci_root in order that all of the busses are probed as part of the normal PCI diff -urP old/arch/alpha/kernel/time.c new/arch/alpha/kernel/time.c --- old/arch/alpha/kernel/time.c Fri May 5 12:00:03 2000 +++ new/arch/alpha/kernel/time.c Thu May 11 10:07:48 2000 @@ -236,7 +236,7 @@ { void (*irq_handler)(int, void *, struct pt_regs *); unsigned int year, mon, day, hour, min, sec, cc1, cc2; - unsigned long cycle_freq, one_percent; + unsigned long cycle_freq, ppm_error; long diff; /* @@ -261,17 +261,24 @@ cc1 = cc2; } - /* If the given value is within 1% of what we calculated, - accept it. Otherwise, use what we found. */ + /* This code used to check for a 1% error. + * PWS600au reports 598802395 which is way off. (ntpd has problems.) + * So I tightened down the check. Hal Murray, Feb 27, 2000. + */ cycle_freq = hwrpb->cycle_freq; - one_percent = cycle_freq / 100; diff = cycle_freq - est_cycle_freq; if (diff < 0) diff = -diff; - if (diff > one_percent) { + ppm_error = (diff * 1000000L) / cycle_freq; +#if 0 + printk("Alpha clock init: HWRPB %lu, Measured %lu, error=%lu ppm.\n", + hwrpb->cycle_freq, est_cycle_freq, ppm_error); +#endif + if (ppm_error > 1000) { + printk("HWRPB cycle frequency (%lu) seems inaccurate -" + " using the measured value of %lu Hz\n", + cycle_freq, est_cycle_freq); cycle_freq = est_cycle_freq; - printk("HWRPB cycle frequency bogus. Estimated %lu Hz\n", - cycle_freq); } else { est_cycle_freq = 0; diff -urP old/arch/alpha/vmlinux.lds new/arch/alpha/vmlinux.lds --- old/arch/alpha/vmlinux.lds Wed May 14 01:41:00 1997 +++ new/arch/alpha/vmlinux.lds Thu May 11 10:07:48 2000 @@ -1,10 +1,11 @@ OUTPUT_FORMAT("elf64-alpha") ENTRY(__start) +PHDRS { kernel PT_LOAD ; } SECTIONS { . = 0xfffffc0000310000; _text = .; - .text : { *(.text) } + .text : { *(.text) } :kernel .text2 : { *(.text2) } _etext = .;