diff options
| author | Linus Torvalds <torvalds@athlon.transmeta.com> | 2002-02-04 20:11:43 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@athlon.transmeta.com> | 2002-02-04 20:11:43 -0800 |
| commit | df0386374805089cbd09cc4a308e893be6738a93 (patch) | |
| tree | 218ddf00b4d68ccbeab2a0cc8f1985d936369422 | |
| parent | 87f504e5c78b910b0c1d6ffb89bc95e492322c84 (diff) | |
v2.4.9.2 -> v2.4.9.3
- Johannes Erdfelt, Oliver Neukum: USB printer driver race fix
- John Byrne: fix stupid i386-SMP irq stack layout bug
- Andreas Bombe, me: yenta IO window fix
- Neil Brown: raid1 buffer state fix
- David Miller, Paul Mackerras: fix up sparc and ppc respectively for kmap/kbd_rate
- Matija Nalis: umsdos fixes, and make it possible to boot up with umsdos
- Francois Romieu: fix bugs in dscc4 driver
- Andy Grover: new PCI config space access functions (eventually for ACPI)
- Albert Cranford: fix incorrect e2fsprog data from ver_linux script
- Dave Jones: re-sync x86 setup code, fix macsonic kmalloc use
- Johannes Erdfelt: remove obsolete plusb USB driver
- Andries Brouwer: fix USB compact flash version info, add blksize ioctls
56 files changed, 1131 insertions, 1594 deletions
diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 364ac608b6c0..9a457df6bfdc 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -11690,19 +11690,6 @@ CONFIG_USB_USBNET The module will be called usbnet.o. If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. -PLUSB driver -CONFIG_USB_PLUSB - A driver for the Prolific PL-2302 USB-to-USB network device. This - 'USB cable' connects two hosts via a point-to-point network with - bandwidth of 5 Mbit/s. Configure this driver after connecting the - USB cable via ifconfig plusb0 10.0.0.1 pointopoint 10.0.0.2 (and - vice versa on the other host). - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called plusb.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. - USB Diamond Rio500 support CONFIG_USB_RIO500 Say Y here if you want to connect a USB Rio500 mp3 player to your @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 10 -EXTRAVERSION =-pre2 +EXTRAVERSION =-pre3 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 1083b11aab48..6e5153049c94 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -742,7 +742,7 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_PEGASUS is not set # CONFIG_USB_CATC is not set # CONFIG_USB_KAWETH is not set -# CONFIG_USB_NET1080 is not set +# CONFIG_USB_USBNET is not set # # USB port drivers diff --git a/arch/i386/kernel/bluesmoke.c b/arch/i386/kernel/bluesmoke.c index 5ae7f060efc4..7c6e59aa6e3c 100644 --- a/arch/i386/kernel/bluesmoke.c +++ b/arch/i386/kernel/bluesmoke.c @@ -19,7 +19,7 @@ static void intel_machine_check(struct pt_regs * regs, long error_code) u32 mcgstl, mcgsth; int i; - rdmsr(0x17a, mcgstl, mcgsth); + rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth); if(mcgstl&(1<<0)) /* Recoverable ? */ recover=0; @@ -27,7 +27,7 @@ static void intel_machine_check(struct pt_regs * regs, long error_code) for(i=0;i<banks;i++) { - rdmsr(0x401+i*4,low, high); + rdmsr(MSR_IA32_MC0_STATUS+i*4,low, high); if(high&(1<<31)) { if(high&(1<<29)) @@ -38,18 +38,18 @@ static void intel_machine_check(struct pt_regs * regs, long error_code) high&=~(1<<31); if(high&(1<<27)) { - rdmsr(0x402+i*4, alow, ahigh); + rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh); printk("[%08x%08x]", alow, ahigh); } if(high&(1<<26)) { - rdmsr(0x402+i*4, alow, ahigh); + rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh); printk(" at %08x%08x", high, low); } printk("\n"); /* Clear it */ - wrmsr(0x401+i*4, 0UL, 0UL); + wrmsr(MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL); /* Serialize */ wmb(); } @@ -61,7 +61,7 @@ static void intel_machine_check(struct pt_regs * regs, long error_code) panic("Unable to continue"); printk(KERN_EMERG "Attempting to continue.\n"); mcgstl&=~(1<<2); - wrmsr(0x17a,mcgstl, mcgsth); + wrmsr(MSR_IA32_MCG_STATUS,mcgstl, mcgsth); } /* @@ -71,8 +71,8 @@ static void intel_machine_check(struct pt_regs * regs, long error_code) static void pentium_machine_check(struct pt_regs * regs, long error_code) { u32 loaddr, hi, lotype; - rdmsr(0x0, loaddr, hi); - rdmsr(0x1, lotype, hi); + rdmsr(MSR_IA32_P5_MC_ADDR, loaddr, hi); + rdmsr(MSR_IA32_P5_MC_TYPE, lotype, hi); printk(KERN_EMERG "CPU#%d: Machine Check Exception: 0x%8X (type 0x%8X).\n", smp_processor_id(), loaddr, lotype); if(lotype&(1<<5)) printk(KERN_EMERG "CPU#%d: Possible thermal failure (CPU on fire ?).\n", smp_processor_id()); @@ -133,8 +133,8 @@ void __init intel_mcheck_init(struct cpuinfo_x86 *c) machine_check_vector = pentium_machine_check; wmb(); /* Read registers before enabling */ - rdmsr(0x0, l, h); - rdmsr(0x1, l, h); + rdmsr(MSR_IA32_P5_MC_ADDR, l, h); + rdmsr(MSR_IA32_P5_MC_TYPE, l, h); if(done==0) printk(KERN_INFO "Intel old style machine check architecture supported.\n"); /* Enable MCE */ @@ -161,17 +161,17 @@ void __init intel_mcheck_init(struct cpuinfo_x86 *c) if(done==0) printk(KERN_INFO "Intel machine check architecture supported.\n"); - rdmsr(0x179, l, h); + rdmsr(MSR_IA32_MCG_CAP, l, h); if(l&(1<<8)) - wrmsr(0x17b, 0xffffffff, 0xffffffff); + wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff); banks = l&0xff; for(i=1;i<banks;i++) { - wrmsr(0x400+4*i, 0xffffffff, 0xffffffff); + wrmsr(MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff); } for(i=0;i<banks;i++) { - wrmsr(0x401+4*i, 0x0, 0x0); + wrmsr(MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0); } set_in_cr4(X86_CR4_MCE); printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n", smp_processor_id()); @@ -191,10 +191,10 @@ static void __init winchip_mcheck_init(struct cpuinfo_x86 *c) /* Winchip C6 */ machine_check_vector = winchip_machine_check; wmb(); - rdmsr(0x107, lo, hi); + rdmsr(MSR_IDT_FCR1, lo, hi); lo|= (1<<2); /* Enable EIERRINT (int 18 MCE) */ lo&= ~(1<<4); /* Enable MCE */ - wrmsr(0x107, lo, hi); + wrmsr(MSR_IDT_FCR1, lo, hi); __asm__ __volatile__ ( "movl %%cr4, %%eax\n\t" "orl $0x40, %%eax\n\t" @@ -236,6 +236,6 @@ void __init mcheck_init(struct cpuinfo_x86 *c) static int __init mcheck_disable(char *str) { mce_disabled = 1; - return 1; + return 0; } __setup("nomce", mcheck_disable); diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c index fa815a804220..afaa4b2db31a 100644 --- a/arch/i386/kernel/mtrr.c +++ b/arch/i386/kernel/mtrr.c @@ -389,21 +389,19 @@ static void set_mtrr_prepare (struct set_mtrr_context *ctxt) return; /* Save value of CR4 and clear Page Global Enable (bit 7) */ - if ( test_bit(X86_FEATURE_PGE, &boot_cpu_data.x86_capability) ) - asm volatile ("movl %%cr4, %0\n\t" - "movl %0, %1\n\t" - "andb $0x7f, %b1\n\t" - "movl %1, %%cr4\n\t" - : "=r" (ctxt->cr4val), "=q" (tmp) : : "memory"); + if ( test_bit(X86_FEATURE_PGE, &boot_cpu_data.x86_capability) ) { + ctxt->cr4val = read_cr4(); + write_cr4(ctxt->cr4val & (unsigned char) ~(1<<7)); + } /* Disable and flush caches. Note that wbinvd flushes the TLBs as a side-effect */ - asm volatile ("movl %%cr0, %0\n\t" - "orl $0x40000000, %0\n\t" - "wbinvd\n\t" - "movl %0, %%cr0\n\t" - "wbinvd\n\t" - : "=r" (tmp) : : "memory"); + { + unsigned int cr0 = read_cr0() | 0x40000000; + wbinvd(); + write_cr0( cr0 ); + wbinvd(); + } if ( mtrr_if == MTRR_IF_INTEL ) { /* Disable MTRRs, and set the default type to uncached */ @@ -420,15 +418,13 @@ static void set_mtrr_prepare (struct set_mtrr_context *ctxt) /* Restore the processor after a set_mtrr_prepare */ static void set_mtrr_done (struct set_mtrr_context *ctxt) { - unsigned long tmp; - if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR ) { __restore_flags (ctxt->flags); return; } /* Flush caches and TLBs */ - asm volatile ("wbinvd" : : : "memory" ); + wbinvd(); /* Restore MTRRdefType */ if ( mtrr_if == MTRR_IF_INTEL ) { @@ -440,15 +436,11 @@ static void set_mtrr_done (struct set_mtrr_context *ctxt) } /* Enable caches */ - asm volatile ("movl %%cr0, %0\n\t" - "andl $0xbfffffff, %0\n\t" - "movl %0, %%cr0\n\t" - : "=r" (tmp) : : "memory"); + write_cr0( read_cr0() & 0xbfffffff ); /* Restore value of CR4 */ if ( test_bit(X86_FEATURE_PGE, &boot_cpu_data.x86_capability) ) - asm volatile ("movl %0, %%cr4" - : : "r" (ctxt->cr4val) : "memory"); + write_cr4(ctxt->cr4val); /* Re-enable interrupts locally (if enabled previously) */ __restore_flags (ctxt->flags); @@ -607,7 +599,7 @@ static void amd_get_mtrr (unsigned int reg, unsigned long *base, { unsigned long low, high; - rdmsr (0xC0000085, low, high); + rdmsr (MSR_K6_UWCCR, low, high); /* Upper dword is region 1, lower is region 0 */ if (reg == 1) low = high; /* The base masks off on the right alignment */ @@ -771,7 +763,7 @@ static void amd_set_mtrr_up (unsigned int reg, unsigned long base, /* * Low is MTRR0 , High MTRR 1 */ - rdmsr (0xC0000085, regs[0], regs[1]); + rdmsr (MSR_K6_UWCCR, regs[0], regs[1]); /* * Blank to disable */ @@ -792,8 +784,8 @@ static void amd_set_mtrr_up (unsigned int reg, unsigned long base, * The writeback rule is quite specific. See the manual. Its * disable local interrupts, write back the cache, set the mtrr */ - __asm__ __volatile__ ("wbinvd" : : : "memory"); - wrmsr (0xC0000085, regs[0], regs[1]); + wbinvd(); + wrmsr (MSR_K6_UWCCR, regs[0], regs[1]); if (do_safe) set_mtrr_done (&ctxt); } /* End Function amd_set_mtrr_up */ @@ -826,7 +818,7 @@ static void centaur_set_mcr_up (unsigned int reg, unsigned long base, } centaur_mcr[reg].high = high; centaur_mcr[reg].low = low; - wrmsr (0x110 + reg, low, high); + wrmsr (MSR_IDT_MCR0 + reg, low, high); if (do_safe) set_mtrr_done( &ctxt ); } /* End Function centaur_set_mtrr_up */ @@ -2012,12 +2004,12 @@ static void __init centaur_mcr1_init(void) * find out what the bios might have done. */ - rdmsr(0x120, lo, hi); + rdmsr(MSR_IDT_MCR_CTRL, lo, hi); if(((lo>>17)&7)==1) /* Type 1 Winchip2 MCR */ { lo&= ~0x1C0; /* clear key */ lo|= 0x040; /* set key to 1 */ - wrmsr(0x120, lo, hi); /* unlock MCR */ + wrmsr(MSR_IDT_MCR_CTRL, lo, hi); /* unlock MCR */ } centaur_mcr_type = 1; @@ -2031,7 +2023,7 @@ static void __init centaur_mcr1_init(void) if(centaur_mcr[i]. high == 0 && centaur_mcr[i].low == 0) { if(!(lo & (1<<(9+i)))) - wrmsr (0x110 + i , 0, 0); + wrmsr (MSR_IDT_MCR0 + i , 0, 0); else /* * If the BIOS set up an MCR we cannot see it @@ -2047,7 +2039,7 @@ static void __init centaur_mcr1_init(void) */ lo |= 15; /* Write combine enables */ - wrmsr(0x120, lo, hi); + wrmsr(MSR_IDT_MCR_CTRL, lo, hi); } /* End Function centaur_mcr1_init */ /* @@ -2071,10 +2063,10 @@ static void __init centaur_mcr0_init(void) for (i = 0; i < 8; ++i) { if(centaur_mcr[i]. high == 0 && centaur_mcr[i].low == 0) - wrmsr (0x110 + i , 0, 0); + wrmsr (MSR_IDT_MCR0 + i , 0, 0); } - wrmsr(0x120, 0x01F0001F, 0); /* Write only */ + wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0); /* Write only */ } /* End Function centaur_mcr0_init */ /* @@ -2231,6 +2223,8 @@ void __init mtrr_init_secondary_cpu(void) */ cyrix_arr_init_secondary (); break; + case MTRR_IF_NONE: + break; default: /* I see no MTRRs I can support in SMP mode... */ printk ("mtrr: SMP support incomplete for this vendor\n"); diff --git a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c index ef3c7c35af01..a0aa4f46b887 100644 --- a/arch/i386/kernel/pci-pc.c +++ b/arch/i386/kernel/pci-pc.c @@ -20,65 +20,145 @@ unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2; int pcibios_last_bus = -1; -struct pci_bus *pci_root_bus; -struct pci_ops *pci_root_ops; +struct pci_bus *pci_root_bus = NULL; +struct pci_ops *pci_root_ops = NULL; + +int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value) = NULL; +int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value) = NULL; /* - * Direct access to PCI hardware... + * This interrupt-safe spinlock protects all accesses to PCI + * configuration space. */ +spinlock_t pci_config_lock = SPIN_LOCK_UNLOCKED; -#ifdef CONFIG_PCI_DIRECT /* * Functions for accessing PCI configuration space with type 1 accesses */ -#define CONFIG_CMD(dev, where) (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3)) +#ifdef CONFIG_PCI_DIRECT + +#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \ + (0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3)) + +static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +{ + unsigned long flags; + + if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + return -EINVAL; + + spin_lock_irqsave(&pci_config_lock, flags); + + outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8); + + switch (len) { + case 1: + *value = inb(0xCFC + (reg & 3)); + break; + case 2: + *value = inw(0xCFC + (reg & 2)); + break; + case 4: + *value = inl(0xCFC); + break; + } + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return 0; +} + +static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +{ + unsigned long flags; + + if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + return -EINVAL; + + spin_lock_irqsave(&pci_config_lock, flags); + + outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8); + + switch (len) { + case 1: + outb((u8)value, 0xCFC + (reg & 3)); + break; + case 2: + outw((u16)value, 0xCFC + (reg & 2)); + break; + case 4: + outl((u32)value, 0xCFC); + break; + } + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return 0; +} + +#undef PCI_CONF1_ADDRESS static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value) { - outl(CONFIG_CMD(dev,where), 0xCF8); - *value = inb(0xCFC + (where&3)); - return PCIBIOS_SUCCESSFUL; + int result; + u32 data; + + if (!value) + return -EINVAL; + + result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 1, &data); + + *value = (u8)data; + + return result; } static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value) { - outl(CONFIG_CMD(dev,where), 0xCF8); - *value = inw(0xCFC + (where&2)); - return PCIBIOS_SUCCESSFUL; + int result; + u32 data; + + if (!value) + return -EINVAL; + + result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 2, &data); + + *value = (u16)data; + + return result; } static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value) { - outl(CONFIG_CMD(dev,where), 0xCF8); - *value = inl(0xCFC); - return PCIBIOS_SUCCESSFUL; + if (!value) + return -EINVAL; + + return pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 4, value); } static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value) { - outl(CONFIG_CMD(dev,where), 0xCF8); - outb(value, 0xCFC + (where&3)); - return PCIBIOS_SUCCESSFUL; + return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 1, value); } static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value) { - outl(CONFIG_CMD(dev,where), 0xCF8); - outw(value, 0xCFC + (where&2)); - return PCIBIOS_SUCCESSFUL; + return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 2, value); } static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value) { - outl(CONFIG_CMD(dev,where), 0xCF8); - outl(value, 0xCFC); - return PCIBIOS_SUCCESSFUL; + return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 4, value); } -#undef CONFIG_CMD - static struct pci_ops pci_direct_conf1 = { pci_conf1_read_config_byte, pci_conf1_read_config_word, @@ -88,68 +168,131 @@ static struct pci_ops pci_direct_conf1 = { pci_conf1_write_config_dword }; + /* * Functions for accessing PCI configuration space with type 2 accesses */ -#define IOADDR(devfn, where) ((0xC000 | ((devfn & 0x78) << 5)) + where) -#define FUNC(devfn) (((devfn & 7) << 1) | 0xf0) -#define SET(dev) if (dev->devfn & 0x80) return PCIBIOS_DEVICE_NOT_FOUND; \ - outb(FUNC(dev->devfn), 0xCF8); \ - outb(dev->bus->number, 0xCFA); +#define PCI_CONF2_ADDRESS(dev, reg) (u16)(0xC000 | (dev << 8) | reg) -static int pci_conf2_read_config_byte(struct pci_dev *dev, int where, u8 *value) +static int pci_conf2_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) { - SET(dev); - *value = inb(IOADDR(dev->devfn,where)); + unsigned long flags; + + if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + return -EINVAL; + + if (dev & 0x10) + return PCIBIOS_DEVICE_NOT_FOUND; + + spin_lock_irqsave(&pci_config_lock, flags); + + outb((u8)(0xF0 | (fn << 1)), 0xCF8); + outb((u8)bus, 0xCFA); + + switch (len) { + case 1: + *value = inb(PCI_CONF2_ADDRESS(dev, reg)); + break; + case 2: + *value = inw(PCI_CONF2_ADDRESS(dev, reg)); + break; + case 4: + *value = inl(PCI_CONF2_ADDRESS(dev, reg)); + break; + } + outb (0, 0xCF8); - return PCIBIOS_SUCCESSFUL; + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return 0; +} + +static int pci_conf2_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +{ + unsigned long flags; + + if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + return -EINVAL; + + if (dev & 0x10) + return PCIBIOS_DEVICE_NOT_FOUND; + + spin_lock_irqsave(&pci_config_lock, flags); + + outb((u8)(0xF0 | (fn << 1)), 0xCF8); + outb((u8)bus, 0xCFA); + + switch (len) { + case 1: + outb ((u8)value, PCI_CONF2_ADDRESS(dev, reg)); + break; + case 2: + outw ((u16)value, PCI_CONF2_ADDRESS(dev, reg)); + break; + case 4: + outl ((u32)value, PCI_CONF2_ADDRESS(dev, reg)); + break; + } + + outb (0, 0xCF8); + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return 0; +} + +#undef PCI_CONF2_ADDRESS + +static int pci_conf2_read_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + int result; + u32 data; + result = pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 1, &data); + *value = (u8)data; + return result; } static int pci_conf2_read_config_word(struct pci_dev *dev, int where, u16 *value) { - SET(dev); - *value = inw(IOADDR(dev->devfn,where)); - outb (0, 0xCF8); - return PCIBIOS_SUCCESSFUL; + int result; + u32 data; + result = pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 2, &data); + *value = (u8)data; + return result; } static int pci_conf2_read_config_dword(struct pci_dev *dev, int where, u32 *value) { - SET(dev); - *value = inl (IOADDR(dev->devfn,where)); - outb (0, 0xCF8); - return PCIBIOS_SUCCESSFUL; + int result; + u32 data; + result = pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 4, &data); + *value = (u8)data; + return result; } static int pci_conf2_write_config_byte(struct pci_dev *dev, int where, u8 value) { - SET(dev); - outb (value, IOADDR(dev->devfn,where)); - outb (0, 0xCF8); - return PCIBIOS_SUCCESSFUL; + return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 1, value); } static int pci_conf2_write_config_word(struct pci_dev *dev, int where, u16 value) { - SET(dev); - outw (value, IOADDR(dev->devfn,where)); - outb (0, 0xCF8); - return PCIBIOS_SUCCESSFUL; + return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 2, value); } static int pci_conf2_write_config_dword(struct pci_dev *dev, int where, u32 value) { - SET(dev); - outl (value, IOADDR(dev->devfn,where)); - outb (0, 0xCF8); - return PCIBIOS_SUCCESSFUL; + return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 4, value); } -#undef SET -#undef IOADDR -#undef FUNC - static struct pci_ops pci_direct_conf2 = { pci_conf2_read_config_byte, pci_conf2_read_config_word, @@ -159,6 +302,7 @@ static struct pci_ops pci_direct_conf2 = { pci_conf2_write_config_dword }; + /* * Before we decide to use direct hardware access mechanisms, we try to do some * trivial checks to ensure it at least _seems_ to be working -- we just test @@ -420,114 +564,176 @@ static int __init pci_bios_find_device (unsigned short vendor, unsigned short de return (int) (ret & 0xff00) >> 8; } +static int pci_bios_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +{ + unsigned long result = 0; + unsigned long flags; + unsigned long bx = ((bus << 8) | (dev << 3) | fn); + + if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + return -EINVAL; + + spin_lock_irqsave(&pci_config_lock, flags); + + switch (len) { + case 1: + __asm__("lcall (%%esi); cld\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:" + : "=c" (*value), + "=a" (result) + : "1" (PCIBIOS_READ_CONFIG_BYTE), + "b" (bx), + "D" ((long)reg), + "S" (&pci_indirect)); + break; + case 2: + __asm__("lcall (%%esi); cld\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:" + : "=c" (*value), + "=a" (result) + : "1" (PCIBIOS_READ_CONFIG_WORD), + "b" (bx), + "D" ((long)reg), + "S" (&pci_indirect)); + break; + case 4: + __asm__("lcall (%%esi); cld\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:" + : "=c" (*value), + "=a" (result) + : "1" (PCIBIOS_READ_CONFIG_DWORD), + "b" (bx), + "D" ((long)reg), + "S" (&pci_indirect)); + break; + } + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return (int)((result & 0xff00) >> 8); +} + +static int pci_bios_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +{ + unsigned long result = 0; + unsigned long flags; + unsigned long bx = ((bus << 8) | (dev << 3) | fn); + + if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + return -EINVAL; + + spin_lock_irqsave(&pci_config_lock, flags); + + switch (len) { + case 1: + __asm__("lcall (%%esi); cld\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:" + : "=a" (result) + : "0" (PCIBIOS_WRITE_CONFIG_BYTE), + "c" (value), + "b" (bx), + "D" ((long)reg), + "S" (&pci_indirect)); + break; + case 2: + __asm__("lcall (%%esi); cld\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:" + : "=a" (result) + : "0" (PCIBIOS_WRITE_CONFIG_WORD), + "c" (value), + "b" (bx), + "D" ((long)reg), + "S" (&pci_indirect)); + break; + case 4: + __asm__("lcall (%%esi); cld\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:" + : "=a" (result) + : "0" (PCIBIOS_WRITE_CONFIG_DWORD), + "c" (value), + "b" (bx), + "D" ((long)reg), + "S" (&pci_indirect)); + break; + } + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return (int)((result & 0xff00) >> 8); +} + static int pci_bios_read_config_byte(struct pci_dev *dev, int where, u8 *value) { - unsigned long ret; - unsigned long bx = (dev->bus->number << 8) | dev->devfn; + int result; + u32 data; - __asm__("lcall (%%esi); cld\n\t" - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=c" (*value), - "=a" (ret) - : "1" (PCIBIOS_READ_CONFIG_BYTE), - "b" (bx), - "D" ((long) where), - "S" (&pci_indirect)); - return (int) (ret & 0xff00) >> 8; + if (!value) + return -EINVAL; + + result = pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 1, &data); + + *value = (u8)data; + + return result; } static int pci_bios_read_config_word(struct pci_dev *dev, int where, u16 *value) { - unsigned long ret; - unsigned long bx = (dev->bus->number << 8) | dev->devfn; + int result; + u32 data; - __asm__("lcall (%%esi); cld\n\t" - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=c" (*value), - "=a" (ret) - : "1" (PCIBIOS_READ_CONFIG_WORD), - "b" (bx), - "D" ((long) where), - "S" (&pci_indirect)); - return (int) (ret & 0xff00) >> 8; + if (!value) + return -EINVAL; + + result = pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 2, &data); + + *value = (u16)data; + + return result; } static int pci_bios_read_config_dword(struct pci_dev *dev, int where, u32 *value) { - unsigned long ret; - unsigned long bx = (dev->bus->number << 8) | dev->devfn; - - __asm__("lcall (%%esi); cld\n\t" - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=c" (*value), - "=a" (ret) - : "1" (PCIBIOS_READ_CONFIG_DWORD), - "b" (bx), - "D" ((long) where), - "S" (&pci_indirect)); - return (int) (ret & 0xff00) >> 8; + if (!value) + return -EINVAL; + + return pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 4, value); } static int pci_bios_write_config_byte(struct pci_dev *dev, int where, u8 value) { - unsigned long ret; - unsigned long bx = (dev->bus->number << 8) | dev->devfn; - - __asm__("lcall (%%esi); cld\n\t" - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=a" (ret) - : "0" (PCIBIOS_WRITE_CONFIG_BYTE), - "c" (value), - "b" (bx), - "D" ((long) where), - "S" (&pci_indirect)); - return (int) (ret & 0xff00) >> 8; + return pci_bios_write(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 1, value); } static int pci_bios_write_config_word(struct pci_dev *dev, int where, u16 value) { - unsigned long ret; - unsigned long bx = (dev->bus->number << 8) | dev->devfn; - - __asm__("lcall (%%esi); cld\n\t" - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=a" (ret) - : "0" (PCIBIOS_WRITE_CONFIG_WORD), - "c" (value), - "b" (bx), - "D" ((long) where), - "S" (&pci_indirect)); - return (int) (ret & 0xff00) >> 8; + return pci_bios_write(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 2, value); } static int pci_bios_write_config_dword(struct pci_dev *dev, int where, u32 value) { - unsigned long ret; - unsigned long bx = (dev->bus->number << 8) | dev->devfn; - - __asm__("lcall (%%esi); cld\n\t" - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=a" (ret) - : "0" (PCIBIOS_WRITE_CONFIG_DWORD), - "c" (value), - "b" (bx), - "D" ((long) where), - "S" (&pci_indirect)); - return (int) (ret & 0xff00) >> 8; + return pci_bios_write(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 4, value); } + /* * Function table for BIOS32 access */ @@ -981,34 +1187,47 @@ void __init pcibios_fixup_bus(struct pci_bus *b) pci_read_bridge_bases(b); } -/* - * Initialization. Try all known PCI access methods. Note that we support - * using both PCI BIOS and direct access: in such cases, we use I/O ports - * to access config space, but we still keep BIOS order of cards to be - * compatible with 2.0.X. This should go away some day. - */ -void __init pcibios_init(void) +void __init pcibios_config_init(void) { - struct pci_ops *bios = NULL; - struct pci_ops *dir = NULL; + /* + * Try all known PCI access methods. Note that we support using + * both PCI BIOS and direct access, with a preference for direct. + */ #ifdef CONFIG_PCI_BIOS - if ((pci_probe & PCI_PROBE_BIOS) && ((bios = pci_find_bios()))) { + if ((pci_probe & PCI_PROBE_BIOS) + && ((pci_root_ops = pci_find_bios()))) { pci_probe |= PCI_BIOS_SORT; pci_bios_present = 1; + pci_config_read = pci_bios_read; + pci_config_write = pci_bios_write; } #endif + #ifdef CONFIG_PCI_DIRECT - if (pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2)) - dir = pci_check_direct(); + if ((pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2)) + && (pci_root_ops = pci_check_direct())) { + if (pci_root_ops == &pci_direct_conf1) { + pci_config_read = pci_conf1_read; + pci_config_write = pci_conf1_write; + } + else { + pci_config_read = pci_conf2_read; + pci_config_write = pci_conf2_write; + } + } #endif - if (dir) - pci_root_ops = dir; - else if (bios) - pci_root_ops = bios; - else { - printk("PCI: No PCI bus detected\n"); + + return; +} + +void __init pcibios_init(void) +{ + if (!pci_root_ops) + pcibios_config_init(); + if (!pci_root_ops) { + printk("PCI: System does not support PCI\n"); return; } diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 4cbe6e15b4fb..3ab1b3a931cf 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -64,6 +64,9 @@ * * VIA C3 Support. * Dave Jones <davej@suse.de>, March 2001 + * + * AMD Athlon/Duron/Thunderbird bluesmoke support. + * Dave Jones <davej@suse.de>, April 2001. */ /* @@ -93,6 +96,7 @@ #include <linux/bootmem.h> #include <asm/processor.h> #include <linux/console.h> +#include <asm/mtrr.h> #include <asm/uaccess.h> #include <asm/system.h> #include <asm/io.h> @@ -145,9 +149,9 @@ struct e820map e820; unsigned char aux_device_present; +extern void mcheck_init(struct cpuinfo_x86 *c); extern int root_mountflags; extern char _text, _etext, _edata, _end; -extern unsigned long cpu_khz; static int disable_x86_serial_nr __initdata = 1; static int disable_x86_fxsr __initdata = 0; @@ -1088,11 +1092,18 @@ static void __init display_cacheinfo(struct cpuinfo_x86 *c) l2size = ecx >> 16; /* AMD errata T13 (order #21922) */ - if (c->x86_vendor == X86_VENDOR_AMD && - c->x86 == 6 && - c->x86_model == 3 && - c->x86_mask == 0) { - l2size = 64; + if ((c->x86_vendor == X86_VENDOR_AMD) && (c->x86 == 6)) { + if (c->x86_model == 3 && c->x86_mask == 0) /* Duron Rev A0 */ + l2size = 64; + if (c->x86_model == 4 && + (c->x86_mask==0 || c->x86_mask==1)) /* Tbird rev A1/A2 */ + l2size = 256; + } + + /* VIA C3 CPUs (670-68F) need further shifting. */ + if (c->x86_vendor == X86_VENDOR_CENTAUR && (c->x86 == 6) && + ((c->x86_model == 7) || (c->x86_model == 8))) { + l2size = l2size >> 8; } if ( l2size == 0 ) @@ -1109,7 +1120,7 @@ static void __init display_cacheinfo(struct cpuinfo_x86 *c) * misexecution of code under Linux. Owners of such processors should * contact AMD for precise details and a CPU swap. * - * See http://www.mygale.com/~poulot/k6bug.html + * See http://www.multimania.com/poulot/k6bug.html * http://www.amd.com/K6/k6docs/revgd.html * * The following test is erm.. interesting. AMD neglected to up @@ -1126,6 +1137,12 @@ static int __init init_amd(struct cpuinfo_x86 *c) int mbytes = max_mapnr >> (20-PAGE_SHIFT); int r; + /* + * FIXME: We should handle the K5 here. Set up the write + * range and also turn on MSR 83 bits 4 and 31 (write alloc, + * no bus pipeline) + */ + /* Bit 31 in normal CPUID used for nonstandard 3DNow ID; 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */ clear_bit(0*32+31, &c->x86_capability); @@ -1185,13 +1202,13 @@ static int __init init_amd(struct cpuinfo_x86 *c) if(mbytes>508) mbytes=508; - rdmsr(0xC0000082, l, h); + rdmsr(MSR_K6_WHCR, l, h); if ((l&0x0000FFFF)==0) { unsigned long flags; l=(1<<0)|((mbytes/4)<<1); local_irq_save(flags); - __asm__ __volatile__ ("wbinvd": : :"memory"); - wrmsr(0xC0000082, l, h); + wbinvd(); + wrmsr(MSR_K6_WHCR, l, h); local_irq_restore(flags); printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n", mbytes); @@ -1206,13 +1223,13 @@ static int __init init_amd(struct cpuinfo_x86 *c) if(mbytes>4092) mbytes=4092; - rdmsr(0xC0000082, l, h); + rdmsr(MSR_K6_WHCR, l, h); if ((l&0xFFFF0000)==0) { unsigned long flags; l=((mbytes>>2)<<22)|(1<<16); local_irq_save(flags); - __asm__ __volatile__ ("wbinvd": : :"memory"); - wrmsr(0xC0000082, l, h); + wbinvd(); + wrmsr(MSR_K6_WHCR, l, h); local_irq_restore(flags); printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n", mbytes); @@ -1226,10 +1243,10 @@ static int __init init_amd(struct cpuinfo_x86 *c) set_bit(X86_FEATURE_K6_MTRR, &c->x86_capability); break; } - break; case 6: /* An Athlon/Duron. We can trust the BIOS probably */ + mcheck_init(c); break; } @@ -1312,9 +1329,10 @@ extern void calibrate_delay(void) __init; static void __init check_cx686_slop(struct cpuinfo_x86 *c) { + unsigned long flags; + if (Cx86_dir0_msb == 3) { unsigned char ccr3, ccr5; - unsigned long flags; local_irq_save(flags); ccr3 = getCx86(CX86_CCR3); @@ -1551,14 +1569,12 @@ static void __init init_centaur(struct cpuinfo_x86 *c) name="??"; } - /* get FCR */ - rdmsr(0x107, lo, hi); - + rdmsr(MSR_IDT_FCR1, lo, hi); newlo=(lo|fcr_set) & (~fcr_clr); if (newlo!=lo) { printk(KERN_INFO "Centaur FCR was 0x%X now 0x%X\n", lo, newlo ); - wrmsr(0x107, newlo, hi ); + wrmsr(MSR_IDT_FCR1, newlo, hi ); } else { printk(KERN_INFO "Centaur FCR is 0x%X\n",lo); } @@ -1577,14 +1593,15 @@ static void __init init_centaur(struct cpuinfo_x86 *c) c->x86_cache_size = (cc>>24)+(dd>>24); } sprintf( c->x86_model_id, "WinChip %s", name ); + mcheck_init(c); break; case 6: switch (c->x86_model) { case 6 ... 7: /* Cyrix III or C3 */ - rdmsr (0x1107, lo, hi); + rdmsr (MSR_VIA_FCR, lo, hi); lo |= (1<<1 | 1<<7); /* Report CX8 & enable PGE */ - wrmsr (0x1107, lo, hi); + wrmsr (MSR_VIA_FCR, lo, hi); set_bit(X86_FEATURE_CX8, &c->x86_capability); set_bit(X86_FEATURE_3DNOW, &c->x86_capability); @@ -1595,7 +1612,6 @@ static void __init init_centaur(struct cpuinfo_x86 *c) } break; } - } @@ -1668,7 +1684,6 @@ static void __init init_rise(struct cpuinfo_x86 *c) if (c->x86_model > 2) printk(" II"); printk("\n"); - printk("If you have one of these please email davej@suse.de\n"); /* Unhide possibly hidden capability flags The mp6 iDragon family don't have MSRs. @@ -1694,7 +1709,6 @@ static void __init init_intel(struct cpuinfo_x86 *c) #ifndef CONFIG_M686 static int f00f_workaround_enabled = 0; #endif - extern void mcheck_init(struct cpuinfo_x86 *c); char *p = NULL; unsigned int l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */ @@ -1989,9 +2003,9 @@ static void __init squash_the_stupid_serial_number(struct cpuinfo_x86 *c) disable_x86_serial_nr ) { /* Disable processor serial number */ unsigned long lo,hi; - rdmsr(0x119,lo,hi); + rdmsr(MSR_IA32_BBL_CR_CTL,lo,hi); lo |= 0x200000; - wrmsr(0x119,lo,hi); + wrmsr(MSR_IA32_BBL_CR_CTL,lo,hi); printk(KERN_NOTICE "CPU serial number disabled.\n"); clear_bit(X86_FEATURE_PN, &c->x86_capability); diff --git a/arch/mips64/kernel/ioctl32.c b/arch/mips64/kernel/ioctl32.c index 9402aaaff8b0..3490c0c54cda 100644 --- a/arch/mips64/kernel/ioctl32.c +++ b/arch/mips64/kernel/ioctl32.c @@ -770,6 +770,8 @@ static struct ioctl32_list ioctl32_handler_table[] = { IOCTL32_HANDLER(BLKPG, blkpg_ioctl_trans), IOCTL32_DEFAULT(BLKELVGET), IOCTL32_DEFAULT(BLKELVSET), + IOCTL32_DEFAULT(BLKBSZGET), + IOCTL32_DEFAULT(BLKBSZSET), #ifdef CONFIG_MD /* status */ diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c index 0f47bd29c6ea..1d3702d21fe3 100644 --- a/arch/ppc/kernel/chrp_setup.c +++ b/arch/ppc/kernel/chrp_setup.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.chrp_setup.c 1.32 08/20/01 22:58:32 paulus + * BK Id: SCCS/s.chrp_setup.c 1.34 08/29/01 10:07:29 paulus */ /* * linux/arch/ppc/kernel/setup.c @@ -78,7 +78,6 @@ extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode); extern char pckbd_unexpected_up(unsigned char keycode); extern void pckbd_leds(unsigned char leds); -extern int pckbd_rate(struct kbd_repeat *rep); extern void pckbd_init_hw(void); extern unsigned char pckbd_sysrq_xlate[128]; extern void select_adb_keyboard(void); @@ -546,7 +545,6 @@ chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.kbd_translate = pckbd_translate; ppc_md.kbd_unexpected_up = pckbd_unexpected_up; ppc_md.kbd_leds = pckbd_leds; - ppc_md.kbd_rate_fn = pckbd_rate; ppc_md.kbd_init_hw = pckbd_init_hw; #ifdef CONFIG_MAGIC_SYSRQ ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; diff --git a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S index e038a6f21029..dfdcd728d232 100644 --- a/arch/ppc/kernel/head_8xx.S +++ b/arch/ppc/kernel/head_8xx.S @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.head_8xx.S 1.19 08/16/01 23:00:17 paulus + * BK Id: SCCS/s.head_8xx.S 1.21 08/28/01 16:27:27 trini */ /* * arch/ppc/kernel/except_8xx.S @@ -823,8 +823,8 @@ initial_mmu: mtspr DC_CST, r8 lis r8, IDC_ENABLE@h mtspr DC_CST, r8 - blr #endif + blr /* diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c index 0d72073c58e5..cd2a265d4b4e 100644 --- a/arch/ppc/kernel/pmac_setup.c +++ b/arch/ppc/kernel/pmac_setup.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pmac_setup.c 1.35 08/20/01 22:37:37 paulus + * BK Id: SCCS/s.pmac_setup.c 1.37 08/29/01 10:07:29 paulus */ /* * linux/arch/ppc/kernel/setup.c @@ -728,7 +728,6 @@ select_adb_keyboard(void) ppc_md.kbd_setkeycode = 0; ppc_md.kbd_getkeycode = 0; ppc_md.kbd_leds = 0; - ppc_md.kbd_rate_fn = 0; #ifdef CONFIG_MAGIC_SYSRQ #ifdef CONFIG_MAC_ADBKEYCODES if (!keyboard_sends_linux_keycodes) { @@ -747,7 +746,6 @@ select_adb_keyboard(void) ppc_md.kbd_translate = mackbd_translate; ppc_md.kbd_unexpected_up = mackbd_unexpected_up; ppc_md.kbd_leds = mackbd_leds; - ppc_md.kbd_rate_fn = NULL; ppc_md.kbd_init_hw = mackbd_init_hw; #ifdef CONFIG_MAGIC_SYSRQ ppc_md.ppc_kbd_sysrq_xlate = mackbd_sysrq_xlate; diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c index 9ee811f21f9a..feb7db27386f 100644 --- a/arch/ppc/kernel/prep_setup.c +++ b/arch/ppc/kernel/prep_setup.c @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.prep_setup.c 1.32 08/20/01 15:06:15 paulus + * BK Id: SCCS/s.prep_setup.c 1.34 08/29/01 10:07:29 paulus */ /* * linux/arch/ppc/kernel/setup.c @@ -89,7 +89,6 @@ extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode); extern char pckbd_unexpected_up(unsigned char keycode); extern void pckbd_leds(unsigned char leds); -extern int pckbd_rate(struct kbd_repeat *rep); extern void pckbd_init_hw(void); extern unsigned char pckbd_sysrq_xlate[128]; @@ -955,7 +954,6 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.kbd_translate = pckbd_translate; ppc_md.kbd_unexpected_up = pckbd_unexpected_up; ppc_md.kbd_leds = pckbd_leds; - ppc_md.kbd_rate_fn = pckbd_rate; ppc_md.kbd_init_hw = pckbd_init_hw; #ifdef CONFIG_MAGIC_SYSRQ ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c index 85548b4d41df..21e02899a5fa 100644 --- a/arch/sparc64/kernel/ioctl32.c +++ b/arch/sparc64/kernel/ioctl32.c @@ -3691,6 +3691,8 @@ COMPATIBLE_IOCTL(BLKRASET) COMPATIBLE_IOCTL(BLKFRASET) COMPATIBLE_IOCTL(BLKSECTSET) COMPATIBLE_IOCTL(BLKSSZGET) +COMPATIBLE_IOCTL(BLKBSZGET) +COMPATIBLE_IOCTL(BLKBSZSET) /* RAID */ COMPATIBLE_IOCTL(RAID_VERSION) diff --git a/drivers/acpi/include/platform/acgcc.h b/drivers/acpi/include/platform/acgcc.h index 4d8d34811047..8c62e903addf 100644 --- a/drivers/acpi/include/platform/acgcc.h +++ b/drivers/acpi/include/platform/acgcc.h @@ -39,7 +39,6 @@ #define BREAKPOINT3 #define disable() __cli() #define enable() __sti() -#define wbinvd() /*! [Begin] no source code translation */ @@ -101,7 +100,6 @@ #define disable() __cli() #define enable() __sti() #define halt() __asm__ __volatile__ ("sti; hlt":::"memory") -#define wbinvd() /*! [Begin] no source code translation * diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index fb39eb06a454..f510b00e2c26 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -31,6 +31,7 @@ #include <linux/completion.h> #include <linux/delay.h> #include <linux/hdreg.h> +#include <linux/blkpg.h> #include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/locks.h> @@ -5094,21 +5095,12 @@ static int DAC960_IOCTL(Inode_T *Inode, File_T *File, .nr_sects, (long *) Argument); case BLKRAGET: - /* Get Read-Ahead. */ - if ((long *) Argument == NULL) return -EINVAL; - return put_user(read_ahead[MAJOR(Inode->i_rdev)], (long *) Argument); case BLKRASET: - /* Set Read-Ahead. */ - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (Argument > 256) return -EINVAL; - read_ahead[MAJOR(Inode->i_rdev)] = Argument; - return 0; case BLKFLSBUF: - /* Flush Buffers. */ - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - fsync_dev(Inode->i_rdev); - invalidate_buffers(Inode->i_rdev); - return 0; + case BLKBSZGET: + case BLKBSZSET: + return blk_ioctl (Inode->i_rdev, Request, Argument); + case BLKRRPART: /* Re-Read Partition Table. */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; diff --git a/drivers/block/blkpg.c b/drivers/block/blkpg.c index 68240f8731e5..43f42cb65917 100644 --- a/drivers/block/blkpg.c +++ b/drivers/block/blkpg.c @@ -274,6 +274,29 @@ int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg) return blkelvset_ioctl(&blk_get_queue(dev)->elevator, (blkelv_ioctl_arg_t *) arg); + case BLKBSZGET: + /* get the logical block size (cf. BLKSSZGET) */ + intval = BLOCK_SIZE; + if (blksize_size[MAJOR(dev)]) + intval = blksize_size[MAJOR(dev)][MINOR(dev)]; + return put_user (intval, (int *) arg); + + case BLKBSZSET: + /* set the logical block size */ + if (!capable (CAP_SYS_ADMIN)) + return -EACCES; + if (!dev || !arg) + return -EINVAL; + if (get_user (intval, (int *) arg)) + return -EFAULT; + if (intval > PAGE_SIZE || intval < 512 || + (intval & (intval - 1))) + return -EINVAL; + if (is_mounted (dev) || is_swap_partition (dev)) + return -EBUSY; + set_blocksize (dev, intval); + return 0; + default: return -EINVAL; } diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 800debe3b416..0c1a044f4172 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -406,6 +406,8 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, case BLKRRPART: return revalidate_logvol(inode->i_rdev, 1); case BLKFLSBUF: + case BLKBSZSET: + case BLKBSZGET: case BLKROSET: case BLKROGET: case BLKRASET: diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 340dc7e65ee6..dc2287324a7e 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -1266,6 +1266,8 @@ static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, } case BLKFLSBUF: + case BLKBSZSET: + case BLKBSZGET: case BLKROSET: case BLKROGET: case BLKRASET: diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 26d06cd8177a..8b4d168a5dec 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -62,6 +62,7 @@ #include <linux/major.h> #include <linux/wait.h> #include <linux/blk.h> +#include <linux/blkpg.h> #include <linux/init.h> #include <linux/devfs_fs_kernel.h> #include <linux/smp_lock.h> @@ -854,6 +855,10 @@ static int lo_ioctl(struct inode * inode, struct file * file, } err = put_user(loop_sizes[lo->lo_number] << 1, (long *) arg); break; + case BLKBSZGET: + case BLKBSZSET: + err = blk_ioctl(inode->i_rdev, cmd, arg); + break; default: err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL; } diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index 0fdeccda1526..3050ba13cd7a 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -1127,6 +1127,8 @@ static int ps2esdi_ioctl(struct inode *inode, case BLKRASET: case BLKRAGET: case BLKFLSBUF: + case BLKBSZGET: + case BLKBSZSET: case BLKPG: return blk_ioctl(inode->i_rdev, cmd, arg); } diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index aaf5fd51d804..4a1b3fce70a2 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -2788,6 +2788,8 @@ static int ide_ioctl (struct inode *inode, struct file *file, case BLKPG: case BLKELVGET: case BLKELVSET: + case BLKBSZGET: + case BLKBSZSET: return blk_ioctl(inode->i_rdev, cmd, arg); case HDIO_GET_BUSSTATE: diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile index 6451d2ed6316..55465e4b7f89 100644 --- a/drivers/macintosh/Makefile +++ b/drivers/macintosh/Makefile @@ -15,7 +15,7 @@ O_TARGET := macintosh.o # Objects that export symbols. -export-objs := adb.o rtc.o mac_hid.o +export-objs := adb.o rtc.o mac_hid.o via-pmu.o # Object file lists. diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 6e7cff42614d..504167fe5166 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -32,24 +32,29 @@ #include <linux/pmu.h> #include <linux/cuda.h> #include <linux/smp_lock.h> +#include <linux/module.h> #include <linux/spinlock.h> +#include <linux/pm.h> +#include <linux/proc_fs.h> +#include <linux/init.h> #include <asm/prom.h> #include <asm/machdep.h> #include <asm/io.h> #include <asm/pgtable.h> #include <asm/system.h> -#include <asm/init.h> #include <asm/irq.h> #include <asm/hardirq.h> #include <asm/feature.h> #include <asm/uaccess.h> #include <asm/mmu_context.h> +#include <asm/cputable.h> #ifdef CONFIG_PMAC_BACKLIGHT #include <asm/backlight.h> #endif /* Some compile options */ #undef SUSPEND_USES_PMU +#define DEBUG_SLEEP /* Misc minor number allocated for /dev/pmu */ #define PMU_MINOR 154 @@ -102,13 +107,11 @@ static volatile enum pmu_state { static struct adb_request *current_req; static struct adb_request *last_req; static struct adb_request *req_awaiting_reply; -static unsigned char interrupt_data[256]; /* Made bigger: I've been told that might happen */ +static unsigned char interrupt_data[32]; static unsigned char *reply_ptr; static int data_index; static int data_len; static volatile int adb_int_pending; -static int pmu_adb_flags; -static int adb_dev_map = 0; static struct adb_request bright_req_1, bright_req_2, bright_req_3; static struct device_node *vias; static int pmu_kind = PMU_UNKNOWN; @@ -118,11 +121,20 @@ static unsigned char *gpio_reg = NULL; static int gpio_irq = -1; static volatile int pmu_suspended = 0; static spinlock_t pmu_lock; +static u8 pmu_intr_mask; +static int pmu_version; +static int drop_interrupts; +#ifdef CONFIG_PMAC_PBOOK +static int sleep_in_progress; +#endif /* CONFIG_PMAC_PBOOK */ int asleep; struct notifier_block *sleep_notifier_list; #ifdef CONFIG_ADB +static int adb_dev_map = 0; +static int pmu_adb_flags; + static int pmu_probe(void); static int pmu_init(void); static int pmu_send_request(struct adb_request *req, int sync); @@ -163,8 +175,25 @@ struct adb_driver via_pmu_driver = { #endif /* CONFIG_ADB */ extern void low_sleep_handler(void); -extern void sleep_save_intrs(int); -extern void sleep_restore_intrs(void); +extern void pmac_sleep_save_intrs(int); +extern void pmac_sleep_restore_intrs(void); +extern void openpic_sleep_save_intrs(void); +extern void openpic_sleep_restore_intrs(void); +extern void enable_kernel_altivec(void); +extern void enable_kernel_fp(void); + +#ifdef DEBUG_SLEEP +int pmu_polled_request(struct adb_request *req); +int pmu_wink(struct adb_request *req); +#endif + +#if defined(CONFIG_PMAC_PBOOK) && defined(CONFIG_PM) +static int generic_notify_sleep(struct pmu_sleep_notifier *self, int when); +static struct pmu_sleep_notifier generic_sleep_notifier = { + generic_notify_sleep, + SLEEP_LEVEL_MISC, +}; +#endif /* defined(CONFIG_PMAC_PBOOK) && defined(CONFIG_PM) */ /* * This table indicates for each PMU opcode: @@ -246,6 +275,11 @@ find_via_pmu() pmu_has_adb = 1; + pmu_intr_mask = PMU_INT_PCEJECT | + PMU_INT_SNDBRT | + PMU_INT_ADB | + PMU_INT_TICK; + if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0) || device_is_compatible(vias->parent, "ohare"))) pmu_kind = PMU_OHARE_BASED; @@ -258,7 +292,12 @@ find_via_pmu() pmu_kind = PMU_KEYLARGO_BASED; pmu_has_adb = (find_type_devices("adb") != NULL); - + pmu_intr_mask = PMU_INT_PCEJECT | + PMU_INT_SNDBRT | + PMU_INT_ADB | + PMU_INT_TICK | + PMU_INT_ENVIRONMENT; + gpiop = find_devices("gpio"); if (gpiop && gpiop->n_addrs) { gpio_reg = ioremap(gpiop->addrs->address, 0x10); @@ -281,11 +320,16 @@ find_via_pmu() return 0; } - printk(KERN_INFO "PMU driver initialized for %s\n", - pbook_type[pmu_kind]); + printk(KERN_INFO "PMU driver %d initialized for %s, firmware: %02x\n", + PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version); sys_ctrler = SYS_CTRLER_PMU; +#if defined(CONFIG_PMAC_PBOOK) && defined(CONFIG_PM) + pmu_register_sleep_notifier(&generic_sleep_notifier); + pm_active = 1; +#endif + return 1; } @@ -367,7 +411,7 @@ init_pmu() out_8(&via[B], via[B] | TREQ); /* negate TREQ */ out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK); /* TACK in, TREQ out */ - pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc); + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask); timeout = 100000; while (!req.complete) { if (--timeout < 0) { @@ -392,13 +436,20 @@ init_pmu() udelay(10); } - /* Tell PMU we are ready. Which PMU support this ? */ + /* Tell PMU we are ready. */ if (pmu_kind == PMU_KEYLARGO_BASED) { pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); while (!req.complete) pmu_poll(); } - + + /* Read PMU version */ + pmu_request(&req, NULL, 1, PMU_GET_VERSION); + while (!req.complete) + pmu_poll(); + if (req.reply_len > 1) + pmu_version = req.reply[1]; + return 1; } @@ -529,7 +580,7 @@ pmu_adb_reset_bus(void) req.done = NULL; req.data[0] = PMU_ADB_CMD; req.data[1] = 0; - req.data[2] = ADB_BUSRESET; /* 3 ??? */ + req.data[2] = ADB_BUSRESET; req.data[3] = 0; req.data[4] = 0; req.reply_len = 0; @@ -759,7 +810,7 @@ pmu_resume(void) } adb_int_pending = 1; #ifdef SUSPEND_USES_PMU - pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc); + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask); spin_unlock_irqrestore(&pmu_lock, flags); while(!req.complete) pmu_poll(); @@ -789,16 +840,11 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) "intr=%x pmu_state=%d\n", intr, pmu_state); break; } + out_8(&via[IFR], intr); if (intr & SR_INT) pmu_sr_intr(regs); - else if (intr & CB1_INT) { + else if (intr & CB1_INT) adb_int_pending = 1; - out_8(&via[IFR], CB1_INT); - } - intr &= ~(SR_INT | CB1_INT); - if (intr != 0) { - out_8(&via[IFR], intr); - } } /* This is not necessary except if synchronous ADB requests are done * with interrupts off, which should not happen. Since I'm not sure @@ -846,23 +892,17 @@ pmu_sr_intr(struct pt_regs *regs) out_8(&via[IFR], SR_INT); return; } - /* This one seems to appear with PMU99. According to OF methods, - * the protocol didn't change... - */ - if (via[B] & TACK) { - while ((in_8(&via[B]) & TACK) != 0) + /* The ack may not yet be low when we get the interrupt */ + while ((in_8(&via[B]) & TACK) != 0) ; - } - - /* reset TREQ and wait for TACK to go high */ - out_8(&via[B], in_8(&via[B]) | TREQ); - wait_for_ack(); /* if reading grab the byte, and reset the interrupt */ if (pmu_state == reading || pmu_state == reading_intr) bite = in_8(&via[SR]); - out_8(&via[IFR], SR_INT); + /* reset TREQ and wait for TACK to go high */ + out_8(&via[B], in_8(&via[B]) | TREQ); + wait_for_ack(); switch (pmu_state) { case sending: @@ -909,9 +949,8 @@ pmu_sr_intr(struct pt_regs *regs) if (data_len == -1) { data_len = bite; if (bite > 32) - printk(KERN_ERR "PMU: bad reply len %d\n", - bite); - } else { + printk(KERN_ERR "PMU: bad reply len %d\n", bite); + } else if (data_index < 32) { reply_ptr[data_index++] = bite; } if (data_index < data_len) { @@ -954,11 +993,14 @@ static void __openfirmware pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) { asleep = 0; - if (len < 1) { -// xmon_printk("empty ADB\n"); + if (drop_interrupts || len < 1) { adb_int_pending = 0; return; } + /* Note: for some reason, we get an interrupt with len=1, + * data[0]==0 after each normal ADB interrupt, at least + * on the Pismo. Still investigating... --BenH + */ if (data[0] & PMU_INT_ADB) { if ((data[0] & PMU_INT_ADB_AUTO) == 0) { struct adb_request *req = req_awaiting_reply; @@ -1085,10 +1127,14 @@ pmu_restart(void) cli(); - pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB | - PMU_INT_TICK ); - while(!req.complete) - pmu_poll(); + drop_interrupts = 1; + + if (pmu_kind != PMU_KEYLARGO_BASED) { + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB | + PMU_INT_TICK ); + while(!req.complete) + pmu_poll(); + } pmu_request(&req, NULL, 1, PMU_RESET); while(!req.complete || (pmu_state != idle)) @@ -1104,10 +1150,14 @@ pmu_shutdown(void) cli(); - pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB | - PMU_INT_TICK ); - while(!req.complete) - pmu_poll(); + drop_interrupts = 1; + + if (pmu_kind != PMU_KEYLARGO_BASED) { + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB | + PMU_INT_TICK ); + while(!req.complete) + pmu_poll(); + } pmu_request(&req, NULL, 5, PMU_SHUTDOWN, 'M', 'A', 'T', 'T'); @@ -1127,6 +1177,22 @@ pmu_present(void) static LIST_HEAD(sleep_notifiers); +#ifdef CONFIG_PM +static int +generic_notify_sleep(struct pmu_sleep_notifier *self, int when) +{ + switch (when) { + case PBOOK_SLEEP_NOW: + if (pm_send_all(PM_SUSPEND, (void *)3)) + return PBOOK_SLEEP_REJECT; + break; + case PBOOK_WAKE: + (void) pm_send_all(PM_RESUME, (void *)0); + } + return PBOOK_SLEEP_OK; +} +#endif /* CONFIG_PM */ + int pmu_register_sleep_notifier(struct pmu_sleep_notifier *n) { @@ -1268,23 +1334,42 @@ pbook_pci_restore(void) } } -#if 0 +#ifdef DEBUG_SLEEP /* N.B. This doesn't work on the 3400 */ -void pmu_blink(int n) +void +pmu_blink(int n) { struct adb_request req; + memset(&req, 0, sizeof(req)); + for (; n > 0; --n) { - pmu_request(&req, NULL, 4, 0xee, 4, 0, 1); - while (!req.complete) pmu_poll(); - udelay(50000); - pmu_request(&req, NULL, 4, 0xee, 4, 0, 0); - while (!req.complete) pmu_poll(); - udelay(50000); + req.nbytes = 4; + req.done = NULL; + req.data[0] = 0xee; + req.data[1] = 4; + req.data[2] = 0; + req.data[3] = 1; + req.reply[0] = ADB_RET_OK; + req.reply_len = 1; + req.reply_expected = 0; + pmu_polled_request(&req); + mdelay(50); + req.nbytes = 4; + req.done = NULL; + req.data[0] = 0xee; + req.data[1] = 4; + req.data[2] = 0; + req.data[3] = 0; + req.reply[0] = ADB_RET_OK; + req.reply_len = 1; + req.reply_expected = 0; + pmu_polled_request(&req); + mdelay(50); } - udelay(150000); + mdelay(50); } -#endif +#endif /* DEBUG_SLEEP */ /* * Put the powerbook to sleep. @@ -1317,7 +1402,6 @@ static void restore_via_state(void) out_8(&via[IER], IER_SET | SR_INT | CB1_INT); } -#define FEATURE_CTRL(base) ((unsigned int *)(base + 0x38)) #define GRACKLE_PM (1<<7) #define GRACKLE_DOZE (1<<5) #define GRACKLE_NAP (1<<4) @@ -1363,7 +1447,8 @@ int __openfirmware powerbook_sleep_G3(void) mb(); /* Wait for completion of async backlight requests */ - while (!bright_req_1.complete || !bright_req_2.complete || !bright_req_3.complete) + while (!bright_req_1.complete || !bright_req_2.complete || + !bright_req_3.complete) pmu_poll(); /* Turn off various things. Darwin does some retry tests here... */ @@ -1375,8 +1460,8 @@ int __openfirmware powerbook_sleep_G3(void) while (!req.complete) pmu_poll(); - /* Disable all interrupts except pmu */ - sleep_save_intrs(vias->intrs[0].line); + /* Disable all interrupts */ + pmac_sleep_save_intrs(-1); /* Make sure the PMU is idle */ while (pmu_state != idle) @@ -1393,6 +1478,9 @@ int __openfirmware powerbook_sleep_G3(void) if (current->thread.regs && (current->thread.regs->msr & MSR_FP) != 0) giveup_fpu(current); + /* We can now disable MSR_EE */ + cli(); + /* For 750, save backside cache setting and disable it */ save_l2cr = _get_L2CR(); /* (returns 0 if not 750) */ if (save_l2cr) @@ -1431,7 +1519,7 @@ int __openfirmware powerbook_sleep_G3(void) _set_L2CR(save_l2cr); /* Restore userland MMU context */ - set_context(current->mm->context); + set_context(current->active_mm->context, current->active_mm->pgd); /* Re-enable DEC interrupts and kick DEC */ asm volatile("mtdec %0" : : "r" (0x7fffffff)); @@ -1464,26 +1552,29 @@ int __openfirmware powerbook_sleep_G3(void) } /* reenable interrupt controller */ - sleep_restore_intrs(); + pmac_sleep_restore_intrs(); /* Leave some time for HW to settle down */ mdelay(100); /* Notify drivers */ - mdelay(10); broadcast_wake(); return 0; } -/* Not finished yet */ int __openfirmware powerbook_sleep_Core99(void) { - int ret; unsigned long save_l2cr; unsigned long wait; struct adb_request req; - + int ret, timeout; + + if (!feature_can_sleep()) { + printk(KERN_ERR "Sleep mode not supported on this machine\n"); + return -ENOSYS; + } + /* Notify device drivers */ ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT); if (ret != PBOOK_SLEEP_OK) { @@ -1507,81 +1598,140 @@ int __openfirmware powerbook_sleep_Core99(void) } /* Give the disks a little time to actually finish writing */ - for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) + for (wait = jiffies + HZ; time_before(jiffies, wait); ) mb(); + /* Wait for completion of async backlight requests */ + while (!bright_req_1.complete || !bright_req_2.complete || + !bright_req_3.complete) + pmu_poll(); + /* Tell PMU what events will wake us up */ pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS, 0xff, 0xff); while (!req.complete) pmu_poll(); + pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_SET_WAKEUP_EVENTS, 0, PMU_PWR_WAKEUP_KEY | PMU_PWR_WAKEUP_LID_OPEN); while (!req.complete) pmu_poll(); - /* Disable all interrupts except pmu */ - sleep_save_intrs(vias->intrs[0].line); + /* Save & disable all interrupts */ + openpic_sleep_save_intrs(); + + /* Make sure the PMU is idle */ + while (pmu_state != idle) + pmu_poll(); /* Make sure the decrementer won't interrupt us */ asm volatile("mtdec %0" : : "r" (0x7fffffff)); + /* Make sure any pending DEC interrupt occuring while we did + * the above didn't re-enable the DEC */ + mb(); + asm volatile("mtdec %0" : : "r" (0x7fffffff)); - /* Save the state of PCI config space for some slots */ - pbook_pci_save(); + /* Giveup the FPU & vec */ + enable_kernel_fp(); - feature_prepare_for_sleep(); +#ifdef CONFIG_ALTIVEC + if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC) + enable_kernel_altivec(); +#endif /* CONFIG_ALTIVEC */ + + /* We can now disable MSR_EE */ + cli(); /* For 750, save backside cache setting and disable it */ save_l2cr = _get_L2CR(); /* (returns 0 if not 750) */ if (save_l2cr) - _set_L2CR(0); + _set_L2CR(save_l2cr & 0x7fffffff); - if (current->thread.regs && (current->thread.regs->msr & MSR_FP) != 0) - giveup_fpu(current); + /* Save the state of PCI config space for some slots */ + //pbook_pci_save(); /* Ask the PMU to put us to sleep */ pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); - while (!req.complete) - mb(); - - cli(); - while (pmu_state != idle) + while (!req.complete && pmu_state != idle) pmu_poll(); - /* Call low-level ASM sleep handler */ - low_sleep_handler(); + out_8(&via[B], in_8(&via[B]) | TREQ); + wait_for_ack(); - /* Make sure the PMU is idle */ - while (pmu_state != idle) - pmu_poll(); + /* The VIA is supposed not to be restored correctly*/ + save_via_state(); - sti(); + /* Shut down various ASICs. There's a chance that we can no longer + * talk to the PMU after this, so I moved it to _after_ sending the + * sleep command to it. Still need to be checked. + */ + feature_prepare_for_sleep(); + /* Call low-level ASM sleep handler */ + low_sleep_handler(); + + /* Restore Apple core ASICs state */ feature_wake_up(); - pbook_pci_restore(); - set_context(current->mm->context); + /* Restore VIA */ + restore_via_state(); + + /* Restore PCI config space. This should be overridable by PCI device + * drivers as some of them may need special restore code. That's yet + * another issue that should be handled by the common code properly, + * maybe one day ? + */ + /* Don't restore PCI for now, it crashes. Maybe unnecessary on pbook */ + //pbook_pci_restore(); + pmu_blink(2); + /* Restore L2 cache */ if (save_l2cr) - _set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */ + _set_L2CR(save_l2cr); + + /* Restore userland MMU context */ + set_context(current->active_mm->context, current->active_mm->pgd); - /* reenable interrupts */ - sleep_restore_intrs(); + /* Re-enable DEC interrupts and kick DEC */ + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + sti(); + asm volatile("mtdec %0" : : "r" (0x10000000)); /* Tell PMU we are ready */ pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); while (!req.complete) pmu_poll(); + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc); + while (!req.complete) + pmu_poll(); + /* ack all pending interrupts */ + timeout = 100000; + interrupt_data[0] = 1; + while (interrupt_data[0] || pmu_state != idle) { + if (--timeout < 0) + break; + if (pmu_state == idle) + adb_int_pending = 1; + via_pmu_interrupt(0, 0, 0); + udelay(10); + } + + /* reenable interrupt controller */ + openpic_sleep_restore_intrs(); + + /* Leave some time for HW to settle down */ + mdelay(100); + /* Notify drivers */ - mdelay(10); broadcast_wake(); return 0; } -#define PB3400_MEM_CTRL ((unsigned int *)0xf8000070) +#define PB3400_MEM_CTRL 0xf8000000 +#define PB3400_MEM_CTRL_SLEEP 0x70 int __openfirmware powerbook_sleep_3400(void) { @@ -1590,6 +1740,16 @@ int __openfirmware powerbook_sleep_3400(void) unsigned int hid0; unsigned long p, wait; struct adb_request sleep_req; + char *mem_ctrl; + unsigned int *mem_ctrl_sleep; + + /* first map in the memory controller registers */ + mem_ctrl = ioremap(PB3400_MEM_CTRL, 0x100); + if (mem_ctrl == NULL) { + printk("powerbook_sleep_3400: ioremap failed\n"); + return -ENOMEM; + } + mem_ctrl_sleep = (unsigned int *) (mem_ctrl + PB3400_MEM_CTRL_SLEEP); /* Notify device drivers */ ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT); @@ -1617,11 +1777,20 @@ int __openfirmware powerbook_sleep_3400(void) for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) mb(); + /* Wait for completion of async backlight requests */ + while (!bright_req_1.complete || !bright_req_2.complete || + !bright_req_3.complete) + pmu_poll(); + /* Disable all interrupts except pmu */ - sleep_save_intrs(vias->intrs[0].line); + pmac_sleep_save_intrs(vias->intrs[0].line); /* Make sure the decrementer won't interrupt us */ asm volatile("mtdec %0" : : "r" (0x7fffffff)); + /* Make sure any pending DEC interrupt occuring while we did + * the above didn't re-enable the DEC */ + mb(); + asm volatile("mtdec %0" : : "r" (0x7fffffff)); /* Save the state of PCI config space for some slots */ pbook_pci_save(); @@ -1629,9 +1798,9 @@ int __openfirmware powerbook_sleep_3400(void) /* Set the memory controller to keep the memory refreshed while we're asleep */ for (i = 0x403f; i >= 0x4000; --i) { - out_be32(PB3400_MEM_CTRL, i); + out_be32(mem_ctrl_sleep, i); do { - x = (in_be32(PB3400_MEM_CTRL) >> 16) & 0x3ff; + x = (in_be32(mem_ctrl_sleep) >> 16) & 0x3ff; } while (x == 0); if (x >= 0x100) break; @@ -1651,32 +1820,36 @@ int __openfirmware powerbook_sleep_3400(void) asm volatile("mfspr %0,1008" : "=r" (hid0) :); hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP; asm volatile("mtspr 1008,%0" : : "r" (hid0)); - save_flags(msr); - msr |= MSR_POW | MSR_EE; - restore_flags(msr); + _nmask_and_or_msr(0, MSR_POW | MSR_EE); udelay(10); /* OK, we're awake again, start restoring things */ - out_be32(PB3400_MEM_CTRL, 0x3f); + out_be32(mem_ctrl_sleep, 0x3f); pbook_pci_restore(); /* wait for the PMU interrupt sequence to complete */ while (asleep) mb(); + /* Re-enable DEC interrupts and kick DEC */ + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + sti(); + asm volatile("mtdec %0" : : "r" (0x10000000)); + /* reenable interrupts */ - sleep_restore_intrs(); + pmac_sleep_restore_intrs(); /* Notify drivers */ broadcast_wake(); + iounmap(mem_ctrl); return 0; } /* * Support for /dev/pmu device */ -#define RB_SIZE 10 +#define RB_SIZE 0x10 struct pmu_private { struct list_head list; int rb_get; @@ -1830,6 +2003,11 @@ static int pmu_ioctl(struct inode * inode, struct file *filp, switch (cmd) { case PMU_IOC_SLEEP: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (sleep_in_progress) + return -EBUSY; + sleep_in_progress = 1; switch (pmu_kind) { case PMU_OHARE_BASED: error = powerbook_sleep_3400(); @@ -1838,20 +2016,24 @@ static int pmu_ioctl(struct inode * inode, struct file *filp, case PMU_PADDINGTON_BASED: error = powerbook_sleep_G3(); break; -#if 0 /* Not ready yet */ case PMU_KEYLARGO_BASED: error = powerbook_sleep_Core99(); break; -#endif default: error = -ENOSYS; } + sleep_in_progress = 0; return error; + case PMU_IOC_CAN_SLEEP: + return put_user(feature_can_sleep(), (__u32 *)arg); + #ifdef CONFIG_PMAC_BACKLIGHT /* Backlight should have its own device or go via * the fbdev */ case PMU_IOC_GET_BACKLIGHT: + if (sleep_in_progress) + return -EBUSY; error = get_backlight_level(); if (error < 0) return error; @@ -1859,6 +2041,8 @@ static int pmu_ioctl(struct inode * inode, struct file *filp, case PMU_IOC_SET_BACKLIGHT: { __u32 value; + if (sleep_in_progress) + return -EBUSY; error = get_user(value, (__u32 *)arg); if (!error) error = set_backlight_level(value); @@ -1893,7 +2077,7 @@ void pmu_device_init(void) } #endif /* CONFIG_PMAC_PBOOK */ -#if 0 +#ifdef DEBUG_SLEEP static inline void polled_handshake(volatile unsigned char *via) { via[B] &= ~TREQ; eieio(); @@ -1939,6 +2123,8 @@ pmu_polled_request(struct adb_request *req) while (pmu_state != idle) pmu_poll(); + while ((via[B] & TACK) == 0) + ; polled_send_byte(v, c); if (l < 0) { l = req->nbytes - 1; @@ -1959,4 +2145,15 @@ pmu_polled_request(struct adb_request *req) restore_flags(flags); return 0; } -#endif /* 0 */ +#endif /* DEBUG_SLEEP */ + +EXPORT_SYMBOL(pmu_request); +EXPORT_SYMBOL(pmu_poll); +EXPORT_SYMBOL(pmu_suspend); +EXPORT_SYMBOL(pmu_resume); +#ifdef CONFIG_PMAC_PBOOK +EXPORT_SYMBOL(pmu_register_sleep_notifier); +EXPORT_SYMBOL(pmu_unregister_sleep_notifier); +EXPORT_SYMBOL(pmu_enable_irled); +#endif /* CONFIG_PMAC_PBOOK */ + diff --git a/drivers/md/md.c b/drivers/md/md.c index 3a4daf75543d..5b97e8c61911 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -921,17 +921,19 @@ static int write_disk_sb(mdk_rdev_t * rdev) dev = rdev->dev; sb_offset = calc_dev_sboffset(dev, rdev->mddev, 1); if (rdev->sb_offset != sb_offset) { - printk("%s's sb offset has changed from %ld to %ld, skipping\n", partition_name(dev), rdev->sb_offset, sb_offset); + printk("%s's sb offset has changed from %ld to %ld, skipping\n", + partition_name(dev), rdev->sb_offset, sb_offset); goto skip; } /* * If the disk went offline meanwhile and it's just a spare, then - * it's size has changed to zero silently, and the MD code does + * its size has changed to zero silently, and the MD code does * not yet know that it's faulty. */ size = calc_dev_size(dev, rdev->mddev, 1); if (size != rdev->size) { - printk("%s's size has changed from %ld to %ld since import, skipping\n", partition_name(dev), rdev->size, size); + printk("%s's size has changed from %ld to %ld since import, skipping\n", + partition_name(dev), rdev->size, size); goto skip; } @@ -2488,27 +2490,14 @@ static int md_ioctl (struct inode *inode, struct file *file, (long *) arg); goto done; - case BLKFLSBUF: - fsync_dev(dev); - invalidate_buffers(dev); - goto done; - + case BLKRAGET: case BLKRASET: - if (arg > 0xff) { - err = -EINVAL; - goto abort; - } - read_ahead[MAJOR(dev)] = arg; - goto done; + case BLKFLSBUF: + case BLKBSZGET: + case BLKBSZSET: + err = blk_ioctl (dev, cmd, arg); + goto abort; - case BLKRAGET: - if (!arg) { - err = -EINVAL; - goto abort; - } - err = md_put_user (read_ahead[ - MAJOR(dev)], (long *) arg); - goto done; default:; } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index bceacf91017c..41fb53ca07c2 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -162,7 +162,7 @@ static struct raid1_bh *raid1_alloc_r1bh(raid1_conf_t *conf) conf->freer1 = r1_bh->next_r1; conf->freer1_cnt--; r1_bh->next_r1 = NULL; - r1_bh->state = 0; + r1_bh->state = (1 << R1BH_PreAlloc); r1_bh->bh_req.b_state = 0; } md_spin_unlock_irq(&conf->device_lock); diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index b37fa410cfeb..dea26603a471 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -135,8 +135,9 @@ int __init macsonic_init(struct net_device* dev) unsigned long desc_base, desc_top; if ((lp->sonic_desc = kmalloc(SIZEOF_SONIC_DESC - * SONIC_BUS_SCALE(lp->dma_bitmode), GFP_DMA)) == NULL) { + * SONIC_BUS_SCALE(lp->dma_bitmode), GFP_KERNEL | GFP_DMA)) == NULL) { printk(KERN_ERR "%s: couldn't allocate descriptor buffers\n", dev->name); + return -ENOMEM; } desc_base = (unsigned long) lp->sonic_desc; desc_top = desc_base + SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode); @@ -165,7 +166,7 @@ int __init macsonic_init(struct net_device* dev) /* FIXME, maybe we should use skbs */ if ((lp->rba = (char *) - kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_DMA)) == NULL) { + kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL | GFP_DMA)) == NULL) { printk(KERN_ERR "%s: couldn't allocate receive buffers\n", dev->name); return -ENOMEM; } diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index bd559edd7982..60bd3f33695f 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -348,7 +348,7 @@ void inline try_get_rx_skb(struct dscc4_dev_priv *priv, int cur, struct net_devi { struct sk_buff *skb; - skb = dev_alloc_skb(RX_MAX(dev->mtu+2)); + skb = dev_alloc_skb(RX_MAX(HDLC_MAX_MRU+2)); priv->rx_skbuff[cur] = skb; if (!skb) { priv->rx_fd[cur--].data = (u32) NULL; @@ -428,9 +428,9 @@ static __inline__ void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, int cur, int pkt_len; skb = dpriv->rx_skbuff[cur]; - pkt_len = TO_SIZE(rx_fd->state2); - pci_dma_sync_single(pdev, rx_fd->data, pkt_len, PCI_DMA_FROMDEVICE); - if((skb->data[pkt_len - 1] & FrameOk) == FrameOk) { + pkt_len = TO_SIZE(rx_fd->state2) - 1; + pci_dma_sync_single(pdev, rx_fd->data, pkt_len + 1, PCI_DMA_FROMDEVICE); + if((skb->data[pkt_len] & FrameOk) == FrameOk) { pci_unmap_single(pdev, rx_fd->data, skb->len, PCI_DMA_FROMDEVICE); dpriv->stats.rx_packets++; dpriv->stats.rx_bytes += pkt_len; @@ -442,11 +442,11 @@ static __inline__ void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, int cur, netif_rx(skb); try_get_rx_skb(dpriv, cur, dev); } else { - if(skb->data[pkt_len - 1] & FrameRdo) + if(skb->data[pkt_len] & FrameRdo) dpriv->stats.rx_fifo_errors++; - else if(!(skb->data[pkt_len - 1] | ~FrameCrc)) + else if(!(skb->data[pkt_len] | ~FrameCrc)) dpriv->stats.rx_crc_errors++; - else if(!(skb->data[pkt_len - 1] | ~FrameVfr)) + else if(!(skb->data[pkt_len] | ~FrameVfr)) dpriv->stats.rx_length_errors++; else dpriv->stats.rx_errors++; @@ -760,7 +760,7 @@ static int dscc4_open(struct net_device *dev) /* FIXME: VIS */ writel(readl(ioaddr + CCR0) | 0x80001000, ioaddr + CCR0); - writel(LengthCheck | (dev->mtu >> 5), ioaddr + RLCR); + writel(LengthCheck | (HDLC_MAX_MRU >> 5), ioaddr + RLCR); /* no address recognition/crc-CCITT/cts enabled */ writel(readl(ioaddr + CCR1) | 0x021c8000, ioaddr + CCR1); @@ -1224,7 +1224,7 @@ try: dev->name, SOURCE_ID(state), state ); return; } - if (state & 0x0df80c01) { + if (state & 0x0df80c00) { printk(KERN_DEBUG "%s (Tx): state=%08x (UFO alert)\n", dev->name, state); return; @@ -1377,7 +1377,7 @@ try: dev->name, SOURCE_ID(state), state); goto try; } - if (state & 0x0df80c01) { + if (state & 0x0df80c00) { printk(KERN_DEBUG "%s (Rx): state=%08x (UFO alert)\n", dev->name, state); goto try; @@ -1609,7 +1609,7 @@ static int dscc4_init_ring(struct net_device *dev) rx_fd->state1 = HiDesc; /* Hi, no Hold */ rx_fd->state2 = 0x00000000; rx_fd->end = 0xbabeface; - rx_fd->state1 |= ((u32)(dev->mtu & RxSizeMax)) << 16; + rx_fd->state1 |= ((u32)(HDLC_MAX_MRU & RxSizeMax)) << 16; try_get_rx_skb(dpriv, i, dev); i++; rx_fd->next = (u32)(dpriv->rx_fd_dma + i*sizeof(struct RxFD)); @@ -1720,7 +1720,7 @@ static int dscc4_attach_hdlc_device(struct net_device *dev) hdlc = &dpriv->hdlc; /* XXX: Don't look at the next line */ hdlc->netdev.base_addr = (unsigned long)dev; - // FIXME: set hdlc->set_mode ? + hdlc->set_mode = NULL; hdlc->open = dscc4_hdlc_open; hdlc->close = dscc4_hdlc_close; hdlc->ioctl = dscc4_hdlc_ioctl; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index a8b1377f5160..f8fcbe5b5a03 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -307,8 +307,8 @@ pci_set_power_state(struct pci_dev *dev, int state) /** * pci_save_state - save the PCI configuration space of a device before suspending - * @dev - PCI device that we're dealing with - * @buffer - buffer to hold config space context + * @dev: - PCI device that we're dealing with + * @buffer: - buffer to hold config space context * * @buffer must be large enough to hold the entire PCI 2.2 config space * (>= 64 bytes). @@ -327,8 +327,8 @@ pci_save_state(struct pci_dev *dev, u32 *buffer) /** * pci_restore_state - Restore the saved state of a PCI device - * @dev - PCI device that we're dealing with - * @buffer - saved PCI config space + * @dev: - PCI device that we're dealing with + * @buffer: - saved PCI config space * */ int @@ -489,6 +489,7 @@ void pci_release_regions(struct pci_dev *pdev) /** * pci_request_regions - Reserved PCI I/O and memory resources * @pdev: PCI device whose resources are to be reserved + * @res_name: Name to be associated with resource. * * Mark all PCI regions associated with PCI device @pdev as * being reserved by owner @res_name. Do not access any diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c index 6303192b2b81..c72c4ca43b0f 100644 --- a/drivers/pcmcia/yenta.c +++ b/drivers/pcmcia/yenta.c @@ -702,6 +702,12 @@ static void yenta_allocate_res(pci_socket_t *socket, int nr, unsigned type) u32 start, end; u32 align, size, min, max; unsigned offset; + unsigned mask; + + /* The granularity of the memory limit is 4kB, on IO it's 4 bytes */ + mask = ~0xfff; + if (type & IORESOURCE_IO) + mask = ~3; offset = 0x1c + 8*nr; bus = socket->dev->subordinate; @@ -715,8 +721,8 @@ static void yenta_allocate_res(pci_socket_t *socket, int nr, unsigned type) if (!root) return; - start = config_readl(socket, offset); - end = config_readl(socket, offset+4) | 0xfff; + start = config_readl(socket, offset) & mask; + end = config_readl(socket, offset+4) | ~mask; if (start && end > start) { res->start = start; res->end = end; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 57f1817c1443..0e1e0ab1f8d6 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -238,8 +238,10 @@ static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, case BLKFLSBUF: case BLKSSZGET: case BLKPG: - case BLKELVGET: - case BLKELVSET: + case BLKELVGET: + case BLKELVSET: + case BLKBSZGET: + case BLKBSZSET: return blk_ioctl(inode->i_rdev, cmd, arg); case BLKRRPART: /* Re-read partition tables */ diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in index e085396c7fc9..d2c623a50e9d 100644 --- a/drivers/usb/Config.in +++ b/drivers/usb/Config.in @@ -64,7 +64,6 @@ comment 'USB Controllers' dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB comment 'USB Network adaptors' - dep_tristate ' PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL dep_tristate ' USB ADMtek Pegasus-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL dep_tristate ' USB CATC NetMate-based Ethernet driver (EXPERIMENTAL)' CONFIG_USB_CATC $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL dep_tristate ' USB KLSI KL5USB101-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_KAWETH $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 3789e22a08ba..ddb549b0c346 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -60,7 +60,6 @@ obj-$(CONFIG_USB_DC2XX) += dc2xx.o obj-$(CONFIG_USB_MDC800) += mdc800.o obj-$(CONFIG_USB_USS720) += uss720.o obj-$(CONFIG_USB_DABUSB) += dabusb.o -obj-$(CONFIG_USB_PLUSB) += plusb.o obj-$(CONFIG_USB_OV511) += ov511.o obj-$(CONFIG_USB_SE401) += se401.o obj-$(CONFIG_USB_PEGASUS) += pegasus.o diff --git a/drivers/usb/plusb.c b/drivers/usb/plusb.c deleted file mode 100644 index 6d92d5dddc5d..000000000000 --- a/drivers/usb/plusb.c +++ /dev/null @@ -1,1060 +0,0 @@ -/*****************************************************************************/ - -/* - * plusb.c -- prolific pl-2301/pl-2302 driver. - * - * Copyright (C) 2000 Deti Fliegl (deti@fliegl.de) - * Copyright (C) 2000 Pavel Machek (pavel@suse.cz) - * Copyright (C) 2000 Eric Z. Ayers (eric@compgen.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * This driver creates a network interface (plusb0, plusb1, ...) that will - * send messages over a USB host-host cable based on the Prolific ASIC. - * It works a lot like plip or PP over an RS-232C null modem cable. - * - * Expect speeds of around 330Kbytes/second over a UHCI host controller. - * OHCI should be faster. Increase the MTU for faster transfers of large - * files (up-to 800Kbytes/second). (16384 is a good size) - * - * $Id: plusb.c,v 1.18 2000/02/14 10:38:58 fliegl Exp $ - * - * Changelog: - * - * v0.1 deti - * Original Version of driver. - * v0.2 15 Sep 2000 pavel - * Patches to decrease latency by rescheduling the bottom half of - * interrupt code. - * v0.3 10 Oct 2000 eric - * Patches to work in v2.2 backport (v2.4 changes the way net_dev.name - * is allocated) - * v0.4 19 Oct 2000 eric - * Some more performance fixes. Lock re-submitting urbs. - * Lower the number of sk_buff's to queue. - * v0.5 25 Oct 2000 eric - * Removed use of usb_bulk_msg() all together. This caused - * the driver to block in an interrupt context. - * Consolidate read urb submission into read_urb_submit(). - * Performance is the same as v0.4. - * v0.5.1 27 Oct 2000 eric - * Extra debugging messages to help diagnose problem with uchi.o stack. - * v0.5.2 27 Oct 2000 eric - * Set the 'start' flag for the network device in plusb_net_start() - * and plusb_net_stop() (doesn't help) - * v0.5.3 27 Oct 2000 pavel - * Commented out handlers when -EPIPE is received, - * (remove calls to usb_clear_halt()) Since the callback is in - * an interrupt context, it doesn't help, it just panics - * the kernel. (what do we do?) - * Under high load, dev_alloc_skb() fails, the read URB must - * be re-submitted. - * Added plusb_change_mtu() and increased the size of _BULK_DATA_LEN - * v0.5.4 31 Oct 2000 eric - * Fix race between plusb_net_xmit() and plusb_bulk_write_complete() - * v0.5.5 1 Nov 2000 eric - * Remove dev->start field, otherwise, it won't compile in 2.4 - * Use dev_kfree_skb_any(). (important in 2.4 kernel) - * v0.5.6 2 Nov 2000 pavel,eric - * Add calls to netif_stop_queue() and netif_start_queue() - * Drop packets that come in while the free list is empty. - * (This version is being submitted after the release of 2.4-test10) - * v0.5.7 6 Nov 2000 - * Fix to not re-submit the urb on error to help when cables - * are yanked (not tested) - * - * - * KNOWN PROBLEMS: (Any suggestions greatfully accepted!) - * - * 2 Nov 2000 - * - The shutdown for this may not be entirely clean. Sometimes, the - * kernel will Oops when the cable is unplugged, or - * if the plusb module is removed. - * - If you ifdown a device and then ifup it again, the link will not - * always work. You have to 'rmmod plusb ; modprobe plusb' on - * both machines to get it to work again. Something must be wrong with - * plusb_net_open() and plusb_net_start() ? Maybe - * the 'suspend' and 'resume' entry points need to be - * implemented? - * - Needs to handle -EPIPE correctly in bulk complete handlers. - * (replace usb_clear_halt() function with async urbs?) - * - I think this code relies too much on one spinlock and does - * too much in the interrupt handler. The net1080 code is - * much more elegant, and should work for this chip. Its - * only drawback is that it is going to be tough to backport - * it to v2.2. - * - Occasionally the device will hang under the 'uhci.o' - * driver. The workaround is to ifdown the device and - * remove the modules, then re-insert them. You may have - * better luck with the 'usb-uhci.o' driver. - * - After using ifconfig down ; ifconfig up, sometimes packets - * continue to be received, but there is a framing problem. - * - * FUTURE DIRECTIONS: - * - * - Fix the known problems. - * - There isn't much functional difference between the net1080 - * driver and this one. It would be neat if the same driver - * could handle both types of chips. Or if both drivers - * could handle both types of chips - this one is easier to - * backport to the 2.2 kernel. - * - Get rid of plusb_add_buf_tail and the single spinlock. - * Use a separate spinlock for the 2 lists, and use atomic - * operators for writeurb_submitted and readurb_submitted members. - * - * - */ - -/*****************************************************************************/ - -#include <linux/module.h> -#include <linux/socket.h> -#include <linux/miscdevice.h> -#include <linux/list.h> -#include <linux/vmalloc.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <asm/uaccess.h> -#include <asm/atomic.h> -#include <linux/delay.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -//#define DEBUG 1 -#include <linux/usb.h> - -#if (LINUX_VERSION_CODE < 0x020300) -#define dev_kfree_skb_any dev_kfree_skb -#endif - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.5.7" -#define DRIVER_AUTHOR "Deti Fliegl, deti@fliegl.de" -#define DRIVER_DESC "PL-2302 USB Interface Driver for Linux (c)2000" - -/* Definitions formerly in plusb.h relocated. No need to export them -EZA */ - -#define _PLUSB_INTPIPE 0x1 -#define _PLUSB_BULKOUTPIPE 0x2 -#define _PLUSB_BULKINPIPE 0x3 - -#define _SKB_NUM 32 - -/* increase size of BULK_DATA_LEN so we can use bigger MTU's*/ -#define _BULK_DATA_LEN 32768 - - -typedef struct -{ - int connected; /* indicates if this structure is active */ - struct usb_device *usbdev; - /* keep track of USB structure */ - int status; /* Prolific status byte returned from interrupt */ - int in_bh; /* flag to indicate that we are in the bulk handler */ - int opened; /* flag to indicate that network dev is open */ - - spinlock_t lock; /* Lock for the buffer list. re-used for - locking around submitting the readurb member. - */ - urb_t *inturb; /* Read buffer for the interrupt callback */ - unsigned char * interrupt_in_buffer; - /* holds data for the inturb*/ - urb_t *readurb; /* Read buffer for the bulk data callback */ - unsigned char * bulk_in_buffer; - /* kmalloc'ed data for the readurb */ - int readurb_submitted; - /* Flag to indicate that readurb already sent */ - urb_t *writeurb; /* Write buffer for the bulk data callback */ - int writeurb_submitted; - /* Flag to indicate that writeurb already sent */ - - struct list_head tx_skb_list; - /* sk_buff's read from net device */ - struct list_head free_skb_list; - /* free sk_buff list */ - struct net_device net_dev; - /* handle to linux network device */ - struct net_device_stats net_stats; - /* stats to return for ifconfig output */ -} plusb_t,*pplusb_t; - -/* - * skb_list - queue of packets from the network driver to be delivered to USB - */ -typedef struct -{ - struct list_head skb_list; - struct sk_buff *skb; - int state; - plusb_t *s; -} skb_list_t,*pskb_list_t; - - -/* --------------------------------------------------------------------- */ - -#define NRPLUSB 4 - -/* - * Interrupt endpoint status byte, from Prolific PL-2301 docs - * Check the 'download' link at www.prolifictech.com - */ -#define _PL_INT_RES1 0x80 /* reserved */ -#define _PL_INT_RES2 0x40 /* reserved */ -#define _PL_INT_RXD _PL_INT_RES2 /* Read data ready - Not documented by Prolific, but seems to work! */ -#define _PL_INT_TX_RDY 0x20 /* OK to transmit data */ -#define _PL_INT_RESET_O 0x10 /* reset output pipe */ -#define _PL_INT_RESET_I 0x08 /* reset input pipe */ -#define _PL_INT_TX_C 0x04 /* transmission complete */ -#define _PL_INT_TX_REQ 0x02 /* transmission received */ -#define _PL_INT_PEER_E 0x01 /* peer exists */ - -/*-------------------------------------------------------------------*/ - -static plusb_t plusb[NRPLUSB]; - -static void plusb_write_bulk_complete(urb_t *purb); -static void plusb_read_bulk_complete(urb_t *purb); -static void plusb_int_complete(urb_t *purb); - -/* --------------------------------------------------------------------- */ - -/* - * plusb_add_buf_tail - Take the head of the src list and append it to - * the tail of the dest list - */ -static int plusb_add_buf_tail (plusb_t *s, struct list_head *dst, struct list_head *src) -{ - unsigned long flags = 0; - struct list_head *tmp; - int ret = 0; - - spin_lock_irqsave (&s->lock, flags); - - if (list_empty (src)) { - // no elements in source buffer - ret = -1; - goto err; - } - tmp = src->next; - list_del (tmp); - list_add_tail (tmp, dst); - - err: spin_unlock_irqrestore (&s->lock, flags); - return ret; -} -/*-------------------------------------------------------------------*/ - -/* - * dequeue_next_skb - submit the first thing on the tx_skb_list to the - * USB stack. This function should be called each time we get a new - * message to send to the other host, or each time a message is successfully - * sent. - */ -static void dequeue_next_skb(char * func, plusb_t * s) -{ - skb_list_t * skb_list; - unsigned long flags = 0; - - if (!s->connected) - return; - - spin_lock_irqsave (&s->lock, flags); - - if (!list_empty (&s->tx_skb_list) && !s->writeurb_submitted) { - int submit_ret; - skb_list = list_entry (s->tx_skb_list.next, skb_list_t, skb_list); - - if (skb_list->skb) { - s->writeurb_submitted = 1; - - /* Use the buffer inside the sk_buff directly. why copy? */ - FILL_BULK_URB_TO(s->writeurb, s->usbdev, - usb_sndbulkpipe(s->usbdev, _PLUSB_BULKOUTPIPE), - skb_list->skb->data, skb_list->skb->len, - plusb_write_bulk_complete, skb_list, 500); - - dbg ("%s: %s: submitting urb. skb_list %p", s->net_dev.name, func, skb_list); - - submit_ret = usb_submit_urb(s->writeurb); - if (submit_ret) { - s->writeurb_submitted = 0; - printk (KERN_CRIT "%s: %s: can't submit writeurb: %d\n", - s->net_dev.name, func, submit_ret); - } - } /* end if the skb value has been filled in */ - } - - spin_unlock_irqrestore (&s->lock, flags); -} - -/* - * submit_read_urb - re-submit the read URB to the stack - */ -void submit_read_urb(char * func, plusb_t * s) -{ - unsigned long flags=0; - - if (!s->connected) - return; - - spin_lock_irqsave (&s->lock, flags); - - if (!s->readurb_submitted) { - int ret; - s->readurb_submitted=1; - s->readurb->dev=s->usbdev; - ret = usb_submit_urb(s->readurb); - if (ret) { - printk (KERN_CRIT "%s: %s: error %d submitting read URB\n", - s->net_dev.name, func, ret); - s->readurb_submitted=0; - } - } - - spin_unlock_irqrestore (&s->lock, flags); - -} -/* --------------------------------------------------------------------- */ - -/* - * plusb_net_xmit - callback from the network device driver for outgoing data - * - * Data has arrived to the network device from the local machine and needs - * to be sent over the USB cable. This is in an interrupt, so we don't - * want to spend too much time in this function. - * - */ -static int plusb_net_xmit(struct sk_buff *skb, struct net_device *dev) -{ - plusb_t *s=dev->priv; - skb_list_t *skb_list; - unsigned int flags; - - dbg("plusb_net_xmit: len:%d i:%d",skb->len,in_interrupt()); - - if(!s->connected || !s->opened) { - /* - NOTE: If we get to this point, you'll return the error - kernel: virtual device plusb0 asks to queue packet - - Other things we could do: - 1) just drop this packet - 2) drop other packets in the queue - */ - return 1; - } - - spin_lock_irqsave (&s->lock, flags); - - if (list_empty(&s->free_skb_list) - || plusb_add_buf_tail (s, &s->tx_skb_list, &s->free_skb_list)) { - /* The buffers on this side are full. DROP the packet - I think that this shouldn't happen with the correct - use of the netif_XXX functions -EZA - */ - dbg ("plusb: Free list is empty."); - kfree_skb(skb); - s->net_stats.tx_dropped++; - spin_unlock_irqrestore (&s->lock, flags); - return 0; - } - - skb_list = list_entry (s->tx_skb_list.prev, skb_list_t, skb_list); - skb_list->skb=skb; - skb_list->state=1; - skb_list->s=s; - - if (list_empty(&s->free_skb_list)) { - /* apply "backpressure". Tell the net layer to stop sending - the driver packets. - */ - netif_stop_queue(dev); - } - - spin_unlock_irqrestore (&s->lock, flags); - - /* If there is no write urb outstanding, pull the first thing - off of the list and submit it to the USB stack - */ - dequeue_next_skb("plusb_net_xmit", s); - - return 0; -} - -/* --------------------------------------------------------------------- */ - -/* - * plusb_write_bulk_complete () - callback after the data has been - * sent to the USB device, or a timeout occurred. - */ -static void plusb_write_bulk_complete(urb_t *purb) -{ - skb_list_t * skb_list=purb->context; - plusb_t *s=skb_list->s; - - dbg ("%s: plusb_write_bulk_complete: status:%d skb_list:%p\n", - s->net_dev.name, purb->status, skb_list); - - skb_list->state=0; - - if( purb->status == -EPIPE ) - printk(KERN_CRIT "%s: plusb_write_bulk_complete: got -EPIPE and don't know what to do!\n", - s->net_dev.name); - - if(!purb->status) { - s->net_stats.tx_packets++; - s->net_stats.tx_bytes+=skb_list->skb->len; - } - else { - err ("%s: plusb_write_bulk_complete: returned ERROR status:%d\n", - s->net_dev.name, purb->status); - - s->net_stats.tx_errors++; - s->net_stats.tx_aborted_errors++; - } - - dbg("plusb_bh: dev_kfree_skb"); - - /* NOTE: In 2.4 it's a problem to call dev_kfree_skb() in a hard IRQ: - Oct 28 23:42:14 bug kernel: Warning: kfree_skb on hard IRQ c023329a - */ - dev_kfree_skb_any(skb_list->skb); - - skb_list->skb = NULL; - if (plusb_add_buf_tail (s, &s->free_skb_list, &s->tx_skb_list)) { - err ("plusb: tx list empty. This shouldn't happen."); - } - - purb->status = 0; - s->writeurb_submitted = 0; - - netif_wake_queue((&s->net_dev)); - - dequeue_next_skb("plusb_write_bulk_complete", s); - - -} - -/* - * plusb_read_bulk_complete - Callback for data arriving from the USB device - * - * This gets called back when a full 'urb' is received from the remote system. - * This urb was allocated by this driver and is kept in the member: s->readurb - * - */ -static void plusb_read_bulk_complete(urb_t *purb) -{ - - plusb_t *s=purb->context; - - dbg("plusb_read_bulk_complete: status:%d length:%d", purb->status,purb->actual_length); - - if(!s->connected) - return; - - if( purb->status == -EPIPE ) - printk(KERN_CRIT "%s: plusb_read_bulk_complete: got -EPIPE and I don't know what to do!\n", - s->net_dev.name); - else if (!purb->status) { - struct sk_buff *skb; - unsigned char *dst; - int len=purb->transfer_buffer_length; - struct net_device_stats *stats=&s->net_stats; - - skb=dev_alloc_skb(len); - - if(!skb) { - printk (KERN_CRIT "%s: plusb_read_bulk_complete: dev_alloc_skb(%d)=NULL, dropping frame\n", s->net_dev.name, len); - stats->rx_dropped++; - } else { - dst=(char *)skb_put(skb, len); - memcpy( dst, purb->transfer_buffer, len); - - skb->dev=&s->net_dev; - skb->protocol=eth_type_trans(skb, skb->dev); - stats->rx_packets++; - stats->rx_bytes+=len; - netif_rx(skb); - } - - } - - s->readurb_submitted = 0; - - if (purb->status) { - /* Give the system a chance to "catch its breath". Shortcut - re-submitting the read URB> It will be re-submitted if - another interrupt comes back. The problem scenario is that - the plub is pulled and the read returns an error. - You don't want to resumbit in this case. - */ - err ("%s: plusb_read_bulk_complete: returned status %d\n", - s->net_dev.name, purb->status); - return; - } - - - purb->status=0; - - /* Keep it coming! resubmit the URB for reading.. Make sure - we aren't in contention with the interrupt callback. - */ - submit_read_urb("plusb_read_bulk_complete", s); -} - -/* --------------------------------------------------------------------- */ -/* - * plusb_int_complete - USB driver callback for interrupt msg from the device - * - * Interrupts are scheduled to go off on a periodic basis (see FILL_INT_URB) - * For the prolific device, this is basically just returning a register - * filled with bits. See the macro definitions for _PL_INT_XXX above. - * Most of these bits are for implementing a machine-machine protocol - * and can be set with a special message (described as the "Quicklink" - * feature in the prolific documentation.) - * - * I don't think we need any of that to work as a network device. If a - * message is lost, big deal - that's what UNIX networking expects from - * the physical layer. - * - */ -static void plusb_int_complete(urb_t *purb) -{ - plusb_t *s=purb->context; - s->status=((unsigned char*)purb->transfer_buffer)[0]&255; - -#if 0 - /* This isn't right because 0x20 is TX_RDY and - sometimes will not be set - */ - if((s->status&0x3f)!=0x20) { - warn("invalid device status %02X", s->status); - return; - } -#endif - if(!s->connected) - return; - - /* Don't turn this on unless you want to see the log flooded. */ -#if 0 - printk("plusb_int_complete: PEER_E:%d TX_REQ:%d TX_C:%d RESET_IN:%d RESET_O: %d TX_RDY:%d RES1:%d RES2:%d\n", - s->status & _PL_INT_PEER_E ? 1 : 0, - s->status & _PL_INT_TX_REQ ? 1 : 0, - s->status & _PL_INT_TX_C ? 1 : 0, - s->status & _PL_INT_RESET_I ? 1 : 0, - s->status & _PL_INT_RESET_O ? 1 : 0, - s->status & _PL_INT_TX_RDY ? 1 : 0, - s->status & _PL_INT_RES1 ? 1 : 0, - s->status & _PL_INT_RES2 ? 1 : 0); -#endif - -#if 1 - /* At first glance, this logic appears to not really be needed, but - it can help recover from intermittent problems where the - usb_submit_urb() fails in the read callback. -EZA - */ - - /* Try to submit the read URB again. Make sure - we aren't in contention with the bulk read callback - */ - submit_read_urb ("plusb_int_complete", s); - - /* While we are at it, why not check to see if the - write urb should be re-submitted? - */ - dequeue_next_skb("plusb_int_complete", s); - -#endif - -} - -/* --------------------------------------------------------------------- */ -/* - * plusb_free_all - deallocate all memory kept for an instance of the device. - */ -static void plusb_free_all(plusb_t *s) -{ - struct list_head *skb; - skb_list_t *skb_list; - - dbg("plusb_free_all"); - - /* set a flag to tell all callbacks to cease and desist */ - s->connected = 0; - - /* If the interrupt handler is about to fire, let it finish up */ - run_task_queue(&tq_immediate); - - if(s->inturb) { - dbg("unlink inturb"); - usb_unlink_urb(s->inturb); - dbg("free_urb inturb"); - usb_free_urb(s->inturb); - s->inturb=NULL; - } - - if(s->interrupt_in_buffer) { - dbg("kfree s->interrupt_in_buffer"); - kfree(s->interrupt_in_buffer); - s->interrupt_in_buffer=NULL; - } - - if(s->readurb) { - dbg("unlink readurb"); - usb_unlink_urb(s->readurb); - dbg("free_urb readurb:"); - usb_free_urb(s->readurb); - s->readurb=NULL; - } - - if(s->bulk_in_buffer) { - dbg("kfree s->bulk_in_buffer"); - kfree(s->bulk_in_buffer); - s->bulk_in_buffer=NULL; - } - - s->readurb_submitted = 0; - - if(s->writeurb) { - dbg("unlink writeurb"); - usb_unlink_urb(s->writeurb); - dbg("free_urb writeurb:"); - usb_free_urb(s->writeurb); - s->writeurb=NULL; - } - - s->writeurb_submitted = 0; - - while(!list_empty(&s->free_skb_list)) { - skb=s->free_skb_list.next; - list_del(skb); - skb_list = list_entry (skb, skb_list_t, skb_list); - kfree(skb_list); - } - - while(!list_empty(&s->tx_skb_list)) { - skb=s->tx_skb_list.next; - list_del(skb); - skb_list = list_entry (skb, skb_list_t, skb_list); - if (skb_list->skb) { - dbg ("Freeing SKB in queue"); - dev_kfree_skb_any(skb_list->skb); - skb_list->skb = NULL; - } - kfree(skb_list); - } - - s->in_bh=0; - - dbg("plusb_free_all: finished"); -} - -/*-------------------------------------------------------------------*/ -/* - * plusb_alloc - allocate memory associated with one instance of the device - */ -static int plusb_alloc(plusb_t *s) -{ - int i; - skb_list_t *skb; - - dbg("plusb_alloc"); - - for(i=0 ; i < _SKB_NUM ; i++) { - skb=kmalloc(sizeof(skb_list_t), GFP_KERNEL); - if(!skb) { - err("kmalloc for skb_list failed"); - goto reject; - } - memset(skb, 0, sizeof(skb_list_t)); - list_add(&skb->skb_list, &s->free_skb_list); - } - - dbg("inturb allocation:"); - s->inturb=usb_alloc_urb(0); - if(!s->inturb) { - err("alloc_urb failed"); - goto reject; - } - - dbg("bulk read urb allocation:"); - s->readurb=usb_alloc_urb(0); - if(!s->readurb) { - err("alloc_urb failed"); - goto reject; - } - - dbg("bulk write urb allocation:"); - s->writeurb=usb_alloc_urb(0); - if(!s->writeurb) { - err("alloc_urb for writeurb failed"); - goto reject; - } - - dbg("readurb/inturb init:"); - s->interrupt_in_buffer=kmalloc(64, GFP_KERNEL); - if(!s->interrupt_in_buffer) { - err("kmalloc failed"); - goto reject; - } - - /* The original value of '10' makes this interrupt fire off a LOT. - It was set so low because the callback determined when to - sumbit the buld read URB. I've lowered it to 100 - the driver - doesn't depend on that logic anymore. -EZA - */ - FILL_INT_URB(s->inturb, s->usbdev, - usb_rcvintpipe (s->usbdev, _PLUSB_INTPIPE), - s->interrupt_in_buffer, 1, - plusb_int_complete, s, HZ); - - dbg("inturb submission:"); - if(usb_submit_urb(s->inturb)<0) { - err("usb_submit_urb failed"); - goto reject; - } - - dbg("readurb init:"); - s->bulk_in_buffer = kmalloc(_BULK_DATA_LEN, GFP_KERNEL); - if (!s->bulk_in_buffer) { - err("kmalloc %d bytes for bulk in buffer failed", _BULK_DATA_LEN); - } - - FILL_BULK_URB(s->readurb, s->usbdev, - usb_rcvbulkpipe(s->usbdev, _PLUSB_BULKINPIPE), - s->bulk_in_buffer, _BULK_DATA_LEN, - plusb_read_bulk_complete, s); - - /* The write urb will be initialized inside the network - interrupt. - */ - - /* get the bulk read going */ - submit_read_urb("plusb_alloc", s); - - dbg ("plusb_alloc: finished. readurb=%p writeurb=%p inturb=%p", - s->readurb, s->writeurb, s->inturb); - - return 0; - - reject: - dbg("plusb_alloc: failed"); - - plusb_free_all(s); - return -ENOMEM; -} - -/*-------------------------------------------------------------------*/ - -static int plusb_net_open(struct net_device *dev) -{ - plusb_t *s=dev->priv; - - dbg("plusb_net_open"); - - if(plusb_alloc(s)) - return -ENOMEM; - - s->opened=1; - - MOD_INC_USE_COUNT; - - netif_start_queue(dev); - - dbg("plusb_net_open: success"); - - return 0; - -} - -/* --------------------------------------------------------------------- */ - -static int plusb_net_stop(struct net_device *dev) -{ - plusb_t *s=dev->priv; - - netif_stop_queue(dev); - - dbg("plusb_net_stop"); - - s->opened=0; - plusb_free_all(s); - - MOD_DEC_USE_COUNT; - dbg("plusb_net_stop:finished"); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static struct net_device_stats *plusb_net_get_stats(struct net_device *dev) -{ - plusb_t *s=dev->priv; - - dbg("net_device_stats"); - - return &s->net_stats; -} - -/* --------------------------------------------------------------------- */ - -static plusb_t *plusb_find_struct (void) -{ - int u; - - for (u = 0; u < NRPLUSB; u++) { - plusb_t *s = &plusb[u]; - if (!s->connected) - return s; - } - return NULL; -} - -/* --------------------------------------------------------------------- */ - -static void plusb_disconnect (struct usb_device *usbdev, void *ptr) -{ - plusb_t *s = ptr; - - dbg("plusb_disconnect"); - - plusb_free_all(s); - - if(!s->opened && s->net_dev.name) { - dbg("unregistering netdev: %s",s->net_dev.name); - unregister_netdev(&s->net_dev); - s->net_dev.name[0] = '\0'; -#if (LINUX_VERSION_CODE < 0x020300) - dbg("plusb_disconnect: About to free name"); - kfree (s->net_dev.name); - s->net_dev.name = NULL; -#endif - } - - dbg("plusb_disconnect: finished"); - MOD_DEC_USE_COUNT; -} - -/* --------------------------------------------------------------------- */ - -static int plusb_change_mtu(struct net_device *dev, int new_mtu) -{ - if ((new_mtu < 68) || (new_mtu > _BULK_DATA_LEN)) - return -EINVAL; - - printk("plusb: changing mtu to %d\n", new_mtu); - dev->mtu = new_mtu; - - /* NOTE: Could we change the size of the READ URB here dynamically - to save kernel memory? - */ - return 0; -} - -/* --------------------------------------------------------------------- */ - -int plusb_net_init(struct net_device *dev) -{ - dbg("plusb_net_init"); - - dev->open=plusb_net_open; - dev->stop=plusb_net_stop; - dev->hard_start_xmit=plusb_net_xmit; - dev->get_stats = plusb_net_get_stats; - ether_setup(dev); - dev->change_mtu = plusb_change_mtu; - /* Setting the default MTU to 16K gives good performance for - me, and keeps the ping latency low too. Setting it up - to 32K made performance go down. -EZA - Pavel says it would be best not to do this... - */ - /*dev->mtu=16384; */ - dev->tx_queue_len = 0; - dev->flags = IFF_POINTOPOINT|IFF_NOARP; - - - dbg("plusb_net_init: finished"); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static void *plusb_probe (struct usb_device *usbdev, unsigned int ifnum, const struct usb_device_id *id) -{ - plusb_t *s; - - dbg("plusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d", - usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, ifnum); - - if (usbdev->descriptor.idVendor != 0x067b || usbdev->descriptor.idProduct > 0x1) - return NULL; - - /* We don't handle multiple configurations */ - if (usbdev->descriptor.bNumConfigurations != 1) - return NULL; - - s = plusb_find_struct (); - if (!s) - return NULL; - - s->usbdev = usbdev; - - if (usb_set_configuration (s->usbdev, usbdev->config[0].bConfigurationValue) < 0) { - err("set_configuration failed"); - return NULL; - } - - if (usb_set_interface (s->usbdev, 0, 0) < 0) { - err("set_interface failed"); - return NULL; - } - -#if (LINUX_VERSION_CODE < 0x020300) - { - int i; - - /* For Kernel version 2.2, the driver is responsible for - allocating this memory. For version 2.4, the rules - have apparently changed, but there is a nifty function - 'init_netdev' that might make this easier... It's in - ../net/net_init.c - but can we get there from here? (no) - -EZA - */ - - /* Find the device number... we seem to have lost it... -EZA */ - for (i=0; i<NRPLUSB; i++) { - if (&plusb[i] == s) - break; - } - - if(!s->net_dev.name) { - s->net_dev.name = kmalloc(strlen("plusbXXXX"), GFP_KERNEL); - sprintf (s->net_dev.name, "plusb%d", i); - s->net_dev.init=plusb_net_init; - s->net_dev.priv=s; - - printk ("plusb_probe: Registering Device\n"); - if(!register_netdev(&s->net_dev)) - info("registered: %s", s->net_dev.name); - else { - err("register_netdev failed"); - s->net_dev.name[0] = '\0'; - } - dbg ("plusb_probe: Connected!"); - } - } -#else - /* Kernel version 2.3+ works a little bit differently than 2.2 */ - if(!s->net_dev.name[0]) { - strcpy(s->net_dev.name, "plusb%d"); - s->net_dev.init=plusb_net_init; - s->net_dev.priv=s; - if(!register_netdev(&s->net_dev)) - info("registered: %s", s->net_dev.name); - else { - err("register_netdev failed"); - s->net_dev.name[0] = '\0'; - } - } -#endif - - s->connected = 1; - - if(s->opened) { - dbg("net device already allocated, restarting USB transfers"); - plusb_alloc(s); - } - - info("bound to interface: %d dev: %p", ifnum, usbdev); - MOD_INC_USE_COUNT; - return s; -} -/* --------------------------------------------------------------------- */ - -static struct usb_driver plusb_driver = -{ - name: "plusb", - probe: plusb_probe, - disconnect: plusb_disconnect, -}; - -/* --------------------------------------------------------------------- */ - -static int __init plusb_init (void) -{ - unsigned u; - dbg("plusb_init"); - - /* initialize struct */ - for (u = 0; u < NRPLUSB; u++) { - plusb_t *s = &plusb[u]; - memset (s, 0, sizeof (plusb_t)); - INIT_LIST_HEAD (&s->tx_skb_list); - INIT_LIST_HEAD (&s->free_skb_list); - spin_lock_init (&s->lock); - } - - /* register misc device */ - usb_register (&plusb_driver); - - dbg("plusb_init: driver registered"); - - info(DRIVER_VERSION ":" DRIVER_DESC); - - return 0; -} - -/* --------------------------------------------------------------------- */ - -static void __exit plusb_cleanup (void) -{ - unsigned u; - - dbg("plusb_cleanup"); - for (u = 0; u < NRPLUSB; u++) { - plusb_t *s = &plusb[u]; -#if (LINUX_VERSION_CODE < 0x020300) - if(s->net_dev.name) { - dbg("unregistering netdev: %s",s->net_dev.name); - unregister_netdev(&s->net_dev); - s->net_dev.name[0] = '\0'; - kfree (s->net_dev.name); - s->net_dev.name = NULL; - } -#else - if(s->net_dev.name[0]) { - dbg("unregistering netdev: %s",s->net_dev.name); - unregister_netdev(&s->net_dev); - s->net_dev.name[0] = '\0'; - } -#endif - } - usb_deregister (&plusb_driver); - dbg("plusb_cleanup: finished"); -} - -/* --------------------------------------------------------------------- */ - -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); - - -module_init (plusb_init); -module_exit (plusb_cleanup); - -/* --------------------------------------------------------------------- */ diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c index b8271eca56c9..b691bcd05956 100644 --- a/drivers/usb/printer.c +++ b/drivers/usb/printer.c @@ -269,6 +269,7 @@ static int usblp_release(struct inode *inode, struct file *file) struct usblp *usblp = file->private_data; down (&usblp->sem); + lock_kernel(); usblp->used = 0; if (usblp->dev) { if (usblp->bidir) @@ -277,6 +278,7 @@ static int usblp_release(struct inode *inode, struct file *file) up(&usblp->sem); } else /* finish cleanup from disconnect */ usblp_cleanup (usblp); + unlock_kernel(); return 0; } @@ -685,11 +687,9 @@ static void usblp_disconnect(struct usb_device *dev, void *ptr) BUG (); } - down (&usblp->sem); lock_kernel(); usblp->dev = NULL; - unlock_kernel(); usb_unlink_urb(&usblp->writeurb); if (usblp->bidir) @@ -699,6 +699,7 @@ static void usblp_disconnect(struct usb_device *dev, void *ptr) usblp_cleanup (usblp); else /* cleanup later, on close */ up (&usblp->sem); + unlock_kernel(); } static struct usb_device_id usblp_ids [] = { diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 9bacf95547fe..8a6a731cfab2 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -96,7 +96,7 @@ UNUSUAL_DEV( 0x04e6, 0x0003, 0x0000, 0x9999, #endif /* This entry is from Andries.Brouwer@cwi.nl */ -UNUSUAL_DEV( 0x04e6, 0x0005, 0x0100, 0x0205, +UNUSUAL_DEV( 0x04e6, 0x0005, 0x0100, 0x0208, "SCM Microsystems", "eUSB SmartMedia / CompactFlash Adapter", US_SC_SCSI, US_PR_DPCM_USB, NULL, diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index d388ac1a3a83..3e63e5d73056 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c @@ -33,7 +33,7 @@ #define dac_val (0x3c9) #define VGA_FB_PHYS 0xA0000 -#define VGA_FB_PHYS_LEN 65535 +#define VGA_FB_PHYS_LEN 65536 /* --------------------------------------------------------------------- */ diff --git a/fs/Makefile b/fs/Makefile index 41265f21614f..d70410913702 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -32,6 +32,7 @@ subdir-$(CONFIG_RAMFS) += ramfs subdir-$(CONFIG_CODA_FS) += coda subdir-$(CONFIG_MINIX_FS) += minix subdir-$(CONFIG_FAT_FS) += fat +subdir-$(CONFIG_UMSDOS_FS) += umsdos subdir-$(CONFIG_MSDOS_FS) += msdos subdir-$(CONFIG_VFAT_FS) += vfat subdir-$(CONFIG_BFS_FS) += bfs @@ -43,7 +44,6 @@ subdir-$(CONFIG_NFS_FS) += nfs subdir-$(CONFIG_NFSD) += nfsd subdir-$(CONFIG_LOCKD) += lockd subdir-$(CONFIG_NLS) += nls -subdir-$(CONFIG_UMSDOS_FS) += umsdos subdir-$(CONFIG_SYSV_FS) += sysv subdir-$(CONFIG_SMB_FS) += smbfs subdir-$(CONFIG_NCP_FS) += ncpfs diff --git a/fs/umsdos/README-WIP.txt b/fs/umsdos/README-WIP.txt index 9c09891de727..14643c738f6e 100644 --- a/fs/umsdos/README-WIP.txt +++ b/fs/umsdos/README-WIP.txt @@ -5,18 +5,11 @@ Changes by Matija Nalis (mnalis@jagor.srce.hr) on umsdos dentry fixing There is no warning any more. Both read-only and read-write stuff is fixed, both in msdos-compatibile mode, and in umsdos EMD mode, and it seems stable. -There are still few hardlink nuisances, but those are not fatal. - -I'd call it pre-release, and ask for as many people as possible to -come and test it! See notes below for some more information, or if -you are trying to use UMSDOS as root partition. Userland NOTE: new umsdos_progs (umssync, umssetup, udosctl & friends) that -will compile and work on 2.2.x kernels and glibc based systems may be found -at http://cvs.linux.hr/ - -Also look at the quick-hack "homepage" for umsdos filesystem at -http://www.voyager.hr/~mnalis/umsdos +will compile and work on 2.2.x+ kernels and glibc based systems, as well as +kernel patches and other umsdos related information may be found at +http://linux.voyager.hr/umsdos/ Information below is getting outdated slowly -- I'll fix it one day when I get enough time - there are more important things to fix right now. @@ -24,7 +17,7 @@ get enough time - there are more important things to fix right now. Legend: those lines marked with '+' on the beggining of line indicates it passed all of my tests, and performed perfect in all of them. -Current status (990202) - UMSDOS 0.85: +Current status (010125) - UMSDOS 0.86j: (1) pure MSDOS (no --linux-.--- EMD file): @@ -35,7 +28,7 @@ READ: WRITE: + creat file - works -+ delete file - works ++ unlink file - works + write file - works + rename file (same dir) - works + rename file (dif. dir) - works @@ -66,21 +59,22 @@ READ: WRITE: + create symlink - works -- create hardlink - works ++ create hardlink - works + create file - works + create special file - works + write to file - works + rename file (same dir) - works + rename file (dif. dir) - works -- rename hardlink (same dir) - -- rename hardlink (dif. dir) - ++ rename hardlink (same dir) - works +- rename hardlink (dif. dir) - works, but see notes below. + rename symlink (same dir) - works + rename symlink (dif. dir) - works + rename dir (same dir) - works + rename dir (dif. dir) - works -+ delete file - works ++ unlink file - works + notify_change (chown,perms) - works -+ delete hardlink - works ++ notify_change for hardlinks - works ++ unlink hardlink - works + mkdir - works + rmdir - works + umssyncing (many ioctls) - works @@ -99,24 +93,11 @@ in filesystems that might be externally modified like umsdos. There is example is specs file about it. Specifically, moving directory which contains hardlinks will break them. -Note: (about pseudoroot) If you are currently trying to use UMSDOS as root -partition (with linux installed in c:\linux) it will boot, but there may be -some problems. Volunteers ready to test pseudoroot are needed (preferably -ones with working backups or unimportant data). For example, '/DOS' pseudo -directory is only partially re-implemented and buggy. It works most of the -time, though. Update: should work ok in 0.84, although it still does not -work correctly in combination with initrd featere. Working on this! - Note: (about creating hardlinks in pseudoroot mode) - hardlinks created in pseudoroot mode are now again compatibile with 'normal' hardlinks, and vice versa. Thanks to Sorin Iordachescu <sorin@rodae.ro> for providing fix. - -Warning: (about hardlinks) - modifying hardlinks (esp. if they are in -different directories) are currently somewhat broken, I'm working on it. -Problem seems to be that code uses and updates EMD of directory where 'real -hardlink' is stored, not EMD of directory where our pseudo-hardlink is -located! I'm looking for ideas how to work around this in clean way, since -without it modifying hardlinks in any but most simple ways is broken! +See http://linux.voyager.hr/umsdos/hlbug.html for more info and upgrade +procedure if you used broken versions... ------------------------------------------------------------------------------ @@ -130,6 +111,4 @@ or panics which force you to reboot etc.) I'm unfortunately somewhat out of time to read linux-kernel@vger, but I do check for messages having "UMSDOS" in the subject, and read them. I might miss some in all that volume, though. I should reply to any direct e-mail -in few days. If I don't, probably I never got your message. You can try -mnalis-umsdos@voyager.hr; however mnalis@jagor.srce.hr is preferable. - +in few days. If I don't, probably I never got your message. diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c index 50a9459b6268..b2a140ce0127 100644 --- a/fs/umsdos/dir.c +++ b/fs/umsdos/dir.c @@ -651,13 +651,13 @@ char * umsdos_d_path(struct dentry *dentry, char * buffer, int len) old_root = dget(current->fs->root); read_unlock(¤t->fs->lock); spin_lock(&dcache_lock); - path = __d_path(dentry, NULL, dentry->d_sb->s_root, NULL, buffer, len); + path = __d_path(dentry, current->fs->rootmnt, dentry->d_sb->s_root, current->fs->rootmnt, buffer, len); /* FIXME: current->fs->rootmnt */ spin_unlock(&dcache_lock); if (*path == '/') path++; /* skip leading '/' */ - if (old_root->d_inode == pseudo_root) + if (current->fs->root->d_inode == pseudo_root) { *(path-1) = '/'; path -= (UMSDOS_PSDROOT_LEN+1); diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c index c1bf4e1dd2ce..51d76ca24009 100644 --- a/fs/umsdos/emd.c +++ b/fs/umsdos/emd.c @@ -18,7 +18,21 @@ #include <linux/pagemap.h> #include <linux/delay.h> -static void copy_entry(struct umsdos_dirent *p, struct umsdos_dirent *q) +void put_entry (struct umsdos_dirent *p, struct umsdos_dirent *q) +{ + p->name_len = q->name_len; + p->flags = q->flags; + p->nlink = cpu_to_le16(q->nlink); + p->uid = cpu_to_le16(q->uid); + p->gid = cpu_to_le16(q->gid); + p->atime = cpu_to_le32(q->atime); + p->mtime = cpu_to_le32(q->mtime); + p->ctime = cpu_to_le32(q->ctime); + p->rdev = cpu_to_le16(q->rdev); + p->mode = cpu_to_le16(q->mode); +} + +static void get_entry(struct umsdos_dirent *p, struct umsdos_dirent *q) { p->name_len = q->name_len; p->name[p->name_len]='\0'; @@ -136,6 +150,7 @@ int umsdos_emd_dir_readentry (struct dentry *demd, loff_t *pos, struct umsdos_di printk (KERN_WARNING "Ignoring invalid EMD entry with size %d\n", entry->name_len); p->name_len = 0; ret = -ENAMETOOLONG; /* notify umssync(8) code that something is wrong */ + /* FIXME: does not work if we did 'ls -l' before 'udosctl uls' ?! */ } recsize = umsdos_evalrecsize(p->name_len); @@ -163,7 +178,7 @@ int umsdos_emd_dir_readentry (struct dentry *demd, loff_t *pos, struct umsdos_di page_cache_release(page2); } else memcpy(entry->spare,p->spare,((char*)p+recsize)-p->spare); - copy_entry(entry, p); + get_entry(entry, p); kunmap(page); page_cache_release(page); *pos += recsize; @@ -249,16 +264,7 @@ int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info, offs+info->recsize-PAGE_CACHE_SIZE); if (ret) goto out_unlock3; - p->name_len = entry->name_len; - p->flags = entry->flags; - p->nlink = cpu_to_le16(entry->nlink); - p->uid = cpu_to_le16(entry->uid); - p->gid = cpu_to_le16(entry->gid); - p->atime = cpu_to_le32(entry->atime); - p->mtime = cpu_to_le32(entry->mtime); - p->ctime = cpu_to_le32(entry->ctime); - p->rdev = cpu_to_le16(entry->rdev); - p->mode = cpu_to_le16(entry->mode); + put_entry (p, entry); memcpy(p->spare,entry->spare, (char *)(page_address(page) + PAGE_CACHE_SIZE) - p->spare); memcpy(page_address(page2), @@ -279,16 +285,7 @@ int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info, offs + info->recsize); if (ret) goto out_unlock; - p->name_len = entry->name_len; - p->flags = entry->flags; - p->nlink = cpu_to_le16(entry->nlink); - p->uid = cpu_to_le16(entry->uid); - p->gid = cpu_to_le16(entry->gid); - p->atime = cpu_to_le32(entry->atime); - p->mtime = cpu_to_le32(entry->mtime); - p->ctime = cpu_to_le32(entry->ctime); - p->rdev = cpu_to_le16(entry->rdev); - p->mode = cpu_to_le16(entry->mode); + put_entry (p, entry); memcpy(p->spare,entry->spare,((char*)p+info->recsize)-p->spare); ret = mapping->a_ops->commit_write(NULL,page,offs, offs + info->recsize); @@ -463,7 +460,7 @@ static int umsdos_find (struct dentry *demd, struct umsdos_info *info) goto skip_it; info->f_pos = pos; - copy_entry(entry, rentry); + get_entry(entry, rentry); ret = 0; break; skip_it: diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c index ff765811c9f3..9a47f8cd388e 100644 --- a/fs/umsdos/inode.c +++ b/fs/umsdos/inode.c @@ -38,7 +38,7 @@ void UMSDOS_put_inode (struct inode *inode) ,atomic_read(&inode->i_count))); if (inode == pseudo_root) { - printk (KERN_ERR "Umsdos: debug: releasing pseudo_root - ino=%lu count=%d\n", inode->i_ino, atomic_read(&inode->i_count)); + Printk ((KERN_ERR "Umsdos: debug: releasing pseudo_root - ino=%lu count=%d\n", inode->i_ino, atomic_read(&inode->i_count))); } if (atomic_read(&inode->i_count) == 1) @@ -49,7 +49,7 @@ void UMSDOS_put_inode (struct inode *inode) void UMSDOS_put_super (struct super_block *sb) { Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n")); - if (saved_root) { + if (saved_root && pseudo_root && sb->s_dev == ROOT_DEV) { shrink_dcache_parent(saved_root); dput(saved_root); saved_root = NULL; @@ -153,16 +153,56 @@ dentry, f_pos)); } -int umsdos_notify_change_locked(struct dentry *, struct iattr *); /* * lock the parent dir before starting ... + * also handles hardlink converting */ int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr) { - struct inode *dir = dentry->d_parent->d_inode; - struct inode *inode = dentry->d_inode; + struct inode *dir, *inode; + struct umsdos_info info; + struct dentry *temp, *old_dentry = NULL; int ret; + ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, + &info); + if (ret) + goto out; + ret = umsdos_findentry (dentry->d_parent, &info, 0); + if (ret) { +printk("UMSDOS_notify_change: %s/%s not in EMD, ret=%d\n", +dentry->d_parent->d_name.name, dentry->d_name.name, ret); + goto out; + } + + if (info.entry.flags & UMSDOS_HLINK) { + /* + * In order to get the correct (real) inode, we just drop + * the original dentry. + */ + d_drop(dentry); +Printk(("UMSDOS_notify_change: hard link %s/%s, fake=%s\n", +dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname)); + + /* Do a real lookup to get the short name dentry */ + temp = umsdos_covered(dentry->d_parent, info.fake.fname, + info.fake.len); + ret = PTR_ERR(temp); + if (IS_ERR(temp)) + goto out; + + /* now resolve the link ... */ + temp = umsdos_solve_hlink(temp); + ret = PTR_ERR(temp); + if (IS_ERR(temp)) + goto out; + old_dentry = dentry; + dentry = temp; /* so umsdos_notify_change_locked will operate on that */ + } + + dir = dentry->d_parent->d_inode; + inode = dentry->d_inode; + ret = inode_change_ok (inode, attr); if (ret) goto out; @@ -173,9 +213,12 @@ int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr) if (ret == 0) inode_setattr (inode, attr); out: + if (old_dentry) + dput (dentry); /* if we had to use fake dentry for hardlinks, dput() it now */ return ret; } + /* * Must be called with the parent lock held. */ @@ -316,16 +359,16 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data, struct super_block *res; struct dentry *new_root; - MSDOS_SB(sb)->options.isvfat = 0; /* * Call msdos-fs to mount the disk. * Note: this returns res == sb or NULL */ res = msdos_read_super (sb, data, silent); + if (!res) goto out_fail; - printk (KERN_INFO "UMSDOS 0.86i " + printk (KERN_INFO "UMSDOS 0.86k " "(compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE); @@ -334,6 +377,7 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data, /* install our dentry operations ... */ sb->s_root->d_op = &umsdos_dentry_operations; + umsdos_patch_dentry_inode(sb->s_root, 0); /* Check whether to change to the /linux root */ @@ -345,10 +389,9 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data, printk("umsdos_read_super: pseudo-root wrong ops!\n"); pseudo_root = new_root->d_inode; - saved_root = sb->s_root; - sb->s_root = new_root; printk(KERN_INFO "UMSDOS: changed to alternate root\n"); + dget (sb->s_root); sb->s_root = dget(new_root); } return sb; @@ -381,10 +424,12 @@ static struct dentry *check_pseudo_root(struct super_block *sb) root = lookup_one_len(UMSDOS_PSDROOT_NAME, sb->s_root,UMSDOS_PSDROOT_LEN); if (IS_ERR(root)) goto out_noroot; + if (!root->d_inode || !S_ISDIR(root->d_inode->i_mode)) goto out_dput; - printk(KERN_INFO "check_pseudo_root: found %s/%s\n", root->d_parent->d_name.name, root->d_name.name); +printk(KERN_INFO "check_pseudo_root: found %s/%s\n", +root->d_parent->d_name.name, root->d_name.name); /* look for /sbin/init */ sbin = lookup_one_len("sbin", root, 4); diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c index e6f9c3f94807..9049610da7ac 100644 --- a/fs/umsdos/namei.c +++ b/fs/umsdos/namei.c @@ -405,8 +405,15 @@ static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry, goto out_unlock; /* make sure it's the same inode! */ ret = -ENOENT; - if (old->d_inode != old_inode) - goto out_dput; + /* + * note: for hardlinks they will be different! + * old_inode will contain inode of .LINKxxx file containing data, and + * old->d_inode will contain inode of file containing path to .LINKxxx file + */ + if (!(old_info.entry.flags & UMSDOS_HLINK)) { + if (old->d_inode != old_inode) + goto out_dput; + } new = umsdos_covered(new_dentry->d_parent, new_info.fake.fname, new_info.fake.len); @@ -531,7 +538,7 @@ int UMSDOS_link (struct dentry *olddentry, struct inode *dir, struct umsdos_info hid_info; #ifdef UMSDOS_DEBUG_VERBOSE -printk("umsdos_link: new %s%s -> %s/%s\n", +printk("umsdos_link: new %s/%s -> %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name, olddentry->d_parent->d_name.name, olddentry->d_name.name); #endif @@ -698,17 +705,36 @@ out_unlock: if (ret == 0) { struct iattr newattrs; + /* Do a real lookup to get the short name dentry */ + temp = umsdos_covered(olddentry->d_parent, + old_info.fake.fname, + old_info.fake.len); + ret = PTR_ERR(temp); + if (IS_ERR(temp)) + goto out_unlock2; + + /* now resolve the link ... */ + temp = umsdos_solve_hlink(temp); + ret = PTR_ERR(temp); + if (IS_ERR(temp)) + goto out_unlock2; + + #ifdef UMSDOS_PARANOIA if (!oldinode->u.umsdos_i.i_is_hlink) printk("UMSDOS_link: %s/%s, ino=%ld, not marked as hlink!\n", olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_ino); #endif - oldinode->i_nlink++; + temp->d_inode->i_nlink++; Printk(("UMSDOS_link: linked %s/%s, ino=%ld, nlink=%d\n", olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_ino, oldinode->i_nlink)); newattrs.ia_valid = 0; - ret = umsdos_notify_change_locked(olddentry, &newattrs); + ret = umsdos_notify_change_locked(temp, &newattrs); + if (ret == 0) + mark_inode_dirty(temp->d_inode); + dput(temp); +out_unlock2: if (ret == 0) mark_inode_dirty(olddentry->d_inode); } diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c index 192009aa56f5..9fbca3941934 100644 --- a/fs/umsdos/rdir.c +++ b/fs/umsdos/rdir.c @@ -111,6 +111,9 @@ struct dentry *umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int */ Printk ((KERN_DEBUG "umsdos_rlookup_x: patch_dentry_inode %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name)); +/* only patch if needed (because we get called even for lookup + (not only rlookup) stuff sometimes, like in umsdos_covered() */ + if (dentry->d_inode->u.umsdos_i.i_patched == 0) umsdos_patch_dentry_inode(dentry, 0); } diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h index c99045972cf3..cdedca57e80c 100644 --- a/include/asm-i386/hw_irq.h +++ b/include/asm-i386/hw_irq.h @@ -130,7 +130,7 @@ asmlinkage void call_##x(void); \ __asm__( \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(x) ":\n\t" \ - "pushl $"#v"\n\t" \ + "pushl $"#v"-256\n\t" \ SAVE_ALL \ SYMBOL_NAME_STR(call_##x)":\n\t" \ "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \ @@ -143,7 +143,7 @@ asmlinkage void call_##x(void); \ __asm__( \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(x) ":\n\t" \ - "pushl $"#v"\n\t" \ + "pushl $"#v"-256\n\t" \ SAVE_ALL \ "movl %esp,%eax\n\t" \ "pushl %eax\n\t" \ diff --git a/include/asm-i386/msr.h b/include/asm-i386/msr.h index 72bf155e92ca..11bcb7f29e42 100644 --- a/include/asm-i386/msr.h +++ b/include/asm-i386/msr.h @@ -1,3 +1,6 @@ +#ifndef __ASM_MSR_H +#define __ASM_MSR_H + /* * Access to machine-specific registers (available on 586 and better only) * Note: the rd* operations modify the parameters directly (without using @@ -5,9 +8,9 @@ */ #define rdmsr(msr,val1,val2) \ - __asm__ __volatile__("rdmsr" \ - : "=a" (val1), "=d" (val2) \ - : "c" (msr)) + __asm__ __volatile__("rdmsr" \ + : "=a" (val1), "=d" (val2) \ + : "c" (msr)) #define wrmsr(msr,val1,val2) \ __asm__ __volatile__("wrmsr" \ @@ -18,10 +21,10 @@ __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) #define rdtscl(low) \ - __asm__ __volatile__ ("rdtsc" : "=a" (low) : : "edx") + __asm__ __volatile__("rdtsc" : "=a" (low) : : "edx") #define rdtscll(val) \ - __asm__ __volatile__ ("rdtsc" : "=A" (val)) + __asm__ __volatile__("rdtsc" : "=A" (val)) #define write_tsc(val1,val2) wrmsr(0x10, val1, val2) @@ -31,6 +34,71 @@ : "c" (counter)) /* symbolic names for some interesting MSRs */ -#define MSR_IA32_PLATFORM_ID 0x17 -#define MSR_IA32_UCODE_WRITE 0x79 -#define MSR_IA32_UCODE_REV 0x8B +/* Intel defined MSRs. */ +#define MSR_IA32_P5_MC_ADDR 0 +#define MSR_IA32_P5_MC_TYPE 1 +#define MSR_IA32_PLATFORM_ID 0x17 +#define MSR_IA32_EBL_CR_POWERON 0x2a + +#define MSR_IA32_APICBASE 0x1b +#define MSR_IA32_APICBASE_BSP (1<<8) +#define MSR_IA32_APICBASE_ENABLE (1<<11) +#define MSR_IA32_APICBASE_BASE (0xfffff<<12) + +#define MSR_IA32_UCODE_WRITE 0x79 +#define MSR_IA32_UCODE_REV 0x8b + +#define MSR_IA32_PERFCTR0 0xc1 +#define MSR_IA32_PERFCTR1 0xc2 + +#define MSR_IA32_BBL_CR_CTL 0x119 + +#define MSR_IA32_MCG_CAP 0x179 +#define MSR_IA32_MCG_STATUS 0x17a +#define MSR_IA32_MCG_CTL 0x17b + +#define MSR_IA32_EVNTSEL0 0x186 +#define MSR_IA32_EVNTSEL1 0x187 + +#define MSR_IA32_DEBUGCTLMSR 0x1d9 +#define MSR_IA32_LASTBRANCHFROMIP 0x1db +#define MSR_IA32_LASTBRANCHTOIP 0x1dc +#define MSR_IA32_LASTINTFROMIP 0x1dd +#define MSR_IA32_LASTINTTOIP 0x1de + +#define MSR_IA32_MC0_CTL 0x400 +#define MSR_IA32_MC0_STATUS 0x401 +#define MSR_IA32_MC0_ADDR 0x402 +#define MSR_IA32_MC0_MISC 0x403 + +/* AMD Defined MSRs */ +#define MSR_K6_EFER 0xC0000080 +#define MSR_K6_STAR 0xC0000081 +#define MSR_K6_WHCR 0xC0000082 +#define MSR_K6_UWCCR 0xC0000085 +#define MSR_K6_PSOR 0xC0000087 +#define MSR_K6_PFIR 0xC0000088 + +#define MSR_K7_EVNTSEL0 0xC0010000 +#define MSR_K7_PERFCTR0 0xC0010004 + +/* Centaur-Hauls/IDT defined MSRs. */ +#define MSR_IDT_FCR1 0x107 +#define MSR_IDT_FCR2 0x108 +#define MSR_IDT_FCR3 0x109 +#define MSR_IDT_FCR4 0x10a + +#define MSR_IDT_MCR0 0x110 +#define MSR_IDT_MCR1 0x111 +#define MSR_IDT_MCR2 0x112 +#define MSR_IDT_MCR3 0x113 +#define MSR_IDT_MCR4 0x114 +#define MSR_IDT_MCR5 0x115 +#define MSR_IDT_MCR6 0x116 +#define MSR_IDT_MCR7 0x117 +#define MSR_IDT_MCR_CTRL 0x120 + +/* VIA Cyrix defined MSRs*/ +#define MSR_VIA_FCR 0x1107 + +#endif /* __ASM_MSR_H */ diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h index 6f2f63a8e3d3..932aa29c5f49 100644 --- a/include/asm-i386/system.h +++ b/include/asm-i386/system.h @@ -110,10 +110,23 @@ static inline unsigned long _get_base(char * addr) }) #define write_cr0(x) \ __asm__("movl %0,%%cr0": :"r" (x)); + +#define read_cr4() ({ \ + unsigned int __dummy; \ + __asm__( \ + "movl %%cr4,%0\n\t" \ + :"=r" (__dummy)); \ + __dummy; \ +}) +#define write_cr4(x) \ + __asm__("movl %0,%%cr4": :"r" (x)); #define stts() write_cr0(8 | read_cr0()) #endif /* __KERNEL__ */ +#define wbinvd() \ + __asm__ __volatile__ ("wbinvd": : :"memory"); + static inline unsigned long get_limit(unsigned long segment) { unsigned long __limit; diff --git a/include/asm-i386/timex.h b/include/asm-i386/timex.h index 1cb3b96b471a..97099dd0d414 100644 --- a/include/asm-i386/timex.h +++ b/include/asm-i386/timex.h @@ -45,4 +45,6 @@ static inline cycles_t get_cycles (void) #endif } +extern unsigned long cpu_khz; + #endif diff --git a/include/asm-ppc/keyboard.h b/include/asm-ppc/keyboard.h index 4cc11f04d47e..d8e414c84cb3 100644 --- a/include/asm-ppc/keyboard.h +++ b/include/asm-ppc/keyboard.h @@ -1,5 +1,5 @@ /* - * BK Id: %F% %I% %G% %U% %#% + * BK Id: SCCS/s.keyboard.h 1.11 08/29/01 10:07:29 paulus */ /* * linux/include/asm-ppc/keyboard.h @@ -75,7 +75,6 @@ static inline void kbd_init_hw(void) ppc_md.kbd_init_hw(); } -#define kbd_rate (ppc_md.kbd_rate_fn) #define kbd_sysrq_xlate (ppc_md.ppc_kbd_sysrq_xlate) extern unsigned long SYSRQ_KEY; diff --git a/include/asm-ppc/kmap_types.h b/include/asm-ppc/kmap_types.h index b5243504f2ca..af0439610908 100644 --- a/include/asm-ppc/kmap_types.h +++ b/include/asm-ppc/kmap_types.h @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.kmap_types.h 1.6 05/17/01 18:14:24 cort + * BK Id: SCCS/s.kmap_types.h 1.9 08/29/01 14:03:05 paulus */ #ifdef __KERNEL__ #ifndef _ASM_KMAP_TYPES_H @@ -10,6 +10,8 @@ enum km_type { KM_BOUNCE_WRITE, KM_SKB_DATA, KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, KM_TYPE_NR }; diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h index 2862d8c89c7b..5f3cb66dd81c 100644 --- a/include/asm-ppc/machdep.h +++ b/include/asm-ppc/machdep.h @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.machdep.h 1.19 08/18/01 18:16:33 paulus + * BK Id: SCCS/s.machdep.h 1.21 08/29/01 10:07:29 paulus */ #ifdef __KERNEL__ #ifndef _PPC_MACHDEP_H @@ -14,7 +14,6 @@ struct pt_regs; struct pci_bus; struct pci_dev; -struct kbd_repeat; struct machdep_calls { void (*setup_arch)(void); @@ -61,7 +60,6 @@ struct machdep_calls { char raw_mode); char (*kbd_unexpected_up)(unsigned char keycode); void (*kbd_leds)(unsigned char leds); - int (*kbd_rate_fn)(struct kbd_repeat *rep); void (*kbd_init_hw)(void); #ifdef CONFIG_MAGIC_SYSRQ unsigned char *ppc_kbd_sysrq_xlate; @@ -74,6 +72,10 @@ struct machdep_calls { /* Called after scanning the bus, before allocating resources */ void (*pcibios_fixup)(void); + /* Called after PPC generic resource fixup to perform + machine specific fixups */ + void (*pcibios_fixup_resources)(struct pci_dev *); + /* Called for each PCI bus in the system when it's probed */ void (*pcibios_fixup_bus)(struct pci_bus *); @@ -82,6 +84,13 @@ struct machdep_calls { * Returns 0 to allow assignment/enabling of the device. */ int (*pcibios_enable_device_hook)(struct pci_dev *, int initial); + /* For interrupt routing */ + unsigned char (*pci_swizzle)(struct pci_dev *, unsigned char *); + int (*pci_map_irq)(struct pci_dev *, unsigned char, unsigned char); + + /* Called in indirect_* to avoid touching devices */ + int (*pci_exclude_device)(unsigned char, unsigned char); + /* Called at then very end of pcibios_init() */ void (*pcibios_after_init)(void); diff --git a/include/asm-sparc/kmap_types.h b/include/asm-sparc/kmap_types.h index 3388fa5bcd3a..82af4b9e8379 100644 --- a/include/asm-sparc/kmap_types.h +++ b/include/asm-sparc/kmap_types.h @@ -6,6 +6,8 @@ enum km_type { KM_BOUNCE_WRITE, KM_SKB_DATA, KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, KM_TYPE_NR }; diff --git a/include/linux/fs.h b/include/linux/fs.h index 8d70498784f5..1a8efa4044ea 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -182,7 +182,9 @@ extern int leases_enable, dir_notify_enable, lease_break_time; /* This was here just to show that the number is taken - probably all these _IO(0x12,*) ioctls should be moved to blkpg.h. */ #endif - +/* A jump here: 108-111 have been used for various private purposes. */ +#define BLKBSZGET _IOR(0x12,112,sizeof(int)) +#define BLKBSZSET _IOW(0x12,113,sizeof(int)) #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ #define FIBMAP _IO(0x00,1) /* bmap access */ diff --git a/include/linux/pmu.h b/include/linux/pmu.h index cd1ac601af84..1186ebc301a8 100644 --- a/include/linux/pmu.h +++ b/include/linux/pmu.h @@ -7,6 +7,9 @@ */ #include <linux/config.h> + +#define PMU_DRIVER_VERSION 2 + /* * PMU commands */ @@ -23,6 +26,7 @@ #define PMU_GET_VOLBUTTON 0x48 /* get volume up/down position */ #define PMU_PCEJECT 0x4c /* eject PC-card from slot */ #define PMU_BATTERY_STATE 0x6b /* report battery state etc. */ +#define PMU_SMART_BATTERY_STATE 0x6f /* report battery state (new way) */ #define PMU_SET_INTR_MASK 0x70 /* set PMU interrupt mask */ #define PMU_INT_ACK 0x78 /* read interrupt bits */ #define PMU_SHUTDOWN 0x7e /* turn power off */ @@ -32,6 +36,7 @@ #define PMU_GET_BRIGHTBUTTON 0xd9 /* report brightness up/down pos */ #define PMU_GET_COVER 0xdc /* report cover open/closed */ #define PMU_SYSTEM_READY 0xdf /* tell PMU we are awake */ +#define PMU_GET_VERSION 0xea /* read the PMU version */ /* Bits to use with the PMU_POWER_CTRL0 command */ #define PMU_POW0_ON 0x80 /* OR this to power ON the device */ @@ -46,16 +51,23 @@ #define PMU_POW_IRLED 0x04 /* IR led power (on wallstreet) */ #define PMU_POW_MEDIABAY 0x08 /* media bay power (wallstreet/lombard ?) */ - /* Bits in PMU interrupt and interrupt mask bytes */ -#define PMU_INT_ADB_AUTO 0x04 /* ADB autopoll, when PMU_INT_ADB */ #define PMU_INT_PCEJECT 0x04 /* PC-card eject buttons */ #define PMU_INT_SNDBRT 0x08 /* sound/brightness up/down buttons */ #define PMU_INT_ADB 0x10 /* ADB autopoll or reply data */ -#define PMU_INT_BATTERY 0x20 -#define PMU_INT_WAKEUP 0x40 +#define PMU_INT_BATTERY 0x20 /* Battery state change */ +#define PMU_INT_ENVIRONMENT 0x40 /* Environment interrupts */ #define PMU_INT_TICK 0x80 /* 1-second tick interrupt */ +/* Other bits in PMU interrupt valid when PMU_INT_ADB is set */ +#define PMU_INT_ADB_AUTO 0x04 /* ADB autopoll, when PMU_INT_ADB */ +#define PMU_INT_WAITING_CHARGER 0x01 /* ??? */ +#define PMU_INT_AUTO_SRQ_POLL 0x02 /* ??? */ + +/* Bits in the environement message (either obtained via PMU_GET_COVER, + * or via PMU_INT_ENVIRONMENT on core99 */ +#define PMU_ENV_LID_CLOSED 0x01 /* The lid is closed */ + /* Kind of PMU (model) */ enum { PMU_UNKNOWN, @@ -99,6 +111,8 @@ enum { #define PMU_IOC_GET_MODEL _IOR('B', 3, sizeof(__u32*)) /* out param: u32* has_adb: 0 or 1 */ #define PMU_IOC_HAS_ADB _IOR('B', 4, sizeof(__u32*)) +/* out param: u32* can_sleep: 0 or 1 */ +#define PMU_IOC_CAN_SLEEP _IOR('B', 5, sizeof(__u32*)) #ifdef __KERNEL__ @@ -160,7 +174,7 @@ struct pmu_sleep_notifier #define SLEEP_LEVEL_NET 60 /* bmac */ #define SLEEP_LEVEL_ADB 50 /* ADB */ #define SLEEP_LEVEL_MISC 30 /* Anything */ -#define SLEEP_LEVEL_LAST 0 /* Anything */ +#define SLEEP_LEVEL_LAST 0 /* Reserved for apm_emu */ /* special register notifier functions */ int pmu_register_sleep_notifier(struct pmu_sleep_notifier* notifier); diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 09eee390b5bc..b2fc5595c04b 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1082,7 +1082,7 @@ skb_cow(struct sk_buff *skb, unsigned int headroom) /** * skb_linearize - convert paged skb to linear one * @skb: buffer to linarize - * @gfp_mask: allocation mode + * @gfp: allocation mode * * If there is no free memory -ENOMEM is returned, otherwise zero * is returned and the old skb data released. */ diff --git a/mm/vmscan.c b/mm/vmscan.c index 1dfb9d1b76a0..e6fed11b1e07 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -818,10 +818,12 @@ int inactive_shortage(void) #define GENERAL_SHORTAGE 4 static int do_try_to_free_pages(unsigned int gfp_mask, int user) { - /* Always walk at least the active queue when called */ - int shortage = INACTIVE_SHORTAGE; + int shortage = 0; int maxtry; + /* Always walk at least the active queue when called */ + refill_inactive_scan(DEF_PRIORITY); + maxtry = 1 << DEF_PRIORITY; do { /* @@ -872,7 +874,8 @@ static int do_try_to_free_pages(unsigned int gfp_mask, int user) break; } while (shortage); - return !shortage; + /* Return success if we're not "totally short" */ + return shortage != (FREE_SHORTAGE | INACTIVE_SHORTAGE | GENERAL_SHORTAGE); } DECLARE_WAIT_QUEUE_HEAD(kswapd_wait); diff --git a/scripts/ver_linux b/scripts/ver_linux index 8bc8096dede1..a5a459f0b1d1 100644 --- a/scripts/ver_linux +++ b/scripts/ver_linux @@ -26,7 +26,7 @@ mount --version | awk -F\- '{print "mount ", $NF}' insmod -V 2>&1 | awk 'NR==1 {print "modutils ",$NF}' -tune2fs 2>&1 | grep tune2fs | sed 's/,//' | awk \ +tune2fs 2>&1 | grep "^tune2fs" | sed 's/,//' | awk \ 'NR==1 {print "e2fsprogs ", $2}' reiserfsck 2>&1 | grep reiserfsprogs | awk \ |
