diff -u --recursive --new-file v2.1.33/linux/CREDITS linux/CREDITS --- v2.1.33/linux/CREDITS Sun Apr 13 10:18:19 1997 +++ linux/CREDITS Sun Apr 13 20:28:27 1997 @@ -257,14 +257,12 @@ N: Alan Cox E: alan@lxorguk.ukuu.org.uk (linux related - except big patches) -E: iialan@www.linux.org.uk (linux.org.uk/big patches) +E: iialan@www.uk.linux.org (linux.org.uk/big patches) E: alan@cymru.net (commercial CymruNET stuff) -E: gw4pts@gw4pts.ampr.org (amateur radio stuff) -E: GW4PTS@GB7SWN (packet radio) -E: Please don't use iialan@iifeak.swan.ac.uk for Linux stuff -S: c/o 3Com/I^2IT Limited +E: Alan.Cox@linux.org (if others fail) +S: CymruNet Limited S: The Innovation Centre -S: University Of Wales +S: Singleton Park S: Swansea, SA2 8PP S: Wales, UK D: NET2Debugged/NET3 author diff -u --recursive --new-file v2.1.33/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.33/linux/Documentation/Configure.help Sun Apr 13 10:18:19 1997 +++ linux/Documentation/Configure.help Mon Apr 14 09:25:59 1997 @@ -539,6 +539,12 @@ any security protocols currently and that this option only really supports security on IPv4 links at the moment. +Socket Security API Support (EXPERIMENTAL) +CONFIG_NET_SECURITY + Enable use of the socket security API. Note that Linux does not include + any security protocols currently and that this option only really supports + security on IPv4 links at the moment. + Sun floppy controller support CONFIG_BLK_DEV_SUNFD This is support for floppy drives on Sun Sparc workstations. Say Y @@ -1530,9 +1536,10 @@ Enable vendor-specific extensions (for SCSI CDROM) CONFIG_BLK_DEV_SR_VENDOR This enables the usage of vendor specific SCSI commands. This is - required for some stuff which is newer than the SCSI-II standard, - most important is the MultiSession CD support. You'll probably want - to say Y here, unless you have a _real old_ CD-ROM drive. + required for some stuff which is newer than the SCSI-II standard: + MultiSession CD support and some ioctls for reading Mode 2 Form 2 + sectors. You'll probably want to say Y here, unless you have a + _real old_ CD-ROM drive. SCSI generic support CONFIG_CHR_DEV_SG diff -u --recursive --new-file v2.1.33/linux/Makefile linux/Makefile --- v2.1.33/linux/Makefile Sun Apr 13 10:18:20 1997 +++ linux/Makefile Mon Apr 14 11:55:24 1997 @@ -1,8 +1,8 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 33 +SUBLEVEL = 34 -ARCH = i386 +ARCH := $(shell uname -m | sed s/i.86/i386/) # # For SMP kernels, set this. We don't want to have this in the config file @@ -14,7 +14,7 @@ SMP = 1 # # SMP profiling options -SMP_PROF = 1 +# SMP_PROF = 1 .EXPORT_ALL_VARIABLES: diff -u --recursive --new-file v2.1.33/linux/Rules.make linux/Rules.make --- v2.1.33/linux/Rules.make Sun Apr 13 10:18:20 1997 +++ linux/Rules.make Sun Apr 13 20:47:29 1997 @@ -197,7 +197,7 @@ endif # CONFIG_MODVERSIONS ifneq "$(strip $(SYMTAB_OBJS))" "" -$(SYMTAB_OBJS): $(TOPDIR)/include/linux/modversions.h +$(SYMTAB_OBJS): $(TOPDIR)/include/linux/modversions.h $(SYMTAB_OBJS:.o=.c) $(CC) $(CFLAGS) -DEXPORT_SYMTAB -c $(@:.o=.c) endif diff -u --recursive --new-file v2.1.33/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.1.33/linux/arch/alpha/kernel/alpha_ksyms.c Thu Mar 27 14:39:59 1997 +++ linux/arch/alpha/kernel/alpha_ksyms.c Mon Apr 14 09:31:08 1997 @@ -19,7 +19,7 @@ #include #include #include - +#include extern void bcopy (const char *src, char *dst, int len); extern struct hwrpb_struct *hwrpb; @@ -37,6 +37,7 @@ extern void __divqu (void); extern void __remqu (void); +EXPORT_SYMBOL(__alpha_bh_counter); /* platform dependent support */ EXPORT_SYMBOL(_inb); diff -u --recursive --new-file v2.1.33/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v2.1.33/linux/arch/alpha/kernel/irq.c Tue Oct 15 23:05:09 1996 +++ linux/arch/alpha/kernel/irq.c Mon Apr 14 11:39:14 1997 @@ -53,7 +53,6 @@ */ static unsigned long irq_mask = ~0UL; - /* * Update the hardware with the irq mask passed in MASK. The function * exploits the fact that it is known that only bit IRQ has changed. @@ -274,6 +273,16 @@ printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461)); } +unsigned int local_irq_count[NR_CPUS]; +atomic_t __alpha_bh_counter; + +#ifdef __SMP__ +#error Me no hablo Alpha SMP +#else +#define irq_enter(cpu, irq) (++local_irq_count[cpu]) +#define irq_exit(cpu, irq) (--local_irq_count[cpu]) +#endif + static void unexpected_irq(int irq, struct pt_regs * regs) { struct irqaction *action; @@ -302,16 +311,19 @@ static inline void handle_irq(int irq, struct pt_regs * regs) { struct irqaction * action = irq_action[irq]; + int cpu = smp_processor_id(); + irq_enter(cpu, irq); kstat.interrupts[irq]++; if (!action) { unexpected_irq(irq, regs); - return; + } else { + do { + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); } - do { - action->handler(irq, action->dev_id, regs); - action = action->next; - } while (action); + irq_exit(cpu, irq); } static inline void device_interrupt(int irq, int ack, struct pt_regs * regs) @@ -323,6 +335,7 @@ return; } + irq_enter(cpu, irq); kstat.interrupts[irq]++; action = irq_action[irq]; /* @@ -336,15 +349,16 @@ */ mask_irq(ack); ack_irq(ack); - if (!action) - return; - if (action->flags & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); - do { - action->handler(irq, action->dev_id, regs); - action = action->next; - } while (action); - unmask_irq(ack); + if (action) { + if (action->flags & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + do { + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + unmask_irq(ack); + } + irq_exit(cpu, irq); } #ifdef CONFIG_PCI diff -u --recursive --new-file v2.1.33/linux/arch/alpha/lib/csum_partial_copy.c linux/arch/alpha/lib/csum_partial_copy.c --- v2.1.33/linux/arch/alpha/lib/csum_partial_copy.c Tue Mar 4 10:25:23 1997 +++ linux/arch/alpha/lib/csum_partial_copy.c Fri Apr 11 10:37:40 1997 @@ -13,7 +13,7 @@ #define ldq_u(x,y) \ -__asm__ __volatile__("ldq_u %0,%1":"=r" (x):"m" (*(unsigned long *)(y))) +__asm__ __volatile__("ldq_u %0,%1":"=r" (x):"m" (*(const unsigned long *)(y))) #define stq_u(x,y) \ __asm__ __volatile__("stq_u %1,%0":"=m" (*(unsigned long *)(y)):"r" (x)) @@ -72,7 +72,7 @@ * Ok. This isn't fun, but this is the EASY case. */ static inline unsigned long -csum_partial_cfu_aligned(unsigned long *src, unsigned long *dst, +csum_partial_cfu_aligned(const unsigned long *src, unsigned long *dst, long len, unsigned long checksum, int *errp) { @@ -165,7 +165,7 @@ * This is slightly less fun than the above.. */ static inline unsigned long -csum_partial_cfu_src_aligned(unsigned long *src, unsigned long *dst, +csum_partial_cfu_src_aligned(const unsigned long *src, unsigned long *dst, unsigned long doff, long len, unsigned long checksum, unsigned long partial_dest, @@ -227,7 +227,7 @@ * look at this too closely, you'll go blind. */ static inline unsigned long -csum_partial_cfu_unaligned(unsigned long * src, unsigned long * dst, +csum_partial_cfu_unaligned(const unsigned long * src, unsigned long * dst, unsigned long soff, unsigned long doff, long len, unsigned long checksum, unsigned long partial_dest, @@ -305,7 +305,7 @@ } static unsigned int -do_csum_partial_copy_from_user(char *src, char *dst, int len, +do_csum_partial_copy_from_user(const char *src, char *dst, int len, unsigned int sum, int *errp) { unsigned long checksum = (unsigned) sum; @@ -316,12 +316,12 @@ if (!doff) { if (!soff) checksum = csum_partial_cfu_aligned( - (unsigned long *) src, + (const unsigned long *) src, (unsigned long *) dst, len-8, checksum, errp); else checksum = csum_partial_cfu_dest_aligned( - (unsigned long *) src, + (const unsigned long *) src, (unsigned long *) dst, soff, len-8, checksum, errp); } else { @@ -329,13 +329,13 @@ ldq_u(partial_dest, dst); if (!soff) checksum = csum_partial_cfu_src_aligned( - (unsigned long *) src, + (const unsigned long *) src, (unsigned long *) dst, doff, len-8, checksum, partial_dest, errp); else checksum = csum_partial_cfu_unaligned( - (unsigned long *) src, + (const unsigned long *) src, (unsigned long *) dst, soff, doff, len-8, checksum, partial_dest, errp); @@ -352,7 +352,7 @@ } unsigned int -csum_partial_copy_from_user(char *src, char *dst, int len, +csum_partial_copy_from_user(const char *src, char *dst, int len, unsigned int sum, int *errp) { if (!access_ok(src, len, VERIFY_READ)) { diff -u --recursive --new-file v2.1.33/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c --- v2.1.33/linux/arch/alpha/mm/init.c Sun Jan 26 02:07:04 1997 +++ linux/arch/alpha/mm/init.c Mon Apr 14 09:31:08 1997 @@ -64,10 +64,10 @@ total++; if (PageReserved(mem_map+i)) reserved++; - else if (!mem_map[i].count) + else if (!atomic_read(&mem_map[i].count)) free++; else - shared += mem_map[i].count-1; + shared += atomic_read(&mem_map[i].count) - 1; } printk("%d pages of RAM\n",total); printk("%d free pages\n",free); @@ -163,7 +163,7 @@ clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags); if (PageReserved(mem_map+MAP_NR(tmp))) continue; - mem_map[MAP_NR(tmp)].count = 1; + atomic_set(&mem_map[MAP_NR(tmp)].count, 1); free_page(tmp); } tmp = nr_free_pages << PAGE_SHIFT; @@ -189,9 +189,9 @@ if (PageReserved(mem_map+i)) continue; val->totalram++; - if (!mem_map[i].count) + if (!atomic_read(&mem_map[i].count)) continue; - val->sharedram += mem_map[i].count-1; + val->sharedram += atomic_read(&mem_map[i].count) - 1; } val->totalram <<= PAGE_SHIFT; val->sharedram <<= PAGE_SHIFT; diff -u --recursive --new-file v2.1.33/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.1.33/linux/arch/i386/defconfig Sun Apr 13 10:18:20 1997 +++ linux/arch/i386/defconfig Fri Apr 11 22:13:19 1997 @@ -30,6 +30,12 @@ # CONFIG_M586 is not set CONFIG_M686=y # CONFIG_VIDEO_SELECT is not set +# CONFIG_PNP_PARPORT is not set + +# +# Plug and Play support +# +# CONFIG_PNP is not set # # Floppy, IDE, and other block devices @@ -131,7 +137,6 @@ # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_PPA is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_QLOGIC_FAS is not set # CONFIG_SCSI_QLOGIC_ISP is not set @@ -163,7 +168,6 @@ # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set # CONFIG_DLCI is not set -# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_NET_RADIO is not set # CONFIG_SLIP is not set @@ -214,7 +218,6 @@ CONFIG_SERIAL=y # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_PRINTER is not set CONFIG_MOUSE=y # CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_BUSMOUSE is not set diff -u --recursive --new-file v2.1.33/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.1.33/linux/arch/i386/kernel/irq.c Sun Apr 13 10:18:20 1997 +++ linux/arch/i386/kernel/irq.c Mon Apr 14 11:39:49 1997 @@ -36,7 +36,7 @@ #include #ifdef __SMP_PROF__ -extern volatile unsigned long smp_apic_timer_ticks[1+NR_CPUS]; +extern volatile unsigned long smp_local_timer_ticks[1+NR_CPUS]; #endif #define CR0_NE 32 @@ -45,6 +45,11 @@ static unsigned char cache_A1 = 0xff; unsigned int local_irq_count[NR_CPUS]; +#ifdef __SMP__ +atomic_t __intel_bh_counter; +#else +int __intel_bh_counter; +#endif #ifdef __SMP_PROF__ static unsigned int int_count[NR_CPUS][NR_IRQS] = {{0},}; @@ -252,6 +257,9 @@ #ifdef __SMP_PROF__ +extern unsigned int prof_multiplier[NR_CPUS]; +extern unsigned int prof_counter[NR_CPUS]; + int get_smp_prof_list(char *buf) { int i,j, len = 0; struct irqaction * action; @@ -259,7 +267,7 @@ unsigned long sum_spins_syscall = 0; unsigned long sum_spins_sys_idle = 0; unsigned long sum_smp_idle_count = 0; - unsigned long sum_apic_timer_ticks = 0; + unsigned long sum_local_timer_ticks = 0; for (i=0;ipid) { + extern int _stext; + eip -= (unsigned long) &_stext; + eip >>= prof_shift; + if (eip < prof_len) + atomic_inc(&prof_buffer[eip]); + else + /* + * Dont ignore out-of-bounds EIP values silently, + * put them into the last histogram slot, so if + * present, they will show up as a sharp peak. + */ + atomic_inc(&prof_buffer[prof_len-1]); + } +} -extern void (*do_profile)(struct pt_regs *); -static void (*default_do_profile)(struct pt_regs *) = NULL; +unsigned int prof_multiplier[NR_CPUS]; +unsigned int prof_counter[NR_CPUS]; +extern void update_one_process( struct task_struct *p, + unsigned long ticks, unsigned long user, + unsigned long system); /* - * APIC timer interrupt + * Local timer interrupt handler. It does both profiling and + * process statistics/rescheduling. + * + * We do profiling in every local tick, statistics/rescheduling + * happen only every 'profiling multiplier' ticks. The default + * multiplier is 1 and it can be changed by writing a 4 bytes multiplier + * value into /proc/profile. */ -void smp_apic_timer_interrupt(struct pt_regs * regs) +static inline void smp_local_timer_interrupt(struct pt_regs * regs) { int cpu = smp_processor_id(); - - if (!user_mode(regs)) { - unsigned long flags; + /* + * Both the profiling function and the statistics + * counters are SMP safe. We leave the APIC irq + * unacked while updating the profiling info, thus + * we cannot be interrupted by the same APIC interrupt. + */ + if (!user_mode(regs)) + x86_do_profile (regs->eip); + + if (!--prof_counter[cpu]) { + int user=0,system=0; + struct task_struct * p = current; /* - * local timer interrupt is not NMI yet, so - * it's simple, we just aquire the global cli - * lock to mess around with profiling info. + * We mess around with thread statistics, but + * since we are the CPU running it, we dont + * have to lock it. We assume that switch_to() + * protects 'current' against local irqs via __cli. + * + * kernel statistics counters are updated via atomic + * operations. * - * later, in the NMI version, we have to build - * our own 'current' pointer (as we could have - * interrupted code that just changes "current") - * and have to lock profiling info between NMI - * interrupts properly. + * update_one_process() might send signals, thus + * we have to get the irq lock for that one. */ - save_flags(flags); - cli(); - default_do_profile(regs); - restore_flags(flags); + + if (user_mode(regs)) + user=1; + else + system=1; + + if (p->pid) { + unsigned long flags; + + save_flags(flags); + cli(); + update_one_process(current, 1, user, system); + restore_flags(flags); + + p->counter -= 1; + if (p->counter < 0) { + p->counter = 0; + need_resched = 1; + } + if (p->priority < DEF_PRIORITY) + atomic_add (user, &kstat.cpu_nice); + else + atomic_add (user, &kstat.cpu_user); + + atomic_add (system, &kstat.cpu_system); + + } else { +#ifdef __SMP_PROF__ + if (test_bit(cpu,&smp_idle_map)) + smp_idle_count[cpu]++; +#endif + /* + * This is a hack until we have need_resched[] + */ + if (read_smp_counter(&smp_process_available)) + need_resched=1; + } + + prof_counter[cpu]=prof_multiplier[cpu]; } +#ifdef __SMP_PROF__ + smp_local_timer_ticks[cpu]++; +#endif /* - * this is safe outside the lock. - */ - smp_apic_timer_ticks[cpu]++; + * We take the 'long' return path, and there every subsystem + * grabs the apropriate locks (kernel lock/ irq lock). + * + * FIXME: we want to decouple profiling from the 'long path'. + * + * Currently this isnt too much of an issue (performancewise), + * we can take more than 100K local irqs per second on a 100 MHz P5. + * [ although we notice need_resched too early, thus the way we + * schedule (deliver signals and handle bhs) changes. ] + * + * Possibly we could solve these problems with 'smart irqs'. + */ +} + +/* + * Local APIC timer interrupt. This is the most natural way for doing + * local interrupts, but local timer interrupts can be emulated by + * broadcast interrupts too. [in case the hw doesnt support APIC timers] + */ +void smp_apic_timer_interrupt(struct pt_regs * regs) +{ + smp_local_timer_interrupt(regs); - apic_read (APIC_SPIV); - apic_write (APIC_EOI, 0); + ack_APIC_irq (); } /* @@ -1373,9 +1474,8 @@ * per second. We assume that the caller has already set up the local * APIC at apic_addr. * - * Later we might want to split HZ into two parts: introduce - * PROFILING_HZ and scheduling HZ. The APIC timer is not exactly - * sync with the external timer chip, it closely follows bus clocks. + * The APIC timer is not exactly sync with the external timer chip, it + * closely follows bus clocks. */ #define RTDSC(x) __asm__ __volatile__ ( ".byte 0x0f,0x31" \ @@ -1407,15 +1507,13 @@ * * We are strictly in irqs off mode here, as we do not want to * get an APIC interrupt go off accidentally. + * + * We do reads before writes even if unnecessary, to get around the + * APIC double write bug. */ #define APIC_DIVISOR 16 -/* - * We do reads before writes even if unnecessary, to get around the - * APIC double write 'bug'. - */ - void setup_APIC_timer (unsigned int clocks) { unsigned long lvtt1_value; @@ -1462,14 +1560,14 @@ * chipset timer can cause. */ - } while (delta<1000); + } while (delta<300); } /* * In this function we calibrate APIC bus clocks to the external - * timer here. Unfortunately we cannot use jiffies and - * the timer irq to calibrate, since some later bootup - * code depends on getting the first irq? Ugh. + * timer. Unfortunately we cannot use jiffies and the timer irq + * to calibrate, since some later bootup code depends on getting + * the first irq? Ugh. * * We want to do the calibration only once since we * want to have local timer irqs syncron. CPUs connected @@ -1481,8 +1579,7 @@ int calibrate_APIC_clock (void) { unsigned long long t1,t2; - unsigned long tt1,tt2; - unsigned int prev_count, curr_count; + long tt1,tt2; long calibration_result; printk("calibrating APIC timer ... "); @@ -1518,15 +1615,13 @@ /* * The APIC bus clock counter is 32 bits only, it - * might have overflown: + * might have overflown, but note that we use signed + * longs, thus no extra care needed. + * + * underflown to be exact, as the timer counts down ;) */ - if (tt2pid) { + extern int _stext; + eip -= (unsigned long) &_stext; + eip >>= prof_shift; + if (eip < prof_len) + atomic_inc(&prof_buffer[eip]); + else + /* + * Dont ignore out-of-bounds EIP values silently, + * put them into the last histogram slot, so if + * present, they will show up as a sharp peak. + */ + atomic_inc(&prof_buffer[prof_len-1]); + } +} + /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick @@ -371,6 +394,14 @@ static inline void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { do_timer(regs); +/* + * In the SMP case we use the local APIC timer interrupt to do the + * profiling. + */ +#ifndef __SMP__ + if (!user_mode(regs)) + x86_do_profile(regs->eip); +#endif /* * If we have an externally synchronized Linux clock, then update @@ -495,6 +526,7 @@ } static struct irqaction irq0 = { timer_interrupt, 0, 0, "timer", NULL, NULL}; + void time_init(void) { diff -u --recursive --new-file v2.1.33/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- v2.1.33/linux/arch/i386/mm/init.c Sun Apr 13 10:18:20 1997 +++ linux/arch/i386/mm/init.c Mon Apr 14 09:31:08 1997 @@ -79,10 +79,10 @@ total++; if (PageReserved(mem_map+i)) reserved++; - else if (!mem_map[i].count) + else if (!atomic_read(&mem_map[i].count)) free++; else - shared += mem_map[i].count-1; + shared += atomic_read(&mem_map[i].count) - 1; } printk("%d pages of RAM\n",total); printk("%d free pages\n",free); @@ -259,7 +259,7 @@ datapages++; continue; } - mem_map[MAP_NR(tmp)].count = 1; + atomic_set(&mem_map[MAP_NR(tmp)].count, 1); #ifdef CONFIG_BLK_DEV_INITRD if (!initrd_start || (tmp < initrd_start || tmp >= initrd_end)) @@ -316,9 +316,9 @@ if (PageReserved(mem_map+i)) continue; val->totalram++; - if (!mem_map[i].count) + if (!atomic_read(&mem_map[i].count)) continue; - val->sharedram += mem_map[i].count-1; + val->sharedram += atomic_read(&mem_map[i].count) - 1; } val->totalram <<= PAGE_SHIFT; val->sharedram <<= PAGE_SHIFT; diff -u --recursive --new-file v2.1.33/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c --- v2.1.33/linux/arch/m68k/mm/init.c Sun Jan 26 02:07:05 1997 +++ linux/arch/m68k/mm/init.c Mon Apr 14 09:31:08 1997 @@ -71,12 +71,12 @@ total++; if (PageReserved(mem_map+i)) reserved++; - else if (!mem_map[i].count) + else if (!atomic_read(&mem_map[i].count)) free++; - else if (mem_map[i].count == 1) + else if (atomic_read(&mem_map[i].count) == 1) nonshared++; else - shared += mem_map[i].count-1; + shared += atomic_read(&mem_map[i].count) - 1; } printk("%d pages of RAM\n",total); printk("%d free pages\n",free); @@ -463,7 +463,7 @@ datapages++; continue; } - mem_map[MAP_NR(tmp)].count = 1; + atomic_set(&mem_map[MAP_NR(tmp)].count, 1); #ifdef CONFIG_BLK_DEV_INITRD if (!initrd_start || (tmp < (initrd_start & PAGE_MASK) || tmp >= initrd_end)) @@ -495,9 +495,9 @@ if (PageReserved(mem_map+i)) continue; val->totalram++; - if (!mem_map[i].count) + if (!atomic_read(&mem_map[i].count)) continue; - val->sharedram += mem_map[i].count-1; + val->sharedram += atomic_read(&mem_map[i].count) - 1; } val->totalram <<= PAGE_SHIFT; val->sharedram <<= PAGE_SHIFT; diff -u --recursive --new-file v2.1.33/linux/arch/mips/kernel/irq.c linux/arch/mips/kernel/irq.c --- v2.1.33/linux/arch/mips/kernel/irq.c Thu Feb 29 21:50:38 1996 +++ linux/arch/mips/kernel/irq.c Mon Apr 14 09:31:08 1997 @@ -397,5 +397,5 @@ bh_base[i].data = NULL; } bh_active = 0; - intr_count = 0; + atomic_set(&intr_count, 0); } diff -u --recursive --new-file v2.1.33/linux/arch/mips/mm/init.c linux/arch/mips/mm/init.c --- v2.1.33/linux/arch/mips/mm/init.c Sun Jan 26 02:07:05 1997 +++ linux/arch/mips/mm/init.c Mon Apr 14 09:31:08 1997 @@ -208,10 +208,10 @@ total++; if (mem_map[i].reserved) reserved++; - else if (!mem_map[i].count) + else if (!atomic_read(&mem_map[i].count)) free++; else - shared += mem_map[i].count-1; + shared += atomic_read(&mem_map[i].count) - 1; } printk("%d pages of RAM\n", total); printk("%d free pages\n", free); @@ -268,7 +268,7 @@ datapages++; continue; } - mem_map[MAP_NR(tmp)].count = 1; + atomic_set(&mem_map[MAP_NR(tmp)].count, 1); free_page(tmp); } tmp = nr_free_pages << PAGE_SHIFT; @@ -299,9 +299,9 @@ if (mem_map[i].reserved) continue; val->totalram++; - if (!mem_map[i].count) + if (!atomic_read(&mem_map[i].count)) continue; - val->sharedram += mem_map[i].count-1; + val->sharedram += atomic_read(&mem_map[i].count) - 1; } val->totalram <<= PAGE_SHIFT; val->sharedram <<= PAGE_SHIFT; diff -u --recursive --new-file v2.1.33/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.1.33/linux/arch/ppc/kernel/irq.c Wed Dec 18 00:49:52 1996 +++ linux/arch/ppc/kernel/irq.c Mon Apr 14 09:31:08 1997 @@ -161,7 +161,7 @@ process_IRQ(int irq, int _irq, struct pt_regs *regs) { struct irq_action *action; - intr_count++; + atomic_inc(&intr_count); if (irq < 16) { /* Mask interrupt */ @@ -242,7 +242,7 @@ { BeBox_enable_irq(irq); } - intr_count--; + atomic_dec(&intr_count); } asmlinkage inline void handle_IRQ(struct pt_regs *regs) diff -u --recursive --new-file v2.1.33/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.1.33/linux/arch/ppc/mm/init.c Sun Jan 26 02:07:06 1997 +++ linux/arch/ppc/mm/init.c Mon Apr 14 09:31:08 1997 @@ -72,10 +72,10 @@ total++; if (PageReserved(mem_map+i)) reserved++; - else if (!mem_map[i].count) + else if (!atomic_read(&mem_map[i].count)) free++; else - shared += mem_map[i].count-1; + shared += atomic_read(&mem_map[i].count) - 1; } printk("%lu pages of RAM\n",total); printk("%lu free pages\n",free); @@ -161,7 +161,7 @@ continue; } clear_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags); - mem_map[MAP_NR(tmp)].count = 1; + atomic_set(&mem_map[MAP_NR(tmp)].count, 1); free_page(tmp); } tmp = nr_free_pages << PAGE_SHIFT; @@ -192,9 +192,9 @@ if (PageReserved(mem_map+i)) continue; val->totalram++; - if (!mem_map[i].count) + if (!atomic_read(&mem_map[i].count)) continue; - val->sharedram += mem_map[i].count-1; + val->sharedram += atomic_read(&mem_map[i].count) - 1; } val->totalram <<= PAGE_SHIFT; val->sharedram <<= PAGE_SHIFT; diff -u --recursive --new-file v2.1.33/linux/arch/sparc/Makefile linux/arch/sparc/Makefile --- v2.1.33/linux/arch/sparc/Makefile Mon Apr 7 11:35:29 1997 +++ linux/arch/sparc/Makefile Fri Apr 11 10:47:35 1997 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.26 1997/03/04 16:26:50 jj Exp $ +# $Id: Makefile,v 1.27 1997/04/07 06:54:08 davem Exp $ # sparc/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -33,7 +33,8 @@ ifdef CONFIG_AP1000 SUBDIRS := $(SUBDIRS) arch/sparc/ap1000 mpp -CORE_FILES := $(TOPDIR)/arch/sparc/ap1000/ap1000lib.o $(TOPDIR)/mpp/mpplib.o $(CORE_FILES) +CORE_FILES := $(TOPDIR)/arch/sparc/ap1000/ap1000lib.o \ + $(TOPDIR)/mpp/mpplib.o $(CORE_FILES) DRIVERS := $(DRIVERS) drivers/ap1000/ap1000.a CFLAGS := $(CFLAGS) -D__MPP__=1 endif diff -u --recursive --new-file v2.1.33/linux/arch/sparc/config.in linux/arch/sparc/config.in --- v2.1.33/linux/arch/sparc/config.in Mon Apr 7 11:35:29 1997 +++ linux/arch/sparc/config.in Fri Apr 11 10:47:35 1997 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.33 1997/02/05 14:25:01 tdyas Exp $ +# $Id: config.in,v 1.35 1997/04/07 06:54:09 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # diff -u --recursive --new-file v2.1.33/linux/arch/sparc/defconfig linux/arch/sparc/defconfig --- v2.1.33/linux/arch/sparc/defconfig Mon Apr 7 11:35:29 1997 +++ linux/arch/sparc/defconfig Mon Apr 14 09:31:08 1997 @@ -49,6 +49,7 @@ CONFIG_SUN_OPENPROMIO=m CONFIG_SUN_MOSTEK_RTC=y # CONFIG_SUN_BPP is not set +# CONFIG_SUN_VIDEOPIX is not set # # Linux/SPARC audio subsystem (EXPERIMENTAL) @@ -187,6 +188,9 @@ CONFIG_ROOT_NFS=y CONFIG_RNFS_BOOTP=y CONFIG_RNFS_RARP=y +CONFIG_NFSD=m +CONFIG_SUNRPC=y +CONFIG_LOCKD=y CONFIG_SMB_FS=m CONFIG_SMB_WIN95=y CONFIG_NCP_FS=m @@ -195,6 +199,7 @@ CONFIG_SYSV_FS=m CONFIG_AFFS_FS=m CONFIG_ROMFS_FS=m +CONFIG_AUTOFS_FS=m CONFIG_AMIGA_PARTITION=y CONFIG_UFS_FS=y CONFIG_BSD_DISKLABEL=y diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile --- v2.1.33/linux/arch/sparc/kernel/Makefile Mon Mar 17 14:54:20 1997 +++ linux/arch/sparc/kernel/Makefile Fri Apr 11 10:47:35 1997 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.38 1997/03/04 16:26:29 jj Exp $ +# $Id: Makefile,v 1.39 1997/04/01 02:21:44 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -15,6 +15,7 @@ .S.o: $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o +CHECKASM_CC = $(CC) -D__SMP__ else @@ -24,7 +25,7 @@ .S.o: $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o - +CHECKASM_CC = $(CC) endif all: kernel.o head.o @@ -62,14 +63,14 @@ check_asm: dummy @echo "#include " > tmp.c - $(CC) -E tmp.c -o tmp.i + $(CHECKASM_CC) -E tmp.c -o tmp.i @echo "/* Automatically generated. Do not edit. */" > check_asm.c; echo "#include " >> check_asm.c; echo 'struct task_struct _task; struct mm_struct _mm; struct thread_struct _thread; int main(void) { printf ("/* Automatically generated. Do not edit. */\n#ifndef __ASM_OFFSETS_H__\n#define __ASM_OFFSETS_H__\n\n");' >> check_asm.c $(SH) ./check_asm.sh task tmp.i check_asm.c $(SH) ./check_asm.sh mm tmp.i check_asm.c $(SH) ./check_asm.sh thread tmp.i check_asm.c @echo 'printf ("\n#endif /* __ASM_OFFSETS_H__ */\n"); return 0; }' >> check_asm.c @rm -f tmp.[ci] - $(CC) -o check_asm check_asm.c + $(CHECKASM_CC) -o check_asm check_asm.c ./check_asm > asm_offsets.h @if test -r $(HPATH)/asm/asm_offsets.h; then if cmp -s asm_offsets.h $(HPATH)/asm/asm_offsets.h; then echo $(HPATH)/asm/asm_offsets.h is unchanged; rm -f asm_offsets.h; else mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; fi; else mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; fi @rm -f check_asm check_asm.c diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S --- v2.1.33/linux/arch/sparc/kernel/entry.S Mon Mar 17 14:54:20 1997 +++ linux/arch/sparc/kernel/entry.S Mon Apr 14 09:31:08 1997 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.133 1997/03/04 16:26:22 jj Exp $ +/* $Id: entry.S,v 1.137 1997/04/14 05:38:17 davem Exp $ * arch/sparc/kernel/entry.S: Sparc trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -288,28 +288,11 @@ SAVE_ALL #ifdef __SMP__ - cmp %l7, 13 - bne 1f - nop - - /* This is where we catch the level 13 reschedule soft-IRQ. */ - GET_PROCESSOR_MID(o3, o2) - set C_LABEL(sun4m_interrupts), %l5 - ld [%l5], %o5 - sethi %hi(0x20000000), %o4 - sll %o3, 12, %o3 - add %o5, %o3, %o5 - ld [%o5], %o1 ! read processor irq pending reg - andcc %o1, %o4, %g0 - be 1f + cmp %l7, 12 + bgu maybe_smp_msg nop - - b,a linux_trap_ipi13_sun4m - -1: - #endif - +real_irq_continue: or %l0, PSR_PIL, %g2 wr %g2, 0x0, %psr WRITE_PAUSE @@ -318,10 +301,102 @@ mov %l7, %o0 ! irq level call C_LABEL(handler_irq) add %sp, REGWIN_SZ, %o1 ! pt_regs ptr + +#if 1 /* ndef __SMP__ */ /* You don't want to know... -DaveM */ wr %l0, PSR_ET, %psr WRITE_PAUSE +#endif + + RESTORE_ALL + +#ifdef __SMP__ + /* Here is where we check for possible SMP IPI passed to us + * on some level other than 15 which is the NMI and only used + * for cross calls. That has a seperate entry point below. + */ +maybe_smp_msg: + GET_PROCESSOR_MID(o3, o2) + set C_LABEL(sun4m_interrupts), %l5 + ld [%l5], %o5 + sethi %hi(0x60000000), %o4 + sll %o3, 12, %o3 + ld [%o5 + %o3], %o1 + andcc %o1, %o4, %g0 + be real_irq_continue + cmp %l7, 13 + add %o5, %o3, %o5 + bne,a 1f + sethi %hi(0x40000000), %o2 + sethi %hi(0x20000000), %o2 +1: + st %o2, [%o5 + 0x4] + WRITE_PAUSE + ld [%o5], %g0 + WRITE_PAUSE + or %l0, PSR_PIL, %l4 + wr %l4, 0x0, %psr + WRITE_PAUSE + wr %l4, PSR_ET, %psr + WRITE_PAUSE + cmp %l7, 13 + bne 2f + nop + call C_LABEL(smp_reschedule_irq) + add %o7, 8, %o7 +2: + call C_LABEL(smp_stop_cpu_irq) + nop + RESTORE_ALL + .align 4 + .globl linux_trap_ipi15_sun4m +linux_trap_ipi15_sun4m: + SAVE_ALL + sethi %hi(0x80000000), %o2 + GET_PROCESSOR_MID(o0, o1) + set C_LABEL(sun4m_interrupts), %l5 + ld [%l5], %o5 + sll %o0, 12, %o0 + add %o5, %o0, %o5 + ld [%o5], %o3 + andcc %o3, %o2, %g0 + be 1f ! Must be an NMI async memory error + st %o2, [%o5 + 4] + WRITE_PAUSE + ld [%o5], %g0 + WRITE_PAUSE + or %l0, PSR_PIL, %l4 + wr %l4, 0x0, %psr + WRITE_PAUSE + wr %l4, PSR_ET, %psr + WRITE_PAUSE + call C_LABEL(smp_cross_call_irq) + nop + b ret_trap_lockless_ipi + clr %l6 +1: + /* NMI async memory error handling. */ + sethi %hi(0x80000000), %l4 + sethi %hi(0x4000), %o3 + sub %o5, %o0, %o5 + add %o5, %o3, %l5 + st %l4, [%l5 + 0xc] + WRITE_PAUSE + ld [%l5], %g0 + WRITE_PAUSE + or %l0, PSR_PIL, %l4 + wr %l4, 0x0, %psr + WRITE_PAUSE + wr %l4, PSR_ET, %psr + WRITE_PAUSE + call C_LABEL(sun4m_nmi) + nop + st %l4, [%l5 + 0x8] + WRITE_PAUSE + ld [%l5], %g0 + WRITE_PAUSE RESTORE_ALL +#endif /* __SMP__ */ /* This routine handles illegal instructions and privileged * instruction attempts from user code. @@ -671,107 +746,6 @@ RESTORE_ALL -#ifdef __SMP__ - .align 4 - .globl linux_trap_ipi13_sun4m -linux_trap_ipi13_sun4m: - sethi %hi(0x20000000), %o2 - GET_PROCESSOR_MID(o0, o1) - set C_LABEL(sun4m_interrupts), %l5 - ld [%l5], %o5 - sll %o0, 12, %o0 - add %o5, %o0, %o5 - st %o2, [%o5 + 4] - WRITE_PAUSE - - ld [%o5], %g0 - WRITE_PAUSE - - /* IRQ's off else we deadlock. */ - or %l0, PSR_PIL, %l4 - wr %l4, 0x0, %psr - WRITE_PAUSE - - wr %l4, PSR_ET, %psr - WRITE_PAUSE - - call C_LABEL(smp_reschedule_irq) - nop - - RESTORE_ALL - - .align 4 - .globl linux_trap_ipi15_sun4m -linux_trap_ipi15_sun4m: - SAVE_ALL - - /* First check for hard NMI memory error. */ - sethi %hi(0xf0000000), %o2 - set C_LABEL(sun4m_interrupts), %l5 - set 0x4000, %o3 - ld [%l5], %l5 - add %l5, %o3, %l5 - ld [%l5], %l6 - andcc %o2, %l6, %o2 - be 1f - nop - - /* Asynchronous fault, why you little ?!#&%@... */ - sethi %hi(0x80000000), %o2 - st %o2, [%l5 + 0xc] - WRITE_PAUSE - ld [%l5], %g0 - WRITE_PAUSE - - /* All interrupts are off... now safe to enable traps - * and call C-code. - */ - or %l0, PSR_PIL, %l4 ! I am very paranoid... - wr %l4, 0x0, %psr - WRITE_PAUSE - wr %l4, PSR_ET, %psr - WRITE_PAUSE - call C_LABEL(sun4m_nmi) - nop - - sethi %hi(0x80000000), %o2 - st %o2, [%l5 + 0x8] - WRITE_PAUSE - ld [%l5], %g0 - WRITE_PAUSE - - RESTORE_ALL - -1: - sethi %hi(0x80000000), %o2 - GET_PROCESSOR_MID(o0, o1) - set C_LABEL(sun4m_interrupts), %l5 - ld [%l5], %o5 - sll %o0, 12, %o0 - add %o5, %o0, %o5 - st %o2, [%o5 + 4] - WRITE_PAUSE - - ld [%o5], %g0 - WRITE_PAUSE - - /* IRQ's off else we deadlock. */ - or %l0, PSR_PIL, %l4 - wr %l4, 0x0, %psr - WRITE_PAUSE - - wr %l4, PSR_ET, %psr - WRITE_PAUSE - - call C_LABEL(smp_message_irq) - nop - - b ret_trap_lockless_ipi - clr %l6 - -#endif - - .align 4 .globl C_LABEL(invalid_segment_patch1_ff) .globl C_LABEL(invalid_segment_patch2_ff) @@ -839,7 +813,22 @@ be sun4c_fault_fromuser and %l5, %l4, %l5 - lduba [%l5] ASI_SEGMAP, %l4 + /* Test for NULL pte_t * in vmalloc area. */ + sethi %hi(SUN4C_VMALLOC_START), %l4 + cmp %l5, %l4 + blu,a C_LABEL(invalid_segment_patch1) + lduba [%l5] ASI_SEGMAP, %l4 + + srl %l5, SUN4C_PGDIR_SHIFT, %l6 + sethi %hi(C_LABEL(swapper_pg_dir)), %l4 + or %l4, %lo(C_LABEL(swapper_pg_dir)), %l4 + sll %l6, 2, %l6 + ld [%l4 + %l6], %l4 + andcc %l4, PAGE_MASK, %g0 + + be sun4c_fault_fromuser + lduba [%l5] ASI_SEGMAP, %l4 + C_LABEL(invalid_segment_patch1): cmp %l4, 0x7f bne 1f @@ -1268,11 +1257,9 @@ #ifdef __SMP__ .globl C_LABEL(ret_from_smpfork) C_LABEL(ret_from_smpfork): - mov NO_PROC_ID, %o5 - sethi %hi(C_LABEL(klock_info)), %o4 - or %o4, %lo(C_LABEL(klock_info)), %o4 - stb %o5, [%o4 + 1] - stb %g0, [%o4 + 0] + /* Nowadays all we need to do is drop the scheduler lock. */ + sethi %hi(C_LABEL(scheduler_lock)), %o4 + stb %g0, [%o4 + %lo(C_LABEL(scheduler_lock))] wr %l0, PSR_ET, %psr WRITE_PAUSE b C_LABEL(ret_sys_call) @@ -1605,6 +1592,7 @@ #else GET_PROCESSOR_OFFSET(o4) set C_LABEL(cpu_data), %o3 + sll %o4, 1, %o4 call .umul ld [%o3 + %o4], %o1 #endif diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c --- v2.1.33/linux/arch/sparc/kernel/ioport.c Sat Nov 9 00:11:39 1996 +++ linux/arch/sparc/kernel/ioport.c Fri Apr 11 10:47:35 1997 @@ -1,4 +1,4 @@ -/* $Id: ioport.c,v 1.22 1996/10/11 00:59:46 davem Exp $ +/* $Id: ioport.c,v 1.24 1997/04/10 03:02:32 davem Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -45,8 +45,8 @@ * The virtual address where the mapping actually took place. */ -void *sparc_alloc_io (void *address, void *virtual, int len, char *name, - int bus_type, int rdonly) +void *sparc_alloc_io (u32 address, void *virtual, int len, char *name, + u32 bus_type, int rdonly) { unsigned long vaddr, base_address; unsigned long addr = (unsigned long) address; @@ -110,7 +110,7 @@ * now have to know the peculiarities of where to read the Lance data * from. (for example) */ -void *sparc_dvma_malloc (int len, char *name) +void *_sparc_dvma_malloc (int len, char *name) { unsigned long vaddr, base_address; diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c --- v2.1.33/linux/arch/sparc/kernel/irq.c Sun Jan 26 02:07:06 1997 +++ linux/arch/sparc/kernel/irq.c Mon Apr 14 09:31:09 1997 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.59 1997/01/06 06:52:21 davem Exp $ +/* $Id: irq.c,v 1.66 1997/04/14 05:38:21 davem Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device @@ -37,6 +37,9 @@ #include #include #include +#include +#include +#include /* * Dave Redman (djhr@tadpole.co.uk) @@ -66,6 +69,8 @@ void (*enable_irq)(unsigned int) = (void (*)(unsigned int)) irq_panic; void (*disable_irq)(unsigned int) = (void (*)(unsigned int)) irq_panic; +void (*enable_pil_irq)(unsigned int) = (void (*)(unsigned int)) irq_panic; +void (*disable_pil_irq)(unsigned int) = (void (*)(unsigned int)) irq_panic; void (*clear_clock_irq)( void ) = irq_panic; void (*clear_profile_irq)( void ) = irq_panic; void (*load_profile_irq)( unsigned int ) = (void (*)(unsigned int)) irq_panic; @@ -178,6 +183,201 @@ restore_flags(flags); } +/* Per-processor IRQ locking depth, both SMP and non-SMP code use this. */ +unsigned int local_irq_count[NR_CPUS]; +atomic_t __sparc_bh_counter; + +#ifdef __SMP__ +/* SMP interrupt locking on Sparc. */ + +/* Who has global_irq_lock. */ +unsigned char global_irq_holder = NO_PROC_ID; + +/* This protects IRQ's. */ +spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; + +/* This protects BH software state (masks, things like that). */ +spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED; + +/* Global IRQ locking depth. */ +atomic_t global_irq_count = ATOMIC_INIT; + +#define irq_active(cpu) \ + (atomic_read(&global_irq_count) != local_irq_count[cpu]) + +static unsigned long previous_irqholder; + +#define INIT_STUCK 10000000 + +#define STUCK \ +if (!--stuck) { \ + printk("wait_on_irq CPU#%d stuck at %08lx, waiting for [%08lx:%x] " \ + "(local=[%d(%x:%x:%x:%x)], global=[%d:%x]) ", \ + cpu, where, previous_irqholder, global_irq_holder, \ + local_count, local_irq_count[0], local_irq_count[1], \ + local_irq_count[2], local_irq_count[3], \ + atomic_read(&global_irq_count), global_irq_lock); \ + printk("g[%d:%x]\n", atomic_read(&global_irq_count), global_irq_lock); \ + stuck = INIT_STUCK; \ +} + +static inline void wait_on_irq(int cpu, unsigned long where) +{ + int stuck = INIT_STUCK; + int local_count = local_irq_count[cpu]; + + while(local_count != atomic_read(&global_irq_count)) { + atomic_sub(local_count, &global_irq_count); + spin_unlock(&global_irq_lock); + while(1) { + STUCK; + if(atomic_read(&global_irq_count)) + continue; + if(global_irq_lock) + continue; + if(spin_trylock(&global_irq_lock)) + break; + } + atomic_add(local_count, &global_irq_count); + } +} + +/* There has to be a better way. */ +void synchronize_irq(void) +{ + int cpu = smp_processor_id(); + int local_count = local_irq_count[cpu]; + + if(local_count != atomic_read(&global_irq_count)) { + unsigned long flags; + + /* See comment below at __global_save_flags to understand + * why we must do it this way on Sparc. + */ + save_and_cli(flags); + restore_flags(flags); + } +} + +#undef INIT_STUCK +#define INIT_STUCK 10000000 + +#undef STUCK +#define STUCK \ +if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;} + +static inline void get_irqlock(int cpu, unsigned long where) +{ + int stuck = INIT_STUCK; + + if(!spin_trylock(&global_irq_lock)) { + if((unsigned char) cpu == global_irq_holder) + return; + do { + do { + STUCK; + barrier(); + } while(global_irq_lock); + } while(!spin_trylock(&global_irq_lock)); + } + wait_on_irq(cpu, where); + global_irq_holder = cpu; + previous_irqholder = where; +} + +void __global_cli(void) +{ + int cpu = smp_processor_id(); + unsigned long where; + + __asm__ __volatile__("mov %%i7, %0\n\t" : "=r" (where)); + __cli(); + get_irqlock(cpu, where); +} + +void __global_sti(void) +{ + release_irqlock(smp_processor_id()); + __sti(); +} + +/* Yes, I know this is broken, but for the time being... + * + * On Sparc we must differentiate between real local processor + * interrupts being disabled and global interrupt locking, this + * is so that interrupt handlers which call this stuff don't get + * interrupts turned back on when restore_flags() runs because + * our current drivers will be very surprised about this, yes I + * know they need to be fixed... -DaveM + */ +unsigned long __global_save_flags(void) +{ + unsigned long flags, retval = 0; + + __save_flags(flags); + if(global_irq_holder == (unsigned char) smp_processor_id()) + retval |= 1; + if(flags & PSR_PIL) + retval |= 2; + return retval; +} + +void __global_restore_flags(unsigned long flags) +{ + if(flags & 1) { + __global_cli(); + } else { + release_irqlock(smp_processor_id()); + + if(flags & 2) + __cli(); + else + __sti(); + } +} + +#undef INIT_STUCK +#define INIT_STUCK 200000000 + +#undef STUCK +#define STUCK \ +if (!--stuck) { \ + printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n", \ + irq, cpu, global_irq_holder); \ + stuck = INIT_STUCK; \ +} + +static void irq_enter(int cpu, int irq) +{ + extern void smp_irq_rotate(int cpu); + int stuck = INIT_STUCK; + + smp_irq_rotate(cpu); + hardirq_enter(cpu); + while(global_irq_lock) { + if((unsigned char) cpu == global_irq_holder) { + printk("YEEEE Local interrupts enabled, global disabled\n"); + break; + } + STUCK; + barrier(); + } +} + +static void irq_exit(int cpu, int irq) +{ + __cli(); + hardirq_exit(cpu); + release_irqlock(cpu); +} + +#else /* !__SMP__ */ + +#define irq_enter(cpu, irq) (local_irq_count[cpu]++) +#define irq_exit(cpu, irq) (local_irq_count[cpu]--) + +#endif /* __SMP__ */ + void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs) { int i; @@ -204,11 +404,11 @@ void handler_irq(int irq, struct pt_regs * regs) { struct irqaction * action; - unsigned int cpu_irq; + unsigned int cpu_irq = irq & NR_IRQS; + int cpu = smp_processor_id(); - lock_kernel(); - intr_count++; - cpu_irq = irq & NR_IRQS; + disable_pil_irq(cpu_irq); + irq_enter(cpu, irq); action = *(cpu_irq + irq_action); kstat.interrupts[cpu_irq]++; do { @@ -217,8 +417,8 @@ action->handler(irq, action->dev_id, regs); action = action->next; } while (action); - intr_count--; - unlock_kernel(); + irq_exit(cpu, irq); + enable_pil_irq(cpu_irq); } #ifdef CONFIG_BLK_DEV_FD @@ -226,11 +426,13 @@ void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs) { - lock_kernel(); - intr_count++; + int cpu = smp_processor_id(); + + disable_pil_irq(irq); + irq_enter(cpu, irq); floppy_interrupt(irq, dev_id, regs); - intr_count--; - unlock_kernel(); + irq_exit(cpu, irq); + disable_pil_irq(irq); } #endif diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/muldiv.c linux/arch/sparc/kernel/muldiv.c --- v2.1.33/linux/arch/sparc/kernel/muldiv.c Fri Dec 13 01:37:30 1996 +++ linux/arch/sparc/kernel/muldiv.c Fri Apr 11 10:47:35 1997 @@ -1,4 +1,4 @@ -/* $Id: muldiv.c,v 1.3 1996/11/26 10:00:28 jj Exp $ +/* $Id: muldiv.c,v 1.4 1997/04/11 00:42:08 davem Exp $ * muldiv.c: Hardware multiply/division illegal instruction trap * for sun4c/sun4 (which do not have those instructions) * @@ -120,7 +120,10 @@ "call .umul\n\t" " mov %1, %%o1\n\t" "mov %%o0, %0\n\t" - "mov %%o1, %1\n\t" : "=r" (rs1), "=r" (rs2) : : "o0", "o1", "o2", "o3", "o4", "o5", "o7"); + "mov %%o1, %1\n\t" + : "=r" (rs1), "=r" (rs2) + : + : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "cc"); #ifdef DEBUG_MULDIV printk ("0x%x%08x\n", rs2, rs1); #endif @@ -138,7 +141,10 @@ "call .mul\n\t" " mov %1, %%o1\n\t" "mov %%o0, %0\n\t" - "mov %%o1, %1\n\t" : "=r" (rs1), "=r" (rs2) : : "o0", "o1", "o2", "o3", "o4", "o5", "o7"); + "mov %%o1, %1\n\t" + : "=r" (rs1), "=r" (rs2) + : + : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "cc"); #ifdef DEBUG_MULDIV printk ("0x%x%08x\n", rs2, rs1); #endif @@ -165,7 +171,11 @@ "call __udivdi3\n\t" " mov %1, %%o3\n\t" "mov %%o1, %0\n\t" - "mov %%o0, %1\n\t" : "=r" (rs1), "=r" (rs2) : "r" (regs->y) : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3"); + "mov %%o0, %1\n\t" + : "=r" (rs1), "=r" (rs2) + : "r" (regs->y) + : "o0", "o1", "o2", "o3", "o4", "o5", "o7", + "g1", "g2", "g3", "cc"); #ifdef DEBUG_MULDIV printk ("0x%x\n", rs1); #endif @@ -190,7 +200,11 @@ "call __divdi3\n\t" " mov %1, %%o3\n\t" "mov %%o1, %0\n\t" - "mov %%o0, %1\n\t" : "=r" (rs1), "=r" (rs2) : "r" (regs->y) : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3"); + "mov %%o0, %1\n\t" + : "=r" (rs1), "=r" (rs2) + : "r" (regs->y) + : "o0", "o1", "o2", "o3", "o4", "o5", "o7", + "g1", "g2", "g3", "cc"); #ifdef DEBUG_MULDIV printk ("0x%x\n", rs1); #endif diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c --- v2.1.33/linux/arch/sparc/kernel/process.c Mon Mar 17 14:54:20 1997 +++ linux/arch/sparc/kernel/process.c Fri Apr 11 10:47:35 1997 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.90 1997/01/31 23:26:16 tdyas Exp $ +/* $Id: process.c,v 1.93 1997/04/11 08:55:40 davem Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -57,6 +57,7 @@ goto out; /* endless idle loop with no priority at all */ + current->priority = -100; current->counter = -100; for (;;) { if (sparc_cpu_model == sun4c) { @@ -99,51 +100,33 @@ #else -/* - * the idle loop on a SparcMultiPenguin... - */ -asmlinkage int sys_idle(void) -{ - int ret = -EPERM; - - lock_kernel(); - if (current->pid != 0) - goto out; - - /* endless idle loop with no priority at all */ - current->counter = -100; - schedule(); - ret = 0; -out: - unlock_kernel(); - return ret; -} - /* This is being executed in task 0 'user space'. */ int cpu_idle(void *unused) { - volatile int *spap = &smp_process_available; - volatile int cval; - + current->priority = -100; while(1) { - if(0==*spap) - continue; - cli(); - /* Acquire exclusive access. */ - while((cval = smp_swap(spap, -1)) == -1) - while(*spap == -1) - ; - if (0==cval) { - /* ho hum, release it. */ - *spap = 0; - sti(); - continue; - } - /* Something interesting happened, whee... */ - *spap = (cval - 1); - sti(); - idle(); + /* + * tq_scheduler currently assumes we're running in a process + * context (ie that we hold the kernel lock..) + */ + if (tq_scheduler) { + lock_kernel(); + run_task_queue(&tq_scheduler); + unlock_kernel(); + } + /* endless idle loop with no priority at all */ + current->counter = -100; + schedule(); } +} + +asmlinkage int sys_idle(void) +{ + if(current->pid != 0) + return -EPERM; + + cpu_idle(NULL); + return 0; } #endif diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c --- v2.1.33/linux/arch/sparc/kernel/ptrace.c Mon Mar 17 14:54:21 1997 +++ linux/arch/sparc/kernel/ptrace.c Fri Apr 11 10:47:35 1997 @@ -592,6 +592,9 @@ unsigned long tmp; int res; + /* XXX Find out what is really going on. */ + flush_cache_all(); + /* Non-word alignment _not_ allowed on Sparc. */ if(addr & (sizeof(unsigned long) - 1)) { pt_error_return(regs, EINVAL); diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/rtrap.S linux/arch/sparc/kernel/rtrap.S --- v2.1.33/linux/arch/sparc/kernel/rtrap.S Mon Mar 17 14:54:21 1997 +++ linux/arch/sparc/kernel/rtrap.S Fri Apr 11 10:47:35 1997 @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.45 1997/03/04 16:26:27 jj Exp $ +/* $Id: rtrap.S,v 1.46 1997/04/01 02:21:48 davem Exp $ * rtrap.S: Return from Sparc trap low-level code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -48,13 +48,8 @@ .globl rtrap_patch3, rtrap_patch4, rtrap_patch5 .globl C_LABEL(ret_trap_lockless_ipi) ret_trap_entry: - sethi %hi(C_LABEL(intr_count)), %g4 - ld [%g4 + %lo(C_LABEL(intr_count))], %g5 - orcc %g5, 0x0, %g0 sethi %hi(C_LABEL(bh_active)), %l3 - bne C_LABEL(ret_trap_lockless_ipi) - sethi %hi(C_LABEL(bh_mask)), %l4 -9: + sethi %hi(C_LABEL(bh_mask)), %l4 ld [%l4 + %lo(C_LABEL(bh_mask))], %g5 ld [%l3 + %lo(C_LABEL(bh_active))], %g4 andcc %g4, %g5, %g0 @@ -62,7 +57,6 @@ nop call C_LABEL(do_bottom_half) nop - b,a 9b C_LABEL(ret_trap_lockless_ipi): andcc %t_psr, PSR_PS, %g0 diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c --- v2.1.33/linux/arch/sparc/kernel/setup.c Thu Mar 27 14:39:59 1997 +++ linux/arch/sparc/kernel/setup.c Fri Apr 11 10:47:35 1997 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.82 1997/03/08 08:27:04 ecd Exp $ +/* $Id: setup.c,v 1.83 1997/04/01 02:21:49 davem Exp $ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -38,6 +39,9 @@ #include #include #include +#include +#include +#include struct screen_info screen_info = { 0, 0, /* orig-x, orig-y */ @@ -75,8 +79,13 @@ void prom_sync_me(void) { unsigned long prom_tbr, flags; + int cpu = smp_processor_id(); - save_and_cli(flags); +#ifdef __SMP__ + global_irq_holder = NO_PROC_ID; + global_irq_lock = global_bh_lock = 0; +#endif + __save_and_cli(flags); __asm__ __volatile__("rd %%tbr, %0\n\t" : "=r" (prom_tbr)); __asm__ __volatile__("wr %0, 0x0, %%tbr\n\t" "nop\n\t" @@ -89,9 +98,9 @@ prom_printf("PROM SYNC COMMAND...\n"); show_free_areas(); if(current->pid != 0) { - sti(); + __sti(); sys_sync(); - cli(); + __cli(); } prom_printf("Returning to prom\n"); @@ -99,7 +108,7 @@ "nop\n\t" "nop\n\t" "nop\n\t" : : "r" (prom_tbr)); - restore_flags(flags); + __restore_flags(flags); return; } diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c --- v2.1.33/linux/arch/sparc/kernel/smp.c Sun Jan 26 02:07:07 1997 +++ linux/arch/sparc/kernel/smp.c Mon Apr 14 09:31:09 1997 @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -18,38 +19,31 @@ #include #include #include +#include +#include +#include + +#define IRQ_RESCHEDULE 13 +#define IRQ_STOP_CPU 14 +#define IRQ_CROSS_CALL 15 extern ctxd_t *srmmu_ctx_table_phys; extern int linux_num_cpus; -struct tlog { - unsigned long pc; - unsigned long psr; -}; - -struct tlog trap_log[4][256]; -unsigned long trap_log_ent[4] = { 0, 0, 0, 0, }; - extern void calibrate_delay(void); -volatile unsigned long stuck_pc = 0; volatile int smp_processors_ready = 0; -int smp_found_config = 0; unsigned long cpu_present_map = 0; int smp_num_cpus = 1; int smp_threads_ready=0; unsigned char mid_xlate[NR_CPUS] = { 0, 0, 0, 0, }; volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; -volatile unsigned long smp_invalidate_needed[NR_CPUS] = { 0, }; volatile unsigned long smp_spinning[NR_CPUS] = { 0, }; +unsigned long smp_proc_in_lock[NR_CPUS] = { 0, }; struct cpuinfo_sparc cpu_data[NR_CPUS]; -unsigned char boot_cpu_id = 0; +static unsigned char boot_cpu_id = 0; static int smp_activated = 0; -static volatile unsigned char smp_cpu_in_msg[NR_CPUS]; -static volatile unsigned long smp_msg_data; -static volatile int smp_src_cpu; -static volatile int smp_msg_id; volatile int cpu_number_map[NR_CPUS]; volatile int cpu_logical_map[NR_CPUS]; @@ -60,7 +54,7 @@ * compared to the Alpha and the intel no? Most Sparcs have 'swap' * instruction which is much better... */ -struct klock_info klock_info = { KLOCK_CLEAR, 0, 0 }; +struct klock_info klock_info = { KLOCK_CLEAR, 0 }; volatile unsigned long ipi_count; #ifdef __SMP_PROF__ @@ -74,7 +68,6 @@ volatile unsigned long smp_idle_map=0; #endif -volatile unsigned long smp_proc_in_lock[NR_CPUS] = {0,}; volatile int smp_process_available=0; /*#define SMP_DEBUG*/ @@ -180,7 +173,7 @@ local_flush_cache_all(); local_flush_tlb_all(); - sti(); + __sti(); } void cpu_panic(void) @@ -200,14 +193,15 @@ { int cpucount = 0; int i = 0; + int first, prev; printk("Entering SMP Mode...\n"); penguin_ctable.which_io = 0; - penguin_ctable.phys_addr = (char *) srmmu_ctx_table_phys; + penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys; penguin_ctable.reg_size = 0; - sti(); + __sti(); cpu_present_map = 0; for(i=0; i < linux_num_cpus; i++) cpu_present_map |= (1<"); -#endif - /* See wait case 3 in smp_message_pass()... */ - smp_cpu_in_msg[me]--; - message_cpu = NO_PROC_ID; - restore_flags(flags); + spin_unlock(&cross_call_lock); + __restore_flags(flags); return; /* made it... */ procs_time_out: printk("smp: Wheee, penguin drops off the bus\n"); - smp_cpu_in_msg[me]--; - message_cpu = NO_PROC_ID; - restore_flags(flags); + spin_unlock(&cross_call_lock); + __restore_flags(flags); return; /* why me... why me... */ } /* Just need to run local copy. */ func(arg1, arg2, arg3, arg4, arg5); - return; - -cross_call_not_master: - printk("Cross call initiated by non master cpu from [%p]\n", - __builtin_return_address(0)); - printk("akp=%x me=%08lx\n", klock_info.akp, me); - restore_flags(flags); - panic("penguin cross call"); } void smp_flush_cache_all(void) @@ -578,171 +486,24 @@ /* Reschedule call back. */ void smp_reschedule_irq(void) { - lock_kernel(); - intr_count++; - if(smp_processor_id() != klock_info.akp) { - panic("SMP Reschedule on CPU #%d, but #%d is active.\n", - smp_processor_id(), klock_info.akp); - } need_resched=1; - intr_count--; - unlock_kernel(); } -#undef DEBUG_CAPTURE - -static struct capture_struct { - int capture_level; - volatile unsigned long processors_in[NR_CPUS]; - volatile unsigned long processors_out[NR_CPUS]; -} cap_info = { 0, }; - -void smp_capture(void) +/* Running cross calls. */ +void smp_cross_call_irq(void) { - unsigned long flags; - int me = smp_processor_id(); - int cpu; - - if(!smp_processors_ready) - return; - - if (me != klock_info.akp) - panic("SMP Capture on CPU #%d, but #%d is active.\n", - me, klock_info.akp); - -#ifdef DEBUG_CAPTURE - printk("C%d(%d)<", smp_processor_id(), cap_info.capture_level); -#endif - save_and_cli(flags); - - if (! cap_info.capture_level++) { - int timeout; - - /* Initialize Capture Info. */ - for (cpu = 0; cpu < smp_num_cpus; cpu++) { - cap_info.processors_in[cpu] = 0; - cap_info.processors_out[cpu] = 0; - } - cap_info.processors_in[me] = 1; - cap_info.processors_out[me] = 1; - - smp_message_pass(MSG_ALL_BUT_SELF, MSG_CAPTURE, 0, 4); - - timeout = CCALL_TIMEOUT; - for (cpu = 0; cpu < smp_num_cpus; cpu++) { - while (!cap_info.processors_in[cpu] && timeout-- > 0) - barrier(); - if (!cap_info.processors_in[cpu]) - goto procs_time_out; -#ifdef DEBUG_CAPTURE - printk("%d", cpu); -#endif - } - } -#ifdef DEBUG_CAPTURE - printk(">"); -#endif - restore_flags(flags); - return; - -procs_time_out: - printk("smp_capture (%d): Wheee, penguin drops off the bus\n", - smp_processor_id()); - printk("smp_capture: map: %ld %ld %ld %ld\n", - cap_info.processors_in[0], cap_info.processors_in[1], - cap_info.processors_in[2], cap_info.processors_in[3]); - smp_cpu_in_msg[me]--; - message_cpu = NO_PROC_ID; - restore_flags(flags); -} - -void smp_release(void) -{ - unsigned long flags; - int me = smp_processor_id(); - int cpu; - - if(!smp_processors_ready) - return; -#ifdef DEBUG_CAPTURE - printk("R%d(%d)<", smp_processor_id(), cap_info.capture_level); -#endif - - if (me != klock_info.akp) - panic("SMP Release on CPU #%d, but #%d is active.\n", - me, klock_info.akp); - - save_and_cli(flags); - - if (! --cap_info.capture_level) { - int timeout; - - for (cpu = 0; cpu < smp_num_cpus; cpu++) - cap_info.processors_in[cpu] = 0; - - timeout = CCALL_TIMEOUT; - for (cpu = 0; cpu < smp_num_cpus; cpu++) { - while (!cap_info.processors_out[cpu] && timeout-- > 0) - barrier(); - if (!cap_info.processors_out[cpu]) - goto procs_time_out; -#ifdef DEBUG_CAPTURE - printk("%d", cpu); -#endif - } - - /* See wait case 4 in smp_message_pass()... */ - smp_cpu_in_msg[me]--; - } -#ifdef DEBUG_CAPTURE - printk(">"); -#endif - restore_flags(flags); - return; + int i = smp_processor_id(); -procs_time_out: - printk("smp_release (%d): Wheee, penguin drops off the bus\n", - smp_processor_id()); - printk("smp_release: map: %ld %ld %ld %ld\n", - cap_info.processors_out[0], cap_info.processors_out[1], - cap_info.processors_out[2], cap_info.processors_out[3]); - smp_cpu_in_msg[me]--; - restore_flags(flags); + ccall_info.processors_in[i] = 1; + ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3, + ccall_info.arg4, ccall_info.arg5); + ccall_info.processors_out[i] = 1; } -/* Message call back. */ -void smp_message_irq(void) +/* Stopping processors. */ +void smp_stop_cpu_irq(void) { - int i=smp_processor_id(); - - switch(smp_msg_id) { - case MSG_CROSS_CALL: - /* Do it to it. */ - ccall_info.processors_in[i] = 1; - ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3, - ccall_info.arg4, ccall_info.arg5); - ccall_info.processors_out[i] = 1; - break; - - case MSG_CAPTURE: - flush_user_windows(); - cap_info.processors_in[i] = 1; - while (cap_info.processors_in[i]) - barrier(); - cap_info.processors_out[i] = 1; - break; - - /* - * Halt other CPU's for a panic or reboot - */ - case MSG_STOP_CPU: - sti(); - while(1) - barrier(); - - default: - printk("CPU #%d sent invalid cross CPU message to CPU #%d: %X(%lX).\n", - smp_src_cpu,smp_processor_id(),smp_msg_id,smp_msg_data); - break; - } + __sti(); + while(1) + barrier(); } diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c --- v2.1.33/linux/arch/sparc/kernel/sparc_ksyms.c Thu Mar 27 14:39:59 1997 +++ linux/arch/sparc/kernel/sparc_ksyms.c Mon Apr 14 09:31:09 1997 @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.49 1997/03/15 07:47:45 davem Exp $ +/* $Id: sparc_ksyms.c,v 1.54 1997/04/14 05:38:25 davem Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -26,6 +27,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -82,6 +86,8 @@ #endif EXPORT_SYMBOL_PRIVATE(_lock_kernel); EXPORT_SYMBOL_PRIVATE(_unlock_kernel); +EXPORT_SYMBOL_PRIVATE(_spinlock_waitfor); +EXPORT_SYMBOL(__sparc_bh_counter); EXPORT_SYMBOL(page_offset); EXPORT_SYMBOL(stack_top); @@ -97,6 +103,20 @@ EXPORT_SYMBOL_PRIVATE(_set_le_bit); EXPORT_SYMBOL_PRIVATE(_clear_le_bit); +/* IRQ implementation. */ +EXPORT_SYMBOL(local_irq_count); +#ifdef __SMP__ +EXPORT_SYMBOL(global_irq_holder); +EXPORT_SYMBOL(global_irq_lock); +EXPORT_SYMBOL(global_bh_lock); +EXPORT_SYMBOL(global_irq_count); +EXPORT_SYMBOL(__global_cli); +EXPORT_SYMBOL(__global_sti); +EXPORT_SYMBOL(__global_save_flags); +EXPORT_SYMBOL(__global_restore_flags); +EXPORT_SYMBOL(synchronize_irq); +#endif + EXPORT_SYMBOL(udelay); EXPORT_SYMBOL(mstk48t02_regs); #if CONFIG_SUN_AUXIO @@ -113,7 +133,7 @@ EXPORT_SYMBOL(mmu_get_scsi_one); EXPORT_SYMBOL(mmu_release_scsi_sgl); EXPORT_SYMBOL(mmu_release_scsi_one); -EXPORT_SYMBOL(sparc_dvma_malloc); +EXPORT_SYMBOL(_sparc_dvma_malloc); EXPORT_SYMBOL(sun4c_unmapioaddr); EXPORT_SYMBOL(srmmu_unmapioaddr); #if CONFIG_SBUS diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/sun4c_irq.c linux/arch/sparc/kernel/sun4c_irq.c --- v2.1.33/linux/arch/sparc/kernel/sun4c_irq.c Fri Dec 13 01:37:31 1996 +++ linux/arch/sparc/kernel/sun4c_irq.c Mon Apr 14 09:31:09 1997 @@ -128,7 +128,7 @@ /* Map the Timer chip, this is implemented in hardware inside * the cache chip on the sun4c. */ - sun4c_timers = sparc_alloc_io ((void *) SUN4C_TIMER_PHYSADDR, 0, + sun4c_timers = sparc_alloc_io (SUN4C_TIMER_PHYSADDR, 0, sizeof(struct sun4c_timer_info), "timer", 0x0, 0x0); @@ -174,6 +174,8 @@ int_regs[0].which_io, 0x0); enable_irq = sun4c_enable_irq; disable_irq = sun4c_disable_irq; + enable_pil_irq = sun4c_enable_irq; + disable_pil_irq = sun4c_disable_irq; clear_clock_irq = sun4c_clear_clock_irq; clear_profile_irq = sun4c_clear_profile_irq; load_profile_irq = sun4c_load_profile_irq; @@ -184,5 +186,5 @@ set_irq_udt = (void (*) (int))sun4c_nop; #endif *interrupt_enable = (SUN4C_INT_ENABLE); - sti(); + /* Cannot enable interrupts until OBP ticker is disabled. */ } diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/sun4m_irq.c linux/arch/sparc/kernel/sun4m_irq.c --- v2.1.33/linux/arch/sparc/kernel/sun4m_irq.c Sun Jan 26 02:07:08 1997 +++ linux/arch/sparc/kernel/sun4m_irq.c Mon Apr 14 09:31:09 1997 @@ -130,6 +130,38 @@ } } +static unsigned long cpu_pil_to_imask[16] = { +/*0*/ 0x00000000, +/*1*/ 0x00000000, +/*2*/ SUN4M_INT_SBUS(0) | SUN4M_INT_VME(0), +/*3*/ SUN4M_INT_SBUS(1) | SUN4M_INT_VME(1), +/*4*/ SUN4M_INT_SCSI, +/*5*/ SUN4M_INT_SBUS(2) | SUN4M_INT_VME(2), +/*6*/ SUN4M_INT_ETHERNET, +/*7*/ SUN4M_INT_SBUS(3) | SUN4M_INT_VME(3), +/*8*/ SUN4M_INT_VIDEO, +/*9*/ SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR, +/*10*/ SUN4M_INT_REALTIME, +/*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY, +/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS, +/*13*/ SUN4M_INT_AUDIO, +/*14*/ 0x00000000, +/*15*/ 0x00000000 +}; + +/* We assume the caller is local cli()'d when these are called, or else + * very bizarre behavior will result. + */ +static void sun4m_disable_pil_irq(unsigned int pil) +{ + sun4m_interrupts->set = cpu_pil_to_imask[pil]; +} + +static void sun4m_enable_pil_irq(unsigned int pil) +{ + sun4m_interrupts->clear = cpu_pil_to_imask[pil]; +} + void sun4m_send_ipi(int cpu, int level) { unsigned long mask; @@ -272,7 +304,7 @@ struct linux_prom_registers int_regs[PROMREG_MAX]; int num_regs; - cli(); + __cli(); if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 || (ie_node = prom_getchild (ie_node)) == 0 || (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) { @@ -327,6 +359,8 @@ } enable_irq = sun4m_enable_irq; disable_irq = sun4m_disable_irq; + enable_pil_irq = sun4m_enable_pil_irq; + disable_pil_irq = sun4m_disable_pil_irq; clear_clock_irq = sun4m_clear_clock_irq; clear_profile_irq = sun4m_clear_profile_irq; load_profile_irq = sun4m_load_profile_irq; @@ -336,5 +370,5 @@ clear_cpu_int = (void (*) (int, int))sun4m_clear_ipi; set_irq_udt = (void (*) (int))sun4m_set_udt; #endif - sti(); + /* Cannot enable interrupts until OBP ticker is disabled. */ } diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/time.c linux/arch/sparc/kernel/time.c --- v2.1.33/linux/arch/sparc/kernel/time.c Sun Jan 26 02:07:08 1997 +++ linux/arch/sparc/kernel/time.c Mon Apr 14 09:31:09 1997 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.23 1997/01/26 04:28:34 davem Exp $ +/* $Id: time.c,v 1.27 1997/04/14 05:38:31 davem Exp $ * linux/arch/sparc/kernel/time.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -54,6 +54,11 @@ last_rtc_update = xtime.tv_sec; else last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ + +#ifdef __SMP__ + /* I really think it should not be done this way... -DaveM */ + smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); +#endif } /* Converts Gregorian date to seconds since 1970-01-01 00:00:00. @@ -198,7 +203,7 @@ prom_apply_obio_ranges(clk_reg, 1); /* Map the clock register io area read-only */ mstk48t02_regs = (struct mostek48t02 *) - sparc_alloc_io((void *) clk_reg[0].phys_addr, + sparc_alloc_io(clk_reg[0].phys_addr, (void *) 0, sizeof(*mstk48t02_regs), "clock", clk_reg[0].which_io, 0x0); mstk48t08_regs = 0; /* To catch weirdness */ @@ -215,7 +220,7 @@ prom_apply_obio_ranges(clk_reg, 1); /* Map the clock register io area read-only */ mstk48t08_regs = (struct mostek48t08 *) - sparc_alloc_io((void *) clk_reg[0].phys_addr, + sparc_alloc_io(clk_reg[0].phys_addr, (void *) 0, sizeof(*mstk48t08_regs), "clock", clk_reg[0].which_io, 0x0); @@ -265,7 +270,9 @@ xtime.tv_sec = mktime(year, mon, day, hour, min, sec); xtime.tv_usec = 0; mregs->creg &= ~MSTK_CREG_READ; - return; + + /* Now that OBP ticker has been silenced, it is safe to enable IRQ. */ + __sti(); } static __inline__ unsigned long do_gettimeoffset(void) @@ -283,21 +290,49 @@ void do_gettimeofday(struct timeval *tv) { +#if CONFIG_AP1000 unsigned long flags; save_and_cli(flags); -#if CONFIG_AP1000 ap_gettimeofday(&xtime); -#endif *tv = xtime; -#if !CONFIG_AP1000 - tv->tv_usec += do_gettimeoffset(); - if(tv->tv_usec >= 1000000) { - tv->tv_usec -= 1000000; - tv->tv_sec++; - } -#endif restore_flags(flags); +#else /* !(CONFIG_AP1000) */ + /* Load doubles must be used on xtime so that what we get + * is guarenteed to be atomic, this is why we can run this + * with interrupts on full blast. Don't touch this... -DaveM + */ + __asm__ __volatile__(" + sethi %hi(master_l10_counter), %o1 + ld [%o1 + %lo(master_l10_counter)], %g3 + sethi %hi(xtime), %g2 +1: ldd [%g2 + %lo(xtime)], %o4 + ld [%g3], %o1 + ldd [%g2 + %lo(xtime)], %o2 + xor %o4, %o2, %o2 + xor %o5, %o3, %o3 + orcc %o2, %o3, %g0 + bne 1b + subcc %o1, 0x0, %g0 + bpos 1f + srl %o1, 0xa, %o1 + sethi %hi(0x2710), %o3 + or %o3, %lo(0x2710), %o3 + sethi %hi(0x1fffff), %o2 + or %o2, %lo(0x1fffff), %o2 + add %o5, %o3, %o5 + and %o1, %o2, %o1 +1: add %o5, %o1, %o5 + sethi %hi(1000000), %o2 + or %o2, %lo(1000000), %o2 + cmp %o5, %o2 + bl,a 1f + st %o4, [%o0 + 0x0] + add %o4, 0x1, %o4 + sub %o5, %o2, %o5 + st %o4, [%o0 + 0x0] +1: st %o5, [%o0 + 0x4]"); +#endif } void do_settimeofday(struct timeval *tv) diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/trampoline.S linux/arch/sparc/kernel/trampoline.S --- v2.1.33/linux/arch/sparc/kernel/trampoline.S Sat Nov 9 00:11:52 1996 +++ linux/arch/sparc/kernel/trampoline.S Mon Apr 14 09:31:09 1997 @@ -1,5 +1,5 @@ -/* $Id: trampoline.S,v 1.5 1996/09/22 06:43:10 davem Exp $ - * mp.S: Multiprocessor low-level routines on the Sparc. +/* $Id: trampoline.S,v 1.6 1997/04/14 05:38:33 davem Exp $ + * trampoline.S: SMP cpu boot-up trampoline code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/unaligned.c linux/arch/sparc/kernel/unaligned.c --- v2.1.33/linux/arch/sparc/kernel/unaligned.c Thu Mar 27 14:39:59 1997 +++ linux/arch/sparc/kernel/unaligned.c Fri Apr 11 10:47:35 1997 @@ -1,4 +1,4 @@ -/* $Id: unaligned.c,v 1.16 1997/03/18 17:53:44 jj Exp $ +/* $Id: unaligned.c,v 1.17 1997/04/11 00:42:08 davem Exp $ * unaligned.c: Unaligned load/store trap handling with special * cases for the kernel to do them more quickly. * @@ -204,7 +204,7 @@ ".word 16b, " #errh "\n\n\t" \ ".previous\n\t" \ : : "r" (dest_reg), "r" (size), "r" (saddr), "r" (is_signed) \ - : "l1", "l2", "g7", "g1"); \ + : "l1", "l2", "g7", "g1", "cc"); \ }) #define store_common(dst_addr, size, src_val, errh) ({ \ @@ -258,7 +258,7 @@ ".word 17b, " #errh "\n\n\t" \ ".previous\n\t" \ : : "r" (dst_addr), "r" (size), "r" (src_val) \ - : "l1", "l2", "g7", "g1"); \ + : "l1", "l2", "g7", "g1", "cc"); \ }) #define do_integer_store(reg_num, size, dst_addr, regs, errh) ({ \ @@ -343,8 +343,10 @@ "mov %0, %%o0\n\t" "call kernel_mna_trap_fault\n\t" " mov %1, %%o1\n\t" - : : "r" (regs), "r" (insn) - : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7"); + : + : "r" (regs), "r" (insn) + : "o0", "o1", "o2", "o3", "o4", "o5", "o7", + "g1", "g2", "g3", "g4", "g5", "g7", "cc"); } else { unsigned long addr = compute_effective_address(regs, insn); @@ -476,8 +478,10 @@ "mov %0, %%o0\n\t" "call user_mna_trap_fault\n\t" " mov %1, %%o1\n\t" - : : "r" (regs), "r" (insn) - : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7"); + : + : "r" (regs), "r" (insn) + : "o0", "o1", "o2", "o3", "o4", "o5", "o7", + "g1", "g2", "g3", "g4", "g5", "g7", "cc"); goto out; } advance(regs); diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/windows.c linux/arch/sparc/kernel/windows.c --- v2.1.33/linux/arch/sparc/kernel/windows.c Sun Jan 26 02:07:09 1997 +++ linux/arch/sparc/kernel/windows.c Fri Apr 11 10:47:35 1997 @@ -33,7 +33,7 @@ : "=&r" (ctr) : "0" (ctr), "i" ((const unsigned long)(&(((struct task_struct *)0)->tss.uwinmask))) - : "g4"); + : "g4", "cc"); } static inline void shift_window_buffer(int first_win, int last_win, struct thread_struct *tp) diff -u --recursive --new-file v2.1.33/linux/arch/sparc/lib/atomic.S linux/arch/sparc/lib/atomic.S --- v2.1.33/linux/arch/sparc/lib/atomic.S Sun Jan 26 02:07:09 1997 +++ linux/arch/sparc/lib/atomic.S Mon Apr 14 09:31:09 1997 @@ -10,10 +10,6 @@ .text .align 4 - /* XXX At boot time patch this with swap [x], y; retl; if - * XXX processor is found to have that instruction. - */ - .globl ___xchg32 ___xchg32: rd %psr, %g3 @@ -34,51 +30,47 @@ jmpl %o7, %g0 /* Note, not + 0x8, see call in system.h */ mov %g4, %o7 - .globl ___xchg32_hw -___xchg32_hw: - swap [%g1], %g2 - jmpl %o7, %g0 /* Note, not + 0x8, see call in system.h */ - mov %g4, %o7 - - /* Atomic add/sub routines. Returns the final value whether you - * want it or not for even _better_ cache hit rates. + /* Read asm-sparc/atomic.h carefully to understand how this works for SMP. + * Really, some things here for SMP are overly clever, go read the header. */ .globl ___atomic_add ___atomic_add: - rd %psr, %g3 - andcc %g3, PSR_PIL, %g0 - bne 1f - nop - wr %g3, PSR_PIL, %psr - nop; nop; nop; -1: - ld [%g1], %g7 - andcc %g3, PSR_PIL, %g0 - add %g7, %g2, %g2 - bne 1f - st %g2, [%g1] - wr %g3, 0x0, %psr - nop; nop; nop; -1: - jmpl %o7, %g0 /* NOTE: not + 8, see callers in atomic.h */ - mov %g4, %o7 + rd %psr, %g3 ! Keep the code small, old way was stupid + or %g3, PSR_PIL, %g7 ! Disable interrupts + wr %g7, 0x0, %psr ! Set %psr + nop; nop; nop; ! Let the bits set +#ifdef __SMP__ +1: ldstub [%g1 + 3], %g7 ! Spin on the byte lock for SMP. + orcc %g7, 0x0, %g0 ! Did we get it? + bne 1b ! Nope... +#endif + ld [%g1], %g7 ! Load locked atomic_t + sra %g7, 8, %g7 ! Get signed 24-bit integer + add %g7, %g2, %g2 ! Add in argument + sll %g2, 8, %g7 ! Transpose back to atomic_t + st %g7, [%g1] ! Clever: This releases the lock as well. + wr %g3, 0x0, %psr ! Restore original PSR_PIL + nop; nop; nop; ! Let the bits set + jmpl %o7, %g0 ! NOTE: not + 8, see callers in atomic.h + mov %g4, %o7 ! Restore %o7 .globl ___atomic_sub ___atomic_sub: - rd %psr, %g3 - andcc %g3, PSR_PIL, %g0 - bne 1f - nop - wr %g3, PSR_PIL, %psr - nop; nop; nop; -1: - ld [%g1], %g7 - andcc %g3, PSR_PIL, %g0 - sub %g7, %g2, %g2 - bne 1f - st %g2, [%g1] - wr %g3, 0x0, %psr - nop; nop; nop; -1: - jmpl %o7, %g0 /* NOTE: not + 8, see callers in atomic.h */ - mov %g4, %o7 + rd %psr, %g3 ! Keep the code small, old way was stupid + or %g3, PSR_PIL, %g7 ! Disable interrupts + wr %g7, 0x0, %psr ! Set %psr + nop; nop; nop; ! Let the bits set +#ifdef __SMP__ +1: ldstub [%g1 + 3], %g7 ! Spin on the byte lock for SMP. + orcc %g7, 0x0, %g0 ! Did we get it? + bne 1b ! Nope... +#endif + ld [%g1], %g7 ! Load locked atomic_t + sra %g7, 8, %g7 ! Get signed 24-bit integer + sub %g7, %g2, %g2 ! Subtract argument + sll %g2, 8, %g7 ! Transpose back to atomic_t + st %g7, [%g1] ! Clever: This releases the lock as well + wr %g3, 0x0, %psr ! Restore original PSR_PIL + nop; nop; nop; ! Let the bits set + jmpl %o7, %g0 ! NOTE: not + 8, see callers in atomic.h + mov %g4, %o7 ! Restore %o7 diff -u --recursive --new-file v2.1.33/linux/arch/sparc/lib/locks.S linux/arch/sparc/lib/locks.S --- v2.1.33/linux/arch/sparc/lib/locks.S Mon Mar 17 14:54:22 1997 +++ linux/arch/sparc/lib/locks.S Mon Apr 14 09:31:09 1997 @@ -1,4 +1,4 @@ -/* $Id: locks.S,v 1.4 1997/03/04 16:26:41 jj Exp $ +/* $Id: locks.S,v 1.9 1997/04/14 05:38:41 davem Exp $ * locks.S: SMP low-level lock primitives on Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -7,6 +7,7 @@ #include #include #include +#include .text .align 4 @@ -24,38 +25,15 @@ .globl ___spinlock_waitfor ___spinlock_waitfor: 1: orcc %g2, 0x0, %g0 - bne 1b + bne,a 1b ldub [%g1], %g2 ldstub [%g1], %g2 jmpl %o7 - 12, %g0 mov %g4, %o7 - /* This is called when the kernel master lock holder changes, - * caller's PC is in %o7, %o7 must be restored to the value - * in %g4 when returning. The interrupt receiver cpu is to - * change to the new kernel lock holder before returning. - * The current implementation assumes that irq_rcvreg is a - * pointer to a word sized register which can be written with - * the MID value of the cpu to receive undirected interrupts. - * CPUID is in %g5, and mid_xlate is a byte table which translates - * CPUID values into the corresponding MID. - */ - .globl ___become_idt -___become_idt: -#ifdef __SMP__ - sethi %hi(C_LABEL(mid_xlate)), %g2 - or %g2, %lo(C_LABEL(mid_xlate)), %g2 - ldub [%g5 + %g2], %g7 - sethi %hi(C_LABEL(irq_rcvreg)), %g2 - ld [%g2 + %lo(C_LABEL(irq_rcvreg))], %g2 - st %g7, [%g2] -#endif - jmpl %o7 + 8, %g0 - mov %g4, %o7 - ___lk_busy_spin: orcc %g2, 0, %g0 - bne ___lk_busy_spin + bne,a ___lk_busy_spin ldub [%g1 + 0], %g2 b 1f ldstub [%g1 + 0], %g2 @@ -73,23 +51,34 @@ 1: orcc %g2, 0, %g0 bne,a ___lk_busy_spin ldub [%g1 + 0], %g2 - ldub [%g1 + 2], %g2 - cmp %g2, %g5 - be 2f - stb %g5, [%g1 + 1] - stb %g5, [%g1 + 2] -#ifdef __SMP__ - set C_LABEL(mid_xlate), %g2 - ldub [%g2 + %g5], %g7 - sethi %hi(C_LABEL(irq_rcvreg)), %g2 - ld [%g2 + %lo(C_LABEL(irq_rcvreg))], %g2 - st %g7, [%g2] -#endif -2: mov -1, %g2 + stb %g5, [%g1 + 1] + mov -1, %g2 st %g2, [%g6 + AOFF_task_lock_depth] wr %g3, 0x0, %psr nop; nop; nop 9: jmpl %o7 + 0x8, %g0 + mov %g4, %o7 + + .globl ___lock_reaquire_kernel +___lock_reaquire_kernel: + rd %psr, %g3 + or %g3, PSR_PIL, %g7 + wr %g7, 0x0, %psr + nop; nop; nop + st %g2, [%g6 + AOFF_task_lock_depth] + ldstub [%g1 + 0], %g2 +1: orcc %g2, 0, %g0 + be 3f + ldub [%g1 + 0], %g2 +2: orcc %g2, 0, %g0 + bne,a 2b + ldub [%g1 + 0], %g2 + b 1b + ldstub [%g1 + 0], %g2 +3: stb %g5, [%g1 + 1] + wr %g3, 0x0, %psr + nop; nop; nop + jmpl %o7 + 0x8, %g0 mov %g4, %o7 #undef NO_PROC_ID diff -u --recursive --new-file v2.1.33/linux/arch/sparc/mm/hypersparc.S linux/arch/sparc/mm/hypersparc.S --- v2.1.33/linux/arch/sparc/mm/hypersparc.S Thu Mar 27 14:40:00 1997 +++ linux/arch/sparc/mm/hypersparc.S Mon Apr 14 09:31:09 1997 @@ -1,4 +1,4 @@ -/* $Id: hypersparc.S,v 1.1 1997/03/10 09:16:52 davem Exp $ +/* $Id: hypersparc.S,v 1.3 1997/04/13 06:38:13 davem Exp $ * hypersparc.S: High speed Hypersparc mmu/cache operations. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -31,7 +31,6 @@ .globl hypersparc_flush_tlb_all, hypersparc_flush_tlb_mm .globl hypersparc_flush_tlb_range, hypersparc_flush_tlb_page - /* Verified... */ hypersparc_flush_cache_all: WINDOW_FLUSH(%g4, %g5) sethi %hi(vac_cache_size), %g4 @@ -46,7 +45,6 @@ sta %g0, [%g0] ASI_M_FLUSH_IWHOLE ! hyper_flush_whole_icache /* We expand the window flush to get maximum performance. */ - /* Verified... */ hypersparc_flush_cache_mm: #ifndef __SMP__ ld [%o0 + AOFF_mm_context], %g1 @@ -84,7 +82,6 @@ sta %g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE ! hyper_flush_whole_icache /* The things we do for performance... */ - /* Verified... */ hypersparc_flush_cache_range: #ifndef __SMP__ ld [%o0 + AOFF_mm_context], %g1 @@ -174,12 +171,12 @@ /* HyperSparc requires a valid mapping where we are about to flush * in order to check for a physical tag match during the flush. */ - /* Verified... */ + /* Verified, my ass... */ hypersparc_flush_cache_page: ld [%o0 + 0x0], %o0 /* XXX vma->vm_mm, GROSS XXX */ + ld [%o0 + AOFF_mm_context], %g2 #ifndef __SMP__ - ld [%o0 + AOFF_mm_context], %g1 - cmp %g1, -1 + cmp %g2, -1 be hypersparc_flush_cache_page_out #endif WINDOW_FLUSH(%g4, %g5) @@ -189,7 +186,7 @@ mov SRMMU_CTX_REG, %o3 andn %o1, (PAGE_SIZE - 1), %o1 lda [%o3] ASI_M_MMUREGS, %o2 - sta %g1, [%o3] ASI_M_MMUREGS + sta %g2, [%o3] ASI_M_MMUREGS or %o1, 0x400, %o5 lda [%o5] ASI_M_FLUSH_PROBE, %g1 orcc %g0, %g1, %g0 @@ -223,12 +220,15 @@ lda [%g7] ASI_M_MMUREGS, %g0 sta %o2, [%g4] ASI_M_MMUREGS hypersparc_flush_cache_page_out: -hypersparc_flush_sig_insns: /* This is "neat"... */ retl sta %g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE +hypersparc_flush_sig_insns: + flush %o2 + retl + flush %o2 + 4 + /* HyperSparc is copy-back. */ - /* Verified... */ hypersparc_flush_page_to_ram: hypersparc_flush_chunk: sethi %hi(vac_line_size), %g1 @@ -271,13 +271,11 @@ retl nop - /* Verified... */ hypersparc_flush_tlb_all: mov 0x400, %g1 retl sta %g0, [%g1] ASI_M_FLUSH_PROBE - /* Verified... */ hypersparc_flush_tlb_mm: mov SRMMU_CTX_REG, %g1 ld [%o0 + AOFF_mm_context], %o1 @@ -293,7 +291,6 @@ retl sta %g5, [%g1] ASI_M_MMUREGS - /* Verified... */ hypersparc_flush_tlb_range: mov SRMMU_CTX_REG, %g1 ld [%o0 + AOFF_mm_context], %o3 @@ -317,7 +314,6 @@ retl sta %g5, [%g1] ASI_M_MMUREGS - /* Verified... */ hypersparc_flush_tlb_page: ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */ mov SRMMU_CTX_REG, %g1 diff -u --recursive --new-file v2.1.33/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c --- v2.1.33/linux/arch/sparc/mm/init.c Sun Jan 26 02:07:09 1997 +++ linux/arch/sparc/mm/init.c Mon Apr 14 09:31:09 1997 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.47 1997/01/02 14:14:28 jj Exp $ +/* $Id: init.c,v 1.48 1997/04/12 04:28:37 davem Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -72,10 +72,10 @@ total++; if (PageReserved(mem_map + i)) reserved++; - else if (!mem_map[i].count) + else if (!atomic_read(&mem_map[i].count)) free++; else - shared += mem_map[i].count-1; + shared += atomic_read(&mem_map[i].count) - 1; } printk("%d pages of RAM\n",total); printk("%d free pages\n",free); @@ -241,7 +241,7 @@ datapages++; continue; } - mem_map[MAP_NR(addr)].count = 1; + atomic_set(&mem_map[MAP_NR(addr)].count, 1); num_physpages++; #ifdef CONFIG_BLK_DEV_INITRD if (!initrd_start || @@ -272,7 +272,7 @@ addr = (unsigned long)(&__init_begin); for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); - mem_map[MAP_NR(addr)].count = 1; + atomic_set(&mem_map[MAP_NR(addr)].count, 1); free_page(addr); } printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); @@ -291,9 +291,9 @@ if (PageReserved(mem_map + i)) continue; val->totalram++; - if (!mem_map[i].count) + if (!atomic_read(&mem_map[i].count)) continue; - val->sharedram += mem_map[i].count-1; + val->sharedram += atomic_read(&mem_map[i].count) - 1; } val->totalram <<= PAGE_SHIFT; val->sharedram <<= PAGE_SHIFT; diff -u --recursive --new-file v2.1.33/linux/arch/sparc/mm/loadmmu.c linux/arch/sparc/mm/loadmmu.c --- v2.1.33/linux/arch/sparc/mm/loadmmu.c Mon Dec 30 01:59:58 1996 +++ linux/arch/sparc/mm/loadmmu.c Fri Apr 11 10:47:35 1997 @@ -1,4 +1,4 @@ -/* $Id: loadmmu.c,v 1.45 1996/12/30 06:16:28 davem Exp $ +/* $Id: loadmmu.c,v 1.46 1997/04/10 05:12:51 davem Exp $ * loadmmu.c: This code loads up all the mm function pointers once the * machine type has been determined. It also sets the static * mmu values such as PAGE_NONE, etc. @@ -41,9 +41,9 @@ char *(*mmu_lockarea)(char *, unsigned long); void (*mmu_unlockarea)(char *, unsigned long); -char *(*mmu_get_scsi_one)(char *, unsigned long, struct linux_sbus *sbus); +__u32 (*mmu_get_scsi_one)(char *, unsigned long, struct linux_sbus *sbus); void (*mmu_get_scsi_sgl)(struct mmu_sglist *, int, struct linux_sbus *sbus); -void (*mmu_release_scsi_one)(char *, unsigned long, struct linux_sbus *sbus); +void (*mmu_release_scsi_one)(__u32, unsigned long, struct linux_sbus *sbus); void (*mmu_release_scsi_sgl)(struct mmu_sglist *, int, struct linux_sbus *sbus); void (*mmu_map_dma_area)(unsigned long addr, int len); diff -u --recursive --new-file v2.1.33/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v2.1.33/linux/arch/sparc/mm/srmmu.c Thu Mar 27 14:40:00 1997 +++ linux/arch/sparc/mm/srmmu.c Mon Apr 14 09:31:09 1997 @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.132 1997/03/18 17:56:47 jj Exp $ +/* $Id: srmmu.c,v 1.135 1997/04/14 05:38:49 davem Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -674,7 +674,7 @@ : "r" (page | 0x400), "r" (page), "i" (ASI_M_FLUSH_PROBE), "i" (ASI_M_FLUSH_PAGE), "r" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS), "r" (vac_line_size), "i" (PAGE_SIZE) - : "g4", "g5"); + : "g4", "g5", "cc"); } static void srmmu_set_pte_nocache_cypress(pte_t *ptep, pte_t pteval) @@ -1155,7 +1155,7 @@ "r" (MXCC_SRCSTREAM), "r" (MXCC_DESSTREAM), "r" (MXCC_STREAM_SIZE), - "i" (ASI_M_MXCC) : "g2", "g3"); + "i" (ASI_M_MXCC) : "g2", "g3", "cc"); /* This was handcoded after a look at the gcc output from * @@ -1234,7 +1234,7 @@ 2: subcc %0, 1, %0 bne 2b restore %%g0, %%g0, %%g0" - : "=&r" (ctr) : "0" (ctr), "i" (UWINMASK_OFFSET) : "g4"); + : "=&r" (ctr) : "0" (ctr), "i" (UWINMASK_OFFSET) : "g4", "cc"); srmmu_flush_whole_tlb(); module_stats.invall++; } @@ -1262,7 +1262,7 @@ : "r" (SRMMU_CTX_REG), "r" (0x300), "r" (mm->context), "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PROBE), "0" (ctr), "i" (UWINMASK_OFFSET) - : "g4"); + : "g4", "cc"); module_stats.invmm++; FLUSH_END } @@ -1283,7 +1283,7 @@ 2: subcc %0, 1, %0 bne 2b restore %%g0, %%g0, %%g0" - : "=&r" (ctr) : "0" (ctr), "i" (UWINMASK_OFFSET) : "g4"); + : "=&r" (ctr) : "0" (ctr), "i" (UWINMASK_OFFSET) : "g4", "cc"); start &= SRMMU_PGDIR_MASK; size = SRMMU_PGDIR_ALIGN(end) - start; __asm__ __volatile__(" @@ -1297,7 +1297,7 @@ : "r" (SRMMU_CTX_REG), "r" (mm->context), "r" (start | 0x200), "r" (size), "r" (SRMMU_PGDIR_SIZE), "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PROBE) - : "g5"); + : "g5", "cc"); module_stats.invrnge++; FLUSH_END } @@ -1318,7 +1318,7 @@ 2: subcc %0, 1, %0 bne 2b restore %%g0, %%g0, %%g0" - : "=&r" (ctr) : "0" (ctr), "i" (UWINMASK_OFFSET) : "g4"); + : "=&r" (ctr) : "0" (ctr), "i" (UWINMASK_OFFSET) : "g4", "cc"); __asm__ __volatile__(" lda [%0] %3, %%g5 sta %1, [%0] %3 @@ -1553,7 +1553,7 @@ : "r" (SRMMU_CTX_REG), "r" (mm->context), "r" (start | 0x200), "r" (size), "r" (SRMMU_PGDIR_SIZE), "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PROBE) - : "g5"); + : "g5", "cc"); module_stats.invrnge++; FLUSH_END } @@ -1822,7 +1822,7 @@ sbus->iommu = (struct iommu_struct *)iommu; } -static char *srmmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus) +static __u32 srmmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus) { unsigned long page = ((unsigned long) vaddr) & PAGE_MASK; @@ -1830,7 +1830,7 @@ flush_page_for_dma(page); page += PAGE_SIZE; } - return vaddr; + return (__u32)vaddr; } static void srmmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) @@ -1843,12 +1843,12 @@ flush_page_for_dma(page); page += PAGE_SIZE; } - sg[sz].dvma_addr = (char *) (sg[sz].addr); + sg[sz].dvma_addr = (__u32) (sg[sz].addr); sz--; } } -static void srmmu_release_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus) +static void srmmu_release_scsi_one(__u32 vaddr, unsigned long len, struct linux_sbus *sbus) { } @@ -2666,7 +2666,10 @@ mreg |= (HYPERSPARC_CMODE); srmmu_set_mmureg(mreg); + +#if 0 /* I think this is bad news... -DaveM */ hyper_clear_all_tags(); +#endif put_ross_icr(HYPERSPARC_ICCR_FTD | HYPERSPARC_ICCR_ICE); hyper_flush_whole_icache(); diff -u --recursive --new-file v2.1.33/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c --- v2.1.33/linux/arch/sparc/mm/sun4c.c Mon Mar 17 14:54:22 1997 +++ linux/arch/sparc/mm/sun4c.c Fri Apr 11 10:47:35 1997 @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.139 1997/01/31 08:05:59 davem Exp $ +/* $Id: sun4c.c,v 1.143 1997/04/11 00:42:14 davem Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -23,8 +23,48 @@ #include #include +/* TODO: Make it such that interrupt handlers cannot dick with + * the user segment lists, most of the cli/sti pairs can + * disappear once that is taken care of. + */ + +/* XXX Ok the real performance win, I figure, will be to use a combined hashing + * XXX and bitmap scheme to keep track of what we have mapped where. The whole + * XXX incentive is to make it such that the range flushes can be serviced + * XXX always in near constant time. --DaveM + */ + extern int num_segmaps, num_contexts; +/* Define this to get extremely anal debugging, undefine for performance. */ +/* #define DEBUG_SUN4C_MM */ + +#define UWINMASK_OFFSET (const unsigned long)(&(((struct task_struct *)0)->tss.uwinmask)) + +/* This is used in many routines below. */ +#define FUW_INLINE do { \ + register int ctr asm("g5"); \ + ctr = 0; \ + __asm__ __volatile__("\n" \ + "1: ld [%%g6 + %2], %%g4 ! flush user windows\n" \ + " orcc %%g0, %%g4, %%g0\n" \ + " add %0, 1, %0\n" \ + " bne 1b\n" \ + " save %%sp, -64, %%sp\n" \ + "2: subcc %0, 1, %0\n" \ + " bne 2b\n" \ + " restore %%g0, %%g0, %%g0\n" \ + : "=&r" (ctr) \ + : "0" (ctr), "i" (UWINMASK_OFFSET) \ + : "g4", "cc"); \ +} while(0); + +/* That's it, we prom_halt() if the cache size is something other than 65536. + * So let's save some cycles and just use that everywhere except for that bootup + * sanity check. + */ +#define SUN4C_VAC_SIZE 65536 + #define SUN4C_KERNEL_BUCKETS 32 #ifndef MAX @@ -100,7 +140,7 @@ /* Clear 'valid' bit in all cache line tags */ begin = AC_CACHETAGS; - end = (AC_CACHETAGS + sun4c_vacinfo.num_bytes); + end = (AC_CACHETAGS + SUN4C_VAC_SIZE); while(begin < end) { __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : "r" (begin), "i" (ASI_CONTROL)); @@ -108,83 +148,68 @@ } } -/* Blow the entire current context out of the virtual cache. */ -static inline void sun4c_flush_context(void) +/* Context level flush. */ +static inline void sun4c_flush_context_hw(void) { - extern unsigned long bcopy; - unsigned long begin, end, flags; + unsigned long end = SUN4C_VAC_SIZE; + unsigned pgsz = PAGE_SIZE; ctxflushes++; + __asm__ __volatile__(" +1: subcc %0, %2, %0 + bg 1b + sta %%g0, [%0] %3 + nop; nop; nop; ! Weitek hwbug +" : "=&r" (end) + : "0" (end), "r" (pgsz), "i" (ASI_HWFLUSHCONTEXT) + : "cc"); +} - begin = ((unsigned long) &bcopy); - end = (begin + sun4c_vacinfo.num_bytes); +/* Don't inline the software version as it eats too many cache lines if expanded. */ +static void sun4c_flush_context_sw(void) +{ + unsigned long nbytes = SUN4C_VAC_SIZE; + unsigned long lsize = sun4c_vacinfo.linesize; - save_and_cli(flags); - if(sun4c_vacinfo.linesize == 32) { - while(begin < end) { - __asm__ __volatile__(" - ld [%0 + 0x00], %%g0 - ld [%0 + 0x20], %%g0 - ld [%0 + 0x40], %%g0 - ld [%0 + 0x60], %%g0 - ld [%0 + 0x80], %%g0 - ld [%0 + 0xa0], %%g0 - ld [%0 + 0xc0], %%g0 - ld [%0 + 0xe0], %%g0 - ld [%0 + 0x100], %%g0 - ld [%0 + 0x120], %%g0 - ld [%0 + 0x140], %%g0 - ld [%0 + 0x160], %%g0 - ld [%0 + 0x180], %%g0 - ld [%0 + 0x1a0], %%g0 - ld [%0 + 0x1c0], %%g0 - ld [%0 + 0x1e0], %%g0 - " : : "r" (begin)); - begin += 512; - } - } else { - while(begin < end) { - __asm__ __volatile__(" - ld [%0 + 0x00], %%g0 - ld [%0 + 0x10], %%g0 - ld [%0 + 0x20], %%g0 - ld [%0 + 0x30], %%g0 - ld [%0 + 0x40], %%g0 - ld [%0 + 0x50], %%g0 - ld [%0 + 0x60], %%g0 - ld [%0 + 0x70], %%g0 - ld [%0 + 0x80], %%g0 - ld [%0 + 0x90], %%g0 - ld [%0 + 0xa0], %%g0 - ld [%0 + 0xb0], %%g0 - ld [%0 + 0xc0], %%g0 - ld [%0 + 0xd0], %%g0 - ld [%0 + 0xe0], %%g0 - ld [%0 + 0xf0], %%g0 - " : : "r" (begin)); - begin += 256; - } - } - restore_flags(flags); + ctxflushes++; + __asm__ __volatile__(" + add %2, %2, %%g1 + add %2, %%g1, %%g2 + add %2, %%g2, %%g3 + add %2, %%g3, %%g4 + add %2, %%g4, %%g5 + add %2, %%g5, %%o4 + add %2, %%o4, %%o5 +1: subcc %0, %%o5, %0 + sta %%g0, [%0] %3 + sta %%g0, [%0 + %2] %3 + sta %%g0, [%0 + %%g1] %3 + sta %%g0, [%0 + %%g2] %3 + sta %%g0, [%0 + %%g3] %3 + sta %%g0, [%0 + %%g4] %3 + sta %%g0, [%0 + %%g5] %3 + bg 1b + sta %%g0, [%1 + %%o4] %3 +" : "=&r" (nbytes) + : "0" (nbytes), "r" (lsize), "i" (ASI_FLUSHCTX) + : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc"); } /* Scrape the segment starting at ADDR from the virtual cache. */ static inline void sun4c_flush_segment(unsigned long addr) { - segflushes++; - addr &= SUN4C_REAL_PGDIR_MASK; - if(sun4c_get_segmap(addr) == invalid_segment) return; + segflushes++; if(sun4c_vacinfo.do_hwflushes) { - unsigned long end = (addr + sun4c_vacinfo.num_bytes); + unsigned long end = (addr + SUN4C_VAC_SIZE); for( ; addr < end; addr += PAGE_SIZE) - __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : + __asm__ __volatile__("sta %%g0, [%0] %1;nop;nop;nop;\n\t" : : "r" (addr), "i" (ASI_HWFLUSHSEG)); } else { - unsigned long nbytes = sun4c_vacinfo.num_bytes; + unsigned long nbytes = SUN4C_VAC_SIZE; unsigned long lsize = sun4c_vacinfo.linesize; __asm__ __volatile__("add %2, %2, %%g1\n\t" @@ -209,12 +234,61 @@ : "=&r" (addr), "=&r" (nbytes), "=&r" (lsize) : "0" (addr), "1" (nbytes), "2" (lsize), "i" (ASI_FLUSHSEG) - : "g1", "g2", "g3", "g4", "g5", "o4", "o5"); + : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc"); + } +} + +/* Call this version when you know hardware flushes are available. */ +static inline void sun4c_flush_segment_hw(unsigned long addr) +{ + if(sun4c_get_segmap(addr) != invalid_segment) { + unsigned long end; + + segflushes++; + for(end = addr + SUN4C_VAC_SIZE; addr < end; addr += PAGE_SIZE) + __asm__ __volatile__("sta %%g0, [%0] %1" + : : "r" (addr), "i" (ASI_HWFLUSHSEG)); + /* Weitek POWER-UP hwbug workaround. */ + __asm__ __volatile__("nop;nop;nop; ! Weitek hwbug"); + } +} + +/* Don't inline the software version as it eats too many cache lines if expanded. */ +static void sun4c_flush_segment_sw(unsigned long addr) +{ + if(sun4c_get_segmap(addr) != invalid_segment) { + unsigned long nbytes = SUN4C_VAC_SIZE; + unsigned long lsize = sun4c_vacinfo.linesize; + + segflushes++; + __asm__ __volatile__(" + add %2, %2, %%g1 + add %2, %%g1, %%g2 + add %2, %%g2, %%g3 + add %2, %%g3, %%g4 + add %2, %%g4, %%g5 + add %2, %%g5, %%o4 + add %2, %%o4, %%o5 +1: subcc %1, %%o5, %1 + sta %%g0, [%0] %6 + sta %%g0, [%0 + %2] %6 + sta %%g0, [%0 + %%g1] %6 + sta %%g0, [%0 + %%g2] %6 + sta %%g0, [%0 + %%g3] %6 + sta %%g0, [%0 + %%g4] %6 + sta %%g0, [%0 + %%g5] %6 + sta %%g0, [%0 + %%o4] %6 + bg 1b + add %0, %%o5, %0 +" : "=&r" (addr), "=&r" (nbytes), "=&r" (lsize) + : "0" (addr), "1" (nbytes), "2" (lsize), + "i" (ASI_FLUSHSEG) + : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc"); } } /* Bolix one page from the virtual cache. */ -static inline void sun4c_flush_page(unsigned long addr) +static void sun4c_flush_page(unsigned long addr) { addr &= PAGE_MASK; @@ -224,7 +298,7 @@ pageflushes++; if(sun4c_vacinfo.do_hwflushes) { - __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : + __asm__ __volatile__("sta %%g0, [%0] %1;nop;nop;nop;\n\t" : : "r" (addr), "i" (ASI_HWFLUSHPAGE)); } else { unsigned long left = PAGE_SIZE; @@ -252,7 +326,57 @@ : "=&r" (addr), "=&r" (left), "=&r" (lsize) : "0" (addr), "1" (left), "2" (lsize), "i" (ASI_FLUSHPG) - : "g1", "g2", "g3", "g4", "g5", "o4", "o5"); + : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc"); + } +} + +/* Again, hw-only and sw-only cache page-level flush variants. */ +static inline void sun4c_flush_page_hw(unsigned long addr) +{ + addr &= PAGE_MASK; + if((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) == + _SUN4C_PAGE_VALID) { + pageflushes++; + __asm__ __volatile__("sta %%g0, [%0] %1" + : : "r" (addr), "i" (ASI_HWFLUSHPAGE)); + /* Weitek POWER-UP hwbug workaround. */ + __asm__ __volatile__("nop;nop;nop; ! Weitek hwbug"); + } +} + +/* Don't inline the software version as it eats too many cache lines if expanded. */ +static void sun4c_flush_page_sw(unsigned long addr) +{ + addr &= PAGE_MASK; + if((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) == + _SUN4C_PAGE_VALID) { + unsigned long left = PAGE_SIZE; + unsigned long lsize = sun4c_vacinfo.linesize; + + pageflushes++; + __asm__ __volatile__(" + add %2, %2, %%g1 + add %2, %%g1, %%g2 + add %2, %%g2, %%g3 + add %2, %%g3, %%g4 + add %2, %%g4, %%g5 + add %2, %%g5, %%o4 + add %2, %%o4, %%o5 +1: subcc %1, %%o5, %1 + sta %%g0, [%0] %6 + sta %%g0, [%0 + %2] %6 + sta %%g0, [%0 + %%g1] %6 + sta %%g0, [%0 + %%g2] %6 + sta %%g0, [%0 + %%g3] %6 + sta %%g0, [%0 + %%g4] %6 + sta %%g0, [%0 + %%g5] %6 + sta %%g0, [%0 + %%o4] %6 + bg 1b + add %0, %%o5, %0 +" : "=&r" (addr), "=&r" (left), "=&r" (lsize) + : "0" (addr), "1" (left), "2" (lsize), + "i" (ASI_FLUSHPG) + : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc"); } } @@ -615,26 +739,33 @@ ring->num_entries++; } -static inline void remove_ring(struct sun4c_mmu_ring *ring, - struct sun4c_mmu_entry *entry) +static inline void add_ring_ordered(struct sun4c_mmu_ring *ring, + struct sun4c_mmu_entry *entry) { - struct sun4c_mmu_entry *next = entry->next; + struct sun4c_mmu_entry *head = &ring->ringhd; + unsigned long addr = entry->vaddr; - (next->prev = entry->prev)->next = next; - ring->num_entries--; + if(head->next != &ring->ringhd) { + while((head->next != &ring->ringhd) && (head->next->vaddr < addr)) + head = head->next; + } + entry->prev = head; + (entry->next = head->next)->prev = entry; + head->next = entry; + ring->num_entries++; } -static inline void recycle_ring(struct sun4c_mmu_ring *ring, - struct sun4c_mmu_entry *entry) +static inline void remove_ring(struct sun4c_mmu_ring *ring, + struct sun4c_mmu_entry *entry) { - struct sun4c_mmu_entry *head = &ring->ringhd; struct sun4c_mmu_entry *next = entry->next; (next->prev = entry->prev)->next = next; - entry->prev = head; - (entry->next = head->next)->prev = entry; - head->next = entry; - /* num_entries stays the same */ + ring->num_entries--; +#ifdef DEBUG_SUN4C_MM + if(ring->num_entries < 0) + panic("sun4c: Ring num_entries < 0!"); +#endif } static inline void free_user_entry(int ctx, struct sun4c_mmu_entry *entry) @@ -646,7 +777,7 @@ static inline void assign_user_entry(int ctx, struct sun4c_mmu_entry *entry) { remove_ring(&sun4c_ufree_ring, entry); - add_ring(sun4c_context_ring+ctx, entry); + add_ring_ordered(sun4c_context_ring+ctx, entry); } static inline void free_kernel_entry(struct sun4c_mmu_entry *entry, @@ -724,24 +855,55 @@ } } -static inline void sun4c_demap_context(struct sun4c_mmu_ring *crp, unsigned char ctx) +static void sun4c_demap_context_hw(struct sun4c_mmu_ring *crp, unsigned char ctx) { - struct sun4c_mmu_entry *this_entry, *next_entry; + struct sun4c_mmu_entry *head = &crp->ringhd; unsigned long flags; - int savectx = sun4c_get_context(); save_and_cli(flags); - this_entry = crp->ringhd.next; - flush_user_windows(); - sun4c_set_context(ctx); - while(crp->num_entries) { - next_entry = this_entry->next; - sun4c_flush_segment(this_entry->vaddr); - sun4c_user_unmap(this_entry); - free_user_entry(ctx, this_entry); - this_entry = next_entry; + if(head->next != head) { + struct sun4c_mmu_entry *entry = head->next; + int savectx = sun4c_get_context(); + + FUW_INLINE + sun4c_set_context(ctx); + sun4c_flush_context_hw(); + do { + struct sun4c_mmu_entry *next = entry->next; + + sun4c_user_unmap(entry); + free_user_entry(ctx, entry); + + entry = next; + } while(entry != head); + sun4c_set_context(savectx); + } + restore_flags(flags); +} + +static void sun4c_demap_context_sw(struct sun4c_mmu_ring *crp, unsigned char ctx) +{ + struct sun4c_mmu_entry *head = &crp->ringhd; + unsigned long flags; + + save_and_cli(flags); + if(head->next != head) { + struct sun4c_mmu_entry *entry = head->next; + int savectx = sun4c_get_context(); + + FUW_INLINE + sun4c_set_context(ctx); + sun4c_flush_context_sw(); + do { + struct sun4c_mmu_entry *next = entry->next; + + sun4c_user_unmap(entry); + free_user_entry(ctx, entry); + + entry = next; + } while(entry != head); + sun4c_set_context(savectx); } - sun4c_set_context(savectx); restore_flags(flags); } @@ -749,17 +911,25 @@ { /* by using .prev we get a kind of "lru" algorithm */ struct sun4c_mmu_entry *entry = crp->ringhd.prev; + unsigned long flags; int savectx = sun4c_get_context(); - flush_user_windows(); +#ifdef DEBUG_SUN4C_MM + if(entry == &crp->ringhd) + panic("sun4c_demap_one: Freeing from empty ctx ring."); +#endif + FUW_INLINE + save_and_cli(flags); sun4c_set_context(ctx); sun4c_flush_segment(entry->vaddr); sun4c_user_unmap(entry); free_user_entry(ctx, entry); sun4c_set_context(savectx); + restore_flags(flags); } -static int sun4c_user_taken_entries = 0; +static int sun4c_user_taken_entries = 0; /* This is how much we have. */ +static int max_user_taken_entries = 0; /* This limits us and prevents deadlock. */ static inline struct sun4c_mmu_entry *sun4c_kernel_strategy(void) { @@ -800,6 +970,10 @@ sun4c_kfree_ring.num_entries, sun4c_kernel_ring.num_entries); #endif +#ifdef DEBUG_SUN4C_MM + if(sun4c_user_taken_entries < 0) + panic("sun4c_shrink_kernel_ring: taken < 0."); +#endif } restore_flags(flags); } @@ -813,25 +987,50 @@ struct ctx_list *next_one; struct sun4c_mmu_ring *rp = 0; unsigned char ctx; +#ifdef DEBUG_SUN4C_MM + int lim = num_contexts; +#endif /* If some are free, return first one. */ - if(sun4c_ufree_ring.num_entries) + if(sun4c_ufree_ring.num_entries) { +#ifdef DEBUG_SUN4C_MM + if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd) + panic("sun4c_user_strategy: num_entries!=0 but ring empty."); +#endif return sun4c_ufree_ring.ringhd.next; + } if (sun4c_user_taken_entries) { sun4c_shrink_kernel_ring(); +#ifdef DEBUG_SUN4C_MM + if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd) + panic("sun4c_user_strategy: kernel shrunk but ufree empty."); +#endif return sun4c_ufree_ring.ringhd.next; } /* Grab one from the LRU context. */ next_one = ctx_used.next; - while (sun4c_context_ring[next_one->ctx_number].num_entries == 0) + while ((sun4c_context_ring[next_one->ctx_number].num_entries == 0) +#ifdef DEBUG_SUN4C_MM + && (--lim >= 0) +#endif + ) next_one = next_one->next; +#ifdef DEBUG_SUN4C_MM + if(lim < 0) + panic("No user segmaps!"); +#endif + ctx = next_one->ctx_number; rp = &sun4c_context_ring[ctx]; sun4c_demap_one(rp, ctx); +#ifdef DEBUG_SUN4C_MM + if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd) + panic("sun4c_user_strategy: demapped one but ufree empty."); +#endif return sun4c_ufree_ring.ringhd.next; } @@ -839,13 +1038,34 @@ { struct sun4c_mmu_entry *entry; +#if 0 + printk("grow: "); +#endif + + /* Prevent deadlock condition. */ + if(sun4c_user_taken_entries >= max_user_taken_entries) { +#if 0 + printk("deadlock avoidance, taken= %d max= %d\n", + sun4c_user_taken_entries, max_user_taken_entries); +#endif + return; + } + if (sun4c_ufree_ring.num_entries) { entry = sun4c_ufree_ring.ringhd.next; +#ifdef DEBUG_SUN4C_MM + if(entry == &sun4c_ufree_ring.ringhd) + panic("\nsun4c_grow_kernel_ring: num_entries!=0, ring empty."); +#endif remove_ring(&sun4c_ufree_ring, entry); add_ring(&sun4c_kfree_ring, entry); +#ifdef DEBUG_SUN4C_MM + if(sun4c_user_taken_entries < 0) + panic("\nsun4c_grow_kernel_ring: taken < 0."); +#endif sun4c_user_taken_entries++; #if 0 - printk("grow: ufree= %d, kfree= %d, kernel= %d\n", + printk("ufree= %d, kfree= %d, kernel= %d\n", sun4c_ufree_ring.num_entries, sun4c_kfree_ring.num_entries, sun4c_kernel_ring.num_entries); @@ -856,12 +1076,14 @@ static inline void alloc_user_segment(unsigned long address, unsigned char ctx) { struct sun4c_mmu_entry *entry; + unsigned long flags; - address &= SUN4C_REAL_PGDIR_MASK; + save_and_cli(flags); entry = sun4c_user_strategy(); + entry->vaddr = (address & SUN4C_REAL_PGDIR_MASK); assign_user_entry(ctx, entry); - entry->vaddr = address; sun4c_user_map(entry); + restore_flags(flags); } /* This is now a fast in-window trap handler to avoid any and all races. */ @@ -896,6 +1118,8 @@ struct task_bucket *sun4c_bucket[NR_TASKS]; +static int sun4c_lowbucket_avail; + #define BUCKET_EMPTY ((struct task_bucket *) 0) #define BUCKET_SIZE (PAGE_SIZE << 2) #define BUCKET_SHIFT 14 /* log2(sizeof(struct task_bucket)) */ @@ -915,8 +1139,13 @@ addr &= SUN4C_REAL_PGDIR_MASK; stolen = sun4c_user_strategy(); remove_ring(&sun4c_ufree_ring, stolen); + max_user_taken_entries--; +#ifdef DEBUG_SUN4C_MM + if(max_user_taken_entries < 0) + panic("get_locked_segment: max_user_taken < 0."); +#endif stolen->vaddr = addr; - flush_user_windows(); + FUW_INLINE sun4c_kernel_map(stolen); restore_flags(flags); } @@ -931,60 +1160,52 @@ addr &= SUN4C_REAL_PGDIR_MASK; pseg = sun4c_get_segmap(addr); entry = &mmu_entry_pool[pseg]; - flush_user_windows(); + + FUW_INLINE sun4c_flush_segment(addr); sun4c_kernel_unmap(entry); add_ring(&sun4c_ufree_ring, entry); +#ifdef DEBUG_SUN4C_MM + if(max_user_taken_entries < 0) + panic("free_locked_segment: max_user_taken < 0."); +#endif + max_user_taken_entries++; restore_flags(flags); } static inline void garbage_collect(int entry) { - unsigned long flags; int start, end; - save_and_cli(flags); - /* 16 buckets per segment... */ entry &= ~15; start = entry; for(end = (start + 16); start < end; start++) if(sun4c_bucket[start] != BUCKET_EMPTY) - goto done; + return; + /* Entire segment empty, release it. */ free_locked_segment(BUCKET_ADDR(entry)); -done: - restore_flags(flags); } static struct task_struct *sun4c_alloc_task_struct(void) { - unsigned long addr, page, flags; + unsigned long addr, page; int entry; - save_and_cli(flags); - page = get_free_page(GFP_KERNEL); - if(!page) { - restore_flags(flags); + if(!page) return (struct task_struct *) 0; - } - /* XXX Bahh, linear search too slow, use hash - * XXX table in final implementation. Or - * XXX keep track of first free when we free - * XXX a bucket... anything but this. - */ - for(entry = 0; entry < NR_TASKS; entry++) + + for(entry = sun4c_lowbucket_avail; entry < NR_TASKS; entry++) if(sun4c_bucket[entry] == BUCKET_EMPTY) break; if(entry == NR_TASKS) { free_page(page); - restore_flags(flags); return (struct task_struct *) 0; } - - /* Prevent an alias from occurring while the page is ours. */ - sun4c_flush_page(page); + if(entry >= sun4c_lowbucket_avail) + sun4c_lowbucket_avail = entry + 1; addr = BUCKET_ADDR(entry); sun4c_bucket[entry] = (struct task_bucket *) addr; @@ -992,8 +1213,6 @@ get_locked_segment(addr); sun4c_put_pte(addr, BUCKET_PTE(page)); - restore_flags(flags); - return (struct task_struct *) addr; } @@ -1013,47 +1232,80 @@ return 0; } - /* Prevent aliases from occurring while the pages are ours. */ - sun4c_flush_page(page[0]); - sun4c_flush_page(page[1]); - saddr += PAGE_SIZE << 1; sun4c_put_pte(saddr, BUCKET_PTE(page[0])); sun4c_put_pte(saddr + PAGE_SIZE, BUCKET_PTE(page[1])); return saddr; } -static void sun4c_free_kernel_stack(unsigned long stack) +static void sun4c_free_kernel_stack_hw(unsigned long stack) { unsigned long page[2]; - unsigned long flags; - save_and_cli(flags); page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack)); page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE)); - sun4c_flush_page(stack); - sun4c_flush_page(stack + PAGE_SIZE); + + /* We are deleting a mapping, so the flushes here are mandatory. */ + sun4c_flush_page_hw(stack); + sun4c_flush_page_hw(stack + PAGE_SIZE); + sun4c_put_pte(stack, 0); sun4c_put_pte(stack + PAGE_SIZE, 0); free_page(page[0]); free_page(page[1]); - restore_flags(flags); } -static void sun4c_free_task_struct(struct task_struct *tsk) +static void sun4c_free_task_struct_hw(struct task_struct *tsk) { unsigned long tsaddr = (unsigned long) tsk; unsigned long page = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr)); - unsigned long flags; int entry = BUCKET_NUM(tsaddr); - save_and_cli(flags); - sun4c_flush_page(tsaddr); + /* We are deleting a mapping, so the flush here is mandatory. */ + sun4c_flush_page_hw(tsaddr); + sun4c_put_pte(tsaddr, 0); sun4c_bucket[entry] = BUCKET_EMPTY; + if(entry < sun4c_lowbucket_avail) + sun4c_lowbucket_avail = entry; + + free_page(page); + garbage_collect(entry); +} + +static void sun4c_free_kernel_stack_sw(unsigned long stack) +{ + unsigned long page[2]; + + page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack)); + page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE)); + + /* We are deleting a mapping, so the flushes here are mandatory. */ + sun4c_flush_page_sw(stack); + sun4c_flush_page_sw(stack + PAGE_SIZE); + + sun4c_put_pte(stack, 0); + sun4c_put_pte(stack + PAGE_SIZE, 0); + free_page(page[0]); + free_page(page[1]); +} + +static void sun4c_free_task_struct_sw(struct task_struct *tsk) +{ + unsigned long tsaddr = (unsigned long) tsk; + unsigned long page = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr)); + int entry = BUCKET_NUM(tsaddr); + + /* We are deleting a mapping, so the flush here is mandatory. */ + sun4c_flush_page_sw(tsaddr); + + sun4c_put_pte(tsaddr, 0); + sun4c_bucket[entry] = BUCKET_EMPTY; + if(entry < sun4c_lowbucket_avail) + sun4c_lowbucket_avail = entry; + free_page(page); garbage_collect(entry); - restore_flags(flags); } __initfunc(static void sun4c_init_buckets(void)) @@ -1066,6 +1318,7 @@ } for(entry = 0; entry < NR_TASKS; entry++) sun4c_bucket[entry] = BUCKET_EMPTY; + sun4c_lowbucket_avail = 0; } static unsigned long sun4c_iobuffer_start; @@ -1151,6 +1404,8 @@ save_and_cli(flags); while (npages != 0) { --npages; + + /* This mapping is marked non-cachable, no flush necessary. */ sun4c_put_pte(vpage, 0); clear_bit((vpage - sun4c_iobuffer_start) >> PAGE_SHIFT, sun4c_iobuffer_map); @@ -1176,39 +1431,37 @@ * by implication and fool the page locking code above * if passed to by mistake. */ -static char *sun4c_get_scsi_one(char *bufptr, unsigned long len, struct linux_sbus *sbus) +static __u32 sun4c_get_scsi_one(char *bufptr, unsigned long len, struct linux_sbus *sbus) { unsigned long page; - page = ((unsigned long) bufptr) & PAGE_MASK; + page = ((unsigned long)bufptr) & PAGE_MASK; if(MAP_NR(page) > max_mapnr) { sun4c_flush_page(page); - return bufptr; /* already locked */ + return (__u32)bufptr; /* already locked */ } - return sun4c_lockarea(bufptr, len); + return (__u32)sun4c_lockarea(bufptr, len); } static void sun4c_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) { while(sz >= 0) { - sg[sz].dvma_addr = sun4c_lockarea(sg[sz].addr, sg[sz].len); + sg[sz].dvma_addr = (__u32)sun4c_lockarea(sg[sz].addr, sg[sz].len); sz--; } } -static void sun4c_release_scsi_one(char *bufptr, unsigned long len, struct linux_sbus *sbus) +static void sun4c_release_scsi_one(__u32 bufptr, unsigned long len, struct linux_sbus *sbus) { - unsigned long page = (unsigned long) bufptr; - - if(page < sun4c_iobuffer_start) + if(bufptr < sun4c_iobuffer_start) return; /* On kernel stack or similar, see above */ - sun4c_unlockarea(bufptr, len); + sun4c_unlockarea((char *)bufptr, len); } static void sun4c_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) { while(sz >= 0) { - sun4c_unlockarea(sg[sz].dvma_addr, sg[sz].len); + sun4c_unlockarea((char *)sg[sz].dvma_addr, sg[sz].len); sz--; } } @@ -1256,14 +1509,12 @@ /* Cache flushing on the sun4c. */ static void sun4c_flush_cache_all(void) { - extern unsigned long bcopy; - unsigned long begin, end, flags; + unsigned long begin, end; - begin = ((unsigned long) &bcopy); - end = (begin + sun4c_vacinfo.num_bytes); + FUW_INLINE + begin = (KERNBASE + SUN4C_REAL_PGDIR_SIZE); + end = (begin + SUN4C_VAC_SIZE); - save_and_cli(flags); - flush_user_windows(); if(sun4c_vacinfo.linesize == 32) { while(begin < end) { __asm__ __volatile__(" @@ -1309,106 +1560,236 @@ begin += 256; } } - restore_flags(flags); } -static void sun4c_flush_cache_mm(struct mm_struct *mm) +static void sun4c_flush_cache_mm_hw(struct mm_struct *mm) { - unsigned long flags; - int octx, new_ctx = mm->context; + int new_ctx = mm->context; + + if(new_ctx != NO_CONTEXT && sun4c_context_ring[new_ctx].num_entries) { + struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; + unsigned long flags; - if(new_ctx != NO_CONTEXT) { save_and_cli(flags); - octx = sun4c_get_context(); - flush_user_windows(); - sun4c_set_context(new_ctx); - sun4c_flush_context(); - sun4c_set_context(octx); + if(head->next != head) { + struct sun4c_mmu_entry *entry = head->next; + int savectx = sun4c_get_context(); + + FUW_INLINE + sun4c_set_context(new_ctx); + sun4c_flush_context_hw(); + do { + struct sun4c_mmu_entry *next = entry->next; + + sun4c_user_unmap(entry); + free_user_entry(new_ctx, entry); + + entry = next; + } while(entry != head); + sun4c_set_context(savectx); + } restore_flags(flags); } } -static void sun4c_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end) +static void sun4c_flush_cache_range_hw(struct mm_struct *mm, unsigned long start, unsigned long end) { - int size, size2, octx, i, new_ctx = mm->context; - unsigned long start2, end2, flags; - struct sun4c_mmu_entry *entry, *entry2; + int new_ctx = mm->context; #if KGPROF_PROFILING kgprof_profile(); #endif - if(new_ctx != NO_CONTEXT) { + struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; + struct sun4c_mmu_entry *entry; + unsigned long flags; + + FUW_INLINE save_and_cli(flags); - size = end - start; + /* All user segmap chains are ordered on entry->vaddr. */ + for(entry = head->next; + (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start); + entry = entry->next) + ; + + /* Tracing various job mixtures showed that this conditional + * only passes ~35% of the time for most worse case situations, + * therefore we avoid all of this gross overhead ~65% of the time. + */ + if((entry != head) && (entry->vaddr < end)) { + int octx = sun4c_get_context(); + sun4c_set_context(new_ctx); + + /* At this point, always, (start >= entry->vaddr) and + * (entry->vaddr < end), once the latter condition + * ceases to hold, or we hit the end of the list, we + * exit the loop. The ordering of all user allocated + * segmaps makes this all work out so beautifully. + */ + do { + struct sun4c_mmu_entry *next = entry->next; + unsigned long realend; + + /* "realstart" is always >= entry->vaddr */ + realend = entry->vaddr + SUN4C_REAL_PGDIR_SIZE; + if(end < realend) + realend = end; + if((realend - entry->vaddr) <= (PAGE_SIZE << 3)) { + unsigned long page = entry->vaddr; + while(page < realend) { + sun4c_flush_page_hw(page); + page += PAGE_SIZE; + } + } else { + sun4c_flush_segment_hw(entry->vaddr); + sun4c_user_unmap(entry); + free_user_entry(new_ctx, entry); + } + entry = next; + } while((entry != head) && (entry->vaddr < end)); + sun4c_set_context(octx); + } + restore_flags(flags); + } +} + +/* XXX no save_and_cli/restore_flags needed, but put here if darkside still crashes */ +static void sun4c_flush_cache_page_hw(struct vm_area_struct *vma, unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + int new_ctx = mm->context; - octx = sun4c_get_context(); - flush_user_windows(); + /* Sun4c has no separate I/D caches so cannot optimize for non + * text page flushes. + */ + if(new_ctx != NO_CONTEXT) { + int octx = sun4c_get_context(); + + FUW_INLINE sun4c_set_context(new_ctx); + sun4c_flush_page_hw(page); + sun4c_set_context(octx); + } +} + +static void sun4c_flush_page_to_ram_hw(unsigned long page) +{ + sun4c_flush_page_hw(page); +} + +static void sun4c_flush_cache_mm_sw(struct mm_struct *mm) +{ + int new_ctx = mm->context; + + if(new_ctx != NO_CONTEXT && sun4c_context_ring[new_ctx].num_entries) { + struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; + unsigned long flags; + + save_and_cli(flags); + if(head->next != head) { + struct sun4c_mmu_entry *entry = head->next; + int savectx = sun4c_get_context(); + + FUW_INLINE + sun4c_set_context(new_ctx); + sun4c_flush_context_sw(); + do { + struct sun4c_mmu_entry *next = entry->next; - entry = sun4c_context_ring[new_ctx].ringhd.next; - i = sun4c_context_ring[new_ctx].num_entries; - while (i--) { - entry2 = entry->next; - if (entry->vaddr < start || entry->vaddr >= end) - goto next_entry; - - start2 = MAX(start,entry->vaddr); - end2 = MIN(end,entry->vaddr+SUN4C_REAL_PGDIR_SIZE); - size2 = end2 - start2; - - if (size2 <= (PAGE_SIZE << 3)) { - start2 &= PAGE_MASK; - while(start2 < end2) { - sun4c_flush_page(start2); - start2 += PAGE_SIZE; - } - } else { - start2 &= SUN4C_REAL_PGDIR_MASK; - sun4c_flush_segment(start2); - - /* We are betting that the entry will not be - * needed for a while. - */ sun4c_user_unmap(entry); free_user_entry(new_ctx, entry); - } - next_entry: - entry = entry2; + entry = next; + } while(entry != head); + sun4c_set_context(savectx); } - sun4c_set_context(octx); restore_flags(flags); } } -static void sun4c_flush_cache_page(struct vm_area_struct *vma, unsigned long page) +static void sun4c_flush_cache_range_sw(struct mm_struct *mm, unsigned long start, unsigned long end) +{ + int new_ctx = mm->context; + +#if KGPROF_PROFILING + kgprof_profile(); +#endif + if(new_ctx != NO_CONTEXT) { + struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; + struct sun4c_mmu_entry *entry; + unsigned long flags; + + FUW_INLINE + save_and_cli(flags); + /* All user segmap chains are ordered on entry->vaddr. */ + for(entry = head->next; + (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start); + entry = entry->next) + ; + + /* Tracing various job mixtures showed that this conditional + * only passes ~35% of the time for most worse case situations, + * therefore we avoid all of this gross overhead ~65% of the time. + */ + if((entry != head) && (entry->vaddr < end)) { + int octx = sun4c_get_context(); + sun4c_set_context(new_ctx); + + /* At this point, always, (start >= entry->vaddr) and + * (entry->vaddr < end), once the latter condition + * ceases to hold, or we hit the end of the list, we + * exit the loop. The ordering of all user allocated + * segmaps makes this all work out so beautifully. + */ + do { + struct sun4c_mmu_entry *next = entry->next; + unsigned long realend; + + /* "realstart" is always >= entry->vaddr */ + realend = entry->vaddr + SUN4C_REAL_PGDIR_SIZE; + if(end < realend) + realend = end; + if((realend - entry->vaddr) <= (PAGE_SIZE << 3)) { + unsigned long page = entry->vaddr; + while(page < realend) { + sun4c_flush_page_sw(page); + page += PAGE_SIZE; + } + } else { + sun4c_flush_segment_sw(entry->vaddr); + sun4c_user_unmap(entry); + free_user_entry(new_ctx, entry); + } + entry = next; + } while((entry != head) && (entry->vaddr < end)); + sun4c_set_context(octx); + } + restore_flags(flags); + } +} + +static void sun4c_flush_cache_page_sw(struct vm_area_struct *vma, unsigned long page) { - unsigned long flags; struct mm_struct *mm = vma->vm_mm; - int octx, new_ctx = mm->context; + int new_ctx = mm->context; /* Sun4c has no separate I/D caches so cannot optimize for non * text page flushes. */ if(new_ctx != NO_CONTEXT) { - save_and_cli(flags); - octx = sun4c_get_context(); - flush_user_windows(); + int octx = sun4c_get_context(); + + FUW_INLINE sun4c_set_context(new_ctx); - sun4c_flush_page(page); + sun4c_flush_page_sw(page); sun4c_set_context(octx); - restore_flags(flags); } } -/* Even though sun4c is write through, a virtual cache alias inconsistancy - * can still occur with COW page handling so we must flush anyways. - */ -static void sun4c_flush_page_to_ram(unsigned long page) +static void sun4c_flush_page_to_ram_sw(unsigned long page) { - sun4c_flush_page(page); + sun4c_flush_page_sw(page); } /* Sun4c cache is unified, both instructions and data live there, so @@ -1447,82 +1828,178 @@ restore_flags(flags); } -static void sun4c_flush_tlb_mm(struct mm_struct *mm) +static void sun4c_flush_tlb_mm_hw(struct mm_struct *mm) { - struct sun4c_mmu_entry *this_entry, *next_entry; - struct sun4c_mmu_ring *crp; - unsigned long flags; - int savectx, new_ctx = mm->context; + int new_ctx = mm->context; if(new_ctx != NO_CONTEXT) { + struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; + unsigned long flags; + save_and_cli(flags); - crp = &sun4c_context_ring[new_ctx]; - savectx = sun4c_get_context(); - this_entry = crp->ringhd.next; - flush_user_windows(); - sun4c_set_context(new_ctx); - while(crp->num_entries) { - next_entry = this_entry->next; - sun4c_flush_segment(this_entry->vaddr); - sun4c_user_unmap(this_entry); - free_user_entry(new_ctx, this_entry); - this_entry = next_entry; + if(head->next != head) { + struct sun4c_mmu_entry *entry = head->next; + int savectx = sun4c_get_context(); + + FUW_INLINE + sun4c_set_context(new_ctx); + sun4c_flush_context_hw(); + do { + struct sun4c_mmu_entry *next = entry->next; + + sun4c_user_unmap(entry); + free_user_entry(new_ctx, entry); + + entry = next; + } while(entry != head); + sun4c_set_context(savectx); + } + restore_flags(flags); + } +} + +static void sun4c_flush_tlb_range_hw(struct mm_struct *mm, unsigned long start, unsigned long end) +{ + int new_ctx = mm->context; + + if(new_ctx != NO_CONTEXT) { + struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; + struct sun4c_mmu_entry *entry; + unsigned long flags; +#if KGPROF_PROFILING + kgprof_profile(); +#endif + + save_and_cli(flags); + /* See commentary in sun4c_flush_cache_range_*(). */ + for(entry = head->next; + (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start); + entry = entry->next) + ; + + if((entry != head) && (entry->vaddr < end)) { + int octx = sun4c_get_context(); + + /* This window flush is paranoid I think... -DaveM */ + FUW_INLINE + sun4c_set_context(new_ctx); + do { + struct sun4c_mmu_entry *next = entry->next; + + sun4c_flush_segment_hw(entry->vaddr); + sun4c_user_unmap(entry); + free_user_entry(new_ctx, entry); + + entry = next; + } while((entry != head) && (entry->vaddr < end)); + sun4c_set_context(octx); } + restore_flags(flags); + } +} + +static void sun4c_flush_tlb_page_hw(struct vm_area_struct *vma, unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + int new_ctx = mm->context; + + if(new_ctx != NO_CONTEXT) { + int savectx = sun4c_get_context(); + + FUW_INLINE + sun4c_set_context(new_ctx); + page &= PAGE_MASK; + sun4c_flush_page_hw(page); + sun4c_put_pte(page, 0); sun4c_set_context(savectx); + } +} + +static void sun4c_flush_tlb_mm_sw(struct mm_struct *mm) +{ + int new_ctx = mm->context; + + if(new_ctx != NO_CONTEXT) { + struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; + unsigned long flags; + + save_and_cli(flags); + if(head->next != head) { + struct sun4c_mmu_entry *entry = head->next; + int savectx = sun4c_get_context(); + + FUW_INLINE + sun4c_set_context(new_ctx); + sun4c_flush_context_sw(); + do { + struct sun4c_mmu_entry *next = entry->next; + + sun4c_user_unmap(entry); + free_user_entry(new_ctx, entry); + + entry = next; + } while(entry != head); + sun4c_set_context(savectx); + } restore_flags(flags); } } -static void sun4c_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) +static void sun4c_flush_tlb_range_sw(struct mm_struct *mm, unsigned long start, unsigned long end) { - struct sun4c_mmu_entry *entry, *entry2; - unsigned long flags; - int i, savectx, new_ctx = mm->context; + int new_ctx = mm->context; - if(new_ctx == NO_CONTEXT) - return; + if(new_ctx != NO_CONTEXT) { + struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; + struct sun4c_mmu_entry *entry; + unsigned long flags; #if KGPROF_PROFILING - kgprof_profile(); + kgprof_profile(); #endif - save_and_cli(flags); - savectx = sun4c_get_context(); - flush_user_windows(); - sun4c_set_context(new_ctx); - start &= SUN4C_REAL_PGDIR_MASK; + save_and_cli(flags); + /* See commentary in sun4c_flush_cache_range_*(). */ + for(entry = head->next; + (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start); + entry = entry->next) + ; + + if((entry != head) && (entry->vaddr < end)) { + int octx = sun4c_get_context(); + + /* This window flush is paranoid I think... -DaveM */ + FUW_INLINE + sun4c_set_context(new_ctx); + do { + struct sun4c_mmu_entry *next = entry->next; - entry = sun4c_context_ring[new_ctx].ringhd.next; - i = sun4c_context_ring[new_ctx].num_entries; - while (i--) { - entry2 = entry->next; - if (entry->vaddr >= start && entry->vaddr < end) { - sun4c_flush_segment(entry->vaddr); - sun4c_user_unmap(entry); - free_user_entry(new_ctx, entry); + sun4c_flush_segment_sw(entry->vaddr); + sun4c_user_unmap(entry); + free_user_entry(new_ctx, entry); + + entry = next; + } while((entry != head) && (entry->vaddr < end)); + sun4c_set_context(octx); } - entry = entry2; + restore_flags(flags); } - sun4c_set_context(savectx); - restore_flags(flags); } -static void sun4c_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +static void sun4c_flush_tlb_page_sw(struct vm_area_struct *vma, unsigned long page) { struct mm_struct *mm = vma->vm_mm; - unsigned long flags; - int savectx, new_ctx = mm->context; + int new_ctx = mm->context; if(new_ctx != NO_CONTEXT) { - save_and_cli(flags); - savectx = sun4c_get_context(); - flush_user_windows(); + int savectx = sun4c_get_context(); + + FUW_INLINE sun4c_set_context(new_ctx); page &= PAGE_MASK; - sun4c_flush_page(page); + sun4c_flush_page_sw(page); sun4c_put_pte(page, 0); sun4c_set_context(savectx); - restore_flags(flags); } } @@ -1548,7 +2025,7 @@ sun4c_put_pte(virt_addr, 0); } -static inline void sun4c_alloc_context(struct mm_struct *mm) +static void sun4c_alloc_context_hw(struct mm_struct *mm) { struct ctx_list *ctxp; @@ -1563,74 +2040,114 @@ ctxp = ctx_used.next; if(ctxp->ctx_mm == current->mm) ctxp = ctxp->next; +#ifdef DEBUG_SUN4C_MM if(ctxp == &ctx_used) panic("out of mmu contexts"); +#endif remove_from_ctx_list(ctxp); add_to_used_ctxlist(ctxp); ctxp->ctx_mm->context = NO_CONTEXT; ctxp->ctx_mm = mm; mm->context = ctxp->ctx_number; - sun4c_demap_context(&sun4c_context_ring[ctxp->ctx_number], + sun4c_demap_context_hw(&sun4c_context_ring[ctxp->ctx_number], ctxp->ctx_number); } -#if some_day_soon /* We need some tweaking to start using this */ -extern void force_user_fault(unsigned long, int); +static void sun4c_switch_to_context_hw(struct task_struct *tsk) +{ + struct ctx_list *ctx; + + if(tsk->mm->context == NO_CONTEXT) { + sun4c_alloc_context_hw(tsk->mm); + } else { + /* Update the LRU ring of contexts. */ + ctx = ctx_list_pool + tsk->mm->context; + remove_from_ctx_list(ctx); + add_to_used_ctxlist(ctx); + } + sun4c_set_context(tsk->mm->context); +} + +static void sun4c_init_new_context_hw(struct mm_struct *mm) +{ + sun4c_alloc_context_hw(mm); + if(mm == current->mm) + sun4c_set_context(mm->context); +} -void sun4c_switch_heuristic(struct pt_regs *regs) +static void sun4c_destroy_context_hw(struct mm_struct *mm) { - unsigned long sp = regs->u_regs[UREG_FP]; - unsigned long sp2 = sp + REGWIN_SZ - 0x8; + struct ctx_list *ctx_old; - force_user_fault(regs->pc, 0); - force_user_fault(sp, 0); - if((sp&PAGE_MASK) != (sp2&PAGE_MASK)) - force_user_fault(sp2, 0); + if(mm->context != NO_CONTEXT && mm->count == 1) { + sun4c_demap_context_hw(&sun4c_context_ring[mm->context], mm->context); + ctx_old = ctx_list_pool + mm->context; + remove_from_ctx_list(ctx_old); + add_to_free_ctxlist(ctx_old); + mm->context = NO_CONTEXT; + } } + +static void sun4c_alloc_context_sw(struct mm_struct *mm) +{ + struct ctx_list *ctxp; + + ctxp = ctx_free.next; + if(ctxp != &ctx_free) { + remove_from_ctx_list(ctxp); + add_to_used_ctxlist(ctxp); + mm->context = ctxp->ctx_number; + ctxp->ctx_mm = mm; + return; + } + ctxp = ctx_used.next; + if(ctxp->ctx_mm == current->mm) + ctxp = ctxp->next; +#ifdef DEBUG_SUN4C_MM + if(ctxp == &ctx_used) + panic("out of mmu contexts"); #endif + remove_from_ctx_list(ctxp); + add_to_used_ctxlist(ctxp); + ctxp->ctx_mm->context = NO_CONTEXT; + ctxp->ctx_mm = mm; + mm->context = ctxp->ctx_number; + sun4c_demap_context_sw(&sun4c_context_ring[ctxp->ctx_number], + ctxp->ctx_number); +} -static void sun4c_switch_to_context(struct task_struct *tsk) +static void sun4c_switch_to_context_sw(struct task_struct *tsk) { struct ctx_list *ctx; - unsigned long flags; - save_and_cli(flags); if(tsk->mm->context == NO_CONTEXT) { - sun4c_alloc_context(tsk->mm); - goto set_context; + sun4c_alloc_context_sw(tsk->mm); + } else { + /* Update the LRU ring of contexts. */ + ctx = ctx_list_pool + tsk->mm->context; + remove_from_ctx_list(ctx); + add_to_used_ctxlist(ctx); } - - /* Update the LRU ring of contexts. */ - ctx = ctx_list_pool + tsk->mm->context; - remove_from_ctx_list(ctx); - add_to_used_ctxlist(ctx); - -set_context: sun4c_set_context(tsk->mm->context); - restore_flags(flags); } -static void sun4c_init_new_context(struct mm_struct *mm) +static void sun4c_init_new_context_sw(struct mm_struct *mm) { - sun4c_alloc_context(mm); + sun4c_alloc_context_sw(mm); if(mm == current->mm) sun4c_set_context(mm->context); } -static void sun4c_destroy_context(struct mm_struct *mm) +static void sun4c_destroy_context_sw(struct mm_struct *mm) { struct ctx_list *ctx_old; if(mm->context != NO_CONTEXT && mm->count == 1) { - unsigned long flags; - - save_and_cli(flags); - sun4c_demap_context(&sun4c_context_ring[mm->context], mm->context); + sun4c_demap_context_sw(&sun4c_context_ring[mm->context], mm->context); ctx_old = ctx_list_pool + mm->context; remove_from_ctx_list(ctx_old); add_to_free_ctxlist(ctx_old); mm->context = NO_CONTEXT; - restore_flags(flags); } } @@ -1657,6 +2174,8 @@ "kfreepsegs\t: %d\n" "usedpsegs\t: %d\n" "ufreepsegs\t: %d\n" + "user_taken\t: %d\n" + "max_taken\t: %d\n" "context\t\t: %d flushes\n" "segment\t\t: %d flushes\n" "page\t\t: %d flushes\n", @@ -1669,6 +2188,8 @@ sun4c_kfree_ring.num_entries, used_user_entries, sun4c_ufree_ring.num_entries, + sun4c_user_taken_entries, + max_user_taken_entries, ctxflushes, segflushes, pageflushes); #if KGPROF_PROFILING @@ -1971,31 +2492,20 @@ * now, so our ref/mod bit tracking quick userfaults eat a few more * cycles than they used to. */ -void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte) +static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long address, pte_t pte) { - unsigned long offset, vaddr, start, flags; + struct inode *inode; pgd_t *pgdp; pte_t *ptep; - save_and_cli(flags); - address &= PAGE_MASK; - if(sun4c_get_segmap(address) == invalid_segment) - alloc_user_segment(address, sun4c_get_context()); - - if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) { - struct vm_area_struct *vmaring; - struct inode *inode; + inode = vma->vm_inode; + if(inode) { + unsigned long offset = (address & PAGE_MASK) - vma->vm_start; + struct vm_area_struct *vmaring = inode->i_mmap; int alias_found = 0; - - /* While on the other hand, this is very uncommon... */ - inode = vma->vm_inode; - if(!inode) - goto done; - - offset = (address & PAGE_MASK) - vma->vm_start; - vmaring = inode->i_mmap; do { - vaddr = vmaring->vm_start + offset; + unsigned long vaddr = vmaring->vm_start + offset; + unsigned long start; if (S4CVAC_BADALIAS(vaddr, address)) { alias_found++; @@ -2007,14 +2517,10 @@ if(!ptep) goto next; if(pte_val(*ptep) & _SUN4C_PAGE_PRESENT) { -#if 1 - printk("Fixing USER/USER alias [%ld:%08lx]\n", - vmaring->vm_mm->context, start); -#endif - sun4c_flush_cache_page(vmaring, start); - *ptep = __pte(pte_val(*ptep) | - _SUN4C_PAGE_NOCACHE); - sun4c_flush_tlb_page(vmaring, start); + flush_cache_page(vmaring, start); + pte_val(*ptep) = (pte_val(*ptep) | + _SUN4C_PAGE_NOCACHE); + flush_tlb_page(vmaring, start); } next: start += PAGE_SIZE; @@ -2025,11 +2531,24 @@ if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) { pgdp = sun4c_pgd_offset(vma->vm_mm, address); ptep = sun4c_pte_offset((pmd_t *) pgdp, address); - *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_NOCACHE); + pte_val(*ptep) = (pte_val(*ptep) | _SUN4C_PAGE_NOCACHE); pte = pte_val(*ptep); } } -done: +} + +void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte) +{ + unsigned long flags; + + save_and_cli(flags); + address &= PAGE_MASK; + if(sun4c_get_segmap(address) == invalid_segment) + alloc_user_segment(address, sun4c_get_context()); + + if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) + sun4c_vac_alias_fixup(vma, address, pte); + sun4c_put_pte(address, pte_val(pte)); restore_flags(flags); } @@ -2045,7 +2564,7 @@ extern unsigned long sparc_iobase_vaddr; kernel_end = (unsigned long) &end; - kernel_end += (SUN4C_REAL_PGDIR_SIZE * 3); + kernel_end += (SUN4C_REAL_PGDIR_SIZE * 4); kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end); sun4c_probe_mmu(); invalid_segment = (num_segmaps - 1); @@ -2083,6 +2602,9 @@ for(i = 0; i < num_segmaps; i++) if(mmu_entry_pool[i].locked) cnt++; + + max_user_taken_entries = num_segmaps - cnt - 40 - 1; + printk("SUN4C: %d mmu entries for the kernel\n", cnt); return start_mem; } @@ -2114,21 +2636,40 @@ /* Functions */ flush_cache_all = sun4c_flush_cache_all; - flush_cache_mm = sun4c_flush_cache_mm; - flush_cache_range = sun4c_flush_cache_range; - flush_cache_page = sun4c_flush_cache_page; - flush_tlb_all = sun4c_flush_tlb_all; - flush_tlb_mm = sun4c_flush_tlb_mm; - flush_tlb_range = sun4c_flush_tlb_range; - flush_tlb_page = sun4c_flush_tlb_page; + if(sun4c_vacinfo.do_hwflushes) { + flush_cache_mm = sun4c_flush_cache_mm_hw; + flush_cache_range = sun4c_flush_cache_range_hw; + flush_cache_page = sun4c_flush_cache_page_hw; + flush_page_to_ram = sun4c_flush_page_to_ram_hw; + flush_tlb_mm = sun4c_flush_tlb_mm_hw; + flush_tlb_range = sun4c_flush_tlb_range_hw; + flush_tlb_page = sun4c_flush_tlb_page_hw; + free_kernel_stack = sun4c_free_kernel_stack_hw; + free_task_struct = sun4c_free_task_struct_hw; + switch_to_context = sun4c_switch_to_context_hw; + destroy_context = sun4c_destroy_context_hw; + init_new_context = sun4c_init_new_context_hw; + } else { + flush_cache_mm = sun4c_flush_cache_mm_sw; + flush_cache_range = sun4c_flush_cache_range_sw; + flush_cache_page = sun4c_flush_cache_page_sw; + flush_page_to_ram = sun4c_flush_page_to_ram_sw; + flush_tlb_mm = sun4c_flush_tlb_mm_sw; + flush_tlb_range = sun4c_flush_tlb_range_sw; + flush_tlb_page = sun4c_flush_tlb_page_sw; + free_kernel_stack = sun4c_free_kernel_stack_sw; + free_task_struct = sun4c_free_task_struct_sw; + switch_to_context = sun4c_switch_to_context_sw; + destroy_context = sun4c_destroy_context_sw; + init_new_context = sun4c_init_new_context_sw; + } - flush_page_to_ram = sun4c_flush_page_to_ram; + flush_tlb_all = sun4c_flush_tlb_all; flush_sig_insns = sun4c_flush_sig_insns; set_pte = sun4c_set_pte; - switch_to_context = sun4c_switch_to_context; pmd_align = sun4c_pmd_align; pgdir_align = sun4c_pgdir_align; vmalloc_start = sun4c_vmalloc_start; @@ -2180,8 +2721,7 @@ pte_mkdirty = sun4c_pte_mkdirty; pte_mkyoung = sun4c_pte_mkyoung; update_mmu_cache = sun4c_update_mmu_cache; - destroy_context = sun4c_destroy_context; - init_new_context = sun4c_init_new_context; + mmu_lockarea = sun4c_lockarea; mmu_unlockarea = sun4c_unlockarea; @@ -2198,8 +2738,6 @@ /* Task struct and kernel stack allocating/freeing. */ alloc_kernel_stack = sun4c_alloc_kernel_stack; alloc_task_struct = sun4c_alloc_task_struct; - free_kernel_stack = sun4c_free_kernel_stack; - free_task_struct = sun4c_free_task_struct; quick_kernel_fault = sun4c_quick_kernel_fault; mmu_info = sun4c_mmu_info; diff -u --recursive --new-file v2.1.33/linux/arch/sparc/prom/misc.c linux/arch/sparc/prom/misc.c --- v2.1.33/linux/arch/sparc/prom/misc.c Thu Dec 19 01:03:33 1996 +++ linux/arch/sparc/prom/misc.c Fri Apr 11 10:47:35 1997 @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.12 1996/12/18 06:46:55 tridge Exp $ +/* $Id: misc.c,v 1.13 1997/04/10 05:12:59 davem Exp $ * misc.c: Miscellaneous prom functions that don't belong * anywhere else. * @@ -92,6 +92,7 @@ prom_halt(void) { unsigned long flags; +again: save_flags(flags); cli(); (*(romvec->pv_halt))(); /* Never get here. */ @@ -99,6 +100,7 @@ "r" (¤t_set[smp_processor_id()]) : "memory"); restore_flags(flags); + goto again; /* PROM is out to get me -DaveM */ } typedef void (*sfunc_t)(void); diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/Makefile linux/arch/sparc64/Makefile --- v2.1.33/linux/arch/sparc64/Makefile Mon Apr 7 11:35:29 1997 +++ linux/arch/sparc64/Makefile Fri Apr 11 10:47:36 1997 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.9 1997/03/14 21:04:39 jj Exp $ +# $Id: Makefile,v 1.14 1997/04/10 23:32:33 davem Exp $ # sparc64/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -17,13 +17,15 @@ NM = sparc64-linux-nm AR = sparc64-linux-ar RANLIB = sparc64-linux-ranlib +ELF2AOUT64 = elf2aout64 # # Uncomment the first CFLAGS if you are doing kgdb source level # debugging of the kernel to get the proper debugging information. #CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7 -CFLAGS := $(CFLAGS) -pipe -fcall-used-g5 -fcall-used-g7 +CFLAGS := $(CFLAGS) -pipe -fno-sibling-call \ + -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare LINKFLAGS = -T arch/sparc64/vmlinux.lds @@ -37,7 +39,11 @@ LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc64/prom/promlib.a \ $(TOPDIR)/arch/sparc64/lib/lib.a +vmlinux.aout: vmlinux + $(ELF2AOUT64) -o $(TOPDIR)/vmlinux.aout $(TOPDIR)/vmlinux + archclean: + rm -f $(TOPDIR)/vmlinux.aout archdep: diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.1.33/linux/arch/sparc64/config.in Mon Apr 7 11:35:29 1997 +++ linux/arch/sparc64/config.in Fri Apr 11 10:47:36 1997 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.1 1996/12/27 17:28:19 davem Exp $ +# $Id: config.in,v 1.5 1997/04/10 17:06:08 jj Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -51,7 +51,8 @@ bool 'System V IPC' CONFIG_SYSVIPC bool 'Sysctl support' CONFIG_SYSCTL tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT -tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +tristate 'Kernel support for 64-bit ELF binaries' CONFIG_BINFMT_ELF +tristate 'Kernel support for 32-bit ELF binaries' CONFIG_BINFMT_ELF32 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA fi diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.1.33/linux/arch/sparc64/defconfig Mon Apr 7 11:35:29 1997 +++ linux/arch/sparc64/defconfig Mon Apr 14 09:31:09 1997 @@ -5,14 +5,12 @@ # # Code maturity level options # -CONFIG_EXPERIMENTAL=y +# CONFIG_EXPERIMENTAL is not set # # Loadable module support # -CONFIG_MODULES=y -CONFIG_MODVERSIONS=y -CONFIG_KERNELD=y +# CONFIG_MODULES is not set # # General setup @@ -46,85 +44,51 @@ # # Misc Linux/SPARC drivers # -CONFIG_SUN_OPENPROMIO=m -CONFIG_SUN_MOSTEK_RTC=y -# CONFIG_SUN_BPP is not set - -# -# Linux/SPARC audio subsystem (EXPERIMENTAL) -# -# CONFIG_SPARCAUDIO is not set -# CONFIG_SPARCAUDIO_AMD7930 is not set -# CONFIG_SPARCAUDIO_CS4231 is not set -CONFIG_SUN_OPENPROMFS=m +# CONFIG_SUN_OPENPROMIO is not set +# CONFIG_SUN_MOSTEK_RTC is not set +# CONFIG_SUN_OPENPROMFS is not set CONFIG_NET=y CONFIG_SYSVIPC=y CONFIG_SYSCTL=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y -CONFIG_BINFMT_JAVA=m +CONFIG_BINFMT_ELF32=y # # Floppy, IDE, and other block devices # -CONFIG_BLK_DEV_FD=y -CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=y -CONFIG_MD_STRIPED=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_BLK_DEV_LOOP=m +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_LOOP is not set # # Networking options # -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y -CONFIG_FIREWALL=y -CONFIG_NET_ALIAS=y +# CONFIG_NETLINK is not set +# CONFIG_FIREWALL is not set +# CONFIG_NET_ALIAS is not set CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_FIREWALL=y -# CONFIG_IP_FIREWALL_NETLINK is not set -# CONFIG_IP_FIREWALL_VERBOSE is not set -CONFIG_IP_MASQUERADE=y - -# -# Protocol-specific masquerading support will be built as modules. -# -# CONFIG_IP_TRANSPARENT_PROXY is not set -# CONFIG_IP_ALWAYS_DEFRAG is not set +# CONFIG_IP_MULTICAST is not set # CONFIG_IP_ACCT is not set # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set -# CONFIG_IP_MROUTE is not set -CONFIG_IP_ALIAS=m -# CONFIG_ARPD is not set # # (it is safe to leave these untouched) # # CONFIG_INET_PCTCP is not set -CONFIG_INET_RARP=m -# CONFIG_PATH_MTU_DISCOVERY is not set +# CONFIG_INET_RARP is not set +CONFIG_PATH_MTU_DISCOVERY=y CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y -CONFIG_IPV6=m # # # -CONFIG_IPX=m -# CONFIG_IPX_INTERN is not set -# CONFIG_IPX_PPROP_ROUTING is not set -CONFIG_ATALK=m -# CONFIG_IPDDP is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set # CONFIG_AX25 is not set -CONFIG_X25=m -# CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set -# CONFIG_LLC is not set -# CONFIG_WAN_ROUTER is not set # # SCSI support @@ -135,10 +99,10 @@ # SCSI support type (disk, tape, CDrom) # CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=y +# CONFIG_CHR_DEV_ST is not set CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y -CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SG is not set # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs @@ -150,51 +114,43 @@ # SCSI low-level drivers # CONFIG_SCSI_SUNESP=y -CONFIG_SCSI_QLOGICPTI=m +# CONFIG_SCSI_QLOGICPTI is not set # # Network device support # CONFIG_NETDEVICES=y -CONFIG_DUMMY=m -CONFIG_PPP=m - -# -# CCP compressors for PPP are only built as modules. -# -CONFIG_SLIP=m -CONFIG_SLIP_COMPRESSED=y -CONFIG_SLIP_SMART=y -# CONFIG_SLIP_MODE_SLIP6 is not set +CONFIG_DUMMY=y +# CONFIG_PPP is not set +# CONFIG_SLIP is not set CONFIG_SUNLANCE=y -CONFIG_HAPPYMEAL=m -CONFIG_SUNQE=m -CONFIG_MYRI_SBUS=m +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNQE is not set +# CONFIG_MYRI_SBUS is not set # # Filesystems # CONFIG_QUOTA=y -CONFIG_MINIX_FS=m +CONFIG_MINIX_FS=y CONFIG_EXT2_FS=y -CONFIG_FAT_FS=m -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=m -CONFIG_UMSDOS_FS=m +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_UMSDOS_FS is not set CONFIG_PROC_FS=y CONFIG_NFS_FS=y -CONFIG_ROOT_NFS=y -CONFIG_RNFS_BOOTP=y -CONFIG_RNFS_RARP=y -CONFIG_SMB_FS=m -CONFIG_SMB_WIN95=y -CONFIG_NCP_FS=m +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set CONFIG_ISO9660_FS=y -CONFIG_HPFS_FS=m -CONFIG_SYSV_FS=m -CONFIG_AFFS_FS=m -CONFIG_ROMFS_FS=m -CONFIG_AMIGA_PARTITION=y +# CONFIG_HPFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_AUTOFS_FS is not set CONFIG_UFS_FS=y CONFIG_BSD_DISKLABEL=y CONFIG_SMD_DISKLABEL=y diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile --- v2.1.33/linux/arch/sparc64/kernel/Makefile Thu Mar 27 14:40:00 1997 +++ linux/arch/sparc64/kernel/Makefile Fri Apr 11 10:47:36 1997 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.7 1997/03/18 17:59:15 jj Exp $ +# $Id: Makefile,v 1.15 1997/04/10 07:53:30 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -16,10 +16,16 @@ all: kernel.o head.o O_TARGET := kernel.o -O_OBJS := etrap.o rtrap.o hack.o process.o setup.o cpu.o idprom.o systbls.o traps.o entry.o devices.o auxio.o ioport.o # signal32.o +O_OBJS := etrap.o rtrap.o hack.o process.o setup.o cpu.o idprom.o \ + systbls.o traps.o entry.o devices.o auxio.o ioport.o \ + irq.o time.o sys_sparc.o sys_sparc32.o signal32.o OX_OBJS := sparc64_ksyms.o -head.o: head.S +ifdef CONFIG_BINFMT_ELF32 + O_OBJS += sparcelf32.o +endif + +head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S $(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o check_asm: dummy diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/cpu.c linux/arch/sparc64/kernel/cpu.c --- v2.1.33/linux/arch/sparc64/kernel/cpu.c Thu Mar 27 14:40:00 1997 +++ linux/arch/sparc64/kernel/cpu.c Fri Apr 11 10:47:36 1997 @@ -25,13 +25,17 @@ * machine type value into consideration too. I will fix this. */ struct cpu_fp_info linux_sparc_fpu[] = { - { 0x17, 0x10, 0, "FIXME: UltraSparc I FPU"}, + { 0x17, 0x10, 0, "UltraSparc I integrated FPU"}, + { 0x17, 0x11, 0, "UltraSparc II integrated FPU"}, + { 0x17, 0x12, 0, "UltraSparc III integrated FPU"}, }; #define NSPARCFPU (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info)) struct cpu_iu_info linux_sparc_chips[] = { - { 0x17, 0x10, "FIXME: UltraSparc I"}, + { 0x17, 0x10, "TI UltraSparc I (SpitFire)"}, + { 0x17, 0x11, "TI UltraSparc II (BlackBird)"}, + { 0x17, 0x12, "TI UltraSparc III (Cheetah)"}, /* A guess... */ }; #define NSPARCCHIPS (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info)) diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/devices.c linux/arch/sparc64/kernel/devices.c --- v2.1.33/linux/arch/sparc64/kernel/devices.c Thu Mar 27 14:40:00 1997 +++ linux/arch/sparc64/kernel/devices.c Fri Apr 11 10:47:36 1997 @@ -11,8 +11,8 @@ #include #include -#include #include +#include struct prom_cpuinfo linux_cpus[NCPUS]; int linux_num_cpus; @@ -31,6 +31,8 @@ if(strcmp(node_str, "cpu") == 0) { cpu_nds[0] = prom_root_node; + linux_cpus[0].prom_node = prom_root_node; + linux_cpus[0].mid = 0; cpu_ctr++; } else { int scan; diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/dtlb_miss.S linux/arch/sparc64/kernel/dtlb_miss.S --- v2.1.33/linux/arch/sparc64/kernel/dtlb_miss.S Mon Mar 17 14:54:23 1997 +++ linux/arch/sparc64/kernel/dtlb_miss.S Fri Apr 11 10:47:36 1997 @@ -1,93 +1,80 @@ -/* $Id: dtlb_miss.S,v 1.5 1997/02/25 20:00:02 jj Exp $ +/* $Id: dtlb_miss.S,v 1.11 1997/04/10 01:59:35 davem Exp $ * dtlb_miss.S: Data TLB miss code, this is included directly * into the trap table. * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ - /* We are in the MMU globals, %g7 contains the physical - * address of current->mm->pgd at all times. - * - * Many subtle things are done here. The high bits of - * the virtual address missed are most easily obtained - * from the tag target (it is at address zero in ASI_IMMU - * so no address formation is necessary to get at this). - * This is used to compute the pgd and pmd table offsets. - * - * Even more clever is that physical page zero is always - * a page full of zeroes. This means we can just follow - * through with all the page table traversals even if nothing - * is mapped because we'll just do loads from page zero - * and get yet another zero. We only need to do the check - * for the valid bit being set in the final pte we obtain. - * - * Furthermore, we set the TSB base register to the address - * zero, and we use the 8KB tsb ptr to calculate the pte - * offset. Again it is at address zero in ASI_IMMU_TSB_8KB_PTR - * so no address formation is necessary, saves more instructions. - * - * We use physical address accesses to get at the page - * tables, and this is for two reasons. This makes it - * impossible to take a fault while we are servicing the - * miss. Also this physical bypass access only allocates - * in the E-cache, and thus we prevent D-cache pollution - * from the miss handlers probing the page tables. - * - * It looks very hairy and slow. But I take only 1 more - * overhead of loads from ram than the Solaris version, and - * my version is one instruction quicker for a true TLB miss. - * And more importantly, all true TLB misses under Linux will be - * serviced in _constant_ time. When using the TSB in the - * manner it was intended to be used (like solaris does) the - * overhead for a TLB miss is _indeterminate_ especially during - * processes startup when the TSB is cold. - * - * XXX I think I can knock off two more instructions here... - */ - - /* I-cache line 0 */ - ldxa [%g0] ASI_DMMU, %g1 ! grab Tag Target either way - brlz,pn %g1, 3f ! special kernel processing - srlx %g1, 8, %g3 ! put high vaddr bits in place - -1: - and %g3, %g2, %g3 ! get offset - ldxa [%g7 + %g3] ASI_PHYS_USE_EC, %g5! load pgd - sllx %g1, 2, %g4 ! begin pmd_offset formation - and %g4, %g2, %g3 ! and now mask it - ldxa [%g5 + %g3] ASI_PHYS_USE_EC, %g4! load pmd - /* I-cache line 1 */ - ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! get 8KB pointer bits - srlx %g1, 1, %g1 ! shift right to get pte_offset - ldxa [%g4 + %g1] ASI_PHYS_USE_EC, %g3! load pte - brlz,a,pt %g3, 2f ! is valid bit clear? - stxa %g3, [%g0] ASI_DTLB_DATA_IN ! nope, load TTE into DTLB - - ba,a,pt %xcc, sparc64_dtlb_refbit_catch ! longer processing needed -2: - retry ! return from trap - -#define KTTE_HIGH_BITS _PAGE_VALID | _PAGE_SZ4MB -#define KTTE_LOW_BITS _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W | _PAGE_G - - nop ! align next insn on cache line -3: - /* I-cache line 2 */ - srax %g1, 19, %g5 ! mask down high bits - cmp %g5, -1 ! if -1 this is VMALLOC area - be,pn %xcc, 1b ! yep - sethi %uhi(KTTE_HIGH_BITS), %g4 ! begin pte formation - - sllx %g1, 23, %g1 ! begin masking for physpage - sllx %g4, 32, %g4 ! high protection TTE bits - or %g4, (KTTE_LOW_BITS), %g4 ! low protection TTE bits - srlx %g1, 41, %g1 ! put physpage into place - /* I-cache line 3 */ - or %g4, %g1, %g1 ! finish TTE computation - stxa %g1, [%g0] ASI_DTLB_DATA_IN ! load TTE into DTLB - retry ! return from trap +/* The basic algorithm is: + * + * if(faulting_context != 0) { + * pgd = pgd_offset(current->mm.pgd, fault_address); + * page_table_walk_continue: + * pmd = pmd_offset(pgd, fault_address); + * pte = pte_offset(pmd, fault_address); + * if(pte & _PAGE_V) { + * tlb_load(pte, fault_address); + * return_from_trap(); + * } + * goto longer_processing; + * } else { + * if(fault_address >= KERNBASE && + * fault_address < VMALLOC_START) { + * tlb_load(__pa(fault_address) | PAGE_KERNEL); + * return_from_trap(); + * } else { + * pgd = pgd_offset(swapper_pg_dir, fault_address); + * goto page_table_walk_continue; + * } + * } + * + * This is optimized for user TLB misses on purpose. + */ - nop; nop; nop; nop; nop; +#define KERN_HIGHBITS (_PAGE_VALID | _PAGE_SZ4MB) +#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) +#define KERN_LOWBITS_IO (_PAGE_E | _PAGE_P | _PAGE_W) + + /* ICACHE line 1 */ + /*0x00*/ ldxa [%g0] ASI_DMMU, %g1 ! Get TAG_TARGET + /*0x04*/ srlx %g1, 8, %g3 ! Position PGD offset + /*0x08*/ srlx %g1, 48, %g5 ! Shift down CONTEXT bits + /*0x0c*/ and %g3, %g2, %g3 ! Mask PGD offset + /*0x10*/ sllx %g1, 2, %g4 ! Position PMD offset + /*0x14*/ brz,pn %g5, 3f ! Context 0 == kernel + /*0x18*/ and %g4, %g2, %g4 ! Mask PMD offset + /*0x1c*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset + + /* ICACHE line 2 */ + /*0x20*/ ldxa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load PGD + /*0x24*/ srlx %g1, 1, %g1 ! PTE offset +2:/*0x28*/ ldxa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD + /*0x2c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE + /*0x30*/ brlz,a,pt %g5, 1f ! Valid set? + /*0x34*/ stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load + /*0x38*/ ba,a,pt %xcc, sparc64_dtlb_refbit_catch ! Nope... +1:/*0x3c*/ retry ! Trap return + +3: /* ICACHE line 3 */ + /*0x40*/ sllx %g1, 43, %g5 ! This gets >= VMALLOC_START... + /*0x44*/ brlz,pn %g5, 4f ! ...if now less than zero. + /*0x48*/ andncc %g1, 0x3ff, %g0 ! Slick trick... + /*0x4c*/ be,pn %xcc, 4f ! Yes, it is some PROM mapping + /*0x50*/ srlx %g5, 21, %g5 ! This is now physical page + /*0x54*/ sethi %uhi(KERN_HIGHBITS), %g1 ! Construct PTE + /*0x58*/ sllx %g1, 32, %g1 ! Move priv bits up + /*0x5c*/ or %g1, %g5, %g1 ! Or in the page + + /* ICACHE line 4 */ + /*0x60*/ or %g1, (KERN_LOWBITS), %g1 ! Set low priv bits + /*0x64*/ stxa %g1, [%g0] ASI_DTLB_DATA_IN ! TLB load + /*0x68*/ retry ! Trap return +4:/*0x6c*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset + /*0x70*/ ldxa [%g6 + %g3] ASI_PHYS_USE_EC, %g5 ! Load kern PGD + /*0x74*/ ba,pt %xcc, 2b ! Go back up top + /*0x78*/ srlx %g1, 1, %g1 + /*0x7c*/ nop -#undef KTTE_HIGH_BITS -#undef KTTE_LOW_BITS +#undef KERN_HIGHBITS +#undef KERN_LOWBITS diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/dtlb_prot.S linux/arch/sparc64/kernel/dtlb_prot.S --- v2.1.33/linux/arch/sparc64/kernel/dtlb_prot.S Mon Mar 17 14:54:23 1997 +++ linux/arch/sparc64/kernel/dtlb_prot.S Fri Apr 11 10:47:36 1997 @@ -1,62 +1,56 @@ -/* $Id: dtlb_prot.S,v 1.5 1997/02/26 11:09:26 jj Exp $ - * dtlb_prot.S: Fast TLB protection trap processing. +/* $Id: dtlb_prot.S,v 1.10 1997/03/25 09:47:13 davem Exp $ + * dtlb_prot.S: Data TLB protection code, this is included directly + * into the trap table. * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ - /* We are in the MMU globals, %g7 contains the physical - * address of current->mm->pgd at all times. %g2 is - * also preloaded with the mask 0x1ff8 to make things - * even quicker. - * - * Many subtle things are done here. The high bits of - * the virtual address missed are most easily obtained - * from the tag target (it is at address zero in ASI_IMMU - * so no address formation is necessary to get at this). - * This is used to compute the pgd and pmd table offsets. - * - * Even more clever is that physical page zero is always - * a page full of zeroes. This means we can just follow - * through with all the page table traversals even if nothing - * is mapped because we'll just do loads from page zero - * and get yet another zero. We only need to do the check - * for the valid bit being set in the final pte we obtain. - * - * Furthermore, we set the TSB base register to the address - * zero, and we use the 8KB tsb ptr to calculate the pte - * offset. Again it is at address zero in ASI_IMMU_TSB_8KB_PTR - * so no address formation is necessary, saves more instructions. - * - * We use physical address accesses to get at the page - * tables, and this is for two reasons. This makes it - * impossible to take a fault while we are servicing the - * miss. Also this physical bypass access only allocates - * in the E-cache, and thus we prevent D-cache pollution - * from the miss handlers probing the page tables. + /* We know kernel never takes protection trap, + * this makes this routine a lot easier than it + * would be otherwise. */ - /* I-cache line 0 */ - ldxa [%g0] ASI_DMMU, %g1 - srlx %g1, 8, %g3 - and %g3, %g2, %g3 - ldxa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 - sllx %g1, 2, %g4 - and %g4, %g2, %g3 - ldxa [%g5 + %g3] ASI_PHYS_USE_EC, %g4 - ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 - /* I-cache line 1 */ - srlx %g1, 1, %g1 - ldxa [%g4 + %g1] ASI_PHYS_USE_EC, %g3 - andcc %g3, _PAGE_WRITE, %g0 - be,pn %xcc, sparc64_dtlb_fault - or %g3, (_PAGE_WRITE|_PAGE_W|_PAGE_MODIFIED|_PAGE_ACCESSED), %g3 - - /* Blamo... */ - stxa %g3, [%g4 + %g1] ASI_DMMU - stxa %g3, [%g0] ASI_DTLB_DATA_IN - retry - - /* I-cache line 2 */ - nop; nop; nop; nop; nop; nop; nop; nop; - /* I-cache line 3 */ - nop; nop; nop; nop; nop; nop; nop; nop; +#define MODIFIED_BITS (_PAGE_WRITE | _PAGE_W | _PAGE_MODIFIED | _PAGE_ACCESSED) + + /* ICACHE line 1 */ + /*0x00*/ ldxa [%g0] ASI_DMMU, %g1 ! Get TAG_TARGET + /*0x04*/ srlx %g1, 8, %g3 ! Position PGD offset + /*0x08*/ sllx %g1, 2, %g4 ! Position PMD offset + /*0x0c*/ and %g3, %g2, %g3 ! Mask PGD offset + /*0x10*/ and %g4, %g2, %g3 ! Mask PMD offset + /*0x14*/ ldxa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load PGD + /*0x18*/ ldxa [%g5 + %g3] ASI_PHYS_USE_EC, %g4 ! Load PMD + /*0x1c*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset + + /* ICACHE line 2 */ + /*0x20*/ srlx %g1, 1, %g1 ! PTE offset + /*0x24*/ ldxa [%g4 + %g1] ASI_PHYS_USE_EC, %g3 ! Load PTE + /*0x28*/ andcc %g3, _PAGE_WRITE, %g0 ! Writable? + /*0x2c*/ be,pt %xcc, sparc64_dtlb_fault ! Nope... + /*0x30*/ or %g3, (MODIFIED_BITS), %g3 ! Yes it is + /*0x34*/ mov TLB_TAG_ACCESS, %g5 ! Get the page + /*0x38*/ ldxa [%g5] ASI_DMMU, %g1 ! From MMU + /*0x3c*/ add %g2, 7, %g5 ! Compute mask + + /* ICACHE line 3 */ + /*0x40*/ andn %g1, %g5, %g1 ! Mask page + /*0x44*/ or %g1, 0x10, %g1 ! 2ndary Context + /*0x48*/ stxa %g0, [%g1] ASI_DMMU_DEMAP ! TLB flush page + /*0x4c*/ membar #Sync ! Synchronize + /*0x50*/ stxa %g3, [%g4 + %g1] ASI_PHYS_USE_EC ! Update sw PTE + /*0x54*/ stxa %g3, [%g0] ASI_DTLB_DATA_IN ! TLB load + /*0x58*/ retry ! Trap return + /*0x5c*/ nop + + /* ICACHE line 4 */ + /*0x60*/ nop + /*0x64*/ nop + /*0x68*/ nop + /*0x6c*/ nop + /*0x70*/ nop + /*0x74*/ nop + /*0x78*/ nop + /*0x7c*/ nop + +#undef MODIFIED_BITS diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S --- v2.1.33/linux/arch/sparc64/kernel/entry.S Thu Mar 27 14:40:00 1997 +++ linux/arch/sparc64/kernel/entry.S Mon Apr 14 09:31:09 1997 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.1 1997/03/18 17:58:59 jj Exp $ +/* $Id: entry.S,v 1.14 1997/04/14 06:56:54 davem Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -16,6 +16,7 @@ #include #include #include +#include #define curptr g6 @@ -23,6 +24,155 @@ .text .align 4 +/* FIXME: This is still debugging hack */ + .globl sparc64_dtlb_fault, sparc64_dtlb_refbit_catch, sparc64_itlb_refbit_catch +sparc64_dtlb_fault: + rdpr %pstate, %g1 + wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate + ba,pt %xcc, etrap + rd %pc, %g7 + call sparc64_dtlb_fault_handler + nop + +sparc64_dtlb_refbit_catch: + rdpr %pstate, %g1 + wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate + ba,pt %xcc, etrap + rd %pc, %g7 + call sparc64_dtlb_refbit_handler + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + +sparc64_itlb_refbit_catch: + rdpr %pstate, %g1 + wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate + ba,pt %xcc, etrap + rd %pc, %g7 + call sparc64_dtlb_refbit_handler + nop + + /* Note check out head.h, this code isn't even used for UP, + * for SMP things will be different. In particular the data + * registers for cross calls will be: + * + * DATA 0: Address of function to call + * DATA 1: Argument 1, place in %g6 + * DATA 2: Argument 2, place in %g7 + * + * With this method we can do most of the cross-call tlb/cache + * flushing in very quickly. + */ + .align 4 + .globl do_ivec +do_ivec: + ldxa [%g0] ASI_INTR_RECEIVE, %g1 + andcc %g1, 0x20, %g0 + be,pn %xcc, do_ivec_return + mov 0x40, %g2 + + /* Load up Interrupt Vector Data 0 register. */ + sethi %uhi(ivector_to_mask), %g4 + ldxa [%g2] ASI_UDB_INTR_R, %g3 + or %g4, %ulo(ivector_to_mask), %g4 + and %g3, 0x7ff, %g3 + sllx %g4, 32, %g4 + sethi %hi(ivector_to_mask), %g5 + sllx %g3, 3, %g3 + or %g5, %lo(ivector_to_mask), %g5 + add %g5, %g4, %g4 + ldx [%g4 + %g3], %g2 + brz,pn %g2, do_ivec_spurious + nop + + /* No branches, worse case we don't know about this interrupt + * yet, so we would just write a zero into the softint register + * which is completely harmless. + */ + wr %g2, 0x0, %set_softint + +do_ivec_return: + /* Acknowledge the UPA */ + stxa %g0, [%g0] ASI_INTR_RECEIVE + membar #Sync + retry + +do_ivec_spurious: + stxa %g0, [%g0] ASI_INTR_RECEIVE + rdpr %pstate, %g1 + wrpr %g1, PSTATE_IG | PSTATE_AG, %pstate + ba,pt %xcc, etrap + rd %pc, %g7 + call report_spurious_ivec + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,pt %xcc, rtrap + nop + +breakpoint_t: + .asciz "Breakpoint Trap %lx\n" + .align 4 + .globl breakpoint_trap +breakpoint_trap: + mov %o0, %o1 + sethi %hi(breakpoint_t), %o0 + or %o0, %lo(breakpoint_t), %o0 + call prom_printf + add %o0, %g4, %o0 + call prom_cmdline + nop + ba,a,pt %xcc, rtrap + + .globl sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall + +sys_pipe: + sethi %hi(sparc_pipe), %g1 + add %g1, %g4, %g1 + jmpl %g1 + %lo(sparc_pipe), %g0 + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + +sys_nis_syscall: + sethi %hi(c_sys_nis_syscall), %g1 + add %g1, %g4, %g1 + jmpl %g1 + %lo(c_sys_nis_syscall), %g0 + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + +sys_execve: + sethi %hi(sparc_execve), %g1 + add %g1, %g4, %g1 + jmpl %g1 + %lo(sparc_execve), %g0 + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + +sys_sigpause: + /* NOTE: %o0 has a correct value already */ + call do_sigpause + add %sp, STACK_BIAS + REGWIN_SZ, %o1 + + ld [%curptr + AOFF_task_flags], %l5 + andcc %l5, 0x20, %g0 + be,pt %icc, ret_sys_call + clr %o0 + call syscall_trace + nop + ba,pt %xcc, ret_sys_call + clr %o0 + + /* This is how fork() was meant to be done, 11 instruction entry. -DaveM */ + .globl sys_fork, sys_vfork, sys_clone +sys_fork: +sys_vfork: + mov SIGCHLD, %o0 + clr %o1 +sys_clone: + mov %o7, %l5 + flushw + rdpr %cwp, %o4 + add %sp, STACK_BIAS + REGWIN_SZ, %o2 + brz,a %o1, 1f + mov %fp, %o1 +1: + /* Don't try this at home. */ + stx %o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0] + call do_fork + add %l5, 8, %o7 + linux_sparc_ni_syscall: sethi %hi(sys_ni_syscall), %l7 or %l7, %lo(sys_ni_syscall), %l7 diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/etrap.S linux/arch/sparc64/kernel/etrap.S --- v2.1.33/linux/arch/sparc64/kernel/etrap.S Thu Mar 27 14:40:00 1997 +++ linux/arch/sparc64/kernel/etrap.S Fri Apr 11 10:47:36 1997 @@ -1,64 +1,114 @@ -/* $Id: etrap.S,v 1.5 1997/03/13 08:24:01 jj Exp $ +/* $Id: etrap.S,v 1.10 1997/04/03 13:03:49 davem Exp $ * etrap.S: Preparing for entry into the kernel on Sparc V9. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ +#include #include #include +#include +#include + +/* We assume that pstate, when entering this, has AG and IE bits set, MG and IG clear */ .text - .align 4 - .globl etrap + .align 32 + .globl etrap, etrap_irq etrap: - rdpr %wstate, %g2 - sethi %uhi(current_set), %g6 - andcc %g2, 7, %g2 - rdpr %tstate, %g1 - be,pn %xcc, 1f /* What happens more often? etrap when already in priv or from userland? */ - sllx %g6, 32, %g6 - /* Just when going from userland to privileged mode, we have to change this stuff. */ - sll %g2, 3, %g2 - wrpr %g2, %wstate - rdpr %canrestore, %g5 - wrpr %g0, 0, %canrestore - wrpr %g5, 0, %otherwin + rdpr %pil, %g4 +etrap_irq: + rdpr %wstate, %g5 + sllx %g4, 20, %g4 + rdpr %tstate, %g1 + rdpr %tpc, %g2 + or %g1, %g4, %g1 + rdpr %tnpc, %g3 + + /* What happens more often? etrap when already in priv or from userland? */ + andcc %g1, TSTATE_PRIV, %g0 + bne,a,pn %xcc, 1f + sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g5 + + /* Just when going from userland to privileged mode, + * we have to change this stuff. + * + * Setup to run in NUCLEUS context, stash user context in + * secondary for later trap return. Note we must not change + * trap level until PRIMARY_CONTEXT is set to zero, else + * we fall out of NUCLEUS too soon and crash hard. + */ + mov PRIMARY_CONTEXT, %g7 + ldxa [%g7] ASI_DMMU, %g4 + mov SECONDARY_CONTEXT, %g6 + stxa %g0, [%g7] ASI_DMMU + stxa %g4, [%g6] ASI_DMMU + wrpr %g0, 0x0, %tl + + sll %g5, 3, %g5 + sethi %uhi(KERNBASE), %g4 + or %g4, %ulo(KERNBASE), %g4 + sethi %hi(current_set), %g6 + or %g6, %lo(current_set), %g6 + sllx %g4, 32, %g4 + wrpr %g5, %wstate + rdpr %canrestore, %g5 + ldx [%g6 + %g4], %g6 +#ifdef __SMP__ +/* FIXME: Fix the above insn for SMP */ +#endif + wrpr %g0, 0, %canrestore + wrpr %g5, 0, %otherwin + ba,pt %xcc, 2f + ldx [%g6 + AOFF_task_saved_kernel_stack], %g5 1: - sethi %hi(current_set), %g4 - or %g4, %lo(current_set), %g4 - rdpr %tpc, %g2 - rdpr %tnpc, %g3 - ldx [%g6 + %g4], %g6 + wrpr %g0, 0x0, %tl +2: + rd %y, %g4 + stx %g1, [%g5 + REGWIN_SZ + PT_V9_TSTATE] + stx %g2, [%g5 + REGWIN_SZ + PT_V9_TPC] + stx %g3, [%g5 + REGWIN_SZ + PT_V9_TNPC] + stx %g4, [%g5 + REGWIN_SZ + PT_V9_Y] + rdpr %pstate, %g1 + save %g5, -STACK_BIAS, %sp + mov %g1, %l1 + mov %g7, %l2 + wrpr %l1, PSTATE_AG, %pstate + stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1] + stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2] + stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3] + stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4] + stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5] + stx %g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6] + stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7] + stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] + stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] + stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2] + stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3] + stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4] + stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5] + stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6] + stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7] + wrpr %l1, (PSTATE_IE | PSTATE_AG), %pstate + sethi %uhi(KERNBASE), %g4 + or %g4, %ulo(KERNBASE), %g4 + sethi %hi(current_set), %g6 + or %g6, %lo(current_set), %g6 + sllx %g4, 32, %g4 + jmpl %l2 + 0x4, %g0 + ldx [%g6 + %g4], %g6 #ifdef __SMP__ /* FIXME: Fix the above insn for SMP */ #endif - rd %y, %g4 - ldx [%g6 + AOFF_task_tss + AOFF_thread_ksp], %g5 - stx %g1, [%g5 + REGWIN_SZ + PT_TSTATE] - stx %g2, [%g5 + REGWIN_SZ + PT_TPC] - stx %g3, [%g5 + REGWIN_SZ + PT_TNPC] - stx %g4, [%g5 + REGWIN_SZ + PT_Y] - rdpr %pstate, %g1 - save %g5, -STACK_BIAS, %sp - andn %g1, (PSTATE_IG | PSTATE_MG | PSTATE_AG), %l1 - wrpr %g0, 0x0, %tl - mov %g7, %l2 - wrpr %l1, 0x0, %pstate - stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_G1] - stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_G2] - stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_G3] - stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_G4] - stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_G5] - stx %g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_G6] - stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_G7] - stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_I0] - stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_I1] - stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_I2] - stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_I3] - stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_I4] - stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_I5] - stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_I6] - stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_I7] - jmpl %l2 + 0x4, %g0 - wrpr %l1, PSTATE_IE, %pstate + + .globl etraptl1 +etraptl1: + rdpr %tl, %g4 + rdpr %tstate, %g1 + sub %g4, 1, %g4 + rdpr %tpc, %g2 + rdpr %tnpc, %g3 + wrpr %g4, 0x0, %tl + ba,pt %xcc, 1b + sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g5 diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/hack.S linux/arch/sparc64/kernel/hack.S --- v2.1.33/linux/arch/sparc64/kernel/hack.S Thu Mar 27 14:40:00 1997 +++ linux/arch/sparc64/kernel/hack.S Fri Apr 11 10:47:36 1997 @@ -4,36 +4,10 @@ to compile... */ .text .align 8 - .globl __copy_user -__copy_user: retl;nop - .globl __csum_partial_copy_sparc_generic -__csum_partial_copy_sparc_generic: retl;nop .globl _sigpause_common _sigpause_common: retl;nop - .globl _stext -_stext: retl;nop - .globl auxio_register -auxio_register: retl;nop - .globl bad_trap -bad_trap: retl;nop - .globl bad_trap_tl1 -bad_trap_tl1: retl;nop .globl breakpoint breakpoint: retl;nop - .globl breakpoint_trap -breakpoint_trap: retl;nop - .globl csum_partial -csum_partial: retl;nop - .globl ctx_free -ctx_free: .skip 32 - .globl ctx_list_pool -ctx_list_pool: .skip 32 - .globl ctx_used -ctx_used: .skip 32 - .globl destroy_context -destroy_context: retl;nop - .globl disable_irq -disable_irq: retl;nop .globl do_cee do_cee: retl;nop .globl do_cee_tl1 @@ -42,10 +16,6 @@ do_dae: retl;nop .globl do_dae_tl1 do_dae_tl1: retl;nop - .globl do_dax -do_dax: retl;nop - .globl do_dax_tl1 -do_dax_tl1: retl;nop .globl do_div0 do_div0: retl;nop .globl do_div0_tl1 @@ -62,16 +32,10 @@ do_fpother: retl;nop .globl do_fpother_tl1 do_fpother_tl1: retl;nop - .globl do_gettimeofday -do_gettimeofday: retl;nop .globl do_iae do_iae: retl;nop .globl do_iae_tl1 do_iae_tl1: retl;nop - .globl do_iax -do_iax: retl;nop - .globl do_iax_tl1 -do_iax_tl1: retl;nop .globl do_ill do_ill: retl;nop .globl do_ill_tl1 @@ -80,10 +44,6 @@ do_irq: retl;nop .globl do_irq_tl1 do_irq_tl1: retl;nop - .globl do_ivec -do_ivec: retl;nop - .globl do_ivec_tl1 -do_ivec_tl1: retl;nop .globl do_lddfmna do_lddfmna: retl;nop .globl do_lddfmna_tl1 @@ -100,8 +60,6 @@ do_privact: retl;nop .globl do_privop do_privop: retl;nop - .globl do_settimeofday -do_settimeofday: retl;nop .globl do_signal do_signal: retl;nop .globl do_stdfmna @@ -116,80 +74,30 @@ do_vaw: retl;nop .globl do_vaw_tl1 do_vaw_tl1: retl;nop - .globl enable_irq -enable_irq: retl;nop .globl floppy_hardint floppy_hardint: retl;nop - .globl flush_user_windows -flush_user_windows: retl;nop - .globl free_irq -free_irq: retl;nop .globl get_cpuid get_cpuid: retl;nop - .globl get_irq_list -get_irq_list: retl;nop .globl getcc getcc: retl;nop .globl halt halt: retl;nop .globl indirect_syscall indirect_syscall: retl;nop - .globl init_IRQ -init_IRQ: retl;nop .globl install_linux_ticker install_linux_ticker: retl;nop .globl install_obp_ticker install_obp_ticker: retl;nop - .globl iommu_init -iommu_init: retl;nop - .globl linux32_syscall -linux32_syscall: retl;nop - .globl linux64_syscall -linux64_syscall: retl;nop .globl linux_dbvec linux_dbvec: retl;nop .globl linux_num_cpus linux_num_cpus: retl;nop - .globl load_mmu -load_mmu: retl;nop - .globl mmu_get_scsi_one -mmu_get_scsi_one: retl;nop - .globl mmu_get_scsi_sgl -mmu_get_scsi_sgl: retl;nop - .globl mmu_info -mmu_info: retl;nop - .globl mmu_lockarea -mmu_lockarea: retl;nop - .globl mmu_release_scsi_one -mmu_release_scsi_one: retl;nop - .globl mmu_release_scsi_sgl -mmu_release_scsi_sgl: retl;nop - .globl mmu_unlockarea -mmu_unlockarea: retl;nop - .globl mstk48t02_regs -mstk48t02_regs: retl;nop .globl netbsd_syscall netbsd_syscall: retl;nop - .globl probe_irq_off -probe_irq_off: retl;nop - .globl probe_irq_on -probe_irq_on: retl;nop - .globl request_fast_irq -request_fast_irq: retl;nop - .globl request_irq -request_irq: retl;nop .globl setcc setcc: retl;nop .globl solaris_syscall solaris_syscall: retl;nop - .globl sparc64_dtlb_fault -sparc64_dtlb_fault: retl;nop - .globl sparc64_dtlb_refbit_catch -sparc64_dtlb_refbit_catch: retl;nop - .globl sparc64_itlb_refbit_catch -sparc64_itlb_refbit_catch: retl;nop - .globl spitfire_get_new_context -spitfire_get_new_context: retl;nop .globl sunos_mmap sunos_mmap: retl;nop .globl sunos_syscall @@ -198,22 +106,6 @@ svr4_getcontext: retl;nop .globl svr4_setcontext svr4_setcontext: retl;nop - .globl swapper_pg_dir -swapper_pg_dir: retl;nop - .globl switch_to -switch_to: retl;nop - .globl sys_call_table -sys_call_table: retl;nop - .globl time_init -time_init: retl;nop - .globl translate_namei -translate_namei: retl;nop - .globl translate_open_namei -translate_open_namei: retl;nop - .globl sparc_brk -sparc_brk: retl;nop - .globl sparc_sigaction -sparc_sigaction: retl;nop .globl sunos_accept sunos_accept: retl;nop .globl sunos_audit @@ -306,41 +198,17 @@ sunos_write: retl;nop .globl sunos_writev sunos_writev: retl;nop - .globl sys_aplib -sys_aplib: retl;nop - .globl sys_clone -sys_clone: retl;nop - .globl sys_execve -sys_execve: retl;nop - .globl sys_fork -sys_fork: retl;nop - .globl sys_getpagesize -sys_getpagesize: retl;nop - .globl sys_ipc -sys_ipc: retl;nop - .globl sys_mmap -sys_mmap: retl;nop - .globl sys_nis_syscall -sys_nis_syscall: retl;nop - .globl sys_pipe -sys_pipe: retl;nop .globl sys_ptrace sys_ptrace: retl;nop - .globl sys_sigpause -sys_sigpause: retl;nop .globl sys_sigreturn sys_sigreturn: retl;nop .globl sys_sigstack sys_sigstack: retl;nop .globl sys_sigsuspend sys_sigsuspend: retl;nop - .globl sys_vfork -sys_vfork: retl;nop .globl syscall_trace syscall_trace: retl;nop - .globl sparc_ultra_mapioaddr -sparc_ultra_mapioaddr: retl;nop - .globl sparc_ultra_unmapioaddr -sparc_ultra_unmapioaddr: retl;nop - .globl mmu_map_dma_area -mmu_map_dma_area: retl;nop + .globl sys32_ptrace +sys32_ptrace: retl;nop + .globl do_sigpause +do_sigpause: retl;nop diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S --- v2.1.33/linux/arch/sparc64/kernel/head.S Thu Mar 27 14:40:00 1997 +++ linux/arch/sparc64/kernel/head.S Fri Apr 11 10:47:36 1997 @@ -1,7 +1,7 @@ -/* $Id: head.S,v 1.17 1997/03/18 17:59:37 jj Exp $ +/* $Id: head.S,v 1.27 1997/04/04 00:49:49 davem Exp $ * head.S: Initial boot code for the Sparc64 port of Linux. * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 David Sitsky (David.Sitsky@anu.edu.au) * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -15,6 +15,7 @@ #include #include #include +#include /* This section from from _start to sparc64_boot_end should fit into * 0xffff.f800.0000.4000 to 0xffff.f800.0000.8000 and will be sharing space @@ -24,9 +25,11 @@ */ .text - .globl start, _start + .globl start, _start, stext, _stext _start: start: +_stext: +stext: bootup_user_stack: ! 0xfffff80000004000 b sparc64_boot @@ -63,6 +66,9 @@ * PROM entry point is on %o4 */ sparc64_boot: + /* Typically PROM has already enabled both MMU's and both on-chip + * caches, but we do it here anyway just to be paranoid. + */ mov (LSU_CONTROL_IC|LSU_CONTROL_DC|LSU_CONTROL_IM|LSU_CONTROL_DM), %g1 stxa %g1, [%g0] ASI_LSU_CONTROL @@ -70,8 +76,10 @@ * Make sure we are in privileged mode, have address masking, * using the ordinary globals and have enabled floating * point. - */ - + * + * Again, typically PROM has left %pil at 13 or similar, and + * (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE) in %pstate. + */ wrpr %g0, 0xf, %pil /* Interrupts off. */ wrpr %g0, (PSTATE_PRIV|PSTATE_PEF), %pstate @@ -90,7 +98,7 @@ set current_pc, %g5 add %g5, %g4, %g5 cmp %g3, %g5 - be %xcc,sun4u_init + be %xcc, sun4u_init nop create_mappings: @@ -99,59 +107,149 @@ sllx %g5, 32, %g5 or %g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W | _PAGE_G), %g5 - /* We aren't mapped in at KERNBASE, so we need to create - * an I and D tlb entry to map KERNBASE to 0. Both entries - * are 4 Megs mappings and are locked in. + /* Base of physical memory cannot reliably be assumed to be + * at 0x0! Figure out where it happens to be. -DaveM */ - set TLB_TAG_ACCESS, %g3 /* 0x30 */ - stxa %g4, [%g3] ASI_IMMU /* 0x50 */ - stxa %g5, [%g0] ASI_ITLB_DATA_IN /* 0x54 */ - membar #Sync + /* Put PADDR tlb data mask into %g3. */ + sethi %uhi(_PAGE_PADDR), %g3 + or %g3, %ulo(_PAGE_PADDR), %g3 + sllx %g3, 32, %g3 + sethi %hi(_PAGE_PADDR), %g7 + or %g7, %lo(_PAGE_PADDR), %g7 + or %g3, %g7, %g3 - /* Put KERNBASE into the I/D Tag Access Register (TAR) */ - stxa %g4, [%g3] ASI_DMMU /* 0x58 */ - stxa %g5, [%g0] ASI_DTLB_DATA_IN - membar #Sync + /* Walk through entire ITLB, looking for entry which maps + * our %pc currently, stick PADDR from there into %g5 tlb data. + */ + clr %l0 /* TLB entry walker. */ + set 0x1fff, %l2 /* Page mask. */ + rd %pc, %l3 + andn %l3, %l2, %g2 /* vaddr comparator */ +1: + /* Yes, the nops seem to be necessary for now, don't ask me why. -DaveM */ + ldxa [%l0] ASI_ITLB_TAG_READ, %g1 + nop + nop + nop + andn %g1, %l2, %g1 /* Get vaddr */ + cmp %g1, %g2 + be,a,pn %xcc, got_tlbentry + ldxa [%l0] ASI_ITLB_DATA_ACCESS, %g1 + cmp %l1, (63 << 3) + blu,pt %xcc, 1b + add %l0, (1 << 3), %l0 + +boot_failed: + /* Debugging 8-) */ + set 0xdeadbeef, %g1 + t 0x11 +got_tlbentry: + /* Nops here again, perhaps Cheetah/Blackbird are better behaved... */ + nop + nop nop - nop + and %g1, %g3, %g1 /* Mask to just get paddr bits. */ + sub %g1, %g2, %g1 /* Get rid of %pc offset to get base. */ + + /* NOTE: We hold on to %g1 paddr base as we need it below to lock + * NOTE: the PROM cif code into the TLB. + */ + + or %g5, %g1, %g5 /* Or it into TAG being built. */ + + /* PROM never puts any TLB entries into the MMU with the lock bit + * set. So we gladly use tlb entry 63 for KERNBASE, 62 for + * boot time locked PROM CIF handler page, we remove the locked + * bit for the CIF page in paging_init(). + */ + mov TLB_TAG_ACCESS, %g3 + mov (63 << 3), %g7 + stxa %g4, [%g3] ASI_IMMU /* KERNBASE into TLB TAG */ + stxa %g5, [%g7] ASI_ITLB_DATA_ACCESS /* TTE into TLB DATA */ membar #Sync - + + /* Same for DTLB */ + stxa %g4, [%g3] ASI_DMMU /* KERNBASE into TLB TAG */ + stxa %g5, [%g7] ASI_DTLB_DATA_ACCESS /* TTE into TLB DATA */ + membar #Sync + + /* Kill instruction prefetch queues. */ + flush %g4 + membar #Sync + ba,pt %xcc, go_to_highmem nop -/* Now do a non-relative jump so that PC is in high-memory */ go_to_highmem: - set sun4u_init, %g1 - jmpl %g1 + %g4, %g0 + /* Now do a non-relative jump so that PC is in high-memory */ + set sun4u_init, %g2 + jmpl %g2 + %g4, %g0 nop sun4u_init: - /* Remap our prom interface code */ - sethi %hi(__p1275_loc), %g7 - or %g7, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W | _PAGE_G | _PAGE_L), %g7 + /* Set ctx 0 */ + mov PRIMARY_CONTEXT, %g7 + stxa %g0, [%g7] ASI_DMMU + membar #Sync + + mov SECONDARY_CONTEXT, %g7 + stxa %g0, [%g7] ASI_DMMU + membar #Sync + /* The lock bit has to be removed from this page later on, - but before firing up init we will use PROM a lot, so we - lock it there now... */ + * but before firing up init we will use PROM a lot, so we + * lock it there now... + */ + + /* Compute PROM CIF interface page TTE. */ + sethi %hi(__p1275_loc), %g7 + or %g7, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W | _PAGE_L), %g7 sethi %uhi(_PAGE_VALID), %g5 sethi %hi(0x8000), %g3 sllx %g5, 32, %g5 mov TLB_TAG_ACCESS, %g6 or %g5, %g7, %g5 - stxa %g3, [%g6] ASI_IMMU - stxa %g5, [%g0] ASI_ITLB_DATA_IN + add %g5, %g1, %g5 /* Add in physbase. */ + + mov (62 << 3), %g7 /* TLB entry 62 */ + stxa %g3, [%g6] ASI_IMMU /* CIF page into TLB TAG */ + stxa %g5, [%g7] ASI_ITLB_DATA_ACCESS /* TTE into TLB DATA */ membar #Sync - stxa %g3, [%g6] ASI_DMMU - stxa %g5, [%g0] ASI_DTLB_DATA_IN + /* Same for DTLB */ + stxa %g3, [%g6] ASI_DMMU /* CIF page into TLB TAG */ + stxa %g5, [%g7] ASI_DTLB_DATA_ACCESS /* TTE into TLB DATA */ membar #Sync + + /* Kill instruction prefetch queues. */ flush %g3 + membar #Sync - nop - nop + /* We are now safely (we hope) in Nucleus context (0), rewrite + * the KERNBASE TTE's so they no longer have the global bit set. + * Don't forget to setup TAG_ACCESS first 8-) + */ + mov TLB_TAG_ACCESS, %g2 + stxa %g4, [%g2] ASI_IMMU + stxa %g4, [%g2] ASI_DMMU + + mov (63 << 3), %g7 + ldxa [%g7] ASI_ITLB_DATA_ACCESS, %g1 + andn %g1, (_PAGE_G), %g1 + stxa %g1, [%g7] ASI_ITLB_DATA_ACCESS membar #Sync - + + ldxa [%g7] ASI_DTLB_DATA_ACCESS, %g1 + andn %g1, (_PAGE_G), %g1 + stxa %g1, [%g7] ASI_DTLB_DATA_ACCESS + membar #Sync + + /* Kill instruction prefetch queues. */ + flush %g4 + membar #Sync + /* Compute the number of windows in this machine * store this in nwindows and nwindowsm1 */ @@ -170,28 +268,12 @@ mov %sp, %l6 mov %o4, %l7 -#if 0 -/* This is to dangerous for now... To many traps unfilled yet... */ - sethi %hi(sparc64_ttable_tl0), %g5 - add %g5, %g4, %g5 - wrpr %g5, %tba -#endif - sethi %hi(bootup_kernel_stack + 0x2000 - STACK_BIAS - REGWIN_SZ), %g5 or %g5, %lo(bootup_kernel_stack + 0x2000 - STACK_BIAS - REGWIN_SZ), %g5 add %g5, %g4, %sp mov 0, %fp - wrpr %g0, PSTATE_PEF | PSTATE_PRIV, %pstate wrpr %g0, 0, %wstate wrpr %g0, 0x0, %tl - fzero %f48 - fzero %f50 - fzero %f52 - fzero %f54 - fzero %f56 - fzero %f58 - fzero %f60 - fzero %f62 /* Clear the bss */ sethi %hi(8191), %l2 @@ -211,6 +293,10 @@ blu,pt %xcc, 1b add %l0, %g4, %o0 + /* Now clear empty_zero_page */ + call bzero_1page + mov %g4, %o0 + mov %l6, %o1 ! OpenPROM stack call prom_init mov %l7, %o0 ! OpenPROM cif handler @@ -219,6 +305,50 @@ call start_kernel nop /* Not reached... */ + + .globl setup_tba +setup_tba: + sethi %hi(sparc64_ttable_tl0), %g5 + add %g5, %g4, %g5 + wrpr %g5, %tba + + /* Set up MMU globals */ + rdpr %pstate, %o1 + wrpr %o1, PSTATE_MG, %pstate + + /* PGD/PMD offset mask, used by TLB miss handlers. */ + sethi %hi(0x1ff8), %g2 + or %g2, %lo(0x1ff8), %g2 + + /* Kernel PGDIR used by TLB miss handlers. */ + mov %o0, %g6 + + /* To catch bootup bugs, this is user PGDIR for TLB miss handlers. */ + clr %g7 + + /* Setup Interrupt globals */ + wrpr %o1, PSTATE_IG, %pstate + sethi %uhi(ivector_to_mask), %g4 + or %g4, %ulo(ivector_to_mask), %g4 + sethi %hi(ivector_to_mask), %g5 + or %g5, %lo(ivector_to_mask), %g5 + or %g5, %g4, %g1 /* IVECTOR table */ + mov 0x40, %g2 /* INTR data 0 register */ + + andn %o1, PSTATE_IE, %o1 + wrpr %g0, %g0, %wstate + wrpr %o1, %g0, %pstate + + /* Zap TSB BASE to zero with TSB_size==1. */ + mov TSB_REG, %o4 + mov 1, %o5 + stxa %o5, [%o4] ASI_DMMU + stxa %o5, [%o4] ASI_IMMU + + membar #Sync + + retl + nop sparc64_boot_end: .skip 0x2000 + _start - sparc64_boot_end diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/ioport.c linux/arch/sparc64/kernel/ioport.c --- v2.1.33/linux/arch/sparc64/kernel/ioport.c Thu Mar 27 14:40:00 1997 +++ linux/arch/sparc64/kernel/ioport.c Fri Apr 11 10:47:36 1997 @@ -1,4 +1,4 @@ -/* $Id: ioport.c,v 1.2 1997/03/18 17:59:31 jj Exp $ +/* $Id: ioport.c,v 1.7 1997/04/10 05:13:01 davem Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -22,6 +22,8 @@ static unsigned long dvma_next_free = DVMA_VADDR; unsigned long sparc_iobase_vaddr = IOBASE_VADDR; +extern void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr); + /* * sparc_alloc_io: * Map and allocates an obio device. @@ -39,8 +41,8 @@ * The virtual address where the mapping actually took place. */ -void *sparc_alloc_io (void *address, void *virtual, int len, char *name, - unsigned bus_type, int rdonly) +void *sparc_alloc_io (u32 address, void *virtual, int len, char *name, + u32 bus_type, int rdonly) { unsigned long vaddr, base_address; unsigned long addr = ((unsigned long) address) + (((unsigned long) bus_type) << 32); @@ -74,7 +76,7 @@ base_address = vaddr; /* Do the actual mapping */ for (; len > 0; len -= PAGE_SIZE) { - mapioaddr(addr, vaddr, rdonly); + mapioaddr(addr, vaddr, bus_type, rdonly); vaddr += PAGE_SIZE; addr += PAGE_SIZE; } @@ -103,8 +105,11 @@ * at addresses above DVMA_VADDR it will grab them, this way it does not * now have to know the peculiarities of where to read the Lance data * from. (for example) + * + * Returns CPU visible address for the buffer returned, dvma_addr is + * set to the DVMA visible address. */ -void *sparc_dvma_malloc (int len, char *name) +void *sparc_dvma_malloc (int len, char *name, __u32 *dvma_addr) { unsigned long vaddr, base_address; @@ -123,7 +128,8 @@ * pages are now mapped dynamically to save space. */ base_address = vaddr; - mmu_map_dma_area(base_address, len); + mmu_map_dma_area(base_address, len, dvma_addr); + /* Assign the memory area. */ dvma_next_free = PAGE_ALIGN(dvma_next_free+len); diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c --- v2.1.33/linux/arch/sparc64/kernel/irq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/irq.c Mon Apr 14 09:31:09 1997 @@ -0,0 +1,638 @@ +/* $Id: irq.c,v 1.11 1997/04/14 05:38:59 davem Exp $ + * irq.c: UltraSparc IRQ handling/init/registry. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include +#include +#include +#include +#include +#include /* XXX ADD add_foo_randomness() calls... -DaveM */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Internal flag, should not be visible elsewhere at all. */ +#define SA_SYSIO_MASKED 0x100 + +/* UPA nodes send interrupt packet to UltraSparc with first data reg value + * low 5 bits holding the IRQ identifier being delivered. We must translate + * this into a non-vector IRQ so we can set the softint on this cpu. To + * make things even more swift we store the complete mask here. + */ + +#define NUM_IVECS 2048 /* XXX may need more on sunfire/wildfire */ + +unsigned long ivector_to_mask[NUM_IVECS]; + +/* This is based upon code in the 32-bit Sparc kernel written mostly by + * David Redman (djhr@tadpole.co.uk). + */ +#define MAX_STATIC_ALLOC 4 +static struct irqaction static_irqaction[MAX_STATIC_ALLOC]; +static int static_irq_count = 0; + +static struct irqaction *irq_action[NR_IRQS+1] = { + NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL +}; + +int get_irq_list(char *buf) +{ + int i, len = 0; + struct irqaction *action; + + for(i = 0; i < (NR_IRQS + 1); i++) { + if(!(action = *(i + irq_action))) + continue; + len += sprintf(buf + len, "%2d: %8d %c %s", + i, kstat.interrupts[i], + (action->flags & SA_INTERRUPT) ? '+' : ' ', + action->name); + for(action = action->next; action; action = action->next) { + len += sprintf(buf+len, ",%s %s", + (action->flags & SA_INTERRUPT) ? " +" : "", + action->name); + } + len += sprintf(buf + len, "\n"); + } + return len; +} + +/* INO number to Sparc PIL level. */ +static unsigned char ino_to_pil[] = { + 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 0 */ + 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 1 */ + 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 2 */ + 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 3 */ + 3, /* Onboard SCSI */ + 5, /* Onboard Ethernet */ +/*XXX*/ 8, /* Onboard BPP */ + 0, /* Bogon */ + 13, /* Audio */ +/*XXX*/15, /* PowerFail */ + 0, /* Bogon */ + 0, /* Bogon */ + 12, /* Zilog Serial Channels (incl. Keyboard/Mouse lines) */ + 11, /* Floppy */ + 0, /* Spare Hardware (bogon for now) */ + 0, /* Keyboard (bogon for now) */ + 0, /* Mouse (bogon for now) */ + 0, /* Serial (bogon for now) */ + 0, 0, /* Bogon, Bogon */ + 10, /* Timer 0 */ + 11, /* Timer 1 */ + 0, 0, /* Bogon, Bogon */ + 15, /* Uncorrectable SBUS Error */ + 15, /* Correctable SBUS Error */ + 15, /* SBUS Error */ +/*XXX*/ 0, /* Power Management (bogon for now) */ +}; + +/* INO number to IMAP register offset for SYSIO external IRQ's. + * This should conform to both Sunfire/Wildfire server and Fusion + * desktop designs. + */ +#define offset(x) ((unsigned long)(&(((struct sysio_regs *)0)->x))) +#define bogon ((unsigned long) -1) +static unsigned long irq_offsets[] = { +/* SBUS Slot 0 --> 3, level 1 --> 7 */ +offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0), +offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0), +offset(imap_slot1),offset(imap_slot1),offset(imap_slot1),offset(imap_slot1), +offset(imap_slot1),offset(imap_slot1),offset(imap_slot1),offset(imap_slot1), +offset(imap_slot2),offset(imap_slot2),offset(imap_slot2),offset(imap_slot2), +offset(imap_slot2),offset(imap_slot2),offset(imap_slot2),offset(imap_slot2), +offset(imap_slot3),offset(imap_slot3),offset(imap_slot3),offset(imap_slot3), +offset(imap_slot3),offset(imap_slot3),offset(imap_slot3),offset(imap_slot3), +/* Onboard devices (not relevant/used on SunFire). */ +offset(imap_scsi), offset(imap_eth), offset(imap_bpp), bogon, +offset(imap_audio), offset(imap_pfail), bogon, bogon, +offset(imap_kms), offset(imap_flpy), offset(imap_shw), +offset(imap_kbd), offset(imap_ms), offset(imap_ser), bogon, bogon, +offset(imap_tim0), offset(imap_tim1), bogon, bogon, +offset(imap_ue), offset(imap_ce), offset(imap_sberr), +offset(imap_pmgmt), +}; + +#undef bogon + +#define NUM_IRQ_ENTRIES (sizeof(irq_offsets) / sizeof(irq_offsets[0])) + +/* Convert an "interrupts" property IRQ level to an SBUS/SYSIO + * Interrupt Mapping register pointer, or NULL if none exists. + */ +static unsigned int *irq_to_imap(unsigned int irq) +{ + unsigned long offset; + struct sysio_regs *sregs; + + if((irq == 14) || + (irq >= NUM_IRQ_ENTRIES) || + ((offset = irq_offsets[irq]) == ((unsigned long)-1))) + return NULL; + sregs = SBus_chain->iommu->sysio_regs; + offset += ((unsigned long) sregs); + return ((unsigned int *)offset) + 1; +} + +/* Convert Interrupt Mapping register pointer to assosciated + * Interrupt Clear register pointer. + */ +static unsigned int *imap_to_iclr(unsigned int *imap) +{ + unsigned long diff; + + diff = offset(iclr_unused0) - offset(imap_slot0); + return (unsigned int *) (((unsigned long)imap) + diff); +} + +#undef offset + +/* For non-SBUS IRQ's we do nothing, else we must enable them in the + * appropriate SYSIO interrupt map registers. + */ +void enable_irq(unsigned int irq) +{ + unsigned long tid; + unsigned int *imap; + + /* If this is for the tick interrupt, just ignore, note + * that this is the one and only locally generated interrupt + * source, all others come from external sources (essentially + * any UPA device which is an interruptor). (actually, on + * second thought Ultra can generate local interrupts for + * async memory errors and we may setup handlers for those + * at some point as well) + * + * XXX See commentary below in request_irq() this assumption + * XXX is broken and needs to be fixed. + */ + if(irq == 14) + return; + + /* Check for bogons. */ + imap = irq_to_imap(irq); + if(imap == NULL) + goto do_the_stb_watoosi; + + /* We send it to our UPA MID, for SMP this will be different. */ + __asm__ __volatile__("ldxa [%%g0] %1, %0" : "=r" (tid) : "i" (ASI_UPA_CONFIG)); + tid = ((tid & UPA_CONFIG_MID) << 9); + + /* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product + * of this SYSIO's preconfigured IGN in the SYSIO Control + * Register, the hardware just mirrors that value here. + * However for Graphics and UPA Slave devices the full + * SYSIO_IMAP_INR field can be set by the programmer here. + * (XXX we will have to handle those for FFB etc. XXX) + */ + *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID); + return; + +do_the_stb_watoosi: + printk("Cannot enable irq(%d), doing the \"STB Watoosi\" instead.", irq); + panic("Trying to enable bogon IRQ"); +} + +void disable_irq(unsigned int irq) +{ + unsigned int *imap; + + /* XXX Grrr, I know this is broken... */ + if(irq == 14) + return; + + /* Check for bogons. */ + imap = irq_to_imap(irq); + if(imap == NULL) + goto do_the_stb_watoosi; + + /* NOTE: We do not want to futz with the IRQ clear registers + * and move the state to IDLE, the SCSI code does call + * disable_irq() to assure atomicity in the queue cmd + * SCSI adapter driver code. Thus we'd lose interrupts. + */ + *imap &= ~(SYSIO_IMAP_VALID); + return; + +do_the_stb_watoosi: + printk("Cannot disable irq(%d), doing the \"STB Watoosi\" instead.", irq); + panic("Trying to enable bogon IRQ"); +} + +int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, const char *name, void *dev_cookie) +{ + struct irqaction *action, *tmp = NULL; + unsigned long flags; + unsigned int cpu_irq, *imap, *iclr; + + /* XXX This really is not the way to do it, the "right way" + * XXX is to have drivers set SA_SBUS or something like that + * XXX in irqflags and we base our decision here on whether + * XXX that flag bit is set or not. + */ + if(irq == 14) + cpu_irq = irq; + else + cpu_irq = ino_to_pil[irq]; + + if(!handler) + return -EINVAL; + + imap = irq_to_imap(irq); + + action = *(cpu_irq + irq_action); + if(action) { + if((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) + for (tmp = action; tmp->next; tmp = tmp->next) + ; + else + return -EBUSY; + + if((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) { + printk("Attempt to mix fast and slow interrupts on IRQ%d " + "denied\n", irq); + return -EBUSY; + } + action = NULL; /* Or else! */ + } + + save_and_cli(flags); + + /* If this is flagged as statically allocated then we use our + * private struct which is never freed. + */ + if(irqflags & SA_STATIC_ALLOC) + if(static_irq_count < MAX_STATIC_ALLOC) + action = &static_irqaction[static_irq_count++]; + else + printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed " + "using kmalloc\n", irq, name); + + if(action == NULL) + action = (struct irqaction *)kmalloc(sizeof(struct irqaction), + GFP_KERNEL); + + if(!action) { + restore_flags(flags); + return -ENOMEM; + } + + if(imap) { + int ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)); + + ivector_to_mask[ivindex] = (1<mask = (unsigned long) iclr; + irqflags |= SA_SYSIO_MASKED; + } else { + action->mask = 0; + } + + action->handler = handler; + action->flags = irqflags; + action->name = name; + action->next = NULL; + action->dev_id = dev_cookie; + + if(tmp) + tmp->next = action; + else + *(cpu_irq + irq_action) = action; + + enable_irq(irq); + restore_flags(flags); + return 0; +} + +void free_irq(unsigned int irq, void *dev_cookie) +{ + struct irqaction *action; + struct irqaction *tmp = NULL; + unsigned long flags; + unsigned int cpu_irq; + + if(irq == 14) + cpu_irq = irq; + else + cpu_irq = ino_to_pil[irq]; + action = *(cpu_irq + irq_action); + if(!action->handler) { + printk("Freeing free IRQ %d\n", irq); + return; + } + if(dev_cookie) { + for( ; action; action = action->next) { + if(action->dev_id == dev_cookie) + break; + tmp = action; + } + if(!action) { + printk("Trying to free free shared IRQ %d\n", irq); + return; + } + } else if(action->flags & SA_SHIRQ) { + printk("Trying to free shared IRQ %d with NULL device cookie\n", irq); + return; + } + + if(action->flags & SA_STATIC_ALLOC) { + printk("Attempt to free statically allocated IRQ %d (%s)\n", + irq, action->name); + return; + } + + save_and_cli(flags); + if(action && tmp) + tmp->next = action->next; + else + *(cpu_irq + irq_action) = action->next; + + if(action->flags & SA_SYSIO_MASKED) { + unsigned int *imap = irq_to_imap(irq); + if(imap != NULL) + ivector_to_mask[*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)] = 0; + else + printk("free_irq: WHeee, SYSIO_MASKED yet no imap reg.\n"); + } + + kfree(action); + if(!*(cpu_irq + irq_action)) + disable_irq(irq); + + restore_flags(flags); +} + +/* Per-processor IRQ locking depth, both SMP and non-SMP code use this. */ +unsigned int local_irq_count[NR_CPUS]; +atomic_t __sparc64_bh_counter; + +#ifdef __SMP__ +#error SMP not supported on sparc64 just yet +#else + +#define irq_enter(cpu, irq) (local_irq_count[cpu]++) +#define irq_exit(cpu, irq) (local_irq_count[cpu]--) + +#endif /* __SMP__ */ + +void report_spurious_ivec(struct pt_regs *regs) +{ + printk("IVEC: Spurious interrupt vector received at (%016lx)\n", + regs->tpc); + return; +} + +void unexpected_irq(int irq, void *dev_cookie, struct pt_regs *regs) +{ + int i; + struct irqaction *action; + unsigned int cpu_irq; + + cpu_irq = irq & NR_IRQS; + action = *(cpu_irq + irq_action); + + prom_printf("Unexpected IRQ[%d]: ", irq); + prom_printf("PC[%016lx] NPC[%016lx] FP[%016lx]\n", + regs->tpc, regs->tnpc, regs->u_regs[14]); + + if(action) { + prom_printf("Expecting: "); + for(i = 0; i < 16; i++) { + if(action->handler) + prom_printf("[%s:%d:0x%016lx] ", action->name, + i, (unsigned long) action->handler); + } + } + prom_printf("AIEEE\n"); + prom_printf("bogus interrupt received\n"); + prom_cmdline (); +} + +void handler_irq(int irq, struct pt_regs *regs) +{ + struct irqaction *action; + int cpu = smp_processor_id(); + + /* XXX */ + if(irq != 14) + clear_softint(1 << irq); + + irq_enter(cpu, irq); + action = *(irq + irq_action); + kstat.interrupts[irq]++; + do { + if(!action || !action->handler) + unexpected_irq(irq, 0, regs); + action->handler(irq, action->dev_id, regs); + if(action->flags & SA_SYSIO_MASKED) + *((unsigned int *)action->mask) = SYSIO_ICLR_IDLE; + } while((action = action->next) != NULL); + irq_exit(cpu, irq); +} + +#ifdef CONFIG_BLK_DEV_FD +extern void floppy_interrupt(int irq, void *dev_cookie, struct pt_regs *regs); + +void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs) +{ + struct irqaction *action = *(irq + irq_action); + int cpu = smp_processor_id(); + + irq_enter(cpu, irq); + floppy_interrupt(irq, dev_cookie, regs); + if(action->flags & SA_SYSIO_MASKED) + *((unsigned int *)action->mask) = SYSIO_ICLR_IDLE; + irq_exit(cpu, irq); +} +#endif + +/* XXX This needs to be written for floppy driver, and soon will be necessary + * XXX for serial driver as well. + */ +int request_fast_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, const char *name) +{ + return -1; +} + +/* We really don't need these at all on the Sparc. We only have + * stubs here because they are exported to modules. + */ +unsigned long probe_irq_on(void) +{ + return 0; +} + +int probe_irq_off(unsigned long mask) +{ + return 0; +} + +/* XXX This is a hack, make it per-cpu so that SMP port will work correctly + * XXX with mixed MHZ Ultras in the machine. -DaveM + */ +static unsigned long cpu_cfreq; +static unsigned long tick_offset; + +/* XXX This doesn't belong here, just do this cruft in the timer.c handler code. */ +static void timer_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + extern void timer_interrupt(int, void *, struct pt_regs *); + unsigned long compare; + + if (!(get_softint () & 1)) { + /* Just to be sure... */ + clear_softint(1 << 14); + printk("Spurious level14 at %016lx\n", regs->tpc); + return; + } + + timer_interrupt(irq, dev_id, regs); + + /* Acknowledge INT_TIMER */ + clear_softint(1 << 0); + + /* Set up for next timer tick. */ + __asm__ __volatile__("rd %%tick_cmpr, %0\n\t" + "add %0, %1, %0\n\t" + "wr %0, 0x0, %%tick_cmpr" + : "=r" (compare) + : "r" (tick_offset)); +} + +/* This is called from time_init() to get the jiffies timer going. */ +void init_timers(void (*cfunc)(int, void *, struct pt_regs *)) +{ + int node, err; + + /* XXX FIX this for SMP -JJ */ + node = linux_cpus [0].prom_node; + cpu_cfreq = prom_getint(node, "clock-frequency"); + tick_offset = cpu_cfreq / HZ; + err = request_irq(14, timer_handler, (SA_INTERRUPT|SA_STATIC_ALLOC), + "timer", NULL); + if(err) { + prom_printf("Serious problem, cannot register timer interrupt\n"); + prom_halt(); + } else { + unsigned long flags; + + save_and_cli(flags); + + __asm__ __volatile__("wr %0, 0x0, %%tick_cmpr\n\t" + "wrpr %%g0, 0x0, %%tick" + : /* No outputs */ + : "r" (tick_offset)); + + clear_softint (get_softint ()); + + restore_flags(flags); + } + sti(); +} + +/* We use this nowhere else, so only define it's layout here. */ +struct sun5_timer { + volatile u32 count0, _unused0; + volatile u32 limit0, _unused1; + volatile u32 count1, _unused2; + volatile u32 limit1, _unused3; +} *prom_timers; + +static void map_prom_timers(void) +{ + unsigned int addr[3]; + int tnode, err; + + /* PROM timer node hangs out in the top level of device siblings... */ + tnode = prom_finddevice("/counter-timer"); + + /* Assume if node is not present, PROM uses different tick mechanism + * which we should not care about. + */ + if(tnode == 0) { + prom_timers = (struct sun5_timer *) 0; + prom_printf("AIEEE, no timers\n"); + return; + } + + /* If PROM is really using this, it must be mapped by him. */ + err = prom_getproperty(tnode, "address", (char *)addr, sizeof(addr)); + if(err == -1) { + prom_printf("PROM does not have timer mapped, trying to continue.\n"); + prom_timers = (struct sun5_timer *) 0; + return; + } + prom_timers = (struct sun5_timer *) addr[0]; +} + +static void kill_prom_timer(void) +{ + if(!prom_timers) + return; + + /* Just as in sun4c/sun4m PROM uses timer which ticks at IRQ 14. + * We turn both off here just to be paranoid. + */ + prom_timers->limit0 = 0; + prom_timers->limit1 = 0; +} + +#if 0 /* Unused at this time. -DaveM */ +static void enable_prom_timer(void) +{ + if(!prom_timers) + return; + + /* Set it to fire off every 10ms. */ + prom_timers->limit1 = 0xa000270f; + prom_timers->count1 = 0; +} +#endif + +__initfunc(void init_IRQ(void)) +{ + int i; + + map_prom_timers(); + kill_prom_timer(); + for(i = 0; i < NUM_IVECS; i++) + ivector_to_mask[i] = 0; + + /* We need to clear any IRQ's pending in the soft interrupt + * registers, a spurious one could be left around from the + * PROM timer which we just disabled. + */ + clear_softint(get_softint()); + + /* Now that ivector table is initialized, it is safe + * to receive IRQ vector traps. We will normally take + * one or two right now, in case some device PROM used + * to boot us wants to speak to us. We just ignore them. + */ + __asm__ __volatile__("rdpr %%pstate, %%g1\n\t" + "or %%g1, %0, %%g1\n\t" + "wrpr %%g1, 0x0, %%pstate" + : /* No outputs */ + : "i" (PSTATE_IE) + : "g1"); +} diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/itlb_miss.S linux/arch/sparc64/kernel/itlb_miss.S --- v2.1.33/linux/arch/sparc64/kernel/itlb_miss.S Mon Mar 17 14:54:23 1997 +++ linux/arch/sparc64/kernel/itlb_miss.S Fri Apr 11 10:47:36 1997 @@ -1,71 +1,49 @@ -/* $Id: itlb_miss.S,v 1.5 1997/02/25 20:00:05 jj Exp $ +/* $Id: itlb_miss.S,v 1.10 1997/03/26 12:24:18 davem Exp $ * itlb_miss.S: Instruction TLB miss code, this is included directly * into the trap table. * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ - /* We are in the MMU globals, %g7 contains the physical - * address of current->mm->pgd at all times. %g2 is - * also preloaded with the mask 0x1ff8 to make things - * even quicker. - * - * Many subtle things are done here. The high bits of - * the virtual address missed are most easily obtained - * from the tag target (it is at address zero in ASI_IMMU - * so no address formation is necessary to get at this). - * This is used to compute the pgd and pmd table offsets. - * - * Even more clever is that physical page zero is always - * a page full of zeroes. This means we can just follow - * through with all the page table traversals even if nothing - * is mapped because we'll just do loads from page zero - * and get yet another zero. We only need to do the check - * for the valid bit being set in the final pte we obtain. - * - * Furthermore, we set the TSB base register to the address - * zero, and we use the 8KB tsb ptr to calculate the pte - * offset. Again it is at address zero in ASI_IMMU_TSB_8KB_PTR - * so no address formation is necessary, saves more instructions. - * - * We use physical address accesses to get at the page - * tables, and this is for two reasons. This makes it - * impossible to take a fault while we are servicing the - * miss. Also this physical bypass access only allocates - * in the E-cache, and thus we prevent D-cache pollution - * from the miss handlers probing the page tables. - * - * It looks very hairy and slow. But I take only 1 more - * overhead of loads from ram than the Solaris version, and - * my version is one instruction quicker for a true TLB miss. - * And more importantly, all true TLB misses under Linux will be - * serviced in _constant_ time. When using the TSB in the - * manner it was intended to be used (like solaris does) the - * overhead for a TLB miss is _indeterminate_ especially during - * processes startup when the TSB is cold. - */ +/* Gratuitous comment. */ - /* I-cache line 0 */ - ldxa [%g0] ASI_IMMU, %g1 ! grab Tag Target - srlx %g1, 8, %g3 ! put high vaddr bits in place - and %g3, %g2, %g3 ! get offset - ldxa [%g7 + %g3] ASI_PHYS_USE_EC, %g5! load pgd - sllx %g1, 2, %g4 ! begin pmd_offset formation - and %g4, %g2, %g3 ! and now mask it - ldxa [%g5 + %g3] ASI_PHYS_USE_EC, %g4! load pmd - ldxa [%g0] ASI_IMMU_TSB_8KB_PTR, %g1 ! get 8KB pointer bits - /* I-cache line 1 */ - srlx %g1, 1, %g1 ! shift right to get pte_offset - ldxa [%g4 + %g1] ASI_PHYS_USE_EC, %g2! load pte - brlz,a,pt %g2, 1f ! is valid bit clear? - stxa %g2, [%g0] ASI_ITLB_DATA_IN ! nope, load TTE into ITLB + /* ICACHE line 1 */ + /*0x00*/ ldxa [%g0] ASI_IMMU, %g1 ! Get TAG_TARGET + /*0x04*/ srlx %g1, 8, %g3 ! Position PGD offset + /*0x08*/ srlx %g1, 48, %g5 ! Shift down CONTEXT bits + /*0x0c*/ and %g3, %g2, %g3 ! Mask PGD offset + /*0x10*/ sllx %g1, 2, %g4 ! Position PMD offset + /*0x14*/ ldxa [%g0] ASI_IMMU_TSB_8KB_PTR, %g1 ! For PTE offset + /*0x18*/ brz,pn %g5, 3f ! Context 0 == kernel + /*0x1c*/ and %g4, %g2, %g4 ! Mask PMD offset - ba,a,pt %xcc, sparc64_itlb_refbit_catch ! longer processing needed -1: - retry ! return from trap + /* ICACHE line 2 */ + /*0x20*/ ldxa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load user PGD + /*0x24*/ srlx %g1, 1, %g1 ! PTE offset + /*0x28*/ ldxa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD +2:/*0x2c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE + /*0x30*/ brlz,a,pt %g5, 1f ! Valid set? + /*0x34*/ stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load + /*0x38*/ ba,a,pt %xcc, sparc64_itlb_refbit_catch ! Nope... +1:/*0x3c*/ retry ! Trap return - nop; nop; - /* I-cache line 2 */ - nop; nop; nop; nop; nop; nop; nop; nop; - /* I-cache line 3 */ - nop; nop; nop; nop; nop; nop; nop; nop; +3: /* ICACHE line 3 */ + /*0x40*/ ldxa [%g6 + %g3] ASI_PHYS_USE_EC, %g5 ! Load kern PGD + /*0x44*/ srlx %g1, 1, %g1 ! PTE offset + /*0x48*/ ba,pt %xcc, 2b ! Continue above + /*0x4c*/ ldxa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD + /*0x50*/ nop + /*0x54*/ nop + /*0x58*/ nop + /*0x5c*/ nop + + /* ICACHE line 4 */ + /*0x60*/ nop + /*0x64*/ nop + /*0x68*/ nop + /*0x6c*/ nop + /*0x70*/ nop + /*0x74*/ nop + /*0x78*/ nop + /*0x7c*/ nop diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c --- v2.1.33/linux/arch/sparc64/kernel/process.c Mon Mar 17 14:54:23 1997 +++ linux/arch/sparc64/kernel/process.c Fri Apr 11 10:47:36 1997 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.3 1997/03/04 16:26:56 jj Exp $ +/* $Id: process.c,v 1.6 1997/04/07 18:57:07 jj Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) @@ -35,8 +35,7 @@ #include #include #include - -extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *); +#include #ifndef __SMP__ @@ -149,13 +148,13 @@ void show_regwindow(struct reg_window *rw) { - printk("l0: %016lx l1: %016lx l2: %016lx l3: %016lx\n" - "l4: %016lx l5: %016lx l6: %016lx l7: %016lx\n", - rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3], + printk("l0: %016lx l1: %016lx l2: %016lx l3: %016lx\n", + rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3]); + printk("l4: %016lx l5: %016lx l6: %016lx l7: %016lx\n", rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]); - printk("i0: %016lx i1: %016lx i2: %016lx i3: %016lx\n" - "i4: %016lx i5: %016lx i6: %016lx i7: %016lx\n", - rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3], + printk("i0: %016lx i1: %016lx i2: %016lx i3: %016lx\n", + rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3]); + printk("i4: %016lx i5: %016lx i6: %016lx i7: %016lx\n", rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]); } @@ -205,13 +204,13 @@ unsigned *stk; int i; - printk("l0: %08x l1: %08x l2: %08x l3: %08x\n" - "l4: %08x l5: %08x l6: %08x l7: %08x\n", - sf->locals[0], sf->locals[1], sf->locals[2], sf->locals[3], + printk("l0: %08x l1: %08x l2: %08x l3: %08x\n", + sf->locals[0], sf->locals[1], sf->locals[2], sf->locals[3]); + printk("l4: %08x l5: %08x l6: %08x l7: %08x\n", sf->locals[4], sf->locals[5], sf->locals[6], sf->locals[7]); - printk("i0: %08x i1: %08x i2: %08x i3: %08x\n" - "i4: %08x i5: %08x fp: %08x ret_pc: %08x\n", - sf->ins[0], sf->ins[1], sf->ins[2], sf->ins[3], + printk("i0: %08x i1: %08x i2: %08x i3: %08x\n", + sf->ins[0], sf->ins[1], sf->ins[2], sf->ins[3]); + printk("i4: %08x i5: %08x fp: %08x ret_pc: %08x\n", sf->ins[4], sf->ins[5], sf->fp, sf->callers_pc); printk("sp: %08x x0: %08x x1: %08x x2: %08x\n" "x3: %08x x4: %08x x5: %08x xx: %08x\n", @@ -246,7 +245,9 @@ printk("o4: %016lx o5: %016lx sp: %016lx ret_pc: %016lx\n", regs->u_regs[12], regs->u_regs[13], regs->u_regs[14], regs->u_regs[15]); - show_regwindow((struct reg_window *)regs->u_regs[14]); +#if 0 + show_regwindow((struct reg_window *)(regs->u_regs[14] + STACK_BIAS)); +#endif } void show_regs32(struct pt_regs32 *regs) @@ -295,8 +296,6 @@ /* XXX missing: float_regs */ printk("fsr: 0x%016lx\n", tss->fsr); - printk("fpqdepth: 0x%016lx\n", tss->fpqdepth); - /* XXX missing: fpqueue */ printk("sstk_info.stack: 0x%016lx\n", (unsigned long)tss->sstk_info.the_stack); @@ -313,33 +312,22 @@ */ void exit_thread(void) { -#if 0 - kill_user_windows(); #ifndef __SMP__ if(last_task_used_math == current) { #else if(current->flags & PF_USEDFPU) { #endif - /* Keep process from leaving FPU in a bogon state. */ - put_psr(get_psr() | PSR_EF); - fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr, - ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); #ifndef __SMP__ last_task_used_math = NULL; #else current->flags &= ~PF_USEDFPU; #endif } - mmu_exit_hook(); -#endif } void flush_thread(void) { -#if 0 - kill_user_windows(); current->tss.w_saved = 0; - current->tss.uwinmask = 0; current->tss.sstk_info.cur_status = 0; current->tss.sstk_info.the_stack = 0; @@ -350,18 +338,13 @@ #else if(current->flags & PF_USEDFPU) { #endif - /* Clean the fpu. */ - put_psr(get_psr() | PSR_EF); - fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr, - ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); #ifndef __SMP__ last_task_used_math = NULL; #else current->flags &= ~PF_USEDFPU; #endif } - mmu_flush_hook(); -#endif + /* Now, this task is no longer a kernel thread. */ current->tss.flags &= ~SPARC_FLAG_KTHREAD; current->tss.current_ds = USER_DS; @@ -418,10 +401,10 @@ static __inline__ struct sparc_stackf * clone_stackframe(struct sparc_stackf *dst, struct sparc_stackf *src) { - unsigned long size; struct sparc_stackf *sp; #if 0 + unsigned long size; size = ((unsigned long)src->fp) - ((unsigned long)src); sp = (struct sparc_stackf *)(((unsigned long)dst) - size); @@ -452,7 +435,7 @@ struct task_struct *p, struct pt_regs *regs) { struct pt_regs *childregs; - struct reg_window *new_stack; + struct reg_window *new_stack, *old_stack; unsigned long stack_offset; #if 0 @@ -462,8 +445,7 @@ if(current->flags & PF_USEDFPU) { #endif put_psr(get_psr() | PSR_EF); - fpsave(&p->tss.float_regs[0], &p->tss.fsr, - &p->tss.fpqueue[0], &p->tss.fpqdepth); + fpsave(&p->tss.float_regs[0], &p->tss.fsr); #ifdef __SMP__ current->flags &= ~PF_USEDFPU; #endif @@ -471,27 +453,28 @@ #endif /* Calculate offset to stack_frame & pt_regs */ - stack_offset = ((PAGE_SIZE<<1) - TRACEREG_SZ); + stack_offset = (PAGE_SIZE - TRACEREG_SZ); -#if 0 - if(regs->psr & PSR_PS) + if(regs->tstate & TSTATE_PRIV) stack_offset -= REGWIN_SZ; -#endif + childregs = ((struct pt_regs *) (p->kernel_stack_page + stack_offset)); - copy_regs(childregs, regs); + *childregs = *regs; new_stack = (((struct reg_window *) childregs) - 1); - copy_regwin(new_stack, (((struct reg_window *) regs) - 1)); + old_stack = (((struct reg_window *) regs) - 1); + *new_stack = *old_stack; -#if 0 - p->tss.ksp = p->saved_kernel_stack = (unsigned long) new_stack; - p->tss.kpc = (((unsigned long) ret_from_syscall) - 0x8); - p->tss.kpsr = current->tss.fork_kpsr; - p->tss.kwim = current->tss.fork_kwim; + p->saved_kernel_stack = ((unsigned long) new_stack); + p->tss.ksp = p->saved_kernel_stack - STACK_BIAS; + p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8; p->tss.kregs = childregs; -#endif -#if 0 - if(regs->psr & PSR_PS) { + /* Don't look... */ + p->tss.cwp = regs->u_regs[UREG_G0]; + + /* tss.wstate was copied by do_fork() */ + + if(regs->tstate & TSTATE_PRIV) { childregs->u_regs[UREG_FP] = p->tss.ksp; p->tss.flags |= SPARC_FLAG_KTHREAD; p->tss.current_ds = KERNEL_DS; @@ -501,6 +484,7 @@ p->tss.flags &= ~SPARC_FLAG_KTHREAD; p->tss.current_ds = USER_DS; +#if 0 if (sp != current->tss.kregs->u_regs[UREG_FP]) { struct sparc_stackf *childstack; struct sparc_stackf *parentstack; @@ -529,8 +513,8 @@ childregs->u_regs[UREG_FP] = (unsigned long)childstack; } +#endif } -#endif /* Set the return value for the child. */ childregs->u_regs[UREG_I0] = current->pid; @@ -538,6 +522,13 @@ /* Set the return value for the parent. */ regs->u_regs[UREG_I1] = 0; +#if 0 + printk("CHILD register dump\n"); + show_regs(childregs); + show_regwindow(new_stack); + while(1) + barrier(); +#endif return 0; } @@ -546,8 +537,8 @@ */ void dump_thread(struct pt_regs * regs, struct user * dump) { - unsigned long first_stack_page; #if 0 + unsigned long first_stack_page; dump->magic = SUNOS_CORE_MAGIC; dump->len = sizeof(struct user); dump->regs.psr = regs->psr; @@ -567,9 +558,6 @@ memcpy(&dump->fpu.fpstatus.fregs.regs[0], ¤t->tss.float_regs[0], (sizeof(unsigned long) * 32)); dump->fpu.fpstatus.fsr = current->tss.fsr; dump->fpu.fpstatus.flags = dump->fpu.fpstatus.extra = 0; - dump->fpu.fpstatus.fpq_count = current->tss.fpqdepth; - memcpy(&dump->fpu.fpstatus.fpq[0], ¤t->tss.fpqueue[0], - ((sizeof(unsigned long) * 2) * 16)); dump->sigcode = current->tss.sig_desc; #endif } diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S --- v2.1.33/linux/arch/sparc64/kernel/rtrap.S Thu Mar 27 14:40:01 1997 +++ linux/arch/sparc64/kernel/rtrap.S Fri Apr 11 10:47:36 1997 @@ -1,68 +1,83 @@ -/* $Id: rtrap.S,v 1.4 1997/03/13 16:24:55 jj Exp $ +/* $Id: rtrap.S,v 1.11 1997/04/03 13:03:50 davem Exp $ * rtrap.S: Preparing for return from trap on Sparc V9. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) */ +#include #include #include +#include + +/* We assume here this is entered with AG, MG and IG bits in pstate clear */ .text .align 4 .globl rtrap rtrap: - sethi %hi(intr_count), %l0 - or %l0, %lo(intr_count), %l0 - ld [%l0 + %g4], %l1 sethi %hi(bh_active), %l2 - brz,pt %l1, 2f - or %l2, %lo(bh_active), %l2 + or %l2, %lo(bh_active), %l2 sethi %hi(bh_mask), %l1 or %l1, %lo(bh_mask), %l1 -1: ldx [%l2 + %g4], %l3 ldx [%l1 + %g4], %l4 andcc %l3, %l4, %g0 be,pt %xcc, 2f - mov 1, %l7 + nop call do_bottom_half - st %l7, [%l0 + %g4] - ba,pt %xcc, 1b - st %g0, [%l0 + %g4] + nop 2: - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE], %l1 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC], %l2 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %l1 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %l2 + sethi %hi(0xf << 20), %l4 andcc %l1, TSTATE_PRIV, %l3 + and %l1, %l4, %l4 rdpr %pstate, %l7 + andn %l1, %l4, %l1 /* XXX May not be needed -DaveM */ be,pt %icc, to_user andn %l7, PSTATE_IE, %l7 3: - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_G1], %g1 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_G2], %g2 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_G3], %g3 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_G4], %g4 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_G5], %g5 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_G6], %g6 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_G7], %g7 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_I0], %i0 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_I1], %i1 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_I2], %i2 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_I3], %i3 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_I4], %i4 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_I5], %i5 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_I6], %i6 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_I7], %i7 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_Y], %o3 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC], %o2 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1], %g1 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2], %g2 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3], %g3 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4], %g4 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5], %g5 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6], %g6 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7], %g7 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %i0 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1], %i1 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2], %i2 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3], %i3 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4], %i4 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5], %i5 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6], %i6 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7], %i7 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_Y], %o3 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %o2 + rdpr %tl, %o4 wr %o3, %g0, %y + add %o4, 1, %o4 + + srl %l4, 20, %l4 wrpr %l7, %g0, %pstate - wrpr %g0, 1, %tl + wrpr %l4, 0x0, %pil + wrpr %o4, %g0, %tl wrpr %l1, %g0, %tstate wrpr %l2, %g0, %tpc brnz,pn %l3, 1f wrpr %o2, %g0, %tnpc - /* we came here from to_user, ie. we have now AG */ + + /* We came here from to_user, ie. we have now AG. + * Also have to push user context back into primary. + */ restore + + mov SECONDARY_CONTEXT, %g6 + mov PRIMARY_CONTEXT, %g7 + ldxa [%g6] ASI_DMMU, %g4 + stxa %g4, [%g7] ASI_DMMU + rdpr %wstate, %g1 rdpr %otherwin, %g2 srl %g1, 3, %g1 @@ -77,7 +92,7 @@ sethi %hi(need_resched), %l0 or %l0, %lo(need_resched), %l0 ld [%l0 + %g4], %l0 - wrpr %o4, PSTATE_IE, %pstate + wrpr %l7, PSTATE_IE, %pstate brz,pt %l0, 1f ldx [%g6 + AOFF_task_signal], %l0 call schedule @@ -85,7 +100,7 @@ 1: ldx [%g6 + AOFF_task_blocked], %o0 or %l7, PSTATE_AG, %l7 ! Will need this for setting back wstate - andcc %l0, %o0, %g0 + andncc %l0, %o0, %g0 be,pt %xcc, 3b mov %l5, %o2 mov %l6, %o3 diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c --- v2.1.33/linux/arch/sparc64/kernel/setup.c Thu Mar 27 14:40:01 1997 +++ linux/arch/sparc64/kernel/setup.c Fri Apr 11 10:47:36 1997 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.1 1997/03/11 17:37:04 jj Exp $ +/* $Id: setup.c,v 1.5 1997/04/04 00:49:52 davem Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -96,7 +96,7 @@ extern void rs_kgdb_hook(int tty_num); /* sparc/serial.c */ -unsigned int boot_flags; +unsigned int boot_flags = 0; #define BOOTME_DEBUG 0x1 #define BOOTME_SINGLE 0x2 #define BOOTME_KGDB 0x4 @@ -109,10 +109,12 @@ void kernel_enter_debugger(void) { +#if 0 if (boot_flags & BOOTME_KGDB) { printk("KGDB: Entered\n"); breakpoint(); } +#endif } int obp_system_intr(void) @@ -205,7 +207,7 @@ #endif if (!strncmp(commands, "mem=", 4)) { /* - * "mem=XXX[kKmM] overrides the PROM-reported + * "mem=XXX[kKmM]" overrides the PROM-reported * memory size. */ memory_size = simple_strtoul(commands + 4, @@ -245,9 +247,14 @@ char saved_command_line[256]; char reboot_command[256]; +unsigned long phys_base; + +static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 }; + __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)) { + unsigned long lowest_paddr; int total, i; /* Initialize PROM console and command line. */ @@ -271,11 +278,12 @@ #endif idprom_init(); - load_mmu(); total = prom_probe_memory(); - *memory_start_p = (((unsigned long) &end)); + lowest_paddr = 0xffffffffffffffffUL; for(i=0; sp_banks[i].num_bytes != 0; i++) { + if(sp_banks[i].base_addr < lowest_paddr) + lowest_paddr = sp_banks[i].base_addr; end_of_phys_memory = sp_banks[i].base_addr + sp_banks[i].num_bytes; if (memory_size) { @@ -290,7 +298,19 @@ } prom_setsync(prom_sync_me); - *memory_end_p = (end_of_phys_memory + KERNBASE); + /* In paging_init() we tip off this value to see if we need + * to change init_mm.pgd to point to the real alias mapping. + */ + phys_base = lowest_paddr; + + *memory_start_p = PAGE_ALIGN(((unsigned long) &end)); + *memory_end_p = (end_of_phys_memory + PAGE_OFFSET); + +#ifndef NO_DAVEM_DEBUGGING + prom_printf("phys_base[%016lx] memory_start[%016lx] memory_end[%016lx]\n", + phys_base, *memory_start_p, *memory_end_p); +#endif + if (!root_flags) root_mountflags &= ~MS_RDONLY; ROOT_DEV = to_kdev_t(root_dev); @@ -302,7 +322,7 @@ #ifdef CONFIG_BLK_DEV_INITRD if (ramdisk_image) { initrd_start = ramdisk_image; - if (initrd_start < KERNBASE) initrd_start += KERNBASE; + if (initrd_start < PAGE_OFFSET) initrd_start += PAGE_OFFSET; initrd_end = initrd_start + ramdisk_size; if (initrd_end > *memory_end_p) { printk(KERN_CRIT "initrd extends beyond end of memory " @@ -318,12 +338,11 @@ #endif /* Due to stack alignment restrictions and assumptions... */ -#if 0 init_task.mm->mmap->vm_page_prot = PAGE_SHARED; - init_task.mm->mmap->vm_start = KERNBASE; + init_task.mm->mmap->vm_start = PAGE_OFFSET; init_task.mm->mmap->vm_end = *memory_end_p; init_task.mm->context = (unsigned long) NO_CONTEXT; -#endif + init_task.tss.kregs = &fake_swapper_regs; #ifdef CONFIG_SUN_SERIAL *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */ @@ -334,7 +353,7 @@ serial_console = 0; #else switch (console_fb) { - case 0: /* Let get our io devices from prom */ + case 0: /* Let's get our io devices from prom */ { int idev = prom_query_input_device(); int odev = prom_query_output_device(); diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c --- v2.1.33/linux/arch/sparc64/kernel/signal32.c Mon Mar 17 14:54:23 1997 +++ linux/arch/sparc64/kernel/signal32.c Fri Apr 11 10:47:36 1997 @@ -1,10 +1,11 @@ -/* $Id: signal32.c,v 1.4 1997/03/03 16:51:46 jj Exp $ +/* $Id: signal32.c,v 1.5 1997/04/07 18:57:09 jj Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include @@ -21,16 +22,17 @@ #include #include #include +#include +#include +#include #define _S(nr) (1<<((nr)-1)) #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) -asmlinkage int sys_waitpid(pid_t pid, unsigned long *stat_addr, int options); +#define synchronize_user_stack() do { } while (0) -extern void fpsave32(unsigned long *fpregs, unsigned long *fsr, - void *fpqueue, unsigned long *fpqdepth); -extern void fpload32(unsigned long *fpregs, unsigned long *fsr); +asmlinkage int sys_waitpid(pid_t pid, unsigned long *stat_addr, int options); asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs, unsigned long orig_o0, int ret_from_syscall); @@ -56,7 +58,7 @@ struct reg_window32 sig_window; int sig_num; int sig_code; - struct sigcontext32 *sig_scptr; + /* struct sigcontext32 * */ u32 sig_scptr; int sig_address; struct sigcontext32 sig_context; }; @@ -70,7 +72,7 @@ struct new_signal_frame32 { struct sparc_stackf32 ss; __siginfo32_t info; - __siginfo_fpu32_t *fpu_save; + /* __siginfo_fpu32_t * */ u32 fpu_save; unsigned int insns [2]; __siginfo_fpu32_t fpu_state; }; @@ -113,12 +115,16 @@ asmlinkage void do_sigpause32(unsigned int set, struct pt_regs *regs) { + lock_kernel (); _sigpause32_common(set, regs); + unlock_kernel (); } asmlinkage void do_sigsuspend32(struct pt_regs *regs) { + lock_kernel (); _sigpause32_common(regs->u_regs[UREG_I0], regs); + unlock_kernel (); } @@ -137,58 +143,59 @@ current->used_math = 1; current->flags &= ~PF_USEDFPU; - copy_32bit_to_kernel_fpuregs(¤t->tss.float_regs[0], - &fpu->si_float_regs[0], - (sizeof(unsigned int) * 32)); + copy_from_user(¤t->tss.float_regs[0], + &fpu->si_float_regs[0], + (sizeof(unsigned int) * 32)); __get_user(current->tss.fsr, &fpu->si_fsr); - __get_user(current->tss.fpqdepth, &fpu->si_fpqdepth); - if (current->tss.fpqdepth != 0) - copy_from_user(¤t->tss.fpqueue[0], - &fpu->si_fpqueue[0], - ((sizeof(unsigned long) + - (sizeof(unsigned long *)))*16)); } void do_new_sigreturn32(struct pt_regs *regs) { struct new_signal_frame32 *sf; - unsigned long up_tstate; + unsigned int psr, i; + unsigned pc, npc, fpu_save, mask; sf = (struct new_signal_frame32 *) regs->u_regs [UREG_FP]; /* 1. Make sure we are not getting garbage from the user */ if (verify_area (VERIFY_READ, sf, sizeof (*sf))){ do_exit (SIGSEGV); - return; } if (((unsigned long) sf) & 3){ do_exit (SIGSEGV); - return; } - if ((sf->info.si_regs.pc | sf->info.si_regs.npc) & 3){ + get_user(pc, &sf->info.si_regs.pc); + __get_user(npc, &sf->info.si_regs.npc); + if ((pc | npc) & 3){ do_exit (SIGSEGV); - return; } + regs->tpc = pc; + regs->tnpc = npc; /* 2. Restore the state */ - copy_32bit_to_kernel_ptregs (regs, &sf->info.si_regs, - sizeof (struct pt_regs)); + __get_user(regs->y, &sf->info.si_regs.y); + __get_user(psr, &sf->info.si_regs.psr); + for (i = 0; i < 16; i++) + __get_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]); /* User can only change condition codes and FPU enabling in %tstate. */ regs->tstate &= ~(TSTATE_ICC | TSTATE_PEF); - regs->tstate |= psr_to_tstate_icc(sf->info.si_regs.psr); - regs->tstate |= (sf->info.si_regs.psr & PSR_EF); + regs->tstate |= psr_to_tstate_icc(psr); + if (psr & PSR_EF) regs->tstate |= TSTATE_PEF; - if (sf->fpu_save) - restore_fpu_state32(regs, sf->fpu_state); - - current->blocked = sf->info.si_mask & _BLOCKABLE; + __get_user(fpu_save, &sf->fpu_save); + if (fpu_save) + restore_fpu_state32(regs, &sf->fpu_state); + __get_user(mask, &sf->info.si_mask); + current->blocked = mask & _BLOCKABLE; + unlock_kernel(); } asmlinkage void do_sigreturn32(struct pt_regs *regs) { struct sigcontext32 *scptr; - unsigned long pc, npc, psr; + unsigned pc, npc, psr; + lock_kernel (); synchronize_user_stack(); if (current->tss.new_signal) return do_new_sigreturn32(regs); @@ -198,8 +205,8 @@ if(verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext32)) || (((unsigned long) scptr) & 3)) { printk("%s [%d]: do_sigreturn, scptr is invalid at " - "pc<%08lx> scptr<%p>\n", - current->comm, current->pid, regs->pc, scptr); + "pc<%016lx> scptr<%p>\n", + current->comm, current->pid, regs->tpc, scptr); do_exit(SIGSEGV); } __get_user(pc, &scptr->sigc_pc); @@ -211,22 +218,23 @@ current->blocked &= _BLOCKABLE; __get_user(current->tss.sstk_info.cur_status, &scptr->sigc_onstack); current->tss.sstk_info.cur_status &= 1; - regs->pc = pc; - regs->npc = npc; + regs->tpc = pc; + regs->tnpc = npc; __get_user(regs->u_regs[UREG_FP], &scptr->sigc_sp); __get_user(regs->u_regs[UREG_I0], &scptr->sigc_o0); __get_user(regs->u_regs[UREG_G1], &scptr->sigc_g1); - /* User can only change condition codes in %psr. */ + /* User can only change condition codes in %tstate. */ __get_user(psr, &scptr->sigc_psr); - regs->psr &= ~(PSR_ICC); - regs->psr |= (psr & PSR_ICC); + regs->tstate &= ~(TSTATE_ICC); + regs->tstate |= psr_to_tstate_icc(psr); + unlock_kernel (); } /* Checks if the fp is valid */ static int invalid_frame_pointer(void *fp, int fplen) { - if ((((unsigned long) fp) & 7) || !__access_ok((unsigned long)fp, fplen)) + if ((((unsigned long) fp) & 7) || ((unsigned long)fp) > 0x100000000ULL - fplen) return 1; return 0; } @@ -239,6 +247,9 @@ struct sigcontext32 *sc; int window = 0; int old_status = current->tss.sstk_info.cur_status; + unsigned psr; + int i; + u32 temp; synchronize_user_stack(); sframep = (struct signal_sframe32 *) regs->u_regs[UREG_FP]; @@ -247,7 +258,7 @@ #ifdef DEBUG_SIGNALS /* fills up the console logs during crashme runs, yuck... */ printk("%s [%d]: User has trashed signal stack\n", current->comm, current->pid); - printk("Sigstack ptr %p handler at pc<%08lx> for sig<%d>\n", + printk("Sigstack ptr %p handler at pc<%016lx> for sig<%d>\n", sframep, pc, signr); #endif /* Don't change signal code and address, so that @@ -265,10 +276,13 @@ __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp); __put_user(pc, &sc->sigc_pc); __put_user(npc, &sc->sigc_npc); - __put_user(regs->psr, &sc->sigc_psr); + psr = tstate_to_psr (regs->tstate); + __put_user(psr, &sc->sigc_psr); __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1); __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0); __put_user(current->tss.w_saved, &sc->sigc_oswins); +#if 0 +/* w_saved is not currently used... */ if(current->tss.w_saved) for(window = 0; window < current->tss.w_saved; window++) { sc->sigc_spbuf[window] = @@ -278,9 +292,12 @@ sizeof(struct reg_window)); } else - copy_to_user(sframep, (char *)regs->u_regs[UREG_FP], - sizeof(struct reg_window)); - +#endif + for (i = 0; i < 16; i++) { + get_user (temp, (((u32 *)(regs->u_regs[UREG_FP]))+i)); + put_user (temp, (((u32 *)sframep)+i)); + } + current->tss.w_saved = 0; /* So process is allowed to execute. */ __put_user(signr, &sframep->sig_num); if(signr == SIGSEGV || @@ -294,10 +311,10 @@ __put_user(0, &sframep->sig_code); __put_user(0, &sframep->sig_address); } - __put_user(sc, &sframep->sig_scptr); + __put_user((u64)sc, &sframep->sig_scptr); regs->u_regs[UREG_FP] = (unsigned long) sframep; - regs->pc = (unsigned long) sa->sa_handler; - regs->npc = (regs->pc + 4); + regs->tpc = (unsigned long) sa->sa_handler; + regs->tnpc = (regs->tpc + 4); } @@ -306,29 +323,20 @@ { #ifdef __SMP__ if (current->flags & PF_USEDFPU) { - put_psr(get_psr() | PSR_EF); - fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr, - ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); - regs->psr &= ~(PSR_EF); + fpsave32(¤t->tss.float_regs[0], ¤t->tss.fsr); + regs->tstate &= ~(TSTATE_PEF); current->flags &= ~(PF_USEDFPU); } #else if (current == last_task_used_math) { - put_psr(get_psr() | PSR_EF); - fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr, - ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); + fpsave32((unsigned long *)¤t->tss.float_regs[0], ¤t->tss.fsr); last_task_used_math = 0; - regs->psr &= ~(PSR_EF); + regs->tstate &= ~(TSTATE_PEF); } #endif copy_to_user(&fpu->si_float_regs[0], ¤t->tss.float_regs[0], (sizeof(unsigned int) * 32)); __put_user(current->tss.fsr, &fpu->si_fsr); - __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth); - if (current->tss.fpqdepth != 0) - copy_to_user(&fpu->si_fpqueue[0], ¤t->tss.fpqueue[0], - ((sizeof(unsigned long) + - (sizeof(unsigned long *)))*16)); current->used_math = 0; } @@ -338,6 +346,8 @@ { struct new_signal_frame32 *sf; int sigframe_size; + u32 psr, tmp; + int i; /* 1. Make sure everything is clean */ synchronize_user_stack(); @@ -345,7 +355,7 @@ if (!current->used_math) sigframe_size -= sizeof(__siginfo_fpu32_t); - sf = (struct new_signal_frame *)(regs->u_regs[UREG_FP] - sigframe_size); + sf = (struct new_signal_frame32 *)(regs->u_regs[UREG_FP] - sigframe_size); if (invalid_frame_pointer (sf, sigframe_size)){ do_exit(SIGILL); @@ -360,21 +370,30 @@ } /* 2. Save the current process state */ - memcpy (&sf->info.si_regs, regs, sizeof (struct pt_regs)); + put_user(regs->tpc, &sf->info.si_regs.pc); + __put_user(regs->tnpc, &sf->info.si_regs.npc); + __put_user(regs->y, &sf->info.si_regs.y); + psr = tstate_to_psr (regs->tstate); + __put_user(psr, &sf->info.si_regs.psr); + for (i = 0; i < 16; i++) + __put_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]); if (current->used_math) { save_fpu_state32(regs, &sf->fpu_state); - sf->fpu_save = &sf->fpu_state; + __put_user((u64)&sf->fpu_state, &sf->fpu_save); } else { - sf->fpu_save = NULL; + __put_user(0, &sf->fpu_save); } - sf->info.si_mask = oldmask; - memcpy (sf, (char *)regs->u_regs [UREG_FP], sizeof(struct reg_window)); + __put_user(oldmask, &sf->info.si_mask); + for (i = 0; i < sizeof(struct reg_window32)/4; i++) { + __get_user(tmp, (((u32 *)regs->u_regs[UREG_FP])+i)); + __put_user(tmp, (((u32 *)sf)+i)); + } /* 3. return to kernel instructions */ - sf->insns [0] = 0x821020d8; /* mov __NR_sigreturn, %g1 */ - sf->insns [1] = 0x91d02010; /* t 0x10 */ + __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ + __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */ /* 4. signal handler back-trampoline and parameters */ regs->u_regs[UREG_FP] = (unsigned long) sf; @@ -383,11 +402,12 @@ regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); /* 5. signal handler */ - regs->pc = (unsigned long) sa->sa_handler; - regs->npc = (regs->pc + 4); + regs->tpc = (unsigned long) sa->sa_handler; + regs->tnpc = (regs->tpc + 4); /* Flush instruction space. */ - flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); + __asm__ __volatile__ ("flush %0; flush %0 + 4" : : "r" (&(sf->insns[0]))); + } /* Setup a Solaris stack frame */ @@ -402,6 +422,8 @@ svr4_gwindows_t *gw; svr4_ucontext_t *uc; int window = 0; + unsigned psr; + int i; synchronize_user_stack(); sfp = (svr4_signal_frame_t *) regs->u_regs[UREG_FP] - REGWIN_SZ; @@ -432,14 +454,17 @@ __put_user(oldmask, &uc->sigmask.sigbits [0]); /* Store registers */ - __put_user(regs->pc, &((*gr) [SVR4_PC])); - __put_user(regs->npc, &((*gr) [SVR4_NPC])); - __put_user(regs->psr, &((*gr) [SVR4_PSR])); + __put_user(regs->tpc, &((*gr) [SVR4_PC])); + __put_user(regs->tnpc, &((*gr) [SVR4_NPC])); + psr = tstate_to_psr (regs->tstate); + __put_user(psr, &((*gr) [SVR4_PSR])); __put_user(regs->y, &((*gr) [SVR4_Y])); /* Copy g [1..7] and o [0..7] registers */ - copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs [UREG_G1], sizeof (long) * 7); - copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (long) * 8); + for (i = 0; i < 7; i++) + __put_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i); + for (i = 0; i < 8; i++) + __put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i); /* Setup sigaltstack, FIXME */ __put_user(0xdeadbeef, &uc->stack.sp); @@ -465,11 +490,13 @@ * These windows are just used in case synchronize_user_stack failed * to flush the user windows. */ +#if 0 for(window = 0; window < current->tss.w_saved; window++) { __put_user((int *) &(gw->win [window]), &gw->winptr [window]); copy_to_user(&gw->win [window], ¤t->tss.reg_window [window], sizeof (svr4_rwindow_t)); __put_user(0, gw->winptr [window]); } +#endif /* 4. We just pay attention to the gw->count field on setcontext */ current->tss.w_saved = 0; /* So process is allowed to execute. */ @@ -483,23 +510,23 @@ __put_user(SVR4_SINOINFO, &si->siginfo.code); regs->u_regs[UREG_FP] = (unsigned long) sfp; - regs->pc = (unsigned long) sa->sa_handler; - regs->npc = (regs->pc + 4); + regs->tpc = (unsigned long) sa->sa_handler; + regs->tnpc = (regs->tpc + 4); #ifdef DEBUG_SIGNALS - printk ("Solaris-frame: %x %x\n", (int) regs->pc, (int) regs->npc); + printk ("Solaris-frame: %x %x\n", (int) regs->tpc, (int) regs->tnpc); #endif /* Arguments passed to signal handler */ if (regs->u_regs [14]){ - struct reg_window *rw = (struct reg_window *) regs->u_regs [14]; + struct reg_window32 *rw = (struct reg_window32 *) regs->u_regs [14]; __put_user(signr, &rw->ins [0]); - __put_user(si, &rw->ins [1]); - __put_user(uc, &rw->ins [2]); - __put_user(sfp, &rw->ins [6]); /* frame pointer */ + __put_user((u64)si, &rw->ins [1]); + __put_user((u64)uc, &rw->ins [2]); + __put_user((u64)sfp, &rw->ins [6]); /* frame pointer */ regs->u_regs[UREG_I0] = signr; - regs->u_regs[UREG_I1] = (uint) si; - regs->u_regs[UREG_I2] = (uint) uc; + regs->u_regs[UREG_I1] = (u32)(u64) si; + regs->u_regs[UREG_I2] = (u32)(u64) uc; } } @@ -508,6 +535,7 @@ { svr4_gregset_t *gr; svr4_mcontext_t *mc; + int i; synchronize_user_stack(); if (current->tss.w_saved){ @@ -525,14 +553,16 @@ __put_user(current->blocked, &uc->sigmask.sigbits [0]); /* Store registers */ - __put_user(regs->pc, &uc->mcontext.greg [SVR4_PC]); - __put_user(regs->npc, &uc->mcontext.greg [SVR4_NPC]); - __put_user(regs->psr, &uc->mcontext.greg [SVR4_PSR]); + __put_user(regs->tpc, &uc->mcontext.greg [SVR4_PC]); + __put_user(regs->tnpc, &uc->mcontext.greg [SVR4_NPC]); + __put_user(tstate_to_psr(regs->tstate), &uc->mcontext.greg [SVR4_PSR]); __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]); /* Copy g [1..7] and o [0..7] registers */ - copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs [UREG_G1], sizeof (uint) * 7); - copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (uint) * 8); + for (i = 0; i < 7; i++) + __put_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i); + for (i = 0; i < 8; i++) + __put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i); /* Setup sigaltstack, FIXME */ __put_user(0xdeadbeef, &uc->stack.sp); @@ -551,7 +581,8 @@ { struct thread_struct *tp = ¤t->tss; svr4_gregset_t *gr; - unsigned long pc, npc, psr; + u32 pc, npc, psr; + int i; /* Fixme: restore windows, or is this already taken care of in * svr4_setup_frame when sync_user_windows is done? @@ -562,7 +593,7 @@ printk ("Uh oh, w_saved is: 0x%lx\n", tp->w_saved); do_exit(SIGSEGV); } - if (((uint) c) & 3){ + if (((unsigned long) c) & 3){ printk ("Unaligned structure passed\n"); do_exit (SIGSEGV); } @@ -585,16 +616,18 @@ /* that we don't want it to mess with our PC and nPC */ __get_user(current->blocked, &c->sigmask.sigbits [0]); current->blocked &= _BLOCKABLE; - regs->pc = pc; - regs->npc = npc | 1; + regs->tpc = pc; + regs->tnpc = npc | 1; __get_user(regs->y, &((*gr) [SVR4_Y])); __get_user(psr, &((*gr) [SVR4_PSR])); - regs->psr &= ~(PSR_ICC); - regs->psr |= (psr & PSR_ICC); + regs->tstate &= ~(TSTATE_ICC); + regs->tstate |= psr_to_tstate_icc(psr); /* Restore g[1..7] and o[0..7] registers */ - copy_from_user(®s->u_regs [UREG_G1], &(*gr)[SVR4_G1], sizeof (long) * 7); - copy_from_user(®s->u_regs [UREG_I0], &(*gr)[SVR4_O0], sizeof (long) * 8); + for (i = 0; i < 7; i++) + __put_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i); + for (i = 0; i < 8; i++) + __put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i); return -EINTR; } @@ -604,12 +637,12 @@ int svr4_signal) { if(svr4_signal) - setup_svr4_frame32(sa, regs->pc, regs->npc, regs, signr, oldmask); + setup_svr4_frame32(sa, regs->tpc, regs->tnpc, regs, signr, oldmask); else { if (current->tss.new_signal) new_setup_frame32(sa, regs, signr, oldmask); else - setup_frame32(sa, regs->pc, regs->npc, regs, signr, oldmask); + setup_frame32(sa, regs->tpc, regs->tnpc, regs, signr, oldmask); } if(sa->sa_flags & SA_ONESHOT) sa->sa_handler = NULL; @@ -624,7 +657,7 @@ case ERESTARTNOHAND: no_system_call_restart: regs->u_regs[UREG_I0] = EINTR; - regs->psr |= PSR_C; + regs->tstate |= TSTATE_ICARRY; break; case ERESTARTSYS: if(!(sa->sa_flags & SA_RESTART)) @@ -632,8 +665,8 @@ /* fallthrough */ case ERESTARTNOINTR: regs->u_regs[UREG_I0] = orig_i0; - regs->pc -= 4; - regs->npc -= 4; + regs->tpc -= 4; + regs->tnpc -= 4; } } @@ -730,4 +763,34 @@ regs->tnpc -= 4; } return 0; +} + +struct sigstack32 { + u32 the_stack; + int cur_status; +}; + +asmlinkage int +sys32_sigstack(struct sigstack32 *ssptr, struct sigstack32 *ossptr) +{ + int ret = -EFAULT; + + lock_kernel(); + /* First see if old state is wanted. */ + if(ossptr) { + if (put_user ((u64)current->tss.sstk_info.the_stack, &ossptr->the_stack) || + __put_user (current->tss.sstk_info.cur_status, &ossptr->cur_status)) + goto out; + } + + /* Now see if we want to update the new state. */ + if(ssptr) { + if (get_user ((u64)current->tss.sstk_info.the_stack, &ssptr->the_stack) || + __put_user (current->tss.sstk_info.cur_status, &ssptr->cur_status)) + goto out; + } + ret = 0; +out: + unlock_kernel(); + return ret; } diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/sparcelf32.c linux/arch/sparc64/kernel/sparcelf32.c --- v2.1.33/linux/arch/sparc64/kernel/sparcelf32.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/sparcelf32.c Fri Apr 11 10:47:36 1997 @@ -0,0 +1,1280 @@ +/* sparcelf32.c: Support 32-bit Sparc ELF binaries on Ultra. + * + * This is just binfmt_elf.c with hooks so that the types are those + * for a 32-bit ELF binaries. + */ + +/* This makes it work. */ +#define ELF_ARCH EM_SPARC +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB; + +/* + * linux/fs/binfmt_elf.c + * + * These are the functions used to load ELF format executables as used + * on SVr4 machines. Information on the format may be found in the book + * "UNIX SYSTEM V RELEASE 4 Programmers Guide: Ansi C and Programming Support + * Tools". + * + * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com). + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define DLINFO_ITEMS 12 + +#include + +static int load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs); +static int load_elf32_library(int fd); +extern int dump_fpu (struct pt_regs *, elf_fpregset_t *); +extern void dump_thread(struct pt_regs *, struct user *); + +extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len); + +/* + * If we don't support core dumping, then supply a NULL so we + * don't even try. + */ +#ifdef USE_ELF_CORE_DUMP +static int elf32_core_dump(long signr, struct pt_regs * regs); +#else +#define elf32_core_dump NULL +#endif + +#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1)) +#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1)) + +static struct linux_binfmt elf32_format = { +#ifndef MODULE + NULL, NULL, load_elf32_binary, load_elf32_library, elf32_core_dump +#else + NULL, &__this_module, load_elf32_binary, load_elf32_library, elf32_core_dump +#endif +}; + +static void set_brk(unsigned long start, unsigned long end) +{ + start = PAGE_ALIGN(start); + end = PAGE_ALIGN(end); + if (end <= start) + return; + do_mmap(NULL, start, end - start, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, 0); +} + + +/* We need to explicitly zero any fractional pages + after the data section (i.e. bss). This would + contain the junk from the file that should not + be in memory */ + + +static void padzero(unsigned long elf_bss) +{ + unsigned long nbyte; + + nbyte = elf_bss & (PAGE_SIZE-1); + if (nbyte) { + nbyte = PAGE_SIZE - nbyte; + clear_user((void *) elf_bss, nbyte); + } +} + +__u32 *create_elf32_tables(char *p, int argc, int envc, + struct elfhdr * exec, + unsigned long load_addr, + unsigned long interp_load_addr, int ibcs) +{ + __u32 *argv, *envp; + __u32 *sp, *csp; + + /* + * Force 16 byte alignment here for generality. + */ + sp = (__u32 *) (~15UL & (unsigned long) p); + csp = sp; + csp -= exec ? DLINFO_ITEMS*2 : 2; + csp -= envc+1; + csp -= argc+1; + if (!(((unsigned long) csp) & 4)) + sp--; + + /* + * Put the ELF interpreter info on the stack + */ +#define NEW_AUX_ENT(nr, id, val) \ + __put_user ((id), sp+(nr*2)); \ + __put_user ((val), sp+(nr*2+1)); \ + + sp -= 2; + NEW_AUX_ENT(0, AT_NULL, 0); + + if (exec) { + sp -= 11*2; + + NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff); + NEW_AUX_ENT (1, AT_PHENT, sizeof (struct elf_phdr)); + NEW_AUX_ENT (2, AT_PHNUM, exec->e_phnum); + NEW_AUX_ENT (3, AT_PAGESZ, PAGE_SIZE); + NEW_AUX_ENT (4, AT_BASE, interp_load_addr); + NEW_AUX_ENT (5, AT_FLAGS, 0); + NEW_AUX_ENT (6, AT_ENTRY, (__u32) exec->e_entry); + NEW_AUX_ENT (7, AT_UID, (__u32) current->uid); + NEW_AUX_ENT (8, AT_EUID, (__u32) current->euid); + NEW_AUX_ENT (9, AT_GID, (__u32) current->gid); + NEW_AUX_ENT (10, AT_EGID, (__u32) current->egid); + } +#undef NEW_AUX_ENT + + sp -= envc+1; + envp = (__u32 *) sp; + sp -= argc+1; + argv = (__u32 *) sp; + if (!ibcs) { + __put_user(((__u32) envp),--sp); + __put_user(((__u32) argv),--sp); + } + + __put_user((__u32)argc,--sp); + current->mm->arg_start = (unsigned long) p; + while (argc-->0) { + __put_user(((__u32)p),argv++); + p += strlen_user(p); + } + __put_user(NULL, argv); + current->mm->arg_end = current->mm->env_start = (unsigned long) p; + while (envc-->0) { + __put_user(((__u32)p),envp++); + p += strlen_user(p); + } + __put_user(NULL, envp); + current->mm->env_end = (unsigned long) p; + return sp; +} + + +/* This is much more generalized than the library routine read function, + so we keep this separate. Technically the library read function + is only provided so that we can read a.out libraries that have + an ELF header */ + +static unsigned long load_elf32_interp(struct elfhdr * interp_elf_ex, + struct inode * interpreter_inode, + unsigned long *interp_load_addr) +{ + struct file * file; + struct elf_phdr *elf_phdata = NULL; + struct elf_phdr *eppnt; + unsigned long load_addr; + int load_addr_set = 0; + int elf_exec_fileno; + int retval; + unsigned long last_bss, elf_bss; + unsigned long error; + int i; + + elf_bss = 0; + last_bss = 0; + error = load_addr = 0; + + /* First of all, some simple consistency checks */ + if ((interp_elf_ex->e_type != ET_EXEC && + interp_elf_ex->e_type != ET_DYN) || + !elf_check_arch(interp_elf_ex->e_machine) || + (!interpreter_inode->i_op || + !interpreter_inode->i_op->default_file_ops->mmap)){ + return ~0UL; + } + + /* Now read in all of the header information */ + + if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) + return ~0UL; + + elf_phdata = (struct elf_phdr *) + kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, + GFP_KERNEL); + if (!elf_phdata) + return ~0UL; + + /* + * If the size of this structure has changed, then punt, since + * we will be doing the wrong thing. + */ + if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) + { + kfree(elf_phdata); + return ~0UL; + } + + retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, + (char *) elf_phdata, + sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1); + + if (retval < 0) { + kfree (elf_phdata); + return retval; + } + + elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY); + if (elf_exec_fileno < 0) { + kfree(elf_phdata); + return ~0UL; + } + + file = current->files->fd[elf_exec_fileno]; + + eppnt = elf_phdata; + for(i=0; ie_phnum; i++, eppnt++) + if (eppnt->p_type == PT_LOAD) { + int elf_type = MAP_PRIVATE | MAP_DENYWRITE; + int elf_prot = 0; + unsigned long vaddr = 0; + unsigned long k; + + if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; + if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; + if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; + if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { + elf_type |= MAP_FIXED; + vaddr = eppnt->p_vaddr; + } else { + load_addr = get_unmapped_area(0, eppnt->p_filesz + + ELF_PAGEOFFSET(eppnt->p_vaddr)); + } + + error = do_mmap(file, + load_addr + ELF_PAGESTART(vaddr), + eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), + elf_prot, + elf_type, + eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr)); + + if (error > -1024UL) { + /* Real error */ + sys_close(elf_exec_fileno); + kfree(elf_phdata); + return ~0UL; + } + + if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { + load_addr = error; + load_addr_set = 1; + } + + /* + * Find the end of the file mapping for this phdr, and keep + * track of the largest address we see for this. + */ + k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; + if (k > elf_bss) elf_bss = k; + + /* + * Do the same thing for the memory mapping - between + * elf_bss and last_bss is the bss section. + */ + k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; + if (k > last_bss) last_bss = k; + } + + /* Now use mmap to map the library into memory. */ + + sys_close(elf_exec_fileno); + + /* + * Now fill out the bss section. First pad the last page up + * to the page boundary, and then perform a mmap to make sure + * that there are zeromapped pages up to and including the last + * bss page. + */ + padzero(elf_bss); + elf_bss = ELF_PAGESTART(elf_bss + ELF_EXEC_PAGESIZE - 1); /* What we have mapped so far */ + + /* Map the last of the bss segment */ + if (last_bss > elf_bss) + do_mmap(NULL, elf_bss, last_bss-elf_bss, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + kfree(elf_phdata); + + *interp_load_addr = load_addr; + return ((unsigned long) interp_elf_ex->e_entry) + load_addr; +} + +static unsigned long load_aout32_interp(struct exec * interp_ex, + struct inode * interpreter_inode) +{ + int retval; + unsigned long elf_entry; + + current->mm->brk = interp_ex->a_bss + + (current->mm->end_data = interp_ex->a_data + + (current->mm->end_code = interp_ex->a_text)); + elf_entry = interp_ex->a_entry; + + + if (N_MAGIC(*interp_ex) == OMAGIC) { + do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + retval = read_exec(interpreter_inode, 32, (char *) 0, + interp_ex->a_text+interp_ex->a_data, 0); + } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) { + do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + retval = read_exec(interpreter_inode, + N_TXTOFF(*interp_ex) , + (char *) N_TXTADDR(*interp_ex), + interp_ex->a_text+interp_ex->a_data, 0); + } else + retval = -1; + + if (retval >= 0) + do_mmap(NULL, ELF_PAGESTART(interp_ex->a_text + interp_ex->a_data + ELF_EXEC_PAGESIZE - 1), + interp_ex->a_bss, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + if (retval < 0) return ~0UL; + return elf_entry; +} + +/* + * These are the functions used to load ELF style executables and shared + * libraries. There is no binary dependent code anywhere else. + */ + +#define INTERPRETER_NONE 0 +#define INTERPRETER_AOUT 1 +#define INTERPRETER_ELF 2 + + +static inline int +do_load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs) +{ + struct elfhdr elf_ex; + struct elfhdr interp_elf_ex; + struct file * file; + struct exec interp_ex; + struct inode *interpreter_inode; + unsigned long load_addr; + int load_addr_set = 0; + unsigned int interpreter_type = INTERPRETER_NONE; + unsigned char ibcs2_interpreter; + int i; + int old_fs; + int error; + struct elf_phdr * elf_ppnt, *elf_phdata; + int elf_exec_fileno; + unsigned long elf_bss, k, elf_brk; + int retval; + char * elf_interpreter; + unsigned long elf_entry, interp_load_addr = 0; + int status; + unsigned long start_code, end_code, end_data; + unsigned long elf_stack; + char passed_fileno[6]; + + ibcs2_interpreter = 0; + status = 0; + load_addr = 0; + elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ + + if (elf_ex.e_ident[0] != 0x7f || + strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) { + return -ENOEXEC; + } + + + /* First of all, some simple consistency checks */ + if ((elf_ex.e_type != ET_EXEC && + elf_ex.e_type != ET_DYN) || + (! elf_check_arch(elf_ex.e_machine)) || + (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops || + !bprm->inode->i_op->default_file_ops->mmap)){ + return -ENOEXEC; + } + + /* Now read in all of the header information */ + + elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize * + elf_ex.e_phnum, GFP_KERNEL); + if (elf_phdata == NULL) { + return -ENOMEM; + } + + retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata, + elf_ex.e_phentsize * elf_ex.e_phnum, 1); + if (retval < 0) { + kfree (elf_phdata); + return retval; + } + + elf_ppnt = elf_phdata; + + elf_bss = 0; + elf_brk = 0; + + elf_exec_fileno = open_inode(bprm->inode, O_RDONLY); + + if (elf_exec_fileno < 0) { + kfree (elf_phdata); + return elf_exec_fileno; + } + + file = current->files->fd[elf_exec_fileno]; + + elf_stack = ~0UL; + elf_interpreter = NULL; + start_code = ~0UL; + end_code = 0; + end_data = 0; + + for(i=0;i < elf_ex.e_phnum; i++){ + if (elf_ppnt->p_type == PT_INTERP) { + if ( elf_interpreter != NULL ) + { + kfree (elf_phdata); + kfree(elf_interpreter); + sys_close(elf_exec_fileno); + return -EINVAL; + } + + /* This is the program interpreter used for + * shared libraries - for now assume that this + * is an a.out format binary + */ + + elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz, + GFP_KERNEL); + if (elf_interpreter == NULL) { + kfree (elf_phdata); + sys_close(elf_exec_fileno); + return -ENOMEM; + } + + retval = read_exec(bprm->inode,elf_ppnt->p_offset, + elf_interpreter, + elf_ppnt->p_filesz, 1); + /* If the program interpreter is one of these two, + then assume an iBCS2 image. Otherwise assume + a native linux image. */ + if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || + strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) + ibcs2_interpreter = 1; +#if 0 + printk("Using ELF interpreter %s\n", elf_interpreter); +#endif + if (retval >= 0) { + old_fs = get_fs(); /* This could probably be optimized */ + set_fs(get_ds()); + retval = open_namei(elf_interpreter, 0, 0, + &interpreter_inode, NULL); + set_fs(old_fs); + } + + if (retval >= 0) + retval = read_exec(interpreter_inode,0,bprm->buf,128, 1); + + if (retval >= 0) { + interp_ex = *((struct exec *) bprm->buf); /* exec-header */ + interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ + + } + if (retval < 0) { + kfree (elf_phdata); + kfree(elf_interpreter); + sys_close(elf_exec_fileno); + return retval; + } + } + elf_ppnt++; + } + + /* Some simple consistency checks for the interpreter */ + if (elf_interpreter){ + interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; + + /* Now figure out which format our binary is */ + if ((N_MAGIC(interp_ex) != OMAGIC) && + (N_MAGIC(interp_ex) != ZMAGIC) && + (N_MAGIC(interp_ex) != QMAGIC)) + interpreter_type = INTERPRETER_ELF; + + if (interp_elf_ex.e_ident[0] != 0x7f || + strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) + interpreter_type &= ~INTERPRETER_ELF; + + if (!interpreter_type) + { + kfree(elf_interpreter); + kfree(elf_phdata); + sys_close(elf_exec_fileno); + return -ELIBBAD; + } + } + + /* OK, we are done with that, now set up the arg stuff, + and then start this sucker up */ + + if (!bprm->sh_bang) { + char * passed_p; + + if (interpreter_type == INTERPRETER_AOUT) { + sprintf(passed_fileno, "%d", elf_exec_fileno); + passed_p = passed_fileno; + + if (elf_interpreter) { + bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2); + bprm->argc++; + } + } + if (!bprm->p) { + if (elf_interpreter) { + kfree(elf_interpreter); + } + kfree (elf_phdata); + sys_close(elf_exec_fileno); + return -E2BIG; + } + } + + /* OK, This is the point of no return */ + flush_old_exec(bprm); + + current->mm->end_data = 0; + current->mm->end_code = 0; + current->mm->start_mmap = ELF_START_MMAP; + current->mm->mmap = NULL; + elf_entry = (unsigned long) elf_ex.e_entry; + + /* Do this so that we can load the interpreter, if need be. We will + change some of these later */ + current->mm->rss = 0; + bprm->p = setup_arg_pages(bprm->p, bprm); + current->mm->start_stack = bprm->p; + + /* Now we do a little grungy work by mmaping the ELF image into + the correct location in memory. At this point, we assume that + the image should be loaded at fixed address, not at a variable + address. */ + + old_fs = get_fs(); + set_fs(get_ds()); + for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { + if (elf_ppnt->p_type == PT_LOAD) { + int elf_prot = 0; + if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; + if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; + if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; + + error = do_mmap(file, + ELF_PAGESTART(elf_ppnt->p_vaddr), + (elf_ppnt->p_filesz + + ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), + elf_prot, + (MAP_FIXED | MAP_PRIVATE | + MAP_DENYWRITE | MAP_EXECUTABLE), + (elf_ppnt->p_offset - + ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); + +#ifdef LOW_ELF_STACK + if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) + elf_stack = ELF_PAGESTART(elf_ppnt->p_vaddr); +#endif + + if (!load_addr_set) { + load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; + load_addr_set = 1; + } + k = elf_ppnt->p_vaddr; + if (k < start_code) start_code = k; + k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; + if (k > elf_bss) elf_bss = k; +#if 1 + if ((elf_ppnt->p_flags & PF_X) && end_code < k) +#else + if ( !(elf_ppnt->p_flags & PF_W) && end_code < k) +#endif + end_code = k; + if (end_data < k) end_data = k; + k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; + if (k > elf_brk) elf_brk = k; + } + } + set_fs(old_fs); + + if (elf_interpreter) { + if (interpreter_type & 1) + elf_entry = load_aout32_interp(&interp_ex, + interpreter_inode); + else if (interpreter_type & 2) + elf_entry = load_elf32_interp(&interp_elf_ex, + interpreter_inode, + &interp_load_addr); + + iput(interpreter_inode); + kfree(elf_interpreter); + + if (elf_entry == ~0UL) { + printk("Unable to load interpreter\n"); + kfree(elf_phdata); + send_sig(SIGSEGV, current, 0); + return 0; + } + } + + kfree(elf_phdata); + + if (interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno); + current->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX); + + if (current->exec_domain && current->exec_domain->module) + __MOD_DEC_USE_COUNT(current->exec_domain->module); + if (current->binfmt && current->binfmt->module) + __MOD_DEC_USE_COUNT(current->binfmt->module); + current->exec_domain = lookup_exec_domain(current->personality); + current->binfmt = &elf32_format; + if (current->exec_domain && current->exec_domain->module) + __MOD_INC_USE_COUNT(current->exec_domain->module); + if (current->binfmt && current->binfmt->module) + __MOD_INC_USE_COUNT(current->binfmt->module); + +#ifndef VM_STACK_FLAGS + current->executable = bprm->inode; + bprm->inode->i_count++; +#endif +#ifdef LOW_ELF_STACK + current->start_stack = bprm->p = elf_stack - 4; +#endif + current->suid = current->euid = current->fsuid = bprm->e_uid; + current->sgid = current->egid = current->fsgid = bprm->e_gid; + current->flags &= ~PF_FORKNOEXEC; + bprm->p = (unsigned long) + create_elf32_tables((char *)bprm->p, + bprm->argc, + bprm->envc, + (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), + load_addr, + interp_load_addr, + (interpreter_type == INTERPRETER_AOUT ? 0 : 1)); + if (interpreter_type == INTERPRETER_AOUT) + current->mm->arg_start += strlen(passed_fileno) + 1; + current->mm->start_brk = current->mm->brk = elf_brk; + current->mm->end_code = end_code; + current->mm->start_code = start_code; + current->mm->end_data = end_data; + current->mm->start_stack = bprm->p; + + /* Calling set_brk effectively mmaps the pages that we need for the bss and break + sections */ + set_brk(elf_bss, elf_brk); + + padzero(elf_bss); + +#if 0 + printk("(start_brk) %x\n" , current->mm->start_brk); + printk("(end_code) %x\n" , current->mm->end_code); + printk("(start_code) %x\n" , current->mm->start_code); + printk("(end_data) %x\n" , current->mm->end_data); + printk("(start_stack) %x\n" , current->mm->start_stack); + printk("(brk) %x\n" , current->mm->brk); +#endif + + if ( current->personality == PER_SVR4 ) + { + /* Why this, you ask??? Well SVr4 maps page 0 as read-only, + and some applications "depend" upon this behavior. + Since we do not have the power to recompile these, we + emulate the SVr4 behavior. Sigh. */ + error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, 0); + } + +#ifdef ELF_PLAT_INIT + /* + * The ABI may specify that certain registers be set up in special + * ways (on i386 %edx is the address of a DT_FINI function, for + * example. This macro performs whatever initialization to + * the regs structure is required. + */ + ELF_PLAT_INIT(regs); +#endif + + + start_thread32(regs, elf_entry, bprm->p); + if (current->flags & PF_PTRACED) + send_sig(SIGTRAP, current, 0); + return 0; +} + +static int +load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs) +{ + int retval; + + MOD_INC_USE_COUNT; + retval = do_load_elf32_binary(bprm, regs); + MOD_DEC_USE_COUNT; + return retval; +} + +/* This is really simpleminded and specialized - we are loading an + a.out library that is given an ELF header. */ + +static inline int +do_load_elf32_library(int fd){ + struct file * file; + struct elfhdr elf_ex; + struct elf_phdr *elf_phdata = NULL; + struct inode * inode; + unsigned long len; + int elf_bss; + int retval; + unsigned long bss; + int error; + int i,j, k; + + len = 0; + file = current->files->fd[fd]; + inode = file->f_inode; + elf_bss = 0; + + if (!file || !file->f_op) + return -EACCES; + + /* seek to the beginning of the file */ + if (file->f_op->llseek) { + if ((error = file->f_op->llseek(inode, file, 0, 0)) != 0) + return -ENOEXEC; + } else + file->f_pos = 0; + + set_fs(KERNEL_DS); + error = file->f_op->read(inode, file, (char *) &elf_ex, sizeof(elf_ex)); + set_fs(USER_DS); + if (error != sizeof(elf_ex)) + return -ENOEXEC; + + if (elf_ex.e_ident[0] != 0x7f || + strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) + return -ENOEXEC; + + /* First of all, some simple consistency checks */ + if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || + !elf_check_arch(elf_ex.e_machine) || + (!inode->i_op || !inode->i_op->default_file_ops->mmap)) + return -ENOEXEC; + + /* Now read in all of the header information */ + + if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE) + return -ENOEXEC; + + elf_phdata = (struct elf_phdr *) + kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL); + if (elf_phdata == NULL) + return -ENOMEM; + + retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata, + sizeof(struct elf_phdr) * elf_ex.e_phnum, 1); + + j = 0; + for(i=0; ip_type == PT_LOAD) j++; + + if (j != 1) { + kfree(elf_phdata); + return -ENOEXEC; + } + + while(elf_phdata->p_type != PT_LOAD) elf_phdata++; + + /* Now use mmap to map the library into memory. */ + error = do_mmap(file, + ELF_PAGESTART(elf_phdata->p_vaddr), + (elf_phdata->p_filesz + + ELF_PAGEOFFSET(elf_phdata->p_vaddr)), + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, + (elf_phdata->p_offset - + ELF_PAGEOFFSET(elf_phdata->p_vaddr))); + + k = elf_phdata->p_vaddr + elf_phdata->p_filesz; + if (k > elf_bss) elf_bss = k; + + if (error != ELF_PAGESTART(elf_phdata->p_vaddr)) { + kfree(elf_phdata); + return error; + } + + padzero(elf_bss); + + len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr+ ELF_EXEC_PAGESIZE - 1); + bss = elf_phdata->p_memsz + elf_phdata->p_vaddr; + if (bss > len) + do_mmap(NULL, len, bss-len, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + kfree(elf_phdata); + return 0; +} + +static int load_elf32_library(int fd) +{ + int retval; + + MOD_INC_USE_COUNT; + retval = do_load_elf32_library(fd); + MOD_DEC_USE_COUNT; + return retval; +} + +/* + * Note that some platforms still use traditional core dumps and not + * the ELF core dump. Each platform can select it as appropriate. + */ +#ifdef USE_ELF_CORE_DUMP + +/* + * ELF core dumper + * + * Modelled on fs/exec.c:aout_core_dump() + * Jeremy Fitzhardinge + */ +/* + * These are the only things you should do on a core-file: use only these + * functions to write out all the necessary info. + */ +static int dump_write(struct file *file, const void *addr, int nr) +{ + return file->f_op->write(file->f_inode, file, addr, nr) == nr; +} + +static int dump_seek(struct file *file, off_t off) +{ + if (file->f_op->llseek) { + if (file->f_op->llseek(file->f_inode, file, off, 0) != off) + return 0; + } else + file->f_pos = off; + return 1; +} + +/* + * Decide whether a segment is worth dumping; default is yes to be + * sure (missing info is worse than too much; etc). + * Personally I'd include everything, and use the coredump limit... + * + * I think we should skip something. But I am not sure how. H.J. + */ +static inline int maydump(struct vm_area_struct *vma) +{ + if (!(vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC))) + return 0; +#if 1 + if (vma->vm_flags & (VM_WRITE|VM_GROWSUP|VM_GROWSDOWN)) + return 1; + if (vma->vm_flags & (VM_READ|VM_EXEC|VM_EXECUTABLE|VM_SHARED)) + return 0; +#endif + return 1; +} + +#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) + +/* An ELF note in memory */ +struct memelfnote +{ + const char *name; + int type; + unsigned int datasz; + void *data; +}; + +static int notesize(struct memelfnote *en) +{ + int sz; + + sz = sizeof(struct elf_note); + sz += roundup(strlen(en->name), 4); + sz += roundup(en->datasz, 4); + + return sz; +} + +/* #define DEBUG */ + +#define DUMP_WRITE(addr, nr) \ + do { if (!dump_write(file, (addr), (nr))) return 0; } while(0) +#define DUMP_SEEK(off) \ + do { if (!dump_seek(file, (off))) return 0; } while(0) + +static int writenote(struct memelfnote *men, struct file *file) +{ + struct elf_note en; + + en.n_namesz = strlen(men->name); + en.n_descsz = men->datasz; + en.n_type = men->type; + + DUMP_WRITE(&en, sizeof(en)); + DUMP_WRITE(men->name, en.n_namesz); + /* XXX - cast from long long to long to avoid need for libgcc.a */ + DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */ + DUMP_WRITE(men->data, men->datasz); + DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */ + + return 1; +} +#undef DUMP_WRITE +#undef DUMP_SEEK + +#define DUMP_WRITE(addr, nr) \ + if (!dump_write(&file, (addr), (nr))) \ + goto close_coredump; +#define DUMP_SEEK(off) \ + if (!dump_seek(&file, (off))) \ + goto close_coredump; +/* + * Actual dumper + * + * This is a two-pass process; first we find the offsets of the bits, + * and then they are actually written out. If we run out of core limit + * we just truncate. + */ +static int elf32_core_dump(long signr, struct pt_regs * regs) +{ + int has_dumped = 0; + struct file file; + struct inode *inode; + unsigned short fs; + char corefile[6+sizeof(current->comm)]; + int segs; + int i; + size_t size; + struct vm_area_struct *vma; + struct elfhdr elf; + off_t offset = 0, dataoff; + int limit = current->rlim[RLIMIT_CORE].rlim_cur; + int numnote = 4; + struct memelfnote notes[4]; + struct elf_prstatus prstatus; /* NT_PRSTATUS */ + elf_fpregset_t fpu; /* NT_PRFPREG */ + struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ + + if (!current->dumpable || limit < PAGE_SIZE || current->mm->count != 1) + return 0; + current->dumpable = 0; + +#ifndef CONFIG_BINFMT_ELF32 + MOD_INC_USE_COUNT; +#endif + + /* Count what's needed to dump, up to the limit of coredump size */ + segs = 0; + size = 0; + for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { + if (maydump(vma)) + { + int sz = vma->vm_end-vma->vm_start; + + if (size+sz >= limit) + break; + else + size += sz; + } + + segs++; + } +#ifdef DEBUG + printk("elf_core_dump: %d segs taking %d bytes\n", segs, size); +#endif + + /* Set up header */ + memcpy(elf.e_ident, ELFMAG, SELFMAG); + elf.e_ident[EI_CLASS] = ELF_CLASS; + elf.e_ident[EI_DATA] = ELF_DATA; + elf.e_ident[EI_VERSION] = EV_CURRENT; + memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); + + elf.e_type = ET_CORE; + elf.e_machine = ELF_ARCH; + elf.e_version = EV_CURRENT; + elf.e_entry = 0; + elf.e_phoff = sizeof(elf); + elf.e_shoff = 0; + elf.e_flags = 0; + elf.e_ehsize = sizeof(elf); + elf.e_phentsize = sizeof(struct elf_phdr); + elf.e_phnum = segs+1; /* Include notes */ + elf.e_shentsize = 0; + elf.e_shnum = 0; + elf.e_shstrndx = 0; + + fs = get_fs(); + set_fs(KERNEL_DS); + memcpy(corefile,"core.",5); +#if 0 + memcpy(corefile+5,current->comm,sizeof(current->comm)); +#else + corefile[4] = '\0'; +#endif + if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) { + inode = NULL; + goto end_coredump; + } + if (!S_ISREG(inode->i_mode)) + goto end_coredump; + if (!inode->i_op || !inode->i_op->default_file_ops) + goto end_coredump; + file.f_mode = 3; + file.f_flags = 0; + file.f_count = 1; + file.f_inode = inode; + file.f_pos = 0; + file.f_reada = 0; + file.f_op = inode->i_op->default_file_ops; + if (file.f_op->open) + if (file.f_op->open(inode,&file)) + goto end_coredump; + if (!file.f_op->write) + goto close_coredump; + has_dumped = 1; + current->flags |= PF_DUMPCORE; + + DUMP_WRITE(&elf, sizeof(elf)); + offset += sizeof(elf); /* Elf header */ + offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */ + + /* + * Set up the notes in similar form to SVR4 core dumps made + * with info from their /proc. + */ + memset(&psinfo, 0, sizeof(psinfo)); + memset(&prstatus, 0, sizeof(prstatus)); + + notes[0].name = "CORE"; + notes[0].type = NT_PRSTATUS; + notes[0].datasz = sizeof(prstatus); + notes[0].data = &prstatus; + prstatus.pr_info.si_signo = prstatus.pr_cursig = signr; + prstatus.pr_sigpend = current->signal; + prstatus.pr_sighold = current->blocked; + psinfo.pr_pid = prstatus.pr_pid = current->pid; + psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid; + psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp; + psinfo.pr_sid = prstatus.pr_sid = current->session; + prstatus.pr_utime.tv_sec = CT_TO_SECS(current->utime); + prstatus.pr_utime.tv_usec = CT_TO_USECS(current->utime); + prstatus.pr_stime.tv_sec = CT_TO_SECS(current->stime); + prstatus.pr_stime.tv_usec = CT_TO_USECS(current->stime); + prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->cutime); + prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->cutime); + prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->cstime); + prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->cstime); + + /* + * This transfers the registers from regs into the standard + * coredump arrangement, whatever that is. + */ +#ifdef ELF_CORE_COPY_REGS + ELF_CORE_COPY_REGS(prstatus.pr_reg, regs) +#else + if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) + { + printk("sizeof(elf_gregset_t) (%d) != sizeof(struct pt_regs) (%d)\n", + sizeof(elf_gregset_t), sizeof(struct pt_regs)); + } + else + *(struct pt_regs *)&prstatus.pr_reg = *regs; +#endif + + notes[1].name = "CORE"; + notes[1].type = NT_PRPSINFO; + notes[1].datasz = sizeof(psinfo); + notes[1].data = &psinfo; + psinfo.pr_state = current->state; + psinfo.pr_sname = (current->state < 0 || current->state > 5) ? '.' : "RSDZTD"[current->state]; + psinfo.pr_zomb = psinfo.pr_sname == 'Z'; + psinfo.pr_nice = current->priority-15; + psinfo.pr_flag = current->flags; + psinfo.pr_uid = current->uid; + psinfo.pr_gid = current->gid; + { + int i, len; + + set_fs(fs); + + len = current->mm->arg_end - current->mm->arg_start; + len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len; + copy_from_user(&psinfo.pr_psargs, + (const char *)current->mm->arg_start, len); + for(i = 0; i < len; i++) + if (psinfo.pr_psargs[i] == 0) + psinfo.pr_psargs[i] = ' '; + psinfo.pr_psargs[len] = 0; + + set_fs(KERNEL_DS); + } + strncpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname)); + + notes[2].name = "CORE"; + notes[2].type = NT_TASKSTRUCT; + notes[2].datasz = sizeof(*current); + notes[2].data = current; + + /* Try to dump the fpu. */ + prstatus.pr_fpvalid = dump_fpu (regs, &fpu); + if (!prstatus.pr_fpvalid) + { + numnote--; + } + else + { + notes[3].name = "CORE"; + notes[3].type = NT_PRFPREG; + notes[3].datasz = sizeof(fpu); + notes[3].data = &fpu; + } + + /* Write notes phdr entry */ + { + struct elf_phdr phdr; + int sz = 0; + + for(i = 0; i < numnote; i++) + sz += notesize(¬es[i]); + + phdr.p_type = PT_NOTE; + phdr.p_offset = offset; + phdr.p_vaddr = 0; + phdr.p_paddr = 0; + phdr.p_filesz = sz; + phdr.p_memsz = 0; + phdr.p_flags = 0; + phdr.p_align = 0; + + offset += phdr.p_filesz; + DUMP_WRITE(&phdr, sizeof(phdr)); + } + + /* Page-align dumped data */ + dataoff = offset = roundup(offset, PAGE_SIZE); + + /* Write program headers for segments dump */ + for(vma = current->mm->mmap, i = 0; + i < segs && vma != NULL; vma = vma->vm_next) { + struct elf_phdr phdr; + size_t sz; + + i++; + + sz = vma->vm_end - vma->vm_start; + + phdr.p_type = PT_LOAD; + phdr.p_offset = offset; + phdr.p_vaddr = vma->vm_start; + phdr.p_paddr = 0; + phdr.p_filesz = maydump(vma) ? sz : 0; + phdr.p_memsz = sz; + offset += phdr.p_filesz; + phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; + if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W; + if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X; + phdr.p_align = PAGE_SIZE; + + DUMP_WRITE(&phdr, sizeof(phdr)); + } + + for(i = 0; i < numnote; i++) + if (!writenote(¬es[i], &file)) + goto close_coredump; + + set_fs(fs); + + DUMP_SEEK(dataoff); + + for(i = 0, vma = current->mm->mmap; + i < segs && vma != NULL; + vma = vma->vm_next) { + unsigned long addr = vma->vm_start; + unsigned long len = vma->vm_end - vma->vm_start; + + i++; + if (!maydump(vma)) + continue; +#ifdef DEBUG + printk("elf_core_dump: writing %08lx %lx\n", addr, len); +#endif + DUMP_WRITE((void *)addr, len); + } + + if ((off_t) file.f_pos != offset) { + /* Sanity check */ + printk("elf_core_dump: file.f_pos (%ld) != offset (%ld)\n", + (off_t) file.f_pos, offset); + } + + close_coredump: + if (file.f_op->release) + file.f_op->release(inode,&file); + + end_coredump: + set_fs(fs); + iput(inode); +#ifndef CONFIG_BINFMT_ELF32 + MOD_DEC_USE_COUNT; +#endif + return has_dumped; +} +#endif /* USE_ELF_CORE_DUMP */ + +int init_elf32_binfmt(void) +{ + return register_binfmt(&elf32_format); +} + +#ifdef MODULE + +int init_module(void) +{ + /* Install the COFF, ELF and XOUT loaders. + * N.B. We *rely* on the table being the right size with the + * right number of free slots... + */ + return init_elf32_binfmt(); +} + + +void cleanup_module( void) +{ + /* Remove the COFF and ELF loaders. */ + unregister_binfmt(&elf32_format); +} +#endif diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c --- v2.1.33/linux/arch/sparc64/kernel/sys_sparc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/sys_sparc.c Fri Apr 11 10:47:36 1997 @@ -0,0 +1,270 @@ +/* $Id: sys_sparc.c,v 1.1 1997/04/09 08:25:18 jj Exp $ + * linux/arch/sparc64/kernel/sys_sparc.c + * + * This file contains various random system calls that + * have a non-standard calling sequence on the Linux/sparc + * platform. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* XXX Make this per-binary type, this way we can detect the type of + * XXX a binary. Every Sparc executable calls this very early on. + */ +asmlinkage unsigned long sys_getpagesize(void) +{ + return PAGE_SIZE; +} + +extern asmlinkage unsigned long sys_brk(unsigned long brk); + +asmlinkage unsigned long sparc_brk(unsigned long brk) +{ + unsigned long ret; + + lock_kernel(); + if(brk >= 0x80000000000ULL) { /* VM hole */ + ret = current->mm->brk; + goto out; + } + ret = sys_brk(brk); +out: + unlock_kernel(); + return ret; +} + +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way unix traditionally does this, though. + */ +asmlinkage int sparc_pipe(struct pt_regs *regs) +{ + int fd[2]; + int error; + + lock_kernel(); + error = do_pipe(fd); + if (error) + goto out; + regs->u_regs[UREG_I1] = fd[1]; + error = fd[0]; +out: + unlock_kernel(); + return error; +} + +/* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * + * This is really horribly ugly. + */ + +asmlinkage int sys_ipc (unsigned call, int first, int second, unsigned long third, void *ptr, long fifth) +{ + int err; + + lock_kernel(); + /* No need for backward compatibility. We can start fresh... */ + + if (call <= SEMCTL) + switch (call) { + case SEMOP: + err = sys_semop (first, (struct sembuf *)ptr, second); + goto out; + case SEMGET: + err = sys_semget (first, second, (int)third); + goto out; + case SEMCTL: { + union semun fourth; + err = -EINVAL; + if (!ptr) + goto out; + err = -EFAULT; + if(get_user(fourth.__pad, (void **)ptr)) + goto out; + err = sys_semctl (first, second, (int)third, fourth); + goto out; + } + default: + err = -EINVAL; + goto out; + } + if (call <= MSGCTL) + switch (call) { + case MSGSND: + err = sys_msgsnd (first, (struct msgbuf *) ptr, + second, (int)third); + goto out; + case MSGRCV: + err = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, (int)third); + goto out; + case MSGGET: + err = sys_msgget ((key_t) first, second); + goto out; + case MSGCTL: + err = sys_msgctl (first, second, (struct msqid_ds *) ptr); + goto out; + default: + err = -EINVAL; + goto out; + } + if (call <= SHMCTL) + switch (call) { + case SHMAT: + err = sys_shmat (first, (char *) ptr, second, (ulong *) third); + goto out; + case SHMDT: + err = sys_shmdt ((char *)ptr); + goto out; + case SHMGET: + err = sys_shmget (first, second, (int)third); + goto out; + case SHMCTL: + err = sys_shmctl (first, second, (struct shmid_ds *) ptr); + goto out; + default: + err = -EINVAL; + goto out; + } + else + err = -EINVAL; +out: + unlock_kernel(); + return err; +} + +extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len); + +/* Linux version of mmap */ +asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, unsigned long fd, + unsigned long off) +{ + struct file * file = NULL; + unsigned long retval = -EBADF; + + lock_kernel(); + if (!(flags & MAP_ANONYMOUS)) { + if (fd >= NR_OPEN || !(file = current->files->fd[fd])){ + goto out; + } + } + retval = -ENOMEM; + if(!(flags & MAP_FIXED) && !addr) { + addr = get_unmapped_area(addr, len); + if(!addr){ + goto out; + } + } + + /* See asm-sparc64/uaccess.h */ + retval = -EINVAL; + if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE))) + goto out; + + if(addr >= 0x80000000000ULL) { + retval = current->mm->brk; + goto out; + } + + retval = do_mmap(file, addr, len, prot, flags, off); +out: + unlock_kernel(); + return retval; +} + +/* we come to here via sys_nis_syscall so it can setup the regs argument */ +asmlinkage unsigned long +c_sys_nis_syscall (struct pt_regs *regs) +{ + lock_kernel(); + printk ("Unimplemented SPARC system call %ld\n",regs->u_regs[1]); + show_regs (regs); + unlock_kernel(); + return -ENOSYS; +} + +/* #define DEBUG_SPARC_BREAKPOINT */ + +asmlinkage void +sparc_breakpoint (struct pt_regs *regs) +{ + lock_kernel(); +#ifdef DEBUG_SPARC_BREAKPOINT + printk ("TRAP: Entering kernel PC=%lx, nPC=%lx\n", regs->tpc, regs->tnpc); +#endif + force_sig(SIGTRAP, current); +#ifdef DEBUG_SPARC_BREAKPOINT + printk ("TRAP: Returning to space: PC=%lx nPC=%lx\n", regs->tpc, regs->tnpc); +#endif + unlock_kernel(); +} + +extern void check_pending(int signum); + +asmlinkage int +sparc_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction) +{ + struct sigaction new_sa, *p; + int err = -EINVAL; + + lock_kernel(); + if(signum < 0) { + current->tss.new_signal = 1; + signum = -signum; + } + + if (signum<1 || signum>32) + goto out; + p = signum - 1 + current->sig->action; + if (action) { + err = -EINVAL; + if (signum==SIGKILL || signum==SIGSTOP) + goto out; + err = -EFAULT; + if(copy_from_user(&new_sa, action, sizeof(struct sigaction))) + goto out; + if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) { + err = verify_area(VERIFY_READ, new_sa.sa_handler, 1); + if (err) + goto out; + } + } + + if (oldaction) { + err = -EFAULT; + if (copy_to_user(oldaction, p, sizeof(struct sigaction))) + goto out; + } + + if (action) { + *p = new_sa; + check_pending(signum); + } + + err = 0; +out: + unlock_kernel(); + return err; +} + +/* only AP+ systems have sys_aplib */ +asmlinkage int sys_aplib(void) +{ + return -ENOSYS; +} diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.1.33/linux/arch/sparc64/kernel/sys_sparc32.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/sys_sparc32.c Fri Apr 11 10:47:36 1997 @@ -0,0 +1,831 @@ +/* $Id: sys_sparc32.c,v 1.3 1997/04/09 08:25:17 jj Exp $ + * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * + * These routines maintain argument size conversion between 32bit and 64bit + * environment. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* As gcc will warn about casting u32 to some ptr, we have to cast it to unsigned long first, and that's what is A() for. + * You just do (void *)A(x), instead of having to type (void *)((unsigned long)x) or instead of just (void *)x, which will + * produce warnings */ +#define A(x) ((unsigned long)x) + +/* FIXME: All struct * etc. stuff should be examined and proper structure conversions + * added ASAP -JJ */ + +extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on); +extern asmlinkage unsigned long sys_brk(unsigned long brk); +extern asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long off); +extern asmlinkage int sys_bdflush(int func, long data); +extern asmlinkage int sys_uselib(const char * library); +extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg); +extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); +extern asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev); +extern asmlinkage int sys_mkdir(const char * pathname, int mode); +extern asmlinkage int sys_rmdir(const char * pathname); +extern asmlinkage int sys_unlink(const char * pathname); +extern asmlinkage int sys_symlink(const char * oldname, const char * newname); +extern asmlinkage int sys_link(const char * oldname, const char * newname); +extern asmlinkage int sys_rename(const char * oldname, const char * newname); +extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr); +extern asmlinkage int sys_statfs(const char * path, struct statfs * buf); +extern asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf); +extern asmlinkage int sys_truncate(const char * path, unsigned long length); +extern asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length); +extern asmlinkage int sys_utime(char * filename, struct utimbuf * times); +extern asmlinkage int sys_utimes(char * filename, struct timeval * utimes); +extern asmlinkage int sys_access(const char * filename, int mode); +extern asmlinkage int sys_chdir(const char * filename); +extern asmlinkage int sys_chroot(const char * filename); +extern asmlinkage int sys_chmod(const char * filename, mode_t mode); +extern asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group); +extern asmlinkage int sys_open(const char * filename,int flags,int mode); +extern asmlinkage int sys_creat(const char * pathname, int mode); +extern asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin); +extern asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high, unsigned long offset_low, loff_t *result, unsigned int origin); +extern asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count); +extern asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count); +extern asmlinkage long sys_readv(unsigned long fd, const struct iovec * vector, unsigned long count); +extern asmlinkage long sys_writev(unsigned long fd, const struct iovec * vector, unsigned long count); +extern asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count); +extern asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp); +extern asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout); +extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf); +extern asmlinkage int sys_newlstat(char * filename, struct stat * statbuf); +extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf); +extern asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz); +extern asmlinkage int sys_sysfs(int option, ...); +extern asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf); +extern asmlinkage int sys_umount(char * name); +extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, unsigned long new_flags, void *data); +extern asmlinkage int sys_syslog(int type, char * bug, int count); +extern asmlinkage int sys_personality(unsigned long personality); +extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru); +extern asmlinkage int sys_waitpid(pid_t pid,unsigned int * stat_addr, int options); +extern asmlinkage int sys_sysinfo(struct sysinfo *info); +extern asmlinkage int sys_getitimer(int which, struct itimerval *value); +extern asmlinkage int sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue); +extern asmlinkage int sys_sched_setscheduler(pid_t pid, int policy, struct sched_param *param); +extern asmlinkage int sys_sched_setparam(pid_t pid, struct sched_param *param); +extern asmlinkage int sys_sched_getparam(pid_t pid, struct sched_param *param); +extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval); +extern asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp); +extern asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset); +extern asmlinkage int sys_sigpending(sigset_t *set); +extern asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler); +extern asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg); +extern asmlinkage int sys_acct(const char *name); +extern asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); +extern asmlinkage long sys_times(struct tms * tbuf); +extern asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist); +extern asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist); +extern asmlinkage int sys_newuname(struct new_utsname * name); +extern asmlinkage int sys_uname(struct old_utsname * name); +extern asmlinkage int sys_olduname(struct oldold_utsname * name); +extern asmlinkage int sys_sethostname(char *name, int len); +extern asmlinkage int sys_gethostname(char *name, int len); +extern asmlinkage int sys_setdomainname(char *name, int len); +extern asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim); +extern asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim); +extern asmlinkage int sys_getrusage(int who, struct rusage *ru); +extern asmlinkage int sys_time(int * tloc); +extern asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz); +extern asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz); +extern asmlinkage int sys_adjtimex(struct timex *txc_p); +extern asmlinkage int sys_msync(unsigned long start, size_t len, int flags); +extern asmlinkage int sys_mlock(unsigned long start, size_t len); +extern asmlinkage int sys_munlock(unsigned long start, size_t len); +extern asmlinkage int sys_munmap(unsigned long addr, size_t len); +extern asmlinkage int sys_mprotect(unsigned long start, size_t len, unsigned long prot); +extern asmlinkage unsigned long sys_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags); +extern asmlinkage int sys_swapoff(const char * specialfile); +extern asmlinkage int sys_swapon(const char * specialfile, int swap_flags); +extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen); +extern asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen); +extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen); +extern asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len); +extern asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len); +extern asmlinkage int sys_send(int fd, void * buff, size_t len, unsigned flags); +extern asmlinkage int sys_sendto(int fd, void * buff, size_t len, unsigned flags, struct sockaddr *addr, int addr_len); +extern asmlinkage int sys_recv(int fd, void * ubuf, size_t size, unsigned flags); +extern asmlinkage int sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags, struct sockaddr *addr, int *addr_len); +extern asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int optlen); +extern asmlinkage int sys_getsockopt(int fd, int level, int optname, char *optval, int *optlen); +extern asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags); +extern asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags); +extern asmlinkage int sys_socketcall(int call, unsigned long *args); + +asmlinkage int sys32_ioperm(u32 from, u32 num, int on) +{ + return sys_ioperm((unsigned long)from, (unsigned long)num, on); +} + +/* + * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation.. + * + * This is really horribly ugly. + */ + +asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) +{ + int version, err; + + lock_kernel(); + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + if (call <= SEMCTL) + switch (call) { + case SEMOP: + /* struct sembuf is the same on 32 and 64bit :)) */ + err = sys_semop (first, (struct sembuf *)A(ptr), second); + goto out; + case SEMGET: + err = sys_semget (first, second, third); + goto out; + case SEMCTL: { + /* XXX union semun32 to union semun64 and back conversion */ + union semun fourth; + err = -EINVAL; + if (!ptr) + goto out; + err = -EFAULT; + if(get_user(fourth.__pad, (void **)A(ptr))) + goto out; + err = sys_semctl (first, second, third, fourth); + goto out; + } + default: + err = -EINVAL; + goto out; + } + if (call <= MSGCTL) + switch (call) { + case MSGSND: + /* XXX struct msgbuf has a long first :(( */ + err = sys_msgsnd (first, (struct msgbuf *) A(ptr), + second, third); + goto out; + case MSGRCV: + switch (version) { + case 0: { + struct ipc_kludge tmp; + err = -EINVAL; + if (!ptr) + goto out; + err = -EFAULT; + if(copy_from_user(&tmp,(struct ipc_kludge *) ptr, sizeof (tmp))) + goto out; + err = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); + goto out; + } + case 1: default: + err = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); + goto out; + } + case MSGGET: + err = sys_msgget ((key_t) first, second); + goto out; + case MSGCTL: + err = sys_msgctl (first, second, (struct msqid_ds *) ptr); + goto out; + default: + err = -EINVAL; + goto out; + } + if (call <= SHMCTL) + switch (call) { + case SHMAT: + switch (version) { + case 0: default: { + ulong raddr; + err = sys_shmat (first, (char *) ptr, second, &raddr); + if (err) + goto out; + err = -EFAULT; + if(put_user (raddr, (ulong *) third)) + goto out; + err = 0; + goto out; + } + case 1: /* iBCS2 emulator entry point */ + err = sys_shmat (first, (char *) ptr, second, (ulong *) third); + goto out; + } + case SHMDT: + err = sys_shmdt ((char *)ptr); + goto out; + case SHMGET: + err = sys_shmget (first, second, third); + goto out; + case SHMCTL: + err = sys_shmctl (first, second, (struct shmid_ds *) ptr); + goto out; + default: + err = -EINVAL; + goto out; + } + else + err = -EINVAL; +out: + unlock_kernel(); + return err; +} + +asmlinkage unsigned long sys32_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off) +{ + return sys_mmap((unsigned long)addr, (unsigned long)len, (unsigned long)prot, (unsigned long)flags, + (unsigned long)fd, (unsigned long)off); +} + +asmlinkage int sys32_bdflush(int func, s32 data) +{ + return sys_bdflush(func, (long)data); +} + +asmlinkage int sys32_uselib(u32 library) +{ + return sys_uselib((const char *)A(library)); +} + +asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, u32 arg) +{ + return sys_fcntl(fd, cmd, (unsigned long)arg); +} + +asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) +{ + return sys_ioctl(fd, cmd, (unsigned long)arg); +} + +asmlinkage int sys32_mknod(u32 filename, int mode, dev_t dev) +{ + return sys_mknod((const char *)A(filename), mode, dev); +} + +asmlinkage int sys32_mkdir(u32 pathname, int mode) +{ + return sys_mkdir((const char *)A(pathname), mode); +} + +asmlinkage int sys32_rmdir(u32 pathname) +{ + return sys_rmdir((const char *)A(pathname)); +} + +asmlinkage int sys32_unlink(u32 pathname) +{ + return sys_unlink((const char *)A(pathname)); +} + +asmlinkage int sys32_symlink(u32 oldname, u32 newname) +{ + return sys_symlink((const char *)A(oldname), (const char *)A(newname)); +} + +asmlinkage int sys32_link(u32 oldname, u32 newname) +{ + return sys_link((const char *)A(oldname), (const char *)A(newname)); +} + +asmlinkage int sys32_rename(u32 oldname, u32 newname) +{ + return sys_rename((const char *)A(oldname), (const char *)A(newname)); +} + +asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr) +{ + return sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr)); +} + +asmlinkage int sys32_statfs(u32 path, u32 buf) +{ + return sys_statfs((const char *)A(path), (struct statfs *)A(buf)); +} + +asmlinkage int sys32_fstatfs(unsigned int fd, u32 buf) +{ + return sys_fstatfs(fd, (struct statfs *)A(buf)); +} + +asmlinkage int sys32_truncate(u32 path, u32 length) +{ + return sys_truncate((const char *)A(path), (unsigned long)length); +} + +asmlinkage int sys32_ftruncate(unsigned int fd, u32 length) +{ + return sys_ftruncate(fd, (unsigned long)length); +} + +asmlinkage int sys32_utime(u32 filename, u32 times) +{ + return sys_utime((char *)A(filename), (struct utimbuf *)A(times)); +} + +asmlinkage int sys32_utimes(u32 filename, u32 utimes) +{ + return sys_utimes((char *)A(filename), (struct timeval *)A(utimes)); +} + +asmlinkage int sys32_access(u32 filename, int mode) +{ + return sys_access((const char *)A(filename), mode); +} + +asmlinkage int sys32_chdir(u32 filename) +{ + return sys_chdir((const char *)A(filename)); +} + +asmlinkage int sys32_chroot(u32 filename) +{ + return sys_chroot((const char *)A(filename)); +} + +asmlinkage int sys32_chmod(u32 filename, mode_t mode) +{ + return sys_chmod((const char *)A(filename), mode); +} + +asmlinkage int sys32_chown(u32 filename, uid_t user, gid_t group) +{ + return sys_chown((const char *)A(filename), user, group); +} + +asmlinkage int sys32_open(u32 filename, int flags, int mode) +{ + return sys_open((const char *)A(filename), flags, mode); +} + +asmlinkage int sys32_creat(u32 pathname, int mode) +{ + return sys_creat((const char *)A(pathname), mode); +} + +asmlinkage long sys32_lseek(unsigned int fd, s32 offset, unsigned int origin) +{ + return sys_lseek(fd, (off_t)offset, origin); +} + +asmlinkage int sys32_llseek(unsigned int fd, u32 offset_high, u32 offset_low, u32 result, unsigned int origin) +{ + return sys_llseek(fd, (unsigned long)offset_high, (unsigned long)offset_low, (loff_t *)A(result), origin); +} + +asmlinkage long sys32_read(unsigned int fd, u32 buf, u32 count) +{ + return sys_read(fd, (char *)A(buf), (unsigned long)count); +} + +asmlinkage long sys32_write(unsigned int fd, u32 buf, u32 count) +{ + return sys_write(fd, (const char *)A(buf), (unsigned long)count); +} + +asmlinkage long sys32_readv(u32 fd, u32 vector, u32 count) +{ + return sys_readv((unsigned long)fd, (const struct iovec *)A(vector), (unsigned long)count); +} + +asmlinkage long sys32_writev(u32 fd, u32 vector, u32 count) +{ + return sys_writev((unsigned long)fd, (const struct iovec *)A(vector), (unsigned long)count); +} + +asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count) +{ + return sys_getdents(fd, (void *)A(dirent), count); +} + +asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp) +{ + return sys_select(n, (fd_set *)A(inp), (fd_set *)A(outp), (fd_set *)A(exp), (struct timeval *)A(tvp)); +} + +asmlinkage int sys32_poll(u32 ufds, unsigned int nfds, int timeout) +{ + return sys_poll((struct pollfd *)A(ufds), nfds, timeout); +} + +asmlinkage int sys32_newstat(u32 filename, u32 statbuf) +{ + return sys_newstat((char *)A(filename), (struct stat *)A(statbuf)); +} + +asmlinkage int sys32_newlstat(u32 filename, u32 statbuf) +{ + return sys_newlstat((char *)A(filename), (struct stat *)A(statbuf)); +} + +asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf) +{ + return sys_newfstat(fd, (struct stat *)A(statbuf)); +} + +asmlinkage int sys32_readlink(u32 path, u32 buf, int bufsiz) +{ + return sys_readlink((const char *)A(path), (char *)A(buf), bufsiz); +} + +asmlinkage int sys32_sysfs(int option, ...) +{ + va_list args; + unsigned int x; + int ret; + + va_start(args, option); + switch (option) { + case 1: + ret = sys_sysfs(option, (const char *)A(va_arg(args, u32))); + break; + case 2: + x = va_arg(args, unsigned int); + ret = sys_sysfs(option, x, (char *)A(va_arg(args, u32))); + break; + case 3: + ret = sys_sysfs(option); + break; + } + va_end(args); + return ret; +} + +asmlinkage int sys32_ustat(dev_t dev, u32 ubuf) +{ + return sys_ustat(dev, (struct ustat *)A(ubuf)); +} + +asmlinkage int sys32_umount(u32 name) +{ + return sys_umount((char *)A(name)); +} + +asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags, u32 data) +{ + return sys_mount((char *)A(dev_name), (char *)A(dir_name), (char *)A(type), + (unsigned long)new_flags, (void *)A(data)); +} + +asmlinkage int sys32_syslog(int type, u32 bug, int count) +{ + return sys_syslog(type, (char *)A(bug), count); +} + +asmlinkage int sys32_personality(u32 personality) +{ + return sys_personality((unsigned long)personality); +} + +asmlinkage int sys32_wait4(pid_t pid, u32 stat_addr, int options, u32 ru) +{ + return sys_wait4(pid, (unsigned int *)A(stat_addr), options, (struct rusage *)A(ru)); +} + +asmlinkage int sys32_waitpid(pid_t pid, u32 stat_addr, int options) +{ + return sys_waitpid(pid, (unsigned int *)A(stat_addr), options); +} + +asmlinkage int sys32_sysinfo(u32 info) +{ + return sys_sysinfo((struct sysinfo *)A(info)); +} + +asmlinkage int sys32_getitimer(int which, u32 value) +{ + return sys_getitimer(which, (struct itimerval *)A(value)); +} + +asmlinkage int sys32_setitimer(int which, u32 value, u32 ovalue) +{ + return sys_setitimer(which, (struct itimerval *)A(value), (struct itimerval *)A(ovalue)); +} + +asmlinkage int sys32_sched_setscheduler(pid_t pid, int policy, u32 param) +{ + return sys_sched_setscheduler(pid, policy, (struct sched_param *)A(param)); +} + +asmlinkage int sys32_sched_setparam(pid_t pid, u32 param) +{ + return sys_sched_setparam(pid, (struct sched_param *)A(param)); +} + +asmlinkage int sys32_sched_getparam(pid_t pid, u32 param) +{ + return sys_sched_getparam(pid, (struct sched_param *)A(param)); +} + +asmlinkage int sys32_sched_rr_get_interval(pid_t pid, u32 interval) +{ + return sys_sched_rr_get_interval(pid, (struct timespec *)A(interval)); +} + +asmlinkage int sys32_nanosleep(u32 rqtp, u32 rmtp) +{ + return sys_nanosleep((struct timespec *)A(rqtp), (struct timespec *)A(rmtp)); +} + +asmlinkage int sys32_sigprocmask(int how, u32 set, u32 oset) +{ + return sys_sigprocmask(how, (sigset_t *)A(set), (sigset_t *)A(oset)); +} + +asmlinkage int sys32_sigpending(u32 set) +{ + return sys_sigpending((sigset_t *)A(set)); +} + +asmlinkage unsigned long sys32_signal(int signum, u32 handler) +{ + return sys_signal(signum, (__sighandler_t)A(handler)); +} + +asmlinkage int sys32_reboot(int magic1, int magic2, int cmd, u32 arg) +{ + return sys_reboot(magic1, magic2, cmd, (void *)A(arg)); +} + +asmlinkage int sys32_acct(u32 name) +{ + return sys_acct((const char *)A(name)); +} + +asmlinkage int sys32_getresuid(u32 ruid, u32 euid, u32 suid) +{ + return sys_getresuid((uid_t *)A(ruid), (uid_t *)A(euid), (uid_t *)A(suid)); +} + +asmlinkage long sys32_times(u32 tbuf) +{ + return sys_times((struct tms *)A(tbuf)); +} + +asmlinkage int sys32_getgroups(int gidsetsize, u32 grouplist) +{ + return sys_getgroups(gidsetsize, (gid_t *)A(grouplist)); +} + +asmlinkage int sys32_setgroups(int gidsetsize, u32 grouplist) +{ + return sys_setgroups(gidsetsize, (gid_t *)A(grouplist)); +} + +asmlinkage int sys32_newuname(u32 name) +{ + return sys_newuname((struct new_utsname *)A(name)); +} + +asmlinkage int sys32_uname(u32 name) +{ + return sys_uname((struct old_utsname *)A(name)); +} + +asmlinkage int sys32_olduname(u32 name) +{ + return sys_olduname((struct oldold_utsname *)A(name)); +} + +asmlinkage int sys32_sethostname(u32 name, int len) +{ + return sys_sethostname((char *)A(name), len); +} + +asmlinkage int sys32_gethostname(u32 name, int len) +{ + return sys_gethostname((char *)A(name), len); +} + +asmlinkage int sys32_setdomainname(u32 name, int len) +{ + return sys_setdomainname((char *)A(name), len); +} + +asmlinkage int sys32_getrlimit(unsigned int resource, u32 rlim) +{ + return sys_getrlimit(resource, (struct rlimit *)A(rlim)); +} + +asmlinkage int sys32_setrlimit(unsigned int resource, u32 rlim) +{ + return sys_setrlimit(resource, (struct rlimit *)A(rlim)); +} + +asmlinkage int sys32_getrusage(int who, u32 ru) +{ + return sys_getrusage(who, (struct rusage *)A(ru)); +} + +asmlinkage int sys32_time(u32 tloc) +{ + return sys_time((int *)A(tloc)); +} + +asmlinkage int sys32_gettimeofday(u32 tv, u32 tz) +{ + return sys_gettimeofday((struct timeval *)A(tv), (struct timezone *)A(tz)); +} + +asmlinkage int sys32_settimeofday(u32 tv, u32 tz) +{ + return sys_settimeofday((struct timeval *)A(tv), (struct timezone *)A(tz)); +} + +asmlinkage int sys32_adjtimex(u32 txc_p) +{ + return sys_adjtimex((struct timex *)A(txc_p)); +} + +asmlinkage int sys32_msync(u32 start, u32 len, int flags) +{ + return sys_msync((unsigned long)start, (size_t)len, flags); +} + +asmlinkage int sys32_mlock(u32 start, u32 len) +{ + return sys_mlock((unsigned long)start, (size_t)len); +} + +asmlinkage int sys32_munlock(u32 start, u32 len) +{ + return sys_munlock((unsigned long)start, (size_t)len); +} + +asmlinkage unsigned long sparc32_brk(u32 brk) +{ + return sys_brk((unsigned long)brk); +} + +asmlinkage int sys32_munmap(u32 addr, u32 len) +{ + return sys_munmap((unsigned long)addr, (size_t)len); +} + +asmlinkage int sys32_mprotect(u32 start, u32 len, u32 prot) +{ + return sys_mprotect((unsigned long)start, (size_t)len, (unsigned long)prot); +} + +asmlinkage unsigned long sys32_mremap(u32 addr, u32 old_len, u32 new_len, u32 flags) +{ + return sys_mremap((unsigned long)addr, (unsigned long)old_len, (unsigned long)new_len, (unsigned long)flags); +} + +asmlinkage int sys32_swapoff(u32 specialfile) +{ + return sys_swapoff((const char *)A(specialfile)); +} + +asmlinkage int sys32_swapon(u32 specialfile, int swap_flags) +{ + return sys_swapon((const char *)A(specialfile), swap_flags); +} + +asmlinkage int sys32_bind(int fd, u32 umyaddr, int addrlen) +{ + return sys_bind(fd, (struct sockaddr *)A(umyaddr), addrlen); +} + +asmlinkage int sys32_accept(int fd, u32 upeer_sockaddr, u32 upeer_addrlen) +{ + return sys_accept(fd, (struct sockaddr *)A(upeer_sockaddr), (int *)A(upeer_addrlen)); +} + +asmlinkage int sys32_connect(int fd, u32 uservaddr, int addrlen) +{ + return sys_connect(fd, (struct sockaddr *)A(uservaddr), addrlen); +} + +asmlinkage int sys32_getsockname(int fd, u32 usockaddr, u32 usockaddr_len) +{ + return sys_getsockname(fd, (struct sockaddr *)A(usockaddr), (int *)A(usockaddr_len)); +} + +asmlinkage int sys32_getpeername(int fd, u32 usockaddr, u32 usockaddr_len) +{ + return sys_getpeername(fd, (struct sockaddr *)A(usockaddr), (int *)A(usockaddr_len)); +} + +asmlinkage int sys32_send(int fd, u32 buff, u32 len, unsigned flags) +{ + return sys_send(fd, (void *)A(buff), (size_t)len, flags); +} + +asmlinkage int sys32_sendto(int fd, u32 buff, u32 len, unsigned flags, u32 addr, int addr_len) +{ + return sys_sendto(fd, (void *)A(buff), (size_t)len, flags, (struct sockaddr *)A(addr), addr_len); +} + +asmlinkage int sys32_recv(int fd, u32 ubuf, u32 size, unsigned flags) +{ + return sys_recv(fd, (void *)A(ubuf), (size_t)size, flags); +} + +asmlinkage int sys32_recvfrom(int fd, u32 ubuf, u32 size, unsigned flags, u32 addr, u32 addr_len) +{ + return sys_recvfrom(fd, (void *)A(ubuf), (size_t)size, flags, (struct sockaddr *)A(addr), (int *)A(addr_len)); +} + +asmlinkage int sys32_setsockopt(int fd, int level, int optname, u32 optval, int optlen) +{ + return sys_setsockopt(fd, level, optname, (char *)A(optval), optlen); +} + +asmlinkage int sys32_getsockopt(int fd, int level, int optname, u32 optval, u32 optlen) +{ + return sys_getsockopt(fd, level, optname, (char *)A(optval), (int *)A(optlen)); +} + +asmlinkage int sys32_sendmsg(int fd, u32 msg, unsigned flags) +{ + return sys_sendmsg(fd, (struct msghdr *)A(msg), flags); +} + +asmlinkage int sys32_recvmsg(int fd, u32 msg, unsigned int flags) +{ + return sys_recvmsg(fd, (struct msghdr *)A(msg), flags); +} + +asmlinkage int sys32_socketcall(int call, u32 args) +{ + return sys_socketcall(call, (unsigned long *)A(args)); +} + +extern void check_pending(int signum); + +asmlinkage int sparc32_sigaction (int signum, u32 action, u32 oldaction) +{ + struct sigaction32 new_sa, old_sa; + struct sigaction *p; + int err = -EINVAL; + + lock_kernel(); + if(signum < 0) { + current->tss.new_signal = 1; + signum = -signum; + } + + if (signum<1 || signum>32) + goto out; + p = signum - 1 + current->sig->action; + if (action) { + err = -EINVAL; + if (signum==SIGKILL || signum==SIGSTOP) + goto out; + err = -EFAULT; + if(copy_from_user(&new_sa, A(action), sizeof(struct sigaction32))) + goto out; + if (((__sighandler_t)A(new_sa.sa_handler)) != SIG_DFL && + ((__sighandler_t)A(new_sa.sa_handler)) != SIG_IGN) { + err = verify_area(VERIFY_READ, (__sighandler_t)A(new_sa.sa_handler), 1); + if (err) + goto out; + } + } + + if (oldaction) { + err = -EFAULT; + old_sa.sa_handler = (unsigned)(u64)(p->sa_handler); + old_sa.sa_mask = (sigset32_t)(p->sa_mask); + old_sa.sa_flags = (unsigned)(p->sa_flags); + old_sa.sa_restorer = (unsigned)(u64)(p->sa_restorer); + if (copy_to_user(A(oldaction), p, sizeof(struct sigaction32))) + goto out; + } + + if (action) { + p->sa_handler = (__sighandler_t)A(new_sa.sa_handler); + p->sa_mask = (sigset_t)(new_sa.sa_mask); + p->sa_flags = new_sa.sa_flags; + p->sa_restorer = (void (*)(void))A(new_sa.sa_restorer); + check_pending(signum); + } + + err = 0; +out: + unlock_kernel(); + return err; +} diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S --- v2.1.33/linux/arch/sparc64/kernel/systbls.S Thu Mar 27 14:40:01 1997 +++ linux/arch/sparc64/kernel/systbls.S Fri Apr 11 10:47:36 1997 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.2 1997/03/18 17:59:03 jj Exp $ +/* $Id: systbls.S,v 1.5 1997/04/09 08:25:16 jj Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -16,63 +16,64 @@ .globl sys_call_table32 sys_call_table32: -/*0*/ .xword sys_setup, sys_exit, sys_fork, sys_read, sys_write -/*5*/ .xword sys_open, sys_close, sys_wait4, sys_creat, sys_link -/*10*/ .xword sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod -/*15*/ .xword sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek +/*0*/ .xword sys_setup, sys_exit, sys_fork, sys32_read, sys32_write +/*5*/ .xword sys32_open, sys_close, sys32_wait4, sys32_creat, sys32_link +/*10*/ .xword sys32_unlink, sunos_execv, sys32_chdir, sys_nis_syscall, sys32_mknod +/*15*/ .xword sys32_chmod, sys32_chown, sparc32_brk, sys_nis_syscall, sys32_lseek /*20*/ .xword sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid -/*25*/ .xword sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause -/*30*/ .xword sys_utime, sys_stty, sys_gtty, sys_access, sys_nice - .xword sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall -/*40*/ .xword sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil - .xword sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid -/*50*/ .xword sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl - .xword sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve -/*60*/ .xword sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize +/*25*/ .xword sys32_time, sys32_ptrace, sys_alarm, sys_nis_syscall, sys_pause +/*30*/ .xword sys32_utime, sys_stty, sys_gtty, sys32_access, sys_nice + .xword sys_ftime, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall +/*40*/ .xword sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_profil + .xword sys_nis_syscall, sys_setgid, sys_getgid, sys32_signal, sys_geteuid +/*50*/ .xword sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl + .xword sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys_execve +/*60*/ .xword sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize .xword sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*70*/ .xword sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect - .xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups -/*80*/ .xword sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall - .xword sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall -/*90*/ .xword sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall +/*70*/ .xword sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect + .xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups +/*80*/ .xword sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall + .xword sys32_swapon, sys32_getitimer, sys_nis_syscall, sys32_sethostname, sys_nis_syscall +/*90*/ .xword sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall .xword sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall /*100*/ .xword sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall /*110*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .xword sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_nis_syscall, sys_nis_syscall -/*120*/ .xword sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod - .xword sys_nis_syscall, sys_setreuid, sys_setregid, sys_rename, sys_truncate -/*130*/ .xword sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .xword sys_nis_syscall, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall -/*140*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit - .xword sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .xword sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall +/*120*/ .xword sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod + .xword sys_nis_syscall, sys_setreuid, sys_setregid, sys32_rename, sys32_truncate +/*130*/ .xword sys32_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .xword sys_nis_syscall, sys32_mkdir, sys32_rmdir, sys_nis_syscall, sys_nis_syscall +/*140*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit + .xword sys32_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall /*150*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .xword sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount -/*160*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall - .xword sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall -/*170*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents + .xword sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys32_umount +/*160*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_setdomainname, sys_nis_syscall + .xword sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall +/*170*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents .xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_nis_syscall - .xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname -/*190*/ .xword sys_init_module, sys_personality, sys_prof, sys_break, sys_lock - .xword sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask -/*200*/ .xword sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir - .xword sys_nis_syscall, sys_socketcall, sys_syslog, sys_olduname, sys_nis_syscall -/*210*/ .xword sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo - .xword sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex -/*220*/ .xword sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid - .xword sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid -/*230*/ .xword sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall - .xword sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall -/*240*/ .xword sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall - .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep -/*250*/ .xword sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nis_syscall +/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys_nis_syscall + .xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname +/*190*/ .xword sys_nis_syscall, sys32_personality, sys_prof, sys_break, sys_lock + .xword sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask +/*200*/ .xword sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old_readdir + .xword sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall +/*210*/ .xword sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo + .xword sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex +/*220*/ .xword sys_sigprocmask, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getpgid + .xword sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid +/*230*/ .xword sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall + .xword sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall +/*240*/ .xword sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall + .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys_nanosleep +/*250*/ .xword sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nis_syscall .xword sys_aplib, sys_nis_syscall /* Now the 64-bit native Linux syscall table. */ - .globl sys_call_table64 + .globl sys_call_table64, sys_call_table sys_call_table64: +sys_call_table: /*0*/ .xword sys_setup, sys_exit, sys_fork, sys_read, sys_write /*5*/ .xword sys_open, sys_close, sys_wait4, sys_creat, sys_link /*10*/ .xword sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/time.c linux/arch/sparc64/kernel/time.c --- v2.1.33/linux/arch/sparc64/kernel/time.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/time.c Fri Apr 11 10:47:36 1997 @@ -0,0 +1,352 @@ +/* $Id: time.c,v 1.2 1997/04/10 03:02:35 davem Exp $ + * time.c: UltraSparc timer and TOD clock support. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * + * Based largely on code which is: + * + * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct mostek48t02 *mstk48t02_regs = 0; +struct mostek48t08 *mstk48t08_regs = 0; +struct mostek48t59 *mstk48t59_regs = 0; + +static int set_rtc_mmss(unsigned long); + +/* timer_interrupt() needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick + * + * NOTE: On SUN5 systems the ticker interrupt comes in using 2 + * interrupts, one at level14 and one with softint bit 0. + */ +void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + /* last time the cmos clock got updated */ + static long last_rtc_update=0; + + do_timer(regs); + + /* Determine when to update the Mostek clock. */ + if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 && + xtime.tv_usec > 500000 - (tick >> 1) && + xtime.tv_usec < 500000 + (tick >> 1)) + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ +} + +/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. + * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 + * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. + * + * [For the Julian calendar (which was used in Russia before 1917, + * Britain & colonies before 1752, anywhere else before 1582, + * and is still in use by some communities) leave out the + * -year/100+year/400 terms, and add 10.] + * + * This algorithm was first published by Gauss (I think). + * + * WARNING: this function will overflow on 2106-02-07 06:28:16 on + * machines were long is 32-bit! (However, as time_t is signed, we + * will already get problems at other places on 2038-01-19 03:14:08) + */ +static inline unsigned long mktime(unsigned int year, unsigned int mon, + unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec) +{ + if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ + mon += 12; /* Puts Feb last since it has leap day */ + year -= 1; + } + return ((( + (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + + year*365 - 719499 + )*24 + hour /* now have hours */ + )*60 + min /* now have minutes */ + )*60 + sec; /* finally seconds */ +} + +/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ +static void kick_start_clock(void) +{ + register struct mostek48t02 *regs = mstk48t02_regs; + unsigned char sec; + int i, count; + + prom_printf("CLOCK: Clock was stopped. Kick start "); + + /* Turn on the kick start bit to start the oscillator. */ + regs->creg |= MSTK_CREG_WRITE; + regs->sec &= ~MSTK_STOP; + regs->hour |= MSTK_KICK_START; + regs->creg &= ~MSTK_CREG_WRITE; + + /* Delay to allow the clock oscillator to start. */ + sec = MSTK_REG_SEC(regs); + for (i = 0; i < 3; i++) { + while (sec == MSTK_REG_SEC(regs)) + for (count = 0; count < 100000; count++) + /* nothing */ ; + prom_printf("."); + sec = regs->sec; + } + prom_printf("\n"); + + /* Turn off kick start and set a "valid" time and date. */ + regs->creg |= MSTK_CREG_WRITE; + regs->hour &= ~MSTK_KICK_START; + MSTK_SET_REG_SEC(regs,0); + MSTK_SET_REG_MIN(regs,0); + MSTK_SET_REG_HOUR(regs,0); + MSTK_SET_REG_DOW(regs,5); + MSTK_SET_REG_DOM(regs,1); + MSTK_SET_REG_MONTH(regs,8); + MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO); + regs->creg &= ~MSTK_CREG_WRITE; + + /* Ensure the kick start bit is off. If it isn't, turn it off. */ + while (regs->hour & MSTK_KICK_START) { + prom_printf("CLOCK: Kick start still on!\n"); + regs->creg |= MSTK_CREG_WRITE; + regs->hour &= ~MSTK_KICK_START; + regs->creg &= ~MSTK_CREG_WRITE; + } + + prom_printf("CLOCK: Kick start procedure successful.\n"); +} + +/* Return nonzero if the clock chip battery is low. */ +static int has_low_battery(void) +{ + register struct mostek48t02 *regs = mstk48t02_regs; + unsigned char data1, data2; + + data1 = regs->eeprom[0]; /* Read some data. */ + regs->eeprom[0] = ~data1; /* Write back the complement. */ + data2 = regs->eeprom[0]; /* Read back the complement. */ + regs->eeprom[0] = data1; /* Restore the original value. */ + + return (data1 == data2); /* Was the write blocked? */ +} + +/* XXX HACK HACK HACK, delete me soon */ +static struct linux_prom_ranges XXX_sbus_ranges[PROMREG_MAX]; +static int XXX_sbus_nranges; + +/* Probe for the real time clock chip. */ +__initfunc(static void clock_probe(void)) +{ + struct linux_prom_registers clk_reg[2]; + char model[128]; + int node, sbusnd, err; + + node = prom_getchild(prom_root_node); + sbusnd = prom_searchsiblings(node, "sbus"); + node = prom_getchild(sbusnd); + + if(node == 0 || node == -1) { + prom_printf("clock_probe: Serious problem can't find sbus PROM node.\n"); + prom_halt(); + } + + /* XXX FIX ME */ + err = prom_getproperty(sbusnd, "ranges", (char *) XXX_sbus_ranges, + sizeof(XXX_sbus_ranges)); + if(err == -1) { + prom_printf("clock_probe: Cannot get XXX sbus ranges\n"); + prom_halt(); + } + XXX_sbus_nranges = (err / sizeof(struct linux_prom_ranges)); + + while(1) { + prom_getstring(node, "model", model, sizeof(model)); + if(strcmp(model, "mk48t02") && + strcmp(model, "mk48t08") && + strcmp(model, "mk48t59")) { + node = prom_getsibling(node); + if(node == 0) { + prom_printf("clock_probe: Cannot find timer chip\n"); + prom_halt(); + } + continue; + } + + err = prom_getproperty(node, "reg", (char *)clk_reg, + sizeof(clk_reg)); + if(err == -1) { + prom_printf("clock_probe: Cannot make Mostek\n"); + prom_halt(); + } + + /* XXX fix me badly */ + prom_adjust_regs(clk_reg, 1, XXX_sbus_ranges, XXX_sbus_nranges); + + if(model[5] == '0' && model[6] == '2') { + mstk48t02_regs = (struct mostek48t02 *) + sparc_alloc_io(clk_reg[0].phys_addr, + (void *) 0, sizeof(*mstk48t02_regs), + "clock", clk_reg[0].which_io, 0x0); + } else if(model[5] == '0' && model[6] == '8') { + mstk48t08_regs = (struct mostek48t08 *) + sparc_alloc_io(clk_reg[0].phys_addr, + (void *) 0, sizeof(*mstk48t08_regs), + "clock", clk_reg[0].which_io, 0x0); + mstk48t02_regs = &mstk48t08_regs->regs; + } else { + mstk48t59_regs = (struct mostek48t59 *) + sparc_alloc_io(clk_reg[0].phys_addr, + (void *) 0, sizeof(*mstk48t59_regs), + "clock", clk_reg[0].which_io, 0x0); + mstk48t02_regs = &mstk48t59_regs->regs; + } + break; + } + + /* Report a low battery voltage condition. */ + if (has_low_battery()) + prom_printf("NVRAM: Low battery voltage!\n"); + + /* Kick start the clock if it is completely stopped. */ + if (mstk48t02_regs->sec & MSTK_STOP) + kick_start_clock(); +} + +#ifndef BCD_TO_BIN +#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10) +#endif + +#ifndef BIN_TO_BCD +#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10) +#endif + +__initfunc(void time_init(void)) +{ + extern void init_timers(void (*func)(int, void *, struct pt_regs *)); + unsigned int year, mon, day, hour, min, sec; + struct mostek48t02 *mregs; + + do_get_fast_time = do_gettimeofday; + + clock_probe(); + init_timers(timer_interrupt); + + mregs = mstk48t02_regs; + if(!mregs) { + prom_printf("Something wrong, clock regs not mapped yet.\n"); + prom_halt(); + } + + mregs->creg |= MSTK_CREG_READ; + sec = MSTK_REG_SEC(mregs); + min = MSTK_REG_MIN(mregs); + hour = MSTK_REG_HOUR(mregs); + day = MSTK_REG_DOM(mregs); + mon = MSTK_REG_MONTH(mregs); + year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) ); + xtime.tv_sec = mktime(year, mon, day, hour, min, sec); + xtime.tv_usec = 0; + mregs->creg &= ~MSTK_CREG_READ; +} + +static __inline__ unsigned long do_gettimeoffset(void) +{ + unsigned long offset = 0; + unsigned int count; + + /* XXX -DaveM */ +#if 0 + count = (*master_l10_counter >> 10) & 0x1fffff; +#else + count = 0; +#endif + + if(test_bit(TIMER_BH, &bh_active)) + offset = 1000000; + + return offset + count; +} + +void do_gettimeofday(struct timeval *tv) +{ + unsigned long flags; + + save_and_cli(flags); + *tv = xtime; + tv->tv_usec += do_gettimeoffset(); + if(tv->tv_usec >= 1000000) { + tv->tv_usec -= 1000000; + tv->tv_sec++; + } + restore_flags(flags); +} + +void do_settimeofday(struct timeval *tv) +{ + cli(); + + tv->tv_usec -= do_gettimeoffset(); + if(tv->tv_usec < 0) { + tv->tv_usec += 1000000; + tv->tv_sec--; + } + + xtime = *tv; + time_state = TIME_BAD; + time_maxerror = 0x70000000; + time_esterror = 0x70000000; + sti(); +} + +static int set_rtc_mmss(unsigned long nowtime) +{ + int real_seconds, real_minutes, mostek_minutes; + struct mostek48t02 *regs = mstk48t02_regs; + + /* Not having a register set can lead to trouble. */ + if (!regs) + return -1; + + /* Read the current RTC minutes. */ + regs->creg |= MSTK_CREG_READ; + mostek_minutes = MSTK_REG_MIN(regs); + regs->creg &= ~MSTK_CREG_READ; + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - mostek_minutes) < 30) { + regs->creg |= MSTK_CREG_WRITE; + MSTK_SET_REG_SEC(regs,real_seconds); + MSTK_SET_REG_MIN(regs,real_minutes); + regs->creg &= ~MSTK_CREG_WRITE; + } else + return -1; + + return 0; +} diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c --- v2.1.33/linux/arch/sparc64/kernel/traps.c Thu Mar 27 14:40:01 1997 +++ linux/arch/sparc64/kernel/traps.c Mon Apr 14 09:31:09 1997 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.1 1997/03/18 17:59:12 jj Exp $ +/* $Id: traps.c,v 1.5 1997/04/14 06:56:55 davem Exp $ * arch/sparc/kernel/traps.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -42,6 +42,53 @@ void syscall_trace_exit(struct pt_regs *regs) { +} + +void sparc64_dtlb_fault_handler (void) +{ + printk ("sparc64_dtlb_fault_handler\n"); + while (1); + /* Die for now... */ +} + +void sparc64_dtlb_refbit_handler (struct pt_regs *regs) +{ + printk ("sparc64_dtlb_refbit_handler[%016lx]\n", regs->tpc); + while (1); + /* Die for now... */ +} + +void sparc64_itlb_refbit_handler (void) +{ + printk ("sparc64_itlb_refbit_handler\n"); + while (1); + /* Die for now... */ +} + +void bad_trap (struct pt_regs *regs, long lvl) +{ + printk ("Bad trap %d (tstate %016lx tpc %016lx tnpc %016lx)\n", lvl, regs->tstate, regs->tpc, regs->tnpc); + while (1); + /* Die for now... */ +} + +void bad_trap_tl1 (struct pt_regs *regs, long lvl) +{ + printk ("Bad trap %d at tl1+ (tstate %016lx tpc %016lx tnpc %016lx)\n", lvl, regs->tstate, regs->tpc, regs->tnpc); + while (1); + /* Die for now... */ +} + +void data_access_exception (struct pt_regs *regs) +{ + printk ("Unhandled data access exception sfsr %016lx sfar %016lx\n", spitfire_get_dsfsr(), spitfire_get_sfar()); + die_if_kernel("Data access exception", regs); +} + +void instruction_access_exception (struct pt_regs *regs) +{ + printk ("Unhandled instruction access exception sfsr %016lx\n", spitfire_get_isfsr()); + die_if_kernel("Instruction access exception", regs); } void instruction_dump (unsigned int *pc) diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/ttable.S linux/arch/sparc64/kernel/ttable.S --- v2.1.33/linux/arch/sparc64/kernel/ttable.S Mon Mar 17 14:54:23 1997 +++ linux/arch/sparc64/kernel/ttable.S Fri Apr 11 10:47:36 1997 @@ -1,4 +1,4 @@ -/* $Id: ttable.S,v 1.5 1997/02/25 12:40:09 jj Exp $ +/* $Id: ttable.S,v 1.11 1997/03/25 09:47:21 davem Exp $ * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -9,7 +9,7 @@ sparc64_ttable_tl0: tl0_resv000: BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3) tl0_resv004: BTRAP(0x4) BTRAP(0x5) BTRAP(0x6) BTRAP(0x7) -tl0_iax: TRAP(do_iax) +tl0_iax: ACCESS_EXCEPTION_TRAP(instruction_access_exception) tl0_resv009: BTRAP(0x9) tl0_iae: TRAP(do_iae) tl0_resv00b: BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf) @@ -26,7 +26,7 @@ tl0_div0: TRAP(do_div0) tl0_resv029: BTRAP(0x29) BTRAP(0x2a) BTRAP(0x2b) BTRAP(0x2c) BTRAP(0x2d) BTRAP(0x2e) tl0_resv02f: BTRAP(0x2f) -tl0_dax: TRAP(do_dax) +tl0_dax: ACCESS_EXCEPTION_TRAP(data_access_exception) tl0_resv031: BTRAP(0x31) tl0_dae: TRAP(do_dae) tl0_resv033: BTRAP(0x33) @@ -36,15 +36,18 @@ tl0_privact: TRAP(do_privact) tl0_resv038: BTRAP(0x38) BTRAP(0x39) BTRAP(0x3a) BTRAP(0x3b) BTRAP(0x3c) BTRAP(0x3d) tl0_resv03e: BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40) -tl0_irq1: TRAP_IRQ(do_irq, 1) TRAP_IRQ(do_irq, 2) TRAP_IRQ(do_irq, 3) -tl0_irq4: TRAP_IRQ(do_irq, 4) TRAP_IRQ(do_irq, 5) TRAP_IRQ(do_irq, 6) -tl0_irq7: TRAP_IRQ(do_irq, 7) TRAP_IRQ(do_irq, 8) TRAP_IRQ(do_irq, 9) -tl0_irq10: TRAP_IRQ(do_irq, 10) TRAP_IRQ(do_irq, 11) TRAP_IRQ(do_irq, 12) -tl0_irq13: TRAP_IRQ(do_irq, 13) TRAP_IRQ(do_irq, 14) TRAP_IRQ(do_irq, 15) +tl0_irq1: TRAP_IRQ(handler_irq, 1) TRAP_IRQ(handler_irq, 2) +tl0_irq3: TRAP_IRQ(handler_irq, 3) TRAP_IRQ(handler_irq, 4) +tl0_irq5: TRAP_IRQ(handler_irq, 5) TRAP_IRQ(handler_irq, 6) +tl0_irq7: TRAP_IRQ(handler_irq, 7) TRAP_IRQ(handler_irq, 8) +tl0_irq9: TRAP_IRQ(handler_irq, 9) TRAP_IRQ(handler_irq, 10) +tl0_irq11: TRAP_IRQ(handler_irq, 11) TRAP_IRQ(handler_irq, 12) +tl0_irq13: TRAP_IRQ(handler_irq, 13) TRAP_IRQ(handler_irq, 14) +tl0_irq15: TRAP_IRQ(handler_irq, 15) tl0_resv050: BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55) tl0_resv056: BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b) tl0_resv05c: BTRAP(0x5c) BTRAP(0x5d) BTRAP(0x5e) BTRAP(0x5f) -tl0_ivec: TRAP(do_ivec) +tl0_ivec: TRAP_IVEC tl0_paw: TRAP(do_paw) tl0_vaw: TRAP(do_vaw) tl0_cee: TRAP(do_cee) @@ -93,7 +96,7 @@ tl0_bkpt: BREAKPOINT_TRAP tl0_resv102: BTRAP(0x102) tl0_flushw: FLUSH_WINDOW_TRAP -tl0_resv103: BTRAP(0x103) BTRAP(0x104) BTRAP(0x105) BTRAP(0x106) BTRAP(0x107) +tl0_resv104: BTRAP(0x104) BTRAP(0x105) BTRAP(0x106) BTRAP(0x107) tl0_solaris: SOLARIS_SYSCALL_TRAP tl0_netbsd: NETBSD_SYSCALL_TRAP tl0_resv10a: BTRAP(0x10a) BTRAP(0x10b) BTRAP(0x10c) BTRAP(0x10d) BTRAP(0x10e) @@ -126,43 +129,43 @@ tl0_resv178: BTRAP(0x178) BTRAP(0x179) BTRAP(0x17a) BTRAP(0x17b) BTRAP(0x17c) tl0_resv17d: BTRAP(0x17d) BTRAP(0x17e) BTRAP(0x17f) #define BTRAPS(x) BTRAP(x) BTRAP(x+1) BTRAP(x+2) BTRAP(x+3) BTRAP(x+4) BTRAP(x+5) BTRAP(x+6) BTRAP(x+7) -tl0_resv180: BTRAPS(0x180) -tl0_resv190: BTRAPS(0x190) -tl0_resv1a0: BTRAPS(0x1a0) -tl0_resv1b0: BTRAPS(0x1b0) -tl0_resv1c0: BTRAPS(0x1c0) -tl0_resv1d0: BTRAPS(0x1d0) -tl0_resv1e0: BTRAPS(0x1e0) -tl0_resv1f0: BTRAPS(0x1f0) +tl0_resv180: BTRAPS(0x180) BTRAPS(0x188) +tl0_resv190: BTRAPS(0x190) BTRAPS(0x198) +tl0_resv1a0: BTRAPS(0x1a0) BTRAPS(0x1a8) +tl0_resv1b0: BTRAPS(0x1b0) BTRAPS(0x1b8) +tl0_resv1c0: BTRAPS(0x1c0) BTRAPS(0x1c8) +tl0_resv1d0: BTRAPS(0x1d0) BTRAPS(0x1d8) +tl0_resv1e0: BTRAPS(0x1e0) BTRAPS(0x1e8) +tl0_resv1f0: BTRAPS(0x1f0) BTRAPS(0x1f8) sparc64_ttable_tl1: tl1_resv000: BOOT_KERNEL BTRAPTL1(0x1) BTRAPTL1(0x2) BTRAPTL1(0x3) tl1_resv004: BTRAPTL1(0x4) BTRAPTL1(0x5) BTRAPTL1(0x6) BTRAPTL1(0x7) -tl1_iax: TRAP(do_iax_tl1) +tl1_iax: ACCESS_EXCEPTION_TRAPTL1(instruction_access_exception) tl1_resv009: BTRAPTL1(0x9) -tl1_iae: TRAP(do_iae_tl1) +tl1_iae: TRAPTL1(do_iae_tl1) tl1_resv00b: BTRAPTL1(0xb) BTRAPTL1(0xc) BTRAPTL1(0xd) BTRAPTL1(0xe) BTRAPTL1(0xf) -tl1_ill: TRAP(do_ill_tl1) +tl1_ill: TRAPTL1(do_ill_tl1) tl1_privop: BTRAPTL1(0x11) tl1_resv012: BTRAPTL1(0x12) BTRAPTL1(0x13) BTRAPTL1(0x14) BTRAPTL1(0x15) tl1_resv016: BTRAPTL1(0x16) BTRAPTL1(0x17) BTRAPTL1(0x18) BTRAPTL1(0x19) tl1_resv01a: BTRAPTL1(0x1a) BTRAPTL1(0x1b) BTRAPTL1(0x1c) BTRAPTL1(0x1d) tl1_resv01e: BTRAPTL1(0x1e) BTRAPTL1(0x1f) -tl1_fpdis: TRAP(do_fpdis_tl1) -tl1_fpieee: TRAP(do_fpieee_tl1) -tl1_fpother: TRAP(do_fpother_tl1) -tl1_tof: TRAP(do_tof_tl1) +tl1_fpdis: TRAPTL1(do_fpdis_tl1) +tl1_fpieee: TRAPTL1(do_fpieee_tl1) +tl1_fpother: TRAPTL1(do_fpother_tl1) +tl1_tof: TRAPTL1(do_tof_tl1) tl1_cwin: CLEAN_WINDOW -tl1_div0: TRAP(do_div0_tl1) +tl1_div0: TRAPTL1(do_div0_tl1) tl1_resv029: BTRAPTL1(0x29) BTRAPTL1(0x2a) BTRAPTL1(0x2b) BTRAPTL1(0x2c) tl1_resv02d: BTRAPTL1(0x2d) BTRAPTL1(0x2e) BTRAPTL1(0x2f) -tl1_dax: TRAP(do_dax_tl1) +tl1_dax: ACCESS_EXCEPTION_TRAPTL1(data_access_exception) tl1_resv031: BTRAPTL1(0x31) -tl1_dae: TRAP(do_dae_tl1) +tl1_dae: TRAPTL1(do_dae_tl1) tl1_resv033: BTRAPTL1(0x33) -tl1_mna: TRAP(do_mna_tl1) -tl1_lddfmna: TRAP(do_lddfmna_tl1) -tl1_stdfmna: TRAP(do_stdfmna_tl1) +tl1_mna: TRAPTL1(do_mna_tl1) +tl1_lddfmna: TRAPTL1(do_lddfmna_tl1) +tl1_stdfmna: TRAPTL1(do_stdfmna_tl1) tl1_privact: BTRAPTL1(0x37) tl1_resv038: BTRAPTL1(0x38) BTRAPTL1(0x39) BTRAPTL1(0x3a) BTRAPTL1(0x3b) tl1_resv03c: BTRAPTL1(0x3c) BTRAPTL1(0x3d) BTRAPTL1(0x3e) BTRAPTL1(0x3f) @@ -177,10 +180,10 @@ tl1_resv054: BTRAPTL1(0x54) BTRAPTL1(0x55) BTRAPTL1(0x56) BTRAPTL1(0x57) tl1_resv058: BTRAPTL1(0x58) BTRAPTL1(0x59) BTRAPTL1(0x5a) BTRAPTL1(0x5b) tl1_resv05c: BTRAPTL1(0x5c) BTRAPTL1(0x5d) BTRAPTL1(0x5e) BTRAPTL1(0x5f) -tl1_ivec: TRAP(do_ivec_tl1) -tl1_paw: TRAP(do_paw_tl1) -tl1_vaw: TRAP(do_vaw_tl1) -tl1_cee: TRAP(do_cee_tl1) +tl1_ivec: TRAP_IVEC +tl1_paw: TRAPTL1(do_paw_tl1) +tl1_vaw: TRAPTL1(do_vaw_tl1) +tl1_cee: TRAPTL1(do_cee_tl1) tl1_iamiss: #include "itlb_miss.S" tl1_damiss: @@ -228,40 +231,22 @@ /* Unless we are going to have software trap insns in the kernel code, we * don't need this. For now we just save 8KB. */ + +#define BTRAPSTL1(x) BTRAPTL1(x) BTRAPTL1(x+1) BTRAPTL1(x+2) BTRAPTL1(x+3) BTRAPTL1(x+4) BTRAPTL1(x+5) BTRAPTL1(x+6) BTRAPTL1(x+7) + tl1_sunos: BTRAPTL1(0x100) tl1_bkpt: BREAKPOINT_TRAP tl1_resv102: BTRAPTL1(0x102) tl1_flushw: FLUSH_WINDOW_TRAP -tl1_resv103: BTRAPTL1(0x103) BTRAPTL1(0x104) BTRAPTL1(0x105) BTRAPTL1(0x106) +tl1_resv104: BTRAPTL1(0x104) BTRAPTL1(0x105) BTRAPTL1(0x106) tl1_resv107: BTRAPTL1(0x107) BTRAPTL1(0x108) BTRAPTL1(0x109) BTRAPTL1(0x10a) tl1_resv10b: BTRAPTL1(0x10b) BTRAPTL1(0x10c) BTRAPTL1(0x10d) BTRAPTL1(0x10e) -tl1_resv10f: BTRAPTL1(0x10f) BTRAPTL1(0x110) BTRAPTL1(0x111) BTRAPTL1(0x112) -tl1_resv113: BTRAPTL1(0x113) BTRAPTL1(0x114) BTRAPTL1(0x115) BTRAPTL1(0x116) -tl1_resv117: BTRAPTL1(0x117) BTRAPTL1(0x118) BTRAPTL1(0x119) BTRAPTL1(0x11a) -tl1_resv11b: BTRAPTL1(0x11b) BTRAPTL1(0x11c) BTRAPTL1(0x11d) BTRAPTL1(0x11e) -tl1_resv11f: BTRAPTL1(0x11f) BTRAPTL1(0x120) BTRAPTL1(0x121) BTRAPTL1(0x122) -tl1_resv123: BTRAPTL1(0x123) BTRAPTL1(0x124) BTRAPTL1(0x125) BTRAPTL1(0x126) -tl1_solindir: BTRAPTL1(0x127) BTRAPTL1(0x128) BTRAPTL1(0x129) BTRAPTL1(0x12a) -tl1_resv12b: BTRAPTL1(0x12b) BTRAPTL1(0x12c) BTRAPTL1(0x12d) BTRAPTL1(0x12e) -tl1_resv12f: BTRAPTL1(0x12f) BTRAPTL1(0x130) BTRAPTL1(0x131) BTRAPTL1(0x132) -tl1_resv133: BTRAPTL1(0x133) BTRAPTL1(0x134) BTRAPTL1(0x135) BTRAPTL1(0x136) -tl1_resv137: BTRAPTL1(0x137) BTRAPTL1(0x138) BTRAPTL1(0x139) BTRAPTL1(0x13a) -tl1_resv13b: BTRAPTL1(0x13b) BTRAPTL1(0x13c) BTRAPTL1(0x13d) BTRAPTL1(0x13e) -tl1_resv13f: BTRAPTL1(0x13f) BTRAPTL1(0x140) BTRAPTL1(0x141) BTRAPTL1(0x142) -tl1_resv143: BTRAPTL1(0x143) BTRAPTL1(0x144) BTRAPTL1(0x145) BTRAPTL1(0x146) -tl1_resv147: BTRAPTL1(0x147) BTRAPTL1(0x148) BTRAPTL1(0x149) BTRAPTL1(0x14a) -tl1_resv14b: BTRAPTL1(0x14b) BTRAPTL1(0x14c) BTRAPTL1(0x14d) BTRAPTL1(0x14e) -tl1_resv14f: BTRAPTL1(0x14f) BTRAPTL1(0x150) BTRAPTL1(0x151) BTRAPTL1(0x152) -tl1_resv153: BTRAPTL1(0x153) BTRAPTL1(0x154) BTRAPTL1(0x155) BTRAPTL1(0x156) -tl1_resv157: BTRAPTL1(0x157) BTRAPTL1(0x158) BTRAPTL1(0x159) BTRAPTL1(0x15a) -tl1_resv15b: BTRAPTL1(0x15b) BTRAPTL1(0x15c) BTRAPTL1(0x15d) BTRAPTL1(0x15e) -tl1_resv15f: BTRAPTL1(0x15f) BTRAPTL1(0x160) BTRAPTL1(0x161) BTRAPTL1(0x162) -tl1_resv163: BTRAPTL1(0x163) BTRAPTL1(0x164) BTRAPTL1(0x165) BTRAPTL1(0x166) -tl1_resv167: BTRAPTL1(0x167) BTRAPTL1(0x168) BTRAPTL1(0x169) BTRAPTL1(0x16a) -tl1_resv16b: BTRAPTL1(0x16b) BTRAPTL1(0x16c) BTRAPTL1(0x16d) BTRAPTL1(0x16e) -tl1_resv16f: BTRAPTL1(0x16f) BTRAPTL1(0x170) BTRAPTL1(0x171) BTRAPTL1(0x172) -tl1_resv173: BTRAPTL1(0x173) BTRAPTL1(0x174) BTRAPTL1(0x175) BTRAPTL1(0x176) -tl1_resv177: BTRAPTL1(0x177) BTRAPTL1(0x178) BTRAPTL1(0x179) BTRAPTL1(0x17a) -tl1_resv17b: BTRAPTL1(0x17b) BTRAPTL1(0x17c) BTRAPTL1(0x17d) BTRAPTL1(0x17e) -tl1_resv17f: BTRAPTL1(0x17f) +tl1_resv10f: BTRAPTL1(0x10f) +tl1_resv110: BTRAPSTL1(0x110) BTRAPSTL1(0x118) +tl1_resv120: BTRAPSTL1(0x120) BTRAPSTL1(0x128) +tl1_resv130: BTRAPSTL1(0x130) BTRAPSTL1(0x138) +tl1_resv140: BTRAPSTL1(0x140) BTRAPSTL1(0x148) +tl1_resv150: BTRAPSTL1(0x150) BTRAPSTL1(0x158) +tl1_resv160: BTRAPSTL1(0x160) BTRAPSTL1(0x168) +tl1_resv170: BTRAPSTL1(0x170) BTRAPSTL1(0x178) #endif diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/lib/Makefile linux/arch/sparc64/lib/Makefile --- v2.1.33/linux/arch/sparc64/lib/Makefile Thu Mar 27 14:40:01 1997 +++ linux/arch/sparc64/lib/Makefile Fri Apr 11 10:47:36 1997 @@ -1,11 +1,12 @@ -# $Id: Makefile,v 1.5 1997/03/14 21:04:27 jj Exp $ +# $Id: Makefile,v 1.7 1997/04/07 18:57:05 jj Exp $ # Makefile for Sparc library files.. # CFLAGS := $(CFLAGS) -ansi OBJS = memset.o blockops.o locks.o memcpy.o strlen.o strncmp.o \ - memscan.o strncpy_from_user.o strlen_user.o memcmp.o + memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \ + copy_to_user.o copy_from_user.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) @@ -17,6 +18,12 @@ memset.o: memset.S $(CC) -D__ASSEMBLY__ -ansi -c -o memset.o memset.S +copy_to_user.o: copy_to_user.S + $(CC) -D__ASSEMBLY__ -ansi -c -o copy_to_user.o copy_to_user.S + +copy_from_user.o: copy_from_user.S + $(CC) -D__ASSEMBLY__ -ansi -c -o copy_from_user.o copy_from_user.S + memcpy.o: memcpy.S $(CC) -D__ASSEMBLY__ -ansi -c -o memcpy.o memcpy.S @@ -31,6 +38,9 @@ locks.o: locks.S $(CC) -D__ASSEMBLY__ -ansi -c -o locks.o locks.S + +checksum.o: checksum.S + $(CC) -D__ASSEMBLY__ -ansi -c -o checksum.o checksum.S memscan.o: memscan.S $(CC) -D__ASSEMBLY__ -ansi -c -o memscan.o memscan.S diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/lib/blockops.S linux/arch/sparc64/lib/blockops.S --- v2.1.33/linux/arch/sparc64/lib/blockops.S Mon Mar 17 14:54:23 1997 +++ linux/arch/sparc64/lib/blockops.S Fri Apr 11 10:47:36 1997 @@ -1,33 +1,32 @@ -/* $Id: blockops.S,v 1.3 1997/02/25 20:00:10 jj Exp $ +/* $Id: blockops.S,v 1.5 1997/03/26 18:34:28 jj Exp $ * arch/sparc64/lib/blockops.S: UltraSparc block zero optimized routines. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include -/* FIXME: Write this. */ -#define BZERO_TEST - /* Zero out 256 bytes of memory at (buf + offset). */ #define BLAST_BLOCK(buf, offset) \ stda %f48, [buf + offset + 0x00] %asi; \ stda %f48, [buf + offset + 0x40] %asi; \ stda %f48, [buf + offset + 0x80] %asi; \ - stda %f48, [buf + offset + 0xc0] %asi; \ + stda %f48, [buf + offset + 0xc0] %asi; - /* Copy 32 bytes of memory at (src + offset) to + /* Copy 256 bytes of memory at (src + offset) to * (dst + offset). */ -#define MIRROR_BLOCK(dst, src, offset, t0, t1, t2, t3) \ - ldx [src + offset + 0x18], t0; \ - ldx [src + offset + 0x10], t1; \ - ldx [src + offset + 0x08], t2; \ - ldx [src + offset + 0x00], t3; \ - stx t0, [dst + offset + 0x18]; \ - stx t1, [dst + offset + 0x10]; \ - stx t2, [dst + offset + 0x08]; \ - stx t3, [dst + offset + 0x00]; +#define MIRROR_BLOCK(dst, src, offset, sync) \ + ldda [src + offset + 0x000] %asi, %f0; \ + ldda [src + offset + 0x040] %asi, %f16; \ + ldda [src + offset + 0x080] %asi, %f32; \ + ldda [src + offset + 0x0c0] %asi, %f48; \ + membar sync; \ + stda %f0, [dst + offset + 0x000] %asi; \ + stda %f16, [dst + offset + 0x040] %asi; \ + stda %f32, [dst + offset + 0x080] %asi; \ + stda %f48, [dst + offset + 0x0c0] %asi; .text .align 4 @@ -38,7 +37,17 @@ mov %o0, %o1 wr %g0, ASI_BLK_P, %asi mov 0x10, %g2 - BZERO_TEST + + membar #Sync|#StoreLoad + + fzero %f48 + fzero %f50 + fzero %f52 + fzero %f54 + fzero %f56 + fzero %f58 + fzero %f60 + fzero %f62 1: BLAST_BLOCK(%o0, 0x000) BLAST_BLOCK(%o0, 0x100) @@ -48,6 +57,8 @@ bne,pt %icc, 1b add %o0, 0x400, %o0 + membar #Sync|#LoadStore|#StoreStore + retl mov %o1, %o0 @@ -56,7 +67,15 @@ mov %o0, %o1 wr %g0, ASI_BLK_P, %asi mov 0x08, %g2 - BZERO_TEST + membar #Sync|#StoreLoad + fzero %f48 + fzero %f50 + fzero %f52 + fzero %f54 + fzero %f56 + fzero %f58 + fzero %f60 + fzero %f62 1: BLAST_BLOCK(%o0, 0x000) BLAST_BLOCK(%o0, 0x100) @@ -66,27 +85,54 @@ bne,pt %icc, 1b add %o0, 0x400, %o0 + membar #Sync|#LoadStore|#StoreStore + retl mov %o1, %o0 + .globl __bfill64 +__bfill64: + /* %o0 = buf */ + stx %o1, [%sp + 0x7ff + 128] + wr %g0, ASI_BLK_P, %asi + mov 0x08, %g2 + ldd [%sp + 0x7ff + 128], %f48 + membar #Sync|#StoreLoad + fmovd %f48, %f50 + fmovd %f48, %f52 + fmovd %f48, %f54 + fmovd %f48, %f56 + fmovd %f48, %f58 + fmovd %f48, %f60 + fmovd %f48, %f62 +1: + BLAST_BLOCK(%o0, 0x000) + BLAST_BLOCK(%o0, 0x100) + BLAST_BLOCK(%o0, 0x200) + BLAST_BLOCK(%o0, 0x300) + subcc %g2, 1, %g2 + bne,pt %icc, 1b + add %o0, 0x400, %o0 + + retl + membar #Sync|#LoadStore|#StoreStore + .globl __copy_1page __copy_1page: /* %o0 = dst, %o1 = src */ - or %g0, 0x10, %g1 + or %g0, 0x08, %g1 + wr %g0, ASI_BLK_P, %asi + membar #Sync|#StoreLoad 1: - MIRROR_BLOCK(%o0, %o1, 0x00, %o2, %o3, %o4, %o5) - MIRROR_BLOCK(%o0, %o1, 0x20, %o2, %o3, %o4, %o5) - MIRROR_BLOCK(%o0, %o1, 0x40, %o2, %o3, %o4, %o5) - MIRROR_BLOCK(%o0, %o1, 0x60, %o2, %o3, %o4, %o5) - MIRROR_BLOCK(%o0, %o1, 0x80, %o2, %o3, %o4, %o5) - MIRROR_BLOCK(%o0, %o1, 0xa0, %o2, %o3, %o4, %o5) - MIRROR_BLOCK(%o0, %o1, 0xc0, %o2, %o3, %o4, %o5) - MIRROR_BLOCK(%o0, %o1, 0xe0, %o2, %o3, %o4, %o5) + MIRROR_BLOCK(%o0, %o1, 0x000, #Sync) + MIRROR_BLOCK(%o0, %o1, 0x100, #Sync) + MIRROR_BLOCK(%o0, %o1, 0x200, #Sync) + MIRROR_BLOCK(%o0, %o1, 0x300, #Sync) subcc %g1, 1, %g1 - add %o0, 0x100, %o0 + add %o0, 0x400, %o0 bne,pt %icc, 1b - add %o1, 0x100, %o1 + add %o1, 0x400, %o1 retl - nop + membar #Sync|#LoadStore|#StoreStore diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/lib/checksum.S linux/arch/sparc64/lib/checksum.S --- v2.1.33/linux/arch/sparc64/lib/checksum.S Thu Mar 27 14:40:01 1997 +++ linux/arch/sparc64/lib/checksum.S Fri Apr 11 10:47:36 1997 @@ -15,6 +15,7 @@ #include #include +#include #define CSUM_BIGCHUNK(buf, offset, sum, t0, t1, t2, t3, t4, t5) \ ldd [buf + offset + 0x00], t0; \ @@ -78,8 +79,8 @@ /* The common case is to get called with a nicely aligned * buffer of size 0x20. Follow the code path for that case. */ - .globl C_LABEL(csum_partial) -C_LABEL(csum_partial): /* %o0=buf, %o1=len, %o2=sum */ + .globl csum_partial +csum_partial: /* %o0=buf, %o1=len, %o2=sum */ andcc %o0, 0x7, %g0 ! alignment problems? be,pt %icc, csum_partial_fix_aligned ! yep, handle it andn %o1, 0x7f, %o3 ! num loop iterations @@ -140,8 +141,8 @@ retl ! get outta here sllx %g4, 32, %g4 ! give gfp back - .globl C_LABEL(__csum_partial_copy_start), C_LABEL(__csum_partial_copy_end) -C_LABEL(__csum_partial_copy_start): + .globl __csum_partial_copy_start, __csum_partial_copy_end +__csum_partial_copy_start: #define EX(x,y,a,b,z) \ 98: x,y; \ @@ -288,8 +289,8 @@ * out of you, game over, lights out. */ .align 8 - .globl C_LABEL(__csum_partial_copy_sparc_generic) -C_LABEL(__csum_partial_copy_sparc_generic): + .globl __csum_partial_copy_sparc_generic +__csum_partial_copy_sparc_generic: /* %o0=src, %o1=dest, %g1=len, %g7=sum */ xor %o0, %o1, %o4 ! get changing bits andcc %o4, 3, %g0 ! check for mismatched alignment @@ -460,7 +461,7 @@ 4: addcc %g7, %g5, %g7 retl addc %g0, %g7, %o0 -C_LABEL(__csum_partial_copy_end): +__csum_partial_copy_end: .section .fixup,#alloc,#execinstr .align 4 @@ -514,7 +515,7 @@ sub %o1, 0x70, %o1 add %o3, 0x70, %o3 clr %o2 - movne %g2, 8, %o2 + movrnz %g2, 8, %o2 ba,pt %xcc, 31f sub %o3, %o2, %o3 96: @@ -538,7 +539,7 @@ mov %i5, %o0 mov %i7, %o1 mov %i4, %o2 - call C_LABEL(lookup_fault) + call lookup_fault mov %g7, %i4 cmp %o0, 2 bne,pn %icc, 1f @@ -547,17 +548,17 @@ mov %i0, %o1 mov %i1, %o0 5: - call C_LABEL(__memcpy) + call __memcpy mov %i2, %o2 brnz,a,pn %o0, 2f add %i3, %i2, %i3 add %i1, %i2, %i1 2: mov %i1, %o0 - call C_LABEL(__bzero) + call __bzero mov %i3, %o1 1: - ldx [%sp + 264], %o2 ! struct_ptr of parent + ldx [%sp + STACK_BIAS + 264], %o2 ! struct_ptr of parent st %i5, [%o2] ret restore diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/lib/copy_from_user.S linux/arch/sparc64/lib/copy_from_user.S --- v2.1.33/linux/arch/sparc64/lib/copy_from_user.S Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/lib/copy_from_user.S Fri Apr 11 10:47:36 1997 @@ -0,0 +1,456 @@ +/* copy_user.S: Sparc optimized copy_from_user code. + * + * Copyright(C) 1995 Linus Torvalds + * Copyright(C) 1996 David S. Miller + * Copyright(C) 1996 Eddie C. Dost + * Copyright(C) 1996,1997 Jakub Jelinek + * + * derived from: + * e-mail between David and Eddie. + * + * Returns 0 if successful, otherwise count of bytes not copied yet + * + * FIXME: This code should be optimized for sparc64... -jj + */ + +#include +#include + +#define EX(x,y,a,b,z) \ +98: x,y; \ + .section .fixup,z##alloc,z##execinstr; \ + .align 4; \ +99: retl; \ + a, b, %o0; \ + .section __ex_table,z##alloc; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4 + +#define EX2(x,y,c,d,e,a,b,z) \ +98: x,y; \ + .section .fixup,z##alloc,z##execinstr; \ + .align 4; \ +99: c, d, e; \ + retl; \ + a, b, %o0; \ + .section __ex_table,z##alloc; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4 + +#define EXO2(x,y,z) \ +98: x,##y; \ + .section __ex_table,z##alloc; \ + .align 4; \ + .word 98b, 97f; \ + .text; \ + .align 4 + +#define EXT(start,end,handler,z) \ + .section __ex_table,z##alloc; \ + .align 4; \ + .word start, 0, end, handler; \ + .text; \ + .align 4 + +/* Please do not change following macros unless you change logic used + * in .fixup at the end of this file as well + */ + +/* Both these macros have to start with exactly the same insn */ +#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ + ldda [%src + offset + 0x00] %asi, %t0; \ + ldda [%src + offset + 0x08] %asi, %t2; \ + ldda [%src + offset + 0x10] %asi, %t4; \ + ldda [%src + offset + 0x18] %asi, %t6; \ + st %t0, [%dst + offset + 0x00]; \ + st %t1, [%dst + offset + 0x04]; \ + st %t2, [%dst + offset + 0x08]; \ + st %t3, [%dst + offset + 0x0c]; \ + st %t4, [%dst + offset + 0x10]; \ + st %t5, [%dst + offset + 0x14]; \ + st %t6, [%dst + offset + 0x18]; \ + st %t7, [%dst + offset + 0x1c]; + +#define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ + ldda [%src + offset + 0x00] %asi, %t0; \ + ldda [%src + offset + 0x08] %asi, %t2; \ + ldda [%src + offset + 0x10] %asi, %t4; \ + ldda [%src + offset + 0x18] %asi, %t6; \ + std %t0, [%dst + offset + 0x00]; \ + std %t2, [%dst + offset + 0x08]; \ + std %t4, [%dst + offset + 0x10]; \ + std %t6, [%dst + offset + 0x18]; + +#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \ + ldda [%src - offset - 0x10] %asi, %t0; \ + ldda [%src - offset - 0x08] %asi, %t2; \ + st %t0, [%dst - offset - 0x10]; \ + st %t1, [%dst - offset - 0x0c]; \ + st %t2, [%dst - offset - 0x08]; \ + st %t3, [%dst - offset - 0x04]; + +#define MOVE_HALFCHUNK(src, dst, offset, t0, t1, t2, t3) \ + lduha [%src + offset + 0x00] %asi, %t0; \ + lduha [%src + offset + 0x02] %asi, %t1; \ + lduha [%src + offset + 0x04] %asi, %t2; \ + lduha [%src + offset + 0x06] %asi, %t3; \ + sth %t0, [%dst + offset + 0x00]; \ + sth %t1, [%dst + offset + 0x02]; \ + sth %t2, [%dst + offset + 0x04]; \ + sth %t3, [%dst + offset + 0x06]; + +#define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) \ + lduba [%src - offset - 0x02] %asi, %t0; \ + lduba [%src - offset - 0x01] %asi, %t1; \ + stb %t0, [%dst - offset - 0x02]; \ + stb %t1, [%dst - offset - 0x01]; + + .text + .align 4 + + .globl __copy_from_user +dword_align: + andcc %o1, 1, %g0 + be 4f + andcc %o1, 2, %g0 + + EXO2(lduba [%o1] %asi, %g2,#) + add %o1, 1, %o1 + stb %g2, [%o0] + sub %o2, 1, %o2 + bne 3f + add %o0, 1, %o0 + + EXO2(lduha [%o1] %asi, %g2,#) + add %o1, 2, %o1 + sth %g2, [%o0] + sub %o2, 2, %o2 + ba,pt %xcc, 3f + add %o0, 2, %o0 +4: + EXO2(lduha [%o1] %asi, %g2,#) + add %o1, 2, %o1 + sth %g2, [%o0] + sub %o2, 2, %o2 + ba,pt %xcc, 3f + add %o0, 2, %o0 + +__copy_from_user: /* %o0=dst %o1=src %o2=len */ + wr %g0, ASI_S, %asi + xor %o0, %o1, %o4 +1: + andcc %o4, 3, %o5 +2: + bne,pn %icc, cannot_optimize + cmp %o2, 15 + + bleu,pn %xcc, short_aligned_end + andcc %o1, 3, %g0 + + bne,pn %icc, dword_align +3: + andcc %o1, 4, %g0 + + be,pt %icc, 2f + mov %o2, %g1 + + EXO2(lda [%o1] %asi, %o4,#) + sub %g1, 4, %g1 + st %o4, [%o0] + add %o1, 4, %o1 + add %o0, 4, %o0 +2: + andcc %g1, 0xffffffffffffff80, %g7 + be,pn %xcc, 3f + andcc %o0, 4, %g0 + + be,pn %icc, ldd_std + 4 +5: + MOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5) + MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5) + MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5) + MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5) +80: + EXT(5b, 80b, 50f,#) + subcc %g7, 128, %g7 + add %o1, 128, %o1 + bne,pt %xcc, 5b + add %o0, 128, %o0 +3: + andcc %g1, 0x70, %g7 + be,pn %icc, copy_user_table_end + andcc %g1, 8, %g0 +100: + rd %pc, %o5 + srl %g7, 1, %o4 + add %g7, %o4, %o4 + add %o1, %g7, %o1 + sub %o5, %o4, %o5 + jmpl %o5 + (copy_user_table_end - 100b), %g0 + add %o0, %g7, %o0 + +copy_user_table: + MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5) + MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5) + MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5) + MOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5) + MOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5) + MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5) + MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5) +copy_user_table_end: + EXT(copy_user_table, copy_user_table_end, 51f,#) + be,pt %icc, copy_user_last7 + andcc %g1, 4, %g0 + + EX(ldda [%o1] %asi, %g2, and %g1, 0xf,#) + add %o0, 8, %o0 + add %o1, 8, %o1 + st %g2, [%o0 - 0x08] + st %g3, [%o0 - 0x04] +copy_user_last7: + be,pn %icc, 1f + andcc %g1, 2, %g0 + + EX(lda [%o1] %asi, %g2, and %g1, 7,#) + add %o1, 4, %o1 + st %g2, [%o0] + add %o0, 4, %o0 +1: + be,pn %icc, 1f + andcc %g1, 1, %g0 + + EX(lduha [%o1] %asi, %g2, and %g1, 3,#) + add %o1, 2, %o1 + sth %g2, [%o0] + add %o0, 2, %o0 +1: + be,pn %icc, 1f + nop + + EX(lduba [%o1] %asi, %g2, add %g0, 1,#) + stb %g2, [%o0] +1: + retl + clr %o0 + +ldd_std: + MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5) + MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5) + MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5) + MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5) +81: + EXT(ldd_std, 81b, 52f,#) + subcc %g7, 128, %g7 + add %o1, 128, %o1 + bne,pt %xcc, ldd_std + add %o0, 128, %o0 + + andcc %g1, 0x70, %g7 + be,pn %icc, copy_user_table_end + andcc %g1, 8, %g0 +101: + rd %pc, %o5 + srl %g7, 1, %o4 + add %g7, %o4, %o4 + add %o1, %g7, %o1 + sub %o5, %o4, %o5 + jmpl %o5 + (copy_user_table_end - 101b), %g0 + add %o0, %g7, %o0 + +cannot_optimize: + bleu short_end + cmp %o5, 2 + + bne byte_chunk + and %o2, 0xfffffffffffffff0, %o3 + + andcc %o1, 1, %g0 + be 10f + nop + + EXO2(lduba [%o1] %asi, %g2,#) + add %o1, 1, %o1 + stb %g2, [%o0] + sub %o2, 1, %o2 + andcc %o2, 0xfffffffffffffff0, %o3 + be short_end + add %o0, 1, %o0 +10: + MOVE_HALFCHUNK(o1, o0, 0x00, g2, g3, g4, g5) + MOVE_HALFCHUNK(o1, o0, 0x08, g2, g3, g4, g5) +82: + EXT(10b, 82b, 53f,#) + subcc %o3, 0x10, %o3 + add %o1, 0x10, %o1 + bne 10b + add %o0, 0x10, %o0 + ba,pt %xcc, 2f + and %o2, 0xe, %o3 + +byte_chunk: + MOVE_SHORTCHUNK(o1, o0, -0x02, g2, g3) + MOVE_SHORTCHUNK(o1, o0, -0x04, g2, g3) + MOVE_SHORTCHUNK(o1, o0, -0x06, g2, g3) + MOVE_SHORTCHUNK(o1, o0, -0x08, g2, g3) + MOVE_SHORTCHUNK(o1, o0, -0x0a, g2, g3) + MOVE_SHORTCHUNK(o1, o0, -0x0c, g2, g3) + MOVE_SHORTCHUNK(o1, o0, -0x0e, g2, g3) + MOVE_SHORTCHUNK(o1, o0, -0x10, g2, g3) +83: + EXT(byte_chunk, 83b, 54f,#) + subcc %o3, 0x10, %o3 + add %o1, 0x10, %o1 + bne,pt %xcc, byte_chunk + add %o0, 0x10, %o0 + +short_end: + and %o2, 0xe, %o3 +2: + rd %pc, %o5 + sll %o3, 3, %o4 + add %o0, %o3, %o0 + sub %o5, %o4, %o5 + add %o1, %o3, %o1 + jmpl %o5 + (short_table_end - 2b), %g0 + andcc %o2, 1, %g0 +84: + MOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3) + MOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3) + MOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3) + MOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3) + MOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3) + MOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3) + MOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3) +short_table_end: + EXT(84b, short_table_end, 55f,#) + be 1f + nop + EX(lduba [%o1] %asi, %g2, add %g0, 1,#) + stb %g2, [%o0] +1: + retl + clr %o0 + +short_aligned_end: + bne short_end + andcc %o2, 8, %g0 + + be 1f + andcc %o2, 4, %g0 + + EXO2(lda [%o1 + 0x00] %asi, %g2,#) + EX(lda [%o1 + 0x04] %asi, %g3, sub %o2, 4,#) + add %o1, 8, %o1 + st %g2, [%o0 + 0x00] + st %g3, [%o0 + 0x04] + add %o0, 8, %o0 +1: + ba,pt %xcc, copy_user_last7 + mov %o2, %g1 + + .section .fixup,#alloc,#execinstr + .align 4 +97: + retl + mov %o2, %o0 +/* exception routine sets %g2 to (broken_insn - first_insn)>>2 */ +50: +/* This magic counts how many bytes are left when crash in MOVE_BIGCHUNK + * happens. This is derived from the amount ldd reads, st stores, etc. + * x = g2 % 12; + * o0 = g1 + g7 - ((g2 / 12) * 32 + (x < 4) ? x * 8 : (x - 4) * 4) + */ + cmp %g2, 12 + bcs 1f + cmp %g2, 24 + bcs 2f + cmp %g2, 36 + bcs 3f + nop + sub %g2, 12, %g2 + sub %g7, 32, %g7 +3: + sub %g2, 12, %g2 + sub %g7, 32, %g7 +2: + sub %g2, 12, %g2 + sub %g7, 32, %g7 +1: + cmp %g2, 4 + bcs,a 1f + sll %g2, 3, %g2 + sub %g2, 4, %g2 + sll %g2, 2, %g2 +1: + and %g1, 0x7f, %o0 + add %o0, %g7, %o0 + retl + sub %o0, %g2, %o0 +51: +/* i = 41 - g2; j = i % 6; + * o0 = (g1 & 15) + (i / 6) * 16 + (j < 4) ? (j + 1) * 4 : (j - 3) * 8; + */ + neg %g2 + and %g1, 0xf, %g1 + add %g2, 41, %g2 +1: + cmp %g2, 6 + bcs,a 2f + cmp %g2, 4 + add %g1, 16, %g1 + b 1b + sub %g2, 6, %g2 +2: + bcs,a 3f + inc %g2 + sub %g2, 3, %g2 + b 2f + sll %g2, 3, %g2 +3: + sll %g2, 2, %g2 +2: + retl + add %g1, %g2, %o0 +52: +/* o0 = g1 + g7 - (g2 / 8) * 32 + (x & 3) * 8 */ + and %g2, 0xfffffffffffffff8, %g4 + and %g2, 3, %g2 + sll %g4, 2, %g4 + sll %g2, 3, %g2 + add %g2, %g4, %g2 + b,a 1b +53: +/* o0 = o3 + (o2 & 15) - (g2 & 8) - (g2 & 3) * 2 */ + and %g2, 3, %g4 + and %g2, 0xfffffffffffffff8, %g2 + sll %g4, 1, %g4 + add %g2, %g4, %g2 + and %o2, 0xf, %o0 + add %o0, %o3, %o0 + retl + sub %o0, %g2, %o0 +54: +/* o0 = o3 + (o2 & 15) - (g2 / 4) * 2 - (g2 & 1) */ + srl %g2, 2, %o4 + and %g2, 1, %o1 + sll %o4, 1, %o4 + and %o2, 0xf, %o2 + sub %o3, %o1, %o3 + sub %o2, %o4, %o2 + retl + add %o2, %o3, %o0 +55: +/* o0 = (o2 & 1) + (27 - g2)/4 * 2 + ((27 - g2) & 1) */ + neg %g2 + and %o2, 1, %o2 + add %g2, 27, %g2 + srl %g2, 2, %o1 + and %g2, 1, %g2 + sll %o1, 1, %o1 + add %o2, %g2, %o0 + retl + add %o0, %o1, %o0 diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/lib/copy_to_user.S linux/arch/sparc64/lib/copy_to_user.S --- v2.1.33/linux/arch/sparc64/lib/copy_to_user.S Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/lib/copy_to_user.S Fri Apr 11 10:47:36 1997 @@ -0,0 +1,456 @@ +/* copy_user.S: Sparc optimized copy_to_user code. + * + * Copyright(C) 1995 Linus Torvalds + * Copyright(C) 1996 David S. Miller + * Copyright(C) 1996 Eddie C. Dost + * Copyright(C) 1996,1997 Jakub Jelinek + * + * derived from: + * e-mail between David and Eddie. + * + * Returns 0 if successful, otherwise count of bytes not copied yet + * + * FIXME: This code should be optimized for sparc64... -jj + */ + +#include +#include + +#define EX(x,y,a,b,z) \ +98: x,y; \ + .section .fixup,z##alloc,z##execinstr; \ + .align 4; \ +99: retl; \ + a, b, %o0; \ + .section __ex_table,z##alloc; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4 + +#define EX2(x,y,c,d,e,a,b,z) \ +98: x,y; \ + .section .fixup,z##alloc,z##execinstr; \ + .align 4; \ +99: c, d, e; \ + retl; \ + a, b, %o0; \ + .section __ex_table,z##alloc; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4 + +#define EXO2(x,y,z) \ +98: x,##y; \ + .section __ex_table,z##alloc; \ + .align 4; \ + .word 98b, 97f; \ + .text; \ + .align 4 + +#define EXT(start,end,handler,z) \ + .section __ex_table,z##alloc; \ + .align 4; \ + .word start, 0, end, handler; \ + .text; \ + .align 4 + +/* Please do not change following macros unless you change logic used + * in .fixup at the end of this file as well + */ + +/* Both these macros have to start with exactly the same insn */ +#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ + ldd [%src + offset + 0x00], %t0; \ + ldd [%src + offset + 0x08], %t2; \ + ldd [%src + offset + 0x10], %t4; \ + ldd [%src + offset + 0x18], %t6; \ + sta %t0, [%dst + offset + 0x00] %asi; \ + sta %t1, [%dst + offset + 0x04] %asi; \ + sta %t2, [%dst + offset + 0x08] %asi; \ + sta %t3, [%dst + offset + 0x0c] %asi; \ + sta %t4, [%dst + offset + 0x10] %asi; \ + sta %t5, [%dst + offset + 0x14] %asi; \ + sta %t6, [%dst + offset + 0x18] %asi; \ + sta %t7, [%dst + offset + 0x1c] %asi; + +#define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ + ldd [%src + offset + 0x00], %t0; \ + ldd [%src + offset + 0x08], %t2; \ + ldd [%src + offset + 0x10], %t4; \ + ldd [%src + offset + 0x18], %t6; \ + stda %t0, [%dst + offset + 0x00] %asi; \ + stda %t2, [%dst + offset + 0x08] %asi; \ + stda %t4, [%dst + offset + 0x10] %asi; \ + stda %t6, [%dst + offset + 0x18] %asi; + +#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \ + ldd [%src - offset - 0x10], %t0; \ + ldd [%src - offset - 0x08], %t2; \ + sta %t0, [%dst - offset - 0x10] %asi; \ + sta %t1, [%dst - offset - 0x0c] %asi; \ + sta %t2, [%dst - offset - 0x08] %asi; \ + sta %t3, [%dst - offset - 0x04] %asi; + +#define MOVE_HALFCHUNK(src, dst, offset, t0, t1, t2, t3) \ + lduh [%src + offset + 0x00], %t0; \ + lduh [%src + offset + 0x02], %t1; \ + lduh [%src + offset + 0x04], %t2; \ + lduh [%src + offset + 0x06], %t3; \ + stha %t0, [%dst + offset + 0x00] %asi; \ + stha %t1, [%dst + offset + 0x02] %asi; \ + stha %t2, [%dst + offset + 0x04] %asi; \ + stha %t3, [%dst + offset + 0x06] %asi; + +#define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) \ + ldub [%src - offset - 0x02], %t0; \ + ldub [%src - offset - 0x01], %t1; \ + stba %t0, [%dst - offset - 0x02] %asi; \ + stba %t1, [%dst - offset - 0x01] %asi; + + .text + .align 4 + + .globl __copy_to_user +dword_align: + andcc %o1, 1, %g0 + be 4f + andcc %o1, 2, %g0 + + ldub [%o1], %g2 + add %o1, 1, %o1 + EXO2(stba %g2, [%o0] %asi,#) + sub %o2, 1, %o2 + bne 3f + add %o0, 1, %o0 + + lduh [%o1], %g2 + add %o1, 2, %o1 + EXO2(stha %g2, [%o0] %asi,#) + sub %o2, 2, %o2 + ba,pt %xcc, 3f + add %o0, 2, %o0 +4: + lduh [%o1], %g2 + add %o1, 2, %o1 + EXO2(stha %g2, [%o0] %asi,#) + sub %o2, 2, %o2 + ba,pt %xcc, 3f + add %o0, 2, %o0 + +__copy_to_user: /* %o0=dst %o1=src %o2=len */ + wr %g0, ASI_S, %asi + xor %o0, %o1, %o4 +1: + andcc %o4, 3, %o5 +2: + bne,pn %icc, cannot_optimize + cmp %o2, 15 + + bleu,pn %xcc, short_aligned_end + andcc %o1, 3, %g0 + + bne,pn %icc, dword_align +3: + andcc %o1, 4, %g0 + + be,pt %icc, 2f + mov %o2, %g1 + + ld [%o1], %o4 + sub %g1, 4, %g1 + EXO2(sta %o4, [%o0] %asi,#) + add %o1, 4, %o1 + add %o0, 4, %o0 +2: + andcc %g1, 0xffffffffffffff80, %g7 + be,pn %xcc, 3f + andcc %o0, 4, %g0 + + be,pn %icc, ldd_std + 4 +5: + MOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5) + MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5) + MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5) + MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5) +80: + EXT(5b, 80b, 50f,#) + subcc %g7, 128, %g7 + add %o1, 128, %o1 + bne,pt %xcc, 5b + add %o0, 128, %o0 +3: + andcc %g1, 0x70, %g7 + be,pn %icc, copy_user_table_end + andcc %g1, 8, %g0 +100: + rd %pc, %o5 + srl %g7, 1, %o4 + add %g7, %o4, %o4 + add %o1, %g7, %o1 + sub %o5, %o4, %o5 + jmpl %o5 + (copy_user_table_end - 100b), %g0 + add %o0, %g7, %o0 + +copy_user_table: + MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5) + MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5) + MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5) + MOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5) + MOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5) + MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5) + MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5) +copy_user_table_end: + EXT(copy_user_table, copy_user_table_end, 51f,#) + be,pt %icc, copy_user_last7 + andcc %g1, 4, %g0 + + ldd [%o1], %g2 + add %o0, 8, %o0 + add %o1, 8, %o1 + EX(sta %g2, [%o0 - 0x08] %asi, and %g1, 0xf,#) + EX2(sta %g3, [%o0 - 0x04] %asi, and %g1, 0xf, %g1, sub %g1, 4,#) +copy_user_last7: + be,pn %icc, 1f + andcc %g1, 2, %g0 + + ld [%o1], %g2 + add %o1, 4, %o1 + EX(sta %g2, [%o0] %asi, and %g1, 7,#) + add %o0, 4, %o0 +1: + be,pn %icc, 1f + andcc %g1, 1, %g0 + + lduh [%o1], %g2 + add %o1, 2, %o1 + EX(stha %g2, [%o0] %asi, and %g1, 3,#) + add %o0, 2, %o0 +1: + be,pn %icc, 1f + nop + + ldub [%o1], %g2 + EX(stba %g2, [%o0] %asi, add %g0, 1,#) +1: + retl + clr %o0 + +ldd_std: + MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5) + MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5) + MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5) + MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5) +81: + EXT(ldd_std, 81b, 52f,#) + subcc %g7, 128, %g7 + add %o1, 128, %o1 + bne,pt %xcc, ldd_std + add %o0, 128, %o0 + + andcc %g1, 0x70, %g7 + be,pn %icc, copy_user_table_end + andcc %g1, 8, %g0 +101: + rd %pc, %o5 + srl %g7, 1, %o4 + add %g7, %o4, %o4 + add %o1, %g7, %o1 + sub %o5, %o4, %o5 + jmpl %o5 + (copy_user_table_end - 101b), %g0 + add %o0, %g7, %o0 + +cannot_optimize: + bleu short_end + cmp %o5, 2 + + bne byte_chunk + and %o2, 0xfffffffffffffff0, %o3 + + andcc %o1, 1, %g0 + be 10f + nop + + ldub [%o1], %g2 + add %o1, 1, %o1 + EXO2(stba %g2, [%o0] %asi,#) + sub %o2, 1, %o2 + andcc %o2, 0xfffffffffffffff0, %o3 + be short_end + add %o0, 1, %o0 +10: + MOVE_HALFCHUNK(o1, o0, 0x00, g2, g3, g4, g5) + MOVE_HALFCHUNK(o1, o0, 0x08, g2, g3, g4, g5) +82: + EXT(10b, 82b, 53f,#) + subcc %o3, 0x10, %o3 + add %o1, 0x10, %o1 + bne 10b + add %o0, 0x10, %o0 + ba,pt %xcc, 2f + and %o2, 0xe, %o3 + +byte_chunk: + MOVE_SHORTCHUNK(o1, o0, -0x02, g2, g3) + MOVE_SHORTCHUNK(o1, o0, -0x04, g2, g3) + MOVE_SHORTCHUNK(o1, o0, -0x06, g2, g3) + MOVE_SHORTCHUNK(o1, o0, -0x08, g2, g3) + MOVE_SHORTCHUNK(o1, o0, -0x0a, g2, g3) + MOVE_SHORTCHUNK(o1, o0, -0x0c, g2, g3) + MOVE_SHORTCHUNK(o1, o0, -0x0e, g2, g3) + MOVE_SHORTCHUNK(o1, o0, -0x10, g2, g3) +83: + EXT(byte_chunk, 83b, 54f,#) + subcc %o3, 0x10, %o3 + add %o1, 0x10, %o1 + bne,pt %xcc, byte_chunk + add %o0, 0x10, %o0 + +short_end: + and %o2, 0xe, %o3 +2: + rd %pc, %o5 + sll %o3, 3, %o4 + add %o0, %o3, %o0 + sub %o5, %o4, %o5 + add %o1, %o3, %o1 + jmpl %o5 + (short_table_end - 2b), %g0 + andcc %o2, 1, %g0 +84: + MOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3) + MOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3) + MOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3) + MOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3) + MOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3) + MOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3) + MOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3) +short_table_end: + EXT(84b, short_table_end, 55f,#) + be 1f + nop + ldub [%o1], %g2 + EX(stba %g2, [%o0] %asi, add %g0, 1,#) +1: + retl + clr %o0 + +short_aligned_end: + bne short_end + andcc %o2, 8, %g0 + + be 1f + andcc %o2, 4, %g0 + + ld [%o1 + 0x00], %g2 + ld [%o1 + 0x04], %g3 + add %o1, 8, %o1 + EXO2(sta %g2, [%o0 + 0x00] %asi,#) + EX(sta %g3, [%o0 + 0x04] %asi, sub %o2, 4,#) + add %o0, 8, %o0 +1: + ba,pt %xcc, copy_user_last7 + mov %o2, %g1 + + .section .fixup,#alloc,#execinstr + .align 4 +97: + retl + mov %o2, %o0 +/* exception routine sets %g2 to (broken_insn - first_insn)>>2 */ +50: +/* This magic counts how many bytes are left when crash in MOVE_BIGCHUNK + * happens. This is derived from the amount ldd reads, st stores, etc. + * x = g2 % 12; + * o0 = g1 + g7 - ((g2 / 12) * 32 + (x < 4) ? x * 8 : (x - 4) * 4) + */ + cmp %g2, 12 + bcs 1f + cmp %g2, 24 + bcs 2f + cmp %g2, 36 + bcs 3f + nop + sub %g2, 12, %g2 + sub %g7, 32, %g7 +3: + sub %g2, 12, %g2 + sub %g7, 32, %g7 +2: + sub %g2, 12, %g2 + sub %g7, 32, %g7 +1: + cmp %g2, 4 + bcs,a 1f + sll %g2, 3, %g2 + sub %g2, 4, %g2 + sll %g2, 2, %g2 +1: + and %g1, 0x7f, %o0 + add %o0, %g7, %o0 + retl + sub %o0, %g2, %o0 +51: +/* i = 41 - g2; j = i % 6; + * o0 = (g1 & 15) + (i / 6) * 16 + (j < 4) ? (j + 1) * 4 : (j - 3) * 8; + */ + neg %g2 + and %g1, 0xf, %g1 + add %g2, 41, %g2 +1: + cmp %g2, 6 + bcs,a 2f + cmp %g2, 4 + add %g1, 16, %g1 + b 1b + sub %g2, 6, %g2 +2: + bcs,a 3f + inc %g2 + sub %g2, 3, %g2 + b 2f + sll %g2, 3, %g2 +3: + sll %g2, 2, %g2 +2: + retl + add %g1, %g2, %o0 +52: +/* o0 = g1 + g7 - (g2 / 8) * 32 + (x & 3) * 8 */ + and %g2, 0xfffffffffffffff8, %g4 + and %g2, 3, %g2 + sll %g4, 2, %g4 + sll %g2, 3, %g2 + add %g2, %g4, %g2 + b,a 1b +53: +/* o0 = o3 + (o2 & 15) - (g2 & 8) - (g2 & 3) * 2 */ + and %g2, 3, %g4 + and %g2, 0xfffffffffffffff8, %g2 + sll %g4, 1, %g4 + add %g2, %g4, %g2 + and %o2, 0xf, %o0 + add %o0, %o3, %o0 + retl + sub %o0, %g2, %o0 +54: +/* o0 = o3 + (o2 & 15) - (g2 / 4) * 2 - (g2 & 1) */ + srl %g2, 2, %o4 + and %g2, 1, %o1 + sll %o4, 1, %o4 + and %o2, 0xf, %o2 + sub %o3, %o1, %o3 + sub %o2, %o4, %o2 + retl + add %o2, %o3, %o0 +55: +/* o0 = (o2 & 1) + (27 - g2)/4 * 2 + ((27 - g2) & 1) */ + neg %g2 + and %o2, 1, %o2 + add %g2, 27, %g2 + srl %g2, 2, %o1 + and %g2, 1, %g2 + sll %o1, 1, %o1 + add %o2, %g2, %o0 + retl + add %o0, %o1, %o0 diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/lib/memcmp.S linux/arch/sparc64/lib/memcmp.S --- v2.1.33/linux/arch/sparc64/lib/memcmp.S Thu Mar 27 14:40:01 1997 +++ linux/arch/sparc64/lib/memcmp.S Fri Apr 11 10:47:36 1997 @@ -1,4 +1,4 @@ -/* $Id: memcmp.S,v 1.1 1997/03/14 21:04:23 jj Exp $ +/* $Id: memcmp.S,v 1.2 1997/04/01 03:43:18 davem Exp $ * Sparc64 optimized memcmp code. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -20,7 +20,7 @@ brnz,pn %o4, 3f addcc %o3, 1, %o3 bne,a,pt %xcc, 1b - ldub [%o0 + %o3], %o5 + ldub [%o0 + %o3], %o4 2: retl clr %o0 diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/lib/memcpy.S linux/arch/sparc64/lib/memcpy.S --- v2.1.33/linux/arch/sparc64/lib/memcpy.S Thu Mar 27 14:40:01 1997 +++ linux/arch/sparc64/lib/memcpy.S Fri Apr 11 10:47:36 1997 @@ -394,21 +394,21 @@ lduw [%o1], %o3 add %o0, -8, %o0 lduw [%o1 + 4], %o4 - b 8f + ba,pt %xcc, 8f add %g3, 1, %g3 2: lduw [%o1], %o4 add %o0, -12, %o0 lduw [%o1 + 4], %o5 add %g3, 2, %g3 - b 9f + ba,pt %xcc, 9f add %o1, -4, %o1 3: lduw [%o1], %g1 add %o0, -4, %o0 lduw [%o1 + 4], %o3 srl %o2, 2, %g3 - b 7f + ba,pt %xcc, 7f add %o1, 4, %o1 4: lduw [%o1], %o5 @@ -522,5 +522,5 @@ stw %g3, [%o0 + 0x04] add %o0, 8, %o0 1: - b 81b + ba,pt %xcc, 81b mov %o2, %g1 diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/lib/memset.S linux/arch/sparc64/lib/memset.S --- v2.1.33/linux/arch/sparc64/lib/memset.S Thu Mar 27 14:40:01 1997 +++ linux/arch/sparc64/lib/memset.S Fri Apr 11 10:47:36 1997 @@ -7,6 +7,7 @@ * occurs and we were called as clear_user. */ +#include #include #define EX(x,y,a,b,z) \ @@ -32,29 +33,29 @@ * in the .fixup section below as well. * Store 64 bytes at (BASE + OFFSET) using value SOURCE. */ #define ZERO_BIG_BLOCK(base, offset, source) \ - stx source, [base + offset + 0x00]; \ - stx source, [base + offset + 0x08]; \ - stx source, [base + offset + 0x10]; \ - stx source, [base + offset + 0x18]; \ - stx source, [base + offset + 0x20]; \ - stx source, [base + offset + 0x28]; \ - stx source, [base + offset + 0x30]; \ - stx source, [base + offset + 0x38]; + stxa source, [base + offset + 0x00] %asi; \ + stxa source, [base + offset + 0x08] %asi; \ + stxa source, [base + offset + 0x10] %asi; \ + stxa source, [base + offset + 0x18] %asi; \ + stxa source, [base + offset + 0x20] %asi; \ + stxa source, [base + offset + 0x28] %asi; \ + stxa source, [base + offset + 0x30] %asi; \ + stxa source, [base + offset + 0x38] %asi; #define ZERO_LAST_BLOCKS(base, offset, source) \ - stx source, [base - offset - 0x38]; \ - stx source, [base - offset - 0x30]; \ - stx source, [base - offset - 0x28]; \ - stx source, [base - offset - 0x20]; \ - stx source, [base - offset - 0x18]; \ - stx source, [base - offset - 0x10]; \ - stx source, [base - offset - 0x08]; \ - stx source, [base - offset - 0x00]; + stxa source, [base - offset - 0x38] %asi; \ + stxa source, [base - offset - 0x30] %asi; \ + stxa source, [base - offset - 0x28] %asi; \ + stxa source, [base - offset - 0x20] %asi; \ + stxa source, [base - offset - 0x18] %asi; \ + stxa source, [base - offset - 0x10] %asi; \ + stxa source, [base - offset - 0x08] %asi; \ + stxa source, [base - offset - 0x00] %asi; .text .align 4 - .globl __bzero, __memset + .globl __bzero, __memset, __bzero_noasi .globl memset, __memset_start, __memset_end __memset_start: __memset: @@ -65,10 +66,13 @@ sll %g3, 16, %g2 or %g3, %g2, %g3 mov %o2, %o1 + wr %g0, ASI_P, %asi sllx %g3, 32, %g2 ba,pt %xcc, 1f or %g3, %g2, %g3 __bzero: + wr %g0, ASI_P, %asi +__bzero_noasi: mov %g0, %g3 1: cmp %o1, 7 @@ -80,13 +84,13 @@ cmp %o2, 3 be,pn %icc, 2f - EX(stb %g3, [%o0], sub %o1, 0,#) + EX(stba %g3, [%o0] %asi, sub %o1, 0,#) cmp %o2, 2 be,pt %icc, 2f - EX(stb %g3, [%o0 + 0x01], sub %o1, 1,#) + EX(stba %g3, [%o0 + 0x01] %asi, sub %o1, 1,#) - EX(stb %g3, [%o0 + 0x02], sub %o1, 2,#) + EX(stba %g3, [%o0 + 0x02] %asi, sub %o1, 2,#) 2: sub %o2, 4, %o2 sub %o0, %o2, %o0 @@ -96,7 +100,7 @@ be,a,pt %icc, 2f andncc %o1, 0x7f, %o3 - EX(st %g3, [%o0], sub %o1, 0,#) + EX(sta %g3, [%o0] %asi, sub %o1, 0,#) sub %o1, 4, %o1 add %o0, 4, %o0 andncc %o1, 0x7f, %o3 ! Now everything is 8 aligned and o1 is len to run @@ -132,17 +136,17 @@ be,pn %icc, 1f andcc %o1, 2, %g0 - EX(st %g3, [%o0], and %o1, 7,#) + EX(sta %g3, [%o0] %asi, and %o1, 7,#) add %o0, 4, %o0 1: be,pn %icc, 1f andcc %o1, 1, %g0 - EX(sth %g3, [%o0], and %o1, 3,#) + EX(stha %g3, [%o0] %asi, and %o1, 3,#) add %o0, 2, %o0 1: bne,a,pn %icc, 8f - EX(stb %g3, [%o0], and %o1, 1,#) + EX(stba %g3, [%o0] %asi, and %o1, 1,#) 8: retl clr %o0 @@ -155,7 +159,7 @@ add %o0, 1, %o0 subcc %o1, 1, %o1 bne,a,pt %icc, 8b - EX(stb %g3, [%o0 - 1], add %o1, 1,#) + EX(stba %g3, [%o0 - 1] %asi, add %o1, 1,#) 0: retl clr %o0 diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c --- v2.1.33/linux/arch/sparc64/mm/init.c Thu Mar 27 14:40:01 1997 +++ linux/arch/sparc64/mm/init.c Mon Apr 14 09:31:09 1997 @@ -1,7 +1,7 @@ -/* $Id: init.c,v 1.4 1997/03/18 17:59:48 jj Exp $ +/* $Id: init.c,v 1.22 1997/04/12 04:28:48 davem Exp $ * arch/sparc64/mm/init.c * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ @@ -13,12 +13,25 @@ #include #include #include +#include +#include +#include +#include +#include extern void show_net_buffers(void); extern unsigned long device_scan(unsigned long); struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS]; +/* Ugly, but necessary... -DaveM */ +unsigned long phys_base, null_pmd_table, null_pte_table; + +extern unsigned long empty_null_pmd_table; +extern unsigned long empty_null_pte_table; + +unsigned long tlb_context_cache = CTX_FIRST_VERSION; + /* * BAD_PAGE is the page that is used for page faults when linux * is out-of-memory. Older versions of linux just did a @@ -32,16 +45,25 @@ * ZERO_PAGE is a special page that is used for zero-initialized * data and COW. */ -pmd_t *__bad_pagetable(void) +pmd_t *__bad_pmd(void) +{ + pmd_t *pmdp = (pmd_t *) &empty_bad_pmd_table; + + __init_pmd(pmdp); + return pmdp; +} + +pte_t *__bad_pte(void) { - memset((void *) EMPTY_PGT, 0, PAGE_SIZE); - return (pmd_t *) EMPTY_PGT; + memset((void *) &empty_bad_pte_table, 0, PAGE_SIZE); + return (pte_t *) (((unsigned long)&empty_bad_pte_table) + phys_base); } pte_t __bad_page(void) { - memset((void *) EMPTY_PGE, 0, PAGE_SIZE); - return pte_mkdirty(mk_pte((unsigned long) EMPTY_PGE, PAGE_SHARED)); + memset((void *) &empty_bad_page, 0, PAGE_SIZE); + return pte_mkdirty(mk_pte((((unsigned long) &empty_bad_page)+phys_base), + PAGE_SHARED)); } void show_mem(void) @@ -57,10 +79,10 @@ total++; if (PageReserved(mem_map + i)) reserved++; - else if (!mem_map[i].count) + else if (!atomic_read(&mem_map[i].count)) free++; else - shared += mem_map[i].count-1; + shared += atomic_read(&mem_map[i].count) - 1; } printk("%d pages of RAM\n",total); printk("%d free pages\n",free); @@ -72,33 +94,520 @@ #endif } -__initfunc(unsigned long sparc_context_init(unsigned long start_mem, int numctx)) +/* IOMMU support, the ideas are right, the code should be cleaned a bit still... */ + +/* XXX Also, play with the streaming buffers at some point, both + * XXX Fusion and Sunfire both have them aparently... -DaveM + */ + +/* This keeps track of pages used in sparc_alloc_dvma() invocations. */ +static unsigned long dvma_map_pages[0x10000000 >> 16] = { 0, }; +static unsigned long dvma_pages_current_offset = 0; +static int dvma_pages_current_index = 0; + +__initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start, + unsigned long memory_end, struct linux_sbus *sbus)) +{ + struct iommu_struct *iommu; + struct sysio_regs *sregs; + struct linux_prom_registers rprop[2]; + unsigned long impl, vers; + unsigned long control, tsbbase; + unsigned long *iopte; + int err, i; + + err = prom_getproperty(iommu_node, "reg", (char *)rprop, + sizeof(rprop)); + if(err == -1) { + prom_printf("iommu_init: Cannot map SYSIO control registers.\n"); + prom_halt(); + } + sregs = (struct sysio_regs *) sparc_alloc_io(rprop[0].phys_addr, + (void *)0, + sizeof(struct sysio_regs), + "SYSIO Regs", + rprop[0].which_io, 0x0); + + memory_start = (memory_start + 7) & ~7; + iommu = (struct iommu_struct *) memory_start; + memory_start += sizeof(struct iommu_struct); + iommu->sysio_regs = sregs; + sbus->iommu = iommu; + + control = sregs->iommu_control; + impl = (control & IOMMU_CTRL_IMPL) >> 60; + vers = (control & IOMMU_CTRL_VERS) >> 56; + printk("IOMMU: IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n", + (unsigned int) impl, (unsigned int)vers, (unsigned long) sregs); + + control &= ~(IOMMU_CTRL_TSBSZ); + control |= (IOMMU_TSBSZ_64K | IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB); + + /* Use only 64k pages, things are layed out in the 32-bit SBUS + * address space like this: + * + * 0x00000000 ---------------------------------------- + * | Direct physical mappings for most | + * | DVMA to paddr's within this range | + * 0xf0000000 ---------------------------------------- + * | For mappings requested via | + * | sparc_alloc_dvma() | + * 0xffffffff ---------------------------------------- + */ + tsbbase = PAGE_ALIGN(memory_start); + memory_start = (tsbbase + ((64 * 1024) * 8)); + iommu->page_table = (iopte_t *) tsbbase; + iopte = (unsigned long *) tsbbase; + + /* Setup aliased mappings... */ + for(i = 0; i < (65536 - 4096); i++) { + *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE); + *iopte |= (i << 16); + iopte++; + } + + /* Clear all sparc_alloc_dvma() maps. */ + for( ; i < 65536; i++) + *iopte++ = 0; + + sregs->iommu_tsbbase = __pa(tsbbase); + sregs->iommu_control = control; + + return memory_start; +} + +void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr) +{ + struct iommu_struct *iommu = SBus_chain->iommu; /* GROSS ME OUT! */ + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* Find out if we need to grab some pages. */ + if(!dvma_map_pages[dvma_pages_current_index] || + ((dvma_pages_current_offset + len) > (1 << 16))) { + unsigned long *iopte; + unsigned long newpages = __get_free_pages(GFP_KERNEL, 3, 0); + int i; + + if(!newpages) + panic("AIEEE cannot get DVMA pages."); + + memset((char *)newpages, 0, (1 << 16)); + + if(!dvma_map_pages[dvma_pages_current_index]) { + dvma_map_pages[dvma_pages_current_index] = newpages; + i = dvma_pages_current_index; + } else { + dvma_map_pages[dvma_pages_current_index + 1] = newpages; + i = dvma_pages_current_index + 1; + } + + /* Stick it in the IOMMU. */ + i = (65536 - 4096) + i; + iopte = (unsigned long *)(iommu->page_table + i); + *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE); + *iopte |= __pa(newpages); + } + + /* Get this out of the way. */ + *dvma_addr = (__u32) ((0xf0000000) + + (dvma_pages_current_index << 16) + + (dvma_pages_current_offset)); + + while(len > 0) { + while((len > 0) && (dvma_pages_current_offset < (1 << 16))) { + pte_t pte; + unsigned long the_page = + dvma_map_pages[dvma_pages_current_index] + + dvma_pages_current_offset; + + /* Map the CPU's view. */ + pgdp = pgd_offset(init_task.mm, addr); + pmdp = pmd_alloc_kernel(pgdp, addr); + ptep = pte_alloc_kernel(pmdp, addr); + pte = mk_pte(the_page, PAGE_KERNEL); + set_pte(ptep, pte); + + dvma_pages_current_offset += PAGE_SIZE; + addr += PAGE_SIZE; + len -= PAGE_SIZE; + } + dvma_pages_current_index++; + dvma_pages_current_offset = 0; + } +} + +__u32 mmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus) +{ + __u32 sbus_addr = (__u32) __pa(vaddr); + + if((sbus_addr < 0xf0000000) && + ((sbus_addr + len) < 0xf0000000)) + return sbus_addr; + + /* "can't happen"... GFP_DMA assures this. */ + panic("Very high scsi_one mappings should never happen."); + return (__u32)0; +} + +void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) +{ + while(sz >= 0) { + __u32 page = (__u32) __pa(((unsigned long) sg[sz].addr)); + if((page < 0xf0000000) && + (page + sg[sz].len) < 0xf0000000) { + sg[sz].dvma_addr = page; + } else { + /* "can't happen"... GFP_DMA assures this. */ + panic("scsi_sgl high mappings should never happen."); + } + sz--; + } +} + +char *mmu_info(void) +{ + return "MMU Type: Spitfire\n\tFIXME: Write this\n"; +} + +static unsigned long mempool; + +struct linux_prom_translation { + unsigned long virt; + unsigned long size; + unsigned long data; +}; + +#define MAX_TRANSLATIONS 64 +static void inherit_prom_mappings(void) { - int ctx; + struct linux_prom_translation transl[MAX_TRANSLATIONS]; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + int node, n, i; + + node = prom_finddevice("/virtual-memory"); + if ((n = prom_getproperty(node, "translations", (char *) transl, + sizeof(transl))) == -1) { + prom_printf("Couldn't get translation property\n"); + prom_halt(); + } + n = n / sizeof(transl[0]); - ctx_list_pool = (struct ctx_list *) start_mem; - start_mem += (numctx * sizeof(struct ctx_list)); - /* Context 0 is reserved for PROM and uaccess stuff */ - for(ctx = 1; ctx < numctx; ctx++) { - struct ctx_list *clist; - - clist = (ctx_list_pool + ctx); - clist->ctx_number = ctx; - clist->ctx_mm = 0; - } - ctx_free.next = ctx_free.prev = &ctx_free; - ctx_used.next = ctx_used.prev = &ctx_used; - for(ctx = 1; ctx < numctx; ctx++) - add_to_free_ctxlist(ctx_list_pool + ctx); - return start_mem; + for (i = 0; i < n; i++) { + unsigned long vaddr; + + if (transl[i].virt >= 0xf0000000 && transl[i].virt < 0x100000000) { + for (vaddr = transl[i].virt; + vaddr < transl[i].virt + transl[i].size; + vaddr += PAGE_SIZE) { + pgdp = pgd_offset(init_task.mm, vaddr); + if (pgd_none(*pgdp)) { + pmdp = sparc_init_alloc(&mempool, + PMD_TABLE_SIZE); + __init_pmd(pmdp); + pgd_set(pgdp, pmdp); + } + pmdp = pmd_offset(pgdp, vaddr); + if (pmd_none(*pmdp)) { + ptep = sparc_init_alloc(&mempool, + PTE_TABLE_SIZE); + pmd_set(pmdp, ptep); + } + ptep = pte_offset(pmdp, vaddr); + set_pte (ptep, __pte(transl[i].data | _PAGE_MODIFIED)); + transl[i].data += PAGE_SIZE; + } + } + } +} + +static void inherit_locked_prom_mappings(void) +{ + int i; + int dtlb_seen = 0; + int itlb_seen = 0; + + /* Fucking losing PROM has more mappings in the TLB, but + * it (conveniently) fails to mention any of these in the + * translations property. The only ones that matter are + * the locked PROM tlb entries, so we impose the following + * irrecovable rule on the PROM, it is allowed 1 locked + * entry in the ITLB and 1 in the DTLB. We move those + * (if necessary) up into tlb entry 62. + * + * Supposedly the upper 16GB of the address space is + * reserved for OBP, BUT I WISH THIS WAS DOCUMENTED + * SOMEWHERE!!!!!!!!!!!!!!!!! Furthermore the entire interface + * used between the client program and the firmware on sun5 + * systems to coordinate mmu mappings is also COMPLETELY + * UNDOCUMENTED!!!!!! Thanks S(t)un! + */ + for(i = 0; i < 62; i++) { + unsigned long data; + + data = spitfire_get_dtlb_data(i); + if(!dtlb_seen && (data & _PAGE_L)) { + unsigned long tag = spitfire_get_dtlb_tag(i); + __asm__ __volatile__("stxa %%g0, [%0] %1" + : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); + membar("#Sync"); + spitfire_put_dtlb_data(i, 0x0UL); + membar("#Sync"); + + /* Re-install it. */ + __asm__ __volatile__("stxa %0, [%1] %2" + : : "r" (tag), "r" (TLB_TAG_ACCESS), + "i" (ASI_DMMU)); + membar("#Sync"); + spitfire_put_dtlb_data(62, data); + membar("#Sync"); + dtlb_seen = 1; + if(itlb_seen) + break; + } + data = spitfire_get_itlb_data(i); + if(!itlb_seen && (data & _PAGE_L)) { + unsigned long tag = spitfire_get_itlb_tag(i); + __asm__ __volatile__("stxa %%g0, [%0] %1" + : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); + membar("#Sync"); + spitfire_put_itlb_data(i, 0x0UL); + membar("#Sync"); + + /* Re-install it. */ + __asm__ __volatile__("stxa %0, [%1] %2" + : : "r" (tag), "r" (TLB_TAG_ACCESS), + "i" (ASI_IMMU)); + membar("#Sync"); + spitfire_put_itlb_data(62, data); + membar("#Sync"); + itlb_seen = 1; + if(dtlb_seen) + break; + } + } +} + +__initfunc(static void +allocate_ptable_skeleton(unsigned long start, unsigned long end)) +{ + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + while (start < end) { + pgdp = pgd_offset(init_task.mm, start); + if (pgd_none(*pgdp)) { + pmdp = sparc_init_alloc(&mempool, + PMD_TABLE_SIZE); + __init_pmd(pmdp); + pgd_set(pgdp, pmdp); + } + pmdp = pmd_offset(pgdp, start); + if (pmd_none(*pmdp)) { + ptep = sparc_init_alloc(&mempool, + PTE_TABLE_SIZE); + pmd_set(pmdp, ptep); + } + start = (start + PMD_SIZE) & PMD_MASK; + } +} + +/* + * Create a mapping for an I/O register. Have to make sure the side-effect + * bit is set. + */ + +void sparc_ultra_mapioaddr(unsigned long physaddr, unsigned long virt_addr, + int bus, int rdonly) +{ + pgd_t *pgdp = pgd_offset(init_task.mm, virt_addr); + pmd_t *pmdp = pmd_offset(pgdp, virt_addr); + pte_t *ptep = pte_offset(pmdp, virt_addr); + pte_t pte; + + physaddr &= PAGE_MASK; + + if(rdonly) + pte = mk_pte_phys(physaddr, __pgprot(pg_iobits)); + else + pte = mk_pte_phys(physaddr, __pgprot(pg_iobits | __DIRTY_BITS)); + +#if 0 + prom_printf("IOMAP: vaddr[%016lx]paddr[%016lx]ptep[%016lx]pte[%016lx])\n", + virt_addr, physaddr, (unsigned long) ptep, pte_val(pte)); + prom_printf("IOMAP: pgd[%016lx,%016lx]\n", + (unsigned long) pgdp, pgd_val(*pgdp)); + prom_printf("IOMAP: pmd[%016lx,%016lx]\n", + (unsigned long) pmdp, pmd_val(*pmdp)); +#endif + + set_pte(ptep, pte); +} + +void sparc_ultra_unmapioaddr(unsigned long virt_addr) +{ + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + pgdp = pgd_offset(init_task.mm, virt_addr); + pmdp = pmd_offset(pgdp, virt_addr); + ptep = pte_offset(pmdp, virt_addr); + + /* No need to flush uncacheable page. */ + pte_clear(ptep); +} + +void sparc_ultra_dump_itlb(void) +{ + int slot; + + prom_printf ("Contents of itlb:\n"); + for (slot = 0; slot < 64; slot+=2) { + prom_printf ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", + slot, spitfire_get_itlb_tag(slot), spitfire_get_itlb_data(slot), + slot+1, spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1)); + } +} + +void sparc_ultra_dump_dtlb(void) +{ + int slot; + + prom_printf ("Contents of dtlb:\n"); + for (slot = 0; slot < 64; slot+=2) { + prom_printf ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", + slot, spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot), + slot+1, spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1)); + } } /* paging_init() sets up the page tables */ +extern unsigned long free_area_init(unsigned long, unsigned long); + __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)) { - return device_scan (start_mem); + extern unsigned long __p1275_loc; + extern unsigned long phys_base; + extern void setup_tba(unsigned long kpgdir); + extern void __bfill64(void *, unsigned long); + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep, pte; + int i; + + /* Must create 2nd locked DTLB entry if physical ram starts at + * 4MB absolute or higher, kernel image has been placed in the + * right place at PAGE_OFFSET but references to start_mem and pages + * will be to the perfect alias mapping, so set it up now. + */ + if(phys_base >= (4 * 1024 * 1024)) { + unsigned long alias_base = phys_base + PAGE_OFFSET; + unsigned long pte; + unsigned long flags; + + /* We assume physical memory starts at some 4mb multiple, + * if this were not true we wouldn't boot up to this point + * anyways. + */ + pte = phys_base | _PAGE_VALID | _PAGE_SZ4MB; + pte |= _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W; + save_flags(flags); cli(); + __asm__ __volatile__(" + stxa %1, [%0] %3 + stxa %2, [%5] %4 + membar #Sync + flush %%g4 + nop + nop + nop" + : /* No outputs */ + : "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pte), + "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3) + : "memory"); + restore_flags(flags); + + /* Now set kernel pgd to upper alias so physical page computations + * work. + */ + init_mm.pgd += (phys_base / (sizeof(pgd_t *))); + } + + null_pmd_table = __pa(((unsigned long)&empty_null_pmd_table) + phys_base); + null_pte_table = __pa(((unsigned long)&empty_null_pte_table) + phys_base); + + pmdp = (pmd_t *) &empty_null_pmd_table; + for(i = 0; i < 1024; i++) + pmd_val(pmdp[i]) = null_pte_table; + + memset((void *) &empty_null_pte_table, 0, PAGE_SIZE); + + /* Now can init the kernel/bad page tables. */ + __bfill64((void *)swapper_pg_dir, null_pmd_table); + __bfill64((void *)&empty_bad_pmd_table, null_pte_table); + + /* We use mempool to create page tables, therefore adjust it up + * such that __pa() macros etc. work. + */ + mempool = PAGE_ALIGN(start_mem) + phys_base; + + /* FIXME: This should be done much nicer. + * Just now we allocate 64M for each. + */ + allocate_ptable_skeleton(IOBASE_VADDR, IOBASE_VADDR + 0x4000000); + allocate_ptable_skeleton(DVMA_VADDR, DVMA_VADDR + 0x4000000); + inherit_prom_mappings(); + allocate_ptable_skeleton(0, 0x8000 + PAGE_SIZE); + + /* Map prom interface page. */ + pgdp = pgd_offset(init_task.mm, 0x8000); + pmdp = pmd_offset(pgdp, 0x8000); + ptep = pte_offset(pmdp, 0x8000); + pte = mk_pte(((unsigned long)&__p1275_loc)+phys_base, PAGE_KERNEL); + set_pte(ptep, pte); + + /* Ok, we can use our TLB miss and window trap handlers safely. */ + setup_tba((unsigned long)init_mm.pgd); + + /* Kill locked PROM interface page mapping, the mapping will + * re-enter on the next PROM interface call via our TLB miss + * handlers. + */ + spitfire_flush_dtlb_primary_page(0x8000); + membar("#Sync"); + spitfire_flush_itlb_primary_page(0x8000); + membar("#Sync"); + + /* Really paranoid. */ + flushi(PAGE_OFFSET); + membar("#Sync"); + + /* Cleanup the extra locked TLB entry we created since we have the + * nice TLB miss handlers of ours installed now. + */ + if(phys_base >= (4 * 1024 * 1024)) { + /* We only created DTLB mapping of this stuff. */ + spitfire_flush_dtlb_nucleus_page(phys_base + PAGE_OFFSET); + membar("#Sync"); + + /* Paranoid */ + flushi(PAGE_OFFSET); + membar("#Sync"); + } + + inherit_locked_prom_mappings(); + + flush_tlb_all(); + + start_mem = free_area_init(PAGE_ALIGN(mempool), end_mem); + + return device_scan (PAGE_ALIGN (start_mem)); } extern int min_free_pages; @@ -110,10 +619,10 @@ unsigned long addr, tmp2 = 0; for(addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) { - if(addr >= KERNBASE && addr < start_mem) + if(addr >= PAGE_OFFSET && addr < start_mem) addr = start_mem; for(tmp2=0; sp_banks[tmp2].num_bytes != 0; tmp2++) { - unsigned long phys_addr = (addr - PAGE_OFFSET); + unsigned long phys_addr = __pa(addr); unsigned long base = sp_banks[tmp2].base_addr; unsigned long limit = base + sp_banks[tmp2].num_bytes; @@ -129,19 +638,17 @@ int codepages = 0; int datapages = 0; unsigned long tmp2, addr; + unsigned long data_end; extern char etext; - /* Saves us work later. */ - memset((void *) ZERO_PAGE, 0, PAGE_SIZE); - end_mem &= PAGE_MASK; max_mapnr = MAP_NR(end_mem); high_memory = (void *) end_mem; start_mem = PAGE_ALIGN(start_mem); - num_physpages = (start_mem - KERNBASE) >> PAGE_SHIFT; + num_physpages = (start_mem - phys_base - PAGE_OFFSET) >> PAGE_SHIFT; - addr = KERNBASE; + addr = PAGE_OFFSET; while(addr < start_mem) { #ifdef CONFIG_BLK_DEV_INITRD if (initrd_below_start_ok && addr >= initrd_start && addr < initrd_end) @@ -153,15 +660,16 @@ } taint_real_pages(start_mem, end_mem); + data_end = start_mem - phys_base; for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) { if(PageReserved(mem_map + MAP_NR(addr))) { - if ((addr < (unsigned long) &etext) && (addr >= KERNBASE)) + if ((addr < (unsigned long) &etext) && (addr >= PAGE_OFFSET)) codepages++; - else if((addr < start_mem) && (addr >= KERNBASE)) + else if((addr < data_end) && (addr >= PAGE_OFFSET)) datapages++; continue; } - mem_map[MAP_NR(addr)].count = 1; + atomic_set(&mem_map[MAP_NR(addr)].count, 1); num_physpages++; #ifdef CONFIG_BLK_DEV_INITRD if (!initrd_start || @@ -172,7 +680,7 @@ tmp2 = nr_free_pages << PAGE_SHIFT; - printk("Memory: %luk available (%dk kernel code, %dk data) [%08lx,%08lx]\n", + printk("Memory: %luk available (%dk kernel code, %dk data) [%016lx,%016lx]\n", tmp2 >> 10, codepages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10), PAGE_OFFSET, end_mem); @@ -182,6 +690,11 @@ min_free_pages = 16; free_pages_low = min_free_pages + (min_free_pages >> 1); free_pages_high = min_free_pages + min_free_pages; + +#if 0 + printk("Done in mem_init() halting\n"); + prom_cmdline(); +#endif } void free_initmem (void) @@ -192,7 +705,7 @@ addr = (unsigned long)(&__init_begin); for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); - mem_map[MAP_NR(addr)].count = 1; + atomic_set(&mem_map[MAP_NR(addr)].count, 1); free_page(addr); } printk ("Freeing unused kernel memory: %dk freed\n", (unsigned)((&__init_end - &__init_begin) >> 10)); @@ -211,9 +724,9 @@ if (PageReserved(mem_map + i)) continue; val->totalram++; - if (!mem_map[i].count) + if (!atomic_read(&mem_map[i].count)) continue; - val->sharedram += mem_map[i].count-1; + val->sharedram += atomic_read(&mem_map[i].count) - 1; } val->totalram <<= PAGE_SHIFT; val->sharedram <<= PAGE_SHIFT; diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/prom/init.c linux/arch/sparc64/prom/init.c --- v2.1.33/linux/arch/sparc64/prom/init.c Thu Mar 27 14:40:01 1997 +++ linux/arch/sparc64/prom/init.c Fri Apr 11 10:47:36 1997 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.6 1997/03/11 17:37:11 jj Exp $ +/* $Id: init.c,v 1.7 1997/03/24 17:43:59 jj Exp $ * init.c: Initialize internal variables used by the PROM * library functions. * @@ -69,14 +69,11 @@ ((buffer[6] - '0') << 8) | (buffer[8] - '0'); - prom_printf ("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + 4); + printk ("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + 4); prom_meminit(); prom_ranges_init(); - - printk("PROMLIB: Sun IEEE Boot Prom %s\n", - buffer + 4); /* Initialization successful. */ } diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/prom/misc.c linux/arch/sparc64/prom/misc.c --- v2.1.33/linux/arch/sparc64/prom/misc.c Mon Mar 17 14:54:24 1997 +++ linux/arch/sparc64/prom/misc.c Fri Apr 11 10:47:36 1997 @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.4 1997/03/04 16:27:11 jj Exp $ +/* $Id: misc.c,v 1.6 1997/04/10 05:13:05 davem Exp $ * misc.c: Miscellaneous prom functions that don't belong * anywhere else. * @@ -40,6 +40,7 @@ /* Drop into the prom, with the chance to continue with the 'go' * prom command. */ +/* XXX Fix the pre and post calls as it locks up my Ultra at the moment -DaveM */ void prom_cmdline(void) { @@ -48,20 +49,24 @@ extern void install_linux_ticker(void); unsigned long flags; - kernel_enter_debugger(); + /* kernel_enter_debugger(); */ #ifdef CONFIG_SUN_CONSOLE +#if 0 if(!serial_console) console_restore_palette (); #endif - install_obp_ticker(); +#endif + /* install_obp_ticker(); */ save_flags(flags); cli(); p1275_cmd ("enter", P1275_INOUT(0,0)); restore_flags(flags); - install_linux_ticker(); + /* install_linux_ticker(); */ #ifdef CONFIG_SUN_CONSOLE +#if 0 if(!serial_console) set_palette (); #endif +#endif } /* Drop into the prom, but completely terminate the program. @@ -70,7 +75,9 @@ void prom_halt(void) { +again: p1275_cmd ("exit", P1275_INOUT(0,0)); + goto again; /* PROM is out to get me -DaveM */ } /* Set prom sync handler to call function 'funcp'. */ @@ -118,4 +125,10 @@ prom_getprev(void) { return prom_prev; +} + +/* Install Linux trap table so PROM uses that instead of it's own. */ +void prom_set_trap_table(unsigned long tba) +{ + p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba); } diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/prom/p1275.c linux/arch/sparc64/prom/p1275.c --- v2.1.33/linux/arch/sparc64/prom/p1275.c Thu Mar 27 14:40:01 1997 +++ linux/arch/sparc64/prom/p1275.c Fri Apr 11 10:47:36 1997 @@ -1,4 +1,4 @@ -/* $Id: p1275.c,v 1.7 1997/03/18 17:59:55 jj Exp $ +/* $Id: p1275.c,v 1.8 1997/04/03 09:29:21 davem Exp $ * p1275.c: Sun IEEE 1275 PROM low level interface routines * * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -10,8 +10,8 @@ #include #include -#include #include +#include #include /* If you change layout of this structure, please change the prom_doit diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/prom/ranges.c linux/arch/sparc64/prom/ranges.c --- v2.1.33/linux/arch/sparc64/prom/ranges.c Thu Mar 27 14:40:01 1997 +++ linux/arch/sparc64/prom/ranges.c Fri Apr 11 10:47:36 1997 @@ -1,4 +1,4 @@ -/* $Id: ranges.c,v 1.2 1997/03/18 17:59:57 jj Exp $ +/* $Id: ranges.c,v 1.3 1997/03/21 12:33:36 jj Exp $ * ranges.c: Handle ranges in newer proms for obio/sbus. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -66,7 +66,7 @@ { } -__initfunc(void prom_sbus_ranges_init(struct linux_sbus *sbus)) +__initfunc(void prom_sbus_ranges_init(int iommund, struct linux_sbus *sbus)) { int success; diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/prom/tree.c linux/arch/sparc64/prom/tree.c --- v2.1.33/linux/arch/sparc64/prom/tree.c Mon Mar 17 14:54:24 1997 +++ linux/arch/sparc64/prom/tree.c Fri Apr 11 10:47:36 1997 @@ -1,4 +1,4 @@ -/* $Id: tree.c,v 1.4 1997/03/04 16:27:14 jj Exp $ +/* $Id: tree.c,v 1.5 1997/03/24 17:44:01 jj Exp $ * tree.c: Basic device tree traversal/scanning for the Linux * prom library. * @@ -18,12 +18,18 @@ * direct descendent. */ __inline__ int +__prom_getchild(int node) +{ + return p1275_cmd ("child", P1275_INOUT(1, 1), node); +} + +__inline__ int prom_getchild(int node) { long cnode; if(node == -1) return 0; - cnode = p1275_cmd ("child", P1275_INOUT(1, 1), node); + cnode = __prom_getchild(node); if(cnode == -1) return 0; return (int)cnode; } @@ -43,12 +49,18 @@ * at this level of depth in the tree. */ __inline__ int +__prom_getsibling(int node) +{ + return p1275_cmd ("peer", P1275_INOUT(1, 1), node); +} + +__inline__ int prom_getsibling(int node) { long sibnode; if(node == -1) return 0; - sibnode = p1275_cmd ("peer", P1275_INOUT(1, 1), node); + sibnode = __prom_getsibling(node); if(sibnode == -1) return 0; return (int)sibnode; } diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/vmlinux.lds linux/arch/sparc64/vmlinux.lds --- v2.1.33/linux/arch/sparc64/vmlinux.lds Thu Mar 27 14:40:02 1997 +++ linux/arch/sparc64/vmlinux.lds Fri Apr 11 10:47:36 1997 @@ -1,12 +1,12 @@ /* ld script to make UltraLinux kernel */ OUTPUT_FORMAT("elf64-sparc", "elf64-sparc", "elf64-sparc") -OUTPUT_ARCH(sparc:v9) +OUTPUT_ARCH(sparc:v9a) ENTRY(_start) SECTIONS { empty_zero_page = 0xfffff80000000000; - empty_bad_page = 0xfffff80000002000; + swapper_pg_dir = 0xfffff80000002000; . = 0x4000; .text 0xfffff80000004000 : { @@ -53,7 +53,15 @@ *(.bss) *(COMMON) . = ALIGN(8192); - empty_bad_page_table = .; + empty_bad_pmd_table = .; + . += 8192; + empty_bad_pte_table = .; + . += 8192; + empty_null_pmd_table = .; + . += 8192; + empty_null_pte_table = .; + . += 8192; + empty_bad_page = .; . += 8192; } _end = . ; diff -u --recursive --new-file v2.1.33/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.1.33/linux/drivers/block/floppy.c Fri Apr 4 08:52:17 1997 +++ linux/drivers/block/floppy.c Mon Apr 14 10:49:11 1997 @@ -1676,7 +1676,7 @@ } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2); } if (handler) { - if(intr_count >= 2) + if (in_interrupt()) schedule_bh( (void *)(void *) handler); else handler(); diff -u --recursive --new-file v2.1.33/linux/drivers/cdrom/Makefile linux/drivers/cdrom/Makefile --- v2.1.33/linux/drivers/cdrom/Makefile Wed Dec 18 05:57:28 1996 +++ linux/drivers/cdrom/Makefile Mon Apr 14 09:26:35 1997 @@ -153,10 +153,10 @@ endif #CONFIG_BLK_DEV_IDECD ifdef USE_GENERIC_CD -L_OBJS += cdrom.o +LX_OBJS += cdrom.o else ifdef USE_MODULAR_GENERIC_CD - M_OBJS += cdrom.o + MX_OBJS += cdrom.o endif endif #The Makefile configuration for the generic cdrom interface diff -u --recursive --new-file v2.1.33/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.1.33/linux/drivers/cdrom/cdrom.c Fri Apr 4 08:52:18 1997 +++ linux/drivers/cdrom/cdrom.c Mon Apr 14 09:38:37 1997 @@ -1,9 +1,9 @@ /* cdrom.c. Common ioctl and open routines for various Linux cdrom drivers. -*- linux-c -*- - Copyright (c) 1996 David van Leeuwen. + Copyright (c) 1996, 1997 David A. van Leeuwen. The routines in the file should provide an interface between software accessing cdroms and the various drivers that implement - specific hardware devices. + specific hardware devices. */ @@ -21,9 +21,29 @@ #include #include +/* define CHECKTYPE if you want to check for audio/data cdrom. You + must use cd player programs that respect the O_NONBLOCK option for + opening the cdrom-device for ioctl-commanding only. (See + Documentation/cdrom/cdrom-standard.tex). Patches for a number of cd + players (CDplayer-2.0, cd-console-1.1, workbone-2.3, cdtool-1.0, + cdp-0.33, cdplayer-0.4, cdthing-1.4, lyn0.8a, playcd-1.0) can be + found in directory + + ftp://ftp.gwdg.de/pub/linux/cdrom/drivers/cm206/ + + A runtime configuration program "checktype.c" to allow for cdrom + medium type checking can be found at the same location. + + In order to be able to get neat system errors like "No medium + found" or "Wrong medium type" upon attempting to mount/play an + empty slot, mount an audio disc or play a data disc, you need to + have a new libc.5.so. */ +#undef CHECKTYPE + #define FM_WRITE 0x2 /* file mode write bit */ -#define VERSION "Generic CD-ROM driver, v 1.21 1996/11/08 03:24:49" +#define VERSION "$Id: cdrom.c,v 1.7 1997/02/27 22:14:26 david Exp $" +#define REVISION "$Revision: 1.7 $" /* Not-exported routines. */ static int cdrom_open(struct inode *ip, struct file *fp); @@ -34,19 +54,19 @@ struct file_operations cdrom_fops = { - NULL, /* lseek */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir */ - NULL, /* poll */ - cdrom_ioctl, /* ioctl */ - NULL, /* mmap */ - cdrom_open, /* open */ - cdrom_release, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ - cdrom_media_changed, /* media_change */ - NULL /* revalidate */ + NULL, /* lseek */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir */ + NULL, /* poll */ + cdrom_ioctl, /* ioctl */ + NULL, /* mmap */ + cdrom_open, /* open */ + cdrom_release, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + cdrom_media_changed, /* media_change */ + NULL /* revalidate */ }; static struct cdrom_device_info *cdromdevs[MAX_BLKDEV] = { @@ -62,68 +82,71 @@ #define ENSURE(call, bits) if (cdo->call == NULL) *change_capability &= ~(bits) /* We don't use $name$ yet, but it could be used for the /proc - * filesystem in the future, or for other purposes. + * filesystem in the future, or for other purposes. */ int register_cdrom(struct cdrom_device_info *cdi, char *name) { - int major = MAJOR (cdi->dev); - struct cdrom_device_ops *cdo = cdi->ops; - int *change_capability = (int *)&cdo->capability; /* hack */ - - if (major < 0 || major >= MAX_BLKDEV) - return -1; - if (cdo->open == NULL || cdo->release == NULL) - return -2; - ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY); - ENSURE(lock_door, CDC_LOCK); - ENSURE(select_speed, CDC_SELECT_SPEED); - ENSURE(select_disc, CDC_SELECT_DISC); - ENSURE(get_last_session, CDC_MULTI_SESSION); - ENSURE(audio_ioctl, CDC_PLAY_AUDIO); - ENSURE(media_changed, CDC_MEDIA_CHANGED); - if (cdromdevs[major]==NULL) cdo->n_minors = 0; - else cdo->n_minors++; - cdi->next = cdromdevs[major]; - cdromdevs[major] = cdi; - cdi->options = CDO_AUTO_CLOSE | CDO_USE_FFLAGS | CDO_LOCK; - cdi->mc_flags = 0; - return 0; + int major = MAJOR (cdi->dev); + struct cdrom_device_ops *cdo = cdi->ops; + int *change_capability = (int *)&cdo->capability; /* hack */ + + if (major < 0 || major >= MAX_BLKDEV) + return -1; + if (cdo->open == NULL || cdo->release == NULL) + return -2; + ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY); + ENSURE(lock_door, CDC_LOCK); + ENSURE(select_speed, CDC_SELECT_SPEED); + ENSURE(select_disc, CDC_SELECT_DISC); + ENSURE(get_last_session, CDC_MULTI_SESSION); + ENSURE(audio_ioctl, CDC_PLAY_AUDIO); + ENSURE(media_changed, CDC_MEDIA_CHANGED); + if (cdromdevs[major]==NULL) cdo->n_minors = 0; + else cdo->n_minors++; + cdi->next = cdromdevs[major]; + cdromdevs[major] = cdi; + cdi->options = CDO_AUTO_CLOSE | CDO_USE_FFLAGS | CDO_LOCK; +#ifdef CHECKTYPE + cdi->options |= CDO_CHECK_TYPE; +#endif + cdi->mc_flags = 0; + return 0; } #undef ENSURE int unregister_cdrom(struct cdrom_device_info *unreg) { - struct cdrom_device_info *cdi, *prev; - int major = MAJOR (unreg->dev); + struct cdrom_device_info *cdi, *prev; + int major = MAJOR (unreg->dev); - if (major < 0 || major >= MAX_BLKDEV) - return -1; + if (major < 0 || major >= MAX_BLKDEV) + return -1; - prev = NULL; - cdi = cdromdevs[major]; - while (cdi != NULL && cdi->dev != unreg->dev) { - prev = cdi; - cdi = cdi->next; - } - - if (cdi == NULL) - return -2; - if (prev) - prev->next = cdi->next; - else - cdromdevs[major] = cdi->next; - cdi->ops->n_minors--; - return 0; + prev = NULL; + cdi = cdromdevs[major]; + while (cdi != NULL && cdi->dev != unreg->dev) { + prev = cdi; + cdi = cdi->next; + } + + if (cdi == NULL) + return -2; + if (prev) + prev->next = cdi->next; + else + cdromdevs[major] = cdi->next; + cdi->ops->n_minors--; + return 0; } static struct cdrom_device_info *cdrom_find_device (kdev_t dev) { - struct cdrom_device_info *cdi = cdromdevs[MAJOR (dev)]; + struct cdrom_device_info *cdi = cdromdevs[MAJOR (dev)]; - while (cdi != NULL && cdi->dev != dev) - cdi = cdi->next; - return cdi; + while (cdi != NULL && cdi->dev != dev) + cdi = cdi->next; + return cdi; } /* We use the open-option O_NONBLOCK to indicate that the @@ -141,83 +164,88 @@ int cdrom_open(struct inode *ip, struct file *fp) { kdev_t dev = ip->i_rdev; - struct cdrom_device_info *cdi = cdrom_find_device(dev); - int purpose = !!(fp->f_flags & O_NONBLOCK); - int ret=0; - - if (cdi == NULL) - return -ENODEV; - if (fp->f_mode & FM_WRITE) - return -EROFS; - purpose = purpose || !(cdi->options & CDO_USE_FFLAGS); - if (cdi->use_count || purpose) - ret = cdi->ops->open(cdi, purpose); - else - ret = open_for_data(cdi); - if (!ret) cdi->use_count++; - return ret; + struct cdrom_device_info *cdi = cdrom_find_device(dev); + int purpose = !!(fp->f_flags & O_NONBLOCK); + int ret=0; + + if (cdi == NULL) + return -ENODEV; + if (fp->f_mode & FM_WRITE) + return -EROFS; + purpose = purpose || !(cdi->options & CDO_USE_FFLAGS); + if (cdi->use_count || purpose) + ret = cdi->ops->open(cdi, purpose); + else + ret = open_for_data(cdi); + if (!ret) cdi->use_count++; + return ret; } static int open_for_data(struct cdrom_device_info * cdi) { - int ret; - struct cdrom_device_ops *cdo = cdi->ops; - if (cdo->drive_status != NULL) { - int ds = cdo->drive_status(cdi, CDSL_CURRENT); - if (ds == CDS_TRAY_OPEN) { - /* can/may i close it? */ - if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY && - cdi->options & CDO_AUTO_CLOSE) { - if (cdo->tray_move(cdi,0)) - return -EIO; - } else - return -ENXIO; /* can't close: too bad */ - ds = cdo->drive_status(cdi, CDSL_CURRENT); - if (ds == CDS_NO_DISC) - return -ENXIO; - } - } - if (cdo->disc_status != NULL) { - int ds = cdo->disc_status(cdi); - if (ds == CDS_NO_DISC) - return -ENXIO; - if (cdi->options & CDO_CHECK_TYPE && - ds != CDS_DATA_1) - return -ENODATA; - } - /* all is well, we can open the device */ - ret = cdo->open(cdi, 0); /* open for data */ - if (cdo->capability & ~cdi->mask & CDC_LOCK && - cdi->options & CDO_LOCK) - cdo->lock_door(cdi, 1); - return ret; + int ret; + struct cdrom_device_ops *cdo = cdi->ops; + if (cdo->drive_status != NULL) { + int ds = cdo->drive_status(cdi, CDSL_CURRENT); + if (ds == CDS_TRAY_OPEN) { + /* can/may i close it? */ + if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY && + cdi->options & CDO_AUTO_CLOSE) { + if (cdo->tray_move(cdi,0)) + return -EIO; + } else + return -ENOMEDIUM; /* can't close: too bad */ + ds = cdo->drive_status(cdi, CDSL_CURRENT); + if (ds == CDS_NO_DISC) + return -ENOMEDIUM; + } + } + if (cdo->disc_status != NULL) { + int ds = cdo->disc_status(cdi); + if (ds == CDS_NO_DISC) + return -ENOMEDIUM; + if (cdi->options & CDO_CHECK_TYPE && + ds != CDS_DATA_1) + return -EMEDIUMTYPE; + } + /* all is well, we can open the device */ + ret = cdo->open(cdi, 0); /* open for data */ + if (cdo->capability & ~cdi->mask & CDC_LOCK && + cdi->options & CDO_LOCK) + cdo->lock_door(cdi, 1); + return ret; } /* Admittedly, the logic below could be performed in a nicer way. */ static int cdrom_release(struct inode *ip, struct file *fp) { - kdev_t dev = ip->i_rdev; - struct cdrom_device_info *cdi = cdrom_find_device (dev); - struct cdrom_device_ops *cdo; - - if (cdi == NULL) - return 0; - cdo = cdi->ops; - if (cdi->use_count == 1 && /* last process that closes dev*/ - cdi->options & CDO_LOCK && - cdo->capability & ~cdi->mask & CDC_LOCK) - cdo->lock_door(cdi, 0); - cdo->release(cdi); - if (cdi->use_count > 0) cdi->use_count--; - if (cdi->use_count == 0) { /* last process that closes dev*/ - sync_dev(dev); - invalidate_buffers(dev); - if (cdi->options & CDO_AUTO_EJECT && - cdo->capability & ~cdi->mask & CDC_OPEN_TRAY) - cdo->tray_move(cdi, 1); - } + kdev_t dev = ip->i_rdev; + struct cdrom_device_info *cdi = cdrom_find_device (dev); + struct cdrom_device_ops *cdo; + int opened_for_data; + + if (cdi == NULL) + return 0; + opened_for_data = !(cdi->options & CDO_USE_FFLAGS) || + !(fp && fp->f_flags & O_NONBLOCK); + cdo = cdi->ops; + if (cdi->use_count == 1 && /* last process that closes dev*/ + opened_for_data && + cdi->options & CDO_LOCK && + cdo->capability & ~cdi->mask & CDC_LOCK) + cdo->lock_door(cdi, 0); + cdo->release(cdi); + if (cdi->use_count > 0) cdi->use_count--; + if (cdi->use_count == 0) { /* last process that closes dev*/ + sync_dev(dev); + invalidate_buffers(dev); + if (opened_for_data && + cdi->options & CDO_AUTO_EJECT && + cdo->capability & ~cdi->mask & CDC_OPEN_TRAY) + cdo->tray_move(cdi, 1); + } return 0; } @@ -230,37 +258,37 @@ static int media_changed(struct cdrom_device_info *cdi, int queue) { - unsigned int mask = (1 << (queue & 1)); - int ret = !!(cdi->mc_flags & mask); + unsigned int mask = (1 << (queue & 1)); + int ret = !!(cdi->mc_flags & mask); - /* changed since last call? */ - if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) { - cdi->mc_flags = 0x3; /* set bit on both queues */ - ret |= 1; - } - cdi->mc_flags &= ~mask; /* clear bit */ - return ret; + /* changed since last call? */ + if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) { + cdi->mc_flags = 0x3; /* set bit on both queues */ + ret |= 1; + } + cdi->mc_flags &= ~mask; /* clear bit */ + return ret; } static int cdrom_media_changed(kdev_t dev) { - struct cdrom_device_info *cdi = cdrom_find_device (dev); - if (cdi == NULL) - return -ENODEV; - if (cdi->ops->media_changed == NULL) - return -EINVAL; - return media_changed(cdi, 0); + struct cdrom_device_info *cdi = cdrom_find_device (dev); + if (cdi == NULL) + return -ENODEV; + if (cdi->ops->media_changed == NULL) + return -EINVAL; + return media_changed(cdi, 0); } /* Requests to the low-level drivers will /always/ be done in the - following format convention: + following format convention: CDROM_LBA: all data-related requests. - CDROM_MSF: all audio-related requests. + CDROM_MSF: all audio-related requests. However, a low-level implementation is allowed to refuse this - request, and return information in its own favorite format. + request, and return information in its own favorite format. It doesn't make sense /at all/ to ask for a play_audio in LBA format, or ask for multi-session info in MSF format. However, for @@ -271,22 +299,22 @@ static void sanitize_format(union cdrom_addr *addr, - u_char * curr, u_char requested) + u_char * curr, u_char requested) { - if (*curr == requested) - return; /* nothing to be done! */ - if (requested == CDROM_LBA) { - addr->lba = (int) addr->msf.frame + - 75 * (addr->msf.second - 2 + 60 * addr->msf.minute); - } else { /* CDROM_MSF */ - int lba = addr->lba; - addr->msf.frame = lba % 75; - lba /= 75; - lba += 2; - addr->msf.second = lba % 60; - addr->msf.minute = lba / 60; - } - *curr = requested; + if (*curr == requested) + return; /* nothing to be done! */ + if (requested == CDROM_LBA) { + addr->lba = (int) addr->msf.frame + + 75 * (addr->msf.second - 2 + 60 * addr->msf.minute); + } else { /* CDROM_MSF */ + int lba = addr->lba; + addr->msf.frame = lba % 75; + lba /= 75; + lba += 2; + addr->msf.second = lba % 60; + addr->msf.minute = lba / 60; + } + *curr = requested; } /* All checking and format change makes this code really hard to read! @@ -296,7 +324,7 @@ * shouldn't be in inner loops. */ #define GETARG(type, x) { \ - int ret=verify_area(VERIFY_READ, (void *) arg, sizeof x); \ + int ret=verify_area(VERIFY_READ, (void *) arg, sizeof x); \ if (ret) return ret; \ copy_from_user(&x, (type *) arg, sizeof x); } #define PUTARG(type, x) { \ @@ -318,238 +346,286 @@ * memory-verification is performed for these ioctls. */ static +int check_for_audio_disc(struct cdrom_device_info * cdi, + struct cdrom_device_ops * cdo); + +static int cdrom_ioctl(struct inode *ip, struct file *fp, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { - kdev_t dev = ip->i_rdev; - struct cdrom_device_info *cdi = cdrom_find_device (dev); - struct cdrom_device_ops *cdo; - - if (cdi == NULL) - return -ENODEV; - cdo = cdi->ops; - /* the first few commands do not deal with audio capabilities, but - only with routines in cdrom device operations. */ - switch (cmd) { - /* maybe we should order cases after statistics of use? */ - - case CDROMMULTISESSION: - { - struct cdrom_multisession ms_info; - u_char requested_format; - if (!(cdo->capability & CDC_MULTI_SESSION)) - return -EINVAL; - GETARG(struct cdrom_multisession, ms_info); - requested_format = ms_info.addr_format; - ms_info.addr_format = CDROM_LBA; - cdo->get_last_session(cdi, &ms_info); - sanitize_format(&ms_info.addr, &ms_info.addr_format, - requested_format); - PUTARG(struct cdrom_multisession, ms_info); - return 0; - } - - case CDROMEJECT: - if (cdo->capability & ~cdi->mask & CDC_OPEN_TRAY) { + kdev_t dev = ip->i_rdev; + struct cdrom_device_info *cdi = cdrom_find_device (dev); + struct cdrom_device_ops *cdo; + + if (cdi == NULL) + return -ENODEV; + cdo = cdi->ops; + /* the first few commands do not deal with audio capabilities, but + only with routines in cdrom device operations. */ + switch (cmd) { + /* maybe we should order cases after statistics of use? */ + + case CDROMMULTISESSION: + { + struct cdrom_multisession ms_info; + u_char requested_format; + if (!(cdo->capability & CDC_MULTI_SESSION)) + return -EINVAL; + GETARG(struct cdrom_multisession, ms_info); + requested_format = ms_info.addr_format; + ms_info.addr_format = CDROM_LBA; + cdo->get_last_session(cdi, &ms_info); + sanitize_format(&ms_info.addr, &ms_info.addr_format, + requested_format); + PUTARG(struct cdrom_multisession, ms_info); + return 0; + } + + case CDROMEJECT: + if (cdo->capability & ~cdi->mask & CDC_OPEN_TRAY) { if (cdi->use_count == 1) { - if (cdo->capability & ~cdi->mask & CDC_LOCK) + if (cdo->capability & ~cdi->mask & CDC_LOCK) cdo->lock_door(cdi, 0); return cdo->tray_move(cdi, 1); } else return -EBUSY; } else - return -EINVAL; - - case CDROMCLOSETRAY: - if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY) + return -EINVAL; + + case CDROMCLOSETRAY: + if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY) return cdo->tray_move(cdi, 0); - else - return -EINVAL; - - case CDROMEJECT_SW: - cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT); - if (arg) - cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT; - return 0; - - case CDROM_MEDIA_CHANGED: - if (cdo->capability & ~cdi->mask & CDC_MEDIA_CHANGED) { - if (arg == CDSL_CURRENT) - return media_changed(cdi, 1); - else if ((int)arg < cdi->capacity && - cdo->capability & ~cdi->mask - &CDC_SELECT_DISC) - return cdo->media_changed (cdi, arg); - else - return -EINVAL; - } - else - return -EINVAL; - - case CDROM_SET_OPTIONS: - cdi->options |= (int) arg; - return cdi->options; - - case CDROM_CLEAR_OPTIONS: - cdi->options &= ~(int) arg; - return cdi->options; - - case CDROM_SELECT_SPEED: - if ((int)arg <= cdi->speed && - cdo->capability & ~cdi->mask & CDC_SELECT_SPEED) - return cdo->select_speed(cdi, arg); - else - return -EINVAL; - - case CDROM_SELECT_DISC: - if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE)) - return cdo->select_disc(cdi, arg); - if ((int)arg < cdi->capacity && - cdo->capability & ~cdi->mask & CDC_SELECT_DISC) + else + return -EINVAL; + + case CDROMEJECT_SW: + cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT); + if (arg) + cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT; + return 0; + + case CDROM_MEDIA_CHANGED: + if (cdo->capability & ~cdi->mask & CDC_MEDIA_CHANGED) { + if (!(cdo->capability & ~cdi->mask & CDC_SELECT_DISC) + || arg == CDSL_CURRENT) + /* cannot select disc or select current disc */ + return media_changed(cdi, 1); + if ((unsigned int)arg < cdi->capacity) + return cdo->media_changed (cdi, arg); + return -EINVAL; + } else + return -EINVAL; + + case CDROM_SET_OPTIONS: + cdi->options |= (int) arg; + return cdi->options; + + case CDROM_CLEAR_OPTIONS: + cdi->options &= ~(int) arg; + return cdi->options; + + case CDROM_SELECT_SPEED: + if ((int)arg <= cdi->speed && + cdo->capability & ~cdi->mask & CDC_SELECT_SPEED) + return cdo->select_speed(cdi, arg); + else + return -EINVAL; + + case CDROM_SELECT_DISC: + if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE)) return cdo->select_disc(cdi, arg); - else + if ((int)arg < cdi->capacity && + cdo->capability & ~cdi->mask & CDC_SELECT_DISC) + return cdo->select_disc(cdi, arg); + else return -EINVAL; - + /* The following function is implemented, although very few audio * discs give Universal Product Code information, which should just be * the Medium Catalog Number on the box. Note, that the way the code * is written on the CD is /not/ uniform across all discs! */ - case CDROM_GET_MCN: { - struct cdrom_mcn mcn; - if (!(cdo->capability & CDC_MCN)) - return -EINVAL; - if (!cdo->get_mcn(cdi, &mcn)) { - PUTARG(struct cdrom_mcn, mcn); - return 0; - } - return -EINVAL; - } - - case CDROM_DRIVE_STATUS: - if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE)) - return cdo->drive_status(cdi, arg); - if (cdo->drive_status == NULL || - ! (cdo->capability & ~cdi->mask & CDC_SELECT_DISC - && (int)arg < cdi->capacity)) - return -EINVAL; - else + case CDROM_GET_MCN: { + struct cdrom_mcn mcn; + if (!(cdo->capability & CDC_MCN)) + return -EINVAL; + if (!cdo->get_mcn(cdi, &mcn)) { + PUTARG(struct cdrom_mcn, mcn); + return 0; + } + return -EINVAL; + } + + case CDROM_DRIVE_STATUS: + if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE)) + return cdo->drive_status(cdi, arg); + if (cdo->drive_status == NULL || + ((cdo->capability & ~cdi->mask & CDC_SELECT_DISC) + && (int)arg >= cdi->capacity)) + return -EINVAL; + else return cdo->drive_status(cdi, arg); - - case CDROM_DISC_STATUS: + + case CDROM_DISC_STATUS: if (cdo->disc_status == NULL) return -EINVAL; else return cdo->disc_status(cdi); - case CDROM_CHANGER_NSLOTS: - return cdi->capacity; + case CDROM_CHANGER_NSLOTS: + return cdi->capacity; /* The following is not implemented, because there are too many * different data type. We could support /1/ raw mode, that is large * enough to hold everything. */ - + #if 0 - case CDROMREADMODE1: { - struct cdrom_msf msf; - char buf[CD_FRAMESIZE]; - GETARG(struct cdrom_msf, msf); - if (!cdo->read_audio(dev, cmd, &msf, &buf, cdi)) { - PUTARG(char *, buf); - return 0; - } - return -EINVAL; - } + case CDROMREADMODE1: { + struct cdrom_msf msf; + char buf[CD_FRAMESIZE]; + GETARG(struct cdrom_msf, msf); + if (!cdo->read_audio(dev, cmd, &msf, &buf, cdi)) { + PUTARG(char *, buf); + return 0; + } + return -EINVAL; + } #endif } /* switch */ - + /* Now all the audio-ioctls follow, they are all routed through the same call audio_ioctl(). */ - if (cdo->capability & CDC_PLAY_AUDIO) +#define CHECKAUDIO if ((ret=check_for_audio_disc(cdi, cdo))) return ret + + if (cdo->capability & CDC_PLAY_AUDIO) { + int ret; switch (cmd) { - case CDROMSUBCHNL: - { - struct cdrom_subchnl q; - u_char requested, back; - GETARG(struct cdrom_subchnl, q); - requested = q.cdsc_format; - q.cdsc_format = CDROM_MSF; - if (!cdo->audio_ioctl(cdi, cmd, &q)) { - back = q.cdsc_format; /* local copy */ - sanitize_format(&q.cdsc_absaddr, &back, - requested); - sanitize_format(&q.cdsc_reladdr, - &q.cdsc_format, requested); - PUTARG(struct cdrom_subchnl, q); - return 0; - } else - return -EINVAL; - } - case CDROMREADTOCHDR: { - struct cdrom_tochdr header; - GETARG(struct cdrom_tochdr, header); - if (!cdo->audio_ioctl(cdi, cmd, &header)) { - PUTARG(struct cdrom_tochdr, header); - return 0; - } else - return -EINVAL; - } - case CDROMREADTOCENTRY: { - struct cdrom_tocentry entry; - u_char requested_format; - GETARG(struct cdrom_tocentry, entry); - requested_format = entry.cdte_format; - /* make interface to low-level uniform */ - entry.cdte_format = CDROM_MSF; - if (!(cdo->audio_ioctl(cdi, cmd, &entry))) { - sanitize_format(&entry.cdte_addr, - &entry.cdte_format, requested_format); - PUTARG(struct cdrom_tocentry, entry); - return 0; - } else - return -EINVAL; - } - case CDROMPLAYMSF: { - struct cdrom_msf msf; - GETARG(struct cdrom_msf, msf); - return cdo->audio_ioctl(cdi, cmd, &msf); - } - case CDROMPLAYTRKIND: { - struct cdrom_ti track_index; - GETARG(struct cdrom_ti, track_index); - return cdo->audio_ioctl(cdi, cmd, &track_index); - } - case CDROMVOLCTRL: { - struct cdrom_volctrl volume; - GETARG(struct cdrom_volctrl, volume); - return cdo->audio_ioctl(cdi, cmd, &volume); - } - case CDROMVOLREAD: { - struct cdrom_volctrl volume; - if (!cdo->audio_ioctl(cdi, cmd, &volume)) { - PUTARG(struct cdrom_volctrl, volume); - return 0; - } - return -EINVAL; - } - case CDROMSTART: - case CDROMSTOP: - case CDROMPAUSE: - case CDROMRESUME: + case CDROMSUBCHNL: + { + struct cdrom_subchnl q; + u_char requested, back; + GETARG(struct cdrom_subchnl, q); + requested = q.cdsc_format; + q.cdsc_format = CDROM_MSF; + if (!cdo->audio_ioctl(cdi, cmd, &q)) { + back = q.cdsc_format; /* local copy */ + sanitize_format(&q.cdsc_absaddr, &back, + requested); + sanitize_format(&q.cdsc_reladdr, + &q.cdsc_format, requested); + PUTARG(struct cdrom_subchnl, q); + return 0; + } else + return -EINVAL; + } + case CDROMREADTOCHDR: { + struct cdrom_tochdr header; + GETARG(struct cdrom_tochdr, header); + CHECKAUDIO; + if (!cdo->audio_ioctl(cdi, cmd, &header)) { + PUTARG(struct cdrom_tochdr, header); + return 0; + } else + return -EINVAL; + } + case CDROMREADTOCENTRY: { + struct cdrom_tocentry entry; + u_char requested_format; + GETARG(struct cdrom_tocentry, entry); + requested_format = entry.cdte_format; + /* make interface to low-level uniform */ + entry.cdte_format = CDROM_MSF; + if (!(cdo->audio_ioctl(cdi, cmd, &entry))) { + sanitize_format(&entry.cdte_addr, + &entry.cdte_format, requested_format); + PUTARG(struct cdrom_tocentry, entry); + return 0; + } else + return -EINVAL; + } + case CDROMPLAYMSF: { + struct cdrom_msf msf; + GETARG(struct cdrom_msf, msf); + CHECKAUDIO; + return cdo->audio_ioctl(cdi, cmd, &msf); + } + case CDROMPLAYTRKIND: { + struct cdrom_ti track_index; + GETARG(struct cdrom_ti, track_index); + CHECKAUDIO; + return cdo->audio_ioctl(cdi, cmd, &track_index); + } + case CDROMVOLCTRL: { + struct cdrom_volctrl volume; + GETARG(struct cdrom_volctrl, volume); + return cdo->audio_ioctl(cdi, cmd, &volume); + } + case CDROMVOLREAD: { + struct cdrom_volctrl volume; + if (!cdo->audio_ioctl(cdi, cmd, &volume)) { + PUTARG(struct cdrom_volctrl, volume); + return 0; + } + return -EINVAL; + } + case CDROMSTART: + CHECKAUDIO; + case CDROMSTOP: + case CDROMPAUSE: + case CDROMRESUME: return cdo->audio_ioctl(cdi, cmd, NULL); } /* switch */ + } if (cdo->dev_ioctl != NULL) /* device specific ioctls? */ return cdo->dev_ioctl(cdi, cmd, arg); return -EINVAL; } +/* This code is similar to that in open_for_data. The routine is called + in case a audio play operation is requested. It doesn't make much sense + do do this on a data disc. + */ +int check_for_audio_disc(struct cdrom_device_info * cdi, + struct cdrom_device_ops * cdo) +{ + if (!(cdi->options & CDO_CHECK_TYPE)) + return 0; + if (cdo->drive_status != NULL) { + int ds = cdo->drive_status(cdi, CDSL_CURRENT); + if (ds == CDS_TRAY_OPEN) { + /* can/may i close it? */ + if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY && + cdi->options & CDO_AUTO_CLOSE) { + if (cdo->tray_move(cdi,0)) + return -EIO; + } else + return -ENOMEDIUM; /* can't close: too bad */ + ds = cdo->drive_status(cdi, CDSL_CURRENT); + if (ds == CDS_NO_DISC) + return -ENOMEDIUM; + } + if (cdo->disc_status != NULL) { + ds = cdo->disc_status(cdi); + if (ds == CDS_NO_DISC) + return -ENOMEDIUM; + if (ds != CDS_AUDIO) + return -EMEDIUMTYPE; + } + } + return 0; +} + +EXPORT_SYMBOL(register_cdrom); +EXPORT_SYMBOL(unregister_cdrom); +EXPORT_SYMBOL(cdrom_fops); + #ifdef MODULE int init_module(void) { - printk(KERN_INFO "Module inserted: " VERSION "\n"); + printk(KERN_INFO "Module cdrom: Generic CDROM driver " REVISION "\n"); return 0; } @@ -564,6 +640,6 @@ /* * Local variables: * comment-column: 40 - * compile-command: "gcc -DMODULE -D__KERNEL__ -I. -I/usr/src/linux-obj/include -Wall -Wstrict-prototypes -O2 -m486 -c cdrom.c -o cdrom.o" + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DCPU=486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o cdrom.o cdrom.c" * End: */ diff -u --recursive --new-file v2.1.33/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.1.33/linux/drivers/char/lp.c Sun Apr 13 10:18:20 1997 +++ linux/drivers/char/lp.c Sun Apr 13 09:23:31 1997 @@ -14,6 +14,7 @@ #include +#include #include #include #include diff -u --recursive --new-file v2.1.33/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c --- v2.1.33/linux/drivers/char/n_tty.c Tue Mar 4 10:25:23 1997 +++ linux/drivers/char/n_tty.c Fri Apr 11 22:12:34 1997 @@ -707,7 +707,7 @@ if (!tty->read_buf) { tty->read_buf = (unsigned char *) - get_free_page(intr_count ? GFP_ATOMIC : GFP_KERNEL); + get_free_page(in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); if (!tty->read_buf) return -ENOMEM; } diff -u --recursive --new-file v2.1.33/linux/drivers/char/selection.c linux/drivers/char/selection.c --- v2.1.33/linux/drivers/char/selection.c Sun Apr 13 10:18:20 1997 +++ linux/drivers/char/selection.c Fri Apr 11 10:37:40 1997 @@ -32,6 +32,8 @@ /* Don't take this from : 011-015 on the screen aren't spaces */ #define isspace(c) ((c) == ' ') +extern void poke_blanked_console(void); + /* Variables for selection control. */ /* Use a dynamic buffer, instead of static (Dec 1994) */ int sel_cons = 0; /* must not be disallocated */ @@ -118,7 +120,7 @@ int sel_mode, new_sel_start, new_sel_end, spc; char *bp, *obp; int i, ps, pe; - + do_unblank_screen(); poke_blanked_console(); @@ -289,7 +291,7 @@ int c = sel_buffer_lth; int l; struct vt_struct *vt = (struct vt_struct *) tty->driver_data; - + if (!bp || !c) return 0; poke_blanked_console(); diff -u --recursive --new-file v2.1.33/linux/drivers/char/tga.c linux/drivers/char/tga.c --- v2.1.33/linux/drivers/char/tga.c Fri Apr 4 08:52:19 1997 +++ linux/drivers/char/tga.c Sun Apr 13 09:23:31 1997 @@ -10,6 +10,7 @@ * This module exports the console io support for DEC's TGA */ +#include #include #include #include diff -u --recursive --new-file v2.1.33/linux/drivers/char/vt.c linux/drivers/char/vt.c --- v2.1.33/linux/drivers/char/vt.c Sun Apr 13 10:18:21 1997 +++ linux/drivers/char/vt.c Sun Apr 13 09:23:31 1997 @@ -9,6 +9,7 @@ * Some code moved for less code duplication - Andi Kleen - Mar 1997 */ +#include #include #include #include diff -u --recursive --new-file v2.1.33/linux/drivers/net/3c505.c linux/drivers/net/3c505.c --- v2.1.33/linux/drivers/net/3c505.c Sun Apr 13 10:18:21 1997 +++ linux/drivers/net/3c505.c Fri Apr 11 10:50:45 1997 @@ -450,7 +450,9 @@ return TRUE; break; case ASF_PCB_NAK: - printk("%s: send_pcb got NAK\n", dev->name); +#ifdef ELP_DEBUG + printk(KERN_DEBUG "%s: send_pcb got NAK\n", dev->name); +#endif goto abort; break; } diff -u --recursive --new-file v2.1.33/linux/drivers/net/de4x5.c.lock~ linux/drivers/net/de4x5.c.lock~ --- v2.1.33/linux/drivers/net/de4x5.c.lock~ Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/de4x5.c.lock~ Mon Apr 14 13:59:30 1997 @@ -0,0 +1 @@ +torvalds@penguin.transmeta.com \ No newline at end of file diff -u --recursive --new-file v2.1.33/linux/drivers/net/de600.c linux/drivers/net/de600.c --- v2.1.33/linux/drivers/net/de600.c Fri Apr 4 08:52:20 1997 +++ linux/drivers/net/de600.c Mon Apr 14 09:31:09 1997 @@ -804,8 +804,8 @@ sk->max_unacked = DE600_MAX_WINDOW - DE600_TCP_WINDOW_DIFF; */ - if (sk->rmem_alloc >= sk->rcvbuf-2*DE600_MIN_WINDOW) return(0); - amt = min((sk->rcvbuf-sk->rmem_alloc)/2/*-DE600_MIN_WINDOW*/, DE600_MAX_WINDOW); + if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf-2*DE600_MIN_WINDOW) return(0); + amt = min((sk->rcvbuf-atomic_read(&sk->rmem_alloc))/2/*-DE600_MIN_WINDOW*/, DE600_MAX_WINDOW); if (amt < 0) return(0); return(amt); } diff -u --recursive --new-file v2.1.33/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.1.33/linux/drivers/net/eepro100.c Sun Apr 13 10:18:21 1997 +++ linux/drivers/net/eepro100.c Mon Apr 14 09:31:09 1997 @@ -1620,7 +1620,7 @@ printk("%s: Allocating a setup frame of size %d.\n", dev->name, sp->mc_setup_frm_len); sp->mc_setup_frm = kmalloc(sp->mc_setup_frm_len, - intr_count ? GFP_ATOMIC : GFP_KERNEL); + in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); if (sp->mc_setup_frm == NULL) { printk("%s: Failed to allocate a setup frame.\n", dev->name); sp->rx_mode = -1; /* We failed, try again. */ diff -u --recursive --new-file v2.1.33/linux/drivers/net/loopback.c linux/drivers/net/loopback.c --- v2.1.33/linux/drivers/net/loopback.c Fri Apr 4 08:52:21 1997 +++ linux/drivers/net/loopback.c Mon Apr 14 09:31:09 1997 @@ -74,7 +74,7 @@ * instead are lobbed from tx queue to rx queue */ - if(skb->users != 1) + if(atomic_read(&skb->users) != 1) { struct sk_buff *skb2=skb; skb=skb_clone(skb, GFP_ATOMIC); /* Clone the buffer */ diff -u --recursive --new-file v2.1.33/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c --- v2.1.33/linux/drivers/net/myri_sbus.c Thu Mar 27 14:40:04 1997 +++ linux/drivers/net/myri_sbus.c Fri Apr 11 22:12:34 1997 @@ -262,7 +262,7 @@ int gfp_flags = GFP_KERNEL; int i; - if(from_irq || intr_count) + if(from_irq || in_interrupt()) gfp_flags = GFP_ATOMIC; myri_clean_rings(mp); @@ -534,7 +534,7 @@ { struct myri_eth *mp = (struct myri_eth *) dev->priv; - return myri_init(mp, intr_count); + return myri_init(mp, in_interrupt()); } static int myri_close(struct device *dev) @@ -570,7 +570,7 @@ DTX(("resetting, return 0\n")); printk("%s: transmit timed out, resetting\n", dev->name); mp->enet_stats.tx_errors++; - myri_init(mp, intr_count); + myri_init(mp, in_interrupt()); dev->tbusy = 0; dev->trans_start = jiffies; return 0; diff -u --recursive --new-file v2.1.33/linux/drivers/net/scc.c linux/drivers/net/scc.c --- v2.1.33/linux/drivers/net/scc.c Sun Apr 13 10:18:21 1997 +++ linux/drivers/net/scc.c Sun Apr 13 09:23:31 1997 @@ -133,6 +133,7 @@ /* ----------------------------------------------------------------------- */ +#include #include #include #include diff -u --recursive --new-file v2.1.33/linux/drivers/net/shaper.c linux/drivers/net/shaper.c --- v2.1.33/linux/drivers/net/shaper.c Mon Apr 7 11:35:29 1997 +++ linux/drivers/net/shaper.c Fri Apr 11 10:47:37 1997 @@ -87,7 +87,7 @@ /* * Lock in an interrupt may fail */ - if(sh->locked && intr_count) + if(sh->locked && in_interrupt()) { restore_flags(flags); return 0; @@ -438,7 +438,7 @@ return sh->rebuild_header(skb); } -static int shaper_cache(struct dst_entry *dst, struct dst_entry *neigh, struct hh_cache *hh) +static int shaper_cache(struct dst_entry *dst, struct neighbour *neigh, struct hh_cache *hh) { struct shaper *sh=dst->dev->priv; struct device *tmp; diff -u --recursive --new-file v2.1.33/linux/drivers/net/shaper.h linux/drivers/net/shaper.h --- v2.1.33/linux/drivers/net/shaper.h Sun Feb 2 05:18:42 1997 +++ linux/drivers/net/shaper.h Fri Apr 11 10:47:37 1997 @@ -33,7 +33,7 @@ void *saddr, unsigned len); int (*rebuild_header)(struct sk_buff *skb); - int (*hard_header_cache)(struct dst_entry *dst, struct dst_entry *neigh, + int (*hard_header_cache)(struct dst_entry *dst, struct neighbour *neigh, struct hh_cache *hh); void (*header_cache_update)(struct hh_cache *hh, struct device *dev, unsigned char * haddr); struct net_device_stats* (*get_stats)(struct device *dev); diff -u --recursive --new-file v2.1.33/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c --- v2.1.33/linux/drivers/net/sunhme.c Thu Mar 27 14:40:04 1997 +++ linux/drivers/net/sunhme.c Fri Apr 11 22:12:35 1997 @@ -921,7 +921,7 @@ struct device *dev = hp->dev; int i, gfp_flags = GFP_KERNEL; - if(from_irq || intr_count) + if(from_irq || in_interrupt()) gfp_flags = GFP_ATOMIC; HMD(("happy_meal_init_rings: counters to zero, ")); @@ -960,7 +960,7 @@ static void sun4c_happy_meal_init_rings(struct happy_meal *hp) { struct hmeal_init_block *hb = hp->happy_block; - struct hmeal_buffers *hbufs = hp->sun4c_buffers; + __u32 hbufs = hp->s4c_buf_dvma; int i; HMD(("happy_meal_init_rings: counters to zero, ")); @@ -968,9 +968,7 @@ HMD(("init rxring, ")); for(i = 0; i < RX_RING_SIZE; i++) { - unsigned char *this_buf = &hbufs->rx_buf[i][0]; - - hb->happy_meal_rxd[i].rx_addr = (unsigned int) this_buf; + hb->happy_meal_rxd[i].rx_addr = hbufs + hbuf_offset(rx_buf, i); hb->happy_meal_rxd[i].rx_flags = (RXFLAG_OWN | ((SUN4C_RX_BUFF_SIZE - RX_OFFSET) << 16)); } @@ -1190,8 +1188,8 @@ /* Set the RX and TX ring ptrs. */ HMD(("ring ptrs\n")); - erxregs->rx_ring = (unsigned long) &hp->happy_block->happy_meal_rxd[0]; - etxregs->tx_ring = (unsigned long) &hp->happy_block->happy_meal_txd[0]; + erxregs->rx_ring = hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0); + etxregs->tx_ring = hp->hblock_dvma + hblock_offset(happy_meal_txd, 0); /* Set the supported SBUS burst sizes. */ HMD(("happy_meal_init: bursts<")); @@ -1690,6 +1688,7 @@ struct happy_meal_rxd *rxbase = &hp->happy_block->happy_meal_rxd[0]; struct happy_meal_rxd *this; struct hmeal_buffers *hbufs = hp->sun4c_buffers; + __u32 hbufs_dvma = hp->s4c_buf_dvma; int elem = hp->rx_new, drops = 0; RXD(("RX<")); @@ -1698,6 +1697,7 @@ struct sk_buff *skb; unsigned int flags = this->rx_flags; unsigned char *thisbuf = &hbufs->rx_buf[elem][0]; + __u32 thisbuf_dvma = hbufs_dvma + hbuf_offset(rx_buf, elem); int len = flags >> 16; RXD(("[%d ", elem)); @@ -1731,7 +1731,7 @@ } } /* Return the buffer to the Happy Meal. */ - this->rx_addr = (unsigned int) thisbuf; + this->rx_addr = thisbuf_dvma; this->rx_flags = (RXFLAG_OWN | ((SUN4C_RX_BUFF_SIZE - RX_OFFSET) << 16)); @@ -1929,6 +1929,7 @@ { struct happy_meal *hp = (struct happy_meal *) dev->priv; struct hmeal_buffers *hbufs = hp->sun4c_buffers; + __u32 txbuf_dvma, hbufs_dvma = hp->s4c_buf_dvma; unsigned char *txbuf; int len, entry; @@ -1968,7 +1969,8 @@ memcpy(txbuf, skb->data, len); SXD(("SX", len, entry)); - hp->happy_block->happy_meal_txd[entry].tx_addr = (unsigned int) txbuf; + txbuf_dvma = hbufs_dvma + hbuf_offset(tx_buf, entry); + hp->happy_block->happy_meal_txd[entry].tx_addr = txbuf_dvma; hp->happy_block->happy_meal_txd[entry].tx_flags = (TXFLAG_OWN | TXFLAG_SOP | TXFLAG_EOP | (len & TXFLAG_SIZE)); hp->tx_new = NEXT_TX(entry); @@ -2153,11 +2155,13 @@ "burst-sizes", 0x00); hp->happy_block = (struct hmeal_init_block *) - sparc_dvma_malloc(PAGE_SIZE, "Happy Meal Init Block"); + sparc_dvma_malloc(PAGE_SIZE, "Happy Meal Init Block", + &hp->hblock_dvma); if(sparc_cpu_model == sun4c) hp->sun4c_buffers = (struct hmeal_buffers *) - sparc_dvma_malloc(sizeof(struct hmeal_buffers), "Happy Meal Bufs"); + sparc_dvma_malloc(sizeof(struct hmeal_buffers), "Happy Meal Bufs", + &hp->s4c_buf_dvma); else hp->sun4c_buffers = 0; diff -u --recursive --new-file v2.1.33/linux/drivers/net/sunhme.h linux/drivers/net/sunhme.h --- v2.1.33/linux/drivers/net/sunhme.h Mon Mar 17 14:54:26 1997 +++ linux/drivers/net/sunhme.h Fri Apr 11 10:47:37 1997 @@ -475,6 +475,9 @@ struct happy_meal_txd happy_meal_txd[TX_RING_MAXSIZE]; }; +#define hblock_offset(mem, elem) \ +((__u32)((unsigned long)(&(((struct hmeal_init_block *)0)->mem[elem])))) + #define SUN4C_PKT_BUF_SZ 1546 #define SUN4C_RX_BUFF_SIZE SUN4C_PKT_BUF_SZ #define SUN4C_TX_BUFF_SIZE SUN4C_PKT_BUF_SZ @@ -484,6 +487,9 @@ char rx_buf[RX_RING_SIZE][SUN4C_RX_BUFF_SIZE]; }; +#define hbuf_offset(mem, elem) \ +((__u32)((unsigned long)(&(((struct hmeal_buffers *)0)->mem[elem][0])))) + /* Now software state stuff. */ enum happy_transceiver { external = 0, @@ -507,14 +513,17 @@ struct hmeal_bigmacregs *bigmacregs; /* I said NO SOLARIS with my bigmac! */ struct hmeal_tcvregs *tcvregs; /* MIF transceiver regs */ - struct hmeal_init_block *happy_block; /* RX and TX descriptors */ + struct hmeal_init_block *happy_block; /* RX and TX descriptors (CPU addr) */ + __u32 hblock_dvma; /* DVMA visible address happy block */ struct sk_buff *rx_skbs[RX_RING_SIZE]; struct sk_buff *tx_skbs[TX_RING_SIZE]; int rx_new, tx_new, rx_old, tx_old; - struct hmeal_buffers *sun4c_buffers; + /* We may use this for Ultra as well, will have to see, maybe not. */ + struct hmeal_buffers *sun4c_buffers; /* CPU visible address. */ + __u32 s4c_buf_dvma; /* DVMA visible address. */ unsigned int happy_flags; /* Driver state flags */ enum happy_transceiver tcvr_type; /* Kind of transceiver in use */ diff -u --recursive --new-file v2.1.33/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c --- v2.1.33/linux/drivers/net/sunlance.c Thu Mar 27 14:40:04 1997 +++ linux/drivers/net/sunlance.c Fri Apr 11 10:47:37 1997 @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.56 1997/03/14 21:04:45 jj Exp $ +/* $Id: sunlance.c,v 1.61 1997/04/10 06:40:54 davem Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza @@ -212,10 +212,17 @@ char rx_buf [RX_RING_SIZE][RX_BUFF_SIZE]; }; +#define libdesc_offset(rt, elem) \ +((__u32)(((unsigned long)(&(((struct lance_init_block *)0)->rt[elem]))))) + +#define libbuff_offset(rt, elem) \ +((__u32)(((unsigned long)(&(((struct lance_init_block *)0)->rt[elem][0]))))) + struct lance_private { char *name; volatile struct lance_regs *ll; volatile struct lance_init_block *init_block; + __u32 init_block_dvma; int rx_new, tx_new; int rx_old, tx_old; @@ -265,13 +272,14 @@ static void load_csrs (struct lance_private *lp) { volatile struct lance_regs *ll = lp->ll; - volatile struct lance_init_block *ib = lp->init_block; + __u32 ib_dvma = lp->init_block_dvma; int leptr; - if(lp->pio_buffer) - leptr = 0; - else - leptr = LANCE_ADDR (ib); + /* This is right now because when we are using a PIO buffered + * init block, init_block_dvma is set to zero. -DaveM + */ + leptr = LANCE_ADDR (ib_dvma); + ll->rap = LE_CSR1; ll->rdp = (leptr & 0xFFFF); ll->rap = LE_CSR2; @@ -291,14 +299,15 @@ { struct lance_private *lp = (struct lance_private *) dev->priv; volatile struct lance_init_block *ib = lp->init_block; - volatile struct lance_init_block *aib; /* for LANCE_ADDR computations */ + __u32 ib_dvma = lp->init_block_dvma; + __u32 aib; /* for LANCE_ADDR computations */ int leptr; int i; - if(lp->pio_buffer) - aib = 0; - else - aib = ib; + /* This is right now because when we are using a PIO buffered + * init block, init_block_dvma is set to zero. -DaveM + */ + aib = ib_dvma; /* Lock out other processes while setting up hardware */ dev->tbusy = 1; @@ -309,6 +318,7 @@ /* Copy the ethernet address to the lance init block * Note that on the sparc you need to swap the ethernet address. + * Note also we want the CPU ptr of the init_block here. */ ib->phys_addr [0] = dev->dev_addr [1]; ib->phys_addr [1] = dev->dev_addr [0]; @@ -322,7 +332,7 @@ /* Setup the Tx ring entries */ for (i = 0; i <= TX_RING_SIZE; i++) { - leptr = LANCE_ADDR(&aib->tx_buf[i][0]); + leptr = LANCE_ADDR(aib + libbuff_offset(tx_buf, i)); ib->btx_ring [i].tmd0 = leptr; ib->btx_ring [i].tmd1_hadr = leptr >> 16; ib->btx_ring [i].tmd1_bits = 0; @@ -336,7 +346,7 @@ if (ZERO) printk ("RX rings:\n"); for (i = 0; i < RX_RING_SIZE; i++) { - leptr = LANCE_ADDR(&aib->rx_buf[i][0]); + leptr = LANCE_ADDR(aib + libbuff_offset(rx_buf, i)); ib->brx_ring [i].rmd0 = leptr; ib->brx_ring [i].rmd1_hadr = leptr >> 16; @@ -350,14 +360,14 @@ /* Setup the initialization block */ /* Setup rx descriptor pointer */ - leptr = LANCE_ADDR(&aib->brx_ring); + leptr = LANCE_ADDR(aib + libdesc_offset(brx_ring, 0)); ib->rx_len = (LANCE_LOG_RX_BUFFERS << 13) | (leptr >> 16); ib->rx_ptr = leptr; if (ZERO) printk ("RX ptr: %8.8x\n", leptr); /* Setup tx descriptor pointer */ - leptr = LANCE_ADDR(&aib->btx_ring); + leptr = LANCE_ADDR(aib + libdesc_offset(btx_ring, 0)); ib->tx_len = (LANCE_LOG_TX_BUFFERS << 13) | (leptr >> 16); ib->tx_ptr = leptr; if (ZERO) @@ -662,7 +672,7 @@ /* On the 4m, setup the ledma to provide the upper bits for buffers */ if (lp->ledma) - lp->ledma->regs->dma_test = ((unsigned int) lp->init_block) + lp->ledma->regs->dma_test = ((unsigned long) lp->init_block) & 0xff000000; lance_init_ring (dev); @@ -747,7 +757,7 @@ lp->ledma->regs->cond_reg |= DMA_RST_ENET; udelay (200); lp->ledma->regs->cond_reg &= ~DMA_RST_ENET; - lp->ledma->regs->dma_test = ((unsigned int) lp->init_block) + lp->ledma->regs->dma_test = ((unsigned long) lp->init_block) & 0xff000000; } lance_init_ring (dev); @@ -966,23 +976,25 @@ sdev->reg_addrs[0].which_io, 0x0); /* Make certain the data structures used by the LANCE are aligned. */ - dev->priv = (void *)(((int)dev->priv + 7) & ~7); + dev->priv = (void *)(((unsigned long)dev->priv + 7) & ~7); lp = (struct lance_private *) dev->priv; - if (lebuffer){ prom_apply_sbus_ranges (lebuffer->my_bus, &lebuffer->reg_addrs [0], lebuffer->num_registers, lebuffer); + lp->init_block = (void *) sparc_alloc_io (lebuffer->reg_addrs [0].phys_addr, 0, sizeof (struct lance_init_block), "lebuffer", lebuffer->reg_addrs [0].which_io, 0); + lp->init_block_dvma = 0; + lp->pio_buffer = 1; } else { lp->init_block = (void *) sparc_dvma_malloc (sizeof (struct lance_init_block), - lancedma); + lancedma, &lp->init_block_dvma); lp->pio_buffer = 0; } lp->busmaster_regval = prom_getintdefault(sdev->prom_node, @@ -1059,7 +1071,7 @@ } /* This should never happen. */ - if ((int)(lp->init_block->brx_ring) & 0x07) { + if ((unsigned long)(lp->init_block->brx_ring) & 0x07) { printk("%s: ERROR: Rx and Tx rings not on even boundary.\n", dev->name); return ENODEV; diff -u --recursive --new-file v2.1.33/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c --- v2.1.33/linux/drivers/net/sunqe.c Thu Mar 27 14:40:04 1997 +++ linux/drivers/net/sunqe.c Fri Apr 11 22:12:35 1997 @@ -131,7 +131,7 @@ struct device *dev = qep->dev; int i, gfp_flags = GFP_KERNEL; - if(from_irq || intr_count) + if(from_irq || in_interrupt()) gfp_flags = GFP_ATOMIC; qep->rx_new = qep->rx_old = qep->tx_new = qep->tx_old = 0; @@ -150,6 +150,8 @@ skb_put(skb, ETH_FRAME_LEN); skb_reserve(skb, 34); + + /* FIX FOR ULTRA */ qb->qe_rxd[i].rx_addr = (unsigned int) skb->data; qb->qe_rxd[i].rx_flags = (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); @@ -163,6 +165,7 @@ { struct qe_init_block *qb = qep->qe_block; struct sunqe_buffers *qbufs = qep->sun4c_buffers; + __u32 qbufs_dvma = qep->s4c_buf_dvma; int i; qep->rx_new = qep->rx_old = qep->tx_new = qep->tx_old = 0; @@ -173,7 +176,7 @@ qb->qe_rxd[i].rx_flags = qb->qe_rxd[i].rx_addr = 0; for(i = 0; i < SUN4C_RX_RING_SIZE; i++) { - qb->qe_rxd[i].rx_addr = (unsigned int) &qbufs->rx_buf[i][0]; + qb->qe_rxd[i].rx_addr = qbufs_dvma + qebuf_offset(rx_buf, i); qb->qe_rxd[i].rx_flags = (RXD_OWN | ((SUN4C_RX_BUFF_SIZE) & RXD_LENGTH)); } @@ -197,8 +200,8 @@ return -EAGAIN; /* Setup initial rx/tx init block pointers. */ - cregs->rxds = (unsigned int) &qep->qe_block->qe_rxd[0]; - cregs->txds = (unsigned int) &qep->qe_block->qe_txd[0]; + cregs->rxds = qep->qblock_dvma + qib_offset(qe_rxd, 0); + cregs->txds = qep->qblock_dvma + qib_offset(qe_txd, 0); /* Enable the various irq's. */ cregs->rimask = 0; @@ -507,6 +510,8 @@ new_skb->dev = qep->dev; skb_put(new_skb, ETH_FRAME_LEN); skb_reserve(new_skb, 34); + + /* FIX FOR ULTRA */ rxbase[elem].rx_addr = (unsigned int) new_skb->data; rxbase[elem].rx_flags = (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); @@ -552,6 +557,7 @@ struct qe_rxd *rxbase = &qep->qe_block->qe_rxd[0]; struct qe_rxd *this; struct sunqe_buffers *qbufs = qep->sun4c_buffers; + __u32 qbufs_dvma = qep->s4c_buf_dvma; int elem = qep->rx_new, drops = 0; this = &rxbase[elem]; @@ -559,6 +565,8 @@ struct sk_buff *skb; unsigned char *this_qbuf = qbufs->rx_buf[elem & (SUN4C_RX_RING_SIZE - 1)]; + __u32 this_qbuf_dvma = qbufs_dvma + + qebuf_offset(rx_buf, (elem & (SUN4C_RX_RING_SIZE - 1))); struct qe_rxd *end_rxd = &rxbase[(elem+SUN4C_RX_RING_SIZE)&(RX_RING_SIZE-1)]; unsigned int flags = this->rx_flags; @@ -585,7 +593,7 @@ qep->net_stats.rx_packets++; } } - end_rxd->rx_addr = (unsigned int) this_qbuf; + end_rxd->rx_addr = this_qbuf_dvma; end_rxd->rx_flags = (RXD_OWN | (SUN4C_RX_BUFF_SIZE & RXD_LENGTH)); elem = NEXT_RX(elem); @@ -727,6 +735,7 @@ qep->tx_skbs[entry] = skb; + /* FIX FOR ULTRA */ qep->qe_block->qe_txd[entry].tx_addr = (unsigned long) skb->data; qep->qe_block->qe_txd[entry].tx_flags = (TXD_OWN | TXD_SOP | TXD_EOP | (len & TXD_LENGTH)); @@ -745,6 +754,7 @@ { struct sunqe *qep = (struct sunqe *) dev->priv; struct sunqe_buffers *qbufs = qep->sun4c_buffers; + __u32 txbuf_dvma, qbufs_dvma = qep->s4c_buf_dvma; unsigned char *txbuf; int len, entry; @@ -763,13 +773,15 @@ entry = qep->tx_new; txbuf = &qbufs->tx_buf[entry & (SUN4C_TX_RING_SIZE - 1)][0]; + txbuf_dvma = qbufs_dvma + + qebuf_offset(tx_buf, (entry & (SUN4C_TX_RING_SIZE - 1))); /* Avoid a race... */ qep->qe_block->qe_txd[entry].tx_flags = TXD_UPDATE; memcpy(txbuf, skb->data, len); - qep->qe_block->qe_txd[entry].tx_addr = (unsigned int) txbuf; + qep->qe_block->qe_txd[entry].tx_addr = txbuf_dvma; qep->qe_block->qe_txd[entry].tx_flags = (TXD_OWN | TXD_SOP | TXD_EOP | (len & TXD_LENGTH)); qep->tx_new = NEXT_TX(entry); @@ -1054,12 +1066,14 @@ } qeps[i]->qe_block = (struct qe_init_block *) - sparc_dvma_malloc(PAGE_SIZE, "QE Init Block"); + sparc_dvma_malloc(PAGE_SIZE, "QE Init Block", + &qeps[i]->qblock_dvma); if(sparc_cpu_model == sun4c) qeps[i]->sun4c_buffers = (struct sunqe_buffers *) sparc_dvma_malloc(sizeof(struct sunqe_buffers), - "QE RX/TX Buffers"); + "QE RX/TX Buffers", + &qeps[i]->s4c_buf_dvma); else qeps[i]->sun4c_buffers = 0; diff -u --recursive --new-file v2.1.33/linux/drivers/net/sunqe.h linux/drivers/net/sunqe.h --- v2.1.33/linux/drivers/net/sunqe.h Mon Mar 17 14:54:26 1997 +++ linux/drivers/net/sunqe.h Fri Apr 11 10:47:37 1997 @@ -317,6 +317,9 @@ struct qe_txd qe_txd[TX_RING_MAXSIZE]; }; +#define qib_offset(mem, elem) \ +((__u32)((unsigned long)(&(((struct qe_init_block *)0)->mem[elem])))) + struct sunqe; struct sunqec { @@ -341,6 +344,9 @@ char rx_buf[SUN4C_RX_RING_SIZE][SUN4C_RX_BUFF_SIZE]; }; +#define qebuf_offset(mem, elem) \ +((__u32)((unsigned long)(&(((struct sunqe_buffers *)0)->mem[elem][0])))) + #define SUN4C_NEXT_RX(num) (((num) + 1) & (SUN4C_RX_RING_SIZE - 1)) #define SUN4C_NEXT_TX(num) (((num) + 1) & (SUN4C_TX_RING_SIZE - 1)) #define SUN4C_PREV_RX(num) (((num) - 1) & (SUN4C_RX_RING_SIZE - 1)) @@ -350,17 +356,19 @@ struct qe_creg *qcregs; /* QEC per-channel Registers */ struct qe_mregs *mregs; /* Per-channel MACE Registers */ struct qe_init_block *qe_block; /* RX and TX descriptors */ + __u32 qblock_dvma; /* RX and TX descriptors */ struct sk_buff *rx_skbs[RX_RING_SIZE]; struct sk_buff *tx_skbs[TX_RING_SIZE]; int rx_new, tx_new, rx_old, tx_old; - struct sunqe_buffers *sun4c_buffers; + struct sunqe_buffers *sun4c_buffers; /* CPU visible address. */ + __u32 s4c_buf_dvma; /* DVMA visible address. */ struct sunqec *parent; - struct net_device_stats net_stats; /* Statistical counters */ + struct net_device_stats net_stats; /* Statistical counters */ struct linux_sbus_device *qe_sbusdev; /* QE's SBUS device struct */ struct device *dev; /* QE's netdevice struct */ int channel; /* Who am I? */ diff -u --recursive --new-file v2.1.33/linux/drivers/pnp/parport_init.c linux/drivers/pnp/parport_init.c --- v2.1.33/linux/drivers/pnp/parport_init.c Sun Apr 13 10:18:21 1997 +++ linux/drivers/pnp/parport_init.c Sun Apr 13 09:23:31 1997 @@ -9,10 +9,12 @@ * and Philip Blundell */ +#include +#include +#include #include #include -#include #include #include #include @@ -761,8 +763,10 @@ #undef PORT } +#ifdef CONFIG_PNP_PARPORT_AUTOPROBE for (pb = parport_enumerate(); pb; pb = pb->next) parport_probe_one(pb); +#endif return 0; } diff -u --recursive --new-file v2.1.33/linux/drivers/pnp/parport_probe.c linux/drivers/pnp/parport_probe.c --- v2.1.33/linux/drivers/pnp/parport_probe.c Sun Apr 13 10:18:21 1997 +++ linux/drivers/pnp/parport_probe.c Fri Apr 11 10:37:40 1997 @@ -5,6 +5,7 @@ * Philip Blundell */ +#include #include #include @@ -20,7 +21,6 @@ #include #include - #undef DEBUG_PROBE static inline int read_nibble(struct parport *port) diff -u --recursive --new-file v2.1.33/linux/drivers/pnp/parport_procfs.c linux/drivers/pnp/parport_procfs.c --- v2.1.33/linux/drivers/pnp/parport_procfs.c Sun Apr 13 10:18:21 1997 +++ linux/drivers/pnp/parport_procfs.c Sun Apr 13 09:23:31 1997 @@ -8,10 +8,12 @@ * and Philip Blundell */ +#include #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.1.33/linux/drivers/pnp/parport_share.c linux/drivers/pnp/parport_share.c --- v2.1.33/linux/drivers/pnp/parport_share.c Sun Apr 13 10:18:21 1997 +++ linux/drivers/pnp/parport_share.c Fri Apr 11 10:50:49 1997 @@ -9,6 +9,7 @@ * and Philip Blundell */ +#include #include #include @@ -64,7 +65,7 @@ if (new.dma >= 0) { if (request_dma(new.dma, new.name)) { printk(KERN_INFO "%s: unable to claim DMA %d\n", - new.name, new..dma); + new.name, new.dma); release_region(new.base, new.size); if( new.modes & PARPORT_MODE_ECR ) release_region(new.base+0x400, 3); diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/audio/audio.c linux/drivers/sbus/audio/audio.c --- v2.1.33/linux/drivers/sbus/audio/audio.c Mon Mar 17 14:54:28 1997 +++ linux/drivers/sbus/audio/audio.c Fri Apr 11 10:47:37 1997 @@ -105,7 +105,6 @@ struct sparcaudio_driver *drv = (struct sparcaudio_driver *)arg; unsigned long flags; - printk(KERN_DEBUG "sparcaudio: next buffer (of=%d)\n",drv->output_front); save_and_cli(flags); drv->ops->start_output(drv, drv->output_buffers[drv->output_front], @@ -123,7 +122,6 @@ /* If the output queue is empty, shutdown the driver. */ if (drv->output_count == 0) { /* Stop the lowlevel driver from outputing. */ - printk("sparcaudio: lowlevel driver shutdown\n"); drv->ops->stop_output(drv); drv->output_active = 0; @@ -184,7 +182,6 @@ while (count > 0) { /* Check to make sure that an output buffer is available. */ if (driver->output_count == driver->num_output_buffers) { - printk(KERN_DEBUG "sparcaudio: waiting for free buffer\n"); interruptible_sleep_on(&driver->output_write_wait); if (current->signal & ~current->blocked) return bytes_written > 0 ? bytes_written : -EINTR; @@ -198,9 +195,6 @@ copy_from_user_ret(driver->output_buffers[driver->output_rear], buf, bytes_to_copy, -EFAULT); - printk(KERN_DEBUG "Stuffing %d in %d\n", - bytes_to_copy, driver->output_rear); - /* Update the queue pointers. */ buf += bytes_to_copy; count -= bytes_to_copy; @@ -212,7 +206,6 @@ /* If the low-level driver is not active, activate it. */ save_and_cli(flags); if (! driver->output_active) { - printk(KERN_DEBUG "sparcaudio: activating lowlevel driver\n"); driver->ops->start_output(driver, driver->output_buffers[driver->output_front], driver->output_sizes[driver->output_front]); driver->output_active = 1; diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/Config.in linux/drivers/sbus/char/Config.in --- v2.1.33/linux/drivers/sbus/char/Config.in Mon Mar 17 14:54:28 1997 +++ linux/drivers/sbus/char/Config.in Fri Apr 11 10:47:37 1997 @@ -39,4 +39,8 @@ comment 'Misc Linux/SPARC drivers' tristate '/dev/openprom device support' CONFIG_SUN_OPENPROMIO tristate 'Mostek real time clock support' CONFIG_SUN_MOSTEK_RTC -tristate 'Bidirectional parallel port support' CONFIG_SUN_BPP + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Bidirectional parallel port support (EXPERIMENTAL)' CONFIG_SUN_BPP + tristate 'Videopix Frame Grabber (EXPERIMENTAL)' CONFIG_SUN_VIDEOPIX +fi diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/Makefile linux/drivers/sbus/char/Makefile --- v2.1.33/linux/drivers/sbus/char/Makefile Mon Mar 17 14:54:28 1997 +++ linux/drivers/sbus/char/Makefile Fri Apr 11 10:47:37 1997 @@ -73,5 +73,15 @@ endif endif +ifeq ($(CONFIG_SUN_VIDEOPIX),y) +O_OBJS += vfc.o +else + ifeq ($(CONFIG_SUN_VIDEOPIX),m) + M_OBJS += vfc.o + endif +endif + include $(TOPDIR)/Rules.make +vfc.o: vfc_dev.o vfc_i2c.o + $(LD) -r -o vfc.o vfc_dev.o vfc_i2c.o diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/bwtwo.c linux/drivers/sbus/char/bwtwo.c --- v2.1.33/linux/drivers/sbus/char/bwtwo.c Thu Mar 27 14:40:05 1997 +++ linux/drivers/sbus/char/bwtwo.c Fri Apr 11 10:47:37 1997 @@ -1,4 +1,4 @@ -/* $Id: bwtwo.c,v 1.10 1997/03/12 23:25:15 ecd Exp $ +/* $Id: bwtwo.c,v 1.12 1997/04/10 03:02:40 davem Exp $ * bwtwo.c: bwtwo console driver * * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -143,10 +143,10 @@ 0x10, 0x20, 0 }; -__initfunc(void bwtwo_setup (fbinfo_t *fb, int slot, uint bwtwo, int bw2_io, +__initfunc(void bwtwo_setup (fbinfo_t *fb, int slot, unsigned long bwtwo, int bw2_io, struct linux_sbus_device *sbdp)) { - printk ("bwtwo%d at 0x%8.8x\n", slot, bwtwo); + printk ("bwtwo%d at 0x%8.8x\n", slot, (uint)bwtwo); fb->type.fb_cmsize = 0; fb->mmap = bwtwo_mmap; fb->loadcmap = 0; @@ -155,8 +155,9 @@ fb->blank = bwtwo_blank; fb->unblank = bwtwo_unblank; - fb->info.bwtwo.regs = sparc_alloc_io ((void *)bwtwo + - BWTWO_REGISTER_OFFSET, 0, sizeof (struct bwtwo_regs), + fb->info.bwtwo.regs = + sparc_alloc_io ((u32)(bwtwo + BWTWO_REGISTER_OFFSET), + 0, sizeof (struct bwtwo_regs), "bwtwo_regs", bw2_io, 0); if (!prom_getbool(sbdp->prom_node, "width")) { @@ -200,7 +201,7 @@ } if(!fb->base) - fb->base = (unsigned long) sparc_alloc_io((void *)bwtwo, 0, + fb->base = (unsigned long) sparc_alloc_io((u32)bwtwo, 0, ((fb->type.fb_depth*fb->type.fb_height*fb->type.fb_width)/8), "bwtwo_fbase", bw2_io, 0); diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/cgfourteen.c linux/drivers/sbus/char/cgfourteen.c --- v2.1.33/linux/drivers/sbus/char/cgfourteen.c Mon Dec 30 02:00:04 1996 +++ linux/drivers/sbus/char/cgfourteen.c Fri Apr 11 10:47:37 1997 @@ -1,4 +1,4 @@ -/* $Id: cgfourteen.c,v 1.17 1996/12/23 10:16:00 ecd Exp $ +/* $Id: cgfourteen.c,v 1.18 1997/03/24 17:44:27 jj Exp $ * cgfourteen.c: Sun SparcStation console support. * * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -424,7 +424,7 @@ *mcr = (*mcr & ~(CG14_MCR_PIXMODE_MASK)); } -__initfunc(void cg14_setup (fbinfo_t *fb, int slot, int con_node, uint cg14, int cg14_io)) +__initfunc(void cg14_setup (fbinfo_t *fb, int slot, int con_node, unsigned long cg14, int cg14_io)) { struct cg14_info *cg14info; uint bases [2]; @@ -468,5 +468,5 @@ /* If the bit is turned on, the card has 8 mb of ram, otherwise just 4 */ cg14info->ramsize = (regs->vca & CG14_VCA_8MB_MASK ? 8 : 4) * 1024 * 1024; printk ("cgfourteen%d at 0x%8.8x with %d megs of RAM rev=%d, impl=%d\n", - slot, cg14, cg14info->ramsize/(1024*1024), regs->rev >> 4, regs->rev & 0xf); + slot, (uint)cg14, cg14info->ramsize/(1024*1024), regs->rev >> 4, regs->rev & 0xf); } diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/cgsix.c linux/drivers/sbus/char/cgsix.c --- v2.1.33/linux/drivers/sbus/char/cgsix.c Mon Mar 17 14:54:28 1997 +++ linux/drivers/sbus/char/cgsix.c Fri Apr 11 10:47:37 1997 @@ -1,4 +1,4 @@ -/* $Id: cgsix.c,v 1.22 1997/02/02 02:12:41 ecd Exp $ +/* $Id: cgsix.c,v 1.26 1997/04/10 03:02:40 davem Exp $ * cgsix.c: cgsix frame buffer driver * * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -246,38 +246,38 @@ switch (vma->vm_offset+page){ case CG6_TEC: map_size = PAGE_SIZE; - map_offset = get_phys ((uint)fb->info.cg6.tec); + map_offset = get_phys ((unsigned long)fb->info.cg6.tec); break; case CG6_FBC: map_size = PAGE_SIZE; - map_offset = get_phys ((uint)fb->info.cg6.fbc); + map_offset = get_phys ((unsigned long)fb->info.cg6.fbc); break; case CG6_FHC: map_size = PAGE_SIZE; - map_offset = get_phys ((uint)fb->info.cg6.fhc); + map_offset = get_phys ((unsigned long)fb->info.cg6.fhc); break; case CG6_THC: map_size = PAGE_SIZE; - map_offset = get_phys ((uint)fb->info.cg6.thc); + map_offset = get_phys ((unsigned long)fb->info.cg6.thc); break; case CG6_BTREGS: map_size = PAGE_SIZE; - map_offset = get_phys ((uint)fb->info.cg6.bt); + map_offset = get_phys ((unsigned long)fb->info.cg6.bt); break; case CG6_DHC: map_size = PAGE_SIZE * 40; - map_offset = get_phys ((uint)fb->info.cg6.dhc); + map_offset = get_phys ((unsigned long)fb->info.cg6.dhc); break; case CG6_ROM: map_size = PAGE_SIZE * 16; - map_offset = get_phys ((uint)fb->info.cg6.rom); + map_offset = get_phys ((unsigned long)fb->info.cg6.rom); break; case CG6_RAM: map_size = size-page; - map_offset = get_phys ((uint) fb->base); + map_offset = get_phys ((unsigned long) fb->base); if (map_size < fb->type.fb_size) map_size = fb->type.fb_size; break; @@ -422,7 +422,7 @@ cg6->bt->control |= 0x03 << 24; } -__initfunc(void cg6_setup (fbinfo_t *fb, int slot, uint cg6, int cg6_io)) +__initfunc(void cg6_setup (fbinfo_t *fb, int slot, unsigned long cg6, int cg6_io)) { struct cg6_info *cg6info; unsigned int rev, cpu, conf; @@ -447,23 +447,24 @@ cg6info = (struct cg6_info *) &fb->info.cg6; /* Map the hardware registers */ - cg6info->bt = sparc_alloc_io ((void *) cg6+CG6_BROOKTREE_OFFSET, 0, + cg6info->bt = sparc_alloc_io ((u32)(cg6+CG6_BROOKTREE_OFFSET), 0, sizeof (struct bt_regs), "cgsix_dac", cg6_io, 0); - cg6info->fhc = sparc_alloc_io ((void *) cg6+CG6_FHC_OFFSET, 0, + cg6info->fhc = sparc_alloc_io ((u32)(cg6+CG6_FHC_OFFSET), 0, sizeof (int), "cgsix_fhc", cg6_io, 0); - cg6info->thc = sparc_alloc_io ((void *) cg6+CG6_THC_OFFSET, 0, + cg6info->thc = sparc_alloc_io ((u32)(cg6+CG6_THC_OFFSET), 0, sizeof (struct cg6_thc), "cgsix_thc", cg6_io, 0); - cg6info->tec = sparc_alloc_io ((void *) cg6+CG6_TEC_OFFSET, 0, + cg6info->tec = sparc_alloc_io ((u32)(cg6+CG6_TEC_OFFSET), 0, sizeof (struct cg6_tec), "cgsix_tec", cg6_io, 0); - cg6info->dhc = sparc_alloc_io ((void *) cg6+CG6_DHC_OFFSET, 0, + cg6info->dhc = sparc_alloc_io ((u32)(cg6+CG6_DHC_OFFSET), 0, 0x40000, "cgsix_dhc", cg6_io, 0); - cg6info->fbc = sparc_alloc_io ((void *) cg6+CG6_FBC_OFFSET, 0, + cg6info->fbc = sparc_alloc_io ((u32)(cg6+CG6_FBC_OFFSET), 0, 0x1000, "cgsix_fbc", cg6_io, 0); - cg6info->rom = sparc_alloc_io ((void *) cg6+CG6_ROM_OFFSET, 0, + cg6info->rom = sparc_alloc_io ((u32)(cg6+CG6_ROM_OFFSET), 0, 0x10000, "cgsix_rom", cg6_io, 0); - if (!fb->base){ - fb->base = (uint) sparc_alloc_io ((void *) cg6+CG6_RAM_OFFSET, 0, - fb->type.fb_size, "cgsix_ram", cg6_io, 0); + if (!fb->base) { + fb->base = (unsigned long) + sparc_alloc_io ((u32)(cg6+CG6_RAM_OFFSET), 0, + fb->type.fb_size, "cgsix_ram", cg6_io, 0); } if (slot == sun_prom_console_id) fb_restore_palette = cg6_restore_palette; @@ -481,7 +482,7 @@ printk("TEC Rev %x ", (cg6info->thc->thc_misc >> CG6_THC_MISC_REV_SHIFT) & CG6_THC_MISC_REV_MASK); - + /* Get FHC Revision */ conf = *(cg6info->fhc); @@ -497,16 +498,18 @@ rev = conf >> CG6_FHC_REV_SHIFT & CG6_FHC_REV_MASK; printk("Rev %x\n", rev); - if (slot && sun_prom_console_id == slot) return; - + if (slot && sun_prom_console_id == slot) + return; + /* Reset the cg6 */ cg6_reset(fb); - if (!slot) - /* Enable Video */ + if (!slot) { + /* Enable Video */ cg6_unblank(fb); - else + } else { cg6_blank(fb); + } } extern unsigned char vga_font[]; diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/cgthree.c linux/drivers/sbus/char/cgthree.c --- v2.1.33/linux/drivers/sbus/char/cgthree.c Thu Mar 27 14:40:05 1997 +++ linux/drivers/sbus/char/cgthree.c Fri Apr 11 10:47:37 1997 @@ -1,4 +1,4 @@ -/* $Id: cgthree.c,v 1.12 1997/03/11 23:44:24 ecd Exp $ +/* $Id: cgthree.c,v 1.16 1997/04/10 03:02:41 davem Exp $ * cgtree.c: cg3 frame buffer driver * * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -25,6 +25,16 @@ #include "cg_common.h" +/* Control Register Constants */ +#define CG3_CR_ENABLE_INTS 0x80 +#define CG3_CR_ENABLE_VIDEO 0x40 +#define CG3_CR_ENABLE_TIMING 0x20 +#define CG3_CR_ENABLE_CURCMP 0x10 +#define CG3_CR_XTAL_MASK 0x0c +#define CG3_CR_DIVISOR_MASK 0x03 + +/* Status Register Constants */ +#define CG3_SR_PENDING_INT 0x80 #define CG3_SR_RES_MASK 0x70 #define CG3_SR_1152_900_76_A 0x40 #define CG3_SR_1152_900_76_B 0x60 @@ -125,6 +135,19 @@ return 0; } +static void +cg3_blank (fbinfo_t *fb) +{ + fb->info.cg3.regs->control &= ~CG3_CR_ENABLE_VIDEO; +} + +static void +cg3_unblank (fbinfo_t *fb) +{ + fb->info.cg3.regs->control |= CG3_CR_ENABLE_VIDEO; +} + + static u8 cg3regvals_66hz[] __initdata = { /* 1152 x 900, 66 Hz */ 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14, 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24, @@ -155,7 +178,7 @@ }; -__initfunc(void cg3_setup (fbinfo_t *fb, int slot, uint cg3, int cg3_io, +__initfunc(void cg3_setup (fbinfo_t *fb, int slot, unsigned long cg3, int cg3_io, struct linux_sbus_device *sbdp)) { struct cg3_info *cg3info = (struct cg3_info *) &fb->info.cg3; @@ -177,10 +200,10 @@ } } } - printk ("cgRDI%d at 0x%8.8x\n", slot, cg3); + printk ("cgRDI%d at 0x%8.8x\n", slot, (uint)cg3); cg3info->cgrdi = 1; } else { - printk ("cgthree%d at 0x%8.8x\n", slot, cg3); + printk ("cgthree%d at 0x%8.8x\n", slot, (uint)cg3); cg3info->cgrdi = 0; } @@ -191,9 +214,11 @@ fb->postsetup = sun_cg_postsetup; fb->ioctl = 0; /* no special ioctls */ fb->reset = 0; + fb->blank = cg3_blank; + fb->unblank = cg3_unblank; /* Map the card registers */ - cg3info->regs = sparc_alloc_io ((void *) cg3+CG3_REGS, 0, + cg3info->regs = sparc_alloc_io ((u32)(cg3+CG3_REGS), 0, sizeof (struct cg3_regs),"cg3_regs", cg3_io, 0); if (!prom_getbool(sbdp->prom_node, "width")) { @@ -233,7 +258,7 @@ } if (!fb->base){ - fb->base=(uint) sparc_alloc_io ((void*) cg3+CG3_RAM, 0, + fb->base=(uint) sparc_alloc_io ((u32)(cg3+CG3_RAM), 0, fb->type.fb_size, "cg3_ram", cg3_io, 0); } } diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/fb.h linux/drivers/sbus/char/fb.h --- v2.1.33/linux/drivers/sbus/char/fb.h Thu Mar 27 14:40:05 1997 +++ linux/drivers/sbus/char/fb.h Fri Apr 11 10:47:37 1997 @@ -1,4 +1,4 @@ -/* $Id: fb.h,v 1.23 1997/03/12 23:25:16 ecd Exp $ +/* $Id: fb.h,v 1.24 1997/03/24 17:44:15 jj Exp $ * fb.h: contains the definitions of the structures that various sun * frame buffer can use to do console driver stuff. * @@ -197,12 +197,12 @@ #define FB_DEV(x) (MINOR(x) / 32) -extern void cg3_setup (fbinfo_t *, int, uint, int, struct linux_sbus_device *); -extern void cg6_setup (fbinfo_t *, int, uint, int); -extern void cg14_setup (fbinfo_t *, int, int, uint, int); -extern void bwtwo_setup (fbinfo_t *, int, uint, int, +extern void cg3_setup (fbinfo_t *, int, unsigned long, int, struct linux_sbus_device *); +extern void cg6_setup (fbinfo_t *, int, unsigned long, int); +extern void cg14_setup (fbinfo_t *, int, int, unsigned long, int); +extern void bwtwo_setup (fbinfo_t *, int, unsigned long, int, struct linux_sbus_device *); -extern void leo_setup (fbinfo_t *, int, uint, int); -extern void tcx_setup (fbinfo_t *, int, int, uint, struct linux_sbus_device *); +extern void leo_setup (fbinfo_t *, int, unsigned long, int); +extern void tcx_setup (fbinfo_t *, int, int, unsigned long, struct linux_sbus_device *); #endif __SPARC_FB_H_ diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/leo.c linux/drivers/sbus/char/leo.c --- v2.1.33/linux/drivers/sbus/char/leo.c Mon Mar 17 14:54:28 1997 +++ linux/drivers/sbus/char/leo.c Fri Apr 11 10:47:37 1997 @@ -1,7 +1,8 @@ -/* $Id: leo.c,v 1.11 1997/02/02 02:12:44 ecd Exp $ +/* $Id: leo.c,v 1.14 1997/04/10 17:06:09 jj Exp $ * leo.c: SUNW,leo 24/8bit frame buffer driver * * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997 Michal Rehacek (Michal.Rehacek@st.mff.cuni.cz) */ #include @@ -508,7 +509,7 @@ return memory_start + (256*4*3) + 256 + 256*3; } -__initfunc(void leo_setup (fbinfo_t *fb, int slot, uint leo, int leo_io)) +__initfunc(void leo_setup (fbinfo_t *fb, int slot, unsigned long leo, int leo_io)) { struct leo_info *leoinfo; int i; @@ -542,25 +543,25 @@ leoinfo->offset = leo; /* Map the hardware registers */ - leoinfo->lc_ss0_krn = sparc_alloc_io ((void *) leo + LEO_OFF_LC_SS0_KRN, 0, + leoinfo->lc_ss0_krn = sparc_alloc_io((u32)(leo + LEO_OFF_LC_SS0_KRN), 0, PAGE_SIZE,"leo_lc_ss0_krn", fb->space, 0); - leoinfo->lc_ss0_usr = sparc_alloc_io ((void *) leo + LEO_OFF_LC_SS0_USR, 0, + leoinfo->lc_ss0_usr = sparc_alloc_io((u32)(leo + LEO_OFF_LC_SS0_USR), 0, PAGE_SIZE,"leo_lc_ss0_usr", fb->space, 0); - leoinfo->lc_ss1_krn = sparc_alloc_io ((void *) leo + LEO_OFF_LC_SS1_KRN, 0, + leoinfo->lc_ss1_krn = sparc_alloc_io((u32)(leo + LEO_OFF_LC_SS1_KRN), 0, PAGE_SIZE,"leo_lc_ss1_krn", fb->space, 0); - leoinfo->lc_ss1_usr = sparc_alloc_io ((void *) leo + LEO_OFF_LC_SS1_USR, 0, + leoinfo->lc_ss1_usr = sparc_alloc_io((u32)(leo + LEO_OFF_LC_SS1_USR), 0, PAGE_SIZE,"leo_lc_ss1_usr", fb->space, 0); - leoinfo->ld_ss0 = sparc_alloc_io ((void *) leo + LEO_OFF_LD_SS0, 0, + leoinfo->ld_ss0 = sparc_alloc_io((u32)(leo + LEO_OFF_LD_SS0), 0, PAGE_SIZE,"leo_ld_ss0", fb->space, 0); - leoinfo->ld_ss1 = sparc_alloc_io ((void *) leo + LEO_OFF_LD_SS1, 0, + leoinfo->ld_ss1 = sparc_alloc_io((u32)(leo + LEO_OFF_LD_SS1), 0, PAGE_SIZE,"leo_ld_ss1", fb->space, 0); - leoinfo->ld_gbl = sparc_alloc_io ((void *) leo + LEO_OFF_LD_GBL, 0, + leoinfo->ld_gbl = sparc_alloc_io((u32)(leo + LEO_OFF_LD_GBL), 0, PAGE_SIZE,"leo_ld_gbl", fb->space, 0); - leoinfo->lx_krn = sparc_alloc_io ((void *) leo + LEO_OFF_LX_KRN, 0, + leoinfo->lx_krn = sparc_alloc_io((u32)(leo + LEO_OFF_LX_KRN), 0, PAGE_SIZE,"leo_lx_krn", fb->space, 0); - leoinfo->cursor = sparc_alloc_io ((void *) leo + LEO_OFF_LX_CURSOR, 0, + leoinfo->cursor = sparc_alloc_io((u32)(leo + LEO_OFF_LX_CURSOR), 0, sizeof(struct leo_cursor),"leo_lx_crsr", fb->space, 0); - fb->base = (long)sparc_alloc_io ((void *) leo + LEO_OFF_SS0, 0, + fb->base = (long)sparc_alloc_io((u32)(leo + LEO_OFF_SS0), 0, 0x800000,"leo_ss0", fb->space, 0); leoinfo->ld_ss0->unk = 0xffff; @@ -617,24 +618,16 @@ do { \ i = us->csr; \ } while (i & 0x20000000); \ - ss->fg = (attr >> 4)<<24; \ - ss->planemask = 0xff000000; \ + ss->fg = (attr & 0xf) << 24; \ + ss->bg = (attr >> 4) << 24; \ ss->rop = 0x310040; \ - us->extent = (count*8-1) | (15<<11); \ - i = us->attrs; \ - us->fill = (x) | ((y) << 11) | ((i & 3) << 29) | ((i & 8) ? 0x80000000 : 0); \ - do { \ - i = us->csr; \ - } while (i & 0x20000000); \ - ss->fg = (attr & 0xf)<<24; \ - us->fontc2 = ~(0); \ + ss->planemask = 0xff000000; \ + us->fontc2 = 0xFFFFFFFE; \ us->attrs = 4; \ - us->fontc = ~(0); \ - us->extent = ((u16)x) | (y << 16); \ - us->src = ((u16)(x + (count << 3))) | ((y + 16) << 16); + us->fontc = 0xFF000000; #define GX_BLITC_END \ } - + static void leo_blitc(unsigned short charattr, int xoff, int yoff) { unsigned char attrib = CHARATTR_TO_SUNCOLOR(charattr); diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/rtc.c linux/drivers/sbus/char/rtc.c --- v2.1.33/linux/drivers/sbus/char/rtc.c Fri Apr 4 08:52:22 1997 +++ linux/drivers/sbus/char/rtc.c Fri Apr 11 10:47:37 1997 @@ -1,4 +1,4 @@ -/* $Id: rtc.c,v 1.9 1997/01/26 07:13:40 davem Exp $ +/* $Id: rtc.c,v 1.10 1997/04/03 08:47:55 davem Exp $ * * Linux/SPARC Real Time Clock Driver * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/suncons.c linux/drivers/sbus/char/suncons.c --- v2.1.33/linux/drivers/sbus/char/suncons.c Thu Mar 27 14:40:05 1997 +++ linux/drivers/sbus/char/suncons.c Fri Apr 11 10:47:37 1997 @@ -1,4 +1,4 @@ -/* $Id: suncons.c,v 1.53 1997/03/15 07:47:50 davem Exp $ +/* $Id: suncons.c,v 1.58 1997/04/04 00:50:04 davem Exp $ * * suncons.c: Sun SparcStation console support. * @@ -257,10 +257,10 @@ return; /* Don't paint anything on fb which is not ours, but turn off the hw cursor in such case */ - save_and_cli(flags); + __save_and_cli(flags); if(cursor_pos == -1) { - restore_flags (flags); + __restore_flags (flags); return; } switch (con_depth){ @@ -287,7 +287,7 @@ break; } cursor_pos = -1; - restore_flags(flags); + __restore_flags(flags); } void @@ -316,13 +316,13 @@ return; } - save_and_cli(flags); + __save_and_cli(flags); idx = (pos - video_mem_base) >> 1; oldpos = cursor_pos; if (!deccm) { hide_cursor (); - restore_flags (flags); + __restore_flags (flags); return; } cursor_pos = idx; @@ -366,7 +366,7 @@ } default: } - restore_flags(flags); + __restore_flags(flags); } /* @@ -434,7 +434,12 @@ putconsxy(0, q); ush = (unsigned short *) video_mem_base + video_num_columns * 2 + 20 + 11 * (linux_num_cpus - 1); - for (p = "Linux/SPARC version " UTS_RELEASE; *p; p++, ush++) { +#ifdef __sparc_v9__ + p = "Linux/UltraSPARC version " UTS_RELEASE; +#else + p = "Linux/SPARC version " UTS_RELEASE; +#endif + for (; *p; p++, ush++) { *ush = (attr << 8) + *p; sun_blitc (*ush, (unsigned long) ush); } @@ -846,7 +851,7 @@ __initfunc(static void sparc_framebuffer_setup(int primary, int con_node, int type, struct linux_sbus_device *sbdp, - uint base, uint con_base, int prom_fb, + uint base, unsigned long con_base, int prom_fb, int parent_node)) { static int frame_buffers = 1; @@ -865,7 +870,8 @@ if (prom_fb) sun_prom_console_id = n; - if (sbdp) io = sbdp->reg_addrs [0].which_io; + if (sbdp) + io = sbdp->reg_addrs [0].which_io; /* Fill in common fb information */ fbinfo [n].type.fb_type = type; @@ -880,7 +886,10 @@ fbinfo [n].type.fb_size = PAGE_ALIGN((linebytes) * (fbinfo [n].type.fb_height)); fbinfo [n].space = io; fbinfo [n].blanked = 0; - fbinfo [n].base = con_base; + if (con_base >= PAGE_OFFSET) + fbinfo [n].base = con_base; + else + fbinfo [n].base = 0; fbinfo [n].cursor.hwsize.fbx = 32; fbinfo [n].cursor.hwsize.fby = 32; fbinfo [n].proc_entry.node = parent_node; @@ -1016,7 +1025,8 @@ int cg14 = 0; char prom_name[40]; int type; - uint con_base; + unsigned long con_base; + u32 tmp; u32 prom_console_node = 0; for (i = 0; i < FRAME_BUFFERS; i++) @@ -1115,7 +1125,8 @@ prom_apply_sbus_ranges (sbdp->my_bus, &sbdp->reg_addrs [0], sbdp->num_registers, sbdp); - propl = prom_getproperty(con_node, "address", (char *) &con_base, 4); + propl = prom_getproperty(con_node, "address", (char *) &tmp, 4); + con_base = tmp; if (propl != 4) con_base = 0; propl = prom_getproperty(con_node, "emulation", prom_name, sizeof (prom_name)); if (propl < 0 || propl >= sizeof (prom_name)) { @@ -1277,7 +1288,7 @@ dst = (unsigned char *)(((unsigned long)con_fb_base) + FBUF_OFFSET(idx)); - save_and_cli(flags); + __save_and_cli(flags); if ((!(charattr & 0xf000)) ^ (idx == cursor_pos)) { for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst+=CHARS_PER_LINE) *dst = ~(*font_row); @@ -1285,7 +1296,7 @@ for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst+=CHARS_PER_LINE) *dst = *font_row; } - restore_flags(flags); + __restore_flags(flags); break; } case 8: { @@ -1329,12 +1340,12 @@ BLITC_SPACE BLITC_SPACE : : "r" (cpl), "r" (x3), "r" (x1), "r" (x2)); - save_and_cli (flags); + __save_and_cli (flags); if (idx != cursor_pos) __asm__ __volatile__ (BLITC_SPC : : "r" (x1), "r" (dst), "r" (cpl)); else __asm__ __volatile__ (BLITC_SPC : : "r" (x1), "r" (under_cursor), "i" (8)); - restore_flags (flags); + __restore_flags (flags); #else bgmask = attrib >> 4; bgmask |= bgmask << 8; @@ -1345,7 +1356,7 @@ *(dst+1) = bgmask; } /* Prevent cursor spots left on the screen */ - save_and_cli(flags); + __save_and_cli(flags); if (idx != cursor_pos) { *dst = bgmask; *(dst+1) = bgmask; @@ -1358,7 +1369,7 @@ under_cursor [2] = bgmask; under_cursor [3] = bgmask; } - restore_flags(flags); + __restore_flags(flags); #endif } else /* non-space */ { fgmask = attrib & 0x0f; @@ -1430,12 +1441,12 @@ /* Prepare the data the bottom line (and put it into g2,g3) */ __asm__ __volatile__ (BLITC_BODYEND : : "r" (fontm_bits), "r" (fgmask), "r" (bgmask), "r" (x3), "r" (x4)); - save_and_cli(flags); + __save_and_cli(flags); if (idx != cursor_pos) __asm__ __volatile__ (BLITC_STORE : : "r" (dst), "r" (cpl)); else __asm__ __volatile__ (BLITC_STORE : : "r" (under_cursor), "i" (8)); - restore_flags (flags); + __restore_flags (flags); #else for(j = 0; j < CHAR_HEIGHT - 2; j++, font_row++, dst += ipl) { rowbits = *font_row; @@ -1458,7 +1469,7 @@ data4 = (data4 & fgmask) | (~data4 & bgmask); /* Prevent cursor spots left on the screen */ - save_and_cli(flags); + __save_and_cli(flags); if (idx != cursor_pos) { *dst = data; @@ -1473,7 +1484,7 @@ under_cursor [3] = data4; } - restore_flags(flags); + __restore_flags(flags); #endif } break; diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/sunfb.c linux/drivers/sbus/char/sunfb.c --- v2.1.33/linux/drivers/sbus/char/sunfb.c Fri Apr 4 08:52:22 1997 +++ linux/drivers/sbus/char/sunfb.c Fri Apr 11 10:47:37 1997 @@ -1,4 +1,4 @@ -/* $Id: sunfb.c,v 1.21 1997/03/14 21:04:53 jj Exp $ +/* $Id: sunfb.c,v 1.22 1997/04/03 08:47:56 davem Exp $ * sunfb.c: Sun generic frame buffer support. * * Copyright (C) 1995, 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c --- v2.1.33/linux/drivers/sbus/char/sunkbd.c Fri Apr 4 08:52:22 1997 +++ linux/drivers/sbus/char/sunkbd.c Fri Apr 11 10:47:37 1997 @@ -383,7 +383,7 @@ e0_keys[scancode - 128]; } -void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs); +void sunkbd_inchar(unsigned char ch, struct pt_regs *regs); static void keyboard_timer (unsigned long ignored); static struct timer_list @@ -400,7 +400,7 @@ save_flags(flags); cli(); /* Auto repeat: send regs = 0 to indicate autorepeat */ - sunkbd_inchar (last_keycode, 0, 0); + sunkbd_inchar (last_keycode, 0); del_timer (&auto_repeat_timer); if (kbd_rate_ticks) { auto_repeat_timer.expires = jiffies + kbd_rate_ticks; @@ -411,7 +411,7 @@ /* #define SKBD_DEBUG */ /* This is our keyboard 'interrupt' routine. */ -void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs) +void sunkbd_inchar(unsigned char ch, struct pt_regs *regs) { unsigned char keycode; char up_flag; /* 0 or SUNKBD_UBIT */ @@ -1393,7 +1393,7 @@ kbd_close (struct inode *i, struct file *f) { if (--kbd_active) - return; + return 0; if (kbd_redirected) kbd_table [kbd_opened-1].kbdmode = VC_XLATE; diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/sunmouse.c linux/drivers/sbus/char/sunmouse.c --- v2.1.33/linux/drivers/sbus/char/sunmouse.c Fri Apr 4 08:52:22 1997 +++ linux/drivers/sbus/char/sunmouse.c Fri Apr 11 10:47:37 1997 @@ -188,7 +188,7 @@ * the Mouse zs8530 channel. */ void -sun_mouse_inbyte(unsigned char byte, unsigned char status) +sun_mouse_inbyte(unsigned char byte) { signed char mvalue; int d; @@ -204,8 +204,6 @@ push_char (byte); return; } - /* Check for framing errors and parity errors */ - /* XXX TODO XXX */ /* If the mouse sends us a byte from 0x80 to 0x87 * we are starting at byte zero in the transaction diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c --- v2.1.33/linux/drivers/sbus/char/sunserial.c Mon Mar 17 14:54:28 1997 +++ linux/drivers/sbus/char/sunserial.c Mon Apr 14 09:31:09 1997 @@ -1,4 +1,4 @@ -/* $Id: sunserial.c,v 1.27 1997/03/04 19:33:55 davem Exp $ +/* $Id: sunserial.c,v 1.37 1997/04/12 23:33:14 ecd Exp $ * serial.c: Serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -39,6 +39,8 @@ #define KEYBOARD_LINE 0x2 #define MOUSE_LINE 0x3 +extern struct wait_queue * keypress_wait; + struct sun_zslayout **zs_chips; struct sun_zschannel **zs_channels; struct sun_zschannel *zs_conschan; @@ -66,8 +68,8 @@ #define SUNKBD_UP 0x80 #define SUNKBD_A 0x4d -extern void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs); -extern void sun_mouse_inbyte(unsigned char byte, unsigned char status); +extern void sunkbd_inchar(unsigned char ch, struct pt_regs *regs); +extern void sun_mouse_inbyte(unsigned char byte); static unsigned char kgdb_regs[16] = { 0, 0, 0, /* write 0, 1, 2 */ @@ -173,7 +175,7 @@ */ static int baud_table[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 0 }; + 9600, 19200, 38400, 76800, 0 }; /* * Reading and writing Zilog8530 registers. The delays are to make this @@ -206,9 +208,20 @@ { unsigned long flags; struct sun_zschannel *channel = info->zs_channel; + unsigned char stat; + int i; + for (i = 0; i < 1000; i++) { + stat = read_zsreg(channel, R1); + if (stat & ALL_SNT) + break; + udelay(100); + } + write_zsreg(channel, R3, 0); + ZS_CLEARSTAT(channel); ZS_CLEARERR(channel); ZS_CLEARFIFO(channel); + /* Load 'em up */ save_flags(flags); cli(); if (info->channelA) @@ -231,7 +244,7 @@ write_zsreg(channel, R5, regs[R5]); write_zsreg(channel, R15, regs[R15]); write_zsreg(channel, R0, RES_EXT_INT); - write_zsreg(channel, R0, RES_EXT_INT); + write_zsreg(channel, R0, ERR_RES); write_zsreg(channel, R1, regs[R1]); write_zsreg(channel, R9, regs[R9]); restore_flags(flags); @@ -349,18 +362,6 @@ return; } -/* On receive, this clears errors and the receiver interrupts */ -static inline void rs_recv_clear(struct sun_zschannel *zsc) -{ - unsigned long flags; - - save_flags(flags); cli(); - zsc->control = ERR_RES; - udelay(5); - zsc->control = RES_H_IUS; - udelay(5); - restore_flags(flags); -} /* * ---------------------------------------------------------------------- @@ -391,7 +392,7 @@ int event) { info->event |= 1 << event; - queue_task_irq_off(&info->tqueue, &tq_serial); + queue_task(&info->tqueue, &tq_serial); mark_bh(SERIAL_BH); } @@ -402,90 +403,86 @@ struct tty_struct *tty = info->tty; unsigned char ch, stat; - ch = (info->zs_channel->data) & info->parity_mask; - udelay(5); - stat = read_zsreg(info->zs_channel, R1); - udelay(5); + do { + ch = (info->zs_channel->data) & info->parity_mask; + udelay(5); - /* If this is the console keyboard, we need to handle - * L1-A's here. - */ - if(info->cons_keyb) { - if(ch == SUNKBD_RESET) { - l1a_state.kbd_id = 1; - l1a_state.l1_down = 0; - } else if(l1a_state.kbd_id) { - l1a_state.kbd_id = 0; - } else if(ch == SUNKBD_L1) { - l1a_state.l1_down = 1; - } else if(ch == (SUNKBD_L1|SUNKBD_UP)) { - l1a_state.l1_down = 0; - } else if(ch == SUNKBD_A && l1a_state.l1_down) { - /* whee... */ - batten_down_hatches(); - /* Clear the line and continue execution... */ - rs_recv_clear(info->zs_channel); - l1a_state.l1_down = 0; - l1a_state.kbd_id = 0; + /* If this is the console keyboard, we need to handle + * L1-A's here. + */ + if(info->cons_keyb) { + if(ch == SUNKBD_RESET) { + l1a_state.kbd_id = 1; + l1a_state.l1_down = 0; + } else if(l1a_state.kbd_id) { + l1a_state.kbd_id = 0; + } else if(ch == SUNKBD_L1) { + l1a_state.l1_down = 1; + } else if(ch == (SUNKBD_L1|SUNKBD_UP)) { + l1a_state.l1_down = 0; + } else if(ch == SUNKBD_A && l1a_state.l1_down) { + /* whee... */ + batten_down_hatches(); + /* Continue execution... */ + l1a_state.l1_down = 0; + l1a_state.kbd_id = 0; + return; + } + sunkbd_inchar(ch, regs); return; } - rs_recv_clear(info->zs_channel); - sunkbd_inchar(ch, stat, regs); - - return; - } - if(info->cons_mouse) { - rs_recv_clear(info->zs_channel); - sun_mouse_inbyte(ch, stat); - return; - } - if(info->is_cons) { - if(ch==0) { /* whee, break received */ - batten_down_hatches(); - rs_recv_clear(info->zs_channel); + if(info->cons_mouse) { + sun_mouse_inbyte(ch); return; + } + if(info->is_cons) { + if(ch==0) { + /* whee, break received */ + batten_down_hatches(); + /* Continue execution... */ + return; #if 0 - } else if (ch == 1) { - show_state(); - return; - } else if (ch == 2) { - show_buffers(); - return; + } else if (ch == 1) { + show_state(); + return; + } else if (ch == 2) { + show_buffers(); + return; #endif + } + /* It is a 'keyboard interrupt' ;-) */ + wake_up(&keypress_wait); + } + /* Look for kgdb 'stop' character, consult the gdb + * documentation for remote target debugging and + * arch/sparc/kernel/sparc-stub.c to see how all this works. + */ + if((info->kgdb_channel) && (ch =='\003')) { + breakpoint(); + return; } - /* It is a 'keyboard interrupt' ;-) */ - wake_up(&keypress_wait); - } - /* Look for kgdb 'stop' character, consult the gdb documentation - * for remote target debugging and arch/sparc/kernel/sparc-stub.c - * to see how all this works. - */ - if((info->kgdb_channel) && (ch =='\003')) { - breakpoint(); - goto clear_and_exit; - } - if(!tty) - goto clear_and_exit; + if(!tty) + return; - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - queue_task_irq_off(&tty->flip.tqueue, &tq_timer); - tty->flip.count++; - if(stat & PAR_ERR) - *tty->flip.flag_buf_ptr++ = TTY_PARITY; - else if(stat & Rx_OVR) - *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; - else if(stat & CRC_ERR) - *tty->flip.flag_buf_ptr++ = TTY_FRAME; - else - *tty->flip.flag_buf_ptr++ = 0; /* XXX */ - *tty->flip.char_buf_ptr++ = ch; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + break; - queue_task_irq_off(&tty->flip.tqueue, &tq_timer); + tty->flip.count++; + *tty->flip.flag_buf_ptr++ = 0; + *tty->flip.char_buf_ptr++ = ch; -clear_and_exit: - rs_recv_clear(info->zs_channel); - return; + /* Check if we have another character... */ + stat = info->zs_channel->control; + udelay(5); + if (!(stat & Rx_CH_AV)) + break; + + /* ... and see if it is clean. */ + stat = read_zsreg(info->zs_channel, R1); + } while (!(stat & (PAR_ERR | Rx_OVR | CRC_ERR))); + + queue_task(&tty->flip.tqueue, &tq_timer); } static _INLINE_ void transmit_chars(struct sun_serial *info) @@ -496,14 +493,14 @@ /* Send next char */ zs_put_char(info->zs_channel, info->x_char); info->x_char = 0; - goto clear_and_return; + return; } if((info->xmit_cnt <= 0) || (tty != 0 && tty->stopped)) { /* That's peculiar... */ info->zs_channel->control = RES_Tx_P; udelay(5); - goto clear_and_return; + return; } /* Send char */ @@ -517,14 +514,7 @@ if(info->xmit_cnt <= 0) { info->zs_channel->control = RES_Tx_P; udelay(5); - goto clear_and_return; } - -clear_and_return: - /* Clear interrupt */ - info->zs_channel->control = RES_H_IUS; - udelay(5); - return; } static _INLINE_ void status_handle(struct sun_serial *info) @@ -537,9 +527,6 @@ /* Clear status condition... */ info->zs_channel->control = RES_EXT_INT; udelay(5); - /* Clear the interrupt */ - info->zs_channel->control = RES_H_IUS; - udelay(5); #if 0 if(status & DCD) { @@ -568,50 +555,106 @@ return; } +static _INLINE_ void special_receive(struct sun_serial *info) +{ + struct tty_struct *tty = info->tty; + unsigned char ch, stat; + + stat = read_zsreg(info->zs_channel, R1); + if (stat & (PAR_ERR | Rx_OVR | CRC_ERR)) { + ch = info->zs_channel->data; + udelay(5); + } + + if (!tty) + goto clear; + + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + goto done; + + tty->flip.count++; + if(stat & PAR_ERR) + *tty->flip.flag_buf_ptr++ = TTY_PARITY; + else if(stat & Rx_OVR) + *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; + else if(stat & CRC_ERR) + *tty->flip.flag_buf_ptr++ = TTY_FRAME; + +done: + queue_task(&tty->flip.tqueue, &tq_timer); +clear: + info->zs_channel->control = ERR_RES; + udelay(5); +} + + /* * This is the serial driver's generic interrupt routine */ void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) { - struct sun_serial * info = (struct sun_serial *)dev_id; + struct sun_serial *info; unsigned char zs_intreg; int i; + info = (struct sun_serial *)dev_id; for (i = 0; i < NUM_SERIAL; i++) { - zs_intreg = read_zsreg(info->zs_channel, 3); + zs_intreg = read_zsreg(info->zs_next->zs_channel, 2); + zs_intreg &= STATUS_MASK; - /* NOTE: The read register 3, which holds the irq status, + /* NOTE: The read register 2, which holds the irq status, * does so for both channels on each chip. Although - * the status value itself must be read from the A - * channel and is only valid when read from channel A. - * Yes... broken hardware... + * the status value itself must be read from the B + * channel and is only valid when read from channel B. + * When read from channel A, read register 2 contains + * the value written to write register 2. */ -#define CHAN_A_IRQMASK (CHARxIP | CHATxIP | CHAEXT) -#define CHAN_B_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT) /* Channel A -- /dev/ttya or /dev/kbd, could be the console */ - if(zs_intreg & CHAN_A_IRQMASK) { - if (zs_intreg & CHARxIP) - receive_chars(info, regs); - if (zs_intreg & CHATxIP) - transmit_chars(info); - if (zs_intreg & CHAEXT) - status_handle(info); + if (zs_intreg == CHA_Rx_AVAIL) { + receive_chars(info, regs); + return; + } + if(zs_intreg == CHA_Tx_EMPTY) { + transmit_chars(info); + return; + } + if (zs_intreg == CHA_EXT_STAT) { + status_handle(info); + return; + } + if (zs_intreg == CHA_SPECIAL) { + special_receive(info); + return; } - - info=info->zs_next; /* Channel B -- /dev/ttyb or /dev/mouse, could be the console */ - if(zs_intreg & CHAN_B_IRQMASK) { - if (zs_intreg & CHBRxIP) - receive_chars(info, regs); - if (zs_intreg & CHBTxIP) - transmit_chars(info); - if (zs_intreg & CHBEXT) - status_handle(info); + if(zs_intreg == CHB_Rx_AVAIL) { + receive_chars(info->zs_next, regs); + return; + } + if(zs_intreg == CHB_Tx_EMPTY) { + transmit_chars(info->zs_next); + return; } + if (zs_intreg == CHB_EXT_STAT) { + status_handle(info->zs_next); + return; + } + + /* NOTE: The default value for the IRQ status in read register + * 2 in channel B is CHB_SPECIAL, so we need to look at + * read register 3 in channel A to check if this is a + * real interrupt, or just the default value. + * Yes... broken hardware... + */ - info = info->zs_next; + zs_intreg = read_zsreg(info->zs_channel, 3); + if (zs_intreg & CHBRxIP) { + special_receive(info->zs_next); + return; + } + info = info->zs_next->zs_next; } } @@ -811,6 +854,7 @@ { unsigned short port; unsigned cflag; + int quot = 0; int i; int brg; @@ -821,13 +865,30 @@ return; i = cflag & CBAUD; if (cflag & CBAUDEX) { - /* XXX CBAUDEX is not obeyed. - * It is impossible at a 32bits SPARC. - * But we have to report this to user ... someday. - */ - i = B9600; + i &= ~CBAUDEX; + if (i != 1) + info->tty->termios->c_cflag &= ~CBAUDEX; + else + i += 15; } - if (baud_table[i]) { + if (i == 15) { + if ((info->flags & ZILOG_SPD_MASK) == ZILOG_SPD_HI) + i += 1; + if ((info->flags & ZILOG_SPD_MASK) == ZILOG_SPD_CUST) + quot = info->custom_divisor; + } + if (quot) { + info->zs_baud = info->baud_base / quot; + info->clk_divisor = 16; + + info->curregs[4] = X16CLK; + info->curregs[11] = TCBR | RCBR; + brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor); + info->curregs[12] = (brg & 255); + info->curregs[13] = ((brg >> 8) & 255); + info->curregs[14] = BRSRC | BRENAB; + zs_rtsdtr(info, 1); + } else if (baud_table[i]) { info->zs_baud = baud_table[i]; info->clk_divisor = 16; @@ -837,8 +898,10 @@ info->curregs[12] = (brg & 255); info->curregs[13] = ((brg >> 8) & 255); info->curregs[14] = BRSRC | BRENAB; - /* } else { */ - /* XXX */ + zs_rtsdtr(info, 1); + } else { + zs_rtsdtr(info, 0); + return; } /* byte size and parity */ @@ -902,7 +965,7 @@ void kbd_put_char(unsigned char ch) { struct sun_zschannel *chan = zs_kbdchan; - int flags; + unsigned long flags; if(!chan) return; @@ -915,7 +978,7 @@ void mouse_put_char(char ch) { struct sun_zschannel *chan = zs_mousechan; - int flags; + unsigned long flags; if(!chan) return; @@ -930,7 +993,7 @@ static void rs_put_char(char ch) { struct sun_zschannel *chan = zs_conschan; - int flags; + unsigned long flags; if(!chan) return; @@ -984,7 +1047,7 @@ rs_put_char(c); - save_flags(flags); cli(); + cli(); left = MIN(info->xmit_cnt, left-1); } @@ -1262,6 +1325,7 @@ info->baud_base = new_serial.baud_base; info->flags = ((info->flags & ~ZILOG_FLAGS) | (new_serial.flags & ZILOG_FLAGS)); + info->custom_divisor = new_serial.custom_divisor; info->type = new_serial.type; info->close_delay = new_serial.close_delay; info->closing_wait = new_serial.closing_wait; @@ -1292,6 +1356,56 @@ return 0; } +static int get_modem_info(struct sun_serial * info, unsigned int *value) +{ + unsigned char status; + unsigned int result; + + cli(); + status = info->zs_channel->control; + sti(); + result = ((info->curregs[5] & RTS) ? TIOCM_RTS : 0) + | ((info->curregs[5] & DTR) ? TIOCM_DTR : 0) + | ((status & DCD) ? TIOCM_CAR : 0) + | ((status & SYNC) ? TIOCM_DSR : 0) + | ((status & CTS) ? TIOCM_CTS : 0); + put_user_ret(result, value, -EFAULT); + return 0; +} + +static int set_modem_info(struct sun_serial * info, unsigned int cmd, + unsigned int *value) +{ + unsigned int arg; + + get_user_ret(arg, value, -EFAULT); + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + info->curregs[5] |= RTS; + if (arg & TIOCM_DTR) + info->curregs[5] |= DTR; + break; + case TIOCMBIC: + if (arg & TIOCM_RTS) + info->curregs[5] &= ~RTS; + if (arg & TIOCM_DTR) + info->curregs[5] &= ~DTR; + break; + case TIOCMSET: + info->curregs[5] = ((info->curregs[5] & ~(RTS | DTR)) + | ((arg & TIOCM_RTS) ? RTS : 0) + | ((arg & TIOCM_DTR) ? DTR : 0)); + break; + default: + return -EINVAL; + } + cli(); + write_zsreg(info->zs_channel, 5, info->curregs[5]); + sti(); + return 0; +} + /* * This routine sends a break character out the serial port. */ @@ -1341,7 +1455,8 @@ send_break(info, arg ? arg*(HZ/10) : HZ/4); return 0; case TIOCGSOFTCAR: - put_user_ret(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg, -EFAULT); + put_user_ret(C_CLOCAL(tty) ? 1 : 0, + (unsigned long *) arg, -EFAULT); return 0; case TIOCSSOFTCAR: get_user_ret(arg, (unsigned long *) arg, -EFAULT); @@ -1349,6 +1464,12 @@ ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return 0; + case TIOCMGET: + return get_modem_info(info, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return set_modem_info(info, cmd, (unsigned int *) arg); case TIOCGSERIAL: return get_serial_info(info, (struct serial_struct *) arg); @@ -1736,7 +1857,7 @@ static void show_serial_version(void) { - char *revision = "$Revision: 1.27 $"; + char *revision = "$Revision: 1.37 $"; char *version, *p; version = strchr(revision, ' '); @@ -1752,12 +1873,12 @@ * Zilogs, what the second does, I don't know. It does work * with using only the first number of each property. */ -static inline struct sun_zslayout *get_zs(int chip) +static struct sun_zslayout *get_zs(int chip) { struct linux_prom_irqs tmp_irq[2]; - unsigned long paddr = 0; - unsigned long vaddr[2] = { 0, 0 }; - int zsnode, tmpnode, iospace, slave, len; + unsigned int paddr = 0; + unsigned int vaddr[2] = { 0, 0 }; + int zsnode, tmpnode, iospace, slave, len, seen, sun4u_irq; static int irq = 0; #if CONFIG_AP1000 @@ -1784,7 +1905,7 @@ if(!irq) zilog_irq = irq = 12; vaddr[0] = (unsigned long) - sparc_alloc_io((char *) paddr, 0, 8, + sparc_alloc_io(paddr, 0, 8, "Zilog Serial", iospace, 0); } else { /* Can use the prom for other machine types */ @@ -1806,6 +1927,10 @@ } if (!tmpnode) panic ("get_zs: couldn't find board%d's bootbus\n", chip >> 1); + } else if (sparc_cpu_model == sun4u) { + tmpnode = prom_searchsiblings(zsnode, "sbus"); + if(tmpnode) + zsnode = prom_getchild(tmpnode); } else { tmpnode = prom_searchsiblings(zsnode, "obio"); if(tmpnode) @@ -1813,35 +1938,42 @@ } if(!zsnode) panic("get_zs no zs serial prom node"); + seen = 0; while(zsnode) { zsnode = prom_searchsiblings(zsnode, "zs"); slave = prom_getintdefault(zsnode, "slave", -1); - if(slave==chip) { + if((slave == chip) || + (sparc_cpu_model == sun4u && seen == chip)) { /* The one we want */ len = prom_getproperty(zsnode, "address", (void *) vaddr, sizeof(vaddr)); - if (len % sizeof(unsigned long)) { + if (len % sizeof(unsigned int)) { prom_printf("WHOOPS: proplen for %s " "was %d, need multiple of " "%d\n", "address", len, - sizeof(unsigned long)); + sizeof(unsigned int)); panic("zilog: address property"); } zs_nodes[chip] = zsnode; - len = prom_getproperty(zsnode, "intr", - (char *) tmp_irq, - sizeof(tmp_irq)); - if (len % sizeof(struct linux_prom_irqs)) { - prom_printf("WHOOPS: proplen for %s " - "was %d, need multiple of " - "%d\n", "address", len, - sizeof(struct linux_prom_irqs)); - panic("zilog: address property"); + if(sparc_cpu_model == sun4u) { + len = prom_getproperty(zsnode, "interrupts", + (char *) &sun4u_irq, + sizeof(tmp_irq)); + tmp_irq[0].pri = sun4u_irq; + } else { + len = prom_getproperty(zsnode, "intr", + (char *) tmp_irq, + sizeof(tmp_irq)); + if (len % sizeof(struct linux_prom_irqs)) { + prom_printf( + "WHOOPS: proplen for %s " + "was %d, need multiple of " + "%d\n", "address", len, + sizeof(struct linux_prom_irqs)); + panic("zilog: address property"); + } } -#ifdef OLD_STYLE_IRQ - tmp_irq[0].pri &= 0xf; -#endif if(!irq) { irq = zilog_irq = tmp_irq[0].pri; } else { @@ -1851,6 +1983,7 @@ break; } zsnode = prom_getsibling(zsnode); + seen++; } if(!zsnode) panic("get_zs whee chip not found"); @@ -2037,8 +2170,8 @@ rs_cons_check(struct sun_serial *ss, int channel) { int i, o, io; - static consout_registered = 0; - static msg_printed = 0; + static int consout_registered = 0; + static int msg_printed = 0; i = o = io = 0; @@ -2144,7 +2277,8 @@ __initfunc(int rs_init(void)) { - int chip, channel, brg, i, flags; + int chip, channel, brg, i; + unsigned long flags; struct sun_serial *info; char dummy; diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/sunserial.h linux/drivers/sbus/char/sunserial.h --- v2.1.33/linux/drivers/sbus/char/sunserial.h Fri Dec 13 01:37:37 1996 +++ linux/drivers/sbus/char/sunserial.h Mon Apr 14 09:31:09 1997 @@ -1,4 +1,4 @@ -/* $Id: sunserial.h,v 1.5 1996/10/16 13:13:41 zaitcev Exp $ +/* $Id: sunserial.h,v 1.9 1997/04/12 23:33:12 ecd Exp $ * serial.h: Definitions for the Sparc Zilog serial driver. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -68,9 +68,7 @@ #define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ #define ZILOG_SPD_MASK 0x0030 -#define ZILOG_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */ - -#define ZILOG_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */ +#define ZILOG_SPD_HI 0x0010 /* Use 76800 instead of 38400 bps */ #define ZILOG_SPD_CUST 0x0030 /* Use user-specified divisor */ #define ZILOG_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */ @@ -366,7 +364,7 @@ #define ZCOUNT 0x2 /* Zero count */ #define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ #define DCD 0x8 /* DCD */ -#define SYNC_HUNT 0x10 /* Sync/hunt */ +#define SYNC 0x10 /* Sync/hunt */ #define CTS 0x20 /* CTS */ #define TxEOM 0x40 /* Tx underrun */ #define BRK_ABRT 0x80 /* Break/Abort */ @@ -389,6 +387,15 @@ #define END_FR 0x80 /* End of Frame (SDLC) */ /* Read Register 2 (channel b only) - Interrupt vector */ +#define CHB_Tx_EMPTY 0x00 +#define CHB_EXT_STAT 0x02 +#define CHB_Rx_AVAIL 0x04 +#define CHB_SPECIAL 0x06 +#define CHA_Tx_EMPTY 0x08 +#define CHA_EXT_STAT 0x0a +#define CHA_Rx_AVAIL 0x0c +#define CHA_SPECIAL 0x0e +#define STATUS_MASK 0x0e /* Read Register 3 (interrupt pending register) ch a only */ #define CHBEXT 0x1 /* Channel B Ext/Stat IP */ @@ -414,6 +421,9 @@ /* Misc macros */ #define ZS_CLEARERR(channel) do { channel->control = ERR_RES; \ + udelay(5); } while(0) + +#define ZS_CLEARSTAT(channel) do { channel->control = RES_EXT_INT; \ udelay(5); } while(0) #define ZS_CLEARFIFO(channel) do { volatile unsigned char garbage; \ diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/tcx.c linux/drivers/sbus/char/tcx.c --- v2.1.33/linux/drivers/sbus/char/tcx.c Mon Dec 30 02:00:05 1996 +++ linux/drivers/sbus/char/tcx.c Fri Apr 11 10:47:37 1997 @@ -1,4 +1,4 @@ -/* $Id: tcx.c,v 1.9 1996/12/23 10:16:17 ecd Exp $ +/* $Id: tcx.c,v 1.11 1997/04/10 03:02:43 davem Exp $ * tcx.c: SUNW,tcx 24/8bit frame buffer driver * * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -272,7 +272,7 @@ tcx->bt->control |= 0x03 << 24; } -__initfunc(void tcx_setup (fbinfo_t *fb, int slot, int node, uint tcx, struct linux_sbus_device *sbdp)) +__initfunc(void tcx_setup (fbinfo_t *fb, int slot, int node, unsigned long tcx, struct linux_sbus_device *sbdp)) { struct tcx_info *tcxinfo; int i; @@ -299,15 +299,16 @@ tcxinfo->tcx_offsets [i] = (long)(sbdp->reg_addrs [i].phys_addr); /* Map the hardware registers */ - tcxinfo->bt = sparc_alloc_io ((void *) tcxinfo->tcx_offsets [TCX_BROOKTREE_OFFSET], 0, + tcxinfo->bt = sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_BROOKTREE_OFFSET], 0, sizeof (struct bt_regs),"tcx_dac", fb->space, 0); - tcxinfo->thc = sparc_alloc_io ((void *) tcxinfo->tcx_offsets [TCX_THC_OFFSET], 0, + tcxinfo->thc = sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_THC_OFFSET], 0, sizeof (struct tcx_thc), "tcx_thc", fb->space, 0); - tcxinfo->tec = sparc_alloc_io ((void *) tcxinfo->tcx_offsets [TCX_TEC_OFFSET], 0, + tcxinfo->tec = sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_TEC_OFFSET], 0, sizeof (struct tcx_tec), "tcx_tec", fb->space, 0); if (!fb->base){ - fb->base = (uint) sparc_alloc_io ((void *) tcxinfo->tcx_offsets [TCX_RAM8BIT_OFFSET], 0, - fb->type.fb_size, "tcx_ram", fb->space, 0); + fb->base = (uint) + sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_RAM8BIT_OFFSET], 0, + fb->type.fb_size, "tcx_ram", fb->space, 0); } if (prom_getbool (node, "hw-cursor")) { @@ -336,8 +337,10 @@ tcxinfo->tcx_sizes[5] = i << 3; tcxinfo->tcx_sizes[6] = i << 3; fb->type.fb_depth = 24; - tcxinfo->tcx_cplane = sparc_alloc_io ((void *) tcxinfo->tcx_offsets [TCX_CONTROLPLANE_OFFSET], 0, - tcxinfo->tcx_sizes [TCX_CONTROLPLANE_OFFSET], "tcx_cplane", fb->space, 0); + tcxinfo->tcx_cplane = + sparc_alloc_io((u32)tcxinfo->tcx_offsets[TCX_CONTROLPLANE_OFFSET], 0, + tcxinfo->tcx_sizes [TCX_CONTROLPLANE_OFFSET], + "tcx_cplane", fb->space, 0); } /* Initialize Brooktree DAC */ diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/vfc.h linux/drivers/sbus/char/vfc.h --- v2.1.33/linux/drivers/sbus/char/vfc.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sbus/char/vfc.h Fri Apr 11 10:47:37 1997 @@ -0,0 +1,171 @@ +#ifndef _LINUX_VFC_H_ +#define _LINUX_VFC_H_ + +/* + * The control register for the vfc is at offset 0x4000 + * The first field ram bank is located at offset 0x5000 + * The second field ram bank is at offset 0x7000 + * i2c_reg address the Phillips PCF8584(see notes in vfc_i2c.c) + * data and transmit register. + * i2c_s1 controls register s1 of the PCF8584 + * i2c_write seems to be similar to i2c_write but I am not + * quite sure why sun uses it + * + * I am also not sure whether or not you can read the fram bank as a + * whole or whether you must read each word individually from offset + * 0x5000 as soon as I figure it out I will update this file */ + +struct vfc_regs { + char pad1[0x4000]; + unsigned int control; /* Offset 0x4000 */ + char pad2[0xffb]; /* from offset 0x4004 to 0x5000 */ + unsigned int fram_bank1; /* Offset 0x5000 */ + char pad3[0xffb]; /* from offset 0x5004 to 0x6000 */ + unsigned int i2c_reg; /* Offset 0x6000 */ + unsigned int i2c_magic2; /* Offset 0x6004 */ + unsigned int i2c_s1; /* Offset 0x6008 */ + unsigned int i2c_write; /* Offset 0x600c */ + char pad4[0xff0]; /* from offset 0x6010 to 0x7000 */ + unsigned int fram_bank2; /* Offset 0x7000 */ + char pad5[0x1000]; +}; + +#define VFC_SAA9051_NR (13) +#define VFC_SAA9051_ADDR (0x8a) + /* The saa9051 returns the following for its status + * bit 0 - 0 + * bit 1 - SECAM color detected (1=found,0=not found) + * bit 2 - COLOR detected (1=found,0=not found) + * bit 3 - 0 + * bit 4 - Field frequency bit (1=60Hz (NTSC), 0=50Hz (PAL)) + * bit 5 - 1 + * bit 6 - horizontal frequency lock (1=transmitter found, + * 0=no transmitter) + * bit 7 - Power on reset bit (1=reset,0=at least one successful + * read of the status byte) + */ + +#define VFC_SAA9051_PONRES (0x80) +#define VFC_SAA9051_HLOCK (0x40) +#define VFC_SAA9051_FD (0x10) +#define VFC_SAA9051_CD (0x04) +#define VFC_SAA9051_CS (0x02) + + +/* The various saa9051 sub addresses */ + +#define VFC_SAA9051_IDEL (0) +#define VFC_SAA9051_HSY_START (1) +#define VFC_SAA9051_HSY_STOP (2) +#define VFC_SAA9051_HC_START (3) +#define VFC_SAA9051_HC_STOP (4) +#define VFC_SAA9051_HS_START (5) +#define VFC_SAA9051_HORIZ_PEAK (6) +#define VFC_SAA9051_HUE (7) +#define VFC_SAA9051_C1 (8) +#define VFC_SAA9051_C2 (9) +#define VFC_SAA9051_C3 (0xa) +#define VFC_SAA9051_SECAM_DELAY (0xb) + + +/* Bit settings for saa9051 sub address 0x06 */ + +#define VFC_SAA9051_AP1 (0x01) +#define VFC_SAA9051_AP2 (0x02) +#define VFC_SAA9051_COR1 (0x04) +#define VFC_SAA9051_COR2 (0x08) +#define VFC_SAA9051_BP1 (0x10) +#define VFC_SAA9051_BP2 (0x20) +#define VFC_SAA9051_PF (0x40) +#define VFC_SAA9051_BY (0x80) + + +/* Bit settings for saa9051 sub address 0x08 */ + +#define VFC_SAA9051_CCFR0 (0x01) +#define VFC_SAA9051_CCFR1 (0x02) +#define VFC_SAA9051_YPN (0x04) +#define VFC_SAA9051_ALT (0x08) +#define VFC_SAA9051_CO (0x10) +#define VFC_SAA9051_VTR (0x20) +#define VFC_SAA9051_FS (0x40) +#define VFC_SAA9051_HPLL (0x80) + + +/* Bit settings for saa9051 sub address 9 */ + +#define VFC_SAA9051_SS0 (0x01) +#define VFC_SAA9051_SS1 (0x02) +#define VFC_SAA9051_AFCC (0x04) +#define VFC_SAA9051_CI (0x08) +#define VFC_SAA9051_SA9D4 (0x10) /* Don't care bit */ +#define VFC_SAA9051_OEC (0x20) +#define VFC_SAA9051_OEY (0x40) +#define VFC_SAA9051_VNL (0x80) + + +/* Bit settings for saa9051 sub address 0x0A */ + +#define VFC_SAA9051_YDL0 (0x01) +#define VFC_SAA9051_YDL1 (0x02) +#define VFC_SAA9051_YDL2 (0x04) +#define VFC_SAA9051_SS2 (0x08) +#define VFC_SAA9051_SS3 (0x10) +#define VFC_SAA9051_YC (0x20) +#define VFC_SAA9051_CT (0x40) +#define VFC_SAA9051_SYC (0x80) + + +#define VFC_SAA9051_SA(a,b) ((a)->saa9051_state_array[(b)+1]) +#define vfc_update_saa9051(a) (vfc_i2c_sendbuf((a),VFC_SAA9051_ADDR,\ + (a)->saa9051_state_array,\ + VFC_SAA9051_NR)) + + +struct vfc_dev { + volatile struct vfc_regs *regs; + struct vfc_regs *phys_regs; + unsigned int control_reg; + struct semaphore device_lock_sem; + struct timer_list poll_timer; + struct wait_queue *poll_wait; + int instance; + int busy; + unsigned long which_io; + unsigned char saa9051_state_array[VFC_SAA9051_NR]; +}; + +extern struct vfc_dev **vfc_dev_lst; + +void captstat_reset(struct vfc_dev *); +void memptr_reset(struct vfc_dev *); + +int vfc_pcf8584_init(struct vfc_dev *); +void vfc_i2c_delay_no_busy(struct vfc_dev *, unsigned long); +void vfc_i2c_delay(struct vfc_dev *); +int vfc_i2c_sendbuf(struct vfc_dev *, unsigned char, char *, int) ; +int vfc_i2c_recvbuf(struct vfc_dev *, unsigned char, char *, int) ; +int vfc_i2c_reset_bus(struct vfc_dev *); +int vfc_init_i2c_bus(struct vfc_dev *); +void vfc_lock_device(struct vfc_dev *); +void vfc_unlock_device(struct vfc_dev *); + +#define VFC_CONTROL_DIAGMODE 0x10000000 +#define VFC_CONTROL_MEMPTR 0x20000000 +#define VFC_CONTROL_CAPTURE 0x02000000 +#define VFC_CONTROL_CAPTRESET 0x04000000 + +#define VFC_STATUS_CAPTURE 0x08000000 + +#ifdef VFC_DEBUG +#define VFC_DEBUG_PRINTK(a) printk a +#else +#define VFC_DEBUG_PRINTK(a) +#endif + +#endif /* _LINUX_VFC_H_ */ + + + + + diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/vfc_dev.c linux/drivers/sbus/char/vfc_dev.c --- v2.1.33/linux/drivers/sbus/char/vfc_dev.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sbus/char/vfc_dev.c Fri Apr 11 10:47:37 1997 @@ -0,0 +1,693 @@ +/* + * drivers/sbus/char/vfc_dev.c + * + * Driver for the Videopix Frame Grabber. + * + * In order to use the VFC you need to progeam the video controller + * chip. This chip is the Phillips SAA9051. You need to call their + * documentation ordering line to get the docs. + * + * Their is very little documentation on the VFC itself. There is + * some useful info that can be found in the manuals that come with + * the card. I will hopefully write some better docs at a later date. + * + * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu) + * */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VFC_MAJOR (60) + +#if 0 +#define VFC_DEBUG +#endif + +#include "vfc.h" +#include + +struct vfc_dev **vfc_dev_lst; +static char vfcstr[]="vfc"; +static unsigned char saa9051_init_array[VFC_SAA9051_NR]= +{ 0x00, 0x64, 0x72, 0x52, + 0x36, 0x18, 0xff, 0x20, + 0xfc, 0x77, 0xe3, 0x50, + 0x3e}; + +void vfc_lock_device(struct vfc_dev *dev) { + down(&dev->device_lock_sem); +} + +void vfc_unlock_device(struct vfc_dev *dev) { + up(&dev->device_lock_sem); +} + + +void vfc_captstat_reset(struct vfc_dev *dev) +{ + dev->control_reg |= VFC_CONTROL_CAPTRESET; + dev->regs->control=dev->control_reg; + dev->control_reg &= ~VFC_CONTROL_CAPTRESET; + dev->regs->control=dev->control_reg; + dev->control_reg |= VFC_CONTROL_CAPTRESET; + dev->regs->control=dev->control_reg; + return; +} + +void vfc_memptr_reset(struct vfc_dev *dev) +{ + dev->control_reg |= VFC_CONTROL_MEMPTR; + dev->regs->control = dev->control_reg; + dev->control_reg &= ~VFC_CONTROL_MEMPTR; + dev->regs->control = dev->control_reg; + dev->control_reg |= VFC_CONTROL_MEMPTR; + dev->regs->control = dev->control_reg; + return; +} + +int vfc_csr_init(struct vfc_dev *dev) +{ + dev->control_reg = 0x80000000; + dev->regs->control = dev->control_reg; + udelay(200); + dev->control_reg &= ~0x80000000; + dev->regs->control = dev->control_reg; + udelay(100); + dev->regs->i2c_magic2 = 0x0f000000; + + vfc_memptr_reset(dev); + + dev->control_reg &= ~VFC_CONTROL_DIAGMODE; + dev->control_reg &= ~VFC_CONTROL_CAPTURE; + dev->control_reg |= 0x40000000; + dev->regs->control=dev->control_reg; + + vfc_captstat_reset(dev); + + return 0; +} + +int vfc_saa9051_init(struct vfc_dev *dev) +{ + int i; + for(i=0;isaa9051_state_array[i]=saa9051_init_array[i]; + } + vfc_i2c_sendbuf(dev,VFC_SAA9051_ADDR, + dev->saa9051_state_array, VFC_SAA9051_NR); + return 0; +} + +int init_vfc_hw(struct vfc_dev *dev) +{ + vfc_lock_device(dev); + vfc_csr_init(dev); + + vfc_pcf8584_init(dev); + vfc_init_i2c_bus(dev); /* hopefully this doesn't undo the magic + sun code above*/ + vfc_saa9051_init(dev); + vfc_unlock_device(dev); + return 0; +} + +int init_vfc_devstruct(struct vfc_dev *dev, int instance) +{ + dev->instance=instance; + dev->device_lock_sem=MUTEX; + dev->control_reg=0; + dev->poll_wait=NULL; + dev->busy=0; + /* initialize the timer struct */ + return 0; +} + +int init_vfc_device(struct linux_sbus_device *sdev,struct vfc_dev *dev, + int instance) { + struct linux_prom_registers reg; + if(!dev) { + printk(KERN_ERR "VFC: Bogus pointer passed\n"); + return -ENOMEM; + } + printk("Initializing vfc%d\n",instance); + dev->regs=NULL; + memcpy(®,&sdev->reg_addrs[0],sizeof(struct linux_prom_registers)); + prom_apply_sbus_ranges(sdev->my_bus, ®, sdev->num_registers, sdev); + dev->regs=sparc_alloc_io(reg.phys_addr, 0, + sizeof(struct vfc_regs), vfcstr, + reg.which_io, 0x0); + dev->which_io=reg.which_io; + dev->phys_regs=(struct vfc_regs *)reg.phys_addr; + if(!dev->regs) return -EIO; + + printk("vfc%d: registers mapped at phys_addr: 0x%lx\n virt_addr: 0x%lx\n", + instance,(unsigned long)reg.phys_addr,(unsigned long)dev->regs); + + if(init_vfc_devstruct(dev,instance)) return -EINVAL; + if(init_vfc_hw(dev)) return -EIO; + + return 0; +} + + +struct vfc_dev *vfc_get_dev_ptr(int instance) +{ + return vfc_dev_lst[instance]; +} + +static int vfc_open(struct inode *inode, struct file *file) +{ + struct vfc_dev *dev; + dev=vfc_get_dev_ptr(MINOR(inode->i_rdev)); + if(!dev) return -ENODEV; + if(dev->busy) return -EBUSY; + dev->busy=1; + MOD_INC_USE_COUNT; + vfc_lock_device(dev); + + vfc_csr_init(dev); + vfc_pcf8584_init(dev); + vfc_init_i2c_bus(dev); + vfc_saa9051_init(dev); + vfc_memptr_reset(dev); + vfc_captstat_reset(dev); + + vfc_unlock_device(dev); + return 0; +} + +static int vfc_release(struct inode *inode,struct file *file) +{ + struct vfc_dev *dev; + dev=vfc_get_dev_ptr(MINOR(inode->i_rdev)); + if(!dev) return -EINVAL; + if(!dev->busy) return 0; + dev->busy=0; + MOD_DEC_USE_COUNT; + return 0; +} + +static int vfc_debug(struct vfc_dev *dev, int cmd, unsigned long arg) +{ + struct vfc_debug_inout inout; + unsigned char *buffer; + + switch(cmd) { + case VFC_I2C_SEND: + if(copy_from_user(&inout, (void *)arg, sizeof(inout))) + return -EFAULT; + + buffer = kmalloc(inout.len*sizeof(char), GFP_KERNEL); + if (!buffer) + return -ENOMEM; + if(copy_from_user(buffer, inout.buffer, inout.len*sizeof(char))) { + kfree_s(buffer,inout.len); + return -EFAULT; + } + + vfc_lock_device(dev); + inout.ret= + vfc_i2c_sendbuf(dev,inout.addr & 0xff, + inout.buffer,inout.len); + if(copy_to_user((void *)arg,&inout,sizeof(inout))) { + kfree_s(buffer,inout.len); + return -EFAULT; + } + vfc_unlock_device(dev); + + kfree_s(buffer, inout.len); + + break; + case VFC_I2C_RECV: + + if(copy_from_user(&inout, (void *)arg, sizeof(inout))) + return -EFAULT; + + buffer = kmalloc(inout.len, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + memset(buffer,0,inout.len*sizeof(char)); + vfc_lock_device(dev); + inout.ret= + vfc_i2c_recvbuf(dev,inout.addr & 0xff + ,buffer,inout.len); + vfc_unlock_device(dev); + + if(copy_to_user(inout.buffer, buffer, inout.len)) { + kfree_s(buffer,inout.len); + return -EFAULT; + } + if(copy_to_user((void *)arg,&inout,sizeof(inout))) { + kfree_s(buffer,inout.len); + return -EFAULT; + } + kfree_s(buffer,inout.len); + break; + default: + return -EINVAL; + } + return 0; +} + +int vfc_capture_start(struct vfc_dev *dev) +{ + vfc_captstat_reset(dev); + dev->control_reg=dev->regs->control; + if((dev->control_reg & VFC_STATUS_CAPTURE)) { + printk(KERN_ERR "vfc%d: vfc capture status not reset\n", + dev->instance); + return -EIO; + } + + vfc_lock_device(dev); + dev->control_reg &= ~VFC_CONTROL_CAPTURE; + dev->regs->control=dev->control_reg; + dev->control_reg |= VFC_CONTROL_CAPTURE; + dev->regs->control=dev->control_reg; + dev->control_reg &= ~VFC_CONTROL_CAPTURE; + dev->regs->control=dev->control_reg; + vfc_unlock_device(dev); + + return 0; +} + +int vfc_capture_poll(struct vfc_dev *dev) +{ + int timeout=1000; + while(!timeout--) { + if((dev->regs->control & VFC_STATUS_CAPTURE)) break; + vfc_i2c_delay_no_busy(dev,100); + } + if(!timeout) { + printk(KERN_WARNING "vfc%d: capture timed out\n", dev->instance); + return -ETIMEDOUT; + } + return 0; +} + + + +static int vfc_set_control_ioctl(struct inode *inode, struct file *file, + struct vfc_dev *dev, unsigned long arg) +{ + int setcmd,ret=0; + if(copy_from_user(&setcmd,(void *)arg,sizeof(unsigned int))) + return -EFAULT; +#if 0 + VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n", + dev->instance,setcmd)); +#endif + switch(setcmd) { + case MEMPRST: + vfc_lock_device(dev); + vfc_memptr_reset(dev); + vfc_unlock_device(dev); + ret=0; + break; + case CAPTRCMD: + vfc_capture_start(dev); + vfc_capture_poll(dev); + break; + case DIAGMODE: + if(suser()) { + vfc_lock_device(dev); + dev->control_reg |= VFC_CONTROL_DIAGMODE; + dev->regs->control = dev->control_reg; + vfc_unlock_device(dev); + ret=0; + } else ret=-EPERM; + break; + case NORMMODE: + vfc_lock_device(dev); + dev->control_reg &= ~VFC_CONTROL_DIAGMODE; + dev->regs->control = dev->control_reg; + vfc_unlock_device(dev); + ret=0; + break; + case CAPTRSTR: + vfc_capture_start(dev); + ret=0; + break; + case CAPTRWAIT: + vfc_capture_poll(dev); + ret=0; + break; + default: + ret=-EINVAL; + } + return ret; +} + + +int vfc_port_change_ioctl(struct inode *inode, struct file *file, + struct vfc_dev *dev, unsigned long arg) +{ + int ret=0; + int cmd; + if(copy_from_user(&cmd, (void *)arg, sizeof(unsigned int))) { + VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " + "vfc_port_change_ioctl\n",dev->instance)); + return -EFAULT; + } + + VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n", + dev->instance,cmd)); + + switch(cmd) { + case 1: + case 2: + VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x72; + VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x52; + VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0x36; + VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0x18; + VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) = VFC_SAA9051_BP2; + VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_CT | VFC_SAA9051_SS3; + VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0x3e; + break; + case 3: + VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x3a; + VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x17; + VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0xfa; + VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0xde; + VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) = VFC_SAA9051_BY | VFC_SAA9051_PF | VFC_SAA9051_BP2; + VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_YC; + VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0; + VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &= ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1); + break; + default: + ret=-EINVAL; + return ret; + break; + } + + switch(cmd) { + case 1: + VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |= VFC_SAA9051_SS0 | VFC_SAA9051_SS1; + break; + case 2: + VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &= ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1); + VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |= VFC_SAA9051_SS0; + break; + case 3: + break; + default: + ret=-EINVAL; + return ret; + break; + } + VFC_SAA9051_SA(dev,VFC_SAA9051_C3) &= ~(VFC_SAA9051_SS2); + ret=vfc_update_saa9051(dev); + udelay(500); + VFC_SAA9051_SA(dev,VFC_SAA9051_C3) |= (VFC_SAA9051_SS2); + ret=vfc_update_saa9051(dev); + return ret; +} + +int vfc_set_video_ioctl(struct inode *inode, struct file *file, + struct vfc_dev *dev, unsigned long arg) +{ + int ret=0; + int cmd; + if(copy_from_user(&cmd, (void *)arg, sizeof(unsigned int))) { + VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " + "vfc_set_video_ioctl\n",dev->instance)); + return -EFAULT; + } + + VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n", + dev->instance,cmd)); + switch(cmd) { + + case STD_NTSC: + VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~VFC_SAA9051_ALT; + VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_YPN | + VFC_SAA9051_CCFR0 | VFC_SAA9051_CCFR1 | VFC_SAA9051_FS; + ret=vfc_update_saa9051(dev); + break; + case STD_PAL: + VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_YPN | + VFC_SAA9051_CCFR1 | + VFC_SAA9051_CCFR0 | + VFC_SAA9051_FS); + VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_ALT; + ret=vfc_update_saa9051(dev); + break; + + case COLOR_ON: + VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_CO; + VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) &= ~(VFC_SAA9051_BY | VFC_SAA9051_PF); + ret=vfc_update_saa9051(dev); + break; + case MONO: + VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_CO); + VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) |= VFC_SAA9051_BY | VFC_SAA9051_PF; + ret=vfc_update_saa9051(dev); + break; + default: + ret=-EINVAL; + break; + } + return ret; +} + +int vfc_get_video_ioctl(struct inode *inode, struct file *file, + struct vfc_dev *dev, unsigned long arg) +{ + int ret=0; + unsigned int status=NO_LOCK; + unsigned char buf[1]; + + if(vfc_i2c_recvbuf(dev,VFC_SAA9051_ADDR,buf,1)) { + printk(KERN_ERR "vfc%d: Unable to get status\n",dev->instance); + return -EIO; + } + + if(buf[0] & VFC_SAA9051_HLOCK) { + status = NO_LOCK; + } else if(buf[0] & VFC_SAA9051_FD) { + if(buf[0] & VFC_SAA9051_CD) + status=NTSC_COLOR; + else + status=NTSC_NOCOLOR; + } else { + if(buf[0] & VFC_SAA9051_CD) + status=PAL_COLOR; + else + status=PAL_NOCOLOR; + } + VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; buf[0]=%x\n",dev->instance, + status,buf[0])); + if(copy_to_user((void *)arg,&status,sizeof(unsigned int))) { + VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " + "vfc_get_video_ioctl\n",dev->instance)); + return -EFAULT; + } + return ret; +} + +static int vfc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret=0; + unsigned int tmp; + struct vfc_dev *dev; + + dev=vfc_get_dev_ptr(MINOR(inode->i_rdev)); + if(!dev) return -ENODEV; + + switch(cmd & 0x0000ffff) { + case VFCGCTRL: +#if 0 + VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n",dev->instance)); +#endif + tmp=dev->regs->control; + if(copy_to_user((void *)arg,&tmp,sizeof(unsigned int))) + return -EFAULT; + ret=0; + break; + case VFCSCTRL: + ret=vfc_set_control_ioctl(inode, file, dev, arg); + break; + case VFCGVID: + ret=vfc_get_video_ioctl(inode,file,dev,arg); + break; + case VFCSVID: + ret=vfc_set_video_ioctl(inode,file,dev,arg); + break; + case VFCHUE: +#if 0 + VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n",dev->instance)); +#endif + + if(copy_from_user(&tmp,(void *)arg,sizeof(unsigned int))) { + VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer " + "to IOCTL(VFCHUE)",dev->instance)); + ret=-EFAULT; + } else { + VFC_SAA9051_SA(dev,VFC_SAA9051_HUE)=tmp; + vfc_update_saa9051(dev); + ret=0; + } + break; + case VFCPORTCHG: + ret=vfc_port_change_ioctl(inode, file, dev, arg); + break; + case VFCRDINFO: + ret=-EINVAL; + VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n",dev->instance)); + break; + default: + ret=vfc_debug(vfc_get_dev_ptr(MINOR(inode->i_rdev)), + cmd,arg); + break; + } + return ret; +} + +static int vfc_mmap(struct inode *inode, struct file *file, + struct vm_area_struct *vma) +{ + unsigned int map_size,ret,map_offset; + struct vfc_dev *dev; + + dev=vfc_get_dev_ptr(MINOR(inode->i_rdev)); + if(!dev) return -ENODEV; + + map_size=vma->vm_end - vma->vm_start; + if(map_size > sizeof(struct vfc_regs)) + map_size=sizeof(struct vfc_regs); + + + if(vma->vm_offset & ~PAGE_MASK) return -ENXIO; + vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO | VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE; + map_offset=(unsigned int)dev->phys_regs; + ret=io_remap_page_range(vma->vm_start,map_offset,map_size, + vma->vm_page_prot, dev->which_io); + if(ret) return -EAGAIN; + vma->vm_inode=inode; + inode->i_count++; + return 0; +} + +static long long vfc_lseek(struct inode *inode, struct file *file, + long long offset, int origin) +{ + return -ESPIPE; +} + +static struct file_operations vfc_fops = { + vfc_lseek, /* vfc_lseek */ + NULL, /* vfc_write */ + NULL, /* vfc_read */ + NULL, /* vfc_readdir */ + NULL, /* vfc_poll */ + vfc_ioctl, + vfc_mmap, + vfc_open, + vfc_release, +}; + + +static int vfc_probe(void) +{ + struct linux_sbus *bus; + struct linux_sbus_device *sdev = NULL; + int ret; + int instance=0,cards=0; + + for_all_sbusdev(sdev,bus) { + if (strcmp(sdev->prom_name,"vfc") == 0) { + cards++; + continue; + } + } + + if (!cards) + return -ENODEV; + + vfc_dev_lst=(struct vfc_dev **)kmalloc(sizeof(struct vfc_dev *)* + (cards+1), + GFP_KERNEL); + if(!vfc_dev_lst) + return -ENOMEM; + memset(vfc_dev_lst,0,sizeof(struct vfc_dev *)*(cards+1)); + vfc_dev_lst[cards]=NULL; + + ret=register_chrdev(VFC_MAJOR,vfcstr,&vfc_fops); + if(ret) { + printk(KERN_ERR "Unable to get major number %d\n",VFC_MAJOR); + kfree(vfc_dev_lst); + return -EIO; + } + + instance=0; + for_all_sbusdev(sdev,bus) { + if (strcmp(sdev->prom_name,"vfc") == 0) { + vfc_dev_lst[instance]=(struct vfc_dev *) + kmalloc(sizeof(struct vfc_dev), GFP_KERNEL); + if(vfc_dev_lst[instance] == NULL) return -ENOMEM; + ret=init_vfc_device(sdev, + vfc_dev_lst[instance], + instance); + if(ret) { + printk(KERN_ERR "Unable to initialize" + " vfc%d device\n",instance); + } else { + } + + instance++; + continue; + } + } + + return 0; +} + +#ifdef MODULE +int init_module(void) +#else +int vfc_init(void) +#endif +{ +#ifdef MODULE + register_symtab(0); +#endif + return vfc_probe(); +} + +#ifdef MODULE +static void deinit_vfc_device(struct vfc_dev *dev) +{ + if(!dev) return; + sparc_free_io((void *)dev->regs,sizeof(struct vfc_regs)); + kfree(dev); +} + +void cleanup_module(void) +{ + struct vfc_dev **devp; + unregister_chrdev(VFC_MAJOR,vfcstr); + for(devp=vfc_dev_lst;*devp;devp++) { + deinit_vfc_device(*devp); + } + kfree(vfc_dev_lst); + return; +} +#endif + + diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/vfc_i2c.c linux/drivers/sbus/char/vfc_i2c.c --- v2.1.33/linux/drivers/sbus/char/vfc_i2c.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sbus/char/vfc_i2c.c Fri Apr 11 10:47:37 1997 @@ -0,0 +1,319 @@ +/* + * drivers/sbus/char/vfc_i2c.c + * + * Driver for the Videopix Frame Grabber. + * + * Functions that support the Phillips i2c(I squared C) bus on the vfc + * Documentation for the Phillips I2C bus can be found on the + * phillips home page + * + * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu) + * + */ + +/* NOTE: It seems to me that the documentation regarding the +pcd8584t/pcf8584 does not show the correct way to address the i2c bus. +Based on the information on the I2C bus itself and the remainder of +the Phillips docs the following algorithims apper to be correct. I am +fairly certain that the flowcharts in the phillips docs are wrong. */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define VFC_DEBUG +#endif + +#include "vfc.h" +#include "vfc_i2c.h" + +#define VFC_I2C_READ (0x1) +#define VFC_I2C_WRITE (0x0) + +/****** + The i2c bus controller chip on the VFC is a pcd8584t, but + phillips claims it doesn't exist. As far as I can tell it is + identical to the PCF8584 so I treat it like it is the pcf8584. + + NOTE: The pcf8584 only cares + about the msb of the word you feed it +*****/ + +int vfc_pcf8584_init(struct vfc_dev *dev) +{ + dev->regs->i2c_s1=RESET; /* This will also choose + register S0_OWN so we can set it*/ + + dev->regs->i2c_reg=0x55000000; /* the pcf8584 shifts this + value left one bit and uses + it as its i2c bus address */ + dev->regs->i2c_s1=SELECT(S2); + dev->regs->i2c_reg=0x14000000; /* this will set the i2c bus at + the same speed sun uses, + and set another magic bit */ + + dev->regs->i2c_s1=CLEAR_I2C_BUS; /* enable the serial port, + idle the i2c bus and set + the data reg to s0 */ + udelay(100); + return 0; +} + +void vfc_i2c_delay_wakeup(struct vfc_dev *dev) +{ + wake_up(&dev->poll_wait); +} + +void vfc_i2c_delay_no_busy(struct vfc_dev *dev,unsigned long usecs) +{ + dev->poll_timer.next = NULL; + dev->poll_timer.prev = NULL; + dev->poll_timer.expires = jiffies + + ((unsigned long)usecs*(HZ))/1000000; + dev->poll_timer.data=(unsigned long)dev; + dev->poll_timer.function=(void *)(unsigned long)vfc_i2c_delay_wakeup; + add_timer(&dev->poll_timer); + sleep_on(&dev->poll_wait); + del_timer(&dev->poll_timer); +} + +void inline vfc_i2c_delay(struct vfc_dev *dev) +{ + vfc_i2c_delay_no_busy(dev,100); +} + +int vfc_init_i2c_bus(struct vfc_dev *dev) +{ + dev->regs->i2c_s1= ENABLE_SERIAL | ACK; + vfc_i2c_reset_bus(dev); + return 0; +} + +int vfc_i2c_reset_bus(struct vfc_dev *dev) +{ + VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: Resetting the i2c bus\n", + dev->instance)); + if(!dev) return -EINVAL; + if(!dev->regs) return -EINVAL; + dev->regs->i2c_s1=SEND_I2C_STOP; + dev->regs->i2c_s1=SEND_I2C_STOP | ACK; + vfc_i2c_delay(dev); + dev->regs->i2c_s1=CLEAR_I2C_BUS; + VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: I2C status %x\n", + dev->instance, dev->regs->i2c_s1)); + return 0; +} + +int vfc_i2c_wait_for_bus(struct vfc_dev *dev) +{ + int timeout=1000; + + while(!(dev->regs->i2c_s1 & BB)) { + if(!(timeout--)) return -ETIMEDOUT; + vfc_i2c_delay(dev); + } + return 0; +} + +int vfc_i2c_wait_for_pin(struct vfc_dev *dev, int ack) +{ + int timeout=1000; + int s1; + + while((s1=dev->regs->i2c_s1) & PIN) { + if(!(timeout--)) return -ETIMEDOUT; + vfc_i2c_delay(dev); + } + if(ack==VFC_I2C_ACK_CHECK) { + if(s1 & LRB) return -EIO; + } + return 0; +} + +#define SHIFT(a) ((a) << 24) +int vfc_i2c_xmit_addr(struct vfc_dev *dev, unsigned char addr, char mode) +{ + int ret,raddr; +#if 1 + dev->regs->i2c_s1=SEND_I2C_STOP; + dev->regs->i2c_s1=SELECT(S0) | ENABLE_SERIAL; + vfc_i2c_delay(dev); +#endif + + switch(mode) { + case VFC_I2C_READ: + dev->regs->i2c_reg=raddr=SHIFT((unsigned int)addr | 0x1); + VFC_DEBUG_PRINTK(("vfc%d: recieving from i2c addr 0x%x\n", + dev->instance,addr | 0x1)); + break; + case VFC_I2C_WRITE: + dev->regs->i2c_reg=raddr=SHIFT((unsigned int)addr & ~0x1); + VFC_DEBUG_PRINTK(("vfc%d: sending to i2c addr 0x%x\n", + dev->instance,addr & ~0x1)); + break; + default: + return -EINVAL; + } + dev->regs->i2c_s1 = SEND_I2C_START; + vfc_i2c_delay(dev); + ret=vfc_i2c_wait_for_pin(dev,VFC_I2C_ACK_CHECK); /* We wait + for the + i2c send + to finish + here but + Sun + doesn't, + hmm */ + if(ret) { + printk(KERN_ERR "vfc%d: VFC xmit addr timed out or no ack\n", + dev->instance); + return ret; + } else if(mode == VFC_I2C_READ) { + if((ret=dev->regs->i2c_reg & 0xff000000) != raddr) { + printk(KERN_WARNING + "vfc%d: returned slave address " + "mismatch(%x,%x)\n", + dev->instance,raddr,ret); + } + } + return 0; +} + +int vfc_i2c_xmit_byte(struct vfc_dev *dev,unsigned char *byte) +{ + int ret; + dev->regs->i2c_reg=SHIFT((unsigned int)*byte); + + ret=vfc_i2c_wait_for_pin(dev,VFC_I2C_ACK_CHECK); + switch(ret) { + case -ETIMEDOUT: + printk(KERN_ERR "vfc%d: VFC xmit byte timed out or no ack\n", + dev->instance); + break; + case -EIO: + ret=XMIT_LAST_BYTE; + break; + default: + break; + } + return ret; +} + +int vfc_i2c_recv_byte(struct vfc_dev *dev, unsigned char *byte, int last) +{ + int ret; + if(last) { + dev->regs->i2c_reg=NEGATIVE_ACK; + VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: sending negative ack\n", + dev->instance)); + } else { + dev->regs->i2c_s1=ACK; + } + + ret=vfc_i2c_wait_for_pin(dev,VFC_I2C_NO_ACK_CHECK); + if(ret) { + printk(KERN_ERR "vfc%d: " + "VFC recv byte timed out\n",dev->instance); + } + *byte=(dev->regs->i2c_reg) >> 24; + return ret; +} + +int vfc_i2c_recvbuf(struct vfc_dev *dev, unsigned char addr, + char *buf, int count) +{ + int ret,last; + + if(!(count && buf && dev && dev->regs) ) return -EINVAL; + + if((ret=vfc_i2c_wait_for_bus(dev))) { + printk(KERN_ERR "vfc%d: VFC I2C bus busy\n",dev->instance); + return ret; + } + + if((ret=vfc_i2c_xmit_addr(dev,addr,VFC_I2C_READ))) { + dev->regs->i2c_s1=SEND_I2C_STOP; + vfc_i2c_delay(dev); + return ret; + } + + last=0; + while(count--) { + if(!count) last=1; + if((ret=vfc_i2c_recv_byte(dev,buf,last))) { + printk(KERN_ERR "vfc%d: " + "VFC error while recieving byte\n", + dev->instance); + } + buf++; + } + + dev->regs->i2c_s1=SEND_I2C_STOP | ACK; + vfc_i2c_delay(dev); + return ret; +} + +int vfc_i2c_sendbuf(struct vfc_dev *dev, unsigned char addr, + char *buf, int count) +{ + int ret; + + if(!(buf && dev && dev->regs) ) return -EINVAL; + + if((ret=vfc_i2c_wait_for_bus(dev))) { + printk(KERN_ERR "vfc%d: VFC I2C bus busy\n",dev->instance); + return ret; + } + + if((ret=vfc_i2c_xmit_addr(dev,addr,VFC_I2C_WRITE))) { + dev->regs->i2c_s1=SEND_I2C_STOP; + vfc_i2c_delay(dev); + return ret; + } + + while(count--) { + ret=vfc_i2c_xmit_byte(dev,buf); + switch(ret) { + case XMIT_LAST_BYTE: + VFC_DEBUG_PRINTK(("vfc%d: " + "Reciever ended transmission with " + " %d bytes remaining\n", + dev->instance,count)); + ret=0; + goto done; + break; + case 0: + break; + default: + printk(KERN_ERR "vfc%d: " + "VFC error while sending byte\n",dev->instance); + break; + } + buf++; + } +done: + dev->regs->i2c_s1=SEND_I2C_STOP | ACK; + + vfc_i2c_delay(dev); + return ret; +} + + + + + + + + + diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/vfc_i2c.h linux/drivers/sbus/char/vfc_i2c.h --- v2.1.33/linux/drivers/sbus/char/vfc_i2c.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sbus/char/vfc_i2c.h Fri Apr 11 10:47:37 1997 @@ -0,0 +1,44 @@ +#ifndef _LINUX_VFC_I2C_H_ +#define _LINUX_VFC_I2C_H_ + +/* control bits */ +#define PIN (0x80000000) +#define ESO (0x40000000) +#define ES1 (0x20000000) +#define ES2 (0x10000000) +#define ENI (0x08000000) +#define STA (0x04000000) +#define STO (0x02000000) +#define ACK (0x01000000) + +/* status bits */ +#define STS (0x20000000) +#define BER (0x10000000) +#define LRB (0x08000000) +#define AAS (0x04000000) +#define LAB (0x02000000) +#define BB (0x01000000) + +#define SEND_I2C_START (PIN | ESO | STA) +#define SEND_I2C_STOP (PIN | ESO | STO) +#define CLEAR_I2C_BUS (PIN | ESO | ACK) +#define NEGATIVE_ACK ((ESO) & ~ACK) + +#define SELECT(a) (a) +#define S0 (PIN | ESO | ES1) +#define S0_OWN (PIN) +#define S2 (PIN | ES1) +#define S3 (PIN | ES2) + +#define ENABLE_SERIAL (PIN | ESO) +#define DISABLE_SERIAL (PIN) +#define RESET (PIN) + +#define XMIT_LAST_BYTE (1) +#define VFC_I2C_ACK_CHECK (1) +#define VFC_I2C_NO_ACK_CHECK (0) + +#endif /* _LINUX_VFC_I2C_H_ */ + + + diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/weitek.c linux/drivers/sbus/char/weitek.c --- v2.1.33/linux/drivers/sbus/char/weitek.c Mon Dec 30 02:00:05 1996 +++ linux/drivers/sbus/char/weitek.c Fri Apr 11 10:47:37 1997 @@ -1,4 +1,4 @@ -/* $Id: weitek.c,v 1.7 1996/12/23 10:16:18 ecd Exp $ +/* $Id: weitek.c,v 1.8 1997/03/24 17:44:26 jj Exp $ * weitek.c: Tadpole P9100/P9000 console driver * * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk) @@ -95,11 +95,11 @@ } #endif -__initfunc(void weitek_setup(fbinfo_t *fb, int slot, uint addr, int io)) +__initfunc(void weitek_setup(fbinfo_t *fb, int slot, unsigned long addr, int io)) { extern struct screen_info screen_info; - printk ("weitek%d at 0x%8.8x\n", slot, addr); + printk ("weitek%d at 0x%8.8x\n", slot, (uint)addr); /* Fill in parameters we left out */ fb->type.fb_type = FBTYPE_NOTSUN1; @@ -114,4 +114,3 @@ prom_printf ("Missing mapping routine and no address found\n"); } } - diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/dvma.c linux/drivers/sbus/dvma.c --- v2.1.33/linux/drivers/sbus/dvma.c Thu Mar 27 14:40:05 1997 +++ linux/drivers/sbus/dvma.c Fri Apr 11 10:47:37 1997 @@ -110,7 +110,8 @@ printk("Revision 1 PLUS "); break; default: - printk("unknown dma version"); + printk("unknown dma version %x", + (dma->regs->cond_reg)&DMA_DEVICE_ID); dma->allocated = 1; break; } diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c --- v2.1.33/linux/drivers/sbus/sbus.c Thu Mar 27 14:40:05 1997 +++ linux/drivers/sbus/sbus.c Fri Apr 11 10:47:38 1997 @@ -35,6 +35,7 @@ */ /* #define DEBUG_FILL */ + __initfunc(static void fill_sbus_device(int nd, struct linux_sbus_device *sbus_dev)) { @@ -63,7 +64,9 @@ sbus_dev->ranges_applied = 0; base = (unsigned long) sbus_dev->reg_addrs[0].phys_addr; - if(base>=SUN_SBUS_BVADDR || sparc_cpu_model == sun4m) { + if(base>=SUN_SBUS_BVADDR || + sparc_cpu_model == sun4m || + sparc_cpu_model == sun4u) { /* Ahh, we can determine the slot and offset */ sbus_dev->slot = sbus_dev_slot(base); sbus_dev->offset = sbus_dev_offset(base); @@ -80,7 +83,6 @@ /* That surely sucked */ } sbus_dev->sbus_addr = (unsigned long) sbus_dev->reg_addrs[0].phys_addr; - if(len>(sizeof(struct linux_prom_registers)*PROMREG_MAX)) { prom_printf("WHOOPS: I got too many register addresses for %s len=%d\n", sbus_dev->prom_name, len); @@ -98,39 +100,58 @@ } sbus_dev->num_vaddrs = (len/4); - len = prom_getproperty(nd, "intr", (void *)sbus_dev->irqs, - sizeof(sbus_dev->irqs)); - if (len == -1) len=0; - if (len&7) { - prom_printf("Grrr, I didn't get a multiple of 8 proplen for " - "device %s got %d\n", sbus_dev->prom_name, len); - len=0; - } - sbus_dev->num_irqs=(len/8); -#if OLD_STYLE_IRQ - /* Grrr, V3 prom tries to be efficient */ - for(len=0; lennum_irqs; len++) { - sbus_dev->irqs[len].pri &= 0xf; + if(sparc_cpu_model == sun4u) { + len = prom_getproperty(nd, "interrupts", (void *)&sbus_dev->irqs[0].pri, + sizeof(sbus_dev->irqs[0].pri)); + if((len == -1) || (len == 0)) { + sbus_dev->irqs[0].pri = 0; + sbus_dev->num_irqs = 0; + } else { + sbus_dev->num_irqs = 1; + } + } else { + len = prom_getproperty(nd, "intr", (void *)sbus_dev->irqs, + sizeof(sbus_dev->irqs)); + if (len == -1) len=0; + if (len&7) { + prom_printf("Grrr, I didn't get a multiple of 8 proplen for " + "device %s got %d\n", sbus_dev->prom_name, len); + len=0; + } + sbus_dev->num_irqs=(len/8); + if(sbus_dev->num_irqs == 0) + sbus_dev->irqs[0].pri=0; } -#endif - if(sbus_dev->num_irqs == 0) sbus_dev->irqs[0].pri=0; - #ifdef DEBUG_FILL +#ifdef __sparc_v9__ + prom_printf("Found %s at SBUS slot %x offset %016lx irq-level %d\n", + sbus_dev->prom_name, sbus_dev->slot, sbus_dev->offset, + sbus_dev->irqs[0].pri); + prom_printf("Base address %016lx\n", sbus_dev->sbus_addr); +#else prom_printf("Found %s at SBUS slot %x offset %08lx irq-level %d\n", sbus_dev->prom_name, sbus_dev->slot, sbus_dev->offset, sbus_dev->irqs[0].pri); prom_printf("Base address %08lx\n", sbus_dev->sbus_addr); +#endif prom_printf("REGISTERS: Probed %d register(s)\n", sbus_dev->num_registers); for(len=0; lennum_registers; len++) +#ifdef __sparc_v9__ prom_printf("Regs<%d> at address<%08lx> IO-space<%d> size<%d " "bytes, %d words>\n", (int) len, (unsigned long) sbus_dev->reg_addrs[len].phys_addr, sbus_dev->reg_addrs[len].which_io, sbus_dev->reg_addrs[len].reg_size, (sbus_dev->reg_addrs[len].reg_size/4)); +#else + prom_printf("Regs<%d> at address<%016lx> IO-space<%d> size<%d " + "bytes, %d words>\n", (int) len, + (unsigned long) sbus_dev->reg_addrs[len].phys_addr, + sbus_dev->reg_addrs[len].which_io, + sbus_dev->reg_addrs[len].reg_size, + (sbus_dev->reg_addrs[len].reg_size/4)); +#endif #endif - - return; } /* This routine gets called from whoever needs the sbus first, to scan @@ -149,6 +170,12 @@ #ifdef CONFIG_SUN_MOSTEK_RTC extern int rtc_init(void); #endif +#ifdef CONFIG_SPARCAUDIO +extern int sparcaudio_init(void); +#endif +#ifdef CONFIG_SUN_AUXIO +extern void auxio_probe(void); +#endif __initfunc(static unsigned long sbus_do_child_siblings(unsigned long memory_start, int start_node, @@ -200,7 +227,14 @@ /* Finding the first sbus is a special case... */ iommund = 0; - if (sparc_cpu_model == sun4d) { + if(sparc_cpu_model == sun4u) { + /* IOMMU "hides" inside SBUS/SYSIO node. */ + iommund = nd = prom_searchsiblings(topnd, "sbus"); + if(nd == 0) { + prom_printf("YEEE, UltraSparc sbus not found\n"); + prom_halt(); + } + } else if(sparc_cpu_model == sun4d) { if((iommund = prom_searchsiblings(topnd, "io-unit")) == 0 || (nd = prom_getchild(iommund)) == 0 || (nd = prom_searchsiblings(nd, "sbi")) == 0) { @@ -309,7 +343,12 @@ memory_start = dvma_init(sbus, memory_start); num_sbus++; - if (sparc_cpu_model == sun4d) { + if(sparc_cpu_model == sun4u) { + this_sbus = prom_getsibling(this_sbus); + if(!this_sbus) + break; + this_sbus = prom_searchsiblings(this_sbus, "sbus"); + } else if(sparc_cpu_model == sun4d) { iommund = prom_getsibling(iommund); if(!iommund) break; iommund = prom_searchsiblings(iommund, "io-unit"); @@ -336,8 +375,15 @@ #ifdef CONFIG_SUN_MOSTEK_RTC rtc_init(); #endif +#ifdef CONFIG_SPARCAUDIO + sparcaudio_init(); +#endif #ifdef CONFIG_SUN_BPP bpp_init(); +#endif +#ifdef CONFIG_SUN_AUXIO + if (sparc_cpu_model == sun4u) + auxio_probe (); #endif return memory_start; } diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/AM53C974.h linux/drivers/scsi/AM53C974.h --- v2.1.33/linux/drivers/scsi/AM53C974.h Mon Apr 7 11:35:29 1997 +++ linux/drivers/scsi/AM53C974.h Fri Apr 11 10:50:49 1997 @@ -27,6 +27,8 @@ #ifndef AM53C974_H #define AM53C974_H +#include + struct AM53C974_hostdata { volatile unsigned in_reset:1; /* flag, says bus reset pending */ volatile unsigned aborted:1; /* flag, says aborted */ diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.1.33/linux/drivers/scsi/Config.in Sun Apr 13 10:18:21 1997 +++ linux/drivers/scsi/Config.in Fri Apr 11 10:50:49 1997 @@ -71,7 +71,7 @@ fi fi if [ "$CONFIG_MCA" = "y" ]; then - bool 'IBMMCA SCSI support' CONFIG_SCSI_IBMMCA + dep_tristate 'IBMMCA SCSI support' CONFIG_SCSI_IBMMCA $CONFIG_SCSI fi if [ "$CONFIG_PNP_PARPORT" != "n" ]; then dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PNP_PARPORT @@ -79,7 +79,6 @@ int ' Pedantic EPP-checking' CONFIG_SCSI_PPA_HAVE_PEDANTIC 2 0 3 int ' EPP timeout' CONFIG_SCSI_PPA_EPP_TIME 128 fi - dep_tristate 'IBMMCA SCSI support' CONFIG_SCSI_IBMMCA $CONFIG_SCSI fi dep_tristate 'PAS16 SCSI support' CONFIG_SCSI_PAS16 $CONFIG_SCSI dep_tristate 'Qlogic FAS SCSI support' CONFIG_SCSI_QLOGIC_FAS $CONFIG_SCSI diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.1.33/linux/drivers/scsi/Makefile Mon Mar 17 14:54:29 1997 +++ linux/drivers/scsi/Makefile Fri Apr 11 10:50:49 1997 @@ -10,6 +10,7 @@ L_OBJS := M_OBJS := MX_OBJS := +MIX_OBJS := MOD_LIST_NAME := SCSI_MODULES SCSI_SRCS = $(wildcard $(L_OBJS:%.o=%.c)) @@ -45,7 +46,7 @@ endif else ifeq ($(CONFIG_SCSI),m) - MX_OBJS += scsi_syms.o + MIX_OBJS += scsi_syms.o M_OBJS += scsi_mod.o endif endif @@ -412,9 +413,9 @@ ncr53c8xx.o : ncr53c8xx.c $(CC) $(CFLAGS) -c ncr53c8xx.c -scsi_mod.o: $(MX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \ +scsi_mod.o: $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \ scsicam.o scsi_proc.o - $(LD) $(LD_RFLAG) -r -o $@ $(MX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o + $(LD) $(LD_RFLAG) -r -o $@ $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o sr_mod.o: sr.o sr_ioctl.o $(SR_VENDOR) $(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o $(SR_VENDOR) diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/atari_NCR5380.c linux/drivers/scsi/atari_NCR5380.c --- v2.1.33/linux/drivers/scsi/atari_NCR5380.c Fri Dec 20 01:20:02 1996 +++ linux/drivers/scsi/atari_NCR5380.c Fri Apr 11 10:47:38 1997 @@ -1026,7 +1026,7 @@ * If we're not in an interrupt, we can call NCR5380_main() * unconditionally, because it cannot be already running. */ - if (intr_count > 0 || ((flags >> 8) & 7) >= 6) + if (in_interrupt() || ((flags >> 8) & 7) >= 6) queue_main(); else NCR5380_main(); diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/atari_scsi.c linux/drivers/scsi/atari_scsi.c --- v2.1.33/linux/drivers/scsi/atari_scsi.c Fri Dec 20 01:20:02 1996 +++ linux/drivers/scsi/atari_scsi.c Fri Apr 11 10:47:38 1997 @@ -549,11 +549,11 @@ save_flags(oldflags); cli(); - while( intr_count == 0 && falcon_got_lock && stdma_others_waiting() ) + while( !in_interrupt() && falcon_got_lock && stdma_others_waiting() ) sleep_on( &falcon_fairness_wait ); while (!falcon_got_lock) { - if (intr_count > 0) + if (in_interrupt()) panic( "Falcon SCSI hasn't ST-DMA lock in interrupt" ); if (!falcon_trying_lock) { falcon_trying_lock = 1; diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c --- v2.1.33/linux/drivers/scsi/esp.c Mon Mar 17 14:54:29 1997 +++ linux/drivers/scsi/esp.c Mon Apr 14 09:31:09 1997 @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -170,7 +169,6 @@ /* Forward declarations. */ static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs); -static void esp_done(struct Sparc_ESP *esp, int error); /* Debugging routines */ struct esp_cmdstrings { @@ -693,6 +691,7 @@ esp->ehost = esp_host; esp->edev = esp_dev; esp->esp_id = nesps++; + /* Put into the chain of esp chips detected */ if(espchain) { elink = espchain; @@ -769,13 +768,15 @@ if(!eregs) panic("ESP registers unmappable"); esp->esp_command = - sparc_dvma_malloc(16, "ESP DVMA Cmd Block"); - if(!esp->esp_command) + sparc_dvma_malloc(16, "ESP DVMA Cmd Block", + &esp->esp_command_dvma); + if(!esp->esp_command || !esp->esp_command_dvma) panic("ESP DVMA transport area unmappable"); /* Set up the irq's etc. */ esp->ehost->base = (unsigned char *) esp->eregs; - esp->ehost->io_port = (unsigned int) esp->eregs; + esp->ehost->io_port = + esp->edev->reg_addrs[0].phys_addr; esp->ehost->n_io_port = (unsigned char) esp->edev->reg_addrs[0].reg_size; esp->ehost->irq = esp->irq = esp->edev->irqs[0].pri; @@ -1256,8 +1257,9 @@ int lun, target; int i; - /* Hold off if we've been reselected. */ - if(esp->disconnected_SC && DMA_IRQ_P(dregs)) return; + /* Hold off if we've been reselected or an IRQ is showing... */ + if(esp->disconnected_SC || DMA_IRQ_P(dregs)) + return; /* Grab first member of the issue queue. */ SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC); @@ -1479,7 +1481,7 @@ tmp |= (DMA_SCSI_DISAB | DMA_ENABLE); tmp &= ~(DMA_ST_WRITE); dregs->cnt = 16; - dregs->st_addr = esp->esp_command; + dregs->st_addr = esp->esp_command_dvma; dregs->cond_reg = tmp; } else { /* Set up the DMA and ESP counters */ @@ -1490,7 +1492,7 @@ if(i) /* Workaround ESC gate array SBUS rerun bug. */ dregs->cnt = (PAGE_SIZE); } - dregs->st_addr = esp->esp_command; + dregs->st_addr = esp->esp_command_dvma; /* Tell ESP to "go". */ esp_cmd(esp, eregs, the_esp_command); @@ -1503,9 +1505,6 @@ struct Sparc_ESP *esp; struct sparc_dma_registers *dregs; unsigned long flags; - int don; - - save_flags(flags); cli(); /* Set up func ptr and initial driver cmd-phase. */ SCpnt->scsi_done = done; @@ -1514,10 +1513,6 @@ esp = (struct Sparc_ESP *) SCpnt->host->hostdata; dregs = esp->dregs; - don = (dregs->cond_reg & DMA_INT_ENAB); - if(don) - DMA_INTSOFF(dregs); - /* We use the scratch area. */ ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->target, SCpnt->lun)); ESPDISC(("N<%02x,%02x>", SCpnt->target, SCpnt->lun)); @@ -1528,10 +1523,13 @@ (struct scatterlist *) SCpnt->request_buffer; SCpnt->SCp.buffers_residual = 0; /* Sneaky. */ - SCpnt->SCp.have_data_in = (int) SCpnt->SCp.ptr = - mmu_get_scsi_one((char *)SCpnt->SCp.buffer, - SCpnt->SCp.this_residual, - esp->edev->my_bus); + SCpnt->SCp.have_data_in = mmu_get_scsi_one((char *)SCpnt->SCp.buffer, + SCpnt->SCp.this_residual, + esp->edev->my_bus); + /* XXX The casts are extremely gross, but with 64-bit kernel + * XXX and 32-bit SBUS what am I to do? -DaveM + */ + SCpnt->SCp.ptr = (char *)((unsigned long)SCpnt->SCp.have_data_in); } else { ESPQUEUE(("use_sg ")); #ifdef DEBUG_ESP_SG @@ -1544,7 +1542,8 @@ mmu_get_scsi_sgl((struct mmu_sglist *) SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, esp->edev->my_bus); - SCpnt->SCp.ptr = (char *) SCpnt->SCp.buffer->dvma_address; + /* XXX Again these casts are sick... -DaveM */ + SCpnt->SCp.ptr=(char *)((unsigned long)SCpnt->SCp.buffer->dvma_address); } SCpnt->SCp.Status = CHECK_CONDITION; SCpnt->SCp.Message = 0xff; @@ -1559,12 +1558,12 @@ append_SC(&esp->issue_SC, SCpnt); } + save_and_cli(flags); + /* Run it now if we can. */ if(!esp->current_SC && !esp->resetting_bus) esp_exec_cmd(esp); - if(don) - DMA_INTSON(dregs); restore_flags(flags); return 0; } @@ -1597,7 +1596,7 @@ #endif ESPLOG(("esp%d: dumping state\n", esp->esp_id)); - ESPLOG(("esp%d: dma -- cond_reg<%08lx> addr<%p>\n", + ESPLOG(("esp%d: dma -- cond_reg<%08x> addr<%08x>\n", esp->esp_id, dregs->cond_reg, dregs->st_addr)); ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n", esp->esp_id, esp->sreg, esp->seqreg, esp->ireg)); @@ -1648,8 +1647,6 @@ int don; ESPLOG(("esp%d: Aborting command\n", esp->esp_id)); - save_flags(flags); cli(); - esp_dump_state(esp, eregs, dregs); /* Wheee, if this is the current command on the bus, the @@ -1658,6 +1655,7 @@ * in the driver and timeout because the eventual phase change * will cause the ESP to (eventually) give an interrupt. */ + save_and_cli(flags); if(esp->current_SC == SCptr) { esp->cur_msgout[0] = ABORT; esp->msgout_len = 1; @@ -1666,13 +1664,16 @@ restore_flags(flags); return SCSI_ABORT_PENDING; } + restore_flags(flags); /* If it is still in the issue queue then we can safely * call the completion routine and report abort success. */ don = (dregs->cond_reg & DMA_INT_ENAB); - if(don) + if(don) { DMA_INTSOFF(dregs); + synchronize_irq(); + } if(esp->issue_SC) { Scsi_Cmnd **prev, *this; for(prev = (&esp->issue_SC), this = esp->issue_SC; @@ -1684,10 +1685,8 @@ this->host_scribble = NULL; this->result = DID_ABORT << 16; this->done(this); - cli(); if(don) DMA_INTSON(dregs); - restore_flags(flags); return SCSI_ABORT_SUCCESS; } } @@ -1698,12 +1697,8 @@ * on the bus at this time. So, we let the SCSI code wait * a little bit and try again later. */ - if(esp->current_SC) { - if(don) - DMA_INTSON(dregs); - restore_flags(flags); + if(esp->current_SC) return SCSI_ABORT_BUSY; - } /* It's disconnected, we have to reconnect to re-establish * the nexus and tell the device to abort. However, we really @@ -1712,9 +1707,6 @@ * happens, we are really hung so reset the bug. */ - if(don) - DMA_INTSON(dregs); - restore_flags(flags); return SCSI_ABORT_SNOOZE; } @@ -1733,14 +1725,12 @@ } /* Internal ESP done function. */ -static inline void esp_done(struct Sparc_ESP *esp, int error) +static void esp_done(struct Sparc_ESP *esp, int error) { - unsigned long flags; Scsi_Cmnd *done_SC; if(esp->current_SC) { - /* Critical section... */ - save_flags(flags); cli(); + unsigned long flags; done_SC = esp->current_SC; esp->current_SC = NULL; @@ -1748,7 +1738,7 @@ /* Free dvma entry. */ if(!done_SC->use_sg) { /* Sneaky. */ - mmu_release_scsi_one((char *)done_SC->SCp.have_data_in, + mmu_release_scsi_one(done_SC->SCp.have_data_in, done_SC->request_bufflen, esp->edev->my_bus); } else { @@ -1765,27 +1755,15 @@ } done_SC->result = error; - if(done_SC->scsi_done) - done_SC->scsi_done(done_SC); - else - panic("esp: esp->current_SC->scsi_done() == NULL"); + done_SC->scsi_done(done_SC); - /* There is a window of time within the scsi_done() path - * of execution where interrupts are turned back on full - * blast and left that way. During that time we could - * reconnect to a disconnected command, then we'd bomb - * out below. We could also end up executing two commands - * at _once_. ...just so you know why the cli() is here... - */ - - cli(); /* GRRR!!! */ + save_and_cli(flags); /* Bus is free, issue any commands in the queue. */ if(esp->issue_SC && !esp->current_SC) esp_exec_cmd(esp); restore_flags(flags); - /* End of critical section... */ } else { /* Panic is safe as current_SC is null so we may still * be able to accept more commands to sync disk buffers. @@ -1951,7 +1929,7 @@ /* Now some dma helpers. */ static inline void dma_setup(struct sparc_dma_registers *dregs, enum dvma_rev drev, - char *addr, int count, int write) + __u32 addr, int count, int write) { unsigned long nreg = dregs->cond_reg; if(write) @@ -1962,8 +1940,8 @@ dregs->cond_reg = nreg; if(drev == dvmaesc1) { /* This ESC gate array sucks! */ - unsigned long src = ((unsigned long) addr); - unsigned long dest = src + count; + __u32 src = addr; + __u32 dest = src + count; if(dest & (PAGE_SIZE - 1)) count = PAGE_ALIGN(count); @@ -1991,13 +1969,16 @@ static inline void dma_invalidate(struct sparc_dma_registers *dregs, enum dvma_rev drev) { - unsigned long tmp; + unsigned int tmp; if(drev == dvmahme) { /* SMCC can bite me. */ tmp = dregs->cond_reg; dregs->cond_reg = DMA_RST_SCSI; - tmp |= (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB|DMA_INT_ENAB); + + /* This would explain a lot. */ + tmp |= (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB); + tmp &= ~(DMA_ENABLE|DMA_ST_WRITE); dregs->cond_reg = 0; dregs->cond_reg = tmp; @@ -2021,14 +2002,14 @@ static inline int dma_can_transfer(Scsi_Cmnd *sp, enum dvma_rev drev) { - unsigned long base, end, sz; + __u32 base, end, sz; if(drev == dvmarev3) { sz = sp->SCp.this_residual; if(sz > 0x1000000) sz = 0x1000000; } else { - base = (unsigned long) sp->SCp.ptr; + base = ((__u32)sp->SCp.ptr); base &= (0x1000000 - 1); end = (base + sp->SCp.this_residual); if(end > 0x1000000) @@ -2239,8 +2220,7 @@ struct sparc_dma_registers *dregs, int fifo_count) { - int rval = (((unsigned long)dregs->st_addr) - - ((unsigned long)esp->esp_command)); + int rval = dregs->st_addr - esp->esp_command_dvma; if(esp->dma->revision == dvmarev1) rval -= (4 - ((dregs->cond_reg & DMA_READ_AHEAD)>>11)); @@ -2252,26 +2232,7 @@ ++sp->SCp.buffer; --sp->SCp.buffers_residual; sp->SCp.this_residual = sp->SCp.buffer->length; - sp->SCp.ptr = sp->SCp.buffer->dvma_address; -} - -/* Complete a command, this is the only way to safely finish - * a command with disconnected commands or a reset interrupt - * pending because scsi_done() can enable interrupts full blast. - */ -static inline void safe_esp_done(struct Sparc_ESP *esp, - struct sparc_dma_registers *dregs, - int error) -{ - int before = 0; - - if(dregs->cond_reg & DMA_INT_ENAB) { - before = 1; - DMA_INTSOFF(dregs); - } - esp_done(esp, error); - if(before) - DMA_INTSON(dregs); + sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address); } /* Please note that the way I've coded these routines is that I _always_ @@ -2318,11 +2279,11 @@ tmp |= DMA_ST_WRITE; else tmp &= ~(DMA_ST_WRITE); - dregs->st_addr = SCptr->SCp.ptr; + dregs->st_addr = ((__u32)SCptr->SCp.ptr); dregs->cond_reg = tmp; } else { esp_setcount(eregs, hmuch, 0); - dma_setup(dregs, esp->dma->revision, SCptr->SCp.ptr, + dma_setup(dregs, esp->dma->revision, ((__u32)SCptr->SCp.ptr), hmuch, (thisphase == in_datain)); ESPDATA(("DMA|TI --> do_intr_end\n")); esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); @@ -2361,6 +2322,11 @@ /* Please go to msgout phase, please please please... */ ESPLOG(("esp%d: !BSERV after data, probably to msgout\n", esp->esp_id)); +#ifdef __SMP__ + ESPLOG(("esp%d: local_irq_count[%x:%x:%x:%x]\n", esp->esp_id, + local_irq_count[0], local_irq_count[1], + local_irq_count[2], local_irq_count[3])); +#endif return esp_do_phase_determine(esp, eregs, dregs); } @@ -2443,6 +2409,11 @@ ESPLOG(("esp%d: use_sg=%d ptr=%p this_residual=%d\n", esp->esp_id, SCptr->use_sg, SCptr->SCp.ptr, SCptr->SCp.this_residual)); +#ifdef __SMP__ + ESPLOG(("esp%d: local_irq_count[%x:%x:%x:%x]\n", esp->esp_id, + local_irq_count[0], local_irq_count[1], + local_irq_count[2], local_irq_count[3])); +#endif bytes_sent = 0; } @@ -2536,9 +2507,9 @@ SCptr->device->sync = 0; } ESPDISC(("F<%02x,%02x>", SCptr->target, SCptr->lun)); - safe_esp_done(esp, dregs, ((SCptr->SCp.Status & 0xff) | - ((SCptr->SCp.Message & 0xff)<<8) | - (DID_OK << 16))); + esp_done(esp, ((SCptr->SCp.Status & 0xff) | + ((SCptr->SCp.Message & 0xff)<<8) | + (DID_OK << 16))); } else if(esp->prevmsgin == DISCONNECT) { /* Normal disconnect. */ esp_cmd(esp, eregs, ESP_CMD_ESEL); @@ -2785,7 +2756,7 @@ dregs->cond_reg |= (DMA_ST_WRITE | DMA_ENABLE); if(esp->dma->revision == dvmaesc1) dregs->cnt = 0x1000; - dregs->st_addr = esp->esp_command; + dregs->st_addr = esp->esp_command_dvma; esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_ICCSEQ); } else { /* Using DVMA for status/message bytes is @@ -2834,7 +2805,7 @@ /* We didn't expect this to happen at all. */ ESPLOG(("device is bolixed\n")); esp_advance_phase(SCptr, in_tgterror); - safe_esp_done(esp, dregs, (DID_ERROR << 16)); + esp_done(esp, (DID_ERROR << 16)); break; case BUS_DEVICE_RESET: @@ -2843,13 +2814,13 @@ dp->sync_min_period = 0; dp->sync = 0; esp_advance_phase(SCptr, in_resetdev); - safe_esp_done(esp, dregs, (DID_RESET << 16)); + esp_done(esp, (DID_RESET << 16)); break; case ABORT: ESPLOG(("device abort successful\n")); esp_advance_phase(SCptr, in_abortone); - safe_esp_done(esp, dregs, (DID_ABORT << 16)); + esp_done(esp, (DID_ABORT << 16)); break; }; @@ -3088,13 +3059,13 @@ * Therefore, we assume that if we've talked successfully * to this target before, bad parity is the problem. */ - safe_esp_done(esp, dregs, (DID_PARITY << 16)); + esp_done(esp, (DID_PARITY << 16)); } else { /* Else, there really isn't anyone there. */ ESPMISC(("esp: selection failure, maybe nobody there?\n")); ESPMISC(("esp: target %d lun %d\n", SCptr->target, SCptr->lun)); - safe_esp_done(esp, dregs, (DID_BAD_TARGET << 16)); + esp_done(esp, (DID_BAD_TARGET << 16)); } return do_intr_end; } @@ -3542,7 +3513,7 @@ tmp |= (DMA_SCSI_DISAB | DMA_ENABLE); tmp &= ~(DMA_ST_WRITE); dregs->cnt = i; - dregs->st_addr = &esp->esp_command[0]; + dregs->st_addr = esp->esp_command_dvma; dregs->cond_reg = tmp; } else { esp_cmd(esp, eregs, ESP_CMD_FLUSH); @@ -3590,7 +3561,7 @@ esp_cmd(esp, eregs, ESP_CMD_TI); } else { dma_setup(dregs, esp->dma->revision, - (char *) esp->esp_command, 2, 0); + esp->esp_command_dvma, 2, 0); esp_setcount(eregs, 2, 0); esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); } @@ -3607,7 +3578,7 @@ esp_cmd(esp, eregs, ESP_CMD_TI); } else { dma_setup(dregs, esp->dma->revision, - (char *) esp->esp_command, 4, 0); + esp->esp_command_dvma, 4, 0); esp_setcount(eregs, 4, 0); esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); } @@ -3625,7 +3596,7 @@ esp_cmd(esp, eregs, ESP_CMD_TI); } else { dma_setup(dregs, esp->dma->revision, - (char *) esp->esp_command, 5, 0); + esp->esp_command_dvma, 5, 0); esp_setcount(eregs, 5, 0); esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); } @@ -3794,8 +3765,6 @@ dregs = esp->dregs; SCptr = esp->current_SC; - DMA_IRQ_ENTRY(esp->dma, dregs); - /* Check for errors. */ esp->sreg = eregs->esp_status; esp->sreg &= (~ESP_STAT_INTR); @@ -3842,7 +3811,7 @@ * translation it did get pointed to a bogus * page. Ho hum... */ - ESPLOG(("esp%d: DMA error %08lx\n", esp->esp_id, + ESPLOG(("esp%d: DMA error %08x\n", esp->esp_id, dregs->cond_reg)); /* DMA gate array itself must be reset to clear the @@ -3874,6 +3843,9 @@ esp->ireg = eregs->esp_intrpt; /* Unlatch intr and stat regs */ + /* This cannot be done until this very moment. -DaveM */ + synchronize_irq(); + /* No current cmd is only valid at this point when there are * commands off the bus or we are trying a reset. */ @@ -3988,13 +3960,10 @@ /* Tricky, we don't want to cause any more commands to * go out until we clear all the live cmds by hand. */ - if(!DMA_ISBROKEN(esp->dma)) - DMA_INTSOFF(dregs); if(esp->current_SC) { Scsi_Cmnd *SCptr = esp->current_SC; if(!SCptr->use_sg) - mmu_release_scsi_one((char *) - SCptr->SCp.have_data_in, + mmu_release_scsi_one(SCptr->SCp.have_data_in, SCptr->request_bufflen, esp->edev->my_bus); else @@ -4003,16 +3972,15 @@ SCptr->use_sg - 1, esp->edev->my_bus); SCptr->result = (DID_RESET << 16); + SCptr->scsi_done(SCptr); - cli(); } esp->current_SC = NULL; if(esp->disconnected_SC) { Scsi_Cmnd *SCptr; while((SCptr = remove_first_SC(&esp->disconnected_SC))) { if(!SCptr->use_sg) - mmu_release_scsi_one((char *) - SCptr->SCp.have_data_in, + mmu_release_scsi_one(SCptr->SCp.have_data_in, SCptr->request_bufflen, esp->edev->my_bus); else @@ -4021,13 +3989,11 @@ SCptr->use_sg - 1, esp->edev->my_bus); SCptr->result = (DID_RESET << 16); + SCptr->scsi_done(SCptr); - cli(); } } esp->resetting_bus = 0; - if(!DMA_ISBROKEN(esp->dma)) - DMA_INTSON(dregs); if(esp->current_SC) { printk("esp%d: weird weird weird, current_SC not NULL after " @@ -4051,35 +4017,71 @@ goto again; esp_handle_done: - DMA_IRQ_EXIT(esp->dma, dregs); return; } +#ifndef __SMP__ static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs) { struct Sparc_ESP *esp; - static int running = 0; int again; - /* It is ok to take irq's on one esp while the other - * is amidst the processing of a reset. - */ - running++; - if(running > esps_running) - ESPLOG(("esp_intr: yieee, recursive interrupt!\n")); - - /* Handle all ESP interrupts showing */ + /* Handle all ESP interrupts showing at this IRQ level. */ repeat: again = 0; for_each_esp(esp) { - if(DMA_IRQ_P(esp->dregs)) { - again = 1; - ESPIRQ(("I%d(", esp->esp_id)); - esp_handle(esp); - ESPIRQ((")")); + /* XXX Ultra: This is gross, what we really need + * XXX is a sbusirq_to_sparc_pil() function, call + * XXX that and stick the result in the esp soft + * XXX state structure. -DaveM + */ +#ifndef __sparc_v9__ + if((esp->irq & 0xf) == irq) { +#endif + if(DMA_IRQ_P(esp->dregs)) { + again = 1; + + DMA_INTSOFF(esp->dregs); + + ESPIRQ(("I%d(", esp->esp_id)); + esp_handle(esp); + ESPIRQ((")")); + + DMA_INTSON(esp->dregs); + } +#ifndef __sparc_v9__ } +#endif } if(again) goto repeat; - running--; } +#else + +#ifdef __sparc_v9__ +#error Dave you need to fix some things first... +#endif + +/* For SMP we only service one ESP on the list list at our IRQ level! */ +static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs) +{ + struct Sparc_ESP *esp; + + /* Handle all ESP interrupts showing at this IRQ level. */ + for_each_esp(esp) { + if((esp->irq & 0xf) == irq) { + if(DMA_IRQ_P(esp->dregs)) { + DMA_INTSOFF(esp->dregs); + + ESPIRQ(("I[%d:%d](", + smp_processor_id(), esp->esp_id)); + esp_handle(esp); + ESPIRQ((")")); + + DMA_INTSON(esp->dregs); + return; + } + } + } +} +#endif diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/esp.h linux/drivers/scsi/esp.h --- v2.1.33/linux/drivers/scsi/esp.h Sun Jan 26 02:07:18 1997 +++ linux/drivers/scsi/esp.h Mon Apr 14 11:43:13 1997 @@ -108,7 +108,8 @@ * of the command types ESP doesn't understand, esp_scmdp keeps track of * which byte we are sending, esp_scmdleft says how many bytes to go. */ - volatile unchar *esp_command; /* Location of command */ + volatile unchar *esp_command; /* Location of command (CPU view) */ + __u32 esp_command_dvma; /* Location of command (DVMA view) */ unsigned char esp_clen; /* Length of this command */ unsigned char esp_slowcmd; unsigned char *esp_scmdp; diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/ibmmca.c linux/drivers/scsi/ibmmca.c --- v2.1.33/linux/drivers/scsi/ibmmca.c Fri Apr 4 08:52:23 1997 +++ linux/drivers/scsi/ibmmca.c Sun Apr 13 09:23:31 1997 @@ -46,6 +46,7 @@ #include +#include #include #include #include diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c --- v2.1.33/linux/drivers/scsi/ppa.c Sun Apr 13 10:18:21 1997 +++ linux/drivers/scsi/ppa.c Fri Apr 11 10:50:49 1997 @@ -1193,7 +1193,7 @@ hreg->n_io_port = ports; hreg->dma_channel = -1; hreg->unique_id = i; - ppa_hosts[i]..host = hreg->host_no; + ppa_hosts[i].host = hreg->host_no; nhosts++; } if (nhosts == 0) diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c --- v2.1.33/linux/drivers/scsi/qlogicpti.c Mon Mar 17 14:54:30 1997 +++ linux/drivers/scsi/qlogicpti.c Mon Apr 14 09:31:09 1997 @@ -283,8 +283,8 @@ param[0] = MBOX_INIT_RES_QUEUE; param[1] = RES_QUEUE_LEN + 1; - param[2] = (u_short) (((u_int) qpti->res)>>16); - param[3] = (u_short) (((u_int) qpti->res) & 0xffff); + param[2] = (u_short) (qpti->res_dvma >> 16); + param[3] = (u_short) (qpti->res_dvma & 0xffff); param[4] = param[5] = 0; if(qlogicpti_mbox_command(qpti, param, 1)) { printk(KERN_EMERG "qlogicpti%d: Cannot init response queue.\n", @@ -295,8 +295,8 @@ param[0] = MBOX_INIT_REQ_QUEUE; param[1] = QLOGICISP_REQ_QUEUE_LEN + 1; - param[2] = (u_short) (((u_int) qpti->req)>>16); - param[3] = (u_short) (((u_int) qpti->req) & 0xffff); + param[2] = (u_short) (qpti->req_dvma >> 16); + param[3] = (u_short) (qpti->req_dvma & 0xffff); param[4] = param[5] = 0; if(qlogicpti_mbox_command(qpti, param, 1)) { printk(KERN_EMERG "qlogicpti%d: Cannot init request queue.\n", @@ -417,6 +417,7 @@ /* Load the firmware. */ #ifndef MODULE + /* XXX THIS SHIT DOES NOT WORK ON ULTRA... FIXME -DaveM */ dvma_addr = (unsigned long) mmu_lockarea((char *)&risc_code01[0], (sizeof(u_short) * risc_code_length01)); param[0] = MBOX_LOAD_RAM; @@ -431,6 +432,7 @@ restore_flags(flags); return 1; } + /* XXX THIS SHIT DOES NOT WORK ON ULTRA... FIXME -DaveM */ mmu_unlockarea((char *)dvma_addr, (sizeof(u_short) * risc_code_length01)); #else for(i = 0; i < risc_code_length01; i++) { @@ -698,10 +700,12 @@ #define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN) - qpti->res = sparc_dvma_malloc(QSIZE(RES_QUEUE_LEN), - "PTISP Response Queue"); - qpti->req = sparc_dvma_malloc(QSIZE(QLOGICISP_REQ_QUEUE_LEN), - "PTISP Request Queue"); + qpti->res_cpu = sparc_dvma_malloc(QSIZE(RES_QUEUE_LEN), + "PTISP Response Queue", + &qpti->res_dvma); + qpti->req_cpu = sparc_dvma_malloc(QSIZE(QLOGICISP_REQ_QUEUE_LEN), + "PTISP Request Queue", + &qpti->req_dvma); #undef QSIZE @@ -834,7 +838,7 @@ struct Continuation_Entry *cont; ++cmd->hdr.entry_cnt; - cont = (struct Continuation_Entry *) &qpti->req[in_ptr]; + cont = (struct Continuation_Entry *) &qpti->req_cpu[in_ptr]; in_ptr = NEXT_REQ_PTR(in_ptr); if(in_ptr == out_ptr) { printk(KERN_EMERG "qlogicpti: Unexpected request queue overflow\n"); @@ -856,9 +860,13 @@ sg_count -= n; } } else { - Cmnd->SCp.ptr = mmu_get_scsi_one((char *)Cmnd->request_buffer, - Cmnd->request_bufflen, - qpti->qdev->my_bus); + /* XXX Casts are extremely gross, but with 64-bit cpu addresses + * XXX and 32-bit SBUS DVMA addresses what am I to do? -DaveM + */ + Cmnd->SCp.ptr = (char *)((unsigned long) + mmu_get_scsi_one((char *)Cmnd->request_buffer, + Cmnd->request_bufflen, + qpti->qdev->my_bus)); cmd->dataseg[0].d_base = (u_int) Cmnd->SCp.ptr; cmd->dataseg[0].d_count = Cmnd->request_bufflen; @@ -892,7 +900,7 @@ struct qlogicpti_regs *qregs = qpti->qregs; u_int in_ptr = qpti->req_in_ptr; u_int out_ptr = qregs->mbox4; - struct Command_Entry *cmd = (struct Command_Entry *) &qpti->req[in_ptr]; + struct Command_Entry *cmd = (struct Command_Entry *) &qpti->req_cpu[in_ptr]; Cmnd->scsi_done = done; in_ptr = NEXT_REQ_PTR(in_ptr); @@ -909,7 +917,7 @@ printk(KERN_EMERG "qlogicpti%d: request queue overflow\n", qpti->qpti_id); return 1; } - cmd = (struct Command_Entry *) &qpti->req[in_ptr]; + cmd = (struct Command_Entry *) &qpti->req_cpu[in_ptr]; in_ptr = NEXT_REQ_PTR(in_ptr); } cmd_frob(cmd, Cmnd, qpti); @@ -1029,7 +1037,7 @@ /* This looks like a network driver! */ out_ptr = qpti->res_out_ptr; while(out_ptr != in_ptr) { - sts = (struct Status_Entry *) &qpti->res[out_ptr]; + sts = (struct Status_Entry *) &qpti->res_cpu[out_ptr]; out_ptr = NEXT_RES_PTR(out_ptr); Cmnd = (Scsi_Cmnd *) sts->handle; /* but_to_virt?!?! */ if(sts->completion_status == CS_RESET_OCCURRED || @@ -1052,8 +1060,7 @@ Cmnd->use_sg - 1, qpti->qdev->my_bus); else - mmu_release_scsi_one((char *) - Cmnd->SCp.ptr, + mmu_release_scsi_one((__u32)Cmnd->SCp.ptr, Cmnd->request_bufflen, qpti->qdev->my_bus); diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/qlogicpti.h linux/drivers/scsi/qlogicpti.h --- v2.1.33/linux/drivers/scsi/qlogicpti.h Sun Jan 26 02:07:19 1997 +++ linux/drivers/scsi/qlogicpti.h Fri Apr 11 10:47:38 1997 @@ -456,8 +456,10 @@ struct qlogicpti_regs *qregs; /* Adapter registers */ u_int req_in_ptr; /* index of next request slot */ u_int res_out_ptr; /* index of next result slot */ - struct pti_queue_entry *res; /* Pointer to RESPONSE dvma */ - struct pti_queue_entry *req; /* Pointer to REQUEST dvma */ + struct pti_queue_entry *res_cpu; /* Ptr to RESPONSE bufs (CPU) */ + __u32 res_dvma; /* Ptr to RESPONSE bufs (DVMA)*/ + struct pti_queue_entry *req_cpu; /* Ptr to REQUEST bufs (CPU) */ + __u32 req_dvma; /* Ptr to REQUEST bufs (DVMA) */ int cmd_count[MAX_TARGETS]; unsigned long tag_ages[MAX_TARGETS]; long send_marker; /* must we send a marker? */ diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v2.1.33/linux/drivers/scsi/scsi.h Mon Apr 7 11:35:30 1997 +++ linux/drivers/scsi/scsi.h Mon Apr 14 11:43:13 1997 @@ -23,6 +23,7 @@ #include +#include /* * Some defs, in case these are not defined elsewhere. diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/sr.h linux/drivers/scsi/sr.h --- v2.1.33/linux/drivers/scsi/sr.h Thu Nov 14 05:26:48 1996 +++ linux/drivers/scsi/sr.h Mon Apr 14 09:26:00 1997 @@ -56,6 +56,8 @@ #ifdef CONFIG_BLK_DEV_SR_VENDOR void sr_vendor_init(int minor); int sr_cd_check(struct cdrom_device_info*); +int sr_read_sector(int minor, int lba, int blksize, unsigned char *dest); + #endif #endif diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c --- v2.1.33/linux/drivers/scsi/sr_ioctl.c Thu Dec 12 06:54:19 1996 +++ linux/drivers/scsi/sr_ioctl.c Mon Apr 14 09:26:00 1997 @@ -69,16 +69,7 @@ printk("CDROM (ioctl) reports ILLEGAL REQUEST.\n"); break; default: - printk("SCSI CD error: host %d id %d lun %d return code = %03x\n", - scsi_CDs[target].device->host->host_no, - scsi_CDs[target].device->id, - scsi_CDs[target].device->lun, - result); - printk("\tSense class %x, sense error %x, extended sense %x\n", - sense_class(SCpnt->sense_buffer[0]), - sense_error(SCpnt->sense_buffer[0]), - SCpnt->sense_buffer[2] & 0xf); - + print_sense("sr", SCpnt); }; result = SCpnt->result; @@ -94,7 +85,7 @@ int sr_tray_move(struct cdrom_device_info *cdi, int pos) { u_char sr_cmd[10]; - + sr_cmd[0] = START_STOP; sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device -> lun) << 5); sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; @@ -121,11 +112,11 @@ SCSI_IOCTL_TEST_UNIT_READY,0)) return CDS_DISC_OK; -#if 0 - /* Enable this if you want to try auto-close. Is'nt enabled by - * default because it does'nt work perfectly (no way to - * difference between "tray open" and "tray closed, no disk"), - * and for caddy drives this is useless anyway. */ +#if 1 + /* Tell tray is open if the drive is not ready. Seems there is + * no way to check whenever the tray is really open, but this way + * we get auto-close-on-open work. And it seems to have no ill + * effects with caddy drives... */ return CDS_TRAY_OPEN; #else return CDS_NO_DISC; @@ -168,7 +159,8 @@ struct cdrom_multisession* ms_info) { ms_info->addr.lba=scsi_CDs[MINOR(cdi->dev)].ms_offset; - ms_info->xa_flag=scsi_CDs[MINOR(cdi->dev)].xa_flag; + ms_info->xa_flag=scsi_CDs[MINOR(cdi->dev)].xa_flag || + scsi_CDs[MINOR(cdi->dev)].ms_offset > 0; return 0; } @@ -516,8 +508,10 @@ return -EINVAL; } +#if 0 if (result) printk("DEBUG: sr_audio: result for ioctl %x: %x\n",cmd,result); +#endif return result; } @@ -530,10 +524,44 @@ target = MINOR(cdi->dev); switch (cmd) { + /* these are compatible with the ide-cd driver */ + case CDROMREADRAW: + case CDROMREADMODE1: case CDROMREADMODE2: + +#if CONFIG_BLK_DEV_SR_VENDOR + { + unsigned char *raw; + struct cdrom_msf msf; + int blocksize, lba, rc; + + if (cmd == CDROMREADMODE1) + blocksize = CD_FRAMESIZE; /* 2048 */ + else if (cmd == CDROMREADMODE2) + blocksize = CD_FRAMESIZE_RAW0; /* 2336 */ + else + /* some SCSI drives do not allow this one */ + blocksize = CD_FRAMESIZE_RAW; /* 2352 */ + + if (copy_from_user(&msf,(void*)arg,sizeof(msf))) + return -EFAULT; + if (!(raw = scsi_malloc(2048+512))) + return -ENOMEM; + + lba = (((msf.cdmsf_min0 * CD_SECS) + msf.cdmsf_sec0) + * CD_FRAMES + msf.cdmsf_frame0) - CD_BLOCK_OFFSET; + rc = sr_read_sector(target, lba, blocksize, raw); + if (!rc) + if (copy_to_user((void*)arg, raw, blocksize)) + rc = -EFAULT; + + scsi_free(raw,2048+512); + return rc; + } +#else return -EINVAL; - case CDROMREADMODE1: - return -EINVAL; +#endif + case BLKRAGET: if (!arg) diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c --- v2.1.33/linux/drivers/scsi/sr_vendor.c Tue Nov 12 22:11:17 1996 +++ linux/drivers/scsi/sr_vendor.c Mon Apr 14 09:26:00 1997 @@ -7,6 +7,23 @@ * be exact: there is'nt anything in my draft copy). * * Gerd Knorr + * + * -------------------------------------------------------------------------- + * + * support for XA/multisession-CD's + * + * - NEC: Detection and support of multisession CD's. + * + * - TOSHIBA: Detection and support of multisession CD's. + * Some XA-Sector tweaking, required for older drives. + * + * - SONY: Detection and support of multisession CD's. + * added by Thomas Quinot + * + * - PIONEER, HITACHI, PLEXTOR, MATSHITA, TEAC: known to work with SONY code. + * + * - HP: Much like SONY, but a little different... (Thomas) + * HP-Writers only ??? Maybe other CD-Writers work with this too ? */ #include @@ -27,9 +44,11 @@ #define VENDOR_NEC 2 #define VENDOR_TOSHIBA 3 #define VENDOR_SONY_LIKE 4 /* much drives are Sony compatible */ -#define VENDOR_HP 5 +#define VENDOR_HP 5 /* HP Writers, others too ?? */ +#if 0 #define DEBUG +#endif void sr_vendor_init(int minor) @@ -37,9 +56,13 @@ char *vendor = scsi_CDs[minor].device->vendor; char *model = scsi_CDs[minor].device->model; - if (!strncmp (vendor, "NEC", 3)) { + if ((!strncmp(vendor,"HP",2) || !strncmp(vendor,"PHILIPS",7)) && + scsi_CDs[minor].device->type == TYPE_WORM) { + scsi_CDs[minor].vendor = VENDOR_HP; + + } else if (!strncmp (vendor, "NEC", 3)) { scsi_CDs[minor].vendor = VENDOR_NEC; - if (!strncmp (model,"CD-ROM DRIVE:25", 15) || + if (!strncmp (model,"CD-ROM DRIVE:25", 15) || !strncmp (model,"CD-ROM DRIVE:36", 15) || !strncmp (model,"CD-ROM DRIVE:83", 15) || !strncmp (model,"CD-ROM DRIVE:84 ",16)) @@ -49,45 +72,102 @@ } else if (!strncmp (vendor, "TOSHIBA", 7)) { scsi_CDs[minor].vendor = VENDOR_TOSHIBA; - } else if (!strncmp (vendor, "HP", 2)) { - scsi_CDs[minor].vendor = VENDOR_HP; - } else { /* most drives can handled like sony ones, so we take * it as default */ scsi_CDs[minor].vendor = VENDOR_SONY_LIKE; +#ifdef DEBUG + printk(KERN_DEBUG + "sr: using \"Sony group\" multisession code\n"); +#endif } } +/* small handy function for switching block length using MODE SELECT, + * used by sr_read_sector() */ -/* - * support for XA/multisession-CD's - * - * - NEC: Detection and support of multisession CD's. - * - * - TOSHIBA: Detection and support of multisession CD's. - * Some XA-Sector tweaking, required for older drives. - * - * - SONY: Detection and support of multisession CD's. - * added by Thomas Quinot - * - * - PIONEER, HITACHI, PLEXTOR, MATSHITA: known to work with SONY code. +static int +set_density_and_blocklength(int minor, unsigned char *buffer, + int density, int blocklength) +{ + unsigned char cmd[12]; /* the scsi-command */ + struct ccs_modesel_head *modesel; + int rc; + + memset(cmd,0,12); + cmd[0] = MODE_SELECT; + cmd[1] = (scsi_CDs[minor].device->lun << 5) | (1 << 4); + cmd[4] = 12; + modesel = (struct ccs_modesel_head*)buffer; + memset(modesel,0,sizeof(*modesel)); + modesel->block_desc_length = 0x08; + modesel->density = density; + modesel->block_length_med = (blocklength >> 8 ) & 0xff; + modesel->block_length_lo = blocklength & 0xff; + rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel)); +#ifdef DEBUG + if (rc) + printk("sr: switching blocklength to %d bytes failed\n", + blocklength); +#endif + return rc; +} + + +/* read a sector with other than 2048 bytes length + * dest is assumed to be allocated with scsi_malloc * - * - HP: Much like SONY, but a little different... (Thomas) - * HP-Writers only ??? + * XXX maybe we have to do some locking here. */ +int +sr_read_sector(int minor, int lba, int blksize, unsigned char *dest) +{ + unsigned char *buffer; /* the buffer for the ioctl */ + unsigned char cmd[12]; /* the scsi-command */ + int rc, density; + + density = (scsi_CDs[minor].vendor == VENDOR_TOSHIBA) ? 0x83 : 0; + + buffer = (unsigned char *) scsi_malloc(512); + if (!buffer) return -ENOMEM; + + rc = set_density_and_blocklength(minor, buffer, density, blksize); + if (!rc) { + memset(cmd,0,12); + cmd[0] = READ_10; + cmd[1] = (scsi_CDs[minor].device->lun << 5); + cmd[2] = (unsigned char)(lba >> 24) & 0xff; + cmd[3] = (unsigned char)(lba >> 16) & 0xff; + cmd[4] = (unsigned char)(lba >> 8) & 0xff; + cmd[5] = (unsigned char) lba & 0xff; + cmd[8] = 1; + rc = sr_do_ioctl(minor, cmd, dest, blksize); + set_density_and_blocklength(minor, buffer, density, 2048); + } + + scsi_free(buffer, 512); + return rc; +} + + +/* This function gets called after a media change. Checks if the CD is + multisession, asks for offset etc. */ + #define BCD_TO_BIN(x) ((((int)x & 0xf0) >> 4)*10 + ((int)x & 0x0f)) int sr_cd_check(struct cdrom_device_info *cdi) { unsigned long sector,min,sec,frame; - unsigned char *buffer; /* the buffer for the ioctl */ - unsigned char cmd[12]; /* the scsi-command */ + unsigned char *buffer; /* the buffer for the ioctl */ + unsigned char *raw_sector; + unsigned char cmd[12]; /* the scsi-command */ int rc,is_xa,no_multi,minor; minor = MINOR(cdi->dev); + if (scsi_CDs[minor].cdi.mask & CDC_MULTI_SESSION) + return 0; buffer = (unsigned char *) scsi_malloc(512); if(!buffer) return -ENOMEM; @@ -116,7 +196,6 @@ sec = BCD_TO_BIN(buffer[16]); frame = BCD_TO_BIN(buffer[17]); sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame; - is_xa = (buffer[14] == 0xb0); break; case VENDOR_TOSHIBA: @@ -141,36 +220,6 @@ sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame; if (sector) sector -= CD_BLOCK_OFFSET; - is_xa = (buffer[0] == 0x20); -#if 0 - /* this is required for some CD's: - * - Enhanced-CD (Hardware tells wrong XA-flag) - * - these broken non-XA multisession CD's - */ - if (is_xa == 0 && sector != 0) { - printk(KERN_WARNING "Warning: multisession offset " - "found, setting XA-flag\n"); - is_xa = 1; - } -#endif - /* now the XA-Sector tweaking: set_density... */ - memset(cmd,0,12); - cmd[0] = MODE_SELECT; - cmd[1] = (scsi_CDs[minor].device->lun << 5) - | (1 << 4); - cmd[4] = 12; - memset(buffer,0,12); - buffer[ 3] = 0x08; - buffer[ 4] = 0x83; - buffer[10] = 0x08; - rc = sr_do_ioctl(minor, cmd, buffer, 12); - if (rc != 0) { - break; - } -#if 0 - /* shoult'nt be required any more */ - scsi_CDs[minor].needs_sector_size = 1; -#endif break; case VENDOR_HP: @@ -209,15 +258,10 @@ sector = buffer[11] + (buffer[10] << 8) + (buffer[9] << 16) + (buffer[8] << 24); #endif - is_xa = !!sector; break; case VENDOR_SONY_LIKE: /* Thomas QUINOT */ -#ifdef DEBUG - printk(KERN_DEBUG - "sr: use \"Sony group\" multisession code\n"); -#endif memset(cmd,0,12); cmd[0] = READ_TOC; cmd[1] = (scsi_CDs[minor].device->lun << 5); @@ -227,7 +271,7 @@ if (rc != 0) { break; } - if ((buffer[0] << 8) + buffer[1] != 0x0a) { + if ((buffer[0] << 8) + buffer[1] < 0x0a) { printk(KERN_INFO "sr (sony): Hmm, seems the drive doesn't support multisession CD's\n"); no_multi = 1; break; @@ -238,7 +282,6 @@ /* ignore sector offsets from first track */ sector = 0; } - is_xa = !!sector; break; case VENDOR_CAN_NOT_HANDLE: @@ -255,19 +298,39 @@ no_multi = 1; break; } - + + scsi_CDs[minor].xa_flag = 0; + if (CDS_AUDIO != sr_disk_status(cdi)) { + /* read a sector in raw mode to check the sector format */ + raw_sector = (unsigned char *) scsi_malloc(2048+512); + if (!buffer) return -ENOMEM; + if (0 == sr_read_sector(minor,sector+16,CD_FRAMESIZE_RAW1, + raw_sector)){ + is_xa = (raw_sector[3] == 0x02); + if (sector > 0 && !is_xa) + printk(KERN_INFO "sr: broken CD found: It is " + "multisession, but has'nt XA sectors\n"); + } else { + /* read a raw sector failed for some reason. */ + is_xa = (sector > 0); + } + scsi_free(raw_sector, 2048+512); + } #ifdef DEBUG - if (sector) - printk(KERN_DEBUG - "sr: multisession CD detected, offset: %lu\n",sector); + else printk("sr: audio CD found\n"); #endif scsi_CDs[minor].ms_offset = sector; scsi_CDs[minor].xa_flag = is_xa; if (no_multi) cdi->mask |= CDC_MULTI_SESSION; - - scsi_free(buffer, 512); +#ifdef DEBUG + printk(KERN_DEBUG + "sr: multisession offset=%lu, XA=%s\n", + sector,is_xa ? "yes" : "no"); +#endif + + scsi_free(buffer, 512); return rc; } diff -u --recursive --new-file v2.1.33/linux/fs/binfmt_em86.c linux/fs/binfmt_em86.c --- v2.1.33/linux/fs/binfmt_em86.c Mon Apr 7 11:35:30 1997 +++ linux/fs/binfmt_em86.c Fri Apr 11 10:37:41 1997 @@ -20,13 +20,13 @@ static int do_load_em86(struct linux_binprm *bprm,struct pt_regs *regs) { - char *cp, *interp, *i_name, *i_arg; + char *interp, *i_name, *i_arg; int retval; struct elfhdr elf_ex; /* Make sure this is a Linux/Intel ELF executable... */ elf_ex = *((struct elfhdr *)bprm->buf); - + if (elf_ex.e_ident[0] != 0x7f || strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) { return -ENOEXEC; diff -u --recursive --new-file v2.1.33/linux/fs/buffer.c linux/fs/buffer.c --- v2.1.33/linux/fs/buffer.c Mon Apr 7 11:35:30 1997 +++ linux/fs/buffer.c Mon Apr 14 09:31:09 1997 @@ -583,7 +583,7 @@ buffer_protected(bh) || buffer_locked(bh)) return 0; - if (mem_map[MAP_NR((unsigned long) bh->b_data)].count != 1 || + if (atomic_read(&mem_map[MAP_NR((unsigned long) bh->b_data)].count) != 1 || buffer_dirty(bh)) { refile_buffer(bh); return 0; @@ -1304,7 +1304,7 @@ int *p, nr[PAGE_SIZE/512]; int i; - page->count++; + atomic_inc(&page->count); set_bit(PG_locked, &page->flags); set_bit(PG_free_after, &page->flags); @@ -1426,7 +1426,7 @@ buffermem -= PAGE_SIZE; mem_map[MAP_NR(page)].buffers = NULL; free_page(page); - return !mem_map[MAP_NR(page)].count; + return !atomic_read(&mem_map[MAP_NR(page)].count); } /* ================== Debugging =================== */ @@ -1536,7 +1536,7 @@ ndirty = 0; nwritten = 0; repeat: - + bh = lru_list[nlist]; if(bh) for (i = nr_buffers_type[nlist]; i-- > 0; bh = next) { @@ -1678,7 +1678,7 @@ ndirty = 0; refilled = 0; repeat: - + bh = lru_list[nlist]; if(bh) for (i = nr_buffers_type[nlist]; i-- > 0 && ndirty < bdf_prm.b_un.ndirty; diff -u --recursive --new-file v2.1.33/linux/fs/exec.c linux/fs/exec.c --- v2.1.33/linux/fs/exec.c Mon Apr 7 11:35:30 1997 +++ linux/fs/exec.c Fri Apr 11 10:47:38 1997 @@ -71,6 +71,10 @@ init_elf_binfmt(); #endif +#ifdef CONFIG_BINFMT_ELF32 + init_elf32_binfmt(); +#endif + #ifdef CONFIG_BINFMT_AOUT init_aout_binfmt(); #endif diff -u --recursive --new-file v2.1.33/linux/fs/fat/misc.c linux/fs/fat/misc.c --- v2.1.33/linux/fs/fat/misc.c Tue Jan 14 16:46:07 1997 +++ linux/fs/fat/misc.c Sat Apr 12 12:24:19 1997 @@ -258,6 +258,9 @@ { int day,year,nl_day,month; + if (sys_tz.tz_dsttime) { + unix_date += 3600; + } unix_date -= sys_tz.tz_minuteswest*60; *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+ (((unix_date/3600) % 24) << 11); diff -u --recursive --new-file v2.1.33/linux/fs/inode.c linux/fs/inode.c --- v2.1.33/linux/fs/inode.c Sun Apr 13 10:18:21 1997 +++ linux/fs/inode.c Mon Apr 14 09:31:09 1997 @@ -529,7 +529,7 @@ best->i_count = 1; best->i_nlink = 1; best->i_version = ++event; - best->i_sem.count = 1; + sema_init(&best->i_sem, 1); best->i_ino = ++ino; best->i_dev = 0; nr_free_inodes--; diff -u --recursive --new-file v2.1.33/linux/fs/isofs/dir.c linux/fs/isofs/dir.c --- v2.1.33/linux/fs/isofs/dir.c Mon Apr 7 11:35:30 1997 +++ linux/fs/isofs/dir.c Fri Apr 11 10:37:41 1997 @@ -172,7 +172,7 @@ * entries should terminate with a null size * or end exactly at the end of the sector. */ - printk("next_offset (%x) > bufsize (%x)\n", + printk("next_offset (%x) > bufsize (%lx)\n", offset,bufsize); break; } diff -u --recursive --new-file v2.1.33/linux/fs/isofs/inode.c linux/fs/isofs/inode.c --- v2.1.33/linux/fs/isofs/inode.c Sun Apr 13 10:18:22 1997 +++ linux/fs/isofs/inode.c Fri Apr 11 10:37:41 1997 @@ -393,7 +393,7 @@ if( (blocksize != 0) && (orig_zonesize < blocksize) ) { - printk("Logical zone size(%ld) < hardware blocksize(%ld)\n", + printk("Logical zone size(%d) < hardware blocksize(%u)\n", orig_zonesize, blocksize); goto out; @@ -549,12 +549,12 @@ * the page with useless information without generating any * I/O errors. */ - max_legal_read_offset = (inode->i_size + PAGE_SIZE - 1) + max_legal_read_offset = (inode->i_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); if( (block << ISOFS_BUFFER_BITS(inode)) >= max_legal_read_offset ) { - printk("_isofs_bmap: block>= EOF(%d, %d)\n", block, + printk("_isofs_bmap: block>= EOF(%d, %ld)\n", block, inode->i_size); } return 0; diff -u --recursive --new-file v2.1.33/linux/fs/nfs/Makefile linux/fs/nfs/Makefile --- v2.1.33/linux/fs/nfs/Makefile Mon Apr 7 11:35:30 1997 +++ linux/fs/nfs/Makefile Mon Apr 14 09:31:09 1997 @@ -12,7 +12,7 @@ nfs2xdr.o ifdef CONFIG_ROOT_NFS - O_OBJS += nfsroot.o + O_OBJS += nfsroot.o mount_clnt.o endif M_OBJS := $(O_TARGET) diff -u --recursive --new-file v2.1.33/linux/fs/nfs/inode.c linux/fs/nfs/inode.c --- v2.1.33/linux/fs/nfs/inode.c Sun Apr 13 10:18:22 1997 +++ linux/fs/nfs/inode.c Mon Apr 14 09:31:09 1997 @@ -83,12 +83,14 @@ void nfs_put_super(struct super_block *sb) { + struct nfs_server *server = &sb->u.nfs_sb.s_server; struct rpc_clnt *rpc; - if ((rpc = sb->u.nfs_sb.s_server.client) != NULL) + if ((rpc = server->client) != NULL) rpc_shutdown_client(rpc); - lockd_down(); /* release rpc.lockd */ + if (!(server->flags & NFS_MOUNT_NONLM)) + lockd_down(); /* release rpc.lockd */ rpciod_down(); /* release rpciod */ lock_super(sb); sb->s_dev = 0; @@ -230,7 +232,8 @@ if ((sb->s_mounted = nfs_fhget(sb, &data->root, NULL)) != NULL) { /* We're airborne */ - lockd_up(); + if (!(server->flags & NFS_MOUNT_NONLM)) + lockd_up(); return sb; } diff -u --recursive --new-file v2.1.33/linux/fs/nfs/mount_clnt.c linux/fs/nfs/mount_clnt.c --- v2.1.33/linux/fs/nfs/mount_clnt.c Wed Dec 31 16:00:00 1969 +++ linux/fs/nfs/mount_clnt.c Mon Apr 14 09:31:09 1997 @@ -0,0 +1,141 @@ +/* + * linux/fs/nfs/mount_clnt.c + * + * MOUNT client to support NFSroot. + * + * Copyright (C) 1997, Olaf Kirch + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef RPC_DEBUG +# define NFSDBG_FACILITY NFSDBG_ROOT +#endif + +/* +#define MOUNT_PROGRAM 100005 +#define MOUNT_VERSION 1 +#define MOUNT_MNT 1 +#define MOUNT_UMNT 3 + */ + +static struct rpc_clnt * mnt_create(char *, struct sockaddr_in *); +extern struct rpc_program mnt_program; + +struct mnt_fhstatus { + unsigned int status; + struct nfs_fh * fh; +}; + +/* + * Obtain an NFS file handle for the given host and path + */ +int +nfs_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh) +{ + struct rpc_clnt *mnt_clnt; + struct mnt_fhstatus result = { 0, fh }; + char hostname[32]; + int status; + + dprintk("NFS: nfs_mount(%08lx:%s)\n", + ntohl(addr->sin_addr.s_addr), path); + + strcpy(hostname, in_ntoa(addr->sin_addr.s_addr)); + if (!(mnt_clnt = mnt_create(hostname, addr))) + return -EACCES; + + status = rpc_call(mnt_clnt, NFS_MNTPROC_MNT, path, &result, 0); + return status < 0? status : (result.status? -EACCES : 0); +} + +static struct rpc_clnt * +mnt_create(char *hostname, struct sockaddr_in *srvaddr) +{ + struct rpc_xprt *xprt; + struct rpc_clnt *clnt; + + if (!(xprt = xprt_create_proto(IPPROTO_UDP, srvaddr, NULL))) + return NULL; + + clnt = rpc_create_client(xprt, hostname, + &mnt_program, NFS_MNT_VERSION, + RPC_AUTH_NULL); + if (!clnt) { + xprt_destroy(xprt); + } else { + clnt->cl_softrtry = 1; + clnt->cl_chatty = 1; + clnt->cl_oneshot = 1; + } + return clnt; +} + +/* + * XDR encode/decode functions for MOUNT + */ +static int +xdr_error(struct rpc_rqst *req, u32 *p, void *dummy) +{ + return -EIO; +} + +static int +xdr_encode_dirpath(struct rpc_rqst *req, u32 *p, const char *path) +{ + p = xdr_encode_string(p, path); + + req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); + return 0; +} + +static int +xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res) +{ + if ((res->status = ntohl(*p++)) == 0) + memcpy(res->fh, p, sizeof(*res->fh)); + return 0; +} + +#define MNT_dirpath_sz (1 + 256) +#define MNT_fhstatus_sz (1 + 8) + +static struct rpc_procinfo mnt_procedures[2] = { + { "mnt_null", + (kxdrproc_t) xdr_error, + (kxdrproc_t) xdr_error, 0, 0 }, + { "mnt_mount", + (kxdrproc_t) xdr_encode_dirpath, + (kxdrproc_t) xdr_decode_fhstatus, + MNT_dirpath_sz, MNT_fhstatus_sz }, +}; + +static struct rpc_version mnt_version1 = { + 1, 2, mnt_procedures +}; + +static struct rpc_version * mnt_version[] = { + NULL, + &mnt_version1, +}; + +static struct rpc_stat mnt_stats; + +struct rpc_program mnt_program = { + "mount", + NFS_MNT_PROGRAM, + sizeof(mnt_version)/sizeof(mnt_version[0]), + mnt_version, + &mnt_stats, +}; diff -u --recursive --new-file v2.1.33/linux/fs/nfs/nfs2xdr.c linux/fs/nfs/nfs2xdr.c --- v2.1.33/linux/fs/nfs/nfs2xdr.c Sun Apr 13 10:18:22 1997 +++ linux/fs/nfs/nfs2xdr.c Mon Apr 14 09:31:09 1997 @@ -416,6 +416,7 @@ if ((void *) (entry+1) > (void *) string) { printk(KERN_NOTICE "NFS: should not happen in %s!\n", __FUNCTION__); + printk(KERN_NOTICE "NFS: len = %d, entry+1=%p, string=%p\n", len, entry+1, string); break; } diff -u --recursive --new-file v2.1.33/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c --- v2.1.33/linux/fs/nfs/nfsroot.c Mon Apr 7 11:35:31 1997 +++ linux/fs/nfs/nfsroot.c Mon Apr 14 09:31:09 1997 @@ -51,6 +51,9 @@ * without giving a path name. Fix BOOTP request * for domainname (domainname is NIS domain, not * DNS domain!). Skip dummy devices for BOOTP. + * Jacek Zapala : Fixed a bug which prevented server-ip address + * from nfsroot parameter from being used. + * Olaf Kirch : Adapted to new NFS code. * */ @@ -81,8 +84,10 @@ #include /* For AX25_P_IP */ #endif #include +#include #include #include +#include #include #include #include @@ -91,11 +96,13 @@ #include #include +#include +#define NFSDBG_FACILITY NFSDBG_ROOT /* Range of privileged ports */ -#define STARTPORT 600 -#define ENDPORT 1023 -#define NPORTS (ENDPORT - STARTPORT + 1) +#define STARTPORT 600 +#define ENDPORT 1023 +#define NPORTS (ENDPORT - STARTPORT + 1) /* Define the timeout for waiting for a RARP/BOOTP reply */ @@ -119,10 +126,10 @@ /* IP configuration */ static struct device *root_dev = NULL; /* Device selected for booting */ static char user_dev_name[IFNAMSIZ]; /* Name of user-selected boot device */ -static struct sockaddr_in myaddr; /* My IP address */ -static struct sockaddr_in server; /* Server IP address */ -static struct sockaddr_in gateway; /* Gateway IP address */ -static struct sockaddr_in netmask; /* Netmask for local subnet */ +static __u32 myaddr; /* My IP address */ +static __u32 servaddr; /* Server IP address */ +static __u32 gateway; /* Gateway IP address */ +static __u32 netmask; /* Netmask for local subnet */ /* BOOTP/RARP variables */ @@ -130,7 +137,7 @@ static int rarp_flag; /* User said: Use RARP! */ static int bootp_dev_count = 0; /* Number of devices allowing BOOTP */ static int rarp_dev_count = 0; /* Number of devices allowing RARP */ -static struct sockaddr_in rarp_serv; /* IP address of RARP server */ +static __u32 rarp_serv; /* IP address of RARP server */ #if defined(CONFIG_RNFS_BOOTP) || defined(CONFIG_RNFS_RARP) #define CONFIG_RNFS_DYNAMIC /* Enable dynamic IP config */ @@ -143,8 +150,9 @@ /* NFS-related data */ static struct nfs_mount_data nfs_data; /* NFS mount info */ -static char nfs_path[NFS_MAXPATHLEN] = ""; /* Name of directory to mount */ -static int nfs_port; /* Port to connect to for NFS */ +static char nfs_path[NFS_MAXPATHLEN]; /* Name of directory to mount */ +static int nfs_port; /* Port to connect to for NFS */ +static int mount_port; /* Mount daemon port number */ /* Yes, we use sys_socket, but there's no include file for it */ @@ -193,9 +201,7 @@ bootp_dev_count++; if (!(dev->flags & IFF_NOARP)) rarp_dev_count++; -#ifdef NFSROOT_DEBUG - printk(KERN_NOTICE "Root-NFS: Opened %s\n", dev->name); -#endif + dprintk("Root-NFS: Opened %s\n", dev->name); } } *last = NULL; @@ -207,6 +213,58 @@ return 0; } +static inline void +set_sockaddr(struct sockaddr_in *sin, __u32 addr, __u16 port) +{ + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = addr; + sin->sin_port = port; +} + +static int +root_dev_chg_route(int op, struct device *dev, __u32 dest, __u32 mask, __u32 gw) +{ + struct rtentry route; + unsigned long oldfs; + int err; + + route.rt_dev = dev->name; + route.rt_mtu = dev->mtu; + route.rt_flags = RTF_UP; + set_sockaddr((struct sockaddr_in *) &route.rt_dst, dest & mask, 0); + set_sockaddr((struct sockaddr_in *) &route.rt_genmask, mask, 0); + + if (gw != 0) { + set_sockaddr((struct sockaddr_in *) &route.rt_gateway, gw, 0); + route.rt_flags |= RTF_GATEWAY; + if ((gw ^ myaddr) & netmask) { + printk(KERN_ERR "Root-NFS: Gateway not on local network!\n"); + return -ENETUNREACH; + } + } + + oldfs = get_fs(); + set_fs(KERNEL_DS); + err = ip_rt_ioctl(op, &route); + set_fs(oldfs); + printk(KERN_NOTICE "%s route %s %s %s: res %d\n", + (op == SIOCADDRT? "add" : "del"), + in_ntoa(dest), in_ntoa(mask), in_ntoa(gw), err); + + return err; +} + +static int +root_dev_add_route(struct device *dev, __u32 dest, __u32 mask, __u32 gateway) +{ + return root_dev_chg_route(SIOCADDRT, dev, dest, mask, gateway); +} + +static int +root_dev_del_route(struct device *dev, __u32 dest, __u32 mask, __u32 gateway) +{ + return root_dev_chg_route(SIOCDELRT, dev, dest, mask, gateway); +} /* * Restore the state of all devices. However, keep the root device open @@ -290,7 +348,7 @@ unsigned long sip, tip; unsigned char *sha, *tha; /* s for "source", t for "target" */ - /* If this test doesn't pass, its not IP, or we should ignore it anyway */ + /* If this test doesn't pass, it's not IP, or we should ignore it anyway */ if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)) { kfree_skb(skb, FREE_READ); return 0; @@ -328,8 +386,8 @@ } /* Discard packets which are not from specified server. */ if (rarp_flag && !bootp_flag && - rarp_serv.sin_addr.s_addr != INADDR_NONE && - rarp_serv.sin_addr.s_addr != sip) { + rarp_serv != INADDR_NONE && + rarp_serv != sip) { kfree_skb(skb, FREE_READ); return 0; } @@ -348,14 +406,10 @@ sti(); root_dev = dev; - if (myaddr.sin_addr.s_addr == INADDR_NONE) { - myaddr.sin_family = dev->family; - myaddr.sin_addr.s_addr = tip; - } - if (server.sin_addr.s_addr == INADDR_NONE) { - server.sin_family = dev->family; - server.sin_addr.s_addr = sip; - } + if (myaddr == INADDR_NONE) + myaddr = tip; + if (servaddr == INADDR_NONE) + servaddr = sip; kfree_skb(skb, FREE_READ); return 0; } @@ -393,10 +447,8 @@ static struct device *bootp_dev = NULL; /* Device selected as best BOOTP target */ -static int bootp_xmit_fd = -1; /* Socket descriptor for transmit */ -static struct socket *bootp_xmit_sock; /* The socket itself */ -static int bootp_recv_fd = -1; /* Socket descriptor for receive */ -static struct socket *bootp_recv_sock; /* The socket itself */ +static struct socket *bootp_xmit_sock; /* BOOTP send socket */ +static struct socket *bootp_recv_sock; /* BOOTP receive socket */ struct bootp_pkt { /* BOOTP packet format */ u8 op; /* 1=request, 2=reply */ @@ -460,18 +512,8 @@ */ static int root_add_bootp_route(void) { - struct rtentry route; - - memset(&route, 0, sizeof(route)); - route.rt_dev = bootp_dev->name; - route.rt_mss = bootp_dev->mtu; - route.rt_flags = RTF_UP; - ((struct sockaddr_in *) &(route.rt_dst)) -> sin_addr.s_addr = 0; - ((struct sockaddr_in *) &(route.rt_dst)) -> sin_family = AF_INET; - ((struct sockaddr_in *) &(route.rt_genmask)) -> sin_addr.s_addr = 0; - ((struct sockaddr_in *) &(route.rt_genmask)) -> sin_family = AF_INET; - if (ip_rt_new(&route)) { - printk(KERN_ERR "BOOTP: Adding of route failed!\n"); + if (root_dev_add_route(bootp_dev, 0, 0, 0) < 0) { + printk(KERN_ERR "BOOTP: Failed to add route\n"); return -1; } bootp_have_route = 1; @@ -484,14 +526,7 @@ */ static int root_del_bootp_route(void) { - struct rtentry route; - - if (!bootp_have_route) - return 0; - memset(&route, 0, sizeof(route)); - ((struct sockaddr_in *) &(route.rt_dst)) -> sin_addr.s_addr = 0; - ((struct sockaddr_in *) &(route.rt_genmask)) -> sin_addr.s_addr = 0; - if (ip_rt_kill(&route)) { + if (bootp_have_route && root_dev_del_route(bootp_dev, 0, 0, 0) < 0) { printk(KERN_ERR "BOOTP: Deleting of route failed!\n"); return -1; } @@ -503,21 +538,13 @@ /* * Open UDP socket. */ -static int root_open_udp_sock(int *fd, struct socket **sock) +static int root_open_udp_sock(struct socket **sock) { - struct file *file; - struct inode *inode; + int err; - *fd = sys_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (*fd >= 0) { - file = current->files->fd[*fd]; - inode = file->f_inode; - *sock = &inode->u.socket_i; - return 0; - } - - printk(KERN_ERR "BOOTP: Cannot open UDP socket!\n"); - return -1; + if ((err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, sock)) < 0) + printk(KERN_ERR "BOOTP: Cannot open UDP socket!\n"); + return err; } @@ -529,9 +556,7 @@ struct sockaddr_in sa; int result; - sa.sin_family = AF_INET; - sa.sin_addr.s_addr = htonl(addr); - sa.sin_port = htons(port); + set_sockaddr(&sa, htonl(addr), htonl(port)); result = sock->ops->connect(sock, (struct sockaddr *) &sa, sizeof(sa), 0); if (result < 0) { printk(KERN_ERR "BOOTP: connect() failed\n"); @@ -549,9 +574,7 @@ struct sockaddr_in sa; int result; - sa.sin_family = AF_INET; - sa.sin_addr.s_addr = htonl(addr); - sa.sin_port = htons(port); + set_sockaddr(&sa, htonl(addr), htonl(port)); result = sock->ops->bind(sock, (struct sockaddr *) &sa, sizeof(sa)); if (result < 0) { printk(KERN_ERR "BOOTP: bind() failed\n"); @@ -575,12 +598,12 @@ set_fs(get_ds()); iov.iov_base = buf; iov.iov_len = size; - msg.msg_name = NULL; + memset(&msg, 0, sizeof(msg)); msg.msg_iov = &iov; msg.msg_iovlen = 1; - msg.msg_accrights = NULL; - result = sock->ops->sendmsg(sock, &msg, size, 0, 0); + result = sock_sendmsg(sock, &msg, size); set_fs(oldfs); + return (result != size); } @@ -599,12 +622,11 @@ set_fs(get_ds()); iov.iov_base = buf; iov.iov_len = size; - msg.msg_name = NULL; + memset(&msg, 0, sizeof(msg)); + msg.msg_flags = MSG_DONTWAIT; msg.msg_iov = &iov; msg.msg_iovlen = 1; - msg.msg_accrights = NULL; - msg.msg_namelen = 0; - result = sock->ops->recvmsg(sock, &msg, size, O_NONBLOCK, 0, &msg.msg_namelen); + result = sock_recvmsg(sock, &msg, size, MSG_DONTWAIT); set_fs(oldfs); return result; } @@ -643,10 +665,10 @@ */ static void root_bootp_close(void) { - if (bootp_xmit_fd != -1) - sys_close(bootp_xmit_fd); - if (bootp_recv_fd != -1) - sys_close(bootp_recv_fd); + if (bootp_xmit_sock) + sock_release(bootp_xmit_sock); + if (bootp_recv_sock) + sock_release(bootp_recv_sock); root_del_bootp_route(); root_free_bootp(); } @@ -695,6 +717,7 @@ xmit_bootp->hlen = best_dev->addr_len; memcpy(xmit_bootp->hw_addr, best_dev->dev_addr, best_dev->addr_len); root_bootp_init_ext(xmit_bootp->vendor_area); + #ifdef NFSROOT_BOOTP_DEBUG { int x; @@ -714,14 +737,14 @@ return -1; /* Open the sockets */ - if (root_open_udp_sock(&bootp_xmit_fd, &bootp_xmit_sock) || - root_open_udp_sock(&bootp_recv_fd, &bootp_recv_sock)) + if (root_open_udp_sock(&bootp_xmit_sock) || + root_open_udp_sock(&bootp_recv_sock)) return -1; /* Bind/connect the sockets */ - ((struct sock *) bootp_xmit_sock->data) -> broadcast = 1; - ((struct sock *) bootp_xmit_sock->data) -> reuse = 1; - ((struct sock *) bootp_recv_sock->data) -> reuse = 1; + bootp_xmit_sock->sk->broadcast = 1; + bootp_xmit_sock->sk->reuse = 1; + bootp_recv_sock->sk->reuse = 1; if (root_bind_udp_sock(bootp_recv_sock, INADDR_ANY, 68) || root_bind_udp_sock(bootp_xmit_sock, INADDR_ANY, 68) || root_connect_udp_sock(bootp_xmit_sock, INADDR_BROADCAST, 67)) @@ -761,9 +784,9 @@ */ static void root_do_bootp_ext(u8 *ext) { +#ifdef NFSROOT_BOOTP_DEBUG u8 *c; -#ifdef NFSROOT_BOOTP_DEBUG printk("BOOTP: Got extension %02x",*ext); for(c=ext+2; chtype != xmit_bootp->htype || recv_bootp->hlen != xmit_bootp->hlen || recv_bootp->xid != xmit_bootp->xid) { -#ifdef NFSROOT_BOOTP_DEBUG - printk("?"); -#endif + dprintk("?"); return; } @@ -827,9 +848,9 @@ root_dev = bootp_dev; /* Extract basic fields */ - myaddr.sin_addr.s_addr = recv_bootp->your_ip; - if (server.sin_addr.s_addr==INADDR_NONE) - server.sin_addr.s_addr = recv_bootp->server_ip; + myaddr = recv_bootp->your_ip; + if (servaddr==INADDR_NONE) + servaddr = recv_bootp->server_ip; /* Parse extensions */ if (recv_bootp->vendor_area[0] == 99 && /* Check magic cookie */ @@ -983,14 +1004,28 @@ printk(" OK\n"); printk(KERN_NOTICE "Root-NFS: Got %s answer from %s, ", (pkt_arrived == ARRIVED_BOOTP) ? "BOOTP" : "RARP", - in_ntoa(server.sin_addr.s_addr)); - printk("my address is %s\n", in_ntoa(myaddr.sin_addr.s_addr)); + in_ntoa(servaddr)); + printk("my address is %s\n", in_ntoa(myaddr)); return 0; } #endif - +/* Get default netmask - used to be exported from net/ipv4 */ +static unsigned long +ip_get_mask(unsigned long addr) +{ + if (!addr) + return 0; + addr = ntohl(addr); + if (IN_CLASSA(addr)) + return htonl(IN_CLASSA_NET); + if (IN_CLASSB(addr)) + return htonl(IN_CLASSB_NET); + if (IN_CLASSC(addr)) + return htonl(IN_CLASSC_NET); + return 0; +} /*************************************************************************** @@ -1060,22 +1095,24 @@ break; if (*cp == '.' || octets == 3) octets++; + if (octets < 4) + cp++; cq = cp; } if (octets == 4 && (*cp == ':' || *cp == '\0')) { if (*cp == ':') *cp++ = '\0'; - server.sin_addr.s_addr = in_aton(name); + servaddr = in_aton(name); name = cp; } /* Clear the nfs_data structure and setup the server hostname */ memset(&nfs_data, 0, sizeof(nfs_data)); - strncpy(nfs_data.hostname, in_ntoa(server.sin_addr.s_addr), + strncpy(nfs_data.hostname, in_ntoa(servaddr), sizeof(nfs_data.hostname)-1); /* Set the name of the directory to mount */ - if (nfs_path[0] == '\0' || !strncmp(name, "default", 7)) + if (nfs_path[0] == '\0' || strncmp(name, "default", 7)) strncpy(buf, name, NFS_MAXPATHLEN); else strncpy(buf, nfs_path, NFS_MAXPATHLEN); @@ -1083,7 +1120,7 @@ *options++ = '\0'; if (!strcmp(buf, "default")) strcpy(buf, NFS_ROOT); - cp = in_ntoa(myaddr.sin_addr.s_addr); + cp = in_ntoa(myaddr); if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) { printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n"); return -1; @@ -1094,10 +1131,11 @@ /* Set some default values */ nfs_port = -1; - nfs_data.version = NFS_MOUNT_VERSION; - nfs_data.flags = 0; + nfs_data.version = NFS_MNT_VERSION; + nfs_data.flags = NFS_MOUNT_NONLM; /* No lockd in nfs root yet */ nfs_data.rsize = NFS_DEF_FILE_IO_BUFFER_SIZE; nfs_data.wsize = NFS_DEF_FILE_IO_BUFFER_SIZE; + nfs_data.bsize = 0; nfs_data.timeo = 7; nfs_data.retrans = 3; nfs_data.acregmin = 3; @@ -1135,17 +1173,17 @@ /* * Tell the user what's going on. */ -#ifdef NFSROOT_DEBUG +#ifdef NFSROOT_BOOTP static void root_nfs_print(void) { #define IN_NTOA(x) (((x) == INADDR_NONE) ? "none" : in_ntoa(x)) printk(KERN_NOTICE "Root-NFS: IP config: dev=%s, ", root_dev ? root_dev->name : "none"); - printk("local=%s, ", IN_NTOA(myaddr.sin_addr.s_addr)); - printk("server=%s, ", IN_NTOA(server.sin_addr.s_addr)); - printk("gw=%s, ", IN_NTOA(gateway.sin_addr.s_addr)); - printk("mask=%s, ", IN_NTOA(netmask.sin_addr.s_addr)); + printk("local=%s, ", IN_NTOA(myaddr)); + printk("server=%s, ", IN_NTOA(servaddr)); + printk("gw=%s, ", IN_NTOA(gateway)); + printk("mask=%s, ", IN_NTOA(netmask)); printk("host=%s, domain=%s\n", system_utsname.nodename[0] ? system_utsname.nodename : "none", system_utsname.domainname[0] ? system_utsname.domainname : "none"); @@ -1189,10 +1227,7 @@ int num = 0; /* Clear all addresses and strings */ - myaddr.sin_family = server.sin_family = rarp_serv.sin_family = - gateway.sin_family = netmask.sin_family = AF_INET; - myaddr.sin_addr.s_addr = server.sin_addr.s_addr = rarp_serv.sin_addr.s_addr = - gateway.sin_addr.s_addr = netmask.sin_addr.s_addr = INADDR_NONE; + myaddr = servaddr = rarp_serv = gateway = netmask = INADDR_NONE; system_utsname.nodename[0] = '\0'; system_utsname.domainname[0] = '\0'; user_dev_name[0] = '\0'; @@ -1215,26 +1250,24 @@ if ((cp = strchr(ip, ':'))) *cp++ = '\0'; if (strlen(ip) > 0) { -#ifdef NFSROOT_DEBUG - printk(KERN_NOTICE "Root-NFS: Config string num %d is \"%s\"\n", + dprintk("Root-NFS: Config string num %d is \"%s\"\n", num, ip); -#endif switch (num) { case 0: - if ((myaddr.sin_addr.s_addr = in_aton(ip)) == INADDR_ANY) - myaddr.sin_addr.s_addr = INADDR_NONE; + if ((myaddr = in_aton(ip)) == INADDR_ANY) + myaddr = INADDR_NONE; break; case 1: - if ((server.sin_addr.s_addr = in_aton(ip)) == INADDR_ANY) - server.sin_addr.s_addr = INADDR_NONE; + if ((servaddr = in_aton(ip)) == INADDR_ANY) + servaddr = INADDR_NONE; break; case 2: - if ((gateway.sin_addr.s_addr = in_aton(ip)) == INADDR_ANY) - gateway.sin_addr.s_addr = INADDR_NONE; + if ((gateway = in_aton(ip)) == INADDR_ANY) + gateway = INADDR_NONE; break; case 3: - if ((netmask.sin_addr.s_addr = in_aton(ip)) == INADDR_ANY) - netmask.sin_addr.s_addr = INADDR_NONE; + if ((netmask = in_aton(ip)) == INADDR_ANY) + netmask = INADDR_NONE; break; case 4: if ((dp = strchr(ip, '.'))) { @@ -1264,7 +1297,7 @@ ip = cp; num++; } - rarp_serv = server; + rarp_serv = servaddr; } @@ -1273,22 +1306,20 @@ */ static int root_nfs_setup(void) { - struct rtentry route; - /* Set the default system name in case none was previously found */ if (!system_utsname.nodename[0]) { - strncpy(system_utsname.nodename, in_ntoa(myaddr.sin_addr.s_addr), __NEW_UTS_LEN); + strncpy(system_utsname.nodename, in_ntoa(myaddr), __NEW_UTS_LEN); system_utsname.nodename[__NEW_UTS_LEN] = '\0'; } /* Set the correct netmask */ - if (netmask.sin_addr.s_addr == INADDR_NONE) - netmask.sin_addr.s_addr = ip_get_mask(myaddr.sin_addr.s_addr); + if (netmask == INADDR_NONE) + netmask = ip_get_mask(myaddr); /* Setup the device correctly */ - root_dev->family = myaddr.sin_family; - root_dev->pa_addr = myaddr.sin_addr.s_addr; - root_dev->pa_mask = netmask.sin_addr.s_addr; + root_dev->family = AF_INET; + root_dev->pa_addr = myaddr; + root_dev->pa_mask = netmask; root_dev->pa_brdaddr = root_dev->pa_addr | ~root_dev->pa_mask; root_dev->pa_dstaddr = 0; @@ -1300,32 +1331,18 @@ * gatewayed default route. Note that this gives sufficient network * setup even for full system operation in all common cases. */ - memset(&route, 0, sizeof(route)); /* Local subnet route */ - route.rt_dev = root_dev->name; - route.rt_mss = root_dev->mtu; - route.rt_flags = RTF_UP; - *((struct sockaddr_in *) &(route.rt_dst)) = myaddr; - (((struct sockaddr_in *) &(route.rt_dst)))->sin_addr.s_addr &= netmask.sin_addr.s_addr; - *((struct sockaddr_in *) &(route.rt_genmask)) = netmask; - if (ip_rt_new(&route)) { + if (root_dev_add_route(root_dev, myaddr, netmask, 0)) + { printk(KERN_ERR "Root-NFS: Adding of local route failed!\n"); return -1; } - if (gateway.sin_addr.s_addr != INADDR_NONE) { /* Default route */ - (((struct sockaddr_in *) &(route.rt_dst)))->sin_addr.s_addr = INADDR_ANY; - (((struct sockaddr_in *) &(route.rt_genmask)))->sin_addr.s_addr = INADDR_ANY; - *((struct sockaddr_in *) &(route.rt_gateway)) = gateway; - route.rt_flags |= RTF_GATEWAY; - if ((gateway.sin_addr.s_addr ^ myaddr.sin_addr.s_addr) & netmask.sin_addr.s_addr) { - printk(KERN_ERR "Root-NFS: Gateway not on local network!\n"); - return -1; - } - if (ip_rt_new(&route)) { + if (gateway != INADDR_NONE) { /* Default route */ + if (root_dev_add_route(root_dev, INADDR_ANY, INADDR_ANY, gateway)) { printk(KERN_ERR "Root-NFS: Adding of default route failed!\n"); return -1; } - } else if ((server.sin_addr.s_addr ^ myaddr.sin_addr.s_addr) & netmask.sin_addr.s_addr) { + } else if ((servaddr ^ myaddr) & netmask) { printk(KERN_ERR "Root-NFS: Boot server not on local network and no default gateway configured!\n"); return -1; } @@ -1340,6 +1357,10 @@ */ int nfs_root_init(char *nfsname, char *nfsaddrs) { +#ifdef NFSROOT_DEBUG + nfs_debug |= NFSDBG_ROOT; +#endif + /* * Decode IP addresses and other configuration info contained * in the nfsaddrs string (which came from the kernel command @@ -1365,8 +1386,8 @@ * in the (diskless) system and if the server is on another subnet. * If only one interface is installed, the routing is obvious. */ - if ((myaddr.sin_addr.s_addr == INADDR_NONE || - server.sin_addr.s_addr == INADDR_NONE || + if ((myaddr == INADDR_NONE || + servaddr == INADDR_NONE || (open_base != NULL && open_base->next != NULL)) #ifdef CONFIG_RNFS_DYNAMIC && root_auto_config() < 0 @@ -1420,206 +1441,50 @@ Routines to actually mount the root directory ***************************************************************************/ - -static struct file *nfs_file; /* File descriptor pointing to inode */ -static struct inode *nfs_sock_inode; /* Inode containing socket */ -static int *rpc_packet = NULL; /* RPC packet */ - - -/* - * Open a UDP socket. - */ -static int root_nfs_open(void) -{ - /* Open the socket */ - if ((nfs_data.fd = sys_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { - printk(KERN_ERR "Root-NFS: Cannot open UDP socket for NFS!\n"); - return -1; - } - nfs_file = current->files->fd[nfs_data.fd]; - nfs_sock_inode = nfs_file->f_inode; - return 0; -} - - -/* - * Close the UDP file descriptor. If nfs_read_super is successful, it - * increases the reference count, so we can simply close the file, and - * the socket keeps open. - */ -static void root_nfs_close(void) -{ - /* - * The following close doesn't touch the server structure, which - * now contains a file pointer pointing into nowhere. The system - * _should_ crash as soon as someone tries to select on the root - * filesystem. Haven't tried it yet - we can still change it back - * to the old way of keeping a static copy of all important data - * structures, including their pointers. At least this should be - * checked out _carefully_ before going into a public release - * kernel. - GK - */ - sys_close(nfs_data.fd); -} - - -/* - * Find a suitable listening port and bind to it - */ -static int root_nfs_bind(void) -{ - int res = -1; - short port = STARTPORT; - struct sockaddr_in *sin = &myaddr; - int i; - - if (nfs_sock_inode->u.socket_i.ops->bind) { - for (i = 0; i < NPORTS && res < 0; i++) { - sin->sin_port = htons(port++); - if (port > ENDPORT) { - port = STARTPORT; - } - res = nfs_sock_inode->u.socket_i.ops->bind(&nfs_sock_inode->u.socket_i, - (struct sockaddr *)sin, - sizeof(struct sockaddr_in)); - } - } - if (res < 0) { - printk(KERN_ERR "Root-NFS: Cannot find a suitable listening port\n"); - root_nfs_close(); - return -1; - } -#ifdef NFSROOT_DEBUG - printk(KERN_NOTICE "Root-NFS: Binding to listening port %d\n", port); -#endif - return 0; -} - - -/* - * Send an RPC request and wait for the answer - */ -static int *root_nfs_call(int *end) -{ - struct socket *sock; - int dummylen; - static struct nfs_server s = { - 0, /* struct file * */ - 0, /* struct rsock * */ - { - 0, "", - }, /* toaddr */ - 0, /* lock */ - NULL, /* wait queue */ - NFS_MOUNT_SOFT, /* flags */ - 0, 0, /* rsize, wsize */ - 0, /* timeo */ - 0, /* retrans */ - 3 * HZ, 60 * HZ, 30 * HZ, 60 * HZ, "\0" - }; - - s.file = nfs_file; - sock = &((nfs_file->f_inode)->u.socket_i); - - /* Extract the other end of the socket into s->toaddr */ - sock->ops->getname(sock, &(s.toaddr), &dummylen, 1); - ((struct sockaddr_in *) &s.toaddr)->sin_port = server.sin_port; - ((struct sockaddr_in *) &s.toaddr)->sin_family = server.sin_family; - ((struct sockaddr_in *) &s.toaddr)->sin_addr.s_addr = server.sin_addr.s_addr; - - s.rsock = rpc_makesock(nfs_file); - s.flags = nfs_data.flags; - s.rsize = nfs_data.rsize; - s.wsize = nfs_data.wsize; - s.timeo = nfs_data.timeo * HZ / 10; - s.retrans = nfs_data.retrans; - strcpy(s.hostname, nfs_data.hostname); - - /* - * First connect the UDP socket to a server port, then send the - * packet out, and finally check whether the answer is OK. - */ - if (nfs_sock_inode->u.socket_i.ops->connect && - nfs_sock_inode->u.socket_i.ops->connect(&nfs_sock_inode->u.socket_i, - (struct sockaddr *) &server, - sizeof(struct sockaddr_in), - nfs_file->f_flags) < 0) - return NULL; - if (nfs_rpc_call(&s, rpc_packet, end, nfs_data.wsize) < 0) - return NULL; - return rpc_verify(rpc_packet); -} - - -/* - * Create an RPC packet header - */ -static int *root_nfs_header(int proc, int program, int version) -{ - int groups[] = { 0, NOGROUP }; - - if (rpc_packet == NULL) { - if (!(rpc_packet = kmalloc(nfs_data.wsize + 1024, GFP_NFS))) { - printk(KERN_ERR "Root-NFS: Cannot allocate UDP buffer\n"); - return NULL; - } - } - return rpc_header(rpc_packet, proc, program, version, 0, 0, groups); -} - - /* * Query server portmapper for the port of a daemon program */ -static int root_nfs_get_port(int program, int version) +static int root_nfs_getport(int program, int version) { - int *p; - - /* Prepare header for portmap request */ - server.sin_port = htons(NFS_PMAP_PORT); - p = root_nfs_header(NFS_PMAP_PROC, NFS_PMAP_PROGRAM, NFS_PMAP_VERSION); - if (!p) - return -1; + struct sockaddr_in sin; - /* Set arguments for portmapper */ - *p++ = htonl(program); - *p++ = htonl(version); - *p++ = htonl(IPPROTO_UDP); - *p++ = 0; - - /* Send request to server portmapper */ - if ((p = root_nfs_call(p)) == NULL) - return -1; - - return ntohl(*p); +printk(KERN_NOTICE "Looking up port of RPC %d/%d on %s\n", + program, version, in_ntoa(servaddr)); + set_sockaddr(&sin, servaddr, 0); + return rpc_getport_external(&sin, program, version, IPPROTO_UDP); } /* * Get portnumbers for mountd and nfsd from server + * The RPC layer does support portmapper queries; the only reason to + * keep this code is that we may want to use fallback ports. But is there + * actually someone who does not run portmap? */ static int root_nfs_ports(void) { - int port; + int port; if (nfs_port < 0) { - if ((port = root_nfs_get_port(NFS_NFS_PROGRAM, NFS_NFS_VERSION)) < 0) { - printk(KERN_ERR "Root-NFS: Unable to get nfsd port number from server, using default\n"); - port = NFS_NFS_PORT; + if ((port = root_nfs_getport(NFS_PROGRAM, NFS_VERSION)) < 0) { + printk(KERN_ERR "Root-NFS: Unable to get nfsd port " + "number from server, using default\n"); + port = NFS_PORT; } nfs_port = port; -#ifdef NFSROOT_DEBUG - printk(KERN_NOTICE "Root-NFS: Portmapper on server returned %d as nfsd port\n", port); -#endif + dprintk("Root-NFS: Portmapper on server returned %d " + "as nfsd port\n", port); } - if ((port = root_nfs_get_port(NFS_MOUNT_PROGRAM, NFS_MOUNT_VERSION)) < 0) { - printk(KERN_ERR "Root-NFS: Unable to get mountd port number from server, using default\n"); - port = NFS_MOUNT_PORT; + + if ((port = root_nfs_getport(NFS_MNT_PROGRAM, NFS_MNT_VERSION)) < 0) { + printk(KERN_ERR "Root-NFS: Unable to get mountd port " + "number from server, using default\n"); + port = NFS_MNT_PORT; } - server.sin_port = htons(port); -#ifdef NFSROOT_DEBUG - printk(KERN_NOTICE "Root-NFS: Portmapper on server returned %d as mountd port\n", port); -#endif + + mount_port = htons(port); + dprintk("Root-NFS: Portmapper on server returned %d " + "as mountd port\n", port); return 0; } @@ -1631,40 +1496,16 @@ */ static int root_nfs_get_handle(void) { - int len, status, *p; - - /* Prepare header for mountd request */ - p = root_nfs_header(NFS_MOUNT_PROC, NFS_MOUNT_PROGRAM, NFS_MOUNT_VERSION); - if (!p) { - root_nfs_close(); - return -1; - } + struct sockaddr_in sin; + int status; - /* Set arguments for mountd */ - len = strlen(nfs_path); - *p++ = htonl(len); - memcpy(p, nfs_path, len); - len = (len + 3) >> 2; - p[len] = 0; - p += len; - - /* Send request to server mountd */ - if ((p = root_nfs_call(p)) == NULL) { - root_nfs_close(); - return -1; - } - status = ntohl(*p++); - if (status == 0) { - nfs_data.root = *((struct nfs_fh *) p); - printk(KERN_NOTICE "Root-NFS: Got file handle for %s via RPC\n", nfs_path); - } else { - printk(KERN_ERR "Root-NFS: Server returned error %d while mounting %s\n", - status, nfs_path); - root_nfs_close(); - return -1; - } + set_sockaddr(&sin, servaddr, mount_port); + status = nfs_mount(&sin, nfs_path, &nfs_data.root); + if (status < 0) + printk(KERN_ERR "Root-NFS: Server returned error %d " + "while mounting %s\n", status, nfs_path); - return 0; + return status; } @@ -1673,23 +1514,12 @@ */ static int root_nfs_do_mount(struct super_block *sb) { - /* First connect to the nfsd port on the server */ - server.sin_port = htons(nfs_port); - nfs_data.addr = server; - if (nfs_sock_inode->u.socket_i.ops->connect && - nfs_sock_inode->u.socket_i.ops->connect(&nfs_sock_inode->u.socket_i, - (struct sockaddr *) &server, - sizeof(struct sockaddr_in), - nfs_file->f_flags) < 0) { - root_nfs_close(); - return -1; - } + /* Pass the server address to NFS */ + set_sockaddr((struct sockaddr_in *) &nfs_data.addr, servaddr, nfs_port); /* Now (finally ;-)) read the super block for mounting */ - if (nfs_read_super(sb, &nfs_data, 1) == NULL) { - root_nfs_close(); + if (nfs_read_super(sb, &nfs_data, 1) == NULL) return -1; - } return 0; } @@ -1700,16 +1530,11 @@ */ int nfs_root_mount(struct super_block *sb) { - if (root_nfs_open() < 0) - return -1; - if (root_nfs_bind() < 0) - return -1; if (root_nfs_ports() < 0) return -1; if (root_nfs_get_handle() < 0) return -1; if (root_nfs_do_mount(sb) < 0) return -1; - root_nfs_close(); return 0; } diff -u --recursive --new-file v2.1.33/linux/fs/nfs/read.c linux/fs/nfs/read.c --- v2.1.33/linux/fs/nfs/read.c Mon Apr 7 11:35:31 1997 +++ linux/fs/nfs/read.c Mon Apr 14 09:31:09 1997 @@ -189,7 +189,7 @@ if (result >= 0) { inode->i_count++; - page->count++; + atomic_inc(&page->count); return 0; } @@ -219,7 +219,7 @@ dprintk("NFS: nfs_readpage %08lx\n", page_address(page)); set_bit(PG_locked, &page->flags); address = page_address(page); - page->count++; + atomic_inc(&page->count); if (!IS_SWAPFILE(inode) && !PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_SIZE) error = nfs_readpage_async(inode, page); diff -u --recursive --new-file v2.1.33/linux/fs/nfs/write.c linux/fs/nfs/write.c --- v2.1.33/linux/fs/nfs/write.c Mon Apr 7 11:35:31 1997 +++ linux/fs/nfs/write.c Mon Apr 14 09:31:09 1997 @@ -339,7 +339,7 @@ wreq->wb_offset = offset; wreq->wb_bytes = bytes; inode->i_count++; - page->count++; + atomic_inc(&page->count); append_write_request(&NFS_WRITEBACK(inode), wreq); @@ -399,7 +399,7 @@ struct page *page = req->wb_page; add_wait_queue(&page->wait, &wait); - page->count++; + atomic_inc(&page->count); repeat: current->state = TASK_INTERRUPTIBLE; if (PageLocked(page)) { diff -u --recursive --new-file v2.1.33/linux/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c --- v2.1.33/linux/fs/nfsd/nfssvc.c Mon Apr 7 11:35:31 1997 +++ linux/fs/nfsd/nfssvc.c Mon Apr 14 09:31:09 1997 @@ -35,7 +35,8 @@ #define NFSDDBG_FACILITY NFSDDBG_SVC #define NFSD_BUFSIZE (1024 + NFSSVC_MAXBLKSIZE) -#define BLOCKABLE_SIGS (~(_S(SIGKILL - 1) | _S(SIGSTOP - 1))) +#define BLOCKABLE_SIGS (~(_S(SIGKILL) | _S(SIGSTOP))) +#define SHUTDOWN_SIGS (_S(SIGKILL)|_S(SIGINT)|_S(SIGTERM)) #define _S(sig) (1 << ((sig) - 1)) extern struct svc_program nfsd_program; @@ -107,6 +108,7 @@ sprintf(current->comm, "nfsd"); oldumask = current->fs->umask; /* Set umask to 0. */ + current->blocked |= ~SHUTDOWN_SIGS; current->fs->umask = 0; nfssvc_boot = xtime; /* record boot time */ lockd_up(); /* start lockd */ @@ -150,8 +152,16 @@ exp_unlock(); } while (err >= 0); - if (err != -EINTR) + if (err != -EINTR) { printk(KERN_WARNING "nfsd: terminating on error %d\n", -err); + } else { + unsigned int signo; + + for (signo = 0; signo < 32; signo++) + if (current->signal & current->blocked & (1< #include #include -#include +#include #include #include @@ -837,7 +837,7 @@ return 0; if ((err = nfsd_open(rqstp, fhp, S_IFDIR, OPEN_READ, &file)) != 0) - return nfserrno(-err); + return err; if (!file.f_op->readdir) { nfsd_close(&file); diff -u --recursive --new-file v2.1.33/linux/fs/proc/array.c linux/fs/proc/array.c --- v2.1.33/linux/fs/proc/array.c Thu Mar 27 14:40:06 1997 +++ linux/fs/proc/array.c Mon Apr 14 11:54:33 1997 @@ -123,7 +123,6 @@ &proc_kcore_operations, }; - /* * This function accesses profiling information. The returned data is * binary: the sampling step and the actual contents of the profile @@ -155,16 +154,38 @@ return read; } -/* Writing to /proc/profile resets the counters */ +#ifdef __SMP__ + +extern int setup_profiling_timer (unsigned int multiplier); + +/* + * Writing to /proc/profile resets the counters + * + * Writing a 'profiling multiplier' value into it also re-sets the profiling + * interrupt frequency, on architectures that support this. + */ static long write_profile(struct inode * inode, struct file * file, const char * buf, unsigned long count) { - int i=prof_len; + int i=prof_len; - while (i--) - prof_buffer[i]=0UL; - return count; + if (count==sizeof(int)) { + unsigned int multiplier; + + if (copy_from_user(&multiplier, buf, sizeof(int))) + return -EFAULT; + + if (setup_profiling_timer(multiplier)) + return -EINVAL; + } + + while (i--) + prof_buffer[i]=0UL; + return count; } +#else +#define write_profile NULL +#endif static struct file_operations proc_profile_operations = { NULL, /* lseek */ @@ -801,7 +822,7 @@ ++*dirty; if (MAP_NR(pte_page(page)) >= max_mapnr) continue; - if (mem_map[MAP_NR(pte_page(page))].count > 1) + if (atomic_read(&mem_map[MAP_NR(pte_page(page))].count) > 1) ++*shared; } while (address < end); } diff -u --recursive --new-file v2.1.33/linux/fs/proc/mem.c linux/fs/proc/mem.c --- v2.1.33/linux/fs/proc/mem.c Sun Jan 26 02:07:45 1997 +++ linux/fs/proc/mem.c Mon Apr 14 09:31:09 1997 @@ -298,7 +298,7 @@ set_pte(src_table, pte_mkdirty(*src_table)); set_pte(dest_table, *src_table); - mem_map[MAP_NR(pte_page(*src_table))].count++; + atomic_inc(&mem_map[MAP_NR(pte_page(*src_table))].count); stmp += PAGE_SIZE; dtmp += PAGE_SIZE; diff -u --recursive --new-file v2.1.33/linux/fs/proc/openpromfs.c linux/fs/proc/openpromfs.c --- v2.1.33/linux/fs/proc/openpromfs.c Fri Apr 4 08:52:24 1997 +++ linux/fs/proc/openpromfs.c Mon Apr 14 09:31:09 1997 @@ -1,4 +1,4 @@ -/* $Id: openpromfs.c,v 1.12 1997/01/26 07:14:18 davem Exp $ +/* $Id: openpromfs.c,v 1.13 1997/04/03 08:49:25 davem Exp $ * openpromfs.c: /proc/openprom handling routines * * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) diff -u --recursive --new-file v2.1.33/linux/fs/romfs/inode.c linux/fs/romfs/inode.c --- v2.1.33/linux/fs/romfs/inode.c Sun Jan 26 02:07:45 1997 +++ linux/fs/romfs/inode.c Mon Apr 14 09:31:09 1997 @@ -373,7 +373,7 @@ int result = -EIO; buf = page_address(page); - page->count++; + atomic_inc(&page->count); offset = page->offset; if (offset < inode->i_size) { avail = inode->i_size-offset; diff -u --recursive --new-file v2.1.33/linux/fs/super.c linux/fs/super.c --- v2.1.33/linux/fs/super.c Mon Apr 7 11:35:31 1997 +++ linux/fs/super.c Mon Apr 14 09:31:09 1997 @@ -99,7 +99,7 @@ memset(lptr, 0, sizeof(struct vfsmount)); lptr->mnt_dev = dev; - lptr->mnt_sem.count = 1; + sema_init(&lptr->mnt_sem, 1); if (dev_name && !getname(dev_name, &tmp)) { if ((lptr->mnt_devname = (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL) diff -u --recursive --new-file v2.1.33/linux/include/asm-alpha/atomic.h linux/include/asm-alpha/atomic.h --- v2.1.33/linux/include/asm-alpha/atomic.h Fri Apr 4 08:52:24 1997 +++ linux/include/asm-alpha/atomic.h Mon Apr 14 09:31:09 1997 @@ -9,7 +9,16 @@ * than regular operations. */ -typedef int atomic_t; +#ifdef __SMP__ +typedef struct { volatile int counter; } atomic_t; +#else +typedef struct { int counter; } atomic_t; +#endif + +#define ATOMIC_INIT { 0 } + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v) (((v)->counter) = i) /* * Make sure gcc doesn't try to be clever and move things around @@ -24,7 +33,7 @@ * branch back to restart the operation. */ -extern __inline__ void atomic_add(atomic_t i, atomic_t * v) +extern __inline__ void atomic_add(int i, atomic_t * v) { unsigned long temp; __asm__ __volatile__( @@ -39,7 +48,7 @@ :"Ir" (i), "m" (__atomic_fool_gcc(v))); } -extern __inline__ void atomic_sub(atomic_t i, atomic_t * v) +extern __inline__ void atomic_sub(int i, atomic_t * v) { unsigned long temp; __asm__ __volatile__( @@ -57,7 +66,7 @@ /* * Same as above, but return the result value */ -extern __inline__ long atomic_add_return(atomic_t i, atomic_t * v) +extern __inline__ long atomic_add_return(int i, atomic_t * v) { long temp, result; __asm__ __volatile__( @@ -74,7 +83,7 @@ return result; } -extern __inline__ long atomic_sub_return(atomic_t i, atomic_t * v) +extern __inline__ long atomic_sub_return(int i, atomic_t * v) { long temp, result; __asm__ __volatile__( diff -u --recursive --new-file v2.1.33/linux/include/asm-alpha/checksum.h linux/include/asm-alpha/checksum.h --- v2.1.33/linux/include/asm-alpha/checksum.h Tue Mar 4 10:25:26 1997 +++ linux/include/asm-alpha/checksum.h Fri Apr 11 10:37:41 1997 @@ -53,7 +53,7 @@ * this is a new version of the above that records errors it finds in *errp, * but continues and zeros the rest of the buffer. */ -unsigned int csum_partial_copy_from_user(char *src, char *dst, int len, unsigned int sum, int *errp); +unsigned int csum_partial_copy_from_user(const char *src, char *dst, int len, unsigned int sum, int *errp); /* * this routine is used for miscellaneous IP-like checksums, mainly diff -u --recursive --new-file v2.1.33/linux/include/asm-alpha/hardirq.h linux/include/asm-alpha/hardirq.h --- v2.1.33/linux/include/asm-alpha/hardirq.h Fri Apr 4 08:52:24 1997 +++ linux/include/asm-alpha/hardirq.h Mon Apr 14 14:10:37 1997 @@ -1,20 +1,24 @@ #ifndef _ALPHA_HARDIRQ_H #define _ALPHA_HARDIRQ_H +#include + extern unsigned int local_irq_count[NR_CPUS]; -#define in_interrupt() (local_irq_count[smp_processor_id()] != 0) +#define in_interrupt() (local_irq_count[smp_processor_id()] != 0) #ifndef __SMP__ -#define hardirq_trylock(cpu) ((cpu) == 0) +#define hardirq_trylock(cpu) (local_irq_count[cpu] == 0) #define hardirq_endlock(cpu) do { } while (0) #define hardirq_enter(cpu) (local_irq_count[cpu]++) #define hardirq_exit(cpu) (local_irq_count[cpu]--) +#define synchronize_irq() do { } while (0) + #else -#error FIXME +#error No habla alpha SMP #endif /* __SMP__ */ #endif /* _ALPHA_HARDIRQ_H */ diff -u --recursive --new-file v2.1.33/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h --- v2.1.33/linux/include/asm-alpha/io.h Sun Oct 6 22:55:48 1996 +++ linux/include/asm-alpha/io.h Thu Apr 10 14:03:51 1997 @@ -38,7 +38,8 @@ */ extern inline void set_hae(unsigned long new_hae) { - unsigned long ipl = swpipl(7); + unsigned long ipl; + swpipl(ipl,7); hae.cache = new_hae; *hae.reg = new_hae; mb(); diff -u --recursive --new-file v2.1.33/linux/include/asm-alpha/semaphore.h linux/include/asm-alpha/semaphore.h --- v2.1.33/linux/include/asm-alpha/semaphore.h Wed Jan 15 18:47:21 1997 +++ linux/include/asm-alpha/semaphore.h Mon Apr 14 09:31:09 1997 @@ -15,12 +15,29 @@ struct wait_queue * wait; }; -#define MUTEX ((struct semaphore) { 1, 0, NULL }) -#define MUTEX_LOCKED ((struct semaphore) { 0, 0, NULL }) +#define MUTEX ((struct semaphore) { { 1 }, { 0 }, NULL }) +#define MUTEX_LOCKED ((struct semaphore) { { 0 }, { 0 }, NULL }) extern void __down(struct semaphore * sem); extern int __down_interruptible(struct semaphore * sem); extern void __up(struct semaphore * sem); + +#define sema_init(sem, val) atomic_set(&((sem)->count), val) + +static inline int waking_non_zero(struct semaphore *sem) +{ + unsigned long flags; + int ret = 0; + + save_flags(flags); + cli(); + if (atomic_read(&sem->waking) > 0) { + atomic_dec(&sem->waking); + ret = 1; + } + restore_flags(flags); + return ret; +} /* * This isn't quite as clever as the x86 side, but the gp register diff -u --recursive --new-file v2.1.33/linux/include/asm-alpha/softirq.h linux/include/asm-alpha/softirq.h --- v2.1.33/linux/include/asm-alpha/softirq.h Fri Apr 4 08:52:24 1997 +++ linux/include/asm-alpha/softirq.h Mon Apr 14 09:31:09 1997 @@ -1,9 +1,12 @@ #ifndef _ALPHA_SOFTIRQ_H #define _ALPHA_SOFTIRQ_H -/* - * Software interrupts.. +/* The locking mechanism for base handlers, to prevent re-entrancy, + * is entirely private to an implementation, it should not be + * referenced at all outside of this file. */ +extern atomic_t __alpha_bh_counter; + #define get_active_bhs() (bh_mask & bh_active) static inline void clear_active_bhs(unsigned long x) @@ -21,11 +24,60 @@ :"Ir" (x), "m" (bh_active)); } +extern inline void init_bh(int nr, void (*routine)(void)) +{ + bh_base[nr] = routine; + bh_mask_count[nr] = 0; + bh_mask |= 1 << nr; +} + +extern inline void mark_bh(int nr) +{ + set_bit(nr, &bh_active); +} + +/* + * These use a mask count to correctly handle + * nested disable/enable calls + */ +extern inline void disable_bh(int nr) +{ + bh_mask &= ~(1 << nr); + bh_mask_count[nr]++; +} + +extern inline void enable_bh(int nr) +{ + if (!--bh_mask_count[nr]) + bh_mask |= 1 << nr; +} + +/* + * start_bh_atomic/end_bh_atomic also nest + * naturally by using a counter + */ +extern inline void start_bh_atomic(void) +{ +#ifdef __SMP__ + atomic_inc(&__alpha_bh_counter); + synchronize_irq(); +#else + atomic_inc(&__alpha_bh_counter); +#endif +} + +extern inline void end_bh_atomic(void) +{ + atomic_dec(&__alpha_bh_counter); +} + #ifndef __SMP__ /* These are for the irq's testing the lock */ -#define softirq_trylock() (intr_count ? 0 : ((intr_count=1),1)) -#define softirq_endlock() (intr_count = 0) +#define softirq_trylock() (atomic_read(&__alpha_bh_counter) ? \ + 0 : \ + ((atomic_set(&__alpha_bh_counter,1)),1)) +#define softirq_endlock() (atomic_set(&__alpha_bh_counter, 0)) #else diff -u --recursive --new-file v2.1.33/linux/include/asm-alpha/uaccess.h linux/include/asm-alpha/uaccess.h --- v2.1.33/linux/include/asm-alpha/uaccess.h Sun Jan 26 02:07:46 1997 +++ linux/include/asm-alpha/uaccess.h Fri Apr 11 10:37:44 1997 @@ -352,10 +352,27 @@ * Complex access routines */ +#define __copy_to_user(to,from,n) __copy_tofrom_user_nocheck((to),(from),(n)) +#define __copy_from_user(to,from,n) __copy_tofrom_user_nocheck((to),(from),(n)) + #define copy_to_user(to,from,n) __copy_tofrom_user((to),(from),(n),__cu_to) #define copy_from_user(to,from,n) __copy_tofrom_user((to),(from),(n),__cu_from) extern void __copy_user(void); + +#define __copy_tofrom_user_nocheck(to,from,n) \ +({ \ + register void * __cu_to __asm__("$6") = (to); \ + register const void * __cu_from __asm__("$7") = (from); \ + register long __cu_len __asm__("$0") = (n); \ + __asm__ __volatile__( \ + "jsr $28,(%3),__copy_user" \ + : "=r" (__cu_len), "=r" (__cu_from), "=r" (__cu_to) \ + : "r" (__copy_user), "0" (__cu_len), \ + "1" (__cu_from), "2" (__cu_to) \ + : "$1","$2","$3","$4","$5","$28","memory"); \ + __cu_len; \ +}) #define __copy_tofrom_user(to,from,n,v) \ ({ \ diff -u --recursive --new-file v2.1.33/linux/include/asm-i386/atomic.h linux/include/asm-i386/atomic.h --- v2.1.33/linux/include/asm-i386/atomic.h Thu Mar 27 14:40:06 1997 +++ linux/include/asm-i386/atomic.h Mon Apr 14 11:20:54 1997 @@ -19,9 +19,18 @@ */ #define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x) -typedef int atomic_t; +#ifdef __SMP__ +typedef struct { volatile int counter; } atomic_t; +#else +typedef struct { int counter; } atomic_t; +#endif -static __inline__ void atomic_add(atomic_t i, volatile atomic_t *v) +#define ATOMIC_INIT { 0 } + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v,i) (((v)->counter) = (i)) + +static __inline__ void atomic_add(int i, volatile atomic_t *v) { __asm__ __volatile__( LOCK "addl %1,%0" @@ -29,7 +38,7 @@ :"ir" (i), "m" (__atomic_fool_gcc(v))); } -static __inline__ void atomic_sub(atomic_t i, volatile atomic_t *v) +static __inline__ void atomic_sub(int i, volatile atomic_t *v) { __asm__ __volatile__( LOCK "subl %1,%0" diff -u --recursive --new-file v2.1.33/linux/include/asm-i386/errno.h linux/include/asm-i386/errno.h --- v2.1.33/linux/include/asm-i386/errno.h Wed Jul 3 21:28:57 1996 +++ linux/include/asm-i386/errno.h Mon Apr 14 09:34:53 1997 @@ -126,4 +126,7 @@ #define EREMOTEIO 121 /* Remote I/O error */ #define EDQUOT 122 /* Quota exceeded */ +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ + #endif diff -u --recursive --new-file v2.1.33/linux/include/asm-i386/hardirq.h linux/include/asm-i386/hardirq.h --- v2.1.33/linux/include/asm-i386/hardirq.h Mon Apr 7 11:35:31 1997 +++ linux/include/asm-i386/hardirq.h Mon Apr 14 14:08:53 1997 @@ -1,12 +1,14 @@ #ifndef __ASM_HARDIRQ_H #define __ASM_HARDIRQ_H +#include + extern unsigned int local_irq_count[NR_CPUS]; #define in_interrupt() (local_irq_count[smp_processor_id()] != 0) #ifndef __SMP__ -#define hardirq_trylock(cpu) ((cpu)==0) /* always true */ +#define hardirq_trylock(cpu) (local_irq_count[cpu] == 0) #define hardirq_endlock(cpu) do { } while (0) #define hardirq_enter(cpu) (local_irq_count[cpu]++) @@ -16,9 +18,11 @@ #else +#include + extern unsigned char global_irq_holder; extern unsigned volatile int global_irq_lock; -extern unsigned volatile int global_irq_count; +extern atomic_t global_irq_count; static inline void release_irqlock(int cpu) { @@ -48,7 +52,7 @@ __save_flags(flags); __cli(); atomic_inc(&global_irq_count); - if (global_irq_count != 1 || test_bit(0,&global_irq_lock)) { + if (atomic_read(&global_irq_count) != 1 || test_bit(0,&global_irq_lock)) { atomic_dec(&global_irq_count); __restore_flags(flags); return 0; diff -u --recursive --new-file v2.1.33/linux/include/asm-i386/io.h linux/include/asm-i386/io.h --- v2.1.33/linux/include/asm-i386/io.h Fri Apr 4 08:52:25 1997 +++ linux/include/asm-i386/io.h Mon Apr 14 11:42:11 1997 @@ -1,8 +1,6 @@ #ifndef _ASM_IO_H #define _ASM_IO_H -#include - /* * This file contains the definitions for the x86 IO instructions * inb/inw/inl/outb/outw/outl and the "string versions" of the same @@ -168,6 +166,7 @@ #ifdef __KERNEL__ +#include #include #define __io_virt(x) ((void *)(PAGE_OFFSET | (unsigned long)(x))) diff -u --recursive --new-file v2.1.33/linux/include/asm-i386/irq.h linux/include/asm-i386/irq.h --- v2.1.33/linux/include/asm-i386/irq.h Sun Apr 13 10:18:22 1997 +++ linux/include/asm-i386/irq.h Sun Apr 13 20:41:16 1997 @@ -72,6 +72,24 @@ "iret" /* + * Some fast irq handlers might want to access saved registers (mostly + * cs or flags) + */ + +struct fast_irq_regs { + long ecx; + long edx; + long eax; + int xds; + int xes; + long eip; + int xcs; + long eflags; + long esp; + int xss; +}; + +/* * The "inb" instructions are not needed, but seem to change the timings * a bit - without them it seems that the harddisk driver won't work on * all hardware. Arghh. @@ -161,12 +179,13 @@ __asm__( \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(x) ":\n\t" \ - SAVE_MOST \ - "movl %esp,%eax\n\t" \ - "pushl %eax\n\t" \ + "pushl $-1\n\t" \ + SAVE_ALL \ + "movl %esp,%eax\n\t" \ + "pushl %eax\n\t" \ "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \ - "addl $4,%esp\n\t" \ - RESTORE_MOST); + "addl $4,%esp\n\t" \ + "jmp ret_from_intr\n"); #endif /* __SMP__ */ diff -u --recursive --new-file v2.1.33/linux/include/asm-i386/semaphore.h linux/include/asm-i386/semaphore.h --- v2.1.33/linux/include/asm-i386/semaphore.h Wed Jan 15 18:47:21 1997 +++ linux/include/asm-i386/semaphore.h Mon Apr 14 11:20:59 1997 @@ -19,14 +19,17 @@ * */ +#include +#include + struct semaphore { - int count; + atomic_t count; int waking; struct wait_queue * wait; }; -#define MUTEX ((struct semaphore) { 1, 0, NULL }) -#define MUTEX_LOCKED ((struct semaphore) { 0, 0, NULL }) +#define MUTEX ((struct semaphore) { { 1 }, 0, NULL }) +#define MUTEX_LOCKED ((struct semaphore) { { 0 }, 0, NULL }) asmlinkage void __down_failed(void /* special register calling convention */); asmlinkage int __down_failed_interruptible(void /* params in registers */); @@ -34,6 +37,44 @@ extern void __down(struct semaphore * sem); extern void __up(struct semaphore * sem); + +#define sema_init(sem, val) atomic_set(&((sem)->count), (val)) + +/* + * These two _must_ execute atomically wrt each other. + * + * This is trivially done with load_locked/store_cond, + * but on the x86 we need an external synchronizer. + * Currently this is just the global interrupt lock, + * bah. Go for a smaller spinlock some day. + * + * (On the other hand this shouldn't be in any critical + * path, so..) + */ +static inline void wake_one_more(struct semaphore * sem) +{ + unsigned long flags; + + save_flags(flags); + cli(); + sem->waking++; + restore_flags(flags); +} + +static inline int waking_non_zero(struct semaphore *sem) +{ + unsigned long flags; + int ret = 0; + + save_flags(flags); + cli(); + if (sem->waking > 0) { + sem->waking--; + ret = 1; + } + restore_flags(flags); + return ret; +} /* * This is ugly, but we want the default case to fall through. diff -u --recursive --new-file v2.1.33/linux/include/asm-i386/softirq.h linux/include/asm-i386/softirq.h --- v2.1.33/linux/include/asm-i386/softirq.h Thu Mar 27 14:40:06 1997 +++ linux/include/asm-i386/softirq.h Mon Apr 14 11:42:12 1997 @@ -1,34 +1,93 @@ #ifndef __ASM_SOFTIRQ_H #define __ASM_SOFTIRQ_H -/* - * Software interrupts.. - */ +#include +#include + #define get_active_bhs() (bh_mask & bh_active) #define clear_active_bhs(x) atomic_clear_mask((x),&bh_active) +extern inline void init_bh(int nr, void (*routine)(void)) +{ + bh_base[nr] = routine; + bh_mask_count[nr] = 0; + bh_mask |= 1 << nr; +} + +extern inline void mark_bh(int nr) +{ + set_bit(nr, &bh_active); +} + +/* + * These use a mask count to correctly handle + * nested disable/enable calls + */ +extern inline void disable_bh(int nr) +{ + bh_mask &= ~(1 << nr); + bh_mask_count[nr]++; +} + +extern inline void enable_bh(int nr) +{ + if (!--bh_mask_count[nr]) + bh_mask |= 1 << nr; +} + #ifdef __SMP__ +/* + * The locking mechanism for base handlers, to prevent re-entrancy, + * is entirely private to an implementation, it should not be + * referenced at all outside of this file. + */ +extern atomic_t __intel_bh_counter; + +extern inline void start_bh_atomic(void) +{ + atomic_inc(&__intel_bh_counter); + synchronize_irq(); +} + +extern inline void end_bh_atomic(void) +{ + atomic_dec(&__intel_bh_counter); +} + /* These are for the irq's testing the lock */ static inline int softirq_trylock(void) { - atomic_inc(&intr_count); - if (intr_count != 1) { - atomic_dec(&intr_count); + atomic_inc(&__intel_bh_counter); + if (atomic_read(&__intel_bh_counter) != 1) { + atomic_dec(&__intel_bh_counter); return 0; } return 1; } -#define softirq_endlock() atomic_dec(&intr_count) +#define softirq_endlock() atomic_dec(&__intel_bh_counter) #else -/* These are for the irq's testing the lock */ -#define softirq_trylock() (intr_count ? 0 : ((intr_count=1),1)) -#define softirq_endlock() (intr_count = 0) +extern int __intel_bh_counter; + +extern inline void start_bh_atomic(void) +{ + __intel_bh_counter++; + barrier(); +} +extern inline void end_bh_atomic(void) +{ + barrier(); + __intel_bh_counter--; +} + +/* These are for the irq's testing the lock */ +#define softirq_trylock() (__intel_bh_counter ? 0 : (__intel_bh_counter=1)) +#define softirq_endlock() (__intel_bh_counter = 0) -#endif +#endif /* SMP */ -#endif +#endif /* __ASM_SOFTIRQ_H */ diff -u --recursive --new-file v2.1.33/linux/include/asm-i386/system.h linux/include/asm-i386/system.h --- v2.1.33/linux/include/asm-i386/system.h Mon Apr 7 11:35:31 1997 +++ linux/include/asm-i386/system.h Sun Apr 13 10:01:22 1997 @@ -73,7 +73,6 @@ __asm__ __volatile__("fwait"); \ prev->flags&=~PF_USEDFPU; \ } \ - prev->processor = NO_PROC_ID; \ current_set[this_cpu] = next; \ __asm__("ljmp %0\n\t" \ : /* no output */ \ diff -u --recursive --new-file v2.1.33/linux/include/asm-m68k/atomic.h linux/include/asm-m68k/atomic.h --- v2.1.33/linux/include/asm-m68k/atomic.h Mon May 6 02:44:32 1996 +++ linux/include/asm-m68k/atomic.h Mon Apr 14 09:31:09 1997 @@ -10,14 +10,18 @@ * We do not have SMP m68k systems, so we don't have to deal with that. */ -typedef int atomic_t; +typedef struct { int counter; } atomic_t; +#define ATOMIC_INIT { 0 } -static __inline__ void atomic_add(atomic_t i, atomic_t *v) +#define atomic_read(v) ((v)->counter) +#define atomic_set(v) (((v)->counter) = i) + +static __inline__ void atomic_add(int i, atomic_t *v) { __asm__ __volatile__("addl %1,%0" : : "m" (*v), "id" (i)); } -static __inline__ void atomic_sub(atomic_t i, atomic_t *v) +static __inline__ void atomic_sub(int i, atomic_t *v) { __asm__ __volatile__("subl %1,%0" : : "m" (*v), "id" (i)); } diff -u --recursive --new-file v2.1.33/linux/include/asm-m68k/errno.h linux/include/asm-m68k/errno.h --- v2.1.33/linux/include/asm-m68k/errno.h Wed Sep 25 00:47:41 1996 +++ linux/include/asm-m68k/errno.h Mon Apr 14 09:34:53 1997 @@ -126,4 +126,7 @@ #define EREMOTEIO 121 /* Remote I/O error */ #define EDQUOT 122 /* Quota exceeded */ +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ + #endif /* _M68K_ERRNO_H */ diff -u --recursive --new-file v2.1.33/linux/include/asm-m68k/ide.h linux/include/asm-m68k/ide.h --- v2.1.33/linux/include/asm-m68k/ide.h Thu Mar 27 14:40:07 1997 +++ linux/include/asm-m68k/ide.h Mon Apr 14 09:31:09 1997 @@ -479,7 +479,7 @@ #ifdef CONFIG_ATARI if (MACH_IS_ATARI) { if (*ide_lock == 0) { - if (intr_count > 0) + if (in_interrupt() > 0) panic( "Falcon IDE hasn't ST-DMA lock in interrupt" ); stdma_lock(handler, data); *ide_lock = 1; @@ -506,12 +506,12 @@ #if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) #define ide_sti() \ do { \ - if (!intr_count) sti(); \ + if (!in_interrupt()) sti(); \ } while(0) #elif defined(CONFIG_ATARI) -#define ide_sti() \ - do { \ - if (!MACH_IS_ATARI || !intr_count) sti(); \ +#define ide_sti() \ + do { \ + if (!MACH_IS_ATARI || !in_interrupt()) sti(); \ } while(0) #else /* !defined(CONFIG_ATARI) */ #define ide_sti() sti() diff -u --recursive --new-file v2.1.33/linux/include/asm-m68k/semaphore.h linux/include/asm-m68k/semaphore.h --- v2.1.33/linux/include/asm-m68k/semaphore.h Fri Nov 22 05:56:36 1996 +++ linux/include/asm-m68k/semaphore.h Mon Apr 14 09:31:09 1997 @@ -26,6 +26,23 @@ extern void __down(struct semaphore * sem); extern void __up(struct semaphore * sem); +#define sema_init(sem, val) ((sem)->count = val) + +static inline int waking_non_zero(struct semaphore *sem) +{ + unsigned long flags; + int ret = 0; + + save_flags(flags); + cli(); + if (atomic_read(&sem->waking) > 0) { + atomic_dec(&sem->waking); + ret = 1; + } + restore_flags(flags); + return ret; +} + /* * This is ugly, but we want the default case to fall through. * "down_failed" is a special asm handler that calls the C diff -u --recursive --new-file v2.1.33/linux/include/asm-mips/processor.h linux/include/asm-mips/processor.h --- v2.1.33/linux/include/asm-mips/processor.h Sun Jan 26 02:07:46 1997 +++ linux/include/asm-mips/processor.h Mon Apr 14 09:31:09 1997 @@ -19,7 +19,7 @@ */ extern char wait_available; /* only available on R4[26]00 */ -extern unsigned long intr_count; +extern atomic_t intr_count; extern unsigned long event; /* diff -u --recursive --new-file v2.1.33/linux/include/asm-ppc/atomic.h linux/include/asm-ppc/atomic.h --- v2.1.33/linux/include/asm-ppc/atomic.h Wed Dec 18 00:54:09 1996 +++ linux/include/asm-ppc/atomic.h Mon Apr 14 09:31:09 1997 @@ -5,13 +5,18 @@ #ifndef _ASM_PPC_ATOMIC_H_ #define _ASM_PPC_ATOMIC_H_ -typedef int atomic_t; +typedef struct { int counter; } atomic_t; +#define ATOMIC_INIT { 0 } + /* * Make sure gcc doesn't try to be clever and move things around * on us. We need to use _exactly_ the address the user gave us, * not some alias that contains the same information. */ #define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x) + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v) (((v)->counter) = i) #define atomic_dec_return(v) ({atomic_sub(1,(v));(v);}) #define atomic_inc_return(v) ({atomic_add(1,(v));(v);}) diff -u --recursive --new-file v2.1.33/linux/include/asm-ppc/errno.h linux/include/asm-ppc/errno.h --- v2.1.33/linux/include/asm-ppc/errno.h Mon May 27 02:00:59 1996 +++ linux/include/asm-ppc/errno.h Mon Apr 14 09:34:53 1997 @@ -124,6 +124,9 @@ #define EREMOTEIO 121 /* Remote I/O error */ #define EDQUOT 122 /* Quota exceeded */ +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ + /* Should never be seen by user programs */ #define ERESTARTSYS 512 #define ERESTARTNOINTR 513 diff -u --recursive --new-file v2.1.33/linux/include/asm-ppc/semaphore.h linux/include/asm-ppc/semaphore.h --- v2.1.33/linux/include/asm-ppc/semaphore.h Wed Dec 18 00:54:10 1996 +++ linux/include/asm-ppc/semaphore.h Mon Apr 14 09:31:09 1997 @@ -18,6 +18,23 @@ extern void atomic_add(int c, int *v); extern void atomic_sub(int c, int *v); +#define sema_init(sem, val) atomic_set(&((sem)->count), val) + +static inline int waking_non_zero(struct semaphore *sem) +{ + unsigned long flags; + int ret = 0; + + save_flags(flags); + cli(); + if (atomic_read(&sem->waking) > 0) { + atomic_dec(&sem->waking); + ret = 1; + } + restore_flags(flags); + return ret; +} + extern inline void down(struct semaphore * sem) { for (;;) diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/atomic.h linux/include/asm-sparc/atomic.h --- v2.1.33/linux/include/asm-sparc/atomic.h Sun Jan 26 02:07:47 1997 +++ linux/include/asm-sparc/atomic.h Mon Apr 14 09:31:09 1997 @@ -6,7 +6,14 @@ #ifndef __ARCH_SPARC_ATOMIC__ #define __ARCH_SPARC_ATOMIC__ -typedef int atomic_t; +#ifdef __SMP__ +/* This is a temporary measure. -DaveM */ +typedef struct { volatile int counter; } atomic_t; +#else +typedef struct { int counter; } atomic_t; +#endif + +#define ATOMIC_INIT { 0 } #ifdef __KERNEL__ #include @@ -15,19 +22,38 @@ /* We do the bulk of the actual work out of line in two common * routines in assembler, see arch/sparc/lib/atomic.S for the * "fun" details. + * + * For SMP the trick is you embed the spin lock byte within + * the word, use the low byte so signedness is easily retained + * via a quick arithmetic shift. It looks like this: + * + * ---------------------------------------- + * | signed 24-bit counter value | lock | atomic_t + * ---------------------------------------- + * 31 8 7 0 */ +static __inline__ int atomic_read(atomic_t *v) +{ + int val; + + __asm__ __volatile__("sra %1, 0x8, %0" + : "=r" (val) + : "r" (v->counter)); + return val; +} +#define atomic_set(v, i) (((v)->counter) = ((i) << 8)) + /* Make sure gcc doesn't try to be clever and move things around * on us. We need to use _exactly_ the address the user gave us, * not some alias that contains the same information. */ #define __atomic_fool_gcc(x) ((struct { int a[100]; } *)x) -static __inline__ void atomic_add(atomic_t i, atomic_t *v) +static __inline__ void atomic_add(int i, atomic_t *v) { register atomic_t *ptr asm("g1"); - register atomic_t increment asm("g2"); - + register int increment asm("g2"); ptr = (atomic_t *) __atomic_fool_gcc(v); increment = i; @@ -37,13 +63,13 @@ add %%o7, 8, %%o7 " : "=&r" (increment) : "0" (increment), "r" (ptr) - : "g3", "g4", "g7", "memory"); + : "g3", "g4", "g7", "memory", "cc"); } -static __inline__ void atomic_sub(atomic_t i, atomic_t *v) +static __inline__ void atomic_sub(int i, atomic_t *v) { register atomic_t *ptr asm("g1"); - register atomic_t increment asm("g2"); + register int increment asm("g2"); ptr = (atomic_t *) __atomic_fool_gcc(v); increment = i; @@ -54,13 +80,13 @@ add %%o7, 8, %%o7 " : "=&r" (increment) : "0" (increment), "r" (ptr) - : "g3", "g4", "g7", "memory"); + : "g3", "g4", "g7", "memory", "cc"); } -static __inline__ int atomic_add_return(atomic_t i, atomic_t *v) +static __inline__ int atomic_add_return(int i, atomic_t *v) { register atomic_t *ptr asm("g1"); - register atomic_t increment asm("g2"); + register int increment asm("g2"); ptr = (atomic_t *) __atomic_fool_gcc(v); increment = i; @@ -71,15 +97,15 @@ add %%o7, 8, %%o7 " : "=&r" (increment) : "0" (increment), "r" (ptr) - : "g3", "g4", "g7", "memory"); + : "g3", "g4", "g7", "memory", "cc"); return increment; } -static __inline__ int atomic_sub_return(atomic_t i, atomic_t *v) +static __inline__ int atomic_sub_return(int i, atomic_t *v) { register atomic_t *ptr asm("g1"); - register atomic_t increment asm("g2"); + register int increment asm("g2"); ptr = (atomic_t *) __atomic_fool_gcc(v); increment = i; @@ -90,7 +116,7 @@ add %%o7, 8, %%o7 " : "=&r" (increment) : "0" (increment), "r" (ptr) - : "g3", "g4", "g7", "memory"); + : "g3", "g4", "g7", "memory", "cc"); return increment; } diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h --- v2.1.33/linux/include/asm-sparc/bitops.h Sun Jan 26 02:07:47 1997 +++ linux/include/asm-sparc/bitops.h Mon Apr 14 09:31:09 1997 @@ -1,4 +1,4 @@ -/* $Id: bitops.h,v 1.43 1997/01/25 04:42:51 davem Exp $ +/* $Id: bitops.h,v 1.46 1997/04/13 06:38:24 davem Exp $ * bitops.h: Bit string operations on the Sparc. * * Copyright 1995 David S. Miller (davem@caip.rutgers.edu) @@ -99,7 +99,6 @@ { register unsigned long mask asm("g2"); register unsigned long *ADDR asm("g1"); - ADDR = ((unsigned long *) addr) + (nr >> 5); mask = 1 << (nr & 31); __asm__ __volatile__(" @@ -108,7 +107,7 @@ add %%o7, 8, %%o7 " : "=&r" (mask) : "0" (mask), "r" (ADDR) - : "g3", "g4", "g5", "g7"); + : "g3", "g4", "g5", "g7", "cc"); return mask; } @@ -126,7 +125,7 @@ add %%o7, 8, %%o7 " : "=&r" (mask) : "0" (mask), "r" (ADDR) - : "g3", "g4", "g5", "g7"); + : "g3", "g4", "g5", "g7", "cc"); return mask; } @@ -144,7 +143,7 @@ add %%o7, 8, %%o7 " : "=&r" (mask) : "0" (mask), "r" (ADDR) - : "g3", "g4", "g5", "g7"); + : "g3", "g4", "g5", "g7", "cc"); return mask; } @@ -276,7 +275,7 @@ add %%o7, 8, %%o7 " : "=&r" (mask) : "0" (mask), "r" (ADDR) - : "g3", "g4", "g5", "g7"); + : "g3", "g4", "g5", "g7", "cc"); return mask; } @@ -294,7 +293,7 @@ add %%o7, 8, %%o7 " : "=&r" (mask) : "0" (mask), "r" (ADDR) - : "g3", "g4", "g5", "g7"); + : "g3", "g4", "g5", "g7", "cc"); return mask; } diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/checksum.h linux/include/asm-sparc/checksum.h --- v2.1.33/linux/include/asm-sparc/checksum.h Thu Mar 27 14:40:07 1997 +++ linux/include/asm-sparc/checksum.h Fri Apr 11 10:47:38 1997 @@ -1,4 +1,4 @@ -/* $Id: checksum.h,v 1.26 1997/03/14 07:54:47 davem Exp $ */ +/* $Id: checksum.h,v 1.27 1997/04/11 00:42:18 davem Exp $ */ #ifndef __SPARC_CHECKSUM_H #define __SPARC_CHECKSUM_H @@ -154,7 +154,7 @@ "xnor\t%%g0, %0, %0" : "=r" (sum), "=&r" (iph) : "r" (ihl), "1" (iph) - : "g2", "g3", "g4"); + : "g2", "g3", "g4", "cc"); return sum; } @@ -178,7 +178,8 @@ "xnor\t%%g0, %0, %0" : "=r" (sum), "=r" (saddr) : "r" (daddr), "r" ((proto<<16)+len), "0" (sum), - "1" (saddr)); + "1" (saddr) + : "cc"); return sum; } @@ -192,7 +193,8 @@ "addx\t%1, %%g0, %1\n\t" "xnor\t%%g0, %1, %0" : "=&r" (sum), "=r" (tmp) - : "0" (sum), "1" (sum<<16)); + : "0" (sum), "1" (sum<<16) + : "cc"); return sum; } @@ -228,7 +230,7 @@ : "=&r" (sum) : "r" (saddr), "r" (daddr), "r"(htonl((__u32) (len))), "r"(htonl(proto)), "r"(sum) - : "g2", "g3", "g4"); + : "g2", "g3", "g4", "cc"); return csum_fold(sum); } diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/delay.h linux/include/asm-sparc/delay.h --- v2.1.33/linux/include/asm-sparc/delay.h Sat Nov 9 00:29:18 1996 +++ linux/include/asm-sparc/delay.h Fri Apr 11 10:47:38 1997 @@ -1,4 +1,4 @@ -/* $Id: delay.h,v 1.8 1996/01/28 02:09:21 davem Exp $ +/* $Id: delay.h,v 1.9 1997/04/11 00:42:19 davem Exp $ * delay.h: Linux delay routines on the Sparc. * * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu). @@ -15,7 +15,8 @@ "1: bne 1b\n\t" "subcc %0, 1, %0\n" : "=&r" (loops) : - "0" (loops)); + "0" (loops) : + "cc"); } /* This is too messy with inline asm on the Sparc. */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/dma.h linux/include/asm-sparc/dma.h --- v2.1.33/linux/include/asm-sparc/dma.h Thu Mar 27 14:40:07 1997 +++ linux/include/asm-sparc/dma.h Fri Apr 11 10:47:38 1997 @@ -1,4 +1,4 @@ -/* $Id: dma.h,v 1.23 1997/03/14 21:05:20 jj Exp $ +/* $Id: dma.h,v 1.24 1997/04/10 05:13:21 davem Exp $ * include/asm-sparc/dma.h * * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu) @@ -8,6 +8,7 @@ #define _ASM_SPARC_DMA_H #include +#include #include /* for invalidate's, etc. */ #include @@ -28,10 +29,10 @@ /* Structure to describe the current status of DMA registers on the Sparc */ struct sparc_dma_registers { - __volatile__ unsigned long cond_reg; /* DMA condition register */ - __volatile__ char * st_addr; /* Start address of this transfer */ - __volatile__ unsigned long cnt; /* How many bytes to transfer */ - __volatile__ unsigned long dma_test; /* DMA test register */ + __volatile__ __u32 cond_reg; /* DMA condition register */ + __volatile__ __u32 st_addr; /* Start address of this transfer */ + __volatile__ __u32 cnt; /* How many bytes to transfer */ + __volatile__ __u32 dma_test; /* DMA test register */ }; /* DVMA chip revisions */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/hardirq.h linux/include/asm-sparc/hardirq.h --- v2.1.33/linux/include/asm-sparc/hardirq.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc/hardirq.h Mon Apr 14 09:31:09 1997 @@ -0,0 +1,72 @@ +/* hardirq.h: 32-bit Sparc hard IRQ support. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef __SPARC_HARDIRQ_H +#define __SPARC_HARDIRQ_H + +#include + +extern unsigned int local_irq_count[NR_CPUS]; +#define in_interrupt() (local_irq_count[smp_processor_id()] != 0) +#define hardirq_depth() (local_irq_count[smp_processor_id()]) + +#ifndef __SMP__ + +#define hardirq_trylock(cpu) (++local_irq_count[cpu], (cpu)==0) +#define hardirq_endlock(cpu) (--local_irq_count[cpu]) + +#define hardirq_enter(cpu) (local_irq_count[cpu]++) +#define hardirq_exit(cpu) (local_irq_count[cpu]--) + +#define synchronize_irq() do { } while(0) + +#else /* __SMP__ */ + +#include +#include +#include +#include + +extern unsigned char global_irq_holder; +extern spinlock_t global_irq_lock; +extern atomic_t global_irq_count; + +#define release_irqlock(cpu) \ +do { if(global_irq_holder == (unsigned char) cpu) { \ + global_irq_holder = NO_PROC_ID; \ + spin_unlock(&global_irq_lock); \ + } \ +} while(0) + +/* Ordering of the counter bumps is _deadly_ important. */ +#define hardirq_enter(cpu) \ + do { ++local_irq_count[cpu]; atomic_inc(&global_irq_count); } while(0) + +#define hardirq_exit(cpu) \ + do { atomic_dec(&global_irq_count); --local_irq_count[cpu]; } while(0) + +#define hardirq_trylock(cpu) \ +({ unsigned long flags; int ret = 1; \ + __save_flags(flags); \ + __cli(); \ + if(atomic_add_return(1, &global_irq_count) != 1 || \ + global_irq_lock) { \ + atomic_dec(&global_irq_count); \ + __restore_flags(flags); \ + ret = 0; \ + } else { \ + ++local_irq_count[cpu]; \ + __sti(); \ + } \ + ret; \ +}) + +#define hardirq_endlock(cpu) do { __cli(); hardirq_exit(cpu); __sti(); } while(0) + +extern void synchronize_irq(void); + +#endif /* __SMP__ */ + +#endif /* __SPARC_HARDIRQ_H */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/io.h linux/include/asm-sparc/io.h --- v2.1.33/linux/include/asm-sparc/io.h Fri Dec 13 01:37:40 1996 +++ linux/include/asm-sparc/io.h Fri Apr 11 10:47:38 1997 @@ -1,8 +1,9 @@ -/* $Id: io.h,v 1.11 1996/11/19 11:26:14 davem Exp $ */ +/* $Id: io.h,v 1.14 1997/04/10 05:13:22 davem Exp $ */ #ifndef __SPARC_IO_H #define __SPARC_IO_H #include +#include #include /* IO address mapping routines need this */ #include @@ -135,9 +136,19 @@ return; } -extern void *sparc_alloc_io (void *, void *, int, char *, int, int); -extern void sparc_free_io (void *, int); -extern void *sparc_dvma_malloc (int, char *); +extern void *sparc_alloc_io (u32 pa, void *va, int sz, char *name, u32 io, int rdonly); +extern void sparc_free_io (void *vaddr, int sz); +extern void *_sparc_dvma_malloc (int sz, char *name); + +/* Returns CPU visible address, dvmaaddr_p is a pointer to where + * the DVMA visible (ie. SBUS/PSYCO+PCI) address should be stored. + */ +static __inline__ void *sparc_dvma_malloc(int size, char *name, __u32 *dvmaaddr_p) +{ + void *cpuaddr = _sparc_dvma_malloc(size, name); + *dvmaaddr_p = (__u32) cpuaddr; + return cpuaddr; +} #define virt_to_phys(x) __pa((unsigned long)(x)) #define phys_to_virt(x) __va((unsigned long)(x)) diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/irq.h linux/include/asm-sparc/irq.h --- v2.1.33/linux/include/asm-sparc/irq.h Sat Nov 9 11:40:09 1996 +++ linux/include/asm-sparc/irq.h Mon Apr 14 09:31:09 1997 @@ -1,4 +1,4 @@ -/* $Id: irq.h,v 1.14 1996/08/29 09:48:18 davem Exp $ +/* $Id: irq.h,v 1.15 1997/04/14 05:39:28 davem Exp $ * irq.h: IRQ registers on the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -20,6 +20,8 @@ */ extern void (*disable_irq)(unsigned int); extern void (*enable_irq)(unsigned int); +extern void (*disable_pil_irq)(unsigned int); +extern void (*enable_pil_irq)(unsigned int); extern void (*clear_clock_irq)( void ); extern void (*clear_profile_irq)( void ); extern void (*load_profile_irq)( unsigned int timeout ); @@ -122,5 +124,6 @@ #define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */ #define SUN4M_INT_SBUS(x) (1 << (x+7)) +#define SUN4M_INT_VME(x) (1 << (x)) #endif diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/openprom.h linux/include/asm-sparc/openprom.h --- v2.1.33/linux/include/asm-sparc/openprom.h Sat Nov 9 00:29:48 1996 +++ linux/include/asm-sparc/openprom.h Fri Apr 11 10:47:38 1997 @@ -1,4 +1,4 @@ -/* $Id: openprom.h,v 1.19 1996/09/25 03:51:08 davem Exp $ */ +/* $Id: openprom.h,v 1.20 1997/04/10 06:41:06 davem Exp $ */ #ifndef __SPARC_OPENPROM_H #define __SPARC_OPENPROM_H @@ -186,9 +186,9 @@ #define PROMINTR_MAX 15 struct linux_prom_registers { - int which_io; /* is this in OBIO space? */ - char *phys_addr; /* The physical address of this register */ - int reg_size; /* How many bytes does this register take up? */ + unsigned int which_io; /* is this in OBIO space? */ + unsigned int phys_addr; /* The physical address of this register */ + unsigned int reg_size; /* How many bytes does this register take up? */ }; struct linux_prom_irqs { diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h --- v2.1.33/linux/include/asm-sparc/pgtable.h Mon Dec 30 01:59:59 1996 +++ linux/include/asm-sparc/pgtable.h Fri Apr 11 10:47:38 1997 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.58 1996/12/30 06:17:03 davem Exp $ */ +/* $Id: pgtable.h,v 1.59 1997/04/10 05:13:23 davem Exp $ */ #ifndef _SPARC_PGTABLE_H #define _SPARC_PGTABLE_H @@ -39,11 +39,11 @@ char *addr; char *__dont_touch; unsigned int len; - char *dvma_addr; + __u32 dvma_addr; }; -extern char *(*mmu_get_scsi_one)(char *, unsigned long, struct linux_sbus *sbus); +extern __u32 (*mmu_get_scsi_one)(char *, unsigned long, struct linux_sbus *sbus); extern void (*mmu_get_scsi_sgl)(struct mmu_sglist *, int, struct linux_sbus *sbus); -extern void (*mmu_release_scsi_one)(char *, unsigned long, struct linux_sbus *sbus); +extern void (*mmu_release_scsi_one)(__u32, unsigned long, struct linux_sbus *sbus); extern void (*mmu_release_scsi_sgl)(struct mmu_sglist *, int, struct linux_sbus *sbus); extern void (*mmu_map_dma_area)(unsigned long addr, int len); diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/pgtsun4c.h linux/include/asm-sparc/pgtsun4c.h --- v2.1.33/linux/include/asm-sparc/pgtsun4c.h Mon Dec 23 00:13:53 1996 +++ linux/include/asm-sparc/pgtsun4c.h Fri Apr 11 10:47:38 1997 @@ -1,4 +1,4 @@ -/* $Id: pgtsun4c.h,v 1.33 1996/12/20 07:55:04 davem Exp $ +/* $Id: pgtsun4c.h,v 1.34 1997/03/23 03:47:08 davem Exp $ * pgtsun4c.h: Sun4c specific pgtable.h defines and code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -112,8 +112,6 @@ __asm__ __volatile__("\n\tstba %1, [%0] %2; nop; nop; nop;\n\t" : : "r" (addr), "r" (entry), "i" (ASI_SEGMAP)); - - return; } extern __inline__ unsigned long sun4c_get_pte(unsigned long addr) @@ -131,8 +129,6 @@ __asm__ __volatile__("\n\tsta %1, [%0] %2; nop; nop; nop;\n\t" : : "r" (addr), "r" ((entry & ~(_SUN4C_PAGE_PRESENT))), "i" (ASI_PTE)); - - return; } extern __inline__ int sun4c_get_context(void) diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/psr.h linux/include/asm-sparc/psr.h --- v2.1.33/linux/include/asm-sparc/psr.h Fri Dec 13 01:37:40 1996 +++ linux/include/asm-sparc/psr.h Fri Apr 11 10:47:38 1997 @@ -1,4 +1,4 @@ -/* $Id: psr.h,v 1.13 1996/12/10 06:06:36 davem Exp $ +/* $Id: psr.h,v 1.14 1997/04/11 00:42:19 davem Exp $ * psr.h: This file holds the macros for masking off various parts of * the processor status register on the Sparc. This is valid * for Version 8. On the V9 this is renamed to the PSTATE @@ -62,7 +62,7 @@ nop " : /* no outputs */ : "r" (new_psr) - : "memory"); + : "memory", "cc"); } /* Get the %fsr register. Be careful, make sure the floating point diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/scatterlist.h linux/include/asm-sparc/scatterlist.h --- v2.1.33/linux/include/asm-sparc/scatterlist.h Mon Dec 30 01:59:59 1996 +++ linux/include/asm-sparc/scatterlist.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: scatterlist.h,v 1.1 1996/12/24 07:38:48 davem Exp $ */ +/* $Id: scatterlist.h,v 1.2 1997/04/10 05:13:24 davem Exp $ */ #ifndef _SPARC_SCATTERLIST_H #define _SPARC_SCATTERLIST_H @@ -8,7 +8,7 @@ * dma indirect buffer. NULL otherwise */ unsigned int length; - char * dvma_address; /* A place to hang host-specific addresses at. */ + __u32 dvma_address; /* A place to hang host-specific addresses at. */ }; #define ISA_DMA_THRESHOLD (~0UL) diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/semaphore.h linux/include/asm-sparc/semaphore.h --- v2.1.33/linux/include/asm-sparc/semaphore.h Thu Mar 27 14:40:09 1997 +++ linux/include/asm-sparc/semaphore.h Mon Apr 14 09:31:09 1997 @@ -13,12 +13,29 @@ struct wait_queue * wait; }; -#define MUTEX ((struct semaphore) { 1, 0, NULL }) -#define MUTEX_LOCKED ((struct semaphore) { 0, 0, NULL }) +#define MUTEX ((struct semaphore) { { (1 << 8) }, { 0 }, NULL }) +#define MUTEX_LOCKED ((struct semaphore) { { 0 }, { 0 }, NULL }) extern void __down(struct semaphore * sem); extern int __down_interruptible(struct semaphore * sem); extern void __up(struct semaphore * sem); + +#define sema_init(sem, val) atomic_set(&((sem)->count), val) + +static inline int waking_non_zero(struct semaphore *sem) +{ + unsigned long flags; + int ret = 0; + + save_flags(flags); + cli(); + if (atomic_read(&sem->waking) > 0) { + atomic_dec(&sem->waking); + ret = 1; + } + restore_flags(flags); + return ret; +} /* This isn't quite as clever as the x86 side, I'll be fixing this * soon enough. diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/smp.h linux/include/asm-sparc/smp.h --- v2.1.33/linux/include/asm-sparc/smp.h Sun Jan 26 02:07:47 1997 +++ linux/include/asm-sparc/smp.h Mon Apr 14 09:31:09 1997 @@ -29,6 +29,8 @@ struct cpuinfo_sparc { unsigned long udelay_val; /* that's it */ + unsigned short next; + unsigned short mid; }; extern struct cpuinfo_sparc cpu_data[NR_CPUS]; @@ -36,7 +38,6 @@ struct klock_info { unsigned char kernel_flag; unsigned char akp; - unsigned char irq_udt; }; extern struct klock_info klock_info; @@ -51,11 +52,6 @@ extern int smp_found_cpus; extern unsigned char boot_cpu_id; extern unsigned long cpu_present_map; -extern __volatile__ unsigned long smp_invalidate_needed[NR_CPUS]; -extern void smp_message_irq(void); -extern unsigned long ipi_count; - -extern void print_lock_state(void); typedef void (*smpfunc_t)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); @@ -69,8 +65,6 @@ extern void smp_store_cpu_info(int id); extern void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5); -extern void smp_capture(void); -extern void smp_release(void); extern __inline__ void xc0(smpfunc_t func) { smp_cross_call(func, 0, 0, 0, 0, 0); } extern __inline__ void xc1(smpfunc_t func, unsigned long arg1) @@ -89,6 +83,7 @@ extern __volatile__ int cpu_number_map[NR_CPUS]; extern __volatile__ int cpu_logical_map[NR_CPUS]; +extern unsigned long smp_proc_in_lock[NR_CPUS]; extern __inline__ int smp_processor_id(void) { @@ -101,8 +96,6 @@ return cpuid; } - -extern __volatile__ unsigned long smp_proc_in_lock[NR_CPUS]; /* for computing process time */ extern __volatile__ int smp_process_available; extern __inline__ int smp_swap(volatile int *addr, int value) @@ -148,7 +141,6 @@ #endif /* !(__ASSEMBLY__) */ /* Sparc specific messages. */ -#define MSG_CAPTURE 0x0004 /* Park a processor. */ #define MSG_CROSS_CALL 0x0005 /* run func on cpus */ /* Empirical PROM processor mailbox constants. If the per-cpu mailbox @@ -162,7 +154,6 @@ #define MBOX_IDLECPU2 0xFD #define MBOX_STOPCPU2 0xFE - #define NO_PROC_ID 0xFF #define PROC_CHANGE_PENALTY 20 @@ -170,11 +161,6 @@ #define SMP_FROM_INT 1 #define SMP_FROM_SYSCALL 2 -#else /* !(__SMP__) */ - -#define smp_capture() do { } while(0) -#define smp_release() do { } while(0) - #endif /* !(__SMP__) */ #endif /* !(_SPARC_SMP_H) */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/smp_lock.h linux/include/asm-sparc/smp_lock.h --- v2.1.33/linux/include/asm-sparc/smp_lock.h Mon Mar 17 14:54:31 1997 +++ linux/include/asm-sparc/smp_lock.h Fri Apr 11 10:47:39 1997 @@ -1,6 +1,6 @@ -/* smp_lock.h: SMP locking primitives on Sparc. +/* smp_lock.h: 32-bit Sparc SMP master lock primitives. * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) */ #ifndef __SPARC_SMPLOCK_H @@ -10,26 +10,46 @@ #include #ifndef __SMP__ -#define lock_kernel() do { } while(0) -#define unlock_kernel() do { } while(0) -typedef struct { } spinlock_t; -#define SPIN_LOCK_UNLOCKED +#define lock_kernel() do { } while(0) +#define unlock_kernel() do { } while(0) +#define release_kernel_lock(task, cpu, depth) ((depth) = 1) +#define reaquire_kernel_lock(task, cpu, depth) do { } while(0) -#define spin_lock_init(lock) do { } while(0) -#define spin_lock(lock) do { } while(0) -#define spin_trylock(lock) do { } while(0) -#define spin_unlock(lock) do { } while(0) - -#define spin_lock_cli(lock) \ -({ unsigned long flags; \ - save_flags(flags); cli(); \ - return flags; \ -}) - -#define spin_unlock_restore(lock, flags) restore_flags(flags) #else +#include + +/* Release global kernel lock and global interrupt lock */ +#define release_kernel_lock(task, cpu, depth) \ +do { \ + if((depth = (task)->lock_depth) != 0) { \ + __cli(); \ + (task)->lock_depth = 0; \ + klock_info.akp = NO_PROC_ID; \ + klock_info.kernel_flag = 0; \ + } \ + release_irqlock(cpu); \ + __sti(); \ +} while(0) + +/* Do not fuck with this without consulting arch/sparc/lib/locks.S first! */ +#define reaquire_kernel_lock(task, cpu, depth) \ +do { \ + if(depth) { \ + register struct klock_info *klip asm("g1"); \ + register int proc asm("g5"); \ + klip = &klock_info; \ + proc = cpu; \ + __asm__ __volatile__("mov %%o7, %%g4\n\t" \ + "call ___lock_reaquire_kernel\n\t" \ + " mov %2, %%g2" \ + : /* No outputs. */ \ + : "r" (klip), "r" (proc), "r" (depth) \ + : "g2", "g3", "g4", "g7", "memory", "cc"); \ + } \ +} while(0) + /* The following acquire and release the master kernel global lock, * the idea is that the usage of this mechanmism becomes less and less * as time goes on, to the point where they are no longer needed at all @@ -41,13 +61,27 @@ { register struct klock_info *klip asm("g1"); register int proc asm("g5"); - klip = &klock_info; proc = smp_processor_id(); + klip = &klock_info; + proc = smp_processor_id(); + +#if 1 /* Debugging */ + if(local_irq_count[proc]) { + __label__ l1; +l1: printk("lock from interrupt context at %p\n", &&l1); + } + if(proc == global_irq_holder) { + __label__ l2; +l2: printk("Ugh at %p\n", &&l2); + sti(); + } +#endif + __asm__ __volatile__(" mov %%o7, %%g4 call ___lock_kernel ld [%%g6 + %0], %%g2 " : : "i" (AOFF_task_lock_depth), "r" (klip), "r" (proc) - : "g2", "g3", "g4", "g7", "memory"); + : "g2", "g3", "g4", "g7", "memory", "cc"); } /* Release kernel global lock. */ @@ -60,89 +94,7 @@ call ___unlock_kernel ld [%%g6 + %0], %%g2 " : : "i" (AOFF_task_lock_depth), "r" (klip) - : "g2", "g3", "g4", "memory"); -} - -/* Simple spin lock operations. There are two variants, one clears IRQ's - * on the local processor, one does not. - */ - -typedef unsigned char spinlock_t; -#define SPIN_LOCK_UNLOCKED 0 - -extern __inline__ void spin_lock_init(spinlock_t *lock) -{ - *lock = 0; -} - -extern __inline__ void spin_lock(spinlock_t *lock) -{ - register spinlock_t *lp asm("g1"); - lp = lock; - __asm__ __volatile__(" - ldstub [%%g1], %%g2 - orcc %%g2, 0x0, %%g0 - be 1f - mov %%o7, %%g4 - call ___spinlock_waitfor - ldub [%%g1], %%g2 -1:" : /* no outputs */ - : "r" (lp) - : "g2", "g4", "memory"); -} - -extern __inline__ int spin_trylock(spinlock_t *lock) -{ - unsigned int result; - - __asm__ __volatile__(" - ldstub [%1], %0 -" : "=r" (result) : "r" (lock) : "memory"); - - return (result == 0); -} - -extern __inline__ void spin_unlock(spinlock_t *lock) -{ - __asm__ __volatile__("stb %%g0, [%0]" : : "r" (lock) : "memory"); -} - -/* These variants clear interrupts and return save_flags() style flags - * to the caller when acquiring a lock. To release the lock you must - * pass the lock pointer as well as the flags returned from the acquisition - * routine when releasing the lock. - */ -extern __inline__ unsigned long spin_lock_cli(spinlock_t *lock) -{ - register spinlock_t *lp asm("g1"); - register unsigned long flags asm("g3"); - lp = lock; - __asm__ __volatile__(" - rd %%psr, %%g3 - or %%g3, %1, %%g4 - wr %%g4, 0, %%psr - nop; nop; nop; - ldstub [%%g1], %%g2 - orcc %%g2, 0x0, %%g0 - be 1f - mov %%o7, %%g4 - call ___spinlock_waitfor - ldub [%%g1], %%g2 -1:" : "=r" (flags) - : "i" (PSR_PIL), "r" (lp) - : "g2", "g4", "memory"); - return flags; -} - -extern __inline__ void spin_unlock_restore(spinlock_t *lock, unsigned long flags) -{ - __asm__ __volatile__(" - stb %%g0, [%0] - wr %1, 0, %%psr - nop; nop; nop; -" : /* no outputs */ - : "r" (lock), "r" (flags) - : "memory"); + : "g2", "g3", "g4", "memory", "cc"); } #endif /* !(__SPARC_SMPLOCK_H) */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/softirq.h linux/include/asm-sparc/softirq.h --- v2.1.33/linux/include/asm-sparc/softirq.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc/softirq.h Mon Apr 14 09:31:09 1997 @@ -0,0 +1,115 @@ +/* softirq.h: 32-bit Sparc soft IRQ support. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef __SPARC_SOFTIRQ_H +#define __SPARC_SOFTIRQ_H + +#include +#include + +/* The locking mechanism for base handlers, to prevent re-entrancy, + * is entirely private to an implementation, it should not be + * referenced at all outside of this file. + */ +extern atomic_t __sparc_bh_counter; + +/* Linus, I'd _really_ like to get rid of this synchronize_irq() -DaveM */ +#define start_bh_atomic() \ + do { atomic_inc(&__sparc_bh_counter); synchronize_irq(); } while(0) + +#define end_bh_atomic() atomic_dec(&__sparc_bh_counter) + +#define get_active_bhs() (bh_mask & bh_active) + +#ifdef __SMP__ + +#include + +extern spinlock_t global_bh_lock; + +#define init_bh(nr, routine) \ +do { unsigned long flags; \ + int ent = nr; \ + spin_lock_irqsave(&global_bh_lock, flags); \ + bh_base[ent] = routine; \ + bh_mask_count[ent] = 0; \ + bh_mask |= 1 << ent; \ + spin_unlock_irqrestore(&global_bh_lock, flags); \ +} while(0) + +#define mark_bh(nr) \ +do { unsigned long flags; \ + spin_lock_irqsave(&global_bh_lock, flags); \ + bh_active |= (1 << nr); \ + spin_unlock_irqrestore(&global_bh_lock, flags); \ +} while(0) + +#define disable_bh(nr) \ +do { unsigned long flags; \ + int ent = nr; \ + spin_lock_irqsave(&global_bh_lock, flags); \ + bh_mask &= ~(1 << ent); \ + bh_mask_count[ent]++; \ + spin_unlock_irqrestore(&global_bh_lock, flags); \ +} while(0) + +#define enable_bh(nr) \ +do { unsigned long flags; \ + int ent = nr; \ + spin_lock_irqsave(&global_bh_lock, flags); \ + if (!--bh_mask_count[ent]) \ + bh_mask |= 1 << ent; \ + spin_unlock_irqrestore(&global_bh_lock, flags); \ +} while(0) + +#define softirq_trylock() \ +({ \ + int ret = 1; \ + if(atomic_add_return(1, &__sparc_bh_counter) != 1) { \ + atomic_dec(&__sparc_bh_counter); \ + ret = 0; \ + } \ + ret; \ +}) +#define softirq_endlock() atomic_dec(&__sparc_bh_counter) +#define clear_active_bhs(mask) \ +do { unsigned long flags; \ + spin_lock_irqsave(&global_bh_lock, flags); \ + bh_active &= ~(mask); \ + spin_unlock_irqrestore(&global_bh_lock, flags); \ +} while(0) + +#else /* !(__SMP__) */ + +#define softirq_trylock() \ + (atomic_read(&__sparc_bh_counter) ? 0 : ((atomic_set(&__sparc_bh_counter,1)),1)) + +#define softirq_endlock() (atomic_set(&__sparc_bh_counter, 0)) +#define clear_active_bhs(x) (bh_active &= ~(x)) + +#define init_bh(nr, routine) \ +do { int ent = nr; \ + bh_base[ent] = routine; \ + bh_mask_count[ent] = 0; \ + bh_mask |= 1 << ent; \ +} while(0) + +#define mark_bh(nr) (bh_active |= (1 << (nr))) + +#define disable_bh(nr) \ +do { int ent = nr; \ + bh_mask &= ~(1 << ent); \ + bh_mask_count[ent]++; \ +} while(0) + +#define enable_bh(nr) \ +do { int ent = nr; \ + if (!--bh_mask_count[ent]) \ + bh_mask |= 1 << ent; \ +} while(0) + +#endif /* __SMP__ */ + +#endif /* __SPARC_SOFTIRQ_H */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/spinlock.h linux/include/asm-sparc/spinlock.h --- v2.1.33/linux/include/asm-sparc/spinlock.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc/spinlock.h Fri Apr 11 10:47:39 1997 @@ -0,0 +1,132 @@ +/* spinlock.h: 32-bit Sparc spinlock support. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef __SPARC_SPINLOCK_H +#define __SPARC_SPINLOCK_H + +#ifndef __ASSEMBLY__ + +#ifndef __SMP__ + +typedef struct { } spinlock_t; +#define SPIN_LOCK_UNLOCKED { } + +#define spin_lock_init(lock) do { } while(0) +#define spin_lock(lock) do { } while(0) +#define spin_trylock(lock) do { } while(0) +#define spin_unlock(lock) do { } while(0) +#define spin_lock_irq(lock) cli() +#define spin_unlock_irq(lock) sti() + +#define spin_lock_irqsave(lock, flags) save_and_cli(flags) +#define spin_unlock_irqrestore(lock, flags) restore_flags(flags) + +#else /* !(__SMP__) */ + +#include + +typedef unsigned char spinlock_t; +#define SPIN_LOCK_UNLOCKED 0 + +extern __inline__ void spin_lock(spinlock_t *lock) +{ + register spinlock_t *lp asm("g1"); + lp = lock; + __asm__ __volatile__(" + ldstub [%%g1], %%g2 + orcc %%g2, 0x0, %%g0 + be 1f + mov %%o7, %%g4 + call ___spinlock_waitfor + ldub [%%g1], %%g2 +1:" : /* no outputs */ + : "r" (lp) + : "g2", "g4", "memory", "cc"); +} + +extern __inline__ int spin_trylock(spinlock_t *lock) +{ + unsigned int result; + __asm__ __volatile__("ldstub [%1], %0" + : "=r" (result) + : "r" (lock) + : "memory"); + return (result == 0); +} + +extern __inline__ void spin_unlock(spinlock_t *lock) +{ + __asm__ __volatile__("stb %%g0, [%0]" : : "r" (lock) : "memory"); +} + +extern __inline__ void spin_lock_irq(spinlock_t *lock) +{ + register spinlock_t *lp asm("g1"); + lp = lock; + __asm__ __volatile__(" + rd %%psr, %%g2 + or %%g2, %0, %%g2 + wr %%g2, 0x0, %%psr + nop; nop; nop; + ldstub [%%g1], %%g2 + orcc %%g2, 0x0, %%g0 + be 1f + mov %%o7, %%g4 + call ___spinlock_waitfor + ldub [%%g1], %%g2 +1:" : /* No outputs */ + : "i" (PSR_PIL), "r" (lp) + : "g2", "g4", "memory", "cc"); +} + +extern __inline__ void spin_unlock_irq(spinlock_t *lock) +{ + __asm__ __volatile__(" + rd %%psr, %%g2 + andn %%g2, %1, %%g2 + stb %%g0, [%0] + wr %%g2, 0x0, %%psr + nop; nop; nop; +" : /* No outputs. */ + : "r" (lock), "i" (PSR_PIL) + : "g2", "memory"); +} + +#define spin_lock_irqsave(lock, flags) \ +do { \ + register spinlock_t *lp asm("g1"); \ + lp = lock; \ + __asm__ __volatile__( \ + "rd %%psr, %0\n\t" \ + "or %0, %1, %%g2\n\t" \ + "wr %%g2, 0x0, %%psr\n\t" \ + "nop; nop; nop;\n\t" \ + "ldstub [%%g1], %%g2\n\t" \ + "orcc %%g2, 0x0, %%g0\n\t" \ + "be 1f\n\t" \ + " mov %%o7, %%g4\n\t" \ + "call ___spinlock_waitfor\n\t" \ + " ldub [%%g1], %%g2\n\t" \ +"1:" : "=r" (flags) \ + : "i" (PSR_PIL), "r" (lp) \ + : "g2", "g4", "memory", "cc"); \ +} while(0) + +extern __inline__ void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) +{ + __asm__ __volatile__(" + stb %%g0, [%0] + wr %1, 0x0, %%psr + nop; nop; nop; +" : /* No outputs. */ + : "r" (lock), "r" (flags) + : "memory", "cc"); +} + +#endif /* __SMP__ */ + +#endif /* !(__ASSEMBLY__) */ + +#endif /* __SPARC_SPINLOCK_H */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/system.h linux/include/asm-sparc/system.h --- v2.1.33/linux/include/asm-sparc/system.h Thu Mar 27 14:40:09 1997 +++ linux/include/asm-sparc/system.h Mon Apr 14 09:31:09 1997 @@ -1,4 +1,4 @@ -/* $Id: system.h,v 1.53 1997/03/19 14:53:43 davem Exp $ */ +/* $Id: system.h,v 1.56 1997/04/14 05:39:30 davem Exp $ */ #ifndef __SPARC_SYSTEM_H #define __SPARC_SYSTEM_H @@ -11,10 +11,10 @@ #include #include #include -#endif #define EMPTY_PGT (&empty_bad_page) #define EMPTY_PGE (&empty_bad_page_table) +#endif /* __KERNEL__ */ #ifndef __ASSEMBLY__ @@ -32,6 +32,9 @@ ap1000 = 0x07, /* almost a sun4m */ }; +/* Really, userland should not be looking at any of this... */ +#ifdef __KERNEL__ + extern enum sparc_cpu sparc_cpu_model; extern unsigned long empty_bad_page; @@ -54,7 +57,6 @@ #ifdef __SMP__ #define SWITCH_ENTER \ - cli(); \ if(prev->flags & PF_USEDFPU) { \ put_psr(get_psr() | PSR_EF); \ fpsave(&prev->tss.float_regs[0], &prev->tss.fsr, \ @@ -63,11 +65,9 @@ prev->tss.kregs->psr &= ~PSR_EF; \ } -#define SWITCH_EXIT sti(); #define SWITCH_DO_LAZY_FPU #else #define SWITCH_ENTER -#define SWITCH_EXIT #define SWITCH_DO_LAZY_FPU if(last_task_used_math != next) next->tss.kregs->psr&=~PSR_EF; #endif @@ -93,7 +93,9 @@ "rd %%wim, %%g5\n\t" \ "wr %%g4, 0x20, %%psr\n\t" \ "nop\n\t" \ + "mov %5, %%g7\n\t" \ "std %%g4, [%%g6 + %2]\n\t" \ + "st %%g7, [%%g6 + %6]\n\t" \ "ldd [%1 + %2], %%g4\n\t" \ "mov %1, %%g6\n\t" \ "st %1, [%0]\n\t" \ @@ -109,12 +111,14 @@ "nop\n\t" \ "jmpl %%o7 + 0x8, %%g0\n\t" \ " nop\n\t" : : "r" (&(current_set[smp_processor_id()])), "r" (next), \ - "i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpsr)), \ - "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)), \ - "r" (task_pc) : "g1", "g2", "g3", "g4", "g5", "g7", "l2", "l3", \ + "i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpsr)), \ + "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)), \ + "r" (task_pc), "i" (255), \ + "i" ((const unsigned long)(&((struct task_struct *)0)->processor)) \ + : "g1", "g2", "g3", "g4", "g5", "g7", "l2", "l3", \ "l4", "l5", "l6", "l7", "i0", "i1", "i2", "i3", "i4", "i5", "o0", "o1", "o2", \ "o3"); \ -here: SWITCH_EXIT } while(0) +here: } while(0) /* Changing the IRQ level on the Sparc. We now avoid writing the psr * whenever possible. @@ -128,10 +132,10 @@ nop " : /* no outputs */ : "r" (__orig_psr) - : "memory"); + : "memory", "cc"); } -extern __inline__ void cli(void) +extern __inline__ void __cli(void) { unsigned long tmp; @@ -150,7 +154,7 @@ : "memory"); } -extern __inline__ void sti(void) +extern __inline__ void __sti(void) { unsigned long tmp; @@ -195,7 +199,7 @@ 1: " : "=r" (retval), "=r" (tmp1), "=r" (tmp2) : "r" (__new_psr), "i" (PSR_PIL) - : "memory"); + : "memory", "cc"); return retval; } @@ -223,9 +227,31 @@ extern char spdeb_buf[256]; -#define save_flags(flags) ((flags) = getipl()) -#define save_and_cli(flags) ((flags) = read_psr_and_cli()) -#define restore_flags(flags) setipl((flags)) +#define __save_flags(flags) ((flags) = getipl()) +#define __save_and_cli(flags) ((flags) = read_psr_and_cli()) +#define __restore_flags(flags) setipl((flags)) + +#ifdef __SMP__ + +extern void __global_cli(void); +extern void __global_sti(void); +extern unsigned long __global_save_flags(void); +extern void __global_restore_flags(unsigned long); +#define cli() __global_cli() +#define sti() __global_sti() +#define save_flags(x) ((x)=__global_save_flags()) +#define restore_flags(x) __global_restore_flags(x) +#define save_and_cli(x) do { (x)=__global_save_flags(); __global_cli(); } while(0) + +#else + +#define cli() __cli() +#define sti() __sti() +#define save_flags(x) __save_flags(x) +#define restore_flags(x) __restore_flags(x) +#define save_and_cli(x) __save_and_cli(x) + +#endif /* XXX Change this if we ever use a PSO mode kernel. */ #define mb() __asm__ __volatile__ ("" : : : "memory") @@ -246,7 +272,7 @@ add %%o7, 8, %%o7 " : "=&r" (ret) : "0" (ret), "r" (ptr) - : "g3", "g4", "g7", "memory"); + : "g3", "g4", "g7", "memory", "cc"); return ret; } @@ -267,6 +293,8 @@ } extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noreturn)); + +#endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/termbits.h linux/include/asm-sparc/termbits.h --- v2.1.33/linux/include/asm-sparc/termbits.h Mon Mar 17 14:54:32 1997 +++ linux/include/asm-sparc/termbits.h Fri Apr 11 10:47:39 1997 @@ -115,44 +115,40 @@ #define WRAP 0x00020000 /* SUNOS specific */ /* c_cflag bit meaning */ -#define CBAUD 0x0000000f -#define B0 0x00000000 /* hang up */ -#define B50 0x00000001 -#define B75 0x00000002 -#define B110 0x00000003 -#define B134 0x00000004 -#define B150 0x00000005 -#define B200 0x00000006 -#define B300 0x00000007 -#define B600 0x00000008 -#define B1200 0x00000009 -#define B1800 0x0000000a -#define B2400 0x0000000b -#define B4800 0x0000000c -#define B9600 0x0000000d -#define B19200 0x0000000e -#define B38400 0x0000000f -#define EXTA B19200 -#define EXTB B38400 -#define CSIZE 0x00000030 -#define CS5 0x00000000 -#define CS6 0x00000010 -#define CS7 0x00000020 -#define CS8 0x00000030 -#define CSTOPB 0x00000040 -#define CREAD 0x00000080 -#define PARENB 0x00000100 -#define PARODD 0x00000200 -#define HUPCL 0x00000400 -#define CLOCAL 0x00000800 -/* We'll never see these speeds with the Zilogs' but for completeness... */ -#define CBAUDEX 0x00010000 -#define B57600 0x00010001 -#define B115200 0x00010002 -#define B230400 0x00010003 -#define B460800 0x00010004 -#define CIBAUD 0x000f0000 /* input baud rate (not used) */ -#define CMSPAR 010000000000 /* mark or space (stick) parity */ +#define CBAUD 0x0000100f +#define B0 0x00000000 /* hang up */ +#define B50 0x00000001 +#define B75 0x00000002 +#define B110 0x00000003 +#define B134 0x00000004 +#define B150 0x00000005 +#define B200 0x00000006 +#define B300 0x00000007 +#define B600 0x00000008 +#define B1200 0x00000009 +#define B1800 0x0000000a +#define B2400 0x0000000b +#define B4800 0x0000000c +#define B9600 0x0000000d +#define B19200 0x0000000e +#define B38400 0x0000000f +#define EXTA B19200 +#define EXTB B38400 +#define CSIZE 0x00000030 +#define CS5 0x00000000 +#define CS6 0x00000010 +#define CS7 0x00000020 +#define CS8 0x00000030 +#define CSTOPB 0x00000040 +#define CREAD 0x00000080 +#define PARENB 0x00000100 +#define PARODD 0x00000200 +#define HUPCL 0x00000400 +#define CLOCAL 0x00000800 +#define CBAUDEX 0x00001000 +#define B76800 0x00001001 +#define CIBAUD 0x100f0000 /* input baud rate (not used) */ +#define CMSPAR 0x40000000 /* mark or space (stick) parity */ #define CRTSCTS 0x80000000 /* flow control */ /* c_lflag bits */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/uaccess.h linux/include/asm-sparc/uaccess.h --- v2.1.33/linux/include/asm-sparc/uaccess.h Mon Mar 17 14:54:33 1997 +++ linux/include/asm-sparc/uaccess.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: uaccess.h,v 1.11 1997/02/06 18:57:10 jj Exp $ +/* $Id: uaccess.h,v 1.13 1997/04/11 00:42:22 davem Exp $ * uaccess.h: User space memore access functions. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -157,7 +157,7 @@ #define __put_user_asm(x,size,addr,ret) \ __asm__ __volatile__( \ "/* Put user asm, inline. */\n" \ -"1:\t" "st"#size " %1, [%2]\n\t" \ +"1:\t" "st"#size " %1, %2\n\t" \ "clr %0\n" \ "2:\n\n\t" \ ".section .fixup,#alloc,#execinstr\n\t" \ @@ -170,23 +170,23 @@ ".align 4\n\t" \ ".word 1b, 3b\n\t" \ ".previous\n\n\t" \ - : "=&r" (ret) : "r" (x), "r" (__m(addr)), \ + : "=&r" (ret) : "r" (x), "m" (*__m(addr)), \ "i" (-EFAULT)) #define __put_user_asm_ret(x,size,addr,ret,foo) \ if (__builtin_constant_p(ret) && ret == -EFAULT) \ __asm__ __volatile__( \ "/* Put user asm ret, inline. */\n" \ -"1:\t" "st"#size " %1, [%2]\n\n\t" \ +"1:\t" "st"#size " %1, %2\n\n\t" \ ".section __ex_table,#alloc\n\t" \ ".align 4\n\t" \ ".word 1b, __ret_efault\n\n\t" \ ".previous\n\n\t" \ - : "=r" (foo) : "r" (x), "r" (__m(addr))); \ + : "=r" (foo) : "r" (x), "m" (*__m(addr))); \ else \ __asm__ __volatile( \ "/* Put user asm ret, inline. */\n" \ -"1:\t" "st"#size " %1, [%2]\n\n\t" \ +"1:\t" "st"#size " %1, %2\n\n\t" \ ".section .fixup,#alloc,#execinstr\n\t" \ ".align 4\n" \ "3:\n\t" \ @@ -197,7 +197,7 @@ ".align 4\n\t" \ ".word 1b, 3b\n\n\t" \ ".previous\n\n\t" \ - : "=r" (foo) : "r" (x), "r" (__m(addr)), "i" (ret)) + : "=r" (foo) : "r" (x), "m" (*__m(addr)), "i" (ret)) extern int __put_user_bad(void); @@ -244,7 +244,7 @@ #define __get_user_asm(x,size,addr,ret) \ __asm__ __volatile__( \ "/* Get user asm, inline. */\n" \ -"1:\t" "ld"#size " [%2], %1\n\t" \ +"1:\t" "ld"#size " %2, %1\n\t" \ "clr %0\n" \ "2:\n\n\t" \ ".section .fixup,#alloc,#execinstr\n\t" \ @@ -258,23 +258,23 @@ ".align 4\n\t" \ ".word 1b, 3b\n\n\t" \ ".previous\n\t" \ - : "=&r" (ret), "=&r" (x) : "r" (__m(addr)), \ + : "=&r" (ret), "=&r" (x) : "m" (*__m(addr)), \ "i" (-EFAULT)) #define __get_user_asm_ret(x,size,addr,retval) \ if (__builtin_constant_p(retval) && retval == -EFAULT) \ __asm__ __volatile__( \ "/* Get user asm ret, inline. */\n" \ -"1:\t" "ld"#size " [%1], %0\n\n\t" \ +"1:\t" "ld"#size " %1, %0\n\n\t" \ ".section __ex_table,#alloc\n\t" \ ".align 4\n\t" \ ".word 1b,__ret_efault\n\n\t" \ ".previous\n\t" \ - : "=&r" (x) : "r" (__m(addr))); \ + : "=&r" (x) : "m" (*__m(addr))); \ else \ __asm__ __volatile__( \ "/* Get user asm ret, inline. */\n" \ -"1:\t" "ld"#size " [%1], %0\n\n\t" \ +"1:\t" "ld"#size " %1, %0\n\n\t" \ ".section .fixup,#alloc,#execinstr\n\t" \ ".align 4\n" \ "3:\n\t" \ @@ -285,7 +285,7 @@ ".align 4\n\t" \ ".word 1b, 3b\n\n\t" \ ".previous\n\t" \ - : "=&r" (x) : "r" (__m(addr)), "i" (retval)) + : "=&r" (x) : "m" (*__m(addr)), "i" (retval)) extern int __get_user_bad(void); @@ -351,7 +351,8 @@ mov %1, %%o0 mov %%o0, %0 " : "=r" (ret) : "r" (addr), "r" (size) : - "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7"); + "o0", "o1", "o2", "o3", "o4", "o5", "o7", + "g1", "g2", "g3", "g4", "g5", "g7", "cc"); return ret; } diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/unistd.h linux/include/asm-sparc/unistd.h --- v2.1.33/linux/include/asm-sparc/unistd.h Fri Apr 4 08:52:25 1997 +++ linux/include/asm-sparc/unistd.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: unistd.h,v 1.29 1997/02/04 07:14:17 miguel Exp $ */ +/* $Id: unistd.h,v 1.32 1997/04/11 00:42:23 davem Exp $ */ #ifndef _SPARC_UNISTD_H #define _SPARC_UNISTD_H @@ -113,35 +113,35 @@ #define __NR_setdopt 94 /* SunOS Specific */ #define __NR_fsync 95 /* Common */ #define __NR_setpriority 96 /* Common */ -#define __NR_socket 97 /* SunOS Specific */ -#define __NR_connect 98 /* SunOS Specific */ -#define __NR_accept 99 /* SunOS Specific */ +#define __NR_socket 97 /* Common */ +#define __NR_connect 98 /* Common */ +#define __NR_accept 99 /* Common */ #define __NR_getpriority 100 /* Common */ -#define __NR_send 101 /* SunOS Specific */ -#define __NR_recv 102 /* SunOS Specific */ +#define __NR_send 101 /* Common */ +#define __NR_recv 102 /* Common */ /* #define __NR_ni_syscall 103 ENOSYS under SunOS */ -#define __NR_bind 104 /* SunOS Specific */ -#define __NR_setsockopt 105 /* SunOS Specific */ -#define __NR_listen 106 /* SunOS Specific */ +#define __NR_bind 104 /* Common */ +#define __NR_setsockopt 105 /* Common */ +#define __NR_listen 106 /* Common */ /* #define __NR_ni_syscall 107 ENOSYS under SunOS */ #define __NR_sigvec 108 /* SunOS Specific */ #define __NR_sigblock 109 /* SunOS Specific */ #define __NR_sigsetmask 110 /* SunOS Specific */ #define __NR_sigpause 111 /* SunOS Specific */ #define __NR_sigstack 112 /* SunOS Specific */ -#define __NR_recvmsg 113 /* SunOS Specific */ -#define __NR_sendmsg 114 /* SunOS Specific */ +#define __NR_recvmsg 113 /* Common */ +#define __NR_sendmsg 114 /* Common */ #define __NR_vtrace 115 /* SunOS Specific */ #define __NR_gettimeofday 116 /* Common */ #define __NR_getrusage 117 /* Common */ -#define __NR_getsockopt 118 /* SunOS Specific */ +#define __NR_getsockopt 118 /* Common */ /* #define __NR_ni_syscall 119 ENOSYS under SunOS */ #define __NR_readv 120 /* Common */ #define __NR_writev 121 /* Common */ #define __NR_settimeofday 122 /* Common */ #define __NR_fchown 123 /* Common */ #define __NR_fchmod 124 /* Common */ -#define __NR_recvfrom 125 /* SunOS Specific */ +#define __NR_recvfrom 125 /* Common */ #define __NR_setreuid 126 /* Common */ #define __NR_setregid 127 /* Common */ #define __NR_rename 128 /* Common */ @@ -149,15 +149,15 @@ #define __NR_ftruncate 130 /* Common */ #define __NR_flock 131 /* Common */ /* #define __NR_ni_syscall 132 ENOSYS under SunOS */ -#define __NR_sendto 133 /* SunOS Specific */ -#define __NR_shutdown 134 /* SunOS Specific */ -#define __NR_socketpair 135 /* SunOS Specific */ +#define __NR_sendto 133 /* Common */ +#define __NR_shutdown 134 /* Common */ +#define __NR_socketpair 135 /* Common */ #define __NR_mkdir 136 /* Common */ #define __NR_rmdir 137 /* Common */ #define __NR_utimes 138 /* SunOS Specific */ /* #define __NR_ni_syscall 139 ENOSYS under SunOS */ #define __NR_adjtime 140 /* SunOS Specific */ -#define __NR_getpeername 141 /* SunOS Specific */ +#define __NR_getpeername 141 /* Common */ #define __NR_gethostid 142 /* SunOS Specific */ /* #define __NR_ni_syscall 143 ENOSYS under SunOS */ #define __NR_getrlimit 144 /* Common */ @@ -166,7 +166,7 @@ /* #define __NR_ni_syscall 147 ENOSYS under SunOS */ /* #define __NR_ni_syscall 148 ENOSYS under SunOS */ /* #define __NR_ni_syscall 149 ENOSYS under SunOS */ -#define __NR_getsockname 150 /* SunOS Specific */ +#define __NR_getsockname 150 /* Common */ #define __NR_getmsg 151 /* SunOS Specific */ #define __NR_putmsg 152 /* SunOS Specific */ #define __NR_poll 153 /* Common */ @@ -285,7 +285,7 @@ "1:\n\t" \ : "=r" (__res)\ : "0" (__NR_##name) \ - : "g1", "o0"); \ + : "g1", "o0", "cc"); \ if (__res < -255 || __res >= 0) \ return (type) __res; \ errno = -__res; \ @@ -305,7 +305,7 @@ "1:\n\t" \ : "=r" (__res), "=r" ((long)(arg1)) \ : "0" (__NR_##name),"1" ((long)(arg1)) \ - : "g1", "o0"); \ + : "g1", "o0", "cc"); \ if (__res < -255 || __res >= 0) \ return (type) __res; \ errno = -__res; \ @@ -326,7 +326,7 @@ "1:\n\t" \ : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)) \ : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)) \ - : "g1", "o0", "o1"); \ + : "g1", "o0", "o1", "cc"); \ if (__res < -255 || __res >= 0) \ return (type) __res; \ errno = -__res; \ @@ -350,7 +350,7 @@ "=r" ((long)(arg3)) \ : "0" (__NR_##name), "1" ((long)(arg1)), "2" ((long)(arg2)), \ "3" ((long)(arg3)) \ - : "g1", "o0", "o1", "o2"); \ + : "g1", "o0", "o1", "o2", "cc"); \ if (__res < -255 || __res>=0) \ return (type) __res; \ errno = -__res; \ @@ -375,7 +375,7 @@ "=r" ((long)(arg3)), "=r" ((long)(arg4)) \ : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)), \ "3" ((long)(arg3)),"4" ((long)(arg4)) \ - : "g1", "o0", "o1", "o2", "o3"); \ + : "g1", "o0", "o1", "o2", "o3", "cc"); \ if (__res < -255 || __res>=0) \ return (type) __res; \ errno = -__res; \ @@ -403,7 +403,7 @@ : "r" ((long)(arg1)),"r" ((long)(arg2)), \ "r" ((long)(arg3)),"r" ((long)(arg4)),"r" ((long)(arg5)), \ "i" (__NR_##name) \ - : "g1", "o0", "o1", "o2", "o3", "o4"); \ + : "g1", "o0", "o1", "o2", "o3", "o4", "cc"); \ if (__res < -255 || __res>=0) \ return (type) __res; \ errno = -__res; \ @@ -474,7 +474,7 @@ "=r" (retval) : "i" (__NR_clone), "r" (flags | CLONE_VM), "i" (__NR_exit), "r" (fn), "r" (arg) : - "g1", "g2", "g3", "o0", "o1", "memory"); + "g1", "g2", "g3", "o0", "o1", "memory", "cc"); return retval; } diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/vfc_ioctls.h linux/include/asm-sparc/vfc_ioctls.h --- v2.1.33/linux/include/asm-sparc/vfc_ioctls.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc/vfc_ioctls.h Fri Apr 11 10:47:39 1997 @@ -0,0 +1,58 @@ +/* Copyright (c) 1996 by Manish Vachharajani */ + +#ifndef _LINUX_VFC_IOCTLS_H_ +#define _LINUX_VFC_IOCTLS_H_ + + /* IOCTLs */ +#define VFC_IOCTL(a) (('j' << 8) | a) +#define VFCGCTRL (VFC_IOCTL (0)) /* get vfc attributes */ +#define VFCSCTRL (VFC_IOCTL (1)) /* set vfc attributes */ +#define VFCGVID (VFC_IOCTL (2)) /* get video decoder attributes */ +#define VFCSVID (VFC_IOCTL (3)) /* set video decoder attributes */ +#define VFCHUE (VFC_IOCTL (4)) /* set hue */ +#define VFCPORTCHG (VFC_IOCTL (5)) /* change port */ +#define VFCRDINFO (VFC_IOCTL (6)) /* read info */ + + /* Options for setting the vfc attributes and status */ +#define MEMPRST 0x1 /* reset FIFO ptr. */ +#define CAPTRCMD 0x2 /* start capture and wait */ +#define DIAGMODE 0x3 /* diag mode */ +#define NORMMODE 0x4 /* normal mode */ +#define CAPTRSTR 0x5 /* start capture */ +#define CAPTRWAIT 0x6 /* wait for capture to finish */ + + + /* Options for the decoder */ +#define STD_NTSC 0x1 /* NTSC mode */ +#define STD_PAL 0x2 /* PAL mode */ +#define COLOR_ON 0x3 /* force color ON */ +#define MONO 0x4 /* force color OFF */ + + /* Values returned by ioctl 2 */ + +#define NO_LOCK 1 +#define NTSC_COLOR 2 +#define NTSC_NOCOLOR 3 +#define PAL_COLOR 4 +#define PAL_NOCOLOR 5 + +/* Not too sure what this does yet */ + /* Options for setting Field number */ +#define ODD_FIELD 0x1 +#define EVEN_FIELD 0x0 +#define ACTIVE_ONLY 0x2 +#define NON_ACTIVE 0x0 + +/* Debug options */ +#define VFC_I2C_SEND 0 +#define VFC_I2C_RECV 1 + +struct vfc_debug_inout +{ + unsigned long addr; + unsigned long ret; + unsigned long len; + unsigned char *buffer; +}; + +#endif /* _LINUX_VFC_IOCTLS_H_ */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/viking.h linux/include/asm-sparc/viking.h --- v2.1.33/linux/include/asm-sparc/viking.h Fri Dec 13 01:37:40 1996 +++ linux/include/asm-sparc/viking.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: viking.h,v 1.17 1996/11/24 17:11:51 ecd Exp $ +/* $Id: viking.h,v 1.18 1997/04/11 00:42:23 davem Exp $ * viking.h: Defines specific to the GNU/Viking MBUS module. * This is SRMMU stuff. * @@ -191,7 +191,7 @@ "1:\n\t" : : "r" (mreg), "r" (mxcc_creg), "r" (MXCC_CREG), "i" (ASI_M_MMUREGS), - "i" (ASI_M_MXCC) : "g2"); + "i" (ASI_M_MXCC) : "g2", "cc"); *mregp = mreg; *mxcc_cregp = mxcc_creg; } diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/a.out.h linux/include/asm-sparc64/a.out.h --- v2.1.33/linux/include/asm-sparc64/a.out.h Mon Dec 30 02:00:02 1996 +++ linux/include/asm-sparc64/a.out.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: a.out.h,v 1.2 1996/12/28 18:39:49 davem Exp $ */ +/* $Id: a.out.h,v 1.3 1997/04/07 18:57:14 jj Exp $ */ #ifndef __SPARC64_A_OUT_H__ #define __SPARC64_A_OUT_H__ @@ -32,14 +32,14 @@ (x).a_drsize) /* Where does text segment go in memory after being loaded? */ -#define N_TXTADDR(x) (((N_MAGIC(x) == ZMAGIC) && \ - ((x).a_entry < SPARC_PGSIZE)) ? \ +#define N_TXTADDR(x) (unsigned long)(((N_MAGIC(x) == ZMAGIC) && \ + ((x).a_entry < SPARC_PGSIZE)) ? \ 0 : SPARC_PGSIZE) /* And same for the data segment.. */ #define N_DATADDR(x) (N_MAGIC(x)==OMAGIC ? \ (N_TXTADDR(x) + (x).a_text) \ - : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) + : (unsigned long)(_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) #define N_TRSIZE(a) ((a).a_trsize) #define N_DRSIZE(a) ((a).a_drsize) diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/asm_offsets.h linux/include/asm-sparc64/asm_offsets.h --- v2.1.33/linux/include/asm-sparc64/asm_offsets.h Mon Mar 17 14:54:33 1997 +++ linux/include/asm-sparc64/asm_offsets.h Fri Apr 11 10:47:39 1997 @@ -53,116 +53,116 @@ #define AOFF_task_ngroups 0x000000e0 #define ASIZ_task_ngroups 0x00000004 #define AOFF_task_groups 0x000000e4 -#define ASIZ_task_groups 0x00000040 -#define AOFF_task_p_opptr 0x00000128 +#define ASIZ_task_groups 0x00000080 +#define AOFF_task_p_opptr 0x00000168 #define ASIZ_task_p_opptr 0x00000008 -#define AOFF_task_p_pptr 0x00000130 +#define AOFF_task_p_pptr 0x00000170 #define ASIZ_task_p_pptr 0x00000008 -#define AOFF_task_p_cptr 0x00000138 +#define AOFF_task_p_cptr 0x00000178 #define ASIZ_task_p_cptr 0x00000008 -#define AOFF_task_p_ysptr 0x00000140 +#define AOFF_task_p_ysptr 0x00000180 #define ASIZ_task_p_ysptr 0x00000008 -#define AOFF_task_p_osptr 0x00000148 +#define AOFF_task_p_osptr 0x00000188 #define ASIZ_task_p_osptr 0x00000008 -#define AOFF_task_wait_chldexit 0x00000150 +#define AOFF_task_wait_chldexit 0x00000190 #define ASIZ_task_wait_chldexit 0x00000008 -#define AOFF_task_uid 0x00000158 +#define AOFF_task_uid 0x00000198 #define ASIZ_task_uid 0x00000002 -#define AOFF_task_euid 0x0000015a +#define AOFF_task_euid 0x0000019a #define ASIZ_task_euid 0x00000002 -#define AOFF_task_suid 0x0000015c +#define AOFF_task_suid 0x0000019c #define ASIZ_task_suid 0x00000002 -#define AOFF_task_fsuid 0x0000015e +#define AOFF_task_fsuid 0x0000019e #define ASIZ_task_fsuid 0x00000002 -#define AOFF_task_gid 0x00000160 +#define AOFF_task_gid 0x000001a0 #define ASIZ_task_gid 0x00000002 -#define AOFF_task_egid 0x00000162 +#define AOFF_task_egid 0x000001a2 #define ASIZ_task_egid 0x00000002 -#define AOFF_task_sgid 0x00000164 +#define AOFF_task_sgid 0x000001a4 #define ASIZ_task_sgid 0x00000002 -#define AOFF_task_fsgid 0x00000166 +#define AOFF_task_fsgid 0x000001a6 #define ASIZ_task_fsgid 0x00000002 -#define AOFF_task_timeout 0x00000168 +#define AOFF_task_timeout 0x000001a8 #define ASIZ_task_timeout 0x00000008 -#define AOFF_task_policy 0x00000170 +#define AOFF_task_policy 0x000001b0 #define ASIZ_task_policy 0x00000008 -#define AOFF_task_rt_priority 0x00000178 +#define AOFF_task_rt_priority 0x000001b8 #define ASIZ_task_rt_priority 0x00000008 -#define AOFF_task_it_real_value 0x00000180 +#define AOFF_task_it_real_value 0x000001c0 #define ASIZ_task_it_real_value 0x00000008 -#define AOFF_task_it_prof_value 0x00000188 +#define AOFF_task_it_prof_value 0x000001c8 #define ASIZ_task_it_prof_value 0x00000008 -#define AOFF_task_it_virt_value 0x00000190 +#define AOFF_task_it_virt_value 0x000001d0 #define ASIZ_task_it_virt_value 0x00000008 -#define AOFF_task_it_real_incr 0x00000198 +#define AOFF_task_it_real_incr 0x000001d8 #define ASIZ_task_it_real_incr 0x00000008 -#define AOFF_task_it_prof_incr 0x000001a0 +#define AOFF_task_it_prof_incr 0x000001e0 #define ASIZ_task_it_prof_incr 0x00000008 -#define AOFF_task_it_virt_incr 0x000001a8 +#define AOFF_task_it_virt_incr 0x000001e8 #define ASIZ_task_it_virt_incr 0x00000008 -#define AOFF_task_real_timer 0x000001b0 +#define AOFF_task_real_timer 0x000001f0 #define ASIZ_task_real_timer 0x00000028 -#define AOFF_task_utime 0x000001d8 +#define AOFF_task_utime 0x00000218 #define ASIZ_task_utime 0x00000008 -#define AOFF_task_stime 0x000001e0 +#define AOFF_task_stime 0x00000220 #define ASIZ_task_stime 0x00000008 -#define AOFF_task_cutime 0x000001e8 +#define AOFF_task_cutime 0x00000228 #define ASIZ_task_cutime 0x00000008 -#define AOFF_task_cstime 0x000001f0 +#define AOFF_task_cstime 0x00000230 #define ASIZ_task_cstime 0x00000008 -#define AOFF_task_start_time 0x000001f8 +#define AOFF_task_start_time 0x00000238 #define ASIZ_task_start_time 0x00000008 -#define AOFF_task_min_flt 0x00000200 +#define AOFF_task_min_flt 0x00000240 #define ASIZ_task_min_flt 0x00000008 -#define AOFF_task_maj_flt 0x00000208 +#define AOFF_task_maj_flt 0x00000248 #define ASIZ_task_maj_flt 0x00000008 -#define AOFF_task_nswap 0x00000210 +#define AOFF_task_nswap 0x00000250 #define ASIZ_task_nswap 0x00000008 -#define AOFF_task_cmin_flt 0x00000218 +#define AOFF_task_cmin_flt 0x00000258 #define ASIZ_task_cmin_flt 0x00000008 -#define AOFF_task_cmaj_flt 0x00000220 +#define AOFF_task_cmaj_flt 0x00000260 #define ASIZ_task_cmaj_flt 0x00000008 -#define AOFF_task_cnswap 0x00000228 +#define AOFF_task_cnswap 0x00000268 #define ASIZ_task_cnswap 0x00000008 -#define AOFF_task_swap_address 0x00000238 +#define AOFF_task_swap_address 0x00000278 #define ASIZ_task_swap_address 0x00000008 -#define AOFF_task_old_maj_flt 0x00000240 +#define AOFF_task_old_maj_flt 0x00000280 #define ASIZ_task_old_maj_flt 0x00000008 -#define AOFF_task_dec_flt 0x00000248 +#define AOFF_task_dec_flt 0x00000288 #define ASIZ_task_dec_flt 0x00000008 -#define AOFF_task_swap_cnt 0x00000250 +#define AOFF_task_swap_cnt 0x00000290 #define ASIZ_task_swap_cnt 0x00000008 -#define AOFF_task_rlim 0x00000258 +#define AOFF_task_rlim 0x00000298 #define ASIZ_task_rlim 0x000000a0 -#define AOFF_task_used_math 0x000002f8 +#define AOFF_task_used_math 0x00000338 #define ASIZ_task_used_math 0x00000002 -#define AOFF_task_comm 0x000002fa +#define AOFF_task_comm 0x0000033a #define ASIZ_task_comm 0x00000010 -#define AOFF_task_link_count 0x0000030c +#define AOFF_task_link_count 0x0000034c #define ASIZ_task_link_count 0x00000004 -#define AOFF_task_tty 0x00000310 +#define AOFF_task_tty 0x00000350 #define ASIZ_task_tty 0x00000008 -#define AOFF_task_semundo 0x00000318 +#define AOFF_task_semundo 0x00000358 #define ASIZ_task_semundo 0x00000008 -#define AOFF_task_semsleeping 0x00000320 +#define AOFF_task_semsleeping 0x00000360 #define ASIZ_task_semsleeping 0x00000008 -#define AOFF_task_ldt 0x00000328 +#define AOFF_task_ldt 0x00000368 #define ASIZ_task_ldt 0x00000008 -#define AOFF_task_tss 0x00000340 -#define ASIZ_task_tss 0x00000700 -#define AOFF_task_fs 0x00000a40 +#define AOFF_task_tss 0x00000380 +#define ASIZ_task_tss 0x00000600 +#define AOFF_task_fs 0x00000980 #define ASIZ_task_fs 0x00000008 -#define AOFF_task_files 0x00000a48 +#define AOFF_task_files 0x00000988 #define ASIZ_task_files 0x00000008 -#define AOFF_task_mm 0x00000a50 +#define AOFF_task_mm 0x00000990 #define ASIZ_task_mm 0x00000008 -#define AOFF_task_sig 0x00000a58 +#define AOFF_task_sig 0x00000998 #define ASIZ_task_sig 0x00000008 -#define AOFF_task_processor 0x00000a60 +#define AOFF_task_processor 0x000009a0 #define ASIZ_task_processor 0x00000004 -#define AOFF_task_last_processor 0x00000a64 +#define AOFF_task_last_processor 0x000009a4 #define ASIZ_task_last_processor 0x00000004 -#define AOFF_task_lock_depth 0x00000a68 +#define AOFF_task_lock_depth 0x000009a8 #define ASIZ_task_lock_depth 0x00000004 #define AOFF_mm_count 0x00000000 #define ASIZ_mm_count 0x00000004 @@ -212,35 +212,35 @@ #define ASIZ_thread_float_regs 0x00000100 #define AOFF_thread_fsr 0x00000100 #define ASIZ_thread_fsr 0x00000008 -#define AOFF_thread_fpqdepth 0x00000108 -#define ASIZ_thread_fpqdepth 0x00000008 -#define AOFF_thread_fpqueue 0x00000110 -#define ASIZ_thread_fpqueue 0x00000100 -#define AOFF_thread_user_globals 0x00000210 -#define ASIZ_thread_user_globals 0x00000040 -#define AOFF_thread_ksp 0x00000250 +#define AOFF_thread_ksp 0x00000108 #define ASIZ_thread_ksp 0x00000008 -#define AOFF_thread_kpc 0x00000258 +#define AOFF_thread_kpc 0x00000110 #define ASIZ_thread_kpc 0x00000008 -#define AOFF_thread_reg_window 0x00000260 +#define AOFF_thread_wstate 0x00000118 +#define ASIZ_thread_wstate 0x00000008 +#define AOFF_thread_cwp 0x00000120 +#define ASIZ_thread_cwp 0x00000008 +#define AOFF_thread_reg_window 0x00000130 #define ASIZ_thread_reg_window 0x00000400 -#define AOFF_thread_rwbuf_stkptrs 0x00000660 +#define AOFF_thread_rwbuf_stkptrs 0x00000530 #define ASIZ_thread_rwbuf_stkptrs 0x00000040 -#define AOFF_thread_w_saved 0x000006a0 +#define AOFF_thread_w_saved 0x00000570 #define ASIZ_thread_w_saved 0x00000008 -#define AOFF_thread_flags 0x000006a8 +#define AOFF_thread_flags 0x00000578 #define ASIZ_thread_flags 0x00000008 -#define AOFF_thread_sig_address 0x000006b0 +#define AOFF_thread_sig_address 0x00000580 #define ASIZ_thread_sig_address 0x00000008 -#define AOFF_thread_sig_desc 0x000006b8 +#define AOFF_thread_sig_desc 0x00000588 #define ASIZ_thread_sig_desc 0x00000008 -#define AOFF_thread_sstk_info 0x000006c0 +#define AOFF_thread_sstk_info 0x00000590 #define ASIZ_thread_sstk_info 0x00000010 -#define AOFF_thread_current_ds 0x000006d0 +#define AOFF_thread_current_ds 0x000005a0 #define ASIZ_thread_current_ds 0x00000004 -#define AOFF_thread_new_signal 0x000006d4 +#define AOFF_thread_new_signal 0x000005a4 #define ASIZ_thread_new_signal 0x00000004 -#define AOFF_thread_core_exec 0x000006d8 +#define AOFF_thread_kregs 0x000005a8 +#define ASIZ_thread_kregs 0x00000008 +#define AOFF_thread_core_exec 0x000005b0 #define ASIZ_thread_core_exec 0x00000020 #endif /* __ASM_OFFSETS_H__ */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/atomic.h linux/include/asm-sparc64/atomic.h --- v2.1.33/linux/include/asm-sparc64/atomic.h Fri Dec 13 01:37:41 1996 +++ linux/include/asm-sparc64/atomic.h Mon Apr 14 09:31:09 1997 @@ -1,4 +1,4 @@ -/* $Id: atomic.h,v 1.6 1996/12/12 15:40:22 davem Exp $ +/* $Id: atomic.h,v 1.13 1997/04/14 06:56:57 davem Exp $ * atomic.h: Thankfully the V9 is at least reasonable for this * stuff. * @@ -14,73 +14,81 @@ */ #define __atomic_fool_gcc(x) ((struct { int a[100]; } *)x) -typedef int atomic_t; +typedef struct { int counter; } atomic_t; +#define ATOMIC_INIT { 0 } -extern __inline__ void atomic_add(atomic_t i, atomic_t *v) +#define atomic_read(v) ((v)->counter) +#define atomic_set(v, i) (((v)->counter) = i) + +extern __inline__ void atomic_add(int i, atomic_t *v) { unsigned long temp0, temp1; __asm__ __volatile__(" - lduw [%2], %0 + lduw [%3], %0 1: - add %0, %3, %1 - cas [%2], %0, %1 + add %0, %2, %1 + cas [%3], %0, %1 cmp %0, %1 bne,a,pn %%icc, 1b - lduw [%2], %0 + lduw [%3], %0 2: -" : "=&r" (temp0), "=&r" (temp1), "=r" (__atomic_fool_gcc(v)) - : "ir" (i), "r" (__atomic_fool_gcc(v))); +" : "=&r" (temp0), "=&r" (temp1) + : "HIr" (i), "r" (__atomic_fool_gcc(v)) + : "cc"); } -extern __inline__ void atomic_sub(atomic_t i, atomic_t *v) +extern __inline__ void atomic_sub(int i, atomic_t *v) { unsigned long temp0, temp1; __asm__ __volatile__(" - lduw [%2], %0 + lduw [%3], %0 1: - sub %0, %3, %1 - cas [%2], %0, %1 + sub %0, %2, %1 + cas [%3], %0, %1 cmp %0, %1 bne,a,pn %%icc, 1b - lduw [%2], %0 + lduw [%3], %0 2: -" : "=&r" (temp0), "=&r" (temp1), "=r" (__atomic_fool_gcc(v)) - : "ir" (i), "r" (__atomic_fool_gcc(v))); +" : "=&r" (temp0), "=&r" (temp1) + : "HIr" (i), "r" (__atomic_fool_gcc(v)) + : "cc"); } /* Same as above, but return the result value. */ -extern __inline__ long atomic_add_return(atomic_t i, atomic_t *v) +extern __inline__ int atomic_add_return(int i, atomic_t *v) { - long temp0, result; + unsigned long temp0, oldval; __asm__ __volatile__(" - lduw [%2], %0 + lduw [%3], %0 1: - add %0, %3, %1 - cas [%2], %0, %1 + add %0, %2, %1 + cas [%3], %0, %1 cmp %0, %1 bne,a,pn %%icc, 1b - lduw [%2], %0 + lduw [%3], %0 2: -" : "=&r" (temp0), "=&r" (result), "=r" (__atomic_fool_gcc(v)) - : "ir" (i), "r" (__atomic_fool_gcc(v))); - return result; +" : "=&r" (temp0), "=&r" (oldval) + : "HIr" (i), "r" (__atomic_fool_gcc(v)) + : "cc"); + return (((int)oldval) + 1); } -extern __inline__ long atomic_sub_return(atomic_t i, atomic_t *v) +extern __inline__ int atomic_sub_return(int i, atomic_t *v) { - long temp0, result; + unsigned long temp0, oldval; __asm__ __volatile__(" - lduw [%2], %0 + lduw [%3], %0 1: - sub %0, %3, %1 - cas [%2], %0, %1 + sub %0, %2, %1 + cas [%3], %0, %1 cmp %0, %1 bne,a,pn %%icc, 1b - lduw [%2], %0 + lduw [%3], %0 2: -" : "=&r" (temp0), "=&r" (result), "=r" (__atomic_fool_gcc(v)) - : "ir" (i), "r" (__atomic_fool_gcc(v))); - return result; +" : "=&r" (temp0), "=&r" (oldval) + : "HIr" (i), "r" (__atomic_fool_gcc(v)) + : "cc"); + return (((int)oldval) - 1); } #define atomic_dec_return(v) atomic_sub_return(1,(v)) diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/bitops.h linux/include/asm-sparc64/bitops.h --- v2.1.33/linux/include/asm-sparc64/bitops.h Thu Mar 27 14:40:09 1997 +++ linux/include/asm-sparc64/bitops.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: bitops.h,v 1.7 1997/03/14 21:05:38 jj Exp $ +/* $Id: bitops.h,v 1.11 1997/04/10 23:32:42 davem Exp $ * bitops.h: Bit string operations on the V9. * * Copyright 1996 David S. Miller (davem@caip.rutgers.edu) @@ -26,18 +26,19 @@ unsigned int * m = ((unsigned int *) addr) + (nr >> 5); __asm__ __volatile__(" - lduw [%2], %0 + lduw [%4], %0 1: - andcc %0, %4, %3 + andcc %0, %3, %2 bne,pn %%icc, 2f - xor %0, %4, %1 - cas [%2], %0, %1 + xor %0, %3, %1 + cas [%4], %0, %1 cmp %0, %1 bne,a,pn %%icc, 1b - lduw [%2], %0 + lduw [%4], %0 2: -" : "=&r" (temp0), "=&r" (temp1), "=r" (m), "=&r" (oldbit) - : "ir" (1UL << (nr & 31)), "r" (m)); +" : "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit) + : "HIr" (1UL << (nr & 31)), "r" (m) + : "cc"); return oldbit != 0; } @@ -48,18 +49,19 @@ unsigned int * m = ((unsigned int *) addr) + (nr >> 5); __asm__ __volatile__(" - lduw [%2], %0 + lduw [%4], %0 1: - andcc %0, %4, %3 + andcc %0, %3, %2 be,pn %%icc, 2f - xor %0, %4, %1 - cas [%2], %0, %1 + xor %0, %3, %1 + cas [%4], %0, %1 cmp %0, %1 bne,a,pn %%icc, 1b - lduw [%2], %0 + lduw [%4], %0 2: -" : "=&r" (temp0), "=&r" (temp1), "=r" (m), "=&r" (oldbit) - : "ir" (1UL << (nr & 31)), "r" (m)); +" : "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit) + : "HIr" (1UL << (nr & 31)), "r" (m) + : "cc"); return oldbit != 0; } @@ -70,16 +72,17 @@ unsigned int * m = ((unsigned int *) addr) + (nr >> 5); __asm__ __volatile__(" - lduw [%2], %0 + lduw [%4], %0 1: - andcc %0, %4, %3 - xor %0, %4, %1 - cas [%2], %0, %1 + and %0, %3, %2 + xor %0, %3, %1 + cas [%4], %0, %1 cmp %0, %1 bne,a,pn %%icc, 1b - lduw [%2], %0 -" : "=&r" (temp0), "=&r" (temp1), "=r" (m), "=&r" (oldbit) - : "ir" (1UL << (nr & 31)), "r" (m)); + lduw [%4], %0 +" : "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit) + : "HIr" (1UL << (nr & 31)), "r" (m) + : "cc"); return oldbit != 0; } @@ -154,18 +157,19 @@ unsigned int * m = ((unsigned int *) addr) + (nr >> 5); __asm__ __volatile__(" - lduwa [%2] %6, %0 + lduwa [%4] %5, %0 1: - andcc %0, %4, %3 + andcc %0, %3, %2 bne,pn %%icc, 2f - xor %0, %4, %1 - casa [%2] %6, %0, %1 + xor %0, %3, %1 + casa [%4] %5, %0, %1 cmp %0, %1 bne,a,pn %%icc, 1b - lduwa [%2] %6, %0 + lduwa [%4] %5, %0 2: -" : "=&r" (temp0), "=&r" (temp1), "=r" (m), "=&r" (oldbit) - : "ir" (1UL << (nr & 31)), "2" (m), "i" (ASI_PL)); +" : "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit) + : "HIr" (1UL << (nr & 31)), "r" (m), "i" (ASI_PL) + : "cc"); return oldbit != 0; } @@ -176,18 +180,19 @@ unsigned int * m = ((unsigned int *) addr) + (nr >> 5); __asm__ __volatile__(" - lduwa [%2] %6, %0 + lduwa [%4] %5, %0 1: - andcc %0, %4, %3 + andcc %0, %3, %2 be,pn %%icc, 2f - xor %0, %4, %1 - casa [%2] %6, %0, %1 + xor %0, %3, %1 + casa [%4] %5, %0, %1 cmp %0, %1 bne,a,pn %%icc, 1b - lduwa [%2] %6, %0 + lduwa [%4] %5, %0 2: -" : "=&r" (temp0), "=&r" (temp1), "=r" (m), "=&r" (oldbit) - : "ir" (1UL << (nr & 31)), "2" (m), "i" (ASI_PL)); +" : "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit) + : "HIr" (1UL << (nr & 31)), "r" (m), "i" (ASI_PL) + : "cc"); return oldbit != 0; } @@ -259,6 +264,12 @@ #define ext2_test_bit test_le_bit #define ext2_find_first_zero_bit find_first_zero_le_bit #define ext2_find_next_zero_bit find_next_zero_le_bit + +/* Bitmap functions for the minix filesystem. */ +#define minix_set_bit(nr,addr) set_bit(nr,addr) +#define minix_clear_bit(nr,addr) clear_bit(nr,addr) +#define minix_test_bit(nr,addr) test_bit(nr,addr) +#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size) #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/checksum.h linux/include/asm-sparc64/checksum.h --- v2.1.33/linux/include/asm-sparc64/checksum.h Thu Mar 27 14:40:09 1997 +++ linux/include/asm-sparc64/checksum.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: checksum.h,v 1.5 1997/03/18 18:00:28 jj Exp $ */ +/* $Id: checksum.h,v 1.6 1997/04/10 23:32:43 davem Exp $ */ #ifndef __SPARC64_CHECKSUM_H #define __SPARC64_CHECKSUM_H @@ -153,7 +153,7 @@ xnor %%g0, %0, %0 " : "=r" (sum), "=&r" (iph) : "r" (ihl), "1" (iph) - : "g2", "g3", "g7"); + : "g2", "g3", "g7", "cc"); return sum; } @@ -177,7 +177,8 @@ addc %0, %%g0, %0 xnor %%g0, %0, %0 " : "=r" (sum), "=r" (saddr) - : "r" (daddr), "r" ((proto<<16)+len), "0" (sum), "1" (saddr)); + : "r" (daddr), "r" ((proto<<16)+len), "0" (sum), "1" (saddr) + : "cc"); return sum; } @@ -192,7 +193,8 @@ addc %1, %%g0, %1 xnor %%g0, %1, %0 " : "=&r" (sum), "=r" (tmp) - : "0" (sum), "1" (sum<<16)); + : "0" (sum), "1" (sum<<16) + : "cc"); return sum; } @@ -227,7 +229,7 @@ " : "=&r" (sum) : "r" (saddr), "r" (daddr), "r"(htonl((__u32) (len))), "r"(htonl(proto)), "r"(sum) - : "g2", "g3", "g7"); + : "g2", "g3", "g7", "cc"); return csum_fold(sum); } diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/delay.h linux/include/asm-sparc64/delay.h --- v2.1.33/linux/include/asm-sparc64/delay.h Fri Dec 13 01:37:41 1996 +++ linux/include/asm-sparc64/delay.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: delay.h,v 1.3 1996/12/12 15:53:48 davem Exp $ +/* $Id: delay.h,v 1.4 1997/04/10 23:32:44 davem Exp $ * delay.h: Linux delay routines on the V9. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu). @@ -17,7 +17,8 @@ bne,pt %%xcc, 1b subcc %0, 1, %0 " : "=&r" (loops) - : "0" (loops)); + : "0" (loops) + : "cc"); } extern __inline__ void udelay(unsigned long usecs) diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/dma.h linux/include/asm-sparc64/dma.h --- v2.1.33/linux/include/asm-sparc64/dma.h Thu Mar 27 14:40:09 1997 +++ linux/include/asm-sparc64/dma.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: dma.h,v 1.3 1997/03/14 21:05:36 jj Exp $ +/* $Id: dma.h,v 1.7 1997/04/10 05:13:28 davem Exp $ * include/asm-sparc64/dma.h * * Copyright 1996 (C) David S. Miller (davem@caip.rutgers.edu) @@ -8,6 +8,7 @@ #define _ASM_SPARC64_DMA_H #include +#include #include #include @@ -17,7 +18,7 @@ * things can compile. */ #define MAX_DMA_CHANNELS 8 -#define MAX_DMA_ADDRESS ((0x100000000) + PAGE_OFFSET) +#define MAX_DMA_ADDRESS ((0xf0000000) + PAGE_OFFSET) #define DMA_MODE_READ 1 #define DMA_MODE_WRITE 2 @@ -27,10 +28,10 @@ /* Structure to describe the current status of DMA registers on the Sparc */ struct sparc_dma_registers { - __volatile__ unsigned int cond_reg; /* DMA condition register */ - __volatile__ char * st_addr; /* Start address of this transfer */ - __volatile__ unsigned int cnt; /* How many bytes to transfer */ - __volatile__ unsigned int dma_test; /* DMA test register */ + __volatile__ __u32 cond_reg; /* DMA condition register */ + __volatile__ __u32 st_addr; /* Start address of this transfer */ + __volatile__ __u32 cnt; /* How many bytes to transfer */ + __volatile__ __u32 dma_test; /* DMA test register */ }; /* DVMA chip revisions */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/elf.h linux/include/asm-sparc64/elf.h --- v2.1.33/linux/include/asm-sparc64/elf.h Mon Dec 30 02:00:02 1996 +++ linux/include/asm-sparc64/elf.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: elf.h,v 1.2 1996/12/26 13:25:25 davem Exp $ */ +/* $Id: elf.h,v 1.3 1997/04/04 00:50:12 davem Exp $ */ #ifndef __ASM_SPARC64_ELF_H #define __ASM_SPARC64_ELF_H @@ -23,9 +23,11 @@ /* * These are used to set parameters in the core dumps. */ +#ifndef ELF_ARCH #define ELF_ARCH EM_SPARC64 #define ELF_CLASS ELFCLASS64 #define ELF_DATA ELFDATA2MSB; +#endif #define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/fbio.h linux/include/asm-sparc64/fbio.h --- v2.1.33/linux/include/asm-sparc64/fbio.h Fri Dec 13 01:37:46 1996 +++ linux/include/asm-sparc64/fbio.h Fri Apr 11 10:47:39 1997 @@ -45,7 +45,10 @@ }; #define FBIOGTYPE _IOR('F', 0, struct fbtype) -/* Used by FBIOPUTCMAP */ +/* Used by FBIOPUTCMAP + * + * XXX 32-bit binary compatability item... -DaveM + */ struct fbcmap { int index; /* first element (0 origin) */ int count; @@ -98,6 +101,7 @@ #define FB_CUR_SETSHAPE 0x10 /* set shape */ #define FB_CUR_SETALL 0x1F /* all of the above */ +/* XXX 32-bit binary compatability item... -DaveM */ struct fbcursor { short set; /* what to set, choose from the list above */ short enable; /* cursor on/off */ @@ -136,6 +140,7 @@ __u32 wi_attrs; __u32 wi_values[32]; }; +/* XXX 32-bit binary compatability item... -DaveM */ struct fb_wid_list { __u32 wl_flags; __u32 wl_count; @@ -178,6 +183,7 @@ __u32 index; }; +/* XXX 32-bit binary compatability item... -DaveM */ struct leo_clut { #define LEO_CLUT_WAIT 0x00000001 /* Not yet implemented */ __u32 flag; diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/fcntl.h linux/include/asm-sparc64/fcntl.h --- v2.1.33/linux/include/asm-sparc64/fcntl.h Fri Dec 13 01:37:46 1996 +++ linux/include/asm-sparc64/fcntl.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: fcntl.h,v 1.1 1996/11/20 15:28:41 davem Exp $ */ +/* $Id: fcntl.h,v 1.2 1997/04/04 00:50:15 davem Exp $ */ #ifndef _SPARC64_FCNTL_H #define _SPARC64_FCNTL_H @@ -48,6 +48,7 @@ blocking */ #define LOCK_UN 8 /* remove lock */ +/* XXX 32-bit binary compatability item... -DaveM */ struct flock { short l_type; short l_whence; diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/firehose.h linux/include/asm-sparc64/firehose.h --- v2.1.33/linux/include/asm-sparc64/firehose.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc64/firehose.h Fri Apr 11 10:47:39 1997 @@ -0,0 +1,139 @@ +/* $Id: firehose.h,v 1.1 1997/04/11 02:38:47 davem Exp $ + * firehose.h: Defines for the Fire Hose Controller (FHC) found + * on Sunfire/Wildfire systems. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef _SPARC64_FIREHOSE_H +#define _SPARC64_FIREHOSE_H + +#include + +/* XXX I have not fully verified the register sizes in this file yet... -DaveM */ + +/* Fire Hose Controller Internal Registers */ +struct fhc_internal_regs { +/*0x0000*/ u32 fhc_id; /* FHC ID Register */ + u32 _unused1[3]; +/*0x0010*/ u32 fhc_rcs; /* FHC Reset Control/Status Register */ + u32 _unused2[3]; +/*0x0020*/ u32 fhc_control; /* FHC Control Register */ + u32 _unused3[3]; +/*0x0030*/ u32 fhc_bsr; /* FHC Board Status Register */ + u32 _unused4[3]; +/*0x0040*/ u32 fhc_ecc; /* FHC ECC Control Register (16 bits) */ + u32 _unused5[43]; +/*0x00f0*/ u32 fhc_jtag_ctrl; /* FHC JTAG Control Register */ + u32 _unused6[3]; +/*0x0100*/ u32 fhc_jtag_cmd; /* FHC JTAG Command Register */ +}; + +/* Part of same space of regs, but mapped seperately in PROM reg property + * for the FHC, thus we have the following few structs... + */ +struct fhc_ign_reg { +/*0x2000*/ u64 fhc_ign; /* FHC Interrupt Group Number */ +}; + +struct fhc_fanfail_regs { +/*0x4000*/ u64 fhc_ff_imap; /* FHC FanFail Interrupt Map */ + u64 _unused1; +/*0x4010*/ u64 fhc_ff_istate; /* FHC FanFail Interrupt State */ +}; + +struct fhc_system_regs { +/*0x6000*/ u64 fhc_sys_imap; /* FHC System Interrupt Map */ + u64 _unused1; +/*0x6010*/ u64 fhc_sys_istate; /* FHC System Interrupt State */ +}; + +struct fhc_uart_regs { +/*0x8000*/ u64 fhc_uart_imap; /* FHC UART Interrupt Map */ + u64 _unused1; +/*0x8010*/ u64 fhc_uart_istate;/* FHC UART Interrupt State */ +}; + +struct fhc_tod_regs { +/*0xa000*/ u64 fhc_tod_imap; /* FHC TOD Interrupt Map */ + u64 _unused1; +/*0xa010*/ u64 fhc_tod_istate; /* FHC TOD Interrupt State */ +}; + +/* All of the above. */ +struct fhc_regs { + struct fhc_internal_regs *pregs; + struct fhc_ign_reg *ireg; + struct fhc_fanfil_regs *ffregs; + struct fhc_system_regs *sregs; + struct fhc_uart_regs *uregs; + struct fhc_tod_regs *tregs; +}; + +/* FHC ID Register */ +#define FHC_ID_VERS 0xf0000000 /* Version of this FHC */ +#define FHC_ID_PARTID 0x0ffff000 /* Part ID code (0x0f9f == FHC) */ +#define FHC_ID_MANUF 0x0000007e /* Manufacturer (0x3e == SUN's JEDEC)*/ +#define FHC_ID_RESV 0x00000001 /* Read as one */ + +/* FHC Control Register */ +#define FHC_CONTROL_ICS 0x00100000 /* Ignore Centerplane Signals */ +#define FHC_CONTROL_FRST 0x00080000 /* Fatal Error Reset Enable */ +#define FHC_CONTROL_LFAT 0x00040000 /* AC/DC signalled a local error */ +#define FHC_CONTROL_SLINE 0x00010000 /* Firmware Synchronization Line */ +#define FHC_CONTROL_DCD 0x00008000 /* DC-->DC Converter Disable */ +#define FHC_CONTROL_POFF 0x00004000 /* AC/DC Controller PLL Disable */ +#define FHC_CONTROL_FOFF 0x00002000 /* FHC Controller PLL Disable */ +#define FHC_CONTROL_AOFF 0x00001000 /* CPU A SRAM/SBD Low Power Mode */ +#define FHC_CONTROL_BOFF 0x00000800 /* CPU B SRAM/SBD Low Power Mode */ +#define FHC_CONTROL_PSOFF 0x00000400 /* Turns off this FHC's power supply */ +#define FHC_CONTROL_IXIST 0x00000200 /* 0=FHC tells clock board it exists */ +#define FHC_CONTROL_XMSTR 0x00000100 /* 1=Causes this FHC to be XIR master*/ +#define FHC_CONTROL_LLED 0x00000040 /* 0=Left LED ON */ +#define FHC_CONTROL_MLED 0x00000020 /* 1=Middle LED ON */ +#define FHC_CONTROL_RLED 0x00000010 /* 1=Right LED */ +#define FHC_CONTROL_BPINS 0x00000003 /* Spare Bidirectional Pins */ + +/* FHC Reset Control/Status Register */ +#define FHC_RCS_POR 0x80000000 /* Last reset was a power cycle */ +#define FHC_RCS_SPOR 0x40000000 /* Last reset was sw power on reset */ +#define FHC_RCS_SXIR 0x20000000 /* Last reset was sw XIR reset */ +#define FHC_RCS_BPOR 0x10000000 /* Last reset was due to POR button */ +#define FHC_RCS_BXIR 0x08000000 /* Last reset was due to XIR button */ +#define FHC_RCS_WEVENT 0x04000000 /* CPU reset was due to wakeup event */ +#define FHC_RCS_CFATAL 0x02000000 /* Centerplane Fatal Error signalled */ +#define FHC_RCS_FENAB 0x01000000 /* Fatal errors elicit system reset */ + +/* FHC Board Status Register */ +#define FHC_BSD_DA64 0x00040000 /* Port A: 0=128bit 1=64bit data path */ +#define FHC_BSD_DB64 0x00020000 /* Port B: 0=128bit 1=64bit data path */ +#define FHC_BSD_BID 0x0001e000 /* Board ID */ +#define FHC_BSD_SA 0x00001c00 /* Port A UPA Speed (from the pins) */ +#define FHC_BSD_SB 0x00000380 /* Port B UPA Speed (from the pins) */ +#define FHC_BSD_NDIAG 0x00000040 /* Not in Diag Mode */ +#define FHC_BSD_NTBED 0x00000020 /* Not in TestBED Mode */ +#define FHC_BSD_NIA 0x0000001c /* Jumper, bit 18 in PROM space */ +#define FHC_BSD_SI 0x00000001 /* Spare input pin value */ + +/* FHC then has an Interrupt Group Number register, essentially this is a 32-bit + * register with the low 5 bits specifying the IGN of this FHC for interrupt + * generation purposes, it is a product of the BoardID/Pins seen by the FHC + * at power on time. I suspect the firmware really sets this value though + * during POST. On board FHC devices generate fixed INO interrupt packet + * values, of course these are concatenated with the IGN before it reaches the + * CPU: + * + * IRQ Source INO Value + * ---------------------------------------- + * "System" Interrupt 0x38 + * Zilogs 0x39 + * Mostek 0x3a + * Fan Failure 0x3b + * Spare 1 0x3c + * Spare 2 0x3d + * + * Consult the sysio.h header for the layout of the Interrupt Mapping and + * Interrupt Clear register bits as they are the same. -DaveM + */ + +#endif /* !(_SPARC64_FIREHOSE_H) */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/fpumacro.h linux/include/asm-sparc64/fpumacro.h --- v2.1.33/linux/include/asm-sparc64/fpumacro.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc64/fpumacro.h Fri Apr 11 10:47:39 1997 @@ -0,0 +1,53 @@ +/* fpumacro.h: FPU related macros. + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#ifndef _SPARC64_FPUMACRO_H +#define _SPARC64_FPUMACRO_H + +extern __inline__ void fpsave32(unsigned long *fpregs, unsigned long *fsr) +{ + __asm__ __volatile__ (" + wr %%g0, %2, %%asi + stx %%fsr, [%1] + stda %%f0, [%0] %%asi + stda %%f16, [%0 + 64] %%asi + " : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P)); +} + +extern __inline__ void fpload32(unsigned long *fpregs, unsigned long *fsr) +{ + __asm__ __volatile__ (" + wr %%g0, %2, %%asi + ldda [%0] %%asi, %%f0 + ldda [%0 + 64] %%asi, %%f16 + ldx [%1], %%fsr + " : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P)); +} + +extern __inline__ void fpsave(unsigned long *fpregs, unsigned long *fsr) +{ + __asm__ __volatile__ (" + wr %%g0, %2, %%asi + stx %%fsr, [%1] + stda %%f0, [%0] %%asi + stda %%f16, [%0 + 64] %%asi + stda %%f32, [%0 + 128] %%asi + stda %%f48, [%0 + 192] %%asi + " : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P)); +} + +extern __inline__ void fpload(unsigned long *fpregs, unsigned long *fsr) +{ + __asm__ __volatile__ (" + wr %%g0, %2, %%asi + ldda [%0] %%asi, %%f0 + ldda [%0 + 64] %%asi, %%f16 + ldda [%0 + 128] %%asi, %%f32 + ldda [%0 + 192] %%asi, %%f48 + ldx [%1], %%fsr + " : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P)); +} + +#endif /* !(_SPARC64_FPUMACRO_H) */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/hardirq.h linux/include/asm-sparc64/hardirq.h --- v2.1.33/linux/include/asm-sparc64/hardirq.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc64/hardirq.h Mon Apr 14 09:31:09 1997 @@ -0,0 +1,29 @@ +/* hardirq.h: 64-bit Sparc hard IRQ support. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef __SPARC64_HARDIRQ_H +#define __SPARC64_HARDIRQ_H + +#include + +extern unsigned int local_irq_count[NR_CPUS]; +#define in_interrupt() (local_irq_count[smp_processor_id()] != 0) +#define hardirq_depth() (local_irq_count[smp_processor_id()]) + +#ifdef __SMP__ +#error SMP not supported on sparc64 +#else /* !(__SMP__) */ + +#define hardirq_trylock(cpu) (++local_irq_count[cpu], (cpu)==0) +#define hardirq_endlock(cpu) (--local_irq_count[cpu]) + +#define hardirq_enter(cpu) (local_irq_count[cpu]++) +#define hardirq_exit(cpu) (local_irq_count[cpu]--) + +#define synchronize_irq() do { } while(0) + +#endif /* __SMP__ */ + +#endif /* !(__SPARC64_HARDIRQ_H) */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/head.h linux/include/asm-sparc64/head.h --- v2.1.33/linux/include/asm-sparc64/head.h Thu Mar 27 14:40:09 1997 +++ linux/include/asm-sparc64/head.h Fri Apr 11 10:47:39 1997 @@ -1,10 +1,13 @@ -/* $Id: head.h,v 1.7 1997/03/18 18:00:36 jj Exp $ */ +/* $Id: head.h,v 1.16 1997/04/08 11:03:13 davem Exp $ */ #ifndef _SPARC64_HEAD_H #define _SPARC64_HEAD_H -#define KERNBASE 0xfffff80000000000 +#include + +#define KERNBASE 0xFFFFF80000000000 #define BOOT_KERNEL b sparc64_boot; nop; nop; nop; nop; nop; nop; nop; +/* We need a "cleaned" instruction... */ #define CLEAN_WINDOW \ clr %o0; clr %o1; clr %o2; clr %o3; \ clr %o4; clr %o5; clr %o6; clr %o7; \ @@ -12,7 +15,7 @@ clr %l4; clr %l5; clr %l6; clr %l7; \ rdpr %cleanwin, %g1; add %g1, 1, %g1; \ wrpr %g1, 0x0, %cleanwin; retry; \ - nop; nop; nop; nop; + nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop; #define TRAP(routine) \ ba,pt %xcc, etrap; \ @@ -24,6 +27,32 @@ nop; \ nop; +#define TRAP_NOSAVE(routine) \ + ba,pt %xcc, routine; \ + nop; \ + nop; nop; nop; nop; nop; nop; + +#define TRAPTL1(routine) \ + ba,pt %xcc, etraptl1; \ + rd %pc, %g7; \ + call routine; \ + add %sp, STACK_BIAS + REGWIN_SZ, %o0; \ + ba,pt %xcc, rtrap; \ + nop; \ + nop; \ + nop; + +/* Just for testing */ +#define PROM_TRAP \ + rd %pc, %g1; \ + sethi %uhi(KERNBASE), %g4; \ + sethi %hi(0xf0000000-0x8000), %g2; \ + sllx %g4, 32, %g4; \ + add %g1, %g2, %g1; \ + sub %g1, %g4, %g1; \ + jmpl %g1 + %g0, %g0; \ + nop; + #define TRAP_ARG(routine, arg) \ ba,pt %xcc, etrap; \ rd %pc, %g7; \ @@ -34,6 +63,16 @@ nop; \ nop; +#define TRAPTL1_ARG(routine, arg) \ + ba,pt %xcc, etraptl1; \ + rd %pc, %g7; \ + add %sp, STACK_BIAS + REGWIN_SZ, %o0; \ + call routine; \ + mov arg, %o1; \ + ba,pt %xcc, rtrap; \ + nop; \ + nop; + #define SYSCALL_TRAP(routine, systbl) \ ba,pt %xcc, etrap; \ rd %pc, %g7; \ @@ -42,6 +81,25 @@ or %l7, %lo(systbl), %l7; \ nop; nop; nop; +#define ACCESS_EXCEPTION_TRAP(routine) \ + rdpr %pstate, %g1; \ + wrpr %g1, PSTATE_MG|PSTATE_AG, %pstate; \ + ba,pt %xcc, etrap; \ + rd %pc, %g7; \ + call routine; \ + add %sp, STACK_BIAS + REGWIN_SZ, %o0; \ + ba,pt %xcc, rtrap; \ + nop; + +#define ACCESS_EXCEPTION_TRAPTL1(routine) \ + rdpr %pstate, %g1; \ + wrpr %g1, PSTATE_MG|PSTATE_AG, %pstate; \ + ba,pt %xcc, etraptl1; \ + rd %pc, %g7; \ + call routine; \ + add %sp, STACK_BIAS + REGWIN_SZ, %o0; \ + ba,pt %xcc, rtrap; \ + nop; #define SUNOS_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sunos_sys_table) #define LINUX_32BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table32) @@ -54,11 +112,36 @@ #define SETCC_TRAP TRAP(setcc) #define INDIRECT_SOLARIS_SYSCALL(tlvl) TRAP_ARG(indirect_syscall, tlvl) -#define TRAP_IRQ(routine, level) TRAP_ARG(routine, level) +#define TRAP_IRQ(routine, level) \ + rdpr %pil, %g4; \ + wrpr %g0, 15, %pil; \ + ba,pt %xcc, etrap_irq; \ + rd %pc, %g7; \ + mov level, %o0; \ + call routine; \ + add %sp, STACK_BIAS + REGWIN_SZ, %o1; \ + ba,a,pt %xcc, rtrap; + +/* On UP this is ok, and worth the effort, for SMP we need + * a different mechanism and thus cannot do it all in trap table. -DaveM + */ +#if 0 /* ndef __SMP__ */ +#define TRAP_IVEC \ + ldxa [%g2] ASI_UDB_INTR_R, %g3; \ + and %g3, 0x7ff, %g3; \ + sllx %g3, 3, %g3; \ + ldx [%g1 + %g3], %g5; \ + wr %g5, 0x0, %set_softint; \ + stxa %g0, [%g0] ASI_INTR_RECEIVE; \ + membar #Sync; \ + retry; +#else +#define TRAP_IVEC TRAP_NOSAVE(do_ivec) +#endif #define BTRAP(lvl) TRAP_ARG(bad_trap, lvl) -#define BTRAPTL1(lvl) TRAP_ARG(bad_trap_tl1, lvl) +#define BTRAPTL1(lvl) TRAPTL1_ARG(bad_trap_tl1, lvl) #define FLUSH_WINDOW_TRAP \ flushw; \ @@ -87,8 +170,8 @@ nop; nop; nop; nop; nop; nop; nop; nop; /* Normal 64bit spill */ -#define SPILL_1_NORMAL \ - wr %g0, ASI_AIUP, %asi; \ +#define SPILL_1_GENERIC(xxx) \ + wr %g0, xxx, %asi; \ stxa %l0, [%sp + STACK_BIAS + 0x00] %asi; \ stxa %l1, [%sp + STACK_BIAS + 0x08] %asi; \ stxa %l2, [%sp + STACK_BIAS + 0x10] %asi; \ @@ -109,8 +192,8 @@ nop; nop; nop; nop; nop; nop; nop; /* Normal 32bit spill */ -#define SPILL_2_NORMAL \ - wr %g0, ASI_AIUP, %asi; \ +#define SPILL_2_GENERIC(xxx) \ + wr %g0, xxx, %asi; \ srl %sp, 0, %sp; \ stda %l0, [%sp + 0x00] %asi; \ stda %l2, [%sp + 0x10] %asi; \ @@ -120,10 +203,12 @@ stda %i2, [%sp + 0x50] %asi; \ stda %i4, [%sp + 0x60] %asi; \ stda %i6, [%sp + 0x70] %asi; \ - saved; retry; nop; nop; nop; nop; nop; \ + saved; retry; nop; nop; nop; nop; \ nop; nop; nop; nop; nop; nop; nop; nop; \ nop; nop; nop; nop; nop; nop; nop; nop; +#define SPILL_1_NORMAL SPILL_1_GENERIC(ASI_AIUP) +#define SPILL_2_NORMAL SPILL_2_GENERIC(ASI_AIUP) #define SPILL_3_NORMAL SPILL_0_NORMAL #define SPILL_4_NORMAL SPILL_0_NORMAL #define SPILL_5_NORMAL SPILL_0_NORMAL @@ -131,8 +216,8 @@ #define SPILL_7_NORMAL SPILL_0_NORMAL #define SPILL_0_OTHER SPILL_0_NORMAL -#define SPILL_1_OTHER SPILL_1_NORMAL -#define SPILL_2_OTHER SPILL_2_NORMAL +#define SPILL_1_OTHER SPILL_1_GENERIC(ASI_AIUS) +#define SPILL_2_OTHER SPILL_2_GENERIC(ASI_AIUS) #define SPILL_3_OTHER SPILL_3_NORMAL #define SPILL_4_OTHER SPILL_4_NORMAL #define SPILL_5_OTHER SPILL_5_NORMAL @@ -157,12 +242,12 @@ ldx [%sp + STACK_BIAS + 0x68], %i5; \ ldx [%sp + STACK_BIAS + 0x70], %i6; \ ldx [%sp + STACK_BIAS + 0x78], %i7; \ - saved; retry; nop; nop; nop; nop; nop; nop; \ + restored; retry; nop; nop; nop; nop; nop; nop; \ nop; nop; nop; nop; nop; nop; nop; nop; /* Normal 64bit fill */ -#define FILL_1_NORMAL \ - wr %g0, ASI_AIUP, %asi; \ +#define FILL_1_GENERIC(xxx) \ + wr %g0, xxx, %asi; \ ldxa [%sp + STACK_BIAS + 0x00] %asi, %l0; \ ldxa [%sp + STACK_BIAS + 0x08] %asi, %l1; \ ldxa [%sp + STACK_BIAS + 0x10] %asi, %l2; \ @@ -179,12 +264,12 @@ ldxa [%sp + STACK_BIAS + 0x68] %asi, %i5; \ ldxa [%sp + STACK_BIAS + 0x70] %asi, %i6; \ ldxa [%sp + STACK_BIAS + 0x78] %asi, %i7; \ - saved; retry; nop; nop; nop; nop; nop; nop; \ + restored; retry; nop; nop; nop; nop; nop; nop; \ nop; nop; nop; nop; nop; nop; nop; /* Normal 32bit fill */ -#define FILL_2_NORMAL \ - wr %g0, ASI_AIUP, %asi; \ +#define FILL_2_GENERIC(xxx) \ + wr %g0, xxx, %asi; \ srl %sp, 0, %sp; \ ldda [%sp + 0x00] %asi, %l0; \ ldda [%sp + 0x10] %asi, %l2; \ @@ -194,10 +279,12 @@ ldda [%sp + 0x50] %asi, %i2; \ ldda [%sp + 0x60] %asi, %i4; \ ldda [%sp + 0x70] %asi, %i6; \ - saved; retry; nop; nop; nop; nop; nop; \ + restored; retry; nop; nop; nop; nop; \ nop; nop; nop; nop; nop; nop; nop; nop; \ nop; nop; nop; nop; nop; nop; nop; nop; +#define FILL_1_NORMAL FILL_1_GENERIC(ASI_AIUP) +#define FILL_2_NORMAL FILL_2_GENERIC(ASI_AIUP) #define FILL_3_NORMAL FILL_0_NORMAL #define FILL_4_NORMAL FILL_0_NORMAL #define FILL_5_NORMAL FILL_0_NORMAL @@ -205,8 +292,8 @@ #define FILL_7_NORMAL FILL_0_NORMAL #define FILL_0_OTHER FILL_0_NORMAL -#define FILL_1_OTHER FILL_1_NORMAL -#define FILL_2_OTHER FILL_2_NORMAL +#define FILL_1_OTHER FILL_1_GENERIC(ASI_AIUS) +#define FILL_2_OTHER FILL_2_GENERIC(ASI_AIUS) #define FILL_3_OTHER FILL_3_NORMAL #define FILL_4_OTHER FILL_4_NORMAL #define FILL_5_OTHER FILL_5_NORMAL diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/idprom.h linux/include/asm-sparc64/idprom.h --- v2.1.33/linux/include/asm-sparc64/idprom.h Fri Dec 13 01:37:47 1996 +++ linux/include/asm-sparc64/idprom.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: idprom.h,v 1.1 1996/11/20 15:33:43 davem Exp $ +/* $Id: idprom.h,v 1.2 1997/04/04 00:50:16 davem Exp $ * idprom.h: Macros and defines for idprom routines * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -7,6 +7,8 @@ #ifndef _SPARC64_IDPROM_H #define _SPARC64_IDPROM_H +#include + /* Offset into the EEPROM where the id PROM is located on the 4c */ #define IDPROM_OFFSET 0x7d8 @@ -16,13 +18,13 @@ struct idprom { - unsigned char id_format; /* Format identifier (always 0x01) */ - unsigned char id_machtype; /* Machine type */ - unsigned char id_ethaddr[6]; /* Hardware ethernet address */ - int id_date; /* Date of manufacture */ - unsigned int id_sernum:24; /* Unique serial number */ - unsigned char id_cksum; /* Checksum - xor of the data bytes */ - unsigned char reserved[16]; + u8 id_format; /* Format identifier (always 0x01) */ + u8 id_machtype; /* Machine type */ + u8 id_ethaddr[6]; /* Hardware ethernet address */ + s32 id_date; /* Date of manufacture */ + u32 id_sernum:24; /* Unique serial number */ + u8 id_cksum; /* Checksum - xor of the data bytes */ + u8 reserved[16]; }; extern struct idprom *idprom; diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/io.h linux/include/asm-sparc64/io.h --- v2.1.33/linux/include/asm-sparc64/io.h Thu Mar 27 14:40:09 1997 +++ linux/include/asm-sparc64/io.h Fri Apr 11 10:47:39 1997 @@ -1,8 +1,9 @@ -/* $Id: io.h,v 1.5 1997/03/18 18:04:00 jj Exp $ */ +/* $Id: io.h,v 1.10 1997/04/10 05:13:29 davem Exp $ */ #ifndef __SPARC64_IO_H #define __SPARC64_IO_H #include +#include #include /* IO address mapping routines need this */ #include @@ -83,24 +84,24 @@ #define inb_p inb #define outb_p outb -extern void sparc_ultra_mapioaddr (unsigned long physaddr, unsigned long virt_addr, int rdonly); +extern void sparc_ultra_mapioaddr (unsigned long physaddr, unsigned long virt_addr, + int bus, int rdonly); extern void sparc_ultra_unmapioaddr (unsigned long virt_addr); -extern __inline__ void mapioaddr (unsigned long physaddr, unsigned long virt_addr, int rdonly) +extern __inline__ void mapioaddr (unsigned long physaddr, unsigned long virt_addr, + int bus, int rdonly) { - sparc_ultra_mapioaddr (physaddr, virt_addr, rdonly); - return; + sparc_ultra_mapioaddr (physaddr, virt_addr, bus, rdonly); } extern __inline__ void unmapioaddr(unsigned long virt_addr) { sparc_ultra_unmapioaddr (virt_addr); - return; } -extern void *sparc_alloc_io (void *, void *, int, char *, unsigned, int); -extern void sparc_free_io (void *, int); -extern void *sparc_dvma_malloc (int, char *); +extern void *sparc_alloc_io (u32 pa, void *va, int sz, char *name, u32 io, int rdonly); +extern void sparc_free_io (void *va, int sz); +extern void *sparc_dvma_malloc (int sz, char *name, __u32 *dvma_addr); #define virt_to_phys(x) __pa((unsigned long)(x)) #define phys_to_virt(x) __va((unsigned long)(x)) diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/ioctls.h linux/include/asm-sparc64/ioctls.h --- v2.1.33/linux/include/asm-sparc64/ioctls.h Fri Dec 13 01:37:47 1996 +++ linux/include/asm-sparc64/ioctls.h Fri Apr 11 10:47:39 1997 @@ -1,8 +1,13 @@ -/* $Id: ioctls.h,v 1.1 1996/12/02 00:05:36 davem Exp $ */ +/* $Id: ioctls.h,v 1.2 1997/04/04 00:50:18 davem Exp $ */ #ifndef _ASM_SPARC64_IOCTLS_H #define _ASM_SPARC64_IOCTLS_H #include + +/* XXX 32-bit binary compatability issues, I am sure that + * XXX only IOCTL's which reference structures will be of + * XXX concern and these are easily fabricated using wrappers. + */ /* Big T */ #define TCGETA _IOR('T', 1, struct termio) diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/iommu.h linux/include/asm-sparc64/iommu.h --- v2.1.33/linux/include/asm-sparc64/iommu.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/iommu.h Fri Apr 11 10:47:39 1997 @@ -6,6 +6,7 @@ #define _SPARC64_IOMMU_H #include +#include /* The iommu handles all virtual to physical address translations * that occur between the SYSIO and physical memory. Access by @@ -17,21 +18,6 @@ */ /* The IOMMU register set. */ -struct iommu_regs { - volatile unsigned long csr; - volatile unsigned long tsb_base; - volatile unsigned long flush; - unsigned char _unused0[PAGE_SIZE - 0x18]; - - volatile unsigned long va_diag; - volatile unsigned long tag_compare; - unsigned char _unused1[0x100 - 0x10]; - - volatile unsigned long lru_diag[0x80 / 8]; - volatile unsigned long tag_diag[0x80 / 8]; - volatile unsigned long ram_diag[0x100 / 8]; -}; - #define IOMMU_CTRL_IMPL 0xf000000000000000 /* Implementation */ #define IOMMU_CTRL_VERS 0x0f00000000000000 /* Version */ #define IOMMU_CTRL_TSBSZ 0x0000000000070000 /* TSB Size */ @@ -57,17 +43,12 @@ #define IOPTE_WRITE 0x0000000000000002 /* Writeable */ struct iommu_struct { - struct iommu_regs *regs; + struct sysio_regs *sysio_regs; iopte_t *page_table; /* For convenience */ unsigned long start; /* First managed virtual address */ unsigned long end; /* Last managed virtual address */ }; - -extern __inline__ void iommu_invalidate_page(struct iommu_regs *regs, unsigned long page) -{ - regs->flush = (page & (PAGE_MASK << 3)); -} #endif /* !(_SPARC_IOMMU_H) */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/ipc.h linux/include/asm-sparc64/ipc.h --- v2.1.33/linux/include/asm-sparc64/ipc.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/ipc.h Fri Apr 11 10:47:39 1997 @@ -6,6 +6,7 @@ * * See arch/sparc64/kernel/sys_sparc.c for ugly details.. */ +/* XXX 32-bit binary compatability... */ struct ipc_kludge { struct msgbuf *msgp; long msgtyp; diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/irq.h linux/include/asm-sparc64/irq.h --- v2.1.33/linux/include/asm-sparc64/irq.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/irq.h Fri Apr 11 10:47:39 1997 @@ -1,11 +1,9 @@ -/* $Id: irq.h,v 1.1 1996/12/26 17:28:13 davem Exp $ +/* $Id: irq.h,v 1.4 1997/04/04 00:50:20 davem Exp $ * irq.h: IRQ registers on the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ -/* XXX Write the sun5 specific code... XXX */ - #ifndef _SPARC64_IRQ_H #define _SPARC64_IRQ_H @@ -15,27 +13,41 @@ #define NR_IRQS 15 -/* Dave Redman (djhr@tadpole.co.uk) - * changed these to function pointers.. it saves cycles and will allow - * the irq dependencies to be split into different files at a later date - * sun4c_irq.c, sun4m_irq.c etc so we could reduce the kernel size. - */ -extern void (*disable_irq)(unsigned int); -extern void (*enable_irq)(unsigned int); -extern void (*clear_clock_irq)( void ); -extern void (*clear_profile_irq)( void ); -extern void (*load_profile_irq)( unsigned int timeout ); -extern void (*init_timers)(void (*lvl10_irq)(int, void *, struct pt_regs *)); -extern void claim_ticker14(void (*irq_handler)(int, void *, struct pt_regs *), - int irq, - unsigned int timeout); +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); +extern void init_timers(void (*lvl10_irq)(int, void *, struct pt_regs *)); #ifdef __SMP__ -extern void (*set_cpu_int)(int, int); -extern void (*clear_cpu_int)(int, int); -extern void (*set_irq_udt)(int); +extern void set_cpu_int(int, int); +extern void clear_cpu_int(int, int); +extern void set_irq_udt(int); #endif -extern int request_fast_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, __const__ char *devname); +extern int request_fast_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, __const__ char *devname); + +extern __inline__ void set_softint(unsigned long bits) +{ + __asm__ __volatile__("wr %0, 0x0, %%set_softint" + : /* No outputs */ + : "r" (bits)); +} + +extern __inline__ void clear_softint(unsigned long bits) +{ + __asm__ __volatile__("wr %0, 0x0, %%clear_softint" + : /* No outputs */ + : "r" (bits)); +} + +extern __inline__ unsigned long get_softint(void) +{ + unsigned long retval; + + __asm__ __volatile__("rd %%softint, %0" + : "=r" (retval)); + return retval; +} #endif diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/kdebug.h linux/include/asm-sparc64/kdebug.h --- v2.1.33/linux/include/asm-sparc64/kdebug.h Thu Mar 27 14:40:09 1997 +++ linux/include/asm-sparc64/kdebug.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: kdebug.h,v 1.1 1997/03/14 21:05:34 jj Exp $ +/* $Id: kdebug.h,v 1.2 1997/04/04 00:50:21 davem Exp $ * kdebug.h: Defines and definitions for debugging the Linux kernel * under various kernel debuggers. * @@ -8,6 +8,8 @@ #define _SPARC64_KDEBUG_H #include + +/* XXX This needs to all be fixed for Ultra/V9 -DaveM */ /* The debugger lives in 1MB of virtual address space right underneath * the boot prom. diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/lsu.h linux/include/asm-sparc64/lsu.h --- v2.1.33/linux/include/asm-sparc64/lsu.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/lsu.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id */ +/* $Id: lsu.h,v 1.2 1997/04/04 00:50:22 davem Exp $ */ #ifndef _SPARC64_LSU_H #define _SPARC64_LSU_H diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/machines.h linux/include/asm-sparc64/machines.h --- v2.1.33/linux/include/asm-sparc64/machines.h Thu Mar 27 14:40:09 1997 +++ linux/include/asm-sparc64/machines.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: machines.h,v 1.1 1997/03/14 21:05:37 jj Exp $ +/* $Id: machines.h,v 1.2 1997/04/04 00:50:23 davem Exp $ * machines.h: Defines for taking apart the machine type value in the * idprom and determining the kind of machine we are on. * @@ -6,6 +6,8 @@ */ #ifndef _SPARC64_MACHINES_H #define _SPARC64_MACHINES_H + +/* XXX This should disappear. -DaveM */ struct Sun_Machine_Models { char *name; diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/mmu_context.h linux/include/asm-sparc64/mmu_context.h --- v2.1.33/linux/include/asm-sparc64/mmu_context.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/mmu_context.h Fri Apr 11 10:47:39 1997 @@ -1,34 +1,74 @@ -/* $Id: mmu_context.h,v 1.4 1996/12/28 18:39:51 davem Exp $ */ +/* $Id: mmu_context.h,v 1.7 1997/04/04 00:50:23 davem Exp $ */ #ifndef __SPARC64_MMU_CONTEXT_H #define __SPARC64_MMU_CONTEXT_H +/* Derived heavily from Linus's Alpha/AXP ASN code... */ + #include #include -#define NO_CONTEXT -1 +#define NO_CONTEXT 0 #ifndef __ASSEMBLY__ /* Initialize the context related info for a new mm_struct * instance. */ -#define init_new_context(mm) ((mm)->context = NO_CONTEXT) +#define init_new_context(mm) ((mm)->context = NO_CONTEXT) + +#define destroy_context(mm) do { } while(0) + +extern unsigned long tlb_context_cache; + +#define MAX_CTX PAGE_SIZE -extern void spitfire_get_new_context(struct mm_struct *mm); +#define CTX_VERSION_SHIFT PAGE_SHIFT +#define CTX_VERSION_MASK ((~0UL) << CTX_VERSION_SHIFT) +#define CTX_FIRST_VERSION ((1UL << CTX_VERSION_SHIFT) + 1UL) + +extern __inline__ void get_new_mmu_context(struct mm_struct *mm, + unsigned long ctx) +{ + if((ctx & ~CTX_VERSION_MASK) > MAX_CTX) { + unsigned long flags; + int entry; + + save_and_cli(flags); + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "stxa %%g0, [%0] %2" + : /* No outputs */ + : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU), + "i" (ASI_DMMU)); + for(entry = 0; entry < 62; entry++) { + spitfire_put_dtlb_data(entry, 0x0UL); + spitfire_put_itlb_data(entry, 0x0UL); + } + membar("#Sync"); + flushi(PAGE_OFFSET); + restore_flags(flags); + + ctx = (ctx & CTX_VERSION_MASK) + CTX_FIRST_VERSION; + if(!ctx) + ctx = CTX_FIRST_VERSION; + } + tlb_context_cache = ctx + 1; + mm->context = ctx; +} extern __inline__ void get_mmu_context(struct task_struct *tsk) { struct mm_struct *mm = tsk->mm; - if(tsk->mm->context == NO_CONTEXT) - spitfire_get_new_context(mm); - - /* Get current set of user windows out of the cpu. */ - flushw_user(); - - /* Jump into new ASN. */ - spitfire_set_primary_context(mm->context); - spitfire_set_secondary_context(mm->context); + if(mm && + !(tsk->tss.flags & SPARC_FLAG_KTHREAD) && + !(tsk->flags & PF_EXITING)) { + unsigned long ctx = tlb_context_cache; + + flushw_user(); + if((mm->context ^ ctx) & CTX_VERSION_MASK) + get_new_mmu_context(mm, ctx); + spitfire_set_secondary_context(mm->context); + } } #endif /* !(__ASSEMBLY__) */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/mostek.h linux/include/asm-sparc64/mostek.h --- v2.1.33/linux/include/asm-sparc64/mostek.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/mostek.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: mostek.h,v 1.1 1996/12/26 13:25:22 davem Exp $ +/* $Id: mostek.h,v 1.2 1997/03/25 03:58:30 davem Exp $ * mostek.h: Describes the various Mostek time of day clock registers. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -114,7 +114,13 @@ }; extern struct mostek48t08 *mstk48t08_regs; -enum sparc_clock_type { MSTK48T02, MSTK48T08, MSTK_INVALID }; -extern enum sparc_clock_type sp_clock_typ; +/* SUN5 systems usually have 48t59 model clock chipsets. But we keep the older + * clock chip definitions around just in case. + */ +struct mostek48t59 { + char offset[6*1024]; + struct mostek48t02 regs; +}; +extern struct mostek48t59 *mstk48t59_regs; #endif /* !(_SPARC64_MOSTEK_H) */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/namei.h linux/include/asm-sparc64/namei.h --- v2.1.33/linux/include/asm-sparc64/namei.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/namei.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: namei.h,v 1.1 1996/12/26 13:25:22 davem Exp $ +/* $Id: namei.h,v 1.2 1997/03/19 17:28:27 jj Exp $ * linux/include/asm-sparc64/namei.h * * Routines to handle famous /usr/gnemul/s*. @@ -11,46 +11,44 @@ #define SPARC_BSD_EMUL "usr/gnemul/sunos/" #define SPARC_SOL_EMUL "usr/gnemul/solaris/" -#define gnemul_namei(pathname, base, follow_links, res_inode) ({ \ - if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') { \ - struct inode *emul_ino; \ - int namelen; \ - const char *name; \ - \ - while (*pathname == '/') \ - pathname++; \ - current->fs->root->i_count++; \ - if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL,\ - &namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) { \ - *res_inode = NULL; \ - if (_namei (pathname, emul_ino, follow_links, res_inode) >= 0 &&\ - *res_inode) \ - return 0; \ - } \ - base = current->fs->root; \ - base->i_count++; \ - } \ +#define translate_namei(pathname, base, follow_links, res_inode) ({ \ + if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') { \ + struct inode *emul_ino; \ + int namelen; \ + const char *name; \ + \ + while (*pathname == '/') \ + pathname++; \ + current->fs->root->i_count++; \ + if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL, \ + &namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) { \ + *res_inode = NULL; \ + if (_namei (pathname, emul_ino, follow_links, res_inode) >= 0 && *res_inode) \ + return 0; \ + } \ + base = current->fs->root; \ + base->i_count++; \ + } \ }) -#define gnemul_open_namei(pathname, flag, mode, res_inode, base) ({ \ - if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') { \ - struct inode *emul_ino; \ - int namelen; \ - const char *name; \ - \ - while (*pathname == '/') \ - pathname++; \ - current->fs->root->i_count++; \ - if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL,\ - &namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) { \ - *res_inode = NULL; \ - if (open_namei (pathname, flag, mode, res_inode, emul_ino) >= 0 && \ - *res_inode) \ - return 0; \ - } \ - base = current->fs->root; \ - base->i_count++; \ - } \ +#define translate_open_namei(pathname, flag, mode, res_inode, base) ({ \ + if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') { \ + struct inode *emul_ino; \ + int namelen; \ + const char *name; \ + \ + while (*pathname == '/') \ + pathname++; \ + current->fs->root->i_count++; \ + if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL, \ + &namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) { \ + *res_inode = NULL; \ + if (open_namei (pathname, flag, mode, res_inode, emul_ino) >= 0 && *res_inode) \ + return 0; \ + } \ + base = current->fs->root; \ + base->i_count++; \ + } \ }) #endif /* __SPARC64_NAMEI_H */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/openprom.h linux/include/asm-sparc64/openprom.h --- v2.1.33/linux/include/asm-sparc64/openprom.h Thu Mar 27 14:40:09 1997 +++ linux/include/asm-sparc64/openprom.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: openprom.h,v 1.3 1997/03/18 18:03:20 jj Exp $ */ +/* $Id: openprom.h,v 1.4 1997/03/24 06:42:08 davem Exp $ */ #ifndef __SPARC64_OPENPROM_H #define __SPARC64_OPENPROM_H @@ -186,9 +186,9 @@ #define PROMINTR_MAX 15 struct linux_prom_registers { - unsigned which_io; /* hi part of physical address */ - unsigned phys_addr; /* The physical address of this register */ - int reg_size; /* How many bytes does this register take up? */ + unsigned which_io; /* hi part of physical address */ + unsigned phys_addr; /* The physical address of this register */ + int reg_size; /* How many bytes does this register take up? */ }; struct linux_prom64_registers { diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/oplib.h linux/include/asm-sparc64/oplib.h --- v2.1.33/linux/include/asm-sparc64/oplib.h Thu Mar 27 14:40:09 1997 +++ linux/include/asm-sparc64/oplib.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: oplib.h,v 1.6 1997/03/18 18:01:30 jj Exp $ +/* $Id: oplib.h,v 1.7 1997/04/03 09:29:25 davem Exp $ * oplib.h: Describes the interface and available routines in the * Linux Prom library. * @@ -271,6 +271,9 @@ extern int prom_pathtoinode(char *path); extern int prom_inst2pkg(int); + +/* Client interface level routines. */ +extern void prom_set_trap_table(unsigned long tba); /* Dorking with Bus ranges... */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/page.h linux/include/asm-sparc64/page.h --- v2.1.33/linux/include/asm-sparc64/page.h Mon Mar 17 14:54:33 1997 +++ linux/include/asm-sparc64/page.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: page.h,v 1.5 1997/02/25 20:00:36 jj Exp $ */ +/* $Id: page.h,v 1.8 1997/03/26 12:24:21 davem Exp $ */ #ifndef _SPARC64_PAGE_H #define _SPARC64_PAGE_H @@ -7,7 +7,13 @@ #ifdef __KERNEL__ +#ifndef __ASSEMBLY__ +/* I have my suspicions... -DaveM */ +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#else #define PAGE_SIZE (1 << PAGE_SHIFT) +#endif + #define PAGE_MASK (~(PAGE_SIZE-1)) #ifndef __ASSEMBLY__ @@ -73,12 +79,21 @@ #endif /* !(__ASSEMBLY__) */ +#ifndef __ASSEMBLY__ +#define TASK_UNMAPPED_BASE 0x0000000070000000UL +#else #define TASK_UNMAPPED_BASE 0x0000000070000000 +#endif /* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) +#ifndef __ASSEMBLY__ +#define PAGE_OFFSET 0xFFFFF80000000000UL +#else #define PAGE_OFFSET 0xFFFFF80000000000 +#endif + #define __pa(x) ((unsigned long)(x) - PAGE_OFFSET) #define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET)) #define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT) diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h --- v2.1.33/linux/include/asm-sparc64/pgtable.h Thu Mar 27 14:40:09 1997 +++ linux/include/asm-sparc64/pgtable.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.13 1997/03/13 16:25:05 jj Exp $ +/* $Id: pgtable.h,v 1.27 1997/04/10 23:32:46 davem Exp $ * pgtable.h: SpitFire page table operations. * * Copyright 1996 David S. Miller (davem@caip.rutgers.edu) @@ -20,6 +20,7 @@ #include #ifndef __ASSEMBLY__ +#include /* Certain architectures need to do special things when pte's * within a page table are directly modified. Thus, the following @@ -42,10 +43,15 @@ #define PTRS_PER_PMD (1UL << (PAGE_SHIFT-3)) #define PTRS_PER_PGD (1UL << (PAGE_SHIFT-3)) +#define PTE_TABLE_SIZE 0x2000 /* 1024 entries 8 bytes each */ +#define PMD_TABLE_SIZE 0x2000 /* 1024 entries 8 bytes each */ +#define PGD_TABLE_SIZE 0x2000 /* 1024 entries 8 bytes each */ + /* the no. of pointers that fit on a page */ #define PTRS_PER_PAGE (1UL << (PAGE_SHIFT-3)) -#define VMALLOC_START 0xFFFFFE0000000000UL +/* NOTE: TLB miss handlers depend heavily upon where this is. */ +#define VMALLOC_START 0xFFFFFc0000000000UL #define VMALLOC_VMADDR(x) ((unsigned long)(x)) #endif /* !(__ASSEMBLY__) */ @@ -77,26 +83,36 @@ #define _PAGE_ACCESSED 0x0000000000000400 /* Accessed Page (ie. referenced) */ #define _PAGE_READ 0x0000000000000200 /* Readable SW Bit */ #define _PAGE_WRITE 0x0000000000000100 /* Writable SW Bit */ +#define _PAGE_PRIV 0x0000000000000080 /* Software privilege bit */ #define _PAGE_CACHE (_PAGE_CP | _PAGE_CV) #define __DIRTY_BITS (_PAGE_MODIFIED | _PAGE_WRITE | _PAGE_W) #define __ACCESS_BITS (_PAGE_ACCESSED | _PAGE_READ | _PAGE_R) +#define __PRIV_BITS (_PAGE_P | _PAGE_PRIV) + +#define PAGE_NONE __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \ + __PRIV_BITS | __ACCESS_BITS) + +#define PAGE_SHARED __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \ + __ACCESS_BITS | _PAGE_W | _PAGE_WRITE) + +#define PAGE_COPY __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \ + __ACCESS_BITS) + +#define PAGE_READONLY __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \ + __ACCESS_BITS) + +#define PAGE_KERNEL __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \ + __PRIV_BITS | __ACCESS_BITS | __DIRTY_BITS) -/* David: Please FIXME these. I just define them somehow to get it compile. jj */ -#define PAGE_NONE __pgprot (_PAGE_VALID | _PAGE_CACHE | _PAGE_P | _PAGE_G | __ACCESS_BITS) -#define PAGE_SHARED __pgprot (_PAGE_VALID | _PAGE_CACHE | _PAGE_G | __ACCESS_BITS | _PAGE_W | _PAGE_WRITE) -#define PAGE_COPY __pgprot (_PAGE_VALID | _PAGE_CACHE | __ACCESS_BITS) -#define PAGE_READONLY __pgprot (_PAGE_VALID | _PAGE_CACHE | __ACCESS_BITS) -#define PAGE_KERNEL __pgprot (_PAGE_VALID | _PAGE_CACHE | _PAGE_P | __ACCESS_BITS | __DIRTY_BITS) #define PAGE_INVALID __pgprot (0) #define _PFN_MASK _PAGE_PADDR -#define _PAGE_CHG_MASK (_PFN_MASK | _PAGE_MODIFIED | _PAGE_ACCESSED) +#define _PAGE_CHG_MASK (_PFN_MASK | _PAGE_MODIFIED | _PAGE_ACCESSED | _PAGE_PRESENT) -/* FIXME: Define this correctly to io page protection. Has to include side effects. */ -#define pg_iobits (_PAGE_VALID | _PAGE_P | __ACCESS_BITS | _PAGE_E) +#define pg_iobits (_PAGE_VALID | __PRIV_BITS | __ACCESS_BITS | _PAGE_E) #define __P000 PAGE_NONE #define __P001 PAGE_READONLY @@ -119,13 +135,28 @@ #ifndef __ASSEMBLY__ extern pte_t __bad_page(void); -extern pmd_t *__bad_pagetable(void); -extern unsigned long __zero_page(void); +extern pmd_t *__bad_pmd(void); +extern pte_t *__bad_pte(void); -#define BAD_PAGETABLE __bad_pagetable() +#define BAD_PMD __bad_pmd() +#define BAD_PTE __bad_pte() #define BAD_PAGE __bad_page() -#define ZERO_PAGE PAGE_OFFSET +/* First phsical page can be anywhere, the following is needed so that + * va-->pa and vice versa conversions work properly without performance + * hit for all __pa()/__va() operations. + */ +extern unsigned long phys_base; + +#define ZERO_PAGE (PAGE_OFFSET + phys_base) + +/* This is for making TLB miss faster to process. */ +extern unsigned long null_pmd_table; +extern unsigned long null_pte_table; + +/* Allocate a block of RAM which is aligned to its size. + This procedure can be used until the call to mem_init(). */ +extern void *sparc_init_alloc(unsigned long *kbrk, unsigned long size); /* Cache and TLB flush operations. */ @@ -164,7 +195,8 @@ bge,pt %%icc, 1b add %2, %1, %0 " : "=&r" (page), "=&r" (temp) - : "r" (page), "0" (page + PAGE_SIZE - 0x40), "1" (PAGE_SIZE - 0x40)); + : "r" (page), "0" (page + PAGE_SIZE - 0x40), "1" (PAGE_SIZE - 0x40) + : "cc"); } extern __inline__ void flush_cache_all(void) @@ -173,7 +205,6 @@ flushw_all(); for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32) { - spitfire_put_dcache_tag(addr, 0x0UL); spitfire_put_icache_tag(addr, 0x0UL); membar("#Sync"); } @@ -189,14 +220,13 @@ flushw_user(); for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32) { - spitfire_put_dcache_tag(addr, 0x0UL); spitfire_put_icache_tag(addr, 0x0UL); membar("#Sync"); } - } - /* Kill the pipeline. */ - flushi(PAGE_OFFSET); + /* Kill the pipeline. */ + flushi(PAGE_OFFSET); + } } extern __inline__ void flush_cache_range(struct mm_struct *mm, unsigned long start, @@ -220,14 +250,17 @@ { struct mm_struct *mm = vma->vm_mm; - if(mm->context != NO_CONTEXT && (vma->vm_flags & VM_EXEC)) { - int ctx; + if(mm->context != NO_CONTEXT) { + unsigned long addr; - ctx = spitfire_get_primary_context(); flushw_user(); - spitfire_set_primary_context(mm->context); - spitfire_flush_icache_page(page & PAGE_MASK); - spitfire_set_primary_context(ctx); + for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32) { + spitfire_put_icache_tag(addr, 0x0UL); + membar("#Sync"); + } + + /* Kill the pipeline. */ + flushi(PAGE_OFFSET); } } @@ -236,27 +269,36 @@ extern __inline__ void flush_tlb_all(void) { + unsigned long flags; int entry; /* Invalidate all non-locked TTE's in both the dtlb and itlb. */ - for(entry = 0; entry < 64; entry++) { - unsigned long dtag, itag; - - dtag = spitfire_get_dtlb_data(entry); - itag = spitfire_get_itlb_data(entry); - if(!(dtag & _PAGE_L)) - spitfire_put_dtlb_data(entry, 0x0UL); - if(!(itag & _PAGE_L)) - spitfire_put_itlb_data(entry, 0x0UL); + save_and_cli(flags); + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "stxa %%g0, [%0] %2" + : /* No outputs */ + : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU), "i" (ASI_DMMU)); + for(entry = 0; entry < 62; entry++) { + spitfire_put_dtlb_data(entry, 0x0UL); + spitfire_put_itlb_data(entry, 0x0UL); } + membar("#Sync"); + flushi(PAGE_OFFSET); + restore_flags(flags); } extern __inline__ void flush_tlb_mm(struct mm_struct *mm) { if(mm->context != NO_CONTEXT) { + unsigned long orig_ctx = spitfire_get_secondary_context(); + unsigned long flags; + + save_and_cli(flags); spitfire_set_secondary_context(mm->context); spitfire_flush_dtlb_secondary_context(); spitfire_flush_itlb_secondary_context(); + spitfire_set_secondary_context(orig_ctx); + restore_flags(flags); } } @@ -264,13 +306,19 @@ unsigned long end) { if(mm->context != NO_CONTEXT) { + unsigned long old_ctx = spitfire_get_secondary_context(); + unsigned long flags; + start &= PAGE_MASK; + save_and_cli(flags); spitfire_set_secondary_context(mm->context); while(start < end) { spitfire_flush_dtlb_secondary_page(start); spitfire_flush_itlb_secondary_page(start); start += PAGE_SIZE; } + spitfire_set_secondary_context(old_ctx); + restore_flags(flags); } } @@ -279,16 +327,22 @@ struct mm_struct *mm = vma->vm_mm; if(mm->context != NO_CONTEXT) { + unsigned long old_ctx = spitfire_get_secondary_context(); + unsigned long flags; + page &= PAGE_MASK; + save_and_cli(flags); spitfire_set_secondary_context(mm->context); if(vma->vm_flags & VM_EXEC) spitfire_flush_itlb_secondary_page(page); spitfire_flush_dtlb_secondary_page(page); + spitfire_set_secondary_context(old_ctx); + restore_flags(flags); } } extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot) -{ return __pte((page - PAGE_OFFSET) | pgprot_val(pgprot)); } +{ return __pte(__pa(page) | pgprot_val(pgprot)); } extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot) { return __pte(physpage | pgprot_val(pgprot)); } @@ -297,33 +351,33 @@ { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; } extern inline void pmd_set(pmd_t *pmdp, pte_t *ptep) -{ pmd_val(*pmdp) = ((unsigned long) ptep) - PAGE_OFFSET; } +{ pmd_val(*pmdp) = __pa((unsigned long) ptep); } extern inline void pgd_set(pgd_t *pgdp, pmd_t *pmdp) -{ pgd_val(*pgdp) = ((unsigned long) pmdp) - PAGE_OFFSET; } +{ pgd_val(*pgdp) = __pa((unsigned long) pmdp); } extern inline unsigned long pte_page(pte_t pte) -{ return PAGE_OFFSET + (pte_val(pte) & _PFN_MASK); } +{ return (unsigned long) __va((pte_val(pte) & _PFN_MASK)); } extern inline unsigned long pmd_page(pmd_t pmd) -{ return (pmd_val(pmd) + PAGE_OFFSET); } +{ return (unsigned long) __va(pmd_val(pmd)); } extern inline unsigned long pgd_page(pgd_t pgd) -{ return (pgd_val(pgd) + PAGE_OFFSET); } +{ return (unsigned long) __va(pgd_val(pgd)); } extern inline int pte_none(pte_t pte) { return !pte_val(pte); } extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; } extern inline void pte_clear(pte_t *pte) { pte_val(*pte) = 0; } -extern inline int pmd_none(pmd_t pmd) { return !pmd_val(pmd); } +extern inline int pmd_none(pmd_t pmd) { return pmd_val(pmd)==null_pte_table; } extern inline int pmd_bad(pmd_t pmd) { return (pmd_val(pmd) & ~PAGE_MASK); } -extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd); } -extern inline void pmd_clear(pmd_t *pmdp) { pmd_val(*pmdp) = 0; } +extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd)!=null_pte_table; } +extern inline void pmd_clear(pmd_t *pmdp) { pmd_val(*pmdp) = null_pte_table; } -extern inline int pgd_none(pgd_t pgd) { return !pgd_val(pgd); } +extern inline int pgd_none(pgd_t pgd) { return pgd_val(pgd)==null_pmd_table; } extern inline int pgd_bad(pgd_t pgd) { return (pgd_val(pgd) & ~PAGE_MASK); } -extern inline int pgd_present(pgd_t pgd) { return pgd_val(pgd); } -extern inline void pgd_clear(pgd_t *pgdp) { pgd_val(*pgdp) = 0; } +extern inline int pgd_present(pgd_t pgd) { return pgd_val(pgd)!=null_pmd_table; } +extern inline void pgd_clear(pgd_t *pgdp) { pgd_val(*pgdp) = null_pmd_table; } /* The following only work if pte_present() is true. * Undefined behaviour if not.. @@ -358,7 +412,7 @@ if(pte_val(pte) & _PAGE_WRITE) return __pte(pte_val(pte) | (_PAGE_MODIFIED | _PAGE_W)); else - return __pte(pte_val(pte) | _PAGE_MODIFIED); + return __pte(pte_val(pte) | (_PAGE_MODIFIED)); } extern inline pte_t pte_mkyoung(pte_t pte) @@ -366,14 +420,14 @@ if(pte_val(pte) & _PAGE_READ) return __pte(pte_val(pte) | (_PAGE_ACCESSED | _PAGE_R)); else - return __pte(pte_val(pte) | _PAGE_ACCESSED); + return __pte(pte_val(pte) | (_PAGE_ACCESSED)); } extern inline void SET_PAGE_DIR(struct task_struct *tsk, pgd_t *pgdir) { register unsigned long paddr asm("o5"); - paddr = ((unsigned long) pgdir) - PAGE_OFFSET; + paddr = __pa(pgdir); if(tsk->mm == current->mm) { __asm__ __volatile__ (" @@ -381,7 +435,8 @@ wrpr %%o4, %1, %%pstate mov %0, %%g7 wrpr %%o4, 0x0, %%pstate - " : : "r" (paddr), "i" (PSTATE_MG|PSTATE_IE) + " : /* No outputs */ + : "r" (paddr), "i" (PSTATE_MG|PSTATE_IE) : "o4"); } } @@ -401,6 +456,13 @@ extern inline pte_t *pte_offset(pmd_t *dir, unsigned long address) { return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PAGE - 1)); } +extern __inline__ void __init_pmd(pmd_t *pmdp) +{ + extern void __bfill64(void *, unsigned long); + + __bfill64((void *)pmdp, null_pte_table); +} + /* Allocate and free page tables. The xxx_kernel() versions are * used to allocate a kernel page table - this turns on supervisor * bits if any. @@ -418,14 +480,14 @@ pmd_set(pmd, page); return page + address; } - pmd_set(pmd, (pte_t *) BAD_PAGETABLE); + pmd_set(pmd, BAD_PTE); return NULL; } free_page((unsigned long) page); } if (pmd_bad(*pmd)) { printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd)); - pmd_set(pmd, (pte_t *) BAD_PAGETABLE); + pmd_set(pmd, BAD_PTE); return NULL; } return (pte_t *) pmd_page(*pmd) + address; @@ -441,17 +503,18 @@ pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL); if (pgd_none(*pgd)) { if (page) { + __init_pmd(page); pgd_set(pgd, page); return page + address; } - pgd_set(pgd, BAD_PAGETABLE); + pgd_set(pgd, BAD_PMD); return NULL; } free_page((unsigned long) page); } if (pgd_bad(*pgd)) { printk("Bad pgd in pmd_alloc_kernel: %08lx\n", pgd_val(*pgd)); - pgd_set(pgd, BAD_PAGETABLE); + pgd_set(pgd, BAD_PMD); return NULL; } return (pmd_t *) pgd_page(*pgd) + address; @@ -470,14 +533,14 @@ pmd_set(pmd, page); return page + address; } - pmd_set(pmd, (pte_t *) BAD_PAGETABLE); + pmd_set(pmd, BAD_PTE); return NULL; } free_page((unsigned long) page); } if (pmd_bad(*pmd)) { printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - pmd_set(pmd, (pte_t *) BAD_PAGETABLE); + pmd_set(pmd, BAD_PTE); return NULL; } return (pte_t *) pmd_page(*pmd) + address; @@ -493,17 +556,18 @@ pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL); if (pgd_none(*pgd)) { if (page) { + __init_pmd(page); pgd_set(pgd, page); return page + address; } - pgd_set(pgd, BAD_PAGETABLE); + pgd_set(pgd, BAD_PMD); return NULL; } free_page((unsigned long) page); } if (pgd_bad(*pgd)) { printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd)); - pgd_set(pgd, BAD_PAGETABLE); + pgd_set(pgd, BAD_PMD); return NULL; } return (pmd_t *) pgd_page(*pgd) + address; @@ -513,10 +577,34 @@ { free_page((unsigned long)pgd); } extern inline pgd_t * pgd_alloc(void) -{ return (pgd_t *) get_free_page(GFP_KERNEL); } +{ + extern void __bfill64(void *, unsigned long); + pgd_t *pgd = (pgd_t *) __get_free_page(GFP_KERNEL); + + if (pgd) + __bfill64((void *)pgd, null_pmd_table); + return pgd; +} extern pgd_t swapper_pg_dir[1024]; +/* Routines for getting a dvma scsi buffer. */ +struct mmu_sglist { + char *addr; + char *__dont_touch; + unsigned int len; + __u32 dvma_addr; +}; + +extern __u32 mmu_get_scsi_one(char *, unsigned long, struct linux_sbus *sbus); +extern void mmu_get_scsi_sgl(struct mmu_sglist *, int, struct linux_sbus *sbus); + +/* These do nothing with the way I have things setup. */ +#define mmu_release_scsi_one(vaddr, len, sbus) do { } while(0) +#define mmu_release_scsi_sgl(sg, sz, sbus) do { } while(0) +#define mmu_lockarea(vaddr, len) (vaddr) +#define mmu_unlockarea(vaddr, len) do { } while(0) + extern inline void update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte) { @@ -576,44 +664,14 @@ /* Make a non-present pseudo-TTE. */ extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) -{ pte_t pte; pte_val(pte) = (type) | (offset << 8); return pte; } +{ pte_t pte; pte_val(pte) = (type<> 8) +#define SWP_TYPE(entry) (((entry>>PAGE_SHIFT) & 0xff)) +#define SWP_OFFSET(entry) ((entry) >> (PAGE_SHIFT+8)) #define SWP_ENTRY(type,offset) pte_val(mk_swap_pte((type),(offset))) - -struct ctx_list { - struct ctx_list *next; - struct ctx_list *prev; - unsigned int ctx_number; - struct mm_struct *ctx_mm; -}; - -extern struct ctx_list *ctx_list_pool; /* Dynamically allocated */ -extern struct ctx_list ctx_free; /* Head of free list */ -extern struct ctx_list ctx_used; /* Head of used contexts list */ - -#define NO_CONTEXT -1 - -extern __inline__ void remove_from_ctx_list(struct ctx_list *entry) -{ - entry->next->prev = entry->prev; - entry->prev->next = entry->next; -} - -extern __inline__ void add_to_ctx_list(struct ctx_list *head, struct ctx_list *entry) -{ - entry->next = head; - (entry->prev = head->prev)->next = entry; - head->prev = entry; -} -#define add_to_free_ctxlist(entry) add_to_ctx_list(&ctx_free, entry) -#define add_to_used_ctxlist(entry) add_to_ctx_list(&ctx_used, entry) #endif /* !(__ASSEMBLY__) */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/posix_types.h linux/include/asm-sparc64/posix_types.h --- v2.1.33/linux/include/asm-sparc64/posix_types.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/posix_types.h Fri Apr 11 10:47:39 1997 @@ -9,25 +9,25 @@ typedef unsigned long long __kernel_size_t; -typedef int __kernel_ssize_t; -typedef unsigned long long int __kernel_ptrdiff_t; +typedef long long __kernel_ssize_t; +typedef long __kernel_ptrdiff_t; typedef long __kernel_time_t; typedef long __kernel_clock_t; typedef int __kernel_pid_t; -typedef unsigned short __kernel_ipc_pid_t; -typedef unsigned short __kernel_uid_t; -typedef unsigned short __kernel_gid_t; -typedef unsigned short __kernel_dev_t; -typedef unsigned long __kernel_ino_t; -typedef unsigned short __kernel_mode_t; +typedef int __kernel_ipc_pid_t; +typedef unsigned int __kernel_uid_t; +typedef unsigned int __kernel_gid_t; +typedef unsigned int __kernel_dev_t; +typedef unsigned int __kernel_ino_t; +typedef unsigned int __kernel_mode_t; typedef unsigned short __kernel_umode_t; -typedef short __kernel_nlink_t; -typedef long __kernel_daddr_t; +typedef unsigned int __kernel_nlink_t; +typedef int __kernel_daddr_t; typedef long __kernel_off_t; typedef char * __kernel_caddr_t; #ifdef __GNUC__ -typedef long long __kernel_loff_t; +typedef long long __kernel_loff_t; #endif typedef struct { diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/processor.h linux/include/asm-sparc64/processor.h --- v2.1.33/linux/include/asm-sparc64/processor.h Thu Mar 27 14:40:09 1997 +++ linux/include/asm-sparc64/processor.h Mon Apr 14 09:31:09 1997 @@ -1,4 +1,4 @@ -/* $Id: processor.h,v 1.10 1997/03/14 21:05:39 jj Exp $ +/* $Id: processor.h,v 1.20 1997/04/11 22:34:54 davem Exp $ * include/asm-sparc64/processor.h * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -24,19 +23,11 @@ #define wp_works_ok 1 #define wp_works_ok__is_a_macro /* for versions in ksyms.c */ -/* Whee, this is STACK_TOP + PAGE_SIZE and the lowest kernel address too... - * That one page is used to protect kernel from intruders, so that - * we can make our access_ok test faster - */ -#define TASK_SIZE (0xFFFFF80000000000UL) +/* User lives in his very own context, and cannot reference us. */ +#define TASK_SIZE ((1UL << (PAGE_SHIFT - 3)) * PGDIR_SIZE) #ifndef __ASSEMBLY__ -struct fpq { - unsigned long *insn_addr; - unsigned long insn; -}; - #define NSWINS 8 /* The Sparc processor specific thread struct. */ @@ -48,12 +39,9 @@ is multiplied by 512 to get the amount of wasted kernel memory. */ unsigned int float_regs[64] __attribute__ ((aligned (64))); unsigned long fsr; - unsigned long fpqdepth; - struct fpq fpqueue[16]; /* Context switch saved kernel state. */ - unsigned long user_globals[8]; /* performance hack */ - unsigned long ksp, kpc; + unsigned long ksp, kpc, wstate, cwp; /* Storage for windows when user stack is bogus. */ struct reg_window reg_window[NSWINS] __attribute__ ((aligned (16))); @@ -82,7 +70,7 @@ #define SPARC_FLAG_NEWSIGNALS 0x4 /* task wants new-style signals */ #define SPARC_FLAG_32BIT 0x8 /* task is older 32-bit binary */ -#define INIT_MMAP { &init_mm, 0xfffff80000000000, 0xfffffe00000, \ +#define INIT_MMAP { &init_mm, 0xfffff80000000000, 0xfffff80001000000, \ PAGE_SHARED , VM_READ | VM_WRITE | VM_EXEC } #define INIT_TSS { \ @@ -90,12 +78,10 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \ -/* FPU status, FPU qdepth, FPU queue */ \ - 0, 0, { { 0, 0, }, }, \ -/* user_globals */ \ - { 0, 0, 0, 0, 0, 0, 0, 0 }, \ -/* ksp, kpc */ \ - 0, 0, \ +/* FPU status */ \ + 0, \ +/* ksp, kpc, wstate, cwp */ \ + 0, 0, 0, 0, \ /* reg_window */ \ { { { 0, }, { 0, } }, }, \ /* rwbuf_stkptrs */ \ @@ -123,79 +109,85 @@ } /* Do necessary setup to start up a newly executed thread. */ -extern __inline__ void start_thread(struct pt_regs *regs, unsigned long pc, - unsigned long sp) -{ - regs->tstate = (regs->tstate & (TSTATE_CWP)) | TSTATE_IE; - regs->tpc = ((pc & (~3)) - 4); - regs->tnpc = regs->tpc + 4; - regs->y = 0; - __asm__ __volatile__(" - stx %%g0, [%0 + %2 + 0x00] - stx %%g0, [%0 + %2 + 0x08] - stx %%g0, [%0 + %2 + 0x10] - stx %%g0, [%0 + %2 + 0x18] - stx %%g0, [%0 + %2 + 0x20] - stx %%g0, [%0 + %2 + 0x28] - stx %%g0, [%0 + %2 + 0x30] - stx %%g0, [%0 + %2 + 0x38] - stx %%g0, [%0 + %2 + 0x40] - stx %%g0, [%0 + %2 + 0x48] - stx %%g0, [%0 + %2 + 0x50] - stx %%g0, [%0 + %2 + 0x58] - stx %%g0, [%0 + %2 + 0x60] - stx %%g0, [%0 + %2 + 0x68] - stx %1, [%0 + %2 + 0x70] - stx %%g0, [%0 + %2 + 0x78] - " : : "r" (regs), "r" (sp - REGWIN_SZ), - "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); -} - -extern __inline__ void start_thread32(struct pt_regs *regs, unsigned long pc, - unsigned long sp) -{ - register unsigned int zero asm("g1"); - - pc &= 0x00000000ffffffffUL; - sp &= 0x00000000ffffffffUL; - - regs->tstate = (regs->tstate & (TSTATE_CWP)) | (TSTATE_IE | TSTATE_AM); - regs->tpc = ((pc & (~3)) - 4); - regs->tnpc = regs->tpc + 4; - regs->y = 0; - zero = 0; - __asm__ __volatile__(" - stx %%g0, [%0 + %2 + 0x00] - stx %%g0, [%0 + %2 + 0x08] - stx %%g0, [%0 + %2 + 0x10] - stx %%g0, [%0 + %2 + 0x18] - stx %%g0, [%0 + %2 + 0x20] - stx %%g0, [%0 + %2 + 0x28] - stx %%g0, [%0 + %2 + 0x30] - stx %%g0, [%0 + %2 + 0x38] - stx %%g0, [%0 + %2 + 0x40] - stx %%g0, [%0 + %2 + 0x48] - stx %%g0, [%0 + %2 + 0x50] - stx %%g0, [%0 + %2 + 0x58] - stx %%g0, [%0 + %2 + 0x60] - stx %%g0, [%0 + %2 + 0x68] - stx %1, [%0 + %2 + 0x70] - stx %%g0, [%0 + %2 + 0x78] - " : : "r" (regs), "r" (sp - REGWIN32_SZ), - "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0])), - "r" (zero)); -} +#define start_thread(regs, pc, sp) \ +do { \ + regs->tstate = (regs->tstate & (TSTATE_CWP)) | TSTATE_IE; \ + regs->tpc = ((pc & (~3)) - 4); \ + regs->tnpc = regs->tpc + 4; \ + regs->y = 0; \ + __asm__ __volatile__( \ + "stx %%g0, [%0 + %2 + 0x00]\n\t" \ + "stx %%g0, [%0 + %2 + 0x08]\n\t" \ + "stx %%g0, [%0 + %2 + 0x10]\n\t" \ + "stx %%g0, [%0 + %2 + 0x18]\n\t" \ + "stx %%g0, [%0 + %2 + 0x20]\n\t" \ + "stx %%g0, [%0 + %2 + 0x28]\n\t" \ + "stx %%g0, [%0 + %2 + 0x30]\n\t" \ + "stx %%g0, [%0 + %2 + 0x38]\n\t" \ + "stx %%g0, [%0 + %2 + 0x40]\n\t" \ + "stx %%g0, [%0 + %2 + 0x48]\n\t" \ + "stx %%g0, [%0 + %2 + 0x50]\n\t" \ + "stx %%g0, [%0 + %2 + 0x58]\n\t" \ + "stx %%g0, [%0 + %2 + 0x60]\n\t" \ + "stx %%g0, [%0 + %2 + 0x68]\n\t" \ + "stx %1, [%0 + %2 + 0x70]\n\t" \ + "stx %%g0, [%0 + %2 + 0x78]\n\t" \ + : \ + : "r" (regs), "r" (sp - REGWIN_SZ), \ + "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \ +} while(0) + +#define start_thread32(regs, pc, sp) \ +do { \ + register unsigned int zero asm("g1"); \ +\ + pc &= 0x00000000ffffffffUL; \ + sp &= 0x00000000ffffffffUL; \ +\ + regs->tstate = (regs->tstate & (TSTATE_CWP)) | (TSTATE_IE | TSTATE_AM); \ + regs->tpc = ((pc & (~3)) - 4); \ + regs->tnpc = regs->tpc + 4; \ + regs->y = 0; \ + current->tss.flags |= SPARC_FLAG_32BIT; \ + zero = 0; \ + __asm__ __volatile__( \ + "stx %%g0, [%0 + %2 + 0x00]\n\t" \ + "stx %%g0, [%0 + %2 + 0x08]\n\t" \ + "stx %%g0, [%0 + %2 + 0x10]\n\t" \ + "stx %%g0, [%0 + %2 + 0x18]\n\t" \ + "stx %%g0, [%0 + %2 + 0x20]\n\t" \ + "stx %%g0, [%0 + %2 + 0x28]\n\t" \ + "stx %%g0, [%0 + %2 + 0x30]\n\t" \ + "stx %%g0, [%0 + %2 + 0x38]\n\t" \ + "stx %%g0, [%0 + %2 + 0x40]\n\t" \ + "stx %%g0, [%0 + %2 + 0x48]\n\t" \ + "stx %%g0, [%0 + %2 + 0x50]\n\t" \ + "stx %%g0, [%0 + %2 + 0x58]\n\t" \ + "stx %%g0, [%0 + %2 + 0x60]\n\t" \ + "stx %%g0, [%0 + %2 + 0x68]\n\t" \ + "stx %1, [%0 + %2 + 0x70]\n\t" \ + "stx %%g0, [%0 + %2 + 0x78]\n\t" \ + : \ + : "r" (regs), "r" (sp - REGWIN32_SZ), \ + "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0])), \ + "r" (zero)); \ +} while(0) /* Free all resources held by a thread. */ #define release_thread(tsk) do { } while(0) #ifdef __KERNEL__ /* Allocation and freeing of basic task resources. */ + +/* XXX FIXME For task_struct must use SLAB or something other than + * XXX kmalloc() as FPU registers in TSS require that entire structure + * XXX be 64-byte aligned as well. + */ #define alloc_kernel_stack(tsk) __get_free_page(GFP_KERNEL) #define free_kernel_stack(stack) free_page(stack) #define alloc_task_struct() kmalloc(sizeof(struct task_struct), GFP_KERNEL) #define free_task_struct(tsk) kfree(tsk) -#endif +#endif /* __KERNEL__ */ #endif /* !(__ASSEMBLY__) */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/psrcompat.h linux/include/asm-sparc64/psrcompat.h --- v2.1.33/linux/include/asm-sparc64/psrcompat.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/psrcompat.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: psrcompat.h,v 1.1 1996/12/26 10:02:30 davem Exp $ */ +/* $Id: psrcompat.h,v 1.2 1997/04/07 18:57:17 jj Exp $ */ #ifndef _SPARC64_PSRCOMPAT_H #define _SPARC64_PSRCOMPAT_H @@ -36,7 +36,7 @@ psr |= ((tstate & TSTATE_ICC) >> 12); /* This is completely arbitrary. */ - __asm__ __volatile__("rdpr %vers, %0" : "=r" (vers)); + __asm__ __volatile__("rdpr %%ver, %0" : "=r" (vers)); psr |= ((vers << 8) >> 32) & PSR_IMPL; psr |= ((vers << 24) >> 36) & PSR_VERS; diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/pstate.h linux/include/asm-sparc64/pstate.h --- v2.1.33/linux/include/asm-sparc64/pstate.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/pstate.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: pstate.h,v 1.2 1996/12/26 09:56:16 davem Exp $ */ +/* $Id: pstate.h,v 1.3 1997/03/25 03:58:31 davem Exp $ */ #ifndef _SPARC64_PSTATE_H #define _SPARC64_PSTATE_H @@ -21,10 +21,10 @@ #define PSTATE_IE 0x0000000000000002 /* Interrupt Enable. */ #define PSTATE_AG 0x0000000000000001 /* Alternate Globals. */ -/* The V9 TSTATE Register (with SpitFire extensions). +/* The V9 TSTATE Register (with SpitFire and Linux extensions). * * --------------------------------------------------------------- - * | Resv | CCR | ASI | Resv | PSTATE | Resv | CWP | + * | Resv | CCR | ASI | %pil | PSTATE | Resv | CWP | * --------------------------------------------------------------- * 63 40 39 32 31 24 23 20 19 8 7 5 4 0 */ @@ -40,6 +40,7 @@ #define TSTATE_IOVFL 0x0000000200000000 /* %icc Overflow. */ #define TSTATE_ICARRY 0x0000000100000000 /* %icc Carry. */ #define TSTATE_ASI 0x00000000ff000000 /* Address Space Identifier. */ +#define TSTATE_PIL 0x0000000000f00000 /* %pil (Linux traps set this) */ #define TSTATE_PSTATE 0x00000000000fff00 /* PSTATE. */ #define TSTATE_IG 0x0000000000080000 /* Interrupt Globals. */ #define TSTATE_MG 0x0000000000040000 /* MMU Globals. */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/resource.h linux/include/asm-sparc64/resource.h --- v2.1.33/linux/include/asm-sparc64/resource.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/resource.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: resource.h,v 1.1 1996/12/26 14:22:34 davem Exp $ +/* $Id: resource.h,v 1.2 1997/04/04 00:50:27 davem Exp $ * resource.h: Resource definitions. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -25,7 +25,7 @@ #define RLIM_NLIMITS 10 #ifdef __KERNEL__ - +/* XXX 32-bit binary compatability... */ #define INIT_RLIMITS \ { \ {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/sbus.h linux/include/asm-sparc64/sbus.h --- v2.1.33/linux/include/asm-sparc64/sbus.h Mon Mar 17 14:54:34 1997 +++ linux/include/asm-sparc64/sbus.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: sbus.h,v 1.2 1997/02/25 20:00:35 jj Exp $ +/* $Id: sbus.h,v 1.3 1997/03/21 17:57:24 jj Exp $ * sbus.h: Defines for the Sun SBus. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -19,8 +19,8 @@ */ /* The base address at which to calculate device OBIO addresses. */ -#define SUN_SBUS_BVADDR 0xf8000000 -#define SBUS_OFF_MASK 0x01ffffff +#define SUN_SBUS_BVADDR 0x00000000 +#define SBUS_OFF_MASK 0x0fffffff /* These routines are used to calculate device address from slot * numbers + offsets, and vice versa. @@ -28,12 +28,12 @@ extern __inline__ unsigned long sbus_devaddr(int slotnum, unsigned long offset) { - return (unsigned long) (SUN_SBUS_BVADDR+((slotnum)<<25)+(offset)); + return (unsigned long) (SUN_SBUS_BVADDR+((slotnum)<<28)+(offset)); } extern __inline__ int sbus_dev_slot(unsigned long dev_addr) { - return (int) (((dev_addr)-SUN_SBUS_BVADDR)>>25); + return (int) (((dev_addr)-SUN_SBUS_BVADDR)>>28); } extern __inline__ unsigned long sbus_dev_offset(unsigned long dev_addr) diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/scatterlist.h linux/include/asm-sparc64/scatterlist.h --- v2.1.33/linux/include/asm-sparc64/scatterlist.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/scatterlist.h Fri Apr 11 10:47:39 1997 @@ -1,4 +1,4 @@ -/* $Id: scatterlist.h,v 1.1 1996/12/26 14:22:32 davem Exp $ */ +/* $Id: scatterlist.h,v 1.4 1997/04/10 05:13:32 davem Exp $ */ #ifndef _SPARC64_SCATTERLIST_H #define _SPARC64_SCATTERLIST_H @@ -10,9 +10,9 @@ * dma indirect buffer. NULL otherwise */ unsigned int length; - char * dvma_address; /* A place to hang host-specific addresses at. */ + __u32 dvma_address; /* A place to hang host-specific addresses at. */ }; -#define ISA_DMA_THRESHOLD ((0x100000000) + PAGE_OFFSET) +#define ISA_DMA_THRESHOLD ((0xf0000000) + PAGE_OFFSET) #endif /* !(_SPARC64_SCATTERLIST_H) */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/semaphore.h linux/include/asm-sparc64/semaphore.h --- v2.1.33/linux/include/asm-sparc64/semaphore.h Mon Mar 17 14:54:34 1997 +++ linux/include/asm-sparc64/semaphore.h Mon Apr 14 09:31:09 1997 @@ -11,19 +11,27 @@ struct wait_queue * wait; }; -#define MUTEX ((struct semaphore) { 1, 0, NULL }) -#define MUTEX_LOCKED ((struct semaphore) { 0, 0, NULL }) +#define MUTEX ((struct semaphore) { { 1 }, { 0 }, NULL }) +#define MUTEX_LOCKED ((struct semaphore) { { 0 }, { 0 }, NULL }) extern void __down(struct semaphore * sem); +extern int __down_interruptible(struct semaphore * sem); extern void __up(struct semaphore * sem); +#define sema_init(sem, val) atomic_set(&((sem)->count), val) + extern __inline__ void down(struct semaphore * sem) { - for (;;) { - if (atomic_dec_return(&sem->count) >= 0) - break; + if (atomic_dec_return(&sem->count) < 0) __down(sem); - } +} + +extern __inline__ int down_interruptible(struct semaphore *sem) +{ + int ret = 0; + if (atomic_dec_return(&sem->count) < 0) + ret = __down_interruptible(sem); + return ret; } extern __inline__ void up(struct semaphore * sem) diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/sigcontext.h linux/include/asm-sparc64/sigcontext.h --- v2.1.33/linux/include/asm-sparc64/sigcontext.h Mon Mar 17 14:54:34 1997 +++ linux/include/asm-sparc64/sigcontext.h Fri Apr 11 10:47:39 1997 @@ -1,8 +1,13 @@ -/* $Id: sigcontext.h,v 1.3 1997/03/03 16:51:55 jj Exp $ */ +/* $Id: sigcontext.h,v 1.4 1997/04/04 00:50:28 davem Exp $ */ #ifndef __SPARC64_SIGCONTEXT_H #define __SPARC64_SIGCONTEXT_H #include + +/* XXX This gets exported to userland as well as kernel, it is probably + * XXX riddled with many hard to find 32-bit binary compatability issues. + * XXX Signals and this file need to be investigated heavily. -DaveM + */ #define SUNOS_MAXWIN 31 diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/smp.h linux/include/asm-sparc64/smp.h --- v2.1.33/linux/include/asm-sparc64/smp.h Mon Mar 17 14:54:34 1997 +++ linux/include/asm-sparc64/smp.h Fri Apr 11 10:47:39 1997 @@ -19,6 +19,7 @@ }; extern int linux_num_cpus; /* number of CPUs probed */ +extern struct prom_cpuinfo linux_cpus[NCPUS]; #endif /* !(__ASSEMBLY__) */ @@ -26,8 +27,6 @@ #ifndef __ASSEMBLY__ -extern struct prom_cpuinfo linux_cpus[NCPUS]; - /* Per processor Sparc parameters we need. */ struct cpuinfo_sparc { @@ -71,8 +70,6 @@ extern void smp_store_cpu_info(int id); extern void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5); -extern void smp_capture(void); -extern void smp_release(void); extern __inline__ void xc0(smpfunc_t func) { smp_cross_call(func, 0, 0, 0, 0, 0); } extern __inline__ void xc1(smpfunc_t func, unsigned long arg1) @@ -126,7 +123,8 @@ 2: membar #StoreStore | #StoreLoad " : "=&r" (temp0), "=&r" (temp1), "=r" (ctr) - : "ir" (i), "r" (ctr)); + : "ir" (i), "r" (ctr) + : "cc"); } extern __inline__ __volatile__ void dec_smp_counter(volatile int *ctr) @@ -144,7 +142,8 @@ 2: membar #StoreStore | #StoreLoad " : "=&r" (temp0), "=&r" (temp1), "=r" (ctr) - : "ir" (i), "r" (ctr)); + : "ir" (i), "r" (ctr) + : "cc"); } extern __inline__ __volatile__ int read_smp_counter(volatile int *ctr) @@ -155,7 +154,6 @@ #endif /* !(__ASSEMBLY__) */ /* Sparc specific messages. */ -#define MSG_CAPTURE 0x0004 /* Park a processor. */ #define MSG_CROSS_CALL 0x0005 /* run func on cpus */ /* Empirical PROM processor mailbox constants. If the per-cpu mailbox diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/smp_lock.h linux/include/asm-sparc64/smp_lock.h --- v2.1.33/linux/include/asm-sparc64/smp_lock.h Thu Mar 27 14:40:09 1997 +++ linux/include/asm-sparc64/smp_lock.h Fri Apr 11 10:47:40 1997 @@ -11,53 +11,14 @@ #include #ifndef __SMP__ -#define lock_kernel() do { } while(0) -#define unlock_kernel() do { } while(0) -#else - -extern __inline__ __volatile__ unsigned char ldstub(volatile unsigned char *lock) -{ - volatile unsigned char retval; - - __asm__ __volatile__("ldstub [%1], %0" : "=&r" (retval) : "r" (lock)); - return retval; -} - -/* - * Locking the kernel - */ -/* Knock knock... */ -extern __inline__ void lock_kernel(void) -{ - int proc = smp_processor_id(); - - while(ldstub(&kernel_flag)) { - if(proc == active_kernel_processor) - break; - do { -#ifdef __SMP_PROF__ - smp_spins[smp_processor_id()]++; -#endif - barrier(); - } while(kernel_flag); /* Don't lock the bus more than we have to. */ - } - active_kernel_processor = proc; - kernel_counter++; -} - -/* I want out... */ -extern __inline__ void unlock_kernel(void) -{ - if(kernel_counter == 0) - panic("Bogus kernel counter.\n"); - - if(!--kernel_counter) { - active_kernel_processor = NO_PROC_ID; - kernel_flag = KLOCK_CLEAR; - } -} +#define lock_kernel() do { } while(0) +#define unlock_kernel() do { } while(0) +#define release_kernel_lock(task, cpu, depth) ((depth) = 1) +#define reaquire_kernel_lock(task, cpu, depth) do { } while(0) +#else +#error SMP on sparc64 not supported yet #endif /* (__SMP__) */ #endif /* !(__SPARC64_SMPLOCK_H) */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/softirq.h linux/include/asm-sparc64/softirq.h --- v2.1.33/linux/include/asm-sparc64/softirq.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc64/softirq.h Mon Apr 14 09:31:09 1997 @@ -0,0 +1,58 @@ +/* softirq.h: 64-bit Sparc soft IRQ support. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef __SPARC64_SOFTIRQ_H +#define __SPARC64_SOFTIRQ_H + +#include +#include + +/* The locking mechanism for base handlers, to prevent re-entrancy, + * is entirely private to an implementation, it should not be + * referenced at all outside of this file. + */ +extern atomic_t __sparc64_bh_counter; + +#define get_active_bhs() (bh_mask & bh_active) + +#ifdef __SMP__ +#error SMP not supported on sparc64 yet +#else + +#define softirq_trylock() (atomic_read(&__sparc64_bh_counter) ? \ + 0 : \ + ((atomic_set(&__sparc64_bh_counter,1)),1)) +#define softirq_endlock() (atomic_set(&__sparc64_bh_counter, 0)) +#define clear_active_bhs(x) (bh_active &= ~(x)) + +#define init_bh(nr, routine) \ +do { int ent = nr; \ + bh_base[ent] = routine; \ + bh_mask_count[ent] = 0; \ + bh_mask |= 1 << ent; \ +} while(0) + +#define mark_bh(nr) (bh_active |= (1 << (nr))) + +#define disable_bh(nr) \ +do { int ent = nr; \ + bh_mask &= ~(1 << ent); \ + bh_mask_count[ent]++; \ +} while(0) + +#define enable_bh(nr) \ +do { int ent = nr; \ + if (!--bh_mask_count[ent]) \ + bh_mask |= 1 << ent; \ +} while(0) + +#define start_bh_atomic() \ + do { atomic_inc(&__sparc64_bh_counter); synchronize_irq(); } while(0) + +#define end_bh_atomic() do { atomic_dec(&__sparc64_bh_counter); } while(0) + +#endif /* !(__SMP__) */ + +#endif /* !(__SPARC64_SOFTIRQ_H) */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/spinlock.h linux/include/asm-sparc64/spinlock.h --- v2.1.33/linux/include/asm-sparc64/spinlock.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc64/spinlock.h Fri Apr 11 10:47:40 1997 @@ -0,0 +1,32 @@ +/* spinlock.h: 64-bit Sparc spinlock support. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef __SPARC64_SPINLOCK_H +#define __SPARC64_SPINLOCK_H + +#ifndef __ASSEMBLY__ + +#ifndef __SMP__ + +typedef struct { } spinlock_t; +#define SPIN_LOCK_UNLOCKED { } + +#define spin_lock_init(lock) do { } while(0) +#define spin_lock(lock) do { } while(0) +#define spin_trylock(lock) do { } while(0) +#define spin_unlock(lock) do { } while(0) +#define spin_lock_irq(lock) cli() +#define spin_unlock_irq(lock) sti() + +#define spin_lock_irqsave(lock, flags) save_and_cli(flags) +#define spin_unlock_irqrestore(lock, flags) restore_flags(flags) + +#else /* !(__SMP__) */ +#error SMP not supported on sparc64 +#endif /* __SMP__ */ + +#endif /* !(__ASSEMBLY__) */ + +#endif /* !(__SPARC64_SPINLOCK_H) */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/spitfire.h linux/include/asm-sparc64/spitfire.h --- v2.1.33/linux/include/asm-sparc64/spitfire.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/spitfire.h Fri Apr 11 10:47:40 1997 @@ -1,4 +1,4 @@ -/* $Id: spitfire.h,v 1.2 1996/12/28 18:39:55 davem Exp $ +/* $Id: spitfire.h,v 1.7 1997/04/04 00:50:29 davem Exp $ * spitfire.h: SpitFire/BlackBird/Cheetah inline MMU operations. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -29,6 +29,48 @@ #ifndef __ASSEMBLY__ +extern __inline__ unsigned long spitfire_get_isfsr(void) +{ + unsigned long ret; + + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (ret) + : "r" (TLB_SFSR), "i" (ASI_IMMU)); + return ret; +} + +extern __inline__ unsigned long spitfire_get_dsfsr(void) +{ + unsigned long ret; + + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (ret) + : "r" (TLB_SFSR), "i" (ASI_DMMU)); + return ret; +} + +extern __inline__ unsigned long spitfire_get_sfar(void) +{ + unsigned long ret; + + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (ret) + : "r" (DMMU_SFAR), "i" (ASI_DMMU)); + return ret; +} + +extern __inline__ void spitfire_put_isfsr(unsigned long sfsr) +{ + __asm__ __volatile__("stxa %0, [%1] %2" : + : "r" (sfsr), "r" (TLB_SFSR), "i" (ASI_IMMU)); +} + +extern __inline__ void spitfire_put_dsfsr(unsigned long sfsr) +{ + __asm__ __volatile__("stxa %0, [%1] %2" : + : "r" (sfsr), "r" (TLB_SFSR), "i" (ASI_DMMU)); +} + extern __inline__ unsigned long spitfire_get_primary_context(void) { unsigned long ctx; @@ -36,12 +78,16 @@ __asm__ __volatile__("ldxa [%1] %2, %0" : "=r" (ctx) : "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + return ctx; } -extern __inline__ unsigned long spitfire_set_primary_context(unsigned long ctx) +extern __inline__ void spitfire_set_primary_context(unsigned long ctx) { __asm__ __volatile__("stxa %0, [%1] %2" - : : "r" (ctx), "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + : /* No outputs */ + : "r" (ctx & 0x1fff), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + membar("#Sync"); } extern __inline__ unsigned long spitfire_get_secondary_context(void) @@ -51,12 +97,16 @@ __asm__ __volatile__("ldxa [%1] %2, %0" : "=r" (ctx) : "r" (SECONDARY_CONTEXT), "i" (ASI_DMMU)); + return ctx; } -extern __inline__ unsigned long spitfire_set_secondary_context(unsigned long ctx) +extern __inline__ void spitfire_set_secondary_context(unsigned long ctx) { __asm__ __volatile__("stxa %0, [%1] %2" - : : "r" (ctx), "r" (SECONDARY_CONTEXT), "i" (ASI_DMMU)); + : /* No outputs */ + : "r" (ctx & 0x1fff), + "r" (SECONDARY_CONTEXT), "i" (ASI_DMMU)); + membar("#Sync"); } /* The data cache is write through, so this just invalidates the @@ -92,11 +142,22 @@ return data; } -extern __inline__ unsigned long spitfire_put_dtlb_data(int entry, unsigned long data) +extern __inline__ unsigned long spitfire_get_dtlb_tag(int entry) +{ + unsigned long tag; + + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (tag) + : "r" (entry << 3), "i" (ASI_DTLB_TAG_READ)); + return tag; +} + +extern __inline__ void spitfire_put_dtlb_data(int entry, unsigned long data) { __asm__ __volatile__("stxa %0, [%1] %2" - : : "r" (data), "r" (entry << 3), - "i" (ASI_DTLB_DATA_ACCESS)); + : /* No outputs */ + : "r" (data), "r" (entry << 3), + "i" (ASI_DTLB_DATA_ACCESS)); } extern __inline__ unsigned long spitfire_get_itlb_data(int entry) @@ -109,11 +170,22 @@ return data; } -extern __inline__ unsigned long spitfire_put_itlb_data(int entry, unsigned long data) +extern __inline__ unsigned long spitfire_get_itlb_tag(int entry) +{ + unsigned long tag; + + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (tag) + : "r" (entry << 3), "i" (ASI_ITLB_TAG_READ)); + return tag; +} + +extern __inline__ void spitfire_put_itlb_data(int entry, unsigned long data) { __asm__ __volatile__("stxa %0, [%1] %2" - : : "r" (data), "r" (entry << 3), - "i" (ASI_ITLB_DATA_ACCESS)); + : /* No outputs */ + : "r" (data), "r" (entry << 3), + "i" (ASI_ITLB_DATA_ACCESS)); } /* Spitfire hardware assisted TLB flushes. */ @@ -122,74 +194,86 @@ extern __inline__ void spitfire_flush_dtlb_primary_context(void) { __asm__ __volatile__("stxa %%g0, [%0] %1" - : : "r" (0x40), "i" (ASI_DMMU_DEMAP)); + : /* No outputs */ + : "r" (0x40), "i" (ASI_DMMU_DEMAP)); } extern __inline__ void spitfire_flush_itlb_primary_context(void) { __asm__ __volatile__("stxa %%g0, [%0] %1" - : : "r" (0x40), "i" (ASI_IMMU_DEMAP)); + : /* No outputs */ + : "r" (0x40), "i" (ASI_IMMU_DEMAP)); } extern __inline__ void spitfire_flush_dtlb_secondary_context(void) { __asm__ __volatile__("stxa %%g0, [%0] %1" - : : "r" (0x41), "i" (ASI_DMMU_DEMAP)); + : /* No outputs */ + : "r" (0x41), "i" (ASI_DMMU_DEMAP)); } extern __inline__ void spitfire_flush_itlb_secondary_context(void) { __asm__ __volatile__("stxa %%g0, [%0] %1" - : : "r" (0x41), "i" (ASI_IMMU_DEMAP)); + : /* No outputs */ + : "r" (0x41), "i" (ASI_IMMU_DEMAP)); } extern __inline__ void spitfire_flush_dtlb_nucleus_context(void) { __asm__ __volatile__("stxa %%g0, [%0] %1" - : : "r" (0x42), "i" (ASI_DMMU_DEMAP)); + : /* No outputs */ + : "r" (0x42), "i" (ASI_DMMU_DEMAP)); } extern __inline__ void spitfire_flush_itlb_nucleus_context(void) { __asm__ __volatile__("stxa %%g0, [%0] %1" - : : "r" (0x42), "i" (ASI_IMMU_DEMAP)); + : /* No outputs */ + : "r" (0x42), "i" (ASI_IMMU_DEMAP)); } /* Page level flushes. */ extern __inline__ void spitfire_flush_dtlb_primary_page(unsigned long page) { __asm__ __volatile__("stxa %%g0, [%0] %1" - : : "r" (page), "i" (ASI_DMMU_DEMAP)); + : /* No outputs */ + : "r" (page), "i" (ASI_DMMU_DEMAP)); } extern __inline__ void spitfire_flush_itlb_primary_page(unsigned long page) { __asm__ __volatile__("stxa %%g0, [%0] %1" - : : "r" (page), "i" (ASI_IMMU_DEMAP)); + : /* No outputs */ + : "r" (page), "i" (ASI_IMMU_DEMAP)); } extern __inline__ void spitfire_flush_dtlb_secondary_page(unsigned long page) { __asm__ __volatile__("stxa %%g0, [%0] %1" - : : "r" (page | 0x10), "i" (ASI_DMMU_DEMAP)); + : /* No outputs */ + : "r" (page | 0x10), "i" (ASI_DMMU_DEMAP)); } extern __inline__ void spitfire_flush_itlb_secondary_page(unsigned long page) { __asm__ __volatile__("stxa %%g0, [%0] %1" - : : "r" (page | 0x10), "i" (ASI_IMMU_DEMAP)); + : /* No outputs */ + : "r" (page | 0x10), "i" (ASI_IMMU_DEMAP)); } extern __inline__ void spitfire_flush_dtlb_nucleus_page(unsigned long page) { __asm__ __volatile__("stxa %%g0, [%0] %1" - : : "r" (page | 0x20), "i" (ASI_DMMU_DEMAP)); + : /* No outputs */ + : "r" (page | 0x20), "i" (ASI_DMMU_DEMAP)); } extern __inline__ void spitfire_flush_itlb_nucleus_page(unsigned long page) { __asm__ __volatile__("stxa %%g0, [%0] %1" - : : "r" (page | 0x20), "i" (ASI_IMMU_DEMAP)); + : /* No outputs */ + : "r" (page | 0x20), "i" (ASI_IMMU_DEMAP)); } #endif /* !(__ASSEMBLY__) */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/string.h linux/include/asm-sparc64/string.h --- v2.1.33/linux/include/asm-sparc64/string.h Mon Mar 17 14:54:34 1997 +++ linux/include/asm-sparc64/string.h Fri Apr 11 10:47:40 1997 @@ -1,4 +1,4 @@ -/* $Id: string.h,v 1.3 1997/03/03 17:11:15 jj Exp $ +/* $Id: string.h,v 1.4 1997/04/01 09:34:41 davem Exp $ * string.h: External definitions for optimized assembly string * routines for the Linux Kernel. * @@ -37,16 +37,18 @@ { extern void __copy_1page(void *, const void *); - if(n <= 32) { - __builtin_memcpy(to, from, n); - } else { - switch(n) { - case 8192: - __copy_1page(to, from); - break; - default: - __memcpy(to, from, n); - break; + if(n) { + if(n <= 32) { + __builtin_memcpy(to, from, n); + } else { + switch(n) { + case 8192: + __copy_1page(to, from); + break; + default: + __memcpy(to, from, n); + break; + } } } return to; diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/sysio.h linux/include/asm-sparc64/sysio.h --- v2.1.33/linux/include/asm-sparc64/sysio.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc64/sysio.h Fri Apr 11 10:47:40 1997 @@ -0,0 +1,337 @@ +/* $Id: sysio.h,v 1.2 1997/04/03 12:26:45 davem Exp $ + * sysio.h: UltraSparc sun5 specific SBUS definitions. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef __SPARC64_SYSIO_H +#define __SPARC64_SYSIO_H + +#include + +/* SUN5 SYSIO Register Set, one per controller probed. */ +struct sysio_regs { +/*0x0000*/ u64 upa_id; /* SYSIO UPA Port ID Register */ +/*0x0008*/ u64 upa_cfg; /* SYSIO UPA Config Register */ +/*0x0010*/ u64 control; /* SYSIO Control Register */ +/*0x0018*/ u64 _unused1; +/*0x0020*/ u64 ecc_control; /* ECC Control Register */ +/*0x0028*/ u64 _unused2; + + /* Uncorrectable Error Fault Registers */ +/*0x0030*/ u64 ue_afsr; /* UE Async Fault Status */ +/*0x0038*/ u64 ue_afar; /* UE Async Fault Address */ + + /* Correctable Error Fault Registers */ +/*0x0040*/ u64 ce_afsr; /* CE Async Fault Status */ +/*0x0048*/ u64 ce_afar; /* CE Async Fault Address */ + + u64 __pad0[0x16]; + + /* Performance Monitoring Registers */ +/*0x0100*/ u64 pmon_control; +/*0x0108*/ u64 pmon_counter; + + u64 __pad1[0x3de]; + + /* SBUS Module Registers */ +/*0x2000*/ u64 sbus_control; /* SBUS Control Register */ +/*0x2008*/ u64 _unused3; +/*0x2010*/ u64 sbus_afsr; /* SBUS Async Fault Status */ +/*0x2018*/ u64 sbus_afar; /* SBUS Async Fault Address */ + + /* SBUS Slot Configuration Registers. + * On Fusion/Electron/Pulsar desktops/servers slots 4-->6 + * are for on-board devices, in particular for Electron/Pulsar + * they are: + * + * slot 4) Audio + * slot 5) MACIO + * slot 6) SLAVIO + * + * On Sunfire/Wildfire enterprise boxen these upper slots + * are unused. + */ +/*0x2020*/ u64 sbus_s0cfg; /* SBUS Slot 0 Config */ +/*0x2028*/ u64 sbus_s1cfg; /* SBUS Slot 1 Config */ +/*0x2030*/ u64 sbus_s2cfg; /* SBUS Slot 2 Config */ +/*0x2038*/ u64 sbus_s3cfg; /* SBUS Slot 3 Config */ +/*0x2040*/ u64 sbus_s4cfg; /* SBUS Slot 4 Config */ +/*0x2048*/ u64 sbus_s5cfg; /* SBUS Slot 5 Config */ +/*0x2050*/ u64 sbus_s6cfg; /* SBUS Slot 6 Config */ + + u64 __pad2[0x75]; + + /* SBUS IOMMU lives here */ +/*0x2400*/ u64 iommu_control; /* IOMMU Control */ +/*0x2408*/ u64 iommu_tsbbase; /* IOMMU TSB Base */ +/*0x2410*/ u64 iommu_flush; /* IOMMU Flush Register */ + + u64 __pad3[0x7d]; + + /* SBUS/IOMMU Streaming Buffer Registers */ +/*0x2800*/ u64 sbuf_control; /* StrBuffer Control */ +/*0x2808*/ u64 sbuf_pflush; /* StrBuffer Page Flush */ +/*0x2810*/ u64 sbus_fsync; /* StrBuffer Flush Synchronization Reg */ + + u64 __pad4[0x7d]; + + /* Interrupt mapping/control registers */ +/*0x2c00*/ u32 imap_slot0, _uim0; /* SBUS Slot 0 Int Mapping */ +/*0x2c08*/ u32 imap_slot1, _uim1; /* SBUS Slot 1 Int Mapping */ +/*0x2c10*/ u32 imap_slot2, _uim2; /* SBUS Slot 2 Int Mapping */ +/*0x2c18*/ u32 imap_slot3, _uim3; /* SBUS Slot 3 Int Mapping */ + + /* Interrupt Retry Timer. */ +/*0x2c20*/ u32 irq_retry, _irpad; + + u64 __pad5[0x7b]; + + /* The following are only used on Fusion/Electron/Pulsar + * desktop systems, they mean nothing on Sunfire/Wildfire + */ +/*0x3000*/ u32 imap_scsi, _uis; /* SCSI Int Mapping */ +/*0x3008*/ u32 imap_eth, _uie; /* Ethernet Int Mapping */ +/*0x3010*/ u32 imap_bpp, _uip; /* Parallel Port Int Mapping */ +/*0x3018*/ u32 imap_audio, _uia; /* Audio Int Mapping */ +/*0x3020*/ u32 imap_pfail, _uipf; /* Power Fail Int Mapping */ +/*0x3028*/ u32 imap_kms, _uik; /* Kbd/Mouse/Serial Int Mapping */ +/*0x3030*/ u32 imap_flpy, _uif; /* Floppy Int Mapping */ +/*0x3038*/ u32 imap_shw, _uishw; /* Spare HW Int Mapping */ +/*0x3040*/ u32 imap_kbd, _uikbd; /* Kbd Only Int Mapping */ +/*0x3048*/ u32 imap_ms, _uims; /* Mouse Only Int Mapping */ +/*0x3050*/ u32 imap_ser, _uiser; /* Serial Only Int Mapping */ +/*0x3058*/ u64 _imap_unused; +/*0x3060*/ u32 imap_tim0, _uit0; /* Timer 0 Int Mapping */ +/*0x3068*/ u32 imap_tim1, _uit1; /* Timer 1 Int Mapping */ +/*0x3070*/ u32 imap_ue, _uiue; /* UE Int Mapping */ +/*0x3078*/ u32 imap_ce, _uice; /* CE Int Mapping */ +/*0x3080*/ u32 imap_sberr, _uisbe; /* SBUS Err Int Mapping */ +/*0x3088*/ u32 imap_pmgmt, _uipm; /* Power Mgmt Int Mapping */ +/*0x3090*/ u32 imap_gfx, _uigfx; /* OB Graphics Int Mapping */ +/*0x3098*/ u32 imap_eupa, _uieupa; /* UPA Expansion Int Mapping */ + + u64 __pad6[0x6c]; + + /* Interrupt Clear Registers */ +/*0x3400*/ u64 iclr_unused0; +/*0x3408*/ u32 iclr_slot0, _ucs0; + u64 __pad7[0x7]; +/*0x3448*/ u32 iclr_slot1, _ucs1; + u64 __pad8[0x7]; +/*0x3488*/ u32 iclr_slot2, _ucs2; + u64 __pad9[0x7]; +/*0x34c8*/ u32 iclr_slot3, _ucs3; + u64 __pad10[0x66]; +/*0x3800*/ u32 iclr_scsi, _ucscsi; +/*0x3808*/ u32 iclr_eth, _uceth; +/*0x3810*/ u32 iclr_bpp, _ucbpp; +/*0x3818*/ u32 iclr_audio, _ucaudio; +/*0x3820*/ u32 iclr_pfail, _ucpfail; +/*0x3828*/ u32 iclr_kms, _uckms; +/*0x3830*/ u32 iclr_flpt, _ucflpy; +/*0x3838*/ u32 iclr_shw, _ucshw; +/*0x3840*/ u32 iclr_kbd, _uckbd; +/*0x3848*/ u32 iclr_ms, _ucms; +/*0x3850*/ u32 iclr_ser, _ucser; +/*0x3858*/ u64 iclr_unused1; +/*0x3860*/ u32 iclr_tim0, _uctim0; +/*0x3868*/ u32 iclr_tim1, _uctim1; +/*0x3870*/ u32 iclr_ue, _ucue; +/*0x3878*/ u32 iclr_ce, _ucce; +/*0x3880*/ u32 iclr_serr, _ucserr; +/*0x3888*/ u32 iclr_pmgmt, _ucpmgmt; + + u64 __pad11[0x6e]; + + /* Counters/Timers */ +/*0x3c00*/ u32 tim0_cnt, _tim0_u0; +/*0x3c08*/ u32 tim0_lim, _tim0_u1; +/*0x3c10*/ u32 tim1_cnt, _tim1_u0; +/*0x3c18*/ u32 tim1_lim, _tim1_u1; + + u64 __pad12[0x7c]; + + /* DMA Scoreboard Diagnostic Registers */ +/*0x4000*/ u64 dscore_reg0; /* DMA Scoreboard Diag Reg 0 */ +/*0x4008*/ u64 dscore_reg1; /* DMA Scoreboard Diag Reg 1 */ + + u64 __pad13[0x7e]; + + /* SBUS IOMMU Diagnostic Registers */ +/*0x4400*/ u64 sbus_vdiag; /* SBUS VADDR Diagnostic Register */ +/*0x4408*/ u64 sbus_tcompare; /* SBUS IOMMU TLB Tag Compare */ + + u64 __pad14[0x1e]; + + /* More IOMMU diagnostic things */ +/*0x4500*/ u64 iommu_lru[16]; /* IOMMU LRU Queue Diagnostic Access */ +/*0x4580*/ u64 iommu_tag[16]; /* IOMMU TLB Tag Diagnostic Access */ +/*0x4600*/ u64 iommu_data[32]; /* IOMMU TLB Data RAM Diagnostic Access */ + + /* Interrupt State Diagnostics */ +/*0x4800*/ u64 sbus_istate; +/*0x4808*/ u64 obio_istate; + + u64 __pad15[0xfe]; + + /* Streaming Buffer Diagnostic Area */ +/*0x5000*/ u64 sbuf_data[128]; /* StrBuffer Data Ram Diagnostic */ +/*0x5400*/ u64 sbuf_errs[128]; /* StrBuffer Error Status Diagnostics */ +/*0x5800*/ u64 sbuf_ptag[16]; /* StrBuffer Page Tag Diagnostics */ +/*0x5880*/ u64 _unusedXXX[16]; +/*0x5900*/ u64 sbuf_ltag[16]; /* StrBuffer Line Tag Diagnostics */ +}; + +/* SYSIO UPA Port ID */ +#define SYSIO_UPPID_FESC 0xff00000000000000 /* FCode escape, 0xfc */ +#define SYSIO_UPPID_RESV1 0x00fffff800000000 /* Reserved */ +#define SYSIO_UPPID_ENV 0x0000000400000000 /* Cannot generate ECC */ +#define SYSIO_UPPID_ORD 0x0000000200000000 /* One Outstanding Read */ +#define SYSIO_UPPID_RESV2 0x0000000180000000 /* Reserved */ +#define SYSIO_UPPID_PDQ 0x000000007e000000 /* Data Queue size */ +#define SYSIO_UPPID_PRQ 0x0000000001e00000 /* Request Queue size */ +#define SYSIO_UPPID_UCAP 0x00000000001f0000 /* UPA Capabilities */ +#define SYSIO_UPPID_JEDEC 0x000000000000ffff /* JEDEC ID for SYSIO */ + +/* SYSIO UPA Configuration Register */ +#define SYSIO_UPCFG_RESV 0xffffffffffffff00 /* Reserved */ +#define SYSIO_UPCFG_SCIQ1 0x00000000000000f0 /* Unused, always zero */ +#define SYSIO_UPCFG_SCIQ2 0x000000000000000f /* Requests Queue size (0x2) */ + +/* SYSIO Control Register */ +#define SYSIO_CONTROL_IMPL 0xf000000000000000 /* Implementation of this SYSIO */ +#define SYSIO_CONTROL_VER 0x0f00000000000000 /* Version of this SYSIO */ +#define SYSIO_CONTROL_MID 0x00f8000000000000 /* UPA Module ID of SYSIO */ +#define SYSIO_CONTROL_IGN 0x0007c00000000000 /* Interrupt Group Number */ +#define SYSIO_CONTROL_RESV 0x00003ffffffffff0 /* Reserved */ +#define SYSIO_CONTROL_APCKEN 0x0000000000000008 /* Address Parity Check Enable */ +#define SYSIO_CONTROL_APERR 0x0000000000000004 /* Incoming System Addr Parerr */ +#define SYSIO_CONTROL_IAP 0x0000000000000002 /* Invert UPA Parity */ +#define SYSIO_CONTROL_MODE 0x0000000000000001 /* SYSIO clock mode */ + +/* SYSIO ECC Control Register */ +#define SYSIO_ECNTRL_ECCEN 0x8000000000000000 /* Enable ECC Checking */ +#define SYSIO_ECNTRL_UEEN 0x4000000000000000 /* Enable UE Interrupts */ +#define SYSIO_ECNTRL_CEEN 0x2000000000000000 /* Enable CE Interrupts */ + +/* Uncorrectable Error AFSR, AFAR holds low 40bits of faulting physical address. */ +#define SYSIO_UEAFSR_PPIO 0x8000000000000000 /* Primary PIO is cause */ +#define SYSIO_UEAFSR_PDRD 0x4000000000000000 /* Primary DVMA read is cause */ +#define SYSIO_UEAFSR_PDWR 0x2000000000000000 /* Primary DVMA write is cause */ +#define SYSIO_UEAFSR_SPIO 0x1000000000000000 /* Secondary PIO is cause */ +#define SYSIO_UEAFSR_SDRD 0x0800000000000000 /* Secondary DVMA read is cause */ +#define SYSIO_UEAFSR_SDWR 0x0400000000000000 /* Secondary DVMA write is cause*/ +#define SYSIO_UEAFSR_RESV1 0x03ff000000000000 /* Reserved */ +#define SYSIO_UEAFSR_DOFF 0x0000e00000000000 /* Doubleword Offset */ +#define SYSIO_UEAFSR_SIZE 0x00001c0000000000 /* Bad transfer size is 2**SIZE */ +#define SYSIO_UEAFSR_MID 0x000003e000000000 /* UPA MID causing the fault */ +#define SYSIO_UEAFSR_RESV2 0x0000001fffffffff /* Reserved */ + +/* Correctable Error AFSR, AFAR holds low 40bits of faulting physical address. */ +#define SYSIO_CEAFSR_PPIO 0x8000000000000000 /* Primary PIO is cause */ +#define SYSIO_CEAFSR_PDRD 0x4000000000000000 /* Primary DVMA read is cause */ +#define SYSIO_CEAFSR_PDWR 0x2000000000000000 /* Primary DVMA write is cause */ +#define SYSIO_CEAFSR_SPIO 0x1000000000000000 /* Secondary PIO is cause */ +#define SYSIO_CEAFSR_SDRD 0x0800000000000000 /* Secondary DVMA read is cause */ +#define SYSIO_CEAFSR_SDWR 0x0400000000000000 /* Secondary DVMA write is cause*/ +#define SYSIO_CEAFSR_RESV1 0x0300000000000000 /* Reserved */ +#define SYSIO_CEAFSR_ESYND 0x00ff000000000000 /* Syndrome Bits */ +#define SYSIO_CEAFSR_DOFF 0x0000e00000000000 /* Double Offset */ +#define SYSIO_CEAFSR_SIZE 0x00001c0000000000 /* Bad transfer size is 2**SIZE */ +#define SYSIO_CEAFSR_MID 0x000003e000000000 /* UPA MID causing the fault */ +#define SYSIO_CEAFSR_RESV2 0x0000001fffffffff /* Reserved */ + +/* DMA Scoreboard Diagnostic Register(s) */ +#define SYSIO_DSCORE_VALID 0x0040000000000000 /* Entry is valid */ +#define SYSIO_DSCORE_C 0x0020000000000000 /* Transaction cacheable */ +#define SYSIO_DSCORE_READ 0x0010000000000000 /* Transaction was a read */ +#define SYSIO_DSCORE_TAG 0x000f000000000000 /* Transaction ID */ +#define SYSIO_DSCORE_ADDR 0x0000ffffffffff80 /* Transaction PADDR */ +#define SYSIO_DSCORE_SIZE 0x0000000000000030 /* Transaction size */ +#define SYSIO_DSCORE_SRC 0x000000000000000f /* Transaction source */ + +/* SYSIO SBUS Control Register */ +#define SYSIO_SBCNTRL_IMPL 0xf000000000000000 /* Implementation */ +#define SYSIO_SBCNTRL_REV 0x0f00000000000000 /* Revision */ +#define SYSIO_SBCNTRL_RESV1 0x00c0000000000000 /* Reserved */ +#define SYSIO_SBCNTRL_DPERR 0x003f000000000000 /* DMA Write Parity Error */ +#define SYSIO_SBCNTRL_RESV2 0x0000800000000000 /* Reserved */ +#define SYSIO_SBCNTRL_PPERR 0x00007f0000000000 /* PIO Load Parity Error */ +#define SYSIO_SBCNTRL_RESV 0x000000fffffffc00 /* Reserved */ +#define SYSIO_SBCNTRL_WEN 0x0000000000000200 /* Power Mgmt Wake Enable */ +#define SYSIO_SBCNTRL_EEN 0x0000000000000100 /* SBUS Error Interrupt Enable */ +#define SYSIO_SBCNTRL_RESV3 0x00000000000000c0 /* Reserved */ +#define SYSIO_SBCNTRL_AEN 0x000000000000003f /* SBUS DVMA Arbitration Enable */ + +/* SYSIO SBUS AFSR, AFAR holds low 40 bits of physical address causing the fault. */ +#define SYSIO_SBAFSR_PLE 0x8000000000000000 /* Primary Late PIO Error */ +#define SYSIO_SBAFSR_PTO 0x4000000000000000 /* Primary SBUS Timeout */ +#define SYSIO_SBAFSR_PBERR 0x2000000000000000 /* Primary SBUS Error ACK */ +#define SYSIO_SBAFSR_SLE 0x1000000000000000 /* Secondary Late PIO Error */ +#define SYSIO_SBAFSR_STO 0x0800000000000000 /* Secondary SBUS Timeout */ +#define SYSIO_SBAFSR_SBERR 0x0400000000000000 /* Secondary SBUS Error ACK */ +#define SYSIO_SBAFSR_RESV1 0x03ff000000000000 /* Reserved */ +#define SYSIO_SBAFSR_RD 0x0000800000000000 /* Primary was late PIO read */ +#define SYSIO_SBAFSR_RESV2 0x0000600000000000 /* Reserved */ +#define SYSIO_SBAFSR_SIZE 0x00001c0000000000 /* Size of transfer */ +#define SYSIO_SBAFSR_MID 0x000003e000000000 /* MID causing the error */ +#define SYSIO_SBAFSR_RESV3 0x0000001fffffffff /* Reserved */ + +/* SYSIO SBUS Slot Configuration Register */ +#define SYSIO_SBSCFG_RESV1 0xfffffffff8000000 /* Reserved */ +#define SYSIO_SBSCFG_SADDR 0x0000000007ff0000 /* Segment Address (PA[40:30]) */ +#define SYSIO_SBSCFG_CP 0x0000000000008000 /* Bypasses are cacheable */ +#define SYSIO_SBSCFG_ETM 0x0000000000004000 /* Ext Transfer Mode supported */ +#define SYSIO_SBSCFG_PE 0x0000000000002000 /* SBUS Parity Checking Enable */ +#define SYSIO_SBSCFG_RESV2 0x0000000000001fe0 /* Reserved */ +#define SYSIO_SBSCFG_BA64 0x0000000000000010 /* 64-byte bursts supported */ +#define SYSIO_SBSCFG_BA32 0x0000000000000008 /* 32-byte bursts supported */ +#define SYSIO_SBSCFG_BA16 0x0000000000000004 /* 16-byte bursts supported */ +#define SYSIO_SBSCFG_BA8 0x0000000000000002 /* 8-byte bursts supported */ +#define SYSIO_SBSCFG_BY 0x0000000000000001 /* IOMMU Bypass Enable */ + +/* IOMMU things defined fully in asm-sparc64/iommu.h */ + +/* Streaming Buffer Control Register */ +#define SYSIO_SBUFCTRL_IMPL 0xf000000000000000 /* Implementation */ +#define SYSIO_SBUFCTRL_REV 0x0f00000000000000 /* Revision */ +#define SYSIO_SBUFCTRL_DE 0x0000000000000002 /* Diag Mode Enable */ +#define SYSIO_SBUFCTRL_SB_EN 0x0000000000000001 /* Streaming Buffer Enable */ + +/* Streaming Buffer Page Invalidate/Flush Register */ +#define SYSIO_SBUFFLUSH_ADDR 0x00000000ffffe000 /* DVMA Page to be flushed */ +#define SYSIO_SBUFFLUSH_RESV 0x0000000000001fff /* Ignored bits */ + +/* Streaming Buffer Flush Synchronization Register */ +#define SYSIO_SBUFSYNC_ADDR 0x000001fffffffffc /* Physical address to update */ +#define SYSIO_SBUFSYNC_RESV 0x0000000000000003 /* Ignored bits */ + +/* SYSIO Interrupt mapping register(s). */ +#define SYSIO_IMAP_VALID 0x80000000 /* This enables delivery. */ +#define SYSIO_IMAP_TID 0x7c000000 /* Target ID (MID to send it to) */ +#define SYSIO_IMAP_RESV 0x03fff800 /* Reserved. */ +#define SYSIO_IMAP_IGN 0x000007c0 /* Interrupt Group Number. */ +#define SYSIO_IMAP_INO 0x0000003f /* Interrupt Number Offset. */ +#define SYSIO_IMAP_INR 0x000007ff /* Interrupt # (Gfx/UPA_slave only)*/ + +/* SYSIO Interrupt clear pseudo register(s). */ +#define SYSIO_ICLR_IDLE 0x00000000 /* Transition to idle state. */ +#define SYSIO_ICLR_TRANSMIT 0x00000001 /* Transition to transmit state. */ +#define SYSIO_ICLR_RESV 0x00000002 /* Reserved. */ +#define SYSIO_ICLR_PENDING 0x00000003 /* Transition to pending state. */ + +/* SYSIO Interrupt Retry Timer register. */ +#define SYSIO_IRETRY_LIMIT 0x000000ff /* The retry interval. */ + +/* SYSIO Interrupt State registers. XXX fields to be documented later */ + +/* SYSIO Counter register. XXX fields to be documented later */ + +/* SYSIO Limit register. XXX fields to be documented later */ + +/* SYSIO Performance Monitor Control register. XXX fields to be documented later */ + +/* SYSIO Performance Monitor Counter register. XXX fields to be documented later */ + +#endif /* !(__SPARC64_SYSIO_H) */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h --- v2.1.33/linux/include/asm-sparc64/system.h Thu Mar 27 14:40:09 1997 +++ linux/include/asm-sparc64/system.h Fri Apr 11 10:47:40 1997 @@ -1,15 +1,13 @@ -/* $Id: system.h,v 1.7 1997/03/18 18:02:41 jj Exp $ */ +/* $Id: system.h,v 1.15 1997/04/10 23:32:49 davem Exp $ */ #ifndef __SPARC64_SYSTEM_H #define __SPARC64_SYSTEM_H #include #include +#include #define NCPUS 4 /* No SMP yet */ -#define EMPTY_PGT (&empty_bad_page) -#define EMPTY_PGE (&empty_bad_page_table) - #ifndef __ASSEMBLY__ /* * Sparc (general) CPU types @@ -29,17 +27,18 @@ extern unsigned long empty_bad_page; -extern unsigned long empty_bad_page_table; +extern unsigned long empty_bad_pmd_table; +extern unsigned long empty_bad_pte_table; extern unsigned long empty_zero_page; #endif #define setipl(__new_ipl) \ __asm__ __volatile__("wrpr %0, %%pil" : : "r" (__new_ipl) : "memory") -#define cli() \ +#define __cli() \ __asm__ __volatile__("wrpr 15, %%pil" : : : "memory") -#define sti() \ +#define __sti() \ __asm__ __volatile__("wrpr 0, %%pil" : : : "memory") #define getipl() \ @@ -64,9 +63,19 @@ retval; \ }) -#define save_flags(flags) ((flags) = getipl()) -#define save_and_cli(flags) ((flags) = read_pil_and_cli()) -#define restore_flags(flags) setipl((flags)) +#define __save_flags(flags) ((flags) = getipl()) +#define __save_and_cli(flags) ((flags) = read_pil_and_cli()) +#define __restore_flags(flags) setipl((flags)) + +#ifndef __SMP__ +#define cli() __cli() +#define sti() __sti() +#define save_flags(x) __save_flags(x) +#define restore_flags(x) __restore_flags(x) +#define save_and_cli(x) __save_and_cli(x) +#else +#error SMP not supported on sparc64 +#endif #define mb() __asm__ __volatile__ ("stbar" : : : "memory") @@ -93,15 +102,81 @@ bne,pn %%xcc, 1b restore %%g0, %%g0, %%g0 " : : "i" (-REGWIN_SZ) - : "g1", "g2"); + : "g1", "g2", "cc"); } +#define flush_user_windows flushw_user + +#ifdef __SMP__ +#error SMP not supported on sparc64 +#else +#if 0 +#define SWITCH_DO_LAZY_FPU(next) \ + if(last_task_used_math != (next)) \ + (next)->tss.kregs->tstate&=~TSTATE_PEF +#else +/* XXX FIX ME BIG TIME XXX -DaveM */ +#define SWITCH_DO_LAZY_FPU(next) do { } while(0) +#endif +#endif + + /* See what happens when you design the chip correctly? + * NOTE NOTE NOTE this is extremely non-trivial what I + * am doing here. GCC needs only two registers to stuff + * things into ('next' and ¤t_set[cpu]) So I "claim" + * that I do not clobber them, when in fact I do. Please, + * when modifying this code inspect output of sched.s very + * carefully to make sure things still work. -DaveM + */ +#define switch_to(prev, next) \ +do { \ + __label__ switch_continue; \ + register unsigned long task_pc asm("o7"); \ + SWITCH_DO_LAZY_FPU(next); \ + task_pc = ((unsigned long) &&switch_continue) - 0x8; \ + __asm__ __volatile__( \ + "flushw\n\t" \ + "stx %%i6, [%%sp + 2047 + 0x70]\n\t" \ + "stx %%i7, [%%sp + 2047 + 0x78]\n\t" \ + "stx %%o6, [%%g6 + %3]\n\t" \ + "rdpr %%wstate, %%o5\n\t" \ + "stx %%o7, [%%g6 + %4]\n\t" \ + "mov %6, %%o4\n\t" \ + "stx %%o5, [%%g6 + %2]\n\t" \ + "st %%o4, [%%g6 + %7]\n\t" \ + "rdpr %%cwp, %%o5\n\t" \ + "stx %%o5, [%%g6 + %8]\n\t" \ + "mov %1, %%g6\n\t" \ + "stx %%g6, [%0]\n\t" \ + "ldx [%%g6 + %8], %%g1\n\t" \ + "wrpr %%g1, %%cwp\n\t" \ + "ldx [%%g6 + %2], %%o5\n\t" \ + "ldx [%%g6 + %3], %%o6\n\t" \ + "ldx [%%g6 + %4], %%o7\n\t" \ + "wrpr %%o5, 0x0, %%wstate\n\t" \ + "ldx [%%sp + 2047 + 0x70], %%i6\n\t" \ + "jmpl %%o7 + 0x8, %%g0\n\t" \ + " ldx [%%sp + 2047 + 0x78], %%i7\n\t" \ + : /* No outputs */ \ + : "r" (&(current_set[smp_processor_id()])), "r" (next), \ + "i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)), \ + "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)), \ + "i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpc)), \ + "r" (task_pc), "i" (255), \ + "i" ((const unsigned long)(&((struct task_struct *)0)->processor)), \ + "i" ((const unsigned long)(&((struct task_struct *)0)->tss.cwp)) \ + : "cc", "g1", "g2", "g3", "g5", "g7", \ + "l2", "l3", "l4", "l5", "l6", "l7", \ + "i0", "i1", "i2", "i3", "i4", "i5", \ + "o0", "o1", "o2", "o3", "o4", "o5"); \ +switch_continue: } while(0) + /* Unlike the hybrid v7/v8 kernel, we can assume swap exists under V9. */ extern __inline__ unsigned long xchg_u32(__volatile__ unsigned int *m, unsigned int val) { - __asm__ __volatile__("swap [%1], %0" + __asm__ __volatile__("swap [%2], %0" : "=&r" (val) - : "r" (m), "0" (val)); + : "0" (val), "r" (m)); return val; } @@ -111,14 +186,15 @@ { unsigned long temp; __asm__ __volatile__(" - ldx [%2], %1 + ldx [%3], %1 1: - casx [%2], %1, %0 + casx [%3], %1, %0 cmp %1, %0 bne,a,pn %%xcc, 1b - ldx [%2], %1 + ldx [%3], %1 " : "=&r" (val), "=&r" (temp) - : "r" (m), "0" (val)); + : "0" (val), "r" (m) + : "cc"); return val; } diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/termbits.h linux/include/asm-sparc64/termbits.h --- v2.1.33/linux/include/asm-sparc64/termbits.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/termbits.h Fri Apr 11 10:47:40 1997 @@ -117,43 +117,40 @@ #define WRAP 0x00020000 /* SUNOS specific */ /* c_cflag bit meaning */ -#define CBAUD 0x0000000f -#define B0 0x00000000 /* hang up */ -#define B50 0x00000001 -#define B75 0x00000002 -#define B110 0x00000003 -#define B134 0x00000004 -#define B150 0x00000005 -#define B200 0x00000006 -#define B300 0x00000007 -#define B600 0x00000008 -#define B1200 0x00000009 -#define B1800 0x0000000a -#define B2400 0x0000000b -#define B4800 0x0000000c -#define B9600 0x0000000d -#define B19200 0x0000000e -#define B38400 0x0000000f -#define EXTA B19200 -#define EXTB B38400 -#define CSIZE 0x00000030 -#define CS5 0x00000000 -#define CS6 0x00000010 -#define CS7 0x00000020 -#define CS8 0x00000030 -#define CSTOPB 0x00000040 -#define CREAD 0x00000080 -#define PARENB 0x00000100 -#define PARODD 0x00000200 -#define HUPCL 0x00000400 -#define CLOCAL 0x00000800 -/* We'll never see these speeds with the Zilogs' but for completeness... */ -#define CBAUDEX 0x00010000 -#define B57600 0x00010001 -#define B115200 0x00010002 -#define B230400 0x00010003 -#define B460800 0x00010004 -#define CIBAUD 0x000f0000 /* input baud rate (not used) */ +#define CBAUD 0x0000100f +#define B0 0x00000000 /* hang up */ +#define B50 0x00000001 +#define B75 0x00000002 +#define B110 0x00000003 +#define B134 0x00000004 +#define B150 0x00000005 +#define B200 0x00000006 +#define B300 0x00000007 +#define B600 0x00000008 +#define B1200 0x00000009 +#define B1800 0x0000000a +#define B2400 0x0000000b +#define B4800 0x0000000c +#define B9600 0x0000000d +#define B19200 0x0000000e +#define B38400 0x0000000f +#define EXTA B19200 +#define EXTB B38400 +#define CSIZE 0x00000030 +#define CS5 0x00000000 +#define CS6 0x00000010 +#define CS7 0x00000020 +#define CS8 0x00000030 +#define CSTOPB 0x00000040 +#define CREAD 0x00000080 +#define PARENB 0x00000100 +#define PARODD 0x00000200 +#define HUPCL 0x00000400 +#define CLOCAL 0x00000800 +#define CBAUDEX 0x00001000 +#define B57600 0x00001001 +#define CIBAUD 0x100f0000 /* input baud rate (not used) */ +#define CMSPAR 0x40000000 /* mark or space (stick) parity */ #define CRTSCTS 0x80000000 /* flow control */ /* c_lflag bits */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/uaccess.h linux/include/asm-sparc64/uaccess.h --- v2.1.33/linux/include/asm-sparc64/uaccess.h Thu Mar 27 14:40:10 1997 +++ linux/include/asm-sparc64/uaccess.h Fri Apr 11 10:47:40 1997 @@ -1,4 +1,4 @@ -/* $Id: uaccess.h,v 1.8 1997/03/14 21:05:33 jj Exp $ */ +/* $Id: uaccess.h,v 1.12 1997/04/10 23:32:50 davem Exp $ */ #ifndef _ASM_UACCESS_H #define _ASM_UACCESS_H @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include #endif #ifndef __ASSEMBLY__ @@ -27,21 +30,27 @@ #define get_fs() (current->tss.current_ds) #define get_ds() (KERNEL_DS) -#define set_fs(val) ((current->tss.current_ds) = (val)) +extern __inline__ void set_fs(int val) +{ + if (val != current->tss.current_ds) { + if (val == KERNEL_DS) { + flushw_user (); + spitfire_set_secondary_context (0); + } else { + spitfire_set_secondary_context (current->mm->context); + } + current->tss.current_ds = val; + } +} -/* We have there a nice not-mapped page at page_offset - PAGE_SIZE, so that this test - * can be fairly lightweight. - * No one can read/write anything from userland in the kernel space by setting - * large size and address near to page_offset - a fault will break his intentions. - */ -#define __user_ok(addr,size) ((addr) < PAGE_OFFSET) +#define __user_ok(addr,size) 1 #define __kernel_ok (get_fs() == KERNEL_DS) -#define __access_ok(addr,size) (__user_ok(((unsigned long)(addr)) & get_fs(),(size))) -#define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size)) +#define __access_ok(addr,size) 1 +#define access_ok(type,addr,size) 1 extern inline int verify_area(int type, const void * addr, unsigned long size) { - return access_ok(type,addr,size)?0:-EFAULT; + return 0; } /* @@ -87,55 +96,28 @@ */ #define put_user(x,ptr) ({ \ unsigned long __pu_addr = (unsigned long)(ptr); \ -__put_user_check((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr))); }) +__put_user_nocheck((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr))); }) #define put_user_ret(x,ptr,retval) ({ \ unsigned long __pu_addr = (unsigned long)(ptr); \ -__put_user_check_ret((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr)),retval); }) +__put_user_nocheck_ret((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr)),retval); }) #define get_user(x,ptr) ({ \ unsigned long __gu_addr = (unsigned long)(ptr); \ -__get_user_check((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr))); }) +__get_user_nocheck((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr))); }) #define get_user_ret(x,ptr,retval) ({ \ unsigned long __gu_addr = (unsigned long)(ptr); \ -__get_user_check_ret((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr)),retval); }) +__get_user_nocheck_ret((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr)),retval); }) -/* - * The "__xxx" versions do not do address space checking, useful when - * doing multiple accesses to the same area (the user has to do the - * checks by hand with "access_ok()") - */ -#define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr))) -#define __put_user_ret(x,ptr,retval) __put_user_nocheck_ret((x),(ptr),sizeof(*(ptr)),retval) -#define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr)),__typeof__(*(ptr))) -#define __get_user_ret(x,ptr,retval) __get_user_nocheck_ret((x),(ptr),sizeof(*(ptr)),__typeof__(*(ptr)),retval) +#define __put_user(x,ptr) put_user(x,ptr) +#define __put_user_ret(x,ptr,retval) put_user_ret(x,ptr,retval) +#define __get_user(x,ptr) get_user(x,ptr) +#define __get_user_ret(x,ptr,retval) get_user_ret(x,ptr,retval) struct __large_struct { unsigned long buf[100]; }; #define __m(x) ((struct __large_struct *)(x)) -#define __put_user_check(data,addr,size) ({ \ -register int __pu_ret; \ -if (__access_ok(addr,size)) { \ -switch (size) { \ -case 1: __put_user_asm(data,b,addr,__pu_ret); break; \ -case 2: __put_user_asm(data,h,addr,__pu_ret); break; \ -case 4: __put_user_asm(data,w,addr,__pu_ret); break; \ -case 8: __put_user_asm(data,x,addr,__pu_ret); break; \ -default: __pu_ret = __put_user_bad(); break; \ -} } else { __pu_ret = -EFAULT; } __pu_ret; }) - -#define __put_user_check_ret(data,addr,size,retval) ({ \ -register int __foo __asm__ ("l1"); \ -if (__access_ok(addr,size)) { \ -switch (size) { \ -case 1: __put_user_asm_ret(data,b,addr,retval,__foo); break; \ -case 2: __put_user_asm_ret(data,h,addr,retval,__foo); break; \ -case 4: __put_user_asm_ret(data,w,addr,retval,__foo); break; \ -case 8: __put_user_asm_ret(data,x,addr,retval,__foo); break; \ -default: if (__put_user_bad()) return retval; break; \ -} } else return retval; }) - #define __put_user_nocheck(data,addr,size) ({ \ register int __pu_ret; \ switch (size) { \ @@ -159,7 +141,7 @@ #define __put_user_asm(x,size,addr,ret) \ __asm__ __volatile__( \ "/* Put user asm, inline. */\n" \ -"1:\t" "st"#size " %1, [%2]\n\t" \ +"1:\t" "st"#size "a %1, [%2] %4\n\t" \ "clr %0\n" \ "2:\n\n\t" \ ".section .fixup,#alloc,#execinstr\n\t" \ @@ -172,23 +154,23 @@ ".align 4\n\t" \ ".word 1b, 3b\n\t" \ ".previous\n\n\t" \ - : "=&r" (ret) : "r" (x), "r" (__m(addr)), \ - "i" (-EFAULT)) + : "=r" (ret) : "r" (x), "r" (__m(addr)), \ + "i" (-EFAULT), "i" (ASI_S)) #define __put_user_asm_ret(x,size,addr,ret,foo) \ if (__builtin_constant_p(ret) && ret == -EFAULT) \ __asm__ __volatile__( \ "/* Put user asm ret, inline. */\n" \ -"1:\t" "st"#size " %1, [%2]\n\n\t" \ +"1:\t" "st"#size "a %1, [%2] %3\n\n\t" \ ".section __ex_table,#alloc\n\t" \ ".align 4\n\t" \ ".word 1b, __ret_efault\n\n\t" \ ".previous\n\n\t" \ - : "=r" (foo) : "r" (x), "r" (__m(addr))); \ + : "=r" (foo) : "r" (x), "r" (__m(addr)), "i" (ASI_S)); \ else \ __asm__ __volatile( \ "/* Put user asm ret, inline. */\n" \ -"1:\t" "st"#size " %1, [%2]\n\n\t" \ +"1:\t" "st"#size "a %1, [%2] %4\n\n\t" \ ".section .fixup,#alloc,#execinstr\n\t" \ ".align 4\n" \ "3:\n\t" \ @@ -199,33 +181,11 @@ ".align 4\n\t" \ ".word 1b, 3b\n\n\t" \ ".previous\n\n\t" \ - : "=r" (foo) : "r" (x), "r" (__m(addr)), "i" (ret)) + : "=r" (foo) : "r" (x), "r" (__m(addr)), \ + "i" (ret), "i" (ASI_S)) extern int __put_user_bad(void); -#define __get_user_check(data,addr,size,type) ({ \ -register int __gu_ret; \ -register unsigned long __gu_val; \ -if (__access_ok(addr,size)) { \ -switch (size) { \ -case 1: __get_user_asm(__gu_val,ub,addr,__gu_ret); break; \ -case 2: __get_user_asm(__gu_val,uh,addr,__gu_ret); break; \ -case 4: __get_user_asm(__gu_val,uw,addr,__gu_ret); break; \ -case 8: __get_user_asm(__gu_val,x,addr,__gu_ret); break; \ -default: __gu_val = 0; __gu_ret = __get_user_bad(); break; \ -} } else { __gu_val = 0; __gu_ret = -EFAULT; } data = (type) __gu_val; __gu_ret; }) - -#define __get_user_check_ret(data,addr,size,type,retval) ({ \ -register unsigned long __gu_val __asm__ ("l1"); \ -if (__access_ok(addr,size)) { \ -switch (size) { \ -case 1: __get_user_asm_ret(__gu_val,ub,addr,retval); break; \ -case 2: __get_user_asm_ret(__gu_val,uh,addr,retval); break; \ -case 4: __get_user_asm_ret(__gu_val,uw,addr,retval); break; \ -case 8: __get_user_asm_ret(__gu_val,x,addr,retval); break; \ -default: if (__get_user_bad()) return retval; \ -} data = (type) __gu_val; } else return retval; }) - #define __get_user_nocheck(data,addr,size,type) ({ \ register int __gu_ret; \ register unsigned long __gu_val; \ @@ -250,7 +210,7 @@ #define __get_user_asm(x,size,addr,ret) \ __asm__ __volatile__( \ "/* Get user asm, inline. */\n" \ -"1:\t" "ld"#size " [%2], %1\n\t" \ +"1:\t" "ld"#size "a [%2] %4, %1\n\t" \ "clr %0\n" \ "2:\n\n\t" \ ".section .fixup,#alloc,#execinstr\n\t" \ @@ -264,80 +224,63 @@ ".align 4\n\t" \ ".word 1b, 3b\n\n\t" \ ".previous\n\t" \ - : "=&r" (ret), "=&r" (x) : "r" (__m(addr)), \ - "i" (-EFAULT)) + : "=r" (ret), "=r" (x) : "r" (__m(addr)), \ + "i" (-EFAULT), "i" (ASI_S)) #define __get_user_asm_ret(x,size,addr,retval) \ if (__builtin_constant_p(retval) && retval == -EFAULT) \ __asm__ __volatile__( \ "/* Get user asm ret, inline. */\n" \ -"1:\t" "ld"#size " [%1], %0\n\n\t" \ +"1:\t" "ld"#size "a [%1] %2, %0\n\n\t" \ ".section __ex_table,#alloc\n\t" \ ".align 4\n\t" \ ".word 1b,__ret_efault\n\n\t" \ ".previous\n\t" \ - : "=&r" (x) : "r" (__m(addr))); \ + : "=r" (x) : "r" (__m(addr)), "i" (ASI_S)); \ else \ __asm__ __volatile__( \ "/* Get user asm ret, inline. */\n" \ -"1:\t" "ld"#size " [%1], %0\n\n\t" \ +"1:\t" "ld"#size "a [%1] %2, %0\n\n\t" \ ".section .fixup,#alloc,#execinstr\n\t" \ ".align 4\n" \ "3:\n\t" \ "ret\n\t" \ - " restore %%g0, %2, %%o0\n\n\t" \ + " restore %%g0, %3, %%o0\n\n\t" \ ".previous\n\t" \ ".section __ex_table,#alloc\n\t" \ ".align 4\n\t" \ ".word 1b, 3b\n\n\t" \ ".previous\n\t" \ - : "=&r" (x) : "r" (__m(addr)), "i" (retval)) + : "=r" (x) : "r" (__m(addr)), "i" (retval), "i" (ASI_S)) extern int __get_user_bad(void); -extern __kernel_size_t __copy_user(void *to, void *from, __kernel_size_t size); +extern __kernel_size_t __copy_to_user(void *to, void *from, __kernel_size_t size); +extern __kernel_size_t __copy_from_user(void *to, void *from, __kernel_size_t size); -#define copy_to_user(to,from,n) ({ \ -void *__copy_to = (void *) (to); \ -__kernel_size_t __copy_size = (__kernel_size_t) (n); \ -__kernel_size_t __copy_res; \ -if(__copy_size && __access_ok(__copy_to, __copy_size)) { \ -__copy_res = __copy_user(__copy_to, (void *) (from), __copy_size); \ -} else __copy_res = __copy_size; \ -__copy_res; }) +#define copy_to_user(to,from,n) \ + __copy_to_user((void *)(to), \ + (void *) (from), (__kernel_size_t)(n)) #define copy_to_user_ret(to,from,n,retval) ({ \ if (copy_to_user(to,from,n)) \ return retval; \ }) -#define __copy_to_user(to,from,n) \ - __copy_user((void *)(to), \ - (void *)(from), n) - #define __copy_to_user_ret(to,from,n,retval) ({ \ if (__copy_to_user(to,from,n)) \ return retval; \ }) -#define copy_from_user(to,from,n) ({ \ -void *__copy_from = (void *) (from); \ -__kernel_size_t __copy_size = (__kernel_size_t) (n); \ -__kernel_size_t __copy_res; \ -if(__copy_size && __access_ok(__copy_from, __copy_size)) { \ -__copy_res = __copy_user((void *) (to), __copy_from, __copy_size); \ -} else __copy_res = __copy_size; \ -__copy_res; }) +#define copy_from_user(to,from,n) \ + __copy_from_user((void *)(to), \ + (void *)(from), (__kernel_size_t)(n)) #define copy_from_user_ret(to,from,n,retval) ({ \ if (copy_from_user(to,from,n)) \ return retval; \ }) -#define __copy_from_user(to,from,n) \ - __copy_user((void *)(to), \ - (void *)(from), n) - #define __copy_from_user_ret(to,from,n,retval) ({ \ if (__copy_from_user(to,from,n)) \ return retval; \ @@ -352,23 +295,18 @@ .word 1f,3 .previous 1: + wr %%g0, %3, %%asi mov %2, %%o1 - call __bzero + call __bzero_noasi mov %1, %%o0 mov %%o0, %0 - " : "=r" (ret) : "r" (addr), "r" (size) : - "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7"); + " : "=r" (ret) : "r" (addr), "r" (size), "i" (ASI_S) : + "cc", "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7"); return ret; } -#define clear_user(addr,n) ({ \ -void *__clear_addr = (void *) (addr); \ -__kernel_size_t __clear_size = (__kernel_size_t) (n); \ -__kernel_size_t __clear_res; \ -if(__clear_size && __access_ok(__clear_addr, __clear_size)) { \ -__clear_res = __clear_user(__clear_addr, __clear_size); \ -} else __clear_res = __clear_size; \ -__clear_res; }) +#define clear_user(addr,n) \ + __clear_user((void *)(addr), (__kernel_size_t)(n)) #define clear_user_ret(addr,size,retval) ({ \ if (clear_user(addr,size)) \ @@ -377,23 +315,12 @@ extern int __strncpy_from_user(unsigned long dest, unsigned long src, int count); -#define strncpy_from_user(dest,src,count) ({ \ -unsigned long __sfu_src = (unsigned long) (src); \ -int __sfu_count = (int) (count); \ -long __sfu_res = -EFAULT; \ -if(__access_ok(__sfu_src, __sfu_count)) { \ -__sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \ -} __sfu_res; }) +#define strncpy_from_user(dest,src,count) \ + __strncpy_from_user((unsigned long)(dest), (unsigned long)(src), (int)(count)) extern int __strlen_user(const char *); -extern __inline__ int strlen_user(const char *str) -{ - if(!access_ok(VERIFY_READ, str, 0)) - return 0; - else - return __strlen_user(str); -} +#define strlen_user __strlen_user #endif /* __ASSEMBLY__ */ diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/unistd.h linux/include/asm-sparc64/unistd.h --- v2.1.33/linux/include/asm-sparc64/unistd.h Thu Mar 27 14:40:10 1997 +++ linux/include/asm-sparc64/unistd.h Fri Apr 11 10:47:40 1997 @@ -1,4 +1,4 @@ -/* $Id: unistd.h,v 1.2 1997/03/18 18:00:26 jj Exp $ */ +/* $Id: unistd.h,v 1.3 1997/04/10 23:32:51 davem Exp $ */ #ifndef _SPARC64_UNISTD_H #define _SPARC64_UNISTD_H @@ -283,7 +283,7 @@ "movcc %%xcc, %%o0, %0\n\t" \ : "=r" (__res)\ : "0" (__NR_##name) \ - : "g1", "o0"); \ + : "g1", "o0", "cc"); \ if (__res >= 0) \ return (type) __res; \ errno = -__res; \ @@ -301,7 +301,7 @@ "movcc %%xcc, %%o0, %0\n\t" \ : "=r" (__res), "=r" ((long)(arg1)) \ : "0" (__NR_##name),"1" ((long)(arg1)) \ - : "g1", "o0"); \ + : "g1", "o0", "cc"); \ if (__res >= 0) \ return (type) __res; \ errno = -__res; \ @@ -320,7 +320,7 @@ "movcc %%xcc, %%o0, %0\n\t" \ : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)) \ : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)) \ - : "g1", "o0", "o1"); \ + : "g1", "o0", "o1", "cc"); \ if (__res >= 0) \ return (type) __res; \ errno = -__res; \ @@ -342,7 +342,7 @@ "=r" ((long)(arg3)) \ : "0" (__NR_##name), "1" ((long)(arg1)), "2" ((long)(arg2)), \ "3" ((long)(arg3)) \ - : "g1", "o0", "o1", "o2"); \ + : "g1", "o0", "o1", "o2", "cc"); \ if (__res>=0) \ return (type) __res; \ errno = -__res; \ @@ -365,7 +365,7 @@ "=r" ((long)(arg3)), "=r" ((long)(arg4)) \ : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)), \ "3" ((long)(arg3)),"4" ((long)(arg4)) \ - : "g1", "o0", "o1", "o2", "o3"); \ + : "g1", "o0", "o1", "o2", "o3", "cc"); \ if (__res>=0) \ return (type) __res; \ errno = -__res; \ @@ -391,7 +391,7 @@ : "r" ((long)(arg1)),"r" ((long)(arg2)), \ "r" ((long)(arg3)),"r" ((long)(arg4)),"r" ((long)(arg5)), \ "i" (__NR_##name) \ - : "g1", "o0", "o1", "o2", "o3", "o4"); \ + : "g1", "o0", "o1", "o2", "o3", "o4", "cc"); \ if (__res>=0) \ return (type) __res; \ errno = -__res; \ @@ -461,7 +461,7 @@ "=r" (retval) : "i" (__NR_clone), "r" (flags | CLONE_VM), "i" (__NR_exit), "r" (fn), "r" (arg) : - "g1", "g2", "g3", "o0", "o1", "memory"); + "g1", "g2", "g3", "o0", "o1", "memory", "cc"); return retval; } diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/upa.h linux/include/asm-sparc64/upa.h --- v2.1.33/linux/include/asm-sparc64/upa.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/upa.h Fri Apr 11 10:47:40 1997 @@ -1,4 +1,4 @@ -/* $Id */ +/* $Id: upa.h,v 1.2 1997/04/04 00:50:30 davem Exp $ */ #ifndef _SPARC64_UPA_H #define _SPARC64_UPA_H diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/vaddrs.h linux/include/asm-sparc64/vaddrs.h --- v2.1.33/linux/include/asm-sparc64/vaddrs.h Thu Mar 27 14:40:10 1997 +++ linux/include/asm-sparc64/vaddrs.h Fri Apr 11 10:47:40 1997 @@ -1,8 +1,6 @@ -/* $Id: vaddrs.h,v 1.1 1997/03/18 18:03:43 jj Exp $ */ +/* $Id: vaddrs.h,v 1.6 1997/04/04 00:50:31 davem Exp $ */ #ifndef _SPARC64_VADDRS_H #define _SPARC64_VADDRS_H - -#include /* asm-sparc64/vaddrs.h: Here will be define the virtual addresses at * which important I/O addresses will be mapped. diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/winmacro.h linux/include/asm-sparc64/winmacro.h --- v2.1.33/linux/include/asm-sparc64/winmacro.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/winmacro.h Wed Dec 31 16:00:00 1969 @@ -1,66 +0,0 @@ -/* $Id: winmacro.h,v 1.1 1996/12/26 13:25:20 davem Exp $ - * winmacro.h: Window loading-unloading macros for Sparc/V9. - * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) - */ - -#ifndef _SPARC64_WINMACRO_H -#define _SPARC64_WINMACRO_H - -#define STORE_V9_WINDOW_GENERIC_ASI(store_insn, base, offset, the_asi) \ - store_insn %l0, [base + offset + RW_V9_L0] the_asi; \ - store_insn %l1, [base + offset + RW_V9_L1] the_asi; \ - store_insn %l2, [base + offset + RW_V9_L2] the_asi; \ - store_insn %l3, [base + offset + RW_V9_L3] the_asi; \ - store_insn %l4, [base + offset + RW_V9_L4] the_asi; \ - store_insn %l5, [base + offset + RW_V9_L5] the_asi; \ - store_insn %l6, [base + offset + RW_V9_L6] the_asi; \ - store_insn %l7, [base + offset + RW_V9_L7] the_asi; \ - store_insn %i0, [base + offset + RW_V9_I0] the_asi; \ - store_insn %i1, [base + offset + RW_V9_I1] the_asi; \ - store_insn %i2, [base + offset + RW_V9_I2] the_asi; \ - store_insn %i3, [base + offset + RW_V9_I3] the_asi; \ - store_insn %i4, [base + offset + RW_V9_I4] the_asi; \ - store_insn %i5, [base + offset + RW_V9_I5] the_asi; \ - store_insn %i6, [base + offset + RW_V9_I6] the_asi; \ - store_insn %i7, [base + offset + RW_V9_I7] the_asi; - -#define STORE_V9_WINDOW_KERNEL(base) \ - stx %l0, [base + RW_V9_L0]; \ - stx %l1, [base + RW_V9_L1]; \ - stx %l2, [base + RW_V9_L2]; \ - stx %l3, [base + RW_V9_L3]; \ - stx %l4, [base + RW_V9_L4]; \ - stx %l5, [base + RW_V9_L5]; \ - stx %l6, [base + RW_V9_L6]; \ - stx %l7, [base + RW_V9_L7]; \ - stx %i0, [base + RW_V9_I0]; \ - stx %i1, [base + RW_V9_I1]; \ - stx %i2, [base + RW_V9_I2]; \ - stx %i3, [base + RW_V9_I3]; \ - stx %i4, [base + RW_V9_I4]; \ - stx %i5, [base + RW_V9_I5]; \ - stx %i6, [base + RW_V9_I6]; \ - stx %i7, [base + RW_V9_I7]; - -#define LOAD_V9_WINDOW_KERNEL(base) \ - ldx [base + RW_V9_L0], %l0; \ - ldx [base + RW_V9_L1], %l1; \ - ldx [base + RW_V9_L2], %l2; \ - ldx [base + RW_V9_L3], %l3; \ - ldx [base + RW_V9_L4], %l4; \ - ldx [base + RW_V9_L5], %l5; \ - ldx [base + RW_V9_L6], %l6; \ - ldx [base + RW_V9_L7], %l7; \ - ldx [base + RW_V9_I0], %i0; \ - ldx [base + RW_V9_I1], %i1; \ - ldx [base + RW_V9_I2], %i2; \ - ldx [base + RW_V9_I3], %i3; \ - ldx [base + RW_V9_I4], %i4; \ - ldx [base + RW_V9_I5], %i5; \ - ldx [base + RW_V9_I6], %i6; \ - ldx [base + RW_V9_I7], %i7; - -#define STORE_V9_WINDOW_ASI_REG(base) \ - -#endif /* !(_SPARC64_WINMACRO_H) */ diff -u --recursive --new-file v2.1.33/linux/include/linux/atalk.h linux/include/linux/atalk.h --- v2.1.33/linux/include/linux/atalk.h Sun Jan 19 05:47:26 1997 +++ linux/include/linux/atalk.h Mon Apr 14 11:43:06 1997 @@ -72,11 +72,15 @@ #ifdef __KERNEL__ +#include + struct ddpehdr { - /* FIXME for bigendians */ - /*__u16 deh_pad:2,deh_hops:4,deh_len:10;*/ - __u16 deh_len:10,deh_hops:4,deh_pad:2; +#ifdef __LITTLE_ENDIAN_BITFIELD + __u16 deh_len:10, deh_hops:4, deh_pad:2; +#else + __u16 deh_pad:2, deh_hops:4, deh_len:10; +#endif __u16 deh_sum; __u16 deh_dnet; __u16 deh_snet; @@ -93,8 +97,11 @@ struct ddpshdr { - /* FIXME for bigendians */ +#ifdef __LITTLE_ENDIAN_BITFIELD __u16 dsh_len:10, dsh_pad:6; +#else + __u16 dsh_pad:6, dsh_len:10; +#endif __u8 dsh_dport; __u8 dsh_sport; /* And netatalk apps expect to stick the type in themselves */ diff -u --recursive --new-file v2.1.33/linux/include/linux/binfmts.h linux/include/linux/binfmts.h --- v2.1.33/linux/include/linux/binfmts.h Sun Jan 26 02:07:48 1997 +++ linux/include/linux/binfmts.h Fri Apr 11 10:47:40 1997 @@ -48,9 +48,11 @@ extern int open_inode(struct inode * inode, int mode); extern int init_elf_binfmt(void); +extern int init_elf32_binfmt(void); extern int init_aout_binfmt(void); extern int init_script_binfmt(void); extern int init_java_binfmt(void); +extern int init_em86_binfmt(void); extern int prepare_binprm(struct linux_binprm *); extern void remove_arg_zero(struct linux_binprm *); diff -u --recursive --new-file v2.1.33/linux/include/linux/cdrom.h linux/include/linux/cdrom.h --- v2.1.33/linux/include/linux/cdrom.h Sun Dec 29 01:18:04 1996 +++ linux/include/linux/cdrom.h Mon Apr 14 09:26:00 1997 @@ -368,7 +368,8 @@ u_char number_blocks_lo; u_char _r3; u_char block_length_hi; /* block length for blocks in this desc */ - u_short block_length; + u_char block_length_med; + u_char block_length_lo; }; /* diff -u --recursive --new-file v2.1.33/linux/include/linux/interrupt.h linux/include/linux/interrupt.h --- v2.1.33/linux/include/linux/interrupt.h Mon Apr 7 11:35:31 1997 +++ linux/include/linux/interrupt.h Mon Apr 14 11:42:12 1997 @@ -3,10 +3,8 @@ #define _LINUX_INTERRUPT_H #include - #include #include -#include struct irqaction { void (*handler)(int, void *, struct pt_regs *); @@ -17,7 +15,6 @@ struct irqaction *next; }; -extern atomic_t intr_count; extern volatile unsigned char bh_running; extern int bh_mask_count[32]; @@ -45,58 +42,8 @@ CM206_BH }; -extern inline void init_bh(int nr, void (*routine)(void)) -{ - bh_base[nr] = routine; - bh_mask_count[nr] = 0; - bh_mask |= 1 << nr; -} - -extern inline void mark_bh(int nr) -{ - set_bit(nr, &bh_active); -} - -/* - * These use a mask count to correctly handle - * nested disable/enable calls - */ -extern inline void disable_bh(int nr) -{ - bh_mask &= ~(1 << nr); - bh_mask_count[nr]++; -} - -extern inline void enable_bh(int nr) -{ - if (!--bh_mask_count[nr]) - bh_mask |= 1 << nr; -} - -/* - * start_bh_atomic/end_bh_atomic also nest - * naturally by using a counter - */ -extern inline void start_bh_atomic(void) -{ -#ifdef __SMP__ - atomic_inc(&intr_count); - synchronize_irq(); -#else - intr_count++; - barrier(); -#endif -} - -extern inline void end_bh_atomic(void) -{ -#ifdef __SMP__ - atomic_dec(&intr_count); -#else - barrier(); - intr_count--; -#endif -} +#include +#include /* * Autoprobing for irqs: diff -u --recursive --new-file v2.1.33/linux/include/linux/ioport.h linux/include/linux/ioport.h --- v2.1.33/linux/include/linux/ioport.h Thu Mar 27 14:40:10 1997 +++ linux/include/linux/ioport.h Fri Apr 11 10:47:40 1997 @@ -23,9 +23,9 @@ extern int get_ioport_list(char *); #ifdef __sparc__ -extern unsigned int occupy_region(unsigned long base, unsigned long end, - unsigned long num, unsigned int align, - const char *name); +extern unsigned long occupy_region(unsigned long base, unsigned long end, + unsigned long num, unsigned int align, + const char *name); #endif #define HAVE_AUTOIRQ diff -u --recursive --new-file v2.1.33/linux/include/linux/netdevice.h linux/include/linux/netdevice.h --- v2.1.33/linux/include/linux/netdevice.h Fri Apr 4 08:52:25 1997 +++ linux/include/linux/netdevice.h Mon Apr 14 11:43:06 1997 @@ -28,6 +28,8 @@ #include #include +#include + /* * For future expansion when we will have different priorities. */ @@ -86,7 +88,7 @@ struct hh_cache { struct hh_cache *hh_next; /* Next entry */ - int hh_refcnt; /* number of users */ + atomic_t hh_refcnt; /* number of users */ unsigned short hh_type; /* protocol identifier, f.e ETH_P_IP */ char hh_uptodate; /* hh_data is valid */ /* cached hardware header; allow for machine alignment needs. */ @@ -354,7 +356,7 @@ extern __inline__ void dev_lock_wait(void) { - while(dev_lockct) + while(atomic_read(&dev_lockct)) schedule(); } diff -u --recursive --new-file v2.1.33/linux/include/linux/nfs.h linux/include/linux/nfs.h --- v2.1.33/linux/include/linux/nfs.h Mon Apr 7 11:35:31 1997 +++ linux/include/linux/nfs.h Mon Apr 14 09:31:10 1997 @@ -84,6 +84,15 @@ #define NFSPROC_READDIR 16 #define NFSPROC_STATFS 17 +/* Mount support for NFSroot */ +#ifdef __KERNEL__ +#define NFS_MNT_PROGRAM 100005 +#define NFS_MNT_VERSION 1 +#define NFS_MNT_PORT 627 +#define NFS_MNTPROC_MNT 1 +#define NFS_MNTPROC_UMNT 3 +#endif + #if defined(__KERNEL__) || defined(NFS_NEED_KERNEL_TYPES) extern struct rpc_program nfs_program; @@ -123,9 +132,9 @@ struct nfs_entry { __u32 fileid; char * name; - unsigned int length; + unsigned int length:31, + eof:1; __u32 cookie; - __u32 eof; }; struct nfs_fsinfo { diff -u --recursive --new-file v2.1.33/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h --- v2.1.33/linux/include/linux/nfs_fs.h Mon Apr 7 11:35:31 1997 +++ linux/include/linux/nfs_fs.h Mon Apr 14 11:42:11 1997 @@ -190,6 +190,12 @@ extern int nfs_readpage_sync(struct inode *, struct page *); /* + * linux/fs/mount_clnt.c + * (Used only by nfsroot module) + */ +extern int nfs_mount(struct sockaddr_in *, char *, struct nfs_fh *); + +/* * inline functions */ static inline int @@ -232,6 +238,7 @@ #define NFSDBG_PROC 0x0010 #define NFSDBG_XDR 0x0020 #define NFSDBG_FILE 0x0040 +#define NFSDBG_ROOT 0x0080 #define NFSDBG_ALL 0xFFFF #ifdef __KERNEL__ diff -u --recursive --new-file v2.1.33/linux/include/linux/skbuff.h linux/include/linux/skbuff.h --- v2.1.33/linux/include/linux/skbuff.h Fri Apr 4 08:52:26 1997 +++ linux/include/linux/skbuff.h Mon Apr 14 11:42:12 1997 @@ -196,12 +196,12 @@ extern __inline__ int skb_cloned(struct sk_buff *skb) { - return (skb->data_skb->count != 1); + return (atomic_read(&skb->data_skb->count) != 1); } extern __inline__ int skb_shared(struct sk_buff *skb) { - return (skb->users != 1); + return (atomic_read(&skb->users) != 1); } /* diff -u --recursive --new-file v2.1.33/linux/include/linux/sunrpc/clnt.h linux/include/linux/sunrpc/clnt.h --- v2.1.33/linux/include/linux/sunrpc/clnt.h Mon Apr 7 11:35:32 1997 +++ linux/include/linux/sunrpc/clnt.h Mon Apr 14 11:44:27 1997 @@ -126,5 +126,12 @@ xprt_set_timeout(&clnt->cl_timeout, retr, incr); } +/* + * Helper function for NFSroot support + */ +#ifdef CONFIG_ROOT_NFS +int rpc_getport_external(struct sockaddr_in *, __u32, __u32, int); +#endif + #endif /* __KERNEL__ */ #endif /* _LINUX_SUNRPC_CLNT_H */ diff -u --recursive --new-file v2.1.33/linux/include/net/af_unix.h linux/include/net/af_unix.h --- v2.1.33/linux/include/net/af_unix.h Thu Dec 12 06:54:21 1996 +++ linux/include/net/af_unix.h Mon Apr 14 09:31:10 1997 @@ -16,7 +16,7 @@ struct unix_address { - int refcnt; + atomic_t refcnt; int len; unsigned hash; struct sockaddr_un name[0]; diff -u --recursive --new-file v2.1.33/linux/include/net/dst.h linux/include/net/dst.h --- v2.1.33/linux/include/net/dst.h Thu Mar 27 14:40:11 1997 +++ linux/include/net/dst.h Mon Apr 14 11:45:18 1997 @@ -116,7 +116,7 @@ static __inline__ void dst_free(struct dst_entry * dst) { - if (!dst->use) { + if (!atomic_read(&dst->use)) { dst_destroy(dst); return; } diff -u --recursive --new-file v2.1.33/linux/include/net/ipv6.h linux/include/net/ipv6.h --- v2.1.33/linux/include/net/ipv6.h Thu Mar 27 14:40:11 1997 +++ linux/include/net/ipv6.h Mon Apr 14 11:45:34 1997 @@ -4,7 +4,7 @@ * Authors: * Pedro Roque * - * $Id: ipv6.h,v 1.5 1997/03/18 18:24:10 davem Exp $ + * $Id: ipv6.h,v 1.6 1997/04/01 02:22:58 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -16,6 +16,7 @@ #define _NET_IPV6_H #include +#include #include #include @@ -199,7 +200,7 @@ extern __inline__ int gfp_any(void) { int pri = GFP_KERNEL; - if (intr_count) + if (in_interrupt()) pri = GFP_ATOMIC; return pri; } diff -u --recursive --new-file v2.1.33/linux/include/net/neighbour.h linux/include/net/neighbour.h --- v2.1.33/linux/include/net/neighbour.h Thu Mar 27 14:40:11 1997 +++ linux/include/net/neighbour.h Mon Apr 14 11:45:18 1997 @@ -116,7 +116,7 @@ struct neighbour *neigh) { start_bh_atomic(); - if (tbl->tbl_lock == 1) + if (atomic_read(&tbl->tbl_lock) == 1) { neigh_table_ins(tbl, neigh); } diff -u --recursive --new-file v2.1.33/linux/include/net/sock.h linux/include/net/sock.h --- v2.1.33/linux/include/net/sock.h Fri Apr 4 08:52:26 1997 +++ linux/include/net/sock.h Mon Apr 14 11:43:08 1997 @@ -794,7 +794,7 @@ extern __inline__ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) { - if (sk->rmem_alloc + skb->truesize >= sk->rcvbuf) + if (atomic_read(&sk->rmem_alloc) + skb->truesize >= sk->rcvbuf) return -ENOMEM; skb_set_owner_r(skb, sk); skb_queue_tail(&sk->receive_queue,skb); @@ -805,7 +805,7 @@ extern __inline__ int __sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) { - if (sk->rmem_alloc + skb->truesize >= sk->rcvbuf) + if (atomic_read(&sk->rmem_alloc) + skb->truesize >= sk->rcvbuf) return -ENOMEM; skb_set_owner_r(skb, sk); __skb_queue_tail(&sk->receive_queue,skb); @@ -816,7 +816,7 @@ extern __inline__ int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb) { - if (sk->rmem_alloc + skb->truesize >= sk->rcvbuf) + if (atomic_read(&sk->rmem_alloc) + skb->truesize >= sk->rcvbuf) return -ENOMEM; skb_set_owner_r(skb, sk); __skb_queue_tail(&sk->error_queue,skb); diff -u --recursive --new-file v2.1.33/linux/include/net/tcp.h linux/include/net/tcp.h --- v2.1.33/linux/include/net/tcp.h Thu Mar 27 14:40:12 1997 +++ linux/include/net/tcp.h Mon Apr 14 11:45:23 1997 @@ -20,6 +20,7 @@ #include #include +#include #include /* This is for all connections with a full identity, no wildcards. */ @@ -188,21 +189,7 @@ void (*destructor) (struct open_request *req); }; -struct open_request { - struct open_request *dl_next; - struct open_request *dl_prev; - __u32 rcv_isn; - __u32 snt_isn; - __u16 mss; - __u16 rmt_port; - unsigned long expires; - int retrans; - struct or_calltable *class; - struct sock *sk; -}; - struct tcp_v4_open_req { - struct open_request req; __u32 loc_addr; __u32 rmt_addr; struct ip_options *opt; @@ -210,7 +197,6 @@ #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) struct tcp_v6_open_req { - struct open_request req; struct in6_addr loc_addr; struct in6_addr rmt_addr; struct ipv6_options *opt; @@ -218,6 +204,31 @@ }; #endif +struct open_request { + struct open_request *dl_next; + struct open_request *dl_prev; + __u32 rcv_isn; + __u32 snt_isn; + __u16 rmt_port; + __u16 mss; + unsigned long expires; + int retrans; + struct or_calltable *class; + struct sock *sk; + union { + struct tcp_v4_open_req v4_req; +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) + struct tcp_v6_open_req v6_req; +#endif + } af; +}; + +/* SLAB cache for open requests. */ +extern kmem_cache_t *tcp_openreq_cachep; + +#define tcp_openreq_alloc() kmem_cache_alloc(tcp_openreq_cachep, SLAB_ATOMIC) +#define tcp_openreq_free(req) kmem_cache_free(tcp_openreq_cachep, req) + /* * Pointers to address related TCP functions * (i.e. things that depend on the address family) @@ -560,7 +571,7 @@ { struct tcp_sl_timer *slt = &tcp_slt_array[timer]; - if (slt->count == 0) + if (atomic_read(&slt->count) == 0) { __tcp_inc_slow_timer(slt); } diff -u --recursive --new-file v2.1.33/linux/ipc/msg.c linux/ipc/msg.c --- v2.1.33/linux/ipc/msg.c Sun Jan 26 02:07:48 1997 +++ linux/ipc/msg.c Fri Apr 11 22:11:21 1997 @@ -137,7 +137,7 @@ return -EAGAIN; if (current->signal & ~current->blocked) return -EINTR; - if (intr_count) { + if (in_interrupt()) { /* Very unlikely, but better safe than sorry */ printk(KERN_WARNING "Ouch, kerneld:msgsnd buffers full!\n"); return -EINTR; @@ -774,7 +774,7 @@ return -ENODEV; /* Do not wait for an answer at interrupt-time! */ - if (intr_count) + if (in_interrupt()) ret_size &= ~KERNELD_WAIT; #ifdef NEW_KERNELD_PROTOCOL else diff -u --recursive --new-file v2.1.33/linux/ipc/shm.c linux/ipc/shm.c --- v2.1.33/linux/ipc/shm.c Sun Jan 26 02:07:48 1997 +++ linux/ipc/shm.c Mon Apr 14 09:31:10 1997 @@ -721,7 +721,7 @@ done: /* pte_val(pte) == shp->shm_pages[idx] */ current->min_flt++; - mem_map[MAP_NR(pte_page(pte))].count++; + atomic_inc(&mem_map[MAP_NR(pte_page(pte))].count); return pte_modify(pte, shmd->vm_page_prot); } @@ -821,7 +821,7 @@ flush_cache_page(shmd, tmp); set_pte(page_table, __pte(shmd->vm_pte + SWP_ENTRY(0, idx << SHM_IDX_SHIFT))); - mem_map[MAP_NR(pte_page(pte))].count--; + atomic_dec(&mem_map[MAP_NR(pte_page(pte))].count); if (shmd->vm_mm->rss > 0) shmd->vm_mm->rss--; flush_tlb_page(shmd, tmp); @@ -831,7 +831,7 @@ break; } - if (mem_map[MAP_NR(pte_page(page))].count != 1) + if (atomic_read(&mem_map[MAP_NR(pte_page(page))].count) != 1) goto check_table; shp->shm_pages[idx] = swap_nr; write_swap_page (swap_nr, (char *) pte_page(page)); diff -u --recursive --new-file v2.1.33/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.1.33/linux/kernel/ksyms.c Mon Apr 7 11:35:32 1997 +++ linux/kernel/ksyms.c Mon Apr 14 09:31:10 1997 @@ -183,14 +183,6 @@ EXPORT_SYMBOL(tty_unregister_driver); EXPORT_SYMBOL(tty_std_termios); -#if defined(CONFIG_BLK_DEV_IDECD) || \ - defined(CONFIG_BLK_DEV_SR) || \ - defined(CONFIG_CM206) -EXPORT_SYMBOL(register_cdrom); -EXPORT_SYMBOL(unregister_cdrom); -EXPORT_SYMBOL(cdrom_fops); -#endif - /* block device driver support */ EXPORT_SYMBOL(block_read); EXPORT_SYMBOL(block_write); @@ -266,7 +258,9 @@ EXPORT_SYMBOL(tq_scheduler); EXPORT_SYMBOL(timer_active); EXPORT_SYMBOL(timer_table); -EXPORT_SYMBOL(intr_count); +#ifdef __SMP__ +EXPORT_SYMBOL(waitqueue_lock); +#endif /* autoirq from drivers/net/auto_irq.c */ EXPORT_SYMBOL(autoirq_setup); diff -u --recursive --new-file v2.1.33/linux/kernel/resource.c linux/kernel/resource.c --- v2.1.33/linux/kernel/resource.c Sun Apr 13 10:18:22 1997 +++ linux/kernel/resource.c Fri Apr 11 10:47:40 1997 @@ -123,8 +123,8 @@ /* * This is for architectures with MMU-managed ports (sparc). */ -unsigned int occupy_region(unsigned long base, unsigned long end, - unsigned long num, unsigned int align, const char *name) +unsigned long occupy_region(unsigned long base, unsigned long end, + unsigned long num, unsigned int align, const char *name) { unsigned long from = 0, till; unsigned long flags; @@ -148,14 +148,14 @@ save_flags(flags); cli(); - /* printk("occupy: search in %08x[%x] ", base, end - base); */ + /* printk("occupy: search in %08lx[%08lx] ", base, end - base); */ s = NULL; for (p = &iolist; p != NULL; p = p1) { p1 = p->next; /* Find window in list */ - from = (p->from+p->num + align-1) & ~(align-1); - till = (p1 == NULL)? (unsigned) (0 - align): p1->from; - /* printk(" %08x:%08x", from, till); */ + from = (p->from+p->num + align-1) & ~((unsigned long)align-1); + till = (p1 == NULL)? (unsigned long) (0 - (unsigned long)align): p1->from; + /* printk(" %08lx:%08lx", from, till); */ /* Clip window with base and end */ if (from < base) from = base; if (till > end) till = end; diff -u --recursive --new-file v2.1.33/linux/kernel/sched.c linux/kernel/sched.c --- v2.1.33/linux/kernel/sched.c Sun Apr 13 10:18:22 1997 +++ linux/kernel/sched.c Mon Apr 14 10:14:08 1997 @@ -16,6 +16,7 @@ * current-task */ +#include #include #include #include @@ -49,7 +50,7 @@ int securelevel = 0; /* system security level */ long tick = (1000000 + HZ/2) / HZ; /* timer interrupt period */ -volatile struct timeval xtime; /* The current time */ +volatile struct timeval xtime __attribute__ ((aligned (8))); /* The current time */ int tickadj = 500/HZ; /* microsecs */ DECLARE_TASK_QUEUE(tq_timer); @@ -362,6 +363,9 @@ * the scheduler lock */ spin_unlock_irq(&runqueue_lock); +#ifdef __SMP__ + prev->processor = NO_PROC_ID; +#endif /* * Note! there may appear new tasks on the run-queue during this, as @@ -510,27 +514,9 @@ * needs to do something only if count was negative before * the increment operation. * - * This routine must execute atomically. - */ -static inline int waking_non_zero(struct semaphore *sem) -{ - int ret; - long flags; - - save_flags(flags); - cli(); - - ret = 0; - if (sem->waking > 0) { - sem->waking--; - ret = 1; - } - - restore_flags(flags); - return ret; -} - -/* + * waking_non_zero() (from asm/semaphore.h) must execute + * atomically. + * * When __up() is called, the count was negative before * incrementing it, and we need to wake up somebody. * @@ -548,7 +534,7 @@ */ void __up(struct semaphore *sem) { - atomic_inc(&sem->waking); + wake_one_more(sem); wake_up(&sem->wait); } @@ -1131,7 +1117,7 @@ } } -static __inline__ void update_one_process(struct task_struct *p, +void update_one_process(struct task_struct *p, unsigned long ticks, unsigned long user, unsigned long system) { do_process_times(p, user, system); @@ -1141,6 +1127,9 @@ static void update_process_times(unsigned long ticks, unsigned long system) { +/* + * SMP does this on a per-CPU basis elsewhere + */ #ifndef __SMP__ struct task_struct * p = current; unsigned long user = ticks - system; @@ -1157,63 +1146,6 @@ kstat.cpu_system += system; } update_one_process(p, ticks, user, system); -#else - int cpu,j; - cpu = smp_processor_id(); - for (j=0;jpid) { - /* assume user-mode process */ - unsigned long utime = ticks; - unsigned long stime = 0; - if (cpu == i) { - utime = ticks-system; - stime = system; - } else if (smp_proc_in_lock[j]) { - utime = 0; - stime = ticks; - } - - update_one_process(p, ticks, utime, stime); - - if (p->priority < DEF_PRIORITY) - kstat.cpu_nice += utime; - else - kstat.cpu_user += utime; - kstat.cpu_system += stime; - - p->counter -= ticks; - if (p->counter >= 0) - continue; - p->counter = 0; - } else { - /* - * Idle processor found, do we have anything - * we could run? - */ - if (!(read_smp_counter(&smp_process_available))) - continue; - } - /* Ok, we should reschedule, do the magic */ - cli(); - if (i==cpu) { - need_resched = 1; - } else { - smp_message_pass(i, MSG_RESCHEDULE, 0L, 0); - } - sti(); - } #endif } @@ -1252,37 +1184,13 @@ run_timer_list(); } -/* - * It is up to the platform where it does the profiling: in the - * global timer interrupt, or in a special interrupt handler. - * - * by default it's done in the global timer interrupt. - */ - -static void default_do_profile (struct pt_regs * regs) -{ - if (prof_buffer && current->pid) { - extern int _stext; - unsigned long ip = instruction_pointer(regs); - ip -= (unsigned long) &_stext; - ip >>= prof_shift; - if (ip < prof_len) - prof_buffer[ip]++; - } -} - -void (*do_profile)(struct pt_regs *) = default_do_profile; - void do_timer(struct pt_regs * regs) { (*(unsigned long *)&jiffies)++; lost_ticks++; mark_bh(TIMER_BH); - if (!user_mode(regs)) { + if (!user_mode(regs)) lost_ticks_system++; - if (do_profile) - do_profile(regs); - } if (tq_timer) mark_bh(TQUEUE_BH); } @@ -1667,7 +1575,7 @@ if (t.tv_sec == 0 && t.tv_nsec <= 2000000L && - current->policy != SCHED_OTHER) + current->policy != SCHED_OTHER) { /* * Short delay requests up to 2 ms will be handled with diff -u --recursive --new-file v2.1.33/linux/kernel/softirq.c linux/kernel/softirq.c --- v2.1.33/linux/kernel/softirq.c Thu Mar 27 14:40:12 1997 +++ linux/kernel/softirq.c Mon Apr 14 09:31:10 1997 @@ -23,16 +23,13 @@ #include #include #include -#include -#include -atomic_t intr_count = 0; +/* intr_count died a painless death... -DaveM */ int bh_mask_count[32]; unsigned long bh_active = 0; unsigned long bh_mask = 0; void (*bh_base[32])(void); - /* * This needs to make sure that only one bottom half handler diff -u --recursive --new-file v2.1.33/linux/mm/filemap.c linux/mm/filemap.c --- v2.1.33/linux/mm/filemap.c Fri Apr 4 08:52:26 1997 +++ linux/mm/filemap.c Mon Apr 14 09:31:10 1997 @@ -168,7 +168,7 @@ buffer cache; we'd have to modify the following test to allow for that case. */ - switch (page->count) { + switch (atomic_read(&page->count)) { case 1: /* If it has been referenced recently, don't free it */ if (clear_bit(PG_referenced, &page->flags)) @@ -214,7 +214,7 @@ unsigned long page_unuse(unsigned long page) { struct page * p = mem_map + MAP_NR(page); - int count = p->count; + int count = atomic_read(&p->count); if (count != 2) return count; @@ -260,7 +260,7 @@ struct inode * inode, unsigned long offset, struct page **hash) { - page->count++; + atomic_inc(&page->count); page->flags &= ~((1 << PG_uptodate) | (1 << PG_error)); page->offset = offset; add_page_to_inode_queue(inode, page); @@ -1000,7 +1000,7 @@ { unsigned long page = SWP_OFFSET(entry); - mem_map[page].count++; + atomic_inc(&mem_map[page].count); page = (page << PAGE_SHIFT) + PAGE_OFFSET; return mk_pte(page,vma->vm_page_prot); } @@ -1023,7 +1023,7 @@ set_pte(ptep, pte_mkclean(pte)); flush_tlb_page(vma, address); page = pte_page(pte); - mem_map[MAP_NR(page)].count++; + atomic_inc(&mem_map[MAP_NR(page)].count); } else { if (pte_none(pte)) return 0; diff -u --recursive --new-file v2.1.33/linux/mm/kmalloc.c linux/mm/kmalloc.c --- v2.1.33/linux/mm/kmalloc.c Thu Mar 27 14:40:12 1997 +++ linux/mm/kmalloc.c Fri Apr 11 22:10:49 1997 @@ -266,8 +266,8 @@ priority &= GFP_LEVEL_MASK; /* Sanity check... */ -#if 0 /* no longer valid */ - if (intr_count && priority != GFP_ATOMIC) { + + if (in_interrupt() && priority != GFP_ATOMIC) { static int count = 0; if (++count < 5) { printk("kmalloc called nonatomically from interrupt %p\n", @@ -275,7 +275,7 @@ priority = GFP_ATOMIC; } } -#endif + save_flags(flags); cli(); page = *pg; diff -u --recursive --new-file v2.1.33/linux/mm/memory.c linux/mm/memory.c --- v2.1.33/linux/mm/memory.c Wed Jan 1 06:20:45 1997 +++ linux/mm/memory.c Mon Apr 14 09:31:10 1997 @@ -199,7 +199,7 @@ pte = pte_mkdirty(pte); set_pte(new_pte, pte_mkold(pte)); set_pte(old_pte, pte); - mem_map[page_nr].count++; + atomic_inc(&mem_map[page_nr].count); } static inline int copy_pte_range(pmd_t *dst_pmd, pmd_t *src_pmd, unsigned long address, unsigned long size, int cow) @@ -546,7 +546,7 @@ if (MAP_NR(page) >= max_mapnr) printk("put_dirty_page: trying to put page %08lx at %08lx\n",page,address); - if (mem_map[MAP_NR(page)].count != 1) + if (atomic_read(&mem_map[MAP_NR(page)].count) != 1) printk("mem_map disagrees with %08lx at %08lx\n",page,address); pgd = pgd_offset(tsk->mm,address); pmd = pmd_alloc(pgd, address); @@ -621,7 +621,7 @@ /* * Do we need to copy? */ - if (mem_map[MAP_NR(old_page)].count != 1) { + if (atomic_read(&mem_map[MAP_NR(old_page)].count) != 1) { if (new_page) { if (PageReserved(mem_map + MAP_NR(old_page))) ++vma->vm_mm->rss; @@ -766,7 +766,8 @@ free_page(pte_page(page)); return; } - if (mem_map[MAP_NR(pte_page(page))].count > 1 && !(vma->vm_flags & VM_SHARED)) + if (atomic_read(&mem_map[MAP_NR(pte_page(page))].count) > 1 && + !(vma->vm_flags & VM_SHARED)) page = pte_wrprotect(page); ++vma->vm_mm->rss; ++tsk->maj_flt; @@ -833,7 +834,8 @@ entry = mk_pte(page, vma->vm_page_prot); if (write_access) { entry = pte_mkwrite(pte_mkdirty(entry)); - } else if (mem_map[MAP_NR(page)].count > 1 && !(vma->vm_flags & VM_SHARED)) + } else if (atomic_read(&mem_map[MAP_NR(page)].count) > 1 && + !(vma->vm_flags & VM_SHARED)) entry = pte_wrprotect(entry); put_page(page_table, entry); /* no need to invalidate: a not-present page shouldn't be cached */ diff -u --recursive --new-file v2.1.33/linux/mm/page_alloc.c linux/mm/page_alloc.c --- v2.1.33/linux/mm/page_alloc.c Thu Mar 27 14:40:12 1997 +++ linux/mm/page_alloc.c Mon Apr 14 09:31:10 1997 @@ -190,7 +190,7 @@ index += size; \ map += size; \ } \ - map->count = 1; \ + atomic_set(&map->count, 1); \ map->age = PAGE_INITIAL_AGE; \ } while (0) @@ -201,8 +201,8 @@ if (order >= NR_MEM_LISTS) return 0; -#if 0 - if (intr_count && priority != GFP_ATOMIC) { + + if (in_interrupt() && priority != GFP_ATOMIC) { static int count = 0; if (++count < 5) { printk("gfp called nonatomically from interrupt %p\n", @@ -210,7 +210,7 @@ priority = GFP_ATOMIC; } } -#endif + reserved_pages = 5; if (priority != GFP_NFS) reserved_pages = min_free_pages; @@ -288,6 +288,7 @@ memset(mem_map, 0, start_mem - (unsigned long) mem_map); do { --p; + atomic_set(&p->count, 0); p->flags = (1 << PG_DMA) | (1 << PG_reserved); p->map_nr = p - mem_map; } while (p > mem_map); diff -u --recursive --new-file v2.1.33/linux/mm/slab.c linux/mm/slab.c --- v2.1.33/linux/mm/slab.c Thu Mar 27 14:40:12 1997 +++ linux/mm/slab.c Fri Apr 11 22:11:10 1997 @@ -478,7 +478,7 @@ printk(KERN_ERR "%sNULL ptr\n", func_nm); return NULL; } - if (0 && intr_count) { + if (in_interrupt()) { printk(KERN_ERR "%sCalled during int - %s\n", func_nm, name); return NULL; } @@ -743,7 +743,7 @@ goto err_end; } - if (0 && intr_count) { + if (in_interrupt()) { printk(KERN_ERR "kmem_dest: Called during int - %s\n", cachep->c_name); err_end: return 1; @@ -809,7 +809,7 @@ goto end; } - if (0 && intr_count) { + if (in_interrupt()) { printk(KERN_ERR "kmem_shrink: Called during int - %s\n", cachep->c_name); goto end; } @@ -951,7 +951,7 @@ * in kmem_cache_alloc(). If a caller is slightly mis-behaving, * will eventually be caught here (where it matters) */ - if (0 && intr_count && (flags & SLAB_LEVEL_MASK) != SLAB_ATOMIC) { + if (in_interrupt() && (flags & SLAB_LEVEL_MASK) != SLAB_ATOMIC) { static int count = 0; if (count < 8) { printk(KERN_ERR "kmem_grow: Called nonatomically from " diff -u --recursive --new-file v2.1.33/linux/mm/swap.c linux/mm/swap.c --- v2.1.33/linux/mm/swap.c Mon Oct 28 04:21:41 1996 +++ linux/mm/swap.c Mon Apr 14 09:31:10 1997 @@ -44,7 +44,7 @@ /* We track the number of pages currently being asynchronously swapped out, so that we don't try to swap TOO many pages out at once */ -atomic_t nr_async_pages = 0; +atomic_t nr_async_pages = ATOMIC_INIT; /* * Constants for the page aging mechanism: the maximum age (actually, diff -u --recursive --new-file v2.1.33/linux/mm/vmscan.c linux/mm/vmscan.c --- v2.1.33/linux/mm/vmscan.c Sun Apr 13 10:18:22 1997 +++ linux/mm/vmscan.c Mon Apr 14 09:31:10 1997 @@ -7,7 +7,7 @@ * kswapd added: 7.1.96 sct * Removed kswapd_ctl limits, and swap out as many pages as needed * to bring the system back to free_pages_high: 2.4.97, Rik van Riel. - * Version: $Id: vmscan.c,v 1.21 1997/01/06 06:54:03 davem Exp $ + * Version: $Id: vmscan.c,v 1.23 1997/04/12 04:31:05 davem Exp $ */ #include @@ -103,7 +103,7 @@ if (vma->vm_ops->swapout(vma, address - vma->vm_start + vma->vm_offset, page_table)) kill_proc(pid, SIGBUS, 1); } else { - if (page_map->count != 1) + if (atomic_read(&page_map->count) != 1) return 0; if (!(entry = get_swap_page())) return 0; @@ -118,7 +118,7 @@ return 1; /* we slept: the process may not exist any more */ } if ((entry = find_in_swap_cache(MAP_NR(page)))) { - if (page_map->count != 1) { + if (atomic_read(&page_map->count) != 1) { set_pte(page_table, pte_mkdirty(pte)); printk("Aiee.. duplicated cached swap-cache entry\n"); return 0; @@ -369,7 +369,7 @@ int kswapd(void *unused) { int i; - char *revision="$Revision: 1.21 $", *s, *e; + char *revision="$Revision: 1.23 $", *s, *e; current->session = 1; current->pgrp = 1; @@ -412,9 +412,9 @@ */ while(nr_free_pages < min_free_pages) try_to_free_page(GFP_KERNEL, 0, 1); - while((nr_free_pages + nr_async_pages) < free_pages_low) + while((nr_free_pages + atomic_read(&nr_async_pages)) < free_pages_low) try_to_free_page(GFP_KERNEL, 0, 1); - while((nr_free_pages + nr_async_pages) < free_pages_high) + while((nr_free_pages + atomic_read(&nr_async_pages)) < free_pages_high) try_to_free_page(GFP_KERNEL, 0, 0); } } @@ -428,13 +428,13 @@ int want_wakeup = 0; static int last_wakeup_low = 0; - if ((nr_free_pages + nr_async_pages) < free_pages_low) { + if ((nr_free_pages + atomic_read(&nr_async_pages)) < free_pages_low) { if (last_wakeup_low) want_wakeup = jiffies >= next_swap_jiffies; else last_wakeup_low = want_wakeup = 1; } - else if (((nr_free_pages + nr_async_pages) < free_pages_high) && + else if (((nr_free_pages + atomic_read(&nr_async_pages)) < free_pages_high) && jiffies >= next_swap_jiffies) { last_wakeup_low = 0; want_wakeup = 1; diff -u --recursive --new-file v2.1.33/linux/net/802/sysctl_net_802.c linux/net/802/sysctl_net_802.c --- v2.1.33/linux/net/802/sysctl_net_802.c Fri Feb 7 05:54:55 1997 +++ linux/net/802/sysctl_net_802.c Sun Apr 13 09:23:31 1997 @@ -12,6 +12,7 @@ #include #include +#include ctl_table e802_table[] = { {0} diff -u --recursive --new-file v2.1.33/linux/net/802/tr.c linux/net/802/tr.c --- v2.1.33/linux/net/802/tr.c Fri Feb 7 05:54:55 1997 +++ linux/net/802/tr.c Sun Apr 13 09:23:31 1997 @@ -14,6 +14,7 @@ #include #include +#include #include #include #include diff -u --recursive --new-file v2.1.33/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c --- v2.1.33/linux/net/appletalk/ddp.c Fri Apr 4 08:52:26 1997 +++ linux/net/appletalk/ddp.c Mon Apr 14 09:31:10 1997 @@ -198,7 +198,9 @@ ntohs(s->protinfo.af_at.dest_net), s->protinfo.af_at.dest_node, s->protinfo.af_at.dest_port); - len += sprintf (buffer+len,"%08X:%08X ", s->wmem_alloc, s->rmem_alloc); + len += sprintf (buffer+len,"%08X:%08X ", + atomic_read(&s->wmem_alloc), + atomic_read(&s->rmem_alloc)); len += sprintf (buffer+len,"%02X %d\n", s->state, SOCK_INODE(s->socket)->i_uid); /* Are we still dumping unwanted data then discard the record */ @@ -1891,7 +1893,7 @@ * Protocol layer */ case TIOCOUTQ: - amount=sk->sndbuf-sk->wmem_alloc; + amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if(amount<0) amount=0; break; diff -u --recursive --new-file v2.1.33/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c --- v2.1.33/linux/net/ax25/af_ax25.c Mon Apr 7 11:35:32 1997 +++ linux/net/ax25/af_ax25.c Mon Apr 14 09:31:10 1997 @@ -360,7 +360,9 @@ struct sk_buff *copy; while (sk != NULL) { - if (sk->type == SOCK_RAW && sk->protocol == proto && sk->rmem_alloc <= sk->rcvbuf) { + if (sk->type == SOCK_RAW && + sk->protocol == proto && + atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) { if ((copy = skb_clone(skb, GFP_ATOMIC)) == NULL) return; @@ -417,7 +419,9 @@ } if (ax25->sk != NULL) { - if (ax25->sk->wmem_alloc != 0 || ax25->sk->rmem_alloc != 0) { /* Defer: outstanding buffers */ + if (atomic_read(&ax25->sk->wmem_alloc) != 0 || + atomic_read(&ax25->sk->rmem_alloc) != 0) { + /* Defer: outstanding buffers */ init_timer(&ax25->timer); ax25->timer.expires = jiffies + 10 * HZ; ax25->timer.function = ax25_destroy_timer; @@ -1532,7 +1536,7 @@ case TIOCOUTQ: if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int))) != 0) return err; - amount = sk->sndbuf - sk->wmem_alloc; + amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if (amount < 0) amount = 0; put_user(amount, (int *)arg); @@ -1607,8 +1611,8 @@ ax25_info.idletimer = sk->protinfo.ax25->idletimer; ax25_info.n2count = sk->protinfo.ax25->n2count; ax25_info.state = sk->protinfo.ax25->state; - ax25_info.rcv_q = sk->rmem_alloc; - ax25_info.snd_q = sk->wmem_alloc; + ax25_info.rcv_q = atomic_read(&sk->rmem_alloc); + ax25_info.snd_q = atomic_read(&sk->wmem_alloc); copy_to_user((void *)arg, &ax25_info, sizeof(ax25_info)); return 0; @@ -1682,8 +1686,8 @@ if (ax25->sk != NULL) { len += sprintf(buffer + len, " %5d %5d\n", - ax25->sk->wmem_alloc, - ax25->sk->rmem_alloc); + atomic_read(&ax25->sk->wmem_alloc), + atomic_read(&ax25->sk->rmem_alloc)); } else { len += sprintf(buffer + len, "\n"); } diff -u --recursive --new-file v2.1.33/linux/net/ax25/ax25_ds_timer.c linux/net/ax25/ax25_ds_timer.c --- v2.1.33/linux/net/ax25/ax25_ds_timer.c Thu Mar 27 14:40:13 1997 +++ linux/net/ax25/ax25_ds_timer.c Mon Apr 14 09:31:10 1997 @@ -146,7 +146,7 @@ * Check the state of the receive buffer. */ if (ax25->sk != NULL) { - if (ax25->sk->rmem_alloc < (ax25->sk->rcvbuf / 2) && (ax25->condition & AX25_COND_OWN_RX_BUSY)) { + if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) && (ax25->condition & AX25_COND_OWN_RX_BUSY)) { ax25->condition &= ~AX25_COND_OWN_RX_BUSY; break; } diff -u --recursive --new-file v2.1.33/linux/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c --- v2.1.33/linux/net/ax25/ax25_in.c Thu Mar 27 14:40:14 1997 +++ linux/net/ax25/ax25_in.c Mon Apr 14 09:31:10 1997 @@ -325,7 +325,7 @@ case AX25_P_TEXT: /* Now find a suitable dgram socket */ if ((sk = ax25_find_socket(&dest, &src, SOCK_DGRAM)) != NULL) { - if (sk->rmem_alloc >= sk->rcvbuf) { + if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) { kfree_skb(skb, FREE_READ); } else { /* diff -u --recursive --new-file v2.1.33/linux/net/ax25/ax25_std_timer.c linux/net/ax25/ax25_std_timer.c --- v2.1.33/linux/net/ax25/ax25_std_timer.c Thu Feb 27 10:57:32 1997 +++ linux/net/ax25/ax25_std_timer.c Mon Apr 14 09:31:10 1997 @@ -66,7 +66,8 @@ * Check the state of the receive buffer. */ if (ax25->sk != NULL) { - if (ax25->sk->rmem_alloc < (ax25->sk->rcvbuf / 2) && (ax25->condition & AX25_COND_OWN_RX_BUSY)) { + if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) && + (ax25->condition & AX25_COND_OWN_RX_BUSY)) { ax25->condition &= ~AX25_COND_OWN_RX_BUSY; ax25->condition &= ~AX25_COND_ACK_PENDING; ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE); diff -u --recursive --new-file v2.1.33/linux/net/ax25/sysctl_net_ax25.c linux/net/ax25/sysctl_net_ax25.c --- v2.1.33/linux/net/ax25/sysctl_net_ax25.c Thu Mar 27 14:40:14 1997 +++ linux/net/ax25/sysctl_net_ax25.c Sun Apr 13 09:23:31 1997 @@ -7,6 +7,7 @@ #include #include +#include #include static int min_ipdefmode[] = {0}, max_ipdefmode[] = {1}; diff -u --recursive --new-file v2.1.33/linux/net/core/datagram.c linux/net/core/datagram.c --- v2.1.33/linux/net/core/datagram.c Sat Jan 25 13:46:14 1997 +++ linux/net/core/datagram.c Mon Apr 14 09:31:10 1997 @@ -123,7 +123,7 @@ goto no_packet; wait_for_packet(sk); - } + } /* Again only user level code calls this function, so nothing interrupt level will suddenly eat the receive_queue */ @@ -228,7 +228,7 @@ if (sock_wspace(sk) >= MIN_WRITE_SPACE) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; } else { - if (sk->sndbuf-sk->wmem_alloc >= MIN_WRITE_SPACE) + if (sk->sndbuf - atomic_read(&sk->wmem_alloc) >= MIN_WRITE_SPACE) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; } } diff -u --recursive --new-file v2.1.33/linux/net/core/dev.c linux/net/core/dev.c --- v2.1.33/linux/net/core/dev.c Sun Apr 13 10:18:22 1997 +++ linux/net/core/dev.c Mon Apr 14 09:31:10 1997 @@ -122,7 +122,7 @@ * Device list lock */ -atomic_t dev_lockct=0; +atomic_t dev_lockct = ATOMIC_INIT; /* * Our notifier list diff -u --recursive --new-file v2.1.33/linux/net/core/dst.c linux/net/core/dst.c --- v2.1.33/linux/net/core/dst.c Thu Mar 27 14:40:14 1997 +++ linux/net/core/dst.c Mon Apr 14 09:31:10 1997 @@ -20,7 +20,7 @@ #include struct dst_entry * dst_garbage_list; -atomic_t dst_total; +atomic_t dst_total = ATOMIC_INIT; static unsigned long dst_gc_timer_expires; static unsigned long dst_gc_timer_inc = DST_GC_MAX; @@ -41,7 +41,7 @@ del_timer(&dst_gc_timer); dstp = &dst_garbage_list; while ((dst = *dstp) != NULL) { - if (dst->use) { + if (atomic_read(&dst->use)) { dstp = &dst->next; delayed++; continue; @@ -58,7 +58,9 @@ dst_gc_timer_inc += DST_GC_INC; dst_gc_timer.expires = jiffies + dst_gc_timer_expires; #if RT_CACHE_DEBUG >= 2 - printk("dst_total: %d/%d/%d %ld\n", dst_total, delayed, hh_count, dst_gc_timer_expires); + printk("dst_total: %d/%d/%d %ld\n", + atomic_read(&dst_total), delayed, + atomic_read(&hh_count), dst_gc_timer_expires); #endif add_timer(&dst_gc_timer); } @@ -83,7 +85,7 @@ return NULL; memset(dst, 0, size); dst->ops = ops; - dst->refcnt = 1; + atomic_set(&dst->refcnt, 1); dst->lastuse = jiffies; dst->input = dst_discard; dst->output = dst_blackhole; diff -u --recursive --new-file v2.1.33/linux/net/core/skbuff.c linux/net/core/skbuff.c --- v2.1.33/linux/net/core/skbuff.c Thu Mar 27 14:40:15 1997 +++ linux/net/core/skbuff.c Mon Apr 14 09:31:10 1997 @@ -60,9 +60,9 @@ * Resource tracking variables */ -atomic_t net_skbcount = 0; -atomic_t net_allocs = 0; -atomic_t net_fails = 0; +static atomic_t net_skbcount = ATOMIC_INIT; +static atomic_t net_allocs = ATOMIC_INIT; +static atomic_t net_fails = ATOMIC_INIT; extern atomic_t ip_frag_mem; @@ -75,11 +75,15 @@ void show_net_buffers(void) { - printk(KERN_INFO "Networking buffers in use : %u\n",net_skbcount); - printk(KERN_INFO "Total network buffer allocations : %u\n",net_allocs); - printk(KERN_INFO "Total failed network buffer allocs : %u\n",net_fails); + printk(KERN_INFO "Networking buffers in use : %u\n", + atomic_read(&net_skbcount)); + printk(KERN_INFO "Total network buffer allocations : %u\n", + atomic_read(&net_allocs)); + printk(KERN_INFO "Total failed network buffer allocs : %u\n", + atomic_read(&net_fails)); #ifdef CONFIG_INET - printk(KERN_INFO "IP fragment buffer size : %u\n",ip_frag_mem); + printk(KERN_INFO "IP fragment buffer size : %u\n", + atomic_read(&ip_frag_mem)); #endif } @@ -606,7 +610,7 @@ int len; unsigned char *bptr; - if (0 && intr_count && priority!=GFP_ATOMIC) + if (in_interrupt() && priority!=GFP_ATOMIC) { static int count = 0; if (++count < 5) { @@ -633,7 +637,7 @@ bptr=(unsigned char *)kmalloc(size,priority); if (bptr == NULL) { - net_fails++; + atomic_inc(&net_fails); return NULL; } #ifdef PARANOID_BUGHUNT_MODE @@ -647,12 +651,12 @@ * by doing the following. Which is to deliberately put the * skb at the _end_ not the start of the memory block. */ - net_allocs++; + atomic_inc(&net_allocs); skb=(struct sk_buff *)(bptr+size)-1; - skb->count = 1; /* only one reference to this */ - skb->data_skb = skb; /* and we're our own data skb */ + atomic_set(&skb->count, 1); /* only one reference to this */ + skb->data_skb = skb; /* and we're our own data skb */ skb->pkt_type = PACKET_HOST; /* Default type */ skb->pkt_bridged = 0; /* Not bridged */ @@ -667,11 +671,11 @@ skb->destructor = NULL; memset(skb->cb, 0, sizeof(skb->cb)); skb->priority = SOPRI_NORMAL; - net_skbcount++; + atomic_inc(&net_skbcount); #if CONFIG_SKB_CHECK skb->magic_debug_cookie = SK_GOOD_SKB; #endif - skb->users = 1; + atomic_set(&skb->users, 1); /* Load the data pointers */ skb->head=bptr; skb->data=bptr; @@ -741,7 +745,7 @@ return NULL; } memcpy(n, skb, sizeof(*n)); - n->count = 1; + atomic_set(&n->count, 1); skb = skb->data_skb; atomic_inc(&skb->count); atomic_inc(&net_allocs); @@ -752,7 +756,7 @@ n->list = NULL; n->sk = NULL; n->tries = 0; - n->users = 1; + atomic_set(&n->users, 1); n->inclone = inbuff; n->destructor = NULL; return n; @@ -807,7 +811,7 @@ n->used=skb->used; n->arp=skb->arp; n->tries=0; - n->users=1; + atomic_set(&n->users, 1); n->pkt_type=skb->pkt_type; n->stamp=skb->stamp; n->destructor = NULL; @@ -862,7 +866,7 @@ n->used=skb->used; n->arp=skb->arp; n->tries=0; - n->users=1; + atomic_set(&n->users, 1); n->pkt_type=skb->pkt_type; n->stamp=skb->stamp; n->destructor = NULL; diff -u --recursive --new-file v2.1.33/linux/net/core/sock.c linux/net/core/sock.c --- v2.1.33/linux/net/core/sock.c Fri Apr 4 08:52:28 1997 +++ linux/net/core/sock.c Mon Apr 14 09:31:10 1997 @@ -512,7 +512,7 @@ struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority) { - if (force || sk->wmem_alloc < sk->sndbuf) { + if (force || atomic_read(&sk->wmem_alloc) < sk->sndbuf) { struct sk_buff * skb = alloc_skb(size, priority); if (skb) { atomic_add(skb->truesize, &sk->wmem_alloc); @@ -526,7 +526,7 @@ struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority) { - if (force || sk->rmem_alloc < sk->rcvbuf) { + if (force || atomic_read(&sk->rmem_alloc) < sk->rcvbuf) { struct sk_buff *skb = alloc_skb(size, priority); if (skb) { atomic_add(skb->truesize, &sk->rmem_alloc); @@ -545,9 +545,9 @@ if (sk != NULL) { - if (sk->rmem_alloc >= sk->rcvbuf-2*MIN_WINDOW) + if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf-2*MIN_WINDOW) return(0); - amt = min((sk->rcvbuf-sk->rmem_alloc)/2-MIN_WINDOW, MAX_WINDOW); + amt = min((sk->rcvbuf-atomic_read(&sk->rmem_alloc))/2-MIN_WINDOW, MAX_WINDOW); if (amt < 0) return(0); return(amt); @@ -562,9 +562,9 @@ { if (sk->shutdown & SEND_SHUTDOWN) return(0); - if (sk->wmem_alloc >= sk->sndbuf) + if (atomic_read(&sk->wmem_alloc) >= sk->sndbuf) return(0); - return sk->sndbuf - sk->wmem_alloc; + return sk->sndbuf - atomic_read(&sk->wmem_alloc); } return(0); } @@ -627,7 +627,7 @@ *errcode=-EPIPE; return NULL; } - tmp = sk->wmem_alloc; + tmp = atomic_read(&sk->wmem_alloc); cli(); if(sk->shutdown&SEND_SHUTDOWN) { @@ -637,7 +637,7 @@ } #if 1 - if( tmp <= sk->wmem_alloc) + if( tmp <= atomic_read(&sk->wmem_alloc)) #else /* ANK: Line above seems either incorrect * or useless. sk->wmem_alloc has a tiny chance to change @@ -647,7 +647,7 @@ * In any case I'd delete this check at all, or * change it to: */ - if (sk->wmem_alloc + size >= sk->sndbuf) + if (atomic_read(&sk->wmem_alloc) + size >= sk->sndbuf) #endif { sk->socket->flags &= ~SO_NOSPACE; @@ -765,7 +765,9 @@ kfree_skb(skb,FREE_READ); } - if(sk->wmem_alloc == 0 && sk->rmem_alloc == 0 && sk->dead) + if(atomic_read(&sk->wmem_alloc) == 0 && + atomic_read(&sk->rmem_alloc) == 0 && + sk->dead) { sk_free(sk); } diff -u --recursive --new-file v2.1.33/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v2.1.33/linux/net/ipv4/af_inet.c Fri Apr 4 08:52:28 1997 +++ linux/net/ipv4/af_inet.c Mon Apr 14 09:31:10 1997 @@ -184,7 +184,7 @@ */ printk(KERN_DEBUG "Socket destroy delayed (r=%d w=%d)\n", - sk->rmem_alloc, sk->wmem_alloc); + atomic_read(&sk->rmem_alloc), atomic_read(&sk->wmem_alloc)); sk->destroy = 1; sk->ack_backlog = 0; @@ -216,7 +216,7 @@ * structure, otherwise we need to keep it around until * everything is gone. */ - if (sk->rmem_alloc == 0 && sk->wmem_alloc == 0) + if (atomic_read(&sk->rmem_alloc) == 0 && atomic_read(&sk->wmem_alloc) == 0) kill_sk_now(sk); else kill_sk_later(sk); @@ -1057,6 +1057,7 @@ }; #endif /* CONFIG_PROC_FS */ +extern void tcp_init(void); /* * Called by socket.c on kernel startup. @@ -1107,6 +1108,9 @@ */ ip_init(); + + /* Setup TCP slab cache for open requests. */ + tcp_init(); /* * Set the ICMP layer up diff -u --recursive --new-file v2.1.33/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v2.1.33/linux/net/ipv4/arp.c Fri Apr 4 08:52:28 1997 +++ linux/net/ipv4/arp.c Mon Apr 14 09:31:10 1997 @@ -230,9 +230,9 @@ int sysctl_arp_dead_res_time = ARP_DEAD_RES_TIME; - +/* This should be completely nuked... -DaveM */ #if RT_CACHE_DEBUG >= 1 -#define ASSERT_BH() if (!intr_count) printk(KERN_CRIT __FUNCTION__ " called from SPL=0\n"); +#define ASSERT_BH() if (!in_interrupt()) printk(KERN_CRIT __FUNCTION__ " called from SPL=0\n"); #else #define ASSERT_BH() #endif @@ -251,8 +251,8 @@ }; -static atomic_t arp_size = 0; -static atomic_t arp_unres_size = 0; +static atomic_t arp_size = ATOMIC_INIT; +static atomic_t arp_unres_size = ATOMIC_INIT; #ifdef CONFIG_ARPD static int arpd_not_running; @@ -424,7 +424,7 @@ arpreq->stamp = arpd_stamp; arpreq->updated = updated; if (ha) - memcpy(arpreq->u.neigh.ha, ha, sizeof(arpreq->u.neigh.ha)); + memcpy(arpreq->ha, ha, sizeof(arpreq->ha)); retval = netlink_post(NETLINK_ARPD, skb); if (retval) @@ -503,7 +503,7 @@ else { start_bh_atomic(); - arp_update(retreq->ip, retreq->u.neigh.ha, dev, retreq->updated, 0); + arp_update(retreq->ip, retreq->ha, dev, retreq->updated, 0); end_bh_atomic(); } @@ -541,7 +541,7 @@ unsigned long now = jiffies; int result = 0; - static last_index; + static int last_index; if (last_index >= ARP_TABLE_SIZE) last_index = 0; @@ -554,7 +554,7 @@ { if (!(entry->flags & ATF_PERM)) { - if (!entry->u.neigh.refcnt && + if (!atomic_read(&entry->u.neigh.refcnt) && now - entry->u.neigh.lastused > sysctl_arp_timeout) { #if RT_CACHE_DEBUG >= 2 @@ -562,11 +562,11 @@ #endif arp_free(pentry); result++; - if (arp_size < ARP_MAXSIZE) + if (atomic_read(&arp_size) < ARP_MAXSIZE) goto done; continue; } - if (!entry->u.neigh.refcnt && + if (!atomic_read(&entry->u.neigh.refcnt) && entry->u.neigh.lastused < oldest_used) { oldest_entry = pentry; @@ -602,7 +602,7 @@ (entry->retries < sysctl_arp_max_tries || entry->timer.expires - now < sysctl_arp_res_time - sysctl_arp_res_time/32)) { - if (!entry->u.neigh.refcnt) { + if (!atomic_read(&entry->u.neigh.refcnt)) { #if RT_CACHE_DEBUG >= 2 printk("arp_unres_expire: %08x discarded\n", entry->ip); #endif @@ -653,7 +653,7 @@ continue; } - if (!entry->u.neigh.refcnt && + if (!atomic_read(&entry->u.neigh.refcnt) && now - entry->u.neigh.lastused > sysctl_arp_timeout) { #if RT_CACHE_DEBUG >= 2 @@ -735,7 +735,7 @@ arp_purge_send_q(entry); - if (entry->u.neigh.refcnt) + if (atomic_read(&entry->u.neigh.refcnt)) { /* * The host is dead, but someone refers to it. @@ -797,19 +797,20 @@ { struct arp_table * entry; - if (how && arp_size >= ARP_MAXSIZE) + if (how && atomic_read(&arp_size) >= ARP_MAXSIZE) arp_force_expire(); - if (how > 1 && arp_unres_size >= ARP_MAX_UNRES) { + if (how > 1 && atomic_read(&arp_unres_size) >= ARP_MAX_UNRES) { arp_unres_expire(); - if (arp_unres_size >= ARP_MAX_UNRES) { - printk(KERN_DEBUG "arp_unres_size=%d\n", arp_unres_size); + if (atomic_read(&arp_unres_size) >= ARP_MAX_UNRES) { + printk(KERN_DEBUG "arp_unres_size=%d\n", + atomic_read(&arp_unres_size)); return NULL; } } entry = (struct arp_table *)neigh_alloc(sizeof(struct arp_table), &arp_neigh_ops); - entry->u.neigh.refcnt = 1; + atomic_set(&entry->u.neigh.refcnt, 1); if (entry != NULL) { @@ -1780,7 +1781,7 @@ && (entry->u.neigh.dev == dev || (!(r->arp_flags&ATF_PUBL) && !dev)) && (!(r->arp_flags&ATF_MAGIC) || r->arp_flags == entry->flags)) { - if (!entry->u.neigh.refcnt) + if (!atomic_read(&entry->u.neigh.refcnt)) { arp_free(entryp); retval = 0; @@ -1935,8 +1936,8 @@ entry->mask==DEF_ARP_NETMASK ? "*" : in_ntoa(entry->mask), entry->u.neigh.dev ? entry->u.neigh.dev->name : "*", - entry->u.neigh.refcnt, - entry->u.neigh.hh ? entry->u.neigh.hh->hh_refcnt : -1, + atomic_read(&entry->u.neigh.refcnt), + entry->u.neigh.hh ? atomic_read(&entry->u.neigh.hh->hh_refcnt) : -1, entry->u.neigh.hh ? entry->u.neigh.hh->hh_uptodate : 0); #endif diff -u --recursive --new-file v2.1.33/linux/net/ipv4/fib.c linux/net/ipv4/fib.c --- v2.1.33/linux/net/ipv4/fib.c Fri Apr 4 08:52:28 1997 +++ linux/net/ipv4/fib.c Mon Apr 14 09:31:10 1997 @@ -117,11 +117,11 @@ */ static struct wait_queue *fib_wait; -atomic_t fib_users; +static atomic_t fib_users = ATOMIC_INIT; static void fib_lock(void) { - while (fib_users) + while (atomic_read(&fib_users)) sleep_on(&fib_wait); atomic_inc(&fib_users); dev_lock_list(); diff -u --recursive --new-file v2.1.33/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c --- v2.1.33/linux/net/ipv4/ip_fragment.c Fri Apr 4 08:52:28 1997 +++ linux/net/ipv4/ip_fragment.c Mon Apr 14 09:31:10 1997 @@ -46,7 +46,7 @@ static struct ipq *ipqueue = NULL; /* IP fragment queue */ -atomic_t ip_frag_mem = 0; /* Memory used for fragments */ +atomic_t ip_frag_mem = ATOMIC_INIT; /* Memory used for fragments */ char *in_ntoa(unsigned long in); @@ -105,7 +105,7 @@ save_flags(flags); cli(); - ip_frag_mem+=skb->truesize; + atomic_add(skb->truesize, &ip_frag_mem); restore_flags(flags); return(fp); @@ -226,7 +226,7 @@ static void ip_evictor(void) { - while(ip_frag_mem>IPFRAG_LOW_THRESH) + while(atomic_read(&ip_frag_mem)>IPFRAG_LOW_THRESH) { if(!ipqueue) panic("ip_evictor: memcount"); @@ -422,7 +422,7 @@ * Start by cleaning up the memory */ - if(ip_frag_mem>IPFRAG_HIGH_THRESH) + if(atomic_read(&ip_frag_mem)>IPFRAG_HIGH_THRESH) ip_evictor(); /* * Find the entry of this IP datagram in the "incomplete datagrams" queue. diff -u --recursive --new-file v2.1.33/linux/net/ipv4/ip_masq_raudio.c linux/net/ipv4/ip_masq_raudio.c --- v2.1.33/linux/net/ipv4/ip_masq_raudio.c Fri Apr 4 08:52:28 1997 +++ linux/net/ipv4/ip_masq_raudio.c Fri Apr 11 10:47:40 1997 @@ -2,7 +2,7 @@ * IP_MASQ_RAUDIO - Real Audio masquerading module * * - * Version: @(#)$Id: ip_masq_raudio.c,v 1.3 1996/05/20 13:24:26 nigel Exp $ + * Version: @(#)$Id: ip_masq_raudio.c,v 1.5 1997/04/03 08:52:02 davem Exp $ * * Author: Nigel Metheringham * [strongly based on ftp module by Juan Jose Ciarlante & Wouter Gadeyne] diff -u --recursive --new-file v2.1.33/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c --- v2.1.33/linux/net/ipv4/ipmr.c Fri Apr 4 08:52:28 1997 +++ linux/net/ipv4/ipmr.c Fri Apr 11 10:47:40 1997 @@ -314,6 +314,8 @@ kfree_skb(skb, FREE_READ); return ret; } + + return ret; } /* @@ -357,7 +359,7 @@ /* If the report failed throw the cache entry out - Brad Parker */ if(ipmr_cache_report(skb, vifi, 0)<0) - impr_cache_delete(cache); + ipmr_cache_delete(cache); } } /* diff -u --recursive --new-file v2.1.33/linux/net/ipv4/proc.c linux/net/ipv4/proc.c --- v2.1.33/linux/net/ipv4/proc.c Sun Apr 13 10:18:22 1997 +++ linux/net/ipv4/proc.c Mon Apr 14 09:31:10 1997 @@ -92,18 +92,27 @@ destp = sp->dummy_th.dest; srcp = sp->dummy_th.source; + /* FIXME: The fact that retransmit_timer occurs as a field + * in two different parts of the socket structure is, + * to say the least, confusing. This code now uses the + * right retransmit_timer variable, but I'm not sure + * the rest of the timer stuff is still correct. + * In particular I'm not sure what the timeout value + * is suppose to reflect (as opposed to tm->when). -- erics + */ + /* Since we are Little Endian we need to swap the bytes :-( */ destp = ntohs(destp); srcp = ntohs(srcp); - timer_active1 = del_timer(&sp->retransmit_timer); + timer_active1 = del_timer(&tp->retransmit_timer); timer_active2 = del_timer(&sp->timer); - if (!timer_active1) sp->retransmit_timer.expires=0; + if (!timer_active1) tp->retransmit_timer.expires=0; if (!timer_active2) sp->timer.expires=0; timer_active=0; timer_expires=(unsigned)-1; - if (timer_active1 && sp->retransmit_timer.expires < timer_expires) { + if (timer_active1 && tp->retransmit_timer.expires < timer_expires) { timer_active=timer_active1; - timer_expires=sp->retransmit_timer.expires; + timer_expires=tp->retransmit_timer.expires; } if (timer_active2 && sp->timer.expires < timer_expires) { timer_active=timer_active2; @@ -112,14 +121,15 @@ sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X" " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld", i, src, srcp, dest, destp, sp->state, - format==0?sp->write_seq-tp->snd_una:sp->wmem_alloc, - format==0?tp->rcv_nxt-sp->copied_seq:sp->rmem_alloc, - timer_active, timer_expires-jiffies, (unsigned) sp->retransmits, + format==0?sp->write_seq-tp->snd_una:atomic_read(&sp->wmem_alloc), + format==0?tp->rcv_nxt-sp->copied_seq:atomic_read(&sp->rmem_alloc), + timer_active, timer_expires-jiffies, + (unsigned) atomic_read(&sp->retransmits), sp->socket ? sp->socket->inode->i_uid:0, timer_active?sp->timeout:0, sp->socket ? sp->socket->inode->i_ino:0); - if (timer_active1) add_timer(&sp->retransmit_timer); + if (timer_active1) add_timer(&tp->retransmit_timer); if (timer_active2) add_timer(&sp->timer); len += sprintf(buffer+len, "%-127s\n", tmpbuf); if(len >= length) diff -u --recursive --new-file v2.1.33/linux/net/ipv4/route.c linux/net/ipv4/route.c --- v2.1.33/linux/net/ipv4/route.c Thu Mar 27 14:40:15 1997 +++ linux/net/ipv4/route.c Mon Apr 14 09:31:10 1997 @@ -111,7 +111,7 @@ * Route cache. */ -static atomic_t rt_cache_size; +static atomic_t rt_cache_size = ATOMIC_INIT; static struct rtable *rt_hash_table[RT_HASH_DIVISOR]; static struct rtable * rt_intern_hash(unsigned hash, struct rtable * rth, u16 protocol); @@ -160,12 +160,12 @@ r->u.dst.dev ? r->u.dst.dev->name : "*", (unsigned long)r->rt_dst, (unsigned long)r->rt_gateway, - r->rt_flags, r->u.dst.refcnt, - r->u.dst.use, 0, + r->rt_flags, atomic_read(&r->u.dst.refcnt), + atomic_read(&r->u.dst.use), 0, (unsigned long)r->rt_src, (int)r->u.dst.pmtu, r->u.dst.window, (int)r->u.dst.rtt, r->key.tos, - r->u.dst.hh ? r->u.dst.hh->hh_refcnt : -1, + r->u.dst.hh ? atomic_read(&r->u.dst.hh->hh_refcnt) : -1, r->u.dst.hh ? r->u.dst.hh->hh_uptodate : 0, r->rt_spec_dst, i); @@ -213,7 +213,8 @@ * Cleanup aged off entries. */ - if (!rth->u.dst.use && now - rth->u.dst.lastuse > RT_CACHE_TIMEOUT) { + if (!atomic_read(&rth->u.dst.use) && + (now - rth->u.dst.lastuse > RT_CACHE_TIMEOUT)) { *rthp = rth_next; atomic_dec(&rt_cache_size); #if RT_CACHE_DEBUG >= 2 @@ -235,7 +236,7 @@ if ( rth_next->u.dst.lastuse - rth->u.dst.lastuse > RT_CACHE_BUBBLE_THRESHOLD || (rth->u.dst.lastuse - rth_next->u.dst.lastuse < 0 && - rth->u.dst.use < rth_next->u.dst.use)) { + atomic_read(&rth->u.dst.use) < atomic_read(&rth_next->u.dst.use))) { #if RT_CACHE_DEBUG >= 2 printk("rt_check_expire bubbled %02x@%08x<->%08x\n", rover, rth->rt_dst, rth_next->rt_dst); #endif @@ -338,7 +339,8 @@ if (!rt_hash_table[i]) continue; for (rthp=&rt_hash_table[i]; (rth=*rthp); rthp=&rth->u.rt_next) { - if (rth->u.dst.use || now - rth->u.dst.lastuse > expire) + if (atomic_read(&rth->u.dst.use) || + (now - rth->u.dst.lastuse > expire)) continue; atomic_dec(&rt_cache_size); *rthp = rth->u.rt_next; @@ -349,7 +351,7 @@ } last_gc = now; - if (rt_cache_size < RT_CACHE_MAX_SIZE) + if (atomic_read(&rt_cache_size) < RT_CACHE_MAX_SIZE) expire = RT_CACHE_TIMEOUT>>1; else expire >>= 1; @@ -380,7 +382,7 @@ #endif memset(hh, 0, sizeof(struct hh_cache)); hh->hh_type = ETH_P_IP; - hh->hh_refcnt = 0; + atomic_set(&hh->hh_refcnt, 0); hh->hh_next = NULL; if (rt->u.dst.dev->hard_header_cache(&rt->u.dst, neigh, hh)) { kfree(hh); @@ -435,7 +437,7 @@ rthp = &rth->u.rt_next; } - if (rt_cache_size >= RT_CACHE_MAX_SIZE) + if (atomic_read(&rt_cache_size) >= RT_CACHE_MAX_SIZE) rt_garbage_collect(); rt->u.rt_next = rt_hash_table[hash]; @@ -519,14 +521,14 @@ /* * Copy all the information. */ - rt->u.dst.refcnt = 1; + atomic_set(&rt->u.dst.refcnt, 1); rt->u.dst.dev = dev; rt->u.dst.input = rth->u.dst.input; rt->u.dst.output = rth->u.dst.output; rt->u.dst.pmtu = dev->mtu; rt->u.dst.rtt = TCP_TIMEOUT_INIT; rt->u.dst.window = 0; - rt->u.dst.use = 1; + atomic_set(&rt->u.dst.use, 1); rt->u.dst.lastuse = jiffies; rt->rt_flags = rth->rt_flags|RTF_DYNAMIC|RTF_MODIFIED; @@ -946,7 +948,7 @@ rth->u.dst.output= ip_rt_bug; - rth->u.dst.use = 1; + atomic_set(&rth->u.dst.use, 1); rth->key.dst = dst_key; rth->rt_dst = dst_key; rth->rt_dst_map = daddr; @@ -1259,7 +1261,7 @@ if (!rth) return -ENOBUFS; - rth->u.dst.use = 1; + atomic_set(&rth->u.dst.use, 1); rth->key.dst = dst_key; rth->key.tos = tos; rth->key.src = src_key; diff -u --recursive --new-file v2.1.33/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c --- v2.1.33/linux/net/ipv4/sysctl_net_ipv4.c Mon Apr 7 11:35:32 1997 +++ linux/net/ipv4/sysctl_net_ipv4.c Sun Apr 13 09:23:31 1997 @@ -7,6 +7,7 @@ #include #include +#include #include #include #include diff -u --recursive --new-file v2.1.33/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.1.33/linux/net/ipv4/tcp.c Fri Apr 4 08:52:28 1997 +++ linux/net/ipv4/tcp.c Mon Apr 14 09:31:10 1997 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.50 1997/03/16 03:25:59 davem Exp $ + * Version: $Id: tcp.c,v 1.55 1997/04/13 10:31:45 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -198,6 +198,8 @@ * Willy Konynenberg : Transparent proxying support. * Keith Owens : Do proper meging with partial SKB's in * tcp_do_sendmsg to avoid burstiness. + * Eric Schenk : Fix fast close down bug with + * shutdown() followed by close(). * * To Fix: * Fast path the code. Two things here - fix the window calculation @@ -431,7 +433,7 @@ unsigned long seq_offset; struct tcp_mib tcp_statistics; - +kmem_cache_t *tcp_openreq_cachep; /* * Find someone to 'accept'. Must be called with @@ -440,25 +442,16 @@ static struct open_request *tcp_find_established(struct tcp_opt *tp) { - struct open_request *req; - - req = tp->syn_wait_queue; + struct open_request *req = tp->syn_wait_queue; if (!req) return NULL; - do { if (req->sk && (req->sk->state == TCP_ESTABLISHED || req->sk->state >= TCP_FIN_WAIT1)) - { return req; - } - - req = req->dl_next; - - } while (req != tp->syn_wait_queue); - + } while ((req = req->dl_next) != tp->syn_wait_queue); return NULL; } @@ -471,13 +464,10 @@ static void tcp_close_pending (struct sock *sk) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - struct open_request *req; - - req = tp->syn_wait_queue; + struct open_request *req = tp->syn_wait_queue; if (!req) return; - do { struct open_request *iter; @@ -490,12 +480,10 @@ (*iter->class->destructor)(iter); tcp_dec_slow_timer(TCP_SLT_SYNACK); sk->ack_backlog--; - kfree(iter); - + tcp_openreq_free(iter); } while (req != tp->syn_wait_queue); tp->syn_wait_queue = NULL; - return; } /* @@ -729,7 +717,7 @@ static inline int tcp_memory_free(struct sock *sk) { - return sk->wmem_alloc < sk->sndbuf; + return atomic_read(&sk->wmem_alloc) < sk->sndbuf; } /* @@ -961,7 +949,7 @@ tmp = MAX_HEADER + sk->prot->max_header + sizeof(struct sk_buff) + 15; if (copy < min(sk->mss, sk->max_window >> 1) && - !(flags & MSG_OOB) && sk->packets_out) + !(flags & MSG_OOB) && atomic_read(&sk->packets_out)) { tmp += min(sk->mss, sk->max_window); } @@ -1177,7 +1165,7 @@ */ while ((skb=skb_peek(&sk->receive_queue)) != NULL) { - if (!skb->used || skb->users>1) + if (!skb->used || atomic_read(&skb->users)>1) break; tcp_eat_skb(sk, skb); } @@ -1439,7 +1427,7 @@ if (flags & MSG_PEEK) continue; skb->used = 1; - if (skb->users == 1) + if (atomic_read(&skb->users) == 1) tcp_eat_skb(sk, skb); continue; @@ -1505,6 +1493,7 @@ case TCP_CLOSE: case TCP_LISTEN: break; + case TCP_LAST_ACK: /* Could have shutdown() then close() */ case TCP_CLOSE_WAIT: /* They have FIN'd us. We send our FIN and wait only for the ACK */ ns=TCP_LAST_ACK; @@ -1681,8 +1670,8 @@ tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_FIN_TIMEOUT); } - release_sock(sk); sk->dead = 1; + release_sock(sk); if(sk->state == TCP_CLOSE) sk->prot->unhash(sk); @@ -1728,11 +1717,9 @@ struct sock *newsk = NULL; int error; - /* - * We need to make sure that this socket is listening, - * and that it has something pending. - */ - + /* We need to make sure that this socket is listening, + * and that it has something pending. + */ error = EINVAL; if (sk->state != TCP_LISTEN) goto no_listen; @@ -1744,7 +1731,7 @@ got_new_connect: tcp_synq_unlink(tp, req); newsk = req->sk; - kfree(req); + tcp_openreq_free(req); sk->ack_backlog--; error = 0; out: @@ -1852,4 +1839,14 @@ { tcp_dec_slow_timer(TCP_SLT_KEEPALIVE); } +} + +void tcp_init(void) +{ + tcp_openreq_cachep = kmem_cache_create("tcp_open_request", + sizeof(struct open_request), + sizeof(long)*8, SLAB_HWCACHE_ALIGN, + NULL, NULL); + if(!tcp_openreq_cachep) + panic("tcp_init: Cannot alloc open_request cache."); } diff -u --recursive --new-file v2.1.33/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v2.1.33/linux/net/ipv4/tcp_input.c Thu Mar 27 14:40:15 1997 +++ linux/net/ipv4/tcp_input.c Mon Apr 14 09:31:10 1997 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_input.c,v 1.39 1997/03/17 04:49:35 davem Exp $ + * Version: $Id: tcp_input.c,v 1.42 1997/04/12 04:32:24 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -37,6 +37,8 @@ * Eric Schenk : Delayed ACK bug fixes. * Eric Schenk : Floyd style fast retrans war avoidance. * David S. Miller : Don't allow zero congestion window. + * Eric Schenk : Fix retransmitter so that it sends + * next packet on ack of previous packet. */ #include @@ -149,11 +151,19 @@ */ tp->rto = (tp->srtt >> 3) + tp->mdev; + tp->rto += (tp->rto >> 2) + (tp->rto >> (tp->snd_cwnd-1)); + if (tp->rto > 120*HZ) tp->rto = 120*HZ; - /* Was 1*HZ - keep .2 as minimum cos of the BSD delayed acks */ + /* Was 1*HZ - keep .2 as minimum cos of the BSD delayed acks + * FIXME: It's not entirely clear this lower bound is the best + * way to avoid the problem. Is it possible to drop the lower + * bound and still avoid trouble with BSD stacks? Perhaps + * some modification to the RTO calculation that takes delayed + * ack bais into account? This needs serious thought. -- erics + */ if (tp->rto < HZ/5) tp->rto = HZ/5; @@ -302,6 +312,15 @@ { struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp); + /* FIXME: if we are already retransmitting should this code + * be skipped? [Floyd high_seq check sort of does this] + * The case I'm worried about is falling into a fast + * retransmit on a link with a congestion window of 1 or 2. + * There was some evidence in 2.0.x that this was problem + * on really slow links (1200 or 2400 baud). I need to + * try this situation again and see what happens. + */ + /* * An ACK is a duplicate if: * (1) it has the same sequence number as the largest number we've @@ -313,7 +332,7 @@ * The packet acked data after high_seq; */ - if (ack == tp->snd_una && sk->packets_out && (not_dup == 0)) + if (ack == tp->snd_una && atomic_read(&sk->packets_out) && (not_dup == 0)) { /* * 1. When the third duplicate ack is received, set ssthresh @@ -327,9 +346,14 @@ if (sk->dup_acks == 3) { - sk->ssthresh = max(sk->cong_window >> 1, 2); - sk->cong_window = sk->ssthresh + 3; + sk->ssthresh = max(tp->snd_cwnd >> 1, 2); + tp->snd_cwnd = sk->ssthresh + 3; tcp_do_retransmit(sk, 0); + /* careful not to timeout just after fast + * retransmit! + */ + tcp_reset_xmit_timer(sk, TIME_RETRANS, + tp->rto); } } @@ -344,7 +368,7 @@ if (sk->dup_acks >= 3) { sk->dup_acks++; - sk->cong_window++; + tp->snd_cwnd++; } } else @@ -357,8 +381,8 @@ if (sk->dup_acks >= 3) { tp->retrans_head = NULL; - sk->cong_window = max(sk->ssthresh, 1); - sk->retransmits = 0; + tp->snd_cwnd = max(sk->ssthresh, 1); + atomic_set(&sk->retransmits, 0); } sk->dup_acks = 0; tp->high_seq = 0; @@ -425,7 +449,7 @@ * Slow Start */ - if (sk->cong_window < sk->ssthresh && + if (tp->snd_cwnd < sk->ssthresh && (seq == tp->snd_nxt || (expected - actual <= TCP_VEGAS_GAMMA * inv_basebd))) { @@ -436,7 +460,7 @@ if (sk->cong_count++) { - sk->cong_window++; + tp->snd_cwnd++; sk->cong_count = 0; } } @@ -450,9 +474,9 @@ { /* Increase Linearly */ - if (sk->cong_count++ >= sk->cong_window) + if (sk->cong_count++ >= tp->snd_cwnd) { - sk->cong_window++; + tp->snd_cwnd++; sk->cong_count = 0; } } @@ -461,21 +485,22 @@ { /* Decrease Linearly */ - if (sk->cong_count++ >= sk->cong_window) + if (sk->cong_count++ >= tp->snd_cwnd) { - sk->cong_window--; + tp->snd_cwnd--; sk->cong_count = 0; } /* Never less than 2 segments */ - if (sk->cong_window < 2) - sk->cong_window = 2; + if (tp->snd_cwnd < 2) + tp->snd_cwnd = 2; } } } static void tcp_cong_avoid_vanj(struct sock *sk, u32 seq, u32 ack, u32 seq_rtt) { + struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp); /* * This is Jacobson's slow start and congestion avoidance. @@ -483,27 +508,38 @@ * integral mss's, we can't do cwnd += 1 / cwnd. * Instead, maintain a counter and increment it once every * cwnd times. + * FIXME: Check to be sure the mathematics works out right + * on this trick when we have to reduce the congestion window. + * The cong_count has to be reset properly when reduction events + * happen. + * FIXME: What happens when the congestion window gets larger + * than the maximum receiver window by some large factor + * Suppose the pipeline never looses packets for a long + * period of time, then traffic increases causing packet loss. + * The congestion window should be reduced, but what it should + * be reduced to is not clear, since 1/2 the old window may + * still be larger than the maximum sending rate we ever achieved. */ - if (sk->cong_window <= sk->ssthresh) + if (tp->snd_cwnd <= sk->ssthresh) { /* * In "safe" area, increase */ - sk->cong_window++; + tp->snd_cwnd++; } else { /* * In dangerous area, increase slowly. * In theory this is - * sk->cong_window += 1 / sk->cong_window + * tp->snd_cwnd += 1 / tp->snd_cwnd */ - if (sk->cong_count >= sk->cong_window) { + if (sk->cong_count >= tp->snd_cwnd) { - sk->cong_window++; + tp->snd_cwnd++; sk->cong_count = 0; } else @@ -551,6 +587,10 @@ acked = FLAG_DATA_ACKED; + /* FIXME: packet counting may break if we have to + * do packet "repackaging" for stacks that don't + * like overlapping packets. + */ atomic_dec(&sk->packets_out); *seq = skb->seq; @@ -702,10 +742,10 @@ * if we where retransmiting don't count rtt estimate */ - if (sk->retransmits) + if (atomic_read(&sk->retransmits)) { - if (sk->packets_out == 0) - sk->retransmits = 0; + if (atomic_read(&sk->packets_out) == 0) + atomic_set(&sk->retransmits, 0); } else { @@ -729,17 +769,30 @@ } } - if (sk->packets_out) + if (atomic_read(&sk->packets_out)) { if (flag & FLAG_DATA_ACKED) { long when; skb = skb_peek(&sk->write_queue); - when = tp->rto - (jiffies - skb->when); - if (when <= 0) + /* + * FIXME: This assumes that when we are retransmitting + * we should only ever respond with one packet. + * This means congestion windows should not grow + * during recovery. In 2.0.X we allow the congestion + * window to grow. It is not clear to me which + * decision is correct. The RFCs should be double + * checked as should the behavior of other stacks. + * Also note that if we do want to allow the + * congestion window to grow during retransmits + * we have to fix the call to congestion window + * updates so that it works during retransmission. + */ + + if (atomic_read(&sk->retransmits)) { tp->retrans_head = NULL; /* @@ -758,6 +811,10 @@ tcp_clear_xmit_timer(sk, TIME_RETRANS); + /* FIXME: danger, if we just did a timeout and got the third + * ack on this packet, then this is going to send it again! + * [No. Floyd retransmit war check keeps this from happening. -- erics] + */ tcp_fast_retrans(sk, ack, (flag & (FLAG_DATA|FLAG_WIN_UPDATE))); /* @@ -1095,21 +1152,27 @@ if ((skb = tp->send_head)) { if (!after(skb->end_seq, tp->snd_una + tp->snd_wnd) && - sk->packets_out < sk->cong_window ) + atomic_read(&sk->packets_out) < tp->snd_cwnd ) { /* * Add more data to the send queue. */ + /* FIXME: the congestion window is checked + * again in tcp_write_xmit anyway?! + */ tcp_write_xmit(sk); if(!sk->dead) sk->write_space(sk); } - else if (sk->packets_out == 0 && !tp->pending) + else if (atomic_read(&sk->packets_out) == 0 && !tp->pending) { /* * Data to queue but no room. */ + /* FIXME: Is it right to do a zero window probe into + * a congestion window limited window??? + */ tcp_reset_xmit_timer(sk, TIME_PROBE0, tp->rto); } } @@ -1384,7 +1447,7 @@ * If our receive queue has grown past its limits, * try to prune away duplicates etc.. */ - if (sk->rmem_alloc > sk->rcvbuf) + if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf) prune_queue(sk); /* diff -u --recursive --new-file v2.1.33/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- v2.1.33/linux/net/ipv4/tcp_ipv4.c Sun Apr 13 10:18:23 1997 +++ linux/net/ipv4/tcp_ipv4.c Mon Apr 14 09:31:10 1997 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.23 1997/03/17 04:49:38 davem Exp $ + * Version: $Id: tcp_ipv4.c,v 1.30 1997/04/13 10:31:44 davem Exp $ * * IPv4 specific functions * @@ -581,11 +581,11 @@ tcp_init_xmit_timers(sk); /* Now works the right way instead of a hacked initial setting */ - sk->retransmits = 0; + atomic_set(&sk->retransmits, 0); skb_queue_tail(&sk->write_queue, buff); - sk->packets_out++; + atomic_inc(&sk->packets_out); buff->when = jiffies; skb1 = skb_clone(buff, GFP_KERNEL); @@ -663,8 +663,8 @@ { struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; - sk->ssthresh = max(sk->cong_window >> 1, 2); - sk->cong_window = sk->ssthresh + 3; + sk->ssthresh = max(tp->snd_cwnd >> 1, 2); + tp->snd_cwnd = sk->ssthresh + 3; tp->high_seq = tp->snd_nxt; return; @@ -800,56 +800,41 @@ static void tcp_v4_send_synack(struct sock *sk, struct open_request *req) { - struct tcp_v4_open_req *af_req = (struct tcp_v4_open_req *) req; struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; struct sk_buff * skb; struct tcphdr *th; unsigned char *ptr; int mss; - int tmp; skb = sock_wmalloc(sk, MAX_SYN_SIZE, 1, GFP_ATOMIC); - if (skb == NULL) - { return; - } - tmp = ip_build_pkt(skb, sk, af_req->loc_addr, af_req->rmt_addr, - af_req->opt); - - if (tmp < 0) - { + if(ip_build_pkt(skb, sk, req->af.v4_req.loc_addr, + req->af.v4_req.rmt_addr, req->af.v4_req.opt) < 0) { kfree_skb(skb, FREE_WRITE); return; } - mss = skb->dst->pmtu; - - mss -= sizeof(struct iphdr) + sizeof(struct tcphdr); - + mss = (skb->dst->pmtu - sizeof(struct iphdr) + sizeof(struct tcphdr)); if (sk->user_mss) mss = min(mss, sk->user_mss); + skb->h.th = th = (struct tcphdr *) skb_put(skb, sizeof(struct tcphdr)); - th =(struct tcphdr *) skb_put(skb, sizeof(struct tcphdr)); - skb->h.th = th; + /* Yuck, make this header setup more efficient... -DaveM */ memset(th, 0, sizeof(struct tcphdr)); - th->syn = 1; th->ack = 1; - th->source = sk->dummy_th.source; th->dest = req->rmt_port; - skb->seq = req->snt_isn; skb->end_seq = skb->seq + 1; - th->seq = ntohl(skb->seq); th->ack_seq = htonl(req->rcv_isn + 1); th->doff = sizeof(*th)/4 + 1; - th->window = ntohs(tp->rcv_wnd); + /* FIXME: csum_partial() of a four byte quantity is itself! -DaveM */ ptr = skb_put(skb, TCPOLEN_MSS); ptr[0] = TCPOPT_MSS; ptr[1] = TCPOLEN_MSS; @@ -858,8 +843,7 @@ skb->csum = csum_partial(ptr, TCPOLEN_MSS, 0); th->check = tcp_v4_check(th, sizeof(*th) + TCPOLEN_MSS, - af_req->loc_addr, - af_req->rmt_addr, + req->af.v4_req.loc_addr, req->af.v4_req.rmt_addr, csum_partial((char *)th, sizeof(*th), skb->csum)); ip_queue_xmit(skb); @@ -868,13 +852,9 @@ static void tcp_v4_or_free(struct open_request *req) { - struct tcp_v4_open_req *af_req = (struct tcp_v4_open_req *) req; - - if (af_req->req.sk) - return; - - if (af_req->opt) - kfree_s(af_req->opt, sizeof(struct options) + af_req->opt->optlen); + if(!req->sk && req->af.v4_req.opt) + kfree_s(req->af.v4_req.opt, + sizeof(struct options) + req->af.v4_req.opt->optlen); } static struct or_calltable or_ipv4 = { @@ -890,11 +870,11 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, __u32 isn) { struct ip_options *opt = (struct ip_options *) ptr; - struct tcp_v4_open_req *af_req; struct open_request *req; struct tcphdr *th = skb->h.th; __u32 saddr = skb->nh.iph->saddr; __u32 daddr = skb->nh.iph->daddr; + __u16 req_mss; /* If the socket is dead, don't accept the connection. */ if (sk->dead) @@ -916,55 +896,40 @@ goto exit; } - af_req = kmalloc(sizeof(struct tcp_v4_open_req), GFP_ATOMIC); - - if (af_req == NULL) - { + req = tcp_openreq_alloc(); + if (req == NULL) { tcp_statistics.TcpAttemptFails++; goto exit; } sk->ack_backlog++; - req = (struct open_request *) af_req; - - memset(af_req, 0, sizeof(struct tcp_v4_open_req)); req->rcv_isn = skb->seq; req->snt_isn = isn; - - /* mss */ - req->mss = tcp_parse_options(th); - - if (!req->mss) - { - req->mss = 536; - } - + req_mss = tcp_parse_options(th); + if (!req_mss) + req_mss = 536; + req->mss = req_mss; req->rmt_port = th->source; + req->af.v4_req.loc_addr = daddr; + req->af.v4_req.rmt_addr = saddr; - af_req->loc_addr = daddr; - af_req->rmt_addr = saddr; - - /* - * options - */ - - if (opt && opt->optlen) - { - af_req->opt = (struct ip_options*) kmalloc(sizeof(struct ip_options) + - opt->optlen, GFP_ATOMIC); - if (af_req->opt) - { - if (ip_options_echo(af_req->opt, skb)) - { - kfree_s(af_req->opt, sizeof(struct options) + - opt->optlen); - af_req->opt = NULL; + /* IPv4 options */ + req->af.v4_req.opt = NULL; + if (opt && opt->optlen) { + int opt_size = sizeof(struct ip_options) + opt->optlen; + + req->af.v4_req.opt = kmalloc(opt_size, GFP_ATOMIC); + if (req->af.v4_req.opt) { + if (ip_options_echo(req->af.v4_req.opt, skb)) { + kfree_s(req->af.v4_req.opt, opt_size); + req->af.v4_req.opt = NULL; } } } - req->class = &or_ipv4; + req->retrans = 0; + req->sk = NULL; tcp_v4_send_synack(sk, req); @@ -973,7 +938,8 @@ tcp_synq_queue(&sk->tp_pinfo.af_tcp, req); sk->data_ready(sk, 0); - exit: + +exit: kfree_skb(skb, FREE_READ); return 0; } @@ -981,7 +947,6 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, struct open_request *req) { - struct tcp_v4_open_req *af_req = (struct tcp_v4_open_req *) req; struct tcp_opt *newtp; struct sock *newsk; struct rtable *rt; @@ -989,9 +954,7 @@ newsk = sk_alloc(GFP_ATOMIC); if (newsk == NULL) - { return NULL; - } memcpy(newsk, sk, sizeof(*newsk)); @@ -1022,15 +985,17 @@ newsk->prot->init(newsk); newsk->cong_count = 0; +#if 0 /* Don't mess up the initialization we did in the init routine! */ newsk->ssthresh = 0; +#endif newtp->backoff = 0; newsk->intr = 0; newsk->proc = 0; newsk->done = 0; newsk->partial = NULL; newsk->pair = NULL; - newsk->wmem_alloc = 0; - newsk->rmem_alloc = 0; + atomic_set(&newsk->wmem_alloc, 0); + atomic_set(&newsk->rmem_alloc, 0); newsk->localroute = sk->localroute; newsk->max_unacked = MAX_WINDOW - TCP_WINDOW_DIFF; @@ -1055,8 +1020,8 @@ newtp->snd_nxt = newsk->write_seq; newsk->urg_data = 0; - newsk->packets_out = 0; - newsk->retransmits = 0; + atomic_set(&newsk->packets_out, 0); + atomic_set(&newsk->retransmits, 0); newsk->linger=0; newsk->destroy = 0; init_timer(&newsk->timer); @@ -1075,15 +1040,14 @@ newsk->socket = NULL; - newsk->daddr = af_req->rmt_addr; - newsk->saddr = af_req->loc_addr; - newsk->rcv_saddr = af_req->loc_addr; + newsk->daddr = req->af.v4_req.rmt_addr; + newsk->saddr = req->af.v4_req.loc_addr; + newsk->rcv_saddr = req->af.v4_req.loc_addr; /* * options / mss / route_cache */ - newsk->opt = af_req->opt; - + newsk->opt = req->af.v4_req.opt; if (ip_route_output(&rt, newsk->opt && newsk->opt->srr ? newsk->opt->faddr : newsk->daddr, newsk->saddr, newsk->ip_tos, NULL)) { @@ -1099,16 +1063,11 @@ newsk->mtu = snd_mss; /* sanity check */ if (newsk->mtu < 64) - { newsk->mtu = 64; - } snd_mss -= sizeof(struct iphdr) + sizeof(struct tcphdr); - if (sk->user_mss) - { snd_mss = min(snd_mss, sk->user_mss); - } newsk->mss = min(req->mss, snd_mss); @@ -1120,77 +1079,50 @@ struct sock *tcp_v4_check_req(struct sock *sk, struct sk_buff *skb) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - struct open_request *req; + struct open_request *req = tp->syn_wait_queue; - /* - * assumption: the socket is not in use. + /* assumption: the socket is not in use. * as we checked the user count on tcp_rcv and we're * running from a soft interrupt. */ - - req = tp->syn_wait_queue; - if (!req) - { return sk; - } do { - struct tcp_v4_open_req *af_req; - - af_req = (struct tcp_v4_open_req *) req; - - if (af_req->rmt_addr == skb->nh.iph->saddr && - af_req->loc_addr == skb->nh.iph->daddr && - req->rmt_port == skb->h.th->source) - { + if (req->af.v4_req.rmt_addr == skb->nh.iph->saddr && + req->af.v4_req.loc_addr == skb->nh.iph->daddr && + req->rmt_port == skb->h.th->source) { u32 flg; - if (req->sk) - { - /* - * socket already created but not + if (req->sk) { + /* socket already created but not * yet accepted()... */ - sk = req->sk; break; } - /* match */ - - /* - * Check for syn retransmission - */ + /* Check for syn retransmission */ flg = *(((u32 *)skb->h.th) + 3); flg &= __constant_htonl(0x002f0000); - if ((flg == __constant_htonl(0x00020000)) && - (!after(skb->seq, req->rcv_isn))) - { - /* - * retransmited syn + (!after(skb->seq, req->rcv_isn))) { + /* retransmited syn * FIXME: must send an ack */ return NULL; } sk = tp->af_specific->syn_recv_sock(sk, skb, req); - tcp_dec_slow_timer(TCP_SLT_SYNACK); - if (sk == NULL) - { return NULL; - } req->expires = 0UL; req->sk = sk; break; } - - req = req->dl_next; - } while (req != tp->syn_wait_queue); + } while ((req = req->dl_next) != tp->syn_wait_queue); skb_orphan(skb); skb_set_owner_r(skb, sk); @@ -1422,8 +1354,8 @@ * See draft-stevens-tcpca-spec-01 for discussion of the * initialization of these values. */ - sk->cong_window = 1; - sk->ssthresh = 0x7fffffff; + tp->snd_cwnd = 1; + sk->ssthresh = 0x7fffffff; /* Infinity */ sk->priority = 1; sk->state = TCP_CLOSE; diff -u --recursive --new-file v2.1.33/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c --- v2.1.33/linux/net/ipv4/tcp_output.c Fri Apr 4 08:52:28 1997 +++ linux/net/ipv4/tcp_output.c Mon Apr 14 09:31:10 1997 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_output.c,v 1.31 1997/03/16 07:03:07 davem Exp $ + * Version: $Id: tcp_output.c,v 1.34 1997/04/12 04:32:33 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -79,14 +79,14 @@ len = skb->end_seq - skb->seq; - if (!sk->nonagle && len < (sk->mss >> 1) && sk->packets_out) + if (!sk->nonagle && len < (sk->mss >> 1) && atomic_read(&sk->packets_out)) { nagle_check = 0; } - return (nagle_check && sk->packets_out < sk->cong_window && + return (nagle_check && atomic_read(&sk->packets_out) < tp->snd_cwnd && !after(skb->end_seq, tp->snd_una + tp->snd_wnd) && - sk->retransmits == 0); + atomic_read(&sk->retransmits) == 0); } /* @@ -189,7 +189,7 @@ if (tp->send_head == NULL) tp->send_head = skb; - if (sk->packets_out == 0 && !tp->pending) + if (atomic_read(&sk->packets_out) == 0 && !tp->pending) { tp->pending = TIME_PROBE0; tcp_reset_xmit_timer(sk, TIME_PROBE0, tp->rto); @@ -309,7 +309,7 @@ * cannot currently occur. */ - sk->retransmits = 0; + atomic_set(&sk->retransmits, 0); printk(KERN_DEBUG "tcp_write_xmit: bug skb in write queue\n"); @@ -720,7 +720,7 @@ */ ct++; - sk->prot->retransmits ++; + sk->prot->retransmits++; /* ???: atomic_t necessary here? -DaveM */ tcp_statistics.TcpRetransSegs++; tp->high_seq = tp->snd_nxt; @@ -736,7 +736,7 @@ * This should cut it off before we send too many packets. */ - if (ct >= sk->cong_window) + if (ct >= tp->snd_cwnd) break; /* diff -u --recursive --new-file v2.1.33/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c --- v2.1.33/linux/net/ipv4/tcp_timer.c Fri Apr 4 08:52:28 1997 +++ linux/net/ipv4/tcp_timer.c Mon Apr 14 09:31:10 1997 @@ -34,8 +34,8 @@ struct tcp_sl_timer tcp_slt_array[TCP_SLT_MAX] = { - {0, TCP_SYNACK_PERIOD, 0, tcp_syn_recv_timer}, /* SYNACK */ - {0, TCP_KEEPALIVE_PERIOD, 0, tcp_keepalive} /* KEEPALIVE */ + {ATOMIC_INIT, TCP_SYNACK_PERIOD, 0, tcp_syn_recv_timer},/* SYNACK */ + {ATOMIC_INIT, TCP_KEEPALIVE_PERIOD, 0, tcp_keepalive} /* KEEPALIVE */ }; /* @@ -165,8 +165,11 @@ /* * Look for a 'soft' timeout. */ - if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) - || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) + if ((sk->state == TCP_ESTABLISHED && + atomic_read(&sk->retransmits) && + !(atomic_read(&sk->retransmits) & 7)) || + (sk->state != TCP_ESTABLISHED && + atomic_read(&sk->retransmits) > TCP_RETR1)) { /* * Attempt to recover if arp has changed (unlikely!) or @@ -179,7 +182,7 @@ * Have we tried to SYN too many times (repent repent 8)) */ - if(sk->retransmits > TCP_SYN_RETRIES && sk->state==TCP_SYN_SENT) + if(atomic_read(&sk->retransmits) > TCP_SYN_RETRIES && sk->state==TCP_SYN_SENT) { if(sk->err_soft) sk->err=sk->err_soft; @@ -199,7 +202,7 @@ /* * Has it gone just too far ? */ - if (sk->retransmits > TCP_RETR2) + if (atomic_read(&sk->retransmits) > TCP_RETR2) { if(sk->err_soft) sk->err = sk->err_soft; @@ -415,16 +418,16 @@ tp->retrans_head = NULL; - if (sk->retransmits == 0) + if (atomic_read(&sk->retransmits) == 0) { /* * remember window where we lost * "one half of the current window but at least 2 segments" */ - sk->ssthresh = max(sk->cong_window >> 1, 2); + sk->ssthresh = max(tp->snd_cwnd >> 1, 2); sk->cong_count = 0; - sk->cong_window = 1; + tp->snd_cwnd = 1; } atomic_inc(&sk->retransmits); @@ -476,9 +479,7 @@ /* TCP_LISTEN is implied. */ if (!sk->sock_readers && tp->syn_wait_queue) { - struct open_request *req; - - req = tp->syn_wait_queue; + struct open_request *req = tp->syn_wait_queue; do { struct open_request *conn; @@ -500,7 +501,7 @@ (*conn->class->destructor)(conn); tcp_dec_slow_timer(TCP_SLT_SYNACK); sk->ack_backlog--; - kfree(conn); + tcp_openreq_free(conn); if (!tp->syn_wait_queue) break; @@ -536,7 +537,7 @@ for (i=0; i < TCP_SLT_MAX; i++, slt++) { - if (slt->count) + if (atomic_read(&slt->count)) { long trigger; diff -u --recursive --new-file v2.1.33/linux/net/ipv4/udp.c linux/net/ipv4/udp.c --- v2.1.33/linux/net/ipv4/udp.c Sun Apr 13 10:18:23 1997 +++ linux/net/ipv4/udp.c Mon Apr 14 09:31:10 1997 @@ -768,7 +768,6 @@ amount = skb->len-sizeof(struct udphdr); } return put_user(amount, (int *)arg); - return(0); } default: @@ -923,8 +922,9 @@ sk->state = TCP_CLOSE; if(uh_cache_sk == sk) uh_cache_sk = NULL; - release_sock(sk); sk->dead = 1; + release_sock(sk); + udp_v4_unhash(sk); destroy_sock(sk); } diff -u --recursive --new-file v2.1.33/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c --- v2.1.33/linux/net/ipv6/addrconf.c Thu Mar 27 14:40:16 1997 +++ linux/net/ipv6/addrconf.c Mon Apr 14 09:31:10 1997 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: addrconf.c,v 1.15 1997/03/18 18:24:23 davem Exp $ + * $Id: addrconf.c,v 1.16 1997/04/12 04:32:44 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,6 +20,7 @@ * */ +#include #include #include #include @@ -68,7 +69,7 @@ */ struct inet6_dev *inet6_dev_lst[IN6_ADDR_HSIZE]; -atomic_t addr_list_lock = 0; +static atomic_t addr_list_lock = ATOMIC_INIT; void addrconf_verify(unsigned long); @@ -241,7 +242,7 @@ struct inet6_ifaddr *iter, **back; int hash; - if (addr_list_lock) { + if (atomic_read(&addr_list_lock)) { ifp->flags |= ADDR_INVALID; return; } diff -u --recursive --new-file v2.1.33/linux/net/ipv6/datagram.c linux/net/ipv6/datagram.c --- v2.1.33/linux/net/ipv6/datagram.c Thu Mar 27 14:40:16 1997 +++ linux/net/ipv6/datagram.c Mon Apr 14 09:31:10 1997 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: datagram.c,v 1.8 1997/03/18 18:24:28 davem Exp $ + * $Id: datagram.c,v 1.10 1997/04/14 05:39:42 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff -u --recursive --new-file v2.1.33/linux/net/ipv6/ip6_fib.c linux/net/ipv6/ip6_fib.c --- v2.1.33/linux/net/ipv6/ip6_fib.c Thu Mar 27 14:40:16 1997 +++ linux/net/ipv6/ip6_fib.c Mon Apr 14 09:31:10 1997 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: ip6_fib.c,v 1.6 1997/03/18 18:24:33 davem Exp $ + * $Id: ip6_fib.c,v 1.7 1997/04/12 04:32:46 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -795,7 +795,7 @@ back = &fn->leaf; for (rt = fn->leaf; rt;) { - if ((rt->rt6i_flags & RTF_CACHE) && rt->rt6i_use == 0) { + if ((rt->rt6i_flags & RTF_CACHE) && atomic_read(&rt->rt6i_use) == 0) { if (now - rt->rt6i_tstamp > timeout) { struct rt6_info *old; diff -u --recursive --new-file v2.1.33/linux/net/ipv6/ipv6_sockglue.c linux/net/ipv6/ipv6_sockglue.c --- v2.1.33/linux/net/ipv6/ipv6_sockglue.c Mon Apr 7 11:35:33 1997 +++ linux/net/ipv6/ipv6_sockglue.c Sun Apr 13 09:23:31 1997 @@ -7,7 +7,7 @@ * * Based on linux/net/ipv4/ip_sockglue.c * - * $Id: ipv6_sockglue.c,v 1.8 1997/03/18 18:24:38 davem Exp $ + * $Id: ipv6_sockglue.c,v 1.9 1997/04/07 06:55:51 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -21,6 +21,7 @@ * o Return an optlen of the truncated length if need be */ +#include #include #include #include diff -u --recursive --new-file v2.1.33/linux/net/ipv6/mcast.c linux/net/ipv6/mcast.c --- v2.1.33/linux/net/ipv6/mcast.c Thu Mar 27 14:40:16 1997 +++ linux/net/ipv6/mcast.c Mon Apr 14 09:31:10 1997 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: mcast.c,v 1.7 1997/03/18 18:24:39 davem Exp $ + * $Id: mcast.c,v 1.8 1997/04/12 04:32:48 davem Exp $ * * Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c * @@ -208,7 +208,7 @@ memcpy(&mc->mca_addr, addr, sizeof(struct in6_addr)); mc->dev = dev; - mc->mca_users = 1; + atomic_set(&mc->mca_users, 1); mc->next = inet6_mcast_lst[hash]; inet6_mcast_lst[hash] = mc; diff -u --recursive --new-file v2.1.33/linux/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c --- v2.1.33/linux/net/ipv6/ndisc.c Thu Mar 27 14:40:17 1997 +++ linux/net/ipv6/ndisc.c Mon Apr 14 09:31:10 1997 @@ -6,7 +6,7 @@ * Pedro Roque * Mike Shaver * - * $Id: ndisc.c,v 1.13 1997/03/18 18:24:41 davem Exp $ + * $Id: ndisc.c,v 1.14 1997/04/12 04:32:51 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -157,7 +157,7 @@ neigh_table_lock(&nd_tbl); start_bh_atomic(); - if (nd_tbl.tbl_lock == 1) { + if (atomic_read(&nd_tbl.tbl_lock) == 1) { ntbl_walk_table(&nd_tbl, ndisc_gc_func, 0, 0, NULL); ndisc_gc_timer.expires = now + nd_gc_interval; } else { @@ -178,7 +178,7 @@ struct nd_neigh *ndn = (struct nd_neigh *) neigh; unsigned long now = jiffies; - if (ndn->ndn_refcnt == 0) { + if (atomic_read(&ndn->ndn_refcnt) == 0) { switch (ndn->ndn_nud_state) { case NUD_REACHABLE: @@ -262,7 +262,7 @@ { struct nd_neigh *ndn = (struct nd_neigh *) neigh; - if (ndn->ndn_refcnt == 0) { + if (atomic_read(&ndn->ndn_refcnt) == 0) { if (ndn->ndn_nud_state & NUD_IN_TIMER) ndisc_del_timer(ndn); @@ -295,7 +295,7 @@ #endif start_bh_atomic(); - if (nd_tbl.tbl_lock == 1) { + if (atomic_read(&nd_tbl.tbl_lock) == 1) { #if ND_DEBUG >= 2 printk(KERN_DEBUG "ndisc_alloc: forcing gc\n"); #endif @@ -1608,7 +1608,7 @@ now - ndn->ndn_tstamp, nd_reachable_time, nd_gc_staletime, - ndn->ndn_refcnt, + atomic_read(&ndn->ndn_refcnt), ndn->ndn_flags, ndn->ndn_dev ? ndn->ndn_dev->name : "NULLDEV"); diff -u --recursive --new-file v2.1.33/linux/net/ipv6/proc.c linux/net/ipv6/proc.c --- v2.1.33/linux/net/ipv6/proc.c Thu Mar 27 14:40:17 1997 +++ linux/net/ipv6/proc.c Mon Apr 14 09:31:10 1997 @@ -7,7 +7,7 @@ * PROC file system. This is very similar to the IPv4 version, * except it reports the sockets in the INET6 address family. * - * Version: $Id: proc.c,v 1.1 1997/03/16 08:47:18 davem Exp $ + * Version: $Id: proc.c,v 1.2 1997/04/12 04:32:55 davem Exp $ * * Authors: David S. Miller (davem@caip.rutgers.edu) * @@ -83,9 +83,10 @@ dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[2], dest->s6_addr32[3], destp, sp->state, - format==0?sp->write_seq-tp->snd_una:sp->wmem_alloc, - format==0?tp->rcv_nxt-sp->copied_seq:sp->rmem_alloc, - timer_active, timer_expires-jiffies, (unsigned) sp->retransmits, + format==0?sp->write_seq-tp->snd_una:atomic_read(&sp->wmem_alloc), + format==0?tp->rcv_nxt-sp->copied_seq:atomic_read(&sp->rmem_alloc), + timer_active, timer_expires-jiffies, + (unsigned) atomic_read(&sp->retransmits), sp->socket ? sp->socket->inode->i_uid:0, timer_active?sp->timeout:0, sp->socket ? sp->socket->inode->i_ino:0); diff -u --recursive --new-file v2.1.33/linux/net/ipv6/raw.c linux/net/ipv6/raw.c --- v2.1.33/linux/net/ipv6/raw.c Thu Mar 27 14:40:17 1997 +++ linux/net/ipv6/raw.c Fri Apr 11 10:47:41 1997 @@ -7,7 +7,7 @@ * * Adapted from linux/net/ipv4/raw.c * - * $Id: raw.c,v 1.11 1997/03/18 18:24:46 davem Exp $ + * $Id: raw.c,v 1.12 1997/04/01 02:23:34 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff -u --recursive --new-file v2.1.33/linux/net/ipv6/route.c linux/net/ipv6/route.c --- v2.1.33/linux/net/ipv6/route.c Thu Mar 27 14:40:17 1997 +++ linux/net/ipv6/route.c Mon Apr 14 09:31:10 1997 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: route.c,v 1.9 1997/03/19 14:56:25 davem Exp $ + * $Id: route.c,v 1.10 1997/04/12 04:32:57 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -62,7 +62,7 @@ }; struct rt6_info ip6_null_entry = { - {{NULL, 0, 0, NULL, + {{NULL, ATOMIC_INIT, ATOMIC_INIT, NULL, 0, 0, 0, 0, 0, 0, 0, 0, -ENETUNREACH, NULL, NULL, ip6_pkt_discard, ip6_pkt_discard, &ip6_dst_ops}}, NULL, {{{0}}}, 256, RTF_REJECT|RTF_NONEXTHOP, ~0UL, @@ -93,7 +93,7 @@ #define ip6_rt_policy (0) #endif -static atomic_t rt6_tbl_lock = 0; +static atomic_t rt6_tbl_lock = ATOMIC_INIT; static int rt6_bh_mask = 0; #define RT_BH_REQUEST 1 @@ -514,7 +514,7 @@ void rt6_ins(struct rt6_info *rt) { start_bh_atomic(); - if (rt6_tbl_lock == 1) + if (atomic_read(&rt6_tbl_lock) == 1) fib6_add(&ip6_routing_table, rt); else rtreq_add(rt, RT_OPER_ADD); @@ -721,7 +721,7 @@ rt6_dflt_pointer = NULL; - if (rt6_tbl_lock == 1) + if (atomic_read(&rt6_tbl_lock) == 1) fib6_del(rt); else rtreq_add(rt, RT_OPER_DEL); diff -u --recursive --new-file v2.1.33/linux/net/ipv6/sysctl_net_ipv6.c linux/net/ipv6/sysctl_net_ipv6.c --- v2.1.33/linux/net/ipv6/sysctl_net_ipv6.c Mon Apr 7 11:35:33 1997 +++ linux/net/ipv6/sysctl_net_ipv6.c Sun Apr 13 09:23:31 1997 @@ -4,6 +4,7 @@ #include #include +#include #include #include #include diff -u --recursive --new-file v2.1.33/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c --- v2.1.33/linux/net/ipv6/tcp_ipv6.c Sun Apr 13 10:18:23 1997 +++ linux/net/ipv6/tcp_ipv6.c Mon Apr 14 09:31:10 1997 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: tcp_ipv6.c,v 1.15 1997/03/18 18:24:56 davem Exp $ + * $Id: tcp_ipv6.c,v 1.20 1997/04/13 10:31:48 davem Exp $ * * Based on: * linux/net/ipv4/tcp.c @@ -445,10 +445,10 @@ tcp_init_xmit_timers(sk); - sk->retransmits = 0; + atomic_set(&sk->retransmits, 0); skb_queue_tail(&sk->write_queue, buff); - sk->packets_out++; + atomic_inc(&sk->packets_out); buff->when = jiffies; skb1 = skb_clone(buff, GFP_KERNEL); skb_set_owner_w(skb1, sk); @@ -570,7 +570,6 @@ static void tcp_v6_send_synack(struct sock *sk, struct open_request *req) { - struct tcp_v6_open_req *af_req = (struct tcp_v6_open_req *) req; struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; struct sk_buff * skb; struct tcphdr *th; @@ -579,19 +578,17 @@ struct flowi fl; skb = sock_wmalloc(sk, MAX_SYN_SIZE, 1, GFP_ATOMIC); - if (skb == NULL) return; fl.proto = IPPROTO_TCP; - fl.nl_u.ip6_u.daddr = &af_req->rmt_addr; - fl.nl_u.ip6_u.saddr = &af_req->loc_addr; - fl.dev = af_req->dev; + fl.nl_u.ip6_u.daddr = &req->af.v6_req.rmt_addr; + fl.nl_u.ip6_u.saddr = &req->af.v6_req.loc_addr; + fl.dev = req->af.v6_req.dev; fl.uli_u.ports.dport = req->rmt_port; fl.uli_u.ports.sport = sk->dummy_th.source; dst = ip6_route_output(sk, &fl); - if (dst->error) { kfree_skb(skb, FREE_WRITE); dst_release(dst); @@ -602,25 +599,23 @@ skb_reserve(skb, (skb->dev->hard_header_len + 15) & ~15); skb->nh.ipv6h = (struct ipv6hdr *) skb_put(skb,sizeof(struct ipv6hdr)); - th = (struct tcphdr *) skb_put(skb, sizeof(struct tcphdr)); - skb->h.th = th; + skb->h.th = th = (struct tcphdr *) skb_put(skb, sizeof(struct tcphdr)); + + /* Yuck, make this header setup more efficient... -DaveM */ memset(th, 0, sizeof(struct tcphdr)); - th->syn = 1; th->ack = 1; - th->source = sk->dummy_th.source; th->dest = req->rmt_port; - skb->seq = req->snt_isn; skb->end_seq = skb->seq + 1; - th->seq = ntohl(skb->seq); th->ack_seq = htonl(req->rcv_isn + 1); th->doff = sizeof(*th)/4 + 1; th->window = ntohs(tp->rcv_wnd); + /* FIXME: csum_partial() of a four byte quantity is itself! -DaveM */ ptr = skb_put(skb, TCPOLEN_MSS); ptr[0] = TCPOPT_MSS; ptr[1] = TCPOLEN_MSS; @@ -629,12 +624,11 @@ skb->csum = csum_partial(ptr, TCPOLEN_MSS, 0); th->check = tcp_v6_check(th, sizeof(*th) + TCPOLEN_MSS, - &af_req->loc_addr, &af_req->rmt_addr, - csum_partial((char *)th, sizeof(*th), - skb->csum)); + &req->af.v6_req.loc_addr, &req->af.v6_req.rmt_addr, + csum_partial((char *)th, sizeof(*th), skb->csum)); ip6_dst_store(sk, dst); - ip6_xmit(sk, skb, &fl, af_req->opt); + ip6_xmit(sk, skb, &fl, req->af.v6_req.opt); dst_release(dst); tcp_statistics.TcpOutSegs++; @@ -652,8 +646,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, __u32 isn) { - struct tcp_v6_open_req *af_req; struct open_request *req; + __u16 req_mss; /* If the socket is dead, don't accept the connection. */ if (sk->dead) { @@ -675,38 +669,30 @@ goto exit; } - af_req = kmalloc(sizeof(struct tcp_v6_open_req), GFP_ATOMIC); - - if (af_req == NULL) { + req = tcp_openreq_alloc(); + if (req == NULL) { tcp_statistics.TcpAttemptFails++; goto exit; } sk->ack_backlog++; - req = (struct open_request *) af_req; - - memset(af_req, 0, sizeof(struct tcp_v6_open_req)); req->rcv_isn = skb->seq; req->snt_isn = isn; - /* mss */ - req->mss = tcp_parse_options(skb->h.th); - - if (!req->mss) - req->mss = 536; - + req_mss = tcp_parse_options(skb->h.th); + if (!req_mss) + req_mss = 536; + req->mss = req_mss; req->rmt_port = skb->h.th->source; - - ipv6_addr_copy(&af_req->rmt_addr, &skb->nh.ipv6h->saddr); - ipv6_addr_copy(&af_req->loc_addr, &skb->nh.ipv6h->daddr); - - /* FIXME: options */ - - /* keep incoming device so that link locals have meaning */ - af_req->dev = skb->dev; + ipv6_addr_copy(&req->af.v6_req.rmt_addr, &skb->nh.ipv6h->saddr); + ipv6_addr_copy(&req->af.v6_req.loc_addr, &skb->nh.ipv6h->daddr); + req->af.v6_req.opt = NULL; /* FIXME: options */ + req->af.v6_req.dev = skb->dev; /* So that link locals have meaning */ req->class = &or_ipv6; + req->retrans = 0; + req->sk = NULL; tcp_v6_send_synack(sk, req); @@ -735,7 +721,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, struct open_request *req) { - struct tcp_v6_open_req *af_req = (struct tcp_v6_open_req *) req; struct ipv6_pinfo *np; struct dst_entry *dst; struct flowi fl; @@ -810,8 +795,8 @@ newsk->done = 0; newsk->partial = NULL; newsk->pair = NULL; - newsk->wmem_alloc = 0; - newsk->rmem_alloc = 0; + atomic_set(&newsk->wmem_alloc, 0); + atomic_set(&newsk->rmem_alloc, 0); newsk->localroute = sk->localroute; newsk->max_unacked = MAX_WINDOW - TCP_WINDOW_DIFF; @@ -836,8 +821,8 @@ newtp->snd_nxt = newsk->write_seq; newsk->urg_data = 0; - newsk->packets_out = 0; - newsk->retransmits = 0; + atomic_set(&newsk->packets_out, 0); + atomic_set(&newsk->retransmits, 0); newsk->linger=0; newsk->destroy = 0; init_timer(&newsk->timer); @@ -856,10 +841,10 @@ newsk->socket = NULL; - ipv6_addr_copy(&np->daddr, &af_req->rmt_addr); - ipv6_addr_copy(&np->saddr, &af_req->loc_addr); - ipv6_addr_copy(&np->rcv_saddr, &af_req->loc_addr); - np->oif = af_req->dev; + ipv6_addr_copy(&np->daddr, &req->af.v6_req.rmt_addr); + ipv6_addr_copy(&np->saddr, &req->af.v6_req.loc_addr); + ipv6_addr_copy(&np->rcv_saddr, &req->af.v6_req.loc_addr); + np->oif = req->af.v6_req.dev; /* * options / mss / route cache @@ -877,7 +862,7 @@ ip6_dst_store(newsk, dst); if (dst->error) - newsk->mtu = af_req->dev->mtu; + newsk->mtu = req->af.v6_req.dev->mtu; else newsk->mtu = dst->pmtu; @@ -963,26 +948,18 @@ struct sock *tcp_v6_check_req(struct sock *sk, struct sk_buff *skb) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - struct open_request *req; + struct open_request *req = tp->syn_wait_queue; - /* - * assumption: the socket is not in use. + /* assumption: the socket is not in use. * as we checked the user count on tcp_rcv and we're * running from a soft interrupt. */ - - req = tp->syn_wait_queue; - if (!req) return sk; do { - struct tcp_v6_open_req *af_req; - - af_req = (struct tcp_v6_open_req *) req; - - if (!ipv6_addr_cmp(&af_req->rmt_addr, &skb->nh.ipv6h->saddr) && - !ipv6_addr_cmp(&af_req->loc_addr, &skb->nh.ipv6h->daddr) && + if (!ipv6_addr_cmp(&req->af.v6_req.rmt_addr, &skb->nh.ipv6h->saddr) && + !ipv6_addr_cmp(&req->af.v6_req.loc_addr, &skb->nh.ipv6h->daddr) && req->rmt_port == skb->h.th->source) { u32 flg; @@ -992,18 +969,13 @@ break; } - /* match */ - - /* - * Check for syn retransmission - */ + /* Check for syn retransmission */ flg = *(((u32 *)skb->h.th) + 3); flg &= __constant_htonl(0x002f0000); if ((flg == __constant_htonl(0x00020000)) && (!after(skb->seq, req->rcv_isn))) { - /* - * retransmited syn + /* retransmited syn * FIXME: must send an ack */ return NULL; @@ -1022,10 +994,7 @@ req->sk = sk; break; } - - req = req->dl_next; - } while (req != tp->syn_wait_queue); - + } while ((req = req->dl_next) != tp->syn_wait_queue); return sk; } @@ -1316,7 +1285,7 @@ tp->rcv_wnd = 8192; /* start with only sending one packet at a time. */ - sk->cong_window = 1; + tp->snd_cwnd = 1; sk->ssthresh = 0x7fffffff; sk->priority = 1; diff -u --recursive --new-file v2.1.33/linux/net/ipv6/udp.c linux/net/ipv6/udp.c --- v2.1.33/linux/net/ipv6/udp.c Sun Apr 13 10:18:23 1997 +++ linux/net/ipv6/udp.c Mon Apr 14 09:31:10 1997 @@ -7,7 +7,7 @@ * * Based on linux/ipv4/udp.c * - * $Id: udp.c,v 1.12 1997/03/18 18:24:59 davem Exp $ + * $Id: udp.c,v 1.16 1997/04/11 22:22:57 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -290,7 +290,7 @@ dst_release(np->dst); ipv6_sock_mc_close(sk); - + udp_v6_unhash(sk); release_sock(sk); destroy_sock(sk); } @@ -382,7 +382,7 @@ sk = udp_v6_lookup(daddr, uh->dest, saddr, uh->source); if (sk == NULL) { - printk(KERN_DEBUG "icmp for unkown sock\n"); + printk(KERN_DEBUG "icmp for unknown sock\n"); return; } diff -u --recursive --new-file v2.1.33/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c --- v2.1.33/linux/net/ipx/af_ipx.c Thu Mar 27 14:40:17 1997 +++ linux/net/ipx/af_ipx.c Mon Apr 14 09:31:10 1997 @@ -1636,7 +1636,8 @@ htons(s->protinfo.af_ipx.dest_addr.sock)); } len += sprintf (buffer+len,"%08X %08X ", - s->wmem_alloc, s->rmem_alloc); + atomic_read(&s->wmem_alloc), + atomic_read(&s->rmem_alloc)); len += sprintf (buffer+len,"%02X %03d\n", s->state, SOCK_INODE(s->socket)->i_uid); @@ -2254,7 +2255,7 @@ switch(cmd) { case TIOCOUTQ: - amount=sk->sndbuf-sk->wmem_alloc; + amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if(amount<0) amount=0; return put_user(amount, (int *)arg); diff -u --recursive --new-file v2.1.33/linux/net/netbeui/af_netbeui.c linux/net/netbeui/af_netbeui.c --- v2.1.33/linux/net/netbeui/af_netbeui.c Thu Feb 27 10:57:32 1997 +++ linux/net/netbeui/af_netbeui.c Mon Apr 14 09:31:10 1997 @@ -513,7 +513,7 @@ * Protocol layer */ case TIOCOUTQ: - amount=sk->sndbuf-sk->wmem_alloc; + amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if(amount<0) amount=0; break; diff -u --recursive --new-file v2.1.33/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c --- v2.1.33/linux/net/netrom/af_netrom.c Mon Apr 7 11:35:33 1997 +++ linux/net/netrom/af_netrom.c Mon Apr 14 09:31:10 1997 @@ -308,7 +308,8 @@ kfree_skb(skb, FREE_READ); } - if (sk->wmem_alloc != 0 || sk->rmem_alloc != 0) { /* Defer: outstanding buffers */ + if (atomic_read(&sk->wmem_alloc) != 0 || atomic_read(&sk->rmem_alloc) != 0) { + /* Defer: outstanding buffers */ init_timer(&sk->timer); sk->timer.expires = jiffies + 10 * HZ; sk->timer.function = nr_destroy_timer; @@ -1183,7 +1184,7 @@ case TIOCOUTQ: if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int))) != 0) return err; - amount = sk->sndbuf - sk->wmem_alloc; + amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if (amount < 0) amount = 0; put_user(amount, (int *)arg); @@ -1277,7 +1278,7 @@ s->protinfo.nr->n2count, s->protinfo.nr->n2, s->protinfo.nr->window, - s->wmem_alloc, s->rmem_alloc); + atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc)); pos = begin + len; diff -u --recursive --new-file v2.1.33/linux/net/netrom/nr_timer.c linux/net/netrom/nr_timer.c --- v2.1.33/linux/net/netrom/nr_timer.c Thu Mar 27 14:40:17 1997 +++ linux/net/netrom/nr_timer.c Mon Apr 14 09:31:10 1997 @@ -85,7 +85,8 @@ /* * Check for the state of the receive buffer. */ - if (sk->rmem_alloc < (sk->rcvbuf / 2) && (sk->protinfo.nr->condition & NR_COND_OWN_RX_BUSY)) { + if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) && + (sk->protinfo.nr->condition & NR_COND_OWN_RX_BUSY)) { sk->protinfo.nr->condition &= ~NR_COND_OWN_RX_BUSY; sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING; sk->protinfo.nr->vl = sk->protinfo.nr->vr; diff -u --recursive --new-file v2.1.33/linux/net/netsyms.c linux/net/netsyms.c --- v2.1.33/linux/net/netsyms.c Mon Apr 7 11:35:33 1997 +++ linux/net/netsyms.c Mon Apr 14 09:31:10 1997 @@ -237,6 +237,7 @@ EXPORT_SYMBOL(net_delete_timer); EXPORT_SYMBOL(udp_prot); EXPORT_SYMBOL(tcp_prot); +EXPORT_SYMBOL(tcp_openreq_cachep); EXPORT_SYMBOL(ipv4_specific); #endif @@ -260,6 +261,7 @@ EXPORT_SYMBOL(register_trdev); EXPORT_SYMBOL(unregister_trdev); EXPORT_SYMBOL(init_trdev); +EXPORT_SYMBOL(tr_freedev); #endif #ifdef CONFIG_NET_ALIAS diff -u --recursive --new-file v2.1.33/linux/net/rose/af_rose.c linux/net/rose/af_rose.c --- v2.1.33/linux/net/rose/af_rose.c Mon Apr 7 11:35:33 1997 +++ linux/net/rose/af_rose.c Mon Apr 14 09:31:10 1997 @@ -357,7 +357,8 @@ kfree_skb(skb, FREE_READ); } - if (sk->wmem_alloc != 0 || sk->rmem_alloc != 0) { /* Defer: outstanding buffers */ + if (atomic_read(&sk->wmem_alloc) != 0 || atomic_read(&sk->rmem_alloc) != 0) { + /* Defer: outstanding buffers */ init_timer(&sk->timer); sk->timer.expires = jiffies + 10 * HZ; sk->timer.function = rose_destroy_timer; @@ -1184,7 +1185,7 @@ case TIOCOUTQ: if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int))) != 0) return err; - amount = sk->sndbuf - sk->wmem_alloc; + amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if (amount < 0) amount = 0; put_user(amount, (unsigned int *)arg); @@ -1290,7 +1291,7 @@ s->protinfo.rose->t2 / ROSE_SLOWHZ, s->protinfo.rose->t3 / ROSE_SLOWHZ, s->protinfo.rose->hb / ROSE_SLOWHZ, - s->wmem_alloc, s->rmem_alloc); + atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc)); pos = begin + len; diff -u --recursive --new-file v2.1.33/linux/net/rose/rose_timer.c linux/net/rose/rose_timer.c --- v2.1.33/linux/net/rose/rose_timer.c Thu Mar 27 14:40:18 1997 +++ linux/net/rose/rose_timer.c Mon Apr 14 09:31:10 1997 @@ -85,7 +85,8 @@ /* * Check for the state of the receive buffer. */ - if (sk->rmem_alloc < (sk->rcvbuf / 2) && (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY)) { + if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) && + (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY)) { sk->protinfo.rose->condition &= ~ROSE_COND_OWN_RX_BUSY; sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING; sk->protinfo.rose->vl = sk->protinfo.rose->vr; diff -u --recursive --new-file v2.1.33/linux/net/sunrpc/pmap_clnt.c linux/net/sunrpc/pmap_clnt.c --- v2.1.33/linux/net/sunrpc/pmap_clnt.c Mon Apr 7 11:35:33 1997 +++ linux/net/sunrpc/pmap_clnt.c Mon Apr 14 09:31:10 1997 @@ -32,7 +32,8 @@ extern struct rpc_program pmap_program; /* - * Obtain the port for a given RPC service on a given host + * Obtain the port for a given RPC service on a given host. This one can + * be called for an ongoing RPC request. */ void rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt) @@ -75,6 +76,34 @@ task->tk_status = -EIO; task->tk_action = NULL; } + +#ifdef CONFIG_ROOT_NFS +int +rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot) +{ + struct rpc_portmap map = { prog, vers, prot, 0 }; + struct rpc_clnt *pmap_clnt; + char hostname[32]; + int status; + + dprintk("RPC: rpc_getport_external(%s, %d, %d, %d)\n", + in_ntoa(sin->sin_addr.s_addr), prog, vers, prot); + + strcpy(hostname, in_ntoa(sin->sin_addr.s_addr)); + if (!(pmap_clnt = pmap_create(hostname, sin, prot))) + return -EACCES; + + /* Setup the call info struct */ + status = rpc_call(pmap_clnt, PMAP_GETPORT, &map, &map.pm_port, 0); + + if (status >= 0) { + if (map.pm_port != 0) + return map.pm_port; + status = -EACCES; + } + return status; +} +#endif static void pmap_getport_done(struct rpc_task *task) diff -u --recursive --new-file v2.1.33/linux/net/sunrpc/svcsock.c linux/net/sunrpc/svcsock.c --- v2.1.33/linux/net/sunrpc/svcsock.c Mon Apr 7 11:35:33 1997 +++ linux/net/sunrpc/svcsock.c Mon Apr 14 09:31:10 1997 @@ -962,6 +962,6 @@ kfree(svsk); } else { printk(KERN_NOTICE "svc: server socket destroy delayed\n"); - svsk->sk_server = NULL; + /* svsk->sk_server = NULL; */ } } diff -u --recursive --new-file v2.1.33/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v2.1.33/linux/net/unix/af_unix.c Thu Mar 27 14:40:18 1997 +++ linux/net/unix/af_unix.c Mon Apr 14 09:31:10 1997 @@ -228,7 +228,7 @@ static void unix_destroy_timer(unsigned long data) { unix_socket *sk=(unix_socket *)data; - if(!unix_locked(sk) && sk->wmem_alloc==0) + if(!unix_locked(sk) && atomic_read(&sk->wmem_alloc) == 0) { unix_release_addr(sk->protinfo.af_unix.addr); sk_free(sk); @@ -281,7 +281,7 @@ sk->protinfo.af_unix.inode=NULL; } - if(!unix_unlock(sk) && sk->wmem_alloc==0) + if(!unix_unlock(sk) && atomic_read(&sk->wmem_alloc) == 0) { unix_release_addr(sk->protinfo.af_unix.addr); sk_free(sk); @@ -348,7 +348,7 @@ sk->protinfo.af_unix.family=AF_UNIX; sk->protinfo.af_unix.inode=NULL; - sk->sock_readers=1; /* Us */ + sk->sock_readers=1; /* Us */ sk->protinfo.af_unix.readsem=MUTEX; /* single task reading lock */ sk->mtu=4096; sk->protinfo.af_unix.list=&unix_sockets_unbound; @@ -418,7 +418,7 @@ } memset(addr, 0, sizeof(*addr) + sizeof(short) + 16); addr->name->sun_family = AF_UNIX; - addr->refcnt = 1; + atomic_set(&addr->refcnt, 1); retry: addr->len = sprintf(addr->name->sun_path+1, "%08x", ordernum) + 1 + sizeof(short); @@ -504,7 +504,7 @@ if (!addr) return -ENOBUFS; - /* We sleeped; recheck ... */ + /* We slept; recheck ... */ if (sk->protinfo.af_unix.addr || sk->protinfo.af_unix.inode) { @@ -515,7 +515,7 @@ memcpy(addr->name, sunaddr, addr_len); addr->len = addr_len; addr->hash = hash; - addr->refcnt = 1; + atomic_set(&addr->refcnt, 1); if (!sunaddr->sun_path[0]) { @@ -1105,26 +1105,16 @@ struct sock *sk = sock->sk; int noblock = flags & MSG_DONTWAIT; struct sk_buff *skb; + int err; if (flags&MSG_OOB) return -EOPNOTSUPP; msg->msg_namelen = 0; -retry: - skb=skb_dequeue(&sk->receive_queue); - - if (skb==NULL) - { - if (sk->shutdown & RCV_SHUTDOWN) - return 0; - if (noblock) - return -EAGAIN; - unix_data_wait(sk); - if (current->signal & ~current->blocked) - return -ERESTARTSYS; - goto retry; - } + skb=skb_recv_datagram(sk, flags, noblock, &err); + if(skb==NULL) + return err; if (msg->msg_name) { @@ -1143,10 +1133,8 @@ else if (size < skb->len) msg->msg_flags |= MSG_TRUNC; - if (memcpy_toiovec(msg->msg_iov, skb->data, size)) { - skb_queue_head(&sk->receive_queue, skb); + if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, size)) return -EFAULT; - } scm->creds = *UNIXCREDS(skb); @@ -1154,9 +1142,9 @@ { if (UNIXCB(skb).fp) unix_detach_fds(scm, skb); - kfree_skb(skb, FREE_WRITE); - return size; - } else + } + else + { /* It is questionable: on PEEK we could: - do not return fds - good, but too simple 8) - return fds, and do not return them on read (old strategy, @@ -1171,8 +1159,8 @@ */ if (UNIXCB(skb).fp) scm->fp = scm_fp_dup(UNIXCB(skb).fp); - - skb_queue_head(&sk->receive_queue, skb); + } + skb_free_datagram(sk,skb); return size; } @@ -1342,7 +1330,7 @@ { case TIOCOUTQ: - amount=sk->sndbuf-sk->wmem_alloc; + amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if(amount<0) amount=0; return put_user(amount, (int *)arg); @@ -1475,7 +1463,7 @@ struct sk_buff *dummy_skb; struct proc_dir_entry *ent; - printk(KERN_INFO "NET3: Unix domain sockets 0.15 for Linux NET3.038.\n"); + printk(KERN_INFO "NET3: Unix domain sockets 0.16 for Linux NET3.038.\n"); if (sizeof(struct unix_skb_parms) > sizeof(dummy_skb->cb)) { printk(KERN_CRIT "unix_proto_init: panic\n"); diff -u --recursive --new-file v2.1.33/linux/net/x25/af_x25.c linux/net/x25/af_x25.c --- v2.1.33/linux/net/x25/af_x25.c Mon Apr 7 11:35:33 1997 +++ linux/net/x25/af_x25.c Mon Apr 14 09:31:10 1997 @@ -328,7 +328,8 @@ kfree_skb(skb, FREE_READ); } - if (sk->wmem_alloc != 0 || sk->rmem_alloc != 0) { /* Defer: outstanding buffers */ + if (atomic_read(&sk->wmem_alloc) != 0 || atomic_read(&sk->rmem_alloc) != 0) { + /* Defer: outstanding buffers */ init_timer(&sk->timer); sk->timer.expires = jiffies + 10 * HZ; sk->timer.function = x25_destroy_timer; @@ -1057,7 +1058,7 @@ case TIOCOUTQ: if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned long))) != 0) return err; - amount = sk->sndbuf - sk->wmem_alloc; + amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if (amount < 0) amount = 0; put_user(amount, (unsigned long *)arg); @@ -1198,7 +1199,7 @@ s->protinfo.x25->t21 / X25_SLOWHZ, s->protinfo.x25->t22 / X25_SLOWHZ, s->protinfo.x25->t23 / X25_SLOWHZ, - s->wmem_alloc, s->rmem_alloc); + atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc)); pos = begin + len; diff -u --recursive --new-file v2.1.33/linux/net/x25/x25_timer.c linux/net/x25/x25_timer.c --- v2.1.33/linux/net/x25/x25_timer.c Thu Mar 27 14:40:18 1997 +++ linux/net/x25/x25_timer.c Mon Apr 14 09:31:10 1997 @@ -84,7 +84,8 @@ /* * Check for the state of the receive buffer. */ - if (sk->rmem_alloc < (sk->rcvbuf / 2) && (sk->protinfo.x25->condition & X25_COND_OWN_RX_BUSY)) { + if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) && + (sk->protinfo.x25->condition & X25_COND_OWN_RX_BUSY)) { sk->protinfo.x25->condition &= ~X25_COND_OWN_RX_BUSY; sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING; sk->protinfo.x25->vl = sk->protinfo.x25->vr; diff -u --recursive --new-file v2.1.33/linux/scripts/Configure linux/scripts/Configure --- v2.1.33/linux/scripts/Configure Sun Apr 13 10:18:23 1997 +++ linux/scripts/Configure Fri Apr 11 10:50:49 1997 @@ -47,8 +47,9 @@ # 090397 Axel Boldt (boldt@math.ucsb.edu) - avoid ? and + in regular # expressions for GNU expr since version 1.15 and up use \? and \+. # -# 300397 Phil Blundell (pjb27@cam.ac.uk) - added support for "limint", -# allow dep_tristate to take a list of dependencies rather than just one. +# 300397 Phil Blundell (pjb27@cam.ac.uk) - added support for min/max +# arguments to "int", allow dep_tristate to take a list of dependencies +# rather than just one. # # Make sure we're really running bash. @@ -311,7 +312,7 @@ if [ $# -gt 3 ]; then min=$4 else - min=1 + min=-10000000 # !! fi if [ $# -gt 4 ]; then max=$5